@heretek-ai/epistemic-swarm 0.4.5 → 0.4.7
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/.claude-plugin/plugin.json +1 -1
- package/package.json +1 -1
- package/plugins/antigravity/plugin.json +1 -1
- package/plugins/gemini/gemini-extension.json +1 -1
- package/plugins/opencode/index.js +61 -31
- package/runner/__pycache__/__init__.cpython-311.pyc +0 -0
- package/runner/__pycache__/auctioneer.cpython-311.pyc +0 -0
- package/runner/__pycache__/auditor_engine.cpython-311.pyc +0 -0
- package/runner/__pycache__/claim_store.cpython-311.pyc +0 -0
- package/runner/__pycache__/claim_witness.cpython-311.pyc +0 -0
- package/runner/__pycache__/living_dossiers.cpython-311.pyc +0 -0
- package/runner/__pycache__/mcp_protocol.cpython-311.pyc +0 -0
- package/runner/__pycache__/mcp_server.cpython-311.pyc +0 -0
- package/runner/__pycache__/pcrb.cpython-311.pyc +0 -0
- package/runner/__pycache__/pcrb_verify.cpython-311.pyc +0 -0
- package/runner/__pycache__/refinement.cpython-311.pyc +0 -0
- package/runner/__pycache__/research_swarm.cpython-311.pyc +0 -0
- package/runner/__pycache__/state_machine.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_auction_order.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_bet1_spike.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_claim_store.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_claim_witness.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_domain_packs.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_fleet_seam.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_living_dossiers.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_mcp_server.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_opencode_ux.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_pcrb.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_refinement.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_swarm.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_webcache.cpython-311.pyc +0 -0
- package/runner/tests/test_opencode_ux.py +59 -4
- package/scripts/__pycache__/bet1_advisory_spike.cpython-311.pyc +0 -0
- package/skills/research_cache/__pycache__/__init__.cpython-311.pyc +0 -0
- package/skills/research_cache/__pycache__/hasher.cpython-311.pyc +0 -0
- package/skills/swarm_config/__pycache__/__init__.cpython-311.pyc +0 -0
- package/skills/swarm_config/__pycache__/configure.cpython-311.pyc +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heretek-ai/epistemic-swarm",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.7",
|
|
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
|
+
"version": "0.4.7",
|
|
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",
|
|
@@ -563,6 +563,10 @@ export function buildCompactionContext(root) {
|
|
|
563
563
|
|
|
564
564
|
const NUDGE_MIN_INTERVAL_MS = 5 * 60 * 1000;
|
|
565
565
|
const activeNudges = new Map();
|
|
566
|
+
// Cleanup functions for the setup() disposer (a setup that returns a plain
|
|
567
|
+
// object crashes host reload: the host calls the return value as a cleanup
|
|
568
|
+
// function). All setup-owned resources register here.
|
|
569
|
+
const setupCleanups = new Set();
|
|
566
570
|
|
|
567
571
|
/**
|
|
568
572
|
* Handle one subscribed event: nudge once per ledger change when degraded
|
|
@@ -661,36 +665,9 @@ export function createOpenCodePlugin(context = {}) {
|
|
|
661
665
|
setup: async (appContext) => {
|
|
662
666
|
const host = appContext || {};
|
|
663
667
|
const opts = context.options || host.options;
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
if (opts.max_iterations) updates.max_iterations = opts.max_iterations;
|
|
668
|
-
if (opts.mode) updates.mode = opts.mode;
|
|
669
|
-
if (opts.divergence_threshold !== undefined) {
|
|
670
|
-
updates.divergence_threshold = opts.divergence_threshold;
|
|
671
|
-
}
|
|
672
|
-
if (Object.keys(updates).length > 0) {
|
|
673
|
-
await callMcp('iumbtems_config', updates, host.cwd);
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
// Phase C: idle staleness nudge (opt out with {staleness_nudge: false}).
|
|
677
|
-
// Subscribes only when the host exposes event/session; one per root.
|
|
678
|
-
try {
|
|
679
|
-
if ((opts?.staleness_nudge ?? true)) {
|
|
680
|
-
const nudgeHost = {
|
|
681
|
-
event: host.event || context.event,
|
|
682
|
-
session: host.session || context.session,
|
|
683
|
-
};
|
|
684
|
-
const root =
|
|
685
|
-
host.location?.directory || context.location?.directory;
|
|
686
|
-
if (root) startStalenessNudge(nudgeHost, root);
|
|
687
|
-
}
|
|
688
|
-
} catch {
|
|
689
|
-
/* lifecycle hooks are best-effort */
|
|
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.
|
|
668
|
+
// V2 host transforms FIRST (official dual-package pattern: V1 calls
|
|
669
|
+
// server(), V2 calls setup()). Registration must precede any slow
|
|
670
|
+
// work: the host may not wait out subprocess calls before reconciling.
|
|
694
671
|
try {
|
|
695
672
|
if (host.command && typeof host.command.transform === 'function') {
|
|
696
673
|
let existing = new Set();
|
|
@@ -744,7 +721,60 @@ export function createOpenCodePlugin(context = {}) {
|
|
|
744
721
|
} catch {
|
|
745
722
|
/* tool transform is best-effort */
|
|
746
723
|
}
|
|
747
|
-
|
|
724
|
+
// Slow work AFTER registration: apply tuple options via MCP config
|
|
725
|
+
// write, scoped to the plugin location (never the service cwd).
|
|
726
|
+
try {
|
|
727
|
+
if (opts && typeof opts === 'object') {
|
|
728
|
+
const updates = {};
|
|
729
|
+
if (opts.search_engine) updates.search_engine = opts.search_engine;
|
|
730
|
+
if (opts.max_iterations) updates.max_iterations = opts.max_iterations;
|
|
731
|
+
if (opts.mode) updates.mode = opts.mode;
|
|
732
|
+
if (opts.divergence_threshold !== undefined) {
|
|
733
|
+
updates.divergence_threshold = opts.divergence_threshold;
|
|
734
|
+
}
|
|
735
|
+
if (Object.keys(updates).length > 0) {
|
|
736
|
+
await callMcp(
|
|
737
|
+
'iumbtems_config',
|
|
738
|
+
updates,
|
|
739
|
+
host.location?.directory || context.location?.directory || host.cwd
|
|
740
|
+
);
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
} catch {
|
|
744
|
+
/* options apply is best-effort */
|
|
745
|
+
}
|
|
746
|
+
// Phase C: idle staleness nudge (opt out with {staleness_nudge: false}).
|
|
747
|
+
// Subscribes only when the host exposes event/session; one per root.
|
|
748
|
+
try {
|
|
749
|
+
if ((opts?.staleness_nudge ?? true)) {
|
|
750
|
+
const nudgeHost = {
|
|
751
|
+
event: host.event || context.event,
|
|
752
|
+
session: host.session || context.session,
|
|
753
|
+
};
|
|
754
|
+
const root =
|
|
755
|
+
host.location?.directory || context.location?.directory;
|
|
756
|
+
if (root) {
|
|
757
|
+
const stop = startStalenessNudge(nudgeHost, root);
|
|
758
|
+
if (typeof stop === 'function') setupCleanups.add(stop);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
} catch {
|
|
762
|
+
/* lifecycle hooks are best-effort */
|
|
763
|
+
}
|
|
764
|
+
// Disposer: the host calls setup's return value as a cleanup function
|
|
765
|
+
// on unload/reload. It MUST be a function (returning a plain object
|
|
766
|
+
// crashes host reload with "not a function"). Aborts nudge streams so
|
|
767
|
+
// reloads never stack duplicate subscriptions.
|
|
768
|
+
return () => {
|
|
769
|
+
for (const stop of [...setupCleanups]) {
|
|
770
|
+
setupCleanups.delete(stop);
|
|
771
|
+
try {
|
|
772
|
+
stop();
|
|
773
|
+
} catch {
|
|
774
|
+
/* cleanup is best-effort */
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
};
|
|
748
778
|
},
|
|
749
779
|
};
|
|
750
780
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -493,7 +493,7 @@ class TestOpenCodeV2Transforms(unittest.TestCase):
|
|
|
493
493
|
self.V2_SETUP
|
|
494
494
|
% """
|
|
495
495
|
console.log(JSON.stringify({
|
|
496
|
-
|
|
496
|
+
cleanupFn: typeof ret === "function",
|
|
497
497
|
commands: addedCommands.map(c => c.name),
|
|
498
498
|
cmdExec: typeof addedCommands.find(c => c.name === "swarm").execute,
|
|
499
499
|
tools: addedTools.map(t => t.name),
|
|
@@ -503,7 +503,7 @@ class TestOpenCodeV2Transforms(unittest.TestCase):
|
|
|
503
503
|
)
|
|
504
504
|
self.assertEqual(res.returncode, 0, f"v2 transform test failed: {res.stderr}")
|
|
505
505
|
data = last_json_object(res.stdout)
|
|
506
|
-
self.
|
|
506
|
+
self.assertEqual(data["cleanupFn"], True)
|
|
507
507
|
for c in [
|
|
508
508
|
"swarm",
|
|
509
509
|
"grill",
|
|
@@ -556,12 +556,67 @@ class TestOpenCodeV2Transforms(unittest.TestCase):
|
|
|
556
556
|
"""
|
|
557
557
|
import plugin from "./plugins/opencode/index.js";
|
|
558
558
|
const ret = await plugin.setup({});
|
|
559
|
-
|
|
559
|
+
ret();
|
|
560
|
+
ret();
|
|
561
|
+
console.log(JSON.stringify({cleanupFn: typeof ret === "function"}));
|
|
560
562
|
"""
|
|
561
563
|
)
|
|
562
564
|
self.assertEqual(res.returncode, 0, f"bare setup test failed: {res.stderr}")
|
|
563
565
|
data = last_json_object(res.stdout)
|
|
564
|
-
self.
|
|
566
|
+
self.assertEqual(data["cleanupFn"], True)
|
|
567
|
+
|
|
568
|
+
def test_options_applied_to_location_dir_after_transforms(self):
|
|
569
|
+
import tempfile
|
|
570
|
+
|
|
571
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
572
|
+
res = run_node(
|
|
573
|
+
f"""
|
|
574
|
+
import plugin from "./plugins/opencode/index.js";
|
|
575
|
+
const added = [];
|
|
576
|
+
const host = {{
|
|
577
|
+
options: {{mode: "audit"}},
|
|
578
|
+
location: {{directory: {tmp!r}}},
|
|
579
|
+
command: {{
|
|
580
|
+
list: async () => ({{data: []}}),
|
|
581
|
+
transform: async (fn) => {{ fn({{add: (d) => added.push(d.name)}}); }}
|
|
582
|
+
}},
|
|
583
|
+
tool: {{transform: async () => {{}}}}
|
|
584
|
+
}};
|
|
585
|
+
await plugin.setup(host);
|
|
586
|
+
console.log(JSON.stringify({{commands: added}}));
|
|
587
|
+
"""
|
|
588
|
+
)
|
|
589
|
+
self.assertEqual(res.returncode, 0, f"options test failed: {res.stderr}")
|
|
590
|
+
data = last_json_object(res.stdout)
|
|
591
|
+
# Transforms registered despite the slow MCP options write.
|
|
592
|
+
self.assertIn("swarm", data["commands"])
|
|
593
|
+
cfg = json.loads(
|
|
594
|
+
Path(tmp, ".research", "config.json").read_text(encoding="utf-8")
|
|
595
|
+
)
|
|
596
|
+
self.assertEqual(cfg.get("mode"), "audit")
|
|
597
|
+
|
|
598
|
+
def test_setup_cleanup_aborts_nudge_streams(self):
|
|
599
|
+
res = run_node(
|
|
600
|
+
"""
|
|
601
|
+
import plugin from "./plugins/opencode/index.js";
|
|
602
|
+
const seen = [];
|
|
603
|
+
const host = {
|
|
604
|
+
options: {},
|
|
605
|
+
location: {directory: "/tmp/oc-nudge-cleanup"},
|
|
606
|
+
event: {subscribe: (opts) => { seen.push(opts && opts.signal); return {[Symbol.asyncIterator]() { return {next: async () => ({done: true})}; }}; }},
|
|
607
|
+
session: {prompt: async () => ({})}
|
|
608
|
+
};
|
|
609
|
+
const cleanup = await plugin.setup(host);
|
|
610
|
+
const before = seen.length;
|
|
611
|
+
cleanup();
|
|
612
|
+
console.log(JSON.stringify({subscribed: before > 0, cleanupFn: typeof cleanup === "function", aborted: seen.length > 0 && seen[0].aborted === true}));
|
|
613
|
+
"""
|
|
614
|
+
)
|
|
615
|
+
self.assertEqual(res.returncode, 0, f"cleanup test failed: {res.stderr}")
|
|
616
|
+
data = last_json_object(res.stdout)
|
|
617
|
+
self.assertTrue(data["subscribed"])
|
|
618
|
+
self.assertTrue(data["cleanupFn"])
|
|
619
|
+
self.assertTrue(data["aborted"])
|
|
565
620
|
|
|
566
621
|
|
|
567
622
|
if __name__ == "__main__":
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|