project-graph-mcp 2.3.0 → 2.3.2

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 (66) hide show
  1. package/package.json +1 -3
  2. package/project-graph-mcp-2.3.0.tgz +0 -0
  3. package/src/network/web-server.js +1 -1
  4. package/vendor/symbiote-node/engine/AgentUICommands.js +100 -0
  5. package/vendor/symbiote-node/engine/Executor.js +371 -0
  6. package/vendor/symbiote-node/engine/Graph.js +314 -0
  7. package/vendor/symbiote-node/engine/GraphServer.js +353 -0
  8. package/vendor/symbiote-node/engine/HandlerLoader.js +145 -0
  9. package/vendor/symbiote-node/engine/History.js +83 -0
  10. package/vendor/symbiote-node/engine/Lifecycle.js +118 -0
  11. package/vendor/symbiote-node/engine/Persistence.js +84 -0
  12. package/vendor/symbiote-node/engine/Registry.js +264 -0
  13. package/vendor/symbiote-node/engine/SocketTypes.js +79 -0
  14. package/vendor/symbiote-node/engine/cli.js +404 -0
  15. package/vendor/symbiote-node/engine/index.js +56 -0
  16. package/vendor/symbiote-node/engine/nanoid.js +28 -0
  17. package/vendor/symbiote-node/engine/package.json +26 -0
  18. package/vendor/symbiote-node/engine/packs/ai/beat-detect.handler.js +215 -0
  19. package/vendor/symbiote-node/engine/packs/ai/content-adapt.handler.js +238 -0
  20. package/vendor/symbiote-node/engine/packs/ai/face-detect.handler.js +287 -0
  21. package/vendor/symbiote-node/engine/packs/ai/grok-generate.handler.js +565 -0
  22. package/vendor/symbiote-node/engine/packs/ai/kling-lipsync.handler.js +414 -0
  23. package/vendor/symbiote-node/engine/packs/ai/lesson-generate.handler.js +343 -0
  24. package/vendor/symbiote-node/engine/packs/ai/opencode.handler.js +164 -0
  25. package/vendor/symbiote-node/engine/packs/ai/replicate-lipsync.handler.js +341 -0
  26. package/vendor/symbiote-node/engine/packs/ai/tts.handler.js +241 -0
  27. package/vendor/symbiote-node/engine/packs/ai/whisper.handler.js +191 -0
  28. package/vendor/symbiote-node/engine/packs/data/db-query.handler.js +67 -0
  29. package/vendor/symbiote-node/engine/packs/data/news-accumulate.handler.js +281 -0
  30. package/vendor/symbiote-node/engine/packs/data/personas.handler.js +160 -0
  31. package/vendor/symbiote-node/engine/packs/data/prompt-loader.handler.js +193 -0
  32. package/vendor/symbiote-node/engine/packs/data/roles.handler.js +216 -0
  33. package/vendor/symbiote-node/engine/packs/data/rss-feed.handler.js +244 -0
  34. package/vendor/symbiote-node/engine/packs/debug/inject.handler.js +52 -0
  35. package/vendor/symbiote-node/engine/packs/flow/agent.handler.js +73 -0
  36. package/vendor/symbiote-node/engine/packs/flow/if.handler.js +107 -0
  37. package/vendor/symbiote-node/engine/packs/flow/loop.handler.js +58 -0
  38. package/vendor/symbiote-node/engine/packs/flow/merge.handler.js +60 -0
  39. package/vendor/symbiote-node/engine/packs/flow/retry.handler.js +65 -0
  40. package/vendor/symbiote-node/engine/packs/flow/switch.handler.js +64 -0
  41. package/vendor/symbiote-node/engine/packs/flow/wait-all.handler.js +39 -0
  42. package/vendor/symbiote-node/engine/packs/io/http-request.handler.js +82 -0
  43. package/vendor/symbiote-node/engine/packs/io/read-file.handler.js +60 -0
  44. package/vendor/symbiote-node/engine/packs/io/write-file.handler.js +63 -0
  45. package/vendor/symbiote-node/engine/packs/transform/anchor-match.handler.js +494 -0
  46. package/vendor/symbiote-node/engine/packs/transform/effects-skeleton.handler.js +417 -0
  47. package/vendor/symbiote-node/engine/packs/transform/json-parse.handler.js +43 -0
  48. package/vendor/symbiote-node/engine/packs/transform/lipsync-select.handler.js +339 -0
  49. package/vendor/symbiote-node/engine/packs/transform/riopla-adapt.handler.js +432 -0
  50. package/vendor/symbiote-node/engine/packs/transform/set.handler.js +57 -0
  51. package/vendor/symbiote-node/engine/packs/transform/template-builder.handler.js +134 -0
  52. package/vendor/symbiote-node/engine/packs/transform/template.handler.js +79 -0
  53. package/vendor/symbiote-node/engine/packs/transform/timeline-build.handler.js +399 -0
  54. package/vendor/symbiote-node/engine/packs/util/delay.handler.js +39 -0
  55. package/vendor/symbiote-node/engine/packs/util/log.handler.js +44 -0
  56. package/vendor/symbiote-node/engine/packs/video-pack.js +323 -0
  57. package/vendor/symbiote-node/package.json +2 -2
  58. package/web/app.js +6 -3
  59. package/web/components/canvas-graph.js +50 -11
  60. package/web/components/code-block.js +1 -1
  61. package/web/components/event-feed/MiniGraphWidget.js +105 -15
  62. package/web/components/follow-ribbon.js +134 -0
  63. package/web/follow-controller.js +241 -0
  64. package/web/panels/code-viewer.js +1 -1
  65. package/web/panels/dep-graph.js +21 -42
  66. package/web/style.css +6 -0
