@reclaimprotocol/agent 0.1.7 → 0.1.10

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/README.md CHANGED
@@ -1,12 +1,16 @@
1
1
  # @reclaimprotocol/agent
2
2
 
3
- Chrome-CDP + zkTLS provider-authoring tools. The agent captures network traffic from a browser, synthesizes Reclaim provider definitions from it (`contains` matchers + `jsonPath` / `xPath` / `regex` redactions), runs a local replay diagnostic, and produces a verified attestor proof via `@reclaimprotocol/attestor-core`.
3
+ Reclaim Protocol lets your app verify **data points** about its users — a follower count, an account balance, an order history. This package gives your AI coding agent the tools to **find, build, test and fix the _data verification providers_** (the recipes that verify a data point) by inspecting and replaying captured requests, checking sessions, evaluate proofs, publishing updates, and much more.
4
+
5
+ Under the hood it's Chrome-CDP + zkTLS provider-authoring tooling: it captures network traffic from a browser, synthesizes provider definitions from it (`contains` matchers + `jsonPath` / `xPath` / `regex` redactions), runs a local replay diagnostic, and produces a verified attestor proof via `@reclaimprotocol/attestor-core`.
4
6
 
5
7
  This package **is** the Reclaim MCP server (bin: `reclaim-mcp-server`). It depends on `@reclaimprotocol/client` for the typed HTTP client and registers the provider-authoring tools below alongside the backend-facing tools (credentials, publishing) in a single MCP surface. A standalone entry (`src/index.ts`) re-exports the client SDK plus `buildAgentTools` for embedding.
6
8
 
7
9
  ## Install
8
10
 
9
- **Prerequisites:** Node ≥ 22.18 and a local Chrome / Chromium / Edge (used for capture and the dashboard login). The first time you call `run_proof`, the agent downloads the ZK circuit files it needs (~280 MB) — so allow a moment for that first proof. The download is deferred to first proof on purpose (not an install step), so the MCP server itself starts immediately.
11
+ **Prerequisites:** **Node ≥ 20** — **works best on a current LTS release (22 or 24)** — and a local Chrome / Chromium / Edge (used for capture and the dashboard login). The first time you call `run_proof`, the agent downloads the ZK circuit files it needs (~280 MB) — so allow a moment for that first proof. The download is deferred to first proof on purpose (not an install step), so the MCP server itself starts immediately.
12
+
13
+ > **Any Node ≥ 20 works, including non-LTS lines like 25** however an LTS line (22 or 24) is *recommended*.
10
14
 
11
15
  It runs as a **stdio MCP server**. Point any MCP-capable agent at this command:
12
16
 
@@ -16,87 +20,18 @@ npx -y --package=@reclaimprotocol/agent reclaim-mcp-server
16
20
 
17
21
  > The `--package=` (short form `-p`) flag selects the `reclaim-mcp-server` binary from the package. We use the long `--package=` form throughout because the short `-p` collides with the `-p`/`--print` flag of some agent CLIs (notably `claude mcp add`), which silently swallows the command. Prefer a global install? Run `npm i -g @reclaimprotocol/agent` and use `reclaim-mcp-server` directly as the `command` (drop the `npx` wrapper and its `args`).
18
22
 
19
- ### Claude Code
20
-
21
- ```bash
22
- # project scope → writes .mcp.json; add `-s user` for a global install
23
- claude mcp add reclaim -- npx -y --package=@reclaimprotocol/agent reclaim-mcp-server
24
- ```
25
-
26
- …or add it to `.mcp.json` yourself:
27
-
28
- ```json
29
- {
30
- "mcpServers": {
31
- "reclaim": {
32
- "command": "npx",
33
- "args": ["-y", "--package=@reclaimprotocol/agent", "reclaim-mcp-server"]
34
- }
35
- }
36
- }
37
- ```
38
-
39
- ### Cursor
40
-
41
- Add to `~/.cursor/mcp.json` (global) or `.cursor/mcp.json` (project):
42
-
43
- ```json
44
- {
45
- "mcpServers": {
46
- "reclaim": {
47
- "command": "npx",
48
- "args": ["-y", "--package=@reclaimprotocol/agent", "reclaim-mcp-server"]
49
- }
50
- }
51
- }
52
- ```
53
-
54
- ### opencode
55
-
56
- Add to `opencode.json` (project) or `~/.config/opencode/opencode.json` (global):
23
+ ### Installing into your coding agent
57
24
 
