opencode-swarm-plugin 0.47.0 → 0.48.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.
package/bin/swarm.ts CHANGED
@@ -3216,6 +3216,7 @@ ${cyan("Commands:")}
3216
3216
  swarm viz Alias for 'swarm serve' (deprecated, use serve)
3217
3217
  --port <n> Port to listen on (default: 4483)
3218
3218
  swarm cells List or get cells from database (replaces 'swarm tool hive_query')
3219
+ swarm memory Manage unified memory system (learnings + sessions)
3219
3220
  swarm log View swarm logs with filtering
3220
3221
  swarm stats Show swarm health metrics powered by swarm-insights (strategy success rates, patterns)
3221
3222
  swarm o11y Show observability health - hook coverage, event capture, session quality
@@ -3243,6 +3244,17 @@ ${cyan("Cell Management:")}
3243
3244
  swarm cells --ready Show next ready (unblocked) cell
3244
3245
  swarm cells --json Raw JSON output (array, no wrapper)
3245
3246
 
3247
+ ${cyan("Memory Management (Hivemind):")}
3248
+ swarm memory store <info> [--tags <tags>] Store a learning/memory
3249
+ swarm memory find <query> [--limit <n>] Search all memories (semantic + FTS)
3250
+ swarm memory get <id> Get specific memory by ID
3251
+ swarm memory remove <id> Delete outdated/incorrect memory
3252
+ swarm memory validate <id> Confirm accuracy (resets 90-day decay)
3253
+ swarm memory stats Show database statistics
3254
+ swarm memory index Index AI sessions (use hivemind_index tool)
3255
+ swarm memory sync Sync to .hive/memories.jsonl (use hivemind_sync tool)
3256
+ swarm memory <command> --json Output JSON for all commands
3257
+
3246
3258
  ${cyan("Log Viewing:")}
3247
3259
  swarm log Tail recent logs (last 50 lines)
3248
3260
  swarm log <module> Filter by module (e.g., compaction)
@@ -5503,6 +5515,319 @@ async function capture() {
5503
5515
  }
5504
5516
  }
5505
5517
 
