@reclaimprotocol/agent 0.1.0 → 0.1.1
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 +1 -1
- package/lib/cdp/capture-engine.d.ts +66 -0
- package/lib/cdp/capture-engine.js +153 -0
- package/lib/cdp/capture.d.ts +9 -20
- package/lib/cdp/capture.js +14 -138
- package/lib/cdp/index.d.ts +3 -0
- package/lib/cdp/index.js +6 -0
- package/lib/config/store.d.ts +7 -6
- package/lib/config/store.js +2 -2
- package/lib/index.d.ts +2 -2
- package/lib/index.js +1 -1
- package/lib/mcp/api/operations.gen.d.ts +101 -45
- package/lib/mcp/api/operations.gen.js +996 -126
- package/lib/mcp/api/to-zod.d.ts +24 -0
- package/lib/mcp/api/to-zod.js +94 -0
- package/lib/mcp/api/tools.js +1 -1
- package/lib/mcp/credentials/authenticate.d.ts +3 -0
- package/lib/mcp/{tools/credentials → credentials}/authenticate.js +3 -3
- package/lib/mcp/credentials/build.d.ts +5 -0
- package/lib/mcp/credentials/build.js +18 -0
- package/lib/mcp/{tools/credentials → credentials}/cache.d.ts +9 -9
- package/lib/mcp/{tools/credentials → credentials}/cache.js +36 -19
- package/lib/mcp/credentials/import.d.ts +2 -0
- package/lib/mcp/{tools/credentials → credentials}/import.js +2 -2
- package/lib/mcp/credentials/issue.d.ts +2 -0
- package/lib/mcp/{tools/credentials → credentials}/issue.js +4 -4
- package/lib/mcp/credentials/keypair.d.ts +17 -0
- package/lib/mcp/credentials/keypair.js +48 -0
- package/lib/mcp/credentials/link.d.ts +3 -0
- package/lib/mcp/credentials/link.js +107 -0
- package/lib/mcp/{tools/credentials → credentials}/list-cached.d.ts +1 -1
- package/lib/mcp/{tools/credentials → credentials}/list-cached.js +5 -5
- package/lib/mcp/credentials/owner-key.d.ts +23 -0
- package/lib/mcp/credentials/owner-key.js +58 -0
- package/lib/mcp/credentials/paths.d.ts +12 -0
- package/lib/mcp/credentials/paths.js +35 -0
- package/lib/mcp/credentials/poll.d.ts +27 -0
- package/lib/mcp/credentials/poll.js +61 -0
- package/lib/mcp/{tools/credentials → credentials}/resolve-owner-key.d.ts +1 -1
- package/lib/mcp/{tools/credentials → credentials}/resolve-owner-key.js +2 -2
- package/lib/mcp/credentials/session-cache.d.ts +14 -0
- package/lib/mcp/credentials/session-cache.js +42 -0
- package/lib/mcp/{tools/credentials → credentials}/status.d.ts +1 -1
- package/lib/mcp/credentials/status.js +76 -0
- package/lib/mcp/instructions.d.ts +1 -0
- package/lib/mcp/instructions.js +11 -0
- package/lib/mcp/register.d.ts +38 -0
- package/lib/mcp/register.js +80 -0
- package/lib/mcp/server.d.ts +2 -2
- package/lib/mcp/server.js +3 -3
- package/lib/mcp/start.js +10 -4
- package/lib/mcp/tools/agent/build.js +2 -15
- package/lib/mcp/tools/agent/index.d.ts +2 -0
- package/lib/mcp/tools/agent/index.js +3 -0
- package/lib/mcp/tools/agent/proof.js +1 -6
- package/lib/mcp/tools/agent/propose.js +13 -2
- package/lib/mcp/tools/agent/publish.js +10 -2
- package/lib/mcp/tools/agent/replay.js +0 -5
- package/lib/mcp/tools/analyze.d.ts +3 -0
- package/lib/mcp/tools/analyze.js +26 -0
- package/lib/mcp/tools/attach.d.ts +11 -0
- package/lib/mcp/tools/attach.js +72 -0
- package/lib/mcp/tools/authenticate/authenticate.js +107 -0
- package/lib/mcp/tools/authenticate/build.d.ts +15 -0
- package/lib/mcp/tools/authenticate/build.js +28 -0
- package/lib/mcp/tools/authenticate/decrypt-key.d.ts +32 -0
- package/lib/mcp/tools/authenticate/decrypt-key.js +49 -0
- package/lib/mcp/tools/authenticate/eth-key.d.ts +38 -0
- package/lib/mcp/tools/authenticate/eth-key.js +130 -0
- package/lib/mcp/tools/authenticate/import.js +57 -0
- package/lib/mcp/tools/authenticate/index.d.ts +2 -0
- package/lib/mcp/tools/authenticate/index.js +4 -0
- package/lib/mcp/tools/authenticate/issue.js +42 -0
- package/lib/mcp/tools/authenticate/resolve-owner-key.d.ts +13 -0
- package/lib/mcp/tools/authenticate/resolve-owner-key.js +53 -0
- package/lib/mcp/tools/capture.d.ts +10 -0
- package/lib/mcp/tools/capture.js +142 -0
- package/lib/mcp/tools/eval.d.ts +5 -0
- package/lib/mcp/tools/eval.js +127 -0
- package/lib/mcp/tools/find.d.ts +3 -0
- package/lib/mcp/tools/find.js +60 -0
- package/lib/mcp/tools/index.d.ts +3 -0
- package/lib/mcp/tools/index.js +6 -0
- package/lib/mcp/tools/owner-key.d.ts +2 -0
- package/lib/mcp/tools/owner-key.js +63 -0
- package/lib/mcp/tools/proof.d.ts +3 -0
- package/lib/mcp/tools/proof.js +214 -0
- package/lib/mcp/tools/propose.d.ts +9 -0
- package/lib/mcp/tools/propose.js +75 -0
- package/lib/mcp/tools/publish.d.ts +3 -0
- package/lib/mcp/tools/publish.js +59 -0
- package/lib/mcp/tools/replay.d.ts +3 -0
- package/lib/mcp/tools/replay.js +46 -0
- package/lib/mcp/tools/session.d.ts +10 -0
- package/lib/mcp/tools/session.js +29 -0
- package/lib/mcp/tools/verification/build.d.ts +12 -0
- package/lib/mcp/tools/verification/build.js +14 -0
- package/lib/mcp/tools/verification/diagnose.d.ts +11 -0
- package/lib/mcp/tools/verification/diagnose.js +132 -0
- package/lib/mcp/tools/verification/index.d.ts +1 -0
- package/lib/mcp/tools/verification/index.js +2 -0
- package/lib/mcp/tools/verification/result.d.ts +12 -0
- package/lib/mcp/tools/verification/result.js +126 -0
- package/lib/mcp/verifications/build.d.ts +5 -0
- package/lib/mcp/verifications/build.js +14 -0
- package/lib/mcp/verifications/create.d.ts +3 -0
- package/lib/mcp/verifications/create.js +57 -0
- package/lib/mcp/verifications/find.d.ts +3 -0
- package/lib/mcp/verifications/find.js +37 -0
- package/lib/mcp/verifications/get.d.ts +3 -0
- package/lib/mcp/verifications/get.js +26 -0
- package/lib/mcp/verifications/update.d.ts +3 -0
- package/lib/mcp/verifications/update.js +78 -0
- package/lib/old/client.d.ts +3 -0
- package/lib/old/instructions.d.ts +0 -6
- package/lib/old/instructions.js +6 -24
- package/lib/old/to-register.d.ts +3 -0
- package/lib/old/to-register.js +35 -7
- package/lib/old/tools/publish.js +13 -1
- package/lib/proof/attestor.d.ts +33 -1
- package/lib/proof/attestor.js +67 -61
- package/lib/proof/index.d.ts +5 -0
- package/lib/proof/index.js +6 -0
- package/lib/proof/proof-core.d.ts +35 -0
- package/lib/proof/proof-core.js +73 -0
- package/lib/proof/zk-files.d.ts +14 -0
- package/lib/proof/zk-files.js +73 -0
- package/lib/provider/index.d.ts +5 -0
- package/lib/provider/index.js +9 -0
- package/lib/provider/to-version.d.ts +9 -12
- package/lib/provider/to-version.js +38 -4
- package/lib/provider/verification-checks.d.ts +12 -0
- package/lib/provider/verification-checks.js +30 -0
- package/lib/routes.gen.d.ts +271 -0
- package/lib/routes.gen.js +73 -0
- package/lib/types/openapi.gen.d.ts +3967 -0
- package/lib/types/openapi.gen.js +5 -0
- package/package.json +18 -10
- package/skill/SKILL.md +35 -14
- package/skill/builder-mode.md +9 -0
- package/skill/old-mode.md +13 -0
- package/src/cdp/capture-engine.ts +256 -0
- package/src/cdp/capture.ts +25 -185
- package/src/cdp/index.ts +6 -0
- package/src/config/store.ts +7 -6
- package/src/index.ts +2 -4
- package/src/mcp/api/operations.gen.ts +1023 -121
- package/src/mcp/api/to-zod.ts +115 -0
- package/src/mcp/api/tools.ts +9 -3
- package/src/mcp/instructions.ts +15 -0
- package/src/mcp/server.ts +5 -4
- package/src/mcp/start.ts +14 -4
- package/src/mcp/tools/agent/build.ts +2 -18
- package/src/mcp/tools/agent/index.ts +4 -0
- package/src/mcp/tools/agent/proof.ts +1 -7
- package/src/mcp/tools/agent/propose.ts +13 -2
- package/src/mcp/tools/agent/publish.ts +10 -2
- package/src/mcp/tools/agent/replay.ts +0 -5
- package/src/mcp/tools/{credentials → authenticate}/authenticate.ts +9 -8
- package/src/mcp/tools/authenticate/build.ts +32 -0
- package/src/mcp/tools/authenticate/decrypt-key.ts +64 -0
- package/src/mcp/tools/authenticate/eth-key.ts +182 -0
- package/src/mcp/tools/authenticate/import.ts +73 -0
- package/src/mcp/tools/authenticate/index.ts +4 -0
- package/src/mcp/tools/authenticate/issue.ts +50 -0
- package/src/mcp/tools/authenticate/resolve-owner-key.ts +60 -0
- package/src/mcp/tools/index.ts +6 -0
- package/src/mcp/tools/verification/build.ts +16 -0
- package/src/mcp/tools/verification/index.ts +2 -0
- package/src/mcp/tools/verification/result.ts +155 -0
- package/src/old/client.ts +3 -0
- package/src/old/instructions.ts +10 -25
- package/src/old/to-register.ts +62 -27
- package/src/old/tools/publish.ts +17 -1
- package/src/proof/attestor.ts +115 -69
- package/src/proof/index.ts +21 -0
- package/src/proof/proof-core.ts +109 -0
- package/src/proof/zk-files.ts +83 -0
- package/src/provider/index.ts +20 -0
- package/src/provider/to-version.ts +52 -11
- package/src/provider/verification-checks.ts +36 -0
- package/lib/mcp/tools/credentials/build.d.ts +0 -16
- package/lib/mcp/tools/credentials/build.js +0 -33
- package/lib/mcp/tools/credentials/status.js +0 -62
- package/src/mcp/tools/credentials/build.ts +0 -37
- package/src/mcp/tools/credentials/cache.ts +0 -161
- package/src/mcp/tools/credentials/env-file.ts +0 -101
- package/src/mcp/tools/credentials/import.ts +0 -72
- package/src/mcp/tools/credentials/issue.ts +0 -107
- package/src/mcp/tools/credentials/list-cached.ts +0 -66
- package/src/mcp/tools/credentials/register.ts +0 -49
- package/src/mcp/tools/credentials/resolve-owner-key.ts +0 -78
- package/src/mcp/tools/credentials/status.ts +0 -82
- package/src/types/openapi.ts +0 -7
- /package/lib/mcp/{tools/credentials → credentials}/env-file.d.ts +0 -0
- /package/lib/mcp/{tools/credentials → credentials}/env-file.js +0 -0
- /package/lib/mcp/{tools/credentials → credentials}/register.d.ts +0 -0
- /package/lib/mcp/{tools/credentials → credentials}/register.js +0 -0
- /package/lib/mcp/tools/{credentials → authenticate}/authenticate.d.ts +0 -0
- /package/lib/mcp/tools/{credentials → authenticate}/import.d.ts +0 -0
- /package/lib/mcp/tools/{credentials → authenticate}/issue.d.ts +0 -0
- /package/lib/mcp/tools/{credentials → authenticate}/session-cache.d.ts +0 -0
- /package/lib/mcp/tools/{credentials → authenticate}/session-cache.js +0 -0
- /package/src/mcp/tools/{credentials → authenticate}/session-cache.ts +0 -0
|
@@ -0,0 +1,26 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
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;
|
|
@@ -0,0 +1,72 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { defineTool } from "../../server.js";
|
|
2
|
+
import { writeSession } from "./session-cache.js";
|
|
3
|
+
export function authenticateTool(client) {
|
|
4
|
+
return defineTool({
|
|
5
|
+
name: 'reclaim_authenticate',
|
|
6
|
+
description: 'Authorize the CLI / MCP to make authenticated API calls by having ' +
|
|
7
|
+
'the user sign in on the dashboard. Two steps:\n\n' +
|
|
8
|
+
'Step 1 — call with no arguments. Returns a `code` and `attachUrl`. ' +
|
|
9
|
+
'Tell the user to open the URL, sign in, and authorize.\n\n' +
|
|
10
|
+
'Step 2 — once the user says they have authorized, call again ' +
|
|
11
|
+
'with the same `code` from step 1 to check if confirmed. ' +
|
|
12
|
+
'Returns `LINKED` with a 2-day bearer token when confirmed, ' +
|
|
13
|
+
'`PENDING` if not yet, or `EXPIRED` if too long has passed.\n\n' +
|
|
14
|
+
'The token is cached in ~/.reclaim/config.json automatically.\n\n' +
|
|
15
|
+
'This bearer token authenticates dashboard/org-management calls ' +
|
|
16
|
+
'(e.g. list_orgs, issuing an org secret). Programmatic verification ' +
|
|
17
|
+
'calls use a separate org secret (rorg_…, set as RECLAIM_ORG_SECRET).',
|
|
18
|
+
inputSchema: {
|
|
19
|
+
type: 'object',
|
|
20
|
+
properties: {
|
|
21
|
+
code: {
|
|
22
|
+
type: 'string',
|
|
23
|
+
pattern: '^[A-HJ-NP-Z2-9]{5}$',
|
|
24
|
+
description: '5-character code from a previous step-1 call. ' +
|
|
25
|
+
'When provided, checks whether the user has ' +
|
|
26
|
+
'confirmed that session instead of opening a new one.',
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
}, async (args) => {
|
|
31
|
+
// Step 2: check an existing session
|
|
32
|
+
if (args.code) {
|
|
33
|
+
return checkSession(client, args.code);
|
|
34
|
+
}
|
|
35
|
+
// Step 1: open a new auth-only session
|
|
36
|
+
const sessionResult = (await client.call('CreateAttachSession'));
|
|
37
|
+
const session = sessionResult.data;
|
|
38
|
+
return {
|
|
39
|
+
status: 'PENDING',
|
|
40
|
+
code: session.code,
|
|
41
|
+
attachUrl: session.attachUrl,
|
|
42
|
+
expiresAt: session.expiresAt,
|
|
43
|
+
instructions: `Open ${session.attachUrl} in your browser, sign in, and click ` +
|
|
44
|
+
'"Authorize this device". ' +
|
|
45
|
+
'Once done, call authenticate again with code: ' +
|
|
46
|
+
`"${session.code}" to confirm.`,
|
|
47
|
+
};
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
async function checkSession(client, code) {
|
|
51
|
+
let session;
|
|
52
|
+
try {
|
|
53
|
+
const sessionResult = (await client.call('GetAttachSession', {
|
|
54
|
+
params: { code }
|
|
55
|
+
}));
|
|
56
|
+
session = sessionResult.data;
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
const status = err.status;
|
|
60
|
+
if (status === 404) {
|
|
61
|
+
return {
|
|
62
|
+
status: 'NOT_FOUND',
|
|
63
|
+
hint: 'Session not found — it may have expired (15-min window). ' +
|
|
64
|
+
'Call authenticate without a code to start a new session.',
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
throw new Error(`Failed to check session: ${err.message}`);
|
|
68
|
+
}
|
|
69
|
+
if (session.status === 'LINKED') {
|
|
70
|
+
const token = session.token?.trim();
|
|
71
|
+
if (token) {
|
|
72
|
+
writeSession({
|
|
73
|
+
token,
|
|
74
|
+
expiresAt: new Date(Date.now() + 2 * 24 * 60 * 60 * 1000).toISOString(),
|
|
75
|
+
});
|
|
76
|
+
client.setToken(token);
|
|
77
|
+
return {
|
|
78
|
+
status: 'LINKED',
|
|
79
|
+
token,
|
|
80
|
+
note: 'Token cached in ~/.reclaim/config.json and active now.',
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
status: 'LINKED_NO_TOKEN',
|
|
85
|
+
hint: 'Session confirmed but no token issued. ' +
|
|
86
|
+
'Restart the backend (npm run dev) and try again.',
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
if (session.status === 'EXPIRED') {
|
|
90
|
+
return {
|
|
91
|
+
status: 'EXPIRED',
|
|
92
|
+
hint: 'Session expired (15-min window passed). ' +
|
|
93
|
+
'Call authenticate without a code to start a new session.',
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
// Still PENDING
|
|
97
|
+
return {
|
|
98
|
+
status: 'PENDING',
|
|
99
|
+
code: session.code,
|
|
100
|
+
attachUrl: session.attachUrl,
|
|
101
|
+
hint: 'Session is still waiting. ' +
|
|
102
|
+
`Make sure you opened ${session.attachUrl}, ` +
|
|
103
|
+
'signed in, and clicked "Authorize this device". ' +
|
|
104
|
+
`Call authenticate again with code: "${session.code}"` +
|
|
105
|
+
' once you have done so.',
|
|
106
|
+
};
|
|
107
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ReclaimClient } from '@reclaimprotocol/client';
|
|
2
|
+
import type { RegisteredTool } from '../../server.ts';
|
|
3
|
+
/**
|
|
4
|
+
* Local-only key tools — no backend client needed. These manage the eth
|
|
5
|
+
* proof-owner key entirely on disk (as a secp256k1 PEM) or via env: generate,
|
|
6
|
+
* import, and resolve which key to sign proofs with. No `~/.reclaim` caching;
|
|
7
|
+
* useful in BOTH builder and OLD-devtools mode.
|
|
8
|
+
*/
|
|
9
|
+
export declare function buildLocalCredentialTools(): RegisteredTool[];
|
|
10
|
+
/**
|
|
11
|
+
* Full builder-mode credential set: the local key tools plus the backend
|
|
12
|
+
* `reclaim_authenticate` device-code flow. Old mode does NOT use the
|
|
13
|
+
* authenticate tool — it has its own.
|
|
14
|
+
*/
|
|
15
|
+
export declare function buildCredentialTools(client: ReclaimClient): RegisteredTool[];
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { authenticateTool } from "./authenticate.js";
|
|
2
|
+
import { importTool } from "./import.js";
|
|
3
|
+
import { issueTool } from "./issue.js";
|
|
4
|
+
import { resolveOwnerKeyTool } from "./resolve-owner-key.js";
|
|
5
|
+
/**
|
|
6
|
+
* Local-only key tools — no backend client needed. These manage the eth
|
|
7
|
+
* proof-owner key entirely on disk (as a secp256k1 PEM) or via env: generate,
|
|
8
|
+
* import, and resolve which key to sign proofs with. No `~/.reclaim` caching;
|
|
9
|
+
* useful in BOTH builder and OLD-devtools mode.
|
|
10
|
+
*/
|
|
11
|
+
export function buildLocalCredentialTools() {
|
|
12
|
+
return [
|
|
13
|
+
resolveOwnerKeyTool(),
|
|
14
|
+
issueTool(),
|
|
15
|
+
importTool(),
|
|
16
|
+
];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Full builder-mode credential set: the local key tools plus the backend
|
|
20
|
+
* `reclaim_authenticate` device-code flow. Old mode does NOT use the
|
|
21
|
+
* authenticate tool — it has its own.
|
|
22
|
+
*/
|
|
23
|
+
export function buildCredentialTools(client) {
|
|
24
|
+
return [
|
|
25
|
+
authenticateTool(client),
|
|
26
|
+
...buildLocalCredentialTools(),
|
|
27
|
+
];
|
|
28
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional X25519 decryption key — only needed when testing ENCRYPTED callback
|
|
3
|
+
* payloads in the consumer role. Resolution is file-only (no env var, no path
|
|
4
|
+
* override, no `~/.reclaim` caching):
|
|
5
|
+
*
|
|
6
|
+
* 1. An X25519 PKCS#8 PEM file named `reclaim-decrypt.pem` in the project
|
|
7
|
+
* root. Mint it with openssl:
|
|
8
|
+
*
|
|
9
|
+
* openssl genpkey -algorithm X25519 -out reclaim-decrypt.pem
|
|
10
|
+
*
|
|
11
|
+
* 2. Absent — plaintext-only testing (no decryption key; encrypted
|
|
12
|
+
* deliveries surface a clear error).
|
|
13
|
+
*
|
|
14
|
+
* The PEM *content* is loaded via the client's `loadDecryptionKey` (jose
|
|
15
|
+
* `ECDH-ES`) and passed straight through as `ReclaimConfig.credential` / to
|
|
16
|
+
* `decryptCallback`.
|
|
17
|
+
*/
|
|
18
|
+
import { type DecryptionKey } from '@reclaimprotocol/client';
|
|
19
|
+
/** Default X25519 PEM filename the agent looks for in the project root. */
|
|
20
|
+
export declare const DEFAULT_DECRYPT_PEM = "reclaim-decrypt.pem";
|
|
21
|
+
/** Resolve the decrypt-PEM path (the default file in the project root). */
|
|
22
|
+
export declare function decryptPemPath(projectDir?: string): string;
|
|
23
|
+
/**
|
|
24
|
+
* Read the raw decryption-key PEM string from the default file, without loading
|
|
25
|
+
* it. Returns `undefined` when the file is absent (plaintext-only).
|
|
26
|
+
*/
|
|
27
|
+
export declare function resolveDecryptKeyInput(projectDir?: string): string | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* Load the optional decryption key. Returns `undefined` when the PEM file is
|
|
30
|
+
* absent (the consumer then handles only plaintext deliveries).
|
|
31
|
+
*/
|
|
32
|
+
export declare function resolveDecryptionKey(projectDir?: string): Promise<DecryptionKey | undefined>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Optional X25519 decryption key — only needed when testing ENCRYPTED callback
|
|
3
|
+
* payloads in the consumer role. Resolution is file-only (no env var, no path
|
|
4
|
+
* override, no `~/.reclaim` caching):
|
|
5
|
+
*
|
|
6
|
+
* 1. An X25519 PKCS#8 PEM file named `reclaim-decrypt.pem` in the project
|
|
7
|
+
* root. Mint it with openssl:
|
|
8
|
+
*
|
|
9
|
+
* openssl genpkey -algorithm X25519 -out reclaim-decrypt.pem
|
|
10
|
+
*
|
|
11
|
+
* 2. Absent — plaintext-only testing (no decryption key; encrypted
|
|
12
|
+
* deliveries surface a clear error).
|
|
13
|
+
*
|
|
14
|
+
* The PEM *content* is loaded via the client's `loadDecryptionKey` (jose
|
|
15
|
+
* `ECDH-ES`) and passed straight through as `ReclaimConfig.credential` / to
|
|
16
|
+
* `decryptCallback`.
|
|
17
|
+
*/
|
|
18
|
+
import { loadDecryptionKey, } from '@reclaimprotocol/client';
|
|
19
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
20
|
+
import { join } from 'node:path';
|
|
21
|
+
import { findProjectRoot } from "../../../paths.js";
|
|
22
|
+
/** Default X25519 PEM filename the agent looks for in the project root. */
|
|
23
|
+
export const DEFAULT_DECRYPT_PEM = 'reclaim-decrypt.pem';
|
|
24
|
+
/** Resolve the decrypt-PEM path (the default file in the project root). */
|
|
25
|
+
export function decryptPemPath(projectDir = findProjectRoot(process.cwd())) {
|
|
26
|
+
return join(projectDir, DEFAULT_DECRYPT_PEM);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Read the raw decryption-key PEM string from the default file, without loading
|
|
30
|
+
* it. Returns `undefined` when the file is absent (plaintext-only).
|
|
31
|
+
*/
|
|
32
|
+
export function resolveDecryptKeyInput(projectDir = findProjectRoot(process.cwd())) {
|
|
33
|
+
const pemPath = decryptPemPath(projectDir);
|
|
34
|
+
if (existsSync(pemPath)) {
|
|
35
|
+
return readFileSync(pemPath, 'utf8');
|
|
36
|
+
}
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Load the optional decryption key. Returns `undefined` when the PEM file is
|
|
41
|
+
* absent (the consumer then handles only plaintext deliveries).
|
|
42
|
+
*/
|
|
43
|
+
export async function resolveDecryptionKey(projectDir = findProjectRoot(process.cwd())) {
|
|
44
|
+
const input = resolveDecryptKeyInput(projectDir);
|
|
45
|
+
if (input === undefined) {
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
return loadDecryptionKey(input);
|
|
49
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** The dotenv file the agent reads from / writes the key to. */
|
|
2
|
+
export declare const ENV_FILE = ".env";
|
|
3
|
+
/** Where the resolved eth key came from. */
|
|
4
|
+
export type EthKeySource = 'env' | 'dotenv' | 'file';
|
|
5
|
+
export type ResolvedEthKey = {
|
|
6
|
+
/** Raw 0x-hex 32-byte scalar. */
|
|
7
|
+
privateKey: string;
|
|
8
|
+
/** Lowercase eth address derived from the scalar. */
|
|
9
|
+
address: string;
|
|
10
|
+
source: EthKeySource;
|
|
11
|
+
/** Absolute path the key was read from (for `dotenv` / `file` sources). */
|
|
12
|
+
path?: string;
|
|
13
|
+
};
|
|
14
|
+
/** Validate + normalize a raw Ethereum private key to lowercase 0x-hex. */
|
|
15
|
+
export declare function normalizeEthHex(value: string): string;
|
|
16
|
+
/** The explicit raw-hex key-file path, if `RECLAIM_PRIVATE_KEY_FILE` is set. */
|
|
17
|
+
export declare function ethKeyFilePath(projectDir?: string): string | undefined;
|
|
18
|
+
/**
|
|
19
|
+
* Resolve the eth proof-owner key without prompting. Returns `undefined` when
|
|
20
|
+
* no key is configured anywhere — the caller decides whether to generate or
|
|
21
|
+
* ask for one (see `resolve_owner_key`).
|
|
22
|
+
*/
|
|
23
|
+
export declare function resolveEthKey(projectDir?: string): ResolvedEthKey | undefined;
|
|
24
|
+
/**
|
|
25
|
+
* Resolve the eth proof-owner private key (0x-hex) or throw a clear, actionable
|
|
26
|
+
* error. Used by the proof flow that can't proceed without a signing key.
|
|
27
|
+
*/
|
|
28
|
+
export declare function requireEthPrivateKey(projectDir?: string): string;
|
|
29
|
+
/**
|
|
30
|
+
* Persist a raw eth private key to the project `.env` as
|
|
31
|
+
* `RECLAIM_PRIVATE_KEY=0x…` (upsert; mode 0600; `.env` added to `.gitignore`).
|
|
32
|
+
* Used by `issue_credentials` (generate) and `import_credentials` (supplied
|
|
33
|
+
* hex). Returns the derived address and the `.env` path.
|
|
34
|
+
*/
|
|
35
|
+
export declare function writeEthKey(privateKeyHex: string, projectDir?: string): {
|
|
36
|
+
path: string;
|
|
37
|
+
address: string;
|
|
38
|
+
};
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Eth proof-owner key resolution — the raw secp256k1 private key passed to
|
|
3
|
+
* attestor-core when the agent creates a local claim. It's a plain 0x-hex
|
|
4
|
+
* Ethereum private key (no PEM), resolved from, in order:
|
|
5
|
+
*
|
|
6
|
+
* 1. `process.env.RECLAIM_PRIVATE_KEY` — a 0x-hex 32-byte scalar.
|
|
7
|
+
* 2. A `.env` file in the project root — its `RECLAIM_PRIVATE_KEY=0x…` line.
|
|
8
|
+
* 3. A key file holding the raw 0x-hex scalar, at `RECLAIM_PRIVATE_KEY_FILE`
|
|
9
|
+
* (absolute or project-relative).
|
|
10
|
+
* 4. Absent — the caller offers to generate one or asks the dev for a key.
|
|
11
|
+
*
|
|
12
|
+
* Generated/imported keys are written to the project `.env` (mode 0600, and the
|
|
13
|
+
* file is added to `.gitignore`). NO `~/.reclaim` caching. This is a LOCAL
|
|
14
|
+
* signing key only — unrelated to org auth (the org secret) or encryption
|
|
15
|
+
* (the X25519 decrypt key).
|
|
16
|
+
*/
|
|
17
|
+
import { deriveFromPrivateKey } from '@reclaimprotocol/client';
|
|
18
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
19
|
+
import { isAbsolute, join } from 'node:path';
|
|
20
|
+
import { findProjectRoot } from "../../../paths.js";
|
|
21
|
+
const ENV_VAR = 'RECLAIM_PRIVATE_KEY';
|
|
22
|
+
/** The dotenv file the agent reads from / writes the key to. */
|
|
23
|
+
export const ENV_FILE = '.env';
|
|
24
|
+
/** Validate + normalize a raw Ethereum private key to lowercase 0x-hex. */
|
|
25
|
+
export function normalizeEthHex(value) {
|
|
26
|
+
const v = value.trim().replace(/^['"]|['"]$/g, '');
|
|
27
|
+
if (!/^(0x)?[0-9a-fA-F]{64}$/.test(v)) {
|
|
28
|
+
throw new Error('not a valid Ethereum private key (expected a 32-byte / 64-hex scalar)');
|
|
29
|
+
}
|
|
30
|
+
return '0x' + v.replace(/^0x/, '').toLowerCase();
|
|
31
|
+
}
|
|
32
|
+
/** Read `RECLAIM_PRIVATE_KEY` from a dotenv file (simple KEY=VALUE parse). */
|
|
33
|
+
function readDotenvKey(path) {
|
|
34
|
+
if (!existsSync(path)) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
for (const line of readFileSync(path, 'utf8').split('\n')) {
|
|
38
|
+
const m = line.match(/^\s*RECLAIM_PRIVATE_KEY\s*=\s*(.+?)\s*$/);
|
|
39
|
+
if (m) {
|
|
40
|
+
return m[1];
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
/** The explicit raw-hex key-file path, if `RECLAIM_PRIVATE_KEY_FILE` is set. */
|
|
46
|
+
export function ethKeyFilePath(projectDir = findProjectRoot(process.cwd())) {
|
|
47
|
+
const p = process.env.RECLAIM_PRIVATE_KEY_FILE;
|
|
48
|
+
if (!p) {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
return isAbsolute(p) ? p : join(projectDir, p);
|
|
52
|
+
}
|
|
53
|
+
function resolved(privateKey, source, path) {
|
|
54
|
+
return {
|
|
55
|
+
privateKey,
|
|
56
|
+
address: deriveFromPrivateKey(privateKey).address,
|
|
57
|
+
source,
|
|
58
|
+
...(path ? { path } : {}),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Resolve the eth proof-owner key without prompting. Returns `undefined` when
|
|
63
|
+
* no key is configured anywhere — the caller decides whether to generate or
|
|
64
|
+
* ask for one (see `resolve_owner_key`).
|
|
65
|
+
*/
|
|
66
|
+
export function resolveEthKey(projectDir = findProjectRoot(process.cwd())) {
|
|
67
|
+
const env = process.env.RECLAIM_PRIVATE_KEY;
|
|
68
|
+
if (env?.trim()) {
|
|
69
|
+
return resolved(normalizeEthHex(env), 'env');
|
|
70
|
+
}
|
|
71
|
+
const envPath = join(projectDir, ENV_FILE);
|
|
72
|
+
const fromDotenv = readDotenvKey(envPath);
|
|
73
|
+
if (fromDotenv) {
|
|
74
|
+
return resolved(normalizeEthHex(fromDotenv), 'dotenv', envPath);
|
|
75
|
+
}
|
|
76
|
+
const keyFile = ethKeyFilePath(projectDir);
|
|
77
|
+
if (keyFile && existsSync(keyFile)) {
|
|
78
|
+
return resolved(normalizeEthHex(readFileSync(keyFile, 'utf8')), 'file', keyFile);
|
|
79
|
+
}
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Resolve the eth proof-owner private key (0x-hex) or throw a clear, actionable
|
|
84
|
+
* error. Used by the proof flow that can't proceed without a signing key.
|
|
85
|
+
*/
|
|
86
|
+
export function requireEthPrivateKey(projectDir = findProjectRoot(process.cwd())) {
|
|
87
|
+
const r = resolveEthKey(projectDir);
|
|
88
|
+
if (!r) {
|
|
89
|
+
throw new Error('No eth proof-owner key found. Set RECLAIM_PRIVATE_KEY (0x-hex), add a '
|
|
90
|
+
+ `RECLAIM_PRIVATE_KEY=0x… line to ${join(projectDir, ENV_FILE)}, or `
|
|
91
|
+
+ 'point RECLAIM_PRIVATE_KEY_FILE at a file holding the raw hex. Run '
|
|
92
|
+
+ 'issue_credentials to generate one, or import_credentials to use a '
|
|
93
|
+
+ 'key you already hold.');
|
|
94
|
+
}
|
|
95
|
+
return r.privateKey;
|
|
96
|
+
}
|
|
97
|
+
/** Append `entry` to the project `.gitignore` if not already present. */
|
|
98
|
+
function ensureGitignored(projectDir, entry) {
|
|
99
|
+
const path = join(projectDir, '.gitignore');
|
|
100
|
+
const current = existsSync(path) ? readFileSync(path, 'utf8') : '';
|
|
101
|
+
if (current.split('\n').some((l) => l.trim() === entry)) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const prefix = current && !current.endsWith('\n') ? '\n' : '';
|
|
105
|
+
writeFileSync(path, current + prefix + entry + '\n');
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Persist a raw eth private key to the project `.env` as
|
|
109
|
+
* `RECLAIM_PRIVATE_KEY=0x…` (upsert; mode 0600; `.env` added to `.gitignore`).
|
|
110
|
+
* Used by `issue_credentials` (generate) and `import_credentials` (supplied
|
|
111
|
+
* hex). Returns the derived address and the `.env` path.
|
|
112
|
+
*/
|
|
113
|
+
export function writeEthKey(privateKeyHex, projectDir = findProjectRoot(process.cwd())) {
|
|
114
|
+
const hex = normalizeEthHex(privateKeyHex);
|
|
115
|
+
const envPath = join(projectDir, ENV_FILE);
|
|
116
|
+
const line = `${ENV_VAR}=${hex}`;
|
|
117
|
+
const existing = existsSync(envPath) ? readFileSync(envPath, 'utf8') : '';
|
|
118
|
+
const re = new RegExp(`^\\s*${ENV_VAR}\\s*=.*$`, 'm');
|
|
119
|
+
let next;
|
|
120
|
+
if (re.test(existing)) {
|
|
121
|
+
next = existing.replace(re, line);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
const prefix = existing && !existing.endsWith('\n') ? '\n' : '';
|
|
125
|
+
next = existing + prefix + line + '\n';
|
|
126
|
+
}
|
|
127
|
+
writeFileSync(envPath, next, { mode: 0o600 });
|
|
128
|
+
ensureGitignored(projectDir, ENV_FILE);
|
|
129
|
+
return { path: envPath, address: deriveFromPrivateKey(hex).address };
|
|
130
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { findProjectRoot } from "../../../paths.js";
|
|
3
|
+
import { defineTool } from "../../server.js";
|
|
4
|
+
import { writeEthKey } from "./eth-key.js";
|
|
5
|
+
export function importTool() {
|
|
6
|
+
return defineTool({
|
|
7
|
+
name: 'import_credentials',
|
|
8
|
+
description: 'Import an eth proof-owner key the dev already holds and persist it ' +
|
|
9
|
+
'to the project `.env` as RECLAIM_PRIVATE_KEY=0x… (mode 0600; `.env` ' +
|
|
10
|
+
'added to .gitignore). Provide EITHER `privateKey` (raw 0x-hex, 64 ' +
|
|
11
|
+
'chars) OR `keyFile` (path to a file holding the raw 0x-hex key). ' +
|
|
12
|
+
'The address is derived locally; the private key is never ' +
|
|
13
|
+
'returned. This is a local signing key only (not registered ' +
|
|
14
|
+
'with any server, ' +
|
|
15
|
+
'unrelated to org auth or encryption).',
|
|
16
|
+
inputSchema: {
|
|
17
|
+
type: 'object',
|
|
18
|
+
properties: {
|
|
19
|
+
privateKey: {
|
|
20
|
+
type: 'string',
|
|
21
|
+
pattern: '^0x?[0-9a-fA-F]{64}$',
|
|
22
|
+
description: 'Raw Ethereum private key, 0x-prefixed hex (64 hex chars).',
|
|
23
|
+
},
|
|
24
|
+
keyFile: {
|
|
25
|
+
type: 'string',
|
|
26
|
+
description: 'Path to a file containing the raw 0x-hex private key ' +
|
|
27
|
+
'(absolute or project-relative).',
|
|
28
|
+
},
|
|
29
|
+
projectDir: {
|
|
30
|
+
type: 'string',
|
|
31
|
+
description: 'Project directory whose `.env` the key is written to. ' +
|
|
32
|
+
'Defaults to the closest ancestor of cwd containing .git or ' +
|
|
33
|
+
'package.json.',
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
}, async (args) => {
|
|
38
|
+
if (!args.privateKey && !args.keyFile) {
|
|
39
|
+
throw new Error('Provide either `privateKey` (0x-hex) or `keyFile`.');
|
|
40
|
+
}
|
|
41
|
+
if (args.privateKey && args.keyFile) {
|
|
42
|
+
throw new Error('Provide only one of `privateKey` or `keyFile`.');
|
|
43
|
+
}
|
|
44
|
+
const projectDir = findProjectRoot(args.projectDir || process.cwd());
|
|
45
|
+
const privateKeyHex = args.keyFile
|
|
46
|
+
? readFileSync(args.keyFile, 'utf8')
|
|
47
|
+
: args.privateKey;
|
|
48
|
+
const { path, address } = writeEthKey(privateKeyHex, projectDir);
|
|
49
|
+
return {
|
|
50
|
+
address,
|
|
51
|
+
path,
|
|
52
|
+
note: 'Eth proof-owner key written to .env as RECLAIM_PRIVATE_KEY ' +
|
|
53
|
+
'(mode 0600). resolve_owner_key resolves it from .env. Keep .env ' +
|
|
54
|
+
'secret — it has been added to .gitignore.',
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// Barrel for the credential tool group: local eth proof-owner key (env/PEM)
|
|
2
|
+
// and the org-token-authenticated builder tools. Import from here.
|
|
3
|
+
export { buildCredentialTools, buildLocalCredentialTools } from "./build.js";
|
|
4
|
+
export { readSession } from "./session-cache.js";
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { generateKeypair } from '@reclaimprotocol/client';
|
|
2
|
+
import { findProjectRoot } from "../../../paths.js";
|
|
3
|
+
import { defineTool } from "../../server.js";
|
|
4
|
+
import { writeEthKey } from "./eth-key.js";
|
|
5
|
+
export function issueTool() {
|
|
6
|
+
return defineTool({
|
|
7
|
+
name: 'issue_credentials',
|
|
8
|
+
description: 'Generate a fresh secp256k1 eth proof-owner key-pair (the key ' +
|
|
9
|
+
'that signs local claim creation) and write the raw private key to ' +
|
|
10
|
+
'the project `.env` as RECLAIM_PRIVATE_KEY=0x… (mode 0600; `.env` ' +
|
|
11
|
+
'added to .gitignore). This is a LOCAL signing key only — it is NOT ' +
|
|
12
|
+
'registered with any server and is unrelated to org auth (the org ' +
|
|
13
|
+
'secret) or encryption (the X25519 decrypt key). ALWAYS confirm with ' +
|
|
14
|
+
'the dev before generating a new key. After writing, run_proof picks ' +
|
|
15
|
+
'it up automatically via resolve_owner_key. The private key is never ' +
|
|
16
|
+
'returned in the response.',
|
|
17
|
+
inputSchema: {
|
|
18
|
+
type: 'object',
|
|
19
|
+
properties: {
|
|
20
|
+
projectDir: {
|
|
21
|
+
type: 'string',
|
|
22
|
+
description: 'Project directory whose `.env` the key is written to. ' +
|
|
23
|
+
'Defaults to the closest ancestor of cwd containing .git or ' +
|
|
24
|
+
'package.json.',
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
}, async (args) => {
|
|
29
|
+
const projectDir = findProjectRoot(args.projectDir || process.cwd());
|
|
30
|
+
const keypair = generateKeypair();
|
|
31
|
+
const { path, address } = writeEthKey(keypair.privateKey, projectDir);
|
|
32
|
+
return {
|
|
33
|
+
address,
|
|
34
|
+
path,
|
|
35
|
+
note: 'Eth proof-owner key written to .env as RECLAIM_PRIVATE_KEY ' +
|
|
36
|
+
'(mode 0600); the private key is NOT in this response on purpose. ' +
|
|
37
|
+
'resolve_owner_key will now resolve it from .env (or set ' +
|
|
38
|
+
'RECLAIM_PRIVATE_KEY in the environment to override). Keep .env ' +
|
|
39
|
+
'secret — it has been added to .gitignore.',
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type RegisteredTool } from '../../server.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Decide which eth proof-owner key `run_proof` should sign with, BEFORE
|
|
4
|
+
* calling it. The key is a raw 0x-hex Ethereum private key, resolved (no
|
|
5
|
+
* `~/.reclaim` cache) from:
|
|
6
|
+
* 1. `RECLAIM_PRIVATE_KEY` in the MCP env
|
|
7
|
+
* 2. a `RECLAIM_PRIVATE_KEY=0x…` line in the project `.env`
|
|
8
|
+
* 3. a file at `RECLAIM_PRIVATE_KEY_FILE` holding the raw hex
|
|
9
|
+
* 4. none → ask the dev to generate (issue_credentials) or provide one
|
|
10
|
+
* (import_credentials), then call again.
|
|
11
|
+
* Never returns the private key — only the derived address.
|
|
12
|
+
*/
|
|
13
|
+
export declare function resolveOwnerKeyTool(): RegisteredTool;
|