@heretek-ai/epistemic-swarm 0.7.22 → 0.7.24

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 (111) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/package.json +5 -1
  3. package/plugins/antigravity/README.md +19 -10
  4. package/plugins/antigravity/antigravity_hooks.py +118 -20
  5. package/plugins/antigravity/commands/audit.md +6 -5
  6. package/plugins/antigravity/commands/brainstorm.md +9 -0
  7. package/plugins/antigravity/commands/brainstorming.md +6 -8
  8. package/plugins/antigravity/commands/darkharvest.md +6 -5
  9. package/plugins/antigravity/commands/domainexpansion.md +8 -5
  10. package/plugins/antigravity/commands/factory.md +10 -5
  11. package/plugins/antigravity/commands/grill.md +6 -5
  12. package/plugins/antigravity/commands/scout.md +6 -5
  13. package/plugins/antigravity/commands/swarm-config.md +4 -5
  14. package/plugins/antigravity/commands/swarm.md +6 -3
  15. package/plugins/antigravity/hook_bus_bridge.js +352 -0
  16. package/plugins/antigravity/hooks.json +1 -1
  17. package/plugins/antigravity/plugin.json +1 -1
  18. package/plugins/opencode/analysis-bridge.js +620 -0
  19. package/plugins/opencode/dep-health.js +1039 -0
  20. package/plugins/opencode/hook-bus.js +496 -0
  21. package/plugins/opencode/index.js +199 -10
  22. package/plugins/opencode/tui.js +115 -6
  23. package/plugins/opencode/weight-baseline.json +16 -0
  24. package/plugins/opencode/weight-signals.js +769 -0
  25. package/prompts/agent_brainstormer.md +29 -0
  26. package/prompts/agent_darkharvest.md +30 -0
  27. package/runner/__pycache__/__init__.cpython-311.pyc +0 -0
  28. package/runner/__pycache__/auctioneer.cpython-311.pyc +0 -0
  29. package/runner/__pycache__/auditor_engine.cpython-311.pyc +0 -0
  30. package/runner/__pycache__/claim_store.cpython-311.pyc +0 -0
  31. package/runner/__pycache__/claim_witness.cpython-311.pyc +0 -0
  32. package/runner/__pycache__/darkharvest_claims.cpython-311.pyc +0 -0
  33. package/runner/__pycache__/errors.cpython-311.pyc +0 -0
  34. package/runner/__pycache__/living_dossiers.cpython-311.pyc +0 -0
  35. package/runner/__pycache__/mcp_protocol.cpython-311.pyc +0 -0
  36. package/runner/__pycache__/mcp_server.cpython-311.pyc +0 -0
  37. package/runner/__pycache__/path_safety.cpython-311.pyc +0 -0
  38. package/runner/__pycache__/pcrb.cpython-311.pyc +0 -0
  39. package/runner/__pycache__/pcrb_verify.cpython-311.pyc +0 -0
  40. package/runner/__pycache__/preflight.cpython-311.pyc +0 -0
  41. package/runner/__pycache__/refinement.cpython-311.pyc +0 -0
  42. package/runner/__pycache__/research_swarm.cpython-311.pyc +0 -0
  43. package/runner/__pycache__/retrieval_log.cpython-311.pyc +0 -0
  44. package/runner/__pycache__/schema_validate.cpython-311.pyc +0 -0
  45. package/runner/__pycache__/schemas.cpython-311.pyc +0 -0
  46. package/runner/__pycache__/state_machine.cpython-311.pyc +0 -0
  47. package/runner/antigravity_hooks.py +118 -20
  48. package/runner/auditor_engine.py +194 -44
  49. package/runner/claim_store.py +64 -20
  50. package/runner/claim_witness.py +243 -14
  51. package/runner/pcrb.py +34 -11
  52. package/runner/refinement.py +140 -31
  53. package/runner/schemas.py +2 -0
  54. package/runner/tests/__pycache__/test_analysis_bridge.cpython-311.pyc +0 -0
  55. package/runner/tests/__pycache__/test_antigravity_plugin.cpython-311.pyc +0 -0
  56. package/runner/tests/__pycache__/test_auction_order.cpython-311.pyc +0 -0
  57. package/runner/tests/__pycache__/test_backends.cpython-311.pyc +0 -0
  58. package/runner/tests/__pycache__/test_bet1_spike.cpython-311.pyc +0 -0
  59. package/runner/tests/__pycache__/test_claim_store.cpython-311.pyc +0 -0
  60. package/runner/tests/__pycache__/test_claim_witness.cpython-311.pyc +0 -0
  61. package/runner/tests/__pycache__/test_claude_plugin.cpython-311.pyc +0 -0
  62. package/runner/tests/__pycache__/test_config_schema.cpython-311.pyc +0 -0
  63. package/runner/tests/__pycache__/test_contract_tooling.cpython-311.pyc +0 -0
  64. package/runner/tests/__pycache__/test_darkharvest_audit.cpython-311.pyc +0 -0
  65. package/runner/tests/__pycache__/test_dep_health.cpython-311.pyc +0 -0
  66. package/runner/tests/__pycache__/test_domain_packs.cpython-311.pyc +0 -0
  67. package/runner/tests/__pycache__/test_dossier_contract.cpython-311.pyc +0 -0
  68. package/runner/tests/__pycache__/test_factory.cpython-311.pyc +0 -0
  69. package/runner/tests/__pycache__/test_fleet_seam.cpython-311.pyc +0 -0
  70. package/runner/tests/__pycache__/test_frontier_concurrency.cpython-311.pyc +0 -0
  71. package/runner/tests/__pycache__/test_frontier_mirror_standalone.cpython-311.pyc +0 -0
  72. package/runner/tests/__pycache__/test_grounding.cpython-311.pyc +0 -0
  73. package/runner/tests/__pycache__/test_hardening_contract.cpython-311.pyc +0 -0
  74. package/runner/tests/__pycache__/test_hook_bus.cpython-311.pyc +0 -0
  75. package/runner/tests/__pycache__/test_living_dossiers.cpython-311.pyc +0 -0
  76. package/runner/tests/__pycache__/test_manifest_concurrency.cpython-311.pyc +0 -0
  77. package/runner/tests/__pycache__/test_mcp_server.cpython-311.pyc +0 -0
  78. package/runner/tests/__pycache__/test_nk_hardening.cpython-311.pyc +0 -0
  79. package/runner/tests/__pycache__/test_opencode_ux.cpython-311.pyc +0 -0
  80. package/runner/tests/__pycache__/test_opencode_v2_registrars.cpython-311.pyc +0 -0
  81. package/runner/tests/__pycache__/test_pcrb.cpython-311.pyc +0 -0
  82. package/runner/tests/__pycache__/test_phase08_waiver_reopens.cpython-311.pyc +0 -0
  83. package/runner/tests/__pycache__/test_refinement.cpython-311.pyc +0 -0
  84. package/runner/tests/__pycache__/test_search_anomaly.cpython-311.pyc +0 -0
  85. package/runner/tests/__pycache__/test_search_provider.cpython-311.pyc +0 -0
  86. package/runner/tests/__pycache__/test_search_provider_plugin.cpython-311.pyc +0 -0
  87. package/runner/tests/__pycache__/test_swarm.cpython-311.pyc +0 -0
  88. package/runner/tests/__pycache__/test_swarm_config.cpython-311.pyc +0 -0
  89. package/runner/tests/__pycache__/test_sweep_regressions.cpython-311.pyc +0 -0
  90. package/runner/tests/__pycache__/test_webcache.cpython-311.pyc +0 -0
  91. package/runner/tests/__pycache__/test_weight_signals.cpython-311.pyc +0 -0
  92. package/runner/tests/test_analysis_bridge.py +450 -0
  93. package/runner/tests/test_antigravity_plugin.py +164 -9
  94. package/runner/tests/test_dep_health.py +595 -0
  95. package/runner/tests/test_hook_bus.py +956 -0
  96. package/runner/tests/test_nk_hardening.py +1046 -0
  97. package/runner/tests/test_weight_signals.py +401 -0
  98. package/schemas/audit_report.schema.json +3 -0
  99. package/scripts/__pycache__/bet1_advisory_spike.cpython-311.pyc +0 -0
  100. package/scripts/__pycache__/build_adapters.cpython-311.pyc +0 -0
  101. package/scripts/__pycache__/check_docs.cpython-311.pyc +0 -0
  102. package/scripts/__pycache__/divergence_experiment.cpython-311.pyc +0 -0
  103. package/scripts/__pycache__/gen_schemas.cpython-311.pyc +0 -0
  104. package/scripts/build_adapters.py +1 -0
  105. package/skills/epistemic_search/scripts/__pycache__/search.cpython-311.pyc +0 -0
  106. package/skills/grilling/__pycache__/__init__.cpython-311.pyc +0 -0
  107. package/skills/grilling/__pycache__/socratic_tree.cpython-311.pyc +0 -0
  108. package/skills/research_cache/__pycache__/__init__.cpython-311.pyc +0 -0
  109. package/skills/research_cache/__pycache__/hasher.cpython-311.pyc +0 -0
  110. package/skills/swarm_config/__pycache__/__init__.cpython-311.pyc +0 -0
  111. package/skills/swarm_config/__pycache__/configure.cpython-311.pyc +0 -0
