@desplega.ai/agent-swarm 1.64.0 → 1.65.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.
@@ -1,21 +1,9 @@
1
1
  import { afterAll, beforeAll, describe, expect, test } from "bun:test";
2
2
  import { unlink } from "node:fs/promises";
3
3
  import { chunkContent } from "../be/chunking";
4
- import {
5
- closeDb,
6
- createAgent,
7
- createMemory,
8
- deleteMemoriesBySourcePath,
9
- deleteMemory,
10
- getDb,
11
- getMemoryById,
12
- getMemoryStats,
13
- initDb,
14
- listMemoriesByAgent,
15
- searchMemoriesByVector,
16
- updateMemoryEmbedding,
17
- } from "../be/db";
4
+ import { closeDb, createAgent, getDb, initDb } from "../be/db";
18
5
  import { cosineSimilarity, deserializeEmbedding, serializeEmbedding } from "../be/embedding";
6
+ import { SqliteMemoryStore } from "../be/memory/providers/sqlite-store";
19
7
 
20
8
  const TEST_DB_PATH = "./test-memory.sqlite";
21
9
 
@@ -23,6 +11,8 @@ describe("Memory System", () => {
23
11
  const agentA = "aaaa0000-0000-4000-8000-000000000001";
24
12
  const agentB = "bbbb0000-0000-4000-8000-000000000002";
25
13
 
14
+ let store: SqliteMemoryStore;
15
+
26
16
  beforeAll(async () => {
27
17
  for (const suffix of ["", "-wal", "-shm"]) {
28
18
  try {
@@ -33,6 +23,7 @@ describe("Memory System", () => {
33
23
  }
34
24
 
35
25
  initDb(TEST_DB_PATH);
26
+ store = new SqliteMemoryStore();
36
27
 
37
28
  createAgent({ id: agentA, name: "Agent A", isLead: false, status: "idle" });
38
29
  createAgent({ id: agentB, name: "Agent B", isLead: true, status: "idle" });
@@ -212,12 +203,12 @@ describe("Memory System", () => {
212
203
  });
213
204
 
214
205
  // ==========================================================================
215
- // DB CRUD tests
206
+ // DB CRUD tests (using SqliteMemoryStore)
216
207
  // ==========================================================================
217
208
 
218
- describe("createMemory", () => {
209
+ describe("store.store (createMemory)", () => {
219
210
  test("creates a memory with all fields", () => {
220
- const memory = createMemory({
211
+ const memory = store.store({
221
212
  agentId: agentA,
222
213
  scope: "agent",
223
214
  name: "Test Memory",
@@ -246,7 +237,8 @@ describe("Memory System", () => {
246
237
  });
247
238
 
248
239
  test("creates with minimal fields", () => {
249
- const memory = createMemory({
240
+ const memory = store.store({
241
+ agentId: null,
250
242
  scope: "swarm",
251
243
  name: "Minimal",
252
244
  content: "Just content",
@@ -263,9 +255,9 @@ describe("Memory System", () => {
263
255
  });
264
256
  });
265
257
 
266
- describe("getMemoryById", () => {
258
+ describe("store.get (getMemoryById)", () => {
267
259
  test("returns existing memory", () => {
268
- const created = createMemory({
260
+ const created = store.store({
269
261
  agentId: agentA,
270
262
  scope: "agent",
271
263
  name: "Findable",
@@ -273,19 +265,19 @@ describe("Memory System", () => {
273
265
  source: "manual",
274
266
  });
275
267
 
276
- const found = getMemoryById(created.id);
268
+ const found = store.get(created.id);
277
269
  expect(found).not.toBeNull();
278
270
  expect(found!.id).toBe(created.id);
279
271
  expect(found!.name).toBe("Findable");
280
272
  });
281
273
 
282
274
  test("returns null for non-existent ID", () => {
283
- const found = getMemoryById("00000000-0000-0000-0000-000000000000");
275
+ const found = store.get("00000000-0000-0000-0000-000000000000");
284
276
  expect(found).toBeNull();
285
277
  });
286
278
 
287
279
  test("updates accessedAt on retrieval", () => {
288
- const created = createMemory({
280
+ const created = store.store({
289
281
  agentId: agentA,
290
282
  scope: "agent",
291
283
  name: "Access Test",
@@ -299,16 +291,16 @@ describe("Memory System", () => {
299
291
  /* spin */
300
292
  }
301
293
 
302
- const found = getMemoryById(created.id);
294
+ const found = store.get(created.id);
303
295
  expect(found).not.toBeNull();
304
296
  // accessedAt should be updated (may or may not differ depending on timing)
305
297
  expect(found!.accessedAt).toBeDefined();
306
298
  });
307
299
  });
308
300
 
309
- describe("updateMemoryEmbedding", () => {
301
+ describe("store.updateEmbedding", () => {
310
302
  test("stores and retrieves embedding BLOB", () => {
311
- const memory = createMemory({
303
+ const memory = store.store({
312
304
  agentId: agentA,
313
305
  scope: "agent",
314
306
  name: "Embedding Test",
@@ -317,10 +309,9 @@ describe("Memory System", () => {
317
309
  });
318
310
 
319
311
  const embedding = new Float32Array([0.1, 0.2, 0.3, -0.5]);
320
- updateMemoryEmbedding(memory.id, serializeEmbedding(embedding));
312
+ store.updateEmbedding(memory.id, embedding, "test-model");
321
313
 
322
314
  // Read back the raw row to check embedding
323
- const { getDb } = require("../be/db");
324
315
  const row = getDb()
325
316
  .prepare("SELECT embedding FROM agent_memory WHERE id = ?")
326
317
  .get(memory.id) as { embedding: Buffer | null };
@@ -333,7 +324,7 @@ describe("Memory System", () => {
333
324
  });
334
325
  });
335
326
 
336
- describe("searchMemoriesByVector", () => {
327
+ describe("store.search (searchMemoriesByVector)", () => {
337
328
  const searchAgentId = "cccc0000-0000-4000-8000-000000000003";
338
329
  const searchAgentId2 = "dddd0000-0000-4000-8000-000000000004";
339
330
 
@@ -353,39 +344,39 @@ describe("Memory System", () => {
353
344
 
354
345
  // Create memories with known embeddings
355
346
  // Memory 1: agent scope for searchAgentId, embedding [1,0,0]
356
- const m1 = createMemory({
347
+ const m1 = store.store({
357
348
  agentId: searchAgentId,
358
349
  scope: "agent",
359
350
  name: "Agent Memory 1",
360
351
  content: "Agent-scoped content",
361
352
  source: "manual",
362
353
  });
363
- updateMemoryEmbedding(m1.id, serializeEmbedding(new Float32Array([1, 0, 0])));
354
+ store.updateEmbedding(m1.id, new Float32Array([1, 0, 0]), "test-model");
364
355
 
365
356
  // Memory 2: swarm scope, embedding [0,1,0]
366
- const m2 = createMemory({
357
+ const m2 = store.store({
367
358
  agentId: searchAgentId,
368
359
  scope: "swarm",
369
360
  name: "Swarm Memory 1",
370
361
  content: "Swarm-scoped content",
371
362
  source: "file_index",
372
363
  });
373
- updateMemoryEmbedding(m2.id, serializeEmbedding(new Float32Array([0, 1, 0])));
364
+ store.updateEmbedding(m2.id, new Float32Array([0, 1, 0]), "test-model");
374
365
 
375
366
  // Memory 3: agent scope for OTHER agent, embedding [0,0,1]
376
- const m3 = createMemory({
367
+ const m3 = store.store({
377
368
  agentId: searchAgentId2,
378
369
  scope: "agent",
379
370
  name: "Other Agent Memory",
380
371
  content: "Other agent's private memory",
381
372
  source: "manual",
382
373
  });
383
- updateMemoryEmbedding(m3.id, serializeEmbedding(new Float32Array([0, 0, 1])));
374
+ store.updateEmbedding(m3.id, new Float32Array([0, 0, 1]), "test-model");
384
375
  });
385
376
 
386
377
  test("worker sees own agent-scoped + swarm memories", () => {
387
378
  const query = new Float32Array([1, 0, 0]); // closest to Memory 1
388
- const results = searchMemoriesByVector(query, searchAgentId, { isLead: false });
379
+ const results = store.search(query, searchAgentId, { isLead: false });
389
380
  const names = results.map((r) => r.name);
390
381
 
391
382
  expect(names).toContain("Agent Memory 1");
@@ -395,7 +386,7 @@ describe("Memory System", () => {
395
386
 
396
387
  test("worker does not see other agent's agent-scoped memories", () => {
397
388
  const query = new Float32Array([0, 0, 1]); // closest to Memory 3
398
- const results = searchMemoriesByVector(query, searchAgentId, { isLead: false });
389
+ const results = store.search(query, searchAgentId, { isLead: false });
399
390
  const names = results.map((r) => r.name);
400
391
 
401
392
  expect(names).not.toContain("Other Agent Memory");
@@ -403,7 +394,7 @@ describe("Memory System", () => {
403
394
 
404
395
  test("lead sees ALL memories across agents", () => {
405
396
  const query = new Float32Array([0, 0, 1]); // closest to Memory 3
406
- const results = searchMemoriesByVector(query, searchAgentId, { isLead: true });
397
+ const results = store.search(query, searchAgentId, { isLead: true });
407
398
  const names = results.map((r) => r.name);
408
399
 
409
400
  expect(names).toContain("Other Agent Memory");
@@ -413,7 +404,7 @@ describe("Memory System", () => {
413
404
 
414
405
  test("results sorted by similarity (highest first)", () => {
415
406
  const query = new Float32Array([1, 0, 0]); // identical to Memory 1's embedding
416
- const results = searchMemoriesByVector(query, searchAgentId, { isLead: true });
407
+ const results = store.search(query, searchAgentId, { isLead: true });
417
408
 
418
409
  expect(results.length).toBeGreaterThan(0);
419
410
  expect(results[0].name).toBe("Agent Memory 1");
@@ -427,11 +418,11 @@ describe("Memory System", () => {
427
418
 
428
419
  test("scope filter works", () => {
429
420
  const query = new Float32Array([1, 1, 1]);
430
- const agentOnly = searchMemoriesByVector(query, searchAgentId, {
421
+ const agentOnly = store.search(query, searchAgentId, {
431
422
  scope: "agent",
432
423
  isLead: false,
433
424
  });
434
- const swarmOnly = searchMemoriesByVector(query, searchAgentId, {
425
+ const swarmOnly = store.search(query, searchAgentId, {
435
426
  scope: "swarm",
436
427
  isLead: false,
437
428
  });
@@ -446,7 +437,7 @@ describe("Memory System", () => {
446
437
 
447
438
  test("source filter works", () => {
448
439
  const query = new Float32Array([1, 1, 1]);
449
- const results = searchMemoriesByVector(query, searchAgentId, {
440
+ const results = store.search(query, searchAgentId, {
450
441
  source: "file_index",
451
442
  isLead: true,
452
443
  });
@@ -458,7 +449,7 @@ describe("Memory System", () => {
458
449
 
459
450
  test("limit works", () => {
460
451
  const query = new Float32Array([1, 1, 1]);
461
- const results = searchMemoriesByVector(query, searchAgentId, {
452
+ const results = store.search(query, searchAgentId, {
462
453
  limit: 1,
463
454
  isLead: true,
464
455
  });
@@ -466,13 +457,13 @@ describe("Memory System", () => {
466
457
  });
467
458
  });
468
459
 
469
- describe("listMemoriesByAgent", () => {
460
+ describe("store.list (listMemoriesByAgent)", () => {
470
461
  test("lists agent memories with pagination", () => {
471
462
  const listAgent = "eeee0000-0000-4000-8000-000000000005";
472
463
  createAgent({ id: listAgent, name: "List Agent", isLead: false, status: "idle" });
473
464
 
474
465
  for (let i = 0; i < 5; i++) {
475
- createMemory({
466
+ store.store({
476
467
  agentId: listAgent,
477
468
  scope: "agent",
478
469
  name: `List Memory ${i}`,
@@ -481,17 +472,17 @@ describe("Memory System", () => {
481
472
  });
482
473
  }
483
474
 
484
- const page1 = listMemoriesByAgent(listAgent, { scope: "agent", limit: 3, offset: 0 });
475
+ const page1 = store.list(listAgent, { scope: "agent", limit: 3, offset: 0 });
485
476
  expect(page1.length).toBe(3);
486
477
 
487
- const page2 = listMemoriesByAgent(listAgent, { scope: "agent", limit: 3, offset: 3 });
478
+ const page2 = store.list(listAgent, { scope: "agent", limit: 3, offset: 3 });
488
479
  expect(page2.length).toBe(2);
489
480
  });
490
481
  });
491
482
 
492
- describe("deleteMemory", () => {
483
+ describe("store.delete (deleteMemory)", () => {
493
484
  test("deletes existing memory", () => {
494
- const memory = createMemory({
485
+ const memory = store.store({
495
486
  agentId: agentA,
496
487
  scope: "agent",
497
488
  name: "To Delete",
@@ -499,26 +490,26 @@ describe("Memory System", () => {
499
490
  source: "manual",
500
491
  });
501
492
 
502
- const deleted = deleteMemory(memory.id);
493
+ const deleted = store.delete(memory.id);
503
494
  expect(deleted).toBe(true);
504
495
 
505
- const found = getMemoryById(memory.id);
496
+ const found = store.get(memory.id);
506
497
  expect(found).toBeNull();
507
498
  });
508
499
 
509
500
  test("returns false for non-existent memory", () => {
510
- const deleted = deleteMemory("00000000-0000-0000-0000-000000000000");
501
+ const deleted = store.delete("00000000-0000-0000-0000-000000000000");
511
502
  expect(deleted).toBe(false);
512
503
  });
513
504
  });
514
505
 
515
- describe("deleteMemoriesBySourcePath", () => {
506
+ describe("store.deleteBySourcePath (deleteMemoriesBySourcePath)", () => {
516
507
  test("deletes all chunks for a source path", () => {
517
508
  const path = "/workspace/personal/memory/to-reindex.md";
518
509
 
519
510
  // Create multiple chunks
520
511
  for (let i = 0; i < 3; i++) {
521
- createMemory({
512
+ store.store({
522
513
  agentId: agentA,
523
514
  scope: "agent",
524
515
  name: "Reindex Test",
@@ -530,35 +521,35 @@ describe("Memory System", () => {
530
521
  });
531
522
  }
532
523
 
533
- const deleted = deleteMemoriesBySourcePath(path, agentA);
524
+ const deleted = store.deleteBySourcePath(path, agentA);
534
525
  expect(deleted).toBe(3);
535
526
 
536
527
  // Verify they're gone
537
- const remaining = listMemoriesByAgent(agentA).filter((m) => m.sourcePath === path);
528
+ const remaining = store.list(agentA).filter((m) => m.sourcePath === path);
538
529
  expect(remaining.length).toBe(0);
539
530
  });
540
531
  });
541
532
 
542
- describe("getMemoryStats", () => {
533
+ describe("store.getStats (getMemoryStats)", () => {
543
534
  test("returns correct stats", () => {
544
535
  const statsAgent = "ffff0000-0000-4000-8000-000000000006";
545
536
  createAgent({ id: statsAgent, name: "Stats Agent", isLead: false, status: "idle" });
546
537
 
547
- createMemory({
538
+ store.store({
548
539
  agentId: statsAgent,
549
540
  scope: "agent",
550
541
  name: "Stat 1",
551
542
  content: "Content",
552
543
  source: "manual",
553
544
  });
554
- createMemory({
545
+ store.store({
555
546
  agentId: statsAgent,
556
547
  scope: "swarm",
557
548
  name: "Stat 2",
558
549
  content: "Content",
559
550
  source: "file_index",
560
551
  });
561
- createMemory({
552
+ store.store({
562
553
  agentId: statsAgent,
563
554
  scope: "agent",
564
555
  name: "Stat 3",
@@ -566,12 +557,14 @@ describe("Memory System", () => {
566
557
  source: "manual",
567
558
  });
568
559
 
569
- const stats = getMemoryStats(statsAgent);
560
+ const stats = store.getStats(statsAgent);
570
561
  expect(stats.total).toBe(3);
571
562
  expect(stats.bySource.manual).toBe(2);
572
563
  expect(stats.bySource.file_index).toBe(1);
573
564
  expect(stats.byScope.agent).toBe(2);
574
565
  expect(stats.byScope.swarm).toBe(1);
566
+ expect(stats.withEmbeddings).toBe(0);
567
+ expect(stats.expired).toBe(0);
575
568
  });
576
569
  });
577
570
 
@@ -601,26 +594,21 @@ describe("Memory System", () => {
601
594
  },
602
595
  ];
603
596
 
604
- const memoryIds = getDb().transaction(() => {
605
- const ids: string[] = [];
606
- for (const chunk of finalChunks) {
607
- const memory = createMemory({
608
- agentId: ingestAgent,
609
- content: chunk.content,
610
- name: "ingest-test",
611
- scope: "agent",
612
- source: "file_index",
613
- sourcePath: "/workspace/personal/memory/ingest-test.md",
614
- chunkIndex: chunk.chunkIndex,
615
- totalChunks: chunk.totalChunks,
616
- });
617
- ids.push(memory.id);
618
- }
619
- return ids;
620
- })();
621
-
622
- expect(memoryIds.length).toBe(1);
623
- const memory = getMemoryById(memoryIds[0]!);
597
+ const memories = store.storeBatch(
598
+ finalChunks.map((chunk) => ({
599
+ agentId: ingestAgent,
600
+ content: chunk.content,
601
+ name: "ingest-test",
602
+ scope: "agent" as const,
603
+ source: "file_index" as const,
604
+ sourcePath: "/workspace/personal/memory/ingest-test.md",
605
+ chunkIndex: chunk.chunkIndex,
606
+ totalChunks: chunk.totalChunks,
607
+ })),
608
+ );
609
+
610
+ expect(memories.length).toBe(1);
611
+ const memory = store.get(memories[0]!.id);
624
612
  expect(memory).not.toBeNull();
625
613
  expect(memory!.source).toBe("file_index");
626
614
  expect(memory!.sourcePath).toBe("/workspace/personal/memory/ingest-test.md");
@@ -630,7 +618,7 @@ describe("Memory System", () => {
630
618
  const path = "/workspace/personal/memory/dedup-test.md";
631
619
 
632
620
  // First indexing
633
- const m1 = createMemory({
621
+ const m1 = store.store({
634
622
  agentId: ingestAgent,
635
623
  content: "Original content",
636
624
  name: "dedup-test",
@@ -639,26 +627,24 @@ describe("Memory System", () => {
639
627
  sourcePath: path,
640
628
  });
641
629
 
642
- // Re-index: delete old + create new in transaction
643
- getDb().transaction(() => {
644
- deleteMemoriesBySourcePath(path, ingestAgent);
645
- createMemory({
646
- agentId: ingestAgent,
647
- content: "Updated content",
648
- name: "dedup-test",
649
- scope: "agent",
650
- source: "file_index",
651
- sourcePath: path,
652
- });
653
- })();
630
+ // Re-index: delete old + create new
631
+ store.deleteBySourcePath(path, ingestAgent);
632
+ store.store({
633
+ agentId: ingestAgent,
634
+ content: "Updated content",
635
+ name: "dedup-test",
636
+ scope: "agent",
637
+ source: "file_index",
638
+ sourcePath: path,
639
+ });
654
640
 
655
641
  // Old memory should be gone
656
- expect(getMemoryById(m1.id)).toBeNull();
642
+ expect(store.get(m1.id)).toBeNull();
657
643
 
658
644
  // New memory should exist
659
- const memories = listMemoriesByAgent(ingestAgent, { scope: "agent" }).filter(
660
- (m) => m.sourcePath === path,
661
- );
645
+ const memories = store
646
+ .list(ingestAgent, { scope: "agent" })
647
+ .filter((m) => m.sourcePath === path);
662
648
  expect(memories.length).toBe(1);
663
649
  expect(memories[0]!.content).toBe("Updated content");
664
650
  });
@@ -670,25 +656,23 @@ describe("Memory System", () => {
670
656
  const chunks = chunkContent(longContent);
671
657
  expect(chunks.length).toBeGreaterThan(1);
672
658
 
673
- getDb().transaction(() => {
674
- deleteMemoriesBySourcePath(path, ingestAgent);
675
- for (const chunk of chunks) {
676
- createMemory({
677
- agentId: ingestAgent,
678
- content: chunk.content,
679
- name: "chunked-test",
680
- scope: "agent",
681
- source: "file_index",
682
- sourcePath: path,
683
- chunkIndex: chunk.chunkIndex,
684
- totalChunks: chunk.totalChunks,
685
- });
686
- }
687
- })();
688
-
689
- const memories = listMemoriesByAgent(ingestAgent, { scope: "agent" }).filter(
690
- (m) => m.sourcePath === path,
659
+ store.deleteBySourcePath(path, ingestAgent);
660
+ store.storeBatch(
661
+ chunks.map((chunk) => ({
662
+ agentId: ingestAgent,
663
+ content: chunk.content,
664
+ name: "chunked-test",
665
+ scope: "agent" as const,
666
+ source: "file_index" as const,
667
+ sourcePath: path,
668
+ chunkIndex: chunk.chunkIndex,
669
+ totalChunks: chunk.totalChunks,
670
+ })),
691
671
  );
672
+
673
+ const memories = store
674
+ .list(ingestAgent, { scope: "agent" })
675
+ .filter((m) => m.sourcePath === path);
692
676
  expect(memories.length).toBe(chunks.length);
693
677
  // Verify chunk metadata
694
678
  for (const m of memories) {
@@ -696,8 +680,8 @@ describe("Memory System", () => {
696
680
  }
697
681
  });
698
682
 
699
- test("memory created without OPENAI_API_KEY has null embedding", () => {
700
- const memory = createMemory({
683
+ test("memory created without embedding has null embedding in DB", () => {
684
+ const memory = store.store({
701
685
  agentId: ingestAgent,
702
686
  content: "No embedding needed",
703
687
  name: "no-embed",
@@ -711,8 +695,8 @@ describe("Memory System", () => {
711
695
  expect(row.embedding).toBeNull();
712
696
  });
713
697
 
714
- test("updateMemoryEmbedding stores and retrieves correctly", () => {
715
- const memory = createMemory({
698
+ test("store.updateEmbedding stores and retrieves correctly", () => {
699
+ const memory = store.store({
716
700
  agentId: ingestAgent,
717
701
  content: "Embed me",
718
702
  name: "embed-update",
@@ -721,7 +705,7 @@ describe("Memory System", () => {
721
705
  });
722
706
 
723
707
  const embedding = new Float32Array([0.5, -0.3, 0.8]);
724
- updateMemoryEmbedding(memory.id, serializeEmbedding(embedding));
708
+ store.updateEmbedding(memory.id, embedding, "test-model");
725
709
 
726
710
  const row = getDb()
727
711
  .prepare("SELECT embedding FROM agent_memory WHERE id = ?")
@@ -0,0 +1,47 @@
1
+ import { afterAll, describe, expect, setDefaultTimeout, test } from "bun:test";
2
+ import { execSync } from "node:child_process";
3
+ import { mkdtempSync, rmSync } from "node:fs";
4
+ import { tmpdir } from "node:os";
5
+ import { join } from "node:path";
6
+
7
+ const REPO_ROOT = join(import.meta.dir, "../..");
8
+ const tempDir = mkdtempSync(join(tmpdir(), "agent-swarm-pack-"));
9
+
10
+ setDefaultTimeout(30_000);
11
+
12
+ afterAll(() => {
13
+ rmSync(tempDir, { force: true, recursive: true });
14
+ });
15
+
16
+ describe("published package", () => {
17
+ test("version command works from an unpacked tarball", () => {
18
+ const tarballPath = join(tempDir, "agent-swarm.tgz");
19
+ const unpackDir = join(tempDir, "unpacked");
20
+
21
+ execSync(`bun pm pack --filename ${JSON.stringify(tarballPath)}`, {
22
+ cwd: REPO_ROOT,
23
+ stdio: "pipe",
24
+ });
25
+ execSync(
26
+ `mkdir -p ${JSON.stringify(unpackDir)} && tar -xzf ${JSON.stringify(tarballPath)} -C ${JSON.stringify(unpackDir)}`,
27
+ {
28
+ cwd: REPO_ROOT,
29
+ stdio: "pipe",
30
+ },
31
+ );
32
+
33
+ // Symlink repo node_modules so top-level imports resolve without a network install
34
+ execSync(
35
+ `ln -s ${JSON.stringify(join(REPO_ROOT, "node_modules"))} ${JSON.stringify(join(unpackDir, "package", "node_modules"))}`,
36
+ { stdio: "pipe" },
37
+ );
38
+
39
+ const output = execSync(`bun ./package/src/cli.tsx version`, {
40
+ cwd: unpackDir,
41
+ encoding: "utf-8",
42
+ stdio: "pipe",
43
+ });
44
+
45
+ expect(output).toContain("agent-swarm v");
46
+ });
47
+ });