Skip to content
Open
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
4 changes: 2 additions & 2 deletions .github/workflows/cd-publish-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ jobs:
if: |
github.event_name == 'workflow_dispatch' ||
startsWith(github.event.head_commit.message, 'chore: bump version to ')
runs-on: blacksmith-2vcpu-ubuntu-2404
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
fetch-depth: 1

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/cd-release-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ concurrency:

jobs:
create-release-pr:
runs-on: blacksmith-2vcpu-ubuntu-2404
runs-on: ubuntu-24.04
if: |
!contains(github.event.head_commit.message, '[skip-release]') &&
!contains(github.event.head_commit.message, 'chore: bump version')
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 0
Expand Down
195 changes: 35 additions & 160 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ on:
- ".codex/**"
- ".opencode/**"
push:
branches:
- main
branches: [main]
paths-ignore:
- "docs/**"
- "README.md"
Expand All @@ -26,187 +25,63 @@ concurrency:
cancel-in-progress: true

jobs:
stage-1-quality:
name: Stage 1 - Quality
if: github.event_name != 'pull_request' || !startsWith(github.head_ref, 'chore/bump-version-')
runs-on: blacksmith-2vcpu-ubuntu-2404
checks:
name: checks
runs-on: ubuntu-24.04
timeout-minutes: 20
env:
PUBLIC_CONVEX_URL: "https://example.convex.cloud"
PUBLIC_CONVEX_URL: "https://placeholder.convex.cloud"
steps:
- name: Checkout
uses: actions/checkout@v6

- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.11
uses: actions/checkout@v7

- name: Cache Bun + Turbo
uses: actions/cache@v5
with:
path: |
~/.bun/install/cache
.turbo
key: ${{ runner.os }}-bun-turbo-${{ hashFiles('**/bun.lock', '**/bun.lockb', 'package.json', 'apps/**/package.json', 'packages/**/package.json') }}
restore-keys: |
${{ runner.os }}-bun-turbo-
- name: Setup toolchain
uses: jdx/mise-action@v5

- name: Install dependencies
run: bun install --frozen-lockfile

- name: Ultracite check
run: bun x ultracite check

- name: Core manual inference tests
- name: Verify toolchain
run: |
bun test \
packages/backend/convex/manualInferenceLogic.test.ts \
apps/web/src/lib/capability.test.ts \
apps/web/src/lib/mappers.test.ts
node --version
bun --version
test "$(bun --version)" = "$(node -p "require('./package.json').packageManager.split('@')[1]")"

- name: Publish summary
if: always()
run: |
echo "## Stage 1 - Quality" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "- ultracite check" >> "$GITHUB_STEP_SUMMARY"
echo "- deterministic manual inference + mapping tests" >> "$GITHUB_STEP_SUMMARY"

stage-2-browser-qa:
name: Stage 2 - Browser QA
needs: stage-1-quality
if: github.event_name != 'pull_request' || !startsWith(github.head_ref, 'chore/bump-version-')
runs-on: blacksmith-2vcpu-ubuntu-2404
env:
PUBLIC_CONVEX_URL: "https://example.convex.cloud"
steps:
- name: Checkout
uses: actions/checkout@v6

- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.11

- name: Cache Bun + Turbo
uses: actions/cache@v5
- name: Cache dependencies and build
uses: actions/cache@v6
with:
path: |
~/.bun/install/cache
.turbo
key: ${{ runner.os }}-bun-turbo-${{ hashFiles('**/bun.lock', '**/bun.lockb', 'package.json', 'apps/**/package.json', 'packages/**/package.json') }}
restore-keys: |
${{ runner.os }}-bun-turbo-

- name: Cache Playwright browsers
uses: actions/cache@v5
with:
path: ~/.cache/ms-playwright
key: ${{ runner.os }}-playwright-${{ hashFiles('**/bun.lock', '**/bun.lockb', 'package.json', 'apps/**/package.json', 'packages/**/package.json') }}
restore-keys: |
${{ runner.os }}-playwright-
key: ${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('mise.toml', 'bun.lock') }}

- name: Install dependencies
run: bun install --frozen-lockfile

- name: Install agent-browser CLI
run: npm install -g agent-browser@latest

- name: Install Playwright Chromium
run: npx playwright install --with-deps chromium

- name: Run local browser QA smoke
run: bun run qa:browser

- name: Upload browser QA artifacts
if: always()
uses: actions/upload-artifact@v7
with:
name: browser-qa-local-${{ github.run_id }}-${{ github.run_attempt }}
path: artifacts/browser-qa/**
if-no-files-found: error

- name: Publish summary
if: always()
run: |
echo "## Stage 2 - Browser QA" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "- local agent-browser smoke flow" >> "$GITHUB_STEP_SUMMARY"
echo "- screenshots uploaded as workflow artifact" >> "$GITHUB_STEP_SUMMARY"
echo "- Browserbase replay runs on the preview-validation workflow" >> "$GITHUB_STEP_SUMMARY"

stage-3-build:
name: Stage 3 - Build
needs: stage-2-browser-qa
if: github.event_name != 'pull_request' || !startsWith(github.head_ref, 'chore/bump-version-')
runs-on: blacksmith-4vcpu-ubuntu-2404
env:
PUBLIC_CONVEX_URL: "https://example.convex.cloud"
steps:
- name: Checkout
uses: actions/checkout@v6

- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.11
- name: Lint
run: bun x ultracite check

- name: Cache Bun + Turbo
uses: actions/cache@v5
with:
path: |
~/.bun/install/cache
.turbo
key: ${{ runner.os }}-bun-turbo-${{ hashFiles('**/bun.lock', '**/bun.lockb', 'package.json', 'apps/**/package.json', 'packages/**/package.json') }}
restore-keys: |
${{ runner.os }}-bun-turbo-
- name: Types
run: bun run check-types

