opencode-swarm-plugin 0.30.7 → 0.31.0

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.
@@ -72,7 +72,7 @@ import {
72
72
  isToolAvailable,
73
73
  warnMissingTool,
74
74
  } from "./tool-availability";
75
- import { getHiveAdapter } from "./hive";
75
+ import { getHiveAdapter, hive_sync, setHiveWorkingDirectory, getHiveWorkingDirectory } from "./hive";
76
76
  import { listSkills } from "./skills";
77
77
  import {
78
78
  canUseWorktreeIsolation,
@@ -1570,6 +1570,30 @@ This will be recorded as a negative learning signal.`;
1570
1570
  );
1571
1571
  }
1572
1572
 
1573
+ // Sync cell to .hive/issues.jsonl (auto-sync on complete)
1574
+ // This ensures the worker's completed work persists before process exits
1575
+ let syncSuccess = false;
1576
+ let syncError: string | undefined;
1577
+ try {
1578
+ // Save current working directory and set to project path
1579
+ const previousWorkingDir = getHiveWorkingDirectory();
1580
+ setHiveWorkingDirectory(args.project_key);
1581
+
1582
+ try {
1583
+ const syncResult = await hive_sync.execute({ auto_pull: false }, _ctx);
1584
+ syncSuccess = !syncResult.includes("error");
1585
+ } finally {
1586
+ // Restore previous working directory
1587
+ setHiveWorkingDirectory(previousWorkingDir);
1588
+ }
1589
+ } catch (error) {
1590
+ // Non-fatal - log warning but don't block completion
1591
+ syncError = error instanceof Error ? error.message : String(error);
1592
+ console.warn(
1593
+ `[swarm_complete] Auto-sync failed (non-fatal): ${syncError}`,
1594
+ );
1595
+ }
1596
+
1573
1597
  // Emit SubtaskOutcomeEvent for learning system
1574
1598
  try {
1575
1599
  const epicId = args.bead_id.includes(".")
@@ -1709,6 +1733,8 @@ This will be recorded as a negative learning signal.`;
1709
1733
  bead_id: args.bead_id,
1710
1734
  closed: true,
1711
1735
  reservations_released: true,
1736
+ synced: syncSuccess,
1737
+ sync_error: syncError,
1712
1738
  message_sent: messageSent,
1713
1739
  message_error: messageError,
1714
1740
  agent_registration: {
@@ -46,7 +46,7 @@ Agents MUST update their cell status as they work. No silent progress.
46
46
 
47
47
  ## Requirements
48
48
 
49
- 1. **Break into 2-{max_subtasks} independent subtasks** that can run in parallel
49
+ 1. **Break into independent subtasks** that can run in parallel (as many as needed)
50
50
  2. **Assign files** - each subtask must specify which files it will modify
51
51
  3. **No file overlap** - files cannot appear in multiple subtasks (they get exclusive locks)
52
52
  4. **Order by dependency** - if subtask B needs subtask A's output, A must come first in the array
@@ -123,7 +123,7 @@ Agents MUST update their cell status as they work. No silent progress.
123
123
 
124
124
  ## Requirements
125
125
 
126
- 1. **Break into 2-{max_subtasks} independent subtasks** that can run in parallel
126
+ 1. **Break into independent subtasks** that can run in parallel (as many as needed)
127
127
  2. **Assign files** - each subtask must specify which files it will modify
128
128
  3. **No file overlap** - files cannot appear in multiple subtasks (they get exclusive locks)
129
129
  4. **Order by dependency** - if subtask B needs subtask A's output, A must come first in the array
@@ -927,10 +927,9 @@ export const swarm_plan_prompt = tool({
927
927
  max_subtasks: tool.schema
928
928
  .number()
929
929
  .int()
930
- .min(2)
931
- .max(10)
932
- .default(5)
933
- .describe("Maximum number of subtasks (default: 5)"),
930
+ .min(1)
931
+ .optional()
932
+ .describe("Suggested max subtasks (optional - LLM decides if not specified)"),
934
933
  context: tool.schema
935
934
  .string()
936
935
  .optional()
@@ -943,7 +942,6 @@ export const swarm_plan_prompt = tool({
943
942
  .number()
944
943
  .int()
945
944
  .min(1)
946
- .max(10)
947
945
  .optional()
948
946
  .describe("Max CASS results to include (default: 3)"),
949
947
  include_skills: tool.schema
@@ -2341,4 +2341,74 @@ describe("Contract Validation", () => {
2341
2341
  expect(parsed.error).toBeUndefined();
2342
2342
  });
2343
2343
  });
2344
+
2345
+ describe("swarm_complete auto-sync", () => {
2346
+ it("calls hive_sync after closing cell on successful completion", async () => {
2347
+ const testProjectPath = "/tmp/swarm-auto-sync-test-" + Date.now();
2348
+ const { getHiveAdapter } = await import("./hive");
2349
+ const adapter = await getHiveAdapter(testProjectPath);
2350
+
2351
+ // Create a task cell directly
2352
+ const cell = await adapter.createCell(testProjectPath, {
2353
+ title: "Test task for auto-sync",
2354
+ type: "task",
2355
+ priority: 2,
2356
+ });
2357
+
2358
+ // Start the task
2359
+ await adapter.updateCell(testProjectPath, cell.id, {
2360
+ status: "in_progress",
2361
+ });
2362
+
2363
+ // Complete with skip_review and skip_verification
2364
+ const result = await swarm_complete.execute(
2365
+ {
2366
+ project_key: testProjectPath,
2367
+ agent_name: "TestAgent",
2368
+ bead_id: cell.id,
2369
+ summary: "Done - testing auto-sync",
2370
+ files_touched: [],
2371
+ skip_verification: true,
2372
+ skip_review: true,
2373
+ },
2374
+ mockContext,
2375
+ );
2376
+
2377
+ const parsed = JSON.parse(result);
2378
+
2379
+ // Should complete successfully
2380
+ expect(parsed.success).toBe(true);
2381
+ expect(parsed.closed).toBe(true);
2382
+
2383
+ // Check that cell is actually closed in database
2384
+ const closedCell = await adapter.getCell(testProjectPath, cell.id);
2385
+ expect(closedCell?.status).toBe("closed");
2386
+
2387
+ // The sync should have flushed the cell to .hive/issues.jsonl
2388
+ // We can verify the cell appears in the JSONL
2389
+ const hivePath = `${testProjectPath}/.hive/issues.jsonl`;
2390
+ const hiveFile = Bun.file(hivePath);
2391
+ const exists = await hiveFile.exists();
2392
+
2393
+ // The file should exist after sync
2394
+ expect(exists).toBe(true);
2395
+
2396
+ if (exists) {
2397
+ const content = await hiveFile.text();
2398
+ const lines = content.trim().split("\n");
2399
+
2400
+ // Should have at least one cell exported
2401
+ expect(lines.length).toBeGreaterThan(0);
2402
+
2403
+ // Parse the exported cells to find our closed cell
2404
+ const cells = lines.map((line) => JSON.parse(line));
2405
+ const exportedCell = cells.find((c) => c.id === cell.id);
2406
+
2407
+ // Our cell should be in the export
2408
+ expect(exportedCell).toBeDefined();
2409
+ expect(exportedCell.status).toBe("closed");
2410
+ expect(exportedCell.title).toBe("Test task for auto-sync");
2411
+ }
2412
+ });
2413
+ });
2344
2414
  });