Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
8f7ff77
fix: Add ESLint 9 flat config + fix per-package lint scripts (sv-ei2)
ThePlenkov Aug 9, 2026
8313ba7
refactor: decouple Gas City harness into reusable sverka-gc-pack
ThePlenkov Aug 10, 2026
b9dee14
ci: migrate to oxlint + biome + husky
ThePlenkov Aug 10, 2026
3f0f13a
ci: add GitHub Actions CI workflow
ThePlenkov Aug 10, 2026
6f1fac0
fix(ci): format package.json files + exclude .claude/ from biome
ThePlenkov Aug 10, 2026
14d93ff
fix(compiler-gitlab): fix invalid regex flag in compile.test.ts
ThePlenkov Aug 10, 2026
148fb8d
feat(pack): add merge-stack formula + skill with /act loop and retros…
ThePlenkov Aug 10, 2026
053fb4a
fix(watchdog): handle transient gc status lookup timeouts
ThePlenkov Aug 10, 2026
a12f173
fix(merge-stack): reverse to TOP-DOWN merge order
ThePlenkov Aug 10, 2026
64977e7
fix(ci): address PR #22 review feedback
ThePlenkov Aug 10, 2026
e95d44a
fix(codacy): add .codacy.yml to configure quality gate
ThePlenkov Aug 10, 2026
6619a40
fix(sonar): add sonar-project.properties + SonarCloud CI job
ThePlenkov Aug 10, 2026
59fe223
feat(ci): add CodeQL analysis job
ThePlenkov Aug 10, 2026
bc0f05d
fix(ci): remove duplicate SonarCloud workflow job
ThePlenkov Aug 10, 2026
77c30f2
fix(ci): CodeQL continue-on-error for private repos
ThePlenkov Aug 10, 2026
a97ccda
fix(codeql): use SARIF-to-annotations instead of Security tab upload
ThePlenkov Aug 10, 2026
b5bc5b0
feat(ci): add Nx caching — GitHub Actions cache + Nx Cloud
ThePlenkov Aug 10, 2026
19d5a75
fix(sonar): simplify exclusions to single-line, remove conflicting so…
ThePlenkov Aug 10, 2026
bce28f0
fix(nx): remove invalid Nx Cloud token, simplify sonar exclusions
ThePlenkov Aug 10, 2026
90c8780
fix(sonar): exclude config files from analysis, fix execSync security…
ThePlenkov Aug 10, 2026
990ca25
fix(nx): remove nxCloudAccessToken, expand sonar exclusions
ThePlenkov Aug 10, 2026
f9dcaac
refactor(checks): generate Node resolver table entries to reduce dupl…
ThePlenkov Aug 10, 2026
6e60c79
ci: add Nx Cloud self-healing fix-ci step
ThePlenkov Aug 10, 2026
54c5a64
fix(ci): resolve SonarCloud security vulnerabilities + warnings
ThePlenkov Aug 10, 2026
ad139a1
fix: address all 16 CodeRabbit review threads on PR #22
ThePlenkov Aug 11, 2026
5896b03
fix: apply biome formatting and resolve CodeRabbit markdown/thread fi…
devin-ai-integration[bot] Aug 11, 2026
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
54 changes: 43 additions & 11 deletions .agents/skills/gc-watchdog/watchdog.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,31 @@
# Usage: bash watchdog.sh [interval_seconds]
# Default interval: 60 seconds.

set -euo pipefail
# NOTE: intentionally NOT using set -e. gc status and bd list can fail
# transiently (session snapshot timeouts, store locks). We handle errors
# per-command and continue the loop.
set -uo pipefail

INTERVAL="${1:-60}"
ITER=0

# Filter out ephemeral wisp/nudge beads from bd output.
# Real issues have IDs like sv-XXXX (4 chars after sv-).
# Wisp/nudge beads have IDs like sv-wisp-XXXX or sv-nudge-XXXX.
# Status symbols: ○ = open, ◐ = in_progress, ● = blocked, ✓ = closed
count_real_issues() {
local status="$1"
bd list --status="$status" 2>/dev/null \
| grep -E '^\s*○ sv-[a-z0-9]{4} ' \
| grep -v "wisp\|nudge" \
| wc -l || true
local count
if ! count=$(
bd list --status="$status" 2>/dev/null \
| grep -E '^\s*[○◐●] sv-[a-z0-9]{4} ' \
| grep -v "wisp\|nudge" \
| wc -l 2>/dev/null
); then
printf '0\n'
return 0
fi
printf '%s\n' "$count"
}

