@heretek-ai/epistemic-swarm 0.4.4 → 0.4.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.
Files changed (37) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/package.json +1 -1
  3. package/plugins/antigravity/plugin.json +1 -1
  4. package/plugins/gemini/gemini-extension.json +1 -1
  5. package/plugins/opencode/index.js +64 -7
  6. package/runner/__pycache__/__init__.cpython-311.pyc +0 -0
  7. package/runner/__pycache__/auctioneer.cpython-311.pyc +0 -0
  8. package/runner/__pycache__/auditor_engine.cpython-311.pyc +0 -0
  9. package/runner/__pycache__/claim_store.cpython-311.pyc +0 -0
  10. package/runner/__pycache__/claim_witness.cpython-311.pyc +0 -0
  11. package/runner/__pycache__/living_dossiers.cpython-311.pyc +0 -0
  12. package/runner/__pycache__/mcp_protocol.cpython-311.pyc +0 -0
  13. package/runner/__pycache__/mcp_server.cpython-311.pyc +0 -0
  14. package/runner/__pycache__/pcrb.cpython-311.pyc +0 -0
  15. package/runner/__pycache__/pcrb_verify.cpython-311.pyc +0 -0
  16. package/runner/__pycache__/refinement.cpython-311.pyc +0 -0
  17. package/runner/__pycache__/research_swarm.cpython-311.pyc +0 -0
  18. package/runner/__pycache__/state_machine.cpython-311.pyc +0 -0
  19. package/runner/tests/__pycache__/test_auction_order.cpython-311.pyc +0 -0
  20. package/runner/tests/__pycache__/test_bet1_spike.cpython-311.pyc +0 -0
  21. package/runner/tests/__pycache__/test_claim_store.cpython-311.pyc +0 -0
  22. package/runner/tests/__pycache__/test_claim_witness.cpython-311.pyc +0 -0
  23. package/runner/tests/__pycache__/test_domain_packs.cpython-311.pyc +0 -0
  24. package/runner/tests/__pycache__/test_fleet_seam.cpython-311.pyc +0 -0
  25. package/runner/tests/__pycache__/test_living_dossiers.cpython-311.pyc +0 -0
  26. package/runner/tests/__pycache__/test_mcp_server.cpython-311.pyc +0 -0
  27. package/runner/tests/__pycache__/test_opencode_ux.cpython-311.pyc +0 -0
  28. package/runner/tests/__pycache__/test_pcrb.cpython-311.pyc +0 -0
  29. package/runner/tests/__pycache__/test_refinement.cpython-311.pyc +0 -0
  30. package/runner/tests/__pycache__/test_swarm.cpython-311.pyc +0 -0
  31. package/runner/tests/__pycache__/test_webcache.cpython-311.pyc +0 -0
  32. package/runner/tests/test_opencode_ux.py +99 -0
  33. package/scripts/__pycache__/bet1_advisory_spike.cpython-311.pyc +0 -0
  34. package/skills/research_cache/__pycache__/__init__.cpython-311.pyc +0 -0
  35. package/skills/research_cache/__pycache__/hasher.cpython-311.pyc +0 -0
  36. package/skills/swarm_config/__pycache__/__init__.cpython-311.pyc +0 -0
  37. package/skills/swarm_config/__pycache__/configure.cpython-311.pyc +0 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "epistemic-swarm",
3
- "version": "0.4.4",
3
+ "version": "0.4.5",
4
4
  "description": "High-Integrity Dialectic Research Agent Harness for Claude Code enforcing empirical evidence over parametric hallucination.",
