@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.
- package/README.md +5 -5
- package/lib/authoring/tools.js +2 -1
- package/lib/consts.d.ts +1 -1
- package/lib/consts.js +1 -1
- package/lib/live/tunnel.d.ts +10 -7
- package/lib/live/tunnel.js +78 -56
- package/lib/mcp/api/operations.gen.d.ts +12 -8
- package/lib/mcp/api/operations.gen.js +378 -580
- package/lib/mcp/api/tools.d.ts +1 -1
- package/lib/mcp/instructions.js +7 -3
- package/lib/mcp/remap_errors.js +9 -5
- package/lib/mcp/start.js +1 -1
- package/lib/mcp/tools/agent/attach.d.ts +2 -2
- package/lib/mcp/tools/agent/attach.js +4 -0
- package/lib/mcp/tools/agent/build.d.ts +1 -1
- package/lib/mcp/tools/agent/live-view-url.d.ts +2 -0
- package/lib/mcp/tools/agent/live-view-url.js +11 -0
- package/lib/mcp/tools/agent/live-view.d.ts +4 -2
- package/lib/mcp/tools/agent/live-view.js +40 -54
- package/lib/mcp/tools/agent/propose.js +10 -4
- package/lib/mcp/tools/agent/publish.d.ts +1 -1
- package/lib/mcp/tools/agent/publish.js +49 -26
- package/lib/mcp/tools/agent/shared.js +0 -9
- package/lib/mcp/tools/authenticate/authenticate.d.ts +1 -1
- package/lib/mcp/tools/authenticate/build.d.ts +1 -1
- package/lib/mcp/tools/authenticate/builder-access.d.ts +1 -1
- package/lib/mcp/tools/verification/result.js +12 -13
- package/lib/old/login-cdp.d.ts +17 -6
- package/lib/old/login-cdp.js +28 -11
- package/lib/old/to-register.d.ts +6 -0
- package/lib/old/to-register.js +35 -5
- package/lib/old/tools/authenticate.d.ts +5 -4
- package/lib/old/tools/authenticate.js +9 -5
- package/lib/old/tools/publish.d.ts +2 -2
- package/lib/old/tools/publish.js +47 -21
- package/lib/proof/attestor-auth.d.ts +13 -0
- package/lib/proof/attestor-auth.js +16 -0
- package/lib/proof/attestor.d.ts +7 -4
- package/lib/proof/attestor.js +7 -4
- package/lib/proof/index.d.ts +1 -0
- package/lib/proof/index.js +1 -0
- package/lib/proof/pod-prover.d.ts +2 -0
- package/lib/proof/pod-prover.js +5 -5
- package/lib/provider/injection-doc.d.ts +2 -0
- package/lib/provider/injection-doc.js +7 -1
- package/lib/provider/post-publish-browser.d.ts +12 -0
- package/lib/provider/post-publish-browser.js +40 -0
- package/lib/provider/to-version.d.ts +19 -7
- package/lib/provider/to-version.js +67 -25
- package/lib/tools/registry.d.ts +1 -1
- package/lib/tools/registry.js +7 -4
- package/package.json +2 -2
- package/skill/SKILL.builder.md +134 -13
- package/skill/SKILL.common.md +30 -19
- package/skill/SKILL.old.md +22 -12
- package/skill/builder-mode.md +19 -9
- package/skill/community-contributions.md +108 -0
- package/skill/hash-validation.md +8 -5
- package/skill/interception.md +35 -22
- package/skill/old-mode.md +11 -5
- package/skill/user-script.md +41 -10
- package/src/authoring/tools.ts +2 -1
- package/src/consts.ts +1 -2
- package/src/live/tunnel.ts +112 -66
- package/src/mcp/api/operations.gen.ts +384 -584
- package/src/mcp/api/tools.ts +1 -1
- package/src/mcp/instructions.ts +7 -3
- package/src/mcp/remap_errors.ts +9 -7
- package/src/mcp/start.ts +1 -1
- package/src/mcp/tools/agent/attach.ts +6 -2
- package/src/mcp/tools/agent/build.ts +1 -1
- package/src/mcp/tools/agent/live-view-url.ts +13 -0
- package/src/mcp/tools/agent/live-view.ts +42 -54
- package/src/mcp/tools/agent/propose.ts +10 -4
- package/src/mcp/tools/agent/publish.ts +63 -28
- package/src/mcp/tools/agent/shared.ts +5 -0
- package/src/mcp/tools/authenticate/authenticate.ts +1 -1
- package/src/mcp/tools/authenticate/build.ts +1 -1
- package/src/mcp/tools/authenticate/builder-access.ts +1 -1
- package/src/mcp/tools/verification/result.ts +11 -13
- package/src/old/login-cdp.ts +38 -11
- package/src/old/to-register.ts +56 -7
- package/src/old/tools/authenticate.ts +9 -5
- package/src/old/tools/publish.ts +64 -22
- package/src/proof/attestor-auth.ts +33 -0
- package/src/proof/attestor.ts +14 -8
- package/src/proof/index.ts +4 -0
- package/src/proof/pod-prover.ts +7 -5
- package/src/provider/injection-doc.ts +9 -1
- package/src/provider/post-publish-browser.ts +56 -0
- package/src/provider/to-version.ts +104 -27
- package/src/tools/registry.ts +12 -9
package/lib/mcp/api/tools.d.ts
CHANGED
|
@@ -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;
|
package/lib/mcp/instructions.js
CHANGED
|
@@ -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
|
|
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
|
|
78
|
-
+ '
|
|
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 '
|
package/lib/mcp/remap_errors.js
CHANGED
|
@@ -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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
|
|
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
|
|
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,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
|
|
3
|
-
* behind a public URL so someone who is not at this
|
|
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
|
|
7
|
-
*
|
|
8
|
-
*
|
|
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: '
|
|
42
|
-
+ '
|
|
43
|
-
+ '
|
|
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
|
-
+ '
|
|
48
|
-
+ '
|
|
49
|
-
+ '`
|
|
50
|
-
+ '
|
|
51
|
-
+ '
|
|
52
|
-
+ '
|
|
53
|
-
+ '
|
|
54
|
-
+ '
|
|
55
|
-
+ '
|
|
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
|
-
+ (
|
|
61
|
+
+ (hostedViewUrl
|
|
69
62
|
? 'That browser already has a hosted live view — use the '
|
|
70
|
-
+ `\`liveViewUrl\` from attach_browser: ${
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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
|
|
119
|
-
+ 'the URL
|
|
120
|
-
+ '
|
|
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: '
|
|
139
|
-
+ '
|
|
140
|
-
+ '
|
|
141
|
-
+ '
|
|
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: '
|
|
53
|
-
+ '
|
|
54
|
-
+ '
|
|
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 {
|
|
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 {
|
|
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).
|
|
111
|
-
'
|
|
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: '
|
|
150
|
-
'
|
|
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: '
|
|
153
|
-
minor: { type: '
|
|
154
|
-
patch: { type: '
|
|
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
|
|
165
|
-
'
|
|
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
|
-
|
|
218
|
-
const ver =
|
|
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
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
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
|
|
259
|
-
'
|
|
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
|
/** 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,
|
|
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: '
|
|
34
|
-
'
|
|
35
|
-
'
|
|
36
|
-
'
|
|
37
|
-
'
|
|
38
|
-
'
|
|
39
|
-
'
|
|
40
|
-
'
|
|
41
|
-
'
|
|
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
|
|
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
|
|
95
|
+
const outcome = await reclaim.results.verify(jws, {
|
|
97
96
|
expectedReclaimSessionId: args.sessionId,
|
|
98
97
|
});
|
|
99
98
|
results.push({
|
package/lib/old/login-cdp.d.ts
CHANGED
|
@@ -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
|
|
34
|
-
* finish signing in, read the resulting Firebase ID token
|
|
35
|
-
* then clean up.
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
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;
|