while true; do
Expand All @@ -40,7 +51,12 @@ while true; do
MAYOR=$(echo "$STATUS" | grep "harness.mayor" | awk '{print $2}')
SESSIONS=$(echo "$STATUS" | grep "Sessions:" | head -1 | sed 's/^ *//')
SUSPENDED=$(echo "$STATUS" | grep "Suspended:" | awk '{print $2}')
CONTROLLER=$(echo "$STATUS" | grep "Controller:" | grep -o "supervisor-managed\|stopped\|error" | head -1)
CONTROLLER=$(echo "$STATUS" | grep "Controller:" | grep -o "supervisor-managed\|stopped\|error" | head -1 || true)

# Handle transient lookup errors (mayor shows "lookup" instead of "awake")
if echo "$MAYOR" | grep -q "lookup"; then
MAYOR="lookup-error"
fi
Comment thread
coderabbitai[bot] marked this conversation as resolved.

# 2. bd work counts
OPEN_COUNT=$(count_real_issues "open")
Expand All @@ -49,18 +65,34 @@ while true; do
# 3. Check for issues
ISSUES=""
[ -z "$MAYOR" ] && ISSUES="$ISSUES MAYOR_MISSING"
{ [ -n "$MAYOR" ] && echo "$MAYOR" | grep -qvE "awake|running|active"; } && ISSUES="$ISSUES MAYOR($MAYOR)"
[ "$SUSPENDED" != "no" ] && ISSUES="$ISSUES SUSPENDED"
[ "$CONTROLLER" != "supervisor-managed" ] && ISSUES="$ISSUES CONTROLLER($CONTROLLER)"
if [ -n "$MAYOR" ] && [ "$MAYOR" != "awake" ] && [ "$MAYOR" != "running" ] && [ "$MAYOR" != "active" ] && [ "$MAYOR" != "lookup-error" ]; then
ISSUES="$ISSUES MAYOR($MAYOR)"
fi
# lookup-error is a transient issue, not a hard failure — report as ⚠ but don't treat as fatal
if [ "$MAYOR" = "lookup-error" ]; then
ISSUES="$ISSUES MAYOR_LOOKUP_TIMEOUT"
fi
# Treat missing status fields as unknown, not healthy defaults
if [ -z "${SUSPENDED:-}" ]; then
ISSUES="$ISSUES SUSPENDED_MISSING"
elif [ "$SUSPENDED" != "no" ]; then
ISSUES="$ISSUES SUSPENDED"
fi
if [ -z "${CONTROLLER:-}" ]; then
ISSUES="$ISSUES CONTROLLER_MISSING"
elif [ "$CONTROLLER" != "supervisor-managed" ]; then
ISSUES="$ISSUES CONTROLLER($CONTROLLER)"
fi

# 4. Report
if [ -n "$ISSUES" ]; then
echo "[$TS] #$ITER ⚠$ISSUES | open:$OPEN_COUNT in_progress:$INPROG_COUNT | $SESSIONS"
echo "[$TS] #$ITER ⚠$ISSUES | open:$OPEN_COUNT in_progress:$INPROG_COUNT | ${SESSIONS:-no-sessions}"
else
echo "[$TS] #$ITER ✓ mayor:$MAYOR | open:$OPEN_COUNT in_progress:$INPROG_COUNT | $SESSIONS"
echo "[$TS] #$ITER ✓ mayor:$MAYOR | open:$OPEN_COUNT in_progress:$INPROG_COUNT | ${SESSIONS:-no-sessions}"
fi

# 5. Exit condition: no open AND no in-progress real work, mayor healthy
# Note: lookup-error is transient, don't exit on it — only exit on clean idle
if [ "$OPEN_COUNT" -eq 0 ] && [ "$INPROG_COUNT" -eq 0 ] && [ -z "$ISSUES" ]; then
echo "[$TS] #$ITER IDLE — no open work, no in-progress work. Watchdog exiting."
exit 0
Expand Down
141 changes: 7 additions & 134 deletions .codacy.yml
Original file line number Diff line number Diff line change
@@ -1,151 +1,24 @@
---
# Codacy configuration — focus on real issues, exclude noise
# Codacy configuration file
# https://docs.codacy.com/repositories-configure/codacy-configuration-file/

# Exclude non-source paths from analysis
exclude_paths:
- "**/*.md"
- "**/*.json"
- "**/*.toml"
- "**/*.yml"
- "**/*.yaml"
- "**/*.config.ts"
- "**/tsdown.config.ts"
- "**/vitest.config.ts"
- "**/__tests__/**"
- "**/*.test.ts"
- "**/*.test.tsx"
- "**/*.spec.ts"
- "pack/**"
- ".agents/**"
- ".gc/**"
- ".husky/**"
- ".devin/**"
- ".beads/**"
- ".evidence/**"
- ".nx/**"
- "website/**"
- "engdocs/**"
- "specs/**"
- "skills/**"
- "template-fragments/**"
- "dist/**"
- "node_modules/**"
- "**/*.md"
- "**/*.json"
- "**/*.toml"

