0nmcp 1.7.0 → 2.0.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.
@@ -0,0 +1,224 @@
1
+ /**
2
+ * ═══════════════════════════════════════════════════════════════════════════
3
+ * 0nMCP — Command Runner
4
+ * ═══════════════════════════════════════════════════════════════════════════
5
+ *
6
+ * Executes named RUNs (command aliases) defined in the SWITCH file.
7
+ *
8
+ * Pipeline commands run built-in actions sequentially:
9
+ * verify, platforms, list, serve, connect
10
+ *
11
+ * Workflow commands run .0n workflow files via the WorkflowRunner.
12
+ *
13
+ * ═══════════════════════════════════════════════════════════════════════════
14
+ */
15
+
16
+ import path from 'path';
17
+ import os from 'os';
18
+ import fs from 'fs';
19
+ import { resolveInputs, parseCommandArgs } from './commands.js';
20
+
21
+ const DOT_ON_DIR = path.join(os.homedir(), '.0n');
22
+
23
+ // Colors
24
+ const c = {
25
+ reset: '\x1b[0m',
26
+ bright: '\x1b[1m',
27
+ red: '\x1b[31m',
28
+ green: '\x1b[32m',
29
+ yellow: '\x1b[33m',
30
+ blue: '\x1b[34m',
31
+ cyan: '\x1b[36m',
32
+ };
33
+
34
+ /**
35
+ * Run a command from the SWITCH file
36
+ * @param {string} alias - The command alias
37
+ * @param {object} def - The command definition
38
+ * @param {string[]} rawArgs - CLI arguments after the alias
39
+ */
40
+ export async function runCommand(alias, def, rawArgs = []) {
41
+ const type = def.type || 'workflow';
42
+ const { args, flags } = parseCommandArgs(rawArgs);
43
+
44
+ console.log(`${c.bright}Running: ${c.cyan}${def.name || alias}${c.reset}`);
45
+ if (def.description) console.log(` ${def.description}\n`);
46
+
47
+ const start = Date.now();
48
+
49
+ try {
50
+ switch (type) {
51
+ case 'pipeline':
52
+ await runPipeline(def, args, flags);
53
+ break;
54
+ case 'workflow':
55
+ await runWorkflow(def, args, flags);
56
+ break;
57
+ default:
58
+ console.log(`${c.red}Unknown command type: ${type}${c.reset}`);
59
+ process.exit(1);
60
+ }
61
+
62
+ const elapsed = Date.now() - start;
63
+ console.log(`\n${c.green}${c.bright}Done${c.reset} ${c.green}(${elapsed}ms)${c.reset}`);
64
+ } catch (err) {
65
+ console.log(`\n${c.red}${c.bright}Failed:${c.reset} ${c.red}${err.message}${c.reset}`);
66
+ process.exit(1);
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Execute a pipeline command — sequential built-in actions
72
+ */
73
+ async function runPipeline(def, args, flags) {
74
+ const steps = def.steps || [];
75
+
76
+ if (steps.length === 0) {
77
+ console.log(`${c.yellow}No steps defined in this command.${c.reset}`);
78
+ return;
79
+ }
80
+
81
+ for (let i = 0; i < steps.length; i++) {
82
+ const step = steps[i];
83
+ const action = step.action;
84
+ const stepNum = `[${i + 1}/${steps.length}]`;
85
+
86
+ console.log(`${c.cyan}${stepNum}${c.reset} ${step.description || action}...`);
87
+
88
+ await executePipelineAction(action, step, args, flags);
89
+
90
+ console.log(`${c.green} ✓${c.reset} ${action} complete\n`);
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Execute a single pipeline action
96
+ */
97
+ async function executePipelineAction(action, step, args, flags) {
98
+ switch (action) {
99
+ case 'verify': {
100
+ const { verifyAll } = await import('./engine/validator.js');
101
+ const connectionsDir = path.join(DOT_ON_DIR, 'connections');
102
+
103
+ if (!fs.existsSync(connectionsDir)) {
104
+ console.log(` ${c.yellow}No connections found.${c.reset}`);
105
+ return;
106
+ }
107
+
108
+ const files = fs.readdirSync(connectionsDir).filter(f => f.endsWith('.0n'));
109
+ const connections = {};
110
+ for (const file of files) {
111
+ try {
112
+ const data = JSON.parse(fs.readFileSync(path.join(connectionsDir, file), 'utf8'));
113
+ if (data.$0n?.sealed) continue;
114
+ connections[data.service] = { credentials: data.auth?.credentials || {} };
115
+ } catch { /* skip */ }
116
+ }
117
+
118
+ if (Object.keys(connections).length === 0) {
119
+ console.log(` ${c.yellow}No unsealed connections to verify.${c.reset}`);
120
+ return;
121
+ }
122
+
123
+ const { results, summary } = await verifyAll(connections);
124
+ for (const [service, result] of Object.entries(results)) {
125
+ const icon = result.valid ? `${c.green} ✓` : `${c.red} ✗`;
126
+ const latency = result.latency_ms ? ` (${result.latency_ms}ms)` : '';
127
+ console.log(`${icon}${c.reset} ${service}${latency}${result.error ? ` — ${result.error}` : ''}`);
128
+ }
129
+ console.log(` ${summary.valid}/${summary.total} valid`);
130
+ break;
131
+ }
132
+
133
+ case 'platforms': {
134
+ const { getPlatformInfo } = await import('./engine/platforms.js');
135
+ const info = getPlatformInfo();
136
+ for (const p of info) {
137
+ const status = p.installed ? `${c.green}installed${c.reset}` : `${c.blue}available${c.reset}`;
138
+ console.log(` ${p.installed ? '●' : '○'} ${p.name} (${status})`);
139
+ }
140
+ break;
141
+ }
142
+
143
+ case 'list': {
144
+ const connectionsDir = path.join(DOT_ON_DIR, 'connections');
145
+ if (!fs.existsSync(connectionsDir)) {
146
+ console.log(` ${c.yellow}No connections found.${c.reset}`);
147
+ return;
148
+ }
149
+
150
+ const files = fs.readdirSync(connectionsDir).filter(f => f.endsWith('.0n'));
151
+ for (const file of files) {
152
+ try {
153
+ const data = JSON.parse(fs.readFileSync(path.join(connectionsDir, file), 'utf8'));
154
+ console.log(` ${c.green}●${c.reset} ${data.$0n?.name || data.service} (${file})`);
155
+ } catch {
156
+ console.log(` ${c.red}●${c.reset} ${file} (error)`);
157
+ }
158
+ }
159
+ break;
160
+ }
161
+
162
+ case 'serve': {
163
+ const port = step.port || flags.port || 3001;
164
+ const host = step.host || flags.host || '0.0.0.0';
165
+ console.log(` Starting server on ${host}:${port}...`);
166
+ const { startServer } = await import('./server.js');
167
+ await startServer({ port: Number(port), host: String(host) });
168
+ break;
169
+ }
170
+
171
+ default:
172
+ console.log(` ${c.yellow}Unknown pipeline action: ${action}${c.reset}`);
173
+ }
174
+ }
175
+
176
+ /**
177
+ * Execute a workflow command — runs a .0n workflow file
178
+ */
179
+ async function runWorkflow(def, args, flags) {
180
+ const workflowName = def.workflow;
181
+ if (!workflowName) {
182
+ console.log(`${c.red}No workflow specified in command definition.${c.reset}`);
183
+ process.exit(1);
184
+ }
185
+
186
+ // Resolve inputs from CLI args/flags
187
+ const inputs = def.inputs ? resolveInputs(def.inputs, args, flags) : {};
188
+
189
+ const { ConnectionManager } = await import('./connections.js');
190
+ const { WorkflowRunner } = await import('./workflow.js');
191
+
192
+ const connections = new ConnectionManager();
193
+ const runner = new WorkflowRunner(connections);
194
+
195
+ if (Object.keys(inputs).length > 0) {
196
+ console.log(`${c.bright}Inputs:${c.reset}`, JSON.stringify(inputs, null, 2));
197
+ console.log('');
198
+ }
199
+
200
+ const result = await runner.run({ workflowPath: workflowName, inputs });
201
+
202
+ if (result.success) {
203
+ console.log(`${c.green}${c.bright}Workflow completed${c.reset}`);
204
+ } else {
205
+ console.log(`${c.red}${c.bright}Workflow failed${c.reset}`);
206
+ }
207
+
208
+ console.log(` Steps: ${result.stepsSuccessful}/${result.stepsExecuted} successful`);
209
+ console.log(` Duration: ${result.duration}ms`);
210
+
211
+ if (result.outputs && Object.keys(result.outputs).length > 0) {
212
+ console.log(`\n${c.bright}Outputs:${c.reset}`);
213
+ console.log(JSON.stringify(result.outputs, null, 2));
214
+ }
215
+
216
+ if (result.errors?.length > 0) {
217
+ console.log(`\n${c.red}Errors:${c.reset}`);
218
+ for (const err of result.errors) {
219
+ console.log(` ${c.red}●${c.reset} ${err.service}.${err.action}: ${err.error}`);
220
+ }
221
+ }
222
+
223
+ if (!result.success) process.exit(1);
224
+ }
package/commands.js ADDED
@@ -0,0 +1,115 @@
1
+ /**
2
+ * ═══════════════════════════════════════════════════════════════════════════
3
+ * 0nMCP — Named Runs / Command Aliases
4
+ * ═══════════════════════════════════════════════════════════════════════════
5
+ *
6
+ * Loads command aliases from the SWITCH file (~/.0n/0n-setup.0n) and makes
7
+ * them available as CLI commands: `0nmcp launch`, `0nmcp hello`, etc.
8
+ *
9
+ * Command types:
10
+ * - pipeline: Sequential built-in actions (verify, platforms, list, serve)
11
+ * - workflow: Run a named .0n workflow from ~/.0n/workflows/
12
+ *
13
+ * ═══════════════════════════════════════════════════════════════════════════
14
+ */
15
+
16
+ import { readFileSync, existsSync } from 'fs';
17
+ import { join } from 'path';
18
+ import { homedir } from 'os';
19
+
20
+ const DOT_ON_DIR = join(homedir(), '.0n');
21
+ const DEFAULT_SWITCH = join(DOT_ON_DIR, '0n-setup.0n');
22
+
23
+ /**
24
+ * Load commands from a SWITCH file
25
+ * @param {string} [switchPath] - Path to SWITCH file. Defaults to ~/.0n/0n-setup.0n
26
+ * @returns {Map<string, object>} Map of alias → command definition
27
+ */
28
+ export function loadCommands(switchPath) {
29
+ const filePath = switchPath || DEFAULT_SWITCH;
30
+ if (!existsSync(filePath)) return new Map();
31
+
32
+ try {
33
+ const raw = readFileSync(filePath, 'utf8');
34
+ const data = JSON.parse(raw);
35
+ if (!data.commands || typeof data.commands !== 'object') return new Map();
36
+ return new Map(Object.entries(data.commands));
37
+ } catch {
38
+ return new Map();
39
+ }
40
+ }
41
+
42
+ /**
43
+ * List all available commands with metadata
44
+ * @param {string} [switchPath]
45
+ * @returns {Array<{alias: string, name: string, description: string, type: string}>}
46
+ */
47
+ export function listCommands(switchPath) {
48
+ const commands = loadCommands(switchPath);
49
+ return [...commands.entries()].map(([alias, def]) => ({
50
+ alias,
51
+ name: def.name || alias,
52
+ description: def.description || '',
53
+ type: def.type || 'workflow',
54
+ }));
55
+ }
56
+
57
+ /**
58
+ * Parse CLI arguments into positional args and named flags
59
+ * @param {string[]} rawArgs - Arguments after the command name
60
+ * @returns {{ args: string[], flags: Record<string, string> }}
61
+ */
62
+ export function parseCommandArgs(rawArgs) {
63
+ const args = [];
64
+ const flags = {};
65
+
66
+ for (let i = 0; i < rawArgs.length; i++) {
67
+ if (rawArgs[i].startsWith('--') && rawArgs[i + 1] && !rawArgs[i + 1].startsWith('--')) {
68
+ flags[rawArgs[i].slice(2)] = rawArgs[i + 1];
69
+ i++;
70
+ } else if (rawArgs[i].startsWith('--')) {
71
+ flags[rawArgs[i].slice(2)] = 'true';
72
+ } else {
73
+ args.push(rawArgs[i]);
74
+ }
75
+ }
76
+
77
+ return { args, flags };
78
+ }
79
+
80
+ /**
81
+ * Resolve template expressions in command inputs
82
+ * Supports {{args.N}}, {{flags.key}}, and literal values
83
+ * @param {Record<string, string>} inputs - Input template map
84
+ * @param {string[]} args - Positional CLI args
85
+ * @param {Record<string, string>} flags - Named CLI flags
86
+ * @returns {Record<string, unknown>}
87
+ */
88
+ export function resolveInputs(inputs, args, flags) {
89
+ const resolved = {};
90
+
91
+ for (const [key, template] of Object.entries(inputs)) {
92
+ if (typeof template !== 'string') {
93
+ resolved[key] = template;
94
+ continue;
95
+ }
96
+
97
+ const argsMatch = template.match(/^\{\{args\.(\d+)\}\}$/);
98
+ if (argsMatch) {
99
+ const idx = parseInt(argsMatch[1]);
100
+ resolved[key] = args[idx] ?? template;
101
+ continue;
102
+ }
103
+
104
+ const flagsMatch = template.match(/^\{\{flags\.(\w+)\}\}$/);
105
+ if (flagsMatch) {
106
+ resolved[key] = flags[flagsMatch[1]] ?? template;
107
+ continue;
108
+ }
109
+
110
+ // Pass through literal values
111
+ resolved[key] = template;
112
+ }
113
+
114
+ return resolved;
115
+ }
package/index.js CHANGED
@@ -28,6 +28,7 @@ import { WorkflowRunner } from "./workflow.js";
28
28
  import { registerAllTools } from "./tools.js";
29
29
  import { registerCrmTools } from "./crm/index.js";
30
30
  import { registerVaultTools, autoUnseal } from "./vault/index.js";
31
+ import { registerContainerTools } from "./vault/tools-container.js";
31
32
  import { unsealedCache } from "./vault/cache.js";
32
33
  import { registerEngineTools } from "./engine/index.js";
33
34
 
@@ -39,7 +40,7 @@ const workflowRunner = new WorkflowRunner(connections);
39
40
 
40
41
  const server = new McpServer({
41
42
  name: "0nMCP",
42
- version: "1.6.0",
43
+ version: "2.0.0",
43
44
  });
44
45
 
45
46
  // ============================================================
@@ -73,6 +74,12 @@ if (vaultResult.unsealed.length > 0) {
73
74
 
74
75
  registerEngineTools(server, z);
75
76
 
77
+ // ============================================================
78
+ // VAULT CONTAINER TOOLS (patent-pending 0nVault containers)
79
+ // ============================================================
80
+
81
+ registerContainerTools(server, z);
82
+
76
83
  // ============================================================
77
84
  // START SERVER (stdio transport)
78
85
  // ============================================================
package/lib/stats.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "generated": "2026-02-15T08:02:44.106Z",
2
+ "generated": "2026-02-25T10:54:43.654Z",
3
3
  "catalogVersion": "1.2.2",
4
4
  "services": 26,
5
5
  "tools": 290,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "0nmcp",
3
- "version": "1.7.0",
3
+ "version": "2.0.0",
4
4
  "mcpName": "io.github.0nork/0nMCP",
5
5
  "description": "Universal AI API Orchestrator — 550 tools, 26 services, portable AI Brain bundles + machine-bound vault encryption + Application Engine. The most comprehensive MCP server available. Free and open source from 0nORK.",
6
6
  "type": "module",
@@ -64,6 +64,15 @@
64
64
  },
65
65
  "./engine/scheduler": {
66
66
  "import": "./engine/scheduler.js"
67
+ },
68
+ "./vault/container": {
69
+ "import": "./vault/container.js"
70
+ },
71
+ "./vault/escrow": {
72
+ "import": "./vault/escrow.js"
73
+ },
74
+ "./vault/seal": {
75
+ "import": "./vault/seal.js"
67
76
  }
68
77
  },
69
78
  "scripts": {
@@ -136,6 +145,15 @@
136
145
  "ai-brain",
137
146
  "credential-import",
138
147
  "platform-config",
148
+ "0nvault",
149
+ "semantic-layers",
150
+ "escrow",
151
+ "seal-of-truth",
152
+ "ed25519",
153
+ "x25519",
154
+ "sha3",
155
+ "argon2",
156
+ "digital-asset-transfer",
139
157
  "0n",
140
158
  "0nork",
141
159
  "0nmcp"
@@ -159,7 +177,10 @@
159
177
  },
160
178
  "dependencies": {
161
179
  "@modelcontextprotocol/sdk": "^1.26.0",
162
- "express": "^4.21.0"
180
+ "argon2": "^0.44.0",
181
+ "express": "^4.21.0",
182
+ "js-sha3": "^0.9.3",
183
+ "tweetnacl": "^1.0.3"
163
184
  },
164
185
  "optionalDependencies": {
165
186
  "0n-spec": "^1.1.0"
@@ -175,6 +196,8 @@
175
196
  "files": [
176
197
  "index.js",
177
198
  "cli.js",
199
+ "commands.js",
200
+ "command-runner.js",
178
201
  "tools.js",
179
202
  "workflow.js",
180
203
  "server.js",
@@ -204,6 +227,6 @@
204
227
  "triggers": 93,
205
228
  "totalCapabilities": 708,
206
229
  "categories": 13,
207
- "lastUpdated": "2026-02-15T08:02:44.106Z"
230
+ "lastUpdated": "2026-02-25T10:54:43.654Z"
208
231
  }
209
232
  }