@reclaimprotocol/agent 0.1.26 → 0.1.28

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 (92) hide show
  1. package/README.md +5 -5
  2. package/lib/authoring/tools.js +2 -1
  3. package/lib/consts.d.ts +1 -1
  4. package/lib/consts.js +1 -1
  5. package/lib/live/tunnel.d.ts +10 -7
  6. package/lib/live/tunnel.js +78 -56
  7. package/lib/mcp/api/operations.gen.d.ts +12 -8
  8. package/lib/mcp/api/operations.gen.js +378 -580
  9. package/lib/mcp/api/tools.d.ts +1 -1
  10. package/lib/mcp/instructions.js +7 -3
  11. package/lib/mcp/remap_errors.js +9 -5
  12. package/lib/mcp/start.js +1 -1
  13. package/lib/mcp/tools/agent/attach.d.ts +2 -2
  14. package/lib/mcp/tools/agent/attach.js +4 -0
  15. package/lib/mcp/tools/agent/build.d.ts +1 -1
  16. package/lib/mcp/tools/agent/live-view-url.d.ts +2 -0
  17. package/lib/mcp/tools/agent/live-view-url.js +11 -0
  18. package/lib/mcp/tools/agent/live-view.d.ts +4 -2
  19. package/lib/mcp/tools/agent/live-view.js +40 -54
  20. package/lib/mcp/tools/agent/propose.js +10 -4
  21. package/lib/mcp/tools/agent/publish.d.ts +1 -1
  22. package/lib/mcp/tools/agent/publish.js +49 -26
  23. package/lib/mcp/tools/agent/shared.js +0 -9
  24. package/lib/mcp/tools/authenticate/authenticate.d.ts +1 -1
  25. package/lib/mcp/tools/authenticate/build.d.ts +1 -1
  26. package/lib/mcp/tools/authenticate/builder-access.d.ts +1 -1
  27. package/lib/mcp/tools/verification/result.js +12 -13
  28. package/lib/old/login-cdp.d.ts +17 -6
  29. package/lib/old/login-cdp.js +28 -11
  30. package/lib/old/to-register.d.ts +6 -0
  31. package/lib/old/to-register.js +35 -5
  32. package/lib/old/tools/authenticate.d.ts +5 -4
  33. package/lib/old/tools/authenticate.js +9 -5
  34. package/lib/old/tools/publish.d.ts +2 -2
  35. package/lib/old/tools/publish.js +47 -21
  36. package/lib/proof/attestor-auth.d.ts +13 -0
  37. package/lib/proof/attestor-auth.js +16 -0
  38. package/lib/proof/attestor.d.ts +7 -4
  39. package/lib/proof/attestor.js +7 -4
  40. package/lib/proof/index.d.ts +1 -0
  41. package/lib/proof/index.js +1 -0
  42. package/lib/proof/pod-prover.d.ts +2 -0
  43. package/lib/proof/pod-prover.js +5 -5
  44. package/lib/provider/injection-doc.d.ts +2 -0
  45. package/lib/provider/injection-doc.js +7 -1
  46. package/lib/provider/post-publish-browser.d.ts +12 -0
  47. package/lib/provider/post-publish-browser.js +40 -0
  48. package/lib/provider/to-version.d.ts +19 -7
  49. package/lib/provider/to-version.js +67 -25
  50. package/lib/tools/registry.d.ts +1 -1
  51. package/lib/tools/registry.js +7 -4
  52. package/package.json +2 -2
  53. package/skill/SKILL.builder.md +134 -13
  54. package/skill/SKILL.common.md +30 -19
  55. package/skill/SKILL.old.md +22 -12
  56. package/skill/builder-mode.md +19 -9
  57. package/skill/community-contributions.md +108 -0
  58. package/skill/hash-validation.md +8 -5
  59. package/skill/interception.md +35 -22
  60. package/skill/old-mode.md +11 -5
  61. package/skill/user-script.md +41 -10
  62. package/src/authoring/tools.ts +2 -1
  63. package/src/consts.ts +1 -2
  64. package/src/live/tunnel.ts +112 -66
  65. package/src/mcp/api/operations.gen.ts +384 -584
  66. package/src/mcp/api/tools.ts +1 -1
  67. package/src/mcp/instructions.ts +7 -3
  68. package/src/mcp/remap_errors.ts +9 -7
  69. package/src/mcp/start.ts +1 -1
  70. package/src/mcp/tools/agent/attach.ts +6 -2
  71. package/src/mcp/tools/agent/build.ts +1 -1
  72. package/src/mcp/tools/agent/live-view-url.ts +13 -0
  73. package/src/mcp/tools/agent/live-view.ts +42 -54
  74. package/src/mcp/tools/agent/propose.ts +10 -4
  75. package/src/mcp/tools/agent/publish.ts +63 -28
  76. package/src/mcp/tools/agent/shared.ts +5 -0
  77. package/src/mcp/tools/authenticate/authenticate.ts +1 -1
  78. package/src/mcp/tools/authenticate/build.ts +1 -1
  79. package/src/mcp/tools/authenticate/builder-access.ts +1 -1
  80. package/src/mcp/tools/verification/result.ts +11 -13
  81. package/src/old/login-cdp.ts +38 -11
  82. package/src/old/to-register.ts +56 -7
  83. package/src/old/tools/authenticate.ts +9 -5
  84. package/src/old/tools/publish.ts +64 -22
  85. package/src/proof/attestor-auth.ts +33 -0
  86. package/src/proof/attestor.ts +14 -8
  87. package/src/proof/index.ts +4 -0
  88. package/src/proof/pod-prover.ts +7 -5
  89. package/src/provider/injection-doc.ts +9 -1
  90. package/src/provider/post-publish-browser.ts +56 -0
  91. package/src/provider/to-version.ts +104 -27
  92. package/src/tools/registry.ts +12 -9
