neozip-mcp 0.1.0-beta
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/.cursor/mcp.json.global.example +10 -0
- package/CHANGELOG.md +16 -0
- package/DOCUMENTATION.md +40 -0
- package/LICENSE +16 -0
- package/README.md +223 -0
- package/SECURITY.md +37 -0
- package/dist/account/account-state.js +86 -0
- package/dist/account/format-account-status.js +37 -0
- package/dist/account/identity-provision.js +75 -0
- package/dist/account/identity-wrap.js +69 -0
- package/dist/account/profile-crypto.js +47 -0
- package/dist/account/profile-store.js +108 -0
- package/dist/account/require-account.js +29 -0
- package/dist/account/token-service-identity.js +395 -0
- package/dist/account/types.js +2 -0
- package/dist/account/wallet-evm.js +39 -0
- package/dist/archive/blockchain-status.js +303 -0
- package/dist/archive/crypto-self.js +114 -0
- package/dist/archive/detect-text.js +56 -0
- package/dist/archive/embed-metadata.js +283 -0
- package/dist/archive/encryption.js +166 -0
- package/dist/archive/extract-entry-buffer.js +18 -0
- package/dist/archive/find-entry.js +21 -0
- package/dist/archive/grep-content.js +141 -0
- package/dist/archive/identity-key.js +176 -0
- package/dist/archive/manifest.js +55 -0
- package/dist/archive/merkle.js +31 -0
- package/dist/archive/metadata-paths.js +14 -0
- package/dist/archive/mint-archive.js +61 -0
- package/dist/archive/open-archive.js +23 -0
- package/dist/archive/read-entry-buffer.js +11 -0
- package/dist/archive/read-entry-content.js +51 -0
- package/dist/archive/recipient-access.js +26 -0
- package/dist/archive/recipient-decrypt.js +21 -0
- package/dist/archive/recipient-lookup.js +55 -0
- package/dist/archive/timestamp-network.js +54 -0
- package/dist/config/capabilities.js +37 -0
- package/dist/config/index.js +74 -0
- package/dist/connect-cli.js +312 -0
- package/dist/connection/coordinator.js +74 -0
- package/dist/connection/credentials.js +29 -0
- package/dist/connection/crypto.js +56 -0
- package/dist/connection/dump.js +79 -0
- package/dist/connection/incomplete-setup.js +81 -0
- package/dist/connection/interactive.js +814 -0
- package/dist/connection/legacy-profile-reader.js +47 -0
- package/dist/connection/magic-link.js +138 -0
- package/dist/connection/migrate.js +76 -0
- package/dist/connection/onboarding.js +524 -0
- package/dist/connection/origin.js +63 -0
- package/dist/connection/phase.js +93 -0
- package/dist/connection/phone.js +20 -0
- package/dist/connection/promote-active.js +53 -0
- package/dist/connection/reset.js +20 -0
- package/dist/connection/setup-guidance.js +154 -0
- package/dist/connection/status-report.js +40 -0
- package/dist/connection/store.js +352 -0
- package/dist/connection/token-auth.js +42 -0
- package/dist/connection/types.js +2 -0
- package/dist/connection/wallet-setup.js +70 -0
- package/dist/constants/wallet-identity.js +11 -0
- package/dist/index.js +47 -0
- package/dist/load-env.js +16 -0
- package/dist/neozipkit-node.js +11 -0
- package/dist/register/resources.js +14 -0
- package/dist/register/tools.js +77 -0
- package/dist/resources/zip-resource.js +40 -0
- package/dist/resources/zip-uri.js +23 -0
- package/dist/security/auth.js +28 -0
- package/dist/security/capabilities.js +85 -0
- package/dist/security/rate-limiter.js +43 -0
- package/dist/security/resource-limiter.js +44 -0
- package/dist/security/sandbox.js +61 -0
- package/dist/server.js +32 -0
- package/dist/startup-account-gate.js +101 -0
- package/dist/startup-summary.js +40 -0
- package/dist/token-service/require-configured.js +23 -0
- package/dist/tools/account.js +504 -0
- package/dist/tools/compress.js +237 -0
- package/dist/tools/connect-status.js +143 -0
- package/dist/tools/extract.js +62 -0
- package/dist/tools/grep-entries.js +42 -0
- package/dist/tools/identity-status.js +157 -0
- package/dist/tools/info.js +147 -0
- package/dist/tools/list.js +118 -0
- package/dist/tools/lookup-recipient.js +37 -0
- package/dist/tools/mint.js +41 -0
- package/dist/tools/read-entry.js +35 -0
- package/dist/tools/search-entries.js +71 -0
- package/dist/tools/stamp.js +60 -0
- package/dist/tools/test.js +90 -0
- package/dist/tools/token-service-account.js +143 -0
- package/dist/tools/upgrade.js +60 -0
- package/dist/tools/verify.js +75 -0
- package/dist/tools/wallet-config-status.js +119 -0
- package/dist/tools/wallet-info.js +64 -0
- package/dist/translators/index.js +106 -0
- package/dist/types/index.js +7 -0
- package/dist/util/mask.js +30 -0
- package/dist/util/token-service-fetch.js +23 -0
- package/dist/vendor/neozipkit-pro.js +3 -0
- package/docs/NEOZIP_CONNECTION_STORE.md +238 -0
- package/docs/NEOZIP_CONNECT_CLI.md +185 -0
- package/docs/OPERATIONS.md +992 -0
- package/docs/examples/CLAUDE.md.example +22 -0
- package/docs/examples/claude/skills/neozip-mcp/SKILL.md +54 -0
- package/docs/examples/claude/skills/neozip-notarization/SKILL.md +75 -0
- package/docs/examples/mcp.json.claude.example +11 -0
- package/docs/examples/neozip-mcp-cursor-rule.mdc +31 -0
- package/docs/installation-guides/INSTALL_CLAUDE_CODE.md +286 -0
- package/docs/installation-guides/INSTALL_CLAUDE_WORKSPACE.md +301 -0
- package/docs/installation-guides/README.md +76 -0
- package/package.json +99 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getTokenServiceUrl, registerEmail, verifyEmailCode, } from "neozip-blockchain/token-service";
|
|
3
|
+
import { maskEmail } from "../util/mask.js";
|
|
4
|
+
import { successResult, errorResult } from "../types/index.js";
|
|
5
|
+
const serverUrlOptions = z
|
|
6
|
+
.object({
|
|
7
|
+
serverUrl: z.string().optional(),
|
|
8
|
+
})
|
|
9
|
+
.optional();
|
|
10
|
+
function resolveServerUrl(config, serverUrl) {
|
|
11
|
+
return getTokenServiceUrl({
|
|
12
|
+
serverUrl: serverUrl || config.tokenServiceUrl || undefined,
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
function buildServiceOptions(config, serverUrl) {
|
|
16
|
+
const options = {
|
|
17
|
+
serverUrl: resolveServerUrl(config, serverUrl),
|
|
18
|
+
};
|
|
19
|
+
if (config.debug)
|
|
20
|
+
options.debug = true;
|
|
21
|
+
return options;
|
|
22
|
+
}
|
|
23
|
+
async function fetchEmailVerificationStatus(email, serverUrl) {
|
|
24
|
+
const base = serverUrl.replace(/\/+$/, "");
|
|
25
|
+
const url = `${base}/auth/email-status?email=${encodeURIComponent(email)}`;
|
|
26
|
+
const response = await fetch(url);
|
|
27
|
+
if (!response.ok) {
|
|
28
|
+
const body = await response.text();
|
|
29
|
+
return {
|
|
30
|
+
verified: false,
|
|
31
|
+
error: `HTTP ${response.status}: ${body.slice(0, 200)}`,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
const data = (await response.json());
|
|
35
|
+
return { verified: Boolean(data.verified) };
|
|
36
|
+
}
|
|
37
|
+
export const tokenServiceStatusParameters = z.object({
|
|
38
|
+
email: z.string().optional(),
|
|
39
|
+
options: serverUrlOptions,
|
|
40
|
+
});
|
|
41
|
+
export async function executeTokenServiceStatus(args, resourceLimiter, config) {
|
|
42
|
+
try {
|
|
43
|
+
const email = (args.email || config.recipientEmail || "").trim();
|
|
44
|
+
if (!email) {
|
|
45
|
+
return errorResult("Email required. Pass email or run neozip-connect to configure an account.");
|
|
46
|
+
}
|
|
47
|
+
const serverUrl = resolveServerUrl(config, args.options?.serverUrl);
|
|
48
|
+
const result = await resourceLimiter.withTimeout(async () => {
|
|
49
|
+
const status = await fetchEmailVerificationStatus(email, serverUrl);
|
|
50
|
+
if (status.error) {
|
|
51
|
+
throw new Error(status.error);
|
|
52
|
+
}
|
|
53
|
+
const lines = [];
|
|
54
|
+
lines.push("NeoZip Token Service account status");
|
|
55
|
+
lines.push(`Service URL: ${serverUrl}`);
|
|
56
|
+
lines.push(`Email: ${maskEmail(email)}`);
|
|
57
|
+
lines.push(`Verified: ${status.verified ? "yes" : "no"}`);
|
|
58
|
+
if (status.verified) {
|
|
59
|
+
lines.push("");
|
|
60
|
+
lines.push("This email can be used for timestamping after neozip-connect verify and reload MCP.");
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
lines.push("");
|
|
64
|
+
lines.push("Email is not verified. Use token_service_register to send a code, then token_service_verify with the 6-digit code from your email.");
|
|
65
|
+
}
|
|
66
|
+
return lines.join("\n");
|
|
67
|
+
}, "token_service_status");
|
|
68
|
+
return successResult(result);
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
return errorResult(err instanceof Error ? err.message : String(err));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
export const tokenServiceRegisterParameters = z.object({
|
|
75
|
+
email: z.string(),
|
|
76
|
+
options: serverUrlOptions,
|
|
77
|
+
});
|
|
78
|
+
export async function executeTokenServiceRegister(args, resourceLimiter, config) {
|
|
79
|
+
try {
|
|
80
|
+
const email = args.email.trim();
|
|
81
|
+
if (!email) {
|
|
82
|
+
return errorResult("Email address is required.");
|
|
83
|
+
}
|
|
84
|
+
const serviceOptions = buildServiceOptions(config, args.options?.serverUrl);
|
|
85
|
+
const result = await resourceLimiter.withTimeout(async () => {
|
|
86
|
+
const response = await registerEmail(email, serviceOptions);
|
|
87
|
+
if (!response.success) {
|
|
88
|
+
throw new Error(response.error || response.message || "Registration failed.");
|
|
89
|
+
}
|
|
90
|
+
const lines = [];
|
|
91
|
+
lines.push("Verification email sent.");
|
|
92
|
+
lines.push(`Service URL: ${serviceOptions.serverUrl}`);
|
|
93
|
+
lines.push(`Email: ${maskEmail(email)}`);
|
|
94
|
+
if (response.message)
|
|
95
|
+
lines.push(response.message);
|
|
96
|
+
lines.push("");
|
|
97
|
+
lines.push("Check your inbox for a 6-digit code, then call token_service_verify with the same email and code.");
|
|
98
|
+
return lines.join("\n");
|
|
99
|
+
}, "token_service_register");
|
|
100
|
+
return successResult(result);
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
return errorResult(err instanceof Error ? err.message : String(err));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
export const tokenServiceVerifyParameters = z.object({
|
|
107
|
+
email: z.string(),
|
|
108
|
+
code: z.string(),
|
|
109
|
+
options: serverUrlOptions,
|
|
110
|
+
});
|
|
111
|
+
export async function executeTokenServiceVerify(args, resourceLimiter, config) {
|
|
112
|
+
try {
|
|
113
|
+
const email = args.email.trim();
|
|
114
|
+
const code = args.code.trim();
|
|
115
|
+
if (!email) {
|
|
116
|
+
return errorResult("Email address is required.");
|
|
117
|
+
}
|
|
118
|
+
if (!code) {
|
|
119
|
+
return errorResult("Verification code is required.");
|
|
120
|
+
}
|
|
121
|
+
const serviceOptions = buildServiceOptions(config, args.options?.serverUrl);
|
|
122
|
+
const result = await resourceLimiter.withTimeout(async () => {
|
|
123
|
+
const response = await verifyEmailCode(email, code, serviceOptions);
|
|
124
|
+
if (!response.success) {
|
|
125
|
+
throw new Error(response.error || response.message || "Verification failed.");
|
|
126
|
+
}
|
|
127
|
+
const lines = [];
|
|
128
|
+
lines.push("Email verified successfully.");
|
|
129
|
+
lines.push(`Service URL: ${serviceOptions.serverUrl}`);
|
|
130
|
+
lines.push(`Email: ${maskEmail(email)}`);
|
|
131
|
+
if (response.message)
|
|
132
|
+
lines.push(response.message);
|
|
133
|
+
lines.push("");
|
|
134
|
+
lines.push("Run neozip-connect verify with this email and code to store credentials, reload MCP, then use compress with timestamp: true or stamp.");
|
|
135
|
+
return lines.join("\n");
|
|
136
|
+
}, "token_service_verify");
|
|
137
|
+
return successResult(result);
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
return errorResult(err instanceof Error ? err.message : String(err));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=token-service-account.js.map
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import * as fs from "fs";
|
|
3
|
+
import { upgradeTimestampArchive } from "../archive/embed-metadata.js";
|
|
4
|
+
import { requireTokenServiceConfigured } from "../token-service/require-configured.js";
|
|
5
|
+
import { successResult, errorResult } from "../types/index.js";
|
|
6
|
+
export const upgradeTimestampedParameters = z.object({
|
|
7
|
+
input: z.string(),
|
|
8
|
+
output: z.string().optional(),
|
|
9
|
+
options: z
|
|
10
|
+
.object({
|
|
11
|
+
serverUrl: z.string().optional(),
|
|
12
|
+
wait: z.boolean().optional(),
|
|
13
|
+
overwrite: z.boolean().optional(),
|
|
14
|
+
})
|
|
15
|
+
.optional(),
|
|
16
|
+
});
|
|
17
|
+
export async function executeUpgradeTimestamped(args, sandbox, resourceLimiter, config) {
|
|
18
|
+
try {
|
|
19
|
+
const tsErr = requireTokenServiceConfigured("upgrade_timestamped", config);
|
|
20
|
+
if (tsErr)
|
|
21
|
+
return errorResult(tsErr);
|
|
22
|
+
const inputPath = await sandbox.validatePath(args.input);
|
|
23
|
+
await resourceLimiter.checkFileSize(inputPath);
|
|
24
|
+
const overwrite = args.options?.overwrite ?? false;
|
|
25
|
+
const outputPath = args.output
|
|
26
|
+
? await sandbox.validatePath(args.output, true)
|
|
27
|
+
: inputPath.replace(/\.(nzip|zip)$/i, "-upgraded.$1");
|
|
28
|
+
if (fs.existsSync(outputPath) && !overwrite) {
|
|
29
|
+
return errorResult(`Output file ${outputPath} already exists. Set overwrite: true to overwrite.`);
|
|
30
|
+
}
|
|
31
|
+
const result = await resourceLimiter.withTimeout(async () => {
|
|
32
|
+
const upgraded = await upgradeTimestampArchive(inputPath, outputPath, config, {
|
|
33
|
+
serverUrl: args.options?.serverUrl,
|
|
34
|
+
wait: args.options?.wait,
|
|
35
|
+
});
|
|
36
|
+
const lines = [];
|
|
37
|
+
lines.push("Upgrade Timestamped archive completed.");
|
|
38
|
+
lines.push(`Input: ${upgraded.inputPath}`);
|
|
39
|
+
lines.push(`Output: ${upgraded.outputPath}`);
|
|
40
|
+
lines.push("Archive type: timestamped (META-INF/TIMESTAMP.NZIP embedded)");
|
|
41
|
+
lines.push(`Merkle root: ${upgraded.merkleRoot}`);
|
|
42
|
+
if (upgraded.transactionHash) {
|
|
43
|
+
lines.push(`Transaction: ${upgraded.transactionHash}`);
|
|
44
|
+
}
|
|
45
|
+
if (upgraded.network)
|
|
46
|
+
lines.push(`Network: ${upgraded.network}`);
|
|
47
|
+
if (upgraded.blockNumber != null) {
|
|
48
|
+
lines.push(`Block: ${upgraded.blockNumber}`);
|
|
49
|
+
}
|
|
50
|
+
if (upgraded.tokenId)
|
|
51
|
+
lines.push(`Token ID: ${upgraded.tokenId}`);
|
|
52
|
+
return lines.join("\n");
|
|
53
|
+
}, "upgrade_timestamped");
|
|
54
|
+
return successResult(result);
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
return errorResult(err instanceof Error ? err.message : String(err));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=upgrade.js.map
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import neozipkit from "neozipkit";
|
|
3
|
+
const { HashCalculator } = neozipkit;
|
|
4
|
+
import { openArchive } from "../archive/open-archive.js";
|
|
5
|
+
import { extractEntryToBuffer } from "../archive/extract-entry-buffer.js";
|
|
6
|
+
import neoBlockchain from "neozip-blockchain";
|
|
7
|
+
const { ZipkitVerifier, TOKENIZED_METADATA } = neoBlockchain;
|
|
8
|
+
import { successResult, errorResult } from "../types/index.js";
|
|
9
|
+
export const verifyParameters = z.object({
|
|
10
|
+
input: z.string(),
|
|
11
|
+
options: z
|
|
12
|
+
.object({
|
|
13
|
+
password: z.string().optional(),
|
|
14
|
+
network: z.string().optional(),
|
|
15
|
+
skipHash: z.boolean().optional(),
|
|
16
|
+
})
|
|
17
|
+
.optional(),
|
|
18
|
+
});
|
|
19
|
+
export async function executeVerify(args, sandbox, resourceLimiter, config) {
|
|
20
|
+
try {
|
|
21
|
+
const result = await resourceLimiter.withTimeout(async () => {
|
|
22
|
+
const { archivePath, zip, entries } = await openArchive(args.input, sandbox, resourceLimiter, config, { password: args.options?.password });
|
|
23
|
+
const tokenEntry = entries.find((e) => (e.fileName || e.filename) === TOKENIZED_METADATA);
|
|
24
|
+
if (!tokenEntry) {
|
|
25
|
+
return "No token metadata (TOKEN.NZIP) found in archive. This ZIP has not been tokenized.";
|
|
26
|
+
}
|
|
27
|
+
const tokenBuffer = await extractEntryToBuffer(zip, tokenEntry);
|
|
28
|
+
if (!tokenBuffer) {
|
|
29
|
+
return "Failed to extract token metadata from archive.";
|
|
30
|
+
}
|
|
31
|
+
const verifier = new ZipkitVerifier({
|
|
32
|
+
debug: false,
|
|
33
|
+
skipHash: args.options?.skipHash,
|
|
34
|
+
});
|
|
35
|
+
const metadataResult = await verifier.extractTokenMetadata(tokenBuffer);
|
|
36
|
+
if (!metadataResult || !metadataResult.success || !metadataResult.metadata) {
|
|
37
|
+
return "Failed to parse token metadata.";
|
|
38
|
+
}
|
|
39
|
+
// Compute merkle root from entries
|
|
40
|
+
let calculatedMerkleRoot;
|
|
41
|
+
const hashCalc = new HashCalculator({ enableAccumulation: true });
|
|
42
|
+
let hasHashes = false;
|
|
43
|
+
for (const entry of entries) {
|
|
44
|
+
const e = entry;
|
|
45
|
+
if ((e.fileName || e.filename) === TOKENIZED_METADATA)
|
|
46
|
+
continue;
|
|
47
|
+
if (e.sha256) {
|
|
48
|
+
hashCalc.addHash(Buffer.from(e.sha256, "hex"));
|
|
49
|
+
hasHashes = true;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (hasHashes) {
|
|
53
|
+
calculatedMerkleRoot = hashCalc.merkleRoot();
|
|
54
|
+
}
|
|
55
|
+
const verificationResult = await verifier.verifyToken(metadataResult.metadata, calculatedMerkleRoot ?? null, { debug: false, skipHash: args.options?.skipHash });
|
|
56
|
+
const lines = [];
|
|
57
|
+
lines.push(`Verification: ${archivePath}`);
|
|
58
|
+
lines.push(`Status: ${verificationResult.success ? "VERIFIED" : "FAILED"}`);
|
|
59
|
+
if (verificationResult.verificationDetails?.tokenId)
|
|
60
|
+
lines.push(`Token ID: ${verificationResult.verificationDetails.tokenId}`);
|
|
61
|
+
if (verificationResult.verificationDetails?.network)
|
|
62
|
+
lines.push(`Network: ${verificationResult.verificationDetails.network}`);
|
|
63
|
+
if (calculatedMerkleRoot)
|
|
64
|
+
lines.push(`Calculated merkle root: ${calculatedMerkleRoot}`);
|
|
65
|
+
if (verificationResult.message)
|
|
66
|
+
lines.push(`Message: ${verificationResult.message}`);
|
|
67
|
+
return lines.join("\n");
|
|
68
|
+
}, "verify");
|
|
69
|
+
return successResult(result);
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
return errorResult(err instanceof Error ? err.message : String(err));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=verify.js.map
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getTokenServiceUrl } from "neozip-blockchain/token-service";
|
|
3
|
+
import { hasConfiguredIdentityKey } from "../archive/identity-key.js";
|
|
4
|
+
import { getConnectionStorePath } from "../connection/credentials.js";
|
|
5
|
+
import { computeConnectionPhase } from "../connection/phase.js";
|
|
6
|
+
import { maskEmail } from "../util/mask.js";
|
|
7
|
+
import { successResult, errorResult } from "../types/index.js";
|
|
8
|
+
export const walletConfigStatusParameters = z.object({
|
|
9
|
+
options: z
|
|
10
|
+
.object({
|
|
11
|
+
format: z.enum(["text", "json"]).optional(),
|
|
12
|
+
})
|
|
13
|
+
.optional(),
|
|
14
|
+
});
|
|
15
|
+
export function buildWalletConfigStatusReport(config, auth) {
|
|
16
|
+
const tokenServiceUrl = getTokenServiceUrl({
|
|
17
|
+
serverUrl: config.tokenServiceUrl || undefined,
|
|
18
|
+
});
|
|
19
|
+
let recipientDecryptUnwrapPath = null;
|
|
20
|
+
if (config.identityPrivateKeyHex?.trim()) {
|
|
21
|
+
recipientDecryptUnwrapPath = "env-hex";
|
|
22
|
+
}
|
|
23
|
+
else if (config.tokenServiceAccessToken?.trim() &&
|
|
24
|
+
config.walletKey?.trim()) {
|
|
25
|
+
recipientDecryptUnwrapPath = "wallet+token";
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
capabilities: config.capabilities,
|
|
29
|
+
capabilitiesMode: config.capabilitiesMode,
|
|
30
|
+
walletKey: {
|
|
31
|
+
configured: auth.hasWalletKey(),
|
|
32
|
+
source: config.walletKeySource,
|
|
33
|
+
},
|
|
34
|
+
network: {
|
|
35
|
+
value: config.network,
|
|
36
|
+
source: config.networkSource,
|
|
37
|
+
},
|
|
38
|
+
recipientEmail: {
|
|
39
|
+
configured: Boolean(config.recipientEmail?.trim()),
|
|
40
|
+
masked: config.recipientEmail
|
|
41
|
+
? maskEmail(config.recipientEmail)
|
|
42
|
+
: null,
|
|
43
|
+
source: config.recipientEmailSource,
|
|
44
|
+
},
|
|
45
|
+
tokenServiceUrl,
|
|
46
|
+
flags: {
|
|
47
|
+
identityPrivateKeyHex: Boolean(config.identityPrivateKeyHex?.trim()),
|
|
48
|
+
tokenServiceAccessToken: Boolean(config.tokenServiceAccessToken?.trim()),
|
|
49
|
+
apiKey: Boolean(config.apiKey?.trim()),
|
|
50
|
+
},
|
|
51
|
+
connection: {
|
|
52
|
+
storePath: getConnectionStorePath(),
|
|
53
|
+
activeId: config.mcpProfileActiveId,
|
|
54
|
+
phase: computeConnectionPhase(),
|
|
55
|
+
},
|
|
56
|
+
readiness: {
|
|
57
|
+
mintReady: auth.hasWalletKey(),
|
|
58
|
+
tokenizeReady: auth.hasWalletKey(),
|
|
59
|
+
timestampReady: Boolean(config.recipientEmail?.trim()),
|
|
60
|
+
recipientDecryptConfigured: hasConfiguredIdentityKey(config),
|
|
61
|
+
recipientDecryptUnwrapPath,
|
|
62
|
+
},
|
|
63
|
+
relatedTools: ["wallet_info", "identity_status", "token_service_status"],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
export function formatWalletConfigStatusText(report) {
|
|
67
|
+
const lines = [];
|
|
68
|
+
lines.push("Wallet & MCP configuration status");
|
|
69
|
+
lines.push("=================================");
|
|
70
|
+
const modeHint = report.capabilitiesMode === "auto" ? " (auto)" : "";
|
|
71
|
+
lines.push(`Capabilities: ${report.capabilities.join(", ")}${modeHint}`);
|
|
72
|
+
lines.push("");
|
|
73
|
+
lines.push("Sources: neozip-connect profile (~/.neozip/connection/)");
|
|
74
|
+
lines.push(` EVM wallet key: ${report.walletKey.configured ? "configured" : "not configured"} (source: ${report.walletKey.source ?? "none"})`);
|
|
75
|
+
lines.push(` Network: ${report.network.value} (source: ${report.network.source})`);
|
|
76
|
+
if (report.recipientEmail.configured) {
|
|
77
|
+
lines.push(` Recipient email: ${report.recipientEmail.masked} (source: ${report.recipientEmail.source})`);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
lines.push(" Recipient email: not configured");
|
|
81
|
+
}
|
|
82
|
+
lines.push(` Token Service URL: ${report.tokenServiceUrl}`);
|
|
83
|
+
lines.push("");
|
|
84
|
+
lines.push("Connection:");
|
|
85
|
+
lines.push(` Store: ${report.connection.storePath}`);
|
|
86
|
+
lines.push(` Active connection: ${report.connection.activeId ?? "none"}`);
|
|
87
|
+
lines.push(` Phase: ${report.connection.phase}`);
|
|
88
|
+
lines.push("");
|
|
89
|
+
lines.push("Secret flags (values never shown):");
|
|
90
|
+
lines.push(` NEOZIP_IDENTITY_PRIVATE_KEY_HEX: ${report.flags.identityPrivateKeyHex ? "set" : "not set"}`);
|
|
91
|
+
lines.push(` Token Service access token (connect): ${report.flags.tokenServiceAccessToken ? "configured" : "not configured"}`);
|
|
92
|
+
lines.push(` NEOZIP_MCP_API_KEY: ${report.flags.apiKey ? "set" : "not set"}`);
|
|
93
|
+
lines.push("");
|
|
94
|
+
lines.push("Readiness:");
|
|
95
|
+
lines.push(` mint: ${report.readiness.mintReady ? "ready" : "needs neozip-connect wallet"}`);
|
|
96
|
+
lines.push(` tokenize (compress): ${report.readiness.tokenizeReady ? "ready" : "needs neozip-connect wallet"}`);
|
|
97
|
+
lines.push(` timestamp/stamp: ${report.readiness.timestampReady ? "ready" : "needs neozip-connect verified email"}`);
|
|
98
|
+
lines.push(` recipient decrypt configured: ${report.readiness.recipientDecryptConfigured ? "yes" : "no"}`);
|
|
99
|
+
if (report.readiness.recipientDecryptUnwrapPath) {
|
|
100
|
+
lines.push(` recipient decrypt path: ${report.readiness.recipientDecryptUnwrapPath}`);
|
|
101
|
+
}
|
|
102
|
+
lines.push("");
|
|
103
|
+
lines.push(`Related: ${report.relatedTools.join(", ")} (balance/address via wallet_info; Token Service crypto via identity_status)`);
|
|
104
|
+
return lines.join("\n");
|
|
105
|
+
}
|
|
106
|
+
export async function executeWalletConfigStatus(args, config, auth) {
|
|
107
|
+
try {
|
|
108
|
+
const report = buildWalletConfigStatusReport(config, auth);
|
|
109
|
+
const format = args.options?.format ?? "text";
|
|
110
|
+
if (format === "json") {
|
|
111
|
+
return successResult(JSON.stringify({ success: true, ...report }, null, 2));
|
|
112
|
+
}
|
|
113
|
+
return successResult(formatWalletConfigStatusText(report));
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
return errorResult(err instanceof Error ? err.message : String(err));
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=wallet-config-status.js.map
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { ethers } from "ethers";
|
|
3
|
+
import neoBlockchain from "neozip-blockchain";
|
|
4
|
+
const { getNetworkByName, getChainIdByName, getSupportedNetworkNames } = neoBlockchain;
|
|
5
|
+
import { AuthGuard } from "../security/auth.js";
|
|
6
|
+
import { successResult, errorResult } from "../types/index.js";
|
|
7
|
+
export const walletInfoParameters = z.object({
|
|
8
|
+
options: z
|
|
9
|
+
.object({
|
|
10
|
+
network: z.string().optional(),
|
|
11
|
+
})
|
|
12
|
+
.optional(),
|
|
13
|
+
});
|
|
14
|
+
export async function executeWalletInfo(args, auth, resourceLimiter, defaultNetwork) {
|
|
15
|
+
try {
|
|
16
|
+
const result = await resourceLimiter.withTimeout(async () => {
|
|
17
|
+
const network = args.options?.network || defaultNetwork;
|
|
18
|
+
const lines = [];
|
|
19
|
+
lines.push("Wallet & Network Status");
|
|
20
|
+
lines.push("=======================");
|
|
21
|
+
lines.push(`Network: ${network}`);
|
|
22
|
+
const chainId = getChainIdByName(network);
|
|
23
|
+
if (chainId) {
|
|
24
|
+
lines.push(`Chain ID: ${chainId}`);
|
|
25
|
+
}
|
|
26
|
+
const contractConfig = getNetworkByName(network);
|
|
27
|
+
if (contractConfig) {
|
|
28
|
+
lines.push(`Contract: ${contractConfig.address}`);
|
|
29
|
+
}
|
|
30
|
+
if (auth.hasWalletKey()) {
|
|
31
|
+
const key = auth.getWalletKey();
|
|
32
|
+
lines.push(`Wallet key: ${AuthGuard.maskKey(key)}`);
|
|
33
|
+
try {
|
|
34
|
+
const wallet = new ethers.Wallet(key);
|
|
35
|
+
lines.push(`Address: ${wallet.address}`);
|
|
36
|
+
if (contractConfig?.rpcUrls?.length) {
|
|
37
|
+
try {
|
|
38
|
+
const provider = new ethers.JsonRpcProvider(contractConfig.rpcUrls[0]);
|
|
39
|
+
const balance = await provider.getBalance(wallet.address);
|
|
40
|
+
lines.push(`Balance: ${ethers.formatEther(balance)} ETH`);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
lines.push("Balance: unable to fetch (RPC unavailable)");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
lines.push("Wallet: invalid key format");
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
lines.push("Wallet key: not configured");
|
|
53
|
+
}
|
|
54
|
+
lines.push("");
|
|
55
|
+
lines.push(`Supported networks: ${getSupportedNetworkNames().join(", ")}`);
|
|
56
|
+
return lines.join("\n");
|
|
57
|
+
}, "wallet_info");
|
|
58
|
+
return successResult(result);
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
return errorResult(err instanceof Error ? err.message : String(err));
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=wallet-info.js.map
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
export function translateText(content) {
|
|
2
|
+
return {
|
|
3
|
+
content,
|
|
4
|
+
format: "text",
|
|
5
|
+
mimeType: "text/plain",
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
export function translateJson(content, options) {
|
|
9
|
+
const maxChars = options?.maxChars ?? 50000;
|
|
10
|
+
try {
|
|
11
|
+
const parsed = JSON.parse(content);
|
|
12
|
+
const pretty = JSON.stringify(parsed, null, 2);
|
|
13
|
+
if (pretty.length <= maxChars) {
|
|
14
|
+
return {
|
|
15
|
+
content: pretty,
|
|
16
|
+
format: "json",
|
|
17
|
+
mimeType: "application/json",
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
const truncated = pretty.slice(0, maxChars);
|
|
21
|
+
return {
|
|
22
|
+
content: `${truncated}\n\n/* JSON truncated: ${pretty.length} characters total */`,
|
|
23
|
+
format: "json",
|
|
24
|
+
truncated: true,
|
|
25
|
+
mimeType: "application/json",
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return {
|
|
30
|
+
content,
|
|
31
|
+
format: "json-invalid",
|
|
32
|
+
mimeType: "text/plain",
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export function translateCsv(content, options) {
|
|
37
|
+
const maxChars = options?.maxChars ?? 20000;
|
|
38
|
+
const maxRows = 50;
|
|
39
|
+
const maxCols = 20;
|
|
40
|
+
const lines = content.split(/\r?\n/).filter((l) => l.length > 0);
|
|
41
|
+
if (lines.length === 0) {
|
|
42
|
+
return { content: "", format: "csv", mimeType: "text/markdown" };
|
|
43
|
+
}
|
|
44
|
+
const rows = lines.slice(0, maxRows + 1).map((line) => {
|
|
45
|
+
const cells = [];
|
|
46
|
+
let current = "";
|
|
47
|
+
let inQuotes = false;
|
|
48
|
+
for (let i = 0; i < line.length; i++) {
|
|
49
|
+
const ch = line[i];
|
|
50
|
+
if (ch === '"') {
|
|
51
|
+
inQuotes = !inQuotes;
|
|
52
|
+
}
|
|
53
|
+
else if (ch === "," && !inQuotes) {
|
|
54
|
+
cells.push(current.trim());
|
|
55
|
+
current = "";
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
current += ch;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
cells.push(current.trim());
|
|
62
|
+
return cells.slice(0, maxCols);
|
|
63
|
+
});
|
|
64
|
+
const colCount = Math.max(...rows.map((r) => r.length));
|
|
65
|
+
const header = rows[0] ?? [];
|
|
66
|
+
const dataRows = rows.slice(1);
|
|
67
|
+
const pad = (cells) => {
|
|
68
|
+
const padded = [...cells];
|
|
69
|
+
while (padded.length < colCount)
|
|
70
|
+
padded.push("");
|
|
71
|
+
return padded;
|
|
72
|
+
};
|
|
73
|
+
const mdLines = [];
|
|
74
|
+
mdLines.push(`| ${pad(header).join(" | ")} |`);
|
|
75
|
+
mdLines.push(`| ${Array(colCount).fill("---").join(" | ")} |`);
|
|
76
|
+
for (const row of dataRows) {
|
|
77
|
+
mdLines.push(`| ${pad(row).join(" | ")} |`);
|
|
78
|
+
}
|
|
79
|
+
let result = mdLines.join("\n");
|
|
80
|
+
let truncated = false;
|
|
81
|
+
if (lines.length > maxRows + 1) {
|
|
82
|
+
result += `\n\n/* CSV truncated: showing ${maxRows} of ${lines.length - 1} data rows */`;
|
|
83
|
+
truncated = true;
|
|
84
|
+
}
|
|
85
|
+
if (result.length > maxChars) {
|
|
86
|
+
result = result.slice(0, maxChars) + "\n\n/* CSV output truncated to fit character limit */";
|
|
87
|
+
truncated = true;
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
content: result,
|
|
91
|
+
format: "csv-markdown",
|
|
92
|
+
truncated,
|
|
93
|
+
mimeType: "text/markdown",
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
export function translateContent(entryPath, content, options) {
|
|
97
|
+
const ext = entryPath.includes(".")
|
|
98
|
+
? entryPath.slice(entryPath.lastIndexOf(".")).toLowerCase()
|
|
99
|
+
: "";
|
|
100
|
+
if (ext === ".json")
|
|
101
|
+
return translateJson(content, options);
|
|
102
|
+
if (ext === ".csv")
|
|
103
|
+
return translateCsv(content, options);
|
|
104
|
+
return translateText(content);
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { spkiBase64ToRawHex } from "../archive/recipient-lookup.js";
|
|
2
|
+
export function maskEmail(email) {
|
|
3
|
+
const normalized = email.trim();
|
|
4
|
+
const at = normalized.indexOf("@");
|
|
5
|
+
if (at <= 0)
|
|
6
|
+
return "***";
|
|
7
|
+
const local = normalized.slice(0, at);
|
|
8
|
+
const domain = normalized.slice(at);
|
|
9
|
+
if (local.length <= 2)
|
|
10
|
+
return `${local[0] ?? ""}***${domain}`;
|
|
11
|
+
return `${local.slice(0, 2)}***${domain}`;
|
|
12
|
+
}
|
|
13
|
+
/** Short fingerprint for X25519 SPKI (base64) or 64-char raw hex. */
|
|
14
|
+
export function maskPublicKey(spkiOrHex) {
|
|
15
|
+
const trimmed = spkiOrHex.trim();
|
|
16
|
+
let rawHex;
|
|
17
|
+
try {
|
|
18
|
+
if (/^[0-9a-fA-F]{64}$/.test(trimmed.replace(/^0x/i, ""))) {
|
|
19
|
+
rawHex = trimmed.replace(/^0x/i, "").toLowerCase();
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
rawHex = spkiBase64ToRawHex(trimmed);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return "invalid";
|
|
27
|
+
}
|
|
28
|
+
return `${rawHex.slice(0, 8)}…`;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=mask.js.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
function fetchCauseCode(err) {
|
|
2
|
+
if (err == null || typeof err !== "object")
|
|
3
|
+
return null;
|
|
4
|
+
const cause = err.cause;
|
|
5
|
+
if (cause == null || typeof cause !== "object")
|
|
6
|
+
return null;
|
|
7
|
+
const code = cause.code;
|
|
8
|
+
return typeof code === "string" ? code : null;
|
|
9
|
+
}
|
|
10
|
+
/** User-facing message when Token Service HTTP calls fail (e.g. local server not running). */
|
|
11
|
+
export function formatTokenServiceFetchError(baseUrl, err) {
|
|
12
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
13
|
+
const causeCode = fetchCauseCode(err);
|
|
14
|
+
if (message === "fetch failed" ||
|
|
15
|
+
causeCode === "ECONNREFUSED" ||
|
|
16
|
+
causeCode === "ENOTFOUND" ||
|
|
17
|
+
causeCode === "ECONNRESET" ||
|
|
18
|
+
causeCode === "EHOSTUNREACH") {
|
|
19
|
+
return `Token Service unreachable at ${baseUrl}. Is it running?`;
|
|
20
|
+
}
|
|
21
|
+
return `Token Service request failed (${baseUrl}): ${message}`;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=token-service-fetch.js.map
|