claude-flow 3.32.2 → 3.32.8
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/.claude/helpers/statusline.cjs +38 -38
- package/.claude-plugin/scripts/ruflo-hook.cjs +2 -2
- package/.claude-plugin/scripts/ruflo-hook.sh +17 -17
- package/package.json +1 -1
- package/v3/@claude-flow/cli/catalog-manifest.json +2 -2
- package/v3/@claude-flow/cli/dist/src/auth/client.d.ts +89 -0
- package/v3/@claude-flow/cli/dist/src/auth/client.js +242 -0
- package/v3/@claude-flow/cli/dist/src/auth/constants.d.ts +7 -0
- package/v3/@claude-flow/cli/dist/src/auth/constants.js +7 -0
- package/v3/@claude-flow/cli/dist/src/auth/scopes.d.ts +14 -0
- package/v3/@claude-flow/cli/dist/src/auth/scopes.js +21 -0
- package/v3/@claude-flow/cli/dist/src/auth/security-bridge.d.ts +36 -0
- package/v3/@claude-flow/cli/dist/src/auth/security-bridge.js +42 -0
- package/v3/@claude-flow/cli/dist/src/auth/session.d.ts +20 -0
- package/v3/@claude-flow/cli/dist/src/auth/session.js +32 -0
- package/v3/@claude-flow/cli/dist/src/auth/state.d.ts +19 -0
- package/v3/@claude-flow/cli/dist/src/auth/state.js +53 -0
- package/v3/@claude-flow/cli/dist/src/auth/types.d.ts +27 -0
- package/v3/@claude-flow/cli/dist/src/auth/types.js +11 -0
- package/v3/@claude-flow/cli/dist/src/commands/auth.d.ts +15 -0
- package/v3/@claude-flow/cli/dist/src/commands/auth.js +244 -0
- package/v3/@claude-flow/cli/dist/src/commands/doctor.js +211 -4
- package/v3/@claude-flow/cli/dist/src/commands/index.js +2 -0
- package/v3/@claude-flow/cli/dist/src/commands/proxy-lifecycle.d.ts +20 -0
- package/v3/@claude-flow/cli/dist/src/commands/proxy-lifecycle.js +277 -0
- package/v3/@claude-flow/cli/dist/src/commands/proxy.js +97 -4
- package/v3/@claude-flow/cli/dist/src/mcp-tools/memory-tools.js +11 -3
- package/v3/@claude-flow/cli/dist/src/proxy/install.d.ts +29 -0
- package/v3/@claude-flow/cli/dist/src/proxy/install.js +135 -0
- package/v3/@claude-flow/cli/dist/src/proxy/lifecycle.d.ts +61 -0
- package/v3/@claude-flow/cli/dist/src/proxy/lifecycle.js +249 -0
- package/v3/@claude-flow/cli/dist/src/proxy/paths.d.ts +34 -0
- package/v3/@claude-flow/cli/dist/src/proxy/paths.js +70 -0
- package/v3/@claude-flow/cli/dist/src/proxy/release.d.ts +47 -0
- package/v3/@claude-flow/cli/dist/src/proxy/release.js +138 -0
- package/v3/@claude-flow/cli/dist/src/proxy/token-bridge.d.ts +5 -0
- package/v3/@claude-flow/cli/dist/src/proxy/token-bridge.js +61 -0
- package/v3/@claude-flow/cli/dist/src/proxy/verify.d.ts +44 -0
- package/v3/@claude-flow/cli/dist/src/proxy/verify.js +68 -0
- package/v3/@claude-flow/cli/package.json +3 -3
- package/.claude/.proven-config-version +0 -1
- package/.claude/proven-config.json +0 -42
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filesystem layout for the managed meta-proxy binary (ADR-307), all under
|
|
3
|
+
* the same `~/.ruflo` state dir every other funnel/proxy/auth file uses
|
|
4
|
+
* (src/funnel/state.ts's `funnelStateDir()` — respects RUFLO_STATE_DIR for
|
|
5
|
+
* tests). Centralized here so doctor.ts, install.ts, and lifecycle.ts share
|
|
6
|
+
* one definition instead of three copies drifting apart.
|
|
7
|
+
*/
|
|
8
|
+
export declare function proxyBinaryPath(): string;
|
|
9
|
+
export declare function proxyPidFilePath(): string;
|
|
10
|
+
export declare function proxyLockFilePath(): string;
|
|
11
|
+
export declare function proxyLogFilePath(): string;
|
|
12
|
+
export declare function proxyInstallManifestPath(): string;
|
|
13
|
+
export declare function proxyConfigPath(): string;
|
|
14
|
+
export declare function proxyTokenPath(): string;
|
|
15
|
+
export declare function proxyInjectedTokenPath(): string;
|
|
16
|
+
export interface InstallManifest {
|
|
17
|
+
version: string;
|
|
18
|
+
sha256: string;
|
|
19
|
+
verifiedAt: string;
|
|
20
|
+
pubkeyFingerprint: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* True if `bind` (a `host:port` string from proxy-config.toml) targets a
|
|
24
|
+
* loopback address — decides whether the non-loopback exposure warning
|
|
25
|
+
* fires (ADR-307). Recognizes the whole IPv4 127.0.0.0/8 block, IPv6 `::1`,
|
|
26
|
+
* IPv4-mapped IPv6 loopback, and the `localhost` hostname.
|
|
27
|
+
*
|
|
28
|
+
* A plain `bind.startsWith('127.0.0.1')` check (the obvious first draft)
|
|
29
|
+
* misclassifies `[::1]:port` as non-loopback — a real bug meta-proxy's own
|
|
30
|
+
* Rust `is_loopback_bind` fixed for the identical reason; this mirrors that
|
|
31
|
+
* fix rather than repeating the mistake on the TypeScript side.
|
|
32
|
+
*/
|
|
33
|
+
export declare function isLoopbackBind(bind: string): boolean;
|
|
34
|
+
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filesystem layout for the managed meta-proxy binary (ADR-307), all under
|
|
3
|
+
* the same `~/.ruflo` state dir every other funnel/proxy/auth file uses
|
|
4
|
+
* (src/funnel/state.ts's `funnelStateDir()` — respects RUFLO_STATE_DIR for
|
|
5
|
+
* tests). Centralized here so doctor.ts, install.ts, and lifecycle.ts share
|
|
6
|
+
* one definition instead of three copies drifting apart.
|
|
7
|
+
*/
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
import { funnelStateDir } from '../funnel/index.js';
|
|
10
|
+
const BINARY_NAME = process.platform === 'win32' ? 'meta-proxy.exe' : 'meta-proxy';
|
|
11
|
+
export function proxyBinaryPath() {
|
|
12
|
+
return join(funnelStateDir(), 'bin', BINARY_NAME);
|
|
13
|
+
}
|
|
14
|
+
export function proxyPidFilePath() {
|
|
15
|
+
return join(funnelStateDir(), 'proxy.pid');
|
|
16
|
+
}
|
|
17
|
+
export function proxyLockFilePath() {
|
|
18
|
+
return join(funnelStateDir(), 'proxy.lock');
|
|
19
|
+
}
|
|
20
|
+
export function proxyLogFilePath() {
|
|
21
|
+
return join(funnelStateDir(), 'proxy.log');
|
|
22
|
+
}
|
|
23
|
+
export function proxyInstallManifestPath() {
|
|
24
|
+
return join(funnelStateDir(), 'proxy', 'install-manifest.json');
|
|
25
|
+
}
|
|
26
|
+
export function proxyConfigPath() {
|
|
27
|
+
return join(funnelStateDir(), 'proxy-config.toml');
|
|
28
|
+
}
|
|
29
|
+
export function proxyTokenPath() {
|
|
30
|
+
return join(funnelStateDir(), 'proxy-token');
|
|
31
|
+
}
|
|
32
|
+
export function proxyInjectedTokenPath() {
|
|
33
|
+
return join(funnelStateDir(), 'proxy-injected-token.json');
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* True if `bind` (a `host:port` string from proxy-config.toml) targets a
|
|
37
|
+
* loopback address — decides whether the non-loopback exposure warning
|
|
38
|
+
* fires (ADR-307). Recognizes the whole IPv4 127.0.0.0/8 block, IPv6 `::1`,
|
|
39
|
+
* IPv4-mapped IPv6 loopback, and the `localhost` hostname.
|
|
40
|
+
*
|
|
41
|
+
* A plain `bind.startsWith('127.0.0.1')` check (the obvious first draft)
|
|
42
|
+
* misclassifies `[::1]:port` as non-loopback — a real bug meta-proxy's own
|
|
43
|
+
* Rust `is_loopback_bind` fixed for the identical reason; this mirrors that
|
|
44
|
+
* fix rather than repeating the mistake on the TypeScript side.
|
|
45
|
+
*/
|
|
46
|
+
export function isLoopbackBind(bind) {
|
|
47
|
+
const hostPart = (host) => {
|
|
48
|
+
const stripped = host.replace(/^\[/, '').replace(/\]$/, '');
|
|
49
|
+
if (stripped.toLowerCase() === 'localhost')
|
|
50
|
+
return true;
|
|
51
|
+
if (/^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(stripped))
|
|
52
|
+
return true; // 127.0.0.0/8
|
|
53
|
+
if (stripped === '::1')
|
|
54
|
+
return true;
|
|
55
|
+
if (/^::ffff:127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/i.test(stripped))
|
|
56
|
+
return true; // IPv4-mapped loopback
|
|
57
|
+
return false;
|
|
58
|
+
};
|
|
59
|
+
// IPv6 bracketed form: [::1]:11435
|
|
60
|
+
const bracketed = bind.match(/^\[([^\]]+)\]:\d+$/);
|
|
61
|
+
if (bracketed)
|
|
62
|
+
return hostPart(bracketed[1]);
|
|
63
|
+
// host:port (IPv4 or hostname) — split on the LAST colon so a bare IPv6
|
|
64
|
+
// address without brackets (ambiguous, shouldn't occur in practice) isn't
|
|
65
|
+
// misparsed as host:port.
|
|
66
|
+
const lastColon = bind.lastIndexOf(':');
|
|
67
|
+
const host = lastColon === -1 ? bind : bind.slice(0, lastColon);
|
|
68
|
+
return hostPart(host);
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* meta-proxy release resolution + download (ADR-307).
|
|
3
|
+
*
|
|
4
|
+
* Two download paths, deliberately not conflated:
|
|
5
|
+
* - **Production** (`downloadReleaseAsset`): public, signed assets from
|
|
6
|
+
* cognitum-one/meta-proxy-dist. Source remains private; normal users need
|
|
7
|
+
* neither GitHub authentication nor access to the source repository.
|
|
8
|
+
* - **Dev-only** (`downloadViaGhCli`): shells out to `gh release download`,
|
|
9
|
+
* gated behind `RUFLO_DEV_PROXY_INSTALL=1` so it is never reachable by
|
|
10
|
+
* accident, and always logs loudly that it is a developer path.
|
|
11
|
+
*
|
|
12
|
+
* @module proxy/release
|
|
13
|
+
*/
|
|
14
|
+
export declare const TARGET_TRIPLES: readonly ["aarch64-apple-darwin", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu", "aarch64-unknown-linux-gnu", "x86_64-pc-windows-msvc"];
|
|
15
|
+
export type TargetTriple = (typeof TARGET_TRIPLES)[number];
|
|
16
|
+
export declare class UnsupportedPlatformError extends Error {
|
|
17
|
+
constructor(platform: string, arch: string);
|
|
18
|
+
}
|
|
19
|
+
/** Maps the running Node process's platform/arch onto one of meta-proxy's 5 published triples. */
|
|
20
|
+
export declare function detectTargetTriple(platform?: string, arch?: string): TargetTriple;
|
|
21
|
+
export declare function releaseArchiveExtension(triple: TargetTriple): 'zip' | 'tar.gz';
|
|
22
|
+
export declare function releaseAssetFilename(version: string, triple: TargetTriple): string;
|
|
23
|
+
export interface ReleaseAssets {
|
|
24
|
+
archiveBytes: Buffer;
|
|
25
|
+
archiveFilename: string;
|
|
26
|
+
sumsBytes: Buffer;
|
|
27
|
+
sigBase64: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Dev-only fallback: `gh release download` via SafeExecutor into `destDir`.
|
|
31
|
+
* Requires the caller's environment to already have `gh` authenticated
|
|
32
|
+
* against a GitHub account with access to the private meta-proxy repo — this
|
|
33
|
+
* is NOT something a normal ruflo end user has, which is exactly why this
|
|
34
|
+
* path is gated and logged, not the default.
|
|
35
|
+
*/
|
|
36
|
+
export declare function downloadViaGhCli(destDir: string, version: string, triple: TargetTriple, log?: (line: string) => void): Promise<ReleaseAssets>;
|
|
37
|
+
/**
|
|
38
|
+
* Production download path — a Cognitum-owned, auth-mediated release-proxy
|
|
39
|
+
* endpoint. Not implemented: no such endpoint exists in the confirmed
|
|
40
|
+
* OpenAPI contract today. Throws a clear, specific error rather than
|
|
41
|
+
* silently falling back to the dev path, so a real user hitting this isn't
|
|
42
|
+
* left guessing whether it's their environment or a genuine gap.
|
|
43
|
+
*/
|
|
44
|
+
export declare function downloadReleaseAsset(version: string, triple: TargetTriple, _destDir: string): Promise<ReleaseAssets>;
|
|
45
|
+
/** Entry point install.ts calls — routes to the dev path when explicitly enabled, else fails clearly. */
|
|
46
|
+
export declare function fetchReleaseAssets(version: string, triple: TargetTriple, destDir: string, log?: (line: string) => void): Promise<ReleaseAssets>;
|
|
47
|
+
//# sourceMappingURL=release.d.ts.map
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* meta-proxy release resolution + download (ADR-307).
|
|
3
|
+
*
|
|
4
|
+
* Two download paths, deliberately not conflated:
|
|
5
|
+
* - **Production** (`downloadReleaseAsset`): public, signed assets from
|
|
6
|
+
* cognitum-one/meta-proxy-dist. Source remains private; normal users need
|
|
7
|
+
* neither GitHub authentication nor access to the source repository.
|
|
8
|
+
* - **Dev-only** (`downloadViaGhCli`): shells out to `gh release download`,
|
|
9
|
+
* gated behind `RUFLO_DEV_PROXY_INSTALL=1` so it is never reachable by
|
|
10
|
+
* accident, and always logs loudly that it is a developer path.
|
|
11
|
+
*
|
|
12
|
+
* @module proxy/release
|
|
13
|
+
*/
|
|
14
|
+
export const TARGET_TRIPLES = [
|
|
15
|
+
'aarch64-apple-darwin',
|
|
16
|
+
'x86_64-apple-darwin',
|
|
17
|
+
'x86_64-unknown-linux-gnu',
|
|
18
|
+
'aarch64-unknown-linux-gnu',
|
|
19
|
+
'x86_64-pc-windows-msvc',
|
|
20
|
+
];
|
|
21
|
+
export class UnsupportedPlatformError extends Error {
|
|
22
|
+
constructor(platform, arch) {
|
|
23
|
+
super(`meta-proxy has no published release for ${platform}/${arch}`);
|
|
24
|
+
this.name = 'UnsupportedPlatformError';
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/** Maps the running Node process's platform/arch onto one of meta-proxy's 5 published triples. */
|
|
28
|
+
export function detectTargetTriple(platform = process.platform, arch = process.arch) {
|
|
29
|
+
if (platform === 'darwin')
|
|
30
|
+
return arch === 'arm64' ? 'aarch64-apple-darwin' : 'x86_64-apple-darwin';
|
|
31
|
+
if (platform === 'linux')
|
|
32
|
+
return arch === 'arm64' ? 'aarch64-unknown-linux-gnu' : 'x86_64-unknown-linux-gnu';
|
|
33
|
+
if (platform === 'win32') {
|
|
34
|
+
if (arch !== 'x64')
|
|
35
|
+
throw new UnsupportedPlatformError(platform, arch);
|
|
36
|
+
return 'x86_64-pc-windows-msvc';
|
|
37
|
+
}
|
|
38
|
+
throw new UnsupportedPlatformError(platform, arch);
|
|
39
|
+
}
|
|
40
|
+
export function releaseArchiveExtension(triple) {
|
|
41
|
+
return triple.endsWith('windows-msvc') ? 'zip' : 'tar.gz';
|
|
42
|
+
}
|
|
43
|
+
export function releaseAssetFilename(version, triple) {
|
|
44
|
+
return `meta-proxy-${version}-${triple}.${releaseArchiveExtension(triple)}`;
|
|
45
|
+
}
|
|
46
|
+
const DEV_INSTALL_ENV = 'RUFLO_DEV_PROXY_INSTALL';
|
|
47
|
+
const RELEASE_SOURCE_ENV = 'RUFLO_PROXY_RELEASE_SOURCE';
|
|
48
|
+
const GH_REPO = 'cognitum-one/meta-proxy';
|
|
49
|
+
const PUBLIC_DIST_BASE = 'https://github.com/cognitum-one/meta-proxy-dist/releases/download';
|
|
50
|
+
const MAX_ARCHIVE_BYTES = 32 * 1024 * 1024;
|
|
51
|
+
async function downloadPublicAsset(url, maxBytes) {
|
|
52
|
+
const response = await fetch(url, { redirect: 'follow', signal: AbortSignal.timeout(120_000) });
|
|
53
|
+
if (!response.ok)
|
|
54
|
+
throw new Error(`release download failed: HTTP ${response.status} for ${url}`);
|
|
55
|
+
const declared = Number(response.headers.get('content-length') ?? 0);
|
|
56
|
+
if (declared > maxBytes)
|
|
57
|
+
throw new Error(`release asset exceeds ${maxBytes} byte limit`);
|
|
58
|
+
const bytes = Buffer.from(await response.arrayBuffer());
|
|
59
|
+
if (bytes.length > maxBytes)
|
|
60
|
+
throw new Error(`release asset exceeds ${maxBytes} byte limit`);
|
|
61
|
+
return bytes;
|
|
62
|
+
}
|
|
63
|
+
async function ghExecutor() {
|
|
64
|
+
// Dynamic import, not a static one: @claude-flow/security is only an
|
|
65
|
+
// optionalDependency of this package (see auth/security-bridge.ts for the
|
|
66
|
+
// same reasoning) — a static top-level import would crash module load for
|
|
67
|
+
// any consumer that doesn't have it installed, even ones that never touch
|
|
68
|
+
// this dev-only download path.
|
|
69
|
+
const { SafeExecutor } = await import('@claude-flow/security');
|
|
70
|
+
return new SafeExecutor({ allowedCommands: ['gh'], timeout: 120_000 });
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Dev-only fallback: `gh release download` via SafeExecutor into `destDir`.
|
|
74
|
+
* Requires the caller's environment to already have `gh` authenticated
|
|
75
|
+
* against a GitHub account with access to the private meta-proxy repo — this
|
|
76
|
+
* is NOT something a normal ruflo end user has, which is exactly why this
|
|
77
|
+
* path is gated and logged, not the default.
|
|
78
|
+
*/
|
|
79
|
+
export async function downloadViaGhCli(destDir, version, triple, log = () => { }) {
|
|
80
|
+
const archiveFilename = releaseAssetFilename(version, triple);
|
|
81
|
+
log(`[dev-only] Downloading meta-proxy ${version} (${triple}) via \`gh release download\` — ` +
|
|
82
|
+
'this path is NOT how production installs work; it exists for local development only ' +
|
|
83
|
+
`(gated behind ${DEV_INSTALL_ENV}=1).`);
|
|
84
|
+
const exec = await ghExecutor();
|
|
85
|
+
const result = await exec.execute('gh', [
|
|
86
|
+
'release',
|
|
87
|
+
'download',
|
|
88
|
+
`v${version}`,
|
|
89
|
+
'--repo',
|
|
90
|
+
GH_REPO,
|
|
91
|
+
'--dir',
|
|
92
|
+
destDir,
|
|
93
|
+
'--pattern',
|
|
94
|
+
archiveFilename,
|
|
95
|
+
'--pattern',
|
|
96
|
+
'SHA256SUMS',
|
|
97
|
+
'--pattern',
|
|
98
|
+
'SHA256SUMS.sig',
|
|
99
|
+
'--clobber',
|
|
100
|
+
]);
|
|
101
|
+
if (result.exitCode !== 0) {
|
|
102
|
+
throw new Error(`gh release download failed (exit ${result.exitCode}): ${result.stderr || result.stdout}`);
|
|
103
|
+
}
|
|
104
|
+
const { readFile } = await import('node:fs/promises');
|
|
105
|
+
const { join } = await import('node:path');
|
|
106
|
+
const [archiveBytes, sumsBytes, sigRaw] = await Promise.all([
|
|
107
|
+
readFile(join(destDir, archiveFilename)),
|
|
108
|
+
readFile(join(destDir, 'SHA256SUMS')),
|
|
109
|
+
readFile(join(destDir, 'SHA256SUMS.sig'), 'utf-8'),
|
|
110
|
+
]);
|
|
111
|
+
return { archiveBytes, archiveFilename, sumsBytes, sigBase64: sigRaw.trim() };
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Production download path — a Cognitum-owned, auth-mediated release-proxy
|
|
115
|
+
* endpoint. Not implemented: no such endpoint exists in the confirmed
|
|
116
|
+
* OpenAPI contract today. Throws a clear, specific error rather than
|
|
117
|
+
* silently falling back to the dev path, so a real user hitting this isn't
|
|
118
|
+
* left guessing whether it's their environment or a genuine gap.
|
|
119
|
+
*/
|
|
120
|
+
export async function downloadReleaseAsset(version, triple, _destDir) {
|
|
121
|
+
const archiveFilename = releaseAssetFilename(version, triple);
|
|
122
|
+
const base = (process.env[RELEASE_SOURCE_ENV] || PUBLIC_DIST_BASE).replace(/\/$/, '');
|
|
123
|
+
const release = `${base}/v${encodeURIComponent(version)}`;
|
|
124
|
+
const [archiveBytes, sumsBytes, sigBytes] = await Promise.all([
|
|
125
|
+
downloadPublicAsset(`${release}/${archiveFilename}`, MAX_ARCHIVE_BYTES),
|
|
126
|
+
downloadPublicAsset(`${release}/SHA256SUMS`, 128 * 1024),
|
|
127
|
+
downloadPublicAsset(`${release}/SHA256SUMS.sig`, 16 * 1024),
|
|
128
|
+
]);
|
|
129
|
+
return { archiveBytes, archiveFilename, sumsBytes, sigBase64: sigBytes.toString('utf8').trim() };
|
|
130
|
+
}
|
|
131
|
+
/** Entry point install.ts calls — routes to the dev path when explicitly enabled, else fails clearly. */
|
|
132
|
+
export async function fetchReleaseAssets(version, triple, destDir, log) {
|
|
133
|
+
if (process.env[DEV_INSTALL_ENV] === '1') {
|
|
134
|
+
return downloadViaGhCli(destDir, version, triple, log);
|
|
135
|
+
}
|
|
136
|
+
return downloadReleaseAsset(version, triple, destDir);
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=release.js.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** ADR-318 access-token-only bridge from ruflo auth to meta-proxy. */
|
|
2
|
+
export declare function removeInjectedToken(): void;
|
|
3
|
+
export declare function refreshInjectedToken(): Promise<boolean>;
|
|
4
|
+
export declare function startTokenRefreshPump(): Promise<() => void>;
|
|
5
|
+
//# sourceMappingURL=token-bridge.d.ts.map
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/** ADR-318 access-token-only bridge from ruflo auth to meta-proxy. */
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import { dirname } from 'node:path';
|
|
4
|
+
import { getValidAccessToken } from '../auth/client.js';
|
|
5
|
+
import { getProfile, listProfiles } from '../auth/state.js';
|
|
6
|
+
import { proxyConfigPath, proxyInjectedTokenPath } from './paths.js';
|
|
7
|
+
const REFRESH_POLL_MS = 30_000;
|
|
8
|
+
function configureInjectedTokenPath() {
|
|
9
|
+
const target = proxyConfigPath();
|
|
10
|
+
fs.mkdirSync(dirname(target), { recursive: true, mode: 0o700 });
|
|
11
|
+
const raw = fs.existsSync(target) ? fs.readFileSync(target, 'utf8') : '';
|
|
12
|
+
const line = `ruflo_injected_token_path = ${JSON.stringify(proxyInjectedTokenPath())}`;
|
|
13
|
+
const pattern = /^ruflo_injected_token_path\s*=.*$/m;
|
|
14
|
+
const next = pattern.test(raw) ? raw.replace(pattern, line) : `${raw}${raw && !raw.endsWith('\n') ? '\n' : ''}${line}\n`;
|
|
15
|
+
const tmp = `${target}.tmp-${process.pid}`;
|
|
16
|
+
fs.writeFileSync(tmp, next, { encoding: 'utf8', mode: 0o600 });
|
|
17
|
+
fs.renameSync(tmp, target);
|
|
18
|
+
}
|
|
19
|
+
export function removeInjectedToken() {
|
|
20
|
+
try {
|
|
21
|
+
fs.unlinkSync(proxyInjectedTokenPath());
|
|
22
|
+
}
|
|
23
|
+
catch { /* absent */ }
|
|
24
|
+
}
|
|
25
|
+
export async function refreshInjectedToken() {
|
|
26
|
+
const { defaultProfile } = listProfiles();
|
|
27
|
+
const profile = getProfile(defaultProfile);
|
|
28
|
+
if (!profile) {
|
|
29
|
+
removeInjectedToken();
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
const accessToken = await getValidAccessToken(defaultProfile);
|
|
34
|
+
const current = getProfile(defaultProfile);
|
|
35
|
+
if (!current)
|
|
36
|
+
return false;
|
|
37
|
+
const body = JSON.stringify({ schemaVersion: 1, accessToken, expiresAt: current.accessTokenExpiresAt });
|
|
38
|
+
configureInjectedTokenPath();
|
|
39
|
+
const target = proxyInjectedTokenPath();
|
|
40
|
+
const tmp = `${target}.tmp-${process.pid}`;
|
|
41
|
+
fs.writeFileSync(tmp, body, { encoding: 'utf8', mode: 0o600 });
|
|
42
|
+
fs.chmodSync(tmp, 0o600);
|
|
43
|
+
fs.renameSync(tmp, target);
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
removeInjectedToken();
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export async function startTokenRefreshPump() {
|
|
52
|
+
await refreshInjectedToken();
|
|
53
|
+
const timer = setInterval(() => void refreshInjectedToken(), REFRESH_POLL_MS);
|
|
54
|
+
const stop = () => {
|
|
55
|
+
clearInterval(timer);
|
|
56
|
+
removeInjectedToken();
|
|
57
|
+
};
|
|
58
|
+
process.once('exit', removeInjectedToken);
|
|
59
|
+
return stop;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=token-bridge.js.map
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* meta-proxy release verification (ADR-307) — mirrors src/init/helper-signing.ts's
|
|
3
|
+
* raw-EdDSA `crypto.verify(null, ...)` pattern almost exactly, and matches the
|
|
4
|
+
* exact scheme confirmed live 2026-07-16 against a real v0.1.0 release: ONE
|
|
5
|
+
* combined `SHA256SUMS.sig` (raw Ed25519 over the `SHA256SUMS` file's bytes,
|
|
6
|
+
* base64-encoded — not a per-binary signature), then a per-asset SHA-256
|
|
7
|
+
* check against the matching `SHA256SUMS` line. Refuse-all-or-nothing on any
|
|
8
|
+
* mismatch, same discipline as `writeCriticalHelpers()`.
|
|
9
|
+
*
|
|
10
|
+
* @module proxy/verify
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* meta-proxy's committed release-signing public key (SPKI PEM), confirmed
|
|
14
|
+
* live 2026-07-16 by verifying a real `SHA256SUMS.sig` from the v0.1.0
|
|
15
|
+
* release against it (crypto.verify -> true).
|
|
16
|
+
*/
|
|
17
|
+
export declare const PROXY_RELEASE_PUBKEY_PEM = "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAjhLDomjIGdcltYC7j+aiESQFD4LWoHaULietG1PuDjw=\n-----END PUBLIC KEY-----";
|
|
18
|
+
export declare class ReleaseVerificationError extends Error {
|
|
19
|
+
constructor(message: string);
|
|
20
|
+
}
|
|
21
|
+
/** Raw EdDSA verify of `SHA256SUMS.sig` (base64) over `SHA256SUMS`'s exact bytes. */
|
|
22
|
+
export declare function verifySha256SumsSignature(sumsBytes: Buffer, sigBase64: string, pubkeyPem?: string): boolean;
|
|
23
|
+
export type ParsedChecksums = Record<string, string>;
|
|
24
|
+
/** Parses `<sha256> <filename>` lines (sha256sum's own output format). */
|
|
25
|
+
export declare function parseSha256Sums(sumsText: string): ParsedChecksums;
|
|
26
|
+
export declare function sha256Hex(bytes: Buffer): string;
|
|
27
|
+
export interface VerifyReleaseInput {
|
|
28
|
+
sumsBytes: Buffer;
|
|
29
|
+
sigBase64: string;
|
|
30
|
+
assetBytes: Buffer;
|
|
31
|
+
assetFilename: string;
|
|
32
|
+
pubkeyPem?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface VerifyReleaseResult {
|
|
35
|
+
sha256: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Full verification: signature over SHA256SUMS, then the asset's own hash
|
|
39
|
+
* against the matching line. Throws `ReleaseVerificationError` on ANY
|
|
40
|
+
* failure — there is no partial-trust outcome, matching ADR-307's "refuses
|
|
41
|
+
* on any mismatch" requirement.
|
|
42
|
+
*/
|
|
43
|
+
export declare function verifyRelease(input: VerifyReleaseInput): VerifyReleaseResult;
|
|
44
|
+
//# sourceMappingURL=verify.d.ts.map
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* meta-proxy release verification (ADR-307) — mirrors src/init/helper-signing.ts's
|
|
3
|
+
* raw-EdDSA `crypto.verify(null, ...)` pattern almost exactly, and matches the
|
|
4
|
+
* exact scheme confirmed live 2026-07-16 against a real v0.1.0 release: ONE
|
|
5
|
+
* combined `SHA256SUMS.sig` (raw Ed25519 over the `SHA256SUMS` file's bytes,
|
|
6
|
+
* base64-encoded — not a per-binary signature), then a per-asset SHA-256
|
|
7
|
+
* check against the matching `SHA256SUMS` line. Refuse-all-or-nothing on any
|
|
8
|
+
* mismatch, same discipline as `writeCriticalHelpers()`.
|
|
9
|
+
*
|
|
10
|
+
* @module proxy/verify
|
|
11
|
+
*/
|
|
12
|
+
import { createHash, createPublicKey, verify as cryptoVerify } from 'node:crypto';
|
|
13
|
+
/**
|
|
14
|
+
* meta-proxy's committed release-signing public key (SPKI PEM), confirmed
|
|
15
|
+
* live 2026-07-16 by verifying a real `SHA256SUMS.sig` from the v0.1.0
|
|
16
|
+
* release against it (crypto.verify -> true).
|
|
17
|
+
*/
|
|
18
|
+
export const PROXY_RELEASE_PUBKEY_PEM = `-----BEGIN PUBLIC KEY-----
|
|
19
|
+
MCowBQYDK2VwAyEAjhLDomjIGdcltYC7j+aiESQFD4LWoHaULietG1PuDjw=
|
|
20
|
+
-----END PUBLIC KEY-----`;
|
|
21
|
+
export class ReleaseVerificationError extends Error {
|
|
22
|
+
constructor(message) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.name = 'ReleaseVerificationError';
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/** Raw EdDSA verify of `SHA256SUMS.sig` (base64) over `SHA256SUMS`'s exact bytes. */
|
|
28
|
+
export function verifySha256SumsSignature(sumsBytes, sigBase64, pubkeyPem = PROXY_RELEASE_PUBKEY_PEM) {
|
|
29
|
+
const pubkey = createPublicKey(pubkeyPem);
|
|
30
|
+
const sig = Buffer.from(sigBase64.trim(), 'base64');
|
|
31
|
+
return cryptoVerify(null, sumsBytes, pubkey, sig);
|
|
32
|
+
}
|
|
33
|
+
/** Parses `<sha256> <filename>` lines (sha256sum's own output format). */
|
|
34
|
+
export function parseSha256Sums(sumsText) {
|
|
35
|
+
const result = {};
|
|
36
|
+
for (const line of sumsText.split(/\r?\n/)) {
|
|
37
|
+
const match = line.match(/^([0-9a-f]{64})\s+(.+)$/i);
|
|
38
|
+
if (!match)
|
|
39
|
+
continue;
|
|
40
|
+
result[match[2]] = match[1].toLowerCase();
|
|
41
|
+
}
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
export function sha256Hex(bytes) {
|
|
45
|
+
return createHash('sha256').update(bytes).digest('hex');
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Full verification: signature over SHA256SUMS, then the asset's own hash
|
|
49
|
+
* against the matching line. Throws `ReleaseVerificationError` on ANY
|
|
50
|
+
* failure — there is no partial-trust outcome, matching ADR-307's "refuses
|
|
51
|
+
* on any mismatch" requirement.
|
|
52
|
+
*/
|
|
53
|
+
export function verifyRelease(input) {
|
|
54
|
+
if (!verifySha256SumsSignature(input.sumsBytes, input.sigBase64, input.pubkeyPem)) {
|
|
55
|
+
throw new ReleaseVerificationError('SHA256SUMS.sig failed Ed25519 verification — refusing to install');
|
|
56
|
+
}
|
|
57
|
+
const sums = parseSha256Sums(input.sumsBytes.toString('utf-8'));
|
|
58
|
+
const expected = sums[input.assetFilename];
|
|
59
|
+
if (!expected) {
|
|
60
|
+
throw new ReleaseVerificationError(`SHA256SUMS has no entry for ${input.assetFilename}`);
|
|
61
|
+
}
|
|
62
|
+
const actual = sha256Hex(input.assetBytes);
|
|
63
|
+
if (actual !== expected) {
|
|
64
|
+
throw new ReleaseVerificationError(`sha256 mismatch for ${input.assetFilename}: expected ${expected.slice(0, 12)}…, got ${actual.slice(0, 12)}…`);
|
|
65
|
+
}
|
|
66
|
+
return { sha256: actual };
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=verify.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@claude-flow/cli",
|
|
3
|
-
"version": "3.32.
|
|
3
|
+
"version": "3.32.8",
|
|
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",
|
|
@@ -111,8 +111,8 @@
|
|
|
111
111
|
"yaml": "^2.8.0"
|
|
112
112
|
},
|
|
113
113
|
"optionalDependencies": {
|
|
114
|
-
"@claude-flow/memory": "^3.0.0-alpha.21",
|
|
115
|
-
"@claude-flow/security": "^3.0.0-alpha.
|
|
114
|
+
"@claude-flow/memory": "^3.0.0-alpha.21",
|
|
115
|
+
"@claude-flow/security": "^3.0.0-alpha.12",
|
|
116
116
|
"agentdb": "^3.0.0-alpha.17",
|
|
117
117
|
"agentic-flow": "^3.0.0-alpha.1",
|
|
118
118
|
"ruvector": "^0.2.27"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
sha256:6141a8ea990c5063b77e090ae8f37f9c539d8aa8f58dcceb30f3a82f97e57319
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"adoptedAt": 1784256882562,
|
|
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
|
-
}
|