omniwire 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.
Files changed (90) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +316 -0
  3. package/dist/claude/integration.d.ts +12 -0
  4. package/dist/claude/integration.js +157 -0
  5. package/dist/claude/integration.js.map +1 -0
  6. package/dist/commands/browser.d.ts +2 -0
  7. package/dist/commands/browser.js +23 -0
  8. package/dist/commands/browser.js.map +1 -0
  9. package/dist/commands/builtins.d.ts +4 -0
  10. package/dist/commands/builtins.js +309 -0
  11. package/dist/commands/builtins.js.map +1 -0
  12. package/dist/commands/router.d.ts +2 -0
  13. package/dist/commands/router.js +174 -0
  14. package/dist/commands/router.js.map +1 -0
  15. package/dist/index.d.ts +2 -0
  16. package/dist/index.js +198 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/mcp/index.d.ts +2 -0
  19. package/dist/mcp/index.js +71 -0
  20. package/dist/mcp/index.js.map +1 -0
  21. package/dist/mcp/rest.d.ts +3 -0
  22. package/dist/mcp/rest.js +98 -0
  23. package/dist/mcp/rest.js.map +1 -0
  24. package/dist/mcp/server.d.ts +4 -0
  25. package/dist/mcp/server.js +419 -0
  26. package/dist/mcp/server.js.map +1 -0
  27. package/dist/mcp/sse.d.ts +2 -0
  28. package/dist/mcp/sse.js +43 -0
  29. package/dist/mcp/sse.js.map +1 -0
  30. package/dist/mcp/sync-tools.d.ts +5 -0
  31. package/dist/mcp/sync-tools.js +124 -0
  32. package/dist/mcp/sync-tools.js.map +1 -0
  33. package/dist/nodes/manager.d.ts +28 -0
  34. package/dist/nodes/manager.js +341 -0
  35. package/dist/nodes/manager.js.map +1 -0
  36. package/dist/nodes/realtime.d.ts +13 -0
  37. package/dist/nodes/realtime.js +46 -0
  38. package/dist/nodes/realtime.js.map +1 -0
  39. package/dist/nodes/shell.d.ts +17 -0
  40. package/dist/nodes/shell.js +137 -0
  41. package/dist/nodes/shell.js.map +1 -0
  42. package/dist/nodes/transfer.d.ts +22 -0
  43. package/dist/nodes/transfer.js +244 -0
  44. package/dist/nodes/transfer.js.map +1 -0
  45. package/dist/nodes/tunnel.d.ts +12 -0
  46. package/dist/nodes/tunnel.js +49 -0
  47. package/dist/nodes/tunnel.js.map +1 -0
  48. package/dist/protocol/config.d.ts +9 -0
  49. package/dist/protocol/config.js +133 -0
  50. package/dist/protocol/config.js.map +1 -0
  51. package/dist/protocol/paths.d.ts +3 -0
  52. package/dist/protocol/paths.js +19 -0
  53. package/dist/protocol/paths.js.map +1 -0
  54. package/dist/protocol/types.d.ts +106 -0
  55. package/dist/protocol/types.js +3 -0
  56. package/dist/protocol/types.js.map +1 -0
  57. package/dist/sync/db.d.ts +53 -0
  58. package/dist/sync/db.js +212 -0
  59. package/dist/sync/db.js.map +1 -0
  60. package/dist/sync/engine.d.ts +23 -0
  61. package/dist/sync/engine.js +251 -0
  62. package/dist/sync/engine.js.map +1 -0
  63. package/dist/sync/hasher.d.ts +2 -0
  64. package/dist/sync/hasher.js +25 -0
  65. package/dist/sync/hasher.js.map +1 -0
  66. package/dist/sync/index.d.ts +6 -0
  67. package/dist/sync/index.js +155 -0
  68. package/dist/sync/index.js.map +1 -0
  69. package/dist/sync/manifest.d.ts +4 -0
  70. package/dist/sync/manifest.js +105 -0
  71. package/dist/sync/manifest.js.map +1 -0
  72. package/dist/sync/memory-bridge.d.ts +7 -0
  73. package/dist/sync/memory-bridge.js +84 -0
  74. package/dist/sync/memory-bridge.js.map +1 -0
  75. package/dist/sync/paths.d.ts +6 -0
  76. package/dist/sync/paths.js +53 -0
  77. package/dist/sync/paths.js.map +1 -0
  78. package/dist/sync/schema.d.ts +2 -0
  79. package/dist/sync/schema.js +72 -0
  80. package/dist/sync/schema.js.map +1 -0
  81. package/dist/sync/types.d.ts +83 -0
  82. package/dist/sync/types.js +11 -0
  83. package/dist/sync/types.js.map +1 -0
  84. package/dist/sync/watcher.d.ts +21 -0
  85. package/dist/sync/watcher.js +87 -0
  86. package/dist/sync/watcher.js.map +1 -0
  87. package/dist/ui/format.d.ts +24 -0
  88. package/dist/ui/format.js +108 -0
  89. package/dist/ui/format.js.map +1 -0
  90. package/package.json +72 -0
