Commit Graph

3 Commits

Author SHA1 Message Date
rUv 401e02d511 fix: complete reports and consistent initialization for v3.32.37 (#2851)
* fix(metaharness): preserve readiness verdict payloads

* test(metaharness): cover blocked genome verdicts

* fix(adr): parse bullet metadata and relationships (#2659)

* fix(adr): align adr-create with AgentDB schema (#2651)

* fix(adr): make index updates idempotent (#2660)

* fix(memory): bound session-end graph consolidation (#2628)

* fix(memory): align active row visibility (#2652)

* fix(memory): honor database path during init

* fix(hooks): keep all shim fallback tags aligned

* fix(codex): omit unbacked full-template skills

* fix(init): generate complete native dual projects

* test(memory): isolate path and legacy-row regressions

* chore(release): prepare v3.32.37
2026-07-29 15:40:17 -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 f0ee0f9688 fix(#1921): plugin hooks use a resilient shim, not bare npx @alpha per fire (#1923)
* fix(#1921): plugin hooks invoke a resilient shim, not bare `npx @alpha` per fire

Every PreToolUse/PostToolUse/Stop hook ran `npx <pkg>@alpha hooks …`, which
(a) re-resolves the @alpha dist-tag from the registry on every fire and
(b) re-installs from cold cache — and when that install crashes (an arborist
`Invalid Version` on npm 10.8.x, deep in a transitive OTEL/grpc subtree) the
user sees a hook error in Claude Code after every assistant turn, plus ~7s of
wasted registry traffic per turn.

Fix: each plugin (`.claude-plugin/`, `plugin/`, `plugins/ruflo-core/`) ships
`scripts/ruflo-hook.sh` — prefers an already-installed `ruflo`/`claude-flow`
binary, falls back to `npx --prefer-offline --yes ruflo@alpha`, and ALWAYS
exits 0. hooks.json invokes `"${CLAUDE_PLUGIN_ROOT}/scripts/ruflo-hook.sh" …
|| true` (the `|| true` covers the unset-$CLAUDE_PLUGIN_ROOT case). stdin
(the hook event JSON) passes through unchanged; the stdin-jq-xargs
shell-injection-safety pattern in plugin/hooks/hooks.json is preserved.

This does NOT fix the underlying arborist crash (which needs the offending
empty-`version` package pinned via `overrides` once it's identified on
npm 10.8.2 — see the issue thread) — it makes a CLI/install failure invisible
and cheap instead of a visible error every turn.

CI guard: scripts/audit-hook-commands.mjs — fails CI if any hook `command`
uses `npx` without `--prefer-offline`, or invokes the CLI without a non-fatal
guard. Wired into v3-ci.yml as `hook-command-audit` (also bash-lints each
ruflo-hook.sh and asserts it exits 0 with no CLI on PATH) + added to
witness-verify needs[]. Path triggers updated to fire on `**/hooks/hooks.json`,
`**/scripts/ruflo-hook.sh`, and `scripts/**`. Witness markers for #1921 +

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

* fix(#1921): make test-hooks.mjs shim-aware; fix shim-lint CI step; regen witness

Rebasing #1921 onto main surfaced 3 CI failures:

- plugin-hooks-smoke (ubuntu + macos): test-hooks.mjs substituted only
  `npx ruflo@alpha` → the local CLI, but the hooks.json now invokes
  `${CLAUDE_PLUGIN_ROOT}/scripts/ruflo-hook.sh <args>`. It now also
  substitutes the shim path → `<cli> hooks <args>` (bypassing the shim, so
  the test exercises the real CLI flag wiring) and strips the shim's
  trailing `|| true` so exit codes are still asserted. 7/7 pass.
- hook-command-audit shim-lint step: `PATH="/nonexistent" bash "$sh"` set
  PATH to a dir with no `bash`, so `bash: command not found`. Now invokes
  bash by full path with `PATH=` empty: `PATH= "$BASH" "$sh"` — the shim's
  `command -v` is a builtin (works with empty PATH) and the npx fallback
  fails cleanly under `|| true` → exit 0. (resolved in v3-ci.yml during the
  rebase.)

Witness manifest regenerated; #1862's marker refreshed to match the
shim-relocated `post-edit -f "$FILE" -s true` (the documented-flag form is
preserved). `ruflo verify` 0 regressed.

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

---------

Co-authored-by: Reuven <cohen@ruv-mac-mini.local>
2026-05-12 00:51:18 -04:00