cyberdyne-mcp 0.6.19 → 0.6.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/dist/client.js +26 -0
- package/dist/onboard.js +10 -6
- package/package.json +1 -1
- package/src/client.ts +24 -0
- package/src/onboard.ts +18 -6
package/dist/client.js
CHANGED
|
@@ -93,6 +93,32 @@ export function saveWallet(walletKey) {
|
|
|
93
93
|
export function saveTokenAndWallet(token, walletKey) {
|
|
94
94
|
return writeConfigFile({ identity_token: token.trim(), walletKey: walletKey.trim() });
|
|
95
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* Last resort (config save failed): write the live minted key to a FRESH 0600 recovery
|
|
98
|
+
* file — never to stderr/logs and never into a thrown error (which would reach the LLM
|
|
99
|
+
* via the MCP tool-result channel). Returns the path, or "" if even this fails.
|
|
100
|
+
*/
|
|
101
|
+
export function saveKeyRecovery(token) {
|
|
102
|
+
try {
|
|
103
|
+
mkdirSync(join(homedir(), ".cyberdyne"), { recursive: true, mode: 0o700 });
|
|
104
|
+
const p = join(homedir(), ".cyberdyne", `key-recovery-${Date.now()}.txt`);
|
|
105
|
+
let flags = FS.O_WRONLY | FS.O_CREAT | FS.O_EXCL;
|
|
106
|
+
if (typeof FS.O_NOFOLLOW === "number")
|
|
107
|
+
flags |= FS.O_NOFOLLOW;
|
|
108
|
+
const fd = openSync(p, flags, 0o600);
|
|
109
|
+
try {
|
|
110
|
+
fchmodSync(fd, 0o600);
|
|
111
|
+
writeSync(fd, token.trim() + "\n");
|
|
112
|
+
}
|
|
113
|
+
finally {
|
|
114
|
+
closeSync(fd);
|
|
115
|
+
}
|
|
116
|
+
return p;
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return "";
|
|
120
|
+
}
|
|
121
|
+
}
|
|
96
122
|
/** Resolve config: token from env first, then the saved login. URL from env only. */
|
|
97
123
|
export function readConfig(env = process.env) {
|
|
98
124
|
const apiUrl = (env.CYBERDYNE_API_URL || DEFAULT_API_URL).replace(/\/+$/, "");
|
package/dist/onboard.js
CHANGED
|
@@ -24,7 +24,7 @@ import { generatePrivateKey, privateKeyToAccount, mnemonicToAccount } from "viem
|
|
|
24
24
|
import { bytesToHex } from "viem";
|
|
25
25
|
import { validateMnemonic } from "@scure/bip39";
|
|
26
26
|
import { wordlist } from "@scure/bip39/wordlists/english";
|
|
27
|
-
import { readConfig, readSavedWalletKey, saveTokenAndWallet, configPath as configFilePath } from "./client.js";
|
|
27
|
+
import { readConfig, readSavedWalletKey, saveTokenAndWallet, saveKeyRecovery, configPath as configFilePath } from "./client.js";
|
|
28
28
|
/** Normalise a private key to the 0x-prefixed form viem expects. */
|
|
29
29
|
function normalizeKey(pk) {
|
|
30
30
|
return (pk.startsWith("0x") ? pk : `0x${pk}`);
|
|
@@ -233,11 +233,15 @@ export async function onboard(env = process.env, opts = {}) {
|
|
|
233
233
|
configPath = saveTokenAndWallet(apiKey, privateKey);
|
|
234
234
|
}
|
|
235
235
|
catch (e) {
|
|
236
|
-
//
|
|
237
|
-
// the
|
|
238
|
-
// LLM's context
|
|
239
|
-
|
|
240
|
-
|
|
236
|
+
// The key is ALREADY minted server-side. Write it to a FRESH 0600 recovery file —
|
|
237
|
+
// never the raw key to stderr/logs, and never into the thrown error (which travels
|
|
238
|
+
// through the MCP tool-result channel into the calling LLM's context). Reference the
|
|
239
|
+
// file by PATH only, so no transcript or log ever captures the credential. (M1.)
|
|
240
|
+
const recoveryPath = saveKeyRecovery(apiKey);
|
|
241
|
+
console.error(`[cyberdyne-mcp] minted agent key but failed to save config.${recoveryPath
|
|
242
|
+
? ` The key was written to ${recoveryPath} (chmod 600) — load it with: cat ${recoveryPath} | npx cyberdyne-mcp login then delete that file.`
|
|
243
|
+
: " Could not write a recovery file; re-run onboard for a fresh key and revoke the orphan in the app."}`);
|
|
244
|
+
throw new Error(`minted agent key ${apiKey.slice(0, 10)}… but failed to save ~/.cyberdyne/config.json: ${e instanceof Error ? e.message : String(e)}.${recoveryPath ? " The full key was written to a 0600 recovery file (path shown in the console/stderr)." : " Re-run onboard for a fresh key."}`);
|
|
241
245
|
}
|
|
242
246
|
// 6. (optional) auto-link Bankr — zero human interaction. If a bk_ key is supplied
|
|
243
247
|
// (opts or CYBERDYNE_BANKR_KEY), use it ONCE to connect the agent's Bankr project
|
package/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -110,6 +110,30 @@ export function saveTokenAndWallet(token: string, walletKey: string): string {
|
|
|
110
110
|
return writeConfigFile({ identity_token: token.trim(), walletKey: walletKey.trim() });
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
/**
|
|
114
|
+
* Last resort (config save failed): write the live minted key to a FRESH 0600 recovery
|
|
115
|
+
* file — never to stderr/logs and never into a thrown error (which would reach the LLM
|
|
116
|
+
* via the MCP tool-result channel). Returns the path, or "" if even this fails.
|
|
117
|
+
*/
|
|
118
|
+
export function saveKeyRecovery(token: string): string {
|
|
119
|
+
try {
|
|
120
|
+
mkdirSync(join(homedir(), ".cyberdyne"), { recursive: true, mode: 0o700 });
|
|
121
|
+
const p = join(homedir(), ".cyberdyne", `key-recovery-${Date.now()}.txt`);
|
|
122
|
+
let flags = FS.O_WRONLY | FS.O_CREAT | FS.O_EXCL;
|
|
123
|
+
if (typeof FS.O_NOFOLLOW === "number") flags |= FS.O_NOFOLLOW;
|
|
124
|
+
const fd = openSync(p, flags, 0o600);
|
|
125
|
+
try {
|
|
126
|
+
fchmodSync(fd, 0o600);
|
|
127
|
+
writeSync(fd, token.trim() + "\n");
|
|
128
|
+
} finally {
|
|
129
|
+
closeSync(fd);
|
|
130
|
+
}
|
|
131
|
+
return p;
|
|
132
|
+
} catch {
|
|
133
|
+
return "";
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
113
137
|
/** Resolve config: token from env first, then the saved login. URL from env only. */
|
|
114
138
|
export function readConfig(env: NodeJS.ProcessEnv = process.env): CyberdyneConfig {
|
|
115
139
|
const apiUrl = (env.CYBERDYNE_API_URL || DEFAULT_API_URL).replace(/\/+$/, "");
|
package/src/onboard.ts
CHANGED
|
@@ -25,7 +25,7 @@ import { bytesToHex } from "viem";
|
|
|
25
25
|
import { validateMnemonic } from "@scure/bip39";
|
|
26
26
|
import { wordlist } from "@scure/bip39/wordlists/english";
|
|
27
27
|
import type { PrivateKeyAccount } from "viem/accounts";
|
|
28
|
-
import { readConfig, readSavedWalletKey, saveTokenAndWallet, configPath as configFilePath } from "./client.js";
|
|
28
|
+
import { readConfig, readSavedWalletKey, saveTokenAndWallet, saveKeyRecovery, configPath as configFilePath } from "./client.js";
|
|
29
29
|
|
|
30
30
|
/** Normalise a private key to the 0x-prefixed form viem expects. */
|
|
31
31
|
function normalizeKey(pk: string): `0x${string}` {
|
|
@@ -278,11 +278,23 @@ export async function onboard(
|
|
|
278
278
|
try {
|
|
279
279
|
configPath = saveTokenAndWallet(apiKey, privateKey);
|
|
280
280
|
} catch (e) {
|
|
281
|
-
//
|
|
282
|
-
// the
|
|
283
|
-
// LLM's context
|
|
284
|
-
|
|
285
|
-
|
|
281
|
+
// The key is ALREADY minted server-side. Write it to a FRESH 0600 recovery file —
|
|
282
|
+
// never the raw key to stderr/logs, and never into the thrown error (which travels
|
|
283
|
+
// through the MCP tool-result channel into the calling LLM's context). Reference the
|
|
284
|
+
// file by PATH only, so no transcript or log ever captures the credential. (M1.)
|
|
285
|
+
const recoveryPath = saveKeyRecovery(apiKey);
|
|
286
|
+
console.error(
|
|
287
|
+
`[cyberdyne-mcp] minted agent key but failed to save config.${
|
|
288
|
+
recoveryPath
|
|
289
|
+
? ` The key was written to ${recoveryPath} (chmod 600) — load it with: cat ${recoveryPath} | npx cyberdyne-mcp login then delete that file.`
|
|
290
|
+
: " Could not write a recovery file; re-run onboard for a fresh key and revoke the orphan in the app."
|
|
291
|
+
}`,
|
|
292
|
+
);
|
|
293
|
+
throw new Error(
|
|
294
|
+
`minted agent key ${apiKey.slice(0, 10)}… but failed to save ~/.cyberdyne/config.json: ${e instanceof Error ? e.message : String(e)}.${
|
|
295
|
+
recoveryPath ? " The full key was written to a 0600 recovery file (path shown in the console/stderr)." : " Re-run onboard for a fresh key."
|
|
296
|
+
}`,
|
|
297
|
+
);
|
|
286
298
|
}
|
|
287
299
|
|
|
288
300
|
// 6. (optional) auto-link Bankr — zero human interaction. If a bk_ key is supplied
|