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
85 changes: 53 additions & 32 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,50 @@
# Continuum CI — TypeScript clients gate
#
# ## What this replaced, and why it mattered
#
# This workflow used to run in `working-directory: src` against
# `src/package-lock.json`, calling `npm run build:ts` and `npm run test:crud`.
# Every one of those is gone: `src/` was the Node monolith, retired when the
# substrate became a headless Rust core (#1840), and both scripts left with it.
#
# So it failed on every run — last success 2026-06-07, red continuously from
# 2026-06-09 — with `Cannot find module 'dotenv'`, an error that describes the
# absence of the whole world it was pointed at rather than any defect in the
# code under test.
#
# A check that ALWAYS fails is worse than no check. It cannot distinguish a
# broken PR from a healthy one, so the only thing anyone can learn from it is to
# stop reading CI — which is exactly what happened: work routed around it
# through the Rust and drift-guard workflows for two months.
#
# ## What it does now
#
# Gates the TypeScript clients workspace — the one thing this file was always
# supposed to cover and had stopped being able to see.
#
# `npm run test:clients` was ALREADY in package.json and ALREADY passing
# locally. Nothing called it. That is how `renderBench.spec.ts` and six sibling
# spec files across `apps/web` and `packages/` came to exist, be green on a
# developer's machine, and gate nothing at all — a correct check that nothing
# invokes, which is indistinguishable from having no check until someone greps
# for the caller.
#
# Triggers on `canary` as well as `main`, because canary is where development
# happens; a gate that only watches the stable line learns about breakage after
# it has already been merged.

name: Continuum CI

on:
push:
branches: [ main ]
branches: [ main, canary ]
pull_request:
branches: [ main ]
branches: [ main, canary ]

jobs:
validate:
clients:
name: TypeScript clients (typecheck + tests)
runs-on: ubuntu-latest
defaults:
run:
working-directory: src

steps:
- uses: actions/checkout@v4
Expand All @@ -21,32 +54,20 @@ jobs:
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: src/package-lock.json
# Root lockfile — npm workspaces hoist, so there is exactly one.
cache-dependency-path: package-lock.json

- name: Install dependencies
# `npm ci` installs the whole workspace from the lockfile, which is what
# makes this job the substrate the tests stand on: without it, every spec
# file fails at COLLECTION with "Failed to load url @continuum/chat-view",
# an error that points a reader at missing source rather than missing deps.
- name: Install workspace
run: npm ci

- name: TypeScript compilation
run: |
npm run build:ts
echo "✅ TypeScript compilation passed"

# Skip full tests for documentation-only PRs
- name: Check if documentation-only PR
id: check_pr
working-directory: .
run: |
if git diff --name-only origin/main..HEAD | grep -qvE '\.(md|txt|yml|yaml)$'; then
echo "skip_tests=false" >> $GITHUB_OUTPUT
else
echo "skip_tests=true" >> $GITHUB_OUTPUT
fi

- name: Run tests
if: steps.check_pr.outputs.skip_tests != 'true'
run: |
npm run test:crud
echo "✅ CRUD tests passed"

- name: Validation complete
run: echo "✅ CI validation complete - local precommit hook validates full system"
- name: Typecheck clients
run: npm run typecheck:clients

# The suite that existed and was never run. Covers apps/web, apps/tui,
# the view packages, and the SDK.
- name: Test clients
run: npm run test:clients
58 changes: 58 additions & 0 deletions .github/workflows/plugin-version-guard.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Plugin version-bump guard.
#
# Why this exists: Claude Code plugin updates are VERSION-based, not
# content-based. A marketplace install copies the plugin to
# ~/.claude/plugins/cache/<marketplace>/<plugin>/<version>/ and pins it. `claude
# plugin update` compares the DECLARED version in plugin.json against the
# installed one and never looks at the files. So if scripts change and the
# version does not, every installed copy answers "already at the latest version"
# forever and the fix reaches nobody. `git pull` does not update a plugin.
#
# The failure this guards, measured 2026-08-09: memory-bridge sat at 0.1.0 since
# 2026-07-25 while its scripts gained a persona-id cache and an entire
# session-capture.sh. The installed copy on BigMama had NEITHER — automatic
# per-turn memory capture had never run once on that machine — while the repo
# held working code and the plugin README said the bridge was live. Bumping
# 0.1.0 -> 0.2.0 propagated two weeks of fixes in one command.
#
# Same class as the install-manifest projection guard and the ts-rs binding
# guard: a consumed artifact and its source must not drift apart in silence.
# Here the "artifact" is every developer's installed copy.
#
# NOTE: this runs in CI, not pre-commit. `.githooks/pre-commit` currently invokes
# tests deleted with the Node monolith and is not installed as the active hook
# (core.hooksPath does not point at it), so wiring a gate there would look
# enforced while running never.
name: Plugin Version Guard

on:
pull_request:
paths:
- 'tools/plugins/**'
- '.github/workflows/plugin-version-guard.yml'
push:
branches: [canary, main]

concurrency:
group: plugin-version-${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

jobs:
plugin-version:
name: plugin content changed => version bumped
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
with:
# Need the base commit to diff against, not just the tip.
fetch-depth: 0

- name: Check every touched plugin bumped its version
run: |
BASE="${{ github.event.pull_request.base.sha || github.event.before }}"
if [ -z "$BASE" ] || [ "$BASE" = "0000000000000000000000000000000000000000" ]; then
echo "no usable base ref (first push / new branch) — nothing to compare"
exit 0
fi
tools/scripts/check-plugin-version.sh "$BASE"
Loading
Loading