societyai 0.1.3 → 0.1.5

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.
package/bin/inspect.js CHANGED
File without changes
package/bin/societyai.js CHANGED
@@ -160,7 +160,7 @@ async function validateCommand(filePath) {
160
160
  const ext = path.extname(fullPath);
161
161
  if (ext === '.ts') {
162
162
  console.log(colorize('dim', ' Compiling TypeScript...'));
163
- execSync(`npx tsc --noEmit "${fullPath}"`, { stdio: 'pipe' });
163
+ execSync(`npx tsc --noEmit "${fullPath}"`, { stdio: 'pipe', cwd: path.dirname(fullPath) });
164
164
  }
165
165
 
166
166
  // Try to load and validate the module
@@ -171,7 +171,16 @@ async function validateCommand(filePath) {
171
171
 
172
172
  // For TypeScript, we need to use ts-node/register
173
173
  if (ext === '.ts') {
174
- require('ts-node/register');
174
+ const projectDir = path.dirname(fullPath);
175
+ const originalCwd = process.cwd();
176
+ process.chdir(projectDir);
177
+ const localTsNode = path.join(projectDir, 'node_modules', 'ts-node', 'register');
178
+ try {
179
+ require(localTsNode);
180
+ } catch (e) {
181
+ require('ts-node/register');
182
+ }
183
+ process.chdir(originalCwd);
175
184
  }
176
185
 
177
186
  const module = require(fullPath);
@@ -188,8 +197,12 @@ async function validateCommand(filePath) {
188
197
  console.warn(colorize('yellow', '⚠️ Warning: Society does not have an execute method'));
189
198
  }
190
199
 
191
- if (!society.agents || society.agents.length === 0) {
192
- console.warn(colorize('yellow', '⚠️ Warning: Society has no agents'));
200
+ // Use build() to get the SocietyConfig for structure validation
201
+ if (typeof society.build === 'function') {
202
+ const config = society.build();
203
+ if (!config.agents || config.agents.length === 0) {
204
+ console.warn(colorize('yellow', '⚠️ Warning: Society has no agents'));
205
+ }
193
206
  }
194
207
  }
195
208
 
@@ -236,23 +249,36 @@ async function visualizeCommand(filePath, options) {
236
249
  // Load the module
237
250
  const ext = path.extname(fullPath);
238
251
  if (ext === '.ts') {
239
- require('ts-node/register');
252
+ const projectDir = path.dirname(fullPath);
253
+ const originalCwd = process.cwd();
254
+ process.chdir(projectDir);
255
+ const localTsNode = path.join(projectDir, 'node_modules', 'ts-node', 'register');
256
+ try {
257
+ require(localTsNode);
258
+ } catch (e) {
259
+ require('ts-node/register');
260
+ }
261
+ process.chdir(originalCwd);
240
262
  }
241
263
 
242
264
  const module = require(fullPath);
243
265
  const society = module.default || module.society;
244
266
 
245
- if (!society || !society.engine) {
246
- console.error(colorize('red', '❌ Error: Could not find Society engine in file'));
267
+ if (!society || typeof society.build !== 'function') {
268
+ console.error(colorize('red', '❌ Error: Could not find Society builder in file'));
247
269
  process.exit(1);
248
270
  }
249
271
 
272
+ const { SocietyExecutor } = require('../dist/agents/society-executor');
273
+ const config = society.build();
274
+ const engine = new SocietyExecutor().buildExecutionGraph(config);
275
+
250
276
  let result = '';
251
277
 
252
278
  switch (format.toLowerCase()) {
253
279
  case 'mermaid':
254
280
  const { GraphVisualizer } = require('../dist/execution/graph-visualizer');
255
- result = GraphVisualizer.toMermaid(society.engine, {
281
+ result = GraphVisualizer.toMermaid(engine, {
256
282
  direction,
257
283
  theme,
258
284
  highlightPath: highlight,
@@ -262,27 +288,27 @@ async function visualizeCommand(filePath, options) {
262
288
  case 'dot':
263
289
  case 'graphviz':
264
290
  const { GraphVisualizer: GV2 } = require('../dist/execution/graph-visualizer');
265
- result = GV2.toDOT(society.engine, { rankdir: direction });
291
+ result = GV2.toDOT(engine, { rankdir: direction });
266
292
  break;
267
293
 
268
294
  case 'json':
269
295
  const { GraphVisualizer: GV3 } = require('../dist/execution/graph-visualizer');
270
- result = JSON.stringify(GV3.toJSON(society.engine), null, 2);
296
+ result = JSON.stringify(GV3.toJSON(engine), null, 2);
271
297
  break;
272
298
 
273
299
  case 'html':
274
300
  const { GraphVisualizer: GV4 } = require('../dist/execution/graph-visualizer');
275
- result = GV4.toHTML(society.engine, { direction, theme, highlightPath: highlight });
301
+ result = GV4.toHTML(engine, { direction, theme, highlightPath: highlight });
276
302
  break;
277
303
 
278
304
  case 'ascii':
279
305
  const { GraphVisualizer: GV5 } = require('../dist/execution/graph-visualizer');
280
- result = GV5.toASCII(society.engine);
306
+ result = GV5.toASCII(engine);
281
307
  break;
282
308
 
283
309
  case 'plantuml':
284
310
  const { GraphVisualizer: GV6 } = require('../dist/execution/graph-visualizer');
285
- result = GV6.toPlantUML(society.engine, direction);
311
+ result = GV6.toPlantUML(engine, direction);
286
312
  break;
287
313
 
288
314
  default:
@@ -334,8 +360,19 @@ async function runCommand(filePath, options) {
334
360
  try {
335
361
  // Load the module
336
362
  const ext = path.extname(fullPath);
363
+ const projectDir = path.dirname(fullPath);
337
364
  if (ext === '.ts') {
338
- require('ts-node/register');
365
+ // Change to project directory so ts-node picks up the local tsconfig.json
366
+ const originalCwd = process.cwd();
367
+ process.chdir(projectDir);
368
+ // Use ts-node from the project's own node_modules if available
369
+ const localTsNode = path.join(projectDir, 'node_modules', 'ts-node', 'register');
370
+ try {
371
+ require(localTsNode);
372
+ } catch (e) {
373
+ require('ts-node/register');
374
+ }
375
+ process.chdir(originalCwd);
339
376
  }
340
377
 
341
378
  const module = require(fullPath);
@@ -347,23 +384,29 @@ async function runCommand(filePath, options) {
347
384
  }
348
385
 
349
386
  // Setup observer for verbose mode
350
- const observer = verbose ? {
351
- onNodeStart: (nodeId, type, input) => {
352
- console.log(colorize('dim', ` ▶️ Node ${nodeId} (${type}) starting...`));
353
- },
354
- onNodeEnd: (nodeId, output, duration) => {
355
- console.log(colorize('dim', ` ✅ Node ${nodeId} completed in ${duration}ms`));
356
- },
357
- onAgentStart: (agentId, modelName, input) => {
358
- console.log(colorize('blue', ` 🤖 Agent ${agentId} (${modelName}) processing...`));
359
- },
360
- onAgentComplete: (agentId, modelName, output) => {
361
- console.log(colorize('green', ` ✅ Agent ${agentId} completed`));
362
- },
363
- onAgentError: (agentId, modelName, error) => {
364
- console.log(colorize('red', ` ❌ Agent ${agentId} error: ${error.message}`));
365
- },
366
- } : undefined;
387
+ if (verbose) {
388
+ society.withObserver({
389
+ onNodeStart: (nodeId, type, input) => {
390
+ console.log(colorize('dim', ` ▶️ Node ${nodeId} (${type}) starting...`));
391
+ },
392
+ onNodeEnd: (nodeId, output, duration) => {
393
+ console.log(colorize('dim', ` ✅ Node ${nodeId} completed in ${duration}ms`));
394
+ },
395
+ onAgentStart: (agentId, modelName, input) => {
396
+ console.log(colorize('blue', ` 🤖 Agent ${agentId} (${modelName}) processing...`));
397
+ },
398
+ onAgentComplete: (agentId, modelName, output) => {
399
+ console.log(colorize('green', ` ✅ Agent ${agentId} completed`));
400
+ },
401
+ onAgentError: (agentId, modelName, error) => {
402
+ console.log(colorize('red', ` ❌ Agent ${agentId} error: ${error.message}`));
403
+ },
404
+ onPhaseStart: () => {},
405
+ onPhaseComplete: () => {},
406
+ onSocietyStart: () => {},
407
+ onSocietyComplete: () => {},
408
+ });
409
+ }
367
410
 
368
411
  // Execute with timeout
369
412
  const timeoutPromise = new Promise((_, reject) => {
@@ -371,7 +414,7 @@ async function runCommand(filePath, options) {
371
414
  });
372
415
 
373
416
  const result = await Promise.race([
374
- society.execute({ input, observer }),
417
+ society.execute(input),
375
418
  timeoutPromise,
376
419
  ]);
377
420
 
@@ -408,6 +451,8 @@ async function runCommand(filePath, options) {
408
451
  console.log(colorize('green', `\n💾 State saved to: ${saveState}`));
409
452
  }
410
453
 
454
+ process.exit(0);
455
+
411
456
  } catch (error) {
412
457
  const duration = Date.now() - startTime;
413
458
  console.error(colorize('red', `\n❌ Execution failed after ${duration}ms: ${error.message}`));
@@ -420,7 +465,7 @@ async function runCommand(filePath, options) {
420
465
 
421
466
  // Init command
422
467
  async function initCommand(template, options) {
423
- const templateName = template || options.template || options.t || 'basic';
468
+ const templateName = options.template || options.t || template || 'basic';
424
469
  const outputDir = options.output || options.o || '.';
425
470
  const projectName = options.name || 'my-society';
426
471
 
@@ -430,10 +475,9 @@ async function initCommand(template, options) {
430
475
 
431
476
  const templates = {
432
477
  basic: {
433
- 'society.ts': `import { Society } from 'societyai';
434
- import { MockModel } from 'societyai/adapters';
478
+ 'society.ts': `import { Society, StandardModelBase } from 'societyai';
435
479
 
436
- const model = new MockModel();
480
+ const model = new StandardModelBase({}, async () => 'Hello from mock model!').withName('mock');
437
481
 
438
482
  export const society = Society.create()
439
483
  .withName('${projectName}')
@@ -449,9 +493,9 @@ export const society = Society.create()
449
493
  .sequential()
450
494
  );
451
495
 
452
- // Execute
496
+ // Execute (only when run directly, not when imported by CLI tools)
453
497
  if (require.main === module) {
454
- society.execute({ input: 'Hello World' })
498
+ society.execute('Hello World')
455
499
  .then(result => console.log(result.output))
456
500
  .catch(console.error);
457
501
  }
@@ -495,13 +539,26 @@ npm start
495
539
 
496
540
  - \`society.ts\` - Main society configuration
497
541
  `,
542
+ 'tsconfig.json': JSON.stringify({
543
+ compilerOptions: {
544
+ target: 'ES2020',
545
+ module: 'commonjs',
546
+ moduleResolution: 'node',
547
+ esModuleInterop: true,
548
+ strict: false,
549
+ skipLibCheck: true,
550
+ outDir: 'dist',
551
+ },
552
+ 'ts-node': {
553
+ transpileOnly: true,
554
+ },
555
+ }, null, 2),
498
556
  },
499
557
 
500
558
  advanced: {
501
- 'society.ts': `import { Society } from 'societyai';
502
- import { MockModel } from 'societyai/adapters';
559
+ 'society.ts': `import { Society, StandardModelBase, MiddlewareChain, Middlewares } from 'societyai';
503
560
 
504
- const model = new MockModel();
561
+ const model = new StandardModelBase({}, async () => 'Hello from mock model!').withName('mock');
505
562
 
506
563
  export const society = Society.create()
507
564
  .withName('${projectName}')
@@ -509,7 +566,6 @@ export const society = Society.create()
509
566
  .withId('analyzer')
510
567
  .withRole(role => role.withSystemPrompt('Analyze the input and extract key insights'))
511
568
  .withModel(model)
512
- .withExecutionMode('isolated')
513
569
  )
514
570
  .addAgent(agent => agent
515
571
  .withId('validator')
@@ -522,23 +578,34 @@ export const society = Society.create()
522
578
  .withModel(model)
523
579
  )
524
580
  .addTask(task => task
525
- .withId('process')
526
- .withAgents(['analyzer', 'validator', 'formatter'])
527
- .withInstructions('Process input through analysis, validation, and formatting')
528
- .withDependencies({
529
- validator: ['analyzer'],
530
- formatter: ['validator'],
531
- })
581
+ .withId('analyze')
582
+ .withAgents(['analyzer'])
583
+ .withInstructions('Analyze the input')
532
584
  .sequential()
533
585
  )
534
- .withMiddleware(chain => chain
535
- .use(Middlewares.logging())
536
- .use(Middlewares.timing())
586
+ .addTask(task => task
587
+ .withId('validate')
588
+ .withAgents(['validator'])
589
+ .withInstructions('Validate the analysis')
590
+ .dependsOn('analyze')
591
+ .sequential()
592
+ )
593
+ .addTask(task => task
594
+ .withId('format')
595
+ .withAgents(['formatter'])
596
+ .withInstructions('Format the final output')
597
+ .dependsOn('validate')
598
+ .sequential()
599
+ )
600
+ .addMiddleware(
601
+ MiddlewareChain.create()
602
+ .use(Middlewares.logging())
603
+ .use(Middlewares.timing())
537
604
  );
538
605
 
539
- // Execute
606
+ // Execute (only when run directly, not when imported by CLI tools)
540
607
  if (require.main === module) {
541
- society.execute({ input: 'Hello World' })
608
+ society.execute('Hello World')
542
609
  .then(result => console.log(result.output))
543
610
  .catch(console.error);
544
611
  }
@@ -586,6 +653,209 @@ npm start
586
653
  - Agents: analyzer, validator, formatter
587
654
  - Pipeline: analyzer → validator → formatter
588
655
  `,
656
+ 'tsconfig.json': JSON.stringify({
657
+ compilerOptions: {
658
+ target: 'ES2020',
659
+ module: 'commonjs',
660
+ moduleResolution: 'node',
661
+ esModuleInterop: true,
662
+ strict: false,
663
+ skipLibCheck: true,
664
+ outDir: 'dist',
665
+ },
666
+ 'ts-node': {
667
+ transpileOnly: true,
668
+ },
669
+ }, null, 2),
670
+ },
671
+
672
+ mcp: {
673
+ 'society.ts': `import { Society, StandardModelBase, MCPServers } from 'societyai';
674
+
675
+ const model = new StandardModelBase({}, async (input) => \`Processed: \${input}\`).withName('mock');
676
+
677
+ async function main() {
678
+ // Connect to an MCP filesystem server (adjust the path as needed)
679
+ const fsTools = await MCPServers.filesystem(process.cwd());
680
+
681
+ const society = Society.create()
682
+ .withName('${projectName}')
683
+ .addAgent(agent => agent
684
+ .withId('assistant')
685
+ .withRole(role => role
686
+ .withSystemPrompt('You are a helpful assistant with access to filesystem tools.')
687
+ .withTools(fsTools.getTools())
688
+ )
689
+ .withModel(model)
690
+ )
691
+ .addTask(task => task
692
+ .withId('main')
693
+ .withAgents(['assistant'])
694
+ .withInstructions('Process the input using available tools')
695
+ .sequential()
696
+ );
697
+
698
+ try {
699
+ const result = await society.execute('Hello World');
700
+ console.log(result.output);
701
+ } finally {
702
+ await fsTools.disconnect();
703
+ }
704
+ }
705
+
706
+ main().catch(console.error);
707
+ `,
708
+ 'package.json': JSON.stringify({
709
+ name: projectName,
710
+ version: '1.0.0',
711
+ description: `A SocietyAI project with MCP tool integration`,
712
+ main: 'society.ts',
713
+ scripts: {
714
+ start: 'ts-node society.ts',
715
+ validate: 'societyai validate society.ts',
716
+ visualize: 'societyai visualize society.ts --format html --output graph.html',
717
+ },
718
+ dependencies: {
719
+ 'societyai': '^0.1.0',
720
+ },
721
+ devDependencies: {
722
+ 'ts-node': '^10.9.0',
723
+ 'typescript': '^5.7.0',
724
+ },
725
+ }, null, 2),
726
+ 'README.md': `# ${projectName}
727
+
728
+ A SocietyAI project with Model Context Protocol (MCP) tool integration.
729
+
730
+ ## Getting Started
731
+
732
+ \`\`\`bash
733
+ npm install
734
+ npm start
735
+ \`\`\`
736
+
737
+ ## Structure
738
+
739
+ - \`society.ts\` - Main society configuration with MCP tool support
740
+ - Uses MCPServers.filesystem to give agents access to filesystem tools
741
+ `,
742
+ 'tsconfig.json': JSON.stringify({
743
+ compilerOptions: {
744
+ target: 'ES2020',
745
+ module: 'commonjs',
746
+ moduleResolution: 'node',
747
+ esModuleInterop: true,
748
+ strict: false,
749
+ skipLibCheck: true,
750
+ outDir: 'dist',
751
+ },
752
+ 'ts-node': {
753
+ transpileOnly: true,
754
+ },
755
+ }, null, 2),
756
+ },
757
+
758
+ 'multi-tenant': {
759
+ 'society.ts': `import { Society, StandardModelBase } from 'societyai';
760
+
761
+ const model = new StandardModelBase({}, async (input) => \`Tenant response: \${input}\`).withName('mock');
762
+
763
+ // Factory function to create a society for a specific tenant
764
+ function createTenantSociety(tenantId: string, tenantConfig: { name: string; instructions: string }) {
765
+ return Society.create(\`society-\${tenantId}\`)
766
+ .withName(\`\${tenantConfig.name} Society\`)
767
+ .withGlobalContext({ tenantId, tenantName: tenantConfig.name })
768
+ .addAgent(agent => agent
769
+ .withId(\`agent-\${tenantId}\`)
770
+ .withRole(role => role.withSystemPrompt(tenantConfig.instructions))
771
+ .withModel(model)
772
+ )
773
+ .addTask(task => task
774
+ .withId('main')
775
+ .withAgents([\`agent-\${tenantId}\`])
776
+ .withInstructions('Process the input for this tenant')
777
+ .sequential()
778
+ );
779
+ }
780
+
781
+ // Define tenants
782
+ const tenants = [
783
+ { id: 'tenant-a', name: 'Tenant A', instructions: 'You handle support tickets for Tenant A. Be formal.' },
784
+ { id: 'tenant-b', name: 'Tenant B', instructions: 'You handle support tickets for Tenant B. Be friendly.' },
785
+ ];
786
+
787
+ // Export the multi-tenant runner
788
+ export async function runForTenant(tenantId: string, input: string) {
789
+ const tenant = tenants.find(t => t.id === tenantId);
790
+ if (!tenant) throw new Error(\`Unknown tenant: \${tenantId}\`);
791
+
792
+ const society = createTenantSociety(tenant.id, { name: tenant.name, instructions: tenant.instructions });
793
+ return society.execute(input);
794
+ }
795
+
796
+ // Run example with all tenants
797
+ async function main() {
798
+ const input = 'Hello, I need help with my account';
799
+ for (const tenant of tenants) {
800
+ const society = createTenantSociety(tenant.id, { name: tenant.name, instructions: tenant.instructions });
801
+ const result = await society.execute(input);
802
+ console.log(\`[\${tenant.name}]: \${result.output}\`);
803
+ }
804
+ }
805
+
806
+ if (require.main === module) {
807
+ main().catch(console.error);
808
+ }
809
+ `,
810
+ 'package.json': JSON.stringify({
811
+ name: projectName,
812
+ version: '1.0.0',
813
+ description: `A multi-tenant SocietyAI project`,
814
+ main: 'society.ts',
815
+ scripts: {
816
+ start: 'ts-node society.ts',
817
+ validate: 'societyai validate society.ts',
818
+ visualize: 'societyai visualize society.ts --format html --output graph.html',
819
+ },
820
+ dependencies: {
821
+ 'societyai': '^0.1.0',
822
+ },
823
+ devDependencies: {
824
+ 'ts-node': '^10.9.0',
825
+ 'typescript': '^5.7.0',
826
+ },
827
+ }, null, 2),
828
+ 'README.md': `# ${projectName}
829
+
830
+ A multi-tenant SocietyAI project where each tenant gets an isolated society instance.
831
+
832
+ ## Getting Started
833
+
834
+ \`\`\`bash
835
+ npm install
836
+ npm start
837
+ \`\`\`
838
+
839
+ ## Structure
840
+
841
+ - \`society.ts\` - Multi-tenant society factory and runner
842
+ - Each tenant gets its own isolated society with custom instructions
843
+ - Use \`runForTenant(tenantId, input)\` to execute for a specific tenant
844
+ `,
845
+ 'tsconfig.json': JSON.stringify({
846
+ compilerOptions: {
847
+ target: 'ES2020',
848
+ module: 'commonjs',
849
+ moduleResolution: 'node',
850
+ esModuleInterop: true,
851
+ strict: false,
852
+ skipLibCheck: true,
853
+ outDir: 'dist',
854
+ },
855
+ 'ts-node': {
856
+ transpileOnly: true,
857
+ },
858
+ }, null, 2),
589
859
  },
590
860
  };
591
861
 
@@ -593,7 +863,7 @@ npm start
593
863
 
594
864
  if (!selectedTemplate) {
595
865
  console.error(colorize('red', `❌ Unknown template: ${templateName}`));
596
- console.error(colorize('dim', 'Available templates: basic, advanced'));
866
+ console.error(colorize('dim', 'Available templates: basic, advanced, mcp, multi-tenant'));
597
867
  process.exit(1);
598
868
  }
599
869
 
@@ -618,6 +888,68 @@ npm start
618
888
  }
619
889
 
620
890
  // Diff command
891
+ async function inspectCommand(filePath) {
892
+ if (!filePath) {
893
+ console.error(colorize('red', '❌ Error: No file specified'));
894
+ console.error(colorize('dim', 'Usage: societyai inspect <path-to-state.json>'));
895
+ process.exit(1);
896
+ }
897
+
898
+ const fullPath = path.resolve(filePath);
899
+ if (!fs.existsSync(fullPath)) {
900
+ console.error(colorize('red', `❌ File not found: ${fullPath}`));
901
+ process.exit(1);
902
+ }
903
+
904
+ try {
905
+ const content = fs.readFileSync(fullPath, 'utf-8');
906
+ const state = JSON.parse(content);
907
+
908
+ console.log('\n🔍 SocietyAI Execution State Inspector\n');
909
+ console.log(`🆔 Execution ID: ${colorize('cyan', state.executionId || 'N/A')}`);
910
+ console.log(`📅 Timestamp: ${state.timestamp ? new Date(state.timestamp).toLocaleString() : 'N/A'}`);
911
+ console.log(`🚦 Status: ${formatInspectStatus(state.status)}`);
912
+
913
+ if (state.executionPath && state.executionPath.length > 0) {
914
+ console.log(`🛣️ Path Length: ${state.executionPath.length} steps`);
915
+ console.log(` Start: ${state.executionPath[0] || 'N/A'}`);
916
+ console.log(` Current: ${state.executionPath[state.executionPath.length - 1] || 'N/A'}`);
917
+ }
918
+
919
+ console.log('\n📋 Queue (Next Nodes):');
920
+ if (!state.queue || state.queue.length === 0) {
921
+ console.log(' (Empty)');
922
+ } else {
923
+ state.queue.forEach((nodeId, idx) => {
924
+ console.log(` ${idx + 1}. ${nodeId}`);
925
+ });
926
+ }
927
+
928
+ if (state.status === 'paused' && state.waitingForNodeId) {
929
+ console.log(`\n⏸️ Waiting For: ${colorize('yellow', state.waitingForNodeId)} (Human Input)`);
930
+ }
931
+
932
+ if (state.deadLetterQueue && state.deadLetterQueue.length > 0) {
933
+ console.log(`\n💀 Dead Letter Queue: ${colorize('red', state.deadLetterQueue.join(', '))}`);
934
+ }
935
+
936
+ console.log(`\n🧠 Memory/Results Captured: ${state.results ? state.results.length : 0} nodes`);
937
+ } catch (error) {
938
+ console.error(colorize('red', `❌ Error reading state file: ${error.message}`));
939
+ process.exit(1);
940
+ }
941
+ }
942
+
943
+ function formatInspectStatus(status) {
944
+ switch (status) {
945
+ case 'active': return colorize('green', 'Active');
946
+ case 'completed': return colorize('cyan', 'Completed');
947
+ case 'failed': return colorize('red', 'Failed');
948
+ case 'paused': return colorize('yellow', 'Paused');
949
+ default: return status || 'Unknown';
950
+ }
951
+ }
952
+
621
953
  async function diffCommand(file1, file2) {
622
954
  console.log(colorize('cyan', '🔍 Comparing Society configurations...'));
623
955
 
@@ -645,7 +977,16 @@ async function diffCommand(file1, file2) {
645
977
  const ext2 = path.extname(path2);
646
978
 
647
979
  if (ext1 === '.ts' || ext2 === '.ts') {
648
- require('ts-node/register');
980
+ const projectDir = path.dirname(path1);
981
+ const originalCwd = process.cwd();
982
+ process.chdir(projectDir);
983
+ const localTsNode = path.join(projectDir, 'node_modules', 'ts-node', 'register');
984
+ try {
985
+ require(localTsNode);
986
+ } catch (e) {
987
+ require('ts-node/register');
988
+ }
989
+ process.chdir(originalCwd);
649
990
  }
650
991
 
651
992
  const module1 = require(path1);
@@ -654,16 +995,19 @@ async function diffCommand(file1, file2) {
654
995
  const society1 = module1.default || module1.society;
655
996
  const society2 = module2.default || module2.society;
656
997
 
657
- if (!society1 || !society2) {
658
- console.error(colorize('red', '❌ Error: Could not find Society in one or both files'));
998
+ if (!society1 || typeof society1.build !== 'function' || !society2 || typeof society2.build !== 'function') {
999
+ console.error(colorize('red', '❌ Error: Could not find Society builder in one or both files'));
659
1000
  process.exit(1);
660
1001
  }
661
1002
 
1003
+ const config1 = society1.build();
1004
+ const config2 = society2.build();
1005
+
662
1006
  console.log(colorize('cyan', '\n📊 Comparison Results:'));
663
1007
 
664
1008
  // Compare agents
665
- const agents1 = society1.agents || [];
666
- const agents2 = society2.agents || [];
1009
+ const agents1 = config1.agents || [];
1010
+ const agents2 = config2.agents || [];
667
1011
 
668
1012
  console.log(colorize('blue', '\nAgents:'));
669
1013
  console.log(colorize('dim', ` File 1: ${agents1.length} agents`));
@@ -688,8 +1032,8 @@ async function diffCommand(file1, file2) {
688
1032
  }
689
1033
 
690
1034
  // Compare tasks
691
- const tasks1 = society1.tasks || [];
692
- const tasks2 = society2.tasks || [];
1035
+ const tasks1 = config1.tasks || [];
1036
+ const tasks2 = config2.tasks || [];
693
1037
 
694
1038
  console.log(colorize('blue', '\nTasks:'));
695
1039
  console.log(colorize('dim', ` File 1: ${tasks1.length} tasks`));
@@ -783,8 +1127,7 @@ async function main() {
783
1127
  break;
784
1128
 
785
1129
  case 'inspect':
786
- // Delegate to inspect.js
787
- require('./inspect');
1130
+ await inspectCommand(args[0]);
788
1131
  break;
789
1132
 
790
1133
  case 'diff':
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "societyai",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "A powerful TypeScript library for creating collaborative multi-agent AI systems with DAG-based orchestration. Build sophisticated workflows where AI agents work together through dependency graphs, conditional routing, and pluggable execution strategies. Features thread-safe parallel execution, memory management, and circuit breaker patterns for production-grade reliability.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -108,7 +108,8 @@
108
108
  "prettier": "^3.1.1",
109
109
  "ts-jest": "^29.1.1",
110
110
  "ts-node": "^10.9.2",
111
- "typescript": "^5.7.3"
111
+ "typescript": "^5.7.3",
112
+ "vitest": "^4.1.0"
112
113
  },
113
114
  "peerDependencies": {
114
115
  "@modelcontextprotocol/sdk": "^0.5.0",