@reclaimprotocol/agent 0.1.0 → 0.1.1-dev.1
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/lib/proof/attestor.js +4 -0
- package/lib/proof/zk-files.d.ts +14 -0
- package/lib/proof/zk-files.js +73 -0
- package/package.json +3 -4
- package/src/proof/attestor.ts +5 -0
- package/src/proof/zk-files.ts +83 -0
package/lib/proof/attestor.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
// reveals), never on responseMatches.
|
|
8
8
|
import { createClaimOnAttestor, } from '@reclaimprotocol/attestor-core';
|
|
9
9
|
import { resolveOwnerPrivateKey } from "../mcp/tools/credentials/cache.js";
|
|
10
|
+
import { ensureZkFiles } from "./zk-files.js";
|
|
10
11
|
/** Trim a captured log stream to the last N entries — for shrinking the
|
|
11
12
|
* LLM-visible response while the full stream stays in the on-disk dump. */
|
|
12
13
|
export function tailLogs(entries, n = LOG_TAIL_LINES) {
|
|
@@ -109,6 +110,9 @@ export async function runAttestorProof(provider, secrets, attestorUrl, ownerAddr
|
|
|
109
110
|
};
|
|
110
111
|
}
|
|
111
112
|
try {
|
|
113
|
+
// Circuits aren't downloaded at install time (that blocked the MCP
|
|
114
|
+
// server's first launch). Fetch them lazily on the first proof.
|
|
115
|
+
await ensureZkFiles();
|
|
112
116
|
const params = {
|
|
113
117
|
url: provider.url,
|
|
114
118
|
method: provider.method,
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ensure the zk circuit resources are on disk before a proof runs. Idempotent
|
|
3
|
+
* and concurrency-safe: the download runs at most once per process, and a
|
|
4
|
+
* failed attempt clears the latch so a later proof can retry.
|
|
5
|
+
*
|
|
6
|
+
* Resolves silently when the resources are already present (the warm npx cache,
|
|
7
|
+
* or after a manual `npm run download:zk-files`) and when
|
|
8
|
+
* `@reclaimprotocol/zk-symmetric-crypto` isn't installed at all (SDK-only
|
|
9
|
+
* consumers have nothing to prove).
|
|
10
|
+
*
|
|
11
|
+
* All output goes to stderr (fd 2): the MCP server speaks JSON-RPC over stdout,
|
|
12
|
+
* so a stray write to fd 1 mid-session would corrupt the protocol.
|
|
13
|
+
*/
|
|
14
|
+
export declare function ensureZkFiles(): Promise<void>;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// Lazy download of the @reclaimprotocol/zk-symmetric-crypto circuit resources
|
|
2
|
+
// that the snarkjs proof engine needs. These are ~280MB and are NOT fetched in
|
|
3
|
+
// a `postinstall` (that blocked the MCP server's first launch past the connect
|
|
4
|
+
// timeout — see the install notes). Instead we fetch them on the first proof,
|
|
5
|
+
// once, so the server starts immediately and only `run_proof` pays the cost.
|
|
6
|
+
import { spawn } from 'node:child_process';
|
|
7
|
+
import { existsSync } from 'node:fs';
|
|
8
|
+
import { createRequire } from 'node:module';
|
|
9
|
+
import { dirname, join } from 'node:path';
|
|
10
|
+
const require = createRequire(import.meta.url);
|
|
11
|
+
let inFlight;
|
|
12
|
+
/**
|
|
13
|
+
* Ensure the zk circuit resources are on disk before a proof runs. Idempotent
|
|
14
|
+
* and concurrency-safe: the download runs at most once per process, and a
|
|
15
|
+
* failed attempt clears the latch so a later proof can retry.
|
|
16
|
+
*
|
|
17
|
+
* Resolves silently when the resources are already present (the warm npx cache,
|
|
18
|
+
* or after a manual `npm run download:zk-files`) and when
|
|
19
|
+
* `@reclaimprotocol/zk-symmetric-crypto` isn't installed at all (SDK-only
|
|
20
|
+
* consumers have nothing to prove).
|
|
21
|
+
*
|
|
22
|
+
* All output goes to stderr (fd 2): the MCP server speaks JSON-RPC over stdout,
|
|
23
|
+
* so a stray write to fd 1 mid-session would corrupt the protocol.
|
|
24
|
+
*/
|
|
25
|
+
export function ensureZkFiles() {
|
|
26
|
+
inFlight ??= download().catch((err) => {
|
|
27
|
+
inFlight = undefined;
|
|
28
|
+
throw err;
|
|
29
|
+
});
|
|
30
|
+
return inFlight;
|
|
31
|
+
}
|
|
32
|
+
async function download() {
|
|
33
|
+
let mainPath;
|
|
34
|
+
try {
|
|
35
|
+
mainPath = require.resolve('@reclaimprotocol/zk-symmetric-crypto');
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
// mainPath is <pkg>/lib/index.js → resources live at <pkg>/resources, the
|
|
41
|
+
// downloader at <pkg>/lib/scripts/download-files.js. We only use the snarkjs
|
|
42
|
+
// engine (createClaimOnAttestor zkEngine: 'snarkjs'), so its presence is the
|
|
43
|
+
// signal that the circuits are ready.
|
|
44
|
+
const libDir = dirname(mainPath);
|
|
45
|
+
const pkgDir = dirname(libDir);
|
|
46
|
+
if (existsSync(join(pkgDir, 'resources', 'snarkjs'))) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const downloadScript = join(libDir, 'scripts', 'download-files.js');
|
|
50
|
+
if (!existsSync(downloadScript)) {
|
|
51
|
+
throw new Error('zk circuit downloader not found in '
|
|
52
|
+
+ '@reclaimprotocol/zk-symmetric-crypto; '
|
|
53
|
+
+ 'run `npm run download:zk-files` and retry.');
|
|
54
|
+
}
|
|
55
|
+
process.stderr.write('[reclaim-agent] downloading zkTLS proof circuits '
|
|
56
|
+
+ '(~280MB, one-time)…\n');
|
|
57
|
+
// stdio fd 1→2: send the downloader's stdout to our stderr so its progress
|
|
58
|
+
// never lands on the MCP server's JSON-RPC stdout.
|
|
59
|
+
await new Promise((resolve, reject) => {
|
|
60
|
+
const child = spawn(process.execPath, [downloadScript], {
|
|
61
|
+
stdio: ['ignore', 2, 2],
|
|
62
|
+
});
|
|
63
|
+
child.on('error', reject);
|
|
64
|
+
child.on('exit', (code) => {
|
|
65
|
+
if (code === 0) {
|
|
66
|
+
resolve();
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
reject(new Error(`zk download exited ${code}`));
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reclaimprotocol/agent",
|
|
3
3
|
"title": "Reclaim Agent",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.1-dev.1",
|
|
5
5
|
"description": "Reclaim Protocol agent — SDK, CLI, and MCP server in one package. SDK + CLI talk to the builder backend; MCP server adds Chrome CDP capture, provider synthesis, replay, and zkTLS proof.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./lib/index.js",
|
|
@@ -45,8 +45,7 @@
|
|
|
45
45
|
"start:cli": "node lib/cli.js",
|
|
46
46
|
"start:mcp": "node lib/mcp-bin.js",
|
|
47
47
|
"inspect": "npx @modelcontextprotocol/inspector node lib/mcp-bin.js",
|
|
48
|
-
"download:zk-files": "node scripts/download-zk-files.js"
|
|
49
|
-
"postinstall": "node scripts/download-zk-files.js"
|
|
48
|
+
"download:zk-files": "node scripts/download-zk-files.js"
|
|
50
49
|
},
|
|
51
50
|
"keywords": [
|
|
52
51
|
"mcp",
|
|
@@ -86,4 +85,4 @@
|
|
|
86
85
|
"typescript": "^5.9.0",
|
|
87
86
|
"yaml": "^2.6.0"
|
|
88
87
|
}
|
|
89
|
-
}
|
|
88
|
+
}
|
package/src/proof/attestor.ts
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
} from '@reclaimprotocol/attestor-core'
|
|
12
12
|
import { resolveOwnerPrivateKey } from '../mcp/tools/credentials/cache.ts'
|
|
13
13
|
import type { ReclaimProvider } from '../provider/schema.ts'
|
|
14
|
+
import { ensureZkFiles } from './zk-files.ts'
|
|
14
15
|
|
|
15
16
|
export interface AttestorLogEntry {
|
|
16
17
|
level: 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal'
|
|
@@ -179,6 +180,10 @@ export async function runAttestorProof(
|
|
|
179
180
|
}
|
|
180
181
|
|
|
181
182
|
try {
|
|
183
|
+
// Circuits aren't downloaded at install time (that blocked the MCP
|
|
184
|
+
// server's first launch). Fetch them lazily on the first proof.
|
|
185
|
+
await ensureZkFiles()
|
|
186
|
+
|
|
182
187
|
const params: ProviderParams<'http'> = {
|
|
183
188
|
url: provider.url,
|
|
184
189
|
method: provider.method,
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// Lazy download of the @reclaimprotocol/zk-symmetric-crypto circuit resources
|
|
2
|
+
// that the snarkjs proof engine needs. These are ~280MB and are NOT fetched in
|
|
3
|
+
// a `postinstall` (that blocked the MCP server's first launch past the connect
|
|
4
|
+
// timeout — see the install notes). Instead we fetch them on the first proof,
|
|
5
|
+
// once, so the server starts immediately and only `run_proof` pays the cost.
|
|
6
|
+
|
|
7
|
+
import { spawn } from 'node:child_process'
|
|
8
|
+
import { existsSync } from 'node:fs'
|
|
9
|
+
import { createRequire } from 'node:module'
|
|
10
|
+
import { dirname, join } from 'node:path'
|
|
11
|
+
|
|
12
|
+
const require = createRequire(import.meta.url)
|
|
13
|
+
|
|
14
|
+
let inFlight: Promise<void> | undefined
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Ensure the zk circuit resources are on disk before a proof runs. Idempotent
|
|
18
|
+
* and concurrency-safe: the download runs at most once per process, and a
|
|
19
|
+
* failed attempt clears the latch so a later proof can retry.
|
|
20
|
+
*
|
|
21
|
+
* Resolves silently when the resources are already present (the warm npx cache,
|
|
22
|
+
* or after a manual `npm run download:zk-files`) and when
|
|
23
|
+
* `@reclaimprotocol/zk-symmetric-crypto` isn't installed at all (SDK-only
|
|
24
|
+
* consumers have nothing to prove).
|
|
25
|
+
*
|
|
26
|
+
* All output goes to stderr (fd 2): the MCP server speaks JSON-RPC over stdout,
|
|
27
|
+
* so a stray write to fd 1 mid-session would corrupt the protocol.
|
|
28
|
+
*/
|
|
29
|
+
export function ensureZkFiles(): Promise<void> {
|
|
30
|
+
inFlight ??= download().catch((err) => {
|
|
31
|
+
inFlight = undefined
|
|
32
|
+
throw err
|
|
33
|
+
})
|
|
34
|
+
return inFlight
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function download(): Promise<void> {
|
|
38
|
+
let mainPath: string
|
|
39
|
+
try {
|
|
40
|
+
mainPath = require.resolve('@reclaimprotocol/zk-symmetric-crypto')
|
|
41
|
+
} catch{
|
|
42
|
+
return
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// mainPath is <pkg>/lib/index.js → resources live at <pkg>/resources, the
|
|
46
|
+
// downloader at <pkg>/lib/scripts/download-files.js. We only use the snarkjs
|
|
47
|
+
// engine (createClaimOnAttestor zkEngine: 'snarkjs'), so its presence is the
|
|
48
|
+
// signal that the circuits are ready.
|
|
49
|
+
const libDir = dirname(mainPath)
|
|
50
|
+
const pkgDir = dirname(libDir)
|
|
51
|
+
if(existsSync(join(pkgDir, 'resources', 'snarkjs'))) {
|
|
52
|
+
return
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const downloadScript = join(libDir, 'scripts', 'download-files.js')
|
|
56
|
+
if(!existsSync(downloadScript)) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
'zk circuit downloader not found in '
|
|
59
|
+
+ '@reclaimprotocol/zk-symmetric-crypto; '
|
|
60
|
+
+ 'run `npm run download:zk-files` and retry.',
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
process.stderr.write(
|
|
65
|
+
'[reclaim-agent] downloading zkTLS proof circuits '
|
|
66
|
+
+ '(~280MB, one-time)…\n',
|
|
67
|
+
)
|
|
68
|
+
// stdio fd 1→2: send the downloader's stdout to our stderr so its progress
|
|
69
|
+
// never lands on the MCP server's JSON-RPC stdout.
|
|
70
|
+
await new Promise<void>((resolve, reject) => {
|
|
71
|
+
const child = spawn(process.execPath, [downloadScript], {
|
|
72
|
+
stdio: ['ignore', 2, 2],
|
|
73
|
+
})
|
|
74
|
+
child.on('error', reject)
|
|
75
|
+
child.on('exit', (code) => {
|
|
76
|
+
if(code === 0) {
|
|
77
|
+
resolve()
|
|
78
|
+
} else {
|
|
79
|
+
reject(new Error(`zk download exited ${code}`))
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
})
|
|
83
|
+
}
|