5518
+ // ============================================================================
5519
+ // Memory Commands
5520
+ // ============================================================================
5521
+
5522
+ /**
5523
+ * Parse args for memory commands
5524
+ */
5525
+ function parseMemoryArgs(subcommand: string, args: string[]): {
5526
+ json: boolean;
5527
+ info?: string;
5528
+ query?: string;
5529
+ id?: string;
5530
+ tags?: string;
5531
+ limit?: number;
5532
+ collection?: string;
5533
+ } {
5534
+ let json = false;
5535
+ let info: string | undefined;
5536
+ let query: string | undefined;
5537
+ let id: string | undefined;
5538
+ let tags: string | undefined;
5539
+ let limit: number | undefined;
5540
+ let collection: string | undefined;
5541
+
5542
+ // First positional arg for store/find/get/remove/validate
5543
+ if (args.length > 0 && !args[0].startsWith("--")) {
5544
+ if (subcommand === "store") {
5545
+ info = args[0];
5546
+ } else if (subcommand === "find") {
5547
+ query = args[0];
5548
+ } else if (subcommand === "get" || subcommand === "remove" || subcommand === "validate") {
5549
+ id = args[0];
5550
+ }
5551
+ }
5552
+
5553
+ for (let i = 0; i < args.length; i++) {
5554
+ const arg = args[i];
5555
+ if (arg === "--json") {
5556
+ json = true;
5557
+ } else if (arg === "--tags" && i + 1 < args.length) {
5558
+ tags = args[++i];
5559
+ } else if (arg === "--limit" && i + 1 < args.length) {
5560
+ const val = parseInt(args[++i], 10);
5561
+ if (!isNaN(val)) limit = val;
5562
+ } else if (arg === "--collection" && i + 1 < args.length) {
5563
+ collection = args[++i];
5564
+ }
5565
+ }
5566
+
5567
+ return { json, info, query, id, tags, limit, collection };
5568
+ }
5569
+
5570
+ /**
5571
+ * Memory command - unified interface to memory operations
5572
+ *
5573
+ * Commands:
5574
+ * swarm memory store <info> [--tags <tags>]
5575
+ * swarm memory find <query> [--limit <n>] [--collection <name>]
5576
+ * swarm memory get <id>
5577
+ * swarm memory remove <id>
5578
+ * swarm memory validate <id>
5579
+ * swarm memory stats
5580
+ * swarm memory index
5581
+ * swarm memory sync
5582
+ */
5583
+ async function memory() {
5584
+ const subcommand = process.argv[3];
5585
+ const args = process.argv.slice(4);
5586
+ const parsed = parseMemoryArgs(subcommand, args);
5587
+
5588
+ // Get project path for libSQL database
5589
+ const projectPath = process.cwd();
5590
+
5591
+ try {
5592
+ // Get database instance using getDb from swarm-mail
5593
+ // This returns a drizzle instance (SwarmDb) that memory adapter expects
5594
+ const { getDb } = await import("swarm-mail");
5595
+
5596
+ // Calculate DB path (same logic as libsql.convenience.ts)
5597
+ const tempDirName = getLibSQLProjectTempDirName(projectPath);
5598
+ const tempDir = join(tmpdir(), tempDirName);
5599
+
5600
+ // Ensure temp directory exists
5601
+ if (!existsSync(tempDir)) {
5602
+ mkdirSync(tempDir, { recursive: true });
5603
+ }
5604
+
5605
+ const dbPath = join(tempDir, "streams.db");
5606
+
5607
+ // Convert to file:// URL (required by libSQL)
5608
+ const dbUrl = `file://${dbPath}`;
5609
+
5610
+ const db = await getDb(dbUrl);
5611
+
5612
+ // Create memory adapter with default Ollama config
5613
+ const { createMemoryAdapter } = await import("swarm-mail");
5614
+ const adapter = createMemoryAdapter(db, {
5615
+ ollamaHost: process.env.OLLAMA_HOST || "http://localhost:11434",
5616
+ ollamaModel: process.env.OLLAMA_MODEL || "mxbai-embed-large",
5617
+ });
5618
+
5619
+ switch (subcommand) {
5620
+ case "store": {
5621
+ if (!parsed.info) {
5622
+ console.error("Usage: swarm memory store <information> [--tags <tags>]");
5623
+ process.exit(1);
5624
+ }
5625
+
5626
+ const result = await adapter.store(parsed.info, {
5627
+ tags: parsed.tags,
5628
+ collection: parsed.collection || "default",
5629
+ });
5630
+
5631
+ if (parsed.json) {
5632
+ console.log(JSON.stringify({ success: true, id: result.id }));
5633
+ } else {
5634
+ p.intro("swarm memory store");
5635
+ p.log.success(`Stored memory: ${result.id}`);
5636
+ if (result.autoTags) {
5637
+ p.log.message(`Auto-tags: ${result.autoTags.tags.join(", ")}`);
5638
+ }
5639
+ p.outro("Done");
5640
+ }
5641
+ break;
5642
+ }
5643
+
5644
+ case "find": {
5645
+ if (!parsed.query) {
5646
+ console.error("Usage: swarm memory find <query> [--limit <n>] [--collection <name>]");
5647
+ process.exit(1);
5648
+ }
5649
+
5650
+ const results = await adapter.find(parsed.query, {
5651
+ limit: parsed.limit || 10,
5652
+ collection: parsed.collection,
5653
+ });
5654
+
5655
+ if (parsed.json) {
5656
+ console.log(JSON.stringify({ success: true, results }));
5657
+ } else {
5658
+ p.intro(`swarm memory find: "${parsed.query}"`);
5659
+ if (results.length === 0) {
5660
+ p.log.warn("No memories found");
5661
+ } else {
5662
+ for (const result of results) {
5663
+ console.log();
5664
+ console.log(cyan(`[${result.memory.id}] Score: ${result.score.toFixed(3)}`));
5665
+ console.log(dim(` Created: ${new Date(result.memory.createdAt).toLocaleDateString()}`));
5666
+ console.log(` ${result.memory.content.slice(0, 200)}${result.memory.content.length > 200 ? "..." : ""}`);
5667
+ if (result.memory.metadata.tags) {
5668
+ console.log(dim(` Tags: ${(result.memory.metadata.tags as string[]).join(", ")}`));
5669
+ }
5670
+ }
5671
+ }
5672
+ p.outro(`Found ${results.length} result(s)`);
5673
+ }
5674
+ break;
5675
+ }
5676
+
5677
+ case "get": {
5678
+ if (!parsed.id) {
5679
+ console.error("Usage: swarm memory get <id>");
5680
+ process.exit(1);
5681
+ }
5682
+
5683
+ const memory = await adapter.get(parsed.id);
5684
+
5685
+ if (parsed.json) {
5686
+ if (memory) {
5687
+ console.log(JSON.stringify({ success: true, memory }));
5688
+ } else {
5689
+ console.log(JSON.stringify({ success: false, error: "Memory not found" }));
5690
+ process.exit(1);
5691
+ }
5692
+ } else {
5693
+ p.intro(`swarm memory get: ${parsed.id}`);
5694
+ if (!memory) {
5695
+ p.log.error("Memory not found");
5696
+ p.outro("Aborted");
5697
+ process.exit(1);
5698
+ } else {
5699
+ console.log();
5700
+ console.log(cyan("Content:"));
5701
+ console.log(memory.content);
5702
+ console.log();
5703
+ console.log(dim(`Created: ${new Date(memory.createdAt).toLocaleDateString()}`));
5704
+ console.log(dim(`Collection: ${memory.collection}`));
5705
+ console.log(dim(`Confidence: ${memory.confidence ?? 0.7}`));
5706
+ if (memory.metadata.tags) {
5707
+ console.log(dim(`Tags: ${(memory.metadata.tags as string[]).join(", ")}`));
5708
+ }
5709
+ p.outro("Done");
5710
+ }
5711
+ }
5712
+ break;
5713
+ }
5714
+
5715
+ case "remove": {
5716
+ if (!parsed.id) {
5717
+ console.error("Usage: swarm memory remove <id>");
5718
+ process.exit(1);
5719
+ }
5720
+
5721
+ await adapter.remove(parsed.id);
5722
+
5723
+ if (parsed.json) {
5724
+ console.log(JSON.stringify({ success: true }));
5725
+ } else {
5726
+ p.intro("swarm memory remove");
5727
+ p.log.success(`Removed memory: ${parsed.id}`);
5728
+ p.outro("Done");
5729
+ }
5730
+ break;
5731
+ }
5732
+
5733
+ case "validate": {
5734
+ if (!parsed.id) {
5735
+ console.error("Usage: swarm memory validate <id>");
5736
+ process.exit(1);
5737
+ }
5738
+
5739
+ await adapter.validate(parsed.id);
5740
+
5741
+ if (parsed.json) {
5742
+ console.log(JSON.stringify({ success: true }));
5743
+ } else {
5744
+ p.intro("swarm memory validate");
5745
+ p.log.success(`Validated memory: ${parsed.id} (decay timer reset)`);
5746
+ p.outro("Done");
5747
+ }
5748
+ break;
5749
+ }
5750
+
5751
+ case "stats": {
5752
+ const stats = await adapter.stats();
5753
+
5754
+ if (parsed.json) {
5755
+ console.log(JSON.stringify({ success: true, stats }));
5756
+ } else {
5757
+ p.intro("swarm memory stats");
5758
+ console.log();
5759
+ console.log(cyan("Database Statistics:"));
5760
+ console.log(` Memories: ${stats.memories}`);
5761
+ console.log(` Embeddings: ${stats.embeddings}`);
5762
+ p.outro("Done");
5763
+ }
5764
+ break;
5765
+ }
5766
+
5767
+ case "index": {
5768
+ // Index is a stub - actual indexing happens via session indexing
5769
+ // which is handled by hivemind_index tool
5770
+ if (parsed.json) {
5771
+ console.log(JSON.stringify({ success: true, message: "Use hivemind_index tool for session indexing" }));
5772
+ } else {
5773
+ p.intro("swarm memory index");
5774
+ p.log.message("Session indexing is handled by the hivemind_index tool");
5775
+ p.log.message("Use: swarm tool hivemind_index");
5776
+ p.outro("Done");
5777
+ }
5778
+ break;
5779
+ }
5780
+
5781
+ case "sync": {
5782
+ // Sync is a stub - actual sync happens via .hive/memories.jsonl
5783
+ // which is handled by hivemind_sync tool
5784
+ if (parsed.json) {
5785
+ console.log(JSON.stringify({ success: true, message: "Use hivemind_sync tool for git sync" }));
5786
+ } else {
5787
+ p.intro("swarm memory sync");
5788
+ p.log.message("Memory sync to .hive/memories.jsonl is handled by the hivemind_sync tool");
5789
+ p.log.message("Use: swarm tool hivemind_sync");
5790
+ p.outro("Done");
5791
+ }
5792
+ break;
5793
+ }
5794
+
5795
+ default: {
5796
+ console.error(`Unknown subcommand: ${subcommand}`);
5797
+ console.error("");
5798
+ console.error("Usage: swarm memory <subcommand> [options]");
5799
+ console.error("");
5800
+ console.error("Subcommands:");
5801
+ console.error(" store <info> [--tags <tags>] Store a memory");
5802
+ console.error(" find <query> [--limit <n>] Search memories");
5803
+ console.error(" get <id> Get memory by ID");
5804
+ console.error(" remove <id> Delete memory");
5805
+ console.error(" validate <id> Reset decay timer");
5806
+ console.error(" stats Show database stats");
5807
+ console.error(" index Index sessions (use hivemind_index)");
5808
+ console.error(" sync Sync to git (use hivemind_sync)");
5809
+ console.error("");
5810
+ console.error("Global options:");
5811
+ console.error(" --json Output JSON");
5812
+ process.exit(1);
5813
+ }
5814
+ }
5815
+ } catch (error) {
5816
+ if (parsed.json) {
5817
+ console.log(JSON.stringify({
5818
+ success: false,
5819
+ error: error instanceof Error ? error.message : String(error),
5820
+ }));
5821
+ process.exit(1);
5822
+ } else {
5823
+ p.log.error("Memory operation failed");
5824
+ p.log.message(error instanceof Error ? error.message : String(error));
5825
+ p.outro("Aborted");
5826
+ process.exit(1);
5827
+ }
5828
+ }
5829
+ }
5830
+
5506
5831
  // ============================================================================
