@heretek-ai/epistemic-swarm 0.7.13 → 0.7.15

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 (84) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +6 -2
  3. package/package.json +2 -1
  4. package/plugins/factory/skills/factory/scripts/factory.py +68 -14
  5. package/plugins/opencode/index.js +21 -0
  6. package/plugins/socratic-grilling/skills/grilling/SKILL.md +14 -1
  7. package/plugins/socratic-grilling/skills/grilling/socratic_tree.py +88 -16
  8. package/runner/__pycache__/__init__.cpython-311.pyc +0 -0
  9. package/runner/__pycache__/auctioneer.cpython-311.pyc +0 -0
  10. package/runner/__pycache__/auditor_engine.cpython-311.pyc +0 -0
  11. package/runner/__pycache__/claim_store.cpython-311.pyc +0 -0
  12. package/runner/__pycache__/claim_witness.cpython-311.pyc +0 -0
  13. package/runner/__pycache__/darkharvest_claims.cpython-311.pyc +0 -0
  14. package/runner/__pycache__/errors.cpython-311.pyc +0 -0
  15. package/runner/__pycache__/living_dossiers.cpython-311.pyc +0 -0
  16. package/runner/__pycache__/mcp_protocol.cpython-311.pyc +0 -0
  17. package/runner/__pycache__/mcp_server.cpython-311.pyc +0 -0
  18. package/runner/__pycache__/path_safety.cpython-311.pyc +0 -0
  19. package/runner/__pycache__/pcrb.cpython-311.pyc +0 -0
  20. package/runner/__pycache__/pcrb_verify.cpython-311.pyc +0 -0
  21. package/runner/__pycache__/preflight.cpython-311.pyc +0 -0
  22. package/runner/__pycache__/refinement.cpython-311.pyc +0 -0
  23. package/runner/__pycache__/research_swarm.cpython-311.pyc +0 -0
  24. package/runner/__pycache__/retrieval_log.cpython-311.pyc +0 -0
  25. package/runner/__pycache__/schema_validate.cpython-311.pyc +0 -0
  26. package/runner/__pycache__/schemas.cpython-311.pyc +0 -0
  27. package/runner/__pycache__/state_machine.cpython-311.pyc +0 -0
  28. package/runner/errors.py +51 -0
  29. package/runner/mcp_server.py +132 -8
  30. package/runner/preflight.py +157 -0
  31. package/runner/research_swarm.py +148 -4
  32. package/runner/schema_validate.py +93 -0
  33. package/runner/schemas.py +270 -0
  34. package/runner/state_machine.py +96 -10
  35. package/runner/tests/__pycache__/test_auction_order.cpython-311.pyc +0 -0
  36. package/runner/tests/__pycache__/test_backends.cpython-311.pyc +0 -0
  37. package/runner/tests/__pycache__/test_bet1_spike.cpython-311.pyc +0 -0
  38. package/runner/tests/__pycache__/test_claim_store.cpython-311.pyc +0 -0
  39. package/runner/tests/__pycache__/test_claim_witness.cpython-311.pyc +0 -0
  40. package/runner/tests/__pycache__/test_claude_plugin.cpython-311.pyc +0 -0
  41. package/runner/tests/__pycache__/test_contract_tooling.cpython-311.pyc +0 -0
  42. package/runner/tests/__pycache__/test_darkharvest_audit.cpython-311.pyc +0 -0
  43. package/runner/tests/__pycache__/test_domain_packs.cpython-311.pyc +0 -0
  44. package/runner/tests/__pycache__/test_dossier_contract.cpython-311.pyc +0 -0
  45. package/runner/tests/__pycache__/test_factory.cpython-311.pyc +0 -0
  46. package/runner/tests/__pycache__/test_fleet_seam.cpython-311.pyc +0 -0
  47. package/runner/tests/__pycache__/test_grounding.cpython-311.pyc +0 -0
  48. package/runner/tests/__pycache__/test_living_dossiers.cpython-311.pyc +0 -0
  49. package/runner/tests/__pycache__/test_manifest_concurrency.cpython-311.pyc +0 -0
  50. package/runner/tests/__pycache__/test_mcp_server.cpython-311.pyc +0 -0
  51. package/runner/tests/__pycache__/test_opencode_ux.cpython-311.pyc +0 -0
  52. package/runner/tests/__pycache__/test_opencode_v2_registrars.cpython-311.pyc +0 -0
  53. package/runner/tests/__pycache__/test_pcrb.cpython-311.pyc +0 -0
  54. package/runner/tests/__pycache__/test_refinement.cpython-311.pyc +0 -0
  55. package/runner/tests/__pycache__/test_swarm.cpython-311.pyc +0 -0
  56. package/runner/tests/__pycache__/test_swarm_config.cpython-311.pyc +0 -0
  57. package/runner/tests/__pycache__/test_sweep_regressions.cpython-311.pyc +0 -0
  58. package/runner/tests/__pycache__/test_webcache.cpython-311.pyc +0 -0
  59. package/runner/tests/test_contract_tooling.py +312 -0
  60. package/runner/tests/test_mcp_server.py +2 -0
  61. package/runner/tests/test_opencode_ux.py +4 -2
  62. package/schemas/alpha_dossier.schema.json +204 -0
  63. package/schemas/audit_report.schema.json +76 -0
  64. package/schemas/beta_dossier.schema.json +214 -0
  65. package/schemas/frontier.schema.json +61 -0
  66. package/schemas/manifest.schema.json +43 -0
  67. package/schemas/scope_manifest.schema.json +47 -0
  68. package/scripts/__pycache__/bet1_advisory_spike.cpython-311.pyc +0 -0
  69. package/scripts/__pycache__/build_adapters.cpython-311.pyc +0 -0
  70. package/scripts/__pycache__/check_docs.cpython-311.pyc +0 -0
  71. package/scripts/__pycache__/divergence_experiment.cpython-311.pyc +0 -0
  72. package/scripts/__pycache__/gen_schemas.cpython-311.pyc +0 -0
  73. package/scripts/check_docs.py +66 -0
  74. package/scripts/gen_schemas.py +69 -0
  75. package/skills/epistemic_search/scripts/__pycache__/search.cpython-311.pyc +0 -0
  76. package/skills/factory/scripts/factory.py +68 -14
  77. package/skills/grilling/SKILL.md +14 -1
  78. package/skills/grilling/__pycache__/__init__.cpython-311.pyc +0 -0
  79. package/skills/grilling/__pycache__/socratic_tree.cpython-311.pyc +0 -0
  80. package/skills/grilling/socratic_tree.py +88 -16
  81. package/skills/research_cache/__pycache__/__init__.cpython-311.pyc +0 -0
  82. package/skills/research_cache/__pycache__/hasher.cpython-311.pyc +0 -0
  83. package/skills/swarm_config/__pycache__/__init__.cpython-311.pyc +0 -0
  84. package/skills/swarm_config/__pycache__/configure.cpython-311.pyc +0 -0
