@rainfall-devkit/sdk 0.2.0 → 0.2.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.
@@ -1,14 +1,18 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ createEdgeNodeSecurity
4
+ } from "../chunk-XEQ6U3JQ.mjs";
2
5
  import {
3
6
  Rainfall
4
7
  } from "../chunk-VDPKDC3R.mjs";
5
8
  import {
9
+ getConfigDir,
6
10
  loadConfig,
7
11
  saveConfig
8
- } from "../chunk-WOITG5TG.mjs";
12
+ } from "../chunk-NTTAVKRT.mjs";
9
13
 
10
14
  // src/cli/index.ts
11
- import { readFileSync } from "fs";
15
+ import { readFileSync, existsSync, mkdirSync, writeFileSync } from "fs";
12
16
  import { join, dirname } from "path";
13
17
  import { fileURLToPath } from "url";
14
18
  import { spawn } from "child_process";
@@ -44,6 +48,9 @@ Commands:
44
48
  config set <key> <value> Set configuration value
45
49
  config llm Show LLM configuration
46
50
 
51
+ edge generate-keys Generate key pair for edge node encryption
52
+ edge status Show edge node security status
53
+
47
54
  version Show version information
48
55
  upgrade Upgrade to the latest version
49
56
 
@@ -64,6 +71,9 @@ Options for 'run':
64
71
  Options for 'daemon start':
65
72
  --port <port> WebSocket port (default: 8765)
66
73
  --openai-port <port> OpenAI API port (default: 8787)
74
+ --mcp-proxy Enable MCP proxy hub (default: enabled)
75
+ --no-mcp-proxy Disable MCP proxy hub
76
+ --secure Enable edge node security (JWT, ACLs, encryption)
67
77
  --debug Enable verbose debug logging
68
78
 
69
79
  Examples:
@@ -443,10 +453,13 @@ function configLLM() {
443
453
  console.log(" anthropic - Use Anthropic API directly");
444
454
  console.log(" ollama - Use local Ollama instance");
445
455
  console.log(" local - Use any OpenAI-compatible endpoint (LM Studio, etc.)");
456
+ console.log(" custom - Use any custom OpenAI-compatible endpoint (RunPod, etc.)");
446
457
  console.log();
447
458
  console.log("Examples:");
448
459
  console.log(" rainfall config set llm.provider local");
449
460
  console.log(" rainfall config set llm.baseUrl http://localhost:1234/v1");
461
+ console.log(" rainfall config set llm.provider custom");
462
+ console.log(" rainfall config set llm.baseUrl https://your-runpod-endpoint.runpod.net/v1");
450
463
  console.log(" rainfall config set llm.provider openai");
451
464
  console.log(" rainfall config set llm.apiKey sk-...");
452
465
  }
