@reclaimprotocol/agent 0.1.4 → 0.1.6
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/backend.d.ts +71 -0
- package/lib/authoring/backend.js +24 -0
- package/lib/authoring/find.d.ts +3 -0
- package/lib/authoring/find.js +54 -0
- package/lib/authoring/index.d.ts +4 -0
- package/lib/authoring/index.js +6 -0
- package/lib/authoring/propose.d.ts +3 -0
- package/lib/authoring/propose.js +109 -0
- package/lib/authoring/replay.d.ts +10 -0
- package/lib/authoring/replay.js +34 -0
- package/lib/authoring/tools.d.ts +16 -0
- package/lib/authoring/tools.js +193 -0
- package/lib/authoring/util.d.ts +27 -0
- package/lib/authoring/util.js +21 -0
- package/lib/cdp/capture-engine.js +1 -1
- package/lib/consts.d.ts +6 -1
- package/lib/consts.js +9 -2
- package/lib/mcp/api/operations.gen.js +46 -18
- package/lib/mcp/server.d.ts +2 -25
- package/lib/mcp/server.js +4 -17
- package/lib/mcp/start.js +4 -2
- package/lib/mcp/tools/agent/analyze.js +3 -3
- package/lib/mcp/tools/agent/build.d.ts +4 -4
- package/lib/mcp/tools/agent/build.js +13 -15
- package/lib/mcp/tools/agent/capture.d.ts +13 -1
- package/lib/mcp/tools/agent/capture.js +18 -85
- package/lib/mcp/tools/agent/eval.d.ts +5 -2
- package/lib/mcp/tools/agent/eval.js +11 -121
- package/lib/mcp/tools/agent/find.d.ts +10 -3
- package/lib/mcp/tools/agent/find.js +25 -31
- package/lib/mcp/tools/agent/proof.d.ts +13 -3
- package/lib/mcp/tools/agent/proof.js +81 -132
- package/lib/mcp/tools/agent/propose.d.ts +10 -9
- package/lib/mcp/tools/agent/propose.js +87 -64
- package/lib/mcp/tools/agent/publish.js +2 -2
- package/lib/mcp/tools/agent/replay.d.ts +10 -3
- package/lib/mcp/tools/agent/replay.js +29 -36
- package/lib/mcp/tools/agent/session.d.ts +1 -3
- package/lib/mcp/tools/agent/session.js +5 -5
- package/lib/mcp/tools/agent/shared.d.ts +8 -0
- package/lib/mcp/tools/agent/shared.js +125 -0
- package/lib/old/client.d.ts +35 -0
- package/lib/old/client.js +18 -0
- package/lib/old/login-cdp.d.ts +24 -0
- package/lib/old/login-cdp.js +28 -3
- package/lib/old/sdk-client.d.ts +39 -0
- package/lib/old/sdk-client.js +85 -0
- package/lib/old/to-register.d.ts +69 -0
- package/lib/old/to-register.js +52 -2
- package/lib/old/tools/build.d.ts +6 -1
- package/lib/old/tools/build.js +11 -1
- package/lib/old/tools/get-provider-info.d.ts +16 -0
- package/lib/old/tools/get-provider-info.js +73 -0
- package/lib/old/tools/get-version-config.d.ts +17 -0
- package/lib/old/tools/get-version-config.js +47 -0
- package/lib/old/tools/publish.js +189 -2
- package/lib/old/tools/update-provider-metadata.d.ts +16 -0
- package/lib/old/tools/update-provider-metadata.js +61 -0
- package/lib/proof/attestor.d.ts +6 -3
- package/lib/proof/attestor.js +10 -1
- package/lib/proof/debug-response-dump.d.ts +4 -0
- package/lib/proof/debug-response-dump.js +55 -0
- package/lib/proof/patch-domhandler.d.ts +1 -0
- package/lib/proof/patch-domhandler.js +59 -0
- package/lib/proof/proof-core.d.ts +1 -1
- package/lib/proof/proof-core.js +1 -1
- package/lib/proof/zk-files.js +7 -6
- package/lib/provider/dom-xpath.d.ts +17 -0
- package/lib/provider/dom-xpath.js +187 -0
- package/lib/provider/draft.d.ts +30 -2
- package/lib/provider/draft.js +117 -28
- package/lib/provider/index.d.ts +4 -0
- package/lib/provider/index.js +7 -0
- package/lib/provider/injection-doc.js +6 -0
- package/lib/provider/matcher.d.ts +17 -20
- package/lib/provider/matcher.js +394 -280
- package/lib/provider/schema.d.ts +7 -5
- package/lib/tools/registry.d.ts +50 -0
- package/lib/tools/registry.js +49 -0
- package/package.json +9 -1
- package/skill/SKILL.builder.md +55 -32
- package/skill/SKILL.old.md +20 -12
- package/skill/builder-mode.md +1 -1
- package/skill/injection-api.md +117 -0
- package/src/authoring/backend.ts +98 -0
- package/src/authoring/index.ts +20 -0
- package/src/authoring/tools.ts +273 -0
- package/src/authoring/util.ts +42 -0
- package/src/cdp/capture-engine.ts +1 -1
- package/src/consts.ts +15 -2
- package/src/mcp/api/operations.gen.ts +46 -18
- package/src/mcp/server.ts +9 -39
- package/src/mcp/start.ts +4 -1
- package/src/mcp/tools/agent/analyze.ts +3 -3
- package/src/mcp/tools/agent/build.ts +13 -21
- package/src/mcp/tools/agent/capture.ts +31 -115
- package/src/mcp/tools/agent/eval.ts +19 -155
- package/src/mcp/tools/agent/find.ts +33 -36
- package/src/mcp/tools/agent/proof.ts +87 -160
- package/src/mcp/tools/agent/propose.ts +93 -85
- package/src/mcp/tools/agent/publish.ts +2 -2
- package/src/mcp/tools/agent/replay.ts +32 -42
- package/src/mcp/tools/agent/session.ts +4 -5
- package/src/mcp/tools/agent/shared.ts +152 -0
- package/src/old/client.ts +56 -0
- package/src/old/login-cdp.ts +28 -3
- package/src/old/sdk-client.ts +105 -0
- package/src/old/to-register.ts +98 -6
- package/src/old/tools/build.ts +12 -0
- package/src/old/tools/get-provider-info.ts +91 -0
- package/src/old/tools/get-version-config.ts +56 -0
- package/src/old/tools/publish.ts +244 -1
- package/src/old/tools/update-provider-metadata.ts +72 -0
- package/src/proof/attestor.ts +16 -4
- package/src/proof/debug-response-dump.ts +70 -0
- package/src/proof/patch-domhandler.ts +68 -0
- package/src/proof/proof-core.ts +1 -1
- package/src/proof/zk-files.ts +7 -6
- package/src/provider/dom-xpath.ts +225 -0
- package/src/provider/draft.ts +168 -35
- package/src/provider/index.ts +8 -0
- package/src/provider/injection-doc.ts +6 -0
- package/src/provider/matcher.ts +477 -357
- package/src/provider/schema.ts +7 -5
- package/src/tools/registry.ts +92 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backend seam for the authoring tools. The tool LOGIC (drive the browser →
|
|
3
|
+
* capture → propose → replay → prove) is written once against this interface;
|
|
4
|
+
* each environment supplies a backend:
|
|
5
|
+
* - local (MCP): a Chrome tab over CDP + the in-process attestor SDK.
|
|
6
|
+
* - remote (cloud): the user's Popcorn browser over CDP + the TEE prover.
|
|
7
|
+
*
|
|
8
|
+
* One backend instance == one live session (a page + its capture). Multi
|
|
9
|
+
* session falls out of instancing: the MCP resolves a backend per tab/capture,
|
|
10
|
+
* the cloud one per run — so the shared tools never carry a session id and hold
|
|
11
|
+
* no cross-session state.
|
|
12
|
+
*/
|
|
13
|
+
import { randomUUID } from 'node:crypto'
|
|
14
|
+
import type { CaptureSession } from '../cdp/capture-engine.ts'
|
|
15
|
+
import type { Extraction } from '../provider/draft.ts'
|
|
16
|
+
import type { ReclaimProvider, SecretParamRef } from '../provider/schema.ts'
|
|
17
|
+
|
|
18
|
+
/** Secret request params (cookie/auth headers), materialized only for the
|
|
19
|
+
* replay/prove call — never surfaced in tool output. */
|
|
20
|
+
export interface SecretParams {
|
|
21
|
+
headers: Record<string, string>
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** A drafted recipe held server-side so the model only handles an opaque
|
|
25
|
+
* `draftId` — the provider is secret-free but the captured secrets never enter
|
|
26
|
+
* the transcript. Shared by propose → replay → run_proof. */
|
|
27
|
+
export interface Draft {
|
|
28
|
+
provider: ReclaimProvider
|
|
29
|
+
secretRefs: SecretParamRef[]
|
|
30
|
+
/** Real secret header values (cookie/auth) for replay/prove — never returned
|
|
31
|
+
* to the model. */
|
|
32
|
+
secrets: Record<string, string>
|
|
33
|
+
/** The captured request this draft was proposed from. */
|
|
34
|
+
requestId: string
|
|
35
|
+
/** One entry per extracted value (value + its redaction), so replay can
|
|
36
|
+
* validate each against its own selector. */
|
|
37
|
+
extractions: Extraction[]
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Per-session draft store: `propose` puts, `replay`/`run_proof` get by id. */
|
|
41
|
+
export interface DraftStore {
|
|
42
|
+
put(draft: Draft): string
|
|
43
|
+
get(id: string): Draft | undefined
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function makeDraftStore(): DraftStore {
|
|
47
|
+
const map = new Map<string, Draft>()
|
|
48
|
+
return {
|
|
49
|
+
put: (draft) => {
|
|
50
|
+
const id = `draft_${randomUUID()}`
|
|
51
|
+
map.set(id, draft)
|
|
52
|
+
return id
|
|
53
|
+
},
|
|
54
|
+
get: (id) => map.get(id),
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Options for a proof run. `ownerAddress` selects the local signing credential
|
|
59
|
+
* and `attestorUrl` overrides the attestor endpoint (both MCP-only); the
|
|
60
|
+
* remote TEE backend ignores them (it signs in-enclave, own attestor). */
|
|
61
|
+
export interface ProveOptions {
|
|
62
|
+
ownerAddress?: string
|
|
63
|
+
attestorUrl?: string
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Everything the shared authoring tools need from one live session. Browser ops
|
|
68
|
+
* go through `sendCdp` (+ `waitForEvent` for load-style waits); capture reads
|
|
69
|
+
* use `capture`; proof/replay are whole operations because they genuinely
|
|
70
|
+
* differ (local attestor + live re-fetch vs remote TEE) — each backend shapes
|
|
71
|
+
* its own result, passed straight through as the tool's output.
|
|
72
|
+
*/
|
|
73
|
+
export interface AuthoringBackend {
|
|
74
|
+
/** Send a raw CDP command scoped to this session's page. */
|
|
75
|
+
sendCdp(method: string, params?: Record<string, unknown>): Promise<unknown>
|
|
76
|
+
/** Resolve once `method` (a CDP event) fires on this session's page, or
|
|
77
|
+
* after `timeoutMs`. Used for `Page.loadEventFired`-style waits. */
|
|
78
|
+
waitForEvent(method: string, timeoutMs: number): Promise<'fired' | 'timeout'>
|
|
79
|
+
/** This session's captured requests (the shared capture engine). */
|
|
80
|
+
readonly capture: CaptureSession
|
|
81
|
+
/** This session's drafts (propose → replay/run_proof). */
|
|
82
|
+
readonly drafts: DraftStore
|
|
83
|
+
/** Prove a drafted recipe. Local: attestor SDK (rich claim view). Remote: TEE
|
|
84
|
+
* `/reclaim/prove` (lean, secret-free summary). Returns the environment's
|
|
85
|
+
* display shape. A backend may record the proven recipe internally (e.g.
|
|
86
|
+
* the cloud publish step) — that side effect is the backend's, not ours. */
|
|
87
|
+
prove(draft: Draft, opts?: ProveOptions): Promise<unknown>
|
|
88
|
+
/**
|
|
89
|
+
* Validate/replay a drafted recipe before proving. With `withoutSecrets` it
|
|
90
|
+
* is the AUTH-BOUND check: re-issue the request stripped of the captured
|
|
91
|
+
* secrets (local: a Node re-fetch without them; remote: an anonymous `fetch`
|
|
92
|
+
* in the Popcorn page, `credentials: 'omit'`) and report whether the values
|
|
93
|
+
* are STILL extractable — i.e. the endpoint is public. Without it, validate
|
|
94
|
+
* extraction for the authenticated request. The shape is environment-specific
|
|
95
|
+
* and passed straight through as the tool's result.
|
|
96
|
+
*/
|
|
97
|
+
replay(draft: Draft, opts?: { withoutSecrets?: boolean }): Promise<unknown>
|
|
98
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Shared authoring tools, backend-injectable. Consumed by the MCP server
|
|
2
|
+
// (local Chrome + attestor backend) and the cloud loop (Popcorn + TEE backend).
|
|
3
|
+
export type {
|
|
4
|
+
AuthoringBackend,
|
|
5
|
+
Draft,
|
|
6
|
+
DraftStore,
|
|
7
|
+
ProveOptions,
|
|
8
|
+
SecretParams,
|
|
9
|
+
} from './backend.ts'
|
|
10
|
+
export { makeDraftStore } from './backend.ts'
|
|
11
|
+
export { authoringTools } from './tools.ts'
|
|
12
|
+
// The shared tool primitive — re-exported so consumers (the cloud loop) get the
|
|
13
|
+
// RegisteredTool type/`defineTool`/`extendTool` without importing the MCP
|
|
14
|
+
// subsystem.
|
|
15
|
+
export {
|
|
16
|
+
defineTool,
|
|
17
|
+
extendTool,
|
|
18
|
+
type RegisteredTool,
|
|
19
|
+
type ToolDefinition,
|
|
20
|
+
} from '../tools/registry.ts'
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The authoring tools, authored ONCE — each directly with the shared
|
|
3
|
+
* `defineTool` primitive (no parallel tool spec). `authoringTools(resolve)`
|
|
4
|
+
* returns them as plain {@link RegisteredTool}s; the MCP (local Chrome +
|
|
5
|
+
* attestor) and the cloud loop (Popcorn + TEE) each pass their own backend
|
|
6
|
+
* resolver, so navigate/inspect/propose/replay/prove logic lives in one place.
|
|
7
|
+
*
|
|
8
|
+
* The resolver hands back the backend per call — the MCP keys it by `captureId`
|
|
9
|
+
* (multi-session), the cloud returns its one run backend. A host that needs
|
|
10
|
+
* extra input schema (the MCP's `captureId` + rich `run_proof` contract) MAPS
|
|
11
|
+
* these tools through `extendTool` at registration; the tools stay plain.
|
|
12
|
+
*
|
|
13
|
+
* Secret guarantee: captured cookie/auth values never enter a tool result. The
|
|
14
|
+
* draft (recipe + secrets) is held server-side; the model only sees an opaque
|
|
15
|
+
* `draftId` and the secret-free provider.
|
|
16
|
+
*/
|
|
17
|
+
import { findTool } from '../mcp/tools/agent/find.ts'
|
|
18
|
+
import { proposeTool } from '../mcp/tools/agent/propose.ts'
|
|
19
|
+
import { replayTool } from '../mcp/tools/agent/replay.ts'
|
|
20
|
+
import type { CapturedRequest } from '../provider/schema.ts'
|
|
21
|
+
import { defineTool, type RegisteredTool } from '../tools/registry.ts'
|
|
22
|
+
import type { AuthoringBackend } from './backend.ts'
|
|
23
|
+
import { objectSchema, publicRequest, type ResolveBackend } from './util.ts'
|
|
24
|
+
|
|
25
|
+
const sleep = (ms: number) => new Promise<void>((r) => setTimeout(r, ms))
|
|
26
|
+
|
|
27
|
+
interface RequestFilter {
|
|
28
|
+
method?: string
|
|
29
|
+
urlGlob?: string
|
|
30
|
+
statusMin?: number
|
|
31
|
+
statusMax?: number
|
|
32
|
+
contentType?: string
|
|
33
|
+
graphqlOp?: string
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function matchesFilter(r: CapturedRequest, f: RequestFilter): boolean {
|
|
37
|
+
if(f.method && r.method !== f.method.toUpperCase()) {
|
|
38
|
+
return false
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if(f.urlGlob && !globMatch(f.urlGlob, r.url)) {
|
|
42
|
+
return false
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if(f.statusMin !== undefined && r.status < f.statusMin) {
|
|
46
|
+
return false
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if(f.statusMax !== undefined && r.status > f.statusMax) {
|
|
50
|
+
return false
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if(f.contentType && !r.contentType.includes(f.contentType)) {
|
|
54
|
+
return false
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if(f.graphqlOp && r.graphqlOp !== f.graphqlOp) {
|
|
58
|
+
return false
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return true
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function globMatch(pattern: string, str: string): boolean {
|
|
65
|
+
const re = new RegExp(
|
|
66
|
+
'^'
|
|
67
|
+
+ pattern.replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*')
|
|
68
|
+
+ '$',
|
|
69
|
+
)
|
|
70
|
+
return re.test(str)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
interface EvalResult {
|
|
74
|
+
result?: { value?: unknown }
|
|
75
|
+
exceptionDetails?: { exception?: { description?: string }, text?: string }
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async function evalInPage(
|
|
79
|
+
backend: AuthoringBackend,
|
|
80
|
+
expression: string,
|
|
81
|
+
): Promise<{ value?: unknown, error?: string }> {
|
|
82
|
+
const res = (await backend.sendCdp('Runtime.evaluate', {
|
|
83
|
+
expression, returnByValue: true, awaitPromise: true,
|
|
84
|
+
})) as EvalResult
|
|
85
|
+
if(res.exceptionDetails) {
|
|
86
|
+
return {
|
|
87
|
+
error: res.exceptionDetails.exception?.description
|
|
88
|
+
?? res.exceptionDetails.text
|
|
89
|
+
?? 'evaluation error',
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return { value: res.result?.value }
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* The authoring tools — navigate/inspect authored inline here; find/propose/
|
|
98
|
+
* replay live in their own files ({@link findTool}/{@link proposeTool}/
|
|
99
|
+
* {@link replayTool}) and are composed in below. Each is a plain `defineTool`
|
|
100
|
+
* primitive, so there is one canonical `RegisteredTool` per tool and no
|
|
101
|
+
* parallel tool shape. Every handler resolves its session backend via
|
|
102
|
+
* `resolveBackend(args)`: the cloud passes `() => backend` (one backend per
|
|
103
|
+
* run); the MCP passes an `args.captureId`-keyed resolver. Hosts that need
|
|
104
|
+
* extra input schema (the MCP's `captureId` session handle + the
|
|
105
|
+
* credential-aware `run_proof` contract) MAP these tools through `extendTool`
|
|
106
|
+
* (see mcp/tools/agent/shared.ts) — the tools themselves stay plain, and args
|
|
107
|
+
* parse loosely so the extra fields still reach the resolver/handler.
|
|
108
|
+
*/
|
|
109
|
+
export function authoringTools(
|
|
110
|
+
resolveBackend: ResolveBackend,
|
|
111
|
+
): RegisteredTool[] {
|
|
112
|
+
return [
|
|
113
|
+
defineTool<Record<string, unknown>>(
|
|
114
|
+
{
|
|
115
|
+
name: 'navigate',
|
|
116
|
+
description: 'Navigate the browser tab to a URL, waiting for load.',
|
|
117
|
+
inputSchema: objectSchema(
|
|
118
|
+
{ url: { type: 'string' }, timeoutMs: { type: 'number' } },
|
|
119
|
+
['url'],
|
|
120
|
+
),
|
|
121
|
+
},
|
|
122
|
+
async(args) => {
|
|
123
|
+
const backend = resolveBackend(args)
|
|
124
|
+
const timeoutMs = Number(args.timeoutMs) || 30_000
|
|
125
|
+
await backend.sendCdp('Page.enable')
|
|
126
|
+
// Start listening BEFORE navigating so the load event isn't missed.
|
|
127
|
+
const load = backend.waitForEvent('Page.loadEventFired', timeoutMs)
|
|
128
|
+
const nav = (await backend.sendCdp(
|
|
129
|
+
'Page.navigate', { url: String(args.url) },
|
|
130
|
+
)) as { errorText?: string }
|
|
131
|
+
if(nav.errorText) {
|
|
132
|
+
return { ok: false, error: nav.errorText }
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const loadStatus = await load
|
|
136
|
+
const final = await evalInPage(backend, 'location.href')
|
|
137
|
+
return { ok: true, loadStatus, finalUrl: final.value }
|
|
138
|
+
},
|
|
139
|
+
),
|
|
140
|
+
defineTool<Record<string, unknown>>(
|
|
141
|
+
{
|
|
142
|
+
name: 'eval_in_page',
|
|
143
|
+
description:
|
|
144
|
+
'Evaluate a JavaScript expression in the page and return its value '
|
|
145
|
+
+ '(use to read the displayed value, check login state, etc.).',
|
|
146
|
+
inputSchema: objectSchema(
|
|
147
|
+
{ expression: { type: 'string' } }, ['expression'],
|
|
148
|
+
),
|
|
149
|
+
},
|
|
150
|
+
(args) => evalInPage(resolveBackend(args), String(args.expression)),
|
|
151
|
+
),
|
|
152
|
+
defineTool<Record<string, unknown>>(
|
|
153
|
+
{
|
|
154
|
+
name: 'wait_for_page',
|
|
155
|
+
description:
|
|
156
|
+
'Poll a JavaScript expression until it is truthy or the timeout '
|
|
157
|
+
+ 'elapses (e.g. wait for the user to finish logging in).',
|
|
158
|
+
inputSchema: objectSchema(
|
|
159
|
+
{ expression: { type: 'string' }, timeoutMs: { type: 'number' } },
|
|
160
|
+
['expression'],
|
|
161
|
+
),
|
|
162
|
+
},
|
|
163
|
+
async(args) => {
|
|
164
|
+
const backend = resolveBackend(args)
|
|
165
|
+
const expr = String(args.expression)
|
|
166
|
+
const deadline = Date.now() + (Number(args.timeoutMs) || 180_000)
|
|
167
|
+
while(Date.now() < deadline) {
|
|
168
|
+
const { value } = await evalInPage(backend, expr)
|
|
169
|
+
if(value) {
|
|
170
|
+
return { ready: true }
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
await sleep(1000)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return { ready: false }
|
|
177
|
+
},
|
|
178
|
+
),
|
|
179
|
+
defineTool<Record<string, unknown>>(
|
|
180
|
+
{
|
|
181
|
+
name: 'get_cookies',
|
|
182
|
+
description:
|
|
183
|
+
'List the NAMES of cookies currently set for the page (values are '
|
|
184
|
+
+ 'NEVER returned). The most reliable, language- and DOM-independent '
|
|
185
|
+
+ 'login signal: after the user logs in, an auth/session cookie '
|
|
186
|
+
+ 'appears (e.g. session/sid/token/auth/jwt/_user/logged_in). '
|
|
187
|
+
+ 'Includes httpOnly cookies the page JS cannot see.',
|
|
188
|
+
inputSchema: objectSchema({}),
|
|
189
|
+
},
|
|
190
|
+
async(args) => {
|
|
191
|
+
const backend = resolveBackend(args)
|
|
192
|
+
const res = (await backend.sendCdp('Network.getCookies')) as {
|
|
193
|
+
cookies?: {
|
|
194
|
+
name: string
|
|
195
|
+
domain?: string
|
|
196
|
+
session?: boolean
|
|
197
|
+
httpOnly?: boolean
|
|
198
|
+
}[]
|
|
199
|
+
}
|
|
200
|
+
return (res.cookies ?? []).map((c) => ({
|
|
201
|
+
name: c.name,
|
|
202
|
+
...(c.domain ? { domain: c.domain } : {}),
|
|
203
|
+
...(c.session ? { session: true } : {}),
|
|
204
|
+
...(c.httpOnly ? { httpOnly: true } : {}),
|
|
205
|
+
}))
|
|
206
|
+
},
|
|
207
|
+
),
|
|
208
|
+
defineTool<Record<string, unknown>>(
|
|
209
|
+
{
|
|
210
|
+
name: 'list_requests',
|
|
211
|
+
description:
|
|
212
|
+
'List captured network requests (method/url/status/size), newest '
|
|
213
|
+
+ 'last. Optionally filter by method / urlGlob / status range / '
|
|
214
|
+
+ 'contentType / graphqlOp. Metadata only — secrets never included.',
|
|
215
|
+
inputSchema: objectSchema({
|
|
216
|
+
filter: {
|
|
217
|
+
type: 'object',
|
|
218
|
+
properties: {
|
|
219
|
+
method: { type: 'string' },
|
|
220
|
+
urlGlob: { type: 'string' },
|
|
221
|
+
statusMin: { type: 'number' },
|
|
222
|
+
statusMax: { type: 'number' },
|
|
223
|
+
contentType: { type: 'string' },
|
|
224
|
+
graphqlOp: { type: 'string' },
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
}),
|
|
228
|
+
},
|
|
229
|
+
async(args) => {
|
|
230
|
+
const backend = resolveBackend(args)
|
|
231
|
+
const filter = (args.filter ?? {}) as RequestFilter
|
|
232
|
+
return [...backend.capture.requests.values()]
|
|
233
|
+
.filter((r) => matchesFilter(r, filter))
|
|
234
|
+
.map(publicRequest)
|
|
235
|
+
},
|
|
236
|
+
),
|
|
237
|
+
findTool(resolveBackend),
|
|
238
|
+
proposeTool(resolveBackend),
|
|
239
|
+
replayTool(resolveBackend),
|
|
240
|
+
defineTool<Record<string, unknown>>(
|
|
241
|
+
{
|
|
242
|
+
name: 'run_proof',
|
|
243
|
+
description:
|
|
244
|
+
'Prove the drafted recipe (zkTLS). Only call after replay_request '
|
|
245
|
+
+ 'looks right. Returns the proof result.',
|
|
246
|
+
inputSchema: objectSchema({ draftId: { type: 'string' } }, ['draftId']),
|
|
247
|
+
},
|
|
248
|
+
// The backend shapes its own result: the cloud returns a lean,
|
|
249
|
+
// secret-free summary (and records the proven recipe for publish); the
|
|
250
|
+
// MCP persists the claim + returns the rich developer view. The MCP adds
|
|
251
|
+
// `ownerAddress`/`attestorUrl` to the schema via `extendTool`; the
|
|
252
|
+
// handler reads them from args (loose parse keeps them).
|
|
253
|
+
async(args) => {
|
|
254
|
+
const backend = resolveBackend(args)
|
|
255
|
+
const draft = backend.drafts.get(String(args.draftId))
|
|
256
|
+
if(!draft) {
|
|
257
|
+
throw new Error(`no draft ${String(args.draftId)}`)
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const opts: { ownerAddress?: string, attestorUrl?: string } = {}
|
|
261
|
+
if(typeof args.ownerAddress === 'string') {
|
|
262
|
+
opts.ownerAddress = args.ownerAddress
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if(typeof args.attestorUrl === 'string') {
|
|
266
|
+
opts.attestorUrl = args.attestorUrl
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return backend.prove(draft, opts)
|
|
270
|
+
},
|
|
271
|
+
),
|
|
272
|
+
]
|
|
273
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Small shared helpers for the authoring tools (see tools.ts). Kept separate so
|
|
3
|
+
* the per-tool files (find.ts, propose.ts, replay.ts) and the inline tools in
|
|
4
|
+
* tools.ts share one copy without a circular import.
|
|
5
|
+
*/
|
|
6
|
+
import type { JSONSchema } from 'zod/v4/core'
|
|
7
|
+
import type { CapturedRequest } from '../provider/schema.ts'
|
|
8
|
+
import type { AuthoringBackend } from './backend.ts'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Resolves the session backend for a tool call. The MCP keys it by
|
|
12
|
+
* `args.captureId` (multi-session); the cloud loop returns its one run backend.
|
|
13
|
+
* Each authoring tool closes over this so the same tool works for both hosts.
|
|
14
|
+
*/
|
|
15
|
+
export type ResolveBackend =
|
|
16
|
+
(args: Record<string, unknown>) => AuthoringBackend
|
|
17
|
+
|
|
18
|
+
/** Build an `object` JSON Schema for a tool input — a small literal shortener,
|
|
19
|
+
* not a tool abstraction. */
|
|
20
|
+
export function objectSchema(
|
|
21
|
+
properties: Record<string, unknown>,
|
|
22
|
+
required?: string[],
|
|
23
|
+
): JSONSchema.ObjectSchema {
|
|
24
|
+
return {
|
|
25
|
+
type: 'object',
|
|
26
|
+
properties,
|
|
27
|
+
...(required?.length ? { required } : {}),
|
|
28
|
+
} as unknown as JSONSchema.ObjectSchema
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Secret-free projection of a captured request for tool output. */
|
|
32
|
+
export function publicRequest(r: CapturedRequest) {
|
|
33
|
+
return {
|
|
34
|
+
requestId: r.requestId,
|
|
35
|
+
method: r.method,
|
|
36
|
+
url: r.url,
|
|
37
|
+
status: r.status,
|
|
38
|
+
contentType: r.contentType,
|
|
39
|
+
size: r.size,
|
|
40
|
+
...(r.graphqlOp ? { graphqlOp: r.graphqlOp } : {}),
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -75,7 +75,7 @@ export function isStaticAsset(url: string): boolean {
|
|
|
75
75
|
try {
|
|
76
76
|
path = new URL(url).pathname
|
|
77
77
|
} catch{
|
|
78
|
-
path = url.split(/[?#]/)[0]
|
|
78
|
+
path = url.split(/[?#]/)[0] || url
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
// Extension of the last path segment only, so `/v1.2/data` isn't misread.
|
package/src/consts.ts
CHANGED
|
@@ -19,6 +19,7 @@ import { DEFAULT_BASE_URL } from '@reclaimprotocol/client'
|
|
|
19
19
|
import { homedir } from 'node:os'
|
|
20
20
|
import { join } from 'node:path'
|
|
21
21
|
import { DEFAULT_OLD_API_URL, DEFAULT_OLD_LOGS_URL } from './old/client.ts'
|
|
22
|
+
import { DEFAULT_SDK_API_URL } from './old/sdk-client.ts'
|
|
22
23
|
|
|
23
24
|
// ---------------------------------------------------------------------------
|
|
24
25
|
// Default / fallback literals (used only as env fallbacks).
|
|
@@ -30,9 +31,14 @@ export const FALLBACK_ATTESTOR_URL = 'wss://attestor.reclaimprotocol.org:444/ws'
|
|
|
30
31
|
/** The devtools dashboard login page — fallback for `RECLAIM_OLD_LOGIN_URL`. */
|
|
31
32
|
export const DEFAULT_LOGIN_URL = 'https://dev.reclaimprotocol.org'
|
|
32
33
|
|
|
33
|
-
// Re-export the
|
|
34
|
+
// Re-export the non-env-fallback defaults so callers can keep importing
|
|
34
35
|
// their URL defaults from a single place if they wish.
|
|
35
|
-
export {
|
|
36
|
+
export {
|
|
37
|
+
DEFAULT_BASE_URL,
|
|
38
|
+
DEFAULT_OLD_API_URL,
|
|
39
|
+
DEFAULT_OLD_LOGS_URL,
|
|
40
|
+
DEFAULT_SDK_API_URL,
|
|
41
|
+
}
|
|
36
42
|
|
|
37
43
|
// ---------------------------------------------------------------------------
|
|
38
44
|
// Logging.
|
|
@@ -101,6 +107,13 @@ export function oldLogsUrl(): string {
|
|
|
101
107
|
return process.env.RECLAIM_OLD_LOGS_URL || DEFAULT_OLD_LOGS_URL
|
|
102
108
|
}
|
|
103
109
|
|
|
110
|
+
/** Public production SDK-backend base URL — the service the verification
|
|
111
|
+
* SDK/attestor itself reads a provider's recipe from at runtime. A
|
|
112
|
+
* DIFFERENT host from the old-devtools dashboard backend (`oldApiUrl`). */
|
|
113
|
+
export function sdkApiUrl(): string {
|
|
114
|
+
return process.env.RECLAIM_SDK_API_URL || DEFAULT_SDK_API_URL
|
|
115
|
+
}
|
|
116
|
+
|
|
104
117
|
/** Builder backend base URL. Shared by mcp/start and the verification tool. */
|
|
105
118
|
export function apiUrl(): string {
|
|
106
119
|
return process.env.RECLAIM_API_URL || DEFAULT_BASE_URL
|