fix(miner): delegate three resolve*DbPath helpers to resolveLocalStoreDbPath (#8336) #3399
Workflow file for this run
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: UI Preview Build | |
| # Per-PR preview pipeline, split by trust (reshaped 2026-07-24 — one fewer runner slot per same-repo | |
| # UI push, which is nearly every UI push at this repo's volume): | |
| # | |
| # SAME-REPO PRs (`build-deploy`): a branch in this repo implies a collaborator, and same-repo | |
| # pull_request runs get secrets — so ONE job builds and deploys inline via the shared | |
| # .github/actions/deploy-ui-preview composite. No artifact hop, no second runner, and the | |
| # workflow_run deploy job below skips runner-free. | |
| # | |
| # FORK PRs (`build`): unchanged two-stage boundary. The build runs fork code with NO secrets (fork | |
| # PRs get a read-only token) and only produces the built `dist` artifact; the trusted | |
| # `ui-preview-deploy.yml` (workflow_run) then deploys that artifact WITH secrets and records the | |
| # GitHub Deployment that Reviewbot reads for the "after" screenshot. Building runs the PR's | |
| # (possibly fork-authored) code — doing that with no secret access, and deploying the resulting | |
| # bundle in a separate trusted step that never executes fork code, is the standard way to give fork | |
| # PRs previews without exposing Cloudflare credentials to untrusted code. Do NOT collapse the fork | |
| # path into build-deploy: that boundary is the entire security model. | |
| on: | |
| pull_request: | |
| # Explicit list because the default (opened/synchronize/reopened) omits ready_for_review -- once the | |
| # build jobs below skip draft PRs, marking a PR ready must itself trigger a real preview build (#6670), | |
| # not wait for the next push. Mirrors ci.yml's pull_request.types comment/list exactly. | |
| types: [opened, synchronize, reopened, ready_for_review] | |
| # Scoped to exactly what apps/loopover-ui actually depends on (packages/loopover-ui-kit only) -- | |
| # NOT the whole "packages/**" workspace, which also matches loopover-miner/loopover-mcp/loopover-engine/ | |
| # discovery-index and previously built+deployed a pointless preview for every PR touching those (#ci-scope). | |
| # This check isn't required (see branch protection), so a future package apps/loopover-ui starts | |
| # depending on that isn't added here will silently stop getting previews rather than failing loud -- | |
| # keep this list in sync with what apps/loopover-ui/package.json actually imports. | |
| paths: | |
| - "apps/loopover-ui/**" | |
| - "packages/loopover-ui-kit/**" | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: ui-preview-build-${{ github.event.pull_request.number }} | |
| cancel-in-progress: true | |
| jobs: | |
| # ------------------------- SAME-REPO: build + deploy in one runner ------------------------- | |
| build-deploy: | |
| name: Build UI preview artifact | |
| # Same-repo only (fork PRs take the `build` job below). Skip draft PRs (#6670, anti-abuse): a full | |
| # npm ci + UI build on every push, including a force-push, to a PR nobody has marked ready yet. | |
| if: ${{ github.event.pull_request.draft != true && github.event.pull_request.head.repo.fork != true }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| permissions: | |
| contents: read | |
| deployments: write # record the preview Deployment Reviewbot reads | |
| # Same environment binding as ui-preview-deploy.yml's job: the org can attach approval gating | |
| # and/or environment-scoped secrets to every path that holds Cloudflare credentials. | |
| environment: | |
| name: preview | |
| url: ${{ steps.deploy.outputs.preview_url }} | |
| steps: | |
| - name: Checkout PR head | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 | |
| with: | |
| ref: ${{ github.event.pull_request.head.sha }} | |
| persist-credentials: false | |
| - name: Setup Node | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7 | |
| with: | |
| node-version-file: .nvmrc | |
| cache: npm | |
| - name: Install dependencies | |
| run: npm ci | |
| # Same steps as the root `ui:build` script, except the last one: that script also builds | |
| # @loopover/ui-miner (`npm --workspace @loopover/ui-miner run build`), a full separate Vite app | |
| # this workflow never uploads or deploys -- every UI PR was paying for that build and throwing | |
| # away the result. `npx turbo run build --filter=@loopover/ui` replaces the last two `ui:build` | |
| # steps (`extension:build && miner-extension:build && ui build` already covered by | |
| # @loopover/ui#build's own turbo.json dependsOn) and skips ui-miner entirely. | |
| - name: Build UI | |
| env: | |
| VITE_LOOPOVER_API_ORIGIN: https://api.loopover.ai | |
| # Preview-only: enables the synthetic demo session (useSession().signInPreview) so reviewbot can | |
| # screenshot the authenticated /app/* dashboard via ?preview=1 instead of the sign-in wall. The | |
| # production build (ui-deploy.yml) does NOT set this, so the escape hatch is dead-code-eliminated | |
| # from prod. (#authed-route-preview) | |
| VITE_PREVIEW: "1" | |
| run: npm run ui:kit:build && npx turbo run build --filter=@loopover/engine && npm run ui:openapi && npx turbo run build --filter=@loopover/ui | |
| # Deploys stay best-effort when the Cloudflare secrets aren't configured (Reviewbot shows | |
| # before-only) — mirrors ui-preview-deploy.yml's guard. | |
| - name: Check Cloudflare secrets | |
| id: cfg | |
| env: | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | |
| run: | | |
| if [ -n "$CLOUDFLARE_API_TOKEN" ] && [ -n "$CLOUDFLARE_ACCOUNT_ID" ]; then | |
| echo "ready=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "ready=false" >> "$GITHUB_OUTPUT" | |
| echo "::notice::CLOUDFLARE_API_TOKEN / CLOUDFLARE_ACCOUNT_ID not set — skipping preview deploy (Reviewbot shows before-only)." | |
| fi | |
| - name: Deploy preview | |
| id: deploy | |
| if: ${{ steps.cfg.outputs.ready == 'true' }} | |
| uses: ./.github/actions/deploy-ui-preview | |
| with: | |
| pr-number: ${{ github.event.pull_request.number }} | |
| # GitHub-set; the same value the checkout above pinned. | |
| head-sha: ${{ github.event.pull_request.head.sha }} | |
| dist-dir: apps/loopover-ui/dist | |
| cloudflare-api-token: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| cloudflare-account-id: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Record FAILED deployment for Reviewbot | |
| # A deploy was attempted but never produced a preview (build-side failures skip this via the | |
| # cfg gate ordering: cfg only runs after a successful build). Record a `failure` | |
| # deployment_status so Reviewbot flips the "after" cell from an eternal spinner to a terminal | |
| # "preview deploy failed" card. Gated on CF creds so a credential-less skip records nothing. | |
| if: ${{ failure() && steps.cfg.outputs.ready == 'true' }} | |
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | |
| with: | |
| script: | | |
| const sha = context.payload.pull_request.head.sha; // GitHub-set; never fork-supplied | |
| const prNumber = context.payload.pull_request.number; | |
| const deployment = await github.rest.repos.createDeployment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| ref: sha, | |
| environment: `preview/pr-${prNumber}`, | |
| auto_merge: false, | |
| required_contexts: [], | |
| transient_environment: true, | |
| description: "LoopOver UI preview (failed)", | |
| payload: JSON.stringify({ pr: prNumber, head_sha: sha }), | |
| }); | |
| await github.rest.repos.createDeploymentStatus({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| deployment_id: deployment.data.id, | |
| state: "failure", | |
| environment: `preview/pr-${prNumber}`, | |
| description: "Preview deploy failed", | |
| }); | |
| core.notice(`Recorded FAILED preview deployment for PR #${prNumber}.`); | |
| # ------------------------- FORK: unprivileged build half only ------------------------- | |
| build: | |
| name: Build UI preview artifact (fork) | |
| # Fork PRs only — no secrets here, ever (see the file header). Draft guard as above. | |
| if: ${{ github.event.pull_request.draft != true && github.event.pull_request.head.repo.fork == true }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - name: Checkout PR head | |
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 | |
| with: | |
| ref: ${{ github.event.pull_request.head.sha }} | |
| persist-credentials: false | |
| - name: Setup Node | |
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7 | |
| with: | |
| node-version-file: .nvmrc | |
| cache: npm | |
| - name: Install dependencies | |
| run: npm ci | |
| # Same build as build-deploy above — see its comment for the turbo-filter rationale. | |
| - name: Build UI | |
| env: | |
| VITE_LOOPOVER_API_ORIGIN: https://api.loopover.ai | |
| VITE_PREVIEW: "1" | |
| run: npm run ui:kit:build && npx turbo run build --filter=@loopover/engine && npm run ui:openapi && npx turbo run build --filter=@loopover/ui | |
| # The trusted deploy workflow downloads this by name + run-id. It contains only the built bundle | |
| # (server/ + client/) — no secrets, no source needed downstream. | |
| - name: Upload built UI artifact | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: ui-preview-dist | |
| path: apps/loopover-ui/dist | |
| if-no-files-found: error | |
| retention-days: 1 |