@reclaimprotocol/agent 0.1.17 → 0.1.20
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 +6 -2
- package/lib/authoring/backend.d.ts +4 -0
- package/lib/authoring/tools.js +4 -1
- package/lib/cdp/capture.d.ts +2 -2
- package/lib/cdp/capture.js +25 -21
- package/lib/cdp/client.d.ts +39 -1
- package/lib/cdp/client.js +125 -1
- package/lib/consts.d.ts +7 -0
- package/lib/consts.js +15 -0
- package/lib/mcp/api/operations.gen.js +33 -9
- package/lib/mcp/instructions.js +27 -3
- package/lib/mcp/start.js +12 -8
- package/lib/mcp/tools/agent/attach.d.ts +18 -4
- package/lib/mcp/tools/agent/attach.js +142 -52
- package/lib/mcp/tools/agent/build.d.ts +1 -1
- package/lib/mcp/tools/agent/build.js +5 -3
- package/lib/mcp/tools/agent/capture.d.ts +1 -0
- package/lib/mcp/tools/agent/capture.js +8 -1
- package/lib/mcp/tools/agent/eval.js +2 -3
- package/lib/mcp/tools/agent/how-it-works.d.ts +1 -1
- package/lib/mcp/tools/agent/how-it-works.js +1 -1
- package/lib/mcp/tools/agent/publish.js +55 -1
- package/lib/mcp/tools/agent/session.d.ts +2 -2
- package/lib/mcp/tools/agent/session.js +21 -5
- package/lib/mcp/tools/agent/shared.js +4 -6
- package/lib/mcp/tools/authenticate/authenticate.d.ts +1 -1
- package/lib/mcp/tools/authenticate/authenticate.js +10 -4
- package/lib/mcp/tools/authenticate/builder-access.d.ts +8 -0
- package/lib/mcp/tools/authenticate/builder-access.js +31 -0
- package/lib/mcp/tools/authenticate/index.d.ts +1 -0
- package/lib/mcp/tools/authenticate/index.js +1 -0
- package/lib/mcp/tools/mode/mode.d.ts +3 -2
- package/lib/mcp/tools/mode/mode.js +24 -4
- package/lib/old/login-cdp.js +11 -3
- package/lib/old/to-register.d.ts +16 -8
- package/lib/old/to-register.js +29 -21
- package/lib/old/tools/publish.js +109 -9
- package/lib/provider/draft.d.ts +20 -0
- package/lib/provider/draft.js +75 -51
- package/lib/provider/index.d.ts +1 -1
- package/lib/provider/index.js +1 -1
- package/lib/provider/injection-doc.js +4 -3
- package/lib/provider/schema.d.ts +26 -1
- package/lib/provider/secrets.d.ts +37 -0
- package/lib/provider/secrets.js +147 -6
- package/lib/provider/to-version.d.ts +26 -2
- package/lib/provider/to-version.js +29 -5
- package/package.json +2 -2
- package/skill/SKILL.builder.md +43 -95
- package/skill/SKILL.common.md +102 -0
- package/skill/SKILL.old.md +20 -74
- package/skill/builder-mode.md +4 -2
- package/skill/injection-api.md +95 -10
- package/skill/old-mode.md +5 -3
- package/src/authoring/backend.ts +4 -0
- package/src/authoring/tools.ts +4 -1
- package/src/cdp/capture.ts +24 -24
- package/src/cdp/client.ts +197 -2
- package/src/consts.ts +20 -0
- package/src/mcp/api/operations.gen.ts +33 -9
- package/src/mcp/instructions.ts +36 -3
- package/src/mcp/start.ts +13 -8
- package/src/mcp/tools/agent/attach.ts +198 -57
- package/src/mcp/tools/agent/build.ts +9 -2
- package/src/mcp/tools/agent/capture.ts +10 -1
- package/src/mcp/tools/agent/eval.ts +2 -3
- package/src/mcp/tools/agent/how-it-works.ts +1 -1
- package/src/mcp/tools/agent/publish.ts +64 -1
- package/src/mcp/tools/agent/session.ts +29 -8
- package/src/mcp/tools/agent/shared.ts +5 -10
- package/src/mcp/tools/authenticate/authenticate.ts +14 -4
- package/src/mcp/tools/authenticate/builder-access.ts +42 -0
- package/src/mcp/tools/authenticate/index.ts +4 -0
- package/src/mcp/tools/mode/mode.ts +28 -4
- package/src/old/login-cdp.ts +13 -3
- package/src/old/to-register.ts +50 -27
- package/src/old/tools/publish.ts +131 -9
- package/src/provider/draft.ts +98 -56
- package/src/provider/index.ts +9 -1
- package/src/provider/injection-doc.ts +4 -3
- package/src/provider/schema.ts +27 -1
- package/src/provider/secrets.ts +171 -6
- package/src/provider/to-version.ts +53 -7
- package/lib/authoring/find.d.ts +0 -3
- package/lib/authoring/find.js +0 -54
- package/lib/authoring/propose.d.ts +0 -3
- package/lib/authoring/propose.js +0 -109
- package/lib/authoring/replay.d.ts +0 -10
- package/lib/authoring/replay.js +0 -34
- package/lib/cli/args.d.ts +0 -14
- package/lib/cli/args.js +0 -19
- package/lib/cli/commands.d.ts +0 -1
- package/lib/cli/commands.js +0 -19
- package/lib/cli.d.ts +0 -1
- package/lib/cli.js +0 -7
- package/lib/mcp/credentials/authenticate.d.ts +0 -3
- package/lib/mcp/credentials/authenticate.js +0 -108
- package/lib/mcp/credentials/build.d.ts +0 -5
- package/lib/mcp/credentials/build.js +0 -18
- package/lib/mcp/credentials/cache.d.ts +0 -70
- package/lib/mcp/credentials/cache.js +0 -131
- package/lib/mcp/credentials/env-file.d.ts +0 -25
- package/lib/mcp/credentials/env-file.js +0 -71
- package/lib/mcp/credentials/import.d.ts +0 -2
- package/lib/mcp/credentials/import.js +0 -52
- package/lib/mcp/credentials/issue.d.ts +0 -2
- package/lib/mcp/credentials/issue.js +0 -84
- package/lib/mcp/credentials/keypair.d.ts +0 -17
- package/lib/mcp/credentials/keypair.js +0 -48
- package/lib/mcp/credentials/link.d.ts +0 -3
- package/lib/mcp/credentials/link.js +0 -107
- package/lib/mcp/credentials/list-cached.d.ts +0 -2
- package/lib/mcp/credentials/list-cached.js +0 -55
- package/lib/mcp/credentials/owner-key.d.ts +0 -23
- package/lib/mcp/credentials/owner-key.js +0 -58
- package/lib/mcp/credentials/paths.d.ts +0 -12
- package/lib/mcp/credentials/paths.js +0 -35
- package/lib/mcp/credentials/poll.d.ts +0 -27
- package/lib/mcp/credentials/poll.js +0 -61
- package/lib/mcp/credentials/register.d.ts +0 -18
- package/lib/mcp/credentials/register.js +0 -30
- package/lib/mcp/credentials/resolve-owner-key.d.ts +0 -12
- package/lib/mcp/credentials/resolve-owner-key.js +0 -68
- package/lib/mcp/credentials/session-cache.d.ts +0 -14
- package/lib/mcp/credentials/session-cache.js +0 -42
- package/lib/mcp/credentials/status.d.ts +0 -3
- package/lib/mcp/credentials/status.js +0 -76
- package/lib/mcp/register.d.ts +0 -38
- package/lib/mcp/register.js +0 -80
- package/lib/mcp/tools/analyze.d.ts +0 -3
- package/lib/mcp/tools/analyze.js +0 -26
- package/lib/mcp/tools/attach.d.ts +0 -11
- package/lib/mcp/tools/attach.js +0 -72
- package/lib/mcp/tools/capture.d.ts +0 -10
- package/lib/mcp/tools/capture.js +0 -142
- package/lib/mcp/tools/eval.d.ts +0 -5
- package/lib/mcp/tools/eval.js +0 -127
- package/lib/mcp/tools/find.d.ts +0 -3
- package/lib/mcp/tools/find.js +0 -60
- package/lib/mcp/tools/owner-key.d.ts +0 -2
- package/lib/mcp/tools/owner-key.js +0 -63
- package/lib/mcp/tools/proof.d.ts +0 -3
- package/lib/mcp/tools/proof.js +0 -214
- package/lib/mcp/tools/propose.d.ts +0 -9
- package/lib/mcp/tools/propose.js +0 -75
- package/lib/mcp/tools/publish.d.ts +0 -3
- package/lib/mcp/tools/publish.js +0 -59
- package/lib/mcp/tools/replay.d.ts +0 -3
- package/lib/mcp/tools/replay.js +0 -46
- package/lib/mcp/tools/session.d.ts +0 -10
- package/lib/mcp/tools/session.js +0 -29
- package/lib/mcp/tools/verification/diagnose.d.ts +0 -11
- package/lib/mcp/tools/verification/diagnose.js +0 -132
- package/lib/mcp/verifications/build.d.ts +0 -5
- package/lib/mcp/verifications/build.js +0 -14
- package/lib/mcp/verifications/create.d.ts +0 -3
- package/lib/mcp/verifications/create.js +0 -57
- package/lib/mcp/verifications/find.d.ts +0 -3
- package/lib/mcp/verifications/find.js +0 -37
- package/lib/mcp/verifications/get.d.ts +0 -3
- package/lib/mcp/verifications/get.js +0 -26
- package/lib/mcp/verifications/update.d.ts +0 -3
- package/lib/mcp/verifications/update.js +0 -78
- package/lib/old/tools/get-version-config.d.ts +0 -17
- package/lib/old/tools/get-version-config.js +0 -47
- package/lib/routes.gen.d.ts +0 -271
- package/lib/routes.gen.js +0 -73
- package/lib/types/openapi.d.ts +0 -4
- package/lib/types/openapi.gen.d.ts +0 -3967
- package/lib/types/openapi.gen.js +0 -5
- package/lib/types/openapi.js +0 -1
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { ReclaimClient } from '@reclaimprotocol/client'
|
|
2
|
+
import { defineTool, type RegisteredTool } from '../../server.ts'
|
|
3
|
+
import { authenticateTool } from './authenticate.ts'
|
|
4
|
+
|
|
5
|
+
/** Legacy-devtools mode needs a distinct Builder login solely for allocating
|
|
6
|
+
* quota-accounted Popcorn sessions. Builder mode uses its native auth tool. */
|
|
7
|
+
export function buildBuilderAuthenticationTools(
|
|
8
|
+
client: ReclaimClient,
|
|
9
|
+
): RegisteredTool[] {
|
|
10
|
+
return [authenticateTool(client, 'authenticate_builder')]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Legacy-devtools mode lacks generated Builder API tools, so it needs this
|
|
14
|
+
* narrow organization-discovery bridge for remote-browser allocation. */
|
|
15
|
+
export function buildBuilderOrganizationTools(
|
|
16
|
+
client: ReclaimClient,
|
|
17
|
+
): RegisteredTool[] {
|
|
18
|
+
return [
|
|
19
|
+
defineTool<{ cursor?: string }>(
|
|
20
|
+
{
|
|
21
|
+
name: 'list_builder_organizations',
|
|
22
|
+
description:
|
|
23
|
+
'List organizations available to the authenticated Builder user. '
|
|
24
|
+
+ 'Use an organization id from this result when calling '
|
|
25
|
+
+ 'attach_browser with mode="builder". Available only in '
|
|
26
|
+
+ 'legacy-devtools publishing mode; Builder mode uses list_orgs.',
|
|
27
|
+
inputSchema: {
|
|
28
|
+
type: 'object',
|
|
29
|
+
properties: {
|
|
30
|
+
cursor: { type: 'string', maxLength: 500 },
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
async({ cursor }) => {
|
|
35
|
+
const { data } = await client.call('ListOrgs', {
|
|
36
|
+
query: { ...(cursor ? { cursor } : {}) },
|
|
37
|
+
})
|
|
38
|
+
return data
|
|
39
|
+
},
|
|
40
|
+
),
|
|
41
|
+
]
|
|
42
|
+
}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
// Barrel for the credential tool group: local eth proof-owner key (env/PEM)
|
|
2
2
|
// and the org-token-authenticated builder tools. Import from here.
|
|
3
|
+
export {
|
|
4
|
+
buildBuilderAuthenticationTools,
|
|
5
|
+
buildBuilderOrganizationTools,
|
|
6
|
+
} from './builder-access.ts'
|
|
3
7
|
export { buildCredentialTools, buildLocalCredentialTools } from './build.ts'
|
|
4
8
|
export { readSession } from './session-cache.ts'
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type { ConfigStore, DevtoolsMode } from '../../../config/store.ts'
|
|
2
2
|
import { defaultConfigPath } from '../../../config/store.ts'
|
|
3
|
+
import { oldModeSource } from '../../../consts.ts'
|
|
3
4
|
import { defineTool, type RegisteredTool } from '../../server.ts'
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
|
-
* The `set_devtools_mode`
|
|
7
|
-
* (
|
|
7
|
+
* The `set_devtools_mode` / `get_devtools_mode` tools: persist which backend
|
|
8
|
+
* the MCP server targets (`old` devtools vs the `builder`), and
|
|
9
|
+
* report the mode currently in effect. The choice is written to
|
|
8
10
|
* `~/.reclaim/config.json` and applied the NEXT time the server starts —
|
|
9
11
|
* the registered tool set, server instructions, and backend client are all
|
|
10
12
|
* fixed at connect time, so the switch requires a restart/reconnect. Follows
|
|
@@ -25,8 +27,8 @@ export function buildModeTools(
|
|
|
25
27
|
{
|
|
26
28
|
name: 'set_devtools_mode',
|
|
27
29
|
description:
|
|
28
|
-
'Choose which backend the MCP server targets: "old" (
|
|
29
|
-
+ '
|
|
30
|
+
'Choose which backend the MCP server targets: "old" (devtools) '
|
|
31
|
+
+ 'or "builder" (the builder backend). '
|
|
30
32
|
+ 'Persists the choice to ~/.reclaim/config.json; it takes effect '
|
|
31
33
|
+ 'the next time the MCP server starts, so restart/reconnect after '
|
|
32
34
|
+ 'switching. An explicit USE_OLD_DEVTOOLS env var overrides this.',
|
|
@@ -54,5 +56,27 @@ export function buildModeTools(
|
|
|
54
56
|
}
|
|
55
57
|
},
|
|
56
58
|
),
|
|
59
|
+
defineTool<Record<string, never>>(
|
|
60
|
+
{
|
|
61
|
+
name: 'get_devtools_mode',
|
|
62
|
+
description:
|
|
63
|
+
'Report which backend this MCP server is currently targeting: '
|
|
64
|
+
+ '"old" (devtools) or "builder" (the builder '
|
|
65
|
+
+ 'backend). Also reports WHY that mode is in effect (source: '
|
|
66
|
+
+ 'a USE_OLD_DEVTOOLS env override, the persisted config, or '
|
|
67
|
+
+ 'the default) and which mode is persisted for the next '
|
|
68
|
+
+ 'start. Use set_devtools_mode to change it.',
|
|
69
|
+
inputSchema: { type: 'object', properties: {} },
|
|
70
|
+
},
|
|
71
|
+
async() => {
|
|
72
|
+
const persisted = config.read()?.mode
|
|
73
|
+
return {
|
|
74
|
+
mode: current,
|
|
75
|
+
source: oldModeSource(persisted),
|
|
76
|
+
persistedMode: persisted ?? null,
|
|
77
|
+
configPath: defaultConfigPath(),
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
),
|
|
57
81
|
]
|
|
58
82
|
}
|
package/src/old/login-cdp.ts
CHANGED
|
@@ -138,15 +138,14 @@ export async function captureFirebaseTokenViaCdp(opts: {
|
|
|
138
138
|
|
|
139
139
|
try {
|
|
140
140
|
const session = await handles.attachToTab(targetId)
|
|
141
|
-
const { Runtime } = session
|
|
142
141
|
const deadline = Date.now() + timeoutMs
|
|
143
142
|
while(Date.now() < deadline) {
|
|
144
|
-
const
|
|
143
|
+
const result = await session.send('Runtime.evaluate', {
|
|
145
144
|
expression: EXTRACT_TOKEN_JS,
|
|
146
145
|
awaitPromise: true,
|
|
147
146
|
returnByValue: true,
|
|
148
147
|
})
|
|
149
|
-
const value =
|
|
148
|
+
const value = runtimeResultValue(result)
|
|
150
149
|
if(typeof value === 'string' && value.length > 0) {
|
|
151
150
|
return { token: value, closedBrowser: launchedByUs }
|
|
152
151
|
}
|
|
@@ -173,3 +172,14 @@ export async function captureFirebaseTokenViaCdp(opts: {
|
|
|
173
172
|
await handles.close().catch(() => {})
|
|
174
173
|
}
|
|
175
174
|
}
|
|
175
|
+
|
|
176
|
+
function runtimeResultValue(value: unknown): unknown {
|
|
177
|
+
if(typeof value !== 'object' || !value || !('result' in value)) {
|
|
178
|
+
return undefined
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const result = value.result
|
|
182
|
+
return typeof result === 'object' && result && 'value' in result
|
|
183
|
+
? result.value
|
|
184
|
+
: undefined
|
|
185
|
+
}
|
package/src/old/to-register.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import assert from 'node:assert'
|
|
1
2
|
import type { ReclaimProvider } from '../provider/schema.ts'
|
|
2
3
|
import type { AllowedJsRequest, DraftRequest } from '../provider/to-version.ts'
|
|
3
4
|
import type {
|
|
@@ -6,7 +7,7 @@ import type {
|
|
|
6
7
|
} from './client.ts'
|
|
7
8
|
|
|
8
9
|
/** Default web settings, mirroring the builder openapi defaults
|
|
9
|
-
* (`ProviderWebSettings.geoLocation`, `PortalClientOptions.useProxy`). The
|
|
10
|
+
* (`ProviderWebSettings.geoLocation`, `PortalClientOptions.useProxy`). The
|
|
10
11
|
* backend accepts both: `geoLocation` lives on the providerConfig, `useProxy`
|
|
11
12
|
* is a Provider-level flag (register only). */
|
|
12
13
|
const DEFAULT_GEO_LOCATION = '{{DYNAMIC_GEO}}'
|
|
@@ -14,15 +15,15 @@ const DEFAULT_USE_PROXY = true
|
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Translate a drafted `ReclaimProvider` (from `propose_provider`) into the
|
|
17
|
-
*
|
|
18
|
+
* devtools backend shapes. Deliberately a SEPARATE module from
|
|
18
19
|
* `provider/to-version.ts` (the builder translator) — the two backends have
|
|
19
20
|
* structurally different bodies:
|
|
20
21
|
*
|
|
21
22
|
* - builder NESTS each redaction into its match's `extract`;
|
|
22
|
-
* -
|
|
23
|
+
* - devtools keeps `responseMatches` and `responseRedactions` as
|
|
23
24
|
* PARALLEL arrays on each `requestData` entry.
|
|
24
25
|
*
|
|
25
|
-
*
|
|
26
|
+
* Devtools limit we enforce here (a clear error beats a confusing
|
|
26
27
|
* server-side 400): only `GET` / `POST` methods. OPRF redactions are passed
|
|
27
28
|
* through unchanged — the backend's `hash` field accepts them.
|
|
28
29
|
*/
|
|
@@ -35,7 +36,7 @@ export interface OldProviderOpts {
|
|
|
35
36
|
/** Defaults to `true` when omitted. Register only (Provider-level flag). */
|
|
36
37
|
useProxy?: boolean
|
|
37
38
|
providerType?: 'PRIVATE' | 'PUBLIC'
|
|
38
|
-
/** Page-injection script —
|
|
39
|
+
/** Page-injection script — the devtools name for the builder's
|
|
39
40
|
* `webSettings.jsUserScripts`. Top-level on register, nested under
|
|
40
41
|
* `providerConfig` on config (add-version). The backend rejects a few
|
|
41
42
|
* deprecated injection APIs (e.g. `window.payloadData`) with a 400. */
|
|
@@ -59,6 +60,14 @@ export interface OldProviderOpts {
|
|
|
59
60
|
/** Config (add-version) ONLY — the register endpoint never reads this
|
|
60
61
|
* field from the request body. Free-form JSON. */
|
|
61
62
|
extensionConfig?: unknown
|
|
63
|
+
/** Provider-level `disableRequestReplay` (HAWKEYE document replay skip).
|
|
64
|
+
* Config (add-version) ONLY: the register endpoint hardcodes it to false
|
|
65
|
+
* — the publish tool follows a register up with an add-version call to
|
|
66
|
+
* apply it for new providers (see `old/tools/publish.ts`). NOTE the
|
|
67
|
+
* builder backend has NO equivalent; its inverse is
|
|
68
|
+
* `webSettings.clientOptions.inapp.interceptorOptions
|
|
69
|
+
* .isDocumentRequestReplayEnabled`. */
|
|
70
|
+
disableRequestReplay?: boolean
|
|
62
71
|
}
|
|
63
72
|
|
|
64
73
|
interface OldResponseMatch {
|
|
@@ -80,11 +89,11 @@ interface OldResponseRedaction {
|
|
|
80
89
|
|
|
81
90
|
interface OldRequestData {
|
|
82
91
|
url: string
|
|
83
|
-
urlType: 'CONSTANT' | 'TEMPLATE'
|
|
92
|
+
urlType: 'REGEX' | 'CONSTANT' | 'TEMPLATE'
|
|
84
93
|
method: 'GET' | 'POST'
|
|
85
94
|
responseMatches: OldResponseMatch[]
|
|
86
95
|
responseRedactions: OldResponseRedaction[]
|
|
87
|
-
credentials: 'include'
|
|
96
|
+
credentials: 'omit' | 'same-origin' | 'include'
|
|
88
97
|
bodySniff?: { enabled: boolean, template: string }
|
|
89
98
|
}
|
|
90
99
|
|
|
@@ -103,36 +112,42 @@ export interface OldInjectedRequestData extends OldRequestData {
|
|
|
103
112
|
* entries — a `ReclaimProvider` satisfies it structurally either way. */
|
|
104
113
|
function requestDataFromProvider(provider: DraftRequest): OldRequestData {
|
|
105
114
|
const method = String(provider.method).toUpperCase()
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
115
|
+
assert(
|
|
116
|
+
method === 'GET' || method === 'POST',
|
|
117
|
+
new Error(
|
|
118
|
+
'Devtools supports only GET/POST requests; got ' +
|
|
109
119
|
`"${provider.method}". Re-capture against a GET/POST endpoint.`,
|
|
110
120
|
)
|
|
111
|
-
|
|
121
|
+
)
|
|
112
122
|
|
|
113
|
-
// The
|
|
123
|
+
// The devtools backend has no dotted interpolation: consumer-supplied params
|
|
114
124
|
// must use the `{{context_<name>}}` form here, not the builder's
|
|
115
125
|
// `{{context.<name>}}`. Catch the mix-up at publish with a clear error
|
|
116
126
|
// instead of a template that silently never resolves.
|
|
117
127
|
const dotted = `${provider.url}\n${provider.body ?? ''}`
|
|
118
128
|
.match(/\{\{context\.[A-Za-z_][A-Za-z0-9_]*\}\}/)
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
129
|
+
assert(
|
|
130
|
+
!dotted,
|
|
131
|
+
new Error(
|
|
132
|
+
`Devtools does not support ${dotted?.[0]} — rename ` +
|
|
122
133
|
'consumer-supplied params to the {{context_<name>}} form ' +
|
|
123
134
|
'for this backend.',
|
|
124
135
|
)
|
|
125
|
-
|
|
136
|
+
)
|
|
126
137
|
|
|
127
138
|
const responseMatches: OldResponseMatch[] = (provider.responseMatches ?? [])
|
|
128
139
|
.map((m, i) => ({
|
|
129
140
|
value: m.value,
|
|
130
141
|
type: m.type ?? 'contains',
|
|
131
|
-
isOptional
|
|
142
|
+
// The backend honors isOptional on BOTH register and add-version
|
|
143
|
+
// (responseMatches pass through verbatim) — forward the author's
|
|
144
|
+
// flag, default false. (`invert` has no old-backend equivalent and
|
|
145
|
+
// stays dropped.)
|
|
146
|
+
isOptional: m.isOptional ?? false,
|
|
132
147
|
order: i,
|
|
133
148
|
}))
|
|
134
149
|
|
|
135
|
-
//
|
|
150
|
+
// Devtools wants `responseMatches` and `responseRedactions` as PARALLEL
|
|
136
151
|
// arrays — same shape the builder uses, so pass them through directly. We do
|
|
137
152
|
// NOT enforce any match/redaction count relationship here (and never pad —
|
|
138
153
|
// empty placeholder matches break proof generation): the author keeps full
|
|
@@ -166,36 +181,38 @@ function requestDataFromProvider(provider: DraftRequest): OldRequestData {
|
|
|
166
181
|
|
|
167
182
|
const requestData: OldRequestData = {
|
|
168
183
|
url: provider.url,
|
|
169
|
-
// `{{param}}` placeholders → TEMPLATE
|
|
170
|
-
//
|
|
171
|
-
urlType: provider.
|
|
184
|
+
// Explicit override wins; otherwise `{{param}}` placeholders → TEMPLATE
|
|
185
|
+
// so the backend templates them, else a fixed CONSTANT url.
|
|
186
|
+
urlType: provider.urlType
|
|
187
|
+
?? (provider.url.includes('{{') ? 'TEMPLATE' : 'CONSTANT'),
|
|
172
188
|
method: method,
|
|
173
189
|
responseMatches,
|
|
174
190
|
responseRedactions,
|
|
175
191
|
// The verification client re-supplies cookies/auth at runtime; secrets
|
|
176
192
|
// are never persisted (propose_provider already stripped them).
|
|
177
|
-
credentials: 'include',
|
|
193
|
+
credentials: provider.credentials ?? 'include',
|
|
178
194
|
}
|
|
179
195
|
if(provider.body !== undefined) {
|
|
180
196
|
requestData.bodySniff = { enabled: true, template: provider.body }
|
|
181
197
|
}
|
|
182
198
|
|
|
183
|
-
// NOTE: `responseVariables` is intentionally omitted — the
|
|
199
|
+
// NOTE: `responseVariables` is intentionally omitted — the devtools backend
|
|
184
200
|
// auto-extracts it from `{{var}}` placeholders in responseMatches. Sending
|
|
185
201
|
// it ourselves would risk drifting from the server's own extraction.
|
|
186
202
|
return requestData
|
|
187
203
|
}
|
|
188
204
|
|
|
189
205
|
/** One `requestData` entry per drafted provider. A multi-request provider
|
|
190
|
-
* becomes parallel entries that the
|
|
191
|
-
* (the same way the builder version carries multiple
|
|
206
|
+
* becomes parallel entries that the devtools backend runs together at
|
|
207
|
+
* verification (the same way the builder version carries multiple
|
|
208
|
+
* `requests`). */
|
|
192
209
|
function requestDataFrom(providers: ReclaimProvider[]): OldRequestData[] {
|
|
193
210
|
return providers.map(requestDataFromProvider)
|
|
194
211
|
}
|
|
195
212
|
|
|
196
213
|
/** Translate fresh `allowedInjectedRequestData` drafts (the author's input
|
|
197
214
|
* shape, `AllowedJsRequest[]` — same shape the builder translator uses for
|
|
198
|
-
* its own `allowedJsRequests`) into the
|
|
215
|
+
* its own `allowedJsRequests`) into the devtools backend's shape. A
|
|
199
216
|
* carried-forward value read back from an existing version is ALREADY in
|
|
200
217
|
* this shape and should be passed straight through instead — don't run it
|
|
201
218
|
* through this a second time. */
|
|
@@ -300,10 +317,16 @@ export function providerToConfigBody(
|
|
|
300
317
|
providerConfig.extensionConfig = opts.extensionConfig
|
|
301
318
|
}
|
|
302
319
|
|
|
320
|
+
// The config (add-version) controller persists providerConfig verbatim,
|
|
321
|
+
// so this lands as-is; the register controller ignores it entirely.
|
|
322
|
+
if(opts.disableRequestReplay !== undefined) {
|
|
323
|
+
providerConfig.disableRequestReplay = opts.disableRequestReplay
|
|
324
|
+
}
|
|
325
|
+
|
|
303
326
|
return { providerConfig, version, versionInfo }
|
|
304
327
|
}
|
|
305
328
|
|
|
306
|
-
/** Minimal version triplet as the
|
|
329
|
+
/** Minimal version triplet as the devtools backend stores it. */
|
|
307
330
|
export interface SemverTriplet {
|
|
308
331
|
major: number
|
|
309
332
|
minor: number
|
package/src/old/tools/publish.ts
CHANGED
|
@@ -19,6 +19,16 @@ import {
|
|
|
19
19
|
|
|
20
20
|
const DEFAULT_VERSION_INFO = 'Updated from MCP browser capture'
|
|
21
21
|
|
|
22
|
+
/** Pull the new provider's id out of a register response, tolerant of the
|
|
23
|
+
* envelope (`{providerId}`, `{provider:{providerId}}`, `{id}`). */
|
|
24
|
+
function extractProviderId(resp: unknown): string | undefined {
|
|
25
|
+
const obj = resp as
|
|
26
|
+
{ providerId?: string, provider?: { providerId?: string }, id?: string }
|
|
27
|
+
| null
|
|
28
|
+
| undefined
|
|
29
|
+
return obj?.providerId ?? obj?.provider?.providerId ?? obj?.id
|
|
30
|
+
}
|
|
31
|
+
|
|
22
32
|
/**
|
|
23
33
|
* The old backend lets you add a version only to a provider YOU own. A
|
|
24
34
|
* `providerId` for a public provider (or anyone else's) comes back as
|
|
@@ -81,11 +91,12 @@ export function createVersionFromCaptureTool(
|
|
|
81
91
|
stepsToFollow?: string
|
|
82
92
|
useIncognitoWebview?: boolean
|
|
83
93
|
extensionConfig?: unknown
|
|
94
|
+
disableRequestReplay?: boolean
|
|
84
95
|
}>(
|
|
85
96
|
{
|
|
86
97
|
name: 'create_provider_version_from_capture',
|
|
87
98
|
description:
|
|
88
|
-
'Publish drafted ReclaimProvider(s) to the
|
|
99
|
+
'Publish drafted ReclaimProvider(s) to the devtools backend. ' +
|
|
89
100
|
'Pass the `provider` object from propose_provider VERBATIM and the ' +
|
|
90
101
|
'`initialUrl` the user landed on (the login/landing page, NOT the ' +
|
|
91
102
|
'API url). \n\n' +
|
|
@@ -103,7 +114,7 @@ export function createVersionFromCaptureTool(
|
|
|
103
114
|
"PUBLIC provider you don't own, omit `providerId` to register your " +
|
|
104
115
|
'own copy (you cannot edit someone else\'s provider here). \n\n' +
|
|
105
116
|
'For data gated behind login/navigation, pass `customInjection` — a ' +
|
|
106
|
-
'page-injection script (
|
|
117
|
+
'page-injection script (the devtools name for the builder\'s ' +
|
|
107
118
|
'jsUserScripts) that drives the page to where the request fires. \n\n' +
|
|
108
119
|
'BY DESIGN, this backend only ever CREATES A NEW VERSION (POST) — ' +
|
|
109
120
|
'there is no partial-patch/edit endpoint, and this tool does NOT ' +
|
|
@@ -120,7 +131,14 @@ export function createVersionFromCaptureTool(
|
|
|
120
131
|
'values plus your change) back into this call. ' +
|
|
121
132
|
'`allowedInjectedRequestData`/`useIncognitoWebview`/' +
|
|
122
133
|
'`extensionConfig` only take effect on add-version — the register ' +
|
|
123
|
-
'endpoint (no `providerId`) ignores them.
|
|
134
|
+
'endpoint (no `providerId`) ignores them. `disableRequestReplay` ' +
|
|
135
|
+
'is also add-version-only, but when it is true the tool follows ' +
|
|
136
|
+
'a register up with an add-version call automatically so it takes ' +
|
|
137
|
+
'effect on new providers too. Per-request fields you may set on ' +
|
|
138
|
+
'`provider`/`providers`: `credentials` (omit/same-origin/include, ' +
|
|
139
|
+
'default include), `urlType` (REGEX/CONSTANT/TEMPLATE, default ' +
|
|
140
|
+
'derived from {{placeholders}}), and `isOptional` on each ' +
|
|
141
|
+
'responseMatch (default false). \n\n' +
|
|
124
142
|
'Captured requests must be GET/POST. OPRF redactions are supported.',
|
|
125
143
|
inputSchema: {
|
|
126
144
|
type: 'object',
|
|
@@ -136,6 +154,21 @@ export function createVersionFromCaptureTool(
|
|
|
136
154
|
method: { type: 'string' },
|
|
137
155
|
headers: { type: 'object' },
|
|
138
156
|
body: { type: 'string' },
|
|
157
|
+
credentials: {
|
|
158
|
+
type: 'string',
|
|
159
|
+
enum: ['omit', 'same-origin', 'include'],
|
|
160
|
+
description:
|
|
161
|
+
'How the verification client supplies cookies/auth ' +
|
|
162
|
+
'when replaying this request. Default `include`.',
|
|
163
|
+
},
|
|
164
|
+
urlType: {
|
|
165
|
+
type: 'string',
|
|
166
|
+
enum: ['REGEX', 'CONSTANT', 'TEMPLATE'],
|
|
167
|
+
description:
|
|
168
|
+
'How the backend treats the URL. Default derived: ' +
|
|
169
|
+
'TEMPLATE when the URL has {{placeholders}}, else ' +
|
|
170
|
+
'CONSTANT.',
|
|
171
|
+
},
|
|
139
172
|
responseMatches: { type: 'array' },
|
|
140
173
|
responseRedactions: { type: 'array' },
|
|
141
174
|
paramValues: { type: 'object' },
|
|
@@ -165,6 +198,14 @@ export function createVersionFromCaptureTool(
|
|
|
165
198
|
method: { type: 'string' },
|
|
166
199
|
headers: { type: 'object' },
|
|
167
200
|
body: { type: 'string' },
|
|
201
|
+
credentials: {
|
|
202
|
+
type: 'string',
|
|
203
|
+
enum: ['omit', 'same-origin', 'include'],
|
|
204
|
+
},
|
|
205
|
+
urlType: {
|
|
206
|
+
type: 'string',
|
|
207
|
+
enum: ['REGEX', 'CONSTANT', 'TEMPLATE'],
|
|
208
|
+
},
|
|
168
209
|
responseMatches: { type: 'array' },
|
|
169
210
|
responseRedactions: { type: 'array' },
|
|
170
211
|
paramValues: { type: 'object' },
|
|
@@ -247,12 +288,42 @@ export function createVersionFromCaptureTool(
|
|
|
247
288
|
'the whole payload), template just that part with ' +
|
|
248
289
|
'`{{paramName}}` and keep the rest as fixed literal text; see ' +
|
|
249
290
|
'the "bodySniff" section of the customInjection field\'s guide ' +
|
|
250
|
-
'for the exact mechanics and a worked example.'
|
|
291
|
+
'for the exact mechanics and a worked example. ' +
|
|
292
|
+
'⚠️ BEFORE populating this to gate ' +
|
|
293
|
+
'`verifyProof(proof, { providerId })`: this whole entry (url, ' +
|
|
294
|
+
'method, body, responseMatches, responseRedactions) feeds a ' +
|
|
295
|
+
'client-side hash-equality check, and `url` is hashed VERBATIM ' +
|
|
296
|
+
'— no regex/template resolution, even with `urlType: REGEX` or ' +
|
|
297
|
+
'`TEMPLATE`. If the real captured URL contains ANY per-session ' +
|
|
298
|
+
'part (a tracking nonce, CSRF token, cache-busting timestamp), ' +
|
|
299
|
+
'no declared spec can EVER hash-match a real proof, no matter ' +
|
|
300
|
+
'how correct the rest of this entry is — populating' +
|
|
301
|
+
'it for such ' +
|
|
302
|
+
'a provider makes verifyProof reject every real proof,' +
|
|
303
|
+
'which is ' +
|
|
304
|
+
'worse than leaving this field empty. Diff the same endpoint\'s' +
|
|
305
|
+
' captured URL across two separate sessions before wiring this ' +
|
|
306
|
+
'up. If provider-hash validation keeps causing problems ' +
|
|
307
|
+
'(unstable url, or any other persistent mismatch), the ' +
|
|
308
|
+
'fallback on the verifying side is `verifyProof(proof, { ' +
|
|
309
|
+
'dangerouslyDisableContentValidation: true })` — trusts only ' +
|
|
310
|
+
'the attestor\'s signature, skips the hash-equality check ' +
|
|
311
|
+
'entirely; see the "Provider-hash validation" section of the ' +
|
|
312
|
+
'customInjection field\'s guide for the full mechanics and ' +
|
|
313
|
+
'when to reach for it.',
|
|
251
314
|
items: {
|
|
252
315
|
type: 'object',
|
|
253
316
|
properties: {
|
|
254
317
|
url: { type: 'string' },
|
|
255
318
|
method: { type: 'string' },
|
|
319
|
+
urlType: {
|
|
320
|
+
type: 'string',
|
|
321
|
+
enum: ['REGEX', 'CONSTANT', 'TEMPLATE'],
|
|
322
|
+
description:
|
|
323
|
+
'How the backend treats this URL. Default derived ' +
|
|
324
|
+
'from {{placeholders}} (TEMPLATE) like a normal ' +
|
|
325
|
+
'request entry.',
|
|
326
|
+
},
|
|
256
327
|
body: {
|
|
257
328
|
type: 'string',
|
|
258
329
|
description:
|
|
@@ -375,6 +446,15 @@ export function createVersionFromCaptureTool(
|
|
|
375
446
|
'Free-form JSON passed through to the client. Add-version ' +
|
|
376
447
|
'ONLY.',
|
|
377
448
|
},
|
|
449
|
+
disableRequestReplay: {
|
|
450
|
+
type: 'boolean',
|
|
451
|
+
description:
|
|
452
|
+
'Skip replaying the main document request (HAWKEYE ' +
|
|
453
|
+
'provider-level flag). Honored on add-version; for a ' +
|
|
454
|
+
'provider (no `providerId`) the register endpoint ignores ' +
|
|
455
|
+
'it, so when true the tool automatically follows the ' +
|
|
456
|
+
'register up with an add-version call that applies it.',
|
|
457
|
+
},
|
|
378
458
|
},
|
|
379
459
|
required: ['initialUrl'],
|
|
380
460
|
},
|
|
@@ -413,6 +493,7 @@ export function createVersionFromCaptureTool(
|
|
|
413
493
|
stepsToFollow: args.stepsToFollow,
|
|
414
494
|
useIncognitoWebview: args.useIncognitoWebview,
|
|
415
495
|
extensionConfig: args.extensionConfig,
|
|
496
|
+
disableRequestReplay: args.disableRequestReplay,
|
|
416
497
|
allowedInjectedRequestData: args.allowedInjectedRequestData
|
|
417
498
|
? injectedRequestDataFrom(
|
|
418
499
|
args.allowedInjectedRequestData,
|
|
@@ -448,6 +529,12 @@ export function createVersionFromCaptureTool(
|
|
|
448
529
|
)
|
|
449
530
|
}
|
|
450
531
|
|
|
532
|
+
// disableRequestReplay is honored ONLY on add-version, so a
|
|
533
|
+
// register can't set it — when true we immediately follow the
|
|
534
|
+
// register with an add-version call (which also lands any other
|
|
535
|
+
// register-ignored fields).
|
|
536
|
+
const followUp = args.disableRequestReplay === true
|
|
537
|
+
|
|
451
538
|
const REGISTER_IGNORED_KEYS = [
|
|
452
539
|
'allowedInjectedRequestData',
|
|
453
540
|
'useIncognitoWebview',
|
|
@@ -459,15 +546,50 @@ export function createVersionFromCaptureTool(
|
|
|
459
546
|
notes.push(
|
|
460
547
|
`${ignoredOnRegister.join(', ')} ` +
|
|
461
548
|
`${ignoredOnRegister.length > 1 ? 'are' : 'is'} ` +
|
|
462
|
-
'ignored on register (no providerId) — the
|
|
463
|
-
'reads them when adding a version.
|
|
464
|
-
|
|
465
|
-
|
|
549
|
+
'ignored on register (no providerId) — the devtools backend only ' +
|
|
550
|
+
'reads them when adding a version. ' +
|
|
551
|
+
(followUp
|
|
552
|
+
? 'They were applied by the follow-up version the tool ' +
|
|
553
|
+
'created to set disableRequestReplay.'
|
|
554
|
+
: 'Publish once to create the provider, then call this ' +
|
|
555
|
+
'again WITH the returned providerId to set them.'),
|
|
466
556
|
)
|
|
467
557
|
}
|
|
468
558
|
|
|
469
559
|
const body = providerToRegisterBody(providers, opts)
|
|
470
|
-
|
|
560
|
+
const registered = await client.registerProvider(body)
|
|
561
|
+
|
|
562
|
+
if(followUp) {
|
|
563
|
+
const newProviderId = extractProviderId(registered)
|
|
564
|
+
if(newProviderId) {
|
|
565
|
+
const versionsResp = await client.listVersions(newProviderId)
|
|
566
|
+
const followVersion = bumpPatchString(
|
|
567
|
+
extractVersions(versionsResp),
|
|
568
|
+
)
|
|
569
|
+
const configBody = providerToConfigBody(
|
|
570
|
+
providers,
|
|
571
|
+
{ ...opts, disableRequestReplay: true },
|
|
572
|
+
followVersion,
|
|
573
|
+
DEFAULT_VERSION_INFO,
|
|
574
|
+
)
|
|
575
|
+
await client.updateProviderConfig(newProviderId, configBody)
|
|
576
|
+
notes.push(
|
|
577
|
+
'disableRequestReplay is ignored by the register endpoint — ' +
|
|
578
|
+
`applied it via a follow-up version (${followVersion}) on ` +
|
|
579
|
+
'the new provider, which also lands any register-ignored ' +
|
|
580
|
+
'fields you passed.',
|
|
581
|
+
)
|
|
582
|
+
} else {
|
|
583
|
+
notes.push(
|
|
584
|
+
'Could not apply disableRequestReplay: the register ' +
|
|
585
|
+
'response did not include the new providerId. Call this ' +
|
|
586
|
+
'tool again WITH `providerId` and `disableRequestReplay: ' +
|
|
587
|
+
'true` to set it.',
|
|
588
|
+
)
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
return withNotes(registered)
|
|
471
593
|
}
|
|
472
594
|
|
|
473
595
|
// New version of an existing provider — pick the next patch above
|