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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions .github/workflows/install-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ jobs:

test-windows-ps:
runs-on: windows-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v7
- name: Set up Python
Expand All @@ -54,15 +55,55 @@ jobs:
python-version: '3.12'
- name: Run PowerShell install
shell: pwsh
env:
CLAWMETRY_SKIP_ONBOARD: '1'
run: .\install.ps1
- name: Verify clawmetry binary
shell: pwsh
run: |
$env:PATH = "$env:LOCALAPPDATA\clawmetry\Scripts;$env:PATH"
clawmetry --version
# Re-running the installer on a node that is ALREADY linked to an account
# must report that setup and leave it alone -- not replay the wizard.
# USERPROFILE points the probe at a synthetic profile, so this exercises
# the real script without depending on runner state.
- name: Gate — connected node keeps its setup
shell: pwsh
env:
CLAWMETRY_REONBOARD: '0'
run: |
$profileDir = Join-Path $env:RUNNER_TEMP "cm-connected"
$dataDir = Join-Path $profileDir ".clawmetry"
New-Item -ItemType Directory -Force -Path $dataDir | Out-Null
Set-Content -Path (Join-Path $dataDir "config.json") -Value '{"api_key":"cm_abc123456789","node_id":"ci-box","account_email":"founder@example.com"}'
Set-Content -Path (Join-Path $dataDir "cloud_plan.json") -Value '{"plan":"cloud_pro"}'
New-Item -ItemType File -Force -Path (Join-Path $dataDir "nocloud") | Out-Null
$env:USERPROFILE = $profileDir
$out = (.\install.ps1 6>&1 | Out-String)
Write-Host $out
if ($out -notmatch "already connected") { throw "no existing-setup summary" }
if ($out -notmatch "founder@example.com") { throw "account email not reported" }
if ($out -notmatch "Pro plan") { throw "plan not reported" }
if ($out -notmatch "Local-only") { throw "cloud sync mode not reported" }
if ($out -notmatch "Keeping your current setup") { throw "did not keep the existing setup" }
if ($out -match "How do you want to run ClawMetry") { throw "wizard replayed over an existing setup" }
# A node with NO account keeps the original behaviour: the wizard runs.
- name: Gate — fresh node still gets the wizard
shell: pwsh
env:
CLAWMETRY_LOCAL_ONLY: '1'
run: |
$profileDir = Join-Path $env:RUNNER_TEMP "cm-fresh"
New-Item -ItemType Directory -Force -Path $profileDir | Out-Null
$env:USERPROFILE = $profileDir
$out = (.\install.ps1 6>&1 | Out-String)
Write-Host $out
if ($out -match "already connected") { throw "claimed a connection that does not exist" }
if ($out -notmatch "How do you want to run ClawMetry") { throw "onboarding wizard did not run" }

test-windows-cmd:
runs-on: windows-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v7
- name: Set up Python
Expand All @@ -71,10 +112,33 @@ jobs:
python-version: '3.12'
- name: Run CMD install
shell: cmd
env:
CLAWMETRY_SKIP_ONBOARD: '1'
run: install.cmd
- name: Verify clawmetry binary
shell: cmd
run: clawmetry --version
# Same gate as the PowerShell path: an already-connected node is reported
# and left alone. CLAWMETRY_REONBOARD=0 answers the question up front so
# the step never waits on input.
- name: Gate — connected node keeps its setup
shell: cmd
env:
CLAWMETRY_REONBOARD: '0'
run: |
mkdir "%RUNNER_TEMP%\cm-connected\.clawmetry"
> "%RUNNER_TEMP%\cm-connected\.clawmetry\config.json" echo {"api_key":"cm_abc123456789","node_id":"ci-box","account_email":"founder@example.com"}
> "%RUNNER_TEMP%\cm-connected\.clawmetry\cloud_plan.json" echo {"plan":"cloud_pro"}
type nul > "%RUNNER_TEMP%\cm-connected\.clawmetry\nocloud"
set "USERPROFILE=%RUNNER_TEMP%\cm-connected"
install.cmd > "%RUNNER_TEMP%\cmd-gate.log" 2>&1
type "%RUNNER_TEMP%\cmd-gate.log"
findstr /C:"already connected" "%RUNNER_TEMP%\cmd-gate.log" >nul || exit /b 1
findstr /C:"founder@example.com" "%RUNNER_TEMP%\cmd-gate.log" >nul || exit /b 1
findstr /C:"Pro plan" "%RUNNER_TEMP%\cmd-gate.log" >nul || exit /b 1
findstr /C:"Keeping your current setup" "%RUNNER_TEMP%\cmd-gate.log" >nul || exit /b 1
findstr /C:"How do you want to run ClawMetry" "%RUNNER_TEMP%\cmd-gate.log" >nul && exit /b 1
exit /b 0

shellcheck:
runs-on: ubuntu-latest
Expand Down
51 changes: 51 additions & 0 deletions install.cmd

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Drift Bot (ClawMetry) — Blueprint: Installer Scripts

