@reclaimprotocol/agent 0.1.33 → 0.1.34

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.
Files changed (88) hide show
  1. package/lib/authoring/backend.d.ts +13 -0
  2. package/lib/authoring/index.d.ts +1 -1
  3. package/lib/authoring/tools.js +78 -42
  4. package/lib/config/store.d.ts +10 -0
  5. package/lib/mcp/api/operations.gen.d.ts +238 -4
  6. package/lib/mcp/api/operations.gen.js +6433 -328
  7. package/lib/mcp/api/tools.js +21 -8
  8. package/lib/mcp/instructions.js +11 -11
  9. package/lib/mcp/server.d.ts +1 -1
  10. package/lib/mcp/server.js +3 -0
  11. package/lib/mcp/success-response.js +5 -1
  12. package/lib/mcp/tools/agent/analyze.js +5 -4
  13. package/lib/mcp/tools/agent/attach.js +11 -7
  14. package/lib/mcp/tools/agent/build.js +3 -1
  15. package/lib/mcp/tools/agent/capture.d.ts +2 -2
  16. package/lib/mcp/tools/agent/capture.js +15 -11
  17. package/lib/mcp/tools/agent/eval.js +4 -3
  18. package/lib/mcp/tools/agent/find.js +9 -10
  19. package/lib/mcp/tools/agent/how-it-works.js +1 -0
  20. package/lib/mcp/tools/agent/live-view.js +10 -7
  21. package/lib/mcp/tools/agent/pod-proof.js +7 -11
  22. package/lib/mcp/tools/agent/propose.js +4 -3
  23. package/lib/mcp/tools/agent/publish.d.ts +2 -1
  24. package/lib/mcp/tools/agent/publish.js +12 -6
  25. package/lib/mcp/tools/agent/replay.js +10 -7
  26. package/lib/mcp/tools/agent/session.js +16 -8
  27. package/lib/mcp/tools/agent/shared.js +3 -2
  28. package/lib/mcp/tools/agent/start-integration.d.ts +15 -0
  29. package/lib/mcp/tools/agent/start-integration.js +61 -0
  30. package/lib/mcp/tools/authenticate/authenticate.js +9 -11
  31. package/lib/mcp/tools/authenticate/build.js +2 -0
  32. package/lib/mcp/tools/authenticate/builder-access.js +1 -0
  33. package/lib/mcp/tools/authenticate/eth-key.d.ts +8 -0
  34. package/lib/mcp/tools/authenticate/eth-key.js +27 -15
  35. package/lib/mcp/tools/authenticate/import.js +18 -31
  36. package/lib/mcp/tools/authenticate/issue-org-token.d.ts +8 -0
  37. package/lib/mcp/tools/authenticate/issue-org-token.js +60 -0
  38. package/lib/mcp/tools/authenticate/issue.js +9 -9
  39. package/lib/mcp/tools/authenticate/org-key-store.d.ts +10 -0
  40. package/lib/mcp/tools/authenticate/org-key-store.js +23 -0
  41. package/lib/mcp/tools/authenticate/resolve-owner-key.js +10 -12
  42. package/lib/mcp/tools/mode/mode.js +2 -0
  43. package/lib/mcp/tools/verification/result.js +10 -7
  44. package/lib/tools/registry.d.ts +12 -0
  45. package/lib/tools/registry.js +1 -0
  46. package/package.json +2 -2
  47. package/skill/SKILL.builder.md +77 -74
  48. package/skill/SKILL.common.md +2 -1
  49. package/skill/builder-mode.md +135 -138
  50. package/skill/start-integration.md +49 -0
  51. package/skill/user-script.md +64 -0
  52. package/skill/verification-client-integration.md +28 -22
  53. package/src/authoring/backend.ts +15 -0
  54. package/src/authoring/index.ts +2 -0
  55. package/src/authoring/tools.ts +86 -42
  56. package/src/config/store.ts +11 -0
  57. package/src/mcp/api/operations.gen.ts +6477 -364
  58. package/src/mcp/api/tools.ts +21 -8
  59. package/src/mcp/instructions.ts +11 -11
  60. package/src/mcp/server.ts +4 -0
  61. package/src/mcp/success-response.ts +5 -1
  62. package/src/mcp/tools/agent/analyze.ts +5 -4
  63. package/src/mcp/tools/agent/attach.ts +11 -7
  64. package/src/mcp/tools/agent/build.ts +5 -1
  65. package/src/mcp/tools/agent/capture.ts +20 -12
  66. package/src/mcp/tools/agent/eval.ts +4 -3
  67. package/src/mcp/tools/agent/find.ts +9 -10
  68. package/src/mcp/tools/agent/how-it-works.ts +1 -0
  69. package/src/mcp/tools/agent/live-view.ts +10 -7
  70. package/src/mcp/tools/agent/pod-proof.ts +7 -11
  71. package/src/mcp/tools/agent/propose.ts +4 -3
  72. package/src/mcp/tools/agent/publish.ts +12 -4
  73. package/src/mcp/tools/agent/replay.ts +10 -7
  74. package/src/mcp/tools/agent/session.ts +16 -8
  75. package/src/mcp/tools/agent/shared.ts +7 -2
  76. package/src/mcp/tools/agent/start-integration.ts +83 -0
  77. package/src/mcp/tools/authenticate/authenticate.ts +9 -11
  78. package/src/mcp/tools/authenticate/build.ts +2 -0
  79. package/src/mcp/tools/authenticate/builder-access.ts +1 -0
  80. package/src/mcp/tools/authenticate/eth-key.ts +48 -18
  81. package/src/mcp/tools/authenticate/import.ts +21 -36
  82. package/src/mcp/tools/authenticate/issue-org-token.ts +84 -0
  83. package/src/mcp/tools/authenticate/issue.ts +9 -9
  84. package/src/mcp/tools/authenticate/org-key-store.ts +25 -0
  85. package/src/mcp/tools/authenticate/resolve-owner-key.ts +10 -12
  86. package/src/mcp/tools/mode/mode.ts +2 -0
  87. package/src/mcp/tools/verification/result.ts +10 -7
  88. package/src/tools/registry.ts +14 -0
