@reclaimprotocol/agent 0.1.5 → 0.1.7
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/lib/authoring/backend.d.ts +0 -24
- package/lib/authoring/find.d.ts +3 -0
- package/lib/authoring/find.js +54 -0
- package/lib/authoring/index.d.ts +3 -3
- package/lib/authoring/index.js +4 -3
- 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 +13 -6
- package/lib/authoring/tools.js +108 -293
- package/lib/authoring/util.d.ts +27 -0
- package/lib/authoring/util.js +21 -0
- package/lib/consts.d.ts +6 -1
- package/lib/consts.js +9 -2
- package/lib/mcp/server.d.ts +2 -41
- package/lib/mcp/server.js +6 -34
- 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/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 +5 -3
- package/lib/mcp/tools/agent/shared.js +29 -19
- package/lib/old/client.d.ts +39 -0
- package/lib/old/client.js +18 -0
- package/lib/old/login-cdp.d.ts +24 -5
- package/lib/old/login-cdp.js +29 -15
- 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 +55 -2
- package/lib/old/tools/authenticate.js +3 -7
- 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 +208 -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/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 +14 -0
- package/lib/tools/registry.js +32 -0
- package/package.json +9 -1
- package/skill/SKILL.builder.md +42 -23
- package/skill/SKILL.old.md +6 -2
- 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/consts.ts +15 -2
- package/src/mcp/server.ts +11 -78
- 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/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 +60 -0
- package/src/old/login-cdp.ts +29 -23
- package/src/old/sdk-client.ts +105 -0
- package/src/old/to-register.ts +102 -6
- package/src/old/tools/authenticate.ts +3 -11
- 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 +264 -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/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
|
@@ -2,8 +2,7 @@ import { mkdirSync, writeFileSync } from 'node:fs';
|
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { agentTraceEnabled } from "../../../consts.js";
|
|
4
4
|
import { reclaimHomeDirPath } from "../../../paths.js";
|
|
5
|
-
import {
|
|
6
|
-
import { defineTool } from "../../server.js";
|
|
5
|
+
import { tailLogs, warnsAndErrors, } from "../../../proof/attestor.js";
|
|
7
6
|
function claimsDir() {
|
|
8
7
|
return join(reclaimHomeDirPath(), 'claims');
|
|
9
8
|
}
|
|
@@ -73,138 +72,88 @@ function isLikelyByteArray(v) {
|
|
|
73
72
|
}
|
|
74
73
|
return true;
|
|
75
74
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
'sentParams the SDK saw post-substitution, ' +
|
|
92
|
-
'FULL attestor log stream, result) to ' +
|
|
93
|
-
'~/.reclaim/proof-runs/<timestamp>.json and ' +
|
|
94
|
-
'returns the path as `runLogPath`. ' +
|
|
95
|
-
'`attestorUrl` overrides the default attestor URL only when the dev ' +
|
|
96
|
-
'supplies a specific ' +
|
|
97
|
-
'alternative — do NOT invent backup URLs ' +
|
|
98
|
-
'(there is one live public attestor right now; ' +
|
|
99
|
-
'surface real errors to the dev instead of guessing). ' +
|
|
100
|
-
'`ownerAddress` (the credential to sign with) is REQUIRED — ' +
|
|
101
|
-
'call resolve_owner_key first to obtain it, then pass it here. ' +
|
|
102
|
-
'errorKind="missing-owner-key" means that address has no known ' +
|
|
103
|
-
'private key; re-run resolve_owner_key or issue/import a credential.',
|
|
104
|
-
inputSchema: {
|
|
105
|
-
type: 'object',
|
|
106
|
-
properties: {
|
|
107
|
-
provider: { type: 'object', properties: {} },
|
|
108
|
-
secretParamsRef: { type: 'string' },
|
|
109
|
-
attestorUrl: { type: 'string' },
|
|
110
|
-
ownerAddress: {
|
|
111
|
-
type: 'string',
|
|
112
|
-
pattern: '^0x[0-9a-fA-F]{40}$',
|
|
113
|
-
description: 'ETH address of the credential to sign the claim with. ' +
|
|
114
|
-
'Get it from resolve_owner_key first. The private key is ' +
|
|
115
|
-
'resolved locally (cache / env / .env) — never passed here.',
|
|
116
|
-
},
|
|
117
|
-
},
|
|
118
|
-
required: ['provider', 'ownerAddress'],
|
|
119
|
-
},
|
|
120
|
-
}, async ({ provider, secretParamsRef, attestorUrl, ownerAddress }) => {
|
|
121
|
-
let resolved = {};
|
|
122
|
-
if (secretParamsRef !== undefined) {
|
|
123
|
-
const r = secrets.resolve(secretParamsRef);
|
|
124
|
-
if (!r) {
|
|
125
|
-
throw new Error(`unknown secretParamsRef "${secretParamsRef}" — ` +
|
|
126
|
-
'the MCP server has restarted or reset_session was called. ' +
|
|
127
|
-
'Re-run propose_provider to mint a fresh ref.');
|
|
128
|
-
}
|
|
129
|
-
resolved = r;
|
|
130
|
-
}
|
|
131
|
-
const result = await runAttestorProof(provider, resolved, { attestorUrl, ownerAddress });
|
|
132
|
-
// Persist the full claim to disk for the dev to inspect/share.
|
|
133
|
-
let claimPath;
|
|
134
|
-
if (result.proof !== undefined && result.proof !== null) {
|
|
135
|
-
try {
|
|
136
|
-
mkdirSync(claimsDir(), { recursive: true });
|
|
137
|
-
claimPath = join(claimsDir(), `${Date.now()}.json`);
|
|
138
|
-
writeFileSync(claimPath, JSON.stringify(result.proof, null, 2), 'utf8');
|
|
139
|
-
}
|
|
140
|
-
catch {
|
|
141
|
-
// Persistence is best-effort; don't fail the proof for it.
|
|
142
|
-
claimPath = undefined;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
const out = {
|
|
146
|
-
verified: result.verified,
|
|
147
|
-
extractedValue: result.extractedValue,
|
|
148
|
-
extractedParameters: result.extractedParameters,
|
|
149
|
-
};
|
|
150
|
-
if (result.identifier !== undefined) {
|
|
151
|
-
out.identifier = result.identifier;
|
|
152
|
-
}
|
|
153
|
-
if (result.owner !== undefined) {
|
|
154
|
-
out.owner = result.owner;
|
|
155
|
-
}
|
|
156
|
-
if (claimPath !== undefined) {
|
|
157
|
-
out.claimPath = claimPath;
|
|
158
|
-
}
|
|
159
|
-
if (result.proof !== undefined && result.proof !== null) {
|
|
160
|
-
out.claim = prettifyClaim(result.proof);
|
|
161
|
-
}
|
|
162
|
-
if (result.error !== undefined) {
|
|
163
|
-
out.error = result.error;
|
|
164
|
-
}
|
|
165
|
-
if (result.errorKind !== undefined) {
|
|
166
|
-
out.errorKind = result.errorKind;
|
|
75
|
+
/**
|
|
76
|
+
* The MCP's rich `run_proof` view: persist the full claim to disk, return
|
|
77
|
+
* identifier + extractedParameters + a prettified claim (request dropped, byte
|
|
78
|
+
* arrays as base64) + trimmed logs, and — under `RECLAIM_AGENT_TRACE=1` — a
|
|
79
|
+
* forensic run dump. This is the developer-facing shape; the cloud backend
|
|
80
|
+
* projects the same {@link ProofResult} to a lean summary instead.
|
|
81
|
+
*/
|
|
82
|
+
export function shapeRichProofResult(result, opts) {
|
|
83
|
+
// Persist the full claim to disk for the dev to inspect/share.
|
|
84
|
+
let claimPath;
|
|
85
|
+
if (result.proof !== undefined && result.proof !== null) {
|
|
86
|
+
try {
|
|
87
|
+
mkdirSync(claimsDir(), { recursive: true });
|
|
88
|
+
claimPath = join(claimsDir(), `${Date.now()}.json`);
|
|
89
|
+
writeFileSync(claimPath, JSON.stringify(result.proof, null, 2), 'utf8');
|
|
167
90
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
? warnsAndErrors(result.attestorLogs)
|
|
172
|
-
: tailLogs(result.attestorLogs);
|
|
173
|
-
if (out.attestorLogs.length === 0) {
|
|
174
|
-
delete out.attestorLogs;
|
|
175
|
-
}
|
|
91
|
+
catch {
|
|
92
|
+
// Persistence is best-effort; don't fail the proof for it.
|
|
93
|
+
claimPath = undefined;
|
|
176
94
|
}
|
|
177
|
-
|
|
178
|
-
|
|
95
|
+
}
|
|
96
|
+
const out = {
|
|
97
|
+
verified: result.verified,
|
|
98
|
+
extractedValue: result.extractedValue,
|
|
99
|
+
extractedParameters: result.extractedParameters,
|
|
100
|
+
};
|
|
101
|
+
if (result.identifier !== undefined) {
|
|
102
|
+
out.identifier = result.identifier;
|
|
103
|
+
}
|
|
104
|
+
if (result.owner !== undefined) {
|
|
105
|
+
out.owner = result.owner;
|
|
106
|
+
}
|
|
107
|
+
if (claimPath !== undefined) {
|
|
108
|
+
out.claimPath = claimPath;
|
|
109
|
+
}
|
|
110
|
+
if (result.proof !== undefined && result.proof !== null) {
|
|
111
|
+
out.claim = prettifyClaim(result.proof);
|
|
112
|
+
}
|
|
113
|
+
if (result.error !== undefined) {
|
|
114
|
+
out.error = result.error;
|
|
115
|
+
}
|
|
116
|
+
if (result.errorKind !== undefined) {
|
|
117
|
+
out.errorKind = result.errorKind;
|
|
118
|
+
}
|
|
119
|
+
// Trim the LLM-visible logs — full stream goes to runLogPath.
|
|
120
|
+
if (result.attestorLogs !== undefined && result.attestorLogs.length > 0) {
|
|
121
|
+
out.attestorLogs = result.verified
|
|
122
|
+
? warnsAndErrors(result.attestorLogs)
|
|
123
|
+
: tailLogs(result.attestorLogs);
|
|
124
|
+
if (out.attestorLogs.length === 0) {
|
|
125
|
+
delete out.attestorLogs;
|
|
179
126
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
127
|
+
}
|
|
128
|
+
if (result.sentParams !== undefined) {
|
|
129
|
+
out.sentParams = result.sentParams;
|
|
130
|
+
}
|
|
131
|
+
// Persist a diagnostic dump for forensics — gated behind
|
|
132
|
+
// RECLAIM_AGENT_TRACE=1 (matches the attestor logger capture). Off by
|
|
133
|
+
// default since happy-path runs don't need it; turn on when investigating
|
|
134
|
+
// proof failures and the file at runLogPath will carry the input provider,
|
|
135
|
+
// sentParams, full attestor log stream, and result.
|
|
136
|
+
if (agentTraceEnabled()) {
|
|
137
|
+
const runLogPath = writeProofRunDump({
|
|
138
|
+
provider: opts.provider,
|
|
139
|
+
hasSecretParamsRef: opts.hasSecrets,
|
|
140
|
+
attestorUrl: opts.attestorUrl,
|
|
141
|
+
result: {
|
|
142
|
+
verified: result.verified,
|
|
143
|
+
error: result.error,
|
|
144
|
+
errorKind: result.errorKind,
|
|
145
|
+
extractedValue: result.extractedValue,
|
|
146
|
+
extractedParameters: result.extractedParameters,
|
|
147
|
+
identifier: result.identifier,
|
|
148
|
+
owner: result.owner,
|
|
149
|
+
sentParams: result.sentParams,
|
|
150
|
+
attestorLogs: result.attestorLogs,
|
|
151
|
+
claimPath,
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
if (runLogPath !== undefined) {
|
|
155
|
+
out.runLogPath = runLogPath;
|
|
207
156
|
}
|
|
208
|
-
|
|
209
|
-
|
|
157
|
+
}
|
|
158
|
+
return out;
|
|
210
159
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
/**
|
|
2
|
+
* `propose_provider` — draft a provider (recipe + captured secrets) from ONE
|
|
3
|
+
* captured request, one match + redaction per target value. Authored once as a
|
|
4
|
+
* plain {@link RegisteredTool}; hosts pass their own backend resolver. The
|
|
5
|
+
* draft (recipe + real secret header values) is held server-side under an
|
|
6
|
+
* opaque `draftId`; the result carries only the secret-free provider.
|
|
7
|
+
*/
|
|
8
|
+
import { type ResolveBackend } from '../../../authoring/util.ts';
|
|
9
|
+
import { type RegisteredTool } from '../../../tools/registry.ts';
|
|
10
|
+
export declare function proposeTool(resolveBackend: ResolveBackend): RegisteredTool;
|
|
@@ -1,85 +1,108 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* `propose_provider` — draft a provider (recipe + captured secrets) from ONE
|
|
3
|
+
* captured request, one match + redaction per target value. Authored once as a
|
|
4
|
+
* plain {@link RegisteredTool}; hosts pass their own backend resolver. The
|
|
5
|
+
* draft (recipe + real secret header values) is held server-side under an
|
|
6
|
+
* opaque `draftId`; the result carries only the secret-free provider.
|
|
7
|
+
*/
|
|
8
|
+
import { objectSchema } from "../../../authoring/util.js";
|
|
2
9
|
import { draftProvider } from "../../../provider/draft.js";
|
|
3
10
|
import { OPRF_MAX_BYTES } from "../../../provider/matcher.js";
|
|
4
11
|
import { verificationWarnings } from "../../../provider/verification-checks.js";
|
|
5
|
-
import { defineTool } from "
|
|
6
|
-
export function
|
|
7
|
-
const map = new Map();
|
|
8
|
-
return {
|
|
9
|
-
put: (values) => {
|
|
10
|
-
const id = `sref_${randomUUID()}`;
|
|
11
|
-
map.set(id, values);
|
|
12
|
-
return id;
|
|
13
|
-
},
|
|
14
|
-
resolve: (ref) => map.get(ref),
|
|
15
|
-
clear: () => map.clear(),
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
|
-
export function proposeTool(captures, secrets) {
|
|
12
|
+
import { defineTool } from "../../../tools/registry.js";
|
|
13
|
+
export function proposeTool(resolveBackend) {
|
|
19
14
|
return defineTool({
|
|
20
15
|
name: 'propose_provider',
|
|
21
|
-
description: 'Draft a
|
|
22
|
-
'
|
|
23
|
-
'
|
|
24
|
-
'
|
|
25
|
-
'
|
|
26
|
-
|
|
27
|
-
'
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
16
|
+
description: 'Draft a provider from ONE captured request. Pass `targets` (an '
|
|
17
|
+
+ 'array): one entry per value to extract, each with its `value` '
|
|
18
|
+
+ '(verbatim) and a distinct `name` (its param). The provider gets '
|
|
19
|
+
+ 'one match + redaction per target. Returns a draftId + recipe '
|
|
20
|
+
+ '(never secrets). Prefer a SINGLE request holding ALL values. '
|
|
21
|
+
+ 'Single-value shorthand: `target` + `name`. Per-target `hash` '
|
|
22
|
+
+ 'OPRF-hashes that value.',
|
|
23
|
+
inputSchema: objectSchema({
|
|
24
|
+
requestId: { type: 'string' },
|
|
25
|
+
name: { type: 'string' },
|
|
26
|
+
targets: {
|
|
27
|
+
type: 'array',
|
|
28
|
+
items: {
|
|
29
|
+
type: 'object',
|
|
30
|
+
properties: {
|
|
31
|
+
value: { type: 'string' },
|
|
32
|
+
name: { type: 'string' },
|
|
33
|
+
hash: {
|
|
34
|
+
type: 'string',
|
|
35
|
+
enum: ['oprf-raw', 'oprf', 'oprf-mpc'],
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
required: ['value', 'name'],
|
|
39
|
+
},
|
|
44
40
|
},
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
41
|
+
target: { type: 'string' },
|
|
42
|
+
hash: { type: 'string', enum: ['oprf-raw', 'oprf', 'oprf-mpc'] },
|
|
43
|
+
}, ['requestId', 'name']),
|
|
44
|
+
}, async (args) => {
|
|
45
|
+
const backend = resolveBackend(args);
|
|
46
|
+
const requestId = String(args.requestId);
|
|
47
|
+
const providerName = String(args.name);
|
|
48
|
+
const defaultHash = args.hash;
|
|
49
|
+
// Explicit multi-value `targets`, else the single `target` shorthand.
|
|
50
|
+
const raw = Array.isArray(args.targets) ? args.targets : [];
|
|
51
|
+
const targets = raw.length
|
|
52
|
+
? raw.map((t) => {
|
|
53
|
+
const o = t;
|
|
54
|
+
return {
|
|
55
|
+
value: String(o.value),
|
|
56
|
+
name: String(o.name),
|
|
57
|
+
...(typeof o.hash === 'string'
|
|
58
|
+
? { hash: o.hash }
|
|
59
|
+
: {}),
|
|
60
|
+
};
|
|
61
|
+
})
|
|
62
|
+
: typeof args.target === 'string'
|
|
63
|
+
? [{
|
|
64
|
+
value: args.target,
|
|
65
|
+
name: providerName,
|
|
66
|
+
...(defaultHash ? { hash: defaultHash } : {}),
|
|
67
|
+
}]
|
|
68
|
+
: [];
|
|
69
|
+
if (targets.length === 0) {
|
|
70
|
+
throw new Error('propose_provider needs a `target` value or a non-empty '
|
|
71
|
+
+ '`targets` array');
|
|
54
72
|
}
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
73
|
+
for (const t of targets) {
|
|
74
|
+
if ((t.hash ?? defaultHash) !== undefined
|
|
75
|
+
&& t.value.length > OPRF_MAX_BYTES) {
|
|
76
|
+
throw new Error(`OPRF caps hashed values at ${OPRF_MAX_BYTES} bytes; got `
|
|
77
|
+
+ `${t.value.length}-byte "${t.value}". Use a tighter `
|
|
78
|
+
+ 'target or drop `hash`.');
|
|
79
|
+
}
|
|
58
80
|
}
|
|
59
|
-
const
|
|
60
|
-
if (!
|
|
61
|
-
throw new Error(`no request ${requestId}`);
|
|
81
|
+
const captured = backend.capture.requests.get(requestId);
|
|
82
|
+
if (!captured) {
|
|
83
|
+
throw new Error(`no captured request ${requestId}`);
|
|
62
84
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
throw new Error(`request body unavailable: ${body.reason}`);
|
|
85
|
+
if (!captured.responseBody) {
|
|
86
|
+
throw new Error(`request body unavailable for ${requestId}`);
|
|
66
87
|
}
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
//
|
|
70
|
-
const
|
|
88
|
+
const { provider, secretRefs, extractions } = draftProvider(captured, targets, providerName, defaultHash);
|
|
89
|
+
// Materialize the real secret header values for later replay/prove;
|
|
90
|
+
// they stay in the server-side draft, never in this result.
|
|
91
|
+
const secrets = {};
|
|
71
92
|
for (const ref of secretRefs) {
|
|
72
|
-
const real =
|
|
93
|
+
const real = captured.requestHeaders[ref.name];
|
|
73
94
|
if (real !== undefined) {
|
|
74
|
-
|
|
95
|
+
secrets[ref.name] = real;
|
|
75
96
|
}
|
|
76
97
|
}
|
|
77
|
-
const
|
|
98
|
+
const draftId = backend.drafts.put({
|
|
99
|
+
provider, secretRefs, secrets, requestId, extractions,
|
|
100
|
+
});
|
|
78
101
|
const warnings = verificationWarnings(provider);
|
|
79
102
|
return {
|
|
103
|
+
draftId,
|
|
80
104
|
provider,
|
|
81
105
|
secretRefs,
|
|
82
|
-
secretParamsRef,
|
|
83
106
|
...(warnings.length ? { verificationWarnings: warnings } : {}),
|
|
84
107
|
};
|
|
85
108
|
});
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/**
|
|
2
|
+
* `replay_request` — validate a drafted recipe before proving: confirm its
|
|
3
|
+
* selectors extract the target(s), and (with `withoutSecrets`) that the
|
|
4
|
+
* endpoint is auth-bound. Authored once as a plain {@link RegisteredTool}; the
|
|
5
|
+
* backend does the actual replay (MCP re-runs locally, cloud re-issues in the
|
|
6
|
+
* TEE pod).
|
|
7
|
+
*/
|
|
8
|
+
import { type ResolveBackend } from '../../../authoring/util.ts';
|
|
9
|
+
import { type RegisteredTool } from '../../../tools/registry.ts';
|
|
10
|
+
export declare function replayTool(resolveBackend: ResolveBackend): RegisteredTool;
|
|
@@ -1,41 +1,34 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/**
|
|
2
|
+
* `replay_request` — validate a drafted recipe before proving: confirm its
|
|
3
|
+
* selectors extract the target(s), and (with `withoutSecrets`) that the
|
|
4
|
+
* endpoint is auth-bound. Authored once as a plain {@link RegisteredTool}; the
|
|
5
|
+
* backend does the actual replay (MCP re-runs locally, cloud re-issues in the
|
|
6
|
+
* TEE pod).
|
|
7
|
+
*/
|
|
8
|
+
import { objectSchema } from "../../../authoring/util.js";
|
|
9
|
+
import { defineTool } from "../../../tools/registry.js";
|
|
10
|
+
export function replayTool(resolveBackend) {
|
|
4
11
|
return defineTool({
|
|
5
12
|
name: 'replay_request',
|
|
6
|
-
description: '
|
|
7
|
-
'
|
|
8
|
-
'
|
|
9
|
-
'
|
|
10
|
-
'
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const r = secrets.resolve(secretParamsRef);
|
|
23
|
-
if (!r) {
|
|
24
|
-
throw new Error(`unknown secretParamsRef "${secretParamsRef}" — ` +
|
|
25
|
-
'the MCP server has restarted or reset_session was called. ' +
|
|
26
|
-
'Re-run propose_provider to mint a fresh ref.');
|
|
27
|
-
}
|
|
28
|
-
resolved = r;
|
|
13
|
+
description: 'Validate the drafted recipe before proving — confirm its selectors '
|
|
14
|
+
+ 'extract the target value. Returns diagnostics; run before '
|
|
15
|
+
+ 'proving. Set `withoutSecrets: true` for the AUTH-BOUND check: it '
|
|
16
|
+
+ 're-issues the request with NO secrets/cookies (an anonymous '
|
|
17
|
+
+ 'visitor). If the values still extract (valid:true), the endpoint '
|
|
18
|
+
+ 'is PUBLIC and the proof would not bind to the user — reject it '
|
|
19
|
+
+ 'and find an auth-bound request instead.',
|
|
20
|
+
inputSchema: objectSchema({
|
|
21
|
+
draftId: { type: 'string' },
|
|
22
|
+
withoutSecrets: { type: 'boolean' },
|
|
23
|
+
}, ['draftId']),
|
|
24
|
+
}, async (args) => {
|
|
25
|
+
const backend = resolveBackend(args);
|
|
26
|
+
const draft = backend.drafts.get(String(args.draftId));
|
|
27
|
+
if (!draft) {
|
|
28
|
+
throw new Error(`no draft ${String(args.draftId)}`);
|
|
29
29
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
matchesOriginal: result.matchesOriginal,
|
|
34
|
-
bodySnippet: result.body.slice(0, 256),
|
|
35
|
-
};
|
|
36
|
-
if (result.hints !== undefined) {
|
|
37
|
-
out.hints = result.hints;
|
|
38
|
-
}
|
|
39
|
-
return out;
|
|
30
|
+
return backend.replay(draft, {
|
|
31
|
+
withoutSecrets: Boolean(args.withoutSecrets),
|
|
32
|
+
});
|
|
40
33
|
});
|
|
41
34
|
}
|
|
@@ -5,6 +5,4 @@ import type { CaptureStore } from './capture.ts';
|
|
|
5
5
|
export declare function sessionTools(attachRef: {
|
|
6
6
|
current?: AttachState;
|
|
7
7
|
config: ConfigStore;
|
|
8
|
-
}, captures: CaptureStore
|
|
9
|
-
clear: () => void;
|
|
10
|
-
}): RegisteredTool[];
|
|
8
|
+
}, captures: CaptureStore): RegisteredTool[];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { defineTool } from "../../server.js";
|
|
2
|
-
export function sessionTools(attachRef, captures
|
|
2
|
+
export function sessionTools(attachRef, captures) {
|
|
3
3
|
return [
|
|
4
4
|
defineTool({
|
|
5
5
|
name: 'get_session',
|
|
@@ -14,15 +14,15 @@ export function sessionTools(attachRef, captures, secrets) {
|
|
|
14
14
|
})),
|
|
15
15
|
defineTool({
|
|
16
16
|
name: 'reset_session',
|
|
17
|
-
description: 'Stop all captures
|
|
17
|
+
description: 'Stop all captures and clear capture state — drops every '
|
|
18
|
+
+ 'session\'s drafts and their in-memory secrets.',
|
|
18
19
|
inputSchema: { type: 'object', properties: {} },
|
|
19
20
|
}, async () => {
|
|
20
|
-
for (const
|
|
21
|
-
await
|
|
21
|
+
for (const entry of captures.sessions.values()) {
|
|
22
|
+
await entry.session.stop().catch(() => { });
|
|
22
23
|
}
|
|
23
24
|
captures.sessions.clear();
|
|
24
25
|
delete captures.activeTab;
|
|
25
|
-
secrets.clear();
|
|
26
26
|
return { reset: true };
|
|
27
27
|
}),
|
|
28
28
|
];
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { RegisteredTool } from '../../server.ts';
|
|
2
2
|
import type { CaptureStore } from './capture.ts';
|
|
3
|
-
/** The shared authoring tools
|
|
4
|
-
*
|
|
5
|
-
* `captureId`
|
|
3
|
+
/** The shared authoring tools mapped to the MCP's shape: resolve each call's
|
|
4
|
+
* local backend from `args.captureId`, and widen the input schema — every tool
|
|
5
|
+
* takes `captureId`; `run_proof` also gets the credential-aware contract. The
|
|
6
|
+
* tools are authored plain in `../../../authoring`; this only wraps them with
|
|
7
|
+
* `extendTool` (handlers untouched — loose arg parse keeps `captureId`). */
|
|
6
8
|
export declare function sharedAuthoringTools(captures: CaptureStore): RegisteredTool[];
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* `start_capture`, since one capture bundles the tab, its requests, and its
|
|
8
8
|
* drafts) and the rich, credential-aware `run_proof` schema.
|
|
9
9
|
*/
|
|
10
|
-
import {
|
|
10
|
+
import { authoringTools, extendTool, } from "../../../authoring/index.js";
|
|
11
11
|
import { runAttestorProof } from "../../../proof/attestor.js";
|
|
12
12
|
import { replayProvider } from "../../../proof/replay.js";
|
|
13
13
|
import { shapeRichProofResult } from "./proof.js";
|
|
@@ -91,25 +91,35 @@ const RUN_PROOF_EXTRAS = {
|
|
|
91
91
|
},
|
|
92
92
|
required: ['ownerAddress'],
|
|
93
93
|
};
|
|
94
|
-
/** The shared authoring tools
|
|
95
|
-
*
|
|
96
|
-
* `captureId`
|
|
94
|
+
/** The shared authoring tools mapped to the MCP's shape: resolve each call's
|
|
95
|
+
* local backend from `args.captureId`, and widen the input schema — every tool
|
|
96
|
+
* takes `captureId`; `run_proof` also gets the credential-aware contract. The
|
|
97
|
+
* tools are authored plain in `../../../authoring`; this only wraps them with
|
|
98
|
+
* `extendTool` (handlers untouched — loose arg parse keeps `captureId`). */
|
|
97
99
|
export function sharedAuthoringTools(captures) {
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
100
|
+
const resolveBackend = (args) => {
|
|
101
|
+
const captureId = String(args.captureId);
|
|
102
|
+
const entry = captures.sessions.get(captureId);
|
|
103
|
+
if (!entry) {
|
|
104
|
+
throw new Error(`no capture ${captureId} — call start_capture first `
|
|
105
|
+
+ '(it has been reset or never started).');
|
|
106
|
+
}
|
|
107
|
+
return localBackend(entry);
|
|
108
|
+
};
|
|
109
|
+
return authoringTools(resolveBackend).map((tool) => {
|
|
110
|
+
if (tool.definition.name === 'run_proof') {
|
|
111
|
+
return extendTool(tool, {
|
|
112
|
+
description: RUN_PROOF_EXTRAS.description,
|
|
113
|
+
properties: {
|
|
114
|
+
captureId: { type: 'string' },
|
|
115
|
+
...RUN_PROOF_EXTRAS.properties,
|
|
116
|
+
},
|
|
117
|
+
required: ['captureId', ...RUN_PROOF_EXTRAS.required],
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
return extendTool(tool, {
|
|
109
121
|
properties: { captureId: { type: 'string' } },
|
|
110
122
|
required: ['captureId'],
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
};
|
|
114
|
-
return buildAuthoringTools(host);
|
|
123
|
+
});
|
|
124
|
+
});
|
|
115
125
|
}
|