5507
5832
  // Main
5508
5833
  // ============================================================================
@@ -5582,6 +5907,9 @@ switch (command) {
5582
5907
  case "capture":
5583
5908
  await capture();
5584
5909
  break;
5910
+ case "memory":
5911
+ await memory();
5912
+ break;
5585
5913
  case "query":
5586
5914
  await query();
5587
5915
  break;
package/dist/bin/swarm.js CHANGED
@@ -124211,6 +124211,7 @@ ${cyan("Commands:")}
124211
124211
  swarm viz Alias for 'swarm serve' (deprecated, use serve)
124212
124212
  --port <n> Port to listen on (default: 4483)
124213
124213
  swarm cells List or get cells from database (replaces 'swarm tool hive_query')
124214
+ swarm memory Manage unified memory system (learnings + sessions)
124214
124215
  swarm log View swarm logs with filtering
124215
124216
  swarm stats Show swarm health metrics powered by swarm-insights (strategy success rates, patterns)
124216
124217
  swarm o11y Show observability health - hook coverage, event capture, session quality
@@ -124238,6 +124239,17 @@ ${cyan("Cell Management:")}
124238
124239
  swarm cells --ready Show next ready (unblocked) cell
124239
124240
  swarm cells --json Raw JSON output (array, no wrapper)
124240
124241
 
124242
+ ${cyan("Memory Management (Hivemind):")}
124243
+ swarm memory store <info> [--tags <tags>] Store a learning/memory
124244
+ swarm memory find <query> [--limit <n>] Search all memories (semantic + FTS)
124245
+ swarm memory get <id> Get specific memory by ID
124246
+ swarm memory remove <id> Delete outdated/incorrect memory
124247
+ swarm memory validate <id> Confirm accuracy (resets 90-day decay)
124248
+ swarm memory stats Show database statistics
124249
+ swarm memory index Index AI sessions (use hivemind_index tool)
124250
+ swarm memory sync Sync to .hive/memories.jsonl (use hivemind_sync tool)
124251
+ swarm memory <command> --json Output JSON for all commands
124252
+
124241
124253
  ${cyan("Log Viewing:")}
124242
124254
  swarm log Tail recent logs (last 50 lines)
124243
124255
  swarm log <module> Filter by module (e.g., compaction)
@@ -125808,6 +125820,247 @@ async function capture3() {
125808
125820
  process.exit(1);
125809
125821
  }
125810
125822
  }
