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,3 @@
1
+ import type { MeshPath } from './types.js';
2
+ export declare function parseMeshPath(input: string): MeshPath | null;
3
+ export declare function formatMeshPath(mp: MeshPath): string;
@@ -0,0 +1,19 @@
1
+ // OmniWire path parser — "node:/path" syntax
2
+ import { findNode } from './config.js';
3
+ export function parseMeshPath(input) {
4
+ const colonIdx = input.indexOf(':');
5
+ if (colonIdx < 1)
6
+ return null;
7
+ const nodeQuery = input.slice(0, colonIdx);
8
+ const path = input.slice(colonIdx + 1);
9
+ if (!path.startsWith('/'))
10
+ return null;
11
+ const node = findNode(nodeQuery);
12
+ if (!node)
13
+ return null;
14
+ return { nodeId: node.id, path };
15
+ }
16
+ export function formatMeshPath(mp) {
17
+ return `${mp.nodeId}:${mp.path}`;
18
+ }
19
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/protocol/paths.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAG7C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACpC,IAAI,QAAQ,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAE9B,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAC3C,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;IACvC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAEvC,MAAM,IAAI,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;IACjC,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IAEvB,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,EAAY;IACzC,OAAO,GAAG,EAAE,CAAC,MAAM,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;AACnC,CAAC"}
@@ -0,0 +1,106 @@
1
+ export interface MeshNode {
2
+ readonly id: string;
3
+ readonly alias: string;
4
+ readonly host: string;
5
+ readonly port: number;
6
+ readonly user: string;
7
+ readonly identityFile: string;
8
+ readonly os: 'linux' | 'windows';
9
+ readonly isLocal: boolean;
10
+ readonly tags: readonly string[];
11
+ }
12
+ export interface NodeStatus {
13
+ readonly nodeId: string;
14
+ readonly online: boolean;
15
+ readonly latencyMs: number | null;
16
+ readonly lastSeen: Date | null;
17
+ readonly uptime: string | null;
18
+ readonly loadAvg: string | null;
19
+ readonly memUsedPct: number | null;
20
+ readonly diskUsedPct: number | null;
21
+ }
22
+ export interface ExecResult {
23
+ readonly nodeId: string;
24
+ readonly stdout: string;
25
+ readonly stderr: string;
26
+ readonly code: number;
27
+ readonly durationMs: number;
28
+ }
29
+ export interface ParsedCommand {
30
+ readonly target: CommandTarget;
31
+ readonly command: string;
32
+ readonly args: string[];
33
+ readonly raw: string;
34
+ }
35
+ export type NodeRole = 'controller' | 'storage' | 'compute' | 'gpu+browser';
36
+ export type CommandTarget = {
37
+ type: 'node';
38
+ nodeId: string;
39
+ } | {
40
+ type: 'all';
41
+ } | {
42
+ type: 'local';
43
+ } | {
44
+ type: 'claude';
45
+ prompt: string;
46
+ } | {
47
+ type: 'builtin';
48
+ name: string;
49
+ } | {
50
+ type: 'shell';
51
+ nodeId: string;
52
+ } | {
53
+ type: 'kernel';
54
+ nodeId: string;
55
+ } | {
56
+ type: 'stream';
57
+ nodeId: string;
58
+ };
59
+ export interface MeshConfig {
60
+ readonly nodes: readonly MeshNode[];
61
+ readonly defaultNode: string;
62
+ readonly meshSubnet: string;
63
+ readonly claudePath: string;
64
+ }
65
+ export type TransferMode = 'netcat-tar' | 'aria2c' | 'ssh-pipe';
66
+ export interface TransferResult {
67
+ readonly srcNode: string;
68
+ readonly dstNode: string;
69
+ readonly srcPath: string;
70
+ readonly dstPath: string;
71
+ readonly mode: TransferMode;
72
+ readonly bytesTransferred: number;
73
+ readonly durationMs: number;
74
+ readonly speedMBps: number;
75
+ }
76
+ export interface FileInfo {
77
+ readonly path: string;
78
+ readonly size: number;
79
+ readonly isDirectory: boolean;
80
+ readonly permissions: string;
81
+ readonly modified: string;
82
+ readonly owner: string;
83
+ }
84
+ export interface DirEntry {
85
+ readonly name: string;
86
+ readonly size: number;
87
+ readonly isDirectory: boolean;
88
+ readonly permissions: string;
89
+ readonly modified: string;
90
+ }
91
+ export interface MeshPath {
92
+ readonly nodeId: string;
93
+ readonly path: string;
94
+ }
95
+ export interface ShellSession {
96
+ readonly id: string;
97
+ readonly nodeId: string;
98
+ readonly startedAt: Date;
99
+ }
100
+ export interface TunnelInfo {
101
+ readonly id: string;
102
+ readonly nodeId: string;
103
+ readonly localPort: number;
104
+ readonly remotePort: number;
105
+ readonly remoteHost: string;
106
+ }
@@ -0,0 +1,3 @@
1
+ // OmniWire Protocol — Node and mesh type definitions
2
+ export {};
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/protocol/types.ts"],"names":[],"mappings":"AAAA,qDAAqD"}
@@ -0,0 +1,53 @@
1
+ import type { SyncItem, NodeSyncState, SyncEvent, SyncEventType, KnowledgeEntry, ClaudeMemoryEntry, NodeHeartbeat, SyncConfig } from './types.js';
2
+ export declare class SyncDB {
3
+ private config;
4
+ private pool;
5
+ constructor(config: SyncConfig);
6
+ init(): Promise<void>;
7
+ close(): Promise<void>;
8
+ upsertItem(item: {
9
+ tool: string;
10
+ category: string;
11
+ relPath: string;
12
+ contentHash: string;
13
+ content: Buffer | null;
14
+ contentSize: number;
15
+ metadata: Record<string, unknown>;
16
+ updatedByNode: string;
17
+ }): Promise<SyncItem>;
18
+ markDeleted(tool: string, relPath: string, nodeId: string): Promise<void>;
19
+ getItem(tool: string, relPath: string): Promise<SyncItem | null>;
20
+ getItemsByTool(tool: string): Promise<SyncItem[]>;
21
+ getAllItems(): Promise<SyncItem[]>;
22
+ getItemsUpdatedSince(since: Date): Promise<SyncItem[]>;
23
+ getItemCounts(): Promise<Array<{
24
+ tool: string;
25
+ category: string;
26
+ count: number;
27
+ }>>;
28
+ upsertNodeSync(nodeId: string, itemId: string, contentHash: string): Promise<void>;
29
+ getNodeSyncState(nodeId: string): Promise<NodeSyncState[]>;
30
+ getPendingItems(nodeId: string): Promise<SyncItem[]>;
31
+ logEvent(itemId: string | null, nodeId: string, eventType: SyncEventType, detail: string | null): Promise<void>;
32
+ getEvents(opts: {
33
+ nodeId?: string;
34
+ eventType?: string;
35
+ limit?: number;
36
+ }): Promise<SyncEvent[]>;
37
+ upsertKnowledge(sourceTool: string, key: string, value: Record<string, unknown>): Promise<void>;
38
+ searchKnowledge(query: string): Promise<KnowledgeEntry[]>;
39
+ upsertClaudeMemory(nodeId: string, key: string, value: string): Promise<void>;
40
+ getClaudeMemory(opts: {
41
+ nodeId?: string;
42
+ key?: string;
43
+ }): Promise<ClaudeMemoryEntry[]>;
44
+ heartbeat(nodeId: string, itemsCount: number, pendingSync: number): Promise<void>;
45
+ getHeartbeats(): Promise<NodeHeartbeat[]>;
46
+ batchUpsertNodeSync(entries: ReadonlyArray<{
47
+ nodeId: string;
48
+ itemId: string;
49
+ contentHash: string;
50
+ }>): Promise<void>;
51
+ pruneEvents(keepCount?: number): Promise<number>;
52
+ private mapSyncItem;
53
+ }
@@ -0,0 +1,212 @@
1
+ // CyberSync — PostgreSQL connection pool + query helpers
2
+ import pg from 'pg';
3
+ import { runMigrations } from './schema.js';
4
+ export class SyncDB {
5
+ config;
6
+ pool;
7
+ constructor(config) {
8
+ this.config = config;
9
+ this.pool = new pg.Pool({
10
+ host: config.pgHost,
11
+ port: config.pgPort,
12
+ database: config.pgDatabase,
13
+ user: config.pgUser,
14
+ password: config.pgPassword,
15
+ max: 8,
16
+ idleTimeoutMillis: 30_000,
17
+ connectionTimeoutMillis: 5_000,
18
+ statement_timeout: 10_000,
19
+ });
20
+ }
21
+ async init() {
22
+ await runMigrations(this.pool);
23
+ }
24
+ async close() {
25
+ await this.pool.end();
26
+ }
27
+ // --- sync_items ---
28
+ async upsertItem(item) {
29
+ const { rows } = await this.pool.query(`INSERT INTO sync_items (tool, category, rel_path, content_hash, content, content_size, metadata, updated_by_node, is_deleted)
30
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, false)
31
+ ON CONFLICT (tool, rel_path) DO UPDATE SET
32
+ content_hash = EXCLUDED.content_hash,
33
+ content = EXCLUDED.content,
34
+ content_size = EXCLUDED.content_size,
35
+ metadata = EXCLUDED.metadata,
36
+ updated_at = now(),
37
+ updated_by_node = EXCLUDED.updated_by_node,
38
+ is_deleted = false
39
+ WHERE sync_items.content_hash != EXCLUDED.content_hash
40
+ RETURNING *`, [item.tool, item.category, item.relPath, item.contentHash, item.content, item.contentSize, JSON.stringify(item.metadata), item.updatedByNode]);
41
+ // If no rows returned, item already up-to-date — fetch existing
42
+ if (rows.length === 0) {
43
+ const existing = await this.pool.query('SELECT * FROM sync_items WHERE tool = $1 AND rel_path = $2', [item.tool, item.relPath]);
44
+ return this.mapSyncItem(existing.rows[0]);
45
+ }
46
+ return this.mapSyncItem(rows[0]);
47
+ }
48
+ async markDeleted(tool, relPath, nodeId) {
49
+ await this.pool.query(`UPDATE sync_items SET is_deleted = true, updated_at = now(), updated_by_node = $3
50
+ WHERE tool = $1 AND rel_path = $2`, [tool, relPath, nodeId]);
51
+ }
52
+ async getItem(tool, relPath) {
53
+ const { rows } = await this.pool.query('SELECT * FROM sync_items WHERE tool = $1 AND rel_path = $2', [tool, relPath]);
54
+ return rows.length > 0 ? this.mapSyncItem(rows[0]) : null;
55
+ }
56
+ async getItemsByTool(tool) {
57
+ const { rows } = await this.pool.query('SELECT * FROM sync_items WHERE tool = $1 AND is_deleted = false ORDER BY rel_path', [tool]);
58
+ return rows.map((r) => this.mapSyncItem(r));
59
+ }
60
+ async getAllItems() {
61
+ const { rows } = await this.pool.query('SELECT * FROM sync_items WHERE is_deleted = false ORDER BY tool, rel_path');
62
+ return rows.map((r) => this.mapSyncItem(r));
63
+ }
64
+ async getItemsUpdatedSince(since) {
65
+ const { rows } = await this.pool.query('SELECT * FROM sync_items WHERE updated_at > $1 ORDER BY updated_at', [since]);
66
+ return rows.map((r) => this.mapSyncItem(r));
67
+ }
68
+ async getItemCounts() {
69
+ const { rows } = await this.pool.query(`SELECT tool, category, count(*)::int as count
70
+ FROM sync_items WHERE is_deleted = false
71
+ GROUP BY tool, category ORDER BY tool, category`);
72
+ return rows;
73
+ }
74
+ // --- node_sync_state ---
75
+ async upsertNodeSync(nodeId, itemId, contentHash) {
76
+ await this.pool.query(`INSERT INTO node_sync_state (node_id, item_id, content_hash, synced_at)
77
+ VALUES ($1, $2, $3, now())
78
+ ON CONFLICT (node_id, item_id) DO UPDATE SET
79
+ content_hash = EXCLUDED.content_hash,
80
+ synced_at = now()`, [nodeId, itemId, contentHash]);
81
+ }
82
+ async getNodeSyncState(nodeId) {
83
+ const { rows } = await this.pool.query('SELECT node_id as "nodeId", item_id as "itemId", content_hash as "contentHash", synced_at as "syncedAt" FROM node_sync_state WHERE node_id = $1', [nodeId]);
84
+ return rows;
85
+ }
86
+ async getPendingItems(nodeId) {
87
+ const { rows } = await this.pool.query(`SELECT si.* FROM sync_items si
88
+ LEFT JOIN node_sync_state nss ON si.id = nss.item_id AND nss.node_id = $1
89
+ WHERE si.is_deleted = false
90
+ AND (nss.content_hash IS NULL OR nss.content_hash != si.content_hash)
91
+ ORDER BY si.updated_at`, [nodeId]);
92
+ return rows.map((r) => this.mapSyncItem(r));
93
+ }
94
+ // --- sync_events ---
95
+ async logEvent(itemId, nodeId, eventType, detail) {
96
+ await this.pool.query('INSERT INTO sync_events (item_id, node_id, event_type, detail) VALUES ($1, $2, $3, $4)', [itemId, nodeId, eventType, detail]);
97
+ }
98
+ async getEvents(opts) {
99
+ const conditions = [];
100
+ const params = [];
101
+ let idx = 1;
102
+ if (opts.nodeId) {
103
+ conditions.push(`node_id = $${idx++}`);
104
+ params.push(opts.nodeId);
105
+ }
106
+ if (opts.eventType) {
107
+ conditions.push(`event_type = $${idx++}`);
108
+ params.push(opts.eventType);
109
+ }
110
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
111
+ const limit = opts.limit ?? 50;
112
+ const { rows } = await this.pool.query(`SELECT id, item_id as "itemId", node_id as "nodeId", event_type as "eventType", detail, created_at as "createdAt"
113
+ FROM sync_events ${where} ORDER BY created_at DESC LIMIT $${idx}`, [...params, limit]);
114
+ return rows;
115
+ }
116
+ // --- knowledge ---
117
+ async upsertKnowledge(sourceTool, key, value) {
118
+ await this.pool.query(`INSERT INTO knowledge (source_tool, key, value)
119
+ VALUES ($1, $2, $3)
120
+ ON CONFLICT (source_tool, key) DO UPDATE SET
121
+ value = EXCLUDED.value, updated_at = now()`, [sourceTool, key, JSON.stringify(value)]);
122
+ }
123
+ async searchKnowledge(query) {
124
+ // Try full-text search first (uses GIN index if available)
125
+ const { rows: ftsRows } = await this.pool.query(`SELECT id, source_tool as "sourceTool", key, value, created_at as "createdAt", updated_at as "updatedAt"
126
+ FROM knowledge
127
+ WHERE to_tsvector('english', key || ' ' || value::text) @@ plainto_tsquery('english', $1)
128
+ ORDER BY updated_at DESC LIMIT 50`, [query]).catch(() => ({ rows: [] }));
129
+ if (ftsRows.length > 0)
130
+ return ftsRows;
131
+ // Fallback to ILIKE for partial matches
132
+ const { rows } = await this.pool.query(`SELECT id, source_tool as "sourceTool", key, value, created_at as "createdAt", updated_at as "updatedAt"
133
+ FROM knowledge
134
+ WHERE key ILIKE $1 OR value::text ILIKE $1
135
+ ORDER BY updated_at DESC LIMIT 50`, [`%${query}%`]);
136
+ return rows;
137
+ }
138
+ // --- claude_memory ---
139
+ async upsertClaudeMemory(nodeId, key, value) {
140
+ await this.pool.query(`INSERT INTO claude_memory (node_id, key, value)
141
+ VALUES ($1, $2, $3)
142
+ ON CONFLICT (node_id, key) DO UPDATE SET
143
+ value = EXCLUDED.value,
144
+ ingested_at = now()`, [nodeId, key, value]);
145
+ }
146
+ async getClaudeMemory(opts) {
147
+ const conditions = [];
148
+ const params = [];
149
+ let idx = 1;
150
+ if (opts.nodeId) {
151
+ conditions.push(`node_id = $${idx++}`);
152
+ params.push(opts.nodeId);
153
+ }
154
+ if (opts.key) {
155
+ conditions.push(`key ILIKE $${idx++}`);
156
+ params.push(`%${opts.key}%`);
157
+ }
158
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
159
+ const { rows } = await this.pool.query(`SELECT id, node_id as "nodeId", key, value, ingested_at as "ingestedAt"
160
+ FROM claude_memory ${where} ORDER BY ingested_at DESC LIMIT 100`, params);
161
+ return rows;
162
+ }
163
+ // --- heartbeats ---
164
+ async heartbeat(nodeId, itemsCount, pendingSync) {
165
+ await this.pool.query(`INSERT INTO node_heartbeats (node_id, last_seen, items_count, pending_sync)
166
+ VALUES ($1, now(), $2, $3)
167
+ ON CONFLICT (node_id) DO UPDATE SET
168
+ last_seen = now(),
169
+ items_count = EXCLUDED.items_count,
170
+ pending_sync = EXCLUDED.pending_sync`, [nodeId, itemsCount, pendingSync]);
171
+ }
172
+ async getHeartbeats() {
173
+ const { rows } = await this.pool.query(`SELECT node_id as "nodeId", last_seen as "lastSeen", items_count as "itemsCount", pending_sync as "pendingSync"
174
+ FROM node_heartbeats ORDER BY node_id`);
175
+ return rows;
176
+ }
177
+ // --- batch operations ---
178
+ async batchUpsertNodeSync(entries) {
179
+ if (entries.length === 0)
180
+ return;
181
+ const nodeIds = entries.map((e) => e.nodeId);
182
+ const itemIds = entries.map((e) => e.itemId);
183
+ const hashes = entries.map((e) => e.contentHash);
184
+ await this.pool.query(`INSERT INTO node_sync_state (node_id, item_id, content_hash, synced_at)
185
+ SELECT unnest($1::text[]), unnest($2::uuid[]), unnest($3::text[]), now()
186
+ ON CONFLICT (node_id, item_id) DO UPDATE SET
187
+ content_hash = EXCLUDED.content_hash, synced_at = now()`, [nodeIds, itemIds, hashes]);
188
+ }
189
+ async pruneEvents(keepCount = 5000) {
190
+ const { rowCount } = await this.pool.query(`DELETE FROM sync_events WHERE id NOT IN (
191
+ SELECT id FROM sync_events ORDER BY created_at DESC LIMIT $1
192
+ )`, [keepCount]);
193
+ return rowCount ?? 0;
194
+ }
195
+ // --- helpers ---
196
+ mapSyncItem(row) {
197
+ return {
198
+ id: row.id,
199
+ tool: row.tool,
200
+ category: row.category,
201
+ relPath: (row.rel_path ?? row.relPath),
202
+ contentHash: (row.content_hash ?? row.contentHash),
203
+ content: row.content,
204
+ contentSize: Number(row.content_size ?? row.contentSize ?? 0),
205
+ metadata: (typeof row.metadata === 'string' ? JSON.parse(row.metadata) : row.metadata ?? {}),
206
+ updatedAt: new Date(row.updated_at ?? row.updatedAt),
207
+ updatedByNode: (row.updated_by_node ?? row.updatedByNode),
208
+ isDeleted: Boolean(row.is_deleted ?? row.isDeleted),
209
+ };
210
+ }
211
+ }
212
+ //# sourceMappingURL=db.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/sync/db.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { SyncDB } from './db.js';
2
+ import type { SyncConfig, ToolManifest, SyncDiff } from './types.js';
3
+ import type { NodeManager } from '../nodes/manager.js';
4
+ import type { TransferEngine } from '../nodes/transfer.js';
5
+ export declare class SyncEngine {
6
+ private db;
7
+ private config;
8
+ private manager;
9
+ private transfer;
10
+ constructor(db: SyncDB, config: SyncConfig, manager: NodeManager, transfer: TransferEngine);
11
+ pushFile(tool: string, relPath: string, absPath: string, opts?: {
12
+ skipRemotePush?: boolean;
13
+ }): Promise<void>;
14
+ deleteFile(tool: string, relPath: string): Promise<void>;
15
+ pullPending(): Promise<number>;
16
+ reconcile(manifests: readonly ToolManifest[]): Promise<{
17
+ pushed: number;
18
+ pulled: number;
19
+ conflicts: number;
20
+ }>;
21
+ getDiff(manifests: readonly ToolManifest[]): Promise<SyncDiff[]>;
22
+ private pushToRemoteNodes;
23
+ }