@@ -504,6 +517,7 @@ async function daemonStart(args) {
504
517
  let port;
505
518
  let openaiPort;
506
519
  let debug = false;
520
+ let enableMcpProxy = true;
507
521
  for (let i = 0; i < args.length; i++) {
508
522
  const arg = args[i];
509
523
  if (arg === "--port") {
@@ -514,11 +528,15 @@ async function daemonStart(args) {
514
528
  if (!isNaN(val)) openaiPort = val;
515
529
  } else if (arg === "--debug") {
516
530
  debug = true;
531
+ } else if (arg === "--mcp-proxy") {
532
+ enableMcpProxy = true;
533
+ } else if (arg === "--no-mcp-proxy") {
534
+ enableMcpProxy = false;
517
535
  }
518
536
  }
519
537
  const { startDaemon } = await import("../daemon/index.mjs");
520
538
  try {
521
- await startDaemon({ port, openaiPort, debug });
539
+ await startDaemon({ port, openaiPort, debug, enableMcpProxy });
522
540
  process.on("SIGINT", async () => {
523
541
  console.log("\n");
524
542
  const { stopDaemon } = await import("../daemon/index.mjs");
@@ -590,6 +608,8 @@ async function daemonStatus() {
590
608
  console.log(` WebSocket port: ${status.port}`);
591
609
  console.log(` OpenAI API port: ${status.openaiPort}`);
592
610
  console.log(` Tools loaded: ${status.toolsLoaded}`);
611
+ console.log(` MCP clients: ${status.mcpClients || 0}`);
612
+ console.log(` MCP tools: ${status.mcpTools || 0}`);
593
613
  console.log(` Clients connected: ${status.clientsConnected}`);
594
614
  console.log(` Edge Node ID: ${status.edgeNodeId || "local"}`);
595
615
  console.log();
@@ -630,6 +650,71 @@ async function workflowRun(args) {
630
650
  console.log(`\u{1F6A7} Running workflow: ${workflowId}`);
631
651
  console.log("Workflow execution coming soon!");
632
652
  }
653
+ async function edgeGenerateKeys() {
654
+ console.log("\u{1F510} Generating edge node key pair...\n");
655
+ try {
656
+ const security = await createEdgeNodeSecurity();
657
+ const keyPair = await security.generateKeyPair();
658
+ const configDir = getConfigDir();
659
+ const keysDir = join(configDir, "keys");
660
+ if (!existsSync(keysDir)) {
661
+ mkdirSync(keysDir, { recursive: true });
662
+ }
663
+ const publicKeyPath = join(keysDir, "edge-node.pub");
664
+ const privateKeyPath = join(keysDir, "edge-node.key");
665
+ writeFileSync(publicKeyPath, keyPair.publicKey, { mode: 420 });
666
+ writeFileSync(privateKeyPath, keyPair.privateKey, { mode: 384 });
667
+ console.log("\u2705 Key pair generated successfully!\n");
668
+ console.log("Public key:", keyPair.publicKey);
669
+ console.log("\nKey files saved to:");
670
+ console.log(" Public:", publicKeyPath);
671
+ console.log(" Private:", privateKeyPath);
672
+ console.log("\n\u{1F4CB} To register this edge node:");
673
+ console.log(" 1. Copy the public key above");
674
+ console.log(" 2. Register with: rainfall edge register <public-key>");
675
+ console.log(" 3. The backend will return an edgeNodeSecret (JWT)");
676
+ console.log(" 4. Store the secret securely - it expires in 30 days");
677
+ } catch (error) {
678
+ console.error("\u274C Failed to generate keys:", error instanceof Error ? error.message : error);
679
+ process.exit(1);
680
+ }
681
+ }
682
+ async function edgeStatus() {
683
+ const configDir = getConfigDir();
684
+ const keysDir = join(configDir, "keys");
685
+ const publicKeyPath = join(keysDir, "edge-node.pub");
686
+ const privateKeyPath = join(keysDir, "edge-node.key");
687
+ console.log("\u{1F510} Edge Node Security Status\n");
688
+ const hasPublicKey = existsSync(publicKeyPath);
689
+ const hasPrivateKey = existsSync(privateKeyPath);
690
+ console.log("Key Pair:");
691
+ console.log(" Public key:", hasPublicKey ? "\u2705 Present" : "\u274C Missing");
692
+ console.log(" Private key:", hasPrivateKey ? "\u2705 Present" : "\u274C Missing");
693
+ if (hasPublicKey) {
694
+ const publicKey = readFileSync(publicKeyPath, "utf-8");
695
+ console.log("\nPublic Key:");
696
+ console.log(" " + publicKey.substring(0, 50) + "...");
697
+ }
698
+ const config = loadConfig();
699
+ if (config.edgeNodeId) {
700
+ console.log("\nRegistration:");
701
+ console.log(" Edge Node ID:", config.edgeNodeId);
702
+ }
703
+ if (config.edgeNodeSecret) {
704
+ console.log(" JWT Secret: \u2705 Present (expires: check with backend)");
705
+ } else {
706
+ console.log(" JWT Secret: \u274C Not configured");
707
+ }
708
+ console.log("\n\u{1F4DA} Next steps:");
709
+ if (!hasPublicKey) {
710
+ console.log(" 1. Run: rainfall edge generate-keys");
711
+ } else if (!config.edgeNodeSecret) {
712
+ console.log(" 1. Register your edge node with the backend");
713
+ console.log(" 2. Store the returned edgeNodeSecret in config");
714
+ } else {
715
+ console.log(" Edge node is configured and ready for secure operation");
716
+ }
717
+ }
633
718
  async function main() {
634
719
  const args = process.argv.slice(2);
635
720
  const command = args[0];
@@ -735,6 +820,20 @@ async function main() {
735
820
  case "upgrade":
736
821
  await upgrade();
737
822
  break;
823
+ case "edge":
824
+ switch (subcommand) {
825
+ case "generate-keys":
826
+ await edgeGenerateKeys();
827
+ break;
828
+ case "status":
829
+ await edgeStatus();
830
+ break;
831
+ default:
832
+ console.error("Error: Unknown edge subcommand");
833
+ console.error("\nUsage: rainfall edge <generate-keys|status>");
834
+ process.exit(1);
835
+ }
836
+ break;
738
837
  case "help":
739
838
  case "--help":
740
839
  case "-h":
@@ -0,0 +1,16 @@
1
+ import {
2
+ getConfigDir,
3
+ getLLMConfig,
4
+ getProviderBaseUrl,
5
+ isLocalProvider,
6
+ loadConfig,
7
+ saveConfig
8
+ } from "./chunk-NTTAVKRT.mjs";
9
+ export {
10
+ getConfigDir,
11
+ getLLMConfig,
12
+ getProviderBaseUrl,
13
+ isLocalProvider,
14
+ loadConfig,
15
+ saveConfig
16
+ };
@@ -0,0 +1,14 @@
1
+ import {
2
+ getLLMConfig,
3
+ getProviderBaseUrl,
4
+ isLocalProvider,
5
+ loadConfig,
6
+ saveConfig
7
+ } from "./chunk-EI7SJH5K.mjs";
8
+ export {
9
+ getLLMConfig,
10
+ getProviderBaseUrl,
11
+ isLocalProvider,
12
+ loadConfig,
13
+ saveConfig
14
+ };
@@ -1,5 +1,10 @@
1
- import { e as RainfallConfig } from '../sdk-DD1OeGRJ.mjs';
2
- import { N as NetworkedExecutorOptions, C as ContextOptions, e as RainfallNetworkedExecutor, R as RainfallDaemonContext, d as RainfallListenerRegistry } from '../listeners-CYI-YwIF.mjs';
1
+ import { R as RainfallConfig, g as MCPClientConfig, h as MCPProxyHub } from '../sdk-4OvXPr8E.mjs';
2
+ export { i as MCPClientInfo, j as MCPToolInfo, k as MCPTransportType } from '../sdk-4OvXPr8E.mjs';
3
+ import { N as NetworkedExecutorOptions, C as ContextOptions, R as RainfallNetworkedExecutor, a as RainfallDaemonContext, b as RainfallListenerRegistry } from '../listeners-MNAnpZj-.mjs';
4
+ import 'ws';
5
+ import '@modelcontextprotocol/sdk/client/index.js';
6
+ import '@modelcontextprotocol/sdk/client/stdio.js';
7
+ import '@modelcontextprotocol/sdk/client/streamableHttp.js';
3
8
 
4
9
  /**
5
10
  * Rainfall Daemon - Local websocket server + OpenAI-compatible proxy
@@ -23,12 +28,20 @@ interface DaemonConfig {
23
28
  networkedOptions?: NetworkedExecutorOptions;
24
29
  /** Context/memory options */
25
30
  contextOptions?: ContextOptions;
31
+ /** Enable MCP proxy hub (default: true) */
32
+ enableMcpProxy?: boolean;
33
+ /** Namespace prefix for MCP tools (default: true) */
34
+ mcpNamespacePrefix?: boolean;
35
+ /** Pre-configured MCP clients to connect on startup */
36
+ mcpClients?: MCPClientConfig[];
26
37
  }
27
38
  interface DaemonStatus {
28
39
  running: boolean;
29
40
  port?: number;
30
41
  openaiPort?: number;
31
42
  toolsLoaded: number;
43
+ mcpClients?: number;
44
+ mcpTools?: number;
32
45
  clientsConnected: number;
33
46
  edgeNodeId?: string;
34
47
  context: {
@@ -57,6 +70,9 @@ declare class RainfallDaemon {
57
70
  private networkedExecutor?;
58
71
  private context?;
59
72
  private listeners?;
73
+ private mcpProxy?;
74
+ private enableMcpProxy;
75
+ private mcpNamespacePrefix;
60
76
  constructor(config?: DaemonConfig);
61
77
  start(): Promise<void>;
62
78
  stop(): Promise<void>;
@@ -72,6 +88,18 @@ declare class RainfallDaemon {
72
88
  * Get the listener registry for passive triggers
73
89
  */
74
90
  getListenerRegistry(): RainfallListenerRegistry | undefined;
91
+ /**
92
+ * Get the MCP Proxy Hub for managing external MCP clients
93
+ */
94
+ getMCPProxy(): MCPProxyHub | undefined;
95
+ /**
96
+ * Connect an MCP client dynamically
97
+ */
98
+ connectMCPClient(config: MCPClientConfig): Promise<string>;
99
+ /**
100
+ * Disconnect an MCP client
101
+ */
102
+ disconnectMCPClient(name: string): Promise<void>;
75
103
  private initializeRainfall;
76
104
  private loadTools;
77
105
  private getToolSchema;
@@ -79,6 +107,10 @@ declare class RainfallDaemon {
79
107
  private handleMCPMessage;
80
108
  private getMCPTools;
81
109
  private executeTool;
110
+ /**
111
+ * Execute a tool, trying MCP proxy first, then falling back to Rainfall tools
112
+ */
113
+ private executeToolWithMCP;
82
114
  private startOpenAIProxy;
83
115
  /**
84
116
  * Build a map of local Rainfall tools for quick lookup
@@ -133,4 +165,4 @@ declare function stopDaemon(): Promise<void>;
133
165
  declare function getDaemonStatus(): DaemonStatus | null;
134
166
  declare function getDaemonInstance(): RainfallDaemon | null;
135
167
 
136
- export { type DaemonConfig, type DaemonStatus, RainfallDaemon, getDaemonInstance, getDaemonStatus, startDaemon, stopDaemon };
168
+ export { type DaemonConfig, type DaemonStatus, MCPClientConfig, MCPProxyHub, RainfallDaemon, getDaemonInstance, getDaemonStatus, startDaemon, stopDaemon };
@@ -1,5 +1,10 @@
1
- import { e as RainfallConfig } from '../sdk-DD1OeGRJ.js';
2
- import { N as NetworkedExecutorOptions, C as ContextOptions, e as RainfallNetworkedExecutor, R as RainfallDaemonContext, d as RainfallListenerRegistry } from '../listeners-QJeEtLbV.js';
1
+ import { R as RainfallConfig, g as MCPClientConfig, h as MCPProxyHub } from '../sdk-4OvXPr8E.js';
2
+ export { i as MCPClientInfo, j as MCPToolInfo, k as MCPTransportType } from '../sdk-4OvXPr8E.js';
3
+ import { N as NetworkedExecutorOptions, C as ContextOptions, R as RainfallNetworkedExecutor, a as RainfallDaemonContext, b as RainfallListenerRegistry } from '../listeners-B5Vy9Ao5.js';
4
+ import 'ws';
5
+ import '@modelcontextprotocol/sdk/client/index.js';
6
+ import '@modelcontextprotocol/sdk/client/stdio.js';
7
+ import '@modelcontextprotocol/sdk/client/streamableHttp.js';
3
8
 
4
9
  /**
5
10
  * Rainfall Daemon - Local websocket server + OpenAI-compatible proxy
@@ -23,12 +28,20 @@ interface DaemonConfig {
23
28
  networkedOptions?: NetworkedExecutorOptions;
24
29
  /** Context/memory options */
25
30
  contextOptions?: ContextOptions;
31
+ /** Enable MCP proxy hub (default: true) */
32
+ enableMcpProxy?: boolean;
33
+ /** Namespace prefix for MCP tools (default: true) */
34
+ mcpNamespacePrefix?: boolean;
35
+ /** Pre-configured MCP clients to connect on startup */
36
+ mcpClients?: MCPClientConfig[];
26
37
  }
27
38
  interface DaemonStatus {
28
39
  running: boolean;
29
40
  port?: number;
30
41
  openaiPort?: number;
31
42
  toolsLoaded: number;
43
+ mcpClients?: number;
44
+ mcpTools?: number;
32
45
  clientsConnected: number;
33
46
  edgeNodeId?: string;
34
47
  context: {
@@ -57,6 +70,9 @@ declare class RainfallDaemon {
57
70
  private networkedExecutor?;
58
71
  private context?;
59
72
  private listeners?;
73
+ private mcpProxy?;
74
+ private enableMcpProxy;
75
+ private mcpNamespacePrefix;
60
76
  constructor(config?: DaemonConfig);
61
77
  start(): Promise<void>;
62
78
  stop(): Promise<void>;
@@ -72,6 +88,18 @@ declare class RainfallDaemon {
72
88
  * Get the listener registry for passive triggers
73
89
  */
74
90
  getListenerRegistry(): RainfallListenerRegistry | undefined;
91
+ /**
92
+ * Get the MCP Proxy Hub for managing external MCP clients
93
+ */
94
+ getMCPProxy(): MCPProxyHub | undefined;
95
+ /**
96
+ * Connect an MCP client dynamically
97
+ */
98
+ connectMCPClient(config: MCPClientConfig): Promise<string>;
99
+ /**
100
+ * Disconnect an MCP client
101
+ */
102
+ disconnectMCPClient(name: string): Promise<void>;
75
103
  private initializeRainfall;
76
104
  private loadTools;
77
105
  private getToolSchema;
@@ -79,6 +107,10 @@ declare class RainfallDaemon {
79
107
  private handleMCPMessage;
80
108
  private getMCPTools;
81
109
  private executeTool;
110
+ /**
111
+ * Execute a tool, trying MCP proxy first, then falling back to Rainfall tools
112
+ */
113
+ private executeToolWithMCP;
82
114
  private startOpenAIProxy;
83
115
  /**
84
116
  * Build a map of local Rainfall tools for quick lookup
@@ -133,4 +165,4 @@ declare function stopDaemon(): Promise<void>;
133
165
  declare function getDaemonStatus(): DaemonStatus | null;
134
166
  declare function getDaemonInstance(): RainfallDaemon | null;
135
167
 
136
- export { type DaemonConfig, type DaemonStatus, RainfallDaemon, getDaemonInstance, getDaemonStatus, startDaemon, stopDaemon };
168
+ export { type DaemonConfig, type DaemonStatus, MCPClientConfig, MCPProxyHub, RainfallDaemon, getDaemonInstance, getDaemonStatus, startDaemon, stopDaemon };