@@ -0,0 +1,352 @@
1
+ /**
2
+ * Antigravity Hook Bus & Quality Gates Bridge.
3
+ *
4
+ * Connects Antigravity's lifecycle events (PreToolUse, PostToolUse, PreInvocation, Stop)
5
+ * to IUMBTEMS's 6-event Hook Bus and the three automated Quality Gates:
6
+ * 1. Analysis Bridge (Biome CLI static analysis for JS/TS)
7
+ * 2. Dependency Health Gate (OSV.dev vulnerability & freshness scanner)
8
+ * 3. Weight Signals (esbuild bundle weight & coverage deltas vs baseline)
9
+ *
10
+ * Also provides:
11
+ * - Pre-commit gating on .research/config.json with optimistic concurrency (expected_hash)
12
+ * - Session context & compaction preservation (buildCompactionContext)
13
+ * - Living dossier claim degradation stop-gating
14
+ *
15
+ * Contract:
16
+ * - Zero runtime dependencies; node builtins only.
17
+ * - Fail-open: internal errors log and allow, never throwing into host.
18
+ */
19
+
20
+ import {
21
+ createHookBus,
22
+ gatePreCommit,
23
+ FAST_TIMEOUT_MS,
24
+ SLOW_TIMEOUT_MS,
25
+ normalizeVerdictEx,
26
+ } from '../opencode/hook-bus.js';
27
+ import { registerAnalysisBridge } from '../opencode/analysis-bridge.js';
28
+ import { registerDepHealth } from '../opencode/dep-health.js';
29
+ import { registerWeightSignals } from '../opencode/weight-signals.js';
30
+ import { buildCompactionContext, readLedgerDegraded } from '../opencode/index.js';
31
+ import { loadConfig, validateConfig } from '../opencode/config-io.js';
32
+ import { existsSync, readFileSync, appendFileSync, writeFileSync, unlinkSync } from 'node:fs';
33
+ import path from 'node:path';
34
+ import { fileURLToPath } from 'node:url';
35
+
36
+ const __filename = fileURLToPath(import.meta.url);
37
+ const __dirname = path.dirname(__filename);
38
+ const PROJECT_ROOT = path.resolve(__dirname, '../..');
39
+
40
+ export function resolveWorkspaceRoot(payload = {}) {
41
+ const ws = payload.workspacePaths || [];
42
+ if (Array.isArray(ws) && ws.length > 0 && ws[0]) {
43
+ return path.resolve(ws[0]);
44
+ }
45
+ if (payload.workspaceRoot) {
46
+ return path.resolve(payload.workspaceRoot);
47
+ }
48
+ if (process.env.IUMBTEMS_WORKSPACE) {
49
+ return path.resolve(process.env.IUMBTEMS_WORKSPACE);
50
+ }
51
+ if (process.env.IUMBTEMS_ROOT) {
52
+ return path.resolve(process.env.IUMBTEMS_ROOT);
53
+ }
54
+ let curr = path.resolve(process.cwd());
55
+ while (curr !== path.dirname(curr)) {
56
+ if (existsSync(path.join(curr, '.research')) || existsSync(path.join(curr, '.git'))) {
57
+ return curr;
58
+ }
59
+ curr = path.dirname(curr);
60
+ }
61
+ return path.resolve(process.cwd());
62
+ }
63
+
64
+ /**
65
+ * Instantiate a hook bus populated with all quality gate subscribers.
66
+ */
67
+ export async function createConfiguredBus(root) {
68
+ const bus = createHookBus();
69
+ const mockHost = {
70
+ location: { directory: root },
71
+ session: {
72
+ hook: () => ({ dispose: () => {} }),
73
+ prompt: () => Promise.resolve(),
74
+ },
75
+ };
76
+
77
+ try {
78
+ await registerAnalysisBridge(mockHost, { bus, root });
79
+ } catch {
80
+ /* fail open */
81
+ }
82
+
83
+ try {
84
+ await registerDepHealth(mockHost, { bus, root });
85
+ } catch {
86
+ /* fail open */
87
+ }
88
+
89
+ try {
90
+ await registerWeightSignals(mockHost, { bus });
91
+ } catch {
92
+ /* fail open */
93
+ }
94
+
95
+ return bus;
96
+ }
97
+
98
+ /**
99
+ * Handle pre-tool-use:
100
+ * - Check pre-commit gating on .research/config.json
101
+ * - Emit pre-tool-use on the bus (Analysis Bridge)
102
+ */
103
+ export async function handlePreTool(payload = {}) {
104
+ const root = resolveWorkspaceRoot(payload);
105
+ const toolCall = payload.toolCall || {};
106
+ const toolName = String(toolCall.name || '').toLowerCase();
107
+ const args = toolCall.args || {};
108
+
109
+ // Check if tool is attempting to edit .research/config.json
110
+ const targetFile = String(args.TargetFile || args.file || args.path || '');
111
+ const isConfigTarget =
112
+ targetFile.endsWith('.research/config.json') ||
113
+ targetFile === '.research/config.json' ||
114
+ (targetFile.includes('.research') && targetFile.includes('config.json'));
115
+
116
+ if (isConfigTarget && (toolName === 'write_to_file' || toolName === 'replace_file_content')) {
117
+ const bus = createHookBus();
118
+ const content = args.CodeContent || args.ReplacementContent || '';
119
+ let parsedUpdates = null;
120
+ try {
121
+ parsedUpdates = JSON.parse(content);
122
+ } catch {
123
+ // If content is not full JSON (e.g. replace_file_content chunk), attempt validation if possible
124
+ }
125
+
126
+ if (parsedUpdates && typeof parsedUpdates === 'object') {
127
+ const problems = validateConfig(parsedUpdates);
128
+ if (problems && problems.length > 0) {
129
+ return {
130
+ decision: 'deny',
131
+ allowed: false,
132
+ reason: `Pre-commit validation rejected .research/config.json update: ${problems.join('; ')}`,
133
+ };
134
+ }
135
+
136
+ const preCommitResult = await gatePreCommit(bus, {
137
+ updates: parsedUpdates,
138
+ root,
139
+ expected_hash: args.expected_hash || args.expectedHash || parsedUpdates.expected_hash || parsedUpdates.expectedHash,
140
+ });
141
+
142
+ if (!preCommitResult.allowed) {
143
+ return {
144
+ decision: 'deny',
145
+ allowed: false,
146
+ reason: `Pre-commit gate denied config write: ${preCommitResult.reason || 'optimistic concurrency or validation failure'}`,
147
+ };
148
+ }
149
+ }
150
+ }
151
+
152
+ const bus = await createConfiguredBus(root);
153
+ const busResult = await bus.emit('pre-tool-use', {
154
+ tool: toolName,
155
+ args,
156
+ sessionID: payload.conversationId,
157
+ targetFile,
158
+ });
159
+
160
+ if (!busResult.allowed) {
161
+ return {
162
+ decision: 'deny',
163
+ allowed: false,
164
+ reason: busResult.reason || 'Blocked by Hook Bus pre-tool-use policy',
165
+ annotations: busResult.annotations || [],
166
+ };
167
+ }
168
+
169
+ return {
170
+ decision: 'allow',
171
+ allowed: true,
172
+ annotations: busResult.annotations || [],
173
+ };
174
+ }
175
+
176
+ /**
177
+ * Handle post-tool-use:
178
+ * - Emit post-tool-use on the bus (triggers Analysis Bridge, Dep Health, Weight Signals)
179
+ * - Persist annotations to .research/quality_gates.jsonl
180
+ */
181
+ export async function handlePostTool(payload = {}) {
182
+ const root = resolveWorkspaceRoot(payload);
183
+ const toolCall = payload.toolCall || {};
184
+ const toolName = String(toolCall.name || '').toLowerCase();
185
+ const args = toolCall.args || {};
186
+ const targetFile = String(args.TargetFile || args.file || args.path || '');
187
+
188
+ const bus = await createConfiguredBus(root);
189
+ const busResult = await bus.emit('post-tool-use', {
190
+ tool: toolName,
191
+ args,
192
+ result: payload.result,
193
+ error: payload.error,
194
+ sessionID: payload.conversationId,
195
+ targetFile,
196
+ });
197
+
198
+ const annotations = busResult.annotations || [];
199
+ if (annotations.length > 0) {
200
+ try {
201
+ const qgLog = path.join(root, '.research', 'quality_gates.jsonl');
202
+ const lines = annotations.map((a) =>
203
+ JSON.stringify({
204
+ at: new Date().toISOString(),
205
+ stepIdx: payload.stepIdx,
206
+ tool: toolName,
207
+ annotation: a,
208
+ })
209
+ );
210
+ appendFileSync(qgLog, lines.join('\n') + '\n', 'utf-8');
211
+ } catch {
212
+ /* ignore file log error */
213
+ }
214
+ }
215
+
216
+ return {
217
+ allowed: busResult.allowed !== false,
218
+ annotations,
219
+ };
220
+ }
221
+
222
+ /**
223
+ * Handle pre-invocation:
224
+ * - Return compaction context from buildCompactionContext
225
+ * - Collect and clear any pending quality gate annotations
226
+ */
227
+ export async function handlePreInvocation(payload = {}) {
228
+ const root = resolveWorkspaceRoot(payload);
229
+ const compaction = buildCompactionContext(root);
230
+
231
+ let pendingAnnotations = [];
232
+ const qgLog = path.join(root, '.research', 'quality_gates.jsonl');
233
+ if (existsSync(qgLog)) {
234
+ try {
235
+ const content = readFileSync(qgLog, 'utf-8');
236
+ const lines = content.trim().split('\n').filter(Boolean);
237
+ for (const line of lines) {
238
+ try {
239
+ const entry = JSON.parse(line);
240
+ if (entry.annotation) {
241
+ pendingAnnotations.push(entry.annotation);
242
+ }
243
+ } catch {
244
+ /* ignore bad json line */
245
+ }
246
+ }
247
+ // Truncate the file so annotations are reported once
248
+ writeFileSync(qgLog, '', 'utf-8');
249
+ } catch {
250
+ /* fail open */
251
+ }
252
+ }
253
+
254
+ return {
255
+ compactionContext: compaction,
256
+ annotations: pendingAnnotations,
257
+ };
258
+ }
259
+
260
+ /**
261
+ * Handle stop:
262
+ * - Emit stop on the bus
263
+ * - Check degraded claims in .research/ledger/claim_status.json
264
+ */
265
+ export async function handleStop(payload = {}) {
266
+ const root = resolveWorkspaceRoot(payload);
267
+
268
+ // If a STOP file was placed, allow immediately
269
+ if (existsSync(path.join(root, '.factory', 'STOP'))) {
270
+ return { decision: 'allow', allowed: true };
271
+ }
272
+
273
+ const bus = await createConfiguredBus(root);
274
+ const busResult = await bus.emit('stop', {
275
+ sessionID: payload.conversationId,
276
+ terminationReason: payload.terminationReason,
277
+ });
278
+
279
+ if (!busResult.allowed) {
280
+ return {
281
+ decision: 'continue',
282
+ allowed: false,
283
+ reason: busResult.reason || 'Blocked by Hook Bus stop policy',
284
+ };
285
+ }
286
+
287
+ const degraded = readLedgerDegraded(root);
288
+ const total = (degraded.stale || []).length + (degraded.suspect || []).length;
289
+ if (total > 0) {
290
+ return {
291
+ decision: 'continue',
292
+ allowed: false,
293
+ reason: `Epistemic audit warning: ${total} claims are degraded (${degraded.stale.length} STALE, ${degraded.suspect.length} SUSPECT) due to source retractions. Review before finishing.`,
294
+ };
295
+ }
296
+
297
+ return { decision: 'allow', allowed: true };
298
+ }
299
+
300
+ /**
301
+ * CLI dispatcher for subprocess calls.
302
+ */
303
+ async function main() {
304
+ const action = process.argv[2] || 'pre_tool';
305
+ let inputData = '';
306
+
307
+ if (process.argv[3]) {
308
+ inputData = process.argv[3];
309
+ } else {
310
+ try {
311
+ inputData = readFileSync(0, 'utf-8');
312
+ } catch {
313
+ inputData = '{}';
314
+ }
315
+ }
316
+
317
+ let payload = {};
318
+ try {
319
+ payload = JSON.parse(inputData.trim() || '{}');
320
+ } catch {
321
+ payload = {};
322
+ }
323
+
324
+ let result = {};
325
+ try {
326
+ if (action === 'pre_tool' || action === 'pre-tool-use') {
327
+ result = await handlePreTool(payload);
328
+ } else if (action === 'post_tool' || action === 'post-tool-use') {
329
+ result = await handlePostTool(payload);
330
+ } else if (action === 'pre_invocation' || action === 'session-start') {
331
+ result = await handlePreInvocation(payload);
332
+ } else if (action === 'stop') {
333
+ result = await handleStop(payload);
334
+ } else {
335
+ result = { decision: 'allow', allowed: true };
336
+ }
337
+ } catch (err) {
338
+ result = {
339
+ decision: 'allow',
340
+ allowed: true,
341
+ error: String(err?.message || err),
342
+ };
343
+ }
344
+
345
+ process.stdout.write(JSON.stringify(result));
346
+ }
347
+
348
+ if (process.argv[1] && process.argv[1].endsWith('hook_bus_bridge.js')) {
349
+ main().catch(() => {
350
+ process.stdout.write(JSON.stringify({ decision: 'allow', allowed: true }));
351
+ });
352
+ }
@@ -2,7 +2,7 @@
2
2
  "epistemic-query-interceptor": {
3
3
  "PreToolUse": [
4
4
  {
5
- "matcher": "search_web|read_url_content",
5
+ "matcher": "*",
6
6
  "hooks": [
7
7
  {
8
8
  "type": "command",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://antigravity.google/schemas/v1/plugin.json",
3
3
  "name": "epistemic-swarm",
4
- "version": "0.7.22",
4
+ "version": "0.7.24",
5
5
  "description": "IUMBTEMS (Epistemic Swarm) \u2014 High-Integrity Dialectic Research, Architecture Auditing, Competitor Teardowns, and Socratic Planning for Antigravity.",
6
6
  "author": {
7
7
  "name": "Heretek AI",