Commit Graph

29 Commits

Author SHA1 Message Date
ruv 392e71912e fix(mcp): rate-limit authenticated HTTP routes 2026-08-14 19:04:54 -04:00
dajiaohuang 6b8f0d0b5a fix(mcp): share state across HTTP transports 2026-08-14 17:10:34 -04:00
dajiaohuang 2dbb790a0b fix(mcp): restore HTTP protocol and CLI tools 2026-08-14 17:10:34 -04:00
rUv 495a451cf6 feat: add ADR-324 agentic policy engine (#2822)
* feat(memory): typed provenance in AgentDB (ADR-323)

Corrects and implements the 2026-07-28 dream-cycle research proposal
(PR #2804, closed as superseded) for typed memory provenance in
AgentDB, addressing MemIR/MemSyco-Bench's "provenance-role collapse"
and memory-induced sycophancy findings.

The dream-cycle PR's proposed schema change targeted the wrong table
(`vector_indexes`, which is per-namespace HNSW index metadata, not
per-entry) and its filename collided with the already-merged
`ADR-322-metaharness-flywheel-integration.md` (#2817) — both corrected
here as ADR-323 against `memory_entries`, the real per-record table.

- memory-initializer.ts: `provenance_type` column (user_claim |
  agent_output | system_observation | tool_result | unknown, default
  unknown) on `memory_entries`, migrated for existing DBs via
  `ensureSchemaColumns()`. `storeEntry()`/`searchEntries()` accept and
  validate `provenanceType`/`provenanceFilter`.
- memory-bridge.ts: same wiring for the native better-sqlite3 AgentDB
  v3 path (`bridgeStoreEntry`/`bridgeSearchEntries`).
- commands/memory.ts: `memory store --provenance <type>`, `memory
  search --provenance-filter <types>` (comma-separated, OR semantics).
- mcp-tools/memory-tools.ts + cli-core/mcp-tools/memory-defs.ts:
  `memory_store`'s `provenance_type` param, `memory_search`'s
  `provenance_filter` param (kept in sync across both tool-def sets).

Found and fixed during implementation: an initial design skipped the
RaBitQ/HNSW acceleration paths entirely whenever a provenance filter
was requested (neither carries provenance_type on their candidates).
This reproducibly crashed the CLI process on exit (a libuv assertion
on Windows) after printing correct results. Fixed by never skipping
those paths — RaBitQ now fetches provenance_type in its existing
per-candidate query, HNSW does one batched (namespace, key) lookup
afterward — eliminating the crash across repeated runs. See ADR-323's
"Implementation note" for detail.

7 new end-to-end tests (adr-323-memory-provenance.test.ts), including
a repeated-run regression guard for the crash. Full existing memory
suite re-verified with no regressions (one pre-existing, environment-
specific #2558 test failure confirmed identical against unmodified
main — better-sqlite3's native bridge is unavailable in this dev
environment, unrelated to this change).

Closes the follow-up from dream-cycle PR #2804 (closed as superseded).

Co-Authored-By: claude-flow <ruv@ruv.net>

* fix(memory): enforce provenance across retrieval paths

* feat: add agentic policy engine

* fix: align Codex MCP integration

* fix: keep MetaHarness dependencies optional

* fix: declare MetaHarness as optional peers

* fix: sync workspace lockfile

* fix: document policy tool selection guidance

* test: cover governed in-process flywheel

* ci: make MetaHarness absence drill deterministic
2026-07-28 22:12:19 -04:00
ruvnet e332689b8c fix(release): harden hooks, statusline, security, and plugin MCP integration 2026-07-16 23:06:29 -04:00
ruflo-loop 9f6cf7d2a1 fix(security): statusline CVE counter reads real scan findings, not hardcoded 3 (#2694)
getSecurityStatus() hardcoded totalCves=3 and counted scan *files* as
'CVEs fixed', fabricating '⚠ 3 CVEs' for every project. Now reads the
NEWEST scan in .claude/security-scans/ and surfaces its real findings
count (summary.total ?? totalFindings ?? findings.length). cvesFixed
stays 0 until a real fix-tracking mechanism exists.

Fixed in all 5 copies:
- v3/@claude-flow/cli/src/funnel/local-signals.ts (TS source of truth)
- v3/@claude-flow/cli/.claude/helpers/statusline.js (cli helper)
- v3/@claude-flow/mcp/.claude/helpers/statusline.cjs (mcp helper)
- v3/@claude-flow/mcp/.claude/helpers/statusline.js (mcp helper)
- v3/@claude-flow/hooks/src/statusline/index.ts (hooks statusline)

Also: executor.ts init defaults totalCves 3->0 (2 sites);
statusline/index.ts audit fallback defaults 3->0.

Added regression test issue-2694-cve-counter.test.ts (pure unit, no CLI).
Updated security-scan-persistence.test.ts to assert CLEAN/0/0 for the
empty fixture (was asserting cvesFixed>=1, the fabricated behavior).
2026-07-16 22:32:52 -04:00
rUv 1d5b06e4a2 fix(federation): unblock main — TS shim types + dispatcher import + witness re-sign (#2604)
* fix(federation): sync shim types + guard optional close() to unblock Build V3

Fixes 7 TS errors on main that block Build V3 across all 3 platforms:
- src/transport/midstream-aware-loader.ts:39-52 — local AgentMessage/
  AgentTransport shim was over-minimized by #2578. Restored required
  {id, type, payload, metadata?} on AgentMessage and made send/onMessage
  2-arg (address, message) to match how plugin.ts actually calls them.
- src/transport/midstream-aware-loader.ts:84 — cast dynamic import()
  through `unknown` since upstream's exported AgentTransport carries a
  richer InboundMessageHandler surface we intentionally hide behind the
  minimal shim.
- src/plugin.ts:481 — this.transport.close is optional (`?`) on the
  shim; guard with optional chaining `close?.()`.

Local tsc build clean after fix.

Co-Authored-By: RuFlo <ruv@ruv.net>

* fix(federation): dispatcher import + re-sign witness manifests (3.25.3 drift)

Two more preexisting main-red root causes, in the same fix:

(1) inbound-dispatcher.ts:22 still imported `AgentMessage` from
    `agentic-flow/transport/loader` — the exact phantom subpath #2578
    eliminated in midstream-aware-loader.ts. Repointed to the local
    shim. This is the residual site #2578 missed; the graph schema smoke
    (ADR-130 P1) failure was a cascade of this same TS type collision.

(2) Re-signed verification/{linux,macos,windows}/manifest.md.json via
    plugins/ruflo-core/scripts/witness/regen.mjs. The 3.25.3 release
    (PR #2602) edited the ADR-104-transport `desc` string in all 3 per-OS
    manifests but did not re-run regen.mjs, so the stored
    integrity.manifestHash no longer matched sha256(JSON.stringify(
    manifest)) and Witness verify exited 1 across all 3 platforms.
    Manifests now verify cleanly (117 pass, 0 drift, 0 regressed).
    Note: witness/regen.mjs takes --manifest + --history and re-signs
    deterministically from manifest.gitCommit; already wired but the
    3.25.3 release process skipped it.

Local verify: pass=117 drift=0 regressed=0 missing=0 on all 3 OSes.
Local tsc build: clean.

Co-Authored-By: RuFlo <ruv@ruv.net>

* fix(hooks): PreToolUse hook emits valid JSON verdict (#2613)

Cursor imports third-party Claude Code hooks under its stricter
`preToolUse` contract, which requires stdout to be a valid JSON
permission verdict (`{"permission":"allow"|"deny"|"ask"}`) and
fail-closes on any other text. The prior PreToolUse commands ran the
ruflo hook shim which prints telemetry to stdout — Cursor then blocked
every Bash/Write/Edit tool call across every workspace.

Fix:
1. ruflo-hook.sh (all three copies) — redirect stdout to /dev/null in
   addition to stderr. Claude Code doesn't consume this stdout either,
   so silencing it is a pure cleanup with no functional cost.
2. hooks.json PreToolUse commands — after invoking the shim, always
   `printf` a well-formed `{"permission":"allow"}` verdict. Valid for
   both Claude Code's JSON-hook contract and Cursor's stricter
   preToolUse contract, so telemetry keeps working while nothing is
   blocked. Also guard `${CLAUDE_PLUGIN_ROOT:-}` so an unset env var
   collapses to the safe empty branch instead of a bash parse error.

Simulated Cursor invocation (CLAUDE_PLUGIN_ROOT unset) now emits:
  {"permission":"allow"}

Co-Authored-By: RuFlo <ruv@ruv.net>

* fix(ci): indirect optional-dep imports in cli — @ruvector/*, @metaharness/router (#2608)

Same install-safety anti-pattern as #2586's prime-radiant fix, now
surfaced in @claude-flow/cli once plugin-agent-federation's TS2307
stopped masking it (630034ca4 on this branch). Build V3 fails with
"Cannot find module '@ruvector/learning-wasm'" and
"Cannot find module '@metaharness/router'" whenever the optional deps
aren't installed — which is the case in the install-safety /
Build V3 configurations.

Every call site is already runtime-guarded (try/catch, availability
probes). But a literal `await import('@ruvector/learning-wasm')` or a
`typeof import('@metaharness/router')` type expression forces tsc to
statically resolve the specifier at build time, so TS2307 fires when
the package is absent.

Fix: route the specifier through a string-typed variable
(`const pkg: string = '...'; await import(pkg)`) — same idiom as the
optional better-sqlite3 loader and #2586. Runtime behaviour unchanged:
the package still loads when present, still falls back cleanly when
absent.

Also replaced services/ruvector-training.ts's static `import type
{ WasmMicroLoRA, ... } from '@ruvector/learning-wasm'` with local
`type X = any` aliases (mirrors the existing FlashAttention et al.
pattern a few lines below).

Verified: with @ruvector/learning-wasm, @ruvector/attention, and
@metaharness/router hidden locally (matching the CI condition), the
cli package now compiles clean (tsc, 0 TS2307). plugin-agent-federation
remains clean as well.

Co-Authored-By: RuFlo <ruv@ruv.net>

* fix(smoke): add metaharness optionalDep to ruflo wrapper (ADR-150 constraint #2)

The all-plugins-smoke, metaharness-ci `score`, and no-metaharness-smoke
CI jobs all fail on the same single step (ruflo-metaharness smoke #16):

  → 16. ruflo wrapper has metaharness in optionalDependencies
        (architectural constraint #2) ... FAIL:
        ruflo wrapper missing metaharness optionalDep

ADR-150 §"Architectural constraint" rule #2 requires `metaharness` and
`@metaharness/*` packages to live in `optionalDependencies` (never
`dependencies`) so ruflo remains operational when they're removed. The
CLI already satisfies this; the wrapper package.json had an empty
`optionalDependencies` block.

Pin to `~0.3.1` — the current npm-published `metaharness@latest`, and
the same range family used by CLAUDE.md's `@metaharness/router@~0.3.2`
pin. Wrapper install remains graceful-fail when the optional dep is
absent (that's the whole point of ADR-150's removable rule #1).

Unblocks PR #2604 merge. Only 3 CI failures on the branch — all
the same rule — so this single change flips them green.

Co-Authored-By: RuFlo <ruv@ruv.net>

* fix(smoke): reconcile ADR-150 rule #2 with #2561 npx-startup budget

Two CI gates were mutually incompatible on this PR:

- ruflo-metaharness smoke #16 (older): asserted \`metaharness\` MUST be
  in \`ruflo/package.json\` optionalDependencies.
- guard #2561 (newer): enforces \`RUFLO_MAX=0\` optionalDependencies
  AND FORBIDs \`metaharness\` specifically, because installing it as a
  ruflo postinstall dep timed out the \`npx -y ruflo@alpha --version\`
  fast-path (measured incident).

Adding \`metaharness\` to ruflo optDeps satisfies #16 but breaks #2561;
removing it satisfies #2561 but leaves #16 red (pre-existing main state).

Fix: correct the smoke #16 rule. ADR-150 §"Architectural constraint"
rule #2 says "when \`@metaharness/*\` or \`metaharness\` appears in a
package's dep graph, it MUST be in \`optionalDependencies\`, never
\`dependencies\`". It does NOT require ruflo to depend on metaharness.
The old check was over-restrictive — it demanded PRESENCE, not just
correct SHAPE-when-present. The new check enforces the actual invariant:
no \`metaharness\` / \`@metaharness/*\` in ruflo's hard \`dependencies\`.
Absence is fine (ruflo delegates to @claude-flow/cli, which keeps
metaharness as a runtime dynamic import via ADR-150 rule #1).

#2561 is stronger evidence (proven cold-npx timeout) than the old #16
assertion, so the correction goes to #16.

Verified locally:
  smoke #16 PASS (new logic)
  guard #2561 PASS

Also reverts the ruflo/package.json optionalDeps change that briefly
tried to satisfy the old #16 rule — the wrapper stays clean.

Co-Authored-By: RuFlo <ruv@ruv.net>

* fix(init): heal duplicate MCP registrations without breaking plugin refs (#2612)

Users who followed pre-rename setup docs ended up with two independent
MCP server registrations pointing at the same binary — one keyed
`claude-flow`, one keyed `ruflo` — doubling Claude Code's tool-schema
load (~350 duplicated tools) with zero added capability. Bug #2612.

The naive fix (rename the canonical key from `claude-flow` → `ruflo`)
silently re-opens #2206 (closed), because ~166 plugin files across
plugins/**/{agents,commands,skills}/*.md reference tools with the
`mcp__claude-flow__*` prefix. Claude Code derives the tool prefix from
the MCP server key; flipping the key to `ruflo` renames every plugin
tool to `mcp__ruflo__*` and every one of those 166 refs errors with
"Unknown tool".

Correct reconciliation:

  - Canonical MCP key STAYS `claude-flow` (preserves #2206 for the 166
    plugin refs). The binary invoked is `ruflo@latest` — only the
    registration name is legacy.
  - Duplicate is HEALED via `ruflo doctor`, not by renaming: detect
    coexisting `ruflo`-keyed + `claude-flow`-keyed registrations for
    the same binary, warn, and instruct the operator to remove the
    `ruflo`-keyed one.

Changes:

  - src/init/mcp-generator.ts — server key restored to `claude-flow`;
    manual `claude mcp add …` commands restored to name `claude-flow`.
    Comment now explains the #2206/#2612 duality.
  - src/init/executor.ts — writeMCPConfig skip-comment updated to
    reflect that `claude-flow` is canonical and `ruflo`-keyed is the
    legacy duplicate form; existing detection accepts both keys (was
    already correct).
  - src/init/claudemd-generator.ts — generated CLAUDE.md `Setup`
    section restored to `claude mcp add claude-flow -- …`.
  - src/commands/doctor.ts — inherit the concurrent session's
    duplicate-detection logic (rufloLocations / duplicateLocations /
    legacyLocations / currentLocations), but flip which key is
    treated as canonical: `claude-flow`/`claude-flow_alpha` are
    current, `ruflo`/`ruflo_alpha` are legacy. Fix-message now
    references removing the `ruflo`-keyed entry and cites #2206.
  - src/commands/swarm.ts — help output uses `claude mcp add
    claude-flow` again.
  - __tests__/issue-2612-mcp-rename.test.ts — regression guard for the
    duplicate-detection warning; header comment documents the
    canonical/legacy roles matching the flipped semantics.
  - CLAUDE.md / v3/@claude-flow/cli/CLAUDE.md / v3/@claude-flow/mcp/CLAUDE.md /
    v3/implementation/init/API.md — kept the binary-update from
    `@claude-flow/cli@latest` → `ruflo@latest` (correct, this IS the
    post-rename wrapper), but restored the MCP server KEY to
    `claude-flow` in every example line.

Verified:
  - tsc clean (CLI package)
  - all 70 test files / 726 tests pass locally, including:
    - __tests__/init-wizard-bugs.test.ts (#2206 canonical key + #2207 dual-key detection)
    - __tests__/stale-mcp-key-2369.test.ts (10 tests, unchanged)
    - __tests__/issue-2612-mcp-rename.test.ts (new — asserts doctor
      surfaces "Duplicate Ruflo MCP registrations found" with legacy
      `ruflo` + current `claude-flow`)
  - Manual doctor run against a synthetic .mcp.json/.claude.json pair
    surfaces the exact warning + remediation string.

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-07-09 10:16:55 -04:00
rUv 626bb79931 fix(memory): atomic DB flushes + backup auto-restore for AgentDB corruption (#2584) (#2585)
Data-durability fix for AgentDB (sql.js) 'database disk image is malformed'
under torn/concurrent full-image flushes.

- Atomic writes: new writeFileAtomic() (temp -> fsync -> rename, + best-effort
  dir fsync) in fs-secure.ts; route writeFileRestricted() through it (covers the
  three main-store flushes) and the decay-path flush + metrics-db.mjs (all 3
  copies). A kill/OOM mid-write or a concurrent writer can no longer leave a
  half-written image.
- Backup auto-restore: restoreMemoryDbFromBackup() picks the newest
  PRAGMA integrity_check=ok backup from .swarm/backups/, parks the corrupt live
  DB, and atomically installs it. Wired into recoverMemoryDatabase() so that
  when the in-place rebuild salvages nothing (the reported case where sqlite
  .recover recovered 0 rows), recovery restores from backup instead of erroring
  every call. Periodic backup rotation already exists (memory-backup.ts).
- Tests: __tests__/memory-durability-2584.test.ts — atomic-writer semantics +
  a synthesized torn-image (integrity_check fails, rebuild salvages nothing)
  that must recover via backup-restore. 6/6 pass.

Note: the report's metrics-db.mjs cite targets .claude-flow/metrics.db, a
separate file from .swarm/memory.db; it was genuinely non-atomic (fixed here)
but was not the writer that tore memory.db — the live-store flushes in
memory-initializer.ts were.


Claude-Session: https://claude.ai/code/session_01S7GYqnVUVxBfZ5W8znqry3
2026-07-05 22:33:05 -04:00
rUv 402b701a9d fix(security): ADR-165 Phase 1 — close 5 critical CVEs + refresh registry + audit CI gate (#2508)
* fix(security): ADR-165 Phase 1 — close all critical CVEs, refresh registry, add CI gate

Closes ADR-165 Phase 1. Both workspaces pass `npm audit --audit-level=critical`.

## Before (2026-06-29)

| Workspace | Critical | High | Moderate | Total |
|-----------|----------|------|----------|-------|
| Root      | **1**    | 6    | 31       | 38    |
| v3        | **4**    | 33   | 57       | 97    |

## After

| Workspace | Critical | High | Moderate | Total |
|-----------|----------|------|----------|-------|
| Root      | **0**    | 0    | 31       | 31    |
| v3        | **0**    | 27   | 58       | 88    |

All 5 critical advisories closed (vitest GHSA-5xrq, handlebars prototype-pollution,
protobufjs constructor-pollution, plus 2 more in v3). 12 of 39 high advisories
closed via overrides; the remaining 27 v3 highs are deeper transitive chains
that would require breaking-change major bumps — flagged for ADR-165 Phase 2.

## Changes

### Root workspace overrides (package.json)

- `vitest`: `^1.0.0` → `^3.2.6` (closes critical GHSA-5xrq CVSS 9.8)
- `hono`: `>=4.11.4` → `>=4.12.25` (closes 6 hono advisories)
- `undici`: `>=7.18.0` → `>=8.5.0` (closes 7 undici advisories — bumps the
  stale pin that ADR-165 flagged as still-in-vulnerable-range)
- `vite`: `>=6.4.6` → `>=8.0.16` (closes 2 vite advisories)
- NEW `@grpc/grpc-js`: `>=1.14.4`
- NEW `form-data`: `>=4.0.6`
- NEW `http-proxy-middleware`: `>=3.0.7`
- `@hono/node-server`: `>=1.19.10` → `>=1.19.14`

### v3 workspace overrides (v3/package.json + pnpm.overrides)

- `vitest`: `^4.0.16` → `^4.1.0` (and `@vitest/coverage-v8` matched)
- Top-level + pnpm overrides: `handlebars: >=4.7.9`, `protobufjs: >=8.6.0`
- 27 sub-package `package.json` updated to `vitest ^4.1.0`

### CVE registry refresh (v3/@claude-flow/security/src/CVE-REMEDIATION.ts)

Rewritten from 5 stale Jan-2026 entries to 16 total: 15 fixed, 1 open
(ADR165-OPEN-01 — PII pipeline wiring per ADR-164 §6.1 not yet on
dispatch-layer). `SECURITY_SUMMARY` is now computed dynamically from the
registry; `validateRemediation()` correctly returns `allFixed: false`
with 1 issue. ADR-165 §5 flagged this as THE Phase 2 priority — now closed.

### New CI gate

`.github/workflows/cve-audit.yml`:
- `audit-root` — `npm audit --audit-level=critical` in root, blocking
- `audit-v3` — same in v3, blocking
- `audit-high-report` — warn-only summary on high-severity drift
- Triggers: PR, push to main, daily cron

### ADR-165 §9 evidence ledger addendum

Captures AFTER-remediation `npm audit --json` metadata for both workspaces.
The diff between BEFORE (already in §9) and AFTER makes Phase 1 verifiable.

Also CORRECTED one prior surprise in §9: the `validate-input.ts` in
`mcp-tools/` is NOT a 9-line shim. It's 269 lines of real implementation.
(That was an inaccurate findings note from the initial audit.)

### §7.3 research items resolved

- `protobufjs` v3 chain confirmed gone after override pins
- `handlebars` v3 chain confirmed not user-reachable on the workflow path
  (toolchain-only; override sufficient)
- `validate-input.ts` confirmed real implementation, not a shim (registry
  entry corrected)
- CORS surface check: no `cors()` / `app.use(cors` call sites — the hono
  CORS-wildcard advisory is not exploitable on the current server
- ADR-164 §6.1 PII pipeline NOT wired in current agentbbs dispatch —
  recorded as ADR165-OPEN-01 (Phase 3 work)

## Gates (all PASS)

- `npm audit --audit-level=critical` root: exit 0 (was non-zero)
- `npm audit --audit-level=critical` v3:   exit 0 (was non-zero)
- vitest suites: 105/109 pass (4 skip-conditional — same as before)
- ADR-112 audit: 352/352 tools with guidance
- business-pods smoke: 11/11 PASS
- agentbbs smoke: 8/8 PASS
- agenticow smoke: 8/8 PASS
- cli build: clean (tsc)

## Phase 2+ deferred

The 27 v3 high-severity advisories that remain are transitive chains with
no patched-in-range version. ADR-165 §6 Phase 2 picks these up after the
`cve-watch.yml` automation in §6 lands (NEW PR — not in scope here).

Co-Authored-By: RuFlo <ruv@ruv.net>
Claude-Session: https://claude.ai/code/session_01WbBa4nccx5aGhXphoHxcni

* chore(lock): regen v3/pnpm-lock.yaml after override updates (PR #2508 CI fix)

PR #2508 added handlebars + protobufjs to v3 overrides + bumped vitest pin,
but v3/pnpm-lock.yaml wasn't regenerated. CI surfaced
ERR_PNPM_LOCKFILE_CONFIG_MISMATCH on every install step.

Same pattern as the previous lockfile-drift fixes on PR #2500 and #2503.

* fix(ci): cve-audit.yml jq-only + regen witness manifests for #1609 marker drift

Two PR #2508 CI failures fixed:

1. Static-regression-guard tripped on cve-audit.yml line 52: the static
   YAML strict-parser sees `if high > 0:` inside the `run: |` block as
   a YAML block-mapping key indicator. Refactored all 3 inline-python
   blocks to use jq (preinstalled on ubuntu-latest) — no embedded
   `if x > 0:` lines, so the YAML guard passes.

2. Witness marker drift smoke flagged fix-marker #1609 — the Phase 1
   vitest bump (4.0.16 → 4.1.0) drifted the cited marker string in
   v3/@claude-flow/aidefence/package.json. Updated `marker` field in
   all 3 platform manifests + `desc` to reference ADR-165 Phase 1, then
   re-signed via plugins/ruflo-core/scripts/witness/regen.mjs.

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-06-29 22:41:24 -04:00
ruv 4c01443712 fix: #2267 #2257 #2256 #2253 — CI/router/ONNX bug cluster
Four open issues fixed on this branch; #2246 already shipped in source, #2243
and #2259 documented as out-of-scope here (see body).

#2267 — v3-ci.yml YAML parse failure on main (5 consecutive failures, 0 jobs
created). Root cause: unquoted ":  " inside step name "Guard 2 — smoke:
generate .cjs ..." — YAML parser saw `smoke:` as a second mapping key. Quote
the name. File now parses to 52 jobs.

#2257 — `.claude/helpers/router.js` mis-routes at 80% confidence via unanchored
regex. Tokens like `cd`/`ci`/`ui`/`add`/`structure` matched inside `decision`/
`infrastructure`/`address`/`addendum`. Switch to a token-list schema with `\b`
word boundaries on single tokens (phrases keep whitespace as a natural
boundary), drop matched-confidence 0.8→0.6 and fall-through 0.5→0.3 since
this is a static heuristic, not a learned classifier. Fixed in canonical
generator (`src/init/helpers-generator.ts::generateAgentRouter`) plus the two
in-repo snapshots (`v3/@claude-flow/cli/.claude/helpers/`,
`v3/@claude-flow/mcp/.claude/helpers/`).
Validated against all 11 reported mis-route cases; generator output verified.

#2256 — `--version` blocks 60+ s on cold ONNX cache (SIGTERM under 60s
timeouts including npx default and MCP stdio 30s window). Short-circuit
`--version`/`-V` in bin/cli.js *before* any heavy import — read version
straight from package.json and exit. Measured: 60s+ → ~31ms. Does not
affect `<cmd> --help` lazy command loading.

#2253 — MCP stdio mode pollutes stdout with ONNX init progress, corrupting
JSON-RPC and breaking Codex/strict clients. Extend log-filters.ts to redirect
known third-party embedder progress prefixes (`Loading model: `,
`  Downloading: `, `  Cache hit: `, `  Disk cache hit: `,
`Model cache cleared`, `🚀 Initializing `, `✅ `) from console.log to
stderr. Filter installed in BOTH `bin/cli.js` (so MCP-mode path benefits
before mcp-client.js imports) and `src/log-filters.ts` (CLI mode). Verified
end-to-end: `echo '<jsonrpc>' | node bin/cli.js` now returns clean
`{"jsonrpc":"2.0","id":1,"result":...}` on stdout with all noise on stderr.

#2246 (memory_search_unified 6-namespace hardcode) — already fixed in source
(3.10.29, ADR-089). Reporter's environment was 3.10.22 dist. Confirmed
present in v3/@claude-flow/cli/dist/src/mcp-tools/memory-tools.js. Ships in
the next published version. No code change.

#2243 (verify.mjs cannot load @noble/ed25519) — not a code bug. Script
already handles missing dep with a clear "Fix:" message and exits 2
(precondition failure). Confirmed signatureValid=true on this checkout. The
issue is operational: the external scheduled runner is a source-only
checkout that needs to run `npm ci` before invoking verify.mjs. Fix belongs
in that runner's config (not in this repo).

#2259 (memory-store/list contradictory persistence surfaces) — out of scope
for this branch. Architectural fix in memory-bridge.ts dispatch; needs its
own PR + tests. Shape: storeEntry/listEntries both call getBridge() but the
bridge's read path diverges from its write path. Tracked separately.

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-06-02 03:59:36 -04:00
rUv 0e1d26c11e fix(security): patch CVEs, shell injection, SSRF in ruflo (#2114)
* fix(security): patch CVEs, shell injection, SSRF in ruflo

CWE-78 Shell Injection (9 execSync → execFileSync conversions):
- .claude/helpers/github-safe.js: replace execSync(`gh ${args.join(' ')}`)
  with execFileSync('gh', args) in no-body and non-body code paths; the
  body-with-file path already used a tempfile but still joined args into
  a shell string for the final gh invocation.
- v3/@claude-flow/cli/.claude/helpers/github-safe.js: same fix (init-
  template copy mirrors the dogfood helper).
- v3/@claude-flow/mcp/.claude/helpers/github-safe.js: older variant
  without body-cap; apply execFileSync throughout.
- scripts/audit-supply-chain.mjs: execSync(`npm view "${name}"`) →
  execFileSync('npm', ['view', name, ...]) so a malicious package name
  in the allowlist JSON cannot inject shell commands.
- scripts/track-clones.mjs: execSync(`gh api repos/${repo}/...`) →
  execFileSync('gh', ['api', `repos/${repo}/...`]).
- plugins/ruflo-core/scripts/witness/perf.mjs: six execSync calls in
  benchmark runners (git rev-parse, pnpm pack ×2, npm init, npm pkg
  set, npm install <tarball>, node verify.mjs) converted to
  execFileSync with split argv arrays.
- v3/@claude-flow/browser/tests/e2e/browser-e2e.test.ts: execSync with
  template-literal command string replaced by execFileSync with a
  split-on-whitespace argv array.

CWE-918 SSRF (2 callCloudFunction guards):
- ruflo/src/mcp-bridge/index.js: add assertSafeUrl() before every
  callCloudFunction call — rejects non-HTTPS schemes and private/
  loopback IP ranges (10.x, 172.16-31.x, 192.168.x, 127.x, ::1,
  fc/fd ULA, localhost, *.local).
- ruflo/src/ruvocal/mcp-bridge/index.js: identical guard applied to
  the ruvocal variant of callCloudFunction.

npm audit: 0 vulnerabilities (package.json overrides already cover all
known CVEs; confirmed clean on this audit run).

All 10 github-safe injection smoke tests pass. No new test file failures
introduced vs pre-patch baseline (verified via vitest diff).

Co-Authored-By: claude-flow <ruv@ruv.net>

* fix(supply-chain): use execFileSync instead of undefined execSync in runCveAudit

The import on line 35 only brought in `execFileSync` from `node:child_process`,
but `runCveAudit` called the never-imported `execSync`, causing a ReferenceError
on every audit run and reporting 2 spurious CVE findings (one per audited package).

Replace `execSync('npm audit ...')` with `execFileSync('npm', [...args])` to
match the already-correct pattern used in `runPublisherTrustAudit` (line 303).
This also provides the CWE-78 shell-injection mitigation already documented in
that function's comment.

Full audit now exits 0: 0 CVE, 0 lockfile, 0 allowlist, 0 typosquat findings.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-05-23 04:52:41 -04:00
ruv 5b71c7ac13 release(alpha.43+44): pin neural→sona@0.1.5, republish modules w/ standalone READMEs, add npm download badges everywhere (#2022)
This commit closes the chain started in ca0a6fa5c (standalone use recipes
landed in repo but never reached npm because no version bumps shipped).

## Changes

### Module version bumps (alpha.43)
- @claude-flow/memory     → 3.0.0-alpha.17  (republish standalone use README)
- @claude-flow/embeddings → 3.0.0-alpha.18  (republish standalone use README)
- @claude-flow/security   → 3.0.0-alpha.8   (republish standalone use README)
- @claude-flow/neural     → 3.0.0-alpha.9   (pin @ruvector/sona to 0.1.5,
                                             republish standalone use README)
- @claude-flow/cli        → 3.7.0-alpha.43  (repin to new modules above)
- claude-flow             → 3.7.0-alpha.43  (umbrella)
- ruflo                   → 3.7.0-alpha.43  (umbrella)

### Umbrella bump (alpha.44) — npm download badges
- @claude-flow/cli        → 3.7.0-alpha.44
- claude-flow             → 3.7.0-alpha.44
- ruflo                   → 3.7.0-alpha.44

### Neural sona pin (root fix for #2022)
@claude-flow/neural alpha.8 had `"@ruvector/sona": "latest"`, and
@ruvector/sona@0.1.6 (current latest on npm) shipped as an empty publish
— README + package.json only, no index.js or native bins. So every
fresh `npm install @claude-flow/neural@alpha.8` broke at import time
with `Cannot find package '.../node_modules/@ruvector/sona/index.js'`.

Alpha.9 pins to the exact known-good 0.1.5 (which has index.js + 7
platform-specific .node bins). Will revert to a range once
@ruvector/sona@0.1.7+ ships with content (tracked in #2022).

### npm download badges across every published package README
Added `shields.io/npm/dm/<pkg>` (monthly downloads) badges to:
  - claims, cli-core, plugins (had no npm badges at all)
  - plugin-agent-federation, plugin-iot-cognitum (no npm badges)
  - browser, codex, mcp (had version badge, missing downloads)
  - umbrella root README (now badges both `ruflo` + `claude-flow`)
The ruflo/README.md and v3/@claude-flow/cli/README.md auto-copy from
root via prepublishOnly, so they inherit the new badges on publish.

Packages that already carried downloads badges (aidefence, deployment,
embeddings, guidance, hooks, integration, memory, neural, performance,
providers, security, shared, swarm, testing) are unchanged.

## Live functional check on the published artifacts

  - Fresh `npm install @claude-flow/neural@3.0.0-alpha.9`:
    sona resolves to 0.1.5; `import('@claude-flow/neural')` returns
    A2CAlgorithm, BalancedMode, BaseModeImplementation, BatchMode,
    CuriosityModule, ... (was broken before alpha.9).
  - Standalone use sections from ca0a6fa5c now visible on npmjs.com for
    memory@alpha.17, embeddings@alpha.18, security@alpha.8, neural@alpha.9.
  - npm dm/ badges resolve and render the current weekly download count.

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-05-16 16:46:34 -04:00
Reuven a075c59fc2 chore: bump versions for #1874 publish chain
@claude-flow/mcp     3.0.0-alpha.8 → 3.0.0-alpha.9
  @claude-flow/shared  3.0.0-alpha.7 → 3.0.0-alpha.8
  @claude-flow/cli     3.7.0-alpha.18 → 3.7.0-alpha.19
  claude-flow          3.7.0-alpha.18 → 3.7.0-alpha.19
  ruflo                3.7.0-alpha.18 → 3.7.0-alpha.19

All published to npm with latest/alpha/v3alpha tags synced. Validated
end-to-end: fresh `npm install ruflo@latest --omit=optional` resolves
to a build where:

  - @claude-flow/mcp/dist/server.js emits  protocolVersion = '2025-11-25'
  - @claude-flow/shared/dist/mcp/server.js emits  protocolVersion = '2024-11-05'
  - @claude-flow/cli/bin/cli.js respects explicit -t http (#1874 follow-up
    that was uncovered while smoke-testing the protocol fix)

Closes the publish chain for #1874.

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-05-09 14:34:54 -04:00
Reuven d065b2d654 fix #1874 + add MCP protocol-compliance smoke layer
The bug
───────

@claude-flow/mcp and @claude-flow/shared returned protocolVersion as
{ major, minor, patch } in the initialize response. The MCP spec
requires a YYYY-MM-DD string. Claude Code's Zod validator rejects
the object form with 'Invalid input: expected string, received
object', so HTTP MCP transport users couldn't connect at all.

Fix
───

  - MCPProtocolVersion type: interface with major/minor/patch →
    type alias for string (both packages).
  - Server constants: '2025-11-25' (mcp) and '2024-11-05' (shared).
  - Existing unit test in mcp.test.ts also corrected — it was
    asserting the wrong shape, so test + prod agreed on a non-spec
    format. This is the most important finding from the
    'why did validation miss this' investigation.
  - README example updated to spec-compliant string.

Why validation missed it (the gap)
──────────────────────────────────

  - Layer 1 (smoke): no smoke test boots the actual HTTP MCP
    server, sends a real initialize request, and validates the
    wire format. The existing tests only exercise tool execution.
  - Layer 2 (witness): tracks fix presence, can't catch
    'always-wrong-from-the-start' bugs that have no good baseline.
  - Layer 3 (history): same — no marker, no signal.
  - The unit test was self-consistent with the buggy production
    code. Both used { major, minor, patch }. Nothing measured
    against the upstream MCP spec or a real client validator.

Closing the gap
───────────────

  plugins/ruflo-core/scripts/test-mcp-protocol.mjs
    Boots the HTTP MCP server, sends initialize, asserts response
    shape against the spec:
      - protocolVersion is a string matching YYYY-MM-DD
      - capabilities is an object
      - serverInfo has { name, version } strings
    Final assertion mirrors what Claude Code's Zod would accept.

  v3-ci.yml: new mcp-protocol-smoke job (Linux + macOS), gated
  before witness-verify. Three layers of regression guard now
  cover this class.

  verification/witness-fixes.json: registers #1874-mcp and
  #1874-shared. Witness now attests the spec strings are present in
  both dist files; future regressions to the object form are caught
  by witness-verify, not just user reports.

Impact
──────

  84/84 fixes verified in the regenerated manifest (was 82).
  Anyone running ruflo mcp start -t http with the new build can now
  connect Claude Code without the Zod rejection.

Closes #1874

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-05-09 13:17:38 -04:00
rUv 02976fcb9d fix(skills): prune duplicate skill sources to fix truncation (closes #1834) (#1836)
The repo carried 367 SKILL.md files across 5 locations, with 5–6x
duplicates of common skills (pair-programming, swarm-orchestration,
sparc-methodology, etc). Claude Code's session-start truncation
warning showed `pair-programming` listed twice in the dropped-skills
list — exactly the kind of duplication this PR removes.

Three structural changes:

1. **Rename `archive/v2/.claude/` → `archive/v2/_v2_claude_snapshot/`**
   The legacy v2 directory shouldn't be discovered as a `.claude/`
   config. 3.9k file renames, all under archive/, no behavior change
   for live code.

2. **Delete `v3/@claude-flow/mcp/.claude/skills/` (29 files)**
   100% duplicates of root `.claude/skills/`. The mcp package's
   `package.json#files` doesn't even include `.claude` — these were
   never published, pure local cruft.

3. **Delete `v3/@claude-flow/cli/.claude/skills/` (37 dups + 3 stray
   `.yaml`/`.md` files at the wrong level), migrate the cli-only
   `browser/` skill up to `.claude/skills/browser/`.**
   The umbrella `claude-flow` package ships `.claude/skills/` from
   the repo root, so end-users still get the canonical set. The
   stray `aidefence.yaml`, `aidefence-scan.md`, `secure-review.md`
   files weren't valid skills anyway (Claude Code expects
   `<name>/SKILL.md`, not loose `.yaml` / `.md` files at the skills
   root) — they were orphaned.

Net result on the developer's session:
  - SKILL.md count: 367 → 196 (-47%)
  - Duplicate `.claude/skills` paths: 5 → 1 (only root)
  - Truncation warning: gone (verified in-session before this commit)

Refs #1834.
2026-05-07 12:57:36 -04:00
rUv 2fd38f4ded fix(wasm): bump default Sonnet from 20250514 to 4.6 (closes #1810) (#1812)
* fix(wasm): bump default Sonnet model from 20250514 to 4.6 (#1810)

`wasm_agent_create` (gallery + plain) hardcoded
`anthropic:claude-sonnet-4-20250514` as the default model. New WASM
agents silently inherited a year-old Sonnet ID unless the caller
passed an explicit `model`, which is a quiet UX/pricing failure that
new users won't catch until they hit version-specific behaviour.

Bump to `anthropic:claude-sonnet-4-6` (current Sonnet at time of
writing) in all four locations the previous ID was hardcoded:

  - `src/ruvector/agent-wasm.ts`  — actual default (this is what
    actually shipped to users)
  - `src/commands/agent-wasm.ts`  — `--model` flag description
  - `src/commands/agent-wasm.ts`  — example command
  - `src/mcp-tools/wasm-agent-tools.ts` — MCP `wasm_agent_create`
    schema description
  - `__tests__/ruvector/agent-wasm.test.ts` — assertion in
    "creates agent with defaults"

A future follow-up should replace the hardcode with a config-driven
default (e.g. read from `claudeFlow.modelPreferences.default`) so
Anthropic version cuts don't require a code change. Tracked
separately.

Closes #1810.

Co-Authored-By: RuFlo <ruv@ruv.net>

* fix(wasm,plugins): pin gallery test + sweep remaining stale model IDs (#1810)

Follow-up to the WASM default bump in this same PR. Reviewing the
issue more carefully, the reporter's repro path goes through
`createAgentFromTemplate('researcher')` (the GALLERY path) — and
while that path *does* inherit the new default (it passes
`model: undefined`, falling through to `createWasmAgent`'s default),
nothing in the test suite actually pinned the gallery output to the
new default. A future regression would only surface in
`creates agent with defaults` (the bare-call test), not in the
gallery test the user actually hits.

  __tests__/ruvector/agent-wasm.test.ts:326
    + expect(info.model).toBe('anthropic:claude-sonnet-4-6');

While I had grep open, also swept the rest of the workspace for
the `claude-sonnet-4-20250514` literal and the matching old
Claude 4.x model IDs:

  - plugins/examples/plugin-creator/index.ts (×2 — runtime + code-gen template string)
  - plugins/examples/plugin-creator/plugin-creator.test.ts (assertion)
  - plugins/src/collections/official/index.ts (×4 — coder, tester, reviewer, coordinator agent defs)
  - plugins/src/providers/index.ts (Claude provider's models[] list — also bumped opus-4-5 → opus-4-7 and 3-5-haiku → haiku-4-5)
  - plugins/README.md (example snippet)
  - mcp/.claude/settings.json (modelPreferences default + routing)

Historical ADR docs (`v3/implementation/adrs/`) still reference
the old IDs by design — they capture decisions at issuance time.
Comments in the WASM agent source that reference the old hardcode
for context are kept too.

Strengthens the original closes-#1810 fix from "default works"
to "default works AND a regression of the gallery path is caught
by tests AND no other surface in the workspace ships the stale
ID anymore."

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-05-06 16:51:44 -04:00
rUv 196c837a9b docs(skill): add Security Considerations to github-project-management (#1574) (#1817)
skills.sh flagged this skill for two prompt-injection / command-injection
risks rooted in the same pattern: the skill instructs the assistant to
read and act on GitHub-hosted content (issue bodies, comments, labels,
PR descriptions) which is untrusted by anyone with write access — or
in public repos, anyone at all.

The skill never explicitly told the agent that those bytes were
adversarial. The fix is documentation: a prominent
"Security Considerations (read first)" section at the top of the skill
that names four concrete risks and the right response for each:

  - Prompt injection inside issue/PR/comment text
  - Shell-command injection via unquoted interpolation of
    `$ISSUE_BODY` / `${{ github.event.label.name }}` / etc.
  - Malicious URLs in issue content (don't auto-fetch)
  - "Treat untrusted content as DATA, not instructions" — extract
    structured fields, summarize neutrally, never act on directives

Also names the workflow-trigger threat surface
(`pull_request_target`, `issue_comment`, `label`, etc.) where the
entire trigger payload is adversarial.

The skill ships in three locations (root `.claude/skills`, plus
`v3/@claude-flow/cli` and `v3/@claude-flow/mcp` package copies);
all three are kept in sync. Existing tooling guidance and code
examples in the skill are unchanged — this PR is additive.

Closes #1574.
2026-05-06 16:51:27 -04:00
rUv 282143a60d Fix init hook bugs: TOOL_INPUT_prompt overflow and description field (#1161)
The PreToolUse:Task hook used $TOOL_INPUT_prompt which expands to the
full agent prompt (thousands of characters), overflowing the shell's
argument length limit. Switched to $TOOL_INPUT_description (the short
3-5 word field) and truncated to 200 chars.

Fixes #1160
2026-02-17 13:28:48 -08:00
rUv eddfb0f709 fix(statusline): avoid Claude Code collision zone with safe multi-line output (#986)
Claude Code writes its internal status (e.g., "7s • 1p") at absolute terminal
coordinates (columns 15-25 on second-to-last line), causing character bleeding
when our statusline has content there.

Changes:
- Add generateSingleLine() for single-line output (complete avoidance)
- Add generateSafeStatusline() with 24-space padding after emoji (2+24=26)
- Make safe mode the default, add --single/--unsafe/--legacy options
- Add comprehensive tests for collision zone avoidance

The collision zone is cols 15-25 on the second-to-last line of output.
By padding with 24 spaces after the emoji (2 cols), content starts at
column 26, safely past the collision zone.

Fixes #985
2026-01-22 16:07:50 -05:00
rUv 9ca9b1d362 fix(v3): Resolve CLI issues #939-#943
## Bug Fixes

### #943 - hive-mind/spawn MCP tool
- Added `hive-mind/spawn` MCP tool that combines agent/spawn + hive-mind/join
- Spawns workers and automatically joins them to hive-mind collective
- Supports count, role, agentType, prefix parameters

### #942 - HTTP Transport singleton pattern
- Fixed singleton to recreate when transport type changes
- Fixed module import path from broken relative to @claude-flow/mcp package
- Added @claude-flow/mcp as CLI dependency

### #940 - dist path mismatch
- Confirmed fixed - package.json exports point to dist/src/ correctly

### #939 - MCP start in Codespace
- Confirmed fixed - MCP server starts with 27 tools

## Published Versions
- @claude-flow/cli@3.0.0-alpha.118
- @claude-flow/mcp@3.0.0-alpha.8
- claude-flow@3.0.0-alpha.77

## Other Changes
- Regenerated agent YAML configs via hooks build-agents
- Added .claude directory to @claude-flow/mcp package

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-15 14:44:49 +00:00
rUv 66bff3a452 Checkpoint: File edits
Automatic checkpoint created by Claude Code
- Branch: v3
- Timestamp: 2026-01-07T19:28:38Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 19:28:38 +00:00
rUv 749a7475d6 Checkpoint: File edits
Automatic checkpoint created by Claude Code
- Branch: v3
- Timestamp: 2026-01-07T19:04:44Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 19:04:44 +00:00
rUv e300bb55eb Checkpoint: File edits
Automatic checkpoint created by Claude Code
- Branch: v3
- Timestamp: 2026-01-07T19:04:42Z
- Changes: 19 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 19:04:42 +00:00
rUv a9366127d4 Checkpoint: File edits
Automatic checkpoint created by Claude Code
- Branch: v3
- Timestamp: 2026-01-07T18:49:12Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 18:49:12 +00:00
rUv 6ad7a378d0 fix(hooks): Fix checkpoint hooks to handle plain file paths
- Updated standard-checkpoint-hooks.sh to accept both JSON and plain paths
- Fixed pre-edit and post-edit functions to detect input format
- Fixed v3 CLI hook flags (-f -> --file, -c -> --command, etc.)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 02:54:48 +00:00
rUv bad2be3919 feat(claims): Complete ADR-016 claims module implementation
- Add @claude-flow/claims package with 161 passing tests
- Implement ClaimService, WorkStealingService, LoadBalancer
- Add domain types, events, rules per ADR-016 spec
- Create 17 MCP tools for claiming, stealing, load balancing
- Add CLI commands for issue management
- Fix type errors: ClaimStatus, status transitions, exports
- Enable auto-commit and auto-push in settings.json
- Update v3 packages and configurations

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-06 22:38:00 +00:00
rUv 1764e25886 checkpoint: File edit:
🚀 Generated with [Claude Code](https://claude.com/claude-code)
📊 V3 Development Progress Checkpoint

Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
2026-01-05 22:28:29 +00:00
rUv 44de76a1a4 checkpoint: File edit:
🚀 Generated with [Claude Code](https://claude.com/claude-code)
📊 V3 Development Progress Checkpoint

Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
2026-01-05 22:13:14 +00:00
rUv 9b33e1b2a0 checkpoint: Manual test
🚀 Generated with [Claude Code](https://claude.com/claude-code)
📊 V3 Development Progress Checkpoint

Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>
2026-01-05 22:05:06 +00:00