diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 143c051..c26b933 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ permissions: jobs: portable-ci: - runs-on: depot-ubuntu-24.04 + runs-on: blacksmith-2vcpu-ubuntu-2404 steps: - name: Checkout uses: actions/checkout@v4 diff --git a/.github/workflows/claude-pr-runner.yml b/.github/workflows/claude-pr-runner.yml index a24299b..30489bb 100644 --- a/.github/workflows/claude-pr-runner.yml +++ b/.github/workflows/claude-pr-runner.yml @@ -30,7 +30,7 @@ jobs: contains(github.event.comment.body, '@claude')) || (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) - runs-on: depot-ubuntu-24.04 + runs-on: blacksmith-2vcpu-ubuntu-2404 steps: - name: Checkout uses: actions/checkout@v4 diff --git a/README.md b/README.md index 1c5ec1f..4c1fd6e 100644 --- a/README.md +++ b/README.md @@ -40,12 +40,12 @@ Windows smoke test: ## CI - GitHub Actions workflow: `.github/workflows/ci.yml` -- Runner target: Depot-hosted runner label `depot-ubuntu-24.04` +- Runner target: Blacksmith runner label `blacksmith-2vcpu-ubuntu-2404` ## Claude PR Runner - Workflow: `.github/workflows/claude-pr-runner.yml` - Trigger: mention `@claude` in PR comments/reviews (or run manually via `workflow_dispatch`) -- Runner target: Depot-hosted runner label `depot-ubuntu-24.04` +- Runner target: Blacksmith runner label `blacksmith-2vcpu-ubuntu-2404` - Configure one auth secret: - `ANTHROPIC_API_KEY` (API key mode), or - `CLAUDE_CODE_OAUTH_TOKEN` (OAuth mode) diff --git a/docs/RUNBOOKS.md b/docs/RUNBOOKS.md index c69e76f..3397958 100644 --- a/docs/RUNBOOKS.md +++ b/docs/RUNBOOKS.md @@ -58,9 +58,15 @@ Backend spec: ## Linux-Portable Run Flow 1. `pcoder` starts/ensures VM via `start-vm.cmd`. 2. VM launcher attempts WHPX acceleration, then auto-fallback to TCG. -3. Project is copied into guest over SCP. -4. Tool command runs over SSH in guest project directory. -5. Project is copied back to host after run (unless `--no-sync-back`). +3. On first boot, cloud-init installs Node.js, `codex`, and `claude` CLI tools (may take several minutes). +4. `pcoder run` waits for cloud-init to complete before running the tool. +5. Project is copied into guest over SCP. +6. Tool command runs over SSH in guest project directory. +7. Project is copied back to host after run (unless `--no-sync-back`). + +**First-boot note:** The first time you boot the VM, cloud-init provisions the guest (creates the `portable` user, installs Node.js and the coding CLI tools). This can take 5–15 minutes depending on network speed and host performance. `pcoder run` automatically waits for cloud-init to finish before launching the tool. Subsequent boots skip provisioning and start much faster. + +**Smoke check with tool checks:** Run `scripts/runtime/windows/smoke-check.cmd` after the first boot completes to verify that `codex` and `claude` are installed in the guest. Use `-SkipToolChecks` to skip tool presence checks if only testing VM boot and SSH connectivity. Acceleration override (Windows troubleshooting): - `PCODER_VM_ACCEL_MODE=auto` (default): try WHPX then fallback to TCG if launch fails. diff --git a/runtime/linux/cloud-init/user-data b/runtime/linux/cloud-init/user-data index 0287c1c..20325aa 100644 --- a/runtime/linux/cloud-init/user-data +++ b/runtime/linux/cloud-init/user-data @@ -1,8 +1,18 @@ #cloud-config users: - name: portable - sudo: ALL=(ALL) NOPASSWD:ALL shell: /bin/bash + sudo: ALL=(ALL) NOPASSWD:ALL + lock_passwd: true + groups: + - sudo + ssh_authorized_keys: + - ssh_pwauth: false -# Placeholder for VM provisioning during image bake. +packages: + - nodejs + - npm + +runcmd: + - npm install -g @openai/codex @anthropic-ai/claude-code diff --git a/scripts/pcoder.cjs b/scripts/pcoder.cjs index beda02e..d04c81c 100755 --- a/scripts/pcoder.cjs +++ b/scripts/pcoder.cjs @@ -1258,6 +1258,18 @@ function buildRemoteRunScript(options) { const lines = [ 'set -e', + 'if command -v cloud-init >/dev/null 2>&1; then', + ' _ci_to=${PCODER_CLOUD_INIT_TIMEOUT:-900}', + ' if ! timeout "$_ci_to" cloud-init status --wait 2>/dev/null; then', + ' _ci_rc=$?', + ' if [ "$_ci_rc" -eq 124 ]; then', + ' echo "pcoder: cloud-init wait exceeded ${_ci_to}s; provisioning may be incomplete" >&2', + ' else', + ' echo "pcoder: cloud-init finished with errors (exit ${_ci_rc}); provisioning may have failed" >&2', + ' fi', + ' exit 1', + ' fi', + 'fi', `cd ${shellEscape(remoteProjectPath)}` ]; diff --git a/scripts/runtime/windows/start-vm.ps1 b/scripts/runtime/windows/start-vm.ps1 index 238807d..226714d 100644 --- a/scripts/runtime/windows/start-vm.ps1 +++ b/scripts/runtime/windows/start-vm.ps1 @@ -106,6 +106,13 @@ users: ssh_authorized_keys: - $PublicKey ssh_pwauth: false + +packages: + - nodejs + - npm + +runcmd: + - npm install -g @openai/codex @anthropic-ai/claude-code "@ $userData | Out-File -Encoding utf8 -FilePath $cloudInitUserDataPath }