claude-flow 3.46.0 → 3.47.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/node_modules/@claude-flow/codex/dist/cli.js +0 -0
- package/node_modules/@claude-flow/plugin-agent-federation/dist/bin.js +0 -0
- package/package.json +1 -1
- package/v3/@claude-flow/cli/catalog-manifest.json +2 -2
- package/v3/@claude-flow/cli/dist/src/commands/federation.js +4 -2
- package/v3/@claude-flow/cli/dist/src/mcp-tools/browser-tools.js +31 -27
- package/v3/@claude-flow/cli/dist/src/mcp-tools/x-federation-join.d.ts +2 -2
- package/v3/@claude-flow/cli/dist/src/mcp-tools/x-federation-join.js +61 -18
- package/v3/@claude-flow/cli/dist/src/runtime/browser-command.d.ts +29 -0
- package/v3/@claude-flow/cli/dist/src/runtime/browser-command.js +101 -0
- package/v3/@claude-flow/cli/package.json +1 -1
- package/.claude/.proven-config-version +0 -1
- package/.claude/proven-config.json +0 -42
|
File without changes
|
|
File without changes
|
package/package.json
CHANGED
|
@@ -13,6 +13,8 @@ async function run(ctx, tool, args, title) {
|
|
|
13
13
|
// CLI flag --gateway takes precedence over the RUFLO_X_GATEWAY_URL env var (ADR-125).
|
|
14
14
|
const data = await callMCPTool(tool, { gatewayUrl: ctx.flags.gateway, ...args });
|
|
15
15
|
printJsonOrTable(ctx, data, title);
|
|
16
|
+
if (data && typeof data === 'object' && (('ok' in data && data.ok === false) || ('degraded' in data && data.degraded === true)))
|
|
17
|
+
return { success: false, exitCode: 1, data };
|
|
16
18
|
return { success: true, data };
|
|
17
19
|
}
|
|
18
20
|
catch (e) {
|
|
@@ -28,8 +30,8 @@ export const federationCommand = {
|
|
|
28
30
|
{ name: 'gateway', description: 'Gateway base URL (takes precedence over RUFLO_X_GATEWAY_URL; default https://x.ruv.io)', type: 'string' },
|
|
29
31
|
],
|
|
30
32
|
subcommands: [
|
|
31
|
-
{ name: 'join', description: 'Join the open swarm with YOUR OWN key
|
|
32
|
-
options: [{ name: 'code', description: 'Invite code (v2.…) — a bearer secret, keep it private', type: 'string'
|
|
33
|
+
{ name: 'join', description: 'Join the open swarm with YOUR OWN key without an invite on open relays (generates ~/.ruflo/nostr.key if absent, registers via NIP-98, verifies via NIP-42)',
|
|
34
|
+
options: [{ name: 'code', description: 'Invite code (v2.…) — a bearer secret, keep it private', type: 'string' }],
|
|
33
35
|
action: (ctx) => run(ctx, 'x_federation_join', { code: ctx.flags.code }, 'Join federation') },
|
|
34
36
|
{ name: 'sync', description: 'Fetch recent verified swarm messages',
|
|
35
37
|
options: [{ name: 'since', description: 'Look-back seconds (default 3600)', type: 'number' }, { name: 'limit', description: 'Max messages', type: 'number' }, { name: 'type', description: 'Filter by message type', type: 'string' }],
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { readFileSync, existsSync } from 'node:fs';
|
|
8
8
|
import { validateIdentifier, validateText } from './validate-input.js';
|
|
9
|
+
import { resolveAgentBrowserLaunch, resolveNpxLaunch } from '../runtime/browser-command.js';
|
|
9
10
|
// Session registry for multi-session support
|
|
10
11
|
const browserSessions = new Map();
|
|
11
12
|
/** Preserve agent-browser's JSON error on non-zero exit without echoing other process output. */
|
|
@@ -46,36 +47,39 @@ function browserCommandFailure(error, missingExecutable) {
|
|
|
46
47
|
export async function execBrowserCommand(args, session = 'default') {
|
|
47
48
|
const { execFileSync } = await import('child_process');
|
|
48
49
|
const fullArgs = ['--session', session, '--json', ...args];
|
|
50
|
+
// ADR-401: fullArgs carries tool-supplied text (fill values, eval scripts,
|
|
51
|
+
// selectors), so no spawn here may use a shell. On Windows the npm shims are
|
|
52
|
+
// resolved to the process behind them instead of enabling `shell: true`,
|
|
53
|
+
// which would hand that text to cmd.exe. Never add a `shell` option below.
|
|
54
|
+
const missing = 'Neither agent-browser nor npx found. Install with: npm i -g agent-browser';
|
|
49
55
|
let result;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
56
|
+
const global = resolveAgentBrowserLaunch();
|
|
57
|
+
if (global) {
|
|
58
|
+
try {
|
|
59
|
+
result = execFileSync(global.command, [...global.argsPrefix, ...fullArgs], {
|
|
60
|
+
encoding: 'utf-8',
|
|
61
|
+
timeout: 30000,
|
|
62
|
+
windowsHide: true,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
if (error.code !== 'ENOENT')
|
|
67
|
+
return browserCommandFailure(error);
|
|
68
|
+
}
|
|
55
69
|
}
|
|
56
|
-
|
|
57
|
-
const
|
|
58
|
-
if (
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
result = execFileSync('npx', ['--yes', 'agent-browser', ...fullArgs], {
|
|
67
|
-
encoding: 'utf-8',
|
|
68
|
-
timeout: 60000,
|
|
69
|
-
shell: process.platform === 'win32',
|
|
70
|
-
windowsHide: true,
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
catch (npxError) {
|
|
74
|
-
return browserCommandFailure(npxError, 'Neither agent-browser nor npx found. Install with: npm i -g agent-browser');
|
|
75
|
-
}
|
|
70
|
+
if (result === undefined) {
|
|
71
|
+
const npx = resolveNpxLaunch();
|
|
72
|
+
if (!npx)
|
|
73
|
+
return browserCommandFailure(Object.assign(new Error('npx not resolvable'), { code: 'ENOENT' }), missing);
|
|
74
|
+
try {
|
|
75
|
+
result = execFileSync(npx.command, [...npx.argsPrefix, '--yes', 'agent-browser', ...fullArgs], {
|
|
76
|
+
encoding: 'utf-8',
|
|
77
|
+
timeout: 60000,
|
|
78
|
+
windowsHide: true,
|
|
79
|
+
});
|
|
76
80
|
}
|
|
77
|
-
|
|
78
|
-
return browserCommandFailure(
|
|
81
|
+
catch (npxError) {
|
|
82
|
+
return browserCommandFailure(npxError, missing);
|
|
79
83
|
}
|
|
80
84
|
}
|
|
81
85
|
let data;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Self-service join
|
|
2
|
+
* Self-service federation join with a local key: public registration or a private invite.
|
|
3
3
|
*
|
|
4
4
|
* Decentralized by design: the user generates/holds THEIR OWN Nostr key locally,
|
|
5
|
-
*
|
|
5
|
+
* registers with a NIP-98-signed request (no admin in the user flow), proves
|
|
6
6
|
* membership with NIP-42, and announces themselves. The gateway never signs for them.
|
|
7
7
|
*
|
|
8
8
|
* `nostr-tools` is an optional dependency (secp256k1/Schnorr is not in node:crypto):
|
|
@@ -36,49 +36,92 @@ export function nip98Header(nt, sk, url, method, body) {
|
|
|
36
36
|
export async function verifyMembership(nt, sk, relayWs) {
|
|
37
37
|
const { default: WebSocket } = await import('ws');
|
|
38
38
|
return new Promise((resolve) => {
|
|
39
|
-
const ws = new WebSocket(relayWs, { perMessageDeflate: false });
|
|
40
|
-
let done = false;
|
|
39
|
+
const ws = new WebSocket(relayWs, { perMessageDeflate: false, maxPayload: 64 * 1024 });
|
|
40
|
+
let done = false, authId;
|
|
41
41
|
const fin = (r) => { if (done)
|
|
42
|
-
return; done = true; try {
|
|
42
|
+
return; done = true; clearTimeout(timer); try {
|
|
43
43
|
ws.close();
|
|
44
44
|
}
|
|
45
45
|
catch { /* */ } resolve(r); };
|
|
46
|
+
const timer = setTimeout(() => fin({ ok: false, reason: 'timeout' }), 15000);
|
|
46
47
|
ws.on('message', (d) => {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
let m;
|
|
49
|
+
try {
|
|
50
|
+
m = JSON.parse(d.toString());
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (!Array.isArray(m))
|
|
56
|
+
return;
|
|
57
|
+
if (m[0] === 'AUTH' && typeof m[1] === 'string' && m[1].length <= 1024 && !authId) {
|
|
58
|
+
const ev = nt.finalizeEvent({ kind: 22242, created_at: Math.floor(Date.now() / 1000), tags: [['relay', relayWs], ['challenge', m[1]]], content: '' }, sk);
|
|
59
|
+
authId = ev.id;
|
|
60
|
+
ws.send(JSON.stringify(['AUTH', ev]));
|
|
61
|
+
}
|
|
62
|
+
else if (m[0] === 'OK' && authId && m[1] === authId)
|
|
63
|
+
fin({ ok: m[2] === true, reason: m[3] });
|
|
52
64
|
});
|
|
53
65
|
ws.on('error', (e) => fin({ ok: false, reason: e.message }));
|
|
54
|
-
|
|
66
|
+
ws.on('close', () => fin({ ok: false, reason: 'closed before authentication' }));
|
|
55
67
|
});
|
|
56
68
|
}
|
|
69
|
+
function secureBase(value) {
|
|
70
|
+
const u = new URL(value);
|
|
71
|
+
if ((u.protocol !== 'https:' && !(u.protocol === 'http:' && ['127.0.0.1', 'localhost', '[::1]'].includes(u.hostname)))
|
|
72
|
+
|| u.username || u.password || u.search || u.hash || u.pathname !== '/')
|
|
73
|
+
throw new Error('gateway must be an HTTPS origin (HTTP allowed only for loopback tests)');
|
|
74
|
+
return u.origin;
|
|
75
|
+
}
|
|
57
76
|
export const xFederationJoinTools = [{
|
|
58
77
|
name: 'x_federation_join',
|
|
59
|
-
description: 'Join the
|
|
78
|
+
description: 'Join the federation with YOUR OWN local key, without an invite when public registration is enabled. Reuses ~/.ruflo/nostr.key (0600), proves key ownership with NIP-98, and verifies membership with NIP-42. Use when a user wants to join as themselves. Publishing as the gateway is wrong for personal identity. Optional private invite codes remain supported; never share keys or codes in chat.',
|
|
60
79
|
inputSchema: { type: 'object', properties: {
|
|
61
|
-
code: { type: 'string', description: '
|
|
80
|
+
code: { type: 'string', description: 'Optional private invite code (v2.…), for invite-only relays.' },
|
|
81
|
+
gatewayUrl: { type: 'string', description: 'Public registration gateway origin; defaults to https://x.ruv.io.' },
|
|
62
82
|
relayHttp: { type: 'string', description: 'Relay HTTPS base for the claim; takes precedence over RUFLO_X_RELAY_HTTP.' },
|
|
63
83
|
relayWs: { type: 'string', description: 'Relay wss URL for NIP-42; takes precedence over RUFLO_X_RELAY_WS.' },
|
|
64
84
|
keyFile: { type: 'string', description: 'Key file path; takes precedence over RUFLO_NOSTR_KEY_FILE (default ~/.ruflo/nostr.key).' }
|
|
65
|
-
}, required: [
|
|
85
|
+
}, required: [] },
|
|
66
86
|
handler: async (input) => {
|
|
67
87
|
const i = input;
|
|
68
88
|
const nt = await loadNostrTools();
|
|
69
89
|
// Validate input before the optional-dependency check so a bad code fails fast and identically
|
|
70
90
|
// whether or not nostr-tools is present.
|
|
71
|
-
if (!/^v2\.[A-Za-z0-9._-]{8,}$/.test(i.code))
|
|
91
|
+
if (i.code !== undefined && !/^v2\.[A-Za-z0-9._-]{8,}$/.test(i.code))
|
|
72
92
|
throw new Error('invite code must look like v2.<token>');
|
|
73
93
|
if (!nt)
|
|
74
94
|
return { degraded: true, reason: 'nostr-tools not installed', hint: 'npm i -g nostr-tools (secp256k1 signing is not in node:crypto)' };
|
|
95
|
+
const registrationBase = i.code ? undefined : secureBase(i.gatewayUrl || process.env.RUFLO_X_GATEWAY_URL || 'https://x.ruv.io');
|
|
75
96
|
const { sk, pubkey, created } = loadOrCreateKey(nt, i.keyFile);
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
97
|
+
// Existing members need no new grant. In particular never downgrade/re-admit
|
|
98
|
+
// their key just because they run join again.
|
|
99
|
+
if (!i.code) {
|
|
100
|
+
const existing = await verifyMembership(nt, sk, RELAY_WS(i.relayWs));
|
|
101
|
+
if (existing.ok)
|
|
102
|
+
return { ok: true, pubkey, keyCreated: created, membershipVerified: true, alreadyMember: true };
|
|
103
|
+
}
|
|
104
|
+
const url = i.code ? `${secureBase(HTTP_BASE(i.relayHttp))}/api/invites/claim` : `${registrationBase}/api/registration`;
|
|
105
|
+
const body = i.code ? JSON.stringify({ code: i.code }) : '{}';
|
|
106
|
+
let r;
|
|
107
|
+
try {
|
|
108
|
+
r = await fetch(url, { method: 'POST', redirect: 'error', headers: { Authorization: nip98Header(nt, sk, url, 'POST', body), 'Content-Type': 'application/json' }, body, signal: AbortSignal.timeout(20_000) });
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
const check = await verifyMembership(nt, sk, RELAY_WS(i.relayWs));
|
|
112
|
+
if (check.ok)
|
|
113
|
+
return { ok: true, pubkey, keyCreated: created, membershipVerified: true };
|
|
114
|
+
throw new Error('Admission response unavailable and relay membership unverified. Keep your local key and retry; do not create another identity.');
|
|
115
|
+
}
|
|
79
116
|
const claim = (await r.json().catch(() => ({})));
|
|
80
|
-
if (!r.ok)
|
|
81
|
-
|
|
117
|
+
if (!r.ok) {
|
|
118
|
+
// A lost acknowledgment can follow a successful grant. Check with the
|
|
119
|
+
// relay before declaring failure; never silently generate a second key.
|
|
120
|
+
const check = await verifyMembership(nt, sk, RELAY_WS(i.relayWs));
|
|
121
|
+
if (check.ok)
|
|
122
|
+
return { ok: true, pubkey, keyCreated: created, membershipVerified: true };
|
|
123
|
+
throw new Error(`join rejected (${r.status}): ${claim.error ?? claim.message ?? 'unknown'}`);
|
|
124
|
+
}
|
|
82
125
|
const auth = await verifyMembership(nt, sk, RELAY_WS(i.relayWs));
|
|
83
126
|
return { ok: auth.ok, pubkey, keyCreated: created, role: claim.role ?? 'member', membershipVerified: auth.ok, ...(auth.ok ? {} : { reason: auth.reason }),
|
|
84
127
|
next: 'Publish kind-1 events tagged ["t","ruflo-swarm"] — or run `ruflo federation sync` to read the swarm.' };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A process target Node can spawn with `shell: false`.
|
|
3
|
+
* The caller appends its own argv after `argsPrefix`.
|
|
4
|
+
*/
|
|
5
|
+
export interface BrowserLaunch {
|
|
6
|
+
command: string;
|
|
7
|
+
argsPrefix: string[];
|
|
8
|
+
}
|
|
9
|
+
export interface BrowserLaunchOptions {
|
|
10
|
+
platform?: NodeJS.Platform;
|
|
11
|
+
nodeExecutable?: string;
|
|
12
|
+
lookup?: (command: string, args: string[]) => string;
|
|
13
|
+
fileExists?: (path: string) => boolean;
|
|
14
|
+
readFile?: (path: string) => string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Locate a globally installed `agent-browser`.
|
|
18
|
+
* POSIX: the command name itself (spawned without a shell, as before).
|
|
19
|
+
* Windows: a native `.exe`, or `node <entry.js>` behind the npm shim; null when
|
|
20
|
+
* neither can be resolved without a shell.
|
|
21
|
+
*/
|
|
22
|
+
export declare function resolveAgentBrowserLaunch(options?: BrowserLaunchOptions): BrowserLaunch | null;
|
|
23
|
+
/**
|
|
24
|
+
* Locate `npx` for the `npx --yes agent-browser` fallback.
|
|
25
|
+
* POSIX: `npx` itself. Windows: `node <npm>/bin/npx-cli.js`, taken from the
|
|
26
|
+
* running Node's own npm or from the npm that `where.exe npx` points at.
|
|
27
|
+
*/
|
|
28
|
+
export declare function resolveNpxLaunch(options?: BrowserLaunchOptions): BrowserLaunch | null;
|
|
29
|
+
//# sourceMappingURL=browser-command.d.ts.map
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { posix, win32 } from 'node:path';
|
|
4
|
+
/**
|
|
5
|
+
* Windows npm shims (`agent-browser.cmd`, `npx.cmd`) are batch files. Node
|
|
6
|
+
* cannot spawn them with `shell: false`, and `shell: true` joins argv with
|
|
7
|
+
* spaces and hands the result to cmd.exe, so every tool-supplied value (a
|
|
8
|
+
* `fill` value, an `eval` script, a selector) becomes shell syntax. Resolve
|
|
9
|
+
* the shim to the JavaScript entry point (or native executable) behind it and
|
|
10
|
+
* spawn that directly, so argv reaches the process as literal data.
|
|
11
|
+
*
|
|
12
|
+
* A target ending in `.cmd` or `.bat` is never returned: spawning one implies
|
|
13
|
+
* cmd.exe regardless of the `shell` option.
|
|
14
|
+
*/
|
|
15
|
+
const BATCH_TARGET = /\.(cmd|bat)$/i;
|
|
16
|
+
function defaults(options) {
|
|
17
|
+
const platform = options.platform ?? process.platform;
|
|
18
|
+
return {
|
|
19
|
+
platform,
|
|
20
|
+
path: platform === 'win32' ? win32 : posix,
|
|
21
|
+
nodeExecutable: options.nodeExecutable ?? process.execPath,
|
|
22
|
+
lookup: options.lookup ?? ((command, args) => execFileSync(command, args, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] })),
|
|
23
|
+
fileExists: options.fileExists ?? existsSync,
|
|
24
|
+
readFile: options.readFile ?? ((file) => readFileSync(file, 'utf8')),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function whereAll(lookup, name) {
|
|
28
|
+
try {
|
|
29
|
+
return lookup('where.exe', [name])
|
|
30
|
+
.split(/\r?\n/)
|
|
31
|
+
.map((line) => line.trim())
|
|
32
|
+
.filter(Boolean);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return [];
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** `bin` of a package.json, resolved to a path that stays inside the package. */
|
|
39
|
+
function packageBinEntry(packageRoot, binName, d) {
|
|
40
|
+
let manifest;
|
|
41
|
+
try {
|
|
42
|
+
manifest = JSON.parse(d.readFile(d.path.join(packageRoot, 'package.json')));
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
const relative = typeof manifest.bin === 'string' ? manifest.bin : manifest.bin?.[binName];
|
|
48
|
+
if (typeof relative !== 'string' || !relative)
|
|
49
|
+
return null;
|
|
50
|
+
const entry = d.path.resolve(packageRoot, relative);
|
|
51
|
+
const rootWithSep = d.path.resolve(packageRoot) + d.path.sep;
|
|
52
|
+
if (!entry.startsWith(rootWithSep))
|
|
53
|
+
return null;
|
|
54
|
+
return d.fileExists(entry) ? entry : null;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Locate a globally installed `agent-browser`.
|
|
58
|
+
* POSIX: the command name itself (spawned without a shell, as before).
|
|
59
|
+
* Windows: a native `.exe`, or `node <entry.js>` behind the npm shim; null when
|
|
60
|
+
* neither can be resolved without a shell.
|
|
61
|
+
*/
|
|
62
|
+
export function resolveAgentBrowserLaunch(options = {}) {
|
|
63
|
+
const d = defaults(options);
|
|
64
|
+
if (d.platform !== 'win32')
|
|
65
|
+
return { command: 'agent-browser', argsPrefix: [] };
|
|
66
|
+
const matches = whereAll(d.lookup, 'agent-browser');
|
|
67
|
+
const executable = matches.find((candidate) => d.path.extname(candidate).toLowerCase() === '.exe' && d.fileExists(candidate));
|
|
68
|
+
if (executable)
|
|
69
|
+
return { command: executable, argsPrefix: [] };
|
|
70
|
+
for (const shim of matches) {
|
|
71
|
+
const packageRoot = d.path.join(d.path.dirname(shim), 'node_modules', 'agent-browser');
|
|
72
|
+
const entry = packageBinEntry(packageRoot, 'agent-browser', d);
|
|
73
|
+
if (!entry || BATCH_TARGET.test(entry))
|
|
74
|
+
continue;
|
|
75
|
+
if (d.path.extname(entry).toLowerCase() === '.exe')
|
|
76
|
+
return { command: entry, argsPrefix: [] };
|
|
77
|
+
return { command: d.nodeExecutable, argsPrefix: [entry] };
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Locate `npx` for the `npx --yes agent-browser` fallback.
|
|
83
|
+
* POSIX: `npx` itself. Windows: `node <npm>/bin/npx-cli.js`, taken from the
|
|
84
|
+
* running Node's own npm or from the npm that `where.exe npx` points at.
|
|
85
|
+
*/
|
|
86
|
+
export function resolveNpxLaunch(options = {}) {
|
|
87
|
+
const d = defaults(options);
|
|
88
|
+
if (d.platform !== 'win32')
|
|
89
|
+
return { command: 'npx', argsPrefix: [] };
|
|
90
|
+
const roots = [
|
|
91
|
+
d.path.dirname(d.nodeExecutable),
|
|
92
|
+
...whereAll(d.lookup, 'npx').map((shim) => d.path.dirname(shim)),
|
|
93
|
+
];
|
|
94
|
+
for (const root of roots) {
|
|
95
|
+
const entry = d.path.join(root, 'node_modules', 'npm', 'bin', 'npx-cli.js');
|
|
96
|
+
if (d.fileExists(entry))
|
|
97
|
+
return { command: d.nodeExecutable, argsPrefix: [entry] };
|
|
98
|
+
}
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=browser-command.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@claude-flow/cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.47.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Ruflo CLI - Enterprise AI agent orchestration with 60+ specialized agents, swarm coordination, MCP server, self-learning hooks, and vector memory for Claude Code",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
sha256:6141a8ea990c5063b77e090ae8f37f9c539d8aa8f58dcceb30f3a82f97e57319
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"adoptedAt": 1790430093159,
|
|
3
|
-
"championId": "sha256:6141a8ea990c5063b77e090ae8f37f9c539d8aa8f58dcceb30f3a82f97e57319",
|
|
4
|
-
"manifest": {
|
|
5
|
-
"schema": "ruflo.proven-config/v1",
|
|
6
|
-
"policy": {
|
|
7
|
-
"ref": "sha256:6141a8ea990c5063b77e090ae8f37f9c539d8aa8f58dcceb30f3a82f97e57319",
|
|
8
|
-
"value": {
|
|
9
|
-
"alpha": 0.3,
|
|
10
|
-
"subjectWeight": 1,
|
|
11
|
-
"mmrLambda": 0.5,
|
|
12
|
-
"bodyWeight": 1.5,
|
|
13
|
-
"typePenaltyFactor": 0.5
|
|
14
|
-
}
|
|
15
|
-
},
|
|
16
|
-
"layer": "framework/node-cli",
|
|
17
|
-
"compatibility": {
|
|
18
|
-
"ruflo": ">=3.24.0"
|
|
19
|
-
},
|
|
20
|
-
"benchmark": {
|
|
21
|
-
"corpus": "ADR-081-labelled-v1",
|
|
22
|
-
"corpusHash": "sha256:2f700b5c363e20a3bd88ce2bc9b87bbbbaa61732c6177894c6ec37890f888982"
|
|
23
|
-
},
|
|
24
|
-
"receipt": {
|
|
25
|
-
"heldOutDelta": 0.07381404928570845,
|
|
26
|
-
"redblue": "PASS",
|
|
27
|
-
"drift": 0,
|
|
28
|
-
"canary": {
|
|
29
|
-
"rollbackRate": 0,
|
|
30
|
-
"latencyP95": 244.612458000076,
|
|
31
|
-
"costPerTask": 0
|
|
32
|
-
},
|
|
33
|
-
"receiptCoverage": 1
|
|
34
|
-
},
|
|
35
|
-
"platform": [
|
|
36
|
-
"linux",
|
|
37
|
-
"macOS",
|
|
38
|
-
"windows"
|
|
39
|
-
]
|
|
40
|
-
},
|
|
41
|
-
"previous": ""
|
|
42
|
-
}
|