Files
ruvnet__ruflo/ruflo/bin/ruflo.js
ruv 07b4c86092 release: 3.10.33 + CI regression guards for #2267 / #2257 / #2256
Published to npm — @claude-flow/cli, claude-flow, ruflo all 3.10.33
(latest, alpha, v3alpha dist-tags). Verified end-to-end against the
published ruflo@3.10.33:
  • `ruflo --version` → 33 ms (was 60 s+ on cold ONNX cache, #2256)
  • MCP stdio `initialize` → clean JSON-RPC on stdout, ONNX progress
    on stderr (#2253)

ruflo wrapper fast-path (#2256 follow-up)
  `ruflo/bin/ruflo.js` imports `@claude-flow/cli/dist/src/index.js`
  directly, bypassing `bin/cli.js` and the --version short-circuit added
  in the previous commit. End-to-end test showed `npx ruflo --version`
  still hit the 1.4 s ONNX init. Same guard now inlined in the wrapper:
  reads version from this wrapper's own package.json and exits before
  any heavy import.

CI regression guards (catches regressions of THIS release at PR-time
instead of at scheduled-cron-time where the previous breakage hid for
5 consecutive runs):

  scripts/smoke-workflows-yaml.mjs (#2267)
    Parses every `.github/workflows/*.yml`. Exits non-zero on any YAML
    syntax error. The root cause of #2267 was an unquoted `:` inside a
    step name string — GitHub Actions accepted the push, scheduled the
    run, and silently produced zero jobs. This guard catches it at PR-
    time so the next "Guard 2 — smoke: foo" doesn't slip through.

  scripts/smoke-router-regex.mjs (#2257)
    Renders the router from the source-of-truth generator
    (helpers-generator.ts::generateAgentRouter) and asserts:
    • 11 known mis-route cases route correctly
    • Confidence on a match is NOT 0.8 (regression of the heuristic-vs-
      learned-classifier overclaim)
    • The generator source still contains \b boundary anchors

  v3-ci.yml: new `static-regression-guards` job runs both smokes early
  (no build, no install of the workspace — just js-yaml + tsx). 53 jobs
  total now parse cleanly.

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-06-02 03:59:36 -04:00

78 lines
2.9 KiB
JavaScript
Executable File

#!/usr/bin/env node
// Ruflo CLI - thin wrapper around @claude-flow/cli with ruflo branding
import { fileURLToPath, pathToFileURL } from 'node:url';
import { dirname, resolve, join } from 'node:path';
import { existsSync, readFileSync } from 'node:fs';
const __dirname = dirname(fileURLToPath(import.meta.url));
// #2256 fast path: --version / -V must NOT trigger heavy imports (the
// downstream @claude-flow/cli dist eagerly loads ruvector + a 23 MB ONNX
// model on cold cache, blocking 60+ s and causing SIGTERM under common
// timeout windows: npx default, MCP stdio 30s window). Resolve version
// from this wrapper's own package.json and exit before any heavy import.
// (bin/cli.js has the same guard for the direct path; needed here too
// because the wrapper imports dist/src/index.js, bypassing bin/cli.js.)
{
const _argv = process.argv.slice(2);
if (_argv.length === 1 && (_argv[0] === '--version' || _argv[0] === '-V')) {
try {
const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'));
process.stdout.write(`ruflo v${pkg.version || '0.0.0'}\n`);
} catch {
process.stdout.write('ruflo v0.0.0\n');
}
process.exit(0);
}
}
// Walk up from ruflo/bin/ to find @claude-flow/cli in node_modules
function findCliPath() {
let dir = resolve(__dirname, '..');
for (let i = 0; i < 10; i++) {
const candidate = join(dir, 'node_modules', '@claude-flow', 'cli', 'bin', 'cli.js');
if (existsSync(candidate)) return dir;
const parent = dirname(dir);
if (parent === dir) break;
dir = parent;
}
return null;
}
// Convert path to file:// URL for cross-platform ESM import (Windows requires this)
function toImportURL(filePath) {
return pathToFileURL(filePath).href;
}
const pkgDir = findCliPath();
const cliBase = pkgDir
? join(pkgDir, 'node_modules', '@claude-flow', 'cli')
: resolve(__dirname, '../../v3/@claude-flow/cli');
// MCP mode: delegate to cli.js directly (branding irrelevant for JSON-RPC)
const cliArgs = process.argv.slice(2);
const isExplicitMCP = cliArgs.length >= 1 && cliArgs[0] === 'mcp' && (cliArgs.length === 1 || cliArgs[1] === 'start');
const isMCPMode = !process.stdin.isTTY && (process.argv.length === 2 || isExplicitMCP);
if (isMCPMode) {
await import(toImportURL(join(cliBase, 'bin', 'cli.js')));
} else {
// CLI mode: use ruflo branding
const { CLI } = await import(toImportURL(join(cliBase, 'dist', 'src', 'index.js')));
const cli = new CLI({
name: 'ruflo',
description: 'Ruflo - AI Agent Orchestration Platform',
});
cli.run()
.then(() => {
// #1641/#1653: Exit cleanly after one-shot commands.
// HNSW VectorDb, sql.js WASM, and ONNX worker threads keep the
// event loop alive after the command handler returns.
process.exit(0);
})
.catch((error) => {
console.error('Fatal error:', error.message);
process.exit(1);
});
}