@@ -21,6 +21,16 @@ export interface Draft {
21
21
  * validate each against its own selector. */
22
22
  extractions: Extraction[];
23
23
  }
24
+ /** A navigation script installed for every later page load of the authoring
25
+ * session. `identifier` is the CDP registration, so it can be removed. */
26
+ export interface KeptScript {
27
+ script: string;
28
+ identifier?: string;
29
+ }
30
+ /** Holds the session's kept script, replaced by each `keep` call. */
31
+ export interface KeptScriptRef {
32
+ keptScript?: KeptScript;
33
+ }
24
34
  /** Per-session draft store: `propose` puts, `replay`/`run_proof` get by id. */
25
35
  export interface DraftStore {
26
36
  put(draft: Draft): string;
@@ -46,6 +56,9 @@ export interface AuthoringBackend {
46
56
  * out. Cloud authoring enables this; local MCP keeps its existing
47
57
  * behavior. */
48
58
  readonly readOnlyPageEval?: boolean;
59
+ /** Where `test_user_script` keeps its script. Absent for hosts that do not
60
+ * publish it (the cloud loop synthesizes its own navigation script). */
61
+ readonly kept?: KeptScriptRef;
49
62
  /** Send a raw CDP command scoped to this session's page. */
50
63
  sendCdp(method: string, params?: Record<string, unknown>): Promise<unknown>;
51
64
  /** Resolve once `method` (a CDP event) fires on this session's page, or
@@ -1,4 +1,4 @@
1
- export type { AuthoringBackend, Draft, DraftStore, ProveOptions, SecretParams, } from './backend.ts';
1
+ export type { AuthoringBackend, Draft, DraftStore, KeptScript, KeptScriptRef, ProveOptions, SecretParams, } from './backend.ts';
2
2
  export { makeDraftStore } from './backend.ts';
3
3
  export { authoringTools } from './tools.ts';
4
4
  export { defineTool, errorAsToolText, extendTool, type RegisteredTool, type ToolDefinition, } from '../tools/registry.ts';
@@ -14,6 +14,7 @@
14
14
  * draft (recipe + secrets) is held server-side; the model only sees an opaque
15
15
  * `draftId` and the secret-free provider.
16
16
  */
17
+ import assert from 'node:assert';
17
18
  import { findTool } from "../mcp/tools/agent/find.js";
18
19
  import { proposeTool } from "../mcp/tools/agent/propose.js";
19
20
  import { replayTool } from "../mcp/tools/agent/replay.js";
@@ -80,10 +81,12 @@ export function authoringTools(resolveBackend) {
80
81
  return [
81
82
  defineTool({
82
83
  name: 'navigate',
83
- description: 'Navigate the captured tab to a URL and wait for its load event. '
84
- + 'Returns the URL the tab actually landed on, so you can detect a '
85
- + 'redirect to a login page.',
84
+ description: 'Navigates the captured tab to a URL and waits for its load event. '
85
+ + 'Returns the URL the tab landed on, to detect a redirect to a '
86
+ + 'sign-in page. Any navigation script kept by `test_user_script` '
87
+ + 'runs on the page.',
86
88
  inputSchema: objectSchema({ url: { type: 'string' }, timeoutMs: { type: 'number' } }, ['url']),
89
+ annotations: { openWorldHint: true, destructiveHint: false },
87
90
  }, async (args) => {
88
91
  const backend = resolveBackend(args);
89
92
  const timeoutMs = Number(args.timeoutMs) || 30000;
@@ -100,19 +103,24 @@ export function authoringTools(resolveBackend) {
100
103
  }),
101
104
  defineTool({
102
105
  name: 'eval_in_page',
103
- description: 'Evaluate a JavaScript expression in the page and return its value. '
104
- + 'Use it to read the value being proven out of the DOM, to check '
105
- + 'login state, or to trigger the target request (for example, '
106
- + '`location.reload()`).',
106
+ description: 'Evaluates a JavaScript expression in the page of the remote '
107
+ + 'authoring browser, not on this machine, and returns its value. '
108
+ + 'Use it to read a data point from the DOM, check sign-in state, '
109
+ + 'or trigger the target request (for example, `location.reload()`). '
110
+ + 'The page cannot reach files or processes on this machine. Return '
111
+ + 'only the values you need, never cookies or tokens.',
107
112
  inputSchema: objectSchema({ expression: { type: 'string' } }, ['expression']),
113
+ annotations: { openWorldHint: true, destructiveHint: false },
108
114
  }, (args) => evalInPage(resolveBackend(args), String(args.expression))),
109
115
  defineTool({
110
116
  name: 'wait_for_page',
111
- description: 'Poll a JavaScript expression once a second until it is truthy or '
112
- + 'the timeout elapses. Use it to wait for content to appear. To '
113
- + 'wait for a login, use wait_for_login instead — page JavaScript '
114
- + 'cannot see the httpOnly session cookie.',
117
+ description: 'Evaluates a JavaScript expression in the remote authoring browser '
118
+ + 'once a second until it is truthy or the timeout elapses. Returns '
119
+ + '{ ready }. Use it to wait for content to appear. To wait for a '
120
+ + 'sign-in, use `wait_for_login`: page JavaScript cannot see the '
121
+ + 'httpOnly session cookie.',
115
122
  inputSchema: objectSchema({ expression: { type: 'string' }, timeoutMs: { type: 'number' } }, ['expression']),
123
+ annotations: { readOnlyHint: true, openWorldHint: true },
116
124
  }, async (args) => {
117
125
  const backend = resolveBackend(args);
118
126
  const expr = String(args.expression);
@@ -128,24 +136,30 @@ export function authoringTools(resolveBackend) {
128
136
  }),
129
137
  defineTool({
130
138
  name: 'test_user_script',
131
- description: 'Dry-run a USER SCRIPT (the `jsUserScripts` / `customInjection` '
132
- + 'field) in the LIVE attached tab while authoring or after provider '
133
- + 'creation. Installs '
134
- + '`script` via CDP so it runs on the next navigation exactly as '
135
- + 'the real field would, then reports whether it ran and what it '
136
- + 'threw. With `navigateUrl`, it navigates there and removes the '
137
- + 'script once the result is read — self-cleaning, safe to repeat. '
138
- + 'WITHOUT `navigateUrl` the script stays installed (navigate '
139
- + 'yourself, then re-call this tool or read '
140
- + '`window.__reclaimUserScriptResult` via eval_in_page) and keeps '
141
- + 'running on every later navigation until a call WITH '
142
- + '`navigateUrl` removes it — so don\'t stack manual-mode calls. '
143
- + 'Guide: how_it_works({ topic: "user-script" }).',
139
+ description: 'Installs a navigation script (the `jsUserScripts` field) in the '
140
+ + 'remote authoring browser, not on this machine, so it runs before '
141
+ + 'each page load, as it does at verification. Reports whether it '
142
+ + 'ran and what it threw. With `navigateUrl`, navigates there and '
143
+ + 'removes the script after reading the result, unless `keep` is '
144
+ + 'true. Without `navigateUrl`, the script stays installed for '
145
+ + 'later navigations until a call with `navigateUrl` removes it. '
146
+ + 'With `keep: true`, the script stays installed for every later '
147
+ + 'navigation in this session, replaces any earlier kept script, and '
148
+ + '`create_provider_version_from_capture` publishes it as '
149
+ + '`jsUserScripts` unless that call passes its own. '
150
+ + 'See how_it_works({ topic: "user-script" }).',
144
151
  inputSchema: objectSchema({
145
152
  script: { type: 'string' },
146
153
  navigateUrl: { type: 'string' },
147
154
  timeoutMs: { type: 'number' },
155
+ keep: {
156
+ type: 'boolean',
157
+ description: 'Keep the script installed for every later navigation in '
158
+ + 'this session and use it as the published navigation '
159
+ + 'script.',
160
+ },
148
161
  }, ['script']),
162
+ annotations: { openWorldHint: true, destructiveHint: false },
149
163
  }, async (args) => {
150
164
  const backend = resolveBackend(args);
151
165
  const script = String(args.script);
@@ -169,10 +183,27 @@ export function authoringTools(resolveBackend) {
169
183
  );
170
184
  }
171
185
  `;
186
+ const keep = args.keep === true;
187
+ const kept = keep ? backend.kept : undefined;
188
+ assert(!keep || kept, new Error('This host does not support `keep`.'));
189
+ // Replace, never stack: only one kept script runs.
190
+ const previous = kept?.keptScript?.identifier;
191
+ if (previous) {
192
+ await backend.sendCdp('Page.removeScriptToEvaluateOnNewDocument', { identifier: previous }).catch(() => { });
193
+ }
172
194
  const installed = (await backend.sendCdp('Page.addScriptToEvaluateOnNewDocument', { source: wrapped }));
195
+ if (kept) {
196
+ kept.keptScript = {
197
+ script,
198
+ ...(installed.identifier
199
+ ? { identifier: installed.identifier }
200
+ : {}),
201
+ };
202
+ }
173
203
  if (typeof args.navigateUrl !== 'string') {
174
204
  return {
175
205
  installed: true,
206
+ ...(keep ? { kept: true } : {}),
176
207
  note: 'Installed for the NEXT navigation only — it did not run on '
177
208
  + 'the current page, and stays installed (runs on every later '
178
209
  + 'navigation too) until a follow-up call with navigateUrl '
@@ -198,6 +229,7 @@ export function authoringTools(resolveBackend) {
198
229
  const result = value;
199
230
  return {
200
231
  installed: true,
232
+ ...(keep ? { kept: true } : {}),
201
233
  navigated: true,
202
234
  ran: result?.ran ?? false,
203
235
  errors: result?.errors ?? [],
@@ -206,20 +238,21 @@ export function authoringTools(resolveBackend) {
206
238
  finally {
207
239
  // One-shot test: remove it so it doesn't keep running (and
208
240
  // potentially redirecting the tab) on every later navigation.
209
- if (installed.identifier) {
241
+ if (installed.identifier && !keep) {
210
242
  await backend.sendCdp('Page.removeScriptToEvaluateOnNewDocument', { identifier: installed.identifier });
211
243
  }
212
244
  }
213
245
  }),
214
246
  defineTool({
215
247
  name: 'get_cookies',
216
- description: 'List the NAMES of cookies currently set for the page (values are '
217
- + 'NEVER returned). The most reliable, language- and DOM-independent '
218
- + 'login signal: after the user logs in, an auth/session cookie '
219
- + 'appears (for example, session, sid, token, auth, jwt, _user, '
220
- + 'logged_in). '
221
- + 'Includes httpOnly cookies the page JS cannot see.',
248
+ description: 'Returns the names, domains, and flags of the cookies set in the '
249
+ + 'remote authoring browser. Values are never returned; they stay '
250
+ + 'in the browser and on the server. A new auth or session cookie '
251
+ + '(for example, session, sid, auth, jwt) is a reliable sign-in '
252
+ + 'signal that does not depend on the page language or DOM. '
253
+ + 'Includes httpOnly cookies that page JavaScript cannot see.',
222
254
  inputSchema: objectSchema({}),
255
+ annotations: { readOnlyHint: true, openWorldHint: true },
223
256
  }, async (args) => {
224
257
  const backend = resolveBackend(args);
225
258
  const res = (await backend.sendCdp('Network.getCookies'));
@@ -243,6 +276,7 @@ export function authoringTools(resolveBackend) {
243
276
  + 'navigating to the login page. Does NOT navigate (never yanks '
244
277
  + 'the user off login/2FA). Returns { loggedIn, newCookies }.',
245
278
  inputSchema: objectSchema({ timeoutMs: { type: 'number' } }),
279
+ annotations: { readOnlyHint: true, openWorldHint: true },
246
280
  }, async (args) => {
247
281
  const backend = resolveBackend(args);
248
282
  const deadline = Date.now() + (Number(args.timeoutMs) || 180000);
@@ -299,9 +333,10 @@ export function authoringTools(resolveBackend) {
299
333
  }),
300
334
  defineTool({
301
335
  name: 'list_requests',
302
- description: 'List captured network requests (method/url/status/size), newest '
303
- + 'last. Optionally filter by method / urlGlob / status range / '
304
- + 'contentType / graphqlOp. Metadata only — secrets never included.',
336
+ description: 'Lists captured network requests (method, URL, status, size), '
337
+ + 'newest last. Filter by method, urlGlob, status range, '
338
+ + 'contentType, or graphqlOp. Returns metadata only, never '
339
+ + 'secrets.',
305
340
  inputSchema: objectSchema({
306
341
  filter: {
307
342
  type: 'object',
@@ -315,6 +350,7 @@ export function authoringTools(resolveBackend) {
315
350
  },
316
351
  },
317
352
  }),
353
+ annotations: { readOnlyHint: true, openWorldHint: false },
318
354
  }, async (args) => {
319
355
  const backend = resolveBackend(args);
320
356
  const filter = (args.filter ?? {});
@@ -327,15 +363,15 @@ export function authoringTools(resolveBackend) {
327
363
  replayTool(resolveBackend),
328
364
  defineTool({
329
365
  name: 'run_proof',
330
- description: 'Prove the drafted recipe (zkTLS). Only call after replay_request '
331
- + 'looks right. Returns the proof result. NOTE: unlike '
332
- + 'replay_request (which re-issues from inside the live attached '
333
- + 'browser tab), the ATTESTOR calls the target from its OWN '
334
- + 'network/IP, separate from the browser\'s. A request that '
335
- + 'replayed fine can still fail here for geo/IP-bound content '
336
- + '(country-locked pages, IP-allowlisted APIs) — if that happens, '
337
- + 'it\'s a property of the site, not a bug in the draft.',
366
+ description: 'Proves the drafted recipe (zkTLS). Call it after `replay_request` '
367
+ + 'looks right. Returns the proof result. Unlike `replay_request`, '
368
+ + 'which re-sends from inside the attached browser tab, the '
369
+ + 'attestor calls the target from its own network and IP. A request '
370
+ + 'that replayed can still fail here for geo- or IP-bound content '
371
+ + '(country-locked pages, IP-allowlisted APIs); that is a property '
372
+ + 'of the site, not a bug in the draft.',
338
373
  inputSchema: objectSchema({ draftId: { type: 'string' } }, ['draftId']),
374
+ annotations: { openWorldHint: true, destructiveHint: false },
339
375
  },
340
376
  // The backend shapes its own result: the cloud returns a lean,
341
377
  // secret-free summary (and records the proven recipe for publish); the
@@ -16,6 +16,8 @@ export interface ReclaimAgentConfig {
16
16
  * - `old_devtools` — externally-supplied identity for OLD-devtools mode
17
17
  * (USE_OLD_DEVTOOLS); independent of `session`'s
18
18
  * builder token. Deletable with the rest of `src/old/`.
19
+ * - `org_keys` — organization API keys saved by `issue_org_token`, so
20
+ * the org-key tools work without the key in a transcript
19
21
  * Sections are persisted independently via `ConfigStore.write`, which
20
22
  * merges rather than replaces, so one subsystem never clobbers another's.
21
23
  *
@@ -29,6 +31,14 @@ export interface ReclaimConfig {
29
31
  browser_agent?: ReclaimAgentConfig;
30
32
  session?: CachedSession;
31
33
  old_devtools?: OldIdentity;
34
+ org_keys?: SavedOrgKeys;
35
+ }
36
+ /** Organization API keys (`rorg_…`) saved by `issue_org_token`. */
37
+ export interface SavedOrgKeys {
38
+ /** Key by organization ID. */
39
+ byOrg: Record<string, string>;
40
+ /** The organization whose key was saved last. */
41
+ recent?: string;
32
42
  }
33
43
  /** Which backend the MCP server targets. See `resolveOldMode` in consts.ts. */
34
44
  export type DevtoolsMode = 'old' | 'builder';