# Configure tools
engines:
# ESLint v9 — disable rules inappropriate for Node 24 / Bun / TypeScript project
# Use eslint-9 (matches our oxlint migration, Codacy's eslint for TS/JS)
eslint-9:
enabled: true
disable_rules:
# eslint-plugin-es-x: forbids ES2015+ syntax (arrow functions, const, import, etc.)
# Completely irrelevant for a modern TypeScript project targeting Node 24+
- ESLint9_es-x_no-arrow-functions
- ESLint9_es-x_no-modules
- ESLint9_es-x_no-block-scoped-variables
- ESLint9_es-x_no-trailing-commas
- ESLint9_es-x_no-template-literals
- ESLint9_es-x_no-classes
- ESLint9_es-x_no-default-parameters
- ESLint9_es-x_no-destructuring
- ESLint9_es-x_no-rest-spread-properties
- ESLint9_es-x_no-spread-elements
- ESLint9_es-x_no-async-functions
- ESLint9_es-x_no-generators
- ESLint9_es-x_no-for-of-loops
- ESLint9_es-x_no-exponential-operators
- ESLint9_es-x_no-promise-objects
- ESLint9_es-x_no-symbol
- ESLint9_es-x_no-map
- ESLint9_es-x_no-set
- ESLint9_es-x_no-weak-map
- ESLint9_es-x_no-weak-set
- ESLint9_es-x_no-proxy
- ESLint9_es-x_no-reflect
- ESLint9_es-x_no-binary-numeric-literals
- ESLint9_es-x_no-octal-numeric-literals
- ESLint9_es-x_no-regex-u-flag
- ESLint9_es-x_no-regex-y-flag
- ESLint9_es-x_no-unicode-codepoint-escapes
- ESLint9_es-x_no-object-super-properties
- ESLint9_es-x_no-array-prototype-copywithin
- ESLint9_es-x_no-array-prototype-fill
- ESLint9_es-x_no-array-prototype-find
- ESLint9_es-x_no-array-prototype-findindex
- ESLint9_es-x_no-array-prototype-flat
- ESLint9_es-x_no-array-prototype-flatmap
- ESLint9_es-x_no-array-prototype-includes
- ESLint9_es-x_no-array-prototype-keys
- ESLint9_es-x_no-array-prototype-values
- ESLint9_es-x_no-array-prototype-entries
- ESLint9_es-x_no-string-prototype-at
- ESLint9_es-x_no-string-prototype-codepoint-at
- ESLint9_es-x_no-string-prototype-ends-with
- ESLint9_es-x_no-string-prototype-includes
- ESLint9_es-x_no-string-prototype-match-all
- ESLint9_es-x_no-string-prototype-pad-end
- ESLint9_es-x_no-string-prototype-pad-start
- ESLint9_es-x_no-string-prototype-repeat
- ESLint9_es-x_no-string-prototype-starts-with
- ESLint9_es-x_no-string-prototype-trim
- ESLint9_es-x_no-string-prototype-trimstart
- ESLint9_es-x_no-string-prototype-trimend
- ESLint9_es-x_no-string-raw
- ESLint9_es-x_no-number-constructor
- ESLint9_es-x_no-number-isfinite
- ESLint9_es-x_no-number-isinteger
- ESLint9_es-x_no-number-isnan
- ESLint9_es-x_no-number-issafeinteger
- ESLint9_es-x_no-number-max-safe-integer
- ESLint9_es-x_no-number-min-safe-integer
- ESLint9_es-x_no-number-epsilon
- ESLint9_es-x_no-number-parse-float
- ESLint9_es-x_no-number-parse-integer
- ESLint9_es-x_no-math-acosh
- ESLint9_es-x_no-math-asinh
- ESLint9_es-x_no-math-atanh
- ESLint9_es-x_no-math-cbrt
- ESLint9_es-x_no-math-clz32
- ESLint9_es-x_no-math-cosh
- ESLint9_es-x_no-math-expm1
- ESLint9_es-x_no-math-fround
- ESLint9_es-x_no-math-hypot
- ESLint9_es-x_no-math-imul
- ESLint9_es-x_no-math-log10
- ESLint9_es-x_no-math-log1p
- ESLint9_es-x_no-math-log2
- ESLint9_es-x_no-math-sign
- ESLint9_es-x_no-math-sinh
- ESLint9_es-x_no-math-tanh
- ESLint9_es-x_no-object-assign
- ESLint9_es-x_no-object-is
- ESLint9_es-x_no-object-entries
- ESLint9_es-x_no-object-fromentries
- ESLint9_es-x_no-object-getownpropertydescriptors
- ESLint9_es-x_no-object-values
- ESLint9_es-x_no-object-keys
- ESLint9_es-x_no-object-define-property
- ESLint9_es-x_no-object-define-properties
- ESLint9_es-x_no-object-create
- ESLint9_es-x_no-object-get-prototype-of
- ESLint9_es-x_no-object-set-prototype-of
- ESLint9_es-x_no-date-prototype-to-primitive
- ESLint9_es-x_no-symbol-prototype-description
- ESLint9_es-x_no-intl
- ESLint9_es-x_no-atomics
- ESLint9_es-x_no-shared-array-buffer