@@ -1,3 +1,3 @@
1
1
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
- import type { ReclaimClient } from '@reclaimprotocol/client';
2
+ import type { ReclaimClient } from '@reclaimprotocol/client/api';
3
3
  export declare function registerTools(server: McpServer, client: ReclaimClient): void;
@@ -61,8 +61,10 @@ const SHARED_TOPIC_FILES = {
61
61
  const TOPIC_SUMMARIES = {
62
62
  'overview': 'Terminology, your stance, and the whole loop at a glance.',
63
63
  'auth': 'Signing in to the backend, and which token authorizes what.',
64
+ 'devtools-migration': 'Importing a public legacy provider with the same '
65
+ + 'UUID.',
64
66
  'browser': 'Choosing a browser source (local Chrome, the Reclaim runtime in '
65
- + 'Docker, a remote Popcorn browser, or a custom CDP endpoint), '
67
+ + 'Docker, a remote Builder browser, or a custom CDP endpoint), '
66
68
  + 'geolocation, live view, and launch troubleshooting.',
67
69
  'capture': 'Tabs, login detection, driving the page, and picking an '
68
70
  + 'authenticated request to prove.',
@@ -74,8 +76,10 @@ const TOPIC_SUMMARIES = {
74
76
  + 'diagnosing failures.',
75
77
  'publish': 'Creating/reusing a provider, versions, multi-request providers, '
76
78
  + 'and going live.',
77
- 'discover': 'Finding the right providers for a dev\'s app and creating a '
78
- + 'verification session.',
79
+ 'discover': 'Finding providers, resolving them, and creating a verification '
80
+ + 'session.',
81
+ 'integration': 'Builder Verification Client integration: the `api=2` bridge, '
82
+ + 'result verification, and optional TEE binding.',
79
83
  'user-script': 'Authoring jsUserScripts / customInjection to drive '
80
84
  + 'login-gated pages.',
81
85
  'interception': 'injectionType / interceptorType, live interception, the '
@@ -1,21 +1,25 @@
1
1
  import { isBoom } from '@hapi/boom';
2
+ import { isProblemDetails, isProblemError } from '@reclaimprotocol/client/api';
2
3
  import { errorAsToolText } from "../tools/registry.js";
3
4
  // One error shape for every MCP tool. The text comes from errorAsToolText
4
5
  // (shared with the cloud loop); Boom problems also attach structuredContent.
5
6
  export const remapErrorAsResponse = (err) => {
6
7
  const text = errorAsToolText(err);
7
- // The client throws a Boom-style ProblemError, so the status lives on
8
- // `output.statusCode` / `problem.status`, not `status`.
9
- if (!isBoom(err) || !err.output?.statusCode) {
8
+ const data = isProblemError(err)
9
+ ? err.data
10
+ : isBoom(err) && err.output?.statusCode
11
+ && isProblemDetails(err.data)
12
+ ? err.data
13
+ : undefined;
14
+ if (!data) {
10
15
  return {
11
16
  isError: true,
12
17
  content: [{ type: 'text', text }],
13
18
  };
14
19
  }
15
- const data = err.data;
16
20
  return {
17
21
  isError: true,
18
- ...(data ? { structuredContent: data } : {}),
22
+ structuredContent: data,
19
23
  content: [{ type: 'text', text }],
20
24
  };
21
25
  };
package/lib/mcp/start.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
- import { ReclaimClient } from '@reclaimprotocol/client';
3
+ import { ReclaimClient } from '@reclaimprotocol/client/api';
4
4
  import { ConfigStore } from "../config/store.js";
5
5
  import { agentDisabled, apiToken, apiUrl, oldApiUrl, oldLogsUrl, resolveOldMode, sdkApiUrl, } from "../consts.js";
6
6
  import { LOGGER } from "../logger.js";
@@ -1,4 +1,4 @@
1
- import type { ReclaimClient } from '@reclaimprotocol/client';
1
+ import type { ReclaimClient } from '@reclaimprotocol/client/api';
2
2
  import { type CdpHandles, connectCdp, connectCdpUrl } from '../../../cdp/client.ts';
3
3
  import { dockerAvailable, startContainer } from '../../../cdp/container.ts';
4
4
  import type { ConfigStore } from '../../../config/store.ts';
@@ -20,7 +20,7 @@ export interface AttachState {
20
20
  liveViewUrl?: string;
21
21
  browserSessionId?: string;
22
22
  orgId?: string;
23
- /** The Popcorn pod's own TEE api base (builder mode only) — lets
23
+ /** The hosted Builder browser's TEE API base — lets
24
24
  * `run_proof_via_pod` prove through the SAME enclave that holds the
25
25
  * browser's TLS session (and its country-routed egress), instead of the
26
26
  * local in-process attestor SDK. */
@@ -6,6 +6,7 @@ import { suggestCountryFromIp } from "../../../cdp/geo.js";
6
6
  import { defaultProfileDir, launchChrome, waitForCdpReady, } from "../../../cdp/launcher.js";
7
7
  import { defaultConfigPath } from "../../../config/store.js";
8
8
  import { defineTool } from "../../server.js";
9
+ import { ensureLiveViewUrl } from "./live-view-url.js";
9
10
  /**
10
11
  * Modes with a live view that `share_browser_view` can put behind a public URL.
11
12
  *
@@ -298,6 +299,9 @@ dependencies = {}) {
298
299
  };
299
300
  }
300
301
  const next = await connect(mode, { ...parsed, orgId }, persisted, builderClient, deps);
302
+ next.liveViewUrl = next.liveViewUrl
303
+ ? ensureLiveViewUrl(next.liveViewUrl)
304
+ : undefined;
301
305
  try {
302
306
  await beforeReplace?.();
303
307
  await disposeAttached(state);
@@ -9,7 +9,7 @@
9
9
  * secrets they hold) live inside each capture entry, so a capture IS the
10
10
  * session for the shared authoring tools.
11
11
  */
12
- import type { ReclaimClient } from '@reclaimprotocol/client';
12
+ import type { ReclaimClient } from '@reclaimprotocol/client/api';
13
13
  import { ConfigStore } from '../../../config/store.ts';
14
14
  import { type RegisteredTool } from '../../server.ts';
15
15
  import { type AttachState } from './attach.ts';
@@ -0,0 +1,2 @@
1
+ /** Add the browser runtime's viewer route and magnification when absent. */
2
+ export declare function ensureLiveViewUrl(value: string): string;
@@ -0,0 +1,11 @@
1
+ const LIVE_VIEW_PATH = 'liveview.html';
2
+ /** Add the browser runtime's viewer route and magnification when absent. */
3
+ export function ensureLiveViewUrl(value) {
4
+ const url = new URL(value);
5
+ const pathname = url.pathname.replace(/\/+$/, '');
6
+ if (!pathname.toLowerCase().endsWith(`/${LIVE_VIEW_PATH}`)) {
7
+ url.pathname = `${pathname}/${LIVE_VIEW_PATH}`;
8
+ }
9
+ url.searchParams.set('magnify', '1');
10
+ return url.toString();
11
+ }
@@ -1,4 +1,4 @@
1
- import { type Tunnel } from '../../../live/tunnel.ts';
1
+ import { startTunnel, type Tunnel } from '../../../live/tunnel.ts';
2
2
  import { type RegisteredTool } from '../../server.ts';
3
3
  import { type AttachState } from './attach.ts';
4
4
  export interface LiveShare {
@@ -9,9 +9,11 @@ export interface LiveShare {
9
9
  export interface LiveShareRef {
10
10
  current?: LiveShare;
11
11
  }
12
+ type TunnelStarter = typeof startTunnel;
12
13
  /** Tear down whatever share is running. Safe when none is. Exported so the
13
14
  * session tools can call it from `dispose_browser` / `reset_session`. */
14
15
  export declare function stopLiveShare(ref: LiveShareRef): Promise<boolean>;
15
16
  export declare function liveViewTools(attachRef: {
16
17
  current?: AttachState;
17
- }, shareRef: LiveShareRef): RegisteredTool[];
18
+ }, shareRef: LiveShareRef, openTunnel?: TunnelStarter): RegisteredTool[];
19
+ export {};
@@ -1,13 +1,11 @@
1
1
  /**
2
- * `share_browser_view` / `stop_browser_view` — put the LOCAL attached tab
3
- * behind a public URL so someone who is not at this machine can watch it, and
4
- * optionally drive it.
2
+ * `share_browser_view` / `stop_browser_view` — put the attached container
3
+ * browser's built-in viewer behind a public URL so someone who is not at this
4
+ * machine can watch it and optionally drive it.
5
5
  *
6
- * Scoped to the CDP-attached modes (`dedicated`, `attach`, `custom`) on
7
- * purpose. A `builder`-mode browser is a Popcorn pod that already ships its
8
- * own hosted live view on `attach_browser`'s `liveViewUrl`; tunnelling a
9
- * second one would duplicate it and burn a share URL for nothing, so this
10
- * refuses and points at the one that exists.
6
+ * Scoped to `container` mode on purpose. A `builder`-mode browser already has
7
+ * a hosted live view at `attach_browser`'s `liveViewUrl`; tunnelling a second
8
+ * one would duplicate it, so this refuses and points at the existing URL.
11
9
  *
12
10
  * The share is deliberately explicit and single-instance: one live view per
13
11
  * attached browser, started only when asked for, and torn down by
@@ -19,6 +17,7 @@ import { startTunnel } from "../../../live/tunnel.js";
19
17
  import { LOGGER } from "../../../logger.js";
20
18
  import { defineTool } from "../../server.js";
21
19
  import { SHAREABLE_MODES } from "./attach.js";
20
+ import { ensureLiveViewUrl } from "./live-view-url.js";
22
21
  /** Tear down whatever share is running. Safe when none is. Exported so the
23
22
  * session tools can call it from `dispose_browser` / `reset_session`. */
24
23
  export async function stopLiveShare(ref) {
@@ -34,40 +33,34 @@ export async function stopLiveShare(ref) {
34
33
  });
35
34
  return true;
36
35
  }
37
- export function liveViewTools(attachRef, shareRef) {
36
+ export function liveViewTools(attachRef, shareRef, openTunnel = startTunnel) {
38
37
  return [
39
38
  defineTool({
40
39
  name: 'share_browser_view',
41
- description: 'Put the attached browser\'s live view behind a PUBLIC HTTPS URL (a '
42
- + 'cloudflared quick tunnel) so someone elsewhere can watch it and '
43
- + 'act in it. Use it to hand a login or a 2FA step to the person '
44
- + 'who holds the credentials, or to let a colleague watch a '
45
- + 'capture. Returns the URL — relay it to the developer VERBATIM, '
40
+ description: 'Opens a public HTTPS tunnel to the attached `container` browser '
41
+ + 'viewer. Use it when someone else must sign in or control it. '
42
+ + 'Returns `url` with `liveview.html?magnify=1`; relay it verbatim '
46
43
  + 'on its own line. '
47
- + 'ONLY for `container` mode, whose browser runs its own viewer. '
48
- + 'A `builder` browser already has a hosted live view: use the '
49
- + '`liveViewUrl` attach_browser returned. A local browser '
50
- + '(`dedicated`, `attach`, `custom`) cannot be shared at all — no '
51
- + 'tunnel can fix that, because there is no viewer behind it. Tell '
52
- + 'them so, and offer to re-attach: `container` is free and needs '
53
- + 'Docker, `builder` needs no install but is chargeable. '
54
- + 'THE URL IS THE ONLY CREDENTIAL: the random hostname is the whole '
55
- + 'secret, with no token or login behind it, so anyone who learns '
56
- + 'it can see and drive this browser as the signed-in user. Share '
57
- + 'it only with the person who needs it, and call stop_browser_view '
58
- + 'the moment they are done. '
59
- + 'Needs cloudflared: an existing install on PATH is used as-is, '
60
- + 'otherwise it is downloaded once to ~/.reclaim/bin on first '
61
- + 'share (never at install time). Set RECLAIM_CLOUDFLARED_PATH to '
62
- + 'point at your own copy instead.',
44
+ + 'Only `container` supports this. For `builder`, relay '
45
+ + 'the `liveViewUrl` from attach_browser; local modes '
46
+ + '(`dedicated`, `attach`, `custom`) '
47
+ + 'cannot be shared. The URL is a credential: anyone with it can '
48
+ + 'control the signed-in browser. Share it only with the intended '
49
+ + 'person and call stop_browser_view when done. `propagating: true` '
50
+ + 'means the tunnel remains live while the Cloudflare edge starts; '
51
+ + 'reuse the URL and reload after a few seconds rather than creating '
52
+ + 'another tunnel.',
63
53
  inputSchema: { type: 'object', properties: {} },
64
54
  }, async () => {
65
55
  const attached = attachRef.current;
66
56
  assert(attached, badRequest('No browser attached. Call attach_browser first.'));
57
+ const hostedViewUrl = attached.liveViewUrl
58
+ ? ensureLiveViewUrl(attached.liveViewUrl)
59
+ : undefined;
67
60
  assert(SHAREABLE_MODES.has(attached.mode), badRequest(`share_browser_view does not apply to \`${attached.mode}\` mode. `
68
- + (attached.liveViewUrl
61
+ + (hostedViewUrl
69
62
  ? 'That browser already has a hosted live view — use the '
70
- + `\`liveViewUrl\` from attach_browser: ${attached.liveViewUrl}`
63
+ + `\`liveViewUrl\` from attach_browser: ${hostedViewUrl}`
71
64
  : 'That browser has no live view to put behind a URL. To let '
72
65
  + 'someone else in, re-attach with mode "container" (the '
73
66
  + 'Reclaim runtime in Docker — free, needs Docker) or '
@@ -83,10 +76,12 @@ export function liveViewTools(attachRef, shareRef) {
83
76
  const viewerPort = attached.viewerPort;
84
77
  assert(viewerPort, badRequest('This browser reports no live-view port. Re-attach with mode '
85
78
  + '"container".'));
86
- const tunnel = await startTunnel(viewerPort);
79
+ const tunnel = await openTunnel(viewerPort, {
80
+ probePath: '/liveview.html?magnify=1',
81
+ });
87
82
  // The path is the runtime's own viewer page; `magnify=1` is what makes
88
83
  // it lay out for the device that opens it.
89
- const url = `${tunnel.url}/liveview.html?magnify=1`;
84
+ const url = ensureLiveViewUrl(tunnel.url);
90
85
  const share = {
91
86
  tunnel, url,
92
87
  };
@@ -94,20 +89,15 @@ export function liveViewTools(attachRef, shareRef) {
94
89
  LOGGER.info({ mode: attached.mode }, 'live view shared');
95
90
  return {
96
91
  url,
97
- ...(share.tunnel.binary.source === 'downloaded'
98
- ? { cloudflaredInstalled: true }
99
- : {}),
100
92
  ...(share.tunnel.ready
101
93
  ? {}
102
94
  : {
103
95
  propagating: true,
104
- // cloudflared's own last words. Without them, "the URL does
105
- // not connect" is unactionable: the tunnel, the local server
106
- // and this machine's egress all look identical from outside.
107
- ...(share.tunnel.diagnostics
108
- ? { cloudflaredLog: share.tunnel.diagnostics }
109
- : {}),
96
+ cloudflaredLog: share.tunnel.cloudflaredLog,
110
97
  }),
98
+ ...(share.tunnel.binary.source === 'downloaded'
99
+ ? { cloudflaredInstalled: true }
100
+ : {}),
111
101
  _notes: [
112
102
  ...(share.tunnel.binary.source === 'downloaded'
113
103
  ? ['cloudflared was not installed, so it was downloaded once '
@@ -115,12 +105,9 @@ export function liveViewTools(attachRef, shareRef) {
115
105
  : []),
116
106
  ...(share.tunnel.ready
117
107
  ? []
118
- : ['The tunnel never confirmed a connection to Cloudflare, so '
119
- + 'the URL may not resolve yet. Give it ~10s and reload '
120
- + 'first. If it still fails, say so and offer to retry '
121
- + '(stop_browser_view then share_browser_view) — a quick '
122
- + 'tunnel does sometimes fail to register. '
123
- + '`cloudflaredLog` has its output if it keeps happening.']),
108
+ : ['The tunnel hostname exists but the public viewer is still '
109
+ + 'propagating. Relay the URL now; if it errors, wait a few '
110
+ + 'seconds and reload. Do not start a second tunnel.']),
124
111
  'Relay `url` to the developer verbatim, on its own line.',
125
112
  'The URL is a credential: it needs no login, and anyone with it '
126
113
  + 'can see this browser and act in it as the signed-in user.',
@@ -135,11 +122,10 @@ export function liveViewTools(attachRef, shareRef) {
135
122
  }),
136
123
  defineTool({
137
124
  name: 'stop_browser_view',
138
- description: 'Close the public URL opened by share_browser_view: shuts the '
139
- + 'tunnel down, so the URL stops resolving for whoever still has '
140
- + 'it. Call it as soon as the person you shared with is finished. '
141
- + 'Nothing else changes — the browser stays attached, its own live '
142
- + 'view keeps serving locally, and any capture keeps running.',
125
+ description: 'Stops the public tunnel opened by share_browser_view; the URL stops '
126
+ + 'resolving. Call it when the viewer is done. The browser stays '
127
+ + 'attached, its local viewer keeps serving, and capture continues. '
128
+ + 'Returns `stopped: false` when no public share is active.',
143
129
  inputSchema: { type: 'object', properties: {} },
144
130
  }, async () => ({ stopped: await stopLiveShare(shareRef) })),
145
131
  ];
@@ -30,7 +30,12 @@ export function proposeTool(resolveBackend) {
30
30
  + 'identifier (letters/digits/underscore, not starting with a '
31
31
  + 'digit); we recommend lower_snake_case (for example, '
32
32
  + '"employer_name"), '
33
- + 'but you choose the exact name.',
33
+ + 'but you choose the exact name. For a parameter used only to build a '
34
+ + 'later claim request, preserve a `REQ_` prefix (body, header, or '
35
+ + 'intermediate value) or `URL_` prefix (path or query value) by '
36
+ + 'setting `shortenNames: false`. The prefix hides that internal '
37
+ + 'parameter from the data-point UI; it remains available to named '
38
+ + 'regexes and `{{param}}` substitutions.',
34
39
  inputSchema: objectSchema({
35
40
  requestId: { type: 'string' },
36
41
  name: { type: 'string' },
@@ -49,9 +54,10 @@ export function proposeTool(resolveBackend) {
49
54
  value: { type: 'string' },
50
55
  name: {
51
56
  type: 'string',
52
- description: 'The param key, or the source of one — see '
53
- + '`shortenNames`. Must stay distinct from other targets\' '
54
- + 'names after whichever treatment applies.',
57
+ description: 'Parameter key. See `shortenNames`. Keep it unique. '
58
+ + 'For hidden internal values, use `REQ_` or `URL_`. Set '
59
+ + '`shortenNames: false`. The prefix hides it from the '
60
+ + 'data-point UI but preserves substitution.',
55
61
  },
56
62
  hash: {
57
63
  type: 'string',
@@ -1,4 +1,4 @@
1
- import type { ReclaimClient } from '@reclaimprotocol/client';
1
+ import type { ReclaimClient } from '@reclaimprotocol/client/api';
2
2
  import { type RegisteredTool } from '../../server.ts';
3
3
  import type { AttachState } from './attach.ts';
4
4
  export declare function createVersionFromCaptureTool(client: ReclaimClient, attachRef?: {
@@ -1,6 +1,9 @@
1
- import { ALLOWED_REQUESTS_HINT, USER_SCRIPT_HINT, } from "../../../provider/injection-doc.js";
1
+ import { badRequest } from '@hapi/boom';
2
+ import assert from 'node:assert';
3
+ import { ALLOWED_REQUESTS_HINT, COOKIE_ATTACHMENT_HINT, USER_SCRIPT_HINT, } from "../../../provider/injection-doc.js";
2
4
  import { countsFor, matchRedactionWarnings, } from "../../../provider/match-redaction-warning.js";
3
- import { nextVersion, providerToCreateVersionRequest, } from "../../../provider/to-version.js";
5
+ import { postPublishBrowserNotes } from "../../../provider/post-publish-browser.js";
6
+ import { providerToCreateVersionRequest, resolveNewVersion, } from "../../../provider/to-version.js";
4
7
  import { defineTool } from "../../server.js";
5
8
  /** Schemas shared by the top-level `provider`/`providers` and the lighter
6
9
  * `allowedJsRequests` drafts — keeps the request shape from drifting between
@@ -107,8 +110,11 @@ export function createVersionFromCaptureTool(client, attachRef) {
107
110
  '(requests[], webSettings, …) for you; do NOT hand-construct that ' +
108
111
  'shape or call create_provider_version directly. Exactly one of ' +
109
112
  '`provider` (one request) or `providers` (a multi-request provider — ' +
110
- 'every entry is required at verification time). Omit `version` to ' +
111
- 'auto-bump past the highest existing one. The version lands on the ' +
113
+ 'every entry is required at verification time). This tool always ' +
114
+ 'creates a new immutable version; never edit an existing version. ' +
115
+ 'Omit `version` and `bump` for a patch bump, pass `bump` for a ' +
116
+ 'major/minor/patch bump, or pass the exact higher `version` the user ' +
117
+ 'directed. The version lands on the ' +
112
118
  'draft branch: call `publish_provider_version` (PRIVATE) or ' +
113
119
  '`submit_provider_version_for_review` (PUBLIC) to go live. ' +
114
120
  '`requiredContext` is derived from any {{context.<name>}} ' +
@@ -146,23 +152,38 @@ export function createVersionFromCaptureTool(client, attachRef) {
146
152
  },
147
153
  version: {
148
154
  type: 'object',
149
- description: 'Semver to publish as. Omit to auto-pick the next ' +
150
- 'version above the highest existing one.',
155
+ description: 'Exact new semver requested by the user. It must be higher ' +
156
+ 'than the current highest version. Do not pass with `bump`.',
151
157
  properties: {
152
- major: { type: 'number', minimum: 0 },
153
- minor: { type: 'number', minimum: 0 },
154
- patch: { type: 'number', minimum: 0 },
158
+ major: { type: 'integer', minimum: 0 },
159
+ minor: { type: 'integer', minimum: 0 },
160
+ patch: { type: 'integer', minimum: 0 },
155
161
  },
156
162
  required: ['major', 'minor', 'patch'],
157
163
  },
164
+ bump: {
165
+ type: 'string',
166
+ enum: ['major', 'minor', 'patch'],
167
+ description: 'Semantic increment from the highest version. Defaults to ' +
168
+ '`patch`. Do not pass with an exact `version`.',
169
+ },
170
+ requiredContext: {
171
+ type: 'object',
172
+ description: 'Complete JSON Schema for consumer-supplied session context. ' +
173
+ 'Omit to derive string properties from {{context.<name>}} ' +
174
+ 'placeholders. Pass refinements while creating this new ' +
175
+ 'version; never update the created version in place.',
176
+ additionalProperties: true,
177
+ },
158
178
  jsUserScripts: {
159
179
  type: 'string',
160
180
  description: USER_SCRIPT_HINT +
161
181
  ' Stored as webSettings.jsUserScripts; the Builder ' +
162
182
  'verification client runs it before every page load ' +
163
183
  '(including before navigating to initialUrl), matching ' +
164
- 'old-devtools customInjection. window.Reclaim is not exposed ' +
165
- 'there yet, so prefer plain browser JS.',
184
+ 'old-devtools customInjection. window.Reclaim is available ' +
185
+ 'for supported bridge actions; prefer plain browser JS for ' +
186
+ 'navigation and interaction.',
166
187
  },
167
188
  allowedJsRequests: {
168
189
  type: 'array',
@@ -179,7 +200,8 @@ export function createVersionFromCaptureTool(client, attachRef) {
179
200
  description: 'In-app interception settings, stored as ' +
180
201
  'webSettings.clientOptions.inapp.interceptorOptions — only ' +
181
202
  'needed for a genuine live-interception provider (a real ' +
182
- 'HAWKEYE/MSWJS script, not the standard capture→replay flow).',
203
+ 'HAWKEYE/MSWJS script, not the standard capture→replay flow). ' +
204
+ COOKIE_ATTACHMENT_HINT,
183
205
  properties: {
184
206
  interceptorType: {
185
207
  type: 'string',
@@ -214,11 +236,15 @@ export function createVersionFromCaptureTool(client, attachRef) {
214
236
  '`providers` (an array of 1+ drafts).');
215
237
  }
216
238
  const providers = hasMany ? args.providers : [args.provider];
217
- // Auto-pick the next version if not explicit
218
- const ver = args.version ?? (await nextVersion(client, args.providerId));
239
+ assert(!(args.version && args.bump), badRequest('Pass either `version` or `bump`, not both.'));
240
+ const ver = await resolveNewVersion(client, args.providerId, {
241
+ version: args.version,
242
+ bump: args.bump,
243
+ });
219
244
  const body = providerToCreateVersionRequest(providers, args.initialUrl, {
220
245
  notes: args.notes,
221
246
  version: ver,
247
+ requiredContext: args.requiredContext,
222
248
  jsUserScripts: args.jsUserScripts,
223
249
  allowedJsRequests: args.allowedJsRequests,
224
250
  interceptorOptions: args.interceptorOptions,
@@ -242,21 +268,18 @@ export function createVersionFromCaptureTool(client, attachRef) {
242
268
  // before closing it (a builder-mode session is quota-accounted and
243
269
  // otherwise just sits until its TTL expires).
244
270
  const attached = attachRef?.current;
245
- if (attached) {
246
- notes.push(`A "${attached.mode}" browser session is still attached` +
247
- (attached.browserSessionId
248
- ? ` (browserSessionId: ${attached.browserSessionId})`
249
- : '') +
250
- '. Ask the developer whether they want to keep it open for ' +
251
- 'further edits — only call dispose_browser once they confirm ' +
252
- 'they\'re done with it.');
253
- }
254
- // Let the dev know how/when the script runs (and the window.Reclaim gap).
271
+ notes.push(...postPublishBrowserNotes(attached, {
272
+ initialUrl: args.initialUrl,
273
+ hasUserScript: !!args.jsUserScripts?.trim(),
274
+ hasInterceptor: !!args.interceptorOptions,
275
+ }));
276
+ // Let the developer know how and when the script runs.
255
277
  if (args.jsUserScripts?.trim()) {
256
278
  notes.push('jsUserScripts will run in the Builder verification client before ' +
257
279
  'every page load (before navigating to initialUrl), matching ' +
258
- 'old-devtool customInjection. window.Reclaim is not yet exposed ' +
259
- 'there, so prefer plain browser JS for navigation/interaction.');
280
+ 'old-devtool customInjection. window.Reclaim is available for ' +
281
+ 'supported bridge actions; prefer plain browser JS for navigation ' +
282
+ 'and interaction.');
260
283
  }
261
284
  return notes.length ? { ...created, _notes: notes } : created;
262
285
  });
@@ -1,12 +1,3 @@
1
- /**
2
- * Build the shared authoring tools for the MCP, bound to a per-capture LOCAL
3
- * backend: a Chrome tab over CDP + the in-process attestor SDK. The tool logic
4
- * (navigate/inspect/propose/replay/prove) is authored once in `../../../
5
- * authoring` with the shared `defineTool` primitive; this only supplies the
6
- * MCP host — resolve the backend from `captureId` (the session handle from
7
- * `start_capture`, since one capture bundles the tab, its requests, and its
8
- * drafts) and the rich, credential-aware `run_proof` schema.
9
- */
10
1
  import { authoringTools, extendTool, } from "../../../authoring/index.js";
11
2
  import { runAttestorProof } from "../../../proof/attestor.js";
12
3
  import { replayProviderInPage } from "../../../proof/page-replay.js";
@@ -1,4 +1,4 @@
1
- import type { ReclaimClient } from '@reclaimprotocol/client';
1
+ import type { ReclaimClient } from '@reclaimprotocol/client/api';
2
2
  import { type RegisteredTool } from '../../server.ts';
3
3
  export declare function authenticateTool(client: ReclaimClient, name?: 'reclaim_authenticate' | 'authenticate_builder'): RegisteredTool;
4
4
  /**
@@ -1,4 +1,4 @@
1
- import type { ReclaimClient } from '@reclaimprotocol/client';
1
+ import type { ReclaimClient } from '@reclaimprotocol/client/api';
2
2
  import type { RegisteredTool } from '../../server.ts';
3
3
  /**
4
4
  * Local-only key tools — no backend client needed. These manage the eth
@@ -1,4 +1,4 @@
1
- import type { ReclaimClient } from '@reclaimprotocol/client';
1
+ import type { ReclaimClient } from '@reclaimprotocol/client/api';
2
2
  import { type RegisteredTool } from '../../server.ts';
3
3
  /** Legacy-devtools mode needs a distinct Builder login for its two
4
4
  * Builder-exclusive features: allocating quota-accounted Popcorn sessions
@@ -1,4 +1,4 @@
1
- import { createReclaim, decryptCallback, verifyResultFull, } from '@reclaimprotocol/client';
1
+ import { createReclaim, decryptCallback, } from '@reclaimprotocol/client';
2
2
  import assert from 'node:assert';
3
3
  import { apiUrl, orgSecret } from "../../../consts.js";
4
4
  import { defineTool } from "../../server.js";
@@ -30,16 +30,15 @@ function resolveOrgSecret() {
30
30
  export function verificationResultTool() {
31
31
  return defineTool({
32
32
  name: 'get_verification_result',
33
- description: 'Check a verification session and return its result when ready. ' +
34
- 'Authenticates with the org secret (RECLAIM_ORG_SECRET). Fetches the ' +
35
- 'session status; if it is terminal and a result has been submitted, ' +
36
- 'pulls the stored result(s) and verifies them locally. Encrypted ' +
37
- 'deliveries (ECIES over secp256k1) are decrypted with your optional ' +
38
- 'eth key (RECLAIM_DECRYPT_KEY or reclaim-decrypt.key); plaintext ' +
39
- 'deliveries are read directly. Returns ' +
40
- '`ready: false` while the session is still pending or no result has ' +
41
- 'been delivered yet. Use list_verification_events for the full ' +
42
- 'lifecycle log.',
33
+ description: 'Reads a verification session and locally checks each submitted ' +
34
+ 'result. Requires RECLAIM_ORG_SECRET. Encrypted ECIES deliveries ' +
35
+ 'also require the matching optional eth key ' +
36
+ '(RECLAIM_DECRYPT_KEY or reclaim-decrypt.key); plaintext deliveries ' +
37
+ 'are read directly. Returns `ready: false` until the session is ' +
38
+ 'terminal and at least one payload is readable. When `ready: true`, ' +
39
+ 'act only on result entries where `valid` is true; `ready` means a ' +
40
+ 'payload was read, not that verification succeeded. Use ' +
41
+ 'list_verification_events to diagnose an unfinished session.',
43
42
  inputSchema: {
44
43
  type: 'object',
45
44
  required: ['sessionId'],
@@ -77,7 +76,7 @@ export function verificationResultTool() {
77
76
  note: 'Session is terminal but no result has been submitted yet.',
78
77
  };
79
78
  }
80
- // Each item's `payload` is a compact JWE (encrypted to the org's
79
+ // Each item's `payload` is an ECIES ciphertext (encrypted to the org's
81
80
  // credential) or the plaintext signed JWS, as raw text. `decryptCallback`
82
81
  // branches on the body shape; an encrypted delivery with no key throws
83
82
  // a clear error, which we surface per-subscription rather than skip.
@@ -93,7 +92,7 @@ export function verificationResultTool() {
93
92
  void err;
94
93
  continue;
95
94
  }
96
- const outcome = await verifyResultFull(jws, {
95
+ const outcome = await reclaim.results.verify(jws, {
97
96
  expectedReclaimSessionId: args.sessionId,
98
97
  });
99
98
  results.push({
@@ -29,13 +29,24 @@ export interface CdpLoginResult {
29
29
  * closed the tab we opened. */
30
30
  closedBrowser: boolean;
31
31
  }
32
+ export interface LocalDashboardBrowser {
33
+ mode: 'dedicated' | 'attach';
34
+ port: number;
35
+ }
36
+ /**
37
+ * Accept only the two loopback Chrome modes used for legacy dashboard login.
38
+ * Config files are user-editable, so validate at runtime rather than trusting
39
+ * the TypeScript shape. Remote Builder, container, custom-CDP, and URL inputs
40
+ * are deliberately unsupported here.
41
+ */
42
+ export declare function localDashboardBrowser(value: unknown): LocalDashboardBrowser;
32
43
  /**
33
- * Open the dashboard login page in Chrome via CDP, wait for the developer to
34
- * finish signing in, read the resulting Firebase ID token from page storage,
35
- * then clean up. If we had to launch a dedicated Chrome for this, we close the
36
- * whole browser afterwards; if we attached to a Chrome that was already up
37
- * (for example, the capture flow's), we only close the tab we opened so we
38
- * don't disrupt it.
44
+ * Open the dashboard login page in a local Chrome via loopback CDP, wait for
45
+ * the developer to finish signing in, read the resulting Firebase ID token
46
+ * from page storage, then clean up. This never uses a Builder, container,
47
+ * custom-CDP, or shared browser. If we launch a dedicated Chrome, we close the
48
+ * whole browser afterward; if we attach to an existing local Chrome, we close
49
+ * only the tab we opened.
39
50
  */
40
51
  export declare function captureFirebaseTokenViaCdp(opts: {
41
52
  loginUrl?: string;