@reclaimprotocol/agent 0.1.18 → 0.1.21
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/mcp/api/operations.gen.js +33 -9
- package/lib/mcp/instructions.js +27 -3
- package/lib/mcp/remap_errors.js +2 -1
- package/lib/mcp/start.js +16 -9
- 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 +9 -2
- package/lib/mcp/tools/agent/build.js +15 -7
- 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/index.d.ts +1 -1
- package/lib/mcp/tools/agent/index.js +1 -1
- package/lib/mcp/tools/agent/publish.d.ts +4 -1
- package/lib/mcp/tools/agent/publish.js +42 -3
- 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 +13 -6
- 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/old/login-cdp.js +11 -3
- package/lib/old/tools/build.d.ts +8 -1
- package/lib/old/tools/build.js +6 -2
- package/lib/old/tools/publish.d.ts +10 -1
- package/lib/old/tools/publish.js +49 -3
- 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/secrets.d.ts +37 -0
- package/lib/provider/secrets.js +147 -6
- package/lib/provider/to-version.d.ts +7 -0
- package/lib/provider/to-version.js +11 -1
- package/package.json +2 -2
- package/skill/SKILL.builder.md +44 -94
- package/skill/SKILL.common.md +102 -0
- package/skill/SKILL.old.md +21 -73
- package/skill/builder-mode.md +2 -2
- package/skill/injection-api.md +95 -10
- package/skill/old-mode.md +2 -2
- 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/mcp/api/operations.gen.ts +33 -9
- package/src/mcp/instructions.ts +36 -3
- package/src/mcp/remap_errors.ts +2 -1
- package/src/mcp/start.ts +24 -9
- package/src/mcp/tools/agent/attach.ts +198 -57
- package/src/mcp/tools/agent/build.ts +20 -6
- 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/index.ts +1 -1
- package/src/mcp/tools/agent/publish.ts +46 -2
- 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 +17 -9
- package/src/mcp/tools/authenticate/builder-access.ts +42 -0
- package/src/mcp/tools/authenticate/index.ts +4 -0
- package/src/old/login-cdp.ts +13 -3
- package/src/old/tools/build.ts +7 -1
- package/src/old/tools/publish.ts +55 -4
- package/src/provider/draft.ts +98 -56
- package/src/provider/index.ts +9 -1
- package/src/provider/secrets.ts +171 -6
- package/src/provider/to-version.ts +12 -1
- 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
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
// How long to poll before giving up and telling the user what to do.
|
|
2
|
-
// Shorter than the 15-min server TTL on purpose — agents can't block long.
|
|
3
|
-
const POLL_TIMEOUT_MS = 3 * 60_000; // 3 minutes
|
|
4
|
-
const POLL_INTERVAL_MS = 5_000; // 5 seconds
|
|
5
|
-
const MAX_CONSECUTIVE_ERRORS = 5;
|
|
6
|
-
/**
|
|
7
|
-
* Poll GET /credentials/attach/sessions/{code} until the session is
|
|
8
|
-
* LINKED or we give up, whichever comes first.
|
|
9
|
-
*
|
|
10
|
-
* Errors inside the loop are surfaced immediately after MAX_CONSECUTIVE_ERRORS
|
|
11
|
-
* rather than being silently swallowed — this is what tells the agent that
|
|
12
|
-
* e.g. the confirmation POST failed or the server restarted.
|
|
13
|
-
*/
|
|
14
|
-
export async function pollUntilLinked(client, session, onToken) {
|
|
15
|
-
const sessionExpiry = new Date(session.expiresAt).getTime();
|
|
16
|
-
const deadline = Math.min(sessionExpiry, Date.now() + POLL_TIMEOUT_MS);
|
|
17
|
-
const startedAt = Date.now();
|
|
18
|
-
let consecutiveErrors = 0;
|
|
19
|
-
while (Date.now() < deadline) {
|
|
20
|
-
await new Promise(r => setTimeout(r, POLL_INTERVAL_MS));
|
|
21
|
-
let polled;
|
|
22
|
-
try {
|
|
23
|
-
polled = await client.call('GetAttachSession', {
|
|
24
|
-
params: { code: session.code },
|
|
25
|
-
query: {}, body: {},
|
|
26
|
-
});
|
|
27
|
-
consecutiveErrors = 0;
|
|
28
|
-
}
|
|
29
|
-
catch (err) {
|
|
30
|
-
consecutiveErrors++;
|
|
31
|
-
if (consecutiveErrors >= MAX_CONSECUTIVE_ERRORS) {
|
|
32
|
-
return {
|
|
33
|
-
outcome: 'error',
|
|
34
|
-
message: `Polling failed ${consecutiveErrors} times in a row: `
|
|
35
|
-
+ err.message
|
|
36
|
-
+ '. The session confirmation may have failed — try opening '
|
|
37
|
-
+ session.attachUrl
|
|
38
|
-
+ ' again and confirming, then retry.',
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
continue; // transient error, retry
|
|
42
|
-
}
|
|
43
|
-
if (polled.status === 'LINKED') {
|
|
44
|
-
const token = polled.token?.trim();
|
|
45
|
-
if (token) {
|
|
46
|
-
onToken?.(token);
|
|
47
|
-
}
|
|
48
|
-
return {
|
|
49
|
-
outcome: 'linked',
|
|
50
|
-
token,
|
|
51
|
-
orgId: polled.linkedOrgId,
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
if (polled.status === 'EXPIRED') {
|
|
55
|
-
return { outcome: 'expired' };
|
|
56
|
-
}
|
|
57
|
-
// status === 'PENDING' → keep polling
|
|
58
|
-
}
|
|
59
|
-
const elapsed = Math.round((Date.now() - startedAt) / 60_000);
|
|
60
|
-
return { outcome: 'timeout', elapsed, attachUrl: session.attachUrl };
|
|
61
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { EthKeypair } from '@reclaimprotocol/client';
|
|
2
|
-
import { type CachedCredential } from './cache.ts';
|
|
3
|
-
import { type EnvWriteResult } from './env-file.ts';
|
|
4
|
-
/** Shape returned by `persistCredentialLocally` — the fields both
|
|
5
|
-
* `issue_credentials` and `import_credentials` expose in their MCP
|
|
6
|
-
* responses. The env-file fields are present only when the credential
|
|
7
|
-
* was persisted to `.env` (`writeEnv: true`); a memory-only credential
|
|
8
|
-
* lives in the cache and omits them. */
|
|
9
|
-
export type PersistedCredential = Pick<CachedCredential, 'address' | 'label'> & Partial<EnvWriteResult> & {
|
|
10
|
-
wroteEnv: boolean;
|
|
11
|
-
};
|
|
12
|
-
/** Local persistence step shared by `issue_credentials` and
|
|
13
|
-
* `import_credentials`. Always upserts the credentials cache; when
|
|
14
|
-
* `writeEnv` is true (default) it also writes `RECLAIM_PRIVATE_KEY` to
|
|
15
|
-
* the project `.env` (0600) and appends `.env` to `.gitignore`. Pass
|
|
16
|
-
* `writeEnv: false` to keep the credential in the cache (memory) only,
|
|
17
|
-
* without touching the project's `.env`. */
|
|
18
|
-
export declare function persistCredentialLocally(keypair: EthKeypair, label: string | undefined, projectDir: string, writeEnv?: boolean): PersistedCredential;
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { upsertCredential } from "./cache.js";
|
|
2
|
-
import { writeAppCredentialsToEnv } from "./env-file.js";
|
|
3
|
-
/** Local persistence step shared by `issue_credentials` and
|
|
4
|
-
* `import_credentials`. Always upserts the credentials cache; when
|
|
5
|
-
* `writeEnv` is true (default) it also writes `RECLAIM_PRIVATE_KEY` to
|
|
6
|
-
* the project `.env` (0600) and appends `.env` to `.gitignore`. Pass
|
|
7
|
-
* `writeEnv: false` to keep the credential in the cache (memory) only,
|
|
8
|
-
* without touching the project's `.env`. */
|
|
9
|
-
export function persistCredentialLocally(keypair, label, projectDir, writeEnv = true) {
|
|
10
|
-
const cached = upsertCredential({
|
|
11
|
-
address: keypair.address,
|
|
12
|
-
privateKey: keypair.privateKey,
|
|
13
|
-
label,
|
|
14
|
-
createdAt: new Date().toISOString(),
|
|
15
|
-
createdIn: projectDir,
|
|
16
|
-
projectDirs: [projectDir],
|
|
17
|
-
});
|
|
18
|
-
if (!writeEnv) {
|
|
19
|
-
return { address: cached.address, label: cached.label, wroteEnv: false };
|
|
20
|
-
}
|
|
21
|
-
const env = writeAppCredentialsToEnv(projectDir, keypair.privateKey);
|
|
22
|
-
return {
|
|
23
|
-
address: cached.address,
|
|
24
|
-
label: cached.label,
|
|
25
|
-
wroteEnv: true,
|
|
26
|
-
envPath: env.envPath,
|
|
27
|
-
gitignorePath: env.gitignorePath,
|
|
28
|
-
gitignoreAppended: env.gitignoreAppended,
|
|
29
|
-
};
|
|
30
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { type RegisteredTool } from '../server.ts';
|
|
2
|
-
/**
|
|
3
|
-
* Decide which app credential `run_proof` should sign with, BEFORE
|
|
4
|
-
* calling it. `run_proof` requires an `ownerAddress` and does no
|
|
5
|
-
* resolution of its own — this is the single place that "checks memory,
|
|
6
|
-
* env, etc and offers options".
|
|
7
|
-
*
|
|
8
|
-
* Checks, in order: `RECLAIM_PRIVATE_KEY` in the MCP env → the project
|
|
9
|
-
* `.env` → the best cached credential for this directory. Never returns
|
|
10
|
-
* the private key — only the address to pass through as `ownerAddress`.
|
|
11
|
-
*/
|
|
12
|
-
export declare function resolveOwnerKeyTool(): RegisteredTool;
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { deriveFromPrivateKey } from '@reclaimprotocol/client';
|
|
2
|
-
import { findProjectRoot } from "../../paths.js";
|
|
3
|
-
import { defineTool } from "../server.js";
|
|
4
|
-
import { suggestCredentialForDir } from "./cache.js";
|
|
5
|
-
import { readPrivateKeyFromEnvFile } from "./env-file.js";
|
|
6
|
-
/**
|
|
7
|
-
* Decide which app credential `run_proof` should sign with, BEFORE
|
|
8
|
-
* calling it. `run_proof` requires an `ownerAddress` and does no
|
|
9
|
-
* resolution of its own — this is the single place that "checks memory,
|
|
10
|
-
* env, etc and offers options".
|
|
11
|
-
*
|
|
12
|
-
* Checks, in order: `RECLAIM_PRIVATE_KEY` in the MCP env → the project
|
|
13
|
-
* `.env` → the best cached credential for this directory. Never returns
|
|
14
|
-
* the private key — only the address to pass through as `ownerAddress`.
|
|
15
|
-
*/
|
|
16
|
-
export function resolveOwnerKeyTool() {
|
|
17
|
-
return defineTool({
|
|
18
|
-
name: 'resolve_owner_key',
|
|
19
|
-
description: 'Resolve which app credential run_proof should sign with — ' +
|
|
20
|
-
'call this BEFORE run_proof. Checks, in order: ' +
|
|
21
|
-
'RECLAIM_PRIVATE_KEY in the MCP env, RECLAIM_PRIVATE_KEY in the ' +
|
|
22
|
-
'project .env, then the best cached credential for this ' +
|
|
23
|
-
'directory. Returns { ready: true, address, source } when one ' +
|
|
24
|
-
'is available — pass `address` to run_proof as `ownerAddress`. ' +
|
|
25
|
-
'Returns { ready: false } when none exists: then ask the dev to ' +
|
|
26
|
-
'provide a private key (import_credentials) or create one ' +
|
|
27
|
-
'(issue_credentials) — optionally with writeEnv:false to keep ' +
|
|
28
|
-
'it in the local cache (memory) only — and call resolve_owner_key ' +
|
|
29
|
-
'again. Never exposes the private key.',
|
|
30
|
-
inputSchema: { type: 'object', properties: {} },
|
|
31
|
-
}, async () => {
|
|
32
|
-
const dir = findProjectRoot(process.cwd());
|
|
33
|
-
const envKey = process.env.RECLAIM_PRIVATE_KEY;
|
|
34
|
-
if (envKey) {
|
|
35
|
-
return {
|
|
36
|
-
ready: true,
|
|
37
|
-
address: deriveFromPrivateKey(envKey).address,
|
|
38
|
-
source: 'env',
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
const dotenvKey = readPrivateKeyFromEnvFile(dir);
|
|
42
|
-
if (dotenvKey) {
|
|
43
|
-
return {
|
|
44
|
-
ready: true,
|
|
45
|
-
address: deriveFromPrivateKey(dotenvKey).address,
|
|
46
|
-
source: 'dotenv',
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
const suggestion = suggestCredentialForDir(dir);
|
|
50
|
-
if (suggestion) {
|
|
51
|
-
return {
|
|
52
|
-
ready: true,
|
|
53
|
-
address: suggestion.credential.address,
|
|
54
|
-
source: 'cache',
|
|
55
|
-
reason: suggestion.reason,
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
return {
|
|
59
|
-
ready: false,
|
|
60
|
-
message: 'No app credential available (no RECLAIM_PRIVATE_KEY in env ' +
|
|
61
|
-
'or .env, and the cache is empty). Ask the dev to provide ' +
|
|
62
|
-
'their private key via import_credentials, or create one via ' +
|
|
63
|
-
'issue_credentials (pass writeEnv:false to keep it out of ' +
|
|
64
|
-
'.env). Then call resolve_owner_key again and pass its ' +
|
|
65
|
-
'address to run_proof as ownerAddress.',
|
|
66
|
-
};
|
|
67
|
-
});
|
|
68
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export type CachedSession = {
|
|
2
|
-
token: string;
|
|
3
|
-
/** ISO timestamp when the token expires (2 days from issue). */
|
|
4
|
-
expiresAt: string;
|
|
5
|
-
/** Email of the user who authorized (if available). */
|
|
6
|
-
email?: string;
|
|
7
|
-
};
|
|
8
|
-
/** Persist a session token to ~/.reclaim/session.json (0600). */
|
|
9
|
-
export declare function writeSession(session: CachedSession): void;
|
|
10
|
-
/**
|
|
11
|
-
* Read the cached session, returning it only if the token is still
|
|
12
|
-
* valid (not yet expired). Returns undefined on any error.
|
|
13
|
-
*/
|
|
14
|
-
export declare function readSession(): CachedSession | undefined;
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync, } from 'node:fs';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
import { reclaimHomeDirPath } from "../../paths.js";
|
|
4
|
-
// Separate from credentials.json — sessions expire, credentials don't.
|
|
5
|
-
function sessionCachePath() {
|
|
6
|
-
return join(reclaimHomeDirPath(), 'session.json');
|
|
7
|
-
}
|
|
8
|
-
/** Persist a session token to ~/.reclaim/session.json (0600). */
|
|
9
|
-
export function writeSession(session) {
|
|
10
|
-
const dir = reclaimHomeDirPath();
|
|
11
|
-
if (!existsSync(dir)) {
|
|
12
|
-
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
13
|
-
}
|
|
14
|
-
chmodSync(dir, 0o700);
|
|
15
|
-
const path = sessionCachePath();
|
|
16
|
-
writeFileSync(path, JSON.stringify(session, null, 2) + '\n', { mode: 0o600 });
|
|
17
|
-
chmodSync(path, 0o600);
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Read the cached session, returning it only if the token is still
|
|
21
|
-
* valid (not yet expired). Returns undefined on any error.
|
|
22
|
-
*/
|
|
23
|
-
export function readSession() {
|
|
24
|
-
const path = sessionCachePath();
|
|
25
|
-
if (!existsSync(path)) {
|
|
26
|
-
return undefined;
|
|
27
|
-
}
|
|
28
|
-
try {
|
|
29
|
-
const raw = readFileSync(path, 'utf8');
|
|
30
|
-
const s = JSON.parse(raw);
|
|
31
|
-
if (!s.token || !s.expiresAt) {
|
|
32
|
-
return undefined;
|
|
33
|
-
}
|
|
34
|
-
if (new Date(s.expiresAt) <= new Date()) {
|
|
35
|
-
return undefined; // expired
|
|
36
|
-
}
|
|
37
|
-
return s;
|
|
38
|
-
}
|
|
39
|
-
catch {
|
|
40
|
-
return undefined;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import { deriveFromPrivateKey, } from '@reclaimprotocol/client';
|
|
2
|
-
import { findProjectRoot } from "../../paths.js";
|
|
3
|
-
import { defineTool } from "../server.js";
|
|
4
|
-
import { findCached, suggestCredentialForDir } from "./cache.js";
|
|
5
|
-
export function statusTool(client) {
|
|
6
|
-
return defineTool({
|
|
7
|
-
name: 'reclaim_status',
|
|
8
|
-
description: 'Report the live mode (SANDBOX | PRODUCTION | REVOKED) ' +
|
|
9
|
-
'of a Reclaim app credential. Pass `address` — or omit it ' +
|
|
10
|
-
'to derive the address from RECLAIM_PRIVATE_KEY, falling ' +
|
|
11
|
-
'back to the best cached credential for this directory. ' +
|
|
12
|
-
'Useful to confirm a credential is linked to an org ' +
|
|
13
|
-
'with billing before running a production flow.',
|
|
14
|
-
inputSchema: {
|
|
15
|
-
type: 'object',
|
|
16
|
-
properties: {
|
|
17
|
-
address: {
|
|
18
|
-
type: 'string',
|
|
19
|
-
pattern: '^0x[0-9a-fA-F]{40}$',
|
|
20
|
-
description: 'Lowercase ETH address. Defaults to the address ' +
|
|
21
|
-
'derived from RECLAIM_PRIVATE_KEY, then the cached ' +
|
|
22
|
-
'credential suggested for the current directory.',
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
},
|
|
26
|
-
}, async (args) => {
|
|
27
|
-
let address = args.address?.toLowerCase();
|
|
28
|
-
if (!address && process.env.RECLAIM_PRIVATE_KEY) {
|
|
29
|
-
address = deriveFromPrivateKey(process.env.RECLAIM_PRIVATE_KEY).address;
|
|
30
|
-
}
|
|
31
|
-
if (!address) {
|
|
32
|
-
address = suggestCredentialForDir(findProjectRoot(process.cwd()))
|
|
33
|
-
?.credential.address;
|
|
34
|
-
}
|
|
35
|
-
if (!address) {
|
|
36
|
-
throw new Error('No address given, RECLAIM_PRIVATE_KEY is not set, and the ' +
|
|
37
|
-
'cache is empty. Run issue_credentials or import_credentials ' +
|
|
38
|
-
'first.');
|
|
39
|
-
}
|
|
40
|
-
try {
|
|
41
|
-
const credResult = (await client.call('GetCredentialByAddress', {
|
|
42
|
-
params: { address },
|
|
43
|
-
}));
|
|
44
|
-
const cred = credResult.data;
|
|
45
|
-
return {
|
|
46
|
-
address: cred.address,
|
|
47
|
-
mode: cred.mode,
|
|
48
|
-
orgId: cred.orgId,
|
|
49
|
-
label: cred.label,
|
|
50
|
-
revokedAt: cred.revokedAt,
|
|
51
|
-
lastUsedAt: cred.lastUsedAt,
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
catch (err) {
|
|
55
|
-
// Anonymous credentials are not registered server-side, so a
|
|
56
|
-
// 404 just means "local-only" — which is SANDBOX. Report what
|
|
57
|
-
// the local cache knows. Other errors propagate. The client
|
|
58
|
-
// throws a Boom-style ProblemError, so the status lives on
|
|
59
|
-
// `output.statusCode` / `problem.status`, not `status`.
|
|
60
|
-
const e = err;
|
|
61
|
-
const code = e.status ?? e.output?.statusCode ?? e.problem?.status;
|
|
62
|
-
if (code !== 404) {
|
|
63
|
-
throw err;
|
|
64
|
-
}
|
|
65
|
-
const cached = findCached(address);
|
|
66
|
-
return {
|
|
67
|
-
address,
|
|
68
|
-
mode: 'SANDBOX',
|
|
69
|
-
...(cached?.label ? { label: cached.label } : {}),
|
|
70
|
-
note: 'Local-only credential — not registered with the server. ' +
|
|
71
|
-
'It operates in SANDBOX. Link it to an org with billing ' +
|
|
72
|
-
'(via link_credential) to reach PRODUCTION.',
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
|
-
}
|
package/lib/mcp/register.d.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Factory entry-point for embedding the reclaim-agent's MCP tools into
|
|
3
|
-
* a host MCP server. Two consumers:
|
|
4
|
-
*
|
|
5
|
-
* - The agent's own standalone `src/index.ts` (uses `ReclaimMcpServer`,
|
|
6
|
-
* the low-level wrapper around `@modelcontextprotocol/sdk`'s Server).
|
|
7
|
-
* - `@reclaimprotocol/client`'s MCP server (uses `McpServer`, the
|
|
8
|
-
* high-level SDK wrapper). Calls `registerAgentTools` to fold the
|
|
9
|
-
* agent's 16 tools alongside its auto-generated API tools.
|
|
10
|
-
*
|
|
11
|
-
* Shared state — Chrome attach state, capture store, secret store — is
|
|
12
|
-
* built once per server and threaded through every tool factory.
|
|
13
|
-
*/
|
|
14
|
-
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
15
|
-
import type { ReclaimClient } from '@reclaimprotocol/client';
|
|
16
|
-
import { ConfigStore } from '../config/store.ts';
|
|
17
|
-
import { type AttachState } from './tools/attach.ts';
|
|
18
|
-
import { type CaptureStore } from './tools/capture.ts';
|
|
19
|
-
import { type SecretStore } from './tools/propose.ts';
|
|
20
|
-
import { type RegisteredTool } from './server.ts';
|
|
21
|
-
export interface AgentState {
|
|
22
|
-
attach: {
|
|
23
|
-
current?: AttachState;
|
|
24
|
-
config: ConfigStore;
|
|
25
|
-
};
|
|
26
|
-
captures: CaptureStore;
|
|
27
|
-
secrets: SecretStore;
|
|
28
|
-
}
|
|
29
|
-
export declare function buildAgentState(): AgentState;
|
|
30
|
-
/** Build the flat list of `RegisteredTool` entries. Useful when the host
|
|
31
|
-
* uses our internal `ReclaimMcpServer` interface (`.register(tool)`).
|
|
32
|
-
* Pass `client` to include `create_provider_version_from_capture`. */
|
|
33
|
-
export declare function buildAgentTools(state: AgentState, client?: ReclaimClient): RegisteredTool[];
|
|
34
|
-
/** Register agent tools on `@reclaimprotocol/client`'s McpServer. Mirrors
|
|
35
|
-
* the same shape as builder's auto-generated `registerTools(server, client)`
|
|
36
|
-
* in `mcp/api/tools.ts`.
|
|
37
|
-
* Pass `client` to include `create_provider_version_from_capture`. */
|
|
38
|
-
export declare function registerAgentTools(server: McpServer, state?: AgentState, client?: ReclaimClient): void;
|
package/lib/mcp/register.js
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Factory entry-point for embedding the reclaim-agent's MCP tools into
|
|
3
|
-
* a host MCP server. Two consumers:
|
|
4
|
-
*
|
|
5
|
-
* - The agent's own standalone `src/index.ts` (uses `ReclaimMcpServer`,
|
|
6
|
-
* the low-level wrapper around `@modelcontextprotocol/sdk`'s Server).
|
|
7
|
-
* - `@reclaimprotocol/client`'s MCP server (uses `McpServer`, the
|
|
8
|
-
* high-level SDK wrapper). Calls `registerAgentTools` to fold the
|
|
9
|
-
* agent's 16 tools alongside its auto-generated API tools.
|
|
10
|
-
*
|
|
11
|
-
* Shared state — Chrome attach state, capture store, secret store — is
|
|
12
|
-
* built once per server and threaded through every tool factory.
|
|
13
|
-
*/
|
|
14
|
-
import { setCryptoImplementation } from '@reclaimprotocol/tls';
|
|
15
|
-
import { webcryptoCrypto } from '@reclaimprotocol/tls/webcrypto';
|
|
16
|
-
import { ConfigStore } from "../config/store.js";
|
|
17
|
-
import { analyzeTool } from "./tools/analyze.js";
|
|
18
|
-
import { attachTool } from "./tools/attach.js";
|
|
19
|
-
import { captureTools } from "./tools/capture.js";
|
|
20
|
-
import { browserTools } from "./tools/eval.js";
|
|
21
|
-
import { findTool } from "./tools/find.js";
|
|
22
|
-
import { proofTool } from "./tools/proof.js";
|
|
23
|
-
import { makeSecretStore, proposeTool, } from "./tools/propose.js";
|
|
24
|
-
import { createVersionFromCaptureTool } from "./tools/publish.js";
|
|
25
|
-
import { replayTool } from "./tools/replay.js";
|
|
26
|
-
import { sessionTools } from "./tools/session.js";
|
|
27
|
-
import { registerToolList } from "./server.js";
|
|
28
|
-
let cryptoInitialized = false;
|
|
29
|
-
/** One-time crypto backend init for @reclaimprotocol/tls. The package
|
|
30
|
-
* ships with an empty `crypto = {}` and defers backend choice to the
|
|
31
|
-
* caller; without this, the first proof call dies inside the SDK with
|
|
32
|
-
* `crypto.randomBytes is not a function`. */
|
|
33
|
-
function ensureCryptoInit() {
|
|
34
|
-
if (cryptoInitialized) {
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
setCryptoImplementation(webcryptoCrypto);
|
|
38
|
-
cryptoInitialized = true;
|
|
39
|
-
}
|
|
40
|
-
export function buildAgentState() {
|
|
41
|
-
return {
|
|
42
|
-
attach: { config: new ConfigStore() },
|
|
43
|
-
captures: { sessions: new Map() },
|
|
44
|
-
secrets: makeSecretStore(),
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
/** Build the flat list of `RegisteredTool` entries. Useful when the host
|
|
48
|
-
* uses our internal `ReclaimMcpServer` interface (`.register(tool)`).
|
|
49
|
-
* Pass `client` to include `create_provider_version_from_capture`. */
|
|
50
|
-
export function buildAgentTools(state, client) {
|
|
51
|
-
ensureCryptoInit();
|
|
52
|
-
const tools = [];
|
|
53
|
-
tools.push(attachTool(state.attach));
|
|
54
|
-
for (const t of captureTools(state.attach, state.captures)) {
|
|
55
|
-
tools.push(t);
|
|
56
|
-
}
|
|
57
|
-
tools.push(findTool(state.captures));
|
|
58
|
-
for (const t of browserTools(state.attach)) {
|
|
59
|
-
tools.push(t);
|
|
60
|
-
}
|
|
61
|
-
for (const t of sessionTools(state.attach, state.captures, state.secrets)) {
|
|
62
|
-
tools.push(t);
|
|
63
|
-
}
|
|
64
|
-
tools.push(analyzeTool(state.captures));
|
|
65
|
-
tools.push(proposeTool(state.captures, state.secrets));
|
|
66
|
-
tools.push(replayTool(state.secrets));
|
|
67
|
-
tools.push(proofTool(state.secrets));
|
|
68
|
-
if (client) {
|
|
69
|
-
tools.push(createVersionFromCaptureTool(client));
|
|
70
|
-
}
|
|
71
|
-
return tools;
|
|
72
|
-
}
|
|
73
|
-
/** Register agent tools on `@reclaimprotocol/client`'s McpServer. Mirrors
|
|
74
|
-
* the same shape as builder's auto-generated `registerTools(server, client)`
|
|
75
|
-
* in `mcp/api/tools.ts`.
|
|
76
|
-
* Pass `client` to include `create_provider_version_from_capture`. */
|
|
77
|
-
export function registerAgentTools(server, state, client) {
|
|
78
|
-
const s = state ?? buildAgentState();
|
|
79
|
-
registerToolList(server, buildAgentTools(s, client));
|
|
80
|
-
}
|
package/lib/mcp/tools/analyze.js
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { detectConcerns } from "../../provider/constraints.js";
|
|
2
|
-
import { defineTool } from "../server.js";
|
|
3
|
-
export function analyzeTool(captures) {
|
|
4
|
-
return defineTool({
|
|
5
|
-
name: 'analyze_request_constraints',
|
|
6
|
-
description: 'Flag potential provider-authoring concerns for a captured request.',
|
|
7
|
-
inputSchema: {
|
|
8
|
-
type: 'object',
|
|
9
|
-
properties: {
|
|
10
|
-
captureId: { type: 'string' },
|
|
11
|
-
requestId: { type: 'string' },
|
|
12
|
-
},
|
|
13
|
-
required: ['captureId', 'requestId'],
|
|
14
|
-
},
|
|
15
|
-
}, async ({ captureId, requestId }) => {
|
|
16
|
-
const session = captures.sessions.get(captureId);
|
|
17
|
-
if (!session) {
|
|
18
|
-
throw new Error(`no capture ${captureId}`);
|
|
19
|
-
}
|
|
20
|
-
const r = session.requests.get(requestId);
|
|
21
|
-
if (!r) {
|
|
22
|
-
throw new Error(`no request ${requestId} in capture ${captureId}`);
|
|
23
|
-
}
|
|
24
|
-
return { concerns: detectConcerns(r) };
|
|
25
|
-
});
|
|
26
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { type CdpHandles } from '../../cdp/client.ts';
|
|
2
|
-
import type { ConfigStore } from '../../config/store.ts';
|
|
3
|
-
import { type RegisteredTool } from '../server.ts';
|
|
4
|
-
export interface AttachState {
|
|
5
|
-
handles: CdpHandles;
|
|
6
|
-
port: number;
|
|
7
|
-
}
|
|
8
|
-
export declare function attachTool(state: {
|
|
9
|
-
current?: AttachState;
|
|
10
|
-
config: ConfigStore;
|
|
11
|
-
}): RegisteredTool;
|
package/lib/mcp/tools/attach.js
DELETED
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { connectCdp } from "../../cdp/client.js";
|
|
2
|
-
import { defaultProfileDir, launchChrome, waitForCdpReady, } from "../../cdp/launcher.js";
|
|
3
|
-
import { defaultConfigPath } from "../../config/store.js";
|
|
4
|
-
import { defineTool } from "../server.js";
|
|
5
|
-
export function attachTool(state) {
|
|
6
|
-
return defineTool({
|
|
7
|
-
name: 'attach_chrome',
|
|
8
|
-
description: 'Attach to a Chrome instance via CDP. ' +
|
|
9
|
-
'Auto-launches a dedicated-profile Chrome ' +
|
|
10
|
-
'on first call if no attachMode is persisted. ' +
|
|
11
|
-
'Persists the chosen mode in ~/.reclaim/config.json.',
|
|
12
|
-
inputSchema: {
|
|
13
|
-
type: 'object',
|
|
14
|
-
properties: {
|
|
15
|
-
attachMode: { type: 'string', enum: ['dedicated', 'attach'] },
|
|
16
|
-
port: { type: 'number' },
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
}, async (parsed) => {
|
|
20
|
-
let cfg = state.config.read();
|
|
21
|
-
if (parsed.attachMode || parsed.port) {
|
|
22
|
-
cfg = {
|
|
23
|
-
attachMode: parsed.attachMode ?? cfg?.attachMode ?? 'dedicated',
|
|
24
|
-
port: parsed.port ?? cfg?.port ?? 9222,
|
|
25
|
-
};
|
|
26
|
-
state.config.write(cfg);
|
|
27
|
-
}
|
|
28
|
-
if (!cfg) {
|
|
29
|
-
return {
|
|
30
|
-
needsChoice: true,
|
|
31
|
-
message: 'First-run: choose attach mode. ' +
|
|
32
|
-
'Call attach_chrome again with attachMode="dedicated" ' +
|
|
33
|
-
'(auto-launch a Chrome profile under ~/.reclaim/chrome-profile) ' +
|
|
34
|
-
'or attachMode="attach" ' +
|
|
35
|
-
'(connect to a Chrome you launched yourself with ' +
|
|
36
|
-
'BOTH --remote-debugging-port=9222 AND ' +
|
|
37
|
-
'--user-data-dir=<some-non-default-path>; ' +
|
|
38
|
-
'since Chrome 136 the debug-port flag is silently ' +
|
|
39
|
-
'ignored if the default profile is in use).',
|
|
40
|
-
configPath: defaultConfigPath(),
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
if (cfg.attachMode === 'dedicated') {
|
|
44
|
-
try {
|
|
45
|
-
await waitForCdpReady(cfg.port, 500);
|
|
46
|
-
}
|
|
47
|
-
catch {
|
|
48
|
-
launchChrome({ port: cfg.port, profileDir: defaultProfileDir() });
|
|
49
|
-
await waitForCdpReady(cfg.port, 10_000);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
else {
|
|
53
|
-
await waitForCdpReady(cfg.port, 2_000).catch(() => {
|
|
54
|
-
throw new Error(`attach mode: nothing answering CDP on port ${cfg.port}. ` +
|
|
55
|
-
'Chrome must be launched with BOTH ' +
|
|
56
|
-
`--remote-debugging-port=${cfg.port} AND ` +
|
|
57
|
-
'--user-data-dir=<some-non-default-path>. ' +
|
|
58
|
-
'Since Chrome 136 (May 2025), the debug-port flag is ' +
|
|
59
|
-
'silently ignored when the default ' +
|
|
60
|
-
"user profile is in use — that's why nothing opens the port. " +
|
|
61
|
-
'Either re-launch Chrome with ' +
|
|
62
|
-
'a custom --user-data-dir, or switch to attachMode="dedicated".');
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
if (state.current) {
|
|
66
|
-
await state.current.handles.close().catch(() => { });
|
|
67
|
-
}
|
|
68
|
-
const handles = await connectCdp(cfg.port);
|
|
69
|
-
state.current = { handles, port: cfg.port };
|
|
70
|
-
return { attached: true, port: cfg.port, mode: cfg.attachMode };
|
|
71
|
-
});
|
|
72
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { type CaptureSession } from '../../cdp/capture.ts';
|
|
2
|
-
import { type RegisteredTool } from '../server.ts';
|
|
3
|
-
import type { AttachState } from './attach.ts';
|
|
4
|
-
export interface CaptureStore {
|
|
5
|
-
sessions: Map<string, CaptureSession>;
|
|
6
|
-
activeTab?: string;
|
|
7
|
-
}
|
|
8
|
-
export declare function captureTools(attachRef: {
|
|
9
|
-
current?: AttachState;
|
|
10
|
-
}, captures: CaptureStore): RegisteredTool[];
|