chore(deps): bump agent-browser from 0.27.0 to 0.33.0 in /v3/@claude-flow/browser #3529
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: V3 CI/CD Pipeline | |
| on: | |
| push: | |
| branches: [main, develop, v3] | |
| paths: | |
| - 'v3/**' | |
| - '.github/workflows/v3-ci.yml' | |
| # Witness-verify + plugin-hooks-smoke depend on these scripts; | |
| # path filter keeps CI in sync with their changes. | |
| - 'plugins/ruflo-core/scripts/witness/**' | |
| - 'plugins/ruflo-core/scripts/test-hooks.mjs' | |
| - 'plugins/ruflo-cost-tracker/scripts/test-hooks.mjs' | |
| - 'verification/**' | |
| # scripts/*.mjs audits (tool-descriptions, plugin-packages, hook-commands) | |
| - 'scripts/**' | |
| # hook-command audit (#1921, #2721) — every plugin hooks.json + the | |
| # cross-platform ruflo-hook.cjs shims (ruflo-hook.sh is legacy/unused | |
| # as of #2721 but kept for reference; no longer referenced by hooks.json) | |
| - '**/hooks/hooks.json' | |
| - '**/scripts/ruflo-hook.cjs' | |
| - '**/scripts/ruflo-hook.sh' | |
| # pre-bash hook safety (#2017) — both handler copies trigger the smoke | |
| - '**/.claude/helpers/hook-handler.cjs' | |
| # ruflo-browser rvf create flag (#2015) — TS source, plugin shell | |
| # scripts, agent-facing recipes all guarded by the same smoke. | |
| - 'v3/@claude-flow/cli/src/mcp-tools/browser-session-tools.ts' | |
| - 'plugins/ruflo-browser/**' | |
| # ruflo-graph-intelligence (#2044, ADR-123) — outside v3 workspace, | |
| # has its own lockfile + tests; needs to be CI-guarded on every change. | |
| - 'plugins/ruflo-graph-intelligence/**' | |
| # Supply-chain hardening (#2046) — every package.json + lockfile + | |
| # allowlist edit triggers the supply-chain audit. | |
| - '**/package.json' | |
| - '**/package-lock.json' | |
| - '**/pnpm-lock.yaml' | |
| - '.github/supply-chain/**' | |
| - 'scripts/audit-supply-chain.mjs' | |
| # Knowledge-graph plugin (#2049) — kg-extract type-import classifier | |
| # + kg-traverse controller wiring drift fast when SKILL.md edits | |
| # silently revert the bug-fix shape. | |
| - 'plugins/ruflo-knowledge-graph/**' | |
| - 'scripts/smoke-kg-extract-type-imports.mjs' | |
| # Neural-trader portfolio CG (#2068, ADR-126 Phase 3) — drift fast | |
| # when the adapter, skill, or runtime mirror diverge from the | |
| # ADR-123 Wedge 8 contract. | |
| - 'plugins/ruflo-neural-trader/src/sublinear-adapter.ts' | |
| - 'plugins/ruflo-neural-trader/src/sublinear-adapter.mjs' | |
| - 'plugins/ruflo-neural-trader/skills/trader-portfolio-cg/**' | |
| - 'scripts/smoke-neural-trader-portfolio-cg.mjs' | |
| # Neural-trader backtest signing (#2068, ADR-126 Phase 4) — Ed25519 | |
| # tamper-evidence for paper→live promotion; verifier MUST pin to a | |
| # trusted key (CWE-347 / #1922 pattern). | |
| - 'plugins/ruflo-neural-trader/src/signed-artifact.ts' | |
| - 'plugins/ruflo-neural-trader/src/signed-artifact.mjs' | |
| - 'plugins/ruflo-neural-trader/skills/trader-backtest/**' | |
| - 'plugins/ruflo-neural-trader/skills/trader-cloud-backtest/**' | |
| - 'scripts/smoke-neural-trader-backtest-signing.mjs' | |
| # Neural-trader SendMessage risk-gate pipeline (#2068, ADR-126 Phase 5) — | |
| # structural gate: trading-strategist refuses --broker without an | |
| # explicit risk-analyst RiskDecision approval. | |
| - 'plugins/ruflo-neural-trader/src/pipeline-messages.ts' | |
| - 'plugins/ruflo-neural-trader/agents/market-analyst.md' | |
| - 'plugins/ruflo-neural-trader/agents/trading-strategist.md' | |
| - 'plugins/ruflo-neural-trader/agents/risk-analyst.md' | |
| - 'plugins/ruflo-neural-trader/agents/backtest-engineer.md' | |
| - 'scripts/smoke-neural-trader-pipeline.mjs' | |
| # Neural-trader feature attribution (#2068, ADR-126 Phase 6) — | |
| # regulator-grade interpretability via single-entry PageRank. | |
| # Same signing scheme as Phase 4; ranking is seed-reproducible. | |
| - 'plugins/ruflo-neural-trader/src/signed-attribution.ts' | |
| - 'plugins/ruflo-neural-trader/src/signed-attribution.mjs' | |
| - 'plugins/ruflo-neural-trader/skills/trader-explain/**' | |
| - 'scripts/smoke-neural-trader-feature-attribution.mjs' | |
| # Plugin-registry CWE-347 regression smoke (#1922) — `discovery.ts` | |
| # signature verifier + the smoke fixture must stay in lockstep. | |
| - 'v3/@claude-flow/cli/src/plugins/store/discovery.ts' | |
| - 'v3/@claude-flow/cli/src/transfer/ipfs/client.ts' | |
| - 'v3/@claude-flow/cli/scripts/publish-registry.ts' | |
| - 'scripts/smoke-plugin-registry-signature.mjs' | |
| # ruvllm WASM auto-init regression smoke (#2086) — the | |
| # `loadRuvllmWasm()` helper in `ruvllm-tools.ts` and the | |
| # `ruvllm_status` un-init diagnostic path must stay in lockstep. | |
| - 'v3/@claude-flow/cli/src/mcp-tools/ruvllm-tools.ts' | |
| - 'v3/@claude-flow/cli/src/ruvector/ruvllm-wasm.ts' | |
| - 'scripts/smoke-ruvllm-wasm-auto-init.mjs' | |
| # agent_execute provider routing (#2042) — executeAgentTask must | |
| # not regress to inline Anthropic fetch, and the OpenRouter branch | |
| # in callAnthropicMessages must stay wired. | |
| - 'v3/@claude-flow/cli/src/mcp-tools/agent-execute-core.ts' | |
| - 'scripts/smoke-agent-execute-providers.mjs' | |
| # memory stats legacy-DB regression guard (#2120) — the WHERE | |
| # status='active' filter must accept NULL too, and the schema | |
| # backfill must promote NULL→'active' on existing DBs. | |
| - 'v3/@claude-flow/cli/src/memory/memory-bridge.ts' | |
| - 'v3/@claude-flow/cli/src/memory/memory-initializer.ts' | |
| - 'v3/@claude-flow/cli/src/commands/status.ts' | |
| - 'scripts/smoke-memory-stats-legacy-db.mjs' | |
| # ADR-125 Phase 7 — no stray DB artifacts after `npm test` in | |
| # @claude-flow/memory. vitest.setup.ts must wipe *.db / *.rvf / | |
| # *.redb files written by agentdb / @ruvector/rvf bindings. | |
| - 'v3/@claude-flow/memory/vitest.setup.ts' | |
| - 'v3/@claude-flow/memory/vitest.config.ts' | |
| - 'v3/@claude-flow/memory/vitest.config.mts' | |
| - 'scripts/smoke-memory-no-stray-db.mjs' | |
| # GitHub skills/agents/helpers surface (#2089, ADR-127) — injection | |
| # smoke + actions pin smoke gate every change to the .github surface. | |
| - '.claude/agents/github/**' | |
| - '.claude/skills/github-*/**' | |
| - 'v3/@claude-flow/cli/.claude/commands/github/**' | |
| - '.claude/helpers/github-safe.js' | |
| - 'v3/@claude-flow/cli/.claude/helpers/github-safe.js' | |
| - 'scripts/smoke-github-safe-injection.mjs' | |
| - 'scripts/smoke-github-actions-pins.mjs' | |
| - 'scripts/smoke-deprecated-actions.mjs' | |
| - 'scripts/smoke-attribution-opt-in.mjs' | |
| - '.github/supply-chain/allowed-deps.json' | |
| # Init-bundle invariants smoke (#2095, ADR-128) — orphan dirs, SKILLS_MAP | |
| # completeness, and plugin-init agent dedup are all guarded by Phase 5. | |
| - 'v3/@claude-flow/cli/.claude/**' | |
| - 'v3/@claude-flow/cli/src/init/**' | |
| - 'plugins/*/agents/**' | |
| - 'plugins/*/skills/**' | |
| - 'plugins/*/commands/**' | |
| - 'scripts/smoke-init-bundle-invariants.mjs' | |
| # ADR-129 — rvagent full integration (P1-P4) | |
| - 'v3/@claude-flow/cli/src/ruvector/agent-wasm.ts' | |
| - 'v3/@claude-flow/cli/src/mcp-tools/wasm-agent-tools.ts' | |
| - 'scripts/smoke-wasm-provider-bridge.mjs' | |
| - 'scripts/smoke-wasm-rvf-compose.mjs' | |
| - 'scripts/smoke-wasm-gallery-crud.mjs' | |
| - 'scripts/smoke-wasm-plugin-bridge.mjs' | |
| # ADR-130 — graph intelligence integration (P1-P6) | |
| - 'v3/@claude-flow/cli/src/memory/memory-initializer.ts' | |
| - 'v3/@claude-flow/cli/src/memory/embedding-quantization.ts' | |
| - 'v3/@claude-flow/cli/src/memory/graph-edge-writer.ts' | |
| - 'v3/@claude-flow/cli/src/mcp-tools/agentdb-tools.ts' | |
| - 'v3/@claude-flow/cli/src/mcp-tools/hooks-tools.ts' | |
| - 'plugins/ruflo-graph-intelligence/src/adapters/knowledge-graph-adapter.ts' | |
| - 'scripts/smoke-graph-schema-migration.mjs' | |
| - 'scripts/smoke-graph-query-dispatch.mjs' | |
| - 'scripts/smoke-trajectory-graph-edges.mjs' | |
| - 'scripts/smoke-graph-plugin-adapter.mjs' | |
| - 'scripts/smoke-graph-pathfinder.mjs' | |
| - 'scripts/benchmark-graph.mjs' | |
| # statusline generator delegation regression guard (#2195) | |
| - 'v3/@claude-flow/cli/src/init/statusline-generator.ts' | |
| - '.claude/helpers/statusline.cjs' | |
| - 'scripts/smoke-statusline-generator-delegation.mjs' | |
| # wizard init regression guard (#2206 #2207 #2208) | |
| - 'v3/@claude-flow/cli/src/init/mcp-generator.ts' | |
| - 'v3/@claude-flow/cli/src/init/executor.ts' | |
| - 'scripts/smoke-wizard-init-regression.mjs' | |
| pull_request: | |
| branches: [main, develop] | |
| paths: | |
| - 'v3/**' | |
| - 'plugins/ruflo-core/scripts/witness/**' | |
| - 'plugins/ruflo-core/scripts/test-hooks.mjs' | |
| - 'plugins/ruflo-cost-tracker/scripts/test-hooks.mjs' | |
| - 'scripts/**' | |
| - '**/hooks/hooks.json' | |
| - '**/scripts/ruflo-hook.cjs' | |
| - '**/scripts/ruflo-hook.sh' | |
| - '**/.claude/helpers/hook-handler.cjs' | |
| # ruflo-browser rvf create flag (#2015) | |
| - 'v3/@claude-flow/cli/src/mcp-tools/browser-session-tools.ts' | |
| - 'plugins/ruflo-browser/**' | |
| # ruflo-graph-intelligence (#2044, ADR-123) | |
| - 'plugins/ruflo-graph-intelligence/**' | |
| # Supply-chain hardening (#2046) — every dep + lockfile change is | |
| # CVE-audited, allowlist-checked, integrity-checked. | |
| - '**/package.json' | |
| - '**/package-lock.json' | |
| - '**/pnpm-lock.yaml' | |
| - '.github/supply-chain/**' | |
| - 'scripts/audit-supply-chain.mjs' | |
| # Knowledge-graph plugin (#2049) | |
| - 'plugins/ruflo-knowledge-graph/**' | |
| - 'scripts/smoke-kg-extract-type-imports.mjs' | |
| # Neural-trader portfolio CG (#2068, ADR-126 Phase 3) | |
| - 'plugins/ruflo-neural-trader/src/sublinear-adapter.ts' | |
| - 'plugins/ruflo-neural-trader/src/sublinear-adapter.mjs' | |
| - 'plugins/ruflo-neural-trader/skills/trader-portfolio-cg/**' | |
| - 'scripts/smoke-neural-trader-portfolio-cg.mjs' | |
| # Neural-trader backtest signing (#2068, ADR-126 Phase 4) | |
| - 'plugins/ruflo-neural-trader/src/signed-artifact.ts' | |
| - 'plugins/ruflo-neural-trader/src/signed-artifact.mjs' | |
| - 'plugins/ruflo-neural-trader/skills/trader-backtest/**' | |
| - 'plugins/ruflo-neural-trader/skills/trader-cloud-backtest/**' | |
| - 'scripts/smoke-neural-trader-backtest-signing.mjs' | |
| # Neural-trader SendMessage risk-gate pipeline (#2068, ADR-126 Phase 5) | |
| - 'plugins/ruflo-neural-trader/src/pipeline-messages.ts' | |
| - 'plugins/ruflo-neural-trader/agents/market-analyst.md' | |
| - 'plugins/ruflo-neural-trader/agents/trading-strategist.md' | |
| - 'plugins/ruflo-neural-trader/agents/risk-analyst.md' | |
| - 'plugins/ruflo-neural-trader/agents/backtest-engineer.md' | |
| - 'scripts/smoke-neural-trader-pipeline.mjs' | |
| # Neural-trader feature attribution (#2068, ADR-126 Phase 6) | |
| - 'plugins/ruflo-neural-trader/src/signed-attribution.ts' | |
| - 'plugins/ruflo-neural-trader/src/signed-attribution.mjs' | |
| - 'plugins/ruflo-neural-trader/skills/trader-explain/**' | |
| - 'scripts/smoke-neural-trader-feature-attribution.mjs' | |
| # Plugin-registry CWE-347 regression (#1922) | |
| - 'v3/@claude-flow/cli/src/plugins/store/discovery.ts' | |
| - 'v3/@claude-flow/cli/src/transfer/ipfs/client.ts' | |
| - 'v3/@claude-flow/cli/scripts/publish-registry.ts' | |
| - 'scripts/smoke-plugin-registry-signature.mjs' | |
| # ruvllm WASM auto-init regression (#2086) | |
| - 'v3/@claude-flow/cli/src/mcp-tools/ruvllm-tools.ts' | |
| - 'v3/@claude-flow/cli/src/ruvector/ruvllm-wasm.ts' | |
| - 'scripts/smoke-ruvllm-wasm-auto-init.mjs' | |
| # agent_execute provider routing (#2042) | |
| - 'v3/@claude-flow/cli/src/mcp-tools/agent-execute-core.ts' | |
| - 'scripts/smoke-agent-execute-providers.mjs' | |
| # memory stats legacy-DB regression (#2120) | |
| - 'v3/@claude-flow/cli/src/memory/memory-bridge.ts' | |
| - 'v3/@claude-flow/cli/src/memory/memory-initializer.ts' | |
| - 'v3/@claude-flow/cli/src/commands/status.ts' | |
| - 'scripts/smoke-memory-stats-legacy-db.mjs' | |
| # ADR-125 Phase 7 — no stray DB artifacts after npm test | |
| - 'v3/@claude-flow/memory/vitest.setup.ts' | |
| - 'v3/@claude-flow/memory/vitest.config.ts' | |
| - 'v3/@claude-flow/memory/vitest.config.mts' | |
| - 'scripts/smoke-memory-no-stray-db.mjs' | |
| # GitHub skills/agents/helpers surface (#2089, ADR-127) | |
| - '.claude/agents/github/**' | |
| - '.claude/skills/github-*/**' | |
| - 'v3/@claude-flow/cli/.claude/commands/github/**' | |
| - '.claude/helpers/github-safe.js' | |
| - 'v3/@claude-flow/cli/.claude/helpers/github-safe.js' | |
| - 'scripts/smoke-github-safe-injection.mjs' | |
| - 'scripts/smoke-github-actions-pins.mjs' | |
| - 'scripts/smoke-deprecated-actions.mjs' | |
| - 'scripts/smoke-attribution-opt-in.mjs' | |
| - '.github/supply-chain/allowed-deps.json' | |
| # Init-bundle invariants smoke (#2095, ADR-128) | |
| - 'v3/@claude-flow/cli/.claude/**' | |
| - 'v3/@claude-flow/cli/src/init/**' | |
| - 'plugins/*/agents/**' | |
| - 'plugins/*/skills/**' | |
| - 'plugins/*/commands/**' | |
| - 'scripts/smoke-init-bundle-invariants.mjs' | |
| # ADR-129 — rvagent full integration (P1-P4) | |
| - 'v3/@claude-flow/cli/src/ruvector/agent-wasm.ts' | |
| - 'v3/@claude-flow/cli/src/mcp-tools/wasm-agent-tools.ts' | |
| - 'scripts/smoke-wasm-provider-bridge.mjs' | |
| - 'scripts/smoke-wasm-rvf-compose.mjs' | |
| - 'scripts/smoke-wasm-gallery-crud.mjs' | |
| - 'scripts/smoke-wasm-plugin-bridge.mjs' | |
| # witness manifests / fix list — so witness-verify runs on PRs that | |
| # touch them (otherwise a stale per-OS manifest only fails post-merge). | |
| - 'verification/**' | |
| # statusline generator delegation regression guard (#2195) | |
| - 'v3/@claude-flow/cli/src/init/statusline-generator.ts' | |
| - '.claude/helpers/statusline.cjs' | |
| - 'scripts/smoke-statusline-generator-delegation.mjs' | |
| # wizard init regression guard (#2206 #2207 #2208) | |
| - 'v3/@claude-flow/cli/src/init/mcp-generator.ts' | |
| - 'v3/@claude-flow/cli/src/init/executor.ts' | |
| - 'scripts/smoke-wizard-init-regression.mjs' | |
| workflow_dispatch: | |
| env: | |
| NODE_VERSION: '20' | |
| PNPM_VERSION: '8' | |
| jobs: | |
| # #2267 + #2257 regression guards — fast, no install, run first so any | |
| # YAML or router regression is caught at PR-time, not at scheduled cron. | |
| static-regression-guards: | |
| name: Static regression guards (#2267 YAML + #2257 router + #2562 lockfile) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: { node-version: '22' } | |
| # js-yaml + tsx are needed by the smokes — install only those. Installed | |
| # into an isolated prefix (not the repo root) and copied into node_modules | |
| # rather than `npm install`-ed directly here: the root package.json now | |
| # carries an `overrides.js-yaml` entry (CVE-1 fix), and npm refuses ANY | |
| # direct/top-level install of a package that also has a top-level | |
| # `overrides` entry for it (EOVERRIDE), regardless of version specifier. | |
| - name: Install smoke deps | |
| run: | | |
| npm install --prefix /tmp/smoke-deps --no-package-lock js-yaml tsx | |
| mkdir -p node_modules | |
| cp -r /tmp/smoke-deps/node_modules/. node_modules/ | |
| - name: "#2267 — every .github/workflows/*.yml must parse" | |
| run: node scripts/smoke-workflows-yaml.mjs | |
| - name: "#2257 — router patterns must be word-boundary-anchored" | |
| run: node --import tsx scripts/smoke-router-regex.mjs | |
| # #2562 — FAST lockfile-drift guard. Editing any v3 workspace manifest | |
| # (esp. v3/@claude-flow/cli deps) without regenerating v3/pnpm-lock.yaml | |
| # makes --frozen-lockfile fail in EVERY downstream install job (~34 red | |
| # jobs, cascading — the #2540→#2552→#2562 recurrence). `--lockfile-only` | |
| # verifies lock↔manifest consistency in seconds WITHOUT downloading | |
| # anything, failing once here with a clear fix instead of 34× later. | |
| - name: Setup pnpm (lockfile guard) | |
| uses: pnpm/action-setup@v6 | |
| with: | |
| version: ${{ env.PNPM_VERSION }} | |
| - name: "#2562 — v3/pnpm-lock.yaml must match workspace package.json (frozen-lockfile drift)" | |
| working-directory: v3 | |
| run: | | |
| if pnpm install --frozen-lockfile --lockfile-only 2>lock-err.log; then | |
| echo "✓ v3/pnpm-lock.yaml is consistent with all workspace manifests" | |
| else | |
| echo "::error title=Lockfile drift::v3/pnpm-lock.yaml is OUT OF SYNC with a package.json. Editing v3 workspace deps requires regenerating the lock in the SAME commit." | |
| echo "::error title=How to fix::Run cd v3 && pnpm install --lockfile-only && git add pnpm-lock.yaml then commit." | |
| echo "--- pnpm reported ---" | |
| grep -A25 "OUTDATED_LOCKFILE\|not up to date\|don't match" lock-err.log | head -40 || cat lock-err.log | head -40 | |
| exit 1 | |
| fi | |
| test: | |
| name: Test V3 Packages | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v6 | |
| with: | |
| version: ${{ env.PNPM_VERSION }} | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| cache: 'pnpm' | |
| cache-dependency-path: v3/pnpm-lock.yaml | |
| - name: Install dependencies | |
| working-directory: v3 | |
| run: pnpm install --frozen-lockfile | |
| - name: Build (so workspace dist/ exists for runtime imports) | |
| # Some test suites do `await import('@claude-flow/X')` and Vite's | |
| # import-analysis pass needs dist/ files at the resolved path. | |
| # --no-bail keeps building past unrelated failures. | |
| working-directory: v3 | |
| run: pnpm --recursive --no-bail run build || true | |
| - name: "ADR-176/177 — self-learning proof artifacts must stay valid" | |
| # Guard the committed evidence that makes the flywheel claim honest: | |
| # the proof-of-mechanism + REAL compounding lineage must replay | |
| # independently (rehash + re-run accept/v1+sig, no service logs), the | |
| # lineage must reconstruct to >=2 promotions back to the immutable root, | |
| # and the shipped config champion must verify against the baked pubkey. | |
| working-directory: v3/@claude-flow/cli | |
| run: node scripts/smoke-flywheel-proof.mjs | |
| - name: "ADR-176 — clean-room replay acceptance test (offline, identical hashes)" | |
| # Replay a PROMOTED generation from its receipt alone: recompute every | |
| # hash bit-identically and re-run accept/v1+sig to reproduce promoted=true, | |
| # with network access trapped. Proves promotions are reproducible without | |
| # trusting any service log. | |
| working-directory: v3/@claude-flow/cli | |
| run: node scripts/replay-generation.mjs | |
| - name: Run tests | |
| working-directory: v3 | |
| # Tolerate exit code 139 (SIGSEGV) ONLY when it occurs at process | |
| # shutdown after all tests reported. Native bindings sometimes | |
| # segfault during onnxruntime-node / ruvector cleanup; this is a | |
| # known issue tracked elsewhere and shouldn't block CI when the | |
| # actual test outcomes were captured. Any other non-zero exit | |
| # (real test failures, vitest errors, etc.) still fails the job. | |
| run: | | |
| set +e | |
| pnpm test | |
| EXIT=$? | |
| set -e | |
| if [ "$EXIT" -eq 139 ]; then | |
| echo "::warning::pnpm test exited with SIGSEGV (139) after tests completed — tolerated as native-binding cleanup race" | |
| exit 0 | |
| fi | |
| exit "$EXIT" | |
| - name: Upload coverage | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: v3-coverage | |
| path: v3/__tests__/coverage/ | |
| typecheck: | |
| name: Type Check V3 | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v6 | |
| with: | |
| version: ${{ env.PNPM_VERSION }} | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| cache: 'pnpm' | |
| cache-dependency-path: v3/pnpm-lock.yaml | |
| - name: Install dependencies | |
| working-directory: v3 | |
| run: pnpm install --frozen-lockfile | |
| - name: Type check | |
| working-directory: v3 | |
| run: pnpm typecheck | |
| continue-on-error: true | |
| build: | |
| name: Build V3 (${{ matrix.os }}) | |
| runs-on: ${{ matrix.os }} | |
| needs: [test] | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v6 | |
| with: | |
| version: ${{ env.PNPM_VERSION }} | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| cache: 'pnpm' | |
| cache-dependency-path: v3/pnpm-lock.yaml | |
| - name: Install dependencies | |
| working-directory: v3 | |
| run: pnpm install --frozen-lockfile | |
| - name: Build | |
| working-directory: v3 | |
| run: pnpm build | |
| - name: Upload build artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: v3-build-${{ matrix.os }} | |
| path: v3/@claude-flow/*/dist/ | |
| smoke-install-no-bsqlite: | |
| # Regression guard for ruvnet/ruflo#1867 — ensures @claude-flow/memory | |
| # installs and loads when better-sqlite3 fails to build (e.g. Node 26 | |
| # without prebuilds). Reproduces the user-visible failure mode by | |
| # installing with --omit=optional. | |
| # | |
| # Independent of the workspace `build` job because we only need to | |
| # build a single package (memory) — no workspace-wide dist required. | |
| # | |
| # Cross-platform: ubuntu + macos (Windows excluded because the smoke | |
| # script uses bash-specific patterns and runs in user environments | |
| # that typically use WSL/git-bash anyway. The runtime fallback path | |
| # the smoke verifies is platform-independent — a passing run on | |
| # Linux+macOS proves the JS code path works everywhere.) | |
| name: Smoke (no better-sqlite3) / ${{ matrix.os }} / Node ${{ matrix.node }} | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest] | |
| node: ['22', '24'] | |
| # macos-latest's bundled Python 3.12 removed distutils, breaking | |
| # node-gyp on Node 24's hnswlib-node + better-sqlite3 builds. Drop | |
| # that one combo until the macOS image ships a compatible setup. | |
| # (Linux Node 24 + macOS Node 22 still cover the cross-product.) | |
| exclude: | |
| - os: macos-latest | |
| node: '24' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js ${{ matrix.node }} | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ matrix.node }} | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v6 | |
| with: | |
| version: ${{ env.PNPM_VERSION }} | |
| - name: Guard #2590 — onnxruntime-node postinstall must be skipped | |
| # Regression guard for ruvnet/ruflo#2590 — onnxruntime-node's postinstall | |
| # fetches a GPU nupkg from nuget.org that ETIMEDOUTs from GitHub runners, | |
| # taking `pnpm install --frozen-lockfile` down. The fix requires BOTH: | |
| # 1) v3/package.json → pnpm.neverBuiltDependencies contains "onnxruntime-node" | |
| # 2) this workflow's memory-smoke install uses --ignore-scripts | |
| # If either regresses, this step fails BEFORE the flaky network install. | |
| run: | | |
| set -euo pipefail | |
| # (1) neverBuiltDependencies gate | |
| node -e ' | |
| const j = require("./v3/package.json"); | |
| const list = (j.pnpm && j.pnpm.neverBuiltDependencies) || []; | |
| if (!list.includes("onnxruntime-node")) { | |
| console.error("REGRESSION #2590: v3/package.json pnpm.neverBuiltDependencies missing onnxruntime-node"); | |
| console.error(" got:", JSON.stringify(list)); | |
| process.exit(1); | |
| } | |
| console.log("ok: onnxruntime-node in pnpm.neverBuiltDependencies"); | |
| ' | |
| # (2) workflow install step must pass --ignore-scripts (belt-and-braces) | |
| if ! grep -qE "pnpm install --frozen-lockfile --ignore-scripts" .github/workflows/v3-ci.yml; then | |
| echo "REGRESSION #2590: memory-smoke install step lost --ignore-scripts" | |
| exit 1 | |
| fi | |
| echo "ok: --ignore-scripts present on memory-smoke pnpm install" | |
| - name: Install workspace + build memory (pnpm — needed for workspace:* protocol) | |
| working-directory: v3 | |
| run: | | |
| pnpm install --frozen-lockfile --ignore-scripts | |
| pnpm --filter @claude-flow/memory... run build | |
| - name: Pack memory tarball | |
| id: pack | |
| working-directory: v3/@claude-flow/memory | |
| run: | | |
| # pnpm pack rewrites workspace:* → resolved versions (npm pack doesn't). | |
| # Pack to RUNNER_TEMP so the path works on both ubuntu and macos. | |
| TARBALL=$(pnpm pack --pack-destination "$RUNNER_TEMP" 2>&1 | grep -E "\.tgz$" | head -1) | |
| [ -z "$TARBALL" ] && { echo "pnpm pack produced no tarball"; exit 1; } | |
| echo "tarball=$TARBALL" >> "$GITHUB_OUTPUT" | |
| - name: Install with --omit=optional (simulates Node 26 native build failure) | |
| run: | | |
| mkdir -p "$RUNNER_TEMP/smoke" | |
| cd "$RUNNER_TEMP/smoke" | |
| npm init -y >/dev/null | |
| npm pkg set type=module | |
| npm install "${{ steps.pack.outputs.tarball }}" --omit=optional --no-audit --no-fund | |
| - name: Assert better-sqlite3 was NOT installed | |
| run: | | |
| if [ -d "$RUNNER_TEMP/smoke/node_modules/better-sqlite3" ]; then | |
| echo "FAIL: better-sqlite3 installed despite --omit=optional — smoke setup is wrong" | |
| exit 1 | |
| fi | |
| echo "ok: better-sqlite3 absent (regression scenario active)" | |
| - name: Run smoke script | |
| run: | | |
| cp v3/@claude-flow/memory/scripts/smoke-no-bsqlite.mjs "$RUNNER_TEMP/smoke/" | |
| cd "$RUNNER_TEMP/smoke" | |
| node smoke-no-bsqlite.mjs | |
| plugin-hooks-smoke: | |
| # Regression guard for ruvnet/ruflo#1859 + #1862 — drives each PostToolUse | |
| # hook from plugins/ruflo-core/hooks/hooks.json with synthetic Claude-Code | |
| # JSON against the locally built CLI. Catches: | |
| # - hooks calling flags the CLI doesn't accept (#1862's --format true) | |
| # - CLI parser ambiguity recording the wrong value (#1859's "true" filename) | |
| # | |
| # Independent of the workspace `build` job — only the cli package needs | |
| # to be built. We use `pnpm --filter @claude-flow/cli...` to scope. | |
| name: Plugin hooks smoke / ${{ matrix.os }} / Node ${{ matrix.node }} | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| # #2721 — windows-latest included: hooks.json no longer wraps | |
| # commands in `/bin/bash -c '...'`, it invokes `node -e "..."` | |
| # directly (see plugins/ruflo-core/hooks/hooks.json), which needs | |
| # no POSIX shell at all. test-hooks.mjs drives the exact command | |
| # string from hooks.json via `shell: true`, so this is a genuine | |
| # regression guard against the #2721 shape recurring, not just a | |
| # POSIX-only smoke. | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| # Node 22 is the project's documented baseline (engines.node: '>=20') | |
| # but Node 20 had environment-specific issues with multi-line stdin | |
| # round-tripping that didn't reproduce on Node 22 or locally — same | |
| # CLI binary, same hooks.json. Tracked as a follow-up; for now the | |
| # regression guard runs on the version users are actually on. | |
| node: ['22'] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v6 | |
| with: | |
| version: ${{ env.PNPM_VERSION }} | |
| - name: Setup Node.js ${{ matrix.node }} | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ matrix.node }} | |
| cache: 'pnpm' | |
| cache-dependency-path: v3/pnpm-lock.yaml | |
| - name: Install + build cli (scoped, tolerates unrelated workspace failures) | |
| working-directory: v3 | |
| shell: bash | |
| run: | | |
| pnpm install --frozen-lockfile | |
| # --no-bail keeps building past unrelated package failures | |
| # (e.g. plugin-agent-federation TS error). We then assert the | |
| # specific dist file we need was produced. | |
| pnpm --recursive --no-bail run build || true | |
| test -f @claude-flow/cli/bin/cli.js \ | |
| || (echo "cli build did not produce bin/cli.js"; exit 1) | |
| test -f @claude-flow/cli/dist/src/commands/hooks.js \ | |
| || (echo "cli build did not produce hooks.js"; exit 1) | |
| - name: Run plugin hooks smoke against local CLI build | |
| shell: bash | |
| run: | | |
| node plugins/ruflo-core/scripts/test-hooks.mjs \ | |
| "node $GITHUB_WORKSPACE/v3/@claude-flow/cli/bin/cli.js" | |
| - name: Run cost-tracker Stop hook smoke against local CLI build | |
| shell: bash | |
| run: | | |
| node plugins/ruflo-cost-tracker/scripts/test-hooks.mjs | |
| browser-rvf-create-flags-smoke: | |
| # Regression guard for ruvnet/ruflo#2015 — the ruflo-browser | |
| # `browser_session_record` MCP tool wraps `ruvector rvf create`. | |
| # ruvector@0.2.25 makes `-d, --dimension <n>` required, so before | |
| # this fix every session-record call failed with | |
| # `error: required option '-d, --dimension <n>' not specified` | |
| # and the wrapper returned `{ success: false, error: "rvf create | |
| # failed" }`. | |
| # | |
| # This smoke scans every place we shell out to `rvf create | |
| # --kind browser-session` across the repo (TS source, compiled | |
| # dist, shell scripts, agent-facing markdown recipes) and fails | |
| # if any call is missing the dimension flag. | |
| name: browser rvf create flag smoke (#2015) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v6 | |
| with: | |
| version: 8 | |
| - name: Build CLI (so the compiled dist is scanned alongside src) | |
| # The CLI uses `workspace:*` deps which only pnpm understands — npm | |
| # install errors with EUNSUPPORTEDPROTOCOL. Install at the v3 | |
| # workspace root (mirrors the Build V3 job) and build everything in | |
| # topological order so cli-core/memory/neural dist exist before cli. | |
| # `continue-on-error: true` keeps the smoke usable even when CLI src | |
| # has unrelated TS errors — the static scan will report any missing | |
| # dist file it cares about, which is the contract we actually want. | |
| continue-on-error: true | |
| run: | | |
| cd v3 | |
| pnpm install --frozen-lockfile | |
| pnpm -r build | |
| - name: Static scan of every rvf create call site | |
| run: node scripts/smoke-browser-rvf-create-flags.mjs | |
| graph-intelligence-build-smoke: | |
| # Regression guard for #2044 / ADR-123 — the ruflo-graph-intelligence | |
| # plugin lives outside the v3 pnpm workspace (it has its own | |
| # package-lock.json) so it does not pick up the workspace's | |
| # frozen-lockfile / -r build path. This job installs + builds + tests | |
| # the plugin in isolation so the eleven sublinear wedges are verified | |
| # on every push and PR. | |
| name: ruflo-graph-intelligence build + test smoke (#2044, ADR-123) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Install plugin dependencies (npm — plugin is outside v3 workspace) | |
| working-directory: plugins/ruflo-graph-intelligence | |
| run: npm ci --no-audit --no-fund --legacy-peer-deps | |
| - name: Type-check | |
| working-directory: plugins/ruflo-graph-intelligence | |
| run: npx tsc --noEmit | |
| - name: Build | |
| working-directory: plugins/ruflo-graph-intelligence | |
| run: npx tsc | |
| - name: Run vitest | |
| working-directory: plugins/ruflo-graph-intelligence | |
| run: npx vitest run | |
| supply-chain-audit: | |
| # Supply-chain hardening (#2046, follow-up to ADR-123). | |
| # | |
| # Five layers of defence run by scripts/audit-supply-chain.mjs: | |
| # 1. CVE — `npm audit --audit-level=high` on each shipped package. | |
| # HIGH/CRITICAL findings in DIRECT deps fail CI. | |
| # 2. Lockfile integrity — every entry must have a SHA-512 `integrity` | |
| # hash. Missing or weak hashes are a tamper vector. | |
| # 3. Top-level allowlist — new direct deps require an explicit | |
| # `.github/supply-chain/allowed-deps.json` addition. Block silent | |
| # additions via maintainer compromise or typo'd PRs. | |
| # 4. Typosquat reject — names matching the policy block-list fail | |
| # regardless of whether the package actually exists upstream. | |
| # 5. Publisher trust snapshot — logs npm maintainer identity for our | |
| # critical upstream deps so unexpected handover is visible in CI | |
| # logs (not a hard fail; informational). | |
| # | |
| # This job runs on every PR that touches a package.json, lockfile, | |
| # allowlist, or the audit script itself. It also runs on pushes to main | |
| # so direct-to-main changes (rare) are caught. | |
| name: Supply-chain audit (#2046) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Install ruflo-graph-intelligence deps (for npm audit) | |
| working-directory: plugins/ruflo-graph-intelligence | |
| run: npm ci --no-audit --no-fund --legacy-peer-deps | |
| - name: Install @claude-flow/browser deps (for npm audit) | |
| working-directory: v3/@claude-flow/browser | |
| run: npm install --no-audit --no-fund --legacy-peer-deps --no-workspaces | |
| - name: Run supply-chain audit | |
| run: node scripts/audit-supply-chain.mjs | |
| - name: Test audit script itself | |
| run: node scripts/__tests__/audit-supply-chain.test.mjs | |
| dependency-review: | |
| # GitHub's official dependency-review-action — runs only on PRs and | |
| # flags any new vulnerable dependency added by the PR vs the base | |
| # branch. Configured to fail on `high` severity and to forbid | |
| # known-bad licenses (GPL-style + non-OSI). | |
| # | |
| # **Setup requirement**: this action needs GitHub's Dependency Graph | |
| # feature enabled at the repo level. Toggle at | |
| # https://github.com/ruvnet/ruflo/settings/security_analysis under | |
| # "Dependency graph". Until that toggle is on, the action errors | |
| # with "Dependency review is not supported on this repository" — so | |
| # this job is marked continue-on-error to keep the CVE/audit/codeowner | |
| # layers of supply-chain hardening usable in the meantime. | |
| # | |
| # https://github.com/actions/dependency-review-action | |
| name: Dependency review (#2046) | |
| runs-on: ubuntu-latest | |
| if: github.event_name == 'pull_request' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| # `continue-on-error` is at the STEP (not job) level so the action's | |
| # "Dependency review is not supported on this repository" error from | |
| # the off-by-default Dependency Graph feature doesn't show as a PR | |
| # check failure. Once the repo owner toggles Dependency Graph on at | |
| # Settings → Security and analysis, remove this line to make the | |
| # action gating again. | |
| - name: Dependency Review | |
| continue-on-error: true | |
| uses: actions/dependency-review-action@v4 | |
| with: | |
| fail-on-severity: high | |
| comment-summary-in-pr: on-failure | |
| # Block licenses we cannot ship: | |
| deny-licenses: AGPL-3.0, GPL-3.0, SSPL-1.0 | |
| # Block known-compromised package versions via pURL (package-url) | |
| # format — this is the action's required input shape per its docs. | |
| # https://github.com/actions/dependency-review-action#configuration-options | |
| deny-packages: pkg:npm/event-stream@3.3.6, pkg:npm/flatmap-stream, pkg:npm/ua-parser-js@0.7.29, pkg:npm/ua-parser-js@0.8.0, pkg:npm/ua-parser-js@1.0.0, pkg:npm/colors@1.4.1, pkg:npm/faker@6.6.6 | |
| witness-marker-drift-smoke: | |
| # Regression guard for ruvnet/ruflo#2021 — the slow witness-verify | |
| # job below catches marker drift but only as a post-build check on | |
| # cross-platform matrix. Direct pushes to main (e.g. the alpha.43 | |
| # release chain) bypass PR-time gating and a bad marker can sneak | |
| # through, leaving the scheduled 12h cron to file a HIGH issue. | |
| # | |
| # This smoke runs verify.mjs's marker-presence layer (no signature | |
| # check, no build, no native deps) on every push and pull-request. | |
| # If a cited file exists on disk and the marker string is missing, | |
| # fail immediately and name the specific fix id that drifted. | |
| # | |
| # The full witness-verify job stays — it adds the signature layer | |
| # and the cross-platform dist build. This smoke is the fast gate | |
| # that fails before that. | |
| name: witness marker drift smoke (#2021) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Scan every witness marker for drift | |
| run: node scripts/smoke-witness-marker-drift.mjs | |
| witness-verify-precondition-smoke: | |
| # Regression guard for ruvnet/ruflo#1880 — the 12h scheduled witness | |
| # verification runs in a source-only checkout (no `npm ci`, no | |
| # `npm run build`). Before this fix, that environment exited 1 | |
| # (real verification failure) because `@noble/ed25519` wasn't | |
| # installed and 87+ dist files referenced by the manifest didn't | |
| # exist on disk — so the scheduled runner filed a "verification | |
| # broken" issue every 12 hours even though nothing was actually | |
| # wrong with the signed manifest. | |
| # | |
| # verify.mjs now reserves exit 2 for precondition failures | |
| # (missing dep, source-only checkout) and exit 1 strictly for real | |
| # failures (signature invalid, dist file regressed). This smoke | |
| # drives both shapes through and asserts the contract holds: | |
| # - missing @noble/ed25519 → exit 2 + named in the error | |
| # - all-manifest-files missing → exit 2 + precondition tag | |
| # - built tree → exit is NEVER 2 | |
| # | |
| # Independent job so a precondition contract break is named clearly | |
| # in the CI summary. Wired into witness-verify's `needs:` below. | |
| name: witness verify precondition smoke (#1880) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Install root dependencies (provides @noble/ed25519 for Case 3) | |
| run: npm ci --legacy-peer-deps | |
| - name: Drive precondition + built-tree shapes through verify.mjs | |
| shell: bash | |
| run: node scripts/smoke-witness-verify-precondition.mjs | |
| kg-extract-type-imports-smoke: | |
| # Regression guard for ruvnet/ruflo#2049 — `kg-extract` previously | |
| # treated TypeScript `import type` and value imports as the same edge | |
| # type, producing phantom runtime cycles in the knowledge graph (a | |
| # 51-service codebase reported a non-existent `findings ⇄ finding-actions` | |
| # cycle driven entirely by a one-way type-only import). | |
| # | |
| # This smoke runs two layers: | |
| # 1. Static contract check on plugins/ruflo-knowledge-graph/skills/{kg-extract,kg-traverse}/SKILL.md | |
| # — assert kg-extract declares `type-depends-on` as a separate relation | |
| # with weight ≤ 0.1, and that neither skill references the | |
| # compiled-out `agentdb_semantic-route` controller. | |
| # 2. Behavioural fixture: write a tiny TS scenario with one type-only | |
| # cycle + one value-import edge to /tmp, run the documented regex | |
| # classifier, and assert the cycle is NOT counted as a value edge. | |
| # | |
| # If a future PR softens either layer (re-introduces semantic-route in | |
| # allowed-tools, drops the type-depends-on relation, or weakens the | |
| # regex), this smoke catches it. | |
| name: kg-extract type-import classification smoke (#2049) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Run kg-extract type-import smoke | |
| run: node scripts/smoke-kg-extract-type-imports.mjs | |
| neural-trader-portfolio-cg-smoke: | |
| # Regression guard for ruvnet/ruflo#2068 — ADR-126 Phase 3. | |
| # | |
| # Phase 3 wires the Conjugate-Gradient portfolio path that ADR-123 | |
| # Wedge 8 promises a 40-60× speedup over the legacy Neumann series. | |
| # The contract is load-bearing on three artifacts that must stay | |
| # in lockstep: | |
| # 1. `src/sublinear-adapter.ts` — the typed adapter shape | |
| # (SublinearAdapter, solveCG, isMcpAvailable, SolveResult) | |
| # that conforms to ADR-123 §262-289. | |
| # 2. `src/sublinear-adapter.mjs` — the runtime mirror that the | |
| # smoke + bench import directly (the plugin has no build step). | |
| # 3. `skills/trader-portfolio-cg/SKILL.md` — frontmatter must | |
| # declare `mcp__ruflo-sublinear__solve` in allowed-tools and | |
| # write to the canonical `trading-risk` namespace. | |
| # | |
| # The smoke runs three layers: | |
| # [1/3] STATIC ADAPTER CONTRACT — class shape, method signatures, | |
| # SolveResult fields, MCP tool name, symmetric-input validation. | |
| # [2/3] STATIC SKILL CONTRACT — frontmatter, allowed-tools, namespace, | |
| # disable-flag documentation, Neumann fallback path. | |
| # [3/3] RUNTIME CORRECTNESS — solves the textbook 2×2 SPD case | |
| # A=[[4,1],[1,3]], b=[1,2] → x=[1/11, 7/11] within 1e-6, and | |
| # exercises the degraded paths (non-square, non-symmetric). | |
| # | |
| # If a future PR drops solveCG, removes the MCP tool from allowed-tools, | |
| # changes the namespace, or breaks the local CG kernel, this smoke | |
| # catches it before merge. | |
| name: neural-trader portfolio CG smoke (#2068, ADR-126 Phase 3) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Run portfolio CG smoke | |
| run: node scripts/smoke-neural-trader-portfolio-cg.mjs | |
| neural-trader-backtest-signing-smoke: | |
| # Regression guard for ruvnet/ruflo#2068 — ADR-126 Phase 4. | |
| # | |
| # Phase 4 wires Ed25519-signed backtest artifacts so the paper→live | |
| # promotion gate has cryptographic tamper evidence. The signing scheme | |
| # mirrors the CWE-347 plugin-registry pattern (#1922): canonical body | |
| # = JSON.stringify without signature fields; verifier pins to a | |
| # caller-supplied `trustedPublicKey`, NOT to the served self-asserted | |
| # `witnessPublicKey` field (which an attacker can swap freely). | |
| # | |
| # Three load-bearing artifacts must stay in lockstep: | |
| # 1. `src/signed-artifact.ts` — the typed signer/verifier contract. | |
| # 2. `src/signed-artifact.mjs` — the runtime mirror imported by the | |
| # smoke + (future) skill harnesses (the plugin has no build step). | |
| # 3. `skills/trader-backtest/SKILL.md` + `skills/trader-cloud-backtest/SKILL.md` | |
| # — the call sites that sign before store + verify before promote. | |
| # | |
| # The smoke runs three layers: | |
| # [1/3] STATIC CONTRACT — verifier pins to trustedPublicKey (NOT to | |
| # artifact.witnessPublicKey), canonical body strips BOTH | |
| # signature fields, .ts and .mjs runtime mirrors agree. | |
| # [2/3] CRYPTO ROUND-TRIP with real Ed25519 — happy path, tampered | |
| # body fails, empty sig/pubkey fails, swapped served pubkey | |
| # still verifies (pin is real), wrong trusted pubkey fails. | |
| # [3/3] CALL-SITE BYTE check — trader-cloud-backtest/SKILL.md calls | |
| # verifyBacktestArtifact AND documents the fail-closed branch; | |
| # trader-backtest/SKILL.md references the signer + degraded | |
| # warning + RUFLO_WITNESS_KEY_PATH env var. | |
| # | |
| # If a future PR drops the verify call, reverts to pinning the served | |
| # field, or removes the fail-closed branch, this smoke catches it | |
| # before merge. | |
| name: neural-trader backtest signing smoke (#2068, ADR-126 Phase 4) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Install root deps (for @noble/ed25519) | |
| run: npm install --legacy-peer-deps --no-audit --no-fund --ignore-scripts | |
| - name: Run backtest signing smoke | |
| run: node scripts/smoke-neural-trader-backtest-signing.mjs | |
| neural-trader-pipeline-smoke: | |
| # Regression guard for ruvnet/ruflo#2068 — ADR-126 Phase 5. | |
| # | |
| # Phase 5 refactors the four neural-trader agents (market-analyst, | |
| # trading-strategist, risk-analyst, backtest-engineer) into a typed | |
| # SendMessage pipeline with risk-analyst as a structural BLOCKING | |
| # GATE. The live broker call (`npx neural-trader --broker <name>`) | |
| # cannot fire without an explicit RiskDecision approval event from | |
| # risk-analyst for the proposal's signalId. | |
| # | |
| # Six load-bearing artifacts must stay in lockstep: | |
| # 1. `src/pipeline-messages.ts` — the three TypeScript message | |
| # schemas (RegimeVerdict, SignalProposal, RiskDecision) + | |
| # PipelineMessage discriminated union. | |
| # 2-5. `agents/{market-analyst,trading-strategist,risk-analyst,backtest-engineer}.md` | |
| # — frontmatter `name:` fields + Comms protocol sections with | |
| # the correct upstream/downstream wiring. | |
| # 6. `trading-strategist.md` — the structural risk-gate guard at | |
| # step 5 of the Strategy Development Workflow that refuses | |
| # `--broker` calls without a risk-analyst approval. | |
| # | |
| # The smoke runs four layers: | |
| # [1/4] AGENT FRONTMATTER — each .md declares `name: <agent>` so | |
| # the agent is SendMessage-addressable. | |
| # [2/4] COMMS PROTOCOL — each .md has a "Comms protocol" section | |
| # with the correct upstream/downstream references; backtest- | |
| # engineer documents its orthogonal-lane status. | |
| # [3/4] STRUCTURAL RISK-GATE — trading-strategist.md contains | |
| # explicit refusal logic: mentions `--broker`, requires | |
| # RiskDecision approval, declares REFUSAL, emits [ERROR], | |
| # marks the gate as NON-NEGOTIABLE/structural. | |
| # [4/4] BEHAVIORAL MOCK — drives a mock pipeline through a guard | |
| # function that mirrors the trading-strategist guard. Happy | |
| # path approves and executes; missing approval / rejected | |
| # decision / mismatched signalId are ALL refused. | |
| # | |
| # If a future PR drops the guard, removes a `name` field, breaks | |
| # the pipeline-messages schema, or rewrites a comms section without | |
| # the upstream/downstream wiring, this smoke catches it before merge. | |
| name: neural-trader pipeline risk-gate smoke (#2068, ADR-126 Phase 5) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Run pipeline risk-gate smoke | |
| run: node scripts/smoke-neural-trader-pipeline.mjs | |
| neural-trader-feature-attribution-smoke: | |
| # Regression guard for ruvnet/ruflo#2068 — ADR-126 Phase 6. | |
| # | |
| # Phase 6 ships regulator-grade feature attribution for LSTM / | |
| # Transformer trading signals. Given a `signalId`, the `trader-explain` | |
| # skill builds a feature-contribution graph, runs single-entry forward- | |
| # push PageRank from the signal output node (via | |
| # `mcp__ruflo-sublinear__page-rank-entry` when registered, local seeded | |
| # power-iteration fallback otherwise), and stores the top-K ranked | |
| # features as a `SignedAttributionArtifact` (the Phase 4 signing | |
| # scheme — same Ed25519 + CWE-347 trusted-pin pattern). | |
| # | |
| # Three load-bearing artifacts must stay in lockstep: | |
| # 1. `src/signed-attribution.ts` — the typed signer/verifier/PR | |
| # contract. | |
| # 2. `src/signed-attribution.mjs` — the runtime mirror imported by | |
| # the smoke + skill harnesses (zero build step). | |
| # 3. `skills/trader-explain/SKILL.md` — the call site that builds | |
| # the graph + signs the result + persists to `trading-analysis`. | |
| # | |
| # The smoke runs three layers: | |
| # [1/3] STATIC CONTRACT — TS/MJS export shape, verifier pins to | |
| # trustedPublicKey (CWE-347), graphMetadata.seed is part of | |
| # the typed shape, skill writes to `trading-analysis`, skill | |
| # documents the local fallback + the --explain fallback. | |
| # [2/3] CRYPTO ROUND-TRIP — Ed25519 signing fixture, tampered | |
| # feature score fails, tampered seed fails (seed is signed-in), | |
| # swapped served pubkey still verifies (pin is real). | |
| # [3/3] REPRODUCIBILITY — same seed → byte-identical PageRank | |
| # scores + identical top-K ordering. Different seed → scores | |
| # differ (proves the seed is load-bearing, not dead weight). | |
| # Mass conservation: scores sum to ~1. | |
| # | |
| # If a future PR breaks any of these properties — drops the verify | |
| # call, removes the seed from graphMetadata, reverts the seeded | |
| # initializer, drops the local fallback, or rewrites the skill | |
| # without the `trading-analysis` namespace — this smoke catches it | |
| # before merge. | |
| name: neural-trader feature attribution smoke (#2068, ADR-126 Phase 6) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Install root deps (for @noble/ed25519) | |
| run: npm install --legacy-peer-deps --no-audit --no-fund --ignore-scripts | |
| - name: Run feature attribution smoke | |
| run: node scripts/smoke-neural-trader-feature-attribution.mjs | |
| plugin-registry-signature-smoke: | |
| # Regression guard for ruvnet/ruflo#1922 (CWE-347 — improper verification | |
| # of cryptographic signature). The plugin-registry signature verifier in | |
| # v3/@claude-flow/cli/src/plugins/store/discovery.ts used to be a stub | |
| # that returned `true` whenever the served `registryPublicKey` field | |
| # started with `"ed25519"`. The call site only `console.warn`ed on | |
| # failure and continued. With `requireVerification: true` (the default), | |
| # a network adversary on the path to an IPFS gateway could swap the | |
| # served registry and have a user install attacker-controlled plugin | |
| # tarballs with filesystem+network+hooks permissions. | |
| # | |
| # This smoke runs three layers: | |
| # 1. Static contract check on discovery.ts — must import | |
| # `verifyEd25519Signature`, must strip both signature fields before | |
| # stringifying, must pin to caller-supplied `expectedPublicKey` | |
| # (not the served `registryPublicKey`), call site must `await` + | |
| # fail-closed. | |
| # 2. Crypto round-trip with real Ed25519, matching the signRegistry() | |
| # scheme in scripts/publish-registry.ts — valid signature passes, | |
| # tampered body fails, empty fields fail, swapped served key | |
| # doesn't defeat the trusted pin. | |
| # 3. Call-site byte check — the `requireVerification` block must | |
| # `await` the verifier AND `return` on failure (not just warn). | |
| # | |
| # If a future PR reverts to prefix-matching, drops the await, or | |
| # silently warns, this smoke catches it before merge. | |
| name: plugin-registry signature verification smoke (#1922, CWE-347) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Install root deps (for @noble/ed25519) | |
| run: npm install --legacy-peer-deps --no-audit --no-fund --ignore-scripts | |
| - name: Run plugin-registry signature smoke | |
| run: node scripts/smoke-plugin-registry-signature.mjs | |
| ruvllm-wasm-auto-init-smoke: | |
| # Regression guard for ruvnet/ruflo#2086 — ruvllm WASM bootstrap not | |
| # exposed via MCP. Reporter: @seo-yas. Every `ruvllm_*` MCP tool that | |
| # touches the WASM runtime calls `loadRuvllmWasm()` in | |
| # `v3/@claude-flow/cli/src/mcp-tools/ruvllm-tools.ts`. That helper used | |
| # to just `import(...)` the module and never call `initRuvllmWasm()`, | |
| # leaving `_wasmReady=false`. Result: `ruvllm_status` reported | |
| # `wasm.initialized=false` even after `ruvllm_sona_create` and | |
| # downstream sona/microlora/hnsw operations silently failed or | |
| # returned empty results. | |
| # | |
| # The fix wires `initRuvllmWasm()` into `loadRuvllmWasm()` (it's | |
| # idempotent — `_wasmReady` short-circuits subsequent calls). | |
| # `ruvllm_status` keeps a separate un-init `loadRuvllmWasmModule()` | |
| # path so diagnostics still report uninitialized state without | |
| # eagerly bootstrapping. | |
| # | |
| # This smoke statically asserts: | |
| # 1. `loadRuvllmWasm()` awaits `mod.initRuvllmWasm()`. | |
| # 2. `loadRuvllmWasmModule()` exists and does NOT init. | |
| # 3. `ruvllm_status` handler uses the un-init loader. | |
| # 4. Every WASM-touching ruvllm_* tool either routes through | |
| # `loadRuvllmWasm()` or looks up a pre-initialized instance. | |
| # 5. No new ruvllm_* tools have been added that bypass the gate. | |
| name: ruvllm WASM auto-init smoke (#2086) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Run ruvllm WASM auto-init smoke | |
| run: node scripts/smoke-ruvllm-wasm-auto-init.mjs | |
| agent-execute-providers-smoke: | |
| # Regression guard for ruvnet/ruflo#2042 — agent_execute hardcoded | |
| # the Anthropic SDK and ignored the v3 provider system. Reporter: | |
| # @ummcke00. Fix routes executeAgentTask through callAnthropicMessages | |
| # which dispatches Anthropic / OpenRouter / Ollama by env var. | |
| name: agent_execute provider routing smoke (#2042) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Run agent_execute providers smoke | |
| run: node scripts/smoke-agent-execute-providers.mjs | |
| memory-stats-legacy-db-smoke: | |
| # Regression guard for ruvnet/ruflo#2120 — `ruflo memory stats` and | |
| # `listEntries` returned 0 entries against a populated | |
| # `.swarm/memory.db` on WSL2 (reporter: @alexandrelealbess on | |
| # alpha.81). Root cause: the `WHERE status = 'active'` filter | |
| # excluded rows where the status column was NULL (legacy DBs | |
| # created before the status column existed, or via the auto-memory | |
| # bridge path that didn't set status). | |
| # | |
| # Fix: (1) accept `status IS NULL` alongside `'active'` in both | |
| # bridgeListEntries and listEntries; (2) backfill `UPDATE | |
| # memory_entries SET status = 'active' WHERE status IS NULL` in | |
| # ensureSchemaColumns; (3) broaden `isInitialized()` in | |
| # `status.ts` to also accept `.swarm/memory.db` existence. | |
| # | |
| # This smoke builds a 251-entry DB with all-NULL status (mirroring | |
| # the reporter's setup), runs listEntries, and asserts total === 251 | |
| # AND that the backfill promoted all rows to 'active'. | |
| name: memory stats legacy-DB smoke (#2120) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Setup pnpm (workspace-aware install) | |
| uses: pnpm/action-setup@v6 | |
| with: | |
| version: 8 | |
| - name: Install root deps (sql.js for the smoke fixture) | |
| # The smoke creates a `.swarm/memory.db` fixture using `sql.js` | |
| # imported from the repo root. Root has no `workspace:*` deps, | |
| # so plain npm works here. | |
| run: npm install --legacy-peer-deps --no-audit --no-fund --ignore-scripts | |
| - name: Install workspace deps + build CLI (pnpm — `workspace:*` protocol) | |
| # `cd v3/@claude-flow/cli && npm install` errors with | |
| # `EUNSUPPORTEDPROTOCOL: Unsupported URL Type "workspace:"` because | |
| # npm doesn't understand workspace:*. The pnpm workspace root is | |
| # `v3/pnpm-workspace.yaml`. The CLI's tsc references project-refs to | |
| # @claude-flow/swarm (and others), so those must be built first — | |
| # `pnpm --filter @claude-flow/cli build` alone fails with TS6305. | |
| # `--recursive --no-bail` builds the whole graph in topological order | |
| # past unrelated package failures; we then assert the specific dist | |
| # file the smoke imports. | |
| working-directory: v3 | |
| run: | | |
| pnpm install --frozen-lockfile=false --ignore-scripts | |
| pnpm --recursive --no-bail run build || true | |
| test -f @claude-flow/cli/dist/src/memory/memory-initializer.js \ | |
| || (echo "CLI build did not produce memory-initializer.js"; exit 1) | |
| - name: Run memory stats legacy-DB smoke | |
| run: node scripts/smoke-memory-stats-legacy-db.mjs | |
| memory-no-stray-db-smoke: | |
| # Regression guard for ADR-125 Phase 7 — vitest.setup.ts in | |
| # @claude-flow/memory must wipe any *.db / *.db-journal / *.db-wal / | |
| # *.rvf / *.redb files written by agentdb / @ruvector/rvf native | |
| # bindings during the test run. This smoke: | |
| # 1. records `git status --porcelain` baseline in v3/@claude-flow/memory | |
| # 2. runs `npm test` inside that package | |
| # 3. asserts no net-new DB-like artifacts appeared after the run | |
| # A failure here means vitest.setup.ts stopped cleaning up, or a new | |
| # binding started writing to a path not covered by LEAK_SUFFIXES. | |
| name: memory no-stray-db smoke (ADR-125 P7) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: 8 | |
| - name: Install workspace deps (pnpm — @claude-flow/memory pulled in workspace:* deps) | |
| # @claude-flow/memory now depends on sibling workspace packages via | |
| # workspace:* protocol, so plain npm install fails with | |
| # EUNSUPPORTEDPROTOCOL. We MUST run install scripts (no --ignore-scripts) | |
| # because the smoke runs `npm test` which opens better-sqlite3 via | |
| # native bindings — the .node addon comes from better-sqlite3's | |
| # prebuild-install postinstall step. | |
| working-directory: v3 | |
| run: | | |
| pnpm install --frozen-lockfile=false | |
| pnpm --recursive --no-bail run build || true | |
| # Belt-and-suspenders: explicit rebuild in case prebuild-install was skipped | |
| pnpm rebuild better-sqlite3 || true | |
| - name: Run memory no-stray-db smoke | |
| run: node scripts/smoke-memory-no-stray-db.mjs | |
| github-safe-injection-smoke: | |
| # Regression guard for ruvnet/ruflo#2089 — ADR-127 Phase 1. | |
| # | |
| # Drives adversarial PR/issue bodies (backticks, $(), semicolons, | |
| # >256KB, empty) through github-safe.js and asserts the body lands in a | |
| # temp file verbatim rather than being passed inline to `gh`. Inline | |
| # interpolation of untrusted body content into shell arguments is the | |
| # prompt-injection vector closed by the swarm-pr.md / swarm-issue.md | |
| # fix in Phase 2. This smoke ensures github-safe.js itself always writes | |
| # the temp file and passes --body-file rather than --body. | |
| # | |
| # Runs against both copies: | |
| # - .claude/helpers/github-safe.js (dogfood) | |
| # - v3/@claude-flow/cli/.claude/helpers/ (init-template) | |
| name: github-safe injection smoke (#2089, ADR-127 Phase 1) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Run github-safe injection smoke | |
| run: node scripts/smoke-github-safe-injection.mjs | |
| github-actions-pins-smoke: | |
| # Static contract guard for ruvnet/ruflo#2089 — ADR-127 Phase 1. | |
| # | |
| # Scans every `uses:` line in: | |
| # .claude/agents/github/*.md | |
| # .claude/skills/github-[name]/SKILL.md | |
| # v3/@claude-flow/cli/.claude/commands/github/[name].md | |
| # | |
| # Asserts each ref is either SHA-pinned (40-hex) or present in | |
| # .github/supply-chain/allowed-deps.json actions.allowed[]. | |
| # | |
| # This smoke catches any future commit that copies @v3 snippets from | |
| # blog posts into the skill files — the most common doc-drift pattern. | |
| # Phase 3 upgrades all @v3 refs to @v4; this smoke is the regression | |
| # gate that prevents them from drifting back. | |
| name: github actions pin smoke (#2089, ADR-127 Phase 1) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Run github actions pin smoke | |
| run: node scripts/smoke-github-actions-pins.mjs | |
| github-deprecated-actions-smoke: | |
| # Regression guard for ruvnet/ruflo#2089 — ADR-127 Phase 3. | |
| # | |
| # Scans every `uses:` line in the same scope as the pins smoke and | |
| # fails if any deprecated action ref is still present: | |
| # - actions/checkout@v3 (v4 available since Nov 2023) | |
| # - actions/setup-node@v3 (v4 available since Nov 2023) | |
| # - actions/create-release@* (deprecated; replaced by gh CLI) | |
| # - actions/upload-release-asset@* (deprecated; replaced by gh CLI) | |
| # - softprops/action-gh-release@v1 (v1 has known CVEs; use @v2) | |
| # | |
| # Phase 3 bumps all @v3 refs to @v4. This smoke is the regression gate | |
| # that prevents them from drifting back via copy-paste from blog posts | |
| # or AI-generated snippets that still reference the old versions. | |
| name: github deprecated actions smoke (#2089, ADR-127 Phase 3) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Run deprecated-actions smoke | |
| run: node scripts/smoke-deprecated-actions.mjs | |
| github-attribution-opt-in-smoke: | |
| # Regression guard for ruvnet/ruflo#2089 — ADR-127 Phase 4. | |
| # | |
| # Phase 4 removes hardcoded "Generated with Claude Code" attribution | |
| # strings from the static github command templates. Attribution is now | |
| # opt-in via --attribution / options.attribution=true (#1670 / #2089). | |
| # Hard-wired footers silently added a third-party Co-Authored-By line | |
| # to every user's commits and were impossible to undo without rewriting | |
| # git history. | |
| # | |
| # This smoke scans the same three trees as the pins smoke and fails if | |
| # the "Generated with" emoji pattern reappears — preventing copy-paste | |
| # regression from blog posts or AI-generated snippets. | |
| name: github attribution opt-in smoke (#2089, ADR-127 Phase 4) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Run attribution opt-in smoke | |
| run: node scripts/smoke-attribution-opt-in.mjs | |
| pre-bash-hook-smoke: | |
| # Regression guard for ruvnet/ruflo#2017 — the `pre-bash` PreToolUse hook | |
| # in `.claude/helpers/hook-handler.cjs` is a security gate that refuses to | |
| # run dangerous commands (`rm -rf /`, fork bombs, etc.). In 3.6.30 it | |
| # silently exited 0 on every dangerous payload because the handler read | |
| # the wrong stdin field (`toolInput` object instead of | |
| # `toolInput.command` string), `.toLowerCase()` threw TypeError, and the | |
| # global safety-timer try/catch swallowed it — printing a misleading | |
| # "[OK] Command validated" while letting the dangerous command through. | |
| # | |
| # This smoke drives real Claude-Code-shaped PreToolUse JSON into BOTH | |
| # the published template (v3/@claude-flow/cli/.claude/helpers/) and the | |
| # repo's dogfood copy (.claude/helpers/), and fails on any of: | |
| # - dangerous command + exit 0 (the security bypass) | |
| # - "[OK] Command validated" on a dangerous input (the misleading log) | |
| # - "[WARN] Hook X encountered an error" anywhere (silent-swallow shape) | |
| # | |
| # Independent job (not nested in plugin-hooks-smoke) so the gate is | |
| # individually visible and the CI summary names the failure clearly. | |
| name: pre-bash hook safety smoke (#2017) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Drive Claude-Code-shaped PreToolUse JSON through both handler copies | |
| shell: bash | |
| run: node scripts/smoke-pre-bash-hook.mjs | |
| mcp-protocol-smoke: | |
| # Regression guard for ruvnet/ruflo#1874 — boots the HTTP MCP server, | |
| # sends a real `initialize` request, and validates the response wire | |
| # format against the MCP spec (YYYY-MM-DD protocolVersion string, | |
| # not a {major,minor,patch} object). This was the missing layer that | |
| # let #1874 ship — the existing in-process unit tests asserted the | |
| # wrong shape, so test+prod agreed on a non-spec format that broke | |
| # Claude Code's Zod validator. | |
| name: MCP protocol smoke / ${{ matrix.os }} | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v6 | |
| with: | |
| version: ${{ env.PNPM_VERSION }} | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| cache: 'pnpm' | |
| cache-dependency-path: v3/pnpm-lock.yaml | |
| - name: Build mcp + shared packages (static scan needs dist) | |
| working-directory: v3 | |
| shell: bash | |
| run: | | |
| pnpm install --frozen-lockfile | |
| pnpm --filter @claude-flow/mcp... --filter @claude-flow/shared... run build | |
| - name: Run MCP protocol-shape compliance scan | |
| shell: bash | |
| run: node plugins/ruflo-core/scripts/test-mcp-protocol.mjs | |
| memory-import-smoke: | |
| # Regression guard for ruvnet/ruflo#1883 + #1884 — drives the import-side | |
| # invariants that single-component tests missed: | |
| # #1883 — memory_import_claude(allProjects=false) failed on WSL because | |
| # project-hash derivation was POSIX-only. Verified via candidate | |
| # set including the Claude-Code Windows hash form. | |
| # #1884 — import handler skipped validateMemoryInput, producing keys | |
| # memory_delete then rejected. Verified via property test | |
| # against 27 adversarial inputs covering the full | |
| # dangerous-character set. | |
| # Static dist scan + property test combined cover the bug class. | |
| name: Memory import smoke / ${{ matrix.os }} | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v6 | |
| with: | |
| version: ${{ env.PNPM_VERSION }} | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| cache: 'pnpm' | |
| cache-dependency-path: v3/pnpm-lock.yaml | |
| - name: Build packages (static scan needs cli dist) | |
| working-directory: v3 | |
| shell: bash | |
| run: | | |
| pnpm install --frozen-lockfile | |
| # Mirror witness-verify pattern — recursive + no-bail so unrelated | |
| # package failures don't block this guard. The smoke script | |
| # explicitly checks for memory-tools.js dist and fails loudly if | |
| # the cli build itself didn't produce it. | |
| pnpm --recursive --no-bail run build || true | |
| - name: Run memory-import regression guards (#1883 + #1884) | |
| shell: bash | |
| run: node plugins/ruflo-core/scripts/test-memory-import.mjs | |
| mcp-roundtrip-smoke: | |
| # Regression guard for ruvnet/ruflo#1889 — paired MCP tool round-trip. | |
| # When two MCP tools form a store/search pair, the contract is that | |
| # data written by one MUST be retrievable by the other. The original | |
| # bug: pattern-store wrote to memory-store-fallback while pattern-search | |
| # only queried ReasoningBank (always empty), so writes were silently | |
| # lost. Static dist-scan asserts both fallback paths are present; | |
| # behavioural probe runs with an internal 30s timeout so CI never hangs | |
| # on slow memory-backend init. | |
| name: MCP paired-tool round-trip smoke (#1889) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v6 | |
| with: | |
| version: ${{ env.PNPM_VERSION }} | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| cache: 'pnpm' | |
| cache-dependency-path: v3/pnpm-lock.yaml | |
| - name: Build cli (smoke needs dist) | |
| working-directory: v3 | |
| shell: bash | |
| run: | | |
| pnpm install --frozen-lockfile | |
| pnpm --recursive --no-bail run build || true | |
| - name: Run #1889 round-trip smoke | |
| shell: bash | |
| run: node plugins/ruflo-core/scripts/test-mcp-roundtrips.mjs | |
| - name: Run #1863 cli-no-crash smoke | |
| shell: bash | |
| # Drives `task create` → `task status` + a few command formatters | |
| # and asserts none crash with an unhandled exception. Catches the | |
| # class where callMCPTool<{...}>() types a response field as | |
| # non-optional but the server omits it → `.join()` on undefined. | |
| run: node plugins/ruflo-core/scripts/test-cli-no-crash.mjs | |
| - name: Run ADR-095 G2 consensus-transport guard | |
| shell: bash | |
| # Asserts @claude-flow/swarm ships a real pluggable ConsensusTransport | |
| # (not the implicit single-process EventEmitter): required exports | |
| # present, LocalTransport round-trip works, Ed25519 sign/verify is | |
| # real (no `return true` stub regression). ADR-095 G2. | |
| run: node plugins/ruflo-core/scripts/test-consensus-transport.mjs | |
| tool-descriptions-audit: | |
| # ADR-112 — gate: every MCP tool description must include "Use when …" | |
| # guidance so Claude knows when to pick Ruflo's tool over native | |
| # (Bash, Read, Grep, Glob, Task, TodoWrite, WebFetch). Baseline lives | |
| # in verification/mcp-tool-baseline.json and is monotone-decreasing — | |
| # the script fails the build if the no-guidance count goes UP. Run | |
| # `node scripts/audit-tool-descriptions.mjs --update-baseline` after | |
| # landing a description-improvement PR to lock the new floor. | |
| name: Tool description discoverability (ADR-112) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Run tool-description audit | |
| shell: bash | |
| run: node scripts/audit-tool-descriptions.mjs | |
| - name: Run CLI ↔ MCP tool coverage audit (#1916) | |
| # Fails if a `ruflo <cmd>` subcommand callMCPTool()s a tool that isn't | |
| # registered in src/mcp-tools/*.ts (it would die with `MCP tool not | |
| # found`). Monotone-decreasing baseline at verification/cli-mcp-tool- | |
| # baseline.json — new dangling references fail; fixing one and running | |
| # `node scripts/audit-cli-mcp-tools.mjs --update-baseline` lowers the floor. | |
| shell: bash | |
| run: node scripts/audit-cli-mcp-tools.mjs | |
| plugin-package-audit: | |
| # Regression guard for #1902/#1903/#1904 — plugin package.json install | |
| # safety. Checks: (A) no unpublished @claude-flow/* hard dep / non-optional | |
| # peer, (B) no bare-stable peer range that can't resolve a 3.x prerelease | |
| # publish, (C) every main/module/exports path is covered by `files`, | |
| # (D) after building each plugin, every main/module/exports path exists on | |
| # disk (#1904). The build step is what makes check D live. | |
| name: Plugin package install-safety (#1902/#1903/#1904) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v6 | |
| with: | |
| version: ${{ env.PNPM_VERSION }} | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| cache: 'pnpm' | |
| cache-dependency-path: v3/pnpm-lock.yaml | |
| - name: Install root deps (semver for audit-wrapper-dep-ranges) | |
| # The audit-wrapper-dep-ranges.mjs script imports `semver` from the | |
| # repo root node_modules. Run a root npm install BEFORE the audit | |
| # job's main install/build step. | |
| shell: bash | |
| run: npm install --legacy-peer-deps --no-audit --no-fund --ignore-scripts | |
| - name: Install workspace + build plugins (so check D — exports-exist-after-build — is live) | |
| working-directory: v3 | |
| shell: bash | |
| run: | | |
| pnpm install --frozen-lockfile | |
| for d in plugins/*/; do | |
| if [ -f "$d/package.json" ] && node -e "process.exit(require('./'+process.argv[1]+'package.json').scripts?.build?0:1)" "$d"; then | |
| echo "::group::build $d" | |
| ( cd "$d" && pnpm install --frozen-lockfile 2>/dev/null || pnpm install 2>/dev/null || true; pnpm run build || true ) | |
| echo "::endgroup::" | |
| fi | |
| done | |
| - name: Run plugin package audit | |
| shell: bash | |
| run: node scripts/audit-plugin-packages.mjs | |
| - name: Run package dep-overlap audit (#1147 / #2018) | |
| # Static guard for the "Invalid Version: " npm 11.x crash. Any package | |
| # declaring the same dep name in both optionalDependencies AND | |
| # peerDependencies trips arborist's dedupe pass when a transitive | |
| # carries a "-dev." prerelease tag. Fail CI on the overlap. | |
| shell: bash | |
| run: node scripts/audit-package-dep-overlap.mjs | |
| - name: Run wrapper dep-range audit (#2127) | |
| # Catches stale alpha-tagged dep ranges in the ruflo wrapper and the | |
| # claude-flow umbrella that point at sibling packages we publish. | |
| # #2127 shipped with `ruflo → @claude-flow/cli@^3.7.0-alpha.11` even | |
| # after cli moved to stable 3.10.0 — a pre-release range against a | |
| # stable dep widens arborist's dedupe walk and can surface as the | |
| # "Invalid Version: (empty)" crash on some npm/Node combos. | |
| shell: bash | |
| run: node scripts/audit-wrapper-dep-ranges.mjs | |
| - name: Run umbrella version-lockstep audit (#2151) | |
| # Asserts @claude-flow/cli, claude-flow, and ruflo all share the | |
| # same version. #2151 reported ruflo@3.10.2 + cli@3.10.1 drift — | |
| # `npx ruflo --version` printed the bundled CLI's 3.10.1, not the | |
| # wrapper's 3.10.2. CLAUDE.md publish rules already require lockstep; | |
| # this audit enforces it so drift can't reach a release. | |
| shell: bash | |
| run: node scripts/audit-umbrella-version-lockstep.mjs | |
| - name: Run better-sqlite3 override audit (#2219) | |
| # agentdb pins better-sqlite3 as an OPTIONAL dep at ^11.8.1, which has | |
| # no Node 24/25/26 prebuild → the optional native build fails silently | |
| # on those runtimes and AgentDB drops to a non-persistent backend | |
| # (silent write loss). Asserts both the root umbrella and the ruflo | |
| # wrapper override better-sqlite3 to >=12.8.0 (which ships Node 20–26 | |
| # prebuilds). Root overrides do NOT reach the published wrapper (#2112), | |
| # so both must carry it. | |
| shell: bash | |
| run: node scripts/audit-better-sqlite3-override.mjs | |
| - name: Run plugin-hooks cross-platform audit (#2132) | |
| # Catches /bin/bash literals, POSIX-only pipelines (jq, xargs, tr), | |
| # and .sh script invocations in plugin hooks.json files — patterns | |
| # that fail on native Windows (exit 126). | |
| # Files with "_platform": "posix" are exempt (Mac/Linux-only, verified | |
| # to have a companion ruflo-hook.cjs Windows shim). New hooks.json | |
| # files without the marker are scanned strictly. | |
| # Strict (no continue-on-error) — fixed in PR fix/2132-windows-hooks. | |
| shell: bash | |
| run: node scripts/audit-plugin-hooks-cross-platform.mjs | |
| - name: Run env-var-precedence audit (ADR-125 / ADR-130) | |
| # Guards the "CLI flag > ENV var > default" precedence rule added in | |
| # ADR-125 (rvagent integration) and ADR-130 (graph intelligence). | |
| # Scans v3/cli/src and plugins/ for any CLAUDE_FLOW_* / RUFLO_* env | |
| # var read that lacks a documented CLI-flag override path or is not | |
| # registered as an intentional escape hatch (CI/credential/process | |
| # signal). Fails closed (exit 1) — prevents future contributors from | |
| # silently ignoring explicit CLI flags when an env var is set. | |
| # Strict (no continue-on-error). | |
| shell: bash | |
| run: node scripts/audit-env-var-precedence.mjs | |
| cli-npx-install-smoke: | |
| # Regression guard for ruvnet/ruflo#1147 and #2018 — both report: | |
| # $ npx @claude-flow/cli@latest … | |
| # npm error Invalid Version: | |
| # Caused by an optionalDependencies/peerDependencies overlap deep in the | |
| # dep tree (see scripts/audit-package-dep-overlap.mjs for the static | |
| # guard). This is the BEHAVIOURAL guard: pack the locally-built CLI, | |
| # install the tarball into a scratch project, fail if `npm install` | |
| # prints "Invalid Version" or exits non-zero. Runs on Node 22 + 24 so | |
| # the newer npm shipped with Node 24 (where the bug surfaces) is | |
| # actually exercised. | |
| name: CLI npx-install smoke (#1147 / #2018) / Node ${{ matrix.node }} | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| node: ['22', '24'] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v6 | |
| with: | |
| version: ${{ env.PNPM_VERSION }} | |
| - name: Setup Node.js ${{ matrix.node }} | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ matrix.node }} | |
| cache: 'pnpm' | |
| cache-dependency-path: v3/pnpm-lock.yaml | |
| - name: Build cli (smoke packs from its dist/) | |
| working-directory: v3 | |
| shell: bash | |
| run: | | |
| pnpm install --frozen-lockfile | |
| pnpm --recursive --no-bail run build || true | |
| test -f @claude-flow/cli/bin/cli.js \ | |
| || (echo "cli build did not produce bin/cli.js"; exit 1) | |
| - name: Pack, install, and run cli (asserts no 'Invalid Version' crash) | |
| shell: bash | |
| run: node scripts/smoke-cli-npx-install.mjs | |
| windows-hook-shim-smoke: | |
| # Smoke test for ruvnet/ruflo#2132 — ruflo-hook.cjs cross-platform shim. | |
| # Proves that plugins/ruflo-core/scripts/ruflo-hook.cjs can be invoked | |
| # via `node ruflo-hook.cjs <subcommand>`, always exits 0, and accepts | |
| # stdin JSON input without crashing. | |
| # Runs on all 3 OS to prove cross-platform behaviour. | |
| name: Windows hook shim smoke (#2132) / ${{ matrix.os }} | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Run ruflo-hook.cjs smoke | |
| shell: bash | |
| run: node scripts/smoke-ruflo-hook-cjs.mjs | |
| windows-init-hooks-smoke: | |
| # Smoke test for ruvnet/ruflo#2132 — init-time platform detection. | |
| # Proves ruflo init generates correct hook commands per platform: | |
| # - windows-latest: node-based (no /bin/bash, no | jq) | |
| # - ubuntu/macos: POSIX-compatible (sh-based, no cmd.exe patterns) | |
| # Also verifies ruflo-hook.cjs is always deployed to .claude/helpers/. | |
| name: Windows init hooks smoke (#2132) / ${{ matrix.os }} | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v6 | |
| with: | |
| version: ${{ env.PNPM_VERSION }} | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| cache: 'pnpm' | |
| cache-dependency-path: v3/pnpm-lock.yaml | |
| - name: Build CLI | |
| working-directory: v3 | |
| shell: bash | |
| run: | | |
| pnpm install --frozen-lockfile | |
| pnpm --recursive --no-bail run build || true | |
| # --no-bail lets unrelated workspace failures pass; assert the | |
| # one dist file the smoke needs is actually produced. | |
| test -f @claude-flow/cli/bin/cli.js \ | |
| || (echo "::error::cli build did not produce bin/cli.js"; exit 1) | |
| - name: Run init hooks smoke | |
| shell: bash | |
| run: node scripts/smoke-windows-init-hooks.mjs | |
| windows-hook-execution-smoke: | |
| # End-to-end validation for ruvnet/ruflo#2132 — simulates a Claude Code | |
| # PostToolUse hook firing. Asserts exit code != 126 ("cannot execute | |
| # binary file") and no POSIX-only pipeline patterns in the generated | |
| # settings.json hook commands. | |
| # Primary target: windows-latest (the OS that originally broke). | |
| # Also runs on ubuntu/macos to catch POSIX regression. | |
| name: Windows hook execution smoke (#2132) / ${{ matrix.os }} | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v6 | |
| with: | |
| version: ${{ env.PNPM_VERSION }} | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| cache: 'pnpm' | |
| cache-dependency-path: v3/pnpm-lock.yaml | |
| - name: Build CLI | |
| working-directory: v3 | |
| shell: bash | |
| run: | | |
| pnpm install --frozen-lockfile | |
| pnpm --recursive --no-bail run build || true | |
| - name: Run Windows hook execution smoke | |
| shell: bash | |
| run: node scripts/smoke-windows-hook-execution.mjs | |
| hook-command-audit: | |
| # Regression guard for #1921 (and #1147) — plugin hooks.json must not | |
| # invoke a bare `npx <pkg>@alpha hooks …` per fire. The fix is | |
| # scripts/ruflo-hook.sh (prefers a local `ruflo`/`claude-flow` binary, | |
| # falls back to `npx --prefer-offline`, always exits 0). | |
| name: Hook-command install safety (#1921) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Run hook-command audit | |
| shell: bash | |
| run: node scripts/audit-hook-commands.mjs | |
| - name: Run hook-handler prompt-resolution audit (#1944) | |
| shell: bash | |
| run: node scripts/audit-hook-handler-prompt.mjs | |
| - name: Run fix-invariants audit (presence-check guard for #1939, #1941, #1943, #1945, #1946, #1951, #1953, #1968) | |
| shell: bash | |
| run: node scripts/audit-fix-invariants.mjs | |
| - name: Run neural-trader install-safety audit (#1974) | |
| shell: bash | |
| run: node scripts/audit-neural-trader-safety.mjs | |
| - name: Lint the ruflo-hook shims | |
| shell: bash | |
| run: | | |
| # Every shim must be valid bash and exit 0 even when no CLI is | |
| # reachable (the #1921 contract). Probe with an empty PATH (invoke | |
| # bash by full path since PATH= can't find it otherwise). | |
| BASH="$(command -v bash)" | |
| for sh in $(git ls-files '**/scripts/ruflo-hook.sh'); do | |
| echo "checking $sh" | |
| bash -n "$sh" | |
| PATH= "$BASH" "$sh" modify-bash </dev/null || { echo "::error::$sh did not exit 0 with no CLI on PATH"; exit 1; } | |
| done | |
| vector-dim-audit: | |
| # Regression guard for #1947 / #1942 / #1952 — `vector_indexes` rows for | |
| # the `default` and `patterns` namespaces must use `dimensions = 384` to | |
| # match the default ONNX embedding model (Xenova/all-MiniLM-L6-v2). A | |
| # mismatched dim (the historical 768) is silent: HNSW rejects every | |
| # `memory_store --vector` insert and `memory_search` always returns 0. | |
| name: Vector-index dimension audit (#1947) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Run vector-dim audit | |
| shell: bash | |
| run: node scripts/audit-vector-dim.mjs | |
| tool-output-guardrail-smoke: | |
| # Smoke test for ADR-131 / ruvnet/ruflo#2149 — ToolOutputGuardrail | |
| # detects the four canonical OWASP ASI01 (Agent Goal Hijacking) attack | |
| # shapes (instruction override, ChatML/Llama frame injection, exfiltration) | |
| # and enforces the documented default policy (critical→reject, | |
| # high→redact, medium→flag, low/none→allow). | |
| # | |
| # The exhaustive behavioural surface is the package's vitest suite; this | |
| # smoke runs against the *built* dist/index.js to catch missing exports | |
| # or accidental relaxation of the default policy. | |
| name: ToolOutputGuardrail smoke (ADR-131, #2149) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v6 | |
| with: | |
| version: ${{ env.PNPM_VERSION }} | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| cache: 'pnpm' | |
| cache-dependency-path: v3/pnpm-lock.yaml | |
| - name: Build @claude-flow/security | |
| working-directory: v3 | |
| shell: bash | |
| run: | | |
| pnpm install --frozen-lockfile | |
| pnpm --filter @claude-flow/security run build | |
| test -f @claude-flow/security/dist/index.js \ | |
| || (echo "::error::@claude-flow/security/dist/index.js missing after build"; exit 1) | |
| node @claude-flow/security/scripts/verify-oauth-exports.mjs | |
| - name: Run guardrail smoke | |
| shell: bash | |
| run: node scripts/smoke-tool-output-guardrail.mjs | |
| witness-verify: | |
| # Cryptographic regression guard: runs `ruflo verify --manifest` against | |
| # the local build to confirm every documented fix in verification.md.json | |
| # still has its marker present. Catches silent regression of any of the | |
| # 81+ fixes without requiring per-fix smoke tests. | |
| # | |
| # The smoke jobs above (smoke-install-no-bsqlite, plugin-hooks-smoke) | |
| # exercise *behavior*; this job validates *presence* — both layers | |
| # combined are what gates `publish`. | |
| # | |
| # Builds the cli + memory + security packages specifically (the ones | |
| # whose dist files are referenced by witness markers). Avoids depending | |
| # on the workspace `build` job so unrelated package failures don't | |
| # block this regression guard. | |
| # | |
| # Cross-platform: ubuntu + macos + windows. The standalone verifier | |
| # is pure JS (only @noble/ed25519) — no native deps, no shell calls. | |
| # Catches platform-specific JSON canonicalization or path-resolution | |
| # bugs (e.g. CRLF normalization on Windows breaking the manifest | |
| # hash) before they reach users. | |
| name: Witness verify (signed manifest) / ${{ matrix.os }} | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| needs: [smoke-install-no-bsqlite, plugin-hooks-smoke, pre-bash-hook-smoke, witness-verify-precondition-smoke, witness-marker-drift-smoke, browser-rvf-create-flags-smoke, mcp-protocol-smoke, memory-import-smoke, tool-descriptions-audit, mcp-roundtrip-smoke, plugin-package-audit, cli-npx-install-smoke, hook-command-audit, vector-dim-audit, windows-hook-shim-smoke, windows-init-hooks-smoke, windows-hook-execution-smoke] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v6 | |
| with: | |
| version: ${{ env.PNPM_VERSION }} | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| cache: 'pnpm' | |
| cache-dependency-path: v3/pnpm-lock.yaml | |
| - name: Install + build packages witness markers reference | |
| working-directory: v3 | |
| shell: bash | |
| run: | | |
| pnpm install --frozen-lockfile | |
| # --no-bail tolerates unrelated package failures. The standalone | |
| # verify.mjs below checks specific dist files exist; if a | |
| # marker-cited file is missing, witness-verify reports it. | |
| pnpm --recursive --no-bail run build || true | |
| - name: Verify witness manifest (via standalone plugin script — no CLI dep) | |
| # `shell: bash` makes Windows use git-bash so the same script | |
| # works across all 3 OSes. RUNNER_TEMP is set on every runner. | |
| shell: bash | |
| run: | | |
| # Use the project-agnostic verifier from ruflo-core plugin. This | |
| # is the same script external adopters use — dogfooding ensures | |
| # the plugin pathway works and avoids CI-specific cli build | |
| # issues (e.g. missing @ruvector/sona, sharp native postinstall). | |
| # Capture both streams; analyze regardless of exit code so we | |
| # always see WHY a verification failed. | |
| # OS-specific manifest path (verification/<os>/manifest.md.json). | |
| # Each runner reads its own snapshot — Linux runner reads | |
| # verification/linux/, macOS reads verification/macos/, etc. | |
| case "$RUNNER_OS" in | |
| Linux) OS_DIR=linux ;; | |
| macOS) OS_DIR=macos ;; | |
| Windows) OS_DIR=windows ;; | |
| *) OS_DIR=linux ;; | |
| esac | |
| MANIFEST="verification/$OS_DIR/manifest.md.json" | |
| echo "verifying: $MANIFEST" | |
| set +e | |
| node plugins/ruflo-core/scripts/witness/verify.mjs \ | |
| --manifest "$MANIFEST" \ | |
| --json > "$RUNNER_TEMP/witness-result.json" 2> "$RUNNER_TEMP/witness-result.err" | |
| VERIFY_EXIT=$? | |
| set -e | |
| echo "--- verify.mjs exit code: $VERIFY_EXIT ---" | |
| echo "--- stderr ---" | |
| cat "$RUNNER_TEMP/witness-result.err" || true | |
| echo "--- summary ---" | |
| node -e " | |
| const fs = require('fs'); | |
| const raw = fs.readFileSync(process.env.RUNNER_TEMP + '/witness-result.json', 'utf8'); | |
| if (!raw.trim()) { console.error('verify.mjs produced no JSON output'); process.exit(1); } | |
| const r = JSON.parse(raw); | |
| console.log(JSON.stringify({signature: r.signature, summary: r.summary}, null, 2)); | |
| const failures = (r.results || []).filter(x => x.status !== 'pass' && x.status !== 'drift'); | |
| if (failures.length) { | |
| console.error('non-pass fixes:'); | |
| for (const f of failures) console.error(' ' + f.status + ': ' + f.id + ' (' + f.file + ')'); | |
| } | |
| if (!r.ok) { console.error('witness verify FAILED'); process.exit(1); } | |
| if (r.summary.regressed > 0) { console.error('regressed fixes:', r.summary.regressed); process.exit(1); } | |
| console.log('witness verify ok:', r.summary.pass, 'pass,', r.summary.drift, 'drift'); | |
| " | |
| - name: Performance verification (lightweight capabilities only) | |
| # Soft gate: appends to verification/<os>/performance.jsonl. Skips | |
| # install_no_optional + memory_round_trip in CI to keep the matrix | |
| # fast — those are slow + network/disk-bound and add minutes. | |
| # Local devs run the full suite with `--capabilities all` (omitted). | |
| shell: bash | |
| run: | | |
| case "$RUNNER_OS" in | |
| Linux) OS_DIR=linux ;; | |
| macOS) OS_DIR=macos ;; | |
| Windows) OS_DIR=windows ;; | |
| esac | |
| node plugins/ruflo-core/scripts/witness/perf.mjs \ | |
| --output "verification/$OS_DIR/performance.jsonl" \ | |
| --capabilities install_pack,memory_load,witness_verify \ | |
| --baseline || echo "perf bench errored — non-blocking" | |
| - name: History summary (ADR-103 — surface regression-introduction commits) | |
| # Soft gate: prints transitions since the previous snapshot. The | |
| # `summary` subcommand exits non-zero on any newly-regressed fix. | |
| shell: bash | |
| run: | | |
| case "$RUNNER_OS" in | |
| Linux) OS_DIR=linux ;; | |
| macOS) OS_DIR=macos ;; | |
| Windows) OS_DIR=windows ;; | |
| *) OS_DIR=linux ;; | |
| esac | |
| HISTORY="verification/$OS_DIR/history.jsonl" | |
| if [ -f "$HISTORY" ]; then | |
| node plugins/ruflo-core/scripts/witness/history.mjs \ | |
| --history "$HISTORY" \ | |
| summary | |
| else | |
| echo "$HISTORY not present — skipping temporal diff" | |
| fi | |
| publish: | |
| name: Publish to npm (alpha) | |
| runs-on: ubuntu-latest | |
| needs: [build, smoke-install-no-bsqlite, plugin-hooks-smoke, witness-verify] | |
| if: github.ref == 'refs/heads/v3' && github.event_name == 'push' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v6 | |
| with: | |
| version: ${{ env.PNPM_VERSION }} | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| registry-url: 'https://registry.npmjs.org' | |
| cache: 'pnpm' | |
| cache-dependency-path: v3/pnpm-lock.yaml | |
| - name: Install dependencies | |
| working-directory: v3 | |
| run: pnpm install --frozen-lockfile | |
| - name: Build | |
| working-directory: v3 | |
| run: pnpm build | |
| - name: Publish alpha | |
| working-directory: v3 | |
| run: pnpm publish:alpha | |
| env: | |
| NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} | |
| init-bundle-invariants-smoke: | |
| # Regression guard for ruvnet/ruflo#2095 — ADR-128 Phase 5. | |
| # | |
| # Statically asserts three invariants of the @claude-flow/cli init bundle: | |
| # | |
| # 1. NO ORPHANED DIRECTORIES — every subdirectory under | |
| # v3/@claude-flow/cli/.claude/{commands,agents}/ is reachable from | |
| # COMMANDS_MAP or AGENTS_MAP in executor.ts. | |
| # | |
| # 2. SKILLS_MAP COMPLETENESS — every skill referenced in SKILLS_MAP | |
| # has a SKILL.md (or README.md) inside the package's .claude/skills/. | |
| # | |
| # 3. NO INIT-PLUGIN AGENT COLLISION — no .md in the init-template | |
| # agents/ shares a basename with any plugin agent. Enforces the | |
| # "plugin is canonical" dedup rule from ADR-128 Phase 2. | |
| # | |
| # Zero runtime deps; pure Node.js readFileSync + readdirSync. | |
| name: init-bundle invariants smoke (#2095, ADR-128 Phase 5) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Run init-bundle invariants smoke | |
| run: node scripts/smoke-init-bundle-invariants.mjs | |
| wasm-provider-bridge-smoke: | |
| # ADR-129 Phase 1 — JsModelProvider routes WasmAgent through the v3 | |
| # provider system. Pre-P1: set_model_provider() was never called and | |
| # the echo-stub bypass competed with the WASM runtime. P1 fix: | |
| # attachJsModelProvider() is called at agent-creation time. | |
| # Static-only smoke: no build, no API keys required. | |
| name: wasm provider bridge smoke (ADR-129 P1) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Run wasm provider bridge smoke | |
| run: node scripts/smoke-wasm-provider-bridge.mjs | |
| wasm-compose-smoke: | |
| # ADR-129 Phase 2 — wasm_agent_compose MCP tool + addMcpTools bridge. | |
| # Fixes the silent drop of template.mcp_tools in buildRvfFromTemplate. | |
| # Static-only smoke: no build, no API keys required. | |
| name: wasm compose smoke (ADR-129 P2) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Run wasm compose smoke | |
| run: node scripts/smoke-wasm-rvf-compose.mjs | |
| wasm-gallery-crud-smoke: | |
| # ADR-129 Phase 3 — 16 new MCP tools (10 gallery CRUD + 6 agent | |
| # introspection), with AIDefence gate on wasm_gallery_import. | |
| # Static-only smoke: no build, no API keys required. | |
| name: wasm gallery CRUD smoke (ADR-129 P3) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Run wasm gallery CRUD smoke | |
| run: node scripts/smoke-wasm-gallery-crud.mjs | |
| wasm-plugin-bridge-smoke: | |
| # ADR-129 Phase 4 — plugin manifest "rvagent" field + includePlugins | |
| # in wasm_agent_compose. Static + behavioral fixture smoke. | |
| name: wasm plugin bridge smoke (ADR-129 P4) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Run wasm plugin bridge smoke | |
| run: node scripts/smoke-wasm-plugin-bridge.mjs | |
| graph-schema-smoke: | |
| # ADR-130 Phase 1 — graph_edges schema + PQ encoder + edge writer | |
| name: graph schema smoke (ADR-130 P1) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v6 | |
| with: | |
| version: ${{ env.PNPM_VERSION }} | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| cache: 'pnpm' | |
| cache-dependency-path: v3/pnpm-lock.yaml | |
| - name: Install root deps (sql.js for smoke scripts) | |
| # The smoke scripts use `await import('sql.js')` (bare ESM specifier), | |
| # which resolves from root node_modules. pnpm install inside v3/ alone | |
| # does not reliably expose sql.js to scripts run from the repo root. | |
| # Same pattern as the #2120 memory-stats smoke job. | |
| run: npm install --legacy-peer-deps --no-audit --no-fund --ignore-scripts | |
| - name: Build better-sqlite3 native binding for graph-edge-writer | |
| # --ignore-scripts above skipped better-sqlite3's prebuild-install, | |
| # leaving node_modules/better-sqlite3 on disk without the .node | |
| # binary. The graph-edge-writer does `await import('better-sqlite3')` | |
| # which Node resolves from the importing module's nearest | |
| # node_modules — that ends up being the *root* tree (closer than | |
| # v3/.pnpm), so the broken root copy wins and _openDb returns null | |
| # → insertGraphEdge returns false → TEST 2/3/5 all fail. Rebuild it. | |
| run: npm rebuild better-sqlite3 | |
| - name: Install v3 workspace deps and build | |
| run: | | |
| cd v3 | |
| pnpm install --frozen-lockfile | |
| pnpm -r build | |
| - name: Run graph schema smoke | |
| run: node scripts/smoke-graph-schema-migration.mjs | |
| graph-query-smoke: | |
| # ADR-130 Phase 2+5 — agentdb_graph-query + agentdb_graph-pathfinder dispatch | |
| name: graph query + pathfinder smoke (ADR-130 P2+P5) | |
| runs-on: ubuntu-latest | |
| needs: graph-schema-smoke | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v6 | |
| with: | |
| version: ${{ env.PNPM_VERSION }} | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| cache: 'pnpm' | |
| cache-dependency-path: v3/pnpm-lock.yaml | |
| - name: Install root deps (sql.js for the smoke fixture) | |
| # Same pattern as the graph-schema-smoke job — sql.js is a root | |
| # transitive dep, not declared in any workspace package.json. | |
| run: npm install --legacy-peer-deps --no-audit --no-fund --ignore-scripts | |
| - name: Build better-sqlite3 native binding | |
| # See graph-schema-smoke comment — same root-resolution hazard. | |
| run: npm rebuild better-sqlite3 | |
| - name: Install v3 workspace deps and build | |
| run: | | |
| cd v3 | |
| pnpm install --frozen-lockfile | |
| pnpm -r build | |
| - name: Symlink sql.js into v3/node_modules | |
| run: | | |
| mkdir -p v3/node_modules | |
| ln -sfn "$(pwd)/node_modules/sql.js" v3/node_modules/sql.js | |
| - name: Run graph query dispatch smoke | |
| run: node scripts/smoke-graph-query-dispatch.mjs | |
| - name: Run graph pathfinder smoke | |
| run: node scripts/smoke-graph-pathfinder.mjs | |
| graph-trajectory-smoke: | |
| # ADR-130 Phase 3 — SONA trajectory-to-graph hooks | |
| name: graph trajectory hooks smoke (ADR-130 P3) | |
| runs-on: ubuntu-latest | |
| needs: graph-schema-smoke | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v6 | |
| with: | |
| version: ${{ env.PNPM_VERSION }} | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| cache: 'pnpm' | |
| cache-dependency-path: v3/pnpm-lock.yaml | |
| - name: Install root deps (sql.js for smoke scripts) | |
| run: npm install --legacy-peer-deps --no-audit --no-fund --ignore-scripts | |
| - name: Build better-sqlite3 native binding | |
| # See graph-schema-smoke comment — same root-resolution hazard. | |
| run: npm rebuild better-sqlite3 | |
| - name: Install dependencies and build | |
| run: | | |
| cd v3 | |
| pnpm install --frozen-lockfile | |
| pnpm -r build | |
| - name: Run trajectory graph edges smoke | |
| # #2312 root cause (fixed): memory-bridge's rescueAgentdbEmbedder | |
| # patched agentdb.embedder.embed to delegate to generateEmbedding — | |
| # which is bridge-first, so the patched embed re-entered itself via | |
| # bridgeGenerateEmbedding in an unbounded async cycle (heap OOM at | |
| # the V8 limit, SIGABRT 134; SONA/EWC were innocent). The rescue now | |
| # delegates to generateLocalEmbedding (a bridge-free leaf), so this | |
| # smoke gates again at default heap — verified green in a node:22 | |
| # Linux container at 512 MB with a cold model cache. | |
| run: node scripts/smoke-trajectory-graph-edges.mjs | |
| graph-plugin-adapter-smoke: | |
| # ADR-130 Phase 4 — plugin adapter contract (GraphEdgesSource) | |
| name: graph plugin adapter smoke (ADR-130 P4) | |
| runs-on: ubuntu-latest | |
| needs: graph-schema-smoke | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v6 | |
| with: | |
| version: ${{ env.PNPM_VERSION }} | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| cache: 'pnpm' | |
| cache-dependency-path: v3/pnpm-lock.yaml | |
| - name: Install root deps (sql.js for smoke scripts) | |
| run: npm install --legacy-peer-deps --no-audit --no-fund --ignore-scripts | |
| - name: Build better-sqlite3 native binding | |
| # See graph-schema-smoke comment — same root-resolution hazard. | |
| run: npm rebuild better-sqlite3 | |
| - name: Install dependencies and build | |
| run: | | |
| cd v3 | |
| pnpm install --frozen-lockfile | |
| pnpm -r build | |
| - name: Run graph plugin adapter smoke | |
| run: node scripts/smoke-graph-plugin-adapter.mjs | |
| graph-benchmark: | |
| # ADR-130 Phase 6 — graph write/query throughput benchmark | |
| name: graph benchmark (ADR-130 P6) | |
| runs-on: ubuntu-latest | |
| needs: [graph-query-smoke, graph-trajectory-smoke, graph-plugin-adapter-smoke] | |
| timeout-minutes: 40 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v6 | |
| with: | |
| version: ${{ env.PNPM_VERSION }} | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| cache: 'pnpm' | |
| cache-dependency-path: v3/pnpm-lock.yaml | |
| - name: Install root deps (sql.js for smoke scripts) | |
| run: npm install --legacy-peer-deps --no-audit --no-fund --ignore-scripts | |
| - name: Build better-sqlite3 native binding | |
| # See graph-schema-smoke comment — same root-resolution hazard. | |
| run: npm rebuild better-sqlite3 | |
| - name: Install dependencies and build | |
| run: | | |
| cd v3 | |
| pnpm install --frozen-lockfile | |
| pnpm -r build | |
| - name: Run graph benchmark | |
| run: node scripts/benchmark-graph.mjs | |
| statusline-generator-delegation-smoke: | |
| # Regression guard for ruvnet/ruflo#2195 — the statusline generator | |
| # previously re-implemented all data readers locally with fragile file | |
| # probes that returned wrong values (DDD 0/5, intelligence 1%, ADR 87/87). | |
| # | |
| # The fix delegates to 'npx @claude-flow/cli@latest hooks statusline --json' | |
| # as the single source of truth and counts ADRs in BOTH directories | |
| # (v3/implementation/adrs/ + v3/docs/adr/). | |
| # | |
| # Two guards: | |
| # [1/2] STATIC — assert generator still delegates to the CLI command | |
| # and does NOT contain the old fragile heuristics. | |
| # [2/2] SMOKE — build the CLI, run the generated .cjs with --json, | |
| # assert all numeric fields are within valid ranges and that | |
| # the known-bad fallback values (domainsCompleted=0 when patterns>0, | |
| # intelligencePct=1 when system is healthy) are not present. | |
| name: statusline generator delegation smoke (#2195) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Guard 1 — static delegation contract | |
| shell: bash | |
| run: | | |
| # #2679: generator now READS .claude/helpers/statusline.cjs as its | |
| # single source of truth rather than duplicating the content in an | |
| # inline template. The delegation contract lives in the HELPER | |
| # file now — grep that instead. Also verify the generator still | |
| # reads it (i.e. the read-and-substitute pattern is intact) so a | |
| # future refactor can't silently break the delegation contract | |
| # by dropping the file read. | |
| HELPER=v3/@claude-flow/cli/.claude/helpers/statusline.cjs | |
| GEN=v3/@claude-flow/cli/src/init/statusline-generator.ts | |
| echo "Checking that the helper delegates to 'hooks statusline --json'..." | |
| grep -q "hooks statusline --json" "$HELPER" \ | |
| || { echo "::error::$HELPER no longer delegates to 'hooks statusline --json' — regression of #2195"; exit 1; } | |
| echo "ok: delegation pattern found in helper" | |
| echo "Checking that the generator reads the helper (#2679 sync pattern)..." | |
| grep -q "statusline.cjs" "$GEN" \ | |
| || { echo "::error::$GEN no longer references statusline.cjs — regression of #2679 read-and-substitute pattern"; exit 1; } | |
| grep -qE "readFileSync.*helperContent|helperContent.*readFileSync" "$GEN" \ | |
| || { echo "::error::$GEN no longer reads helper via readFileSync — regression of #2679"; exit 1; } | |
| echo "ok: read-and-substitute pattern intact" | |
| echo "Checking that the old fragile heuristics are NOT present (in helper)..." | |
| # The buggy fallback computed domains from file-based pattern counts — | |
| # this produced domainsCompleted=0 when AgentDB had 26k+ patterns. | |
| ! grep -q "getLearningStats\b" "$HELPER" \ | |
| || { echo "::error::$HELPER still has getLearningStats (old local reader) — regression of #2195"; exit 1; } | |
| ! grep -q "getV3Progress\b" "$HELPER" \ | |
| || { echo "::error::$HELPER still has getV3Progress (old local reader) — regression of #2195"; exit 1; } | |
| echo "ok: old local-reader heuristics removed" | |
| echo "Checking that both ADR directories are counted..." | |
| grep -q "v3/docs/adr" "$HELPER" \ | |
| || { echo "::error::$HELPER missing v3/docs/adr ADR directory — regression of #2195 ADR-count bug"; exit 1; } | |
| grep -q "v3/implementation/adrs" "$HELPER" \ | |
| || { echo "::error::$HELPER missing v3/implementation/adrs ADR directory"; exit 1; } | |
| echo "ok: both ADR directories present" | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v6 | |
| with: | |
| version: ${{ env.PNPM_VERSION }} | |
| - name: Install and build CLI | |
| working-directory: v3 | |
| run: | | |
| pnpm install --frozen-lockfile | |
| pnpm --recursive --no-bail run build || true | |
| test -f @claude-flow/cli/dist/src/init/statusline-generator.js \ | |
| || { echo "::error::statusline-generator.js not built"; exit 1; } | |
| - name: "Guard 2 — smoke: generate .cjs and validate output ranges" | |
| shell: bash | |
| run: node scripts/smoke-statusline-generator-delegation.mjs | |
| wizard-init-regression-guard: | |
| # Regression guard for ruvnet/ruflo#2206 #2207 #2208 — three init-wizard | |
| # bugs that collectively broke every new user install: | |
| # | |
| # #2206: mcp-generator registered the server under key 'ruflo', causing all | |
| # 33 ruflo plugins to fail with "Unknown tool mcp__claude-flow__*". | |
| # The key must be 'claude-flow'; the command args (ruflo@latest) are | |
| # correct and must NOT change. | |
| # | |
| # #2207: detectExistingRufloMCP only checked for 'ruflo' in mcpServers. | |
| # After #2206, the key becomes 'claude-flow', so the detector would | |
| # NEVER recognise a prior install. Both keys must be accepted. Also | |
| # guarded: bare .claude/settings.json must NOT be a false positive. | |
| # | |
| # #2208: init --force silently destroyed existing CLAUDE.md without backup, | |
| # causing data loss. A .pre-ruflo backup must be created before | |
| # any overwrite; timestamped fallback when a backup already exists. | |
| # | |
| # Three guards (static + runtime each): | |
| # [1/3] STATIC #2206 — mcp-generator source must write 'claude-flow' key | |
| # [2/3] RUNTIME #2206 + #2208 — build CLI, run init in tmp dir, assert | |
| # .mcp.json has 'claude-flow' key and CLAUDE.md.pre-ruflo was created | |
| # [3/3] RUNTIME #2207 — bare .claude/settings.json must NOT trigger | |
| # the duplicate-detection guard (false-positive check) | |
| name: wizard init regression guard (#2206 #2207 #2208) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '22' | |
| - name: Guard 1 — static #2206 server key contract | |
| shell: bash | |
| run: | | |
| echo "=== Guard 1: mcp-generator must write the claude-flow key ===" | |
| echo "Checking mcp-generator uses 'claude-flow' as the server key..." | |
| grep -qE "mcpServers\['claude-flow'\]|mcpServers\[\"claude-flow\"\]" \ | |
| v3/@claude-flow/cli/src/init/mcp-generator.ts \ | |
| || { echo "::error::mcp-generator no longer writes 'claude-flow' server key — #2206 regression"; exit 1; } | |
| echo "ok: 'claude-flow' key found" | |
| echo "Checking mcp-generator does NOT use bare 'ruflo' as the server key..." | |
| ! grep -qE "mcpServers\['ruflo'\]|mcpServers\[\"ruflo\"\]" \ | |
| v3/@claude-flow/cli/src/init/mcp-generator.ts \ | |
| || { echo "::error::mcp-generator writes 'ruflo' server key — breaks mcp__claude-flow__* tool naming (#2206)"; exit 1; } | |
| echo "ok: bare 'ruflo' server key absent" | |
| echo "Checking command args still invoke ruflo@latest (must NOT change)..." | |
| grep -q "ruflo@latest" v3/@claude-flow/cli/src/init/mcp-generator.ts \ | |
| || { echo "::error::mcp-generator no longer invokes ruflo@latest — command args must be preserved (#2206)"; exit 1; } | |
| echo "ok: ruflo@latest invocation present" | |
| echo "Guard 1 passed." | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v6 | |
| with: | |
| version: ${{ env.PNPM_VERSION }} | |
| - name: Install and build CLI | |
| working-directory: v3 | |
| run: | | |
| pnpm install --frozen-lockfile | |
| pnpm --recursive --no-bail run build || true | |
| test -f @claude-flow/cli/dist/src/init/executor.js \ | |
| || { echo "::error::executor.js not built — CLI build failed"; exit 1; } | |
| test -f @claude-flow/cli/dist/src/init/mcp-generator.js \ | |
| || { echo "::error::mcp-generator.js not built"; exit 1; } | |
| - name: Guard 2 — runtime #2206 server key + #2208 CLAUDE.md backup | |
| shell: bash | |
| run: | | |
| echo "=== Guard 2: generated .mcp.json key and CLAUDE.md backup ===" | |
| TMP=$(mktemp -d) | |
| cd "$TMP" | |
| # Seed CLAUDE.md with sentinel content so #2208 backup is observable | |
| printf '# Sentinel Project Content — do not lose\n' > CLAUDE.md | |
| # Run init --force (non-interactive); ignore non-zero exit from | |
| # optional components that need extra deps (skills, helpers, etc.) | |
| HOME="$TMP" node "$GITHUB_WORKSPACE/v3/@claude-flow/cli/bin/cli.js" \ | |
| init --force 2>&1 || true | |
| echo "--- .mcp.json contents ---" | |
| cat .mcp.json 2>/dev/null || echo "(not found)" | |
| # #2206: 'claude-flow' key must exist | |
| node -e " | |
| const cfg = JSON.parse(require('fs').readFileSync('.mcp.json','utf-8')); | |
| if (!cfg.mcpServers || !('claude-flow' in cfg.mcpServers)) { | |
| console.error('FAIL: .mcp.json missing claude-flow server key (#2206)'); | |
| process.exit(1); | |
| } | |
| console.log('ok: claude-flow key present in .mcp.json'); | |
| " || { echo "::error::generated .mcp.json missing 'claude-flow' server key (#2206)"; exit 1; } | |
| # #2206: stray 'ruflo' key must NOT exist | |
| node -e " | |
| const cfg = JSON.parse(require('fs').readFileSync('.mcp.json','utf-8')); | |
| if (cfg.mcpServers && 'ruflo' in cfg.mcpServers) { | |
| console.error('FAIL: .mcp.json has stray ruflo server key (#2206)'); | |
| process.exit(1); | |
| } | |
| console.log('ok: stray ruflo key absent'); | |
| " || { echo "::error::generated .mcp.json has stray 'ruflo' server key (#2206)"; exit 1; } | |
| # #2208: CLAUDE.md.pre-ruflo backup must exist with sentinel content | |
| BACKUP=$(ls CLAUDE.md.pre-ruflo* 2>/dev/null | head -1) | |
| if [ -z "$BACKUP" ]; then | |
| echo "::error::init --force did not create CLAUDE.md.pre-ruflo backup (#2208)" | |
| exit 1 | |
| fi | |
| echo "ok: backup file created: $BACKUP" | |
| grep -q "Sentinel Project Content" "$BACKUP" \ | |
| || { echo "::error::CLAUDE.md backup missing original sentinel content (#2208)"; exit 1; } | |
| echo "ok: backup contains original content" | |
| echo "Guard 2 passed." | |
| - name: Guard 3 — runtime #2207 false-positive check | |
| shell: bash | |
| run: | | |
| echo "=== Guard 3: bare .claude/settings.json must NOT trigger duplicate detection ===" | |
| TMP=$(mktemp -d) | |
| cd "$TMP" | |
| # Simulate Claude Code's own project settings.json with NO ruflo registration | |
| mkdir -p .claude | |
| echo '{"env": {}, "hooks": {}}' > .claude/settings.json | |
| # Run init WITHOUT --force; use a custom HOME with no ~/.claude.json | |
| # so the real user's global config doesn't interfere | |
| FAKE_HOME=$(mktemp -d) | |
| OUT=$(HOME="$FAKE_HOME" node "$GITHUB_WORKSPACE/v3/@claude-flow/cli/bin/cli.js" \ | |
| init 2>&1 || true) | |
| echo "--- init output ---" | |
| echo "$OUT" | |
| # The init must NOT claim "already initialized" due to the bare settings.json | |
| if echo "$OUT" | grep -qi "existing 'ruflo' MCP registration\|existing 'claude-flow' MCP registration"; then | |
| echo "::error::init false-positives on bare .claude/settings.json (#2207)" | |
| exit 1 | |
| fi | |
| echo "ok: no false-positive on bare .claude/settings.json" | |
| rm -rf "$FAKE_HOME" | |
| echo "Guard 3 passed." |