@@ -0,0 +1,79 @@
1
+ /**
2
+ * SocketTypes.js - Universal typed socket system
3
+ *
4
+ * Defines socket types for node connections with color coding
5
+ * and compatibility rules. Domain packs register additional types.
6
+ *
7
+ * @module agi-graph/SocketTypes
8
+ */
9
+
10
+ /**
11
+ * @typedef {object} SocketTypeDef
12
+ * @property {string} color - Hex color for UI rendering
13
+ * @property {string} label - Human-readable label
14
+ * @property {string[]} compatible - Types this socket can connect to
15
+ */
16
+
17
+ /** @type {Map<string, SocketTypeDef>} */
18
+ const _types = new Map();
19
+
20
+ /**
21
+ * Register a socket type
22
+ * @param {string} name
23
+ * @param {SocketTypeDef} def
24
+ */
25
+ export function registerSocketType(name, def) {
26
+ _types.set(name, { ...def, compatible: def.compatible || [name] });
27
+ }
28
+
29
+ /**
30
+ * Register multiple socket types at once
31
+ * @param {Record<string, SocketTypeDef>} types
32
+ */
33
+ export function registerSocketTypes(types) {
34
+ for (const [name, def] of Object.entries(types)) {
35
+ registerSocketType(name, def);
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Get socket type definition
41
+ * @param {string} name
42
+ * @returns {SocketTypeDef|undefined}
43
+ */
44
+ export function getSocketType(name) {
45
+ return _types.get(name);
46
+ }
47
+
48
+ /**
49
+ * Get all registered socket types
50
+ * @returns {Map<string, SocketTypeDef>}
51
+ */
52
+ export function getAllSocketTypes() {
53
+ return new Map(_types);
54
+ }
55
+
56
+ /**
57
+ * Check if two socket types are compatible
58
+ * @param {string} from - Source socket type
59
+ * @param {string} to - Target socket type
60
+ * @returns {boolean}
61
+ */
62
+ export function areSocketsCompatible(from, to) {
63
+ if (from === 'any' || to === 'any') return true;
64
+ if (from === to) return true;
65
+ const fromDef = _types.get(from);
66
+ if (!fromDef) return false;
67
+ return fromDef.compatible.includes(to);
68
+ }
69
+
70
+ // Core socket types (always available)
71
+ registerSocketTypes({
72
+ any: { color: '#FFFFFF', label: 'Any', compatible: [] },
73
+ float: { color: '#A1A1A1', label: 'Float', compatible: ['float', 'int'] },
74
+ int: { color: '#598C5C', label: 'Integer', compatible: ['int', 'float'] },
75
+ string: { color: '#70B2FF', label: 'String', compatible: ['string'] },
76
+ boolean: { color: '#CCA6D6', label: 'Boolean', compatible: ['boolean'] },
77
+ object: { color: '#E09050', label: 'Object', compatible: ['object'] },
78
+ array: { color: '#50C878', label: 'Array', compatible: ['array'] },
79
+ });
@@ -0,0 +1,404 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * cli.js - AGI-Graph command-line runner
5
+ *
6
+ * Execute, validate, and inspect workflow JSON files.
7
+ *
8
+ * Usage:
9
+ * node symbiote-node/cli.js run <workflow.json> [--pack custom] [--secrets secrets.json] [--verbose]
10
+ * node symbiote-node/cli.js validate <workflow.json> [--pack custom]
11
+ * node symbiote-node/cli.js list [--pack custom]
12
+ * node symbiote-node/cli.js inspect <workflow.json>
13
+ *
14
+ * @module symbiote-node/cli */
15
+
16
+ import { readFile } from 'node:fs/promises';
17
+ import { resolve, dirname } from 'node:path';
18
+ import { fileURLToPath } from 'node:url';
19
+ import { performance } from 'node:perf_hooks';
20
+
21
+ import {
22
+ Graph,
23
+ Executor,
24
+ listDrivers,
25
+ getNodeType,
26
+ findCompatible,
27
+ getNodeMenu,
28
+ validateParams,
29
+ deserialize,
30
+ clearRegistry,
31
+ loadHandlers,
32
+ createServer,
33
+ } from './index.js';
34
+
35
+ const __dirname = dirname(fileURLToPath(import.meta.url));
36
+
37
+ // ─── Argument Parsing ────────────────────────────────────────────────────────
38
+
39
+ /**
40
+ * Parse CLI arguments into command and options
41
+ * @param {string[]} argv
42
+ * @returns {{command: string, target: string, options: Record<string, string|boolean>}}
43
+ */
44
+ function parseArgs(argv) {
45
+ const args = argv.slice(2);
46
+ const command = args[0];
47
+ let target = '';
48
+ /** @type {Record<string, string|boolean>} */
49
+ const options = {};
50
+
51
+ for (let i = 1; i < args.length; i++) {
52
+ if (args[i].startsWith('--')) {
53
+ const key = args[i].slice(2);
54
+ const next = args[i + 1];
55
+ if (next && !next.startsWith('--')) {
56
+ options[key] = next;
57
+ i++;
58
+ } else {
59
+ options[key] = true;
60
+ }
61
+ } else if (!target) {
62
+ target = args[i];
63
+ }
64
+ }
65
+
66
+ return { command, target, options };
67
+ }
68
+
69
+ // ─── Secrets Loader ──────────────────────────────────────────────────────────
70
+
71
+ /**
72
+ * Load secrets from JSON file
73
+ * @param {string} [secretsPath]
74
+ * @returns {Promise<Record<string, string>>}
75
+ */
76
+ async function loadSecrets(secretsPath) {
77
+ if (!secretsPath) {
78
+ // Try default location
79
+ const defaultPath = resolve(process.cwd(), 'secrets.json');
80
+ try {
81
+ const data = await readFile(defaultPath, 'utf-8');
82
+ return JSON.parse(data);
83
+ } catch {
84
+ return {};
85
+ }
86
+ }
87
+
88
+ try {
89
+ const data = await readFile(resolve(secretsPath), 'utf-8');
90
+ return JSON.parse(data);
91
+ } catch (err) {
92
+ console.error(`⚠ Could not load secrets from ${secretsPath}: ${err.message}`);
93
+ return {};
94
+ }
95
+ }
96
+
97
+ // ─── Pack Loader ─────────────────────────────────────────────────────────────
98
+
99
+ /**
100
+ * Load domain packs by name
101
+ * @param {string|string[]} packs
102
+ */
103
+ async function loadPacks(packs) {
104
+ const packList = Array.isArray(packs) ? packs : packs.split(',');
105
+ for (const pack of packList) {
106
+ const packName = pack.trim();
107
+ try {
108
+ await import(`./packs/${packName}-pack.js`);
109
+ console.log(` ✔ Pack loaded: ${packName}`);
110
+ } catch (err) {
111
+ console.error(` ✖ Failed to load pack "${packName}": ${err.message}`);
112
+ process.exit(1);
113
+ }
114
+ }
115
+ }
116
+
117
+ // ─── Commands ────────────────────────────────────────────────────────────────
118
+
119
+ /**
120
+ * Run a workflow JSON file
121
+ * @param {string} filePath
122
+ * @param {Record<string, string|boolean>} options
123
+ */
124
+ async function cmdRun(filePath, options) {
125
+ const verbose = !!options.verbose;
126
+ console.log(`\n🚀 symbiote-node run: ${filePath}\n`);
127
+ // Load packs
128
+ if (options.pack) {
129
+ await loadPacks(/** @type {string} */(options.pack));
130
+ }
131
+
132
+ // Load handler files
133
+ if (options.handlers) {
134
+ const dir = resolve(/** @type {string} */(options.handlers));
135
+ const types = await loadHandlers(dir);
136
+ if (verbose) console.log(` 🔧 Loaded ${types.length} handler(s) from ${options.handlers}`);
137
+ }
138
+
139
+ // Load secrets
140
+ const secrets = await loadSecrets(/** @type {string|undefined} */(options.secrets));
141
+ if (Object.keys(secrets).length > 0 && verbose) {
142
+ console.log(` 🔑 Secrets loaded: ${Object.keys(secrets).join(', ')}`);
143
+ }
144
+
145
+ // Load workflow
146
+ const raw = await readFile(resolve(filePath), 'utf-8');
147
+ const workflowData = JSON.parse(raw);
148
+
149
+ console.log(` 📄 Workflow: ${workflowData.name || workflowData.id}`);
150
+ console.log(` 📊 Nodes: ${workflowData.nodes?.length || 0}`);
151
+ console.log(` 🔗 Connections: ${workflowData.connections?.length || 0}`);
152
+ console.log();
153
+
154
+ // Deserialize into Graph
155
+ const graph = deserialize(raw);
156
+
157
+ // Execute
158
+ const executor = new Executor();
159
+ const t0 = performance.now();
160
+
161
+ try {
162
+ const result = await executor.run(graph, {
163
+ cache: workflowData.execution?.cache,
164
+ secrets,
165
+ });
166
+
167
+ const elapsed = (performance.now() - t0).toFixed(1);
168
+ console.log(` ✔ Execution complete in ${elapsed}ms`);
169
+ console.log(` 📋 Execution order: ${result.executionOrder.length} nodes`);
170
+
171
+ if (verbose) {
172
+ console.log('\n Execution log:');
173
+ for (const entry of result.log) {
174
+ const status = entry.skipped ? '⏭ skipped' : `✔ ${entry.time.toFixed(2)}ms`;
175
+ const nodeData = graph.getNode(entry.nodeId);
176
+ console.log(` ${nodeData?.name || entry.nodeId}: ${status}`);
177
+ }
178
+
179
+ console.log('\n Outputs:');
180
+ for (const [nodeId, output] of Object.entries(result.outputs)) {
181
+ const nodeData = graph.getNode(nodeId);
182
+ console.log(` ${nodeData?.name || nodeId}:`, JSON.stringify(output, null, 2).slice(0, 200));
183
+ }
184
+ }
185
+
186
+ // Summary
187
+ const outputNodes = result.executionOrder.filter(id => {
188
+ const node = graph.getNode(id);
189
+ return node?.type?.startsWith('output/');
190
+ });
191
+
192
+ if (outputNodes.length > 0) {
193
+ console.log(`\n Output nodes:`);
194
+ for (const id of outputNodes) {
195
+ const node = graph.getNode(id);
196
+ console.log(` → ${node.name || node.type} (${id})`);
197
+ }
198
+ }
199
+
200
+ console.log(`\n✅ Done\n`);
201
+
202
+ } catch (err) {
203
+ const elapsed = (performance.now() - t0).toFixed(1);
204
+ console.error(`\n ✖ Execution failed after ${elapsed}ms: ${err.message}\n`);
205
+ process.exit(1);
206
+ }
207
+ }
208
+
209
+ /**
210
+ * Validate a workflow JSON file without executing
211
+ * @param {string} filePath
212
+ * @param {Record<string, string|boolean>} options
213
+ */
214
+ async function cmdValidate(filePath, options) {
215
+ console.log(`\n🔍 symbiote-node validate: ${filePath}\n`);
216
+ if (options.pack) {
217
+ await loadPacks(/** @type {string} */(options.pack));
218
+ }
219
+
220
+ if (options.handlers) {
221
+ const dir = resolve(/** @type {string} */(options.handlers));
222
+ await loadHandlers(dir);
223
+ }
224
+
225
+ const raw = await readFile(resolve(filePath), 'utf-8');
226
+ const data = JSON.parse(raw);
227
+
228
+ let errors = 0;
229
+ let warnings = 0;
230
+
231
+ // Check all node types exist
232
+ for (const node of (data.nodes || [])) {
233
+ const typeDef = getNodeType(node.type);
234
+ if (!typeDef) {
235
+ console.error(` ✖ Unknown node type: ${node.type} (node: ${node.id})`);
236
+ errors++;
237
+ continue;
238
+ }
239
+
240
+ // Validate params
241
+ const validation = validateParams(node.type, node.params || {});
242
+ if (!validation.valid) {
243
+ for (const err of validation.errors) {
244
+ console.error(` ✖ ${node.id} (${node.type}): ${err}`);
245
+ errors++;
246
+ }
247
+ }
248
+ }
249
+
250
+ // Check connections reference valid nodes
251
+ const nodeIds = new Set((data.nodes || []).map(n => n.id));
252
+ for (const conn of (data.connections || [])) {
253
+ if (!nodeIds.has(conn.from)) {
254
+ console.error(` ✖ Connection references unknown source node: ${conn.from}`);
255
+ errors++;
256
+ }
257
+ if (!nodeIds.has(conn.to)) {
258
+ console.error(` ✖ Connection references unknown target node: ${conn.to}`);
259
+ errors++;
260
+ }
261
+ }
262
+
263
+ // Check for nodes with no connections (orphans)
264
+ const connectedNodes = new Set();
265
+ for (const conn of (data.connections || [])) {
266
+ connectedNodes.add(conn.from);
267
+ connectedNodes.add(conn.to);
268
+ }
269
+ for (const node of (data.nodes || [])) {
270
+ if (!connectedNodes.has(node.id)) {
271
+ console.warn(` ⚠ Orphan node: ${node.id} (${node.type})`);
272
+ warnings++;
273
+ }
274
+ }
275
+
276
+ console.log();
277
+ if (errors === 0) {
278
+ console.log(` ✅ Valid (${warnings} warning${warnings !== 1 ? 's' : ''})\n`);
279
+ } else {
280
+ console.error(` ❌ ${errors} error${errors !== 1 ? 's' : ''}, ${warnings} warning${warnings !== 1 ? 's' : ''}\n`);
281
+ process.exit(1);
282
+ }
283
+ }
284
+
285
+ /**
286
+ * List all registered node types
287
+ * @param {Record<string, string|boolean>} options
288
+ */
289
+ async function cmdList(options) {
290
+ console.log(`\n📋 symbiote-node node types\n`);
291
+ if (options.pack) {
292
+ await loadPacks(/** @type {string} */(options.pack));
293
+ }
294
+
295
+ if (options.handlers) {
296
+ const dir = resolve(/** @type {string} */(options.handlers));
297
+ await loadHandlers(dir);
298
+ }
299
+
300
+ const menu = getNodeMenu();
301
+ for (const group of menu) {
302
+ console.log(` ═══ ${group.category.toUpperCase()} ═══`);
303
+ for (const node of group.nodes) {
304
+ const typeDef = getNodeType(node.type);
305
+ const ins = typeDef?.driver.inputs?.length || 0;
306
+ const outs = typeDef?.driver.outputs?.length || 0;
307
+ console.log(` ${node.type} [${ins}→${outs}] ${node.description || ''}`);
308
+ }
309
+ console.log();
310
+ }
311
+
312
+ const total = listDrivers().length;
313
+ console.log(` Total: ${total} node types\n`);
314
+ }
315
+
316
+ /**
317
+ * Inspect a workflow — show structure without executing
318
+ * @param {string} filePath
319
+ */
320
+ async function cmdInspect(filePath) {
321
+ console.log(`\n🔎 symbiote-node inspect: ${filePath}\n`);
322
+ const raw = await readFile(resolve(filePath), 'utf-8');
323
+ const data = JSON.parse(raw);
324
+
325
+ console.log(` Name: ${data.name || '(unnamed)'}`);
326
+ console.log(` ID: ${data.id || '(none)'}`);
327
+ console.log(` Version: ${data.version || '(none)'}`);
328
+ console.log();
329
+
330
+ // Nodes
331
+ console.log(` Nodes (${data.nodes?.length || 0}):`);
332
+ for (const node of (data.nodes || [])) {
333
+ const paramKeys = Object.keys(node.params || {});
334
+ const paramStr = paramKeys.length > 0 ? ` {${paramKeys.join(', ')}}` : '';
335
+ console.log(` ${node.id} [${node.type}] ${node.name || ''}${paramStr}`);
336
+ }
337
+
338
+ // Connections
339
+ console.log(`\n Connections (${data.connections?.length || 0}):`);
340
+ for (const conn of (data.connections || [])) {
341
+ console.log(` ${conn.from}.${conn.out} → ${conn.to}.${conn.in}`);
342
+ }
343
+
344
+ // Execution
345
+ if (data.execution) {
346
+ console.log(`\n Execution: mode=${data.execution.mode}, cache=${data.execution.cache}`);
347
+ }
348
+
349
+ console.log();
350
+ }
351
+
352
+ // ─── Main ────────────────────────────────────────────────────────────────────
353
+
354
+ const HELP = `
355
+ symbiote-node CLI — Universal node-based workflow runner
356
+ Commands:
357
+ run <file.workflow.json> Execute a workflow
358
+ validate <file.workflow.json> Validate without executing
359
+ list List all registered node types
360
+ inspect <file.workflow.json> Show workflow structure
361
+ serve <file.workflow.json> Start WebSocket + HTTP server
362
+
363
+ Options:
364
+ --pack <name> Load domain pack (e.g. "custom") --handlers <dir> Load handler files from directory
365
+ --secrets <path> Path to secrets.json
366
+ --port <number> Server port (default: 3100)
367
+ --verbose Show detailed execution log
368
+ `;
369
+
370
+ const { command, target, options } = parseArgs(process.argv);
371
+
372
+ switch (command) {
373
+ case 'run':
374
+ if (!target) { console.error('Usage: symbiote-node run <file.workflow.json>'); process.exit(1); } await cmdRun(target, options);
375
+ break;
376
+
377
+ case 'validate':
378
+ if (!target) { console.error('Usage: symbiote-node validate <file.workflow.json>'); process.exit(1); } await cmdValidate(target, options);
379
+ break;
380
+
381
+ case 'list':
382
+ await cmdList(options);
383
+ break;
384
+
385
+ case 'inspect':
386
+ if (!target) { console.error('Usage: symbiote-node inspect <file.workflow.json>'); process.exit(1); } await cmdInspect(target);
387
+ break;
388
+
389
+ case 'serve': {
390
+ const port = parseInt(options.port) || 3100;
391
+ await createServer({
392
+ port,
393
+ workflowFile: target,
394
+ handlersDir: options.handlers ? resolve(options.handlers) : undefined,
395
+ watchFiles: true,
396
+ verbose: !!options.verbose,
397
+ });
398
+ break;
399
+ }
400
+
401
+ default:
402
+ console.log(HELP);
403
+ break;
404
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * symbiote-node - Universal node-based execution engine *
3
+ * AI-first, domain-agnostic graph runtime.
4
+ * Zero dependencies, pure ESM.
5
+ *
6
+ * @module symbiote-node */
7
+
8
+ // Core
9
+ export { Graph } from './Graph.js';
10
+ export { Executor } from './Executor.js';
11
+ export { History } from './History.js';
12
+ export { nanoid } from './nanoid.js';
13
+
14
+ // Registry (AI discovery)
15
+ export {
16
+ registerNodeType,
17
+ registerPack,
18
+ getNodeType,
19
+ listDrivers,
20
+ findCompatible,
21
+ findByCapability,
22
+ getNodeMenu,
23
+ registerCustomDrivers,
24
+ validateParams,
25
+ listPacks,
26
+ clearRegistry,
27
+ } from './Registry.js';
28
+
29
+ // Socket types
30
+ export {
31
+ registerSocketType,
32
+ registerSocketTypes,
33
+ getSocketType,
34
+ getAllSocketTypes,
35
+ areSocketsCompatible,
36
+ } from './SocketTypes.js';
37
+
38
+ // Persistence
39
+ export {
40
+ serialize,
41
+ deserialize,
42
+ saveToFile,
43
+ loadFromFile,
44
+ } from './Persistence.js';
45
+
46
+ // Lifecycle
47
+ export { runLifecycle } from './Lifecycle.js';
48
+
49
+ // Handler loader (Node.js only)
50
+ export { loadHandlers, watchHandlers } from './HandlerLoader.js';
51
+
52
+ // Agent UI commands
53
+ export * as AgentUI from './AgentUICommands.js';
54
+
55
+ // Graph server — import directly: import { createServer } from 'symbiote-node/engine/GraphServer.js'
56
+ // Not re-exported here because it requires 'ws' package (optional peer dependency)
@@ -0,0 +1,28 @@
1
+ /**
2
+ * nanoid.js - Minimal ID generator
3
+ *
4
+ * Generates short unique IDs (8 chars) for nodes, workflows, etc.
5
+ * No dependencies. Crypto-based when available, Math.random fallback.
6
+ *
7
+ * @module agi-graph/nanoid
8
+ */
9
+
10
+ const ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyz';
11
+ const ID_LENGTH = 8;
12
+
13
+ /**
14
+ * Generate a short unique ID
15
+ * @param {number} [length=8] - ID length
16
+ * @returns {string}
17
+ */
18
+ export function nanoid(length = ID_LENGTH) {
19
+ let id = '';
20
+ const bytes = typeof globalThis.crypto?.getRandomValues === 'function'
21
+ ? globalThis.crypto.getRandomValues(new Uint8Array(length))
22
+ : Array.from({ length }, () => Math.floor(Math.random() * 256));
23
+
24
+ for (let i = 0; i < length; i++) {
25
+ id += ALPHABET[bytes[i] % ALPHABET.length];
26
+ }
27
+ return id;
28
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "symbiote-node",
3
+ "version": "0.2.0",
4
+ "description": "Universal node-based execution engine. Domain-agnostic graph runtime.",
5
+ "type": "module",
6
+ "main": "index.js",
7
+ "bin": {
8
+ "symbiote-node": "./cli.js" },
9
+ "exports": {
10
+ ".": "./index.js",
11
+ "./cli": "./cli.js",
12
+ "./packs/*": "./packs/*"
13
+ },
14
+ "files": [
15
+ "*.js",
16
+ "packs/"
17
+ ],
18
+ "keywords": [
19
+ "graph",
20
+ "nodes",
21
+ "workflow",
22
+ "dag",
23
+ "automation",
24
+ "execution-engine" ],
25
+ "license": "MIT"
26
+ }