feat: implement Rust-only Zeroshot v2 MVP #2492
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| # Codecov setup: | |
| # 1. Go to https://codecov.io and sign in with GitHub | |
| # 2. Add the covibes/zeroshot repository | |
| # 3. Get the upload token from Settings > General | |
| # 4. Add it as a GitHub secret: Settings > Secrets and variables > Actions > New repository secret | |
| # Name: CODECOV_TOKEN | |
| # Value: <your-token-from-codecov> | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| branches: [main] | |
| merge_group: | |
| types: [checks_requested] | |
| workflow_dispatch: | |
| inputs: | |
| include_docker_e2e: | |
| description: Run the non-hermetic live-provider Docker E2E job | |
| required: false | |
| type: boolean | |
| default: false | |
| jobs: | |
| # Fast quality gates - must pass before anything else | |
| check: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 | |
| with: | |
| node-version: 22 | |
| cache: 'npm' | |
| - name: Setup Rust 1.97.0 | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| toolchain: 1.97.0 | |
| components: clippy,rustfmt | |
| - name: Install Opcore Rust metrics analyzer | |
| run: npm run opcore:install:rust-metrics | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Build Opcore graph | |
| run: npm run opcore:graph:build | |
| - name: Opcore introduced-change gate | |
| env: | |
| CARGO_BUILD_JOBS: 1 | |
| OPCORE_BASE: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha || github.event.before || 'HEAD^' }} | |
| run: npm run opcore:check -- --base "$OPCORE_BASE" | |
| - name: Check generated Cluster Protocol artifacts | |
| run: npm run protocol:check | |
| - name: Check Rust formatting | |
| run: cargo fmt --all -- --check | |
| - name: Lint Rust | |
| run: cargo clippy --workspace --all-targets -- -D warnings | |
| - name: Test Rust workspace | |
| run: cargo test --workspace | |
| - name: Security audit | |
| run: npm run audit:production | |
| continue-on-error: false | |
| - name: Lint | |
| run: npm run lint | |
| - name: Duplicate code check | |
| run: npm run dupcheck | |
| - name: Type check | |
| run: npm run typecheck | |
| - name: Check provider CLI helper | |
| run: npm run check:agent-cli-provider:ci | |
| - name: Hosted target tests | |
| run: npm run test:hosted-target | |
| timeout-minutes: 5 | |
| - name: Unit tests with coverage (fast) | |
| run: npm run test:coverage | |
| timeout-minutes: 3 | |
| - name: E2E tests (fake provider) | |
| run: npm run test:e2e | |
| timeout-minutes: 5 | |
| - name: Integration tests (slow) | |
| run: npm run test:slow | |
| timeout-minutes: 15 | |
| - name: Upload coverage to Codecov | |
| uses: codecov/codecov-action@v5 | |
| with: | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| files: ./coverage/lcov.info | |
| flags: unittests | |
| name: codecov-zeroshot | |
| fail_ci_if_error: false | |
| continue-on-error: true | |
| # Tier 2: worktree/container isolation e2e (real Docker). Non-blocking and | |
| # opt-in via workflow_dispatch - the Docker sub-tests in `check`'s | |
| # "Integration tests (slow)" step self-skip under CI (this is what that | |
| # step's Docker coverage was previously silently missing). | |
| e2e-docker: | |
| if: github.event_name == 'workflow_dispatch' && inputs.include_docker_e2e | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 | |
| with: | |
| node-version: 22 | |
| cache: 'npm' | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Link CLI | |
| run: npm link | |
| - name: Docker isolation e2e | |
| run: npm run test:e2e:docker | |
| timeout-minutes: 15 | |
| # Cross-platform/version compatibility (main only) | |
| # NOTE: macOS runners cost 10x Linux minutes - keep this scoped to main. | |
| install-matrix: | |
| needs: check | |
| if: | | |
| always() && | |
| needs.check.result == 'success' && | |
| ( | |
| github.ref == 'refs/heads/main' || | |
| github.event_name == 'workflow_dispatch' || | |
| (github.event_name == 'pull_request' && github.base_ref == 'main') || | |
| (github.event_name == 'merge_group' && ( | |
| github.event.merge_group.base_ref == 'main' || | |
| github.event.merge_group.base_ref == 'refs/heads/main' || | |
| startsWith(github.ref, 'refs/heads/gh-readonly-queue/main/') | |
| )) | |
| ) | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: ubuntu-latest | |
| node: 22 | |
| - os: macos-latest | |
| node: 22 | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - name: Setup Node.js ${{ matrix.node }} | |
| uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 | |
| with: | |
| node-version: ${{ matrix.node }} | |
| cache: 'npm' | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Link CLI | |
| run: npm link | |
| - name: CLI smoke test | |
| run: | | |
| zeroshot --help | |
| zeroshot --version | |
| zeroshot list | |
| - name: Test process-metrics (platform-specific) | |
| run: | | |
| node -e " | |
| (async () => { | |
| const { getProcessMetrics, formatMetrics, getStateIcon, isPlatformSupported, getPlatformInfo } = require('./src/process-metrics'); | |
| const os = require('os'); | |
| console.log('Platform:', os.platform()); | |
| console.log('Supported:', isPlatformSupported()); | |
| console.log('Platform info:', JSON.stringify(getPlatformInfo())); | |
| // Test metrics collection | |
| const metrics = await getProcessMetrics(process.pid, { samplePeriodMs: 100 }); | |
| console.log('Metrics:', JSON.stringify(metrics, null, 2)); | |
| // Validate required fields | |
| if (!metrics.exists) throw new Error('Process should exist'); | |
| if (typeof metrics.cpuPercent !== 'number') throw new Error('cpuPercent must be number'); | |
| if (typeof metrics.memoryMB !== 'number') throw new Error('memoryMB must be number'); | |
| if (!metrics.state) throw new Error('state must be set'); | |
| console.log('Formatted:', formatMetrics(metrics)); | |
| console.log('State icon:', getStateIcon(metrics.state, metrics.network?.hasActivity)); | |
| console.log('✓ Process metrics test passed on', os.platform()); | |
| })().catch(e => { console.error(e); process.exit(1); }); | |
| " | |
| - name: Test status-footer | |
| run: | | |
| node -e " | |
| const { StatusFooter } = require('./src/status-footer'); | |
| const footer = new StatusFooter({ enabled: false }); | |
| footer.setCluster('test-cluster'); | |
| footer.setClusterState('running'); | |
| footer.updateAgent({ id: 'worker', state: 'executing_task', pid: process.pid, iteration: 1 }); | |
| const statusLine = footer.buildStatusLine(80); | |
| if (!statusLine.includes('running')) throw new Error('Status line missing state'); | |
| if (!statusLine.includes('1/1')) throw new Error('Status line missing agent count'); | |
| footer.stop(); | |
| console.log('✓ StatusFooter test passed'); | |
| " | |
| release-preflight: | |
| name: Release preflight | |
| if: | | |
| (github.event_name == 'pull_request' && github.base_ref == 'main') || | |
| (github.event_name == 'merge_group' && ( | |
| github.event.merge_group.base_ref == 'main' || | |
| github.event.merge_group.base_ref == 'refs/heads/main' || | |
| startsWith(github.ref, 'refs/heads/gh-readonly-queue/main/') | |
| )) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0 | |
| with: | |
| node-version: 22 | |
| cache: 'npm' | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Validate release contract | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: npm run release:preflight | |
| required: | |
| name: required | |
| if: ${{ always() }} | |
| needs: | |
| - check | |
| - install-matrix | |
| - release-preflight | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Require every applicable CI gate | |
| env: | |
| CHECK_RESULT: ${{ needs.check.result }} | |
| INSTALL_MATRIX_RESULT: ${{ needs.install-matrix.result }} | |
| RELEASE_PREFLIGHT_RESULT: ${{ needs.release-preflight.result }} | |
| run: | | |
| if [[ "$CHECK_RESULT" != "success" ]]; then | |
| echo "::error::check concluded with $CHECK_RESULT" | |
| exit 1 | |
| fi | |
| if [[ "$INSTALL_MATRIX_RESULT" != "success" ]]; then | |
| echo "::error::install-matrix concluded with $INSTALL_MATRIX_RESULT" | |
| exit 1 | |
| fi | |
| if [[ "$RELEASE_PREFLIGHT_RESULT" != "success" && "$RELEASE_PREFLIGHT_RESULT" != "skipped" ]]; then | |
| echo "::error::release-preflight concluded with $RELEASE_PREFLIGHT_RESULT" | |
| exit 1 | |
| fi |