The blueprint specifies that both installer entry points shall apply the existing-setup gate at the "already up to date" early exit and the post-install path. The CMD installer only applies the gate after a successful install (around line 73), not on an early exit for already-current installations.

Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,57 @@ if %ERRORLEVEL% NEQ 0 (
)

echo ✓ Installed clawmetry
echo.

REM ── Existing setup: account probe + "re-onboard?" gate ──────────────────
REM Same contract as install.sh / install.ps1: this script is also the upgrade

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Drift Bot (ClawMetry) — Blueprint: Installer Scripts

The blueprint specifies that both installer entry points shall apply the existing-setup gate at two points: the "already up to date" early exit and the post-install path. The CMD installer only applies the gate after a successful install, not on an early exit for already-current installations.

REM path, so on a machine that is ALREADY linked to a ClawMetry account it
REM reports that setup and asks before replaying the wizard over it. With no
REM account linked it runs `clawmetry onboard` straight away.
REM
REM The probe below both PRINTS the summary and carries the answer in its exit
REM code (0 = connected), so batch never has to parse JSON. Any failure -- an
REM unreadable config, a CLI too old for `status --json`, no network -- exits
REM non-zero, which means "not connected" and simply runs the wizard as before.
if "%CLAWMETRY_SKIP_ONBOARD%"=="1" (
echo Skipping onboard ^(CLAWMETRY_SKIP_ONBOARD=1^) - set up later with: clawmetry onboard
goto :cm_onboard_done
)

set "CM_STATUS_FILE=%TEMP%\clawmetry-status.json"
%PYTHON% -m clawmetry status --json > "%CM_STATUS_FILE%" 2>nul
%PYTHON% -c "import json,os;h=os.path.expanduser('~');d=os.path.join(h,'.clawmetry');g=lambda p:(json.loads(open(p).read()) if p and os.path.exists(p) else {});c=g(os.path.join(d,'config.json'));s=g(os.environ.get('CM_STATUS_FILE',''));cl=s.get('cloud_sync') or {};a=cl.get('account') or {};k=str(c.get('api_key') or '') or os.environ.get('CLAWMETRY_API_KEY','');e=str(a.get('email') or c.get('account_email') or '');ph=bool(a.get('placeholder')) or e.lower().endswith(('@clawmetry.auto','@clawmetry.linked'));conn=(bool(k) or bool(cl.get('api_key_masked'))) and not ph;pl=str(a.get('plan') or g(os.path.join(d,'cloud_plan.json')).get('plan') or '');lo=cl.get('local_only');lo=(bool(c.get('local_only')) or os.path.exists(os.path.join(d,'nocloud'))) if lo is None else bool(lo);L={'oss':'OSS','cloud_free':'Free','free':'Free','trial':'Trial','cloud_starter':'Starter','cloud_pro':'Pro','pro':'Self-hosted Pro','enterprise':'Enterprise'};lab=L.get(pl.lower(),pl.replace('cloud_','').replace('_',' ').title());n=str(cl.get('node_id') or c.get('node_id') or '');v=str(s.get('version') or '');out=[];out.append(' You are already connected to ClawMetry');out.append('');out.append(' Account: '+e+(' ['+lab+' plan]' if lab else '')) if e else None;out.append(' Cloud sync: '+('Local-only, data stays on this machine' if lo else 'On, syncing to app.clawmetry.com'));out.append(' Version: '+v) if v else None;out.append(' Node: '+n) if n else None;print(chr(10).join(out)) if conn else None;raise SystemExit(0 if conn else 1)" 2>nul
set "CM_PROBE_RC=%ERRORLEVEL%"
del "%CM_STATUS_FILE%" >nul 2>&1
set "CM_STATUS_FILE="

if not "%CM_PROBE_RC%"=="0" (
%PYTHON% -m clawmetry onboard
goto :cm_onboard_done
)

REM CLAWMETRY_REONBOARD forces the answer without asking; anything else asks,
REM and an empty answer (including a non-interactive run, where `set /p`
REM returns immediately) keeps the setup that is already on this machine.
if /I "%CLAWMETRY_REONBOARD%"=="1" goto :cm_reonboard
if /I "%CLAWMETRY_REONBOARD%"=="0" goto :cm_keep
echo.
set "CM_ANS="
set /p "CM_ANS= Re-run setup [account, cloud vs local-only, license]? [y/N]: "
if /I "%CM_ANS%"=="y" goto :cm_reonboard
if /I "%CM_ANS%"=="yes" goto :cm_reonboard

:cm_keep
echo.
echo Keeping your current setup.
echo Change it anytime: clawmetry onboard
goto :cm_onboard_done

:cm_reonboard
%PYTHON% -m clawmetry onboard

:cm_onboard_done

echo.
echo Ready! Run 'clawmetry' to start the dashboard.
echo Then open http://localhost:8900 in your browser.
Expand Down
Loading
Loading