@@ -11,10 +11,17 @@ import argparse
11
11
  from pathlib import Path
12
12
  from typing import Dict, List, Optional, Any
13
13
 
14
+
14
15
  class DecisionNode:
15
- def __init__(self, node_id: str, title: str, question: str,
16
- recommended: str, options: Optional[List[str]] = None,
17
- prerequisites: Optional[List[str]] = None):
16
+ def __init__(
17
+ self,
18
+ node_id: str,
19
+ title: str,
20
+ question: str,
21
+ recommended: str,
22
+ options: Optional[List[str]] = None,
23
+ prerequisites: Optional[List[str]] = None,
24
+ ):
18
25
  self.node_id = node_id
19
26
  self.title = title
20
27
  self.question = question
@@ -34,18 +41,18 @@ class DecisionNode:
34
41
  "recommended": self.recommended,
35
42
  "options": self.options,
36
43
  "prerequisites": self.prerequisites,
37
- "settled_answer": self.settled_answer
44
+ "settled_answer": self.settled_answer,
38
45
  }
39
46
 
40
47
  @classmethod
41
- def from_dict(cls, data: Dict[str, Any]) -> 'DecisionNode':
48
+ def from_dict(cls, data: Dict[str, Any]) -> "DecisionNode":
42
49
  node = cls(
43
50
  node_id=data["node_id"],
44
51
  title=data["title"],
45
52
  question=data["question"],
46
53
  recommended=data["recommended"],
47
54
  options=data.get("options", []),
48
- prerequisites=data.get("prerequisites", [])
55
+ prerequisites=data.get("prerequisites", []),
49
56
  )
50
57
  node.settled_answer = data.get("settled_answer")
51
58
  return node
@@ -82,7 +89,9 @@ class DesignTree:
82
89
  self.nodes[node_id].settled_answer = answer
83
90
 
84
91
  def is_complete(self) -> bool:
85
- return len(self.compute_frontier()) == 0 and all(n.is_settled() for n in self.nodes.values())
92
+ return len(self.compute_frontier()) == 0 and all(
93
+ n.is_settled() for n in self.nodes.values()
94
+ )
86
95
 
87
96
  def export_frontier_json(self, output_path: Path):
88
97
  safe_path = Path(os.path.realpath(str(output_path)))
@@ -93,13 +102,13 @@ class DesignTree:
93
102
  "nodes": {k: v.to_dict() for k, v in self.nodes.items()},
94
103
  "settled_constraints": {
95
104
  k: v.settled_answer for k, v in self.nodes.items() if v.is_settled()
96
- }
105
+ },
97
106
  }
98
107
  with open(safe_path, "w", encoding="utf-8") as f:
99
108
  json.dump(data, f, indent=2)
100
109
 
101
110
  @classmethod
102
- def load_from_json(cls, file_path: Path) -> 'DesignTree':
111
+ def load_from_json(cls, file_path: Path) -> "DesignTree":
103
112
  safe_path = Path(os.path.realpath(str(file_path)))
104
113
  with open(safe_path, "r", encoding="utf-8") as f:
105
114
  data = json.load(f)