# Markdown linter — disable noisy rules
markdownlint:
# Enable biome for formatting checks (matches our biome.json)
biome:
enabled: true
disable_rules:
- MD034 # Bare URL used
- MD024 # Multiple headings with same content
- MD025 # Multiple top-level headings
- MD036 # Emphasis used instead of a heading
- MD041 # First line in a file should be a top-level heading

# Disable analysis of markdown files (we only care about code)
languages:
markdown:
enabled: false
20 changes: 20 additions & 0 deletions .github/codeql/codeql-config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: "Sverka CodeQL Config"

# Exclude non-source paths from CodeQL analysis
paths:
- packages
paths-ignore:
- packages/*/dist/**
- "**/node_modules/**"
- "**/__tests__/**"
- "**/*.test.ts"
- pack/**
- .agents/**
- .gc/**
- website/**
- engdocs/**
- specs/**

# Query suite: security-extended (set in workflow)
queries:
- uses: security-extended
126 changes: 126 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
name: CI

on:
pull_request:
branches: ["**"]
push:
branches: [main]

# Cancel in-progress runs for the same ref (saves CI minutes).
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

jobs:
build-test-lint:
name: Build, Test, Lint, Typecheck
runs-on: ubuntu-24.04
timeout-minutes: 10
permissions:
contents: read

steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
fetch-depth: 0 # Nx needs full history for affected detection
Comment thread
coderabbitai[bot] marked this conversation as resolved.
persist-credentials: false

- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: "1.3.14"

- name: Setup Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: "24"

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

- name: Restore Nx cache
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: .nx/cache
key: nx-${{ runner.os }}-${{ hashFiles('**/package.json', '**/tsconfig.json', '**/src/**') }}
restore-keys: |
nx-${{ runner.os }}-

- name: Format check
run: bun run format:check

- name: Lint (oxlint)
run: bun run lint

- name: Typecheck
run: bun run typecheck

- name: Build
run: bun run build

- name: Test
run: bun run test

# Nx Cloud self-healing CI: auto-applies fixes for failed CI tasks.
# Requires the NX_CLOUD_ACCESS_TOKEN repo secret to be set.
# continue-on-error so the gate stays green before the secret is configured.
- name: Nx fix-ci (self-healing)
if: always()
continue-on-error: true
env:
NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}
run: bunx nx@21.0.0 fix-ci

- name: Upload build artifacts
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: dist
path: packages/*/dist/
if-no-files-found: ignore
retention-days: 7

codeql:
name: CodeQL Analysis
runs-on: ubuntu-24.04
timeout-minutes: 15
permissions:
actions: read
contents: read
strategy:
fail-fast: false
matrix:
language: [javascript-typescript]
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
with:
fetch-depth: 0
persist-credentials: false

- name: Initialize CodeQL
uses: github/codeql-action/init@e8e594e8799b6bc05d33c13d3d14e484b7b9cbc0 # v3.29.4
with:
languages: ${{ matrix.language }}
config-file: .github/codeql/codeql-config.yml

- name: Autobuild
uses: github/codeql-action/autobuild@e8e594e8799b6bc05d33c13d3d14e484b7b9cbc0 # v3.29.4

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@e8e594e8799b6bc05d33c13d3d14e484b7b9cbc0 # v3.29.4
with:
category: "/language:${{ matrix.language }}"
# Don't upload SARIF to Security tab (requires Advanced Security,
# paid for private repos). Instead, convert to PR annotations below.
upload: never
output: ${{ github.workspace }}/results/javascript.sarif

- name: Convert SARIF to PR annotations
if: always()
run: |
SARIF_FILE=$(find results/javascript.sarif -name '*.sarif' -type f | head -1)
if [ -n "$SARIF_FILE" ]; then
python3 scripts/sarif-to-annotations.py < "$SARIF_FILE"
else
echo "::warning title=sarif-to-annotations::No SARIF file found in results/javascript.sarif"
fi
1 change: 1 addition & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
bunx lint-staged
Loading