0nmcp 2.0.0 → 2.1.0

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/vault/deed.js ADDED
@@ -0,0 +1,319 @@
1
+ // ============================================================
2
+ // 0nMCP — Vault: Business Deed
3
+ // ============================================================
4
+ // Digital Business Asset Transfer System.
5
+ // Packages an entire business's digital assets (API keys, logins,
6
+ // credentials, configurations, workflows, AI prompts) into a
7
+ // single verifiable, transferable, encrypted .0nv container.
8
+ //
9
+ // Lifecycle: CREATE > PACKAGE > ESCROW > ACCEPT > IMPORT > FLIP
10
+ //
11
+ // Patent Pending: US Provisional Patent Application #63/990,046
12
+ // ============================================================
13
+
14
+ import { join } from "path";
15
+ import { homedir } from "os";
16
+ import { existsSync, mkdirSync } from "fs";
17
+ import { assembleContainer, disassembleContainer, inspectContainer, saveContainer, loadContainer } from "./container.js";
18
+ import { LAYER_NAMES } from "./layers.js";
19
+ import { createSeal } from "./seal.js";
20
+ import { generateSigningKeyPair, sign, sha3Hex } from "./crypto-container.js";
21
+ import { registerTransfer, lookupTransfer } from "./registry.js";
22
+ import { collectCredentials } from "./deed-collector.js";
23
+ import { importDeedToSystem } from "./deed-importer.js";
24
+
25
+ const VAULT_DIR = join(homedir(), ".0n", "vault");
26
+ const DEED_VERSION = "1.0.0";
27
+
28
+ function ensureVaultDir() {
29
+ if (!existsSync(VAULT_DIR)) mkdirSync(VAULT_DIR, { recursive: true });
30
+ }
31
+
32
+ // ── Deed Metadata Builder ───────────────────────────────────
33
+
34
+ function buildDeedMetadata(options, services, credentialCount) {
35
+ return {
36
+ deed: {
37
+ version: DEED_VERSION,
38
+ type: "business_deed",
39
+ business: {
40
+ name: options.name || "Unnamed Business",
41
+ domain: options.domain || null,
42
+ description: options.description || null,
43
+ valuation: options.valuation || null,
44
+ currency: options.currency || "USD",
45
+ },
46
+ creator: {
47
+ name: options.creatorName || null,
48
+ email: options.creatorEmail || null,
49
+ },
50
+ services,
51
+ credential_count: credentialCount,
52
+ transfer_history: [],
53
+ created: new Date().toISOString(),
54
+ },
55
+ };
56
+ }
57
+
58
+ // ── BusinessDeed Class ──────────────────────────────────────
59
+
60
+ export class BusinessDeed {
61
+
62
+ /**
63
+ * Create a new Business Deed — package credentials into a .0nv file.
64
+ *
65
+ * @param {Object} options
66
+ * @param {string} options.name - Business name
67
+ * @param {string} [options.domain] - Business domain
68
+ * @param {string} [options.description] - Business description
69
+ * @param {number} [options.valuation] - Business valuation
70
+ * @param {string} [options.currency] - Currency code (default: USD)
71
+ * @param {string} [options.creatorName] - Creator's name
72
+ * @param {string} [options.creatorEmail] - Creator's email
73
+ * @param {Object} [options.credentials] - Pre-structured credentials { service: { field: value } }
74
+ * @param {Array} [options.workflows] - Workflow definitions
75
+ * @param {Object} [options.envVars] - Environment variables
76
+ * @param {Object} [options.mcpConfigs] - MCP server configurations
77
+ * @param {Object} [options.siteProfiles] - Site/CRO profiles
78
+ * @param {Object} [options.aiBrain] - AI agent data, prompts, memory
79
+ * @param {string} options.passphrase - Encryption passphrase
80
+ * @param {string} [options.output] - Output file path
81
+ * @param {Array} [options.escrowParties] - Escrow party definitions
82
+ * @param {Object} [options.accessMatrix] - Per-party layer access
83
+ * @returns {Promise<Object>} Created deed info
84
+ */
85
+ async create(options) {
86
+ const {
87
+ credentials = {},
88
+ workflows = [],
89
+ envVars = {},
90
+ mcpConfigs = {},
91
+ siteProfiles = {},
92
+ aiBrain = {},
93
+ passphrase,
94
+ output,
95
+ escrowParties = [],
96
+ accessMatrix = {},
97
+ } = options;
98
+
99
+ if (!passphrase) throw new Error("Passphrase is required");
100
+
101
+ // Determine services from credentials
102
+ const services = Object.keys(credentials);
103
+ const credentialCount = services.reduce((sum, svc) => sum + Object.keys(credentials[svc]).length, 0);
104
+
105
+ // Build deed metadata
106
+ const deedMeta = buildDeedMetadata(options, services, credentialCount);
107
+
108
+ // Assemble all 7 layers
109
+ const layers = {};
110
+ if (workflows.length > 0) layers.workflows = workflows;
111
+ if (Object.keys(credentials).length > 0) layers.credentials = credentials;
112
+ if (Object.keys(envVars).length > 0) layers.env_vars = envVars;
113
+ if (Object.keys(mcpConfigs).length > 0) layers.mcp_configs = mcpConfigs;
114
+ if (Object.keys(siteProfiles).length > 0) layers.site_profiles = siteProfiles;
115
+ if (Object.keys(aiBrain).length > 0) layers.ai_brain = aiBrain;
116
+
117
+ // Audit trail always includes deed metadata
118
+ layers.audit_trail = deedMeta;
119
+
120
+ // Ensure at least credentials or some layer has data
121
+ if (Object.keys(layers).length <= 1) {
122
+ throw new Error("Deed must contain at least one data layer (credentials, workflows, env_vars, etc.)");
123
+ }
124
+
125
+ const result = await assembleContainer({
126
+ layers,
127
+ passphrase,
128
+ escrowParties,
129
+ accessMatrix,
130
+ metadata: { type: "business_deed", business: options.name },
131
+ });
132
+
133
+ // Save to file
134
+ ensureVaultDir();
135
+ const filePath = output || join(VAULT_DIR, `deed-${result.transferId}.0nv`);
136
+ const savedPath = saveContainer(result.buffer, filePath);
137
+
138
+ return {
139
+ file: savedPath,
140
+ transferId: result.transferId,
141
+ sealHex: result.sealHex,
142
+ publicKey: result.publicKey.toString("hex"),
143
+ services,
144
+ credentialCount,
145
+ layerCount: result.layerCount,
146
+ layers: result.layers,
147
+ containerSize: result.buffer.length,
148
+ business: deedMeta.deed.business,
149
+ timestamp: new Date(result.timestamp).toISOString(),
150
+ };
151
+ }
152
+
153
+ /**
154
+ * Open a deed — decrypt and return all layer data.
155
+ *
156
+ * @param {string} filePath - Path to .0nv file
157
+ * @param {string} passphrase - Decryption passphrase
158
+ * @param {string[]} [onlyLayers] - Only decrypt these layers
159
+ * @returns {Promise<Object>}
160
+ */
161
+ async open(filePath, passphrase, onlyLayers = null) {
162
+ const buffer = loadContainer(filePath);
163
+ const result = await disassembleContainer(buffer, passphrase, onlyLayers);
164
+
165
+ // Extract deed metadata from audit_trail
166
+ const deedMeta = result.layers.audit_trail?.deed || null;
167
+
168
+ return {
169
+ ...result,
170
+ deed: deedMeta,
171
+ };
172
+ }
173
+
174
+ /**
175
+ * Inspect a deed without decrypting — metadata + seal only.
176
+ *
177
+ * @param {string} filePath
178
+ * @returns {Object}
179
+ */
180
+ inspect(filePath) {
181
+ const buffer = loadContainer(filePath);
182
+ const info = inspectContainer(buffer);
183
+
184
+ // Check registry for transfer history
185
+ const transfer = lookupTransfer(info.metadata.transferId);
186
+
187
+ return {
188
+ ...info,
189
+ type: "business_deed",
190
+ transfer: transfer.found ? transfer.transfer : null,
191
+ };
192
+ }
193
+
194
+ /**
195
+ * Verify deed integrity — Seal of Truth + Ed25519 signature.
196
+ *
197
+ * @param {string} filePath
198
+ * @returns {Object}
199
+ */
200
+ verify(filePath) {
201
+ const buffer = loadContainer(filePath);
202
+ const info = inspectContainer(buffer);
203
+ const transfer = lookupTransfer(info.metadata.transferId);
204
+
205
+ return {
206
+ verified: info.seal.valid && info.signature.valid,
207
+ seal: info.seal,
208
+ signature: info.signature,
209
+ transferId: info.metadata.transferId,
210
+ created: info.metadata.created,
211
+ transfer: transfer.found ? transfer.transfer : null,
212
+ patent: info.patent,
213
+ };
214
+ }
215
+
216
+ /**
217
+ * Accept a deed transfer — buyer signs acceptance with chain of custody.
218
+ * Opens the deed, records the acceptance in the audit trail,
219
+ * and creates a new container with updated transfer history.
220
+ *
221
+ * @param {string} filePath - Path to .0nv deed
222
+ * @param {string} passphrase - Deed passphrase
223
+ * @param {Object} buyer - { name, email }
224
+ * @param {string} [newPassphrase] - Optional new passphrase for re-encrypted deed
225
+ * @param {string} [outputPath] - Optional output path for accepted deed
226
+ * @returns {Promise<Object>}
227
+ */
228
+ async accept(filePath, passphrase, buyer, newPassphrase = null, outputPath = null) {
229
+ // Open existing deed
230
+ const buffer = loadContainer(filePath);
231
+ const result = await disassembleContainer(buffer, passphrase);
232
+
233
+ if (!result.seal.valid || !result.signature.valid) {
234
+ throw new Error("Cannot accept deed — seal or signature verification failed");
235
+ }
236
+
237
+ const deedMeta = result.layers.audit_trail?.deed;
238
+ if (!deedMeta) {
239
+ throw new Error("Not a valid business deed — no deed metadata found in audit_trail");
240
+ }
241
+
242
+ // Record acceptance in transfer history
243
+ const acceptanceRecord = {
244
+ action: "accept",
245
+ from: deedMeta.creator,
246
+ to: { name: buyer.name, email: buyer.email },
247
+ timestamp: new Date().toISOString(),
248
+ originalSeal: result.seal.hash,
249
+ originalTransferId: result.metadata.transferId,
250
+ };
251
+
252
+ deedMeta.transfer_history.push(acceptanceRecord);
253
+ deedMeta.creator = { name: buyer.name, email: buyer.email };
254
+ result.layers.audit_trail.deed = deedMeta;
255
+
256
+ // Re-create container with updated audit trail (optionally with new passphrase)
257
+ const usePassphrase = newPassphrase || passphrase;
258
+ const newResult = await assembleContainer({
259
+ layers: result.layers,
260
+ passphrase: usePassphrase,
261
+ metadata: { type: "business_deed_accepted", buyer: buyer.name },
262
+ });
263
+
264
+ ensureVaultDir();
265
+ const outPath = outputPath || join(VAULT_DIR, `deed-accepted-${newResult.transferId}.0nv`);
266
+ const savedPath = saveContainer(newResult.buffer, outPath);
267
+
268
+ return {
269
+ file: savedPath,
270
+ transferId: newResult.transferId,
271
+ sealHex: newResult.sealHex,
272
+ previousTransferId: result.metadata.transferId,
273
+ previousSeal: result.seal.hash,
274
+ buyer,
275
+ services: deedMeta.services,
276
+ credentialCount: deedMeta.credential_count,
277
+ transferHistory: deedMeta.transfer_history,
278
+ };
279
+ }
280
+
281
+ /**
282
+ * Import a deed — decrypt and write to live system configuration.
283
+ *
284
+ * @param {string} filePath - Path to .0nv deed
285
+ * @param {string} passphrase - Decryption passphrase
286
+ * @param {string} [targetDir] - Target ~/.0n/ directory
287
+ * @returns {Promise<Object>} Import report
288
+ */
289
+ async importDeed(filePath, passphrase, targetDir = null) {
290
+ const buffer = loadContainer(filePath);
291
+ const result = await disassembleContainer(buffer, passphrase);
292
+
293
+ if (!result.seal.valid || !result.signature.valid) {
294
+ throw new Error("Cannot import deed — seal or signature verification failed");
295
+ }
296
+
297
+ return importDeedToSystem(result.layers, targetDir);
298
+ }
299
+
300
+ /**
301
+ * Export — collect credentials from sources and package as deed in one step.
302
+ *
303
+ * @param {Object} sources - { envFile, jsonFile, csvFile, connectionsDir, manual }
304
+ * @param {Object} options - Same as create() options
305
+ * @returns {Promise<Object>}
306
+ */
307
+ async export(sources, options) {
308
+ const collected = await collectCredentials(sources);
309
+
310
+ return this.create({
311
+ ...options,
312
+ credentials: collected.credentials,
313
+ envVars: collected.envVars,
314
+ services: collected.services,
315
+ });
316
+ }
317
+ }
318
+
319
+ export const DEED_VERSION_STR = DEED_VERSION;
@@ -0,0 +1,257 @@
1
+ // ============================================================
2
+ // 0nMCP — Vault: Business Deed MCP Tools
3
+ // ============================================================
4
+ // 6 MCP tools for the Business Deed digital asset transfer system.
5
+ //
6
+ // Patent Pending: US Provisional Patent Application #63/990,046
7
+ // ============================================================
8
+
9
+ import { BusinessDeed } from "./deed.js";
10
+ import { collectCredentials, validateCollected } from "./deed-collector.js";
11
+ import { LAYER_NAMES } from "./layers.js";
12
+
13
+ const deed = new BusinessDeed();
14
+
15
+ /**
16
+ * Register Business Deed tools on an MCP server.
17
+ *
18
+ * @param {import("@modelcontextprotocol/sdk/server/mcp.js").McpServer} server
19
+ * @param {import("zod").ZodType} z
20
+ */
21
+ export function registerDeedTools(server, z) {
22
+
23
+ // ─── deed_create ────────────────────────────────────────────
24
+ server.tool(
25
+ "deed_create",
26
+ `Create a Business Deed — package an entire business's digital assets into a single
27
+ encrypted, verifiable .0nv container file. Includes API keys, credentials, workflows,
28
+ configs, and AI data across 7 semantic layers with Argon2id double-encryption for secrets.
29
+
30
+ This is the digital equivalent of signing over a business deed — one file that proves
31
+ ownership, packages all operational credentials, and enables instant activation.
32
+
33
+ Lifecycle: CREATE > PACKAGE > ESCROW > ACCEPT > IMPORT
34
+
35
+ Patent Pending: US Provisional Patent Application #63/990,046
36
+
37
+ Example: deed_create({
38
+ name: "My SaaS Business",
39
+ passphrase: "secure-pass",
40
+ credentials: { stripe: { apiKey: "sk_..." }, github: { token: "ghp_..." } },
41
+ envVars: { DATABASE_URL: "postgres://..." }
42
+ })`,
43
+ {
44
+ name: z.string().describe("Business name"),
45
+ passphrase: z.string().describe("Encryption passphrase for the deed"),
46
+ domain: z.string().optional().describe("Business domain (e.g., example.com)"),
47
+ description: z.string().optional().describe("Business description"),
48
+ valuation: z.number().optional().describe("Business valuation amount"),
49
+ currency: z.string().optional().describe("Currency code (default: USD)"),
50
+ creatorName: z.string().optional().describe("Creator's name"),
51
+ creatorEmail: z.string().optional().describe("Creator's email"),
52
+ credentials: z.record(z.record(z.string())).optional().describe("Service credentials: { service: { field: value } }"),
53
+ workflows: z.array(z.any()).optional().describe("Workflow definitions to include"),
54
+ envVars: z.record(z.string()).optional().describe("Environment variables to include"),
55
+ mcpConfigs: z.record(z.any()).optional().describe("MCP server configurations"),
56
+ siteProfiles: z.record(z.any()).optional().describe("Site/CRO profiles"),
57
+ aiBrain: z.record(z.any()).optional().describe("AI agent data, prompts, memory"),
58
+ output: z.string().optional().describe("Output .0nv file path"),
59
+ },
60
+ async (params) => {
61
+ try {
62
+ const result = await deed.create(params);
63
+
64
+ return {
65
+ content: [{ type: "text", text: JSON.stringify({
66
+ success: true,
67
+ ...result,
68
+ patent: "US Provisional #63/990,046",
69
+ }, null, 2) }],
70
+ };
71
+ } catch (err) {
72
+ return {
73
+ content: [{ type: "text", text: JSON.stringify({
74
+ success: false, error: err.message,
75
+ }, null, 2) }],
76
+ };
77
+ }
78
+ }
79
+ );
80
+
81
+ // ─── deed_open ──────────────────────────────────────────────
82
+ server.tool(
83
+ "deed_open",
84
+ `Open and decrypt a Business Deed (.0nv file).
85
+ Verifies Ed25519 signature and Seal of Truth, then decrypts all layers.
86
+ Returns credentials, workflows, configs, and deed metadata.
87
+
88
+ Example: deed_open({ file: "deed-abc123.0nv", passphrase: "secure-pass" })`,
89
+ {
90
+ file: z.string().describe("Path to .0nv deed file"),
91
+ passphrase: z.string().describe("Decryption passphrase"),
92
+ layers: z.array(z.string()).optional().describe("Only decrypt these layers (default: all)"),
93
+ },
94
+ async ({ file, passphrase, layers: onlyLayers }) => {
95
+ try {
96
+ const result = await deed.open(file, passphrase, onlyLayers || null);
97
+
98
+ return {
99
+ content: [{ type: "text", text: JSON.stringify({
100
+ success: true,
101
+ ...result,
102
+ }, null, 2) }],
103
+ };
104
+ } catch (err) {
105
+ return {
106
+ content: [{ type: "text", text: JSON.stringify({
107
+ success: false, error: err.message,
108
+ }, null, 2) }],
109
+ };
110
+ }
111
+ }
112
+ );
113
+
114
+ // ─── deed_inspect ───────────────────────────────────────────
115
+ server.tool(
116
+ "deed_inspect",
117
+ `Inspect a Business Deed without decrypting.
118
+ Shows business name, services, layer info, seal verification, and transfer history.
119
+ No passphrase required — all metadata is public.
120
+
121
+ Example: deed_inspect({ file: "deed-abc123.0nv" })`,
122
+ {
123
+ file: z.string().describe("Path to .0nv deed file"),
124
+ },
125
+ async ({ file }) => {
126
+ try {
127
+ const result = deed.inspect(file);
128
+
129
+ return {
130
+ content: [{ type: "text", text: JSON.stringify({
131
+ success: true,
132
+ ...result,
133
+ }, null, 2) }],
134
+ };
135
+ } catch (err) {
136
+ return {
137
+ content: [{ type: "text", text: JSON.stringify({
138
+ success: false, error: err.message,
139
+ }, null, 2) }],
140
+ };
141
+ }
142
+ }
143
+ );
144
+
145
+ // ─── deed_verify ────────────────────────────────────────────
146
+ server.tool(
147
+ "deed_verify",
148
+ `Verify a Business Deed's Seal of Truth and Ed25519 signature.
149
+ Confirms the deed is authentic, unmodified, and from the original creator.
150
+ Also checks the transfer registry for chain of custody.
151
+
152
+ Example: deed_verify({ file: "deed-abc123.0nv" })`,
153
+ {
154
+ file: z.string().describe("Path to .0nv deed file"),
155
+ },
156
+ async ({ file }) => {
157
+ try {
158
+ const result = deed.verify(file);
159
+
160
+ return {
161
+ content: [{ type: "text", text: JSON.stringify({
162
+ success: true,
163
+ ...result,
164
+ }, null, 2) }],
165
+ };
166
+ } catch (err) {
167
+ return {
168
+ content: [{ type: "text", text: JSON.stringify({
169
+ success: false, error: err.message,
170
+ }, null, 2) }],
171
+ };
172
+ }
173
+ }
174
+ );
175
+
176
+ // ─── deed_accept ────────────────────────────────────────────
177
+ server.tool(
178
+ "deed_accept",
179
+ `Accept a Business Deed transfer — buyer signs acceptance with chain of custody.
180
+ Creates a new deed container with updated transfer history and optionally re-encrypts
181
+ with a new passphrase for the buyer.
182
+
183
+ Example: deed_accept({
184
+ file: "deed-abc123.0nv",
185
+ passphrase: "seller-pass",
186
+ buyerName: "New Owner",
187
+ buyerEmail: "buyer@example.com"
188
+ })`,
189
+ {
190
+ file: z.string().describe("Path to .0nv deed file"),
191
+ passphrase: z.string().describe("Current deed passphrase"),
192
+ buyerName: z.string().describe("Buyer's name"),
193
+ buyerEmail: z.string().describe("Buyer's email"),
194
+ newPassphrase: z.string().optional().describe("New passphrase for re-encrypted deed"),
195
+ output: z.string().optional().describe("Output path for accepted deed"),
196
+ },
197
+ async ({ file, passphrase, buyerName, buyerEmail, newPassphrase, output }) => {
198
+ try {
199
+ const result = await deed.accept(
200
+ file,
201
+ passphrase,
202
+ { name: buyerName, email: buyerEmail },
203
+ newPassphrase || null,
204
+ output || null
205
+ );
206
+
207
+ return {
208
+ content: [{ type: "text", text: JSON.stringify({
209
+ success: true,
210
+ ...result,
211
+ }, null, 2) }],
212
+ };
213
+ } catch (err) {
214
+ return {
215
+ content: [{ type: "text", text: JSON.stringify({
216
+ success: false, error: err.message,
217
+ }, null, 2) }],
218
+ };
219
+ }
220
+ }
221
+ );
222
+
223
+ // ─── deed_import ────────────────────────────────────────────
224
+ server.tool(
225
+ "deed_import",
226
+ `Import a Business Deed — decrypt and write credentials to live system config.
227
+ Writes .0n connection files, .env file, MCP configs, workflows, and AI brain data.
228
+ The deed's Seal of Truth and signature are verified before import.
229
+
230
+ Example: deed_import({ file: "deed-abc123.0nv", passphrase: "secure-pass" })`,
231
+ {
232
+ file: z.string().describe("Path to .0nv deed file"),
233
+ passphrase: z.string().describe("Decryption passphrase"),
234
+ targetDir: z.string().optional().describe("Target directory (default: ~/.0n/)"),
235
+ },
236
+ async ({ file, passphrase, targetDir }) => {
237
+ try {
238
+ const result = await deed.importDeed(file, passphrase, targetDir || null);
239
+
240
+ return {
241
+ content: [{ type: "text", text: JSON.stringify({
242
+ success: true,
243
+ ...result,
244
+ }, null, 2) }],
245
+ };
246
+ } catch (err) {
247
+ return {
248
+ content: [{ type: "text", text: JSON.stringify({
249
+ success: false, error: err.message,
250
+ }, null, 2) }],
251
+ };
252
+ }
253
+ }
254
+ );
255
+ }
256
+
257
+ export const DEED_TOOL_COUNT = 6;