125823
+ function parseMemoryArgs(subcommand, args3) {
125824
+ let json4 = false;
125825
+ let info;
125826
+ let query2;
125827
+ let id;
125828
+ let tags;
125829
+ let limit;
125830
+ let collection;
125831
+ if (args3.length > 0 && !args3[0].startsWith("--")) {
125832
+ if (subcommand === "store") {
125833
+ info = args3[0];
125834
+ } else if (subcommand === "find") {
125835
+ query2 = args3[0];
125836
+ } else if (subcommand === "get" || subcommand === "remove" || subcommand === "validate") {
125837
+ id = args3[0];
125838
+ }
125839
+ }
125840
+ for (let i = 0;i < args3.length; i++) {
125841
+ const arg = args3[i];
125842
+ if (arg === "--json") {
125843
+ json4 = true;
125844
+ } else if (arg === "--tags" && i + 1 < args3.length) {
125845
+ tags = args3[++i];
125846
+ } else if (arg === "--limit" && i + 1 < args3.length) {
125847
+ const val = parseInt(args3[++i], 10);
125848
+ if (!isNaN(val))
125849
+ limit = val;
125850
+ } else if (arg === "--collection" && i + 1 < args3.length) {
125851
+ collection = args3[++i];
125852
+ }
125853
+ }
125854
+ return { json: json4, info, query: query2, id, tags, limit, collection };
125855
+ }
125856
+ async function memory() {
125857
+ const subcommand = process.argv[3];
125858
+ const args3 = process.argv.slice(4);
125859
+ const parsed = parseMemoryArgs(subcommand, args3);
125860
+ const projectPath = process.cwd();
125861
+ try {
125862
+ const { getDb: getDb2 } = await import("swarm-mail");
125863
+ const tempDirName = getLibSQLProjectTempDirName(projectPath);
125864
+ const tempDir = join29(tmpdir3(), tempDirName);
125865
+ if (!existsSync20(tempDir)) {
125866
+ mkdirSync11(tempDir, { recursive: true });
125867
+ }
125868
+ const dbPath = join29(tempDir, "streams.db");
125869
+ const dbUrl = `file://${dbPath}`;
125870
+ const db2 = await getDb2(dbUrl);
125871
+ const { createMemoryAdapter: createMemoryAdapter3 } = await import("swarm-mail");
125872
+ const adapter = createMemoryAdapter3(db2, {
125873
+ ollamaHost: process.env.OLLAMA_HOST || "http://localhost:11434",
125874
+ ollamaModel: process.env.OLLAMA_MODEL || "mxbai-embed-large"
125875
+ });
125876
+ switch (subcommand) {
125877
+ case "store": {
125878
+ if (!parsed.info) {
125879
+ console.error("Usage: swarm memory store <information> [--tags <tags>]");
125880
+ process.exit(1);
125881
+ }
125882
+ const result = await adapter.store(parsed.info, {
125883
+ tags: parsed.tags,
125884
+ collection: parsed.collection || "default"
125885
+ });
125886
+ if (parsed.json) {
125887
+ console.log(JSON.stringify({ success: true, id: result.id }));
125888
+ } else {
125889
+ p.intro("swarm memory store");
125890
+ p.log.success(`Stored memory: ${result.id}`);
125891
+ if (result.autoTags) {
125892
+ p.log.message(`Auto-tags: ${result.autoTags.tags.join(", ")}`);
125893
+ }
125894
+ p.outro("Done");
125895
+ }
125896
+ break;
125897
+ }
125898
+ case "find": {
125899
+ if (!parsed.query) {
125900
+ console.error("Usage: swarm memory find <query> [--limit <n>] [--collection <name>]");
125901
+ process.exit(1);
125902
+ }
125903
+ const results = await adapter.find(parsed.query, {
125904
+ limit: parsed.limit || 10,
125905
+ collection: parsed.collection
125906
+ });
125907
+ if (parsed.json) {
125908
+ console.log(JSON.stringify({ success: true, results }));
125909
+ } else {
125910
+ p.intro(`swarm memory find: "${parsed.query}"`);
125911
+ if (results.length === 0) {
125912
+ p.log.warn("No memories found");
125913
+ } else {
125914
+ for (const result of results) {
125915
+ console.log();
125916
+ console.log(cyan(`[${result.memory.id}] Score: ${result.score.toFixed(3)}`));
125917
+ console.log(dim(` Created: ${new Date(result.memory.createdAt).toLocaleDateString()}`));
125918
+ console.log(` ${result.memory.content.slice(0, 200)}${result.memory.content.length > 200 ? "..." : ""}`);
125919
+ if (result.memory.metadata.tags) {
125920
+ console.log(dim(` Tags: ${result.memory.metadata.tags.join(", ")}`));
125921
+ }
125922
+ }
125923
+ }
125924
+ p.outro(`Found ${results.length} result(s)`);
125925
+ }
125926
+ break;
125927
+ }
125928
+ case "get": {
125929
+ if (!parsed.id) {
125930
+ console.error("Usage: swarm memory get <id>");
125931
+ process.exit(1);
125932
+ }
125933
+ const memory2 = await adapter.get(parsed.id);
125934
+ if (parsed.json) {
125935
+ if (memory2) {
125936
+ console.log(JSON.stringify({ success: true, memory: memory2 }));
125937
+ } else {
125938
+ console.log(JSON.stringify({ success: false, error: "Memory not found" }));
125939
+ process.exit(1);
125940
+ }
125941
+ } else {
125942
+ p.intro(`swarm memory get: ${parsed.id}`);
125943
+ if (!memory2) {
125944
+ p.log.error("Memory not found");
125945
+ p.outro("Aborted");
125946
+ process.exit(1);
125947
+ } else {
125948
+ console.log();
125949
+ console.log(cyan("Content:"));
125950
+ console.log(memory2.content);
125951
+ console.log();
125952
+ console.log(dim(`Created: ${new Date(memory2.createdAt).toLocaleDateString()}`));
125953
+ console.log(dim(`Collection: ${memory2.collection}`));
125954
+ console.log(dim(`Confidence: ${memory2.confidence ?? 0.7}`));
125955
+ if (memory2.metadata.tags) {
125956
+ console.log(dim(`Tags: ${memory2.metadata.tags.join(", ")}`));
125957
+ }
125958
+ p.outro("Done");
125959
+ }
125960
+ }
125961
+ break;
125962
+ }
125963
+ case "remove": {
125964
+ if (!parsed.id) {
125965
+ console.error("Usage: swarm memory remove <id>");
125966
+ process.exit(1);
125967
+ }
125968
+ await adapter.remove(parsed.id);
125969
+ if (parsed.json) {
125970
+ console.log(JSON.stringify({ success: true }));
125971
+ } else {
125972
+ p.intro("swarm memory remove");
125973
+ p.log.success(`Removed memory: ${parsed.id}`);
125974
+ p.outro("Done");
125975
+ }
125976
+ break;
125977
+ }
125978
+ case "validate": {
125979
+ if (!parsed.id) {
125980
+ console.error("Usage: swarm memory validate <id>");
125981
+ process.exit(1);
125982
+ }
125983
+ await adapter.validate(parsed.id);
125984
+ if (parsed.json) {
125985
+ console.log(JSON.stringify({ success: true }));
125986
+ } else {
125987
+ p.intro("swarm memory validate");
125988
+ p.log.success(`Validated memory: ${parsed.id} (decay timer reset)`);
125989
+ p.outro("Done");
125990
+ }
125991
+ break;
125992
+ }
125993
+ case "stats": {
125994
+ const stats2 = await adapter.stats();
125995
+ if (parsed.json) {
125996
+ console.log(JSON.stringify({ success: true, stats: stats2 }));
125997
+ } else {
125998
+ p.intro("swarm memory stats");
125999
+ console.log();
126000
+ console.log(cyan("Database Statistics:"));
126001
+ console.log(` Memories: ${stats2.memories}`);
126002
+ console.log(` Embeddings: ${stats2.embeddings}`);
126003
+ p.outro("Done");
126004
+ }
126005
+ break;
126006
+ }
126007
+ case "index": {
126008
+ if (parsed.json) {
126009
+ console.log(JSON.stringify({ success: true, message: "Use hivemind_index tool for session indexing" }));
126010
+ } else {
126011
+ p.intro("swarm memory index");
126012
+ p.log.message("Session indexing is handled by the hivemind_index tool");
126013
+ p.log.message("Use: swarm tool hivemind_index");
126014
+ p.outro("Done");
126015
+ }
126016
+ break;
126017
+ }
126018
+ case "sync": {
126019
+ if (parsed.json) {
126020
+ console.log(JSON.stringify({ success: true, message: "Use hivemind_sync tool for git sync" }));
126021
+ } else {
126022
+ p.intro("swarm memory sync");
126023
+ p.log.message("Memory sync to .hive/memories.jsonl is handled by the hivemind_sync tool");
126024
+ p.log.message("Use: swarm tool hivemind_sync");
126025
+ p.outro("Done");
126026
+ }
126027
+ break;
126028
+ }
126029
+ default: {
126030
+ console.error(`Unknown subcommand: ${subcommand}`);
126031
+ console.error("");
126032
+ console.error("Usage: swarm memory <subcommand> [options]");
126033
+ console.error("");
126034
+ console.error("Subcommands:");
126035
+ console.error(" store <info> [--tags <tags>] Store a memory");
126036
+ console.error(" find <query> [--limit <n>] Search memories");
126037
+ console.error(" get <id> Get memory by ID");
126038
+ console.error(" remove <id> Delete memory");
126039
+ console.error(" validate <id> Reset decay timer");
126040
+ console.error(" stats Show database stats");
126041
+ console.error(" index Index sessions (use hivemind_index)");
126042
+ console.error(" sync Sync to git (use hivemind_sync)");
126043
+ console.error("");
126044
+ console.error("Global options:");
126045
+ console.error(" --json Output JSON");
126046
+ process.exit(1);
126047
+ }
126048
+ }
126049
+ } catch (error54) {
126050
+ if (parsed.json) {
126051
+ console.log(JSON.stringify({
126052
+ success: false,
126053
+ error: error54 instanceof Error ? error54.message : String(error54)
126054
+ }));
126055
+ process.exit(1);
126056
+ } else {
126057
+ p.log.error("Memory operation failed");
126058
+ p.log.message(error54 instanceof Error ? error54.message : String(error54));
126059
+ p.outro("Aborted");
126060
+ process.exit(1);
126061
+ }
126062
+ }
126063
+ }
125811
126064
  var command = process.argv[2];
