@heretek-ai/epistemic-swarm 0.7.25 → 1.0.2
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/index.ts +1 -0
- package/package.json +63 -139
- package/rpc.ts +1 -0
- package/server.ts +1 -0
- package/src/agents.ts +69 -0
- package/src/continue.ts +40 -0
- package/src/hooks.ts +283 -0
- package/src/panels.tsx +220 -0
- package/src/policy.ts +221 -0
- package/src/pr.ts +37 -0
- package/src/research.ts +63 -0
- package/src/rpc-def.ts +136 -0
- package/src/rpc.ts +331 -0
- package/src/runtime.ts +112 -0
- package/src/server.ts +311 -0
- package/src/session.ts +61 -0
- package/src/tools.ts +61 -0
- package/src/tui.tsx +206 -0
- package/tui.tsx +1 -0
- package/.agents/skills/brainstorming/SKILL.md +0 -19
- package/.agents/skills/code_audit/SKILL.md +0 -19
- package/.agents/skills/darkharvest/SKILL.md +0 -19
- package/.agents/skills/epistemic_search/SKILL.md +0 -19
- package/.agents/skills/factory/SKILL.md +0 -19
- package/.agents/skills/grilling/SKILL.md +0 -19
- package/.agents/skills/oss_scout/SKILL.md +0 -19
- package/.agents/skills/research_cache/SKILL.md +0 -19
- package/.agents/skills/swarm_config/SKILL.md +0 -19
- package/.claude-plugin/marketplace.json +0 -61
- package/.claude-plugin/plugin.json +0 -76
- package/.omp/README.md +0 -39
- package/.omp/SYSTEM.md +0 -17
- package/.omp/commands/audit.md +0 -10
- package/.omp/commands/brainstorming.md +0 -12
- package/.omp/commands/darkharvest.md +0 -11
- package/.omp/commands/domainexpansion.md +0 -9
- package/.omp/commands/factory.md +0 -9
- package/.omp/commands/grill.md +0 -9
- package/.omp/commands/scout.md +0 -10
- package/.omp/commands/swarm-config.md +0 -10
- package/.omp/commands/swarm.md +0 -9
- package/.omp/hooks/post/epistemic-audit.ts +0 -16
- package/.omp/hooks/pre/epistemic-redirect.ts +0 -21
- package/.omp/prompts/brainstorming.md +0 -8
- package/.omp/prompts/swarm.md +0 -8
- package/LICENSE +0 -126
- package/MARKETPLACE.md +0 -130
- package/README.md +0 -403
- package/bin/cli.js +0 -297
- package/config/claude-settings-patch.json +0 -10
- package/config/docker-compose.infra.yml +0 -23
- package/config/domain_packs/biopharma.json +0 -23
- package/config/domain_packs/legal.json +0 -19
- package/config/domain_packs/quant.json +0 -19
- package/config/mcp-research-servers.json +0 -33
- package/config/mcp_launcher.py +0 -153
- package/config/opencode-snippet.json +0 -156
- package/config/searxng_mcp.py +0 -92
- package/extensions/pi/index.js +0 -357
- package/hooks/hooks.json +0 -45
- package/install.sh +0 -473
- package/plugins/antigravity/README.md +0 -72
- package/plugins/antigravity/agents/alpha-thesis.md +0 -36
- package/plugins/antigravity/agents/beta-antithesis.md +0 -35
- package/plugins/antigravity/agents/brainstormer.md +0 -27
- package/plugins/antigravity/agents/code-auditor.md +0 -28
- package/plugins/antigravity/agents/darkharvester.md +0 -30
- package/plugins/antigravity/agents/epistemic-auditor.md +0 -28
- package/plugins/antigravity/agents/manager.md +0 -26
- package/plugins/antigravity/agents/oss-scout.md +0 -27
- package/plugins/antigravity/agents/programmer.md +0 -25
- package/plugins/antigravity/agents/qa-a.md +0 -22
- package/plugins/antigravity/agents/qa-b.md +0 -22
- package/plugins/antigravity/antigravity_hooks.py +0 -265
- package/plugins/antigravity/commands/audit.md +0 -11
- package/plugins/antigravity/commands/brainstorm.md +0 -9
- package/plugins/antigravity/commands/brainstorming.md +0 -10
- package/plugins/antigravity/commands/darkharvest.md +0 -12
- package/plugins/antigravity/commands/domainexpansion.md +0 -12
- package/plugins/antigravity/commands/factory.md +0 -14
- package/plugins/antigravity/commands/grill.md +0 -10
- package/plugins/antigravity/commands/scout.md +0 -11
- package/plugins/antigravity/commands/swarm-config.md +0 -9
- package/plugins/antigravity/commands/swarm.md +0 -12
- package/plugins/antigravity/hook_bus_bridge.js +0 -352
- package/plugins/antigravity/hooks.json +0 -44
- package/plugins/antigravity/mcp_config.json +0 -33
- package/plugins/antigravity/mcp_launcher.py +0 -58
- package/plugins/antigravity/plugin.json +0 -13
- package/plugins/antigravity/rules/AGENTS.md +0 -127
- package/plugins/antigravity/rules/epistemic-integrity.md +0 -16
- package/plugins/antigravity/skills/brainstorming/SKILL.md +0 -19
- package/plugins/antigravity/skills/code_audit/SKILL.md +0 -19
- package/plugins/antigravity/skills/darkharvest/SKILL.md +0 -19
- package/plugins/antigravity/skills/epistemic_search/SKILL.md +0 -19
- package/plugins/antigravity/skills/factory/SKILL.md +0 -19
- package/plugins/antigravity/skills/grilling/SKILL.md +0 -19
- package/plugins/antigravity/skills/oss_scout/SKILL.md +0 -19
- package/plugins/antigravity/skills/research_cache/SKILL.md +0 -19
- package/plugins/antigravity/skills/swarm_config/SKILL.md +0 -19
- package/plugins/codex/AGENTS.md.snippet +0 -10
- package/plugins/codex/README.md +0 -37
- package/plugins/codex/config.toml.snippet +0 -28
- package/plugins/codex/openai.yaml +0 -24
- package/plugins/codex/skills/brainstorming/SKILL.md +0 -19
- package/plugins/codex/skills/code_audit/SKILL.md +0 -19
- package/plugins/codex/skills/darkharvest/SKILL.md +0 -19
- package/plugins/codex/skills/epistemic_search/SKILL.md +0 -19
- package/plugins/codex/skills/factory/SKILL.md +0 -19
- package/plugins/codex/skills/grilling/SKILL.md +0 -19
- package/plugins/codex/skills/oss_scout/SKILL.md +0 -19
- package/plugins/codex/skills/research_cache/SKILL.md +0 -19
- package/plugins/codex/skills/swarm_config/SKILL.md +0 -19
- package/plugins/darkharvest/.claude-plugin/plugin.json +0 -15
- package/plugins/darkharvest/agents/harvest-proponent.md +0 -22
- package/plugins/darkharvest/agents/harvest-redteam.md +0 -20
- package/plugins/darkharvest/evals/teardown-verdict/graders/license-line.md +0 -6
- package/plugins/darkharvest/evals/teardown-verdict/graders/skill-fired.md +0 -5
- package/plugins/darkharvest/evals/teardown-verdict/prompt.md +0 -6
- package/plugins/darkharvest/skills/darkharvest/SKILL.md +0 -70
- package/plugins/darkharvest/skills/darkharvest/scripts/harvest.py +0 -289
- package/plugins/factory/.claude-plugin/plugin.json +0 -15
- package/plugins/factory/agents/factory-manager.md +0 -22
- package/plugins/factory/agents/programmer.md +0 -16
- package/plugins/factory/agents/qa-adversarial.md +0 -17
- package/plugins/factory/agents/qa-functional.md +0 -17
- package/plugins/factory/evals/gate-halt/graders/gates-first.md +0 -6
- package/plugins/factory/evals/gate-halt/graders/skill-fired.md +0 -5
- package/plugins/factory/evals/gate-halt/prompt.md +0 -6
- package/plugins/factory/skills/factory/SKILL.md +0 -61
- package/plugins/factory/skills/factory/scripts/factory.py +0 -300
- package/plugins/gemini/GEMINI.md +0 -16
- package/plugins/gemini/README.md +0 -20
- package/plugins/gemini/commands/audit.toml +0 -6
- package/plugins/gemini/commands/brainstorming.toml +0 -10
- package/plugins/gemini/commands/darkharvest.toml +0 -8
- package/plugins/gemini/commands/domainexpansion.toml +0 -7
- package/plugins/gemini/commands/factory.toml +0 -8
- package/plugins/gemini/commands/grill.toml +0 -6
- package/plugins/gemini/commands/scout.toml +0 -7
- package/plugins/gemini/commands/swarm-config.toml +0 -7
- package/plugins/gemini/commands/swarm.toml +0 -8
- package/plugins/gemini/gemini-extension.json +0 -38
- package/plugins/gemini/hooks/hooks.json +0 -11
- package/plugins/gemini/skills/brainstorming/SKILL.md +0 -19
- package/plugins/gemini/skills/code_audit/SKILL.md +0 -19
- package/plugins/gemini/skills/darkharvest/SKILL.md +0 -19
- package/plugins/gemini/skills/epistemic_search/SKILL.md +0 -19
- package/plugins/gemini/skills/factory/SKILL.md +0 -19
- package/plugins/gemini/skills/grilling/SKILL.md +0 -19
- package/plugins/gemini/skills/oss_scout/SKILL.md +0 -19
- package/plugins/gemini/skills/research_cache/SKILL.md +0 -19
- package/plugins/gemini/skills/swarm_config/SKILL.md +0 -19
- package/plugins/opencode/analysis-bridge.js +0 -620
- package/plugins/opencode/config-io.js +0 -1651
- package/plugins/opencode/dep-health.js +0 -1039
- package/plugins/opencode/hook-bus.js +0 -496
- package/plugins/opencode/index.js +0 -2992
- package/plugins/opencode/tui.js +0 -1551
- package/plugins/opencode/weight-baseline.json +0 -16
- package/plugins/opencode/weight-signals.js +0 -769
- package/plugins/research-cache/.claude-plugin/plugin.json +0 -15
- package/plugins/research-cache/skills/research_cache/SKILL.md +0 -36
- package/plugins/research-cache/skills/research_cache/__init__.py +0 -0
- package/plugins/research-cache/skills/research_cache/hasher.py +0 -302
- package/plugins/socratic-grilling/.claude-plugin/plugin.json +0 -15
- package/plugins/socratic-grilling/skills/grilling/SKILL.md +0 -61
- package/plugins/socratic-grilling/skills/grilling/__init__.py +0 -0
- package/plugins/socratic-grilling/skills/grilling/socratic_tree.py +0 -363
- package/prompts/agent_alpha_thesis.md +0 -70
- package/prompts/agent_beta_antithesis.md +0 -78
- package/prompts/agent_brainstormer.md +0 -143
- package/prompts/agent_code_auditor.md +0 -88
- package/prompts/agent_darkharvest.md +0 -140
- package/prompts/agent_oss_scout.md +0 -78
- package/prompts/antigravity_repo_factcheck.md +0 -143
- package/prompts/base_epistemic_system.md +0 -50
- package/prompts/epistemic_auditor.md +0 -74
- package/prompts/orchestrator.md +0 -70
- package/runner/__init__.py +0 -0
- 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__/darkharvest_claims.cpython-311.pyc +0 -0
- package/runner/__pycache__/errors.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__/path_safety.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__/preflight.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__/retrieval_log.cpython-311.pyc +0 -0
- package/runner/__pycache__/schema_validate.cpython-311.pyc +0 -0
- package/runner/__pycache__/schemas.cpython-311.pyc +0 -0
- package/runner/__pycache__/state_machine.cpython-311.pyc +0 -0
- package/runner/antigravity_hooks.py +0 -265
- package/runner/auctioneer.py +0 -169
- package/runner/auditor_engine.py +0 -711
- package/runner/claim_store.py +0 -417
- package/runner/claim_witness.py +0 -412
- package/runner/darkharvest_claims.py +0 -358
- package/runner/errors.py +0 -51
- package/runner/living_dossiers.py +0 -395
- package/runner/mcp_protocol.py +0 -188
- package/runner/mcp_server.py +0 -1447
- package/runner/path_safety.py +0 -62
- package/runner/pcrb.py +0 -290
- package/runner/pcrb_verify.py +0 -267
- package/runner/preflight.py +0 -1011
- package/runner/refinement.py +0 -580
- package/runner/research_swarm.py +0 -1848
- package/runner/retrieval_log.py +0 -90
- package/runner/schema_validate.py +0 -193
- package/runner/schemas.py +0 -630
- package/runner/state_machine.py +0 -463
- package/runner/tests/__pycache__/test_analysis_bridge.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_antigravity_plugin.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_auction_order.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_backends.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_claude_plugin.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_config_schema.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_contract_tooling.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_darkharvest_audit.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_dep_health.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_domain_packs.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_dossier_contract.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_factory.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_fleet_seam.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_frontier_concurrency.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_frontier_mirror_standalone.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_grounding.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_hardening_contract.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_hook_bus.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_living_dossiers.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_manifest_concurrency.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_mcp_server.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_nk_hardening.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_opencode_ux.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_opencode_v2_registrars.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_pcrb.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_phase08_waiver_reopens.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_refinement.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_search_anomaly.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_search_provider.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_search_provider_plugin.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_swarm.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_swarm_config.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_sweep_regressions.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_webcache.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_weight_signals.cpython-311.pyc +0 -0
- package/runner/tests/fixtures/auction_objective.json +0 -35
- package/runner/tests/fixtures/borderline_claims.json +0 -27
- package/runner/tests/fixtures/config_validation_cases.json +0 -276
- package/runner/tests/fixtures/ddg_anomaly_page.html +0 -176
- package/runner/tests/fixtures/ddg_results_page.html +0 -28
- package/runner/tests/fixtures/divergence_objectives.json +0 -31
- package/runner/tests/test_analysis_bridge.py +0 -450
- package/runner/tests/test_antigravity_plugin.py +0 -361
- package/runner/tests/test_auction_order.py +0 -173
- package/runner/tests/test_backends.py +0 -457
- package/runner/tests/test_bet1_spike.py +0 -95
- package/runner/tests/test_claim_store.py +0 -162
- package/runner/tests/test_claim_witness.py +0 -186
- package/runner/tests/test_claude_plugin.py +0 -170
- package/runner/tests/test_config_schema.py +0 -879
- package/runner/tests/test_contract_tooling.py +0 -312
- package/runner/tests/test_darkharvest_audit.py +0 -395
- package/runner/tests/test_dep_health.py +0 -595
- package/runner/tests/test_domain_packs.py +0 -217
- package/runner/tests/test_dossier_contract.py +0 -196
- package/runner/tests/test_factory.py +0 -258
- package/runner/tests/test_fleet_seam.py +0 -113
- package/runner/tests/test_frontier_concurrency.py +0 -288
- package/runner/tests/test_frontier_mirror_standalone.py +0 -156
- package/runner/tests/test_grounding.py +0 -183
- package/runner/tests/test_hardening_contract.py +0 -391
- package/runner/tests/test_hook_bus.py +0 -956
- package/runner/tests/test_living_dossiers.py +0 -204
- package/runner/tests/test_manifest_concurrency.py +0 -187
- package/runner/tests/test_mcp_server.py +0 -257
- package/runner/tests/test_nk_hardening.py +0 -1046
- package/runner/tests/test_opencode_ux.py +0 -2438
- package/runner/tests/test_opencode_v2_registrars.py +0 -2157
- package/runner/tests/test_pcrb.py +0 -240
- package/runner/tests/test_phase08_waiver_reopens.py +0 -539
- package/runner/tests/test_refinement.py +0 -255
- package/runner/tests/test_search_anomaly.py +0 -342
- package/runner/tests/test_search_provider.py +0 -1534
- package/runner/tests/test_search_provider_plugin.py +0 -401
- package/runner/tests/test_swarm.py +0 -444
- package/runner/tests/test_swarm_config.py +0 -520
- package/runner/tests/test_sweep_regressions.py +0 -453
- package/runner/tests/test_webcache.py +0 -271
- package/runner/tests/test_weight_signals.py +0 -401
- package/schemas/alpha_dossier.schema.json +0 -204
- package/schemas/audit_report.schema.json +0 -79
- package/schemas/beta_dossier.schema.json +0 -214
- package/schemas/config.schema.json +0 -311
- package/schemas/frontier.schema.json +0 -61
- package/schemas/manifest.schema.json +0 -49
- package/schemas/scope_manifest.schema.json +0 -47
- package/scripts/__pycache__/bet1_advisory_spike.cpython-311.pyc +0 -0
- package/scripts/__pycache__/build_adapters.cpython-311.pyc +0 -0
- package/scripts/__pycache__/check_docs.cpython-311.pyc +0 -0
- package/scripts/__pycache__/divergence_experiment.cpython-311.pyc +0 -0
- package/scripts/__pycache__/gen_schemas.cpython-311.pyc +0 -0
- package/scripts/auction_experiment.py +0 -188
- package/scripts/bet1_advisory_spike.py +0 -442
- package/scripts/build_adapters.py +0 -417
- package/scripts/check_docs.py +0 -66
- package/scripts/divergence_experiment.py +0 -214
- package/scripts/gen_schemas.py +0 -69
- package/skills/brainstorming/SKILL.md +0 -106
- package/skills/brainstorming/__init__.py +0 -1
- package/skills/brainstorming/scripts/brainstorm.py +0 -201
- package/skills/code_audit/SKILL.md +0 -45
- package/skills/darkharvest/SKILL.md +0 -70
- package/skills/darkharvest/scripts/harvest.py +0 -289
- package/skills/epistemic_search/SKILL.md +0 -67
- package/skills/epistemic_search/__init__.py +0 -1
- package/skills/epistemic_search/scripts/__pycache__/search.cpython-311.pyc +0 -0
- package/skills/epistemic_search/scripts/fetch.py +0 -156
- package/skills/epistemic_search/scripts/search.py +0 -551
- package/skills/epistemic_search/scripts/webcache.py +0 -339
- package/skills/factory/SKILL.md +0 -61
- package/skills/factory/scripts/factory.py +0 -300
- package/skills/grilling/SKILL.md +0 -61
- package/skills/grilling/__init__.py +0 -0
- package/skills/grilling/__pycache__/__init__.cpython-311.pyc +0 -0
- package/skills/grilling/__pycache__/socratic_tree.cpython-311.pyc +0 -0
- package/skills/grilling/socratic_tree.py +0 -363
- package/skills/oss_scout/SKILL.md +0 -49
- package/skills/research_cache/SKILL.md +0 -36
- package/skills/research_cache/__init__.py +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/research_cache/hasher.py +0 -302
- package/skills/swarm_config/SKILL.md +0 -178
- package/skills/swarm_config/__init__.py +0 -35
- package/skills/swarm_config/__pycache__/__init__.cpython-311.pyc +0 -0
- package/skills/swarm_config/__pycache__/configure.cpython-311.pyc +0 -0
- package/skills/swarm_config/configure.py +0 -1002
package/src/server.ts
ADDED
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
// Epistemic Swarm for OpenCode v2 (server plugin). Additive: registers our
|
|
2
|
+
// agents, tools, skills, commands, hooks and RPC through runtime transforms;
|
|
3
|
+
// writes no config files and never touches built-in agents or defaults.
|
|
4
|
+
import { readdir, readFile } from "node:fs/promises"
|
|
5
|
+
import path from "node:path"
|
|
6
|
+
import {
|
|
7
|
+
factoryLayout,
|
|
8
|
+
factorySummary,
|
|
9
|
+
formatReport,
|
|
10
|
+
git,
|
|
11
|
+
loadSkills,
|
|
12
|
+
readJson,
|
|
13
|
+
researchSourcesDir,
|
|
14
|
+
runGates,
|
|
15
|
+
} from "@heretek-ai/es-core"
|
|
16
|
+
import { Plugin } from "@opencode/plugin"
|
|
17
|
+
import { compileAgents } from "./agents.ts"
|
|
18
|
+
import { createFactoryContinuation } from "./continue.ts"
|
|
19
|
+
import { createHookBridge } from "./hooks.ts"
|
|
20
|
+
import { createPolicyHooks } from "./policy.ts"
|
|
21
|
+
import { createWebfetchCache, registerWebsearch } from "./research.ts"
|
|
22
|
+
import { createRpcHandlers } from "./rpc.ts"
|
|
23
|
+
import { EsRpc } from "./rpc-def.ts"
|
|
24
|
+
import { createRuntime, parseOptions } from "./runtime.ts"
|
|
25
|
+
import { createSessionHooks, createSpendTracker } from "./session.ts"
|
|
26
|
+
import { registerTools } from "./tools.ts"
|
|
27
|
+
|
|
28
|
+
export const PLUGIN_ID = "epistemic-swarm"
|
|
29
|
+
|
|
30
|
+
export default Plugin.define({
|
|
31
|
+
id: PLUGIN_ID,
|
|
32
|
+
async setup(ctx) {
|
|
33
|
+
const options = parseOptions(ctx.options as Record<string, unknown>)
|
|
34
|
+
const runtime = await createRuntime(ctx.location.directory, options)
|
|
35
|
+
|
|
36
|
+
// Agents: canonical registry → v2 agents with wildcard-deny scoping.
|
|
37
|
+
const servers = await ctx.mcp.list().then(
|
|
38
|
+
(page: any) => ((page?.data ?? page ?? []) as Array<{ name: string }>).map((server) => server.name),
|
|
39
|
+
() => [] as string[],
|
|
40
|
+
)
|
|
41
|
+
const agents = await compileAgents(runtime.options, servers)
|
|
42
|
+
await ctx.agent.transform((editor) => {
|
|
43
|
+
for (const compiled of agents)
|
|
44
|
+
editor.update(compiled.spec.id, (agent) => {
|
|
45
|
+
agent.mode = compiled.spec.mode
|
|
46
|
+
agent.hidden = compiled.spec.hidden
|
|
47
|
+
agent.description = compiled.spec.description
|
|
48
|
+
agent.system = compiled.system
|
|
49
|
+
agent.permissions = [...agent.permissions, ...compiled.permissions] as any
|
|
50
|
+
if (compiled.model) agent.model = compiled.model as any
|
|
51
|
+
})
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
// Skills: one shared SKILL.md tree, registered at runtime (no files written).
|
|
55
|
+
const skills = await loadSkills()
|
|
56
|
+
await ctx.skill.transform((editor) => {
|
|
57
|
+
for (const skill of skills)
|
|
58
|
+
editor.add({
|
|
59
|
+
id: skill.id,
|
|
60
|
+
name: skill.name,
|
|
61
|
+
description: skill.description,
|
|
62
|
+
path: skill.path,
|
|
63
|
+
content: skill.content,
|
|
64
|
+
} as any)
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
await ctx.tool.transform((editor) => registerTools(editor, runtime))
|
|
68
|
+
await ctx.websearch.transform((editor) => registerWebsearch(editor as any, runtime))
|
|
69
|
+
|
|
70
|
+
// Our policy runs first, so its denials win over any user hook.
|
|
71
|
+
const policy = createPolicyHooks(runtime)
|
|
72
|
+
const bridge = await createHookBridge(ctx as any, runtime, () => servers)
|
|
73
|
+
const sessionAgents = new Map<string, string | undefined>()
|
|
74
|
+
const agentOf = async (sessionID: string) => {
|
|
75
|
+
if (!sessionAgents.has(sessionID))
|
|
76
|
+
sessionAgents.set(
|
|
77
|
+
sessionID,
|
|
78
|
+
((await ctx.session.get({ sessionID } as any).catch(() => undefined)) as any)?.agent,
|
|
79
|
+
)
|
|
80
|
+
return sessionAgents.get(sessionID)
|
|
81
|
+
}
|
|
82
|
+
await ctx.tool.hook("execute.before", policy.before as any)
|
|
83
|
+
await ctx.tool.hook("execute.before", bridge.before as any)
|
|
84
|
+
await ctx.tool.hook("execute.after", policy.after as any)
|
|
85
|
+
await ctx.tool.hook("execute.after", createWebfetchCache(runtime) as any)
|
|
86
|
+
await ctx.tool.hook("execute.after", bridge.after as any)
|
|
87
|
+
await ctx.permission.hook("evaluate", policy.evaluate as any)
|
|
88
|
+
await ctx.permission.hook("evaluate", bridge.evaluate as any)
|
|
89
|
+
await ctx.shell.hook("create.before", policy.shellEnv)
|
|
90
|
+
await ctx.shell.hook("create.before", bridge.shell as any)
|
|
91
|
+
await ctx.session.hook("prompt", (async (event: any) =>
|
|
92
|
+
bridge.prompt(event, await agentOf(event.sessionID))) as any)
|
|
93
|
+
|
|
94
|
+
const session = createSessionHooks(runtime)
|
|
95
|
+
await ctx.session.hook("context", session.context as any)
|
|
96
|
+
await ctx.session.hook("context", bridge.context as any)
|
|
97
|
+
await ctx.session.hook("compaction", session.compaction as any)
|
|
98
|
+
const continuation = createFactoryContinuation(ctx as any, runtime)
|
|
99
|
+
|
|
100
|
+
// Human-only channel for the TUI (approvals, trust, resume).
|
|
101
|
+
let registration: { events: { emit: (...args: any[]) => Promise<void> } } | undefined
|
|
102
|
+
const notify = async () => {
|
|
103
|
+
const state = await runtime.factory.read()
|
|
104
|
+
await registration?.events
|
|
105
|
+
.emit("changed", { stage: state?.stage ?? "NONE", summary: factorySummary(state) })
|
|
106
|
+
.catch(() => undefined)
|
|
107
|
+
}
|
|
108
|
+
registration = await ctx.rpc.register(EsRpc, createRpcHandlers(runtime, notify, bridge.engine) as any)
|
|
109
|
+
|
|
110
|
+
await ctx.command.transform((editor) => {
|
|
111
|
+
editor.add({
|
|
112
|
+
name: "grill",
|
|
113
|
+
description: "Grill an idea until the design and spend ceiling are settled (Epistemic Swarm)",
|
|
114
|
+
execute: async ({ sessionID, prompt, delivery }) => {
|
|
115
|
+
await ctx.session.switchAgent({ sessionID, agent: "grill" } as any)
|
|
116
|
+
await ctx.session.prompt({
|
|
117
|
+
...prompt,
|
|
118
|
+
sessionID,
|
|
119
|
+
text: prompt.text?.trim() ? `Grill me on: ${prompt.text}` : "Start grilling me on my idea.",
|
|
120
|
+
delivery,
|
|
121
|
+
} as any)
|
|
122
|
+
},
|
|
123
|
+
})
|
|
124
|
+
editor.add({
|
|
125
|
+
name: "brainstorm",
|
|
126
|
+
description: "Fan out divergent lenses on an idea and return a diversified shortlist (Epistemic Swarm)",
|
|
127
|
+
execute: async ({ sessionID, prompt, delivery }) => {
|
|
128
|
+
await ctx.session.switchAgent({ sessionID, agent: "brainstormer" } as any)
|
|
129
|
+
await ctx.session.prompt({
|
|
130
|
+
...prompt,
|
|
131
|
+
sessionID,
|
|
132
|
+
text: prompt.text?.trim()
|
|
133
|
+
? `Brainstorm: ${prompt.text}`
|
|
134
|
+
: "Ask me for the idea to brainstorm (one sentence), then run the lens fan-out.",
|
|
135
|
+
delivery,
|
|
136
|
+
} as any)
|
|
137
|
+
},
|
|
138
|
+
})
|
|
139
|
+
editor.add({
|
|
140
|
+
name: "harvest",
|
|
141
|
+
description: "Tear down competitor projects: licences, feature matrix, clean-room specs (Epistemic Swarm)",
|
|
142
|
+
execute: async ({ sessionID, prompt, delivery }) => {
|
|
143
|
+
await ctx.session.switchAgent({ sessionID, agent: "harvester" } as any)
|
|
144
|
+
await ctx.session.prompt({
|
|
145
|
+
...prompt,
|
|
146
|
+
sessionID,
|
|
147
|
+
text: prompt.text?.trim()
|
|
148
|
+
? `Darkharvest: ${prompt.text}`
|
|
149
|
+
: "Ask me for the teardown objective and the candidate projects, then run the harvest.",
|
|
150
|
+
delivery,
|
|
151
|
+
} as any)
|
|
152
|
+
},
|
|
153
|
+
})
|
|
154
|
+
editor.add({
|
|
155
|
+
name: "design",
|
|
156
|
+
description: "Interview me into a design system: tokens, contrast gates, style guide (Epistemic Swarm)",
|
|
157
|
+
execute: async ({ sessionID, prompt, delivery }) => {
|
|
158
|
+
await ctx.session.switchAgent({ sessionID, agent: "designer" } as any)
|
|
159
|
+
await ctx.session.prompt({
|
|
160
|
+
...prompt,
|
|
161
|
+
sessionID,
|
|
162
|
+
text: prompt.text?.trim()
|
|
163
|
+
? `Run the design interview. Product: ${prompt.text}`
|
|
164
|
+
: "Ask me for the product name and start the design interview, one question at a time.",
|
|
165
|
+
delivery,
|
|
166
|
+
} as any)
|
|
167
|
+
},
|
|
168
|
+
})
|
|
169
|
+
editor.add({
|
|
170
|
+
name: "factory",
|
|
171
|
+
description: "Drive the build factory from its current stage (Epistemic Swarm)",
|
|
172
|
+
execute: async ({ sessionID, prompt, delivery }) => {
|
|
173
|
+
await ctx.session.switchAgent({ sessionID, agent: "factory" } as any)
|
|
174
|
+
const state = await runtime.factory.read()
|
|
175
|
+
await ctx.session.prompt({
|
|
176
|
+
...prompt,
|
|
177
|
+
sessionID,
|
|
178
|
+
text: `${factorySummary(state)}\nContinue the factory run from its current stage.${prompt.text?.trim() ? `\nHuman note: ${prompt.text}` : ""}`,
|
|
179
|
+
delivery,
|
|
180
|
+
} as any)
|
|
181
|
+
},
|
|
182
|
+
})
|
|
183
|
+
editor.add({
|
|
184
|
+
name: "gates",
|
|
185
|
+
description: "Run the mechanical gates on changed files (Epistemic Swarm)",
|
|
186
|
+
execute: async ({ sessionID }) => {
|
|
187
|
+
const changed = (await git(runtime.root, ["status", "--porcelain=v1", "-uall"], { allowFail: true })).stdout
|
|
188
|
+
.split("\n")
|
|
189
|
+
.filter(Boolean)
|
|
190
|
+
.map((line) => line.slice(3).split(" -> ").at(-1)!)
|
|
191
|
+
const report = await runGates({
|
|
192
|
+
root: runtime.root,
|
|
193
|
+
scope: changed.length ? "touched" : "full",
|
|
194
|
+
touched: changed,
|
|
195
|
+
stateDir: runtime.stateDir,
|
|
196
|
+
})
|
|
197
|
+
await ctx.session.synthetic({ sessionID, text: formatReport(report) } as any)
|
|
198
|
+
},
|
|
199
|
+
})
|
|
200
|
+
editor.add({
|
|
201
|
+
name: "lsp",
|
|
202
|
+
description: "Language servers: configured, available and running (Epistemic Swarm)",
|
|
203
|
+
execute: async ({ sessionID }) => {
|
|
204
|
+
const status = await runtime.lsp.status()
|
|
205
|
+
const settings = await runtime.lsp.settings()
|
|
206
|
+
const lines = [status.enabled ? "LSP is on." : "LSP is disabled (lsp: false)."]
|
|
207
|
+
for (const server of settings.servers) {
|
|
208
|
+
const command = await runtime.lsp.command(server, runtime.root)
|
|
209
|
+
const running = status.running.filter((item) => item.id === server.id)
|
|
210
|
+
lines.push(
|
|
211
|
+
`${server.id} [${server.extensions.join(" ")}]: ${Array.isArray(command) ? `available (${command.join(" ")})` : command.unavailable}${running.length ? ` · running for ${running.length} root(s)` : ""}`,
|
|
212
|
+
)
|
|
213
|
+
}
|
|
214
|
+
lines.push(...status.diagnostics.map((item) => `! ${item}`))
|
|
215
|
+
await ctx.session.synthetic({ sessionID, text: lines.join("\n") } as any)
|
|
216
|
+
},
|
|
217
|
+
})
|
|
218
|
+
editor.add({
|
|
219
|
+
name: "hooks",
|
|
220
|
+
description: "Show the hook bridge: sources, handlers, trust and diagnostics (Epistemic Swarm)",
|
|
221
|
+
execute: async ({ sessionID }) => {
|
|
222
|
+
await bridge.engine.refresh()
|
|
223
|
+
const status = bridge.engine.status()
|
|
224
|
+
const trust =
|
|
225
|
+
status.projectHandlers === 0
|
|
226
|
+
? "nothing to trust"
|
|
227
|
+
: status.trusted
|
|
228
|
+
? "trusted"
|
|
229
|
+
: "NOT trusted: run /es-trust or `es trust`"
|
|
230
|
+
const lines = [
|
|
231
|
+
`Hook bridge: ${status.handlers} handler(s), ${status.projectHandlers} from the project (${trust}).`,
|
|
232
|
+
...status.projectLines,
|
|
233
|
+
...status.diagnostics.map((item) => `! ${item}`),
|
|
234
|
+
...bridge.engine.recent.slice(-10).map((item) => `recent error: ${item}`),
|
|
235
|
+
"Stop hooks are emulated after the turn ends (advisory for plain chat).",
|
|
236
|
+
]
|
|
237
|
+
await ctx.session.synthetic({ sessionID, text: lines.join("\n") } as any)
|
|
238
|
+
},
|
|
239
|
+
})
|
|
240
|
+
editor.add({
|
|
241
|
+
name: "status",
|
|
242
|
+
description: "Show the factory state (Epistemic Swarm)",
|
|
243
|
+
execute: async ({ sessionID }) => {
|
|
244
|
+
await ctx.session.synthetic({ sessionID, text: factorySummary(await runtime.factory.read()) } as any)
|
|
245
|
+
},
|
|
246
|
+
})
|
|
247
|
+
editor.add({
|
|
248
|
+
name: "config",
|
|
249
|
+
description: "Show the effective Epistemic Swarm config and where it came from (Epistemic Swarm)",
|
|
250
|
+
execute: async ({ sessionID }) => {
|
|
251
|
+
const lines = [
|
|
252
|
+
runtime.configSources.length
|
|
253
|
+
? `Layers: ${runtime.configSources.join(" → ")} → plugin options`
|
|
254
|
+
: "Layers: defaults only (no config files)",
|
|
255
|
+
JSON.stringify(runtime.config, null, 2),
|
|
256
|
+
]
|
|
257
|
+
await ctx.session.synthetic({ sessionID, text: lines.join("\n") } as any)
|
|
258
|
+
},
|
|
259
|
+
})
|
|
260
|
+
editor.add({
|
|
261
|
+
name: "research",
|
|
262
|
+
description: "Research stage: report, audit coverage and cached sources (Epistemic Swarm)",
|
|
263
|
+
execute: async ({ sessionID }) => {
|
|
264
|
+
const layout = factoryLayout(runtime.root)
|
|
265
|
+
const report = await readFile(layout.researchReport, "utf8").catch(() => undefined)
|
|
266
|
+
const coverage = await readJson<{
|
|
267
|
+
claims?: number
|
|
268
|
+
grounded?: number
|
|
269
|
+
untagged?: number
|
|
270
|
+
ungrounded?: number
|
|
271
|
+
malformed?: number
|
|
272
|
+
sources?: number
|
|
273
|
+
passed?: boolean
|
|
274
|
+
}>(path.join(layout.research, "coverage.json")).catch(() => undefined)
|
|
275
|
+
const sources = (await readdir(researchSourcesDir(runtime.root)).catch(() => [])).filter((file) =>
|
|
276
|
+
file.endsWith(".md"),
|
|
277
|
+
)
|
|
278
|
+
const lines = [
|
|
279
|
+
report === undefined
|
|
280
|
+
? "No research report yet (.factory/research/REPORT.md)."
|
|
281
|
+
: `Report: ${report.length} characters in .factory/research/REPORT.md.`,
|
|
282
|
+
coverage
|
|
283
|
+
? `Audit: ${coverage.grounded ?? 0}/${coverage.claims ?? 0} claims grounded (untagged ${coverage.untagged ?? 0}, ungrounded ${coverage.ungrounded ?? 0}, malformed ${coverage.malformed ?? 0}); cited sources ${coverage.sources ?? 0}; passed ${coverage.passed ? "yes" : "no"}.`
|
|
284
|
+
: "No coverage.json yet (es_research_complete writes it).",
|
|
285
|
+
`Cached sources: ${sources.length}.`,
|
|
286
|
+
]
|
|
287
|
+
await ctx.session.synthetic({ sessionID, text: lines.join("\n") } as any)
|
|
288
|
+
},
|
|
289
|
+
})
|
|
290
|
+
})
|
|
291
|
+
|
|
292
|
+
// Spend: per-step host cost for factory-agent sessions (estimated from tokens when cost is 0).
|
|
293
|
+
const track = createSpendTracker(runtime, agentOf)
|
|
294
|
+
const abort = new AbortController()
|
|
295
|
+
void (async () => {
|
|
296
|
+
try {
|
|
297
|
+
for await (const event of ctx.event.subscribe({ signal: abort.signal }) as AsyncIterable<any>) {
|
|
298
|
+
await track(event).catch(() => undefined)
|
|
299
|
+
await bridge.onEvent(event, agentOf).catch(() => undefined)
|
|
300
|
+
await continuation(event, agentOf).catch(() => undefined)
|
|
301
|
+
}
|
|
302
|
+
} catch {
|
|
303
|
+
// stream closed on unload
|
|
304
|
+
}
|
|
305
|
+
})()
|
|
306
|
+
return async () => {
|
|
307
|
+
abort.abort()
|
|
308
|
+
await runtime.lsp.stopAll()
|
|
309
|
+
}
|
|
310
|
+
},
|
|
311
|
+
})
|
package/src/session.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// Session-level integration: factory-state injection for factory agents,
|
|
2
|
+
// per-agent es_* tool visibility (without touching built-in agents' config),
|
|
3
|
+
// compaction that preserves the factory state, and spend accounting from
|
|
4
|
+
// the host's per-step cost.
|
|
5
|
+
import { AGENTS, ALL_ES_TOOLS, factorySummary } from "@heretek-ai/es-core"
|
|
6
|
+
import { visibleEsTools } from "./agents.ts"
|
|
7
|
+
import type { Runtime } from "./runtime.ts"
|
|
8
|
+
|
|
9
|
+
const FACTORY_AGENTS = new Set(AGENTS.map((agent) => agent.id))
|
|
10
|
+
|
|
11
|
+
export function createSessionHooks(runtime: Runtime) {
|
|
12
|
+
const context = async (event: { agent: string; system: any[]; tools: Record<string, unknown> }) => {
|
|
13
|
+
const visible = new Set(visibleEsTools(event.agent))
|
|
14
|
+
for (const name of ALL_ES_TOOLS) if (!visible.has(name)) delete event.tools[name]
|
|
15
|
+
if (!FACTORY_AGENTS.has(event.agent)) return
|
|
16
|
+
const state = await runtime.factory.read().catch(() => undefined)
|
|
17
|
+
event.system.push({ type: "text", text: factorySummary(state) })
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const compaction = async (event: { agent: string; system: any[] }) => {
|
|
21
|
+
if (!FACTORY_AGENTS.has(event.agent)) return
|
|
22
|
+
const state = await runtime.factory.read().catch(() => undefined)
|
|
23
|
+
event.system.push({
|
|
24
|
+
type: "text",
|
|
25
|
+
text: `Preserve this factory state verbatim at the top of your summary; the run continues from it:\n${factorySummary(state)}`,
|
|
26
|
+
})
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return { context, compaction }
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface StepEnded {
|
|
33
|
+
readonly type: string
|
|
34
|
+
readonly data?: {
|
|
35
|
+
sessionID?: string
|
|
36
|
+
cost?: number
|
|
37
|
+
tokens?: { input?: number; output?: number; reasoning?: number }
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Accumulate factory spend from session.step.ended events of factory-agent sessions. */
|
|
42
|
+
export function createSpendTracker(runtime: Runtime, lookupAgent: (sessionID: string) => Promise<string | undefined>) {
|
|
43
|
+
const agents = new Map<string, string | undefined>()
|
|
44
|
+
const inputPerM = runtime.options.estimate?.inputPerM ?? 3
|
|
45
|
+
const outputPerM = runtime.options.estimate?.outputPerM ?? 15
|
|
46
|
+
return async (event: StepEnded) => {
|
|
47
|
+
if (event.type !== "session.step.ended" || !event.data?.sessionID) return
|
|
48
|
+
const sessionID = event.data.sessionID
|
|
49
|
+
if (!agents.has(sessionID)) agents.set(sessionID, await lookupAgent(sessionID).catch(() => undefined))
|
|
50
|
+
if (!FACTORY_AGENTS.has(agents.get(sessionID) ?? "")) return
|
|
51
|
+
const cost = Number(event.data.cost ?? 0)
|
|
52
|
+
if (cost > 0) {
|
|
53
|
+
await runtime.factory.recordSpend(cost, false)
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
const tokens = event.data.tokens ?? {}
|
|
57
|
+
const estimate =
|
|
58
|
+
((tokens.input ?? 0) * inputPerM + ((tokens.output ?? 0) + (tokens.reasoning ?? 0)) * outputPerM) / 1_000_000
|
|
59
|
+
if (estimate > 0) await runtime.factory.recordSpend(estimate, true)
|
|
60
|
+
}
|
|
61
|
+
}
|
package/src/tools.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// Epistemic Swarm tools for OpenCode v2: the harness-neutral core operations,
|
|
2
|
+
// registered as direct (codemode:false) tools, each under its own permission
|
|
3
|
+
// action so per-agent rules can hide it. Refusals become model-facing tool errors.
|
|
4
|
+
import {
|
|
5
|
+
brainstormTools,
|
|
6
|
+
designTools,
|
|
7
|
+
esTools,
|
|
8
|
+
harvestTools,
|
|
9
|
+
lspTools,
|
|
10
|
+
pendingApprovals,
|
|
11
|
+
researchTools,
|
|
12
|
+
} from "@heretek-ai/es-core"
|
|
13
|
+
import { Error as ToolError } from "@opencode/plugin/promise/tool"
|
|
14
|
+
import type { Runtime } from "./runtime.ts"
|
|
15
|
+
|
|
16
|
+
export function registerTools(editor: { add(tool: any): void }, runtime: Runtime) {
|
|
17
|
+
const lsp = lspTools({ root: runtime.root, manager: runtime.lsp, policy: () => runtime.policy() })
|
|
18
|
+
const research = researchTools({
|
|
19
|
+
root: runtime.root,
|
|
20
|
+
policy: () => runtime.policy(),
|
|
21
|
+
...(runtime.options.searchProvider ? { provider: runtime.options.searchProvider } : {}),
|
|
22
|
+
})
|
|
23
|
+
const brainstorm = brainstormTools({
|
|
24
|
+
root: runtime.root,
|
|
25
|
+
...(runtime.config.embeddings ? { embeddings: runtime.config.embeddings } : {}),
|
|
26
|
+
})
|
|
27
|
+
const harvest = harvestTools({
|
|
28
|
+
root: runtime.root,
|
|
29
|
+
whitelist: runtime.config.licenseWhitelist,
|
|
30
|
+
stateDir: runtime.stateDir,
|
|
31
|
+
})
|
|
32
|
+
const design = designTools({ root: runtime.root })
|
|
33
|
+
for (const def of [
|
|
34
|
+
...esTools({ ...runtime, lsp: runtime.lsp }),
|
|
35
|
+
...lsp,
|
|
36
|
+
...research,
|
|
37
|
+
...brainstorm,
|
|
38
|
+
...harvest,
|
|
39
|
+
...design,
|
|
40
|
+
])
|
|
41
|
+
editor.add({
|
|
42
|
+
name: def.name,
|
|
43
|
+
description: def.description,
|
|
44
|
+
input: def.input,
|
|
45
|
+
// es_* tools each get their own action; LSP tools share "lsp" (navigation) and "lsp_rename" (writes).
|
|
46
|
+
options: {
|
|
47
|
+
codemode: false,
|
|
48
|
+
permission: def.name.startsWith("lsp_") ? (def.name === "lsp_rename" ? "lsp_rename" : "lsp") : def.name,
|
|
49
|
+
},
|
|
50
|
+
execute: async (input: unknown, context: { agent: string; sessionID: string; signal: AbortSignal }) => {
|
|
51
|
+
try {
|
|
52
|
+
return { content: await def.execute(input ?? {}, context) }
|
|
53
|
+
} catch (error) {
|
|
54
|
+
if (error instanceof ToolError) throw error
|
|
55
|
+
throw new ToolError({ message: error instanceof Error ? error.message : String(error) })
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export { pendingApprovals }
|
package/src/tui.tsx
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
// Epistemic Swarm TUI plugin: the human-only dialogs. Approvals, trust and
|
|
2
|
+
// resume happen here (or in the `es` CLI), never through an agent tool. Each
|
|
3
|
+
// dialog shows a server-computed preview; confirming redeems that preview's
|
|
4
|
+
// token, so what the human saw is exactly what gets signed.
|
|
5
|
+
import { userInfo } from "node:os"
|
|
6
|
+
import { Plugin } from "@opencode/plugin/tui"
|
|
7
|
+
import { registerPanels } from "./panels.tsx"
|
|
8
|
+
import { EsRpc } from "./rpc-def.ts"
|
|
9
|
+
|
|
10
|
+
type Preview = { ok: boolean; title: string; lines: string[]; problems: string[]; token?: string }
|
|
11
|
+
|
|
12
|
+
export default Plugin.define({
|
|
13
|
+
id: "epistemic-swarm.tui",
|
|
14
|
+
setup(context) {
|
|
15
|
+
const rpc = context.client.rpc(EsRpc) as any
|
|
16
|
+
const location = () => context.location ?? context.data.location.default()
|
|
17
|
+
const call = (method: string, input: unknown = {}) => rpc[method](input, { location: location() })
|
|
18
|
+
const stopPanels = registerPanels(context, call, (listener) => rpc.events.on("changed", () => listener()))
|
|
19
|
+
const user = userInfo().username
|
|
20
|
+
const toast = (message: string, variant: "success" | "error" | "info" = "info") =>
|
|
21
|
+
context.ui.toast.show({ title: "Epistemic Swarm", message, variant })
|
|
22
|
+
|
|
23
|
+
const confirm = async (preview: Preview, label: string) => {
|
|
24
|
+
if (!preview.ok || !preview.token) {
|
|
25
|
+
await context.ui.dialog.alert({
|
|
26
|
+
title: preview.title,
|
|
27
|
+
message: [...preview.problems, ...preview.lines].join("\n"),
|
|
28
|
+
})
|
|
29
|
+
return undefined
|
|
30
|
+
}
|
|
31
|
+
const ok = await context.ui.dialog.confirm({
|
|
32
|
+
title: preview.title,
|
|
33
|
+
message: preview.lines.join("\n"),
|
|
34
|
+
label: { confirm: label, cancel: "Cancel" },
|
|
35
|
+
})
|
|
36
|
+
return ok ? preview.token : undefined
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const guarded = (fn: (input?: string) => Promise<void>) => async (input?: string) => {
|
|
40
|
+
try {
|
|
41
|
+
await fn(input)
|
|
42
|
+
} catch (error: any) {
|
|
43
|
+
toast(error?.data?.reason ?? error?.message ?? String(error), "error")
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const approve = guarded(async (input) => {
|
|
48
|
+
const status = await call("status")
|
|
49
|
+
const stage =
|
|
50
|
+
input?.trim() ||
|
|
51
|
+
(status.pending.length === 1
|
|
52
|
+
? status.pending[0]
|
|
53
|
+
: await context.ui.dialog.select({
|
|
54
|
+
title: "Approve which checkpoint?",
|
|
55
|
+
options: [
|
|
56
|
+
{ title: "Frontier (design tree + spend ceiling)", value: "frontier" },
|
|
57
|
+
{ title: "Spec (roadmap + every GOAL.md)", value: "spec" },
|
|
58
|
+
],
|
|
59
|
+
}))
|
|
60
|
+
if (stage !== "frontier" && stage !== "spec") return
|
|
61
|
+
const token = await confirm(await call("previewApproval", { stage }), "Approve")
|
|
62
|
+
if (!token) return
|
|
63
|
+
toast((await call("approve", { stage, user, token })).message, "success")
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
const trust = guarded(async () => {
|
|
67
|
+
const token = await confirm(await call("previewTrust"), "Trust")
|
|
68
|
+
if (!token) return
|
|
69
|
+
toast((await call("trust", { user, token })).message, "success")
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
const resume = guarded(async () => {
|
|
73
|
+
const preview: Preview = await call("previewResume")
|
|
74
|
+
const token = await confirm(preview, "Resume")
|
|
75
|
+
if (!token) return
|
|
76
|
+
const drift = preview.lines.some((line) => line.startsWith("Control-file drift"))
|
|
77
|
+
let raiseCeilingUSD: number | undefined
|
|
78
|
+
if (/spend ceiling/i.test(preview.lines[0] ?? "")) {
|
|
79
|
+
const raised = await context.ui.dialog.prompt({ title: "New spend ceiling (USD)", placeholder: "e.g. 50" })
|
|
80
|
+
raiseCeilingUSD = raised ? Number(raised) : undefined
|
|
81
|
+
}
|
|
82
|
+
const extendRuntime = /runtime cap/i.test(preview.lines[0] ?? "")
|
|
83
|
+
const result = await call("resume", {
|
|
84
|
+
user,
|
|
85
|
+
token,
|
|
86
|
+
...(drift ? { acceptControlDrift: true } : {}),
|
|
87
|
+
...(raiseCeilingUSD ? { raiseCeilingUSD } : {}),
|
|
88
|
+
...(extendRuntime ? { extendRuntime: true } : {}),
|
|
89
|
+
})
|
|
90
|
+
toast(result.message, "success")
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
const lspInstall = guarded(async (input) => {
|
|
94
|
+
const id =
|
|
95
|
+
input?.trim() ||
|
|
96
|
+
(await context.ui.dialog.prompt({
|
|
97
|
+
title: "Install which language server?",
|
|
98
|
+
placeholder: "typescript, pyright",
|
|
99
|
+
}))
|
|
100
|
+
if (!id) return
|
|
101
|
+
const token = await confirm(await call("previewLspInstall", { id }), "Install")
|
|
102
|
+
if (!token) return
|
|
103
|
+
toast((await call("lspInstall", { id, user, token })).message, "success")
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
const status = guarded(async () => {
|
|
107
|
+
const result = await call("status")
|
|
108
|
+
await context.ui.dialog.alert({
|
|
109
|
+
title: "Factory",
|
|
110
|
+
message: result.summary.replace(/<\/?factory-state>/g, "").trim(),
|
|
111
|
+
})
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
context.keymap.layer(() => ({
|
|
115
|
+
mode: "global",
|
|
116
|
+
commands: [
|
|
117
|
+
{
|
|
118
|
+
id: "es.approve",
|
|
119
|
+
title: "Epistemic Swarm: approve a checkpoint",
|
|
120
|
+
group: "Epistemic Swarm",
|
|
121
|
+
palette: true,
|
|
122
|
+
slash: { name: "es-approve", arguments: true },
|
|
123
|
+
run: approve,
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
id: "es.trust",
|
|
127
|
+
title: "Epistemic Swarm: trust gate commands",
|
|
128
|
+
group: "Epistemic Swarm",
|
|
129
|
+
palette: true,
|
|
130
|
+
slash: { name: "es-trust" },
|
|
131
|
+
run: trust,
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
id: "es.resume",
|
|
135
|
+
title: "Epistemic Swarm: resume a halted factory",
|
|
136
|
+
group: "Epistemic Swarm",
|
|
137
|
+
palette: true,
|
|
138
|
+
slash: { name: "es-resume" },
|
|
139
|
+
run: resume,
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
id: "es.status",
|
|
143
|
+
title: "Epistemic Swarm: factory status",
|
|
144
|
+
group: "Epistemic Swarm",
|
|
145
|
+
palette: true,
|
|
146
|
+
slash: { name: "es-status" },
|
|
147
|
+
run: status,
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
id: "es.lsp.install",
|
|
151
|
+
title: "Epistemic Swarm: install a language server",
|
|
152
|
+
group: "Epistemic Swarm",
|
|
153
|
+
palette: true,
|
|
154
|
+
slash: { name: "es-lsp-install", arguments: true },
|
|
155
|
+
run: lspInstall,
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
id: "es.panel.factory",
|
|
159
|
+
title: "Epistemic Swarm: factory dashboard",
|
|
160
|
+
group: "Epistemic Swarm",
|
|
161
|
+
palette: true,
|
|
162
|
+
slash: { name: "es-factory" },
|
|
163
|
+
run: () => {
|
|
164
|
+
context.ui.panel.open("factory", { presentation: "fullscreen" })
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
id: "es.panel.lsp",
|
|
169
|
+
title: "Epistemic Swarm: language server panel",
|
|
170
|
+
group: "Epistemic Swarm",
|
|
171
|
+
palette: true,
|
|
172
|
+
slash: { name: "es-lsp-panel" },
|
|
173
|
+
run: () => {
|
|
174
|
+
context.ui.panel.open("lsp", { presentation: "fullscreen" })
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
id: "es.panel.hooks",
|
|
179
|
+
title: "Epistemic Swarm: hook inspector",
|
|
180
|
+
group: "Epistemic Swarm",
|
|
181
|
+
palette: true,
|
|
182
|
+
slash: { name: "es-hooks" },
|
|
183
|
+
run: () => {
|
|
184
|
+
context.ui.panel.open("hooks", { presentation: "fullscreen" })
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
id: "es.panel.brainstorm",
|
|
189
|
+
title: "Epistemic Swarm: brainstorm board",
|
|
190
|
+
group: "Epistemic Swarm",
|
|
191
|
+
palette: true,
|
|
192
|
+
slash: { name: "es-brainstorm" },
|
|
193
|
+
run: () => {
|
|
194
|
+
context.ui.panel.open("brainstorm", { presentation: "fullscreen" })
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
],
|
|
198
|
+
}))
|
|
199
|
+
|
|
200
|
+
const stop = rpc.events.on("changed", (event: any) => toast(`Factory → ${event.data.stage}`))
|
|
201
|
+
return () => {
|
|
202
|
+
stopPanels()
|
|
203
|
+
stop()
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
})
|
package/tui.tsx
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "./src/tui.tsx"
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: brainstorming
|
|
3
|
-
description: >-
|
|
4
|
-
Lateral creative brainstorming and divergent ideation skill. Use when exploring what-if features, lateral architectures, speculative product directions, or when user invokes /brainstorming. Generates novel feature vectors, paradigm inversions, and falsifiable spike hypotheses instead of bug fixes.
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Brainstorming (thin adapter stub)
|
|
8
|
-
|
|
9
|
-
This file is a POINTER, not the implementation. It exists so harness skill
|
|
10
|
-
discovery finds an entry; the real skill lives in the IUMBTEMS repo.
|
|
11
|
-
|
|
12
|
-
- Canonical prose & scripts: `skills/brainstorming/`
|
|
13
|
-
- Canonical programmatic surface: `python3 runner/mcp_server.py` (stdio MCP),
|
|
14
|
-
or one-shot: `python3 runner/mcp_server.py call <tool> '{...json...}'`
|
|
15
|
-
- MCP tools for this skill: `iumbtems_brainstorm`
|
|
16
|
-
|
|
17
|
-
Epistemic rules apply regardless of harness: tag claims as
|
|
18
|
-
`[VERIFIED: <hash>]`, `[INFERRED: <reasoning>]`, `[HYPOTHESIS: <test>]`, or
|
|
19
|
-
`[NEGATIVE_KNOWLEDGE: <query>]`. Writes go only to `.research/`.
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: code-audit
|
|
3
|
-
description: >-
|
|
4
|
-
Deep dialectic codebase auditing skill. Deploys architectural thesis vs adversarial red-team antithesis to discover security vulnerabilities, race conditions, resource leaks, and architectural flaws with exact line-level proof.
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# Code Audit (thin adapter stub)
|
|
8
|
-
|
|
9
|
-
This file is a POINTER, not the implementation. It exists so harness skill
|
|
10
|
-
discovery finds an entry; the real skill lives in the IUMBTEMS repo.
|
|
11
|
-
|
|
12
|
-
- Canonical prose & scripts: `skills/code_audit/`
|
|
13
|
-
- Canonical programmatic surface: `python3 runner/mcp_server.py` (stdio MCP),
|
|
14
|
-
or one-shot: `python3 runner/mcp_server.py call <tool> '{...json...}'`
|
|
15
|
-
- MCP tools for this skill: `iumbtems_code_audit`
|
|
16
|
-
|
|
17
|
-
Epistemic rules apply regardless of harness: tag claims as
|
|
18
|
-
`[VERIFIED: <hash>]`, `[INFERRED: <reasoning>]`, `[HYPOTHESIS: <test>]`, or
|
|
19
|
-
`[NEGATIVE_KNOWLEDGE: <query>]`. Writes go only to `.research/`.
|