58
- ```json
59
- {
60
- "$schema": "https://opencode.ai/config.json",
61
- "mcp": {
62
- "reclaim": {
63
- "type": "local",
64
- "command": ["npx", "-y", "--package=@reclaimprotocol/agent", "reclaim-mcp-server"],
65
- "enabled": true
66
- }
67
- }
68
- }
69
- ```
25
+ Copy-paste setup for **Claude Code** (plugin marketplace), **Claude Desktop**, **Cursor**, **opencode**, **Codex**, **Windsurf**, **VS Code**, **Cline** and other MCP clients lives in the public **[reclaimprotocol/developer-tools](https://github.com/reclaimprotocol/developer-tools)** repo — that's where the Claude Code plugin/marketplace is published.
70
26
 
71
- ### Codex
27
+ The quickest path, in Claude Code:
72
28
 
73
- ```bash
74
- # writes ~/.codex/config.toml
75
- codex mcp add reclaim -- npx -y --package=@reclaimprotocol/agent reclaim-mcp-server
76
29
  ```
77
-
78
- …or add it to `~/.codex/config.toml` yourself (Codex uses TOML, not JSON):
79
-
80
- ```toml
81
- [mcp_servers.reclaim]
82
- command = "npx"
83
- args = ["-y", "--package=@reclaimprotocol/agent", "reclaim-mcp-server"]
30
+ /plugin marketplace add reclaimprotocol/developer-tools
31
+ /plugin install reclaim@reclaim
84
32
  ```
85
33
 
86
- ### Antigravity, Windsurf, VS Code, Cline & other MCP clients
87
-
88
- These all use the standard `mcpServers` shape — add a server through the app's MCP settings (or its `mcp`/`mcpServers` config file) with:
89
-
90
- ```json
91
- {
92
- "mcpServers": {
93
- "reclaim": {
94
- "command": "npx",
95
- "args": ["-y", "--package=@reclaimprotocol/agent", "reclaim-mcp-server"]
96
- }
97
- }
98
- }
99
- ```
34
+ For any other client, point it at the stdio command above (`npx -y --package=@reclaimprotocol/agent reclaim-mcp-server`) — see the developer-tools README for per-client config and the Claude Desktop / GUI-app notes.
100
35
 
101
36
  ### Optional environment
102
37
 
@@ -189,7 +124,7 @@ npm run download:zk-files --workspace=packages/agent
189
124
 
190
125
  ## Platform notes
191
126
 
192
- - **Node >=22.18** is required (declared in `engines`). The floor is 22.18 because the test suite and dev workflow run bare `.ts` files directly, and unflagged TypeScript type-stripping landed in Node 22.18.
127
+ - **Node >=20** is required to run the published package (declared in `engines`) — it ships compiled `lib/*.js`, so no TypeScript type-stripping is needed at runtime. Any line ≥ 20 works, including non-LTS like 25: the one native addon that used to break this, `re2`, is an **optional** dependency as of `@reclaimprotocol/attestor-core` 5.0.8 and degrades to native `RegExp` when its binary is absent. (The other native dep, `koffi`, is N-API — ABI-independent, all-platform prebuilts — so it was never version-sensitive.) An LTS line (22/24) is recommended so `re2` is present for faster, ReDoS-safe matching. Working on the package **from a checkout** additionally needs **Node >=22.18**, because the test suite and dev workflow run bare `.ts` files directly and unflagged TypeScript type-stripping landed in 22.18.
193
128
  - **Chrome 136+ silently disables `--remote-debugging-port`** when launched against the default user profile. `dedicated` mode (the default) sidesteps this by always passing `--user-data-dir=~/.reclaim/chrome-profile`.
194
129
 
195
130
  ## Tests
@@ -81,7 +81,7 @@ export function authoringTools(resolveBackend) {
81
81
  inputSchema: objectSchema({ url: { type: 'string' }, timeoutMs: { type: 'number' } }, ['url']),
82
82
  }, async (args) => {
83
83
  const backend = resolveBackend(args);
84
- const timeoutMs = Number(args.timeoutMs) || 30_000;
84
+ const timeoutMs = Number(args.timeoutMs) || 30000;
85
85
  await backend.sendCdp('Page.enable');
86
86
  // Start listening BEFORE navigating so the load event isn't missed.
87
87
  const load = backend.waitForEvent('Page.loadEventFired', timeoutMs);
@@ -107,7 +107,7 @@ export function authoringTools(resolveBackend) {
107
107
  }, async (args) => {
108
108
  const backend = resolveBackend(args);
109
109
  const expr = String(args.expression);
110
- const deadline = Date.now() + (Number(args.timeoutMs) || 180_000);
110
+ const deadline = Date.now() + (Number(args.timeoutMs) || 180000);
111
111
  while (Date.now() < deadline) {
112
112
  const { value } = await evalInPage(backend, expr);
113
113
  if (value) {
@@ -1,26 +1,38 @@
1
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
+ if (kind === "m") throw new TypeError("Private method is not writable");
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
+ };
7
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
+ };
12
+ var _BodyStore_store, _BodyStore_bytes, _BodyStore_opts;
1
13
  export class BodyStore {
2
- #store = new Map(); // insertion order = LRU order
3
- #bytes = 0;
4
- #opts;
5
14
  constructor(opts) {
6
- this.#opts = opts;
15
+ _BodyStore_store.set(this, new Map()); // insertion order = LRU order
16
+ _BodyStore_bytes.set(this, 0);
17
+ _BodyStore_opts.set(this, void 0);
18
+ __classPrivateFieldSet(this, _BodyStore_opts, opts, "f");
7
19
  }
8
20
  set(requestId, body) {
9
- if (this.#store.has(requestId)) {
10
- this.#bytes -= byteLen(this.#store.get(requestId));
11
- this.#store.delete(requestId);
21
+ if (__classPrivateFieldGet(this, _BodyStore_store, "f").has(requestId)) {
22
+ __classPrivateFieldSet(this, _BodyStore_bytes, __classPrivateFieldGet(this, _BodyStore_bytes, "f") - byteLen(__classPrivateFieldGet(this, _BodyStore_store, "f").get(requestId)), "f");
23
+ __classPrivateFieldGet(this, _BodyStore_store, "f").delete(requestId);
12
24
  }
13
- this.#store.set(requestId, body);
14
- this.#bytes += byteLen(body);
15
- while (this.#bytes > this.#opts.maxBytes && this.#store.size > 0) {
16
- const oldestKey = this.#store.keys().next().value;
17
- const oldestVal = this.#store.get(oldestKey);
18
- this.#bytes -= byteLen(oldestVal);
19
- this.#store.delete(oldestKey);
25
+ __classPrivateFieldGet(this, _BodyStore_store, "f").set(requestId, body);
26
+ __classPrivateFieldSet(this, _BodyStore_bytes, __classPrivateFieldGet(this, _BodyStore_bytes, "f") + byteLen(body), "f");
27
+ while (__classPrivateFieldGet(this, _BodyStore_bytes, "f") > __classPrivateFieldGet(this, _BodyStore_opts, "f").maxBytes && __classPrivateFieldGet(this, _BodyStore_store, "f").size > 0) {
28
+ const oldestKey = __classPrivateFieldGet(this, _BodyStore_store, "f").keys().next().value;
29
+ const oldestVal = __classPrivateFieldGet(this, _BodyStore_store, "f").get(oldestKey);
30
+ __classPrivateFieldSet(this, _BodyStore_bytes, __classPrivateFieldGet(this, _BodyStore_bytes, "f") - byteLen(oldestVal), "f");
31
+ __classPrivateFieldGet(this, _BodyStore_store, "f").delete(oldestKey);
20
32
  }
21
33
  }
22
34
  get(requestId) {
23
- const body = this.#store.get(requestId);
35
+ const body = __classPrivateFieldGet(this, _BodyStore_store, "f").get(requestId);
24
36
  if (body === undefined) {
25
37
  return {
26
38
  available: false,
@@ -28,11 +40,12 @@ export class BodyStore {
28
40
  };
29
41
  }
30
42
  // Refresh LRU position by re-inserting.
31
- this.#store.delete(requestId);
32
- this.#store.set(requestId, body);
43
+ __classPrivateFieldGet(this, _BodyStore_store, "f").delete(requestId);
44
+ __classPrivateFieldGet(this, _BodyStore_store, "f").set(requestId, body);
33
45
  return { available: true, body };
34
46
  }
35
47
  }
48
+ _BodyStore_store = new WeakMap(), _BodyStore_bytes = new WeakMap(), _BodyStore_opts = new WeakMap();
36
49
  function byteLen(s) {
37
50
  return Buffer.byteLength(s, 'utf8');
38
51
  }
@@ -85,7 +85,7 @@ export function launchChrome(opts) {
85
85
  });
86
86
  return child;
87
87
  }
88
- export async function waitForCdpReady(port, timeoutMs = 10_000) {
88
+ export async function waitForCdpReady(port, timeoutMs = 10000) {
89
89
  const deadline = Date.now() + timeoutMs;
90
90
  while (Date.now() < deadline) {
91
91
  try {
@@ -1,3 +1,15 @@
1
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
+ if (kind === "m") throw new TypeError("Private method is not writable");
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
+ };
7
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
+ };
12
+ var _ConfigStore_path;
1
13
  import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync, } from 'node:fs';
2
14
  import { dirname, join } from 'node:path';
3
15
  import { reclaimHomeDirPath } from "../paths.js";
@@ -9,16 +21,16 @@ import { reclaimHomeDirPath } from "../paths.js";
9
21
  * own validation (token expiry, credential shape) on top.
10
22
  */
11
23
  export class ConfigStore {
12
- #path;
13
24
  constructor(path = defaultConfigPath()) {
14
- this.#path = path;
25
+ _ConfigStore_path.set(this, void 0);
26
+ __classPrivateFieldSet(this, _ConfigStore_path, path, "f");
15
27
  }
16
28
  read() {
17
- if (!existsSync(this.#path)) {
29
+ if (!existsSync(__classPrivateFieldGet(this, _ConfigStore_path, "f"))) {
18
30
  return undefined;
19
31
  }
20
32
  try {
21
- return JSON.parse(readFileSync(this.#path, 'utf8'));
33
+ return JSON.parse(readFileSync(__classPrivateFieldGet(this, _ConfigStore_path, "f"), 'utf8'));
22
34
  }
23
35
  catch {
24
36
  return undefined;
@@ -31,16 +43,17 @@ export class ConfigStore {
31
43
  */
32
44
  write(patch) {
33
45
  const next = { ...this.read(), ...patch, version: 1 };
34
- const dir = dirname(this.#path);
46
+ const dir = dirname(__classPrivateFieldGet(this, _ConfigStore_path, "f"));
35
47
  mkdirSync(dir, { recursive: true, mode: 0o700 });
36
48
  chmodSync(dir, 0o700);
37
- writeFileSync(this.#path, JSON.stringify(next, null, 2) + '\n', {
49
+ writeFileSync(__classPrivateFieldGet(this, _ConfigStore_path, "f"), JSON.stringify(next, null, 2) + '\n', {
38
50
  mode: 0o600,
39
51
  });
40
- chmodSync(this.#path, 0o600);
52
+ chmodSync(__classPrivateFieldGet(this, _ConfigStore_path, "f"), 0o600);
41
53
  return next;
42
54
  }
43
55
  }
56
+ _ConfigStore_path = new WeakMap();
44
57
  export function defaultConfigPath() {
45
58
  return join(reclaimHomeDirPath(), 'config.json');
46
59
  }
@@ -46,11 +46,11 @@ export function attachTool(state) {
46
46
  }
47
47
  catch {
48
48
  launchChrome({ port: cfg.port, profileDir: defaultProfileDir() });
49
- await waitForCdpReady(cfg.port, 10_000);
49
+ await waitForCdpReady(cfg.port, 10000);
50
50
  }
51
51
  }
52
52
  else {
53
- await waitForCdpReady(cfg.port, 2_000).catch(() => {
53
+ await waitForCdpReady(cfg.port, 2000).catch(() => {
54
54
  throw new Error(`attach mode: nothing answering CDP on port ${cfg.port}. ` +
55
55
  'Chrome must be launched with BOTH ' +
56
56
  `--remote-debugging-port=${cfg.port} AND ` +
package/lib/old/client.js CHANGED
@@ -1,3 +1,15 @@
1
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
+ if (kind === "m") throw new TypeError("Private method is not writable");
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
+ };
7
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
+ };
12
+ var _ReclaimOldClient_instances, _ReclaimOldClient_identity, _ReclaimOldClient_fetch, _ReclaimOldClient_request, _ReclaimOldClient_authHeaderName, _ReclaimOldClient_authHeaderValue, _ReclaimOldClient_requireIdentity, _ReclaimOldClient_parseBody, _ReclaimOldClient_asBoom;
1
13
  import { Boom } from '@hapi/boom';
2
14
  import { NAME, VERSION } from "../pkg.js";
3
15
  /** Default origin of the OLD devtools backend. The client appends the
@@ -18,43 +30,42 @@ export const DEFAULT_OLD_LOGS_URL = 'https://logs.reclaimprotocol.org';
18
30
  * identically to builder-mode `ProblemError`s.
19
31
  */
20
32
  export class ReclaimOldClient {
21
- baseUrl;
22
- logsBaseUrl;
23
- #identity;
24
- #fetch;
25
33
  constructor(opts = {}) {
34
+ _ReclaimOldClient_instances.add(this);
35
+ _ReclaimOldClient_identity.set(this, void 0);
36
+ _ReclaimOldClient_fetch.set(this, void 0);
26
37
  this.baseUrl = (opts.baseUrl || DEFAULT_OLD_API_URL).replace(/\/+$/, '');
27
38
  this.logsBaseUrl = (opts.logsBaseUrl || DEFAULT_OLD_LOGS_URL)
28
39
  .replace(/\/+$/, '');
29
- this.#identity = opts.identity;
30
- this.#fetch = opts.fetch ?? fetch;
40
+ __classPrivateFieldSet(this, _ReclaimOldClient_identity, opts.identity, "f");
41
+ __classPrivateFieldSet(this, _ReclaimOldClient_fetch, opts.fetch ?? fetch, "f");
31
42
  }
32
43
  setIdentity(identity) {
33
- this.#identity = identity;
44
+ __classPrivateFieldSet(this, _ReclaimOldClient_identity, identity, "f");
34
45
  }
35
46
  getIdentity() {
36
- return this.#identity;
47
+ return __classPrivateFieldGet(this, _ReclaimOldClient_identity, "f");
37
48
  }
38
49
  /** Validate + provision a bearer identity. The backend creates the user
39
50
  * row on first login, which is what makes later authed calls work. */
40
51
  loginWithToken() {
41
- return this.#request('POST', '/users/login', { auth: true });
52
+ return __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_request).call(this, 'POST', '/users/login', { auth: true });
42
53
  }
43
54
  registerProvider(body) {
44
- return this.#request('POST', '/providers/register', { body, auth: true });
55
+ return __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_request).call(this, 'POST', '/providers/register', { body, auth: true });
45
56
  }
46
57
  updateProviderConfig(providerId, body) {
47
- return this.#request('POST', `/providers/${encodeURIComponent(providerId)}/config`, { body, auth: true });
58
+ return __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_request).call(this, 'POST', `/providers/${encodeURIComponent(providerId)}/config`, { body, auth: true });
48
59
  }
49
60
  listVersions(providerId) {
50
- return this.#request('GET', `/providers/${encodeURIComponent(providerId)}/versions`, { auth: true });
61
+ return __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_request).call(this, 'GET', `/providers/${encodeURIComponent(providerId)}/versions`, { auth: true });
51
62
  }
52
63
  /** Full `providerConfig` (loginUrl, customInjection, requestData, ...) for
53
64
  * one version — the latest when `version` is omitted. Readable for ANY
54
65
  * non-archived provider (not owner-restricted), same as the dashboard's
55
66
  * edit-form prefill fetch. */
56
67
  getProviderConfig(providerId, version) {
57
- return this.#request('GET', `/providers/${encodeURIComponent(providerId)}/config`, {
68
+ return __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_request).call(this, 'GET', `/providers/${encodeURIComponent(providerId)}/config`, {
58
69
  auth: true,
59
70
  query: version ? { versionNumber: version } : undefined,
60
71
  });
@@ -65,7 +76,7 @@ export class ReclaimOldClient {
65
76
  * fields sent here are simply ignored (this endpoint only reads the
66
77
  * ones above from the body). */
67
78
  updateProviderMetadata(providerId, body) {
68
- return this.#request('POST', `/providers/${encodeURIComponent(providerId)}`, { body, auth: true });
79
+ return __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_request).call(this, 'POST', `/providers/${encodeURIComponent(providerId)}`, { body, auth: true });
69
80
  }
70
81
  /** Analytics logs for a verification session, from the logs service (a
71
82
  * DIFFERENT host than the devtools API — hence its own fetch, not
@@ -78,20 +89,20 @@ export class ReclaimOldClient {
78
89
  Accept: 'application/json',
79
90
  'User-Agent': `${NAME}/${VERSION}`,
80
91
  };
81
- if (this.#identity) {
82
- headers[this.#authHeaderName()] = this.#authHeaderValue();
92
+ if (__classPrivateFieldGet(this, _ReclaimOldClient_identity, "f")) {
93
+ headers[__classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_authHeaderName).call(this)] = __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_authHeaderValue).call(this);
83
94
  }
84
- const res = await this.#fetch(url, { method: 'GET', headers });
85
- const json = await this.#parseBody(res);
95
+ const res = await __classPrivateFieldGet(this, _ReclaimOldClient_fetch, "f").call(this, url, { method: 'GET', headers });
96
+ const json = await __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_parseBody).call(this, res);
86
97
  if (!res.ok) {
87
- throw this.#asBoom(res, json);
98
+ throw __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_asBoom).call(this, res, json);
88
99
  }
89
100
  return json;
90
101
  }
91
102
  getMyProviders(query = {}) {
92
103
  // Every one of these query params is REQUIRED by the backend
93
104
  // validator (missing/invalid → 400), so default them all here.
94
- return this.#request('GET', '/providers/user/paginated', {
105
+ return __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_request).call(this, 'GET', '/providers/user/paginated', {
95
106
  auth: true,
96
107
  query: {
97
108
  pageKey: query.pageKey ?? 0,
@@ -104,88 +115,83 @@ export class ReclaimOldClient {
104
115
  },
105
116
  });
106
117
  }
107
- async #request(method, path, opts = {}) {
108
- let url = `${this.baseUrl}/api${path}`;
109
- if (opts.query) {
110
- const search = new URLSearchParams();
111
- for (const [k, v] of Object.entries(opts.query)) {
112
- if (v === undefined) {
113
- continue;
114
- }
115
- search.append(k, String(v));
116
- }
117
- const qs = search.toString();
118
- if (qs) {
119
- url += `?${qs}`;
118
+ }
119
+ _ReclaimOldClient_identity = new WeakMap(), _ReclaimOldClient_fetch = new WeakMap(), _ReclaimOldClient_instances = new WeakSet(), _ReclaimOldClient_request = async function _ReclaimOldClient_request(method, path, opts = {}) {
120
+ let url = `${this.baseUrl}/api${path}`;
121
+ if (opts.query) {
122
+ const search = new URLSearchParams();
123
+ for (const [k, v] of Object.entries(opts.query)) {
124
+ if (v === undefined) {
125
+ continue;
120
126
  }
127
+ search.append(k, String(v));
121
128
  }
122
- const headers = {
123
- Accept: 'application/json',
124
- 'User-Agent': `${NAME}/${VERSION}`,
125
- };
126
- if (opts.auth) {
127
- headers[this.#authHeaderName()] = this.#authHeaderValue();
129
+ const qs = search.toString();
130
+ if (qs) {
131
+ url += `?${qs}`;
128
132
  }
129
- const init = { method, headers };
130
- if (method !== 'GET' && method !== 'HEAD') {
131
- init.body = JSON.stringify(opts.body ?? {});
132
- headers['Content-Type'] = 'application/json';
133
- }
134
- const res = await this.#fetch(url, init);
135
- const json = await this.#parseBody(res);
136
- // Old API convention: { message, ...data, isSuccess }. Treat a non-2xx
137
- // OR an explicit isSuccess:false as an error so a 200-with-failure
138
- // body never slips through as success.
139
- const failed = !res.ok ||
140
- (json !== undefined &&
141
- typeof json === 'object' &&
142
- json.isSuccess === false);
143
- if (failed) {
144
- throw this.#asBoom(res, json);
145
- }
146
- return json;
147
- }
148
- #authHeaderName() {
149
- const id = this.#requireIdentity();
150
- return id.kind === 'bearer' ? 'Authorization' : 'x-eth-uid';
151
- }
152
- #authHeaderValue() {
153
- const id = this.#requireIdentity();
154
- return id.kind === 'bearer' ? `Bearer ${id.token}` : id.uid;
155
133
  }
156
- #requireIdentity() {
157
- if (!this.#identity) {
158
- throw new Boom('Not authenticated against old devtools. Call reclaim_authenticate ' +
159
- 'with a dashboard token (or eth uid) first.', { statusCode: 401, data: { status: 401, detail: 'no identity set' } });
160
- }
161
- return this.#identity;
162
- }
163
- async #parseBody(res) {
164
- if (res.status === 204 || res.headers.get('content-length') === '0') {
165
- return undefined;
166
- }
167
- try {
168
- return await res.json();
169
- }
170
- catch {
171
- return undefined;
172
- }
173
- }
174
- #asBoom(res, json) {
175
- const message = (json && typeof json === 'object' &&
176
- typeof json.message === 'string'
177
- ? json.message
178
- : undefined) || res.statusText || 'Old devtools request failed';
179
- // Shape `data` like a ProblemDetails so remapErrorAsResponse can render
180
- // `${message}: ${data.detail}` and expose the raw body as structured.
181
- return new Boom(message, {
182
- statusCode: res.ok ? 502 : res.status,
183
- data: {
184
- status: res.status,
185
- title: message,
186
- detail: message,
187
- body: json,
188
- },
189
- });
190
- }
191
- }
134
+ const headers = {
135
+ Accept: 'application/json',
136
+ 'User-Agent': `${NAME}/${VERSION}`,
137
+ };
138
+ if (opts.auth) {
139
+ headers[__classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_authHeaderName).call(this)] = __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_authHeaderValue).call(this);
140
+ }
141
+ const init = { method, headers };
142
+ if (method !== 'GET' && method !== 'HEAD') {
143
+ init.body = JSON.stringify(opts.body ?? {});
144
+ headers['Content-Type'] = 'application/json';
145
+ }
146
+ const res = await __classPrivateFieldGet(this, _ReclaimOldClient_fetch, "f").call(this, url, init);
147
+ const json = await __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_parseBody).call(this, res);
148
+ // Old API convention: { message, ...data, isSuccess }. Treat a non-2xx
149
+ // OR an explicit isSuccess:false as an error so a 200-with-failure
150
+ // body never slips through as success.
151
+ const failed = !res.ok ||
152
+ (json !== undefined &&
153
+ typeof json === 'object' &&
154
+ json.isSuccess === false);
155
+ if (failed) {
156
+ throw __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_asBoom).call(this, res, json);
157
+ }
158
+ return json;
159
+ }, _ReclaimOldClient_authHeaderName = function _ReclaimOldClient_authHeaderName() {
160
+ const id = __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_requireIdentity).call(this);
161
+ return id.kind === 'bearer' ? 'Authorization' : 'x-eth-uid';
162
+ }, _ReclaimOldClient_authHeaderValue = function _ReclaimOldClient_authHeaderValue() {
163
+ const id = __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_requireIdentity).call(this);
164
+ return id.kind === 'bearer' ? `Bearer ${id.token}` : id.uid;
165
+ }, _ReclaimOldClient_requireIdentity = function _ReclaimOldClient_requireIdentity() {
166
+ if (!__classPrivateFieldGet(this, _ReclaimOldClient_identity, "f")) {
167
+ throw new Boom('Not authenticated against old devtools. Call reclaim_authenticate ' +
168
+ 'with a dashboard token (or eth uid) first.', { statusCode: 401, data: { status: 401, detail: 'no identity set' } });
169
+ }
170
+ return __classPrivateFieldGet(this, _ReclaimOldClient_identity, "f");
171
+ }, _ReclaimOldClient_parseBody = async function _ReclaimOldClient_parseBody(res) {
172
+ if (res.status === 204 || res.headers.get('content-length') === '0') {
173
+ return undefined;
174
+ }
175
+ try {
176
+ return await res.json();
177
+ }
178
+ catch {
179
+ return undefined;
180
+ }
181
+ }, _ReclaimOldClient_asBoom = function _ReclaimOldClient_asBoom(res, json) {
182
+ const message = (json && typeof json === 'object' &&
183
+ typeof json.message === 'string'
184
+ ? json.message
185
+ : undefined) || res.statusText || 'Old devtools request failed';
186
+ // Shape `data` like a ProblemDetails so remapErrorAsResponse can render
187
+ // `${message}: ${data.detail}` and expose the raw body as structured.
188
+ return new Boom(message, {
189
+ statusCode: res.ok ? 502 : res.status,
190
+ data: {
191
+ status: res.status,
192
+ title: message,
193
+ detail: message,
194
+ body: json,
195
+ },
196
+ });
197
+ };
@@ -88,7 +88,7 @@ export const EXTRACT_TOKEN_JS = `(async () => {
88
88
  */
89
89
  export async function captureFirebaseTokenViaCdp(opts) {
90
90
  const loginUrl = opts.loginUrl || oldLoginUrl() || DEFAULT_LOGIN_URL;
91
- const timeoutMs = opts.timeoutMs ?? 180_000;
91
+ const timeoutMs = opts.timeoutMs ?? 180000;
92
92
  const pollMs = opts.pollMs ?? 1000;
93
93
  const cfg = new ConfigStore().read()?.browser_agent;
94
94
  const mode = cfg?.attachMode ?? 'dedicated';
@@ -105,7 +105,7 @@ export async function captureFirebaseTokenViaCdp(opts) {
105
105
  '--user-data-dir, or switch to dedicated mode (attach_chrome).');
106
106
  }
107
107
  launchChrome({ port, profileDir: defaultProfileDir() });
108
- await waitForCdpReady(port, 10_000);
108
+ await waitForCdpReady(port, 10000);
109
109
  launchedByUs = true;
110
110
  }
111
111
  const handles = await connectCdp(port);
@@ -1,3 +1,15 @@
1
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
+ if (kind === "m") throw new TypeError("Private method is not writable");
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
+ };
7
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
+ };
12
+ var _ReclaimSdkClient_instances, _ReclaimSdkClient_fetch, _ReclaimSdkClient_get;
1
13
  import { Boom } from '@hapi/boom';
2
14
  import { NAME, VERSION } from "../pkg.js";
3
15
  /**
@@ -25,61 +37,61 @@ export const DEFAULT_SDK_API_URL = 'https://api.reclaimprotocol.org';
25
37
  * the same way as every other tool in this package.
26
38
  */
27
39
  export class ReclaimSdkClient {
28
- baseUrl;
29
- #fetch;
30
40
  constructor(opts = {}) {
41
+ _ReclaimSdkClient_instances.add(this);
42
+ _ReclaimSdkClient_fetch.set(this, void 0);
31
43
  this.baseUrl = (opts.baseUrl || DEFAULT_SDK_API_URL).replace(/\/+$/, '');
32
- this.#fetch = opts.fetch ?? fetch;
44
+ __classPrivateFieldSet(this, _ReclaimSdkClient_fetch, opts.fetch ?? fetch, "f");
33
45
  }
34
46
  /** Full provider + providerConfig (includes `customInjection`). Latest
35
47
  * version when `versionNumber` is omitted. */
36
48
  getProvider(providerId, versionNumber) {
37
- return this.#get(`/providers/${encodeURIComponent(providerId)}`, versionNumber);
49
+ return __classPrivateFieldGet(this, _ReclaimSdkClient_instances, "m", _ReclaimSdkClient_get).call(this, `/providers/${encodeURIComponent(providerId)}`, versionNumber);
38
50
  }
39
51
  /** Trimmed runtime recipe (no `customInjection`; adds
40
52
  * `isScriptRequestingClaim`). Latest version when `versionNumber` is
41
53
  * omitted. */
42
54
  getProviderConfigs(providerId, versionNumber) {
43
- return this.#get(`/providers/${encodeURIComponent(providerId)}/configs`, versionNumber);
55
+ return __classPrivateFieldGet(this, _ReclaimSdkClient_instances, "m", _ReclaimSdkClient_get).call(this, `/providers/${encodeURIComponent(providerId)}/configs`, versionNumber);
44
56
  }
45
- async #get(path, versionNumber) {
46
- let url = `${this.baseUrl}/api${path}`;
47
- if (versionNumber) {
48
- url += `?versionNumber=${encodeURIComponent(versionNumber)}`;
49
- }
50
- const res = await this.#fetch(url, {
51
- method: 'GET',
52
- headers: {
53
- Accept: 'application/json',
54
- 'User-Agent': `${NAME}/${VERSION}`,
57
+ }
58
+ _ReclaimSdkClient_fetch = new WeakMap(), _ReclaimSdkClient_instances = new WeakSet(), _ReclaimSdkClient_get = async function _ReclaimSdkClient_get(path, versionNumber) {
59
+ let url = `${this.baseUrl}/api${path}`;
60
+ if (versionNumber) {
61
+ url += `?versionNumber=${encodeURIComponent(versionNumber)}`;
62
+ }
63
+ const res = await __classPrivateFieldGet(this, _ReclaimSdkClient_fetch, "f").call(this, url, {
64
+ method: 'GET',
65
+ headers: {
66
+ Accept: 'application/json',
67
+ 'User-Agent': `${NAME}/${VERSION}`,
68
+ },
69
+ });
70
+ let json;
71
+ try {
72
+ json = await res.json();
73
+ }
74
+ catch {
75
+ json = undefined;
76
+ }
77
+ const failed = !res.ok ||
78
+ (json !== undefined &&
79
+ typeof json === 'object' &&
80
+ json.isSuccess === false);
81
+ if (failed) {
82
+ const message = (json && typeof json === 'object' &&
83
+ typeof json.message === 'string'
84
+ ? json.message
85
+ : undefined) || res.statusText || 'SDK backend request failed';
86
+ throw new Boom(message, {
87
+ statusCode: res.ok ? 502 : res.status,
88
+ data: {
89
+ status: res.status,
90
+ title: message,
91
+ detail: message,
92
+ body: json,
55
93
  },
56
94
  });
57
- let json;
58
- try {
59
- json = await res.json();
60
- }
61
- catch {
62
- json = undefined;
63
- }
64
- const failed = !res.ok ||
65
- (json !== undefined &&
66
- typeof json === 'object' &&
67
- json.isSuccess === false);
68
- if (failed) {
69
- const message = (json && typeof json === 'object' &&
70
- typeof json.message === 'string'
71
- ? json.message
72
- : undefined) || res.statusText || 'SDK backend request failed';
73
- throw new Boom(message, {
74
- statusCode: res.ok ? 502 : res.status,
75
- data: {
76
- status: res.status,
77
- title: message,
78
- detail: message,
79
- body: json,
80
- },
81
- });
82
- }
83
- return json;
84
95
  }
85
- }
96
+ return json;
97
+ };
@@ -24,10 +24,10 @@ let inFlight;
24
24
  * so a stray write to fd 1 mid-session would corrupt the protocol.
25
25
  */
26
26
  export function ensureZkFiles() {
27
- inFlight ??= download().catch((err) => {
27
+ inFlight ?? (inFlight = download().catch((err) => {
28
28
  inFlight = undefined;
29
29
  throw err;
30
- });
30
+ }));
31
31
  return inFlight;
32
32
  }
33
33
  async function download() {
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@reclaimprotocol/agent",
3
3
  "title": "Reclaim Agent",
4
- "version": "0.1.7",
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.",
4
+ "version": "0.1.10",
5
+ "description": "Reclaim Protocol's tools for agents — Reclaim Protocol lets your app verify **data points** about its users — a follower count, an account balance, an order history. This package gives your AI coding agent the tools to **find, build, test and fix the _data verification providers_** (the recipes that verify a data point) by inspecting and replaying captured requests, checking sessions, evaluate proofs, publishing updates, and much more.",
6
6
  "type": "module",
7
7
  "main": "./lib/index.js",
8
8
  "types": "./lib/index.d.ts",
@@ -44,7 +44,7 @@
44
44
  "README.md"
45
45
  ],
46
46
  "engines": {
47
- "node": ">=22.18"
47
+ "node": ">=20"
48
48
  },
49
49
  "repository": {
50
50
  "url": "https://github.com/reclaimprotocol/builder",
@@ -83,7 +83,7 @@
83
83
  "dependencies": {
84
84
  "@hapi/boom": "^9.1.4",
85
85
  "@modelcontextprotocol/sdk": "^1.29.0",
86
- "@reclaimprotocol/attestor-core": "^5.0.7",
86
+ "@reclaimprotocol/attestor-core": "^5.0.8",
87
87
  "@reclaimprotocol/client": "*",
88
88
  "@reclaimprotocol/tls": "^0.1.3",
89
89
  "chrome-remote-interface": "^0.33.0",