opencode-swarm-plugin 0.43.0 → 0.44.1
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/bin/cass.characterization.test.ts +422 -0
- package/bin/swarm.serve.test.ts +6 -4
- package/bin/swarm.test.ts +68 -0
- package/bin/swarm.ts +81 -8
- package/dist/compaction-prompt-scoring.js +139 -0
- package/dist/contributor-tools.d.ts +42 -0
- package/dist/contributor-tools.d.ts.map +1 -0
- package/dist/eval-capture.js +12811 -0
- package/dist/hive.d.ts.map +1 -1
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7728 -62590
- package/dist/plugin.js +23833 -78695
- package/dist/sessions/agent-discovery.d.ts +59 -0
- package/dist/sessions/agent-discovery.d.ts.map +1 -0
- package/dist/sessions/index.d.ts +10 -0
- package/dist/sessions/index.d.ts.map +1 -0
- package/dist/swarm-orchestrate.d.ts.map +1 -1
- package/dist/swarm-prompts.d.ts.map +1 -1
- package/dist/swarm-review.d.ts.map +1 -1
- package/package.json +17 -5
- package/.changeset/swarm-insights-data-layer.md +0 -63
- package/.hive/analysis/eval-failure-analysis-2025-12-25.md +0 -331
- package/.hive/analysis/session-data-quality-audit.md +0 -320
- package/.hive/eval-results.json +0 -483
- package/.hive/issues.jsonl +0 -138
- package/.hive/memories.jsonl +0 -729
- package/.opencode/eval-history.jsonl +0 -327
- package/.turbo/turbo-build.log +0 -9
- package/CHANGELOG.md +0 -2255
- package/SCORER-ANALYSIS.md +0 -598
- package/docs/analysis/subagent-coordination-patterns.md +0 -902
- package/docs/analysis-socratic-planner-pattern.md +0 -504
- package/docs/planning/ADR-001-monorepo-structure.md +0 -171
- package/docs/planning/ADR-002-package-extraction.md +0 -393
- package/docs/planning/ADR-003-performance-improvements.md +0 -451
- package/docs/planning/ADR-004-message-queue-features.md +0 -187
- package/docs/planning/ADR-005-devtools-observability.md +0 -202
- package/docs/planning/ADR-007-swarm-enhancements-worktree-review.md +0 -168
- package/docs/planning/ADR-008-worker-handoff-protocol.md +0 -293
- package/docs/planning/ADR-009-oh-my-opencode-patterns.md +0 -353
- package/docs/planning/ROADMAP.md +0 -368
- package/docs/semantic-memory-cli-syntax.md +0 -123
- package/docs/swarm-mail-architecture.md +0 -1147
- package/docs/testing/context-recovery-test.md +0 -470
- package/evals/ARCHITECTURE.md +0 -1189
- package/evals/README.md +0 -768
- package/evals/compaction-prompt.eval.ts +0 -149
- package/evals/compaction-resumption.eval.ts +0 -289
- package/evals/coordinator-behavior.eval.ts +0 -307
- package/evals/coordinator-session.eval.ts +0 -154
- package/evals/evalite.config.ts.bak +0 -15
- package/evals/example.eval.ts +0 -31
- package/evals/fixtures/compaction-cases.ts +0 -350
- package/evals/fixtures/compaction-prompt-cases.ts +0 -311
- package/evals/fixtures/coordinator-sessions.ts +0 -328
- package/evals/fixtures/decomposition-cases.ts +0 -105
- package/evals/lib/compaction-loader.test.ts +0 -248
- package/evals/lib/compaction-loader.ts +0 -320
- package/evals/lib/data-loader.evalite-test.ts +0 -289
- package/evals/lib/data-loader.test.ts +0 -345
- package/evals/lib/data-loader.ts +0 -281
- package/evals/lib/llm.ts +0 -115
- package/evals/scorers/compaction-prompt-scorers.ts +0 -145
- package/evals/scorers/compaction-scorers.ts +0 -305
- package/evals/scorers/coordinator-discipline.evalite-test.ts +0 -539
- package/evals/scorers/coordinator-discipline.ts +0 -325
- package/evals/scorers/index.test.ts +0 -146
- package/evals/scorers/index.ts +0 -328
- package/evals/scorers/outcome-scorers.evalite-test.ts +0 -27
- package/evals/scorers/outcome-scorers.ts +0 -349
- package/evals/swarm-decomposition.eval.ts +0 -121
- package/examples/commands/swarm.md +0 -745
- package/examples/plugin-wrapper-template.ts +0 -2426
- package/examples/skills/hive-workflow/SKILL.md +0 -212
- package/examples/skills/skill-creator/SKILL.md +0 -223
- package/examples/skills/swarm-coordination/SKILL.md +0 -292
- package/global-skills/cli-builder/SKILL.md +0 -344
- package/global-skills/cli-builder/references/advanced-patterns.md +0 -244
- package/global-skills/learning-systems/SKILL.md +0 -644
- package/global-skills/skill-creator/LICENSE.txt +0 -202
- package/global-skills/skill-creator/SKILL.md +0 -352
- package/global-skills/skill-creator/references/output-patterns.md +0 -82
- package/global-skills/skill-creator/references/workflows.md +0 -28
- package/global-skills/swarm-coordination/SKILL.md +0 -995
- package/global-skills/swarm-coordination/references/coordinator-patterns.md +0 -235
- package/global-skills/swarm-coordination/references/strategies.md +0 -138
- package/global-skills/system-design/SKILL.md +0 -213
- package/global-skills/testing-patterns/SKILL.md +0 -430
- package/global-skills/testing-patterns/references/dependency-breaking-catalog.md +0 -586
- package/opencode-swarm-plugin-0.30.7.tgz +0 -0
- package/opencode-swarm-plugin-0.31.0.tgz +0 -0
- package/scripts/cleanup-test-memories.ts +0 -346
- package/scripts/init-skill.ts +0 -222
- package/scripts/migrate-unknown-sessions.ts +0 -349
- package/scripts/validate-skill.ts +0 -204
- package/src/agent-mail.ts +0 -1724
- package/src/anti-patterns.test.ts +0 -1167
- package/src/anti-patterns.ts +0 -448
- package/src/compaction-capture.integration.test.ts +0 -257
- package/src/compaction-hook.test.ts +0 -838
- package/src/compaction-hook.ts +0 -1204
- package/src/compaction-observability.integration.test.ts +0 -139
- package/src/compaction-observability.test.ts +0 -187
- package/src/compaction-observability.ts +0 -324
- package/src/compaction-prompt-scorers.test.ts +0 -475
- package/src/compaction-prompt-scoring.ts +0 -300
- package/src/dashboard.test.ts +0 -611
- package/src/dashboard.ts +0 -462
- package/src/error-enrichment.test.ts +0 -403
- package/src/error-enrichment.ts +0 -219
- package/src/eval-capture.test.ts +0 -1015
- package/src/eval-capture.ts +0 -929
- package/src/eval-gates.test.ts +0 -306
- package/src/eval-gates.ts +0 -218
- package/src/eval-history.test.ts +0 -508
- package/src/eval-history.ts +0 -214
- package/src/eval-learning.test.ts +0 -378
- package/src/eval-learning.ts +0 -360
- package/src/eval-runner.test.ts +0 -223
- package/src/eval-runner.ts +0 -402
- package/src/export-tools.test.ts +0 -476
- package/src/export-tools.ts +0 -257
- package/src/hive.integration.test.ts +0 -2241
- package/src/hive.ts +0 -1628
- package/src/index.ts +0 -935
- package/src/learning.integration.test.ts +0 -1815
- package/src/learning.ts +0 -1079
- package/src/logger.test.ts +0 -189
- package/src/logger.ts +0 -135
- package/src/mandate-promotion.test.ts +0 -473
- package/src/mandate-promotion.ts +0 -239
- package/src/mandate-storage.integration.test.ts +0 -601
- package/src/mandate-storage.test.ts +0 -578
- package/src/mandate-storage.ts +0 -794
- package/src/mandates.ts +0 -540
- package/src/memory-tools.test.ts +0 -195
- package/src/memory-tools.ts +0 -344
- package/src/memory.integration.test.ts +0 -334
- package/src/memory.test.ts +0 -158
- package/src/memory.ts +0 -527
- package/src/model-selection.test.ts +0 -188
- package/src/model-selection.ts +0 -68
- package/src/observability-tools.test.ts +0 -359
- package/src/observability-tools.ts +0 -871
- package/src/output-guardrails.test.ts +0 -438
- package/src/output-guardrails.ts +0 -381
- package/src/pattern-maturity.test.ts +0 -1160
- package/src/pattern-maturity.ts +0 -525
- package/src/planning-guardrails.test.ts +0 -491
- package/src/planning-guardrails.ts +0 -438
- package/src/plugin.ts +0 -23
- package/src/post-compaction-tracker.test.ts +0 -251
- package/src/post-compaction-tracker.ts +0 -237
- package/src/query-tools.test.ts +0 -636
- package/src/query-tools.ts +0 -324
- package/src/rate-limiter.integration.test.ts +0 -466
- package/src/rate-limiter.ts +0 -774
- package/src/replay-tools.test.ts +0 -496
- package/src/replay-tools.ts +0 -240
- package/src/repo-crawl.integration.test.ts +0 -441
- package/src/repo-crawl.ts +0 -610
- package/src/schemas/cell-events.test.ts +0 -347
- package/src/schemas/cell-events.ts +0 -807
- package/src/schemas/cell.ts +0 -257
- package/src/schemas/evaluation.ts +0 -166
- package/src/schemas/index.test.ts +0 -199
- package/src/schemas/index.ts +0 -286
- package/src/schemas/mandate.ts +0 -232
- package/src/schemas/swarm-context.ts +0 -115
- package/src/schemas/task.ts +0 -161
- package/src/schemas/worker-handoff.test.ts +0 -302
- package/src/schemas/worker-handoff.ts +0 -131
- package/src/skills.integration.test.ts +0 -1192
- package/src/skills.test.ts +0 -643
- package/src/skills.ts +0 -1549
- package/src/storage.integration.test.ts +0 -341
- package/src/storage.ts +0 -884
- package/src/structured.integration.test.ts +0 -817
- package/src/structured.test.ts +0 -1046
- package/src/structured.ts +0 -762
- package/src/swarm-decompose.test.ts +0 -188
- package/src/swarm-decompose.ts +0 -1302
- package/src/swarm-deferred.integration.test.ts +0 -157
- package/src/swarm-deferred.test.ts +0 -38
- package/src/swarm-insights.test.ts +0 -214
- package/src/swarm-insights.ts +0 -459
- package/src/swarm-mail.integration.test.ts +0 -970
- package/src/swarm-mail.ts +0 -739
- package/src/swarm-orchestrate.integration.test.ts +0 -282
- package/src/swarm-orchestrate.test.ts +0 -548
- package/src/swarm-orchestrate.ts +0 -3084
- package/src/swarm-prompts.test.ts +0 -1270
- package/src/swarm-prompts.ts +0 -2077
- package/src/swarm-research.integration.test.ts +0 -701
- package/src/swarm-research.test.ts +0 -698
- package/src/swarm-research.ts +0 -472
- package/src/swarm-review.integration.test.ts +0 -285
- package/src/swarm-review.test.ts +0 -879
- package/src/swarm-review.ts +0 -709
- package/src/swarm-strategies.ts +0 -407
- package/src/swarm-worktree.test.ts +0 -501
- package/src/swarm-worktree.ts +0 -575
- package/src/swarm.integration.test.ts +0 -2377
- package/src/swarm.ts +0 -38
- package/src/tool-adapter.integration.test.ts +0 -1221
- package/src/tool-availability.ts +0 -461
- package/tsconfig.json +0 -28
|
@@ -1,548 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for swarm orchestration research phase
|
|
3
|
-
*
|
|
4
|
-
* Validates:
|
|
5
|
-
* - Tech stack extraction from task descriptions
|
|
6
|
-
* - Researcher spawning for identified technologies
|
|
7
|
-
* - Summary collection from semantic-memory
|
|
8
|
-
* - Research result aggregation
|
|
9
|
-
* - Eval capture integration (captureSubtaskOutcome wiring)
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { describe, test, expect, beforeEach, afterEach, spyOn } from "bun:test";
|
|
13
|
-
import { runResearchPhase, extractTechStack, swarm_complete } from "./swarm-orchestrate";
|
|
14
|
-
import * as evalCapture from "./eval-capture.js";
|
|
15
|
-
import * as fs from "node:fs";
|
|
16
|
-
|
|
17
|
-
describe("extractTechStack", () => {
|
|
18
|
-
test("extracts Next.js from task description", () => {
|
|
19
|
-
const task = "Add authentication to the Next.js app";
|
|
20
|
-
const techStack = extractTechStack(task);
|
|
21
|
-
|
|
22
|
-
expect(techStack).toContain("next");
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
test("extracts React from task description", () => {
|
|
26
|
-
const task = "Build a React component for user profiles";
|
|
27
|
-
const techStack = extractTechStack(task);
|
|
28
|
-
|
|
29
|
-
expect(techStack).toContain("react");
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
test("extracts multiple technologies", () => {
|
|
33
|
-
const task = "Build a Zod schema for validating Next.js API routes with TypeScript";
|
|
34
|
-
const techStack = extractTechStack(task);
|
|
35
|
-
|
|
36
|
-
expect(techStack).toContain("zod");
|
|
37
|
-
expect(techStack).toContain("next");
|
|
38
|
-
expect(techStack).toContain("typescript");
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
test("returns empty array for generic tasks", () => {
|
|
42
|
-
const task = "Refactor the authentication module";
|
|
43
|
-
const techStack = extractTechStack(task);
|
|
44
|
-
|
|
45
|
-
// Might extract some keywords but should be minimal
|
|
46
|
-
expect(Array.isArray(techStack)).toBe(true);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
test("handles case-insensitive matching", () => {
|
|
50
|
-
const task = "Add NEXT.JS and REACT hooks";
|
|
51
|
-
const techStack = extractTechStack(task);
|
|
52
|
-
|
|
53
|
-
expect(techStack).toContain("next");
|
|
54
|
-
expect(techStack).toContain("react");
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
test("deduplicates repeated mentions", () => {
|
|
58
|
-
const task = "Use Zod for Zod schemas with Zod validation";
|
|
59
|
-
const techStack = extractTechStack(task);
|
|
60
|
-
|
|
61
|
-
// Should only appear once
|
|
62
|
-
const zodCount = techStack.filter(t => t === "zod").length;
|
|
63
|
-
expect(zodCount).toBe(1);
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
describe("runResearchPhase", () => {
|
|
68
|
-
const testProjectPath = "/Users/joel/Code/joelhooks/opencode-swarm-plugin";
|
|
69
|
-
|
|
70
|
-
test("returns research result with tech stack", async () => {
|
|
71
|
-
const task = "Add Next.js API routes with Zod validation";
|
|
72
|
-
|
|
73
|
-
const result = await runResearchPhase(task, testProjectPath);
|
|
74
|
-
|
|
75
|
-
expect(result).toHaveProperty("tech_stack");
|
|
76
|
-
expect(result.tech_stack).toBeInstanceOf(Array);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
test("returns summaries keyed by technology", async () => {
|
|
80
|
-
const task = "Add Next.js API routes";
|
|
81
|
-
|
|
82
|
-
const result = await runResearchPhase(task, testProjectPath);
|
|
83
|
-
|
|
84
|
-
expect(result).toHaveProperty("summaries");
|
|
85
|
-
expect(typeof result.summaries).toBe("object");
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
test("returns memory IDs for stored research", async () => {
|
|
89
|
-
const task = "Add Zod schemas";
|
|
90
|
-
|
|
91
|
-
const result = await runResearchPhase(task, testProjectPath);
|
|
92
|
-
|
|
93
|
-
expect(result).toHaveProperty("memory_ids");
|
|
94
|
-
expect(result.memory_ids).toBeInstanceOf(Array);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
test("skips research for tasks with no tech mentions", async () => {
|
|
98
|
-
const task = "Refactor the authentication module";
|
|
99
|
-
|
|
100
|
-
const result = await runResearchPhase(task, testProjectPath);
|
|
101
|
-
|
|
102
|
-
// Should return empty result quickly
|
|
103
|
-
expect(result.tech_stack).toHaveLength(0);
|
|
104
|
-
expect(result.summaries).toEqual({});
|
|
105
|
-
expect(result.memory_ids).toHaveLength(0);
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
test("handles check_upgrades option", async () => {
|
|
109
|
-
const task = "Add Next.js caching";
|
|
110
|
-
|
|
111
|
-
const result = await runResearchPhase(task, testProjectPath, {
|
|
112
|
-
checkUpgrades: true,
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
// Should still return valid result
|
|
116
|
-
expect(result).toHaveProperty("tech_stack");
|
|
117
|
-
expect(result).toHaveProperty("summaries");
|
|
118
|
-
});
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
// describe("swarm_research_phase tool", () => {
|
|
122
|
-
// test.todo("exposes research phase as plugin tool");
|
|
123
|
-
// test.todo("validates task parameter");
|
|
124
|
-
// test.todo("validates project_path parameter");
|
|
125
|
-
// test.todo("returns JSON string with research results");
|
|
126
|
-
// });
|
|
127
|
-
|
|
128
|
-
// ============================================================================
|
|
129
|
-
// Eval Capture Integration Tests (swarm_complete)
|
|
130
|
-
// ============================================================================
|
|
131
|
-
|
|
132
|
-
describe("captureSubtaskOutcome integration", () => {
|
|
133
|
-
const mockContext = {
|
|
134
|
-
sessionID: `test-complete-${Date.now()}`,
|
|
135
|
-
messageID: `test-message-${Date.now()}`,
|
|
136
|
-
agent: "test-agent",
|
|
137
|
-
abort: new AbortController().signal,
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
let testProjectPath: string;
|
|
141
|
-
|
|
142
|
-
beforeEach(async () => {
|
|
143
|
-
testProjectPath = `/tmp/test-swarm-complete-${Date.now()}`;
|
|
144
|
-
fs.mkdirSync(testProjectPath, { recursive: true });
|
|
145
|
-
|
|
146
|
-
// Create .hive directory and issues.jsonl
|
|
147
|
-
const hiveDir = `${testProjectPath}/.hive`;
|
|
148
|
-
fs.mkdirSync(hiveDir, { recursive: true });
|
|
149
|
-
fs.writeFileSync(`${hiveDir}/issues.jsonl`, "", "utf-8");
|
|
150
|
-
|
|
151
|
-
// Set hive working directory to testProjectPath
|
|
152
|
-
const { setHiveWorkingDirectory } = await import("./hive");
|
|
153
|
-
setHiveWorkingDirectory(testProjectPath);
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
afterEach(() => {
|
|
157
|
-
if (fs.existsSync(testProjectPath)) {
|
|
158
|
-
fs.rmSync(testProjectPath, { recursive: true, force: true });
|
|
159
|
-
}
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
test("calls captureSubtaskOutcome after successful completion with all params", async () => {
|
|
163
|
-
// Import hive tools
|
|
164
|
-
const { hive_create_epic } = await import("./hive");
|
|
165
|
-
|
|
166
|
-
// Spy on captureSubtaskOutcome
|
|
167
|
-
const captureOutcomeSpy = spyOn(evalCapture, "captureSubtaskOutcome");
|
|
168
|
-
|
|
169
|
-
// Create an epic with a subtask using hive_create_epic
|
|
170
|
-
const epicResult = await hive_create_epic.execute({
|
|
171
|
-
epic_title: "Add OAuth",
|
|
172
|
-
epic_description: "Implement OAuth authentication",
|
|
173
|
-
subtasks: [
|
|
174
|
-
{
|
|
175
|
-
title: "Add auth service",
|
|
176
|
-
priority: 2,
|
|
177
|
-
files: ["src/auth/service.ts", "src/auth/schema.ts"],
|
|
178
|
-
},
|
|
179
|
-
],
|
|
180
|
-
}, mockContext);
|
|
181
|
-
|
|
182
|
-
const epicData = JSON.parse(epicResult);
|
|
183
|
-
expect(epicData.success).toBe(true);
|
|
184
|
-
|
|
185
|
-
const epicId = epicData.epic.id;
|
|
186
|
-
const beadId = epicData.subtasks[0].id;
|
|
187
|
-
|
|
188
|
-
const startTime = Date.now() - 120000; // Started 2 minutes ago
|
|
189
|
-
const plannedFiles = ["src/auth/service.ts", "src/auth/schema.ts"];
|
|
190
|
-
const actualFiles = ["src/auth/service.ts", "src/auth/schema.ts", "src/auth/types.ts"];
|
|
191
|
-
|
|
192
|
-
// Call swarm_complete
|
|
193
|
-
const result = await swarm_complete.execute(
|
|
194
|
-
{
|
|
195
|
-
project_key: testProjectPath,
|
|
196
|
-
agent_name: "TestAgent",
|
|
197
|
-
bead_id: beadId,
|
|
198
|
-
summary: "Implemented OAuth service with JWT strategy",
|
|
199
|
-
files_touched: actualFiles,
|
|
200
|
-
skip_verification: true, // Skip verification for test
|
|
201
|
-
skip_review: true, // Skip review for test
|
|
202
|
-
planned_files: plannedFiles,
|
|
203
|
-
start_time: startTime,
|
|
204
|
-
error_count: 0,
|
|
205
|
-
retry_count: 0,
|
|
206
|
-
},
|
|
207
|
-
mockContext,
|
|
208
|
-
);
|
|
209
|
-
|
|
210
|
-
const parsed = JSON.parse(result);
|
|
211
|
-
expect(parsed.success).toBe(true);
|
|
212
|
-
|
|
213
|
-
// Verify captureSubtaskOutcome was called with correct params
|
|
214
|
-
expect(captureOutcomeSpy).toHaveBeenCalledTimes(1);
|
|
215
|
-
|
|
216
|
-
const call = captureOutcomeSpy.mock.calls[0][0];
|
|
217
|
-
expect(call.epicId).toBe(epicId);
|
|
218
|
-
expect(call.projectPath).toBe(testProjectPath);
|
|
219
|
-
expect(call.beadId).toBe(beadId);
|
|
220
|
-
expect(call.title).toBe("Add auth service");
|
|
221
|
-
expect(call.plannedFiles).toEqual(plannedFiles);
|
|
222
|
-
expect(call.actualFiles).toEqual(actualFiles);
|
|
223
|
-
expect(call.durationMs).toBeGreaterThan(0);
|
|
224
|
-
expect(call.errorCount).toBe(0);
|
|
225
|
-
expect(call.retryCount).toBe(0);
|
|
226
|
-
expect(call.success).toBe(true);
|
|
227
|
-
|
|
228
|
-
captureOutcomeSpy.mockRestore();
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
test("does not call captureSubtaskOutcome when required params missing", async () => {
|
|
232
|
-
const { hive_create_epic } = await import("./hive");
|
|
233
|
-
const captureOutcomeSpy = spyOn(evalCapture, "captureSubtaskOutcome");
|
|
234
|
-
|
|
235
|
-
// Create an epic with a subtask
|
|
236
|
-
const epicResult = await hive_create_epic.execute({
|
|
237
|
-
epic_title: "Fix bug",
|
|
238
|
-
subtasks: [
|
|
239
|
-
{
|
|
240
|
-
title: "Fix auth bug",
|
|
241
|
-
priority: 1,
|
|
242
|
-
files: ["src/auth.ts"],
|
|
243
|
-
},
|
|
244
|
-
],
|
|
245
|
-
}, mockContext);
|
|
246
|
-
|
|
247
|
-
const epicData = JSON.parse(epicResult);
|
|
248
|
-
const beadId = epicData.subtasks[0].id;
|
|
249
|
-
|
|
250
|
-
// Call without planned_files or start_time
|
|
251
|
-
const result = await swarm_complete.execute(
|
|
252
|
-
{
|
|
253
|
-
project_key: testProjectPath,
|
|
254
|
-
agent_name: "TestAgent",
|
|
255
|
-
bead_id: beadId,
|
|
256
|
-
summary: "Fixed the bug",
|
|
257
|
-
skip_verification: true,
|
|
258
|
-
skip_review: true,
|
|
259
|
-
// No planned_files, start_time
|
|
260
|
-
},
|
|
261
|
-
mockContext,
|
|
262
|
-
);
|
|
263
|
-
|
|
264
|
-
const parsed = JSON.parse(result);
|
|
265
|
-
expect(parsed.success).toBe(true);
|
|
266
|
-
|
|
267
|
-
// Capture should still be called, but with default values
|
|
268
|
-
// (The function is called in all success cases, it just handles missing params)
|
|
269
|
-
expect(captureOutcomeSpy).toHaveBeenCalledTimes(1);
|
|
270
|
-
|
|
271
|
-
captureOutcomeSpy.mockRestore();
|
|
272
|
-
});
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
// ============================================================================
|
|
276
|
-
// Event Emission Tests (subtask_outcome events to libSQL)
|
|
277
|
-
// ============================================================================
|
|
278
|
-
|
|
279
|
-
describe("subtask_outcome event emission", () => {
|
|
280
|
-
const mockContext = {
|
|
281
|
-
sessionID: `test-event-emission-${Date.now()}`,
|
|
282
|
-
messageID: `test-message-${Date.now()}`,
|
|
283
|
-
agent: "test-agent",
|
|
284
|
-
abort: new AbortController().signal,
|
|
285
|
-
};
|
|
286
|
-
|
|
287
|
-
let testProjectPath: string;
|
|
288
|
-
|
|
289
|
-
beforeEach(async () => {
|
|
290
|
-
testProjectPath = `/tmp/test-event-emission-${Date.now()}`;
|
|
291
|
-
fs.mkdirSync(testProjectPath, { recursive: true });
|
|
292
|
-
|
|
293
|
-
// Create .hive directory and issues.jsonl
|
|
294
|
-
const hiveDir = `${testProjectPath}/.hive`;
|
|
295
|
-
fs.mkdirSync(hiveDir, { recursive: true });
|
|
296
|
-
fs.writeFileSync(`${hiveDir}/issues.jsonl`, "", "utf-8");
|
|
297
|
-
|
|
298
|
-
// Set hive working directory to testProjectPath
|
|
299
|
-
const { setHiveWorkingDirectory } = await import("./hive");
|
|
300
|
-
setHiveWorkingDirectory(testProjectPath);
|
|
301
|
-
});
|
|
302
|
-
|
|
303
|
-
afterEach(() => {
|
|
304
|
-
if (fs.existsSync(testProjectPath)) {
|
|
305
|
-
fs.rmSync(testProjectPath, { recursive: true, force: true });
|
|
306
|
-
}
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
test("swarm_complete emits subtask_outcome event to libSQL database", async () => {
|
|
310
|
-
// Import dependencies
|
|
311
|
-
const { hive_create_epic } = await import("./hive");
|
|
312
|
-
const { readEvents, getSwarmMailLibSQL } = await import("swarm-mail");
|
|
313
|
-
|
|
314
|
-
// Create an epic with a subtask
|
|
315
|
-
const epicResult = await hive_create_epic.execute({
|
|
316
|
-
epic_title: "Add feature X",
|
|
317
|
-
subtasks: [
|
|
318
|
-
{
|
|
319
|
-
title: "Implement X service",
|
|
320
|
-
priority: 2,
|
|
321
|
-
files: ["src/x.ts"],
|
|
322
|
-
},
|
|
323
|
-
],
|
|
324
|
-
}, mockContext);
|
|
325
|
-
|
|
326
|
-
const epicData = JSON.parse(epicResult);
|
|
327
|
-
const epicId = epicData.epic.id;
|
|
328
|
-
const beadId = epicData.subtasks[0].id;
|
|
329
|
-
|
|
330
|
-
const startTime = Date.now() - 60000; // Started 1 minute ago
|
|
331
|
-
|
|
332
|
-
// Call swarm_complete
|
|
333
|
-
const result = await swarm_complete.execute(
|
|
334
|
-
{
|
|
335
|
-
project_key: testProjectPath,
|
|
336
|
-
agent_name: "TestAgent",
|
|
337
|
-
bead_id: beadId,
|
|
338
|
-
summary: "Implemented X service",
|
|
339
|
-
files_touched: ["src/x.ts"],
|
|
340
|
-
skip_verification: true,
|
|
341
|
-
skip_review: true,
|
|
342
|
-
planned_files: ["src/x.ts"],
|
|
343
|
-
start_time: startTime,
|
|
344
|
-
error_count: 0,
|
|
345
|
-
retry_count: 0,
|
|
346
|
-
},
|
|
347
|
-
mockContext,
|
|
348
|
-
);
|
|
349
|
-
|
|
350
|
-
const parsed = JSON.parse(result);
|
|
351
|
-
expect(parsed.success).toBe(true);
|
|
352
|
-
|
|
353
|
-
// Query events from libSQL database
|
|
354
|
-
const events = await readEvents({
|
|
355
|
-
projectKey: testProjectPath,
|
|
356
|
-
types: ["subtask_outcome"],
|
|
357
|
-
}, testProjectPath);
|
|
358
|
-
|
|
359
|
-
// Should have exactly 1 subtask_outcome event
|
|
360
|
-
expect(events.length).toBe(1);
|
|
361
|
-
|
|
362
|
-
const event = events[0] as any;
|
|
363
|
-
expect(event.type).toBe("subtask_outcome");
|
|
364
|
-
expect(event.epic_id).toBe(epicId);
|
|
365
|
-
expect(event.bead_id).toBe(beadId);
|
|
366
|
-
expect(event.success).toBe(true);
|
|
367
|
-
expect(event.duration_ms).toBeGreaterThan(0);
|
|
368
|
-
});
|
|
369
|
-
|
|
370
|
-
test("subtask_outcome event updates eval_records.outcomes in libSQL", async () => {
|
|
371
|
-
// Import dependencies
|
|
372
|
-
const { hive_create_epic } = await import("./hive");
|
|
373
|
-
const { getSwarmMailLibSQL } = await import("swarm-mail");
|
|
374
|
-
|
|
375
|
-
// Create an epic with a subtask
|
|
376
|
-
const epicResult = await hive_create_epic.execute({
|
|
377
|
-
epic_title: "Add feature Y",
|
|
378
|
-
subtasks: [
|
|
379
|
-
{
|
|
380
|
-
title: "Implement Y service",
|
|
381
|
-
priority: 2,
|
|
382
|
-
files: ["src/y.ts"],
|
|
383
|
-
},
|
|
384
|
-
],
|
|
385
|
-
}, mockContext);
|
|
386
|
-
|
|
387
|
-
const epicData = JSON.parse(epicResult);
|
|
388
|
-
const epicId = epicData.epic.id;
|
|
389
|
-
const beadId = epicData.subtasks[0].id;
|
|
390
|
-
|
|
391
|
-
const startTime = Date.now() - 90000; // Started 1.5 minutes ago
|
|
392
|
-
|
|
393
|
-
// Call swarm_complete
|
|
394
|
-
await swarm_complete.execute(
|
|
395
|
-
{
|
|
396
|
-
project_key: testProjectPath,
|
|
397
|
-
agent_name: "TestAgent",
|
|
398
|
-
bead_id: beadId,
|
|
399
|
-
summary: "Implemented Y service",
|
|
400
|
-
files_touched: ["src/y.ts", "src/y.test.ts"],
|
|
401
|
-
skip_verification: true,
|
|
402
|
-
skip_review: true,
|
|
403
|
-
planned_files: ["src/y.ts"],
|
|
404
|
-
start_time: startTime,
|
|
405
|
-
error_count: 0,
|
|
406
|
-
retry_count: 0,
|
|
407
|
-
},
|
|
408
|
-
mockContext,
|
|
409
|
-
);
|
|
410
|
-
|
|
411
|
-
// Query eval_records from libSQL
|
|
412
|
-
const swarmMail = await getSwarmMailLibSQL(testProjectPath);
|
|
413
|
-
const db = await swarmMail.getDatabase();
|
|
414
|
-
|
|
415
|
-
const result = await db.query<{ outcomes: string | null }>(
|
|
416
|
-
`SELECT outcomes FROM eval_records WHERE id = ?`,
|
|
417
|
-
[epicId]
|
|
418
|
-
);
|
|
419
|
-
|
|
420
|
-
expect(result.rows.length).toBe(1);
|
|
421
|
-
|
|
422
|
-
const outcomes = result.rows[0].outcomes;
|
|
423
|
-
expect(outcomes).not.toBeNull();
|
|
424
|
-
|
|
425
|
-
const parsed = JSON.parse(outcomes || "[]");
|
|
426
|
-
expect(parsed.length).toBe(1);
|
|
427
|
-
|
|
428
|
-
const outcome = parsed[0];
|
|
429
|
-
expect(outcome.bead_id).toBe(beadId);
|
|
430
|
-
expect(outcome.success).toBe(true);
|
|
431
|
-
expect(outcome.duration_ms).toBeGreaterThan(0);
|
|
432
|
-
expect(outcome.planned_files).toEqual(["src/y.ts"]);
|
|
433
|
-
expect(outcome.actual_files).toEqual(["src/y.ts", "src/y.test.ts"]);
|
|
434
|
-
});
|
|
435
|
-
});
|
|
436
|
-
|
|
437
|
-
// ============================================================================
|
|
438
|
-
// Eval Capture Integration Tests (swarm_record_outcome)
|
|
439
|
-
// ============================================================================
|
|
440
|
-
|
|
441
|
-
describe("finalizeEvalRecord integration", () => {
|
|
442
|
-
const mockContext = {
|
|
443
|
-
sessionID: `test-finalize-${Date.now()}`,
|
|
444
|
-
messageID: `test-message-${Date.now()}`,
|
|
445
|
-
agent: "test-agent",
|
|
446
|
-
abort: new AbortController().signal,
|
|
447
|
-
};
|
|
448
|
-
|
|
449
|
-
test("calls finalizeEvalRecord when project_path and epic_id provided", async () => {
|
|
450
|
-
const { swarm_record_outcome } = await import("./swarm-orchestrate");
|
|
451
|
-
|
|
452
|
-
// Spy on finalizeEvalRecord
|
|
453
|
-
const finalizeEvalSpy = spyOn(evalCapture, "finalizeEvalRecord");
|
|
454
|
-
finalizeEvalSpy.mockReturnValue(null); // Mock return value
|
|
455
|
-
|
|
456
|
-
const testProjectPath = "/tmp/test-project";
|
|
457
|
-
const testEpicId = "bd-test123";
|
|
458
|
-
const testBeadId = `${testEpicId}.0`;
|
|
459
|
-
|
|
460
|
-
// Call swarm_record_outcome with epic_id and project_path
|
|
461
|
-
await swarm_record_outcome.execute({
|
|
462
|
-
bead_id: testBeadId,
|
|
463
|
-
duration_ms: 120000,
|
|
464
|
-
error_count: 0,
|
|
465
|
-
retry_count: 0,
|
|
466
|
-
success: true,
|
|
467
|
-
files_touched: ["src/test.ts"],
|
|
468
|
-
epic_id: testEpicId,
|
|
469
|
-
project_path: testProjectPath,
|
|
470
|
-
}, mockContext);
|
|
471
|
-
|
|
472
|
-
// Verify finalizeEvalRecord was called
|
|
473
|
-
expect(finalizeEvalSpy).toHaveBeenCalledTimes(1);
|
|
474
|
-
expect(finalizeEvalSpy).toHaveBeenCalledWith({
|
|
475
|
-
epicId: testEpicId,
|
|
476
|
-
projectPath: testProjectPath,
|
|
477
|
-
});
|
|
478
|
-
|
|
479
|
-
finalizeEvalSpy.mockRestore();
|
|
480
|
-
});
|
|
481
|
-
|
|
482
|
-
test("does not call finalizeEvalRecord when epic_id or project_path missing", async () => {
|
|
483
|
-
const { swarm_record_outcome } = await import("./swarm-orchestrate");
|
|
484
|
-
|
|
485
|
-
// Spy on finalizeEvalRecord
|
|
486
|
-
const finalizeEvalSpy = spyOn(evalCapture, "finalizeEvalRecord");
|
|
487
|
-
|
|
488
|
-
const testBeadId = "bd-test123.0";
|
|
489
|
-
|
|
490
|
-
// Call without epic_id or project_path
|
|
491
|
-
await swarm_record_outcome.execute({
|
|
492
|
-
bead_id: testBeadId,
|
|
493
|
-
duration_ms: 120000,
|
|
494
|
-
error_count: 0,
|
|
495
|
-
retry_count: 0,
|
|
496
|
-
success: true,
|
|
497
|
-
}, mockContext);
|
|
498
|
-
|
|
499
|
-
// Verify finalizeEvalRecord was NOT called
|
|
500
|
-
expect(finalizeEvalSpy).toHaveBeenCalledTimes(0);
|
|
501
|
-
|
|
502
|
-
finalizeEvalSpy.mockRestore();
|
|
503
|
-
});
|
|
504
|
-
|
|
505
|
-
test("includes finalized record in response when available", async () => {
|
|
506
|
-
const { swarm_record_outcome } = await import("./swarm-orchestrate");
|
|
507
|
-
|
|
508
|
-
// Mock finalizeEvalRecord to return a record
|
|
509
|
-
const mockFinalRecord = {
|
|
510
|
-
id: "bd-test123",
|
|
511
|
-
timestamp: new Date().toISOString(),
|
|
512
|
-
project_path: "/tmp/test-project",
|
|
513
|
-
task: "Test task",
|
|
514
|
-
strategy: "file-based" as const,
|
|
515
|
-
subtask_count: 2,
|
|
516
|
-
epic_title: "Test Epic",
|
|
517
|
-
subtasks: [],
|
|
518
|
-
overall_success: true,
|
|
519
|
-
total_duration_ms: 240000,
|
|
520
|
-
total_errors: 0,
|
|
521
|
-
};
|
|
522
|
-
|
|
523
|
-
const finalizeEvalSpy = spyOn(evalCapture, "finalizeEvalRecord");
|
|
524
|
-
finalizeEvalSpy.mockReturnValue(mockFinalRecord);
|
|
525
|
-
|
|
526
|
-
const testProjectPath = "/tmp/test-project";
|
|
527
|
-
const testEpicId = "bd-test123";
|
|
528
|
-
const testBeadId = `${testEpicId}.0`;
|
|
529
|
-
|
|
530
|
-
// Call with epic_id and project_path
|
|
531
|
-
const result = await swarm_record_outcome.execute({
|
|
532
|
-
bead_id: testBeadId,
|
|
533
|
-
duration_ms: 120000,
|
|
534
|
-
error_count: 0,
|
|
535
|
-
retry_count: 0,
|
|
536
|
-
success: true,
|
|
537
|
-
epic_id: testEpicId,
|
|
538
|
-
project_path: testProjectPath,
|
|
539
|
-
}, mockContext);
|
|
540
|
-
|
|
541
|
-
// Parse result and check for finalized record
|
|
542
|
-
const parsed = JSON.parse(result);
|
|
543
|
-
expect(parsed).toHaveProperty("finalized_eval_record");
|
|
544
|
-
expect(parsed.finalized_eval_record).toEqual(mockFinalRecord);
|
|
545
|
-
|
|
546
|
-
finalizeEvalSpy.mockRestore();
|
|
547
|
-
});
|
|
548
|
-
});
|