From 63a6e911bd3ad50750168966d1c96f07fc898d39 Mon Sep 17 00:00:00 2001 From: kali-upper Date: Tue, 3 Nov 2026 22:15:40 +0200 Subject: [PATCH 1/2] feat(display): colors are the only user-facing clone names across menus and scripts The shortcut files have been color-named since 2026-11-01 (ZCode Blue.lnk etc.) but GHOST.bat rows and the suite scripts' console output still spoke the frozen keys - Second/Fifth for ZCode, c1/c2 for the newer suites. Two vocabularies for one clone confused users. Menus: all 31 :Opt rows across the four clone submenus now read 'Launch Blue clone' / 'Reset Red clone' / 'Launch Yellow clone'; tails carry only qualifiers; dispatch labels and notes follow. Window titles were already color-based. Scripts: every user-visible print now leads with the color. launchers and watchers use their existing DisplayName/Title/Color fields; reset_zcode.ps1, sync_zcode_assets.ps1 and launch_cline_clone.ps1 gained small key-to-color helpers. Identification lines (banners, section headers, summaries) keep the frozen key as 'Color (key)' / 'Color / key' so CLI params and docs stay correlatable; status lines are color-only. .lnk Description metadata is color-led; the suite generator templates teach the pattern. Frozen plumbing untouched: -Instance/-Target params, clone dirs, AUMIDs, log filenames, port tables, window classes. Verified: 14/14 parse-check, repo-integrity 11/11, GH_SEQ chained smoke of all four submenus (17 stubbed launches, zero CMD errors), live -Instance Sixth run ('[ram-guard] Orange is already running...'), sync -Target Sixth -DryRun ('=== Orange / Sixth (ZCodeSixthHome) ==='). --- AGENTS.md | 22 ++-- CHANGELOG.md | 13 +++ GHOST.bat | 68 ++++++------ docs/cli.md | 15 +-- src/windows/launch_cline_clone.ps1 | 8 +- src/windows/launch_opencode_clone.ps1 | 4 +- src/windows/launch_zcode_cli_light.ps1 | 12 +-- src/windows/launch_zcode_second_instance.ps1 | 18 ++-- src/windows/reset_zcode.ps1 | 92 +++++++++++------ tools/install_autoclaw2_clone_shortcuts.ps1 | 2 +- tools/install_cline_clone_shortcuts.ps1 | 2 +- tools/install_opencode_clone_shortcuts.ps1 | 2 +- tools/install_zcode_second_shortcuts.ps1 | 4 +- tools/new_clone_suite.ps1 | 10 +- tools/refresh_zcode_second_chats.ps1 | 6 +- tools/sync_zcode_assets.ps1 | 103 ++++++++++--------- tools/watch_zcode_mcp_sync.ps1 | 23 +++-- tools/watch_zcode_taskbar.ps1 | 10 +- 18 files changed, 240 insertions(+), 174 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 8b04b34..9ea280b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -488,25 +488,29 @@ Each IDE script is a **thin target manifest**: dot-source utils -> Assert-Admin (Bit us in `GHOST.bat` option [10]: the menu drowned in `[pid:*]` logs.) - **Submenu ids are display-ordered (renumbered 2026-10-29).** Every submenu's local ids run strictly ascending 1..N in visual order, grouped by `:Div` - sections — ZCode: Launch Clones [1]-[8] (Second/Third/Fourth/Fifth/Sixth, - ALL, light worker, shortcuts) / Reset Clones [9]-[16] (Second..Sixth, + sections — ZCode: Launch Clones [1]-[8] (Blue/Yellow/Green/Red/Orange, + ALL, light worker, shortcuts) / Reset Clones [9]-[16] (Blue..Orange, Primary, Both, ALL SIX) / Sync + Chat Refresh [17]-[23] / Watchers + Diagnostics [24]-[26] / Maintenance [27]-[29] (patch, login helper, shortcuts remove); AutoClaw2: Launch Clones [1]-[7] - (c1..c5, ALL, shortcuts) / Maintenance [8]-[9] (rewired to the AutoClaw2 + (Blue..Orange, ALL, shortcuts) / Maintenance [8]-[9] (rewired to the AutoClaw2 suite the same day — born display-ordered); Cline: Launch Clones [1]-[7] - (c1..c5, ALL, shortcuts) / Maintenance [8]-[9]; OpenCode: Launch Clones - [1]-[7] (c1..c5, ALL, shortcuts) / Maintenance [8]-[10] (patch, status, + (Blue..Orange, ALL, shortcuts) / Maintenance [8]-[9]; OpenCode: Launch Clones + [1]-[7] (Blue..Orange, ALL, shortcuts) / Maintenance [8]-[10] (patch, status, remove — 2026-10-31: shortcuts moved into Launch and the patch row into Maintenance, locals [7]/[8] swapped, gids unchanged). **Gids NEVER renumber** — specs, wiring history and repo-integrity cite them; a renumber touches only the submenu echo block + its resolver ladder. Add future rows in display order inside their section — never a higher id out of sequence (the .bat harness asserts ascending ids per submenu). - **Row pattern (2026-10-31): the label carries the action + name ONLY — the - color and all qualifiers live in the tail** (`Reset Third instance` + - `- Yellow (survivors kept running)`); never embed a `- descriptor` inside - a label. **Naming scheme (2026-11-01 display unification):** the shortcut + **Row pattern (2026-11-03, supersedes the 2026-10-31 rule): the label + carries the action + COLOR name ONLY** (`Reset Red clone` + + `- survivors kept running`) — qualifiers live in the tail, never a + `- descriptor` inside a label, and the frozen keys (Second..Sixth / c1..cN) + are never user-visible in menu rows, window titles or script console + output; they survive only in CLI params, dirs, AUMIDs and log filenames, + and in identification lines as `Color (key)` / `Color / key`. + **Naming scheme (2026-11-01 display unification):** the shortcut FILE names use the color vocabulary shared by all four suites — ` .lnk` (`ZCode Blue.lnk` .. `ZCode Orange.lnk`, matching the `ZCode ` window titles); the pre-unification ordinal/cN names are diff --git a/CHANGELOG.md b/CHANGELOG.md index f9c8282..1d2116a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,19 @@ Format based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). follow-up note now reminds about relaunching via the OpenCode shortcuts (a bare OpenCode.exe opens the PRIMARY profile). +### Changed +- **Colors are now the ONLY user-facing clone names** (2026-11-03): GHOST.bat + rows (`Launch Blue clone` / `Reset Red clone` / `Launch Yellow clone` for + ZCode, AutoClaw2, Cline and OpenCode) and the suite scripts' console output + (ram-guard, seed, telegram-route, reset banners and per-step tags, sync + headers and tags, taskbar/MCP watcher logs, shortcut installers, status + lines) lead with the COLOR vocabulary, matching the shortcut file names + unified on 2026-11-01 — the frozen keys (Second..Sixth, c1..cN) survive + only in CLI params, dirs, AUMIDs and log filenames, and in identification + lines as `Color (key)` / `Color / key` so params and docs stay + correlatable. `.lnk` Description metadata is color-led too; the suite + generator templates teach the pattern to future suites. + ### Fixed - **ZCode clone shortcuts hung invisibly at the RAM guard** (2026-11-01): the Desktop/Start-menu shortcuts run the launcher with `-WindowStyle diff --git a/GHOST.bat b/GHOST.bat index 0277299..7bfefbb 100644 --- a/GHOST.bat +++ b/GHOST.bat @@ -112,23 +112,23 @@ cls if defined ESC (echo %ESC%[96mGHOST / ZCode Multi-Instance ^& Clones%ESC%[0m) else echo GHOST / ZCode Multi-Instance ^& Clones echo. call :Div "Launch Clones" -call :Opt 1 "Launch Second instance" "- Blue branding (independent window)" -call :Opt 2 "Launch Third instance" "- Yellow branding (independent window)" -call :Opt 3 "Launch Fourth instance" "- Green branding (independent window)" -call :Opt 4 "Launch Fifth instance" "- Red branding (independent window)" -call :Opt 5 "Launch Sixth instance" "- Orange branding (independent window)" -call :Opt 6 "Launch ALL clones" "- Second..Sixth, one after another" +call :Opt 1 "Launch Blue clone" "- independent window" +call :Opt 2 "Launch Yellow clone" "- independent window" +call :Opt 3 "Launch Green clone" "- independent window" +call :Opt 4 "Launch Red clone" "- independent window" +call :Opt 5 "Launch Orange clone" "- independent window" +call :Opt 6 "Launch ALL clones" "- Blue..Orange, one after another" call :Opt 7 "Launch light headless worker" "- run a clone account with no desktop window - low RAM" call :Opt 8 "Install clone shortcuts" "- all 5 - Desktop + Start menu" echo. call :Div "Reset Clones" -call :Opt 9 "Reset Second instance" "- Blue (survivors kept running)" -call :Opt 10 "Reset Third instance" "- Yellow (survivors kept running)" -call :Opt 11 "Reset Fourth instance" "- Green (survivors kept running)" -call :Opt 12 "Reset Fifth instance" "- Red (survivors kept running)" -call :Opt 13 "Reset Sixth instance" "- Orange (survivors kept running)" +call :Opt 9 "Reset Blue clone" "- survivors kept running" +call :Opt 10 "Reset Yellow clone" "- survivors kept running" +call :Opt 11 "Reset Green clone" "- survivors kept running" +call :Opt 12 "Reset Red clone" "- survivors kept running" +call :Opt 13 "Reset Orange clone" "- survivors kept running" call :Opt 14 "Reset ZCode Primary instance" "" -call :Opt 15 "Reset Second + Primary" "(independent IDs)" +call :Opt 15 "Reset Blue + Primary" "(independent IDs)" call :Opt 16 "Reset ALL SIX instances" "(independent IDs)" echo. call :Div "Sync + Chat Refresh" @@ -136,7 +136,7 @@ call :Opt 17 "Sync clone assets" "- MCPs + skills + plugins from Primary" call :Opt 18 "Sync MCPs to all clones" "- live - running instances included" call :Opt 19 "MCP sync watcher" "- auto-sync on Primary change (separate window)" call :Opt 20 "Sync MCPs + apply live now" "- recycles running instances - idle-guarded" -call :Opt 21 "Refresh Second chats" "- show Primary chats without app restart" +call :Opt 21 "Refresh Blue chats" "- show Primary chats without app restart" call :Opt 22 "Refresh ALL chats" "- re-index every running sidebar" call :Opt 23 "Watch errors" "- auto-refresh chats on quota or captcha failure" echo. @@ -199,12 +199,12 @@ cls if defined ESC (echo %ESC%[96mGHOST / AutoClaw2 Multi-Instance ^& Clones%ESC%[0m) else echo GHOST / AutoClaw2 Multi-Instance ^& Clones echo. call :Div "Launch Clones" -call :Opt 1 "Launch c1" "- Blue - own profile, identity, sign-in" -call :Opt 2 "Launch c2" "- Yellow" -call :Opt 3 "Launch c3" "- Green" -call :Opt 4 "Launch c4" "- Red" -call :Opt 5 "Launch c5" "- Orange" -call :Opt 6 "Launch ALL clones" "- c1..c5, one after another" +call :Opt 1 "Launch Blue clone" "- own profile, identity, sign-in" +call :Opt 2 "Launch Yellow clone" "" +call :Opt 3 "Launch Green clone" "" +call :Opt 4 "Launch Red clone" "" +call :Opt 5 "Launch Orange clone" "" +call :Opt 6 "Launch ALL clones" "- Blue..Orange, one after another" call :Opt 7 "Install clone shortcuts" "- all 5 - Desktop + Start menu" echo. call :Div "Maintenance" @@ -234,12 +234,12 @@ cls if defined ESC (echo %ESC%[96mGHOST / Cline Multi-Instance ^& Clones%ESC%[0m) else echo GHOST / Cline Multi-Instance ^& Clones echo. call :Div "Launch Clones" -call :Opt 1 "Launch c1" "- Blue - own state, web login, ports" -call :Opt 2 "Launch c2" "- Yellow" -call :Opt 3 "Launch c3" "- Green" -call :Opt 4 "Launch c4" "- Red" -call :Opt 5 "Launch c5" "- Orange" -call :Opt 6 "Launch ALL clones" "- c1..c5, one after another" +call :Opt 1 "Launch Blue clone" "- own state, web login, ports" +call :Opt 2 "Launch Yellow clone" "" +call :Opt 3 "Launch Green clone" "" +call :Opt 4 "Launch Red clone" "" +call :Opt 5 "Launch Orange clone" "" +call :Opt 6 "Launch ALL clones" "- Blue..Orange, one after another" call :Opt 7 "Install clone shortcuts" "- all 5 - Desktop + Start menu" echo. call :Div "Maintenance" @@ -269,12 +269,12 @@ cls if defined ESC (echo %ESC%[96mGHOST / OpenCode Multi-Instance ^& Clones%ESC%[0m) else echo GHOST / OpenCode Multi-Instance ^& Clones echo. call :Div "Launch Clones" -call :Opt 1 "Launch c1" "- Blue - own clone home, login, identity" -call :Opt 2 "Launch c2" "- Yellow" -call :Opt 3 "Launch c3" "- Green" -call :Opt 4 "Launch c4" "- Red" -call :Opt 5 "Launch c5" "- Orange" -call :Opt 6 "Launch ALL clones" "- c1..c5, one after another" +call :Opt 1 "Launch Blue clone" "- own clone home, login, identity" +call :Opt 2 "Launch Yellow clone" "" +call :Opt 3 "Launch Green clone" "" +call :Opt 4 "Launch Red clone" "" +call :Opt 5 "Launch Orange clone" "" +call :Opt 6 "Launch ALL clones" "- Blue..Orange, one after another" call :Opt 7 "Install clone shortcuts" "- all 5 - Desktop + Start menu" echo. call :Div "Maintenance" @@ -470,10 +470,10 @@ if "%~1"=="8" (call :Run "src\windows\reset_minimax_opencode.ps1" & exit /b) if "%~1"=="9" (call :Detached "ZCode captcha watch" "-NoExit -NoProfile" "tools\watch_zcode_captcha.ps1" "" "Watchdog launched in a separate window - leave it open." "To verify it runs: check %LOCALAPPDATA%\watch-zcode-captcha\watch.log" & exit /b) if "%~1"=="10" (call :Detached "ZCode Blue" "-NoProfile" "src\windows\launch_zcode_second_instance.ps1" "" "Launcher opened in a separate window - it closes automatically when done." & exit /b) if "%~1"=="11" (call :RunZcodeReset "src\windows\reset_zcode.ps1" -Target Secondary & exit /b) -if "%~1"=="12" (call :ConfirmReset "Reset Second + Primary - independent IDs" "src\windows\reset_zcode.ps1" "-Target Both" & exit /b) +if "%~1"=="12" (call :ConfirmReset "Reset Blue + Primary - independent IDs" "src\windows\reset_zcode.ps1" "-Target Both" & exit /b) if "%~1"=="13" (call :RunWith "tools\patch_zcode_icon_override.ps1" "Patch finished - relaunch instances via their ZCode shortcuts - a bare ZCode.exe opens the PRIMARY profile." -WaitForClose & exit /b) if "%~1"=="14" (call :RunWith "tools\install_zcode_second_shortcuts.ps1" "Look for the new ZCode Blue, ZCode Yellow, ZCode Green, ZCode Red and ZCode Orange shortcuts on your Desktop and in the Start menu." & exit /b) -if "%~1"=="15" (call :RunWith "tools\refresh_zcode_second_chats.ps1" "The blue Secondary window refreshes its chat list by itself in a few seconds." & exit /b) +if "%~1"=="15" (call :RunWith "tools\refresh_zcode_second_chats.ps1" "The Blue clone window refreshes its chat list by itself in a few seconds." & exit /b) if "%~1"=="16" (call :Detached "ZCode Yellow" "-NoProfile" "src\windows\launch_zcode_second_instance.ps1" "-Instance Third" "Launcher opened in a separate window - it closes automatically when done." & exit /b) if "%~1"=="17" (call :Detached "ZCode Green" "-NoProfile" "src\windows\launch_zcode_second_instance.ps1" "-Instance Fourth" "Launcher opened in a separate window - it closes automatically when done." & exit /b) if "%~1"=="18" ( @@ -488,7 +488,7 @@ if "%~1"=="18" ( call :StartClone "ZCode Orange" "src\windows\launch_zcode_second_instance.ps1" "-Instance Sixth" echo Five launcher windows opened - each closes automatically when done. echo First runs clone the Primary profile, so expect a short delay per clone. - echo Launch logs: tools\logs\launch_zcode_Second..Sixth.log - one file per clone. + echo Launch logs: tools\logs - one launch_zcode log file per clone. pause exit /b ) diff --git a/docs/cli.md b/docs/cli.md index bbef365..4ba8aa1 100644 --- a/docs/cli.md +++ b/docs/cli.md @@ -41,8 +41,10 @@ powershell -ExecutionPolicy Bypass -File "src\windows\spoof_wmi_serials.ps1" -Dr Menu equivalents for the reset targets: `reset_zcode.ps1 -Target Primary` = IDE Resets [7] **and** ZCode [14] (the same task from both menus); -`-Target Secondary` / `Both` / `Third` / `Fourth` / `Fifth` / `Sixth` / `All` = ZCode -[9] / [15] / [10] / [11] / [12] / [13] / [16]. The AutoClaw v1.20 suite +`-Target Secondary` / `Both` / `Third` / `Fourth` / `Fifth` / `Sixth` / `All` = +ZCode [9] Reset **Blue** clone / [15] **Blue** + Primary / [10] **Yellow** / +[11] **Green** / [12] **Red** / [13] **Orange** / [16] **ALL SIX** (menus display +the COLOR names; the CLI params keep the frozen keys). The AutoClaw v1.20 suite (`reset_autoclaw.ps1` and friends) was REMOVED 2026-10-31 with the v1.20 app (uninstalled from the dev host 2026-10-29) — recover it from git history or `archive/autoclaw-v1.20/` for a v1.20 host. AutoClaw2 has no reset script @@ -73,9 +75,10 @@ First launch of each clone copies history into its own home ZCodeFifthHome | ZCodeSixthHome`), scrubs it to fresh IDs, and reconciles Telegram channel bots via sha8 credential comparison (duplicates of Primary disabled, unique clone bots preserved — -see [docs/ZCODE_TELEGRAM_BOTS.md](ZCODE_TELEGRAM_BOTS.md)). Branding: -Second = blue, Third = yellow, Fourth = green, Fifth = red #CA0607, -Sixth = orange #CB5D06 +see [docs/ZCODE_TELEGRAM_BOTS.md](ZCODE_TELEGRAM_BOTS.md)). Colors ARE the +display vocabulary (menus, console output, shortcut names): Blue, Yellow, +Green, Red #CA0607, Orange #CB5D06 — the `-Instance` params keep the frozen +keys Second/Third/Fourth/Fifth/Sixth (separate taskbar buttons + window titles "ZCode Blue"/"ZCode Yellow"/ "ZCode Green"/"ZCode Red"/"ZCode Orange"). Every launch also ensures the two resident watchers an install needs are alive and set to autostart (launcher @@ -125,7 +128,7 @@ powershell -NoProfile -ExecutionPolicy Bypass -File "tools\refresh_zcode_second_ Shows chats created in another instance inside a running sidebar by recycling the target's app-server (auto-respawn reseeds its index; verify-after). ZCode -[21] = Second only, ZCode [22] = all instances. A hot-activity guard waits out +[21] = Blue clone only, ZCode [22] = all instances. A hot-activity guard waits out in-flight turns (`-Force` bypasses). Watcher mode (`-Watch`, ZCode [23]) tails the CLI JSONL logs for terminal failures (captcha stall / quota / rate-limit) and refreshes every RUNNING instance on a 300 s cooldown. diff --git a/src/windows/launch_cline_clone.ps1 b/src/windows/launch_cline_clone.ps1 index b6e29f2..b1909e3 100644 --- a/src/windows/launch_cline_clone.ps1 +++ b/src/windows/launch_cline_clone.ps1 @@ -63,6 +63,10 @@ param( ) $ErrorActionPreference = 'Stop' +# Display vocabulary (2026-11-03): colors are the user-facing clone names; +# the frozen c1..c5 keys stay in params, dirs and AUMIDs only. +$CloneColor = @{ 'c1' = 'Blue'; 'c2' = 'Yellow'; 'c3' = 'Green'; 'c4' = 'Red'; 'c5' = 'Orange' }[$Instance] + # --- Portable paths --------------------------------------------------------- $ExePath = Join-Path $env:LOCALAPPDATA 'Cline\cline-app.exe' $ClonesRoot = Join-Path $env:USERPROFILE 'ClineClonesHome' @@ -126,7 +130,7 @@ function Test-HubLockHeld { # --- Status mode ------------------------------------------------------------ if ($Status) { - Write-Host "=== Cline clone '$Instance' status ===" + Write-Host "=== Cline $CloneColor clone status ===" Write-Host "profile dir : $CloneDir" Write-Host "exists : $(Test-Path $CloneDir)" if (Test-Path $HubLock) { @@ -192,7 +196,7 @@ $env:WEBVIEW2_USER_DATA_FOLDER = $WebViewDir $env:CLINE_HUB_PORT = [string]$ports.Hub $env:CLINE_SIDECAR_PORT = [string]$ports.Sidecar -Write-Host "launching Cline clone '$Instance' ..." +Write-Host "launching Cline $CloneColor clone ..." Write-Host " CLINE_DIR = $env:CLINE_DIR" Write-Host " WEBVIEW2_USER_DATA_FOLDER = $env:WEBVIEW2_USER_DATA_FOLDER" Write-Host " CLINE_HUB_PORT = $env:CLINE_HUB_PORT" diff --git a/src/windows/launch_opencode_clone.ps1 b/src/windows/launch_opencode_clone.ps1 index a8ee56b..ceb9714 100644 --- a/src/windows/launch_opencode_clone.ps1 +++ b/src/windows/launch_opencode_clone.ps1 @@ -105,7 +105,7 @@ function Get-CloneProcess { # --- Status mode -------------------------------------------------------------- if ($Status) { - Write-Host "=== OpenCode clone '$Instance' status ===" + Write-Host "=== OpenCode $($InstanceDefs[$Instance].Color) clone status ===" Write-Host "clone home : $CloneHome" Write-Host "exists : $(Test-Path $CloneHome)" foreach ($sub in @('desktop','session','data','config','cache','state')) { @@ -210,7 +210,7 @@ Write-Host " aumidSuffix=$($verify.aumidSuffix) title='$($verify.title)'" # too (engine v2: the app's main bundle is ESM - no require - so the # injected resolver reads ONLY argv). Each flag is quoted as ONE argument so # spaced values stay single argv entries; the injected parser strips quotes. -Write-Host "[4/5] Launching OpenCode clone '$Instance' ..." +Write-Host "[4/5] Launching OpenCode $($InstanceDefs[$Instance].Color) clone ..." $installDir = Split-Path $ExePath -Parent $launchArgs = @( "`"--opencode-clone-home=$CloneHome`"", diff --git a/src/windows/launch_zcode_cli_light.ps1 b/src/windows/launch_zcode_cli_light.ps1 index 315dcfb..1b1ff31 100644 --- a/src/windows/launch_zcode_cli_light.ps1 +++ b/src/windows/launch_zcode_cli_light.ps1 @@ -84,7 +84,7 @@ $CloneHome = Join-Path $UserProfile $cfg.Home $CloneZCode = Join-Path $CloneHome '.zcode' if (-not (Test-Path -LiteralPath (Join-Path $CloneZCode 'v2\credentials.json'))) { - throw "Clone home $Instance has no profile yet ($CloneZCode). Launch its desktop instance once (GHOST.bat ZCode [1]-[5]) to seed it, then retry." + throw "Clone home $($cfg.DisplayName) has no profile yet ($CloneZCode). Launch its desktop instance once (GHOST.bat ZCode [1]-[5]) to seed it, then retry." } # Per-account env levers. USERPROFILE is set alongside HOME because the CLI's @@ -158,7 +158,7 @@ if (-not $NoLoginWarn) { } catch { $hasDefaultModel = $false } } if (-not $hasDefaultModel) { - Write-Host "[model] WARNING: $Instance has no standalone CLI login - headless runs use the FREE" -ForegroundColor Yellow + Write-Host "[model] WARNING: $($cfg.DisplayName) has no standalone CLI login - headless runs use the FREE" -ForegroundColor Yellow Write-Host '[model] opencode-zen model, NOT this account''s Start Plan (the desktop app injects the' -ForegroundColor Yellow Write-Host '[model] plan adapter only into its own children; hand-edited defaults are ignored).' -ForegroundColor Yellow Write-Host '[model] One-time fix - in a terminal run:' -ForegroundColor Yellow @@ -173,7 +173,7 @@ if (-not $NoLoginWarn) { } if ($Login) { - Write-Host "[login] One-time standalone login for $Instance (home: $CloneHome)." -ForegroundColor Cyan + Write-Host "[login] One-time standalone login for $($cfg.DisplayName) (home: $CloneHome)." -ForegroundColor Cyan Write-Host "[login] A browser window will open - sign in with THIS clone's account." -ForegroundColor Cyan & $NodeExe $ZcodeCli login zai if ($LASTEXITCODE -ne 0) { @@ -208,21 +208,21 @@ function Invoke-LightPrompt { } if ($Server) { - Write-Host "[light] $Instance ($($cfg.DisplayName)) app-server on stdio - the CALLER owns this pipe." -ForegroundColor Cyan + Write-Host "[light] $($cfg.DisplayName) app-server on stdio - the CALLER owns this pipe." -ForegroundColor Cyan Write-Host "[light] home=$CloneHome cli=$ZcodeCli" & $NodeExe $ZcodeCli app-server exit $LASTEXITCODE } if (-not [string]::IsNullOrWhiteSpace($Prompt)) { - Write-Host "[light] $Instance ($($cfg.DisplayName)) one-shot task (mode=$Mode, cwd=$Cwd)..." -ForegroundColor Cyan + Write-Host "[light] $($cfg.DisplayName) one-shot task (mode=$Mode, cwd=$Cwd)..." -ForegroundColor Cyan $ok = Invoke-LightPrompt -Text $Prompt if (-not $ok) { exit 1 } exit 0 } # Interactive REPL: one node process per task, per-account isolation everywhere. -Write-Host ("[light] ZCode {0} light worker - account isolated to {1}" -f $Instance, $cfg.Home) -ForegroundColor Cyan +Write-Host ("[light] ZCode {0} light worker - account isolated to {1}" -f $cfg.DisplayName, $cfg.Home) -ForegroundColor Cyan Write-Host '[light] Type a task and press Enter. Empty input exits. Each task is a fresh session' Write-Host '[light] in the clone''s own store (shareable with its desktop app).' while ($true) { diff --git a/src/windows/launch_zcode_second_instance.ps1 b/src/windows/launch_zcode_second_instance.ps1 index c476f21..778c18b 100644 --- a/src/windows/launch_zcode_second_instance.ps1 +++ b/src/windows/launch_zcode_second_instance.ps1 @@ -205,7 +205,7 @@ function Test-ThisCloneRunning { $mainsNow = Get-ZcodeMainIds if ($mainsNow.Count -ge $MaxConcurrent) { if (Test-ThisCloneRunning) { - Write-Host ("[ram-guard] {0} is already running - this relaunch only focuses its window." -f $Instance) + Write-Host ("[ram-guard] {0} is already running - this relaunch only focuses its window." -f $cfg.DisplayName) } else { $zcodeProcs = @(Get-Process -Name ZCode -ErrorAction SilentlyContinue) $zcodeCommit = ($zcodeProcs | Measure-Object -Property PrivateMemorySize64 -Sum).Sum / 1MB @@ -254,7 +254,7 @@ New-Item -ItemType Directory -Path $CloneSession -Force | Out-Null # 2) One-time seed: clone history so the clone opens with same chats/projects. # Never overwrites an existing clone profile (instances stay independent afterwards). if (-not (Test-Path -LiteralPath (Join-Path $CloneZCode 'v2\setting.json'))) { - Write-Host "[seed] First run for ${Instance}: cloning .zcode -> $($cfg.Home)\.zcode (excluding live locks)..." + Write-Host "[seed] First run for $($cfg.DisplayName): cloning .zcode -> $($cfg.Home)\.zcode (excluding live locks)..." if (-not (Test-Path -LiteralPath $PrimaryZCode)) { throw "Primary .zcode not found: $PrimaryZCode" } New-Item -ItemType Directory -Path $CloneZCode -Force | Out-Null # robocopy exit codes 0-7 = success; 8+ = at least one failure (disk full, @@ -334,7 +334,7 @@ if (-not (Test-Path -LiteralPath (Join-Path $CloneZCode 'v2\setting.json'))) { } } catch { Write-Host "[seed-scrub] WARN: $($_.Exception.Message) (launch continues)" -ForegroundColor Yellow } } else { - Write-Host "[seed] $Instance profile already exists, skipping clone (independent)." + Write-Host "[seed] $($cfg.DisplayName) profile already exists, skipping clone (independent)." } # 2c) Telegram routing (marker-guarded): one credential = one instance (EC-D03). @@ -416,9 +416,9 @@ if ($tgMarkerText -like 'v2 unique-bot*') { if ($changed) { [System.IO.File]::WriteAllText($tgCfg, ($bj | ConvertTo-Json -Depth 20), $tgNoBom) } } catch { Write-Host "[telegram-route] $cfgName SKIP ($($_.Exception.Message))" -ForegroundColor Yellow } } - if ($tgDisabled -gt 0) { Write-Host ("[telegram-route] Disabled {0} duplicate Telegram bot(s) in $Instance; Telegram stays on Primary." -f $tgDisabled) -ForegroundColor Green } - if ($tgPreserved -gt 0) { Write-Host ("[telegram-route] Preserved $tgPreserved unique Telegram bot row(s) in $Instance (distinct credential)." -f $tgPreserved) -ForegroundColor Green } - if (($tgDisabled -eq 0) -and ($tgPreserved -eq 0)) { Write-Host "[telegram-route] No enabled Telegram bots in $Instance; nothing to do." -ForegroundColor DarkGray } + if ($tgDisabled -gt 0) { Write-Host ("[telegram-route] Disabled {0} duplicate Telegram bot(s) in {1}; Telegram stays on Primary." -f $tgDisabled, $cfg.DisplayName) -ForegroundColor Green } + if ($tgPreserved -gt 0) { Write-Host ("[telegram-route] Preserved {0} unique Telegram bot row(s) in {1} (distinct credential)." -f $tgPreserved, $cfg.DisplayName) -ForegroundColor Green } + if (($tgDisabled -eq 0) -and ($tgPreserved -eq 0)) { Write-Host "[telegram-route] No enabled Telegram bots in $($cfg.DisplayName); nothing to do." -ForegroundColor DarkGray } # Drop stale polling locks, but ONLY when this clone is not running (a live # poller owns its lock dir). A running instance picks up the config change # on its next restart. @@ -459,12 +459,12 @@ if ($tgMarkerText -like 'v2 unique-bot*') { } } if ($cloneLive) { - if ($tgDisabled -gt 0) { Write-Host "[telegram-route] $Instance is running: restart it once to apply (config saved)." -ForegroundColor Yellow } + if ($tgDisabled -gt 0) { Write-Host "[telegram-route] $($cfg.DisplayName) is running: restart it once to apply (config saved)." -ForegroundColor Yellow } } else { $tgLockRoot = Join-Path $CloneZCode 'v2\bots-runtime-locks\telegram-polling' if (($tgDisabled -gt 0) -and (Test-Path -LiteralPath $tgLockRoot)) { Get-ChildItem -LiteralPath $tgLockRoot -Force -ErrorAction SilentlyContinue | ForEach-Object { Remove-Item -LiteralPath $_.FullName -Recurse -Force -Confirm:$false -ErrorAction SilentlyContinue } - Write-Host "[telegram-route] Stale $Instance polling locks cleared." -ForegroundColor Green + Write-Host "[telegram-route] Stale $($cfg.DisplayName) polling locks cleared." -ForegroundColor Green } } } catch { Write-Host "[telegram-route] lock check SKIP ($($_.Exception.Message))" -ForegroundColor Yellow } @@ -656,7 +656,7 @@ $newPid = $null $diff = @($nowMains | Where-Object { $beforeMains -notcontains $_ }) if ($diff.Count -gt 0) { $newPid = $diff[0]; break } } -if ($newPid) { Write-Host "[launch] $Instance ZCode PID=$newPid. $($cfg.DisplayName)-branded window should now appear with its own taskbar button." } +if ($newPid) { Write-Host "[launch] $($cfg.DisplayName) ZCode PID=$newPid. $($cfg.DisplayName)-branded window should now appear with its own taskbar button." } else { Write-Host "[launch] Launched (already running: existing window focused). $($cfg.DisplayName) branding = this instance, unbranded = Primary." } Write-Host '[verify] If the window is NOT brand-colored, the installed app.asar needs the one-time patch:' Write-Host ' close ZCode, run tools\patch_zcode_icon_override.ps1, then relaunch.' diff --git a/src/windows/reset_zcode.ps1 b/src/windows/reset_zcode.ps1 index b01f539..39198b5 100644 --- a/src/windows/reset_zcode.ps1 +++ b/src/windows/reset_zcode.ps1 @@ -86,6 +86,34 @@ param( $ErrorActionPreference = "Stop" +# --- Display vocabulary (2026-11-03) ------------------------------------------- +# Colors are the ONLY user-facing clone names; the frozen keys (Secondary..Sixth) +# survive in params, dirs, AUMIDs and identification lines (color + key in +# parens). Mirrors the shortcut naming unified in PR #20. +function Get-ZcodeLabelColor([string]$Key) { + switch ($Key) { + 'Secondary' { 'Blue' } + 'Third' { 'Yellow' } + 'Fourth' { 'Green' } + 'Fifth' { 'Red' } + 'Sixth' { 'Orange' } + default { $Key } + } +} +function Get-ZcodeTargetDisplay([string]$Key) { + switch ($Key) { + 'Primary' { 'Primary' } + 'Secondary' { 'Blue (Secondary)' } + 'Third' { 'Yellow (Third)' } + 'Fourth' { 'Green (Fourth)' } + 'Fifth' { 'Red (Fifth)' } + 'Sixth' { 'Orange (Sixth)' } + 'Both' { 'Both (Blue + Primary)' } + 'All' { 'All (Blue..Orange)' } + default { $Key } + } +} + # --- Self-elevation ----------------------------------------------------------- # Re-launch elevated with the same script path when not already admin. # Forwards -Target / -SkipQoder so child runs keep their scope after UAC. @@ -108,7 +136,7 @@ if (-not $zcodeIsAdmin) { exit } -Write-GhostBanner -Target "ZCode/Qoder Identity Reset [$Target]" -Version "1.4" +Write-GhostBanner -Target "ZCode/Qoder Identity Reset [$(Get-ZcodeTargetDisplay $Target)]" -Version "1.4" # === Local helpers (mirroring the Cursor reference pattern) =================== @@ -1319,7 +1347,7 @@ function Stop-ZcodeTargetTree { [switch]$RequireSurvivor ) - Write-Host "[*] Terminating ZCode $Label instance tree only (survivors preserved)..." -ForegroundColor Cyan + Write-Host "[*] Terminating ZCode $(Get-ZcodeTargetDisplay $Label) instance tree only (survivors preserved)..." -ForegroundColor Cyan $entryMap = Get-ZcodeTargetMains $entryTotal = 0 foreach ($k in $script:ZcodeAllLabels) { $entryTotal += @($entryMap[$k]).Count } @@ -1360,14 +1388,14 @@ function Stop-ZcodeTargetTree { else { $consecutiveClean++ if ($consecutiveClean -ge 2) { - Write-Host "[OK] ZCode $Label tree terminated (2 clean checks); survivor mains: $survivors" -ForegroundColor Green + Write-Host "[OK] ZCode $(Get-ZcodeTargetDisplay $Label) tree terminated (2 clean checks); survivor mains: $survivors" -ForegroundColor Green return $true } } } else { $consecutiveClean = 0 } } - Write-Host "[FAILED] ZCode $Label tree still running after $MaxAttempts attempts. Aborting." -ForegroundColor Red + Write-Host "[FAILED] ZCode $(Get-ZcodeTargetDisplay $Label) tree still running after $MaxAttempts attempts. Aborting." -ForegroundColor Red return $false } @@ -1484,21 +1512,21 @@ if (($Target -eq 'Both') -or ($Target -eq 'All')) { ) } $childCount = $children.Count - Write-Host "=== ZCode Identity Reset v1.4 (${Target}: independent IDs per instance) ===" -ForegroundColor Cyan + Write-Host "=== ZCode Identity Reset v1.4 - $(Get-ZcodeTargetDisplay $Target) - independent IDs per instance ===" -ForegroundColor Cyan $exitCodes = @() for ($ci = 0; $ci -lt $childCount; $ci++) { $child = $children[$ci] $qoderNote = '' if (-not $child.SkipQoder) { $qoderNote = ' (incl. Qoder)' } - Write-Host ("[{0} {1}/{2}] Resetting {3} instance{4}..." -f $Target, ($ci + 1), $childCount, $child.Label, $qoderNote) -ForegroundColor Cyan + Write-Host ("[{0} {1}/{2}] Resetting {3} instance{4}..." -f (Get-ZcodeTargetDisplay $Target), ($ci + 1), $childCount, (Get-ZcodeTargetDisplay $child.Label), $qoderNote) -ForegroundColor Cyan $fwdArgs = @('-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', $v14Script, '-Target', $child.Label) if ($child.SkipQoder) { $fwdArgs += '-SkipQoder' } & powershell @fwdArgs $exitCodes += $LASTEXITCODE } - Write-Host "`n=== $Target-mode summary ===" -ForegroundColor Cyan + Write-Host "`n=== Summary - $(Get-ZcodeTargetDisplay $Target) mode ===" -ForegroundColor Cyan for ($ci = 0; $ci -lt $childCount; $ci++) { - Write-Host ("{0} exit: {1}" -f $children[$ci].Label, $exitCodes[$ci]) -ForegroundColor Gray + Write-Host ("{0} exit: {1}" -f (Get-ZcodeTargetDisplay $children[$ci].Label), $exitCodes[$ci]) -ForegroundColor Gray } Write-Host "NOTE: IDs were generated independently per instance (never duplicated)." -ForegroundColor Yellow Write-Host "NOTE: change_device_id.ps1 is machine-wide and affects ALL ZCode instances + Qoder." -ForegroundColor Yellow @@ -1518,8 +1546,8 @@ $actions = @() $ids = New-IdentitySet if (-not (Test-Path -LiteralPath $zcodeRoaming)) { - Write-Host "ZCode $Target instance not found at: $zcodeRoaming" -ForegroundColor Red - Write-Host "Hint: launch it once via its clone shortcut / launcher (Secondary/Third/Fourth/Fifth/Sixth) or ZCode.exe (Primary)." -ForegroundColor Yellow + Write-Host "ZCode $(Get-ZcodeTargetDisplay $Target) instance not found at: $zcodeRoaming" -ForegroundColor Red + Write-Host "Hint: launch it once via its clone shortcut / launcher (Blue/Yellow/Green/Red/Orange) or ZCode.exe (Primary)." -ForegroundColor Yellow exit 1 } @@ -1536,8 +1564,8 @@ if ($SkipQoder) { New-Item -Path $backupRoot -ItemType Directory -Force | Out-Null -Write-Host "=== ZCode / Qoder Identity Reset v1.4 (Target: $Target) ===" -ForegroundColor Cyan -Write-Host "ZCode ${Target}: $zcodeRoaming" -ForegroundColor Gray +Write-Host "=== ZCode / Qoder Identity Reset v1.4 - Target: $(Get-ZcodeTargetDisplay $Target) ===" -ForegroundColor Cyan +Write-Host "ZCode $(Get-ZcodeTargetDisplay $Target): $zcodeRoaming" -ForegroundColor Gray Write-Host "ZCode data: $zcodeUserProfile" -ForegroundColor Gray if ($qoderPresent) { Write-Host ("Qoder profiles: " + (($qoderProfiles | ForEach-Object { Get-ProfileLabel -MainRoot $qoderRoaming -ProfileRoot $_ }) -join ", ")) -ForegroundColor Gray @@ -1604,15 +1632,15 @@ else { $p = Join-Path $pr "User\globalStorage\storage.json" if (Test-Path -LiteralPath $p) { if (Set-JsonIdentity -Path $p -Updates $storageUpdates -Audit ([ref]$audit) -BackupRoot $backupRoot -BackupLabel (Get-AppRelativeBackupLabel -RootPath $pr -TargetPath $p) -Actions ([ref]$actions)) { - Write-Host " [$label] [OK] storage.json verified" -ForegroundColor Green + Write-Host " [$(Get-ZcodeLabelColor $label)] [OK] storage.json verified" -ForegroundColor Green } else { - Write-Host " [$label] [FAILED] storage.json verification failed" -ForegroundColor Red + Write-Host " [$(Get-ZcodeLabelColor $label)] [FAILED] storage.json verification failed" -ForegroundColor Red $stepFailed = $true } } else { - Write-Host " [$label] [SKIP] storage.json not present" -ForegroundColor Yellow + Write-Host " [$(Get-ZcodeLabelColor $label)] [SKIP] storage.json not present" -ForegroundColor Yellow Add-AuditEntry -Audit ([ref]$audit) -File $p -Key "telemetry.*" -Before "missing" -After "skipped" -Ok $true } } @@ -1633,15 +1661,15 @@ else { $p = Join-Path $pr "machineid" if (Test-Path -LiteralPath $p) { if (Set-VerifiedMachineIdFile -Path $p -Value $ids.devDeviceId -BackupRoot $backupRoot -BackupLabel (Get-AppRelativeBackupLabel -RootPath $pr -TargetPath $p) -Audit ([ref]$audit) -Actions ([ref]$actions)) { - Write-Host " [$label] [OK] machineid verified" -ForegroundColor Green + Write-Host " [$(Get-ZcodeLabelColor $label)] [OK] machineid verified" -ForegroundColor Green } else { - Write-Host " [$label] [FAILED] machineid verification failed" -ForegroundColor Red + Write-Host " [$(Get-ZcodeLabelColor $label)] [FAILED] machineid verification failed" -ForegroundColor Red $stepFailed = $true } } else { - Write-Host " [$label] [SKIP] machineid not present" -ForegroundColor Yellow + Write-Host " [$(Get-ZcodeLabelColor $label)] [SKIP] machineid not present" -ForegroundColor Yellow Add-AuditEntry -Audit ([ref]$audit) -File $p -Key "machineid" -Before "missing" -After "skipped" -Ok $true } } @@ -1756,15 +1784,15 @@ else { $p = Join-Path $pr "User\globalStorage\state.vscdb" if (Test-Path -LiteralPath $p) { if (Set-SqliteKeys -Path $p -Updates @{ "storage.serviceMachineId" = $ids.devDeviceId } -Audit ([ref]$audit) -BackupRoot $backupRoot -BackupLabel (Get-AppRelativeBackupLabel -RootPath $pr -TargetPath $p) -Actions ([ref]$actions)) { - Write-Host " [$label] [OK] state.vscdb verified" -ForegroundColor Green + Write-Host " [$(Get-ZcodeLabelColor $label)] [OK] state.vscdb verified" -ForegroundColor Green } else { - Write-Host " [$label] [FAILED] state.vscdb verification failed" -ForegroundColor Red + Write-Host " [$(Get-ZcodeLabelColor $label)] [FAILED] state.vscdb verification failed" -ForegroundColor Red $stepFailed = $true } } else { - Write-Host " [$label] [SKIP] state.vscdb not present" -ForegroundColor Yellow + Write-Host " [$(Get-ZcodeLabelColor $label)] [SKIP] state.vscdb not present" -ForegroundColor Yellow Add-AuditEntry -Audit ([ref]$audit) -File $p -Key "storage.serviceMachineId" -Before "missing" -After "skipped" -Ok $true } } @@ -1783,7 +1811,7 @@ else { foreach ($pr in $qoderProfiles) { $label = Get-ProfileLabel -MainRoot $qoderRoaming -ProfileRoot $pr $p = Join-Path $pr "User\globalStorage\state.vscdb" - Write-Host " [$label] scrubbing secrets..." -ForegroundColor DarkGray + Write-Host " [$(Get-ZcodeLabelColor $label)] scrubbing secrets..." -ForegroundColor DarkGray if (-not (Clear-SecretsFromSqlite -Path $p -BackupRoot $backupRoot -BackupLabel (Get-AppRelativeBackupLabel -RootPath $pr -TargetPath $p) -Audit ([ref]$audit) -Actions ([ref]$actions))) { $stepFailed = $true } @@ -1803,7 +1831,7 @@ else { foreach ($pr in $qoderProfiles) { $label = Get-ProfileLabel -MainRoot $qoderRoaming -ProfileRoot $pr $p = Join-Path $pr "User\globalStorage\state.vscdb.backup" - Write-Host " [$label] stale backup..." -ForegroundColor DarkGray + Write-Host " [$(Get-ZcodeLabelColor $label)] stale backup..." -ForegroundColor DarkGray if (-not (Remove-VerifiedFileNoBackup -Path $p -AuditKey "state.vscdb.backup" -Audit ([ref]$audit))) { $stepFailed = $true } @@ -1833,7 +1861,7 @@ else { foreach ($pr in $qoderProfiles) { $label = Get-ProfileLabel -MainRoot $qoderRoaming -ProfileRoot $pr $p = Join-Path $pr "Preferences" - Write-Host " [$label] device_id_salt..." -ForegroundColor DarkGray + Write-Host " [$(Get-ZcodeLabelColor $label)] device_id_salt..." -ForegroundColor DarkGray if (-not (Set-DeviceIdSalt -Path $p -NewSalt $newDeviceIdSaltQoder -BackupRoot $backupRoot -BackupLabel (Get-AppRelativeBackupLabel -RootPath $pr -TargetPath $p) -Audit ([ref]$audit) -Actions ([ref]$actions))) { $stepFailed = $true } @@ -1863,7 +1891,7 @@ else { foreach ($pr in $qoderProfiles) { $label = Get-ProfileLabel -MainRoot $qoderRoaming -ProfileRoot $pr $p = Join-Path $pr "Local State" - Write-Host " [$label] os_crypt..." -ForegroundColor DarkGray + Write-Host " [$(Get-ZcodeLabelColor $label)] os_crypt..." -ForegroundColor DarkGray if (-not (Remove-OsCryptEncryptedKey -Path $p -BackupRoot $backupRoot -BackupLabel (Get-AppRelativeBackupLabel -RootPath $pr -TargetPath $p) -Audit ([ref]$audit) -Actions ([ref]$actions))) { $stepFailed = $true } @@ -2148,7 +2176,7 @@ else { foreach ($pr in $qoderProfiles) { $label = Get-ProfileLabel -MainRoot $qoderRoaming -ProfileRoot $pr $stepStart = $audit.Count - Write-Host " [$label] browser data..." -ForegroundColor DarkGray + Write-Host " [$(Get-ZcodeLabelColor $label)] browser data..." -ForegroundColor DarkGray $profileFiles = @($qoderFileRelPaths | ForEach-Object { Join-Path $pr $_ }) $profileActions = Clear-BinaryIdentityStore -Paths $profileFiles -Action "delete" -BackupRoot $backupRoot -Audit ([ref]$audit) -RootPath $pr $actions += @($profileActions) @@ -2179,10 +2207,10 @@ else { } $status = Get-StepAuditStatus -Audit ([ref]$audit) -StartIndex $stepStart -Path $pr if ($status.Success) { - Write-Host " [$label] [OK] browser data cleared" -ForegroundColor Green + Write-Host " [$(Get-ZcodeLabelColor $label)] [OK] browser data cleared" -ForegroundColor Green } else { - Write-Host " [$label] [FAILED] browser data had failures" -ForegroundColor Red + Write-Host " [$(Get-ZcodeLabelColor $label)] [FAILED] browser data had failures" -ForegroundColor Red $stepFailed = $true } } @@ -2209,7 +2237,7 @@ if ($qoderPresent) { # so it is identity-bearing. Per-file delete survives locked log files. $logsPath = Join-Path $pr "logs" if (Test-Path -LiteralPath $logsPath) { - Write-Host " [$label] logs/ (per-file delete)..." -ForegroundColor DarkGray + Write-Host " [$(Get-ZcodeLabelColor $label)] logs/ (per-file delete)..." -ForegroundColor DarkGray $null = Clear-TreeFilesIndividually -Path $logsPath -BackupRoot $backupRoot -BackupLabel (Get-AppRelativeBackupLabel -RootPath $pr -TargetPath $logsPath) -Audit ([ref]$audit) -Actions ([ref]$actions) } else { @@ -2289,7 +2317,7 @@ else { Where-Object { Test-Path -LiteralPath $_ } } if ($workspaceDbPaths.Count -eq 0) { - Write-Host " [$label] [SKIP] no workspace state.vscdb files found" -ForegroundColor Yellow + Write-Host " [$(Get-ZcodeLabelColor $label)] [SKIP] no workspace state.vscdb files found" -ForegroundColor Yellow Add-AuditEntry -Audit ([ref]$audit) -File $workspaceStorageRoot -Key "workspaceStorage" -Before "none" -After "skipped" -Ok $true continue } @@ -2479,8 +2507,8 @@ Write-Host "NOTE: change_device_id.ps1 is machine-wide and affects ALL ZCode ins [System.IO.File]::WriteAllText("$env:TEMP\zcode_v1.3_done.txt", ("Pass: {0} Fail: {1} Audit: {2}" -f $passCount, $failCount, $auditPath), (New-Object System.Text.UTF8Encoding $false)) if ($failCount -gt 0) { - Write-Host "ZCode/Qoder reset v1.4 [$Target] completed with failures. Review $auditPath." -ForegroundColor Red + Write-Host "ZCode/Qoder reset v1.4 [$(Get-ZcodeTargetDisplay $Target)] completed with failures. Review $auditPath." -ForegroundColor Red exit 1 } -Write-Host "ZCode/Qoder reset v1.4 [$Target] completed successfully." -ForegroundColor Green +Write-Host "ZCode/Qoder reset v1.4 [$(Get-ZcodeTargetDisplay $Target)] completed successfully." -ForegroundColor Green diff --git a/tools/install_autoclaw2_clone_shortcuts.ps1 b/tools/install_autoclaw2_clone_shortcuts.ps1 index d898c06..bb1bdba 100644 --- a/tools/install_autoclaw2_clone_shortcuts.ps1 +++ b/tools/install_autoclaw2_clone_shortcuts.ps1 @@ -214,7 +214,7 @@ foreach ($id in $TargetIds) { $s.Arguments = "-NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File `"$Launcher`" -Instance $id" $s.WorkingDirectory = Split-Path -Parent $Launcher $s.IconLocation = "$iconPath,0" - $s.Description = "AutoClaw2 clone $id ($($def.DisplayName)) - isolated profile" + $s.Description = "AutoClaw2 $($def.DisplayName) clone - isolated profile" $s.Save() try { Set-ShortcutAumid -LnkPath $lnk -Aumid $aumid } catch { Write-Warning "AUMID set failed on $lnk : $($_.Exception.Message)"; $script:Failed = $true } diff --git a/tools/install_cline_clone_shortcuts.ps1 b/tools/install_cline_clone_shortcuts.ps1 index 81f80b7..e6a4418 100644 --- a/tools/install_cline_clone_shortcuts.ps1 +++ b/tools/install_cline_clone_shortcuts.ps1 @@ -212,7 +212,7 @@ foreach ($id in $TargetIds) { $s.Arguments = "-NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File `"$Launcher`" -Instance $id" $s.WorkingDirectory = Split-Path -Parent $Launcher $s.IconLocation = "$iconPath,0" - $s.Description = "Cline clone $id ($($def.DisplayName)) - isolated profile" + $s.Description = "Cline $($def.DisplayName) clone - isolated profile" $s.Save() try { Set-ShortcutAumid -LnkPath $lnk -Aumid $aumid } catch { Write-Warning "AUMID set failed on $lnk : $($_.Exception.Message)" } diff --git a/tools/install_opencode_clone_shortcuts.ps1 b/tools/install_opencode_clone_shortcuts.ps1 index d307af8..a4d751a 100644 --- a/tools/install_opencode_clone_shortcuts.ps1 +++ b/tools/install_opencode_clone_shortcuts.ps1 @@ -260,7 +260,7 @@ foreach ($id in $TargetIds) { $s.Arguments = "-NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File `"$Launcher`" -Instance $id" $s.WorkingDirectory = Split-Path -Parent $Launcher $s.IconLocation = "$iconPath,0" - $s.Description = "OpenCode clone $id ($($def.DisplayName)) - isolated clone home" + $s.Description = "OpenCode $($def.DisplayName) clone - isolated clone home" $s.Save() try { Set-ShortcutAumid -LnkPath $lnk -Aumid $aumid } catch { Write-Warning "AUMID set failed on $lnk : $($_.Exception.Message)" } diff --git a/tools/install_zcode_second_shortcuts.ps1 b/tools/install_zcode_second_shortcuts.ps1 index 13f009b..ac8d5b8 100644 --- a/tools/install_zcode_second_shortcuts.ps1 +++ b/tools/install_zcode_second_shortcuts.ps1 @@ -388,7 +388,7 @@ foreach ($inst in $Instance) { IconIco = $iconIco IconOk = $iconOk IconLocation = "$iconIco,0" - Description = "Launch an independent $inst ZCode clone ($($def.DisplayName.ToLowerInvariant()) branding, separate taskbar button)" + Description = "Launch an independent ZCode $($def.DisplayName) clone - separate taskbar button" Arguments = "-NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File `"$Launcher`" -Instance $inst" Targets = @(Get-ShortcutTargets -ShortcutName $def.ShortcutName) } @@ -399,7 +399,7 @@ $ws = New-Object -ComObject WScript.Shell foreach ($inst in $Instance) { $spec = $installed[$inst] Remove-LegacyShortcuts -Def $spec.Def - Write-Host " [$inst] $($spec.Def.ShortcutName)" + Write-Host " [$($def.DisplayName)] $($spec.Def.ShortcutName)" foreach ($t in $spec.Targets) { Write-Host " -> $t" $sc = $ws.CreateShortcut($t) diff --git a/tools/new_clone_suite.ps1 b/tools/new_clone_suite.ps1 index 55cd8cd..2cddb77 100644 --- a/tools/new_clone_suite.ps1 +++ b/tools/new_clone_suite.ps1 @@ -326,7 +326,7 @@ if (-not (Test-Path -LiteralPath $SeedMarker)) { # port lever (env var survives? settings.json? marker # file read by an asar patch - the AutoClaw home-override pattern) recorded # to instance-record.json with the DISCOVERED ports, never the requested one. -Write-Host ("[launch] {0} (skeleton - wire the real levers after discovery)" -f $Instance) -ForegroundColor Yellow +Write-Host ("[launch] {0} (skeleton - wire the real levers after discovery; print the COLOR name here, not the {1} key)" -f '', $Instance) -ForegroundColor Yellow $env:TEMP = $CloneTmp $env:TMP = $CloneTmp # cmd /c start "" "" <- detached launch; a GUI app that calls @@ -547,8 +547,10 @@ cls if defined ESC (echo %ESC%[96mGHOST / $Pascal Multi-Instance ^& Clones%ESC%[0m) else echo GHOST / $Pascal Multi-Instance ^& Clones echo. call :Div "Launch Clones" -call :Opt 1 "Launch inst1" "- first clone (own profile, identity, ports)" -call :Opt 2 "Reset inst1" "" +rem Row pattern (2026-11-03): label = action + COLOR name (e.g. "Launch Blue clone"); +rem the frozen instance key (inst1) never appears user-visible - only in params/dirs. +call :Opt 1 "Launch clone" "- first clone - own profile, identity, ports" +call :Opt 2 "Reset clone" "" echo. call :Opt 0 "Back to Main Menu" "" echo. @@ -591,7 +593,7 @@ exit /b if ($idx -lt 0) { throw "GHOST.bat anchor missing: gid $maxGid dispatch line" } $lineEnd = $bat.IndexOf("`r`n", $idx) $newGids = @( - ('if "%~1"=="{0}" (call :Detached "{1} inst1" "-NoProfile" "src\windows\launch_{2}_clone.ps1" "" "Launcher opened in a separate window - it closes automatically when done." & exit /b)' -f ($GidBase), $Pascal, $Slug) + ('if "%~1"=="{0}" (call :Detached "{1} " "-NoProfile" "src\windows\launch_{2}_clone.ps1" "" "Launcher opened in a separate window - it closes automatically when done." & exit /b)' -f ($GidBase), $Pascal, $Slug) ('if "%~1"=="{0}" (call :Run "src\windows\reset_{1}.ps1" -Target inst1 & exit /b)' -f ($GidBase + 1), $Slug) ) -join "`r`n" $bat = $bat.Substring(0, $lineEnd + 2) + $newGids + "`r`n" + $bat.Substring($lineEnd + 2) diff --git a/tools/refresh_zcode_second_chats.ps1 b/tools/refresh_zcode_second_chats.ps1 index 9a6d446..20f0d96 100644 --- a/tools/refresh_zcode_second_chats.ps1 +++ b/tools/refresh_zcode_second_chats.ps1 @@ -360,7 +360,7 @@ function Invoke-RefreshPass { $anyRunning = $false foreach ($def in $defs) { $st = Get-InstanceState $def - $label = $def.Name + ' (' + $def.Title + ')' + $label = $def.Title + ' (' + $def.Name + ')' if ($st.Status -eq 'not-installed') { if ($strictSingle) { Stop-WithError "$label tasks-index not found: $($st.TasksIndex) -- launch that instance once first" } Write-Host " ${label}: skipped - never launched on this machine" @@ -403,7 +403,7 @@ function Invoke-RefreshPass { if ($DryRun) { foreach ($w in $work) { - Write-Host " $($w.Def.Name): [DRY-RUN] would recycle $($w.Servers.Count) app-server process(es); no action taken." -ForegroundColor Cyan + Write-Host " $($w.Def.Title): [DRY-RUN] would recycle $($w.Servers.Count) app-server process(es); no action taken." -ForegroundColor Cyan Write-RunLog "DRYRUN target=$($w.Def.Name) missing=$($w.MissingCount) servers=$($w.Servers.Count)" } return 'nothing' @@ -422,7 +422,7 @@ function Invoke-RefreshPass { Write-Host '[3/3] Recycling app-server(s) + verifying (auto-respawn expected)...' $recycledAny = $false foreach ($w in $work) { - $label = $w.Def.Name + ' (' + $w.Def.Title + ')' + $label = $w.Def.Title + ' (' + $w.Def.Name + ')' # re-collect: PIDs may have changed if an app-server respawned during the wait $desc = @(Get-DescendantProcesses ($w.Mains | ForEach-Object { [int]$_.Id })) $servers = @($desc | Where-Object { $_.CommandLine -like '*app-server*' }) diff --git a/tools/sync_zcode_assets.ps1 b/tools/sync_zcode_assets.ps1 index b59f5eb..b6d955d 100644 --- a/tools/sync_zcode_assets.ps1 +++ b/tools/sync_zcode_assets.ps1 @@ -102,13 +102,20 @@ $LogFile = Join-Path $LogDir 'sync_zcode_assets.log' # and refresh_zcode_second_chats.ps1 ($InstanceDefs): classification is by # process markers (home/roaming dir names in the command line), never titles. $InstanceDefs = @( - @{ Name = 'Second'; HomeRel = 'ZCodeSecondHome'; Markers = @('ZCode-Second', 'ZCodeSecondHome') } - @{ Name = 'Third'; HomeRel = 'ZCodeThirdHome'; Markers = @('ZCode-Third', 'ZCodeThirdHome') } - @{ Name = 'Fourth'; HomeRel = 'ZCodeFourthHome'; Markers = @('ZCode-Fourth', 'ZCodeFourthHome') } - @{ Name = 'Fifth'; HomeRel = 'ZCodeFifthHome'; Markers = @('ZCode-Fifth', 'ZCodeFifthHome') } - @{ Name = 'Sixth'; HomeRel = 'ZCodeSixthHome'; Markers = @('ZCode-Sixth', 'ZCodeSixthHome') } + @{ Name = 'Second'; HomeRel = 'ZCodeSecondHome'; Color = 'Blue'; Markers = @('ZCode-Second', 'ZCodeSecondHome') } + @{ Name = 'Third'; HomeRel = 'ZCodeThirdHome'; Color = 'Yellow'; Markers = @('ZCode-Third', 'ZCodeThirdHome') } + @{ Name = 'Fourth'; HomeRel = 'ZCodeFourthHome'; Color = 'Green'; Markers = @('ZCode-Fourth', 'ZCodeFourthHome') } + @{ Name = 'Fifth'; HomeRel = 'ZCodeFifthHome'; Color = 'Red'; Markers = @('ZCode-Fifth', 'ZCodeFifthHome') } + @{ Name = 'Sixth'; HomeRel = 'ZCodeSixthHome'; Color = 'Orange'; Markers = @('ZCode-Sixth', 'ZCodeSixthHome') } ) +# Display vocabulary (2026-11-03): colors lead every user-visible tag/header; +# the frozen key follows after a slash so params/dirs stay correlatable. +function Get-SyncTargetDisplay([string]$Key) { + $d = @($InstanceDefs | Where-Object { $_.Name -eq $Key })[0] + if ($d) { '{0} / {1}' -f $d.Color, $d.Name } else { $Key } +} + $Script:FailedTargets = @() $Stamp = Get-Date -Format 'yyyyMMdd-HHmmss' @@ -209,12 +216,12 @@ function Sync-McpDefinitions([string]$Name, [string]$CloneZ, [string]$CloneConfi $primaryCfg = Read-JsonFile $PrimaryConfig $cloneCfg = Read-JsonFile $CloneConfig } catch { - Write-Tag "FAILED:$Name" ("config.json unreadable: {0}" -f $_.Exception.Message) 'Red' + Write-Tag "FAILED:$(Get-SyncTargetDisplay $Name)" ("config.json unreadable: {0}" -f $_.Exception.Message) 'Red' Add-Audit $CloneZ $area 'load' $false $_.Exception.Message return $false } if ($null -eq $primaryCfg -or $null -eq $cloneCfg) { - Write-Tag "FAILED:$Name" 'config.json parsed empty.' 'Red' + Write-Tag "FAILED:$(Get-SyncTargetDisplay $Name)" 'config.json parsed empty.' 'Red' Add-Audit $CloneZ $area 'load' $false 'parsed empty' return $false } @@ -223,7 +230,7 @@ function Sync-McpDefinitions([string]$Name, [string]$CloneZ, [string]$CloneConfi # every definition deleted): the merge would iterate an empty set -- # clone-only servers stay, nothing is written. OK/empty, not a layout # failure (FAILED stays reserved for unreadable config). - Write-Tag "OK:$Name" 'Primary has no mcp.servers - nothing to sync (clone-only servers kept).' 'Green' + Write-Tag "OK:$(Get-SyncTargetDisplay $Name)" 'Primary has no mcp.servers - nothing to sync (clone-only servers kept).' 'Green' Add-Audit $CloneZ $area 'load' $true 'primary mcp.servers empty' return $true } @@ -238,14 +245,14 @@ function Sync-McpDefinitions([string]$Name, [string]$CloneZ, [string]$CloneConfi $changed = Invoke-McpMerge -PrimaryServers $pServers -CloneServers $cServers if ($changed.Count -eq 0) { - Write-Tag "OK:$Name" 'MCP server definitions already match the Primary.' 'Green' + Write-Tag "OK:$(Get-SyncTargetDisplay $Name)" 'MCP server definitions already match the Primary.' 'Green' Add-Audit $CloneZ $area 'verify' $true 'already in sync' return $true } - Write-Tag "INFO:$Name" ("MCP definition drift on: {0}" -f ($changed -join ', ')) 'Cyan' + Write-Tag "INFO:$(Get-SyncTargetDisplay $Name)" ("MCP definition drift on: {0}" -f ($changed -join ', ')) 'Cyan' if ($DryRun) { - Write-Tag "DRY:$Name" 'would backup config.json then merge + verify (no write in DryRun).' 'Cyan' + Write-Tag "DRY:$(Get-SyncTargetDisplay $Name)" 'would backup config.json then merge + verify (no write in DryRun).' 'Cyan' return $true } @@ -278,18 +285,18 @@ function Sync-McpDefinitions([string]$Name, [string]$CloneZ, [string]$CloneConfi } } if ($bad.Count -gt 0) { - Write-Tag "FAILED:$Name" ("verify-after mismatch ({0}) - config restored from backup." -f ($bad -join ', ')) 'Red' + Write-Tag "FAILED:$(Get-SyncTargetDisplay $Name)" ("verify-after mismatch ({0}) - config restored from backup." -f ($bad -join ', ')) 'Red' Copy-Item -LiteralPath $bak -Destination $CloneConfig -Force Add-Audit $CloneZ $area 'verify' $false ('mismatch: ' + ($bad -join ', ')) return $false } - Write-Tag "OK:$Name" ("MCP definitions synced + verified ({0}); backup: {1}" -f ($changed -join ', '), (Split-Path -Leaf $bak)) 'Green' + Write-Tag "OK:$(Get-SyncTargetDisplay $Name)" ("MCP definitions synced + verified ({0}); backup: {1}" -f ($changed -join ', '), (Split-Path -Leaf $bak)) 'Green' return $true } function Sync-SkillsJunction([string]$Name, [string]$CloneZ, [string]$CloneHome) { if (-not (Test-Path -LiteralPath $PrimaryAgents)) { - Write-Tag "WARN:$Name" ("shared skills store {0} not found - skills sync skipped." -f $PrimaryAgents) 'Yellow' + Write-Tag "WARN:$(Get-SyncTargetDisplay $Name)" ("shared skills store {0} not found - skills sync skipped." -f $PrimaryAgents) 'Yellow' Add-Audit $CloneZ 'skills' 'junction' $false 'primary .agents missing' return $true } @@ -301,19 +308,19 @@ function Sync-SkillsJunction([string]$Name, [string]$CloneZ, [string]$CloneHome) if ([string]::IsNullOrEmpty($item.LinkType)) { $dest = Join-Path $CloneZ ("skills.pre-sync-" + $Stamp) if ($DryRun) { - Write-Tag "DRY:$Name" ("would move stale skills copy aside -> {0}" -f (Split-Path -Leaf $dest)) 'Cyan' + Write-Tag "DRY:$(Get-SyncTargetDisplay $Name)" ("would move stale skills copy aside -> {0}" -f (Split-Path -Leaf $dest)) 'Cyan' } else { Move-Item -LiteralPath $staleSkills -Destination $dest -Force if (Test-Path -LiteralPath $staleSkills) { - Write-Tag "FAILED:$Name" 'stale skills dir still present after the move.' 'Red' + Write-Tag "FAILED:$(Get-SyncTargetDisplay $Name)" 'stale skills dir still present after the move.' 'Red' Add-Audit $CloneZ 'skills' 'retire-copy' $false 'move failed' return $false } - Write-Tag "OK:$Name" ("stale skills copy moved aside -> {0}" -f (Split-Path -Leaf $dest)) 'Green' + Write-Tag "OK:$(Get-SyncTargetDisplay $Name)" ("stale skills copy moved aside -> {0}" -f (Split-Path -Leaf $dest)) 'Green' Add-Audit $CloneZ 'skills' 'retire-copy' $true (Split-Path -Leaf $dest) } } else { - Write-Tag "OK:$Name" '.zcode\skills is already a link - left untouched.' 'Green' + Write-Tag "OK:$(Get-SyncTargetDisplay $Name)" '.zcode\skills is already a link - left untouched.' 'Green' } } @@ -323,12 +330,12 @@ function Sync-SkillsJunction([string]$Name, [string]$CloneZ, [string]$CloneHome) $movedAside = $null if (Test-Path -LiteralPath $cloneAgents) { if (Test-LinkIs $cloneAgents $PrimaryAgents) { - Write-Tag "OK:$Name" '.agents junction already points at the shared store.' 'Green' + Write-Tag "OK:$(Get-SyncTargetDisplay $Name)" '.agents junction already points at the shared store.' 'Green' $needCreate = $false } else { $dest = "$cloneAgents.pre-sync-$Stamp" if ($DryRun) { - Write-Tag "DRY:$Name" ("would move existing .agents aside -> {0}" -f (Split-Path -Leaf $dest)) 'Cyan' + Write-Tag "DRY:$(Get-SyncTargetDisplay $Name)" ("would move existing .agents aside -> {0}" -f (Split-Path -Leaf $dest)) 'Cyan' } else { Move-Item -LiteralPath $cloneAgents -Destination $dest -Force $movedAside = $dest @@ -338,10 +345,10 @@ function Sync-SkillsJunction([string]$Name, [string]$CloneZ, [string]$CloneHome) } if ($needCreate) { if ($DryRun) { - Write-Tag "DRY:$Name" ("would junction {0} -> {1}" -f $cloneAgents, $PrimaryAgents) 'Cyan' + Write-Tag "DRY:$(Get-SyncTargetDisplay $Name)" ("would junction {0} -> {1}" -f $cloneAgents, $PrimaryAgents) 'Cyan' } else { if (-not (New-DirJunction $cloneAgents $PrimaryAgents)) { - Write-Tag "FAILED:$Name" ("could not create .agents junction -> {0}" -f $PrimaryAgents) 'Red' + Write-Tag "FAILED:$(Get-SyncTargetDisplay $Name)" ("could not create .agents junction -> {0}" -f $PrimaryAgents) 'Red' Add-Audit $CloneZ 'skills' 'junction' $false 'create failed' # Rollback: without it the clone is stranded -- its original # .agents renamed aside and NO link in place (skill discovery @@ -349,15 +356,15 @@ function Sync-SkillsJunction([string]$Name, [string]$CloneZ, [string]$CloneHome) if ($movedAside) { try { if (Test-Path -LiteralPath $cloneAgents) { - Write-Tag "FAILED:$Name" ("rollback skipped - a link still occupies {0}; the original is kept at {1}" -f $cloneAgents, $movedAside) 'Red' + Write-Tag "FAILED:$(Get-SyncTargetDisplay $Name)" ("rollback skipped - a link still occupies {0}; the original is kept at {1}" -f $cloneAgents, $movedAside) 'Red' Add-Audit $CloneZ 'skills' 'rollback' $false 'path occupied' } else { Move-Item -LiteralPath $movedAside -Destination $cloneAgents -Force - Write-Tag "INFO:$Name" ("original .agents restored from {0}" -f $movedAside) 'Yellow' + Write-Tag "INFO:$(Get-SyncTargetDisplay $Name)" ("original .agents restored from {0}" -f $movedAside) 'Yellow' Add-Audit $CloneZ 'skills' 'rollback' $true (Split-Path -Leaf $movedAside) } } catch { - Write-Tag "FAILED:$Name" ("rollback of the original .agents failed: {0} - restore manually from {1}" -f $_.Exception.Message, $movedAside) 'Red' + Write-Tag "FAILED:$(Get-SyncTargetDisplay $Name)" ("rollback of the original .agents failed: {0} - restore manually from {1}" -f $_.Exception.Message, $movedAside) 'Red' Add-Audit $CloneZ 'skills' 'rollback' $false $_.Exception.Message } } @@ -370,7 +377,7 @@ function Sync-SkillsJunction([string]$Name, [string]$CloneZ, [string]$CloneHome) # Verify-after: junction intact + skills actually reachable through it. if (-not (Test-LinkIs $cloneAgents $PrimaryAgents)) { - Write-Tag "FAILED:$Name" '.agents is not a correct junction after the sync.' 'Red' + Write-Tag "FAILED:$(Get-SyncTargetDisplay $Name)" '.agents is not a correct junction after the sync.' 'Red' Add-Audit $CloneZ 'skills' 'verify' $false 'junction verify failed' return $false } @@ -386,15 +393,15 @@ function Sync-SkillsJunction([string]$Name, [string]$CloneZ, [string]$CloneHome) # This script auto-runs as launcher step 2d, so a hard FAIL here # would flag every clone launch. Aligns with the "primary .agents # missing" WARN path earlier in this function. - Write-Tag "WARN:$Name" ("junction correct, but {0} skill(s) visible through it - the shared store has no skills yet." -f $cnt) 'Yellow' + Write-Tag "WARN:$(Get-SyncTargetDisplay $Name)" ("junction correct, but {0} skill(s) visible through it - the shared store has no skills yet." -f $cnt) 'Yellow' Add-Audit $CloneZ 'skills' 'verify' $true ("junction ok, $cnt skills visible (empty shared store)") return $true } - Write-Tag "FAILED:$Name" 'no skills visible through the .agents junction and the shared store is gone.' 'Red' + Write-Tag "FAILED:$(Get-SyncTargetDisplay $Name)" 'no skills visible through the .agents junction and the shared store is gone.' 'Red' Add-Audit $CloneZ 'skills' 'verify' $false '0 skills visible, shared store missing' return $false } - Write-Tag "OK:$Name" (".agents junction verified - {0} skills visible through it." -f $cnt) 'Green' + Write-Tag "OK:$(Get-SyncTargetDisplay $Name)" (".agents junction verified - {0} skills visible through it." -f $cnt) 'Green' Add-Audit $CloneZ 'skills' 'junction' $true "$cnt skills visible" return $true } @@ -421,13 +428,13 @@ function Sync-PluginCache([string]$Name, [string]$CloneZ, [string]$CloneCli) { } if (($diff.Count -eq 0) -and (-not $knownDrift)) { - Write-Tag "OK:$Name" ("plugin cache already in sync ({0} plugin versions)." -f $pSet.Count) 'Green' + Write-Tag "OK:$(Get-SyncTargetDisplay $Name)" ("plugin cache already in sync ({0} plugin versions)." -f $pSet.Count) 'Green' Add-Audit $CloneZ 'plugins' 'verify' $true 'already in sync' return $true } if ($DryRun) { - Write-Tag "DRY:$Name" ("would robocopy /MIR plugin cache + marketplaces ({0} differing entries)." -f $diff.Count) 'Cyan' + Write-Tag "DRY:$(Get-SyncTargetDisplay $Name)" ("would robocopy /MIR plugin cache + marketplaces ({0} differing entries)." -f $diff.Count) 'Cyan' return $true } @@ -437,13 +444,13 @@ function Sync-PluginCache([string]$Name, [string]$CloneZ, [string]$CloneCli) { if (-not (Test-Path -LiteralPath $pair[0])) { continue } $null = & robocopy.exe $pair[0] $pair[1] /MIR /R:1 /W:1 /NFL /NDL /NJH /NJS /NP if ($LASTEXITCODE -ge 8) { - Write-Tag "FAIL:$Name" ("robocopy exited {0} for {1}" -f $LASTEXITCODE, $pair[0]) 'Red' + Write-Tag "FAIL:$(Get-SyncTargetDisplay $Name)" ("robocopy exited {0} for {1}" -f $LASTEXITCODE, $pair[0]) 'Red' $fail = $true } elseif ($LASTEXITCODE -ge 4) { # Exit 4-7 = mismatches: locked/AV-held files can survive /R:1. # Not a hard failure (the verify-after below still runs), but the # mirror is suspect and must be named in the verify result. - Write-Tag "WARN:$Name" ("robocopy exited {0} for {1} - some files may not have copied (mismatch)." -f $LASTEXITCODE, (Split-Path -Leaf $pair[0])) 'Yellow' + Write-Tag "WARN:$(Get-SyncTargetDisplay $Name)" ("robocopy exited {0} for {1} - some files may not have copied (mismatch)." -f $LASTEXITCODE, (Split-Path -Leaf $pair[0])) 'Yellow' $suspect += ("robocopy exit {0} on {1}" -f $LASTEXITCODE, (Split-Path -Leaf $pair[0])) } } @@ -455,10 +462,10 @@ function Sync-PluginCache([string]$Name, [string]$CloneZ, [string]$CloneCli) { # state -- delete it explicitly so the sets converge, never silently OK. try { Remove-Item -LiteralPath $cKnown -Force - Write-Tag "INFO:$Name" 'stale clone known_marketplaces.json deleted (the Primary has none).' 'Cyan' + Write-Tag "INFO:$(Get-SyncTargetDisplay $Name)" 'stale clone known_marketplaces.json deleted (the Primary has none).' 'Cyan' Add-Audit $CloneZ 'plugins' 'mirror' $true 'stale clone known_marketplaces.json deleted' } catch { - Write-Tag "FAILED:$Name" ("could not delete the stale clone known_marketplaces.json: {0}" -f $_.Exception.Message) 'Red' + Write-Tag "FAILED:$(Get-SyncTargetDisplay $Name)" ("could not delete the stale clone known_marketplaces.json: {0}" -f $_.Exception.Message) 'Red' Add-Audit $CloneZ 'plugins' 'mirror' $false $_.Exception.Message $fail = $true } @@ -478,7 +485,7 @@ function Sync-PluginCache([string]$Name, [string]$CloneZ, [string]$CloneCli) { # Same read-only-Primary shape as the known file, but deleting a whole # marketplace dir is destructive -- warn loudly instead of mirroring # to empty. - Write-Tag "WARN:$Name" ("the Primary has no marketplaces dir - the clone's copy was left as-is (Primary is read-only).") 'Yellow' + Write-Tag "WARN:$(Get-SyncTargetDisplay $Name)" ("the Primary has no marketplaces dir - the clone's copy was left as-is (Primary is read-only).") 'Yellow' Add-Audit $CloneZ 'plugins' 'mirror' $true 'clone-only marketplaces dir left in place' } $pKnownNow = Test-Path -LiteralPath $pKnown @@ -492,11 +499,11 @@ function Sync-PluginCache([string]$Name, [string]$CloneZ, [string]$CloneCli) { } $detail = (@($bad) + @($suspect) | Where-Object { $_ }) -join '; ' if (($bad.Count -gt 0) -or $fail) { - Write-Tag "FAILED:$Name" ("plugin cache verify-after mismatch ({0}) - re-run after closing the instances." -f $detail) 'Red' + Write-Tag "FAILED:$(Get-SyncTargetDisplay $Name)" ("plugin cache verify-after mismatch ({0}) - re-run after closing the instances." -f $detail) 'Red' Add-Audit $CloneZ 'plugins' 'mirror' $false ("mismatch: " + $detail) return $false } - Write-Tag "OK:$Name" ("plugin cache mirrored + verified ({0} plugin versions)." -f $vSet.Count) 'Green' + Write-Tag "OK:$(Get-SyncTargetDisplay $Name)" ("plugin cache mirrored + verified ({0} plugin versions)." -f $vSet.Count) 'Green' $okDetail = "$($vSet.Count) versions" if ($suspect.Count -gt 0) { $okDetail += '; robocopy mismatch warnings: ' + ($suspect -join '; ') } Add-Audit $CloneZ 'plugins' 'mirror' $true $okDetail @@ -510,10 +517,10 @@ function Invoke-InstanceSync([hashtable]$Def) { $cloneCli = Join-Path $cloneZ 'cli' Write-Host '' - Write-Host "=== $name ($($Def.HomeRel)) ===" -ForegroundColor White + Write-Host "=== $($Def.Color) / $name ($($Def.HomeRel)) ===" -ForegroundColor White if (-not (Test-Path -LiteralPath $cloneZ)) { - Write-Tag "SKIP:$name" 'not seeded yet - first launch copies the Primary profile (launcher step 2); this sync verifies afterwards.' 'Yellow' + Write-Tag "SKIP:$(Get-SyncTargetDisplay $name)" 'not seeded yet - first launch copies the Primary profile (launcher step 2); this sync verifies afterwards.' 'Yellow' return $true } if ($RunningNames.ContainsKey($name)) { @@ -523,19 +530,19 @@ function Invoke-InstanceSync([hashtable]$Def) { # exit, and reads mcp.servers at every app-server spawn (one per # new session). Writing under a running instance is safe; the # synced definitions land on its next chat without a restart. - Write-Tag "INFO:$name" 'instance is RUNNING - MCP merge proceeds (no exit-time rewrite; applies at next session).' 'Cyan' + Write-Tag "INFO:$(Get-SyncTargetDisplay $name)" 'instance is RUNNING - MCP merge proceeds (no exit-time rewrite; applies at next session).' 'Cyan' } else { - Write-Tag "SKIP:$name" 'instance is RUNNING - skills/plugin mirroring must not race a live app; close it and re-run, or use -McpOnly.' 'Yellow' + Write-Tag "SKIP:$(Get-SyncTargetDisplay $name)" 'instance is RUNNING - skills/plugin mirroring must not race a live app; close it and re-run, or use -McpOnly.' 'Yellow' return $true } } if (-not (Test-Path -LiteralPath $cloneCli)) { - Write-Tag "WARN:$name" '.zcode exists but .zcode\cli is missing - unexpected layout, skipping.' 'Yellow' + Write-Tag "WARN:$(Get-SyncTargetDisplay $name)" '.zcode exists but .zcode\cli is missing - unexpected layout, skipping.' 'Yellow' return $true } $cloneConfig = Join-Path $cloneCli 'config.json' if (-not (Test-Path -LiteralPath $cloneConfig)) { - Write-Tag "WARN:$name" 'clone config.json missing - run the clone launcher once to seed, then re-run.' 'Yellow' + Write-Tag "WARN:$(Get-SyncTargetDisplay $name)" 'clone config.json missing - run the clone launcher once to seed, then re-run.' 'Yellow' return $true } @@ -592,15 +599,17 @@ foreach ($def in $targets) { Write-Host '' Write-Host '--- Summary ---' foreach ($r in $results) { - if ($r.Ok) { Write-Host ("[{0}] OK" -f $r.Name) -ForegroundColor Green } + $rDisplay = Get-SyncTargetDisplay $r.Name + if ($r.Ok) { Write-Host ("[{0}] OK" -f $rDisplay) -ForegroundColor Green } else { - Write-Host ("[{0}] FAILED" -f $r.Name) -ForegroundColor Red + Write-Host ("[{0}] FAILED" -f $rDisplay) -ForegroundColor Red $Script:FailedTargets += $r.Name } } if ($Script:FailedTargets.Count -gt 0) { - Write-Host ("FAILED targets: {0} - details in {1}" -f ($Script:FailedTargets -join ', '), $LogFile) -ForegroundColor Red + $failedDisplay = (@($Script:FailedTargets | ForEach-Object { Get-SyncTargetDisplay $_ }) -join ', ') + Write-Host ("FAILED targets: {0} - details in {1}" -f $failedDisplay, $LogFile) -ForegroundColor Red exit 1 } Write-Host ("All targets OK. Log: {0}" -f $LogFile) -ForegroundColor Green diff --git a/tools/watch_zcode_mcp_sync.ps1 b/tools/watch_zcode_mcp_sync.ps1 index 770e357..b1eed5a 100644 --- a/tools/watch_zcode_mcp_sync.ps1 +++ b/tools/watch_zcode_mcp_sync.ps1 @@ -346,27 +346,27 @@ function Invoke-ApplyLivePass { try { $st = Get-LiveInstanceState $def if ($st.Status -eq 'not-running') { - Write-WatchLog ("live-apply {0}: not running - config applies on next launch." -f $def.Name) + Write-WatchLog ("live-apply {0}: not running - config applies on next launch." -f $def.Title) continue } if ($st.Status -eq 'no-appserver') { - Write-WatchLog ("live-apply {0}: running, no workspace open - picks up at next spawn." -f $def.Name) + Write-WatchLog ("live-apply {0}: running, no workspace open - picks up at next spawn." -f $def.Title) continue } if (-not (Wait-ForIdleGuard $st.Servers)) { - Write-WatchLog ("live-apply {0}: deferred - chat still active after ~90s ({1})." -f $def.Name, $script:GuardWhy) 'WARN' + Write-WatchLog ("live-apply {0}: deferred - chat still active after ~90s ({1})." -f $def.Title, $script:GuardWhy) 'WARN' continue } # re-collect: PIDs may have changed during the guard wait $desc = @(Get-DescendantProcesses ($st.Mains | ForEach-Object { [int]$_.Id })) $servers = @($desc | Where-Object { $_.CommandLine -like '*app-server*' }) if ($servers.Count -eq 0) { - Write-WatchLog ("live-apply {0}: app-server went away while waiting - picks up at next spawn." -f $def.Name) + Write-WatchLog ("live-apply {0}: app-server went away while waiting - picks up at next spawn." -f $def.Title) continue } $oldIds = @($servers | ForEach-Object { [int]$_.ProcessId }) foreach ($targetId in $oldIds) { Stop-Process -Id $targetId -Force -ErrorAction SilentlyContinue } - Write-WatchLog ("live-apply {0}: recycled app-server pid(s) {1} - waiting for respawn..." -f $def.Name, ($oldIds -join ',')) 'SYNC' + Write-WatchLog ("live-apply {0}: recycled app-server pid(s) {1} - waiting for respawn..." -f $def.Title, ($oldIds -join ',')) 'SYNC' $respawned = $false for ($i = 0; $i -lt 30; $i++) { Start-Sleep -Seconds 1 @@ -374,10 +374,10 @@ function Invoke-ApplyLivePass { $fresh = @($descNow | Where-Object { $_.CommandLine -like '*app-server*' -and $oldIds -notcontains [int]$_.ProcessId }) if ($fresh.Count -gt 0) { $respawned = $true; break } } - if ($respawned) { Write-WatchLog ("live-apply {0}: app-server respawned after ~{1}s - new MCP definitions are live." -f $def.Name, ($i + 1)) 'SYNC' } - else { Write-WatchLog ("live-apply {0}: [FAIL] app-server did not respawn within 30s - check the window." -f $def.Name) 'FAIL' } + if ($respawned) { Write-WatchLog ("live-apply {0}: app-server respawned after ~{1}s - new MCP definitions are live." -f $def.Title, ($i + 1)) 'SYNC' } + else { Write-WatchLog ("live-apply {0}: [FAIL] app-server did not respawn within 30s - check the window." -f $def.Title) 'FAIL' } } catch { - Write-WatchLog ("live-apply {0} FAILED: {1}" -f $def.Name, $_.Exception.Message) 'FAIL' + Write-WatchLog ("live-apply {0} FAILED: {1}" -f $def.Title, $_.Exception.Message) 'FAIL' } } } @@ -471,8 +471,11 @@ if ($InstallAutostart -or $RemoveAutostart) { } # ---- One-shot / resident ---------------------------------------------------- +# Display name for the -Target param: color title for a single clone, 'All' as-is +# (param values stay frozen keys; only the printed word changes). +$targetDisplay = if ($Target -eq 'All') { 'All' } else { @($InstanceDefs | Where-Object { $_.Name -eq $Target })[0].Title } if ($RunOnce) { - Write-WatchLog ("one-shot pass starting (target {0}, DryRun {1}, ApplyLive {2})" -f $Target, [bool]$DryRun, [bool]$ApplyLive) + Write-WatchLog ("one-shot pass starting (target {0}, DryRun {1}, ApplyLive {2})" -f $targetDisplay, [bool]$DryRun, [bool]$ApplyLive) $status = Invoke-WatchPass if ($ApplyLive) { Invoke-ApplyLivePass } Write-WatchLog ("single pass complete (-RunOnce, status {0})" -f $status) @@ -522,7 +525,7 @@ if (-not $created) { $mutex.Close() exit 0 } -Write-WatchLog ('watcher started (pid {0}, interval {1}s, target {2}, ApplyLive {3}, script {4})' -f $PID, $IntervalSeconds, $Target, [bool]$ApplyLive, $PSCommandPath) +Write-WatchLog ('watcher started (pid {0}, interval {1}s, target {2}, ApplyLive {3}, script {4})' -f $PID, $IntervalSeconds, $targetDisplay, [bool]$ApplyLive, $PSCommandPath) try { while ($true) { $status = Invoke-WatchPass diff --git a/tools/watch_zcode_taskbar.ps1 b/tools/watch_zcode_taskbar.ps1 index 93520a2..0c50db0 100644 --- a/tools/watch_zcode_taskbar.ps1 +++ b/tools/watch_zcode_taskbar.ps1 @@ -177,9 +177,9 @@ function Invoke-IdentityKick { [void][ZcodeWindowAumid]::Stamp($hwnd, "$($Inst.Aumid).kick") Start-Sleep -Milliseconds 300 $got = [ZcodeWindowAumid]::Stamp($hwnd, $Inst.Aumid) - Write-WatchLog ('{0}: pid {1} hwnd 0x{2:X} title "{3}" identity "{4}" -> kicked via "{5}.kick" -> stamped "{6}"' -f $Inst.Name, $Win.Id, [Int64]$hwnd, $Win.MainWindowTitle, $Cur, $Inst.Aumid, $got) 'STAMP' + Write-WatchLog ('{0}: pid {1} hwnd 0x{2:X} title "{3}" identity "{4}" -> kicked via "{5}.kick" -> stamped "{6}"' -f $Inst.Title, $Win.Id, [Int64]$hwnd, $Win.MainWindowTitle, $Cur, $Inst.Aumid, $got) 'STAMP' if ($got -ne $Inst.Aumid) { - Write-WatchLog ('{0}: FAILED - read-back "{1}" != "{2}". If this watcher runs at a lower integrity level than the ZCode window (UIPI), run it from the same level or higher.' -f $Inst.Name, $got, $Inst.Aumid) 'FAIL' + Write-WatchLog ('{0}: FAILED - read-back "{1}" != "{2}". If this watcher runs at a lower integrity level than the ZCode window (UIPI), run it from the same level or higher.' -f $Inst.Title, $got, $Inst.Aumid) 'FAIL' } } @@ -277,7 +277,7 @@ function Invoke-IdentityPass { if ($inst.Name -eq 'Primary') { foreach ($cand in $Instances) { if ($cand.Name -ne 'Primary' -and $cand.Title -eq $w.MainWindowTitle) { - Write-WatchLog ("{0}: pid {1} markers said Primary but title is '{2}' - trusting title" -f $cand.Name, $w.Id, $w.MainWindowTitle) 'WARN' + Write-WatchLog ("{0}: pid {1} markers said Primary but title is '{2}' - trusting title" -f $cand.Title, $w.Id, $w.MainWindowTitle) 'WARN' $inst = $cand break } @@ -297,7 +297,7 @@ function Invoke-IdentityPass { $hits = @($unknownWins | Where-Object { $_.MainWindowTitle -eq $inst.Title }) if ($hits.Count -eq 0) { continue } if ($hits.Count -gt 1) { - Write-WatchLog ("{0}: {1} windows titled '{2}' - ambiguous (app.asar patch missing?), stamping skipped" -f $inst.Name, $hits.Count, $inst.Title) 'WARN' + Write-WatchLog ("{0}: {1} windows titled '{2}' - ambiguous (app.asar patch missing?), stamping skipped" -f $inst.Title, $hits.Count, $inst.Title) 'WARN' continue } # A window is only here because its pid has no WMI data. ONE window @@ -306,7 +306,7 @@ function Invoke-IdentityPass { # Primary row never guesses - skip loudly. Clone v6 titles are unique # and keep stamping. if ($inst.Name -eq 'Primary') { - Write-WatchLog ("{0}: lone window titled '{1}' with no WMI data for pid {2} - ambiguous (could be a splash-phase clone), stamping skipped" -f $inst.Name, $inst.Title, $hits[0].Id) 'WARN' + Write-WatchLog ("{0}: lone window titled '{1}' with no WMI data for pid {2} - ambiguous (could be a splash-phase clone), stamping skipped" -f $inst.Title, $inst.Title, $hits[0].Id) 'WARN' continue } $firstSeen = -not $SeenHwnds.ContainsKey([Int64]$hits[0].MainWindowHandle) From 5aa2f153152325245142682034eaf2e5e5a11992 Mon Sep 17 00:00:00 2001 From: kali-upper Date: Tue, 3 Nov 2026 22:26:48 +0200 Subject: [PATCH 2/2] test(harness): assert color-first clone row labels The .bat harness's M/N/O scenarios asserted the OLD key-led row text ('Reset Second instance.*- Blue', 'Launch c1'). GHOST.bat now renders color-first labels ('Reset Blue clone', 'Launch Blue clone') per the display-vocabulary unification, so the regexes follow. All 19 scenarios pass locally. --- .bat-harness-test.ps1 | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.bat-harness-test.ps1 b/.bat-harness-test.ps1 index 42fcef0..c5e49dd 100644 --- a/.bat-harness-test.ps1 +++ b/.bat-harness-test.ps1 @@ -182,11 +182,11 @@ if ($out -notmatch 'Invalid input') { $failures += 'L: rejection hint missing' # and tail are split by ANSI codes in the colored render, so the color # assertions use .* between them. $out = Invoke-Scenario 'M_zcode_reset_render' @('2', '0', '0') -if ($out -notmatch '\[ 9\].*Reset Second instance.*- Blue') { $failures += 'M: ZCode [9] Second reset+Blue not rendered' } -if ($out -notmatch '\[10\].*Reset Third instance.*- Yellow') { $failures += 'M: ZCode [10] Third reset+Yellow not rendered' } -if ($out -notmatch '\[11\].*Reset Fourth instance.*- Green') { $failures += 'M: ZCode [11] Fourth reset+Green not rendered' } -if ($out -notmatch '\[12\].*Reset Fifth instance.*- Red') { $failures += 'M: ZCode [12] Fifth reset+Red not rendered' } -if ($out -notmatch '\[13\].*Reset Sixth instance.*- Orange') { $failures += 'M: ZCode [13] Sixth reset+Orange not rendered' } +if ($out -notmatch '\[ 9\].*Reset Blue clone') { $failures += 'M: ZCode [9] Blue reset not rendered' } +if ($out -notmatch '\[10\].*Reset Yellow clone') { $failures += 'M: ZCode [10] Yellow reset not rendered' } +if ($out -notmatch '\[11\].*Reset Green clone') { $failures += 'M: ZCode [11] Green reset not rendered' } +if ($out -notmatch '\[12\].*Reset Red clone') { $failures += 'M: ZCode [12] Red reset not rendered' } +if ($out -notmatch '\[13\].*Reset Orange clone') { $failures += 'M: ZCode [13] Orange reset not rendered' } if ($out -notmatch '\[16\].*Reset ALL SIX instances') { $failures += 'M: ZCode [16] all-six reset not rendered' } if ($out -notmatch '\[14\].*Reset ZCode Primary instance') { $failures += 'M: ZCode [14] Primary reset not rendered' } if ($out -notmatch '\[ 9\].*survivors kept running') { $failures += 'M: ZCode [9] reset tail not rendered' } @@ -198,7 +198,7 @@ $out = Invoke-Scenario 'N_cline_render' @('5', '0', '0') if ($out -match 'Unknown task') { $failures += 'N: Unknown task on Cline submenu render' } if ($out -match '%PENDING_CHAIN%') { $failures += 'N: literal %PENDING_CHAIN% leaked' } if ($out -notmatch 'Cline Multi-Instance') { $failures += 'N: Cline submenu not shown' } -if ($out -notmatch '\[ 1\].*Launch c1') { $failures += 'N: Cline [1] Launch c1 not rendered' } +if ($out -notmatch '\[ 1\].*Launch Blue clone') { $failures += 'N: Cline [1] Launch Blue clone not rendered' } if ($out -notmatch '\[ 6\].*Launch ALL clones') { $failures += 'N: Cline [6] Launch ALL not rendered' } if ($out -notmatch '\[ 8\].*Clone status') { $failures += 'N: Cline [8] Clone status not rendered' } $out = Invoke-Scenario 'N_cline_invalid' @('5 77', '0', '0') @@ -211,7 +211,7 @@ $out = Invoke-Scenario 'O_opencode_render' @('6', '0', '0') if ($out -match 'Unknown task') { $failures += 'O: Unknown task on OpenCode submenu render' } if ($out -match '%PENDING_CHAIN%') { $failures += 'O: literal %PENDING_CHAIN% leaked' } if ($out -notmatch 'OpenCode Multi-Instance') { $failures += 'O: OpenCode submenu not shown' } -if ($out -notmatch '\[ 1\].*Launch c1') { $failures += 'O: OpenCode [1] Launch c1 not rendered' } +if ($out -notmatch '\[ 1\].*Launch Blue clone') { $failures += 'O: OpenCode [1] Launch Blue clone not rendered' } if ($out -notmatch '\[ 7\].*Install clone shortcuts') { $failures += 'O: OpenCode [7] Install shortcuts not rendered' } if ($out -notmatch '\[ 8\].*Apply clone-home patch') { $failures += 'O: OpenCode [8] Apply clone-home patch not rendered' } if ($out -notmatch '\[10\].*Remove clone shortcuts') { $failures += 'O: OpenCode [10] Remove shortcuts not rendered' }