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
3 changes: 0 additions & 3 deletions .claude/skills/contributing-to-loopover/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,9 +241,6 @@ npm audit --audit-level=moderate # the dependency-review job's local eq
`command-reference:check`, `ui:lint`, `ui:typecheck`, `ui:test`, `ui:build`. If any step fails, fix it
and re-run — do not push a red tree. (Full per-check table in `reference.md`; check `package.json`'s
own `test:ci` script if this list and that script ever disagree — the script is the source of truth.)
One CI-gating exception `test:ci` does **not** run: the extension lint/typecheck checks
(`extension:lint`, `extension:typecheck`, `miner-extension:lint`, `miner-extension:typecheck`), gated in
CI's `validate-code` on `push || ui==true` — run them separately if you touch the VS Code / miner extensions.

If `ui:lint` fails on formatting, run `npm --workspace @loopover/ui run format`. If
`ui:openapi:check` fails, you forgot Phase 4's `ui:openapi`.
Expand Down
8 changes: 0 additions & 8 deletions .claude/skills/contributing-to-loopover/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,20 +96,12 @@ build && npm --workspace @loopover/ui run preview`, or `npm run ui:preview` from
builds everything first), to actually exercise the production build locally. `test/unit/loopover-ui-preview-script.test.ts`
regression-guards the script itself against reverting to `vite preview`.

| ui → extension lint | `eslint` (VS Code + miner extensions) | `npm run extension:lint && npm run miner-extension:lint` | extension ESLint error (same `push \|\| ui==true` trigger as the `ui →` rows) |
| ui → extension typecheck | `tsc --noEmit` (extensions) | `npm run extension:typecheck && npm run miner-extension:typecheck` | extension type error (same `push \|\| ui==true` trigger) |
| changes → dependency review (PR only) | dependency-review (moderate+; a step inside the `changes` job since 2026-07-24, not a separate job) | `npm audit --audit-level=moderate` | a **newly added** dep has a moderate+ advisory |

**One command for *almost* everything except the dependency review:** `npm run test:ci`. There is **no** CodeQL/Analyze
workflow in this repo. There is **no** root-level Prettier gate — Prettier is enforced only inside
`ui:lint` (so it only bites `apps/loopover-ui/**`).

**One CI-gating exception `test:ci` does NOT cover:** the four extension lint/typecheck checks
(`extension:lint`, `extension:typecheck`, `miner-extension:lint`, `miner-extension:typecheck`) run in CI's
`validate-code` job (gated on `push || ui==true`, the `ui →` rows above) but are **absent from the `test:ci`
chain** — so a green local `test:ci` does not exercise them. Run them separately (or rely on CI) if your
change touches `apps/loopover-extension/**` or `apps/loopover-miner-extension/**`.

**Local-only checks with no separate named CI status — `npm run test:ci` is the only thing that catches
these for a normal PR:**

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Two products, self-host-first:

- **AMS (Autonomous Miner System)** — `packages/loopover-miner` (npm: `@loopover/miner`) +
`packages/loopover-engine` (npm: `@loopover/engine`, shared core also used by ORB) +
`apps/loopover-miner-ui` + `apps/loopover-miner-extension`. The contributor/miner side: finds
`apps/loopover-miner-ui`. The contributor/miner side: finds
issues, plans, writes code, opens PRs, autonomously. Self-host (a local Miner Node) is the only
shipped deployment target; hosted AMS is a later phase (see "AMS/ORB Cloud Readiness" below).
- **ORB (Owner/One-shot Review Brain)** — `src/**` (the Worker app: `src/review`, `src/queue`,
Expand Down
4 changes: 2 additions & 2 deletions .github/actions/deploy-ui-preview/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ runs:
test -d client || { echo "::error::bundle missing client/ assets dir"; exit 1; }
# 3) Allowlist file extensions — fail on anything that isn't a normal web/build output (blocks
# smuggled scripts/binaries). A few extensionless CF asset files are explicitly permitted.
# `zip` covers the served downloads (e.g. /downloads/loopover-extension.zip) — a passive
# static asset wrangler only uploads (never executes), so allowing it doesn't run fork code.
# `zip` covers any served static download the app might publish under public/downloads/ — a
# passive static asset wrangler only uploads (never executes), so allowing it doesn't run fork code.
# `.nojekyll` is a zero-byte, purely-advisory host-compatibility marker the SSR build tooling
# (Nitro, TanStack Start's build layer) emits into client/ by default for broad static-host
# portability — no executable content, same risk profile as _headers/_redirects/.assetsignore
Expand Down
42 changes: 10 additions & 32 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -138,17 +138,13 @@ jobs:
observability:
- 'grafana/dashboards/**'
- 'prometheus/rules/**'
# The UI's own app/extension code -- triggers the FULL toolchain (lint/typecheck/test/build).
# The UI's own app code -- triggers the FULL toolchain (lint/typecheck/test/build).
# A dependency bump (package.json/package-lock.json) stays here too since it can break the UI
# build or types in ways only that full toolchain would catch.
ui:
- 'apps/loopover-ui/**'
- 'apps/loopover-miner-ui/**'
- 'apps/loopover-extension/**'
- 'apps/loopover-miner-extension/**'
- 'packages/loopover-ui-kit/**'
- 'scripts/build-extension.ts'
- 'scripts/build-miner-extension.ts'
- 'package.json'
- 'package-lock.json'
# Backend changes that can drift the OpenAPI contract the UI type-checks against, but say
Expand Down Expand Up @@ -448,7 +444,7 @@ jobs:
# The matching "Save Turborepo cache" step is NOT alongside this one -- it's moved all the way down
# to after "UI build" (the last step in this job that invokes turbo), since actions/cache/save takes
# one synchronous snapshot at the moment it runs and every later turbo-routed step in between (Build
# MCP, Build miner CLI, Build UI-kit package, UI lint/typecheck, Extension lint/typecheck, UI build)
# MCP, Build miner CLI, Build UI-kit package, UI lint/typecheck, UI build)
# would otherwise write to .turbo/cache AFTER the snapshot already happened, so none of their cache
# entries would ever persist cross-run. Confirmed this was a real gap (not just theoretical) by
# reading the actual step order before moving it.
Expand All @@ -459,7 +455,7 @@ jobs:
# shards) raced for the SAME cache key. actions/cache/save no-ops on a duplicate key within a run (see
# the comment on validate-tests' own Save step below), and a validate-tests shard reaches its Save
# step after only ~6 steps versus this job's ~20+, so a shard almost always won the race -- meaning
# the richer cache this job builds (engine + mcp + miner + ui-kit + ui + extension) was very likely
# the richer cache this job builds (engine + mcp + miner + ui-kit + ui) was very likely
# silently discarded in favor of a shard's much leaner engine-only save, defeating most of the point
# of the Save-repositioning fix above. Splitting the prefixes gives each job's Restore/Save pair its
# own independent lineage instead of racing.
Expand Down Expand Up @@ -729,7 +725,7 @@ jobs:
# docs, manifest, engine-parity, branding, .nvmrc, release-manifest, observability, the MCP
# version audit just above, ...) -- any ONE of those failing without continue-on-error otherwise
# skips every step after it by GitHub Actions' own default, INCLUDING this build. "UI tests
# (ui-miner)"/"UI tests (miner-extension)" already had this guard (see their own comment below);
# (ui-miner)" already had this guard (see its own comment below);
# this build step and everything through "UI tests (ui)" didn't, so a same-day MCP release
# tripping the version-audit step above skipped ui-kit's build entirely, and ui-miner's tests
# (which DID still run, guarded) then failed with a confusing "Failed to resolve import
Expand Down Expand Up @@ -773,8 +769,8 @@ jobs:
# task for any package (per the plan doc: test orchestration stays out of Turborepo entirely, so
# Codecov's codecov/patch keeps one centralized source of truth), so this can't use the same
# union-`--filter` fix already applied to "UI lint"/"UI typecheck" two steps above. Plain `&&` meant a
# failing @loopover/ui test silently prevented @loopover/ui-miner's and @loopover/miner-extension's
# tests from ever running in that invocation -- same class of failure-masking bug those two steps'
# failing @loopover/ui test silently prevented @loopover/ui-miner's tests from ever running in that
# invocation -- same class of failure-masking bug those two steps'
# own comment already describes, just still present here. `!cancelled()` on all 3 (not `always()`)
# matches the pattern already used by "Save Turborepo cache"/"Save TypeScript incremental build
# cache" elsewhere in this file: still run after an earlier step's failure, just not after the job
Expand All @@ -785,38 +781,20 @@ jobs:
- name: UI tests (ui-miner)
if: ${{ !cancelled() && (github.event_name == 'push' || needs.changes.outputs.ui == 'true') }}
run: npm --workspace @loopover/ui-miner run test
- name: UI tests (miner-extension)
if: ${{ !cancelled() && (github.event_name == 'push' || needs.changes.outputs.ui == 'true') }}
run: npm --workspace @loopover/miner-extension run test
# Same rationale and --filter union semantics as "UI lint"/"UI typecheck" above -- and the same
# `!cancelled()` need as "Build UI-kit package" through "UI tests (ui)" above: an earlier
# unrelated step failing (a drift check, the MCP version audit) would otherwise skip these too,
# silently hiding real Extension lint/typecheck results behind it.
- name: Extension lint
if: ${{ !cancelled() && (github.event_name == 'push' || needs.changes.outputs.ui == 'true') }}
run: npx turbo run lint --filter=@loopover/extension --filter=@loopover/miner-extension
- name: Extension typecheck
if: ${{ !cancelled() && (github.event_name == 'push' || needs.changes.outputs.ui == 'true') }}
run: npx turbo run typecheck --filter=@loopover/extension --filter=@loopover/miner-extension
# `npm run ui:build` also regenerates apps/loopover-ui/public/openapi.json (needed for a
# standalone build), but this step's trigger condition is a strict subset of "OpenAPI drift
# check" above (push || ui==true, vs. push || ui==true || uiContract==true), so whenever this
# step runs, that check already ran and passed in this same job -- the committed spec is
# already byte-identical to what regenerating it here would produce. apps/loopover-ui's own
# `build` script (vite build) doesn't touch openapi.json either, so routing through Turborepo
# preserves that skip: @loopover/ui#build's dependsOn (turbo.json) is
# ["^build", "@loopover/extension#build", "@loopover/miner-extension#build"] -- the exact same
# extension + miner-extension build pair this step ran explicitly before, now resolved by turbo's
# own graph instead of hand-chained `&&`, plus ^build (ui-kit, already a same-job cache hit from
# "Build UI-kit package" above). Verified locally: deleting the committed-gitignored extension zip
# and running this exact invocation regenerates it correctly (the cross-package outputs edge is
# honored, not just replayed from cache).
# preserves that skip: @loopover/ui#build's dependsOn (turbo.json) is just ["^build"] (ui-kit,
# already a same-job cache hit from "Build UI-kit package" above).
- name: UI build
if: ${{ !cancelled() && (github.event_name == 'push' || needs.changes.outputs.ui == 'true') }}
run: npx turbo run build --filter=@loopover/ui
# Paired with "Restore Turborepo cache" above (same key, same gate condition) -- deliberately
# positioned here, after every turbo-routed step in this job (Build engine package, Build MCP, Build
# miner CLI, Build UI-kit package, UI lint/typecheck, Extension lint/typecheck, UI build), rather than
# miner CLI, Build UI-kit package, UI lint/typecheck, UI build), rather than
# immediately after "Build engine package" the way it was originally: actions/cache/save takes one
# synchronous snapshot at the moment it runs, so anything written to .turbo/cache by a later step
# would never be captured if this ran earlier. `!cancelled()` (not `always()`) still saves whatever
Expand Down Expand Up @@ -896,7 +874,7 @@ jobs:
# actions/cache/save no-ops on a duplicate key within a run -- see the shard-vs-shard version of that
# same race below. Because a shard reaches its own Save after only ~6 steps versus validate-code's
# ~20+, a shard almost always won that race, meaning validate-code's much richer cache (engine + mcp +
# miner + ui-kit + ui + extension) was very likely discarded every run in favor of a shard's
# miner + ui-kit + ui) was very likely discarded every run in favor of a shard's
# engine-only one. Splitting the prefixes gives each job's own lineage instead of racing; within THIS
# prefix, the 6 shards below still race each other for one slot, which is fine since they all save the
# exact same content (engine + mcp + miner builds all run in this job) -- whichever shard wins, the
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ui-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,4 @@ jobs:
- name: Validate frontend
env:
VITE_LOOPOVER_API_ORIGIN: https://api.loopover.ai
run: npm run ui:openapi:check && npm run ui:lint && npm run ui:typecheck && npm run extension:lint && npm run miner-extension:lint && npm run extension:typecheck && npm run miner-extension:typecheck && npm run extension:build && npm run miner-extension:build && npm --workspace @loopover/ui run build
run: npm run ui:openapi:check && npm run ui:lint && npm run ui:typecheck && npm --workspace @loopover/ui run build
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ coverage/
*.tsbuildinfo
site/.vitepress/cache/
!migrations/*.sql
apps/loopover-ui/public/downloads/loopover-extension.zip
.worker-configuration.gen-check.d.ts
# Ad-hoc operator backup files (e.g. `cp file.yml file.yml.bak-notes-20260707`) -- general
# catch-alls so a stray manual snapshot never dirties `git status` on a Git-backed self-host
Expand Down
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ Every PR should include:
- A link to a currently open issue this PR resolves (e.g. `Closes #123`) — there is no exemption
for explaining why an issue isn't needed.
- The exact validation commands run from the repo root.
- JPG/JPEG or PNG screenshot evidence for visible UI, frontend, docs, or extension changes,
- JPG/JPEG or PNG screenshot evidence for visible UI, frontend, or docs changes,
attached in the PR description as organized, captioned, clickable thumbnails. SVG screenshots
are not accepted as review evidence. Recordings/GIFs are supplemental to (never a replacement
for) static screenshots for anything a still image CAN show — but for an effect a static image
Expand Down Expand Up @@ -323,7 +323,7 @@ docs(contributing): clarify review gates
```

Use one of these types: `feat`, `fix`, `test`, `docs`, `refactor`, `build`, `ci`, `chore`, or
`revert`. Keep the scope lowercase and specific, such as `api`, `ui`, `mcp`, `extension`, `auth`,
`revert`. Keep the scope lowercase and specific, such as `api`, `ui`, `mcp`, `auth`,
`github`, `signals`, `data`, `docs`, or `release`. Avoid vague scopes or summaries such as
`misc`, `general`, `updates`, `update stuff`, or `small tweaks`. Do not end PR titles with a
trailing period. Release PR titles must use `chore(release): <version>`.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ See [Tuning your reviews](https://loopover.ai/docs/tuning) for the full flag, se
| Miner package | [`@loopover/miner`](packages/loopover-miner/README.md) — local foundation CLI for the autonomous miner runtime |
| API | [API browser](https://loopover.ai/api) and [OpenAPI JSON](https://api.loopover.ai/openapi.json) |
| GitHub App | [Setup docs](https://loopover.ai/docs/github-app) — self-hosting is the only currently available path |
| Browser extension | [Extension page](https://loopover.ai/extension) |

## MCP Install

Expand Down
1 change: 0 additions & 1 deletion apps/loopover-extension/.gitignore

This file was deleted.

Loading
Loading