- name: Install dependencies
run: bun install --frozen-lockfile
- name: Unit tests
run: bun run test:unit

- name: Build
run: bun run build

- name: TUI compile smoke test
- name: TUI compile smoke
run: |
mkdir -p apps/tui/dist
bun build apps/tui/src/index.tsx --compile --outfile apps/tui/dist/cable-intel-tui
bun run --cwd apps/tui build:bin
./apps/tui/dist/cable-intel-tui --help

- name: Publish summary
if: always()
run: |
echo "## Stage 3 - Build" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "- workspace build" >> "$GITHUB_STEP_SUMMARY"
echo "- TUI compile smoke test" >> "$GITHUB_STEP_SUMMARY"
- name: Install browser
run: bunx --no-install agent-browser install --with-deps

checks:
name: checks
if: always()
needs:
- stage-1-quality
- stage-2-browser-qa
- stage-3-build
runs-on: blacksmith-2vcpu-ubuntu-2404
steps:
- name: Skip staged CI for automated release PRs
if: github.event_name == 'pull_request' && startsWith(github.head_ref, 'chore/bump-version-')
run: echo "Automated version-bump PR; staged CI is intentionally skipped."
- name: Browser smoke
run: bun run qa:browser -- --skip-build

- name: Finalize staged CI result
if: github.event_name != 'pull_request' || !startsWith(github.head_ref, 'chore/bump-version-')
run: |
if [ "${{ needs.stage-1-quality.result }}" != "success" ]; then
echo "Stage 1 failed."
exit 1
fi
if [ "${{ needs.stage-2-browser-qa.result }}" != "success" ]; then
echo "Stage 2 failed."
exit 1
fi
if [ "${{ needs.stage-3-build.result }}" != "success" ]; then
echo "Stage 3 failed."
exit 1
fi
echo "All CI stages passed."
- name: Upload browser evidence
if: always()
uses: actions/upload-artifact@v7
with:
name: browser-qa-local-${{ github.run_id }}-${{ github.run_attempt }}
path: artifacts/browser-qa/**
if-no-files-found: warn
2 changes: 1 addition & 1 deletion .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7

- name: Initialize CodeQL
uses: github/codeql-action/init@v4
Expand Down
50 changes: 16 additions & 34 deletions .github/workflows/org-required-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,43 +23,25 @@ jobs:
github.event_name == 'pull_request' ||
(github.event_name == 'deployment_status' && github.event.deployment_status.state == 'success')
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- name: Checkout
uses: actions/checkout@v7

- name: Wait for merge gates
uses: actions/github-script@v9
with:
script: |
const owner = context.repo.owner;
const repo = context.repo.repo;
let pr = context.payload.pull_request;
let pull_number;
let headSha;

if (pr) {
pull_number = pr.number;
headSha = pr.head.sha;
} else {
const deploymentStatus = context.payload.deployment_status;
const deploymentSha = deploymentStatus?.deployment?.sha;
if (!deploymentSha) {
core.info("No pull request or deployment SHA context. Passing check.");
return;
}

headSha = deploymentSha;
const associatedPrs = await github.rest.repos.listPullRequestsAssociatedWithCommit({
owner,
repo,
commit_sha: headSha,
});

pr =
associatedPrs.data.find((candidate) => candidate.state === "open") ?? null;
if (!pr) {
core.info(`No open pull request associated with SHA ${headSha}. Passing check.`);
return;
}
pull_number = pr.number;
const { resolveMergeGateContext } = await import(`${process.env.GITHUB_WORKSPACE}/scripts/ci/merge-gate-context.js`);
const resolved = await resolveMergeGateContext(context, github);
if (!resolved) {
core.info("No current open PR head associated with this deployment.");
return;
}
const { pullRequest: pr, headSha } = resolved;
const pull_number = pr.number;

const files = await github.paginate(github.rest.pulls.listFiles, {
owner,
Expand Down Expand Up @@ -119,14 +101,14 @@ jobs:
};

while (Date.now() < deadline) {
const [checkRunsResp, statusesResp] = await Promise.all([
github.rest.checks.listForRef({
const [checkRuns, statuses] = await Promise.all([
github.paginate(github.rest.checks.listForRef, {
owner,
repo,
ref: headSha,
per_page: 100,
}),
github.rest.repos.listCommitStatusesForRef({
github.paginate(github.rest.repos.listCommitStatusesForRef, {
owner,
repo,
ref: headSha,
Expand All @@ -135,14 +117,14 @@ jobs:
]);

const checkRunsByName = new Map();
for (const checkRun of checkRunsResp.data.check_runs) {
for (const checkRun of checkRuns) {
if (!checkRunsByName.has(checkRun.name)) {
checkRunsByName.set(checkRun.name, checkRun);
}
}

const statusesByContext = new Map();
for (const status of statusesResp.data) {
for (const status of statuses) {
if (!statusesByContext.has(status.context)) {
statusesByContext.set(status.context, status);
}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pr-auto-merge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
github.event.pull_request.draft == false &&
github.event.pull_request.base.ref == github.event.repository.default_branch &&
github.event.pull_request.head.repo.full_name == github.repository
runs-on: blacksmith-2vcpu-ubuntu-2404
runs-on: ubuntu-24.04
steps:
- name: Enable auto-merge
env:
Expand Down
Loading
Loading