@@ -0,0 +1,137 @@
1
+ // OmniWire Shell Manager — persistent root shell sessions with PTY
2
+ // All connections are root — full kernel access by default
3
+ // NOTE: All remote commands in this file run over authenticated SSH2 channels
4
+ // (client.shell() and manager.exec() are SSH2 methods, NOT child_process)
5
+ const IDLE_TIMEOUT_MS = 60_000; // 60s idle timeout
6
+ export class ShellManager {
7
+ manager;
8
+ shells = new Map();
9
+ idCounter = 0;
10
+ constructor(manager) {
11
+ this.manager = manager;
12
+ }
13
+ async openShell(nodeId) {
14
+ const client = this.manager.getClient(nodeId);
15
+ if (!client)
16
+ throw new Error(`Node ${nodeId} is not connected`);
17
+ const channel = await new Promise((resolve, reject) => {
18
+ client.shell({ term: 'xterm-256color', rows: 40, cols: 120 }, (err, stream) => {
19
+ if (err)
20
+ reject(err);
21
+ else
22
+ resolve(stream);
23
+ });
24
+ });
25
+ const id = `shell-${++this.idCounter}`;
26
+ const session = { id, nodeId, startedAt: new Date() };
27
+ const idleTimer = this.createIdleTimer(id);
28
+ this.shells.set(id, { session, channel, idleTimer });
29
+ // Auto-cleanup on channel close
30
+ channel.on('close', () => {
31
+ const s = this.shells.get(id);
32
+ if (s)
33
+ clearTimeout(s.idleTimer);
34
+ this.shells.delete(id);
35
+ });
36
+ return session;
37
+ }
38
+ getChannel(shellId) {
39
+ const shell = this.shells.get(shellId);
40
+ if (shell) {
41
+ // Reset idle timer on access
42
+ clearTimeout(shell.idleTimer);
43
+ shell.idleTimer = this.createIdleTimer(shellId);
44
+ }
45
+ return shell?.channel ?? null;
46
+ }
47
+ closeShell(shellId) {
48
+ const shell = this.shells.get(shellId);
49
+ if (shell) {
50
+ clearTimeout(shell.idleTimer);
51
+ shell.channel.end();
52
+ this.shells.delete(shellId);
53
+ }
54
+ }
55
+ listShells() {
56
+ return Array.from(this.shells.values()).map((s) => s.session);
57
+ }
58
+ closeAll() {
59
+ for (const [id] of this.shells) {
60
+ this.closeShell(id);
61
+ }
62
+ }
63
+ createIdleTimer(shellId) {
64
+ return setTimeout(() => {
65
+ const shell = this.shells.get(shellId);
66
+ if (shell) {
67
+ process.stderr.write(`[shell] ${shellId} timed out after ${IDLE_TIMEOUT_MS / 1000}s idle\n`);
68
+ shell.channel.end();
69
+ this.shells.delete(shellId);
70
+ }
71
+ }, IDLE_TIMEOUT_MS);
72
+ }
73
+ // Interactive shell mode — pipes stdin/stdout directly
74
+ async enterInteractive(nodeId, stdin, stdout, onExit) {
75
+ const session = await this.openShell(nodeId);
76
+ const channel = this.getChannel(session.id);
77
+ // Pipe shell output to terminal
78
+ channel.on('data', (data) => stdout.write(data));
79
+ channel.stderr.on('data', (data) => stdout.write(data));
80
+ // Handle Ctrl+] to exit interactive mode
81
+ const rawMode = stdin.isRaw;
82
+ if ('setRawMode' in stdin) {
83
+ stdin.setRawMode(true);
84
+ }
85
+ const onData = (data) => {
86
+ // Ctrl+] (0x1d) exits interactive mode
87
+ if (data[0] === 0x1d) {
88
+ cleanup();
89
+ return;
90
+ }
91
+ channel.write(data);
92
+ };
93
+ const cleanup = () => {
94
+ stdin.removeListener('data', onData);
95
+ if ('setRawMode' in stdin) {
96
+ stdin.setRawMode(rawMode ?? false);
97
+ }
98
+ this.closeShell(session.id);
99
+ onExit();
100
+ };
101
+ stdin.on('data', onData);
102
+ channel.on('close', cleanup);
103
+ }
104
+ }
105
+ // Kernel-level operations (all nodes are root)
106
+ // Uses manager.exec() — SSH2 client.exec(), NOT child_process
107
+ export async function kernelExec(manager, nodeId, operation, args) {
108
+ let cmd;
109
+ switch (operation) {
110
+ case 'dmesg':
111
+ cmd = `dmesg ${args}`;
112
+ break;
113
+ case 'sysctl':
114
+ cmd = args.includes('=') ? `sysctl -w ${args}` : `sysctl ${args}`;
115
+ break;
116
+ case 'modprobe':
117
+ cmd = `modprobe ${args}`;
118
+ break;
119
+ case 'lsmod':
120
+ cmd = `lsmod ${args}`;
121
+ break;
122
+ case 'strace':
123
+ cmd = `strace ${args}`;
124
+ break;
125
+ case 'perf':
126
+ cmd = `perf ${args}`;
127
+ break;
128
+ default:
129
+ cmd = `${operation} ${args}`;
130
+ }
131
+ const result = await manager.exec(nodeId, cmd);
132
+ if (result.code !== 0 && result.stderr) {
133
+ return `Error: ${result.stderr}`;
134
+ }
135
+ return result.stdout;
136
+ }
137
+ //# sourceMappingURL=shell.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell.js","sourceRoot":"","sources":["../../src/nodes/shell.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import type { NodeManager } from './manager.js';
2
+ import type { TransferResult, TransferMode, FileInfo, DirEntry } from '../protocol/types.js';
3
+ export declare class TransferEngine {
4
+ private manager;
5
+ private statCache;
6
+ constructor(manager: NodeManager);
7
+ transfer(srcNode: string, srcPath: string, dstNode: string, dstPath: string, opts?: {
8
+ mode?: TransferMode;
9
+ }): Promise<TransferResult>;
10
+ private selectMode;
11
+ private findFreePort;
12
+ private transferNetcat;
13
+ private transferAria2c;
14
+ private transferSshPipe;
15
+ private transferSftp;
16
+ readFile(nodeId: string, path: string): Promise<string>;
17
+ writeFile(nodeId: string, path: string, content: string): Promise<void>;
18
+ stat(nodeId: string, path: string): Promise<FileInfo>;
19
+ readdir(nodeId: string, path: string): Promise<DirEntry[]>;
20
+ mkdir(nodeId: string, path: string): Promise<void>;
21
+ unlink(nodeId: string, path: string): Promise<void>;
22
+ }
@@ -0,0 +1,244 @@
1
+ // OmniWire Transfer Engine — raw TCP transfers over WireGuard mesh
2
+ // Modes: netcat+tar (fastest), aria2c (large files), SSH pipe (small files)
3
+ // NOTE: All commands execute via SSH on remote Linux nodes (not local shell).
4
+ // The manager.exec() method uses ssh2 client.exec() for remote nodes, which
5
+ // does not involve local shell interpretation. Path inputs come from trusted
6
+ // terminal/MCP context (operator's own commands).
7
+ import { findNode } from '../protocol/config.js';
8
+ const STAT_CACHE_TTL = 10_000; // 10s stat cache
9
+ export class TransferEngine {
10
+ manager;
11
+ statCache = new Map();
12
+ constructor(manager) {
13
+ this.manager = manager;
14
+ }
15
+ async transfer(srcNode, srcPath, dstNode, dstPath, opts) {
16
+ const start = Date.now();
17
+ // Determine file size for auto mode selection
18
+ const stat = await this.stat(srcNode, srcPath);
19
+ const mode = opts?.mode ?? this.selectMode(stat.size, stat.isDirectory);
20
+ let bytesTransferred = stat.size;
21
+ switch (mode) {
22
+ case 'netcat-tar':
23
+ bytesTransferred = await this.transferNetcat(srcNode, srcPath, dstNode, dstPath, stat.isDirectory);
24
+ break;
25
+ case 'aria2c':
26
+ bytesTransferred = await this.transferAria2c(srcNode, srcPath, dstNode, dstPath);
27
+ break;
28
+ case 'ssh-pipe':
29
+ bytesTransferred = await this.transferSshPipe(srcNode, srcPath, dstNode, dstPath);
30
+ break;
31
+ }
32
+ const durationMs = Date.now() - start;
33
+ const speedMBps = durationMs > 0 ? (bytesTransferred / 1024 / 1024) / (durationMs / 1000) : 0;
34
+ return { srcNode, dstNode, srcPath, dstPath, mode, bytesTransferred, durationMs, speedMBps };
35
+ }
36
+ selectMode(sizeBytes, isDirectory) {
37
+ if (isDirectory)
38
+ return 'netcat-tar';
39
+ if (sizeBytes < 10 * 1024 * 1024)
40
+ return 'ssh-pipe'; // < 10MB
41
+ if (sizeBytes > 1024 * 1024 * 1024)
42
+ return 'aria2c'; // > 1GB
43
+ return 'netcat-tar'; // 10MB - 1GB
44
+ }
45
+ // Single SSH call to find free port — kernel assigns guaranteed free port via Python
46
+ // Uses manager.exec() which runs via SSH2 client.exec(), not child_process
47
+ async findFreePort(nodeId) {
48
+ const result = await this.manager.exec(nodeId, `python3 -c "import socket; s=socket.socket(); s.bind(('',0)); print(s.getsockname()[1]); s.close()"`);
49
+ const port = parseInt(result.stdout.trim());
50
+ if (!port || isNaN(port)) {
51
+ // Fallback: random port
52
+ return 49152 + Math.floor(Math.random() * (65535 - 49152));
53
+ }
54
+ return port;
55
+ }
56
+ async transferNetcat(srcNode, srcPath, dstNode, dstPath, isDirectory) {
57
+ const dstIp = findNode(dstNode)?.host;
58
+ if (!dstIp)
59
+ throw new Error(`Unknown node: ${dstNode}`);
60
+ const port = await this.findFreePort(dstNode);
61
+ const dstDir = isDirectory ? dstPath : dstPath.substring(0, dstPath.lastIndexOf('/')) || '/tmp';
62
+ const srcDir = srcPath.substring(0, srcPath.lastIndexOf('/')) || '/';
63
+ const srcName = srcPath.substring(srcPath.lastIndexOf('/') + 1);
64
+ // Start receiver first (background, timeout 30s) — gzip compressed
65
+ const receiverCmd = `timeout 30 bash -c 'nc -l -p ${port} | tar xzf - -C "${dstDir}"'`;
66
+ const receiverPromise = this.manager.exec(dstNode, `mkdir -p "${dstDir}" && ${receiverCmd}`);
67
+ // Small delay to ensure receiver is listening
68
+ await new Promise((r) => setTimeout(r, 200));
69
+ // Start sender — gzip compressed
70
+ const senderCmd = isDirectory
71
+ ? `tar czf - -C "${srcPath}" . | nc -w 10 ${dstIp} ${port}`
72
+ : `tar czf - -C "${srcDir}" "${srcName}" | nc -w 10 ${dstIp} ${port}`;
73
+ const senderResult = await this.manager.exec(srcNode, senderCmd);
74
+ await receiverPromise;
75
+ if (senderResult.code !== 0) {
76
+ throw new Error(`netcat transfer failed: ${senderResult.stderr}`);
77
+ }
78
+ const sizeResult = await this.manager.exec(dstNode, `du -sb "${dstPath}" 2>/dev/null | awk '{print $1}'`);
79
+ return parseInt(sizeResult.stdout.trim()) || 0;
80
+ }
81
+ async transferAria2c(srcNode, srcPath, dstNode, dstPath) {
82
+ const srcIp = findNode(srcNode)?.host;
83
+ if (!srcIp)
84
+ throw new Error(`Unknown node: ${srcNode}`);
85
+ const port = await this.findFreePort(srcNode);
86
+ const srcDir = srcPath.substring(0, srcPath.lastIndexOf('/')) || '/';
87
+ const fileName = srcPath.substring(srcPath.lastIndexOf('/') + 1);
88
+ const dstDir = dstPath.substring(0, dstPath.lastIndexOf('/')) || '/tmp';
89
+ // Start HTTP server on source (background, auto-kill after transfer)
90
+ const serverCmd = `cd "${srcDir}" && timeout 300 python3 -m http.server ${port} --bind 0.0.0.0 &`;
91
+ await this.manager.exec(srcNode, `bash -c '${serverCmd}'`);
92
+ await new Promise((r) => setTimeout(r, 500));
93
+ try {
94
+ const downloadCmd = `mkdir -p "${dstDir}" && aria2c -x16 -s16 --allow-overwrite=true -d "${dstDir}" -o "${fileName}" "http://${srcIp}:${port}/${fileName}" 2>&1`;
95
+ const result = await this.manager.exec(dstNode, downloadCmd);
96
+ if (result.code !== 0)
97
+ throw new Error(`aria2c transfer failed: ${result.stderr || result.stdout}`);
98
+ }
99
+ finally {
100
+ await this.manager.exec(srcNode, `pkill -f "python3 -m http.server ${port}" 2>/dev/null || true`);
101
+ }
102
+ const sizeResult = await this.manager.exec(dstNode, `stat -c%s "${dstPath}" 2>/dev/null || echo 0`);
103
+ return parseInt(sizeResult.stdout.trim()) || 0;
104
+ }
105
+ async transferSshPipe(srcNode, srcPath, dstNode, dstPath) {
106
+ // Try SFTP first (binary-safe, no encoding overhead)
107
+ const srcClient = this.manager.getClient(srcNode);
108
+ const dstClient = this.manager.getClient(dstNode);
109
+ if (srcClient && dstClient) {
110
+ try {
111
+ return await this.transferSftp(srcClient, dstClient, srcPath, dstPath);
112
+ }
113
+ catch {
114
+ // SFTP failed, fall through to base64 method
115
+ }
116
+ }
117
+ // Fallback: base64 over SSH (for local node or SFTP failure)
118
+ const b64Result = await this.manager.exec(srcNode, `base64 "${srcPath}"`);
119
+ if (b64Result.code !== 0)
120
+ throw new Error(`Failed to encode ${srcPath}: ${b64Result.stderr}`);
121
+ const dstDir = dstPath.substring(0, dstPath.lastIndexOf('/')) || '/tmp';
122
+ const b64Content = b64Result.stdout;
123
+ // Use printf + base64 -d to avoid heredoc issues with special content
124
+ const writeCmd = `mkdir -p "${dstDir}" && printf '%s' '${b64Content.replace(/'/g, "'\\''")}' | base64 -d > "${dstPath}"`;
125
+ const writeResult = await this.manager.exec(dstNode, writeCmd);
126
+ if (writeResult.code !== 0)
127
+ throw new Error(`Failed to write ${dstPath} on ${dstNode}: ${writeResult.stderr}`);
128
+ const sizeResult = await this.manager.exec(dstNode, `stat -c%s "${dstPath}" 2>/dev/null || echo 0`);
129
+ return parseInt(sizeResult.stdout.trim()) || 0;
130
+ }
131
+ // SFTP-based transfer — zero encoding overhead, binary-safe
132
+ transferSftp(srcClient, dstClient, srcPath, dstPath) {
133
+ return new Promise((resolve, reject) => {
134
+ srcClient.sftp((sftpErr, srcSftp) => {
135
+ if (sftpErr)
136
+ return reject(sftpErr);
137
+ srcSftp.readFile(srcPath, (readErr, data) => {
138
+ srcSftp.end();
139
+ if (readErr)
140
+ return reject(readErr);
141
+ dstClient.sftp((dstSftpErr, dstSftp) => {
142
+ if (dstSftpErr)
143
+ return reject(dstSftpErr);
144
+ dstSftp.writeFile(dstPath, data, (writeErr) => {
145
+ dstSftp.end();
146
+ if (writeErr)
147
+ return reject(writeErr);
148
+ resolve(data.length);
149
+ });
150
+ });
151
+ });
152
+ });
153
+ });
154
+ }
155
+ async readFile(nodeId, path) {
156
+ const result = await this.manager.exec(nodeId, `cat "${path}"`);
157
+ if (result.code !== 0)
158
+ throw new Error(`Failed to read ${path} on ${nodeId}: ${result.stderr}`);
159
+ return result.stdout;
160
+ }
161
+ async writeFile(nodeId, path, content) {
162
+ const dir = path.substring(0, path.lastIndexOf('/')) || '/tmp';
163
+ // Try SFTP first (no heredoc issues, binary-safe)
164
+ const client = this.manager.getClient(nodeId);
165
+ if (client) {
166
+ try {
167
+ // Ensure directory exists
168
+ await this.manager.exec(nodeId, `mkdir -p "${dir}"`);
169
+ await new Promise((resolve, reject) => {
170
+ client.sftp((err, sftp) => {
171
+ if (err)
172
+ return reject(err);
173
+ sftp.writeFile(path, Buffer.from(content, 'utf-8'), (writeErr) => {
174
+ sftp.end();
175
+ writeErr ? reject(writeErr) : resolve();
176
+ });
177
+ });
178
+ });
179
+ return;
180
+ }
181
+ catch {
182
+ // SFTP failed, fall through to heredoc
183
+ }
184
+ }
185
+ // Fallback: base64 pipe (safe for any content)
186
+ const b64 = Buffer.from(content, 'utf-8').toString('base64');
187
+ const cmd = `mkdir -p "${dir}" && echo '${b64}' | base64 -d > "${path}"`;
188
+ const result = await this.manager.exec(nodeId, cmd);
189
+ if (result.code !== 0)
190
+ throw new Error(`Failed to write ${path} on ${nodeId}: ${result.stderr}`);
191
+ }
192
+ async stat(nodeId, path) {
193
+ // Check cache first
194
+ const cacheKey = `${nodeId}:${path}`;
195
+ const cached = this.statCache.get(cacheKey);
196
+ if (cached && Date.now() - cached.at < STAT_CACHE_TTL) {
197
+ return cached.info;
198
+ }
199
+ const cmd = `stat -c '%s %F %a %Y %U' "${path}" 2>/dev/null && echo OK || echo NOTFOUND`;
200
+ const result = await this.manager.exec(nodeId, cmd);
201
+ if (result.stdout.includes('NOTFOUND') || result.code !== 0) {
202
+ throw new Error(`File not found: ${path} on ${nodeId}`);
203
+ }
204
+ const lines = result.stdout.trim().split('\n');
205
+ const parts = lines[0].split(' ');
206
+ const info = {
207
+ path,
208
+ size: parseInt(parts[0]) || 0,
209
+ isDirectory: parts[1]?.includes('directory') ?? false,
210
+ permissions: parts[2] ?? '000',
211
+ modified: parts[3] ?? '',
212
+ owner: parts[4] ?? 'unknown',
213
+ };
214
+ this.statCache.set(cacheKey, { info, at: Date.now() });
215
+ return info;
216
+ }
217
+ async readdir(nodeId, path) {
218
+ const cmd = `ls -la --time-style=long-iso "${path}" 2>/dev/null | tail -n +2`;
219
+ const result = await this.manager.exec(nodeId, cmd);
220
+ if (result.code !== 0)
221
+ throw new Error(`Failed to list ${path} on ${nodeId}: ${result.stderr}`);
222
+ return result.stdout.split('\n').filter(Boolean).map((line) => {
223
+ const parts = line.split(/\s+/);
224
+ return {
225
+ name: parts.slice(7).join(' '),
226
+ size: parseInt(parts[4]) || 0,
227
+ isDirectory: line.startsWith('d'),
228
+ permissions: parts[0] ?? '',
229
+ modified: `${parts[5]} ${parts[6]}`,
230
+ };
231
+ });
232
+ }
233
+ async mkdir(nodeId, path) {
234
+ const result = await this.manager.exec(nodeId, `mkdir -p "${path}"`);
235
+ if (result.code !== 0)
236
+ throw new Error(`Failed to mkdir ${path} on ${nodeId}: ${result.stderr}`);
237
+ }
238
+ async unlink(nodeId, path) {
239
+ const result = await this.manager.exec(nodeId, `rm -f "${path}"`);
240
+ if (result.code !== 0)
241
+ throw new Error(`Failed to unlink ${path} on ${nodeId}: ${result.stderr}`);
242
+ }
243
+ }
244
+ //# sourceMappingURL=transfer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transfer.js","sourceRoot":"","sources":["../../src/nodes/transfer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { NodeManager } from './manager.js';
2
+ import type { TunnelInfo } from '../protocol/types.js';
3
+ export declare class TunnelManager {
4
+ private manager;
5
+ private tunnels;
6
+ private idCounter;
7
+ constructor(manager: NodeManager);
8
+ create(nodeId: string, localPort: number, remotePort: number, remoteHost?: string): Promise<TunnelInfo>;
9
+ close(tunnelId: string): void;
10
+ list(): TunnelInfo[];
11
+ closeAll(): void;
12
+ }
@@ -0,0 +1,49 @@
1
+ // OmniWire Tunnel Manager — SSH port forwarding over WireGuard mesh
2
+ import { createServer } from 'node:net';
3
+ export class TunnelManager {
4
+ manager;
5
+ tunnels = new Map();
6
+ idCounter = 0;
7
+ constructor(manager) {
8
+ this.manager = manager;
9
+ }
10
+ async create(nodeId, localPort, remotePort, remoteHost = '127.0.0.1') {
11
+ const client = this.manager.getClient(nodeId);
12
+ if (!client)
13
+ throw new Error(`Node ${nodeId} is not connected`);
14
+ const id = `tunnel-${++this.idCounter}`;
15
+ const server = createServer((socket) => {
16
+ client.forwardOut('127.0.0.1', localPort, remoteHost, remotePort, (err, stream) => {
17
+ if (err) {
18
+ socket.end();
19
+ return;
20
+ }
21
+ socket.pipe(stream);
22
+ stream.pipe(socket);
23
+ });
24
+ });
25
+ await new Promise((resolve, reject) => {
26
+ server.listen(localPort, '127.0.0.1', () => resolve());
27
+ server.on('error', reject);
28
+ });
29
+ const info = { id, nodeId, localPort, remotePort, remoteHost };
30
+ this.tunnels.set(id, { ...info, server });
31
+ return info;
32
+ }
33
+ close(tunnelId) {
34
+ const tunnel = this.tunnels.get(tunnelId);
35
+ if (tunnel) {
36
+ tunnel.server.close();
37
+ this.tunnels.delete(tunnelId);
38
+ }
39
+ }
40
+ list() {
41
+ return Array.from(this.tunnels.values()).map(({ server: _, ...info }) => info);
42
+ }
43
+ closeAll() {
44
+ for (const [id] of this.tunnels) {
45
+ this.close(id);
46
+ }
47
+ }
48
+ }
49
+ //# sourceMappingURL=tunnel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tunnel.js","sourceRoot":"","sources":["../../src/nodes/tunnel.ts"],"names":[],"mappings":"AAAA,oEAAoE;AAIpE,OAAO,EAAE,YAAY,EAAe,MAAM,UAAU,CAAC;AAMrD,MAAM,OAAO,aAAa;IAIJ;IAHZ,OAAO,GAA8B,IAAI,GAAG,EAAE,CAAC;IAC/C,SAAS,GAAG,CAAC,CAAC;IAEtB,YAAoB,OAAoB;QAApB,YAAO,GAAP,OAAO,CAAa;IAAG,CAAC;IAE5C,KAAK,CAAC,MAAM,CACV,MAAc,EACd,SAAiB,EACjB,UAAkB,EAClB,aAAqB,WAAW;QAEhC,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAC9C,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,QAAQ,MAAM,mBAAmB,CAAC,CAAC;QAEhE,MAAM,EAAE,GAAG,UAAU,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC;QAExC,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,MAAM,EAAE,EAAE;YACrC,MAAM,CAAC,UAAU,CACf,WAAW,EACX,SAAS,EACT,UAAU,EACV,UAAU,EACV,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE;gBACd,IAAI,GAAG,EAAE,CAAC;oBACR,MAAM,CAAC,GAAG,EAAE,CAAC;oBACb,OAAO;gBACT,CAAC;gBACD,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;gBACpB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACtB,CAAC,CACF,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC1C,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;YACvD,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;QAEH,MAAM,IAAI,GAAe,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC;QAC3E,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QAE1C,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,QAAgB;QACpB,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC1C,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YACtB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAED,IAAI;QACF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;IACjF,CAAC;IAED,QAAQ;QACN,KAAK,MAAM,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAChC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACjB,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,9 @@
1
+ import type { MeshConfig, MeshNode, NodeRole } from './types.js';
2
+ export declare function localNodeId(): string;
3
+ export declare const NODE_ROLES: Record<string, NodeRole>;
4
+ export declare function getNodeForRole(role: NodeRole): MeshNode | undefined;
5
+ export declare function getDefaultNodeForTask(task: 'storage' | 'browser' | 'compute' | 'local'): string;
6
+ export declare const CONFIG: MeshConfig;
7
+ export declare function findNode(query: string): MeshNode | undefined;
8
+ export declare function remoteNodes(): MeshNode[];
9
+ export declare function allNodes(): MeshNode[];
@@ -0,0 +1,133 @@
1
+ // OmniWire mesh configuration — loaded from ~/.omniwire/mesh.json or env
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { readFileSync, existsSync } from 'node:fs';
5
+ const home = homedir();
6
+ const sshDir = join(home, '.ssh');
7
+ function resolveIdentityFile(identityFile) {
8
+ if (!identityFile)
9
+ return '';
10
+ // If already absolute, return as-is
11
+ if (identityFile.startsWith('/') || identityFile.includes(':'))
12
+ return identityFile;
13
+ return join(sshDir, identityFile);
14
+ }
15
+ function buildLocalNode() {
16
+ const isWindows = process.platform === 'win32';
17
+ return {
18
+ id: localNodeId(),
19
+ alias: isWindows ? 'local' : 'local',
20
+ host: '127.0.0.1',
21
+ port: 0,
22
+ user: isWindows ? (process.env.USERNAME ?? 'user') : (process.env.USER ?? 'user'),
23
+ identityFile: '',
24
+ os: isWindows ? 'windows' : 'linux',
25
+ isLocal: true,
26
+ tags: ['local', isWindows ? 'windows' : 'linux'],
27
+ };
28
+ }
29
+ export function localNodeId() {
30
+ if (process.platform === 'win32')
31
+ return 'windows';
32
+ return process.env.OMNIWIRE_NODE_ID ?? 'local';
33
+ }
34
+ function loadMeshJson() {
35
+ // 1. Try ~/.omniwire/mesh.json
36
+ const configPath = join(home, '.omniwire', 'mesh.json');
37
+ if (existsSync(configPath)) {
38
+ try {
39
+ const raw = readFileSync(configPath, 'utf8');
40
+ return JSON.parse(raw);
41
+ }
42
+ catch {
43
+ process.stderr.write(`[omniwire] Warning: failed to parse ${configPath}\n`);
44
+ }
45
+ }
46
+ // 2. Try OMNIWIRE_CONFIG env var (JSON string)
47
+ const envConfig = process.env.OMNIWIRE_CONFIG;
48
+ if (envConfig) {
49
+ try {
50
+ return JSON.parse(envConfig);
51
+ }
52
+ catch {
53
+ process.stderr.write('[omniwire] Warning: failed to parse OMNIWIRE_CONFIG env var\n');
54
+ }
55
+ }
56
+ return null;
57
+ }
58
+ function buildConfig() {
59
+ const json = loadMeshJson();
60
+ const localNode = buildLocalNode();
61
+ if (!json || !json.nodes || json.nodes.length === 0) {
62
+ // Minimal fallback: local node only
63
+ return {
64
+ nodes: [localNode],
65
+ roles: { [localNode.id]: 'controller' },
66
+ meshSubnet: '10.0.0.0/24',
67
+ claudePath: 'claude',
68
+ };
69
+ }
70
+ const remoteNodes = json.nodes.map((n) => ({
71
+ id: n.id,
72
+ alias: n.alias ?? n.id.slice(0, 3),
73
+ host: n.host,
74
+ port: n.port ?? 22,
75
+ user: n.user,
76
+ identityFile: resolveIdentityFile(n.identityFile),
77
+ os: n.os ?? 'linux',
78
+ isLocal: n.isLocal ?? false,
79
+ tags: n.tags ?? [],
80
+ }));
81
+ // Prepend local node if not already in json
82
+ const hasLocal = remoteNodes.some((n) => n.isLocal);
83
+ const nodes = hasLocal ? remoteNodes : [localNode, ...remoteNodes];
84
+ // Build roles map: from json.roles, then fall back to per-node role fields
85
+ const roles = { [localNode.id]: 'controller' };
86
+ if (json.roles) {
87
+ Object.assign(roles, json.roles);
88
+ }
89
+ else {
90
+ for (const n of json.nodes) {
91
+ if (n.role)
92
+ roles[n.id] = n.role;
93
+ }
94
+ }
95
+ return {
96
+ nodes,
97
+ roles,
98
+ meshSubnet: json.meshSubnet ?? '10.0.0.0/24',
99
+ claudePath: json.claudePath ?? 'claude',
100
+ };
101
+ }
102
+ const _config = buildConfig();
103
+ const NODES = _config.nodes;
104
+ export const NODE_ROLES = _config.roles;
105
+ export function getNodeForRole(role) {
106
+ const id = Object.entries(NODE_ROLES).find(([, r]) => r === role)?.[0];
107
+ return id ? NODES.find((n) => n.id === id) : undefined;
108
+ }
109
+ export function getDefaultNodeForTask(task) {
110
+ switch (task) {
111
+ case 'storage': return getNodeForRole('storage')?.id ?? localNodeId();
112
+ case 'browser': return getNodeForRole('gpu+browser')?.id ?? localNodeId();
113
+ case 'compute': return getNodeForRole('compute')?.id ?? getNodeForRole('storage')?.id ?? localNodeId();
114
+ case 'local': return localNodeId();
115
+ }
116
+ }
117
+ export const CONFIG = {
118
+ nodes: NODES,
119
+ defaultNode: 'local',
120
+ meshSubnet: _config.meshSubnet,
121
+ claudePath: _config.claudePath,
122
+ };
123
+ export function findNode(query) {
124
+ const q = query.toLowerCase();
125
+ return CONFIG.nodes.find((n) => n.id === q || n.alias === q || n.host === q);
126
+ }
127
+ export function remoteNodes() {
128
+ return CONFIG.nodes.filter((n) => !n.isLocal);
129
+ }
130
+ export function allNodes() {
131
+ return [...CONFIG.nodes];
132
+ }
133
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/protocol/config.ts"],"names":[],"mappings":"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"}