opencode-swarm-plugin 0.25.2 → 0.25.3
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/.turbo/turbo-build.log +2 -2
- package/CHANGELOG.md +20 -0
- package/dist/beads.d.ts +6 -0
- package/dist/beads.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +192 -287
- package/dist/plugin.js +191 -292
- package/dist/rate-limiter.d.ts.map +1 -1
- package/dist/storage.d.ts.map +1 -1
- package/dist/swarm-orchestrate.d.ts.map +1 -1
- package/docs/swarm-mail-architecture.md +1 -1
- package/package.json +2 -2
- package/src/beads.integration.test.ts +55 -61
- package/src/beads.ts +239 -410
- package/src/index.ts +1 -15
- package/src/rate-limiter.ts +0 -5
- package/src/storage.ts +0 -9
- package/src/swarm-mail.integration.test.ts +5 -1
- package/src/swarm-orchestrate.ts +24 -14
- package/src/swarm.integration.test.ts +83 -0
- package/src/agent-mail.integration.test.ts +0 -1429
package/src/index.ts
CHANGED
|
@@ -121,9 +121,6 @@ export const SwarmPlugin: Plugin = async (
|
|
|
121
121
|
});
|
|
122
122
|
|
|
123
123
|
if (response.ok) {
|
|
124
|
-
console.log(
|
|
125
|
-
`[swarm-plugin] Auto-released ${activeAgentMailState.reservations.length} file reservation(s)`,
|
|
126
|
-
);
|
|
127
124
|
activeAgentMailState.reservations = [];
|
|
128
125
|
}
|
|
129
126
|
} catch (error) {
|
|
@@ -202,9 +199,6 @@ export const SwarmPlugin: Plugin = async (
|
|
|
202
199
|
const guardrailResult = guardrailOutput(toolName, output.output);
|
|
203
200
|
if (guardrailResult.truncated) {
|
|
204
201
|
output.output = guardrailResult.output;
|
|
205
|
-
console.log(
|
|
206
|
-
`[swarm-plugin] Guardrail truncated ${toolName}: ${guardrailResult.originalLength} → ${guardrailResult.truncatedLength} chars`,
|
|
207
|
-
);
|
|
208
202
|
}
|
|
209
203
|
}
|
|
210
204
|
|
|
@@ -242,20 +236,12 @@ export const SwarmPlugin: Plugin = async (
|
|
|
242
236
|
// Auto-release after swarm:complete
|
|
243
237
|
if (toolName === "swarm_complete" && activeAgentMailState) {
|
|
244
238
|
await releaseReservations();
|
|
245
|
-
console.log(
|
|
246
|
-
"[swarm-plugin] Auto-released reservations after swarm:complete",
|
|
247
|
-
);
|
|
248
239
|
}
|
|
249
240
|
|
|
250
241
|
// Auto-sync beads after closing
|
|
251
242
|
if (toolName === "beads_close") {
|
|
252
243
|
// Trigger async sync without blocking - fire and forget
|
|
253
|
-
void $`bd sync
|
|
254
|
-
.quiet()
|
|
255
|
-
.nothrow()
|
|
256
|
-
.then(() => {
|
|
257
|
-
console.log("[swarm-plugin] Auto-synced beads after close");
|
|
258
|
-
});
|
|
244
|
+
void $`bd sync`.quiet().nothrow();
|
|
259
245
|
}
|
|
260
246
|
},
|
|
261
247
|
};
|
package/src/rate-limiter.ts
CHANGED
|
@@ -490,11 +490,6 @@ export class SqliteRateLimiter implements RateLimiter {
|
|
|
490
490
|
if (result.changes < BATCH_SIZE) break;
|
|
491
491
|
}
|
|
492
492
|
|
|
493
|
-
if (totalDeleted > 0) {
|
|
494
|
-
console.log("[RateLimiter] Cleanup completed:", {
|
|
495
|
-
deletedRows: totalDeleted,
|
|
496
|
-
});
|
|
497
|
-
}
|
|
498
493
|
}
|
|
499
494
|
|
|
500
495
|
async recordRequest(agentName: string, endpoint: string): Promise<void> {
|
package/src/storage.ts
CHANGED
|
@@ -329,10 +329,6 @@ export class SemanticMemoryStorage implements LearningStorage {
|
|
|
329
329
|
constructor(config: Partial<StorageConfig> = {}) {
|
|
330
330
|
// Use getDefaultStorageConfig() to ensure env vars are read at runtime
|
|
331
331
|
this.config = { ...getDefaultStorageConfig(), ...config };
|
|
332
|
-
console.log(
|
|
333
|
-
`[storage] SemanticMemoryStorage initialized with collections:`,
|
|
334
|
-
this.config.collections,
|
|
335
|
-
);
|
|
336
332
|
}
|
|
337
333
|
|
|
338
334
|
// -------------------------------------------------------------------------
|
|
@@ -381,7 +377,6 @@ export class SemanticMemoryStorage implements LearningStorage {
|
|
|
381
377
|
args.push("--metadata", JSON.stringify(metadata));
|
|
382
378
|
}
|
|
383
379
|
|
|
384
|
-
console.log(`[storage] store() -> collection="${collection}"`);
|
|
385
380
|
sessionStats.storesCount++;
|
|
386
381
|
|
|
387
382
|
const result = await execSemanticMemory(args);
|
|
@@ -416,9 +411,6 @@ export class SemanticMemoryStorage implements LearningStorage {
|
|
|
416
411
|
args.push("--fts");
|
|
417
412
|
}
|
|
418
413
|
|
|
419
|
-
console.log(
|
|
420
|
-
`[storage] find() -> collection="${collection}", query="${query.slice(0, 50)}${query.length > 50 ? "..." : ""}", limit=${limit}, fts=${useFts}`,
|
|
421
|
-
);
|
|
422
414
|
sessionStats.queriesCount++;
|
|
423
415
|
|
|
424
416
|
const result = await execSemanticMemory(args);
|
|
@@ -456,7 +448,6 @@ export class SemanticMemoryStorage implements LearningStorage {
|
|
|
456
448
|
}
|
|
457
449
|
|
|
458
450
|
private async list<T>(collection: string): Promise<T[]> {
|
|
459
|
-
console.log(`[storage] list() -> collection="${collection}"`);
|
|
460
451
|
sessionStats.queriesCount++;
|
|
461
452
|
|
|
462
453
|
const result = await execSemanticMemory([
|
|
@@ -9,7 +9,11 @@
|
|
|
9
9
|
|
|
10
10
|
import { randomUUID } from "node:crypto";
|
|
11
11
|
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
resetDatabase,
|
|
14
|
+
getDatabase,
|
|
15
|
+
closeDatabase,
|
|
16
|
+
} from "swarm-mail";
|
|
13
17
|
import {
|
|
14
18
|
swarmmail_init,
|
|
15
19
|
swarmmail_send,
|
package/src/swarm-orchestrate.ts
CHANGED
|
@@ -1031,7 +1031,7 @@ export const swarm_complete = tool({
|
|
|
1031
1031
|
.optional()
|
|
1032
1032
|
.describe("Number of retry attempts during task"),
|
|
1033
1033
|
},
|
|
1034
|
-
async execute(args) {
|
|
1034
|
+
async execute(args, _ctx) {
|
|
1035
1035
|
// Extract epic ID early for error notifications
|
|
1036
1036
|
const epicId = args.bead_id.includes(".")
|
|
1037
1037
|
? args.bead_id.split(".")[0]
|
|
@@ -1295,9 +1295,6 @@ Continuing with completion, but this should be fixed for future subtasks.`;
|
|
|
1295
1295
|
|
|
1296
1296
|
if (storeResult.exitCode === 0) {
|
|
1297
1297
|
memoryStored = true;
|
|
1298
|
-
console.log(
|
|
1299
|
-
`[swarm_complete] Stored learning for ${args.bead_id} in semantic-memory`,
|
|
1300
|
-
);
|
|
1301
1298
|
} else {
|
|
1302
1299
|
memoryError = `semantic-memory store failed: ${storeResult.stderr.toString().slice(0, 200)}`;
|
|
1303
1300
|
console.warn(`[swarm_complete] ${memoryError}`);
|
|
@@ -1351,15 +1348,27 @@ Continuing with completion, but this should be fixed for future subtasks.`;
|
|
|
1351
1348
|
.filter(Boolean)
|
|
1352
1349
|
.join("\n");
|
|
1353
1350
|
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1351
|
+
// Send completion message (non-fatal if it fails)
|
|
1352
|
+
let messageSent = false;
|
|
1353
|
+
let messageError: string | undefined;
|
|
1354
|
+
try {
|
|
1355
|
+
await sendSwarmMessage({
|
|
1356
|
+
projectPath: args.project_key,
|
|
1357
|
+
fromAgent: args.agent_name,
|
|
1358
|
+
toAgents: [], // Thread broadcast
|
|
1359
|
+
subject: `Complete: ${args.bead_id}`,
|
|
1360
|
+
body: completionBody,
|
|
1361
|
+
threadId: epicId,
|
|
1362
|
+
importance: "normal",
|
|
1363
|
+
});
|
|
1364
|
+
messageSent = true;
|
|
1365
|
+
} catch (error) {
|
|
1366
|
+
// Non-fatal - log and continue
|
|
1367
|
+
messageError = error instanceof Error ? error.message : String(error);
|
|
1368
|
+
console.warn(
|
|
1369
|
+
`[swarm_complete] Failed to send completion message: ${messageError}`,
|
|
1370
|
+
);
|
|
1371
|
+
}
|
|
1363
1372
|
|
|
1364
1373
|
// Build success response with semantic-memory integration
|
|
1365
1374
|
const response = {
|
|
@@ -1367,7 +1376,8 @@ Continuing with completion, but this should be fixed for future subtasks.`;
|
|
|
1367
1376
|
bead_id: args.bead_id,
|
|
1368
1377
|
closed: true,
|
|
1369
1378
|
reservations_released: true,
|
|
1370
|
-
message_sent:
|
|
1379
|
+
message_sent: messageSent,
|
|
1380
|
+
message_error: messageError,
|
|
1371
1381
|
agent_registration: {
|
|
1372
1382
|
verified: agentRegistered,
|
|
1373
1383
|
warning: registrationWarning || undefined,
|
|
@@ -1548,6 +1548,89 @@ describe("Swarm Prompt V2 (with Swarm Mail/Beads)", () => {
|
|
|
1548
1548
|
},
|
|
1549
1549
|
);
|
|
1550
1550
|
});
|
|
1551
|
+
|
|
1552
|
+
describe("swarm_complete error handling", () => {
|
|
1553
|
+
let beadsAvailable = false;
|
|
1554
|
+
|
|
1555
|
+
beforeAll(async () => {
|
|
1556
|
+
beadsAvailable = await isBeadsAvailable();
|
|
1557
|
+
});
|
|
1558
|
+
|
|
1559
|
+
it.skipIf(!beadsAvailable)(
|
|
1560
|
+
"returns structured error when bead close fails",
|
|
1561
|
+
async () => {
|
|
1562
|
+
// Try to complete a non-existent bead
|
|
1563
|
+
const result = await swarm_complete.execute(
|
|
1564
|
+
{
|
|
1565
|
+
project_key: "/tmp/test-error-handling",
|
|
1566
|
+
agent_name: "test-agent",
|
|
1567
|
+
bead_id: "bd-nonexistent-12345",
|
|
1568
|
+
summary: "This should fail",
|
|
1569
|
+
skip_verification: true,
|
|
1570
|
+
},
|
|
1571
|
+
mockContext,
|
|
1572
|
+
);
|
|
1573
|
+
|
|
1574
|
+
const parsed = JSON.parse(result);
|
|
1575
|
+
|
|
1576
|
+
// Should return structured error, not throw
|
|
1577
|
+
expect(parsed.success).toBe(false);
|
|
1578
|
+
expect(parsed.error).toContain("Failed to close bead");
|
|
1579
|
+
expect(parsed.failed_step).toBe("bd close");
|
|
1580
|
+
expect(parsed.bead_id).toBe("bd-nonexistent-12345");
|
|
1581
|
+
expect(parsed.recovery).toBeDefined();
|
|
1582
|
+
expect(parsed.recovery.steps).toBeInstanceOf(Array);
|
|
1583
|
+
},
|
|
1584
|
+
);
|
|
1585
|
+
|
|
1586
|
+
it.skipIf(!beadsAvailable)(
|
|
1587
|
+
"includes message_sent status in response",
|
|
1588
|
+
async () => {
|
|
1589
|
+
const createResult =
|
|
1590
|
+
await Bun.$`bd create "Test message status" -t task --json`
|
|
1591
|
+
.quiet()
|
|
1592
|
+
.nothrow();
|
|
1593
|
+
|
|
1594
|
+
if (createResult.exitCode !== 0) {
|
|
1595
|
+
console.warn(
|
|
1596
|
+
"Could not create bead:",
|
|
1597
|
+
createResult.stderr.toString(),
|
|
1598
|
+
);
|
|
1599
|
+
return;
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
const bead = JSON.parse(createResult.stdout.toString());
|
|
1603
|
+
|
|
1604
|
+
try {
|
|
1605
|
+
const result = await swarm_complete.execute(
|
|
1606
|
+
{
|
|
1607
|
+
project_key: "/tmp/test-message-status",
|
|
1608
|
+
agent_name: "test-agent",
|
|
1609
|
+
bead_id: bead.id,
|
|
1610
|
+
summary: "Test message status tracking",
|
|
1611
|
+
skip_verification: true,
|
|
1612
|
+
},
|
|
1613
|
+
mockContext,
|
|
1614
|
+
);
|
|
1615
|
+
|
|
1616
|
+
const parsed = JSON.parse(result);
|
|
1617
|
+
|
|
1618
|
+
// Should have message_sent field (true or false)
|
|
1619
|
+
expect(parsed).toHaveProperty("message_sent");
|
|
1620
|
+
// If message failed, should have message_error
|
|
1621
|
+
if (!parsed.message_sent) {
|
|
1622
|
+
expect(parsed).toHaveProperty("message_error");
|
|
1623
|
+
}
|
|
1624
|
+
} catch (error) {
|
|
1625
|
+
// Clean up bead if test fails
|
|
1626
|
+
await Bun.$`bd close ${bead.id} --reason "Test cleanup"`
|
|
1627
|
+
.quiet()
|
|
1628
|
+
.nothrow();
|
|
1629
|
+
throw error;
|
|
1630
|
+
}
|
|
1631
|
+
},
|
|
1632
|
+
);
|
|
1633
|
+
});
|
|
1551
1634
|
});
|
|
1552
1635
|
|
|
1553
1636
|
// ============================================================================
|