@@ -111,12 +120,16 @@ class DesignTree:
111
120
 
112
121
  def _display_frontier(tree: DesignTree, frontier: list) -> None:
113
122
  print(f"\nšŸŽÆ Objective: {tree.objective}")
114
- print(f"šŸ“Š Total Nodes: {len(tree.nodes)} | Settled: {sum(1 for n in tree.nodes.values() if n.is_settled())}")
123
+ print(
124
+ f"šŸ“Š Total Nodes: {len(tree.nodes)} | Settled: {sum(1 for n in tree.nodes.values() if n.is_settled())}"
125
+ )
115
126
  if not frontier:
116
127
  if tree.nodes and tree.is_complete():
117
128
  print("āœ… Frontier is EMPTY. All prerequisite branches are fully settled!")
118
129
  else:
119
- print("ā„¹ļø No active frontier nodes. Define new decision nodes to begin grilling.")
130
+ print(
131
+ "ā„¹ļø No active frontier nodes. Define new decision nodes to begin grilling."
132
+ )
120
133
  else:
121
134
  print(f"\n⚔ Current Active Frontier ({len(frontier)} questions ready):")
122
135
  for idx, node in enumerate(frontier, 1):
@@ -126,11 +139,49 @@ def _display_frontier(tree: DesignTree, frontier: list) -> None:
126
139
 
127
140
 
128
141
  def main():
129
- parser = argparse.ArgumentParser(description="Epistemic Swarm Socratic Decision Tree")
142
+ parser = argparse.ArgumentParser(
143
+ description="Epistemic Swarm Socratic Decision Tree"
144
+ )
130
145
  parser.add_argument("--objective", type=str, help="Research objective")
131
- parser.add_argument("--file", type=str, default=".research/frontier.json", help="Path to frontier.json")
132
- parser.add_argument("--show-frontier", action="store_true", help="Print the current decision frontier")
133
- parser.add_argument("--settle", nargs=2, metavar=("NODE_ID", "ANSWER"), help="Settle a decision node")
146
+ parser.add_argument(
147
+ "--file",
148
+ type=str,
149
+ default=".research/frontier.json",
150
+ help="Path to frontier.json",
151
+ )
152
+ parser.add_argument(
153
+ "--show-frontier",
154
+ action="store_true",
155
+ help="Print the current decision frontier",
156
+ )
157
+ parser.add_argument(
158
+ "--settle",
159
+ nargs=2,
160
+ metavar=("NODE_ID", "ANSWER"),
161
+ help="Settle a decision node",
162
+ )
163
+ parser.add_argument(
164
+ "--add-node",
165
+ action="store_true",
166
+ help="Add a decision node (with --id/--question)",
167
+ )
168
+ parser.add_argument("--id", type=str, help="Node id (with --add-node)")
169
+ parser.add_argument("--question", type=str, help="Node question (with --add-node)")
170
+ parser.add_argument(
171
+ "--title", type=str, default="", help="Node title (defaults to --id)"
172
+ )
173
+ parser.add_argument(
174
+ "--recommended", type=str, default="", help="Recommended option"
175
+ )
176
+ parser.add_argument(
177
+ "--depends-on",
178
+ type=str,
179
+ default="",
180
+ help="Comma-separated prerequisite node ids",
181
+ )
182
+ parser.add_argument(
183
+ "--export", action="store_true", help="Write the frontier JSON and exit"
184
+ )
134
185
 
135
186
  args = parser.parse_args()
136
187
  frontier_path = Path(os.path.realpath(str(args.file)))
@@ -141,14 +192,35 @@ def main():
141
192
  objective = args.objective or "Epistemic Swarm Research Objective"
142
193
  tree = DesignTree(objective=objective)
143
194
 
195
+ if args.add_node:
196
+ if not args.id or not args.question:
197
+ parser.error("--add-node requires --id and --question")
198
+ prereqs = [p.strip() for p in (args.depends_on or "").split(",") if p.strip()]
199
+ tree.add_node(
200
+ DecisionNode(
201
+ node_id=args.id,
202
+ title=args.title or args.id,
203
+ question=args.question,
204
+ recommended=args.recommended or "",
205
+ options=[],
206
+ prerequisites=prereqs,
207
+ )
208
+ )
209
+ tree.export_frontier_json(frontier_path)
210
+ print(f"Added node {args.id} -> {frontier_path}")
211
+
144
212
  if args.settle:
145
213
  node_id, answer = args.settle
146
214
  tree.settle_node(node_id, answer)
147
215
  tree.export_frontier_json(frontier_path)
148
216
  print(f"Settled {node_id} -> {answer}")
149
217
 
218
+ if args.export:
219
+ tree.export_frontier_json(frontier_path)
220
+ print(f"Exported frontier -> {frontier_path}")
221
+
150
222
  frontier = tree.compute_frontier()
151
- if args.show_frontier or not args.settle:
223
+ if args.show_frontier or not (args.settle or args.add_node or args.export):
152
224
  _display_frontier(tree, frontier)
153
225
 
154
226