opencode-swarm-plugin 0.37.0 → 0.39.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/.env +2 -0
- package/.hive/eval-results.json +26 -0
- package/.hive/issues.jsonl +20 -5
- package/.hive/memories.jsonl +35 -1
- package/.opencode/eval-history.jsonl +12 -0
- package/.turbo/turbo-build.log +4 -4
- package/.turbo/turbo-test.log +319 -319
- package/CHANGELOG.md +258 -0
- package/README.md +50 -0
- package/bin/swarm.test.ts +475 -0
- package/bin/swarm.ts +385 -208
- package/dist/compaction-hook.d.ts +1 -1
- package/dist/compaction-hook.d.ts.map +1 -1
- package/dist/compaction-prompt-scoring.d.ts +124 -0
- package/dist/compaction-prompt-scoring.d.ts.map +1 -0
- package/dist/eval-capture.d.ts +81 -1
- package/dist/eval-capture.d.ts.map +1 -1
- package/dist/eval-gates.d.ts +84 -0
- package/dist/eval-gates.d.ts.map +1 -0
- package/dist/eval-history.d.ts +117 -0
- package/dist/eval-history.d.ts.map +1 -0
- package/dist/eval-learning.d.ts +216 -0
- package/dist/eval-learning.d.ts.map +1 -0
- package/dist/hive.d.ts +59 -0
- package/dist/hive.d.ts.map +1 -1
- package/dist/index.d.ts +87 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +823 -131
- package/dist/plugin.js +655 -131
- package/dist/post-compaction-tracker.d.ts +133 -0
- package/dist/post-compaction-tracker.d.ts.map +1 -0
- package/dist/swarm-decompose.d.ts +30 -0
- package/dist/swarm-decompose.d.ts.map +1 -1
- package/dist/swarm-orchestrate.d.ts +23 -0
- package/dist/swarm-orchestrate.d.ts.map +1 -1
- package/dist/swarm-prompts.d.ts +25 -1
- package/dist/swarm-prompts.d.ts.map +1 -1
- package/dist/swarm.d.ts +19 -0
- package/dist/swarm.d.ts.map +1 -1
- package/evals/README.md +595 -94
- package/evals/compaction-prompt.eval.ts +149 -0
- package/evals/coordinator-behavior.eval.ts +8 -8
- package/evals/fixtures/compaction-prompt-cases.ts +305 -0
- package/evals/lib/compaction-loader.test.ts +248 -0
- package/evals/lib/compaction-loader.ts +320 -0
- package/evals/lib/data-loader.test.ts +345 -0
- package/evals/lib/data-loader.ts +107 -6
- package/evals/scorers/compaction-prompt-scorers.ts +145 -0
- package/evals/scorers/compaction-scorers.ts +13 -13
- package/evals/scorers/coordinator-discipline.evalite-test.ts +3 -2
- package/evals/scorers/coordinator-discipline.ts +13 -13
- package/examples/plugin-wrapper-template.ts +177 -8
- package/package.json +7 -2
- package/scripts/migrate-unknown-sessions.ts +349 -0
- package/src/compaction-capture.integration.test.ts +257 -0
- package/src/compaction-hook.test.ts +139 -2
- package/src/compaction-hook.ts +113 -2
- package/src/compaction-prompt-scorers.test.ts +299 -0
- package/src/compaction-prompt-scoring.ts +298 -0
- package/src/eval-capture.test.ts +422 -0
- package/src/eval-capture.ts +94 -2
- package/src/eval-gates.test.ts +306 -0
- package/src/eval-gates.ts +218 -0
- package/src/eval-history.test.ts +508 -0
- package/src/eval-history.ts +214 -0
- package/src/eval-learning.test.ts +378 -0
- package/src/eval-learning.ts +360 -0
- package/src/index.ts +61 -1
- package/src/post-compaction-tracker.test.ts +251 -0
- package/src/post-compaction-tracker.ts +237 -0
- package/src/swarm-decompose.test.ts +40 -47
- package/src/swarm-decompose.ts +2 -2
- package/src/swarm-orchestrate.test.ts +270 -7
- package/src/swarm-orchestrate.ts +100 -13
- package/src/swarm-prompts.test.ts +121 -0
- package/src/swarm-prompts.ts +297 -4
- package/src/swarm-research.integration.test.ts +157 -0
- package/src/swarm-review.ts +3 -3
- /package/evals/{evalite.config.ts → evalite.config.ts.bak} +0 -0
|
@@ -495,6 +495,158 @@ describe("End-to-end research workflow", () => {
|
|
|
495
495
|
});
|
|
496
496
|
});
|
|
497
497
|
|
|
498
|
+
describe("Research spawn instructions (NEW)", () => {
|
|
499
|
+
let testProjectPath: string;
|
|
500
|
+
|
|
501
|
+
beforeEach(() => {
|
|
502
|
+
testProjectPath = join(tmpdir(), `spawn-test-${Date.now()}`);
|
|
503
|
+
mkdirSync(testProjectPath, { recursive: true });
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
afterEach(() => {
|
|
507
|
+
rmSync(testProjectPath, { recursive: true, force: true });
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
test("runResearchPhase generates spawn instructions for each technology", async () => {
|
|
511
|
+
// Create package.json with dependencies
|
|
512
|
+
const packageJson = {
|
|
513
|
+
dependencies: {
|
|
514
|
+
zod: "^3.22.4",
|
|
515
|
+
typescript: "^5.3.3",
|
|
516
|
+
},
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
writeFileSync(
|
|
520
|
+
join(testProjectPath, "package.json"),
|
|
521
|
+
JSON.stringify(packageJson, null, 2),
|
|
522
|
+
);
|
|
523
|
+
|
|
524
|
+
// Run research phase
|
|
525
|
+
const result = await runResearchPhase(
|
|
526
|
+
"Add Zod validation to TypeScript API",
|
|
527
|
+
testProjectPath,
|
|
528
|
+
);
|
|
529
|
+
|
|
530
|
+
// Should have spawn_instructions array
|
|
531
|
+
expect(result.spawn_instructions).toBeDefined();
|
|
532
|
+
expect(Array.isArray(result.spawn_instructions)).toBe(true);
|
|
533
|
+
|
|
534
|
+
// Should have one instruction per technology
|
|
535
|
+
expect(result.spawn_instructions.length).toBe(result.tech_stack.length);
|
|
536
|
+
|
|
537
|
+
// Each instruction should have required fields
|
|
538
|
+
for (const instruction of result.spawn_instructions) {
|
|
539
|
+
expect(instruction.research_id).toBeDefined();
|
|
540
|
+
expect(instruction.research_id).toMatch(/^research-/); // Should start with "research-"
|
|
541
|
+
expect(instruction.tech).toBeDefined();
|
|
542
|
+
expect(result.tech_stack).toContain(instruction.tech); // Tech should be from tech_stack
|
|
543
|
+
expect(instruction.prompt).toBeDefined();
|
|
544
|
+
expect(typeof instruction.prompt).toBe("string");
|
|
545
|
+
expect(instruction.prompt.length).toBeGreaterThan(0);
|
|
546
|
+
expect(instruction.subagent_type).toBe("swarm/researcher");
|
|
547
|
+
}
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
test("runResearchPhase prompts contain correct technology", async () => {
|
|
551
|
+
const packageJson = {
|
|
552
|
+
dependencies: {
|
|
553
|
+
zod: "^3.22.4",
|
|
554
|
+
},
|
|
555
|
+
};
|
|
556
|
+
|
|
557
|
+
writeFileSync(
|
|
558
|
+
join(testProjectPath, "package.json"),
|
|
559
|
+
JSON.stringify(packageJson, null, 2),
|
|
560
|
+
);
|
|
561
|
+
|
|
562
|
+
const result = await runResearchPhase("Use Zod", testProjectPath);
|
|
563
|
+
|
|
564
|
+
// Should have exactly one spawn instruction (one tech)
|
|
565
|
+
expect(result.spawn_instructions.length).toBe(1);
|
|
566
|
+
|
|
567
|
+
const instruction = result.spawn_instructions[0];
|
|
568
|
+
expect(instruction.tech).toBe("zod");
|
|
569
|
+
expect(instruction.prompt).toContain("zod");
|
|
570
|
+
expect(instruction.prompt).toContain(testProjectPath);
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
test("runResearchPhase with multiple technologies generates multiple instructions", async () => {
|
|
574
|
+
const packageJson = {
|
|
575
|
+
dependencies: {
|
|
576
|
+
zod: "^3.22.4",
|
|
577
|
+
typescript: "^5.3.3",
|
|
578
|
+
react: "^18.2.0",
|
|
579
|
+
},
|
|
580
|
+
};
|
|
581
|
+
|
|
582
|
+
writeFileSync(
|
|
583
|
+
join(testProjectPath, "package.json"),
|
|
584
|
+
JSON.stringify(packageJson, null, 2),
|
|
585
|
+
);
|
|
586
|
+
|
|
587
|
+
const result = await runResearchPhase(
|
|
588
|
+
"Build React app with Zod and TypeScript",
|
|
589
|
+
testProjectPath,
|
|
590
|
+
);
|
|
591
|
+
|
|
592
|
+
// Should extract 3 technologies
|
|
593
|
+
expect(result.tech_stack.length).toBe(3);
|
|
594
|
+
|
|
595
|
+
// Should have 3 spawn instructions
|
|
596
|
+
expect(result.spawn_instructions.length).toBe(3);
|
|
597
|
+
|
|
598
|
+
// Each tech should have one instruction
|
|
599
|
+
const techs = result.spawn_instructions.map((i) => i.tech);
|
|
600
|
+
expect(techs).toContain("zod");
|
|
601
|
+
expect(techs).toContain("typescript");
|
|
602
|
+
expect(techs).toContain("react");
|
|
603
|
+
|
|
604
|
+
// Research IDs should be unique
|
|
605
|
+
const researchIds = result.spawn_instructions.map((i) => i.research_id);
|
|
606
|
+
const uniqueIds = new Set(researchIds);
|
|
607
|
+
expect(uniqueIds.size).toBe(researchIds.length);
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
test("runResearchPhase with empty tech_stack returns empty spawn_instructions", async () => {
|
|
611
|
+
// Don't create package.json - no dependencies
|
|
612
|
+
|
|
613
|
+
const result = await runResearchPhase(
|
|
614
|
+
"Implement something with FooBarBaz",
|
|
615
|
+
testProjectPath,
|
|
616
|
+
);
|
|
617
|
+
|
|
618
|
+
// Should have empty tech_stack (no known technologies)
|
|
619
|
+
expect(result.tech_stack).toEqual([]);
|
|
620
|
+
|
|
621
|
+
// Should have empty spawn_instructions
|
|
622
|
+
expect(result.spawn_instructions).toEqual([]);
|
|
623
|
+
|
|
624
|
+
// Other fields should be empty
|
|
625
|
+
expect(result.summaries).toEqual({});
|
|
626
|
+
expect(result.memory_ids).toEqual([]);
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
test("spawn instruction prompts include swarmmail_init", async () => {
|
|
630
|
+
const packageJson = {
|
|
631
|
+
dependencies: {
|
|
632
|
+
zod: "^3.22.4",
|
|
633
|
+
},
|
|
634
|
+
};
|
|
635
|
+
|
|
636
|
+
writeFileSync(
|
|
637
|
+
join(testProjectPath, "package.json"),
|
|
638
|
+
JSON.stringify(packageJson, null, 2),
|
|
639
|
+
);
|
|
640
|
+
|
|
641
|
+
const result = await runResearchPhase("Use Zod", testProjectPath);
|
|
642
|
+
|
|
643
|
+
// Prompt should include swarmmail_init (researcher workers need this)
|
|
644
|
+
const instruction = result.spawn_instructions[0];
|
|
645
|
+
expect(instruction.prompt).toContain("swarmmail_init");
|
|
646
|
+
expect(instruction.prompt).toContain("semantic-memory_store");
|
|
647
|
+
});
|
|
648
|
+
});
|
|
649
|
+
|
|
498
650
|
describe("Real-world fixture: this repo", () => {
|
|
499
651
|
test("discovers tools and versions from actual repo", async () => {
|
|
500
652
|
// Use the plugin package directory, not monorepo root
|
|
@@ -540,5 +692,10 @@ describe("Real-world fixture: this repo", () => {
|
|
|
540
692
|
expect(result.summaries).toBeDefined();
|
|
541
693
|
expect(result.memory_ids).toBeDefined();
|
|
542
694
|
expect(Array.isArray(result.memory_ids)).toBe(true);
|
|
695
|
+
|
|
696
|
+
// NEW: Should have spawn_instructions
|
|
697
|
+
expect(result.spawn_instructions).toBeDefined();
|
|
698
|
+
expect(Array.isArray(result.spawn_instructions)).toBe(true);
|
|
699
|
+
expect(result.spawn_instructions.length).toBeGreaterThan(0);
|
|
543
700
|
});
|
|
544
701
|
});
|
package/src/swarm-review.ts
CHANGED
|
@@ -470,7 +470,7 @@ export const swarm_review_feedback = tool({
|
|
|
470
470
|
.optional()
|
|
471
471
|
.describe("JSON array of ReviewIssue objects (for needs_changes)"),
|
|
472
472
|
},
|
|
473
|
-
async execute(args): Promise<string> {
|
|
473
|
+
async execute(args, _ctx): Promise<string> {
|
|
474
474
|
// Parse issues if provided
|
|
475
475
|
let parsedIssues: ReviewIssue[] = [];
|
|
476
476
|
if (args.issues) {
|
|
@@ -512,7 +512,7 @@ export const swarm_review_feedback = tool({
|
|
|
512
512
|
// Capture review approval decision
|
|
513
513
|
try {
|
|
514
514
|
captureCoordinatorEvent({
|
|
515
|
-
session_id:
|
|
515
|
+
session_id: _ctx.sessionID || "unknown",
|
|
516
516
|
epic_id: epicId,
|
|
517
517
|
timestamp: new Date().toISOString(),
|
|
518
518
|
event_type: "DECISION",
|
|
@@ -562,7 +562,7 @@ You may now complete the task with \`swarm_complete\`.`,
|
|
|
562
562
|
// Capture review rejection decision
|
|
563
563
|
try {
|
|
564
564
|
captureCoordinatorEvent({
|
|
565
|
-
session_id:
|
|
565
|
+
session_id: _ctx.sessionID || "unknown",
|
|
566
566
|
epic_id: epicId,
|
|
567
567
|
timestamp: new Date().toISOString(),
|
|
568
568
|
event_type: "DECISION",
|
|
File without changes
|