opencode-swarm-plugin 0.12.15 → 0.12.17
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/.beads/issues.jsonl +17 -17
- package/dist/index.js +138 -50
- package/dist/plugin.js +130 -48
- package/package.json +1 -1
- package/src/beads.ts +201 -67
- package/src/index.ts +6 -2
- package/src/storage.ts +14 -2
package/src/beads.ts
CHANGED
|
@@ -9,9 +9,89 @@
|
|
|
9
9
|
* - Validate all output with Zod schemas
|
|
10
10
|
* - Throw typed errors on failure
|
|
11
11
|
* - Support atomic epic creation with rollback hints
|
|
12
|
+
*
|
|
13
|
+
* IMPORTANT: Call setBeadsWorkingDirectory() before using tools to ensure
|
|
14
|
+
* bd commands run in the correct project directory.
|
|
12
15
|
*/
|
|
13
16
|
import { tool } from "@opencode-ai/plugin";
|
|
14
17
|
import { z } from "zod";
|
|
18
|
+
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// Working Directory Configuration
|
|
21
|
+
// ============================================================================
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Module-level working directory for bd commands.
|
|
25
|
+
* Set this via setBeadsWorkingDirectory() before using tools.
|
|
26
|
+
* If not set, commands run in process.cwd() which may be wrong for plugins.
|
|
27
|
+
*/
|
|
28
|
+
let beadsWorkingDirectory: string | null = null;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Set the working directory for all beads commands.
|
|
32
|
+
* Call this from the plugin initialization with the project directory.
|
|
33
|
+
*
|
|
34
|
+
* @param directory - Absolute path to the project directory
|
|
35
|
+
*/
|
|
36
|
+
export function setBeadsWorkingDirectory(directory: string): void {
|
|
37
|
+
beadsWorkingDirectory = directory;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Get the current working directory for beads commands.
|
|
42
|
+
* Returns the configured directory or process.cwd() as fallback.
|
|
43
|
+
*/
|
|
44
|
+
export function getBeadsWorkingDirectory(): string {
|
|
45
|
+
return beadsWorkingDirectory || process.cwd();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Run a bd command in the correct working directory.
|
|
50
|
+
* Uses Bun.spawn with cwd option to ensure commands run in project directory.
|
|
51
|
+
*/
|
|
52
|
+
async function runBdCommand(
|
|
53
|
+
args: string[],
|
|
54
|
+
): Promise<{ exitCode: number; stdout: string; stderr: string }> {
|
|
55
|
+
const cwd = getBeadsWorkingDirectory();
|
|
56
|
+
const proc = Bun.spawn(["bd", ...args], {
|
|
57
|
+
cwd,
|
|
58
|
+
stdout: "pipe",
|
|
59
|
+
stderr: "pipe",
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const [stdout, stderr] = await Promise.all([
|
|
63
|
+
new Response(proc.stdout).text(),
|
|
64
|
+
new Response(proc.stderr).text(),
|
|
65
|
+
]);
|
|
66
|
+
|
|
67
|
+
const exitCode = await proc.exited;
|
|
68
|
+
|
|
69
|
+
return { exitCode, stdout, stderr };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Run a git command in the correct working directory.
|
|
74
|
+
*/
|
|
75
|
+
async function runGitCommand(
|
|
76
|
+
args: string[],
|
|
77
|
+
): Promise<{ exitCode: number; stdout: string; stderr: string }> {
|
|
78
|
+
const cwd = getBeadsWorkingDirectory();
|
|
79
|
+
const proc = Bun.spawn(["git", ...args], {
|
|
80
|
+
cwd,
|
|
81
|
+
stdout: "pipe",
|
|
82
|
+
stderr: "pipe",
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const [stdout, stderr] = await Promise.all([
|
|
86
|
+
new Response(proc.stdout).text(),
|
|
87
|
+
new Response(proc.stderr).text(),
|
|
88
|
+
]);
|
|
89
|
+
|
|
90
|
+
const exitCode = await proc.exited;
|
|
91
|
+
|
|
92
|
+
return { exitCode, stdout, stderr };
|
|
93
|
+
}
|
|
94
|
+
|
|
15
95
|
import {
|
|
16
96
|
BeadSchema,
|
|
17
97
|
BeadCreateArgsSchema,
|
|
@@ -159,19 +239,40 @@ export const beads_create = tool({
|
|
|
159
239
|
const validated = BeadCreateArgsSchema.parse(args);
|
|
160
240
|
const cmdParts = buildCreateCommand(validated);
|
|
161
241
|
|
|
162
|
-
// Execute command
|
|
163
|
-
const result = await
|
|
242
|
+
// Execute command in the correct working directory
|
|
243
|
+
const result = await runBdCommand(cmdParts.slice(1)); // Remove 'bd' prefix
|
|
164
244
|
|
|
165
245
|
if (result.exitCode !== 0) {
|
|
166
246
|
throw new BeadError(
|
|
167
|
-
`Failed to create bead: ${result.stderr
|
|
247
|
+
`Failed to create bead: ${result.stderr}`,
|
|
168
248
|
cmdParts.join(" "),
|
|
169
249
|
result.exitCode,
|
|
170
|
-
result.stderr
|
|
250
|
+
result.stderr,
|
|
171
251
|
);
|
|
172
252
|
}
|
|
173
253
|
|
|
174
|
-
|
|
254
|
+
// Validate output before parsing
|
|
255
|
+
const stdout = result.stdout.trim();
|
|
256
|
+
if (!stdout) {
|
|
257
|
+
throw new BeadError(
|
|
258
|
+
"bd create returned empty output",
|
|
259
|
+
cmdParts.join(" "),
|
|
260
|
+
0,
|
|
261
|
+
"Empty stdout",
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Check for error messages in stdout (bd sometimes outputs errors to stdout)
|
|
266
|
+
if (stdout.startsWith("error:") || stdout.startsWith("Error:")) {
|
|
267
|
+
throw new BeadError(
|
|
268
|
+
`bd create failed: ${stdout}`,
|
|
269
|
+
cmdParts.join(" "),
|
|
270
|
+
0,
|
|
271
|
+
stdout,
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const bead = parseBead(stdout);
|
|
175
276
|
return JSON.stringify(bead, null, 2);
|
|
176
277
|
},
|
|
177
278
|
});
|
|
@@ -210,17 +311,17 @@ export const beads_create_epic = tool({
|
|
|
210
311
|
description: validated.epic_description,
|
|
211
312
|
});
|
|
212
313
|
|
|
213
|
-
const epicResult = await
|
|
314
|
+
const epicResult = await runBdCommand(epicCmd.slice(1)); // Remove 'bd' prefix
|
|
214
315
|
|
|
215
316
|
if (epicResult.exitCode !== 0) {
|
|
216
317
|
throw new BeadError(
|
|
217
|
-
`Failed to create epic: ${epicResult.stderr
|
|
318
|
+
`Failed to create epic: ${epicResult.stderr}`,
|
|
218
319
|
epicCmd.join(" "),
|
|
219
320
|
epicResult.exitCode,
|
|
220
321
|
);
|
|
221
322
|
}
|
|
222
323
|
|
|
223
|
-
const epic = parseBead(epicResult.stdout
|
|
324
|
+
const epic = parseBead(epicResult.stdout);
|
|
224
325
|
created.push(epic);
|
|
225
326
|
|
|
226
327
|
// 2. Create subtasks
|
|
@@ -232,17 +333,17 @@ export const beads_create_epic = tool({
|
|
|
232
333
|
parent_id: epic.id,
|
|
233
334
|
});
|
|
234
335
|
|
|
235
|
-
const subtaskResult = await
|
|
336
|
+
const subtaskResult = await runBdCommand(subtaskCmd.slice(1)); // Remove 'bd' prefix
|
|
236
337
|
|
|
237
338
|
if (subtaskResult.exitCode !== 0) {
|
|
238
339
|
throw new BeadError(
|
|
239
|
-
`Failed to create subtask: ${subtaskResult.stderr
|
|
340
|
+
`Failed to create subtask: ${subtaskResult.stderr}`,
|
|
240
341
|
subtaskCmd.join(" "),
|
|
241
342
|
subtaskResult.exitCode,
|
|
242
343
|
);
|
|
243
344
|
}
|
|
244
345
|
|
|
245
|
-
const subtaskBead = parseBead(subtaskResult.stdout
|
|
346
|
+
const subtaskBead = parseBead(subtaskResult.stdout);
|
|
246
347
|
created.push(subtaskBead);
|
|
247
348
|
}
|
|
248
349
|
|
|
@@ -256,33 +357,53 @@ export const beads_create_epic = tool({
|
|
|
256
357
|
} catch (error) {
|
|
257
358
|
// Partial failure - execute rollback automatically
|
|
258
359
|
const rollbackCommands: string[] = [];
|
|
360
|
+
const rollbackErrors: string[] = [];
|
|
259
361
|
|
|
260
362
|
for (const bead of created) {
|
|
261
363
|
try {
|
|
262
|
-
const
|
|
263
|
-
"bd",
|
|
364
|
+
const closeArgs = [
|
|
264
365
|
"close",
|
|
265
366
|
bead.id,
|
|
266
367
|
"--reason",
|
|
267
368
|
"Rollback partial epic",
|
|
268
369
|
"--json",
|
|
269
370
|
];
|
|
270
|
-
await
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
371
|
+
const rollbackResult = await runBdCommand(closeArgs);
|
|
372
|
+
if (rollbackResult.exitCode === 0) {
|
|
373
|
+
rollbackCommands.push(
|
|
374
|
+
`bd close ${bead.id} --reason "Rollback partial epic"`,
|
|
375
|
+
);
|
|
376
|
+
} else {
|
|
377
|
+
rollbackErrors.push(
|
|
378
|
+
`${bead.id}: exit ${rollbackResult.exitCode} - ${rollbackResult.stderr.trim()}`,
|
|
379
|
+
);
|
|
380
|
+
}
|
|
274
381
|
} catch (rollbackError) {
|
|
275
|
-
// Log rollback failure
|
|
382
|
+
// Log rollback failure and collect error
|
|
383
|
+
const errMsg =
|
|
384
|
+
rollbackError instanceof Error
|
|
385
|
+
? rollbackError.message
|
|
386
|
+
: String(rollbackError);
|
|
276
387
|
console.error(`Failed to rollback bead ${bead.id}:`, rollbackError);
|
|
388
|
+
rollbackErrors.push(`${bead.id}: ${errMsg}`);
|
|
277
389
|
}
|
|
278
390
|
}
|
|
279
391
|
|
|
280
|
-
// Throw error with rollback info
|
|
392
|
+
// Throw error with rollback info including any failures
|
|
281
393
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
394
|
+
let rollbackInfo = "";
|
|
395
|
+
|
|
396
|
+
if (rollbackCommands.length > 0) {
|
|
397
|
+
rollbackInfo += `\n\nRolled back ${rollbackCommands.length} bead(s):\n${rollbackCommands.join("\n")}`;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
if (rollbackErrors.length > 0) {
|
|
401
|
+
rollbackInfo += `\n\nRollback failures (${rollbackErrors.length}):\n${rollbackErrors.join("\n")}`;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if (!rollbackInfo) {
|
|
405
|
+
rollbackInfo = "\n\nNo beads to rollback.";
|
|
406
|
+
}
|
|
286
407
|
|
|
287
408
|
throw new BeadError(
|
|
288
409
|
`Epic creation failed: ${errorMsg}${rollbackInfo}`,
|
|
@@ -333,17 +454,17 @@ export const beads_query = tool({
|
|
|
333
454
|
}
|
|
334
455
|
}
|
|
335
456
|
|
|
336
|
-
const result = await
|
|
457
|
+
const result = await runBdCommand(cmd.slice(1)); // Remove 'bd' prefix
|
|
337
458
|
|
|
338
459
|
if (result.exitCode !== 0) {
|
|
339
460
|
throw new BeadError(
|
|
340
|
-
`Failed to query beads: ${result.stderr
|
|
461
|
+
`Failed to query beads: ${result.stderr}`,
|
|
341
462
|
cmd.join(" "),
|
|
342
463
|
result.exitCode,
|
|
343
464
|
);
|
|
344
465
|
}
|
|
345
466
|
|
|
346
|
-
const beads = parseBeads(result.stdout
|
|
467
|
+
const beads = parseBeads(result.stdout);
|
|
347
468
|
const limited = beads.slice(0, validated.limit);
|
|
348
469
|
|
|
349
470
|
return JSON.stringify(limited, null, 2);
|
|
@@ -385,17 +506,17 @@ export const beads_update = tool({
|
|
|
385
506
|
}
|
|
386
507
|
cmd.push("--json");
|
|
387
508
|
|
|
388
|
-
const result = await
|
|
509
|
+
const result = await runBdCommand(cmd.slice(1)); // Remove 'bd' prefix
|
|
389
510
|
|
|
390
511
|
if (result.exitCode !== 0) {
|
|
391
512
|
throw new BeadError(
|
|
392
|
-
`Failed to update bead: ${result.stderr
|
|
513
|
+
`Failed to update bead: ${result.stderr}`,
|
|
393
514
|
cmd.join(" "),
|
|
394
515
|
result.exitCode,
|
|
395
516
|
);
|
|
396
517
|
}
|
|
397
518
|
|
|
398
|
-
const bead = parseBead(result.stdout
|
|
519
|
+
const bead = parseBead(result.stdout);
|
|
399
520
|
return JSON.stringify(bead, null, 2);
|
|
400
521
|
},
|
|
401
522
|
});
|
|
@@ -421,17 +542,17 @@ export const beads_close = tool({
|
|
|
421
542
|
"--json",
|
|
422
543
|
];
|
|
423
544
|
|
|
424
|
-
const result = await
|
|
545
|
+
const result = await runBdCommand(cmd.slice(1)); // Remove 'bd' prefix
|
|
425
546
|
|
|
426
547
|
if (result.exitCode !== 0) {
|
|
427
548
|
throw new BeadError(
|
|
428
|
-
`Failed to close bead: ${result.stderr
|
|
549
|
+
`Failed to close bead: ${result.stderr}`,
|
|
429
550
|
cmd.join(" "),
|
|
430
551
|
result.exitCode,
|
|
431
552
|
);
|
|
432
553
|
}
|
|
433
554
|
|
|
434
|
-
const bead = parseBead(result.stdout
|
|
555
|
+
const bead = parseBead(result.stdout);
|
|
435
556
|
return `Closed ${bead.id}: ${validated.reason}`;
|
|
436
557
|
},
|
|
437
558
|
});
|
|
@@ -446,19 +567,23 @@ export const beads_start = tool({
|
|
|
446
567
|
id: tool.schema.string().describe("Bead ID"),
|
|
447
568
|
},
|
|
448
569
|
async execute(args, ctx) {
|
|
449
|
-
const
|
|
450
|
-
|
|
451
|
-
|
|
570
|
+
const result = await runBdCommand([
|
|
571
|
+
"update",
|
|
572
|
+
args.id,
|
|
573
|
+
"--status",
|
|
574
|
+
"in_progress",
|
|
575
|
+
"--json",
|
|
576
|
+
]);
|
|
452
577
|
|
|
453
578
|
if (result.exitCode !== 0) {
|
|
454
579
|
throw new BeadError(
|
|
455
|
-
`Failed to start bead: ${result.stderr
|
|
456
|
-
|
|
580
|
+
`Failed to start bead: ${result.stderr}`,
|
|
581
|
+
`bd update ${args.id} --status in_progress --json`,
|
|
457
582
|
result.exitCode,
|
|
458
583
|
);
|
|
459
584
|
}
|
|
460
585
|
|
|
461
|
-
const bead = parseBead(result.stdout
|
|
586
|
+
const bead = parseBead(result.stdout);
|
|
462
587
|
return `Started: ${bead.id}`;
|
|
463
588
|
},
|
|
464
589
|
});
|
|
@@ -470,19 +595,17 @@ export const beads_ready = tool({
|
|
|
470
595
|
description: "Get the next ready bead (unblocked, highest priority)",
|
|
471
596
|
args: {},
|
|
472
597
|
async execute(args, ctx) {
|
|
473
|
-
const
|
|
474
|
-
|
|
475
|
-
const result = await Bun.$`${cmd}`.quiet().nothrow();
|
|
598
|
+
const result = await runBdCommand(["ready", "--json"]);
|
|
476
599
|
|
|
477
600
|
if (result.exitCode !== 0) {
|
|
478
601
|
throw new BeadError(
|
|
479
|
-
`Failed to get ready beads: ${result.stderr
|
|
480
|
-
|
|
602
|
+
`Failed to get ready beads: ${result.stderr}`,
|
|
603
|
+
"bd ready --json",
|
|
481
604
|
result.exitCode,
|
|
482
605
|
);
|
|
483
606
|
}
|
|
484
607
|
|
|
485
|
-
const beads = parseBeads(result.stdout
|
|
608
|
+
const beads = parseBeads(result.stdout);
|
|
486
609
|
|
|
487
610
|
if (beads.length === 0) {
|
|
488
611
|
return "No ready beads";
|
|
@@ -510,14 +633,17 @@ export const beads_sync = tool({
|
|
|
510
633
|
|
|
511
634
|
/**
|
|
512
635
|
* Helper to run a command with timeout
|
|
636
|
+
* Properly clears the timeout to avoid lingering timers
|
|
513
637
|
*/
|
|
514
638
|
const withTimeout = async <T>(
|
|
515
639
|
promise: Promise<T>,
|
|
516
640
|
timeoutMs: number,
|
|
517
641
|
operation: string,
|
|
518
642
|
): Promise<T> => {
|
|
519
|
-
|
|
520
|
-
|
|
643
|
+
let timeoutId: ReturnType<typeof setTimeout> | undefined;
|
|
644
|
+
|
|
645
|
+
const timeoutPromise = new Promise<never>((_, reject) => {
|
|
646
|
+
timeoutId = setTimeout(
|
|
521
647
|
() =>
|
|
522
648
|
reject(
|
|
523
649
|
new BeadError(
|
|
@@ -526,21 +652,28 @@ export const beads_sync = tool({
|
|
|
526
652
|
),
|
|
527
653
|
),
|
|
528
654
|
timeoutMs,
|
|
529
|
-
)
|
|
530
|
-
);
|
|
531
|
-
|
|
655
|
+
);
|
|
656
|
+
});
|
|
657
|
+
|
|
658
|
+
try {
|
|
659
|
+
return await Promise.race([promise, timeoutPromise]);
|
|
660
|
+
} finally {
|
|
661
|
+
if (timeoutId !== undefined) {
|
|
662
|
+
clearTimeout(timeoutId);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
532
665
|
};
|
|
533
666
|
|
|
534
667
|
// 1. Pull if requested
|
|
535
668
|
if (autoPull) {
|
|
536
669
|
const pullResult = await withTimeout(
|
|
537
|
-
|
|
670
|
+
runGitCommand(["pull", "--rebase"]),
|
|
538
671
|
TIMEOUT_MS,
|
|
539
672
|
"git pull --rebase",
|
|
540
673
|
);
|
|
541
674
|
if (pullResult.exitCode !== 0) {
|
|
542
675
|
throw new BeadError(
|
|
543
|
-
`Failed to pull: ${pullResult.stderr
|
|
676
|
+
`Failed to pull: ${pullResult.stderr}`,
|
|
544
677
|
"git pull --rebase",
|
|
545
678
|
pullResult.exitCode,
|
|
546
679
|
);
|
|
@@ -549,13 +682,13 @@ export const beads_sync = tool({
|
|
|
549
682
|
|
|
550
683
|
// 2. Sync beads
|
|
551
684
|
const syncResult = await withTimeout(
|
|
552
|
-
|
|
685
|
+
runBdCommand(["sync"]),
|
|
553
686
|
TIMEOUT_MS,
|
|
554
687
|
"bd sync",
|
|
555
688
|
);
|
|
556
689
|
if (syncResult.exitCode !== 0) {
|
|
557
690
|
throw new BeadError(
|
|
558
|
-
`Failed to sync beads: ${syncResult.stderr
|
|
691
|
+
`Failed to sync beads: ${syncResult.stderr}`,
|
|
559
692
|
"bd sync",
|
|
560
693
|
syncResult.exitCode,
|
|
561
694
|
);
|
|
@@ -563,21 +696,21 @@ export const beads_sync = tool({
|
|
|
563
696
|
|
|
564
697
|
// 3. Push
|
|
565
698
|
const pushResult = await withTimeout(
|
|
566
|
-
|
|
699
|
+
runGitCommand(["push"]),
|
|
567
700
|
TIMEOUT_MS,
|
|
568
701
|
"git push",
|
|
569
702
|
);
|
|
570
703
|
if (pushResult.exitCode !== 0) {
|
|
571
704
|
throw new BeadError(
|
|
572
|
-
`Failed to push: ${pushResult.stderr
|
|
705
|
+
`Failed to push: ${pushResult.stderr}`,
|
|
573
706
|
"git push",
|
|
574
707
|
pushResult.exitCode,
|
|
575
708
|
);
|
|
576
709
|
}
|
|
577
710
|
|
|
578
711
|
// 4. Verify clean state
|
|
579
|
-
const statusResult = await
|
|
580
|
-
const status = statusResult.stdout.
|
|
712
|
+
const statusResult = await runGitCommand(["status", "--porcelain"]);
|
|
713
|
+
const status = statusResult.stdout.trim();
|
|
581
714
|
|
|
582
715
|
if (status !== "") {
|
|
583
716
|
return `Beads synced and pushed, but working directory not clean:\n${status}`;
|
|
@@ -599,19 +732,17 @@ export const beads_link_thread = tool({
|
|
|
599
732
|
async execute(args, ctx) {
|
|
600
733
|
// Update bead description to include thread link
|
|
601
734
|
// This is a workaround since bd doesn't have native metadata support
|
|
602
|
-
const queryResult = await
|
|
603
|
-
.quiet()
|
|
604
|
-
.nothrow();
|
|
735
|
+
const queryResult = await runBdCommand(["show", args.bead_id, "--json"]);
|
|
605
736
|
|
|
606
737
|
if (queryResult.exitCode !== 0) {
|
|
607
738
|
throw new BeadError(
|
|
608
|
-
`Failed to get bead: ${queryResult.stderr
|
|
739
|
+
`Failed to get bead: ${queryResult.stderr}`,
|
|
609
740
|
`bd show ${args.bead_id} --json`,
|
|
610
741
|
queryResult.exitCode,
|
|
611
742
|
);
|
|
612
743
|
}
|
|
613
744
|
|
|
614
|
-
const bead = parseBead(queryResult.stdout
|
|
745
|
+
const bead = parseBead(queryResult.stdout);
|
|
615
746
|
const existingDesc = bead.description || "";
|
|
616
747
|
|
|
617
748
|
// Add thread link if not already present
|
|
@@ -624,14 +755,17 @@ export const beads_link_thread = tool({
|
|
|
624
755
|
? `${existingDesc}\n\n${threadMarker}`
|
|
625
756
|
: threadMarker;
|
|
626
757
|
|
|
627
|
-
const updateResult =
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
758
|
+
const updateResult = await runBdCommand([
|
|
759
|
+
"update",
|
|
760
|
+
args.bead_id,
|
|
761
|
+
"-d",
|
|
762
|
+
newDesc,
|
|
763
|
+
"--json",
|
|
764
|
+
]);
|
|
631
765
|
|
|
632
766
|
if (updateResult.exitCode !== 0) {
|
|
633
767
|
throw new BeadError(
|
|
634
|
-
`Failed to update bead: ${updateResult.stderr
|
|
768
|
+
`Failed to update bead: ${updateResult.stderr}`,
|
|
635
769
|
`bd update ${args.bead_id} -d ...`,
|
|
636
770
|
updateResult.exitCode,
|
|
637
771
|
);
|
package/src/index.ts
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
*/
|
|
23
23
|
import type { Plugin, PluginInput, Hooks } from "@opencode-ai/plugin";
|
|
24
24
|
|
|
25
|
-
import { beadsTools } from "./beads";
|
|
25
|
+
import { beadsTools, setBeadsWorkingDirectory } from "./beads";
|
|
26
26
|
import {
|
|
27
27
|
agentMailTools,
|
|
28
28
|
type AgentMailState,
|
|
@@ -48,7 +48,11 @@ import { repoCrawlTools } from "./repo-crawl";
|
|
|
48
48
|
export const SwarmPlugin: Plugin = async (
|
|
49
49
|
input: PluginInput,
|
|
50
50
|
): Promise<Hooks> => {
|
|
51
|
-
const {
|
|
51
|
+
const { $, directory } = input;
|
|
52
|
+
|
|
53
|
+
// Set the working directory for beads commands
|
|
54
|
+
// This ensures bd runs in the project directory, not ~/.config/opencode
|
|
55
|
+
setBeadsWorkingDirectory(directory);
|
|
52
56
|
|
|
53
57
|
/** Track active sessions for cleanup */
|
|
54
58
|
let activeAgentMailState: AgentMailState | null = null;
|
package/src/storage.ts
CHANGED
|
@@ -248,6 +248,9 @@ export class SemanticMemoryStorage implements LearningStorage {
|
|
|
248
248
|
const result = await execSemanticMemory(args);
|
|
249
249
|
|
|
250
250
|
if (result.exitCode !== 0) {
|
|
251
|
+
console.warn(
|
|
252
|
+
`[storage] semantic-memory find() failed with exit code ${result.exitCode}: ${result.stderr.toString().trim()}`,
|
|
253
|
+
);
|
|
251
254
|
return [];
|
|
252
255
|
}
|
|
253
256
|
|
|
@@ -268,7 +271,10 @@ export class SemanticMemoryStorage implements LearningStorage {
|
|
|
268
271
|
return content;
|
|
269
272
|
}
|
|
270
273
|
});
|
|
271
|
-
} catch {
|
|
274
|
+
} catch (error) {
|
|
275
|
+
console.warn(
|
|
276
|
+
`[storage] Failed to parse semantic-memory find() output: ${error instanceof Error ? error.message : String(error)}`,
|
|
277
|
+
);
|
|
272
278
|
return [];
|
|
273
279
|
}
|
|
274
280
|
}
|
|
@@ -282,6 +288,9 @@ export class SemanticMemoryStorage implements LearningStorage {
|
|
|
282
288
|
]);
|
|
283
289
|
|
|
284
290
|
if (result.exitCode !== 0) {
|
|
291
|
+
console.warn(
|
|
292
|
+
`[storage] semantic-memory list() failed with exit code ${result.exitCode}: ${result.stderr.toString().trim()}`,
|
|
293
|
+
);
|
|
285
294
|
return [];
|
|
286
295
|
}
|
|
287
296
|
|
|
@@ -300,7 +309,10 @@ export class SemanticMemoryStorage implements LearningStorage {
|
|
|
300
309
|
return content;
|
|
301
310
|
}
|
|
302
311
|
});
|
|
303
|
-
} catch {
|
|
312
|
+
} catch (error) {
|
|
313
|
+
console.warn(
|
|
314
|
+
`[storage] Failed to parse semantic-memory list() output: ${error instanceof Error ? error.message : String(error)}`,
|
|
315
|
+
);
|
|
304
316
|
return [];
|
|
305
317
|
}
|
|
306
318
|
}
|