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,124 @@
1
+ // CyberSync — 8 MCP tools for sync status, control, and knowledge queries
2
+ import { z } from 'zod';
3
+ import { ALL_TOOLS } from '../sync/manifest.js';
4
+ export function registerSyncTools(server, db, engine, manifests, nodeId) {
5
+ // --- Tool 23: cybersync_status ---
6
+ server.tool('cybersync_status', 'CyberSync status: item counts, pending syncs, last heartbeat per node.', {}, async () => {
7
+ const heartbeats = await db.getHeartbeats();
8
+ const counts = await db.getItemCounts();
9
+ const lines = ['=== Node Heartbeats ==='];
10
+ for (const hb of heartbeats) {
11
+ lines.push(`${hb.nodeId}: last_seen=${hb.lastSeen.toISOString()}, items=${hb.itemsCount}, pending=${hb.pendingSync}`);
12
+ }
13
+ lines.push('', '=== Item Counts ===');
14
+ for (const c of counts) {
15
+ lines.push(`${c.tool}/${c.category}: ${c.count}`);
16
+ }
17
+ return { content: [{ type: 'text', text: lines.join('\n') }] };
18
+ });
19
+ // --- Tool 24: cybersync_sync_now ---
20
+ server.tool('cybersync_sync_now', 'Trigger immediate full reconciliation of all tool configs.', {}, async () => {
21
+ const result = await engine.reconcile(manifests);
22
+ return {
23
+ content: [{
24
+ type: 'text',
25
+ text: `Reconciliation complete: pushed=${result.pushed}, pulled=${result.pulled}, conflicts=${result.conflicts}`,
26
+ }],
27
+ };
28
+ });
29
+ // --- Tool 25: cybersync_diff ---
30
+ server.tool('cybersync_diff', 'Show items that differ between local node and the sync database.', {
31
+ tool: z.string().optional().describe('Filter by tool name'),
32
+ }, async ({ tool }) => {
33
+ const filteredManifests = tool
34
+ ? manifests.filter((m) => m.tool === tool)
35
+ : manifests;
36
+ const diffs = await engine.getDiff(filteredManifests);
37
+ if (diffs.length === 0) {
38
+ return { content: [{ type: 'text', text: 'No differences found. All items in sync.' }] };
39
+ }
40
+ const lines = diffs.map((d) => `[${d.direction}] ${d.tool}:${d.relPath} (local=${d.localHash?.slice(0, 8) ?? 'missing'}, remote=${d.remoteHash.slice(0, 8)})`);
41
+ return { content: [{ type: 'text', text: `${diffs.length} differences:\n${lines.join('\n')}` }] };
42
+ });
43
+ // --- Tool 26: cybersync_history ---
44
+ server.tool('cybersync_history', 'Query sync event history.', {
45
+ node: z.string().optional().describe('Filter by node'),
46
+ event_type: z.string().optional().describe('Filter by event type (push, pull, conflict, delete, reconcile, error)'),
47
+ limit: z.number().optional().describe('Max results (default 50)'),
48
+ }, async ({ node, event_type, limit }) => {
49
+ const events = await db.getEvents({
50
+ nodeId: node,
51
+ eventType: event_type,
52
+ limit: limit ?? 50,
53
+ });
54
+ if (events.length === 0) {
55
+ return { content: [{ type: 'text', text: 'No events found.' }] };
56
+ }
57
+ const lines = events.map((e) => `[${e.createdAt.toISOString()}] ${e.nodeId} ${e.eventType}: ${e.detail ?? ''}`);
58
+ return { content: [{ type: 'text', text: lines.join('\n') }] };
59
+ });
60
+ // --- Tool 27: cybersync_search_knowledge ---
61
+ server.tool('cybersync_search_knowledge', 'Search the unified knowledge base across all AI tools and nodes.', {
62
+ query: z.string().describe('Search query (matches key and value)'),
63
+ }, async ({ query }) => {
64
+ const results = await db.searchKnowledge(query);
65
+ if (results.length === 0) {
66
+ return { content: [{ type: 'text', text: `No knowledge entries matching "${query}".` }] };
67
+ }
68
+ const lines = results.map((r) => `[${r.sourceTool}] ${r.key}: ${JSON.stringify(r.value).slice(0, 200)}`);
69
+ return { content: [{ type: 'text', text: `${results.length} results:\n${lines.join('\n')}` }] };
70
+ });
71
+ // --- Tool 28: cybersync_get_memory ---
72
+ server.tool('cybersync_get_memory', 'Get Claude memory entries from PostgreSQL (ingested from memory.db).', {
73
+ node: z.string().optional().describe('Filter by node'),
74
+ key: z.string().optional().describe('Search key pattern'),
75
+ }, async ({ node, key }) => {
76
+ const entries = await db.getClaudeMemory({ nodeId: node, key });
77
+ if (entries.length === 0) {
78
+ return { content: [{ type: 'text', text: 'No memory entries found.' }] };
79
+ }
80
+ const lines = entries.map((e) => `[${e.nodeId}] ${e.key}: ${e.value.slice(0, 300)}`);
81
+ return { content: [{ type: 'text', text: `${entries.length} entries:\n${lines.join('\n')}` }] };
82
+ });
83
+ // --- Tool 29: cybersync_manifest ---
84
+ server.tool('cybersync_manifest', 'Show what files are tracked per AI tool.', {
85
+ tool: z.string().optional().describe(`Tool name: ${ALL_TOOLS.join(', ')}`),
86
+ }, async ({ tool }) => {
87
+ const filtered = tool
88
+ ? manifests.filter((m) => m.tool === tool)
89
+ : manifests;
90
+ const lines = [];
91
+ for (const m of filtered) {
92
+ lines.push(`=== ${m.tool} ===`);
93
+ lines.push(`Base: ${m.baseDir}`);
94
+ lines.push(`Sync: ${m.syncGlobs.join(', ')}`);
95
+ lines.push(`Exclude: ${m.excludeGlobs.join(', ') || '(none)'}`);
96
+ if (m.ingestDb)
97
+ lines.push(`Ingest DB: ${m.ingestDb}`);
98
+ // Count items in DB
99
+ const items = await db.getItemsByTool(m.tool);
100
+ lines.push(`DB items: ${items.length}`);
101
+ lines.push('');
102
+ }
103
+ return { content: [{ type: 'text', text: lines.join('\n') }] };
104
+ });
105
+ // --- Tool 30: cybersync_force_push ---
106
+ server.tool('cybersync_force_push', 'Force push a specific file to all online nodes, overwriting remote copies.', {
107
+ tool: z.string().describe('Tool name'),
108
+ rel_path: z.string().describe('Relative path within tool directory'),
109
+ }, async ({ tool, rel_path }) => {
110
+ const manifest = manifests.find((m) => m.tool === tool);
111
+ if (!manifest) {
112
+ return { content: [{ type: 'text', text: `Unknown tool: ${tool}` }] };
113
+ }
114
+ const absPath = `${manifest.baseDir}/${rel_path}`;
115
+ try {
116
+ await engine.pushFile(tool, rel_path, absPath);
117
+ return { content: [{ type: 'text', text: `Force pushed ${tool}:${rel_path} to all online nodes.` }] };
118
+ }
119
+ catch (err) {
120
+ return { content: [{ type: 'text', text: `Error: ${err.message}` }] };
121
+ }
122
+ });
123
+ }
124
+ //# sourceMappingURL=sync-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-tools.js","sourceRoot":"","sources":["../../src/mcp/sync-tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import { Client } from 'ssh2';
2
+ import type { NodeStatus, ExecResult } from '../protocol/types.js';
3
+ type ReconnectCallback = (nodeId: string) => void;
4
+ export declare class NodeManager {
5
+ private connections;
6
+ private reconnectCallbacks;
7
+ private reconnectDelays;
8
+ private statusCache;
9
+ private healthTimer;
10
+ connectAll(): Promise<void>;
11
+ private connect;
12
+ private scheduleReconnect;
13
+ getClient(nodeId: string): Client | null;
14
+ onReconnect(cb: ReconnectCallback): void;
15
+ isConnected(nodeId: string): boolean;
16
+ getOnlineNodes(): string[];
17
+ exec(nodeId: string, command: string): Promise<ExecResult>;
18
+ private execLocal;
19
+ execAll(command: string): Promise<ExecResult[]>;
20
+ execRemote(command: string): Promise<ExecResult[]>;
21
+ execOn(nodeIds: string[], command: string): Promise<ExecResult[]>;
22
+ getNodeStatus(nodeId: string): Promise<NodeStatus>;
23
+ getAllStatus(): Promise<NodeStatus[]>;
24
+ streamExec(nodeId: string, command: string, onData: (chunk: string) => void, onError: (chunk: string) => void): Promise<number>;
25
+ private startHealthPing;
26
+ disconnect(): void;
27
+ }
28
+ export {};
@@ -0,0 +1,341 @@
1
+ // OmniWire Node Manager — persistent SSH connections to all mesh nodes
2
+ import { Client } from 'ssh2';
3
+ import { readFileSync } from 'node:fs';
4
+ import { execFile } from 'node:child_process';
5
+ import { remoteNodes } from '../protocol/config.js';
6
+ const MAX_OUTPUT_BYTES = 2 * 1024 * 1024; // 2MB output guard
7
+ const STATUS_CACHE_TTL = 5000; // 5s status cache
8
+ const HEALTH_PING_INTERVAL = 30_000; // 30s health pings
9
+ const CIRCUIT_OPEN_DURATION = 60_000; // 60s circuit breaker
10
+ const CIRCUIT_FAILURE_THRESHOLD = 3;
11
+ export class NodeManager {
12
+ connections = new Map();
13
+ reconnectCallbacks = [];
14
+ reconnectDelays = new Map();
15
+ statusCache = new Map();
16
+ healthTimer = null;
17
+ async connectAll() {
18
+ const nodes = remoteNodes();
19
+ await Promise.allSettled(nodes.map((node) => this.connect(node)));
20
+ this.startHealthPing();
21
+ }
22
+ async connect(node) {
23
+ if (node.isLocal)
24
+ return;
25
+ const client = new Client();
26
+ const conn = {
27
+ node,
28
+ client,
29
+ connected: false,
30
+ lastPing: null,
31
+ reconnecting: false,
32
+ failures: 0,
33
+ circuitOpenUntil: 0,
34
+ };
35
+ this.connections.set(node.id, conn);
36
+ return new Promise((resolve, reject) => {
37
+ const timeout = setTimeout(() => {
38
+ client.end();
39
+ reject(new Error(`Connection to ${node.id} timed out`));
40
+ }, 8000);
41
+ client.on('ready', () => {
42
+ clearTimeout(timeout);
43
+ conn.connected = true;
44
+ conn.lastPing = new Date();
45
+ resolve();
46
+ });
47
+ client.on('error', (err) => {
48
+ clearTimeout(timeout);
49
+ conn.connected = false;
50
+ reject(err);
51
+ });
52
+ client.on('close', () => {
53
+ conn.connected = false;
54
+ this.scheduleReconnect(node);
55
+ });
56
+ const config = {
57
+ host: node.host,
58
+ port: node.port,
59
+ username: node.user,
60
+ privateKey: readFileSync(node.identityFile),
61
+ readyTimeout: 8000,
62
+ keepaliveInterval: 5000,
63
+ keepaliveCountMax: 3,
64
+ algorithms: {
65
+ compress: ['zlib@openssh.com', 'zlib', 'none'],
66
+ },
67
+ };
68
+ client.connect(config);
69
+ });
70
+ }
71
+ scheduleReconnect(node) {
72
+ const conn = this.connections.get(node.id);
73
+ if (!conn || conn.reconnecting)
74
+ return;
75
+ conn.reconnecting = true;
76
+ const currentDelay = this.reconnectDelays.get(node.id) ?? 1000;
77
+ const jitter = Math.floor(Math.random() * 1000);
78
+ setTimeout(async () => {
79
+ try {
80
+ conn.client = new Client();
81
+ await this.connect(node);
82
+ conn.reconnecting = false;
83
+ conn.failures = 0;
84
+ conn.circuitOpenUntil = 0;
85
+ this.reconnectDelays.set(node.id, 1000); // reset on success
86
+ for (const cb of this.reconnectCallbacks)
87
+ cb(node.id);
88
+ }
89
+ catch {
90
+ conn.reconnecting = false;
91
+ // Exponential backoff: 1s → 2s → 4s → 8s → 16s → 30s cap
92
+ this.reconnectDelays.set(node.id, Math.min(currentDelay * 2, 30_000));
93
+ this.scheduleReconnect(node);
94
+ }
95
+ }, currentDelay + jitter);
96
+ }
97
+ getClient(nodeId) {
98
+ if (nodeId === 'windows')
99
+ return null;
100
+ const conn = this.connections.get(nodeId);
101
+ return conn?.connected ? conn.client : null;
102
+ }
103
+ onReconnect(cb) {
104
+ this.reconnectCallbacks.push(cb);
105
+ }
106
+ isConnected(nodeId) {
107
+ if (nodeId === 'windows')
108
+ return true;
109
+ return this.connections.get(nodeId)?.connected ?? false;
110
+ }
111
+ getOnlineNodes() {
112
+ const online = ['windows'];
113
+ for (const [id, conn] of this.connections) {
114
+ if (conn.connected)
115
+ online.push(id);
116
+ }
117
+ return online;
118
+ }
119
+ // Remote execution via SSH2 client.exec() — NOT child_process.exec()
120
+ // All commands run on remote nodes over authenticated SSH channels
121
+ async exec(nodeId, command) {
122
+ const start = Date.now();
123
+ if (nodeId === 'windows') {
124
+ return this.execLocal(command, start);
125
+ }
126
+ const conn = this.connections.get(nodeId);
127
+ // Circuit breaker: skip if circuit is open
128
+ if (conn && conn.circuitOpenUntil > Date.now()) {
129
+ return {
130
+ nodeId,
131
+ stdout: '',
132
+ stderr: `Node ${nodeId} circuit open (${conn.failures} consecutive failures)`,
133
+ code: -1,
134
+ durationMs: Date.now() - start,
135
+ };
136
+ }
137
+ if (!conn?.connected) {
138
+ return {
139
+ nodeId,
140
+ stdout: '',
141
+ stderr: `Node ${nodeId} is offline`,
142
+ code: -1,
143
+ durationMs: Date.now() - start,
144
+ };
145
+ }
146
+ return new Promise((resolve) => {
147
+ let stdout = '';
148
+ let stderr = '';
149
+ let truncated = false;
150
+ conn.client.exec(command, (err, stream) => {
151
+ if (err) {
152
+ conn.failures++;
153
+ if (conn.failures >= CIRCUIT_FAILURE_THRESHOLD) {
154
+ conn.circuitOpenUntil = Date.now() + CIRCUIT_OPEN_DURATION;
155
+ }
156
+ resolve({
157
+ nodeId,
158
+ stdout: '',
159
+ stderr: err.message,
160
+ code: -1,
161
+ durationMs: Date.now() - start,
162
+ });
163
+ return;
164
+ }
165
+ stream.on('data', (data) => {
166
+ if (!truncated && stdout.length < MAX_OUTPUT_BYTES) {
167
+ stdout += data.toString();
168
+ if (stdout.length >= MAX_OUTPUT_BYTES)
169
+ truncated = true;
170
+ }
171
+ });
172
+ stream.stderr.on('data', (data) => {
173
+ if (stderr.length < MAX_OUTPUT_BYTES) {
174
+ stderr += data.toString();
175
+ }
176
+ });
177
+ stream.on('close', (code) => {
178
+ conn.lastPing = new Date();
179
+ conn.failures = 0; // reset on success
180
+ const suffix = truncated ? '\n[truncated at 2MB]' : '';
181
+ resolve({
182
+ nodeId,
183
+ stdout: stdout.trimEnd() + suffix,
184
+ stderr: stderr.trimEnd(),
185
+ code: code ?? 0,
186
+ durationMs: Date.now() - start,
187
+ });
188
+ });
189
+ });
190
+ });
191
+ }
192
+ // Local execution uses execFile with bash -c to avoid shell injection
193
+ // Command strings here come from the user's own terminal input, not external sources
194
+ execLocal(command, start) {
195
+ return new Promise((resolve) => {
196
+ execFile('bash', ['-c', command], { timeout: 30000 }, (err, stdout, stderr) => {
197
+ resolve({
198
+ nodeId: 'windows',
199
+ stdout: (stdout ?? '').trimEnd(),
200
+ stderr: (stderr ?? '').trimEnd(),
201
+ code: err ? err.code ?? 1 : 0,
202
+ durationMs: Date.now() - start,
203
+ });
204
+ });
205
+ });
206
+ }
207
+ async execAll(command) {
208
+ const nodeIds = this.getOnlineNodes();
209
+ return Promise.all(nodeIds.map((id) => this.exec(id, command)));
210
+ }
211
+ async execRemote(command) {
212
+ const nodeIds = this.getOnlineNodes().filter((id) => id !== 'windows');
213
+ return Promise.all(nodeIds.map((id) => this.exec(id, command)));
214
+ }
215
+ async execOn(nodeIds, command) {
216
+ return Promise.all(nodeIds.map((id) => this.exec(id, command)));
217
+ }
218
+ async getNodeStatus(nodeId) {
219
+ if (nodeId === 'windows') {
220
+ return {
221
+ nodeId: 'windows',
222
+ online: true,
223
+ latencyMs: 0,
224
+ lastSeen: new Date(),
225
+ uptime: null,
226
+ loadAvg: null,
227
+ memUsedPct: null,
228
+ diskUsedPct: null,
229
+ };
230
+ }
231
+ // Return cached status if fresh enough
232
+ const cached = this.statusCache.get(nodeId);
233
+ if (cached && Date.now() - cached.at < STATUS_CACHE_TTL) {
234
+ return cached.status;
235
+ }
236
+ if (!this.isConnected(nodeId)) {
237
+ const status = {
238
+ nodeId,
239
+ online: false,
240
+ latencyMs: null,
241
+ lastSeen: this.connections.get(nodeId)?.lastPing ?? null,
242
+ uptime: null,
243
+ loadAvg: null,
244
+ memUsedPct: null,
245
+ diskUsedPct: null,
246
+ };
247
+ this.statusCache.set(nodeId, { status, at: Date.now() });
248
+ return status;
249
+ }
250
+ const start = Date.now();
251
+ const result = await this.exec(nodeId, "uptime -p; cat /proc/loadavg | awk '{print $1,$2,$3}'; free | awk '/Mem:/{printf \"%.1f\", $3/$2*100}'; echo; df / | awk 'NR==2{print $5}'");
252
+ const latency = Date.now() - start;
253
+ let status;
254
+ if (result.code !== 0) {
255
+ status = {
256
+ nodeId,
257
+ online: true,
258
+ latencyMs: latency,
259
+ lastSeen: new Date(),
260
+ uptime: null,
261
+ loadAvg: null,
262
+ memUsedPct: null,
263
+ diskUsedPct: null,
264
+ };
265
+ }
266
+ else {
267
+ const lines = result.stdout.split('\n');
268
+ status = {
269
+ nodeId,
270
+ online: true,
271
+ latencyMs: latency,
272
+ lastSeen: new Date(),
273
+ uptime: lines[0] ?? null,
274
+ loadAvg: lines[1] ?? null,
275
+ memUsedPct: parseFloat(lines[2]) || null,
276
+ diskUsedPct: parseFloat(lines[3]) || null,
277
+ };
278
+ }
279
+ this.statusCache.set(nodeId, { status, at: Date.now() });
280
+ return status;
281
+ }
282
+ async getAllStatus() {
283
+ const ids = ['windows', ...remoteNodes().map((n) => n.id)];
284
+ return Promise.all(ids.map((id) => this.getNodeStatus(id)));
285
+ }
286
+ async streamExec(nodeId, command, onData, onError) {
287
+ if (nodeId === 'windows') {
288
+ return new Promise((resolve) => {
289
+ const proc = execFile('bash', ['-c', command], { timeout: 60000 });
290
+ proc.stdout?.on('data', (d) => onData(d.toString()));
291
+ proc.stderr?.on('data', (d) => onError(d.toString()));
292
+ proc.on('close', (code) => resolve(code ?? 0));
293
+ });
294
+ }
295
+ const conn = this.connections.get(nodeId);
296
+ if (!conn?.connected) {
297
+ onError(`Node ${nodeId} is offline`);
298
+ return -1;
299
+ }
300
+ return new Promise((resolve) => {
301
+ conn.client.exec(command, (err, stream) => {
302
+ if (err) {
303
+ onError(err.message);
304
+ resolve(-1);
305
+ return;
306
+ }
307
+ stream.on('data', (d) => onData(d.toString()));
308
+ stream.stderr.on('data', (d) => onError(d.toString()));
309
+ stream.on('close', (code) => resolve(code ?? 0));
310
+ });
311
+ });
312
+ }
313
+ // Periodic health ping — verifies end-to-end SSH responsiveness
314
+ startHealthPing() {
315
+ this.healthTimer = setInterval(async () => {
316
+ for (const [nodeId, conn] of this.connections) {
317
+ if (!conn.connected || conn.circuitOpenUntil > Date.now())
318
+ continue;
319
+ const start = Date.now();
320
+ const result = await this.exec(nodeId, 'echo 1');
321
+ const elapsed = Date.now() - start;
322
+ if (elapsed > 3000 || result.code !== 0) {
323
+ process.stderr.write(`[health] ${nodeId} degraded (${elapsed}ms, code=${result.code})\n`);
324
+ }
325
+ }
326
+ }, HEALTH_PING_INTERVAL);
327
+ }
328
+ disconnect() {
329
+ if (this.healthTimer) {
330
+ clearInterval(this.healthTimer);
331
+ this.healthTimer = null;
332
+ }
333
+ for (const conn of this.connections.values()) {
334
+ conn.client.end();
335
+ conn.connected = false;
336
+ }
337
+ this.connections.clear();
338
+ this.statusCache.clear();
339
+ }
340
+ }
341
+ //# sourceMappingURL=manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/nodes/manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { NodeManager } from './manager.js';
2
+ export declare class RealtimeChannel {
3
+ private manager;
4
+ constructor(manager: NodeManager);
5
+ run(nodeId: string, command: string): Promise<{
6
+ stdout: string;
7
+ stderr: string;
8
+ code: number;
9
+ }>;
10
+ stream(nodeId: string, command: string, onData: (chunk: string) => void, signal?: AbortSignal): Promise<number>;
11
+ fire(nodeId: string, command: string): Promise<void>;
12
+ multiplex(command: string, onData: (nodeId: string, chunk: string) => void): Promise<Map<string, number>>;
13
+ }
@@ -0,0 +1,46 @@
1
+ // OmniWire Realtime Channel — multiplexed low-latency command dispatch
2
+ // NOTE: All execution goes through manager.exec() / manager.streamExec()
3
+ // which use SSH2 client channels, NOT child_process. No local shell involved.
4
+ export class RealtimeChannel {
5
+ manager;
6
+ constructor(manager) {
7
+ this.manager = manager;
8
+ }
9
+ // Run command with minimal overhead, return result
10
+ async run(nodeId, command) {
11
+ const result = await this.manager.exec(nodeId, command);
12
+ return { stdout: result.stdout, stderr: result.stderr, code: result.code };
13
+ }
14
+ // Stream real-time output (tail -f, watch, top, etc.)
15
+ async stream(nodeId, command, onData, signal) {
16
+ return new Promise((resolve) => {
17
+ if (signal?.aborted) {
18
+ resolve(-1);
19
+ return;
20
+ }
21
+ const code = this.manager.streamExec(nodeId, command, onData, onData // stderr also goes to output for streams
22
+ );
23
+ signal?.addEventListener('abort', () => {
24
+ resolve(-1);
25
+ });
26
+ code.then(resolve);
27
+ });
28
+ }
29
+ // Fire-and-forget background task on a remote node
30
+ async fire(nodeId, command) {
31
+ // Escaping for nohup wrapper — runs entirely on remote node via SSH
32
+ const escaped = command.replace(/'/g, "'\\''");
33
+ await this.manager.exec(nodeId, `nohup bash -c '${escaped}' &>/dev/null &`);
34
+ }
35
+ // Run on all nodes simultaneously, interleaved output
36
+ async multiplex(command, onData) {
37
+ const nodes = this.manager.getOnlineNodes();
38
+ const results = new Map();
39
+ await Promise.all(nodes.map(async (nodeId) => {
40
+ const code = await this.manager.streamExec(nodeId, command, (chunk) => onData(nodeId, chunk), (chunk) => onData(nodeId, chunk));
41
+ results.set(nodeId, code);
42
+ }));
43
+ return results;
44
+ }
45
+ }
46
+ //# sourceMappingURL=realtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime.js","sourceRoot":"","sources":["../../src/nodes/realtime.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,yEAAyE;AACzE,8EAA8E;AAI9E,MAAM,OAAO,eAAe;IACN;IAApB,YAAoB,OAAoB;QAApB,YAAO,GAAP,OAAO,CAAa;IAAG,CAAC;IAE5C,mDAAmD;IACnD,KAAK,CAAC,GAAG,CAAC,MAAc,EAAE,OAAe;QACvC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACxD,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;IAC7E,CAAC;IAED,sDAAsD;IACtD,KAAK,CAAC,MAAM,CACV,MAAc,EACd,OAAe,EACf,MAA+B,EAC/B,MAAoB;QAEpB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;gBAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;gBAAC,OAAO;YAAC,CAAC;YAE7C,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAClC,MAAM,EACN,OAAO,EACP,MAAM,EACN,MAAM,CAAC,yCAAyC;aACjD,CAAC;YAEF,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;gBACrC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;YACd,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACrB,CAAC,CAAC,CAAC;IACL,CAAC;IAED,mDAAmD;IACnD,KAAK,CAAC,IAAI,CAAC,MAAc,EAAE,OAAe;QACxC,oEAAoE;QACpE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC/C,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,kBAAkB,OAAO,iBAAiB,CAAC,CAAC;IAC9E,CAAC;IAED,sDAAsD;IACtD,KAAK,CAAC,SAAS,CACb,OAAe,EACf,MAA+C;QAE/C,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC;QAC5C,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;QAE1C,MAAM,OAAO,CAAC,GAAG,CACf,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;YACzB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,UAAU,CACxC,MAAM,EACN,OAAO,EACP,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAChC,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CACjC,CAAC;YACF,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC5B,CAAC,CAAC,CACH,CAAC;QAEF,OAAO,OAAO,CAAC;IACjB,CAAC;CACF"}
@@ -0,0 +1,17 @@
1
+ import type { ClientChannel } from 'ssh2';
2
+ import type { NodeManager } from './manager.js';
3
+ import type { ShellSession } from '../protocol/types.js';
4
+ export declare class ShellManager {
5
+ private manager;
6
+ private shells;
7
+ private idCounter;
8
+ constructor(manager: NodeManager);
9
+ openShell(nodeId: string): Promise<ShellSession>;
10
+ getChannel(shellId: string): ClientChannel | null;
11
+ closeShell(shellId: string): void;
12
+ listShells(): ShellSession[];
13
+ closeAll(): void;
14
+ private createIdleTimer;
15
+ enterInteractive(nodeId: string, stdin: NodeJS.ReadableStream, stdout: NodeJS.WritableStream, onExit: () => void): Promise<void>;
16
+ }
17
+ export declare function kernelExec(manager: NodeManager, nodeId: string, operation: string, args: string): Promise<string>;