5
5
  "author": {
6
6
  "name": "Heretek AI",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heretek-ai/epistemic-swarm",
3
- "version": "0.4.4",
3
+ "version": "0.4.5",
4
4
  "description": "IUMBTEMS: I Use My Brain To Express My Self — High-Integrity Dialectic Research Agent Harness for Claude Code, OpenCode V2, Pi, OMP (oh-my-pi), Gemini CLI, Codex CLI, and AntiGravity",
5
5
  "main": "bin/cli.js",
6
6
  "bin": {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://antigravity.google/schemas/v1/plugin.json",
3
3
  "name": "epistemic-swarm",
4
- "version": "0.4.4",
4
+ "version": "0.4.5",
5
5
  "description": "IUMBTEMS Epistemic Swarm: dialectic research, code audit, OSS scout, and lateral brainstorming for AntiGravity.",
6
6
  "author": "Heretek AI",
7
7
  "license": "Apache-2.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "epistemic-swarm",
3
- "version": "0.4.4",
3
+ "version": "0.4.5",
4
4
  "description": "IUMBTEMS Epistemic Swarm: dialectic research, code audit, OSS scout, and lateral brainstorming for Gemini CLI.",
5
5
  "mcpServers": {
6
6
  "brave-search": {
@@ -659,7 +659,8 @@ export function createOpenCodePlugin(context = {}) {
659
659
  }),
660
660
 
661
661
  setup: async (appContext) => {
662
- const opts = context.options || appContext?.options;
662
+ const host = appContext || {};
663
+ const opts = context.options || host.options;
663
664
  if (opts && typeof opts === 'object') {
664
665
  const updates = {};
665
666
  if (opts.search_engine) updates.search_engine = opts.search_engine;
@@ -669,24 +670,80 @@ export function createOpenCodePlugin(context = {}) {
669
670
  updates.divergence_threshold = opts.divergence_threshold;
670
671
  }
671
672
  if (Object.keys(updates).length > 0) {
672
- await callMcp('iumbtems_config', updates, appContext?.cwd);
673
+ await callMcp('iumbtems_config', updates, host.cwd);
673
674
  }
674
675
  }
675
676
  // Phase C: idle staleness nudge (opt out with {staleness_nudge: false}).
676
677
  // Subscribes only when the host exposes event/session; one per root.
677
678
  try {
678
679
  if ((opts?.staleness_nudge ?? true)) {
679
- const host = {
680
- event: appContext?.event || context.event,
681
- session: appContext?.session || context.session,
680
+ const nudgeHost = {
681
+ event: host.event || context.event,
682
+ session: host.session || context.session,
682
683
  };
683
684
  const root =
684
- appContext?.location?.directory || context.location?.directory;
685
- if (root) startStalenessNudge(host, root);
685
+ host.location?.directory || context.location?.directory;
686
+ if (root) startStalenessNudge(nudgeHost, root);
686
687
  }
687
688
  } catch {
688
689
  /* lifecycle hooks are best-effort */
689
690
  }
691
+ // V2 host transforms (official dual-package pattern: V1 calls server(),
692
+ // V2 calls setup()). Registers slash commands + tools via the owning
693
+ // domains; each guarded so V1 hosts and partial V2 hosts keep working.
694
+ try {
695
+ if (host.command && typeof host.command.transform === 'function') {
696
+ let existing = new Set();
697
+ try {
698
+ const listed = await host.command.list();
699
+ existing = new Set(((listed && listed.data) || []).map((c) => c && c.name));
700
+ } catch {
701
+ /* treat as empty */
702
+ }
703
+ await host.command.transform((draft) => {
704
+ for (const cmd of OPENCODE_COMMANDS) {
705
+ if (!cmd || !cmd.name || existing.has(cmd.name)) continue;
706
+ existing.add(cmd.name);
707
+ draft.add({
708
+ name: cmd.name,
709
+ description: cmd.description,
710
+ execute: async (input) => {
711
+ const args = (input && input.prompt && input.prompt.text) || '';
712
+ const prompt = (input && input.prompt && typeof input.prompt === 'object') ? input.prompt : {};
713
+ await host.session.prompt({
714
+ ...prompt,
715
+ sessionID: input && input.sessionID,
716
+ text: cmd.template.split('$ARGUMENTS').join(String(args).trim()),
717
+ delivery: input && input.delivery,
718
+ });
719
+ },
720
+ });
721
+ }
722
+ });
723
+ }
724
+ } catch {
725
+ /* command transform is best-effort */
726
+ }
727
+ try {
728
+ if (host.tool && typeof host.tool.transform === 'function') {
729
+ await host.tool.transform((draft) => {
730
+ for (const [name, spec] of Object.entries(buildToolMap())) {
731
+ draft.add({
732
+ name,
733
+ description: spec.description,
734
+ input: spec.input,
735
+ options: { codemode: false },
736
+ execute: async (args = {}, toolContext) => {
737
+ const r = await callMcp(name, normalizeArgs(name, args), toolContext?.cwd);
738
+ return { content: r.content };
739
+ },
740
+ });
741
+ }
742
+ });
743
+ }
744
+ } catch {
745
+ /* tool transform is best-effort */
746
+ }
690
747
  return { initialized: true, platform: 'opencode-v2' };
691
748
  },
692
749
  };
@@ -465,5 +465,104 @@ class TestOpenCodeLifecycle(unittest.TestCase):
465
465
  self.assertEqual(data["sid"], "ses_1")
466
466
 
467
467
 
468
+ class TestOpenCodeV2Transforms(unittest.TestCase):
469
+ """V2 host (setup ctx transforms): commands + tools via owning domains."""
470
+
471
+ V2_SETUP = """
472
+ import plugin from "./plugins/opencode/index.js";
473
+ const addedCommands = [];
474
+ const addedTools = [];
475
+ const prompts = [];
476
+ const host = {
477
+ options: {},
478
+ command: {
479
+ list: async () => ({data: [{name: "goal"}]}),
480
+ transform: async (fn) => { fn({add: (d) => addedCommands.push(d)}); return () => {}; }
481
+ },
482
+ tool: {
483
+ transform: async (fn) => { fn({add: (t) => addedTools.push(t)}); return () => {}; }
484
+ },
485
+ session: { prompt: async (p) => { prompts.push(p); return {}; } }
486
+ };
487
+ const ret = await plugin.setup(host);
488
+ %s
489
+ """
490
+
491
+ def test_v2_registers_commands_and_tools(self):
492
+ res = run_node(
493
+ self.V2_SETUP
494
+ % """
495
+ console.log(JSON.stringify({
496
+ ret: ret.initialized,
497
+ commands: addedCommands.map(c => c.name),
498
+ cmdExec: typeof addedCommands.find(c => c.name === "swarm").execute,
499
+ tools: addedTools.map(t => t.name),
500
+ toolExec: typeof addedTools.find(t => t.name === "iumbtems_config").execute
501
+ }));
502
+ """
503
+ )
504
+ self.assertEqual(res.returncode, 0, f"v2 transform test failed: {res.stderr}")
505
+ data = last_json_object(res.stdout)
506
+ self.assertTrue(data["ret"])
507
+ for c in [
508
+ "swarm",
509
+ "grill",
510
+ "swarm-config",
511
+ "audit",
512
+ "scout",
513
+ "brainstorming",
514
+ "brainstorm",
515
+ ]:
516
+ self.assertIn(c, data["commands"])
517
+ self.assertNotIn("goal", data["commands"])
518
+ self.assertEqual(data["cmdExec"], "function")
519
+ self.assertEqual(len(data["tools"]), 13)
520
+ self.assertIn("iumbtems_brainstorm", data["tools"])
521
+ self.assertEqual(data["toolExec"], "function")
522
+
523
+ def test_v2_command_execute_forwards_prompt(self):
524
+ res = run_node(
525
+ self.V2_SETUP
526
+ % """
527
+ const swarm = addedCommands.find(c => c.name === "swarm");
528
+ await swarm.execute({sessionID: "ses_9", prompt: {text: "probe objective"}, delivery: "steer"});
529
+ console.log(JSON.stringify({prompts}));
530
+ """
531
+ )
532
+ self.assertEqual(res.returncode, 0, f"v2 execute test failed: {res.stderr}")
533
+ data = last_json_object(res.stdout)["prompts"]
534
+ self.assertEqual(len(data), 1)
535
+ self.assertEqual(data[0]["sessionID"], "ses_9")
536
+ self.assertIn("probe objective", data[0]["text"])
537
+ self.assertNotIn("$ARGUMENTS", data[0]["text"])
538
+ self.assertEqual(data[0]["delivery"], "steer")
539
+
540
+ def test_v2_tool_execute_returns_content(self):
541
+ res = run_node(
542
+ self.V2_SETUP
543
+ % """
544
+ const cfg = addedTools.find(t => t.name === "iumbtems_config");
545
+ const r = await cfg.execute({}, {});
546
+ console.log(JSON.stringify({keys: Object.keys(r), status: r.status, hasContent: typeof r.content === "string"}));
547
+ """
548
+ )
549
+ self.assertEqual(res.returncode, 0, f"v2 tool test failed: {res.stderr}")
550
+ data = last_json_object(res.stdout)
551
+ self.assertEqual(data["keys"], ["content"])
552
+ self.assertTrue(data["hasContent"])
553
+
554
+ def test_setup_without_v2_domains_still_works(self):
555
+ res = run_node(
556
+ """
557
+ import plugin from "./plugins/opencode/index.js";
558
+ const ret = await plugin.setup({});
559
+ console.log(JSON.stringify({ret: ret.initialized}));
560
+ """
561
+ )
562
+ self.assertEqual(res.returncode, 0, f"bare setup test failed: {res.stderr}")
563
+ data = last_json_object(res.stdout)
564
+ self.assertTrue(data["ret"])
565
+
566
+
468
567
  if __name__ == "__main__":
469
568
  unittest.main()