125812
126065
  switch (command) {
125813
126066
  case "setup": {
@@ -125880,6 +126133,9 @@ switch (command) {
125880
126133
  case "capture":
125881
126134
  await capture3();
125882
126135
  break;
126136
+ case "memory":
126137
+ await memory();
126138
+ break;
125883
126139
  case "query":
125884
126140
  await query();
125885
126141
  break;
@@ -1401,6 +1401,71 @@ const cass_stats = tool({
1401
1401
  execute: (args, ctx) => execTool("cass_stats", args, ctx),
1402
1402
  });
1403
1403
 
1404
+ // =============================================================================
1405
+ // Hivemind Tools (Unified Memory - Sessions + Learnings)
1406
+ // =============================================================================
1407
+
1408
+ const hivemind_store = tool({
1409
+ description: "Store a memory (learnings, decisions, patterns) with metadata and tags. Include WHY, not just WHAT.",
1410
+ args: {
1411
+ information: tool.schema.string().describe("The learning, decision, or pattern to store (include context and reasoning)"),
1412
+ tags: tool.schema.string().optional().describe("Comma-separated tags for categorization (e.g., 'auth,oauth,tokens')"),
1413
+ },
1414
+ execute: (args, ctx) => execTool("hivemind_store", args, ctx),
1415
+ });
1416
+
1417
+ const hivemind_find = tool({
1418
+ description: "Search all memories (learnings + sessions) by semantic similarity. Use BEFORE implementing to check if any agent solved it before.",
1419
+ args: {
1420
+ query: tool.schema.string().describe("Search query (e.g., 'token refresh race condition')"),
1421
+ limit: tool.schema.number().optional().describe("Max results to return (default: 5)"),
1422
+ collection: tool.schema.string().optional().describe("Filter by collection: 'default' (learnings), 'claude', 'cursor', etc., or omit for all"),
1423
+ },
1424
+ execute: (args, ctx) => execTool("hivemind_find", args, ctx),
1425
+ });
1426
+
1427
+ const hivemind_get = tool({
1428
+ description: "Get specific memory by ID",
1429
+ args: {
1430
+ id: tool.schema.string().describe("Memory ID (e.g., 'mem_xyz123')"),
1431
+ },
1432
+ execute: (args, ctx) => execTool("hivemind_get", args, ctx),
1433
+ });
1434
+
1435
+ const hivemind_remove = tool({
1436
+ description: "Delete outdated/incorrect memory",
1437
+ args: {
1438
+ id: tool.schema.string().describe("Memory ID to remove"),
1439
+ },
1440
+ execute: (args, ctx) => execTool("hivemind_remove", args, ctx),
1441
+ });
1442
+
1443
+ const hivemind_validate = tool({
1444
+ description: "Confirm memory is still accurate (resets 90-day decay timer)",
1445
+ args: {
1446
+ id: tool.schema.string().describe("Memory ID to validate"),
1447
+ },
1448
+ execute: (args, ctx) => execTool("hivemind_validate", args, ctx),
1449
+ });
1450
+
1451
+ const hivemind_stats = tool({
1452
+ description: "Memory statistics and health check (documents, chunks, embeddings)",
1453
+ args: {},
1454
+ execute: (args, ctx) => execTool("hivemind_stats", args, ctx),
1455
+ });
1456
+
1457
+ const hivemind_index = tool({
1458
+ description: "Index AI session directories (automatically indexes ~/.config/opencode/sessions, ~/.cursor-tutor, etc.)",
1459
+ args: {},
1460
+ execute: (args, ctx) => execTool("hivemind_index", args, ctx),
1461
+ });
1462
+
1463
+ const hivemind_sync = tool({
1464
+ description: "Sync learnings to .hive/memories.jsonl for git-backed team sharing",
1465
+ args: {},
1466
+ execute: (args, ctx) => execTool("hivemind_sync", args, ctx),
1467
+ });
1468
+
1404
1469
  // =============================================================================
1405
1470
  // Plugin Export
1406
1471
  // =============================================================================
@@ -2573,6 +2638,15 @@ const SwarmPlugin: Plugin = async (
2573
2638
  cass_health,
2574
2639
  cass_index,
2575
2640
  cass_stats,
2641
+ // Hivemind (Unified Memory - Sessions + Learnings)
2642
+ hivemind_store,
2643
+ hivemind_find,
2644
+ hivemind_get,
2645
+ hivemind_remove,
2646
+ hivemind_validate,
2647
+ hivemind_stats,
2648
+ hivemind_index,
2649
+ hivemind_sync,
2576
2650
  },
2577
2651
 
2578
2652
  // Swarm-aware compaction hook with LLM-powered continuation prompts
@@ -1401,6 +1401,71 @@ const cass_stats = tool({
1401
1401
  execute: (args, ctx) => execTool("cass_stats", args, ctx),
1402
1402
  });
1403
1403
 
1404
+ // =============================================================================
1405
+ // Hivemind Tools (Unified Memory - Sessions + Learnings)
1406
+ // =============================================================================
1407
+
1408
+ const hivemind_store = tool({
1409
+ description: "Store a memory (learnings, decisions, patterns) with metadata and tags. Include WHY, not just WHAT.",
1410
+ args: {
1411
+ information: tool.schema.string().describe("The learning, decision, or pattern to store (include context and reasoning)"),
1412
+ tags: tool.schema.string().optional().describe("Comma-separated tags for categorization (e.g., 'auth,oauth,tokens')"),
1413
+ },
1414
+ execute: (args, ctx) => execTool("hivemind_store", args, ctx),
1415
+ });
1416
+
1417
+ const hivemind_find = tool({
1418
+ description: "Search all memories (learnings + sessions) by semantic similarity. Use BEFORE implementing to check if any agent solved it before.",
1419
+ args: {
1420
+ query: tool.schema.string().describe("Search query (e.g., 'token refresh race condition')"),
1421
+ limit: tool.schema.number().optional().describe("Max results to return (default: 5)"),
1422
+ collection: tool.schema.string().optional().describe("Filter by collection: 'default' (learnings), 'claude', 'cursor', etc., or omit for all"),
1423
+ },
1424
+ execute: (args, ctx) => execTool("hivemind_find", args, ctx),
1425
+ });
1426
+
1427
+ const hivemind_get = tool({
1428
+ description: "Get specific memory by ID",
1429
+ args: {
1430
+ id: tool.schema.string().describe("Memory ID (e.g., 'mem_xyz123')"),
1431
+ },
1432
+ execute: (args, ctx) => execTool("hivemind_get", args, ctx),
1433
+ });
1434
+
1435
+ const hivemind_remove = tool({
1436
+ description: "Delete outdated/incorrect memory",
1437
+ args: {
1438
+ id: tool.schema.string().describe("Memory ID to remove"),
1439
+ },
1440
+ execute: (args, ctx) => execTool("hivemind_remove", args, ctx),
1441
+ });
1442
+
1443
+ const hivemind_validate = tool({
1444
+ description: "Confirm memory is still accurate (resets 90-day decay timer)",
1445
+ args: {
1446
+ id: tool.schema.string().describe("Memory ID to validate"),
1447
+ },
1448
+ execute: (args, ctx) => execTool("hivemind_validate", args, ctx),
1449
+ });
1450
+
1451
+ const hivemind_stats = tool({
1452
+ description: "Memory statistics and health check (documents, chunks, embeddings)",
1453
+ args: {},
1454
+ execute: (args, ctx) => execTool("hivemind_stats", args, ctx),
1455
+ });
1456
+
1457
+ const hivemind_index = tool({
1458
+ description: "Index AI session directories (automatically indexes ~/.config/opencode/sessions, ~/.cursor-tutor, etc.)",
1459
+ args: {},
1460
+ execute: (args, ctx) => execTool("hivemind_index", args, ctx),
1461
+ });
1462
+
1463
+ const hivemind_sync = tool({
1464
+ description: "Sync learnings to .hive/memories.jsonl for git-backed team sharing",
1465
+ args: {},
1466
+ execute: (args, ctx) => execTool("hivemind_sync", args, ctx),
1467
+ });
1468
+
1404
1469
  // =============================================================================
1405
1470
  // Plugin Export
1406
1471
  // =============================================================================
@@ -2573,6 +2638,15 @@ const SwarmPlugin: Plugin = async (
2573
2638
  cass_health,
2574
2639
  cass_index,
2575
2640
  cass_stats,
2641
+ // Hivemind (Unified Memory - Sessions + Learnings)
2642
+ hivemind_store,
2643
+ hivemind_find,
2644
+ hivemind_get,
2645
+ hivemind_remove,
2646
+ hivemind_validate,
2647
+ hivemind_stats,
2648
+ hivemind_index,
2649
+ hivemind_sync,
2576
2650
  },
2577
2651
 
2578
2652
  // Swarm-aware compaction hook with LLM-powered continuation prompts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm-plugin",
3
- "version": "0.47.0",
3
+ "version": "0.48.0",
4
4
  "description": "Multi-agent swarm coordination for OpenCode with learning capabilities, beads integration, and Agent Mail",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",