opencode-swarm-plugin 0.26.1 → 0.27.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.
- package/.turbo/turbo-build.log +4 -4
- package/CHANGELOG.md +23 -0
- package/README.md +43 -46
- package/bin/swarm.ts +8 -8
- package/dist/compaction-hook.d.ts +57 -0
- package/dist/compaction-hook.d.ts.map +1 -0
- package/dist/hive.d.ts +741 -0
- package/dist/hive.d.ts.map +1 -0
- package/dist/index.d.ts +139 -23
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1353 -350
- package/dist/learning.d.ts +9 -9
- package/dist/plugin.js +1176 -350
- package/dist/schemas/cell-events.d.ts +1352 -0
- package/dist/schemas/{bead-events.d.ts.map → cell-events.d.ts.map} +1 -1
- package/dist/schemas/{bead.d.ts → cell.d.ts} +173 -29
- package/dist/schemas/cell.d.ts.map +1 -0
- package/dist/schemas/index.d.ts +11 -7
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/structured.d.ts +17 -7
- package/dist/structured.d.ts.map +1 -1
- package/dist/swarm-decompose.d.ts +5 -5
- package/dist/swarm-orchestrate.d.ts +16 -2
- package/dist/swarm-orchestrate.d.ts.map +1 -1
- package/dist/swarm-prompts.d.ts +9 -9
- package/dist/swarm-prompts.d.ts.map +1 -1
- package/dist/swarm-review.d.ts +210 -0
- package/dist/swarm-review.d.ts.map +1 -0
- package/dist/swarm-worktree.d.ts +185 -0
- package/dist/swarm-worktree.d.ts.map +1 -0
- package/dist/swarm.d.ts +7 -0
- package/dist/swarm.d.ts.map +1 -1
- package/dist/tool-availability.d.ts +3 -2
- package/dist/tool-availability.d.ts.map +1 -1
- package/docs/analysis-socratic-planner-pattern.md +1 -1
- package/docs/planning/ADR-007-swarm-enhancements-worktree-review.md +168 -0
- package/docs/testing/context-recovery-test.md +2 -2
- package/evals/README.md +2 -2
- package/evals/scorers/index.ts +7 -7
- package/examples/commands/swarm.md +21 -23
- package/examples/plugin-wrapper-template.ts +310 -44
- package/examples/skills/{beads-workflow → hive-workflow}/SKILL.md +40 -40
- package/examples/skills/swarm-coordination/SKILL.md +1 -1
- package/global-skills/swarm-coordination/SKILL.md +14 -14
- package/global-skills/swarm-coordination/references/coordinator-patterns.md +3 -3
- package/package.json +2 -2
- package/src/compaction-hook.ts +161 -0
- package/src/{beads.integration.test.ts → hive.integration.test.ts} +92 -80
- package/src/{beads.ts → hive.ts} +378 -219
- package/src/index.ts +57 -20
- package/src/learning.ts +9 -9
- package/src/output-guardrails.test.ts +4 -4
- package/src/output-guardrails.ts +9 -9
- package/src/planning-guardrails.test.ts +1 -1
- package/src/planning-guardrails.ts +1 -1
- package/src/schemas/{bead-events.test.ts → cell-events.test.ts} +83 -77
- package/src/schemas/cell-events.ts +807 -0
- package/src/schemas/{bead.ts → cell.ts} +95 -41
- package/src/schemas/evaluation.ts +1 -1
- package/src/schemas/index.ts +90 -18
- package/src/schemas/swarm-context.ts +2 -2
- package/src/structured.test.ts +15 -15
- package/src/structured.ts +18 -11
- package/src/swarm-decompose.ts +23 -23
- package/src/swarm-orchestrate.ts +135 -21
- package/src/swarm-prompts.ts +43 -43
- package/src/swarm-review.test.ts +702 -0
- package/src/swarm-review.ts +696 -0
- package/src/swarm-worktree.test.ts +501 -0
- package/src/swarm-worktree.ts +575 -0
- package/src/swarm.integration.test.ts +12 -12
- package/src/tool-availability.ts +36 -3
- package/dist/beads.d.ts +0 -386
- package/dist/beads.d.ts.map +0 -1
- package/dist/schemas/bead-events.d.ts +0 -698
- package/dist/schemas/bead.d.ts.map +0 -1
- package/src/schemas/bead-events.ts +0 -583
package/dist/plugin.js
CHANGED
|
@@ -27051,10 +27051,10 @@ echo "Project directory: $1"
|
|
|
27051
27051
|
};
|
|
27052
27052
|
});
|
|
27053
27053
|
|
|
27054
|
-
// src/
|
|
27054
|
+
// src/hive.ts
|
|
27055
27055
|
init_dist();
|
|
27056
27056
|
import {
|
|
27057
|
-
|
|
27057
|
+
createHiveAdapter,
|
|
27058
27058
|
FlushManager,
|
|
27059
27059
|
importFromJSONL,
|
|
27060
27060
|
getSwarmMail
|
|
@@ -27062,32 +27062,32 @@ import {
|
|
|
27062
27062
|
import { existsSync, readFileSync } from "node:fs";
|
|
27063
27063
|
import { join } from "node:path";
|
|
27064
27064
|
|
|
27065
|
-
// src/schemas/
|
|
27065
|
+
// src/schemas/cell.ts
|
|
27066
27066
|
init_zod();
|
|
27067
|
-
var
|
|
27067
|
+
var CellStatusSchema = exports_external.enum([
|
|
27068
27068
|
"open",
|
|
27069
27069
|
"in_progress",
|
|
27070
27070
|
"blocked",
|
|
27071
27071
|
"closed"
|
|
27072
27072
|
]);
|
|
27073
|
-
var
|
|
27073
|
+
var CellTypeSchema = exports_external.enum([
|
|
27074
27074
|
"bug",
|
|
27075
27075
|
"feature",
|
|
27076
27076
|
"task",
|
|
27077
27077
|
"epic",
|
|
27078
27078
|
"chore"
|
|
27079
27079
|
]);
|
|
27080
|
-
var
|
|
27080
|
+
var CellDependencySchema = exports_external.object({
|
|
27081
27081
|
id: exports_external.string(),
|
|
27082
27082
|
type: exports_external.enum(["blocks", "blocked-by", "related", "discovered-from"])
|
|
27083
27083
|
});
|
|
27084
|
-
var
|
|
27085
|
-
id: exports_external.string().regex(/^[a-z0-9]+(-[a-z0-9]+)+(\.[\w-]+)?$/, "Invalid
|
|
27084
|
+
var CellSchema = exports_external.object({
|
|
27085
|
+
id: exports_external.string().regex(/^[a-z0-9]+(-[a-z0-9]+)+(\.[\w-]+)?$/, "Invalid cell ID format (expected: project-slug-hash or project-slug-hash.N)"),
|
|
27086
27086
|
title: exports_external.string().min(1, "Title required"),
|
|
27087
27087
|
description: exports_external.string().optional().default(""),
|
|
27088
|
-
status:
|
|
27088
|
+
status: CellStatusSchema.default("open"),
|
|
27089
27089
|
priority: exports_external.number().int().min(0).max(3).default(2),
|
|
27090
|
-
issue_type:
|
|
27090
|
+
issue_type: CellTypeSchema.default("task"),
|
|
27091
27091
|
created_at: exports_external.string().datetime({
|
|
27092
27092
|
offset: true,
|
|
27093
27093
|
message: "Must be ISO-8601 datetime with timezone (e.g., 2024-01-15T10:30:00Z)"
|
|
@@ -27098,30 +27098,30 @@ var BeadSchema = exports_external.object({
|
|
|
27098
27098
|
}).optional(),
|
|
27099
27099
|
closed_at: exports_external.string().datetime({ offset: true }).optional(),
|
|
27100
27100
|
parent_id: exports_external.string().optional(),
|
|
27101
|
-
dependencies: exports_external.array(
|
|
27101
|
+
dependencies: exports_external.array(CellDependencySchema).default([]),
|
|
27102
27102
|
metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
27103
27103
|
});
|
|
27104
|
-
var
|
|
27104
|
+
var CellCreateArgsSchema = exports_external.object({
|
|
27105
27105
|
title: exports_external.string().min(1, "Title required"),
|
|
27106
|
-
type:
|
|
27106
|
+
type: CellTypeSchema.default("task"),
|
|
27107
27107
|
priority: exports_external.number().int().min(0).max(3).default(2),
|
|
27108
27108
|
description: exports_external.string().optional(),
|
|
27109
27109
|
parent_id: exports_external.string().optional(),
|
|
27110
27110
|
id: exports_external.string().optional()
|
|
27111
27111
|
});
|
|
27112
|
-
var
|
|
27112
|
+
var CellUpdateArgsSchema = exports_external.object({
|
|
27113
27113
|
id: exports_external.string(),
|
|
27114
|
-
status:
|
|
27114
|
+
status: CellStatusSchema.optional(),
|
|
27115
27115
|
description: exports_external.string().optional(),
|
|
27116
27116
|
priority: exports_external.number().int().min(0).max(3).optional()
|
|
27117
27117
|
});
|
|
27118
|
-
var
|
|
27118
|
+
var CellCloseArgsSchema = exports_external.object({
|
|
27119
27119
|
id: exports_external.string(),
|
|
27120
27120
|
reason: exports_external.string().min(1, "Reason required")
|
|
27121
27121
|
});
|
|
27122
|
-
var
|
|
27123
|
-
status:
|
|
27124
|
-
type:
|
|
27122
|
+
var CellQueryArgsSchema = exports_external.object({
|
|
27123
|
+
status: CellStatusSchema.optional(),
|
|
27124
|
+
type: CellTypeSchema.optional(),
|
|
27125
27125
|
ready: exports_external.boolean().optional(),
|
|
27126
27126
|
limit: exports_external.number().int().positive().default(20)
|
|
27127
27127
|
});
|
|
@@ -27132,7 +27132,7 @@ var SubtaskSpecSchema = exports_external.object({
|
|
|
27132
27132
|
dependencies: exports_external.array(exports_external.number().int().min(0)).default([]),
|
|
27133
27133
|
estimated_complexity: exports_external.number().int().min(1).max(5).default(3)
|
|
27134
27134
|
});
|
|
27135
|
-
var
|
|
27135
|
+
var CellTreeSchema = exports_external.object({
|
|
27136
27136
|
epic: exports_external.object({
|
|
27137
27137
|
title: exports_external.string().min(1),
|
|
27138
27138
|
description: exports_external.string().optional().default("")
|
|
@@ -27152,10 +27152,11 @@ var EpicCreateArgsSchema = exports_external.object({
|
|
|
27152
27152
|
});
|
|
27153
27153
|
var EpicCreateResultSchema = exports_external.object({
|
|
27154
27154
|
success: exports_external.boolean(),
|
|
27155
|
-
epic:
|
|
27156
|
-
subtasks: exports_external.array(
|
|
27155
|
+
epic: CellSchema,
|
|
27156
|
+
subtasks: exports_external.array(CellSchema),
|
|
27157
27157
|
rollback_hint: exports_external.string().optional()
|
|
27158
27158
|
});
|
|
27159
|
+
var BeadSchema = CellSchema;
|
|
27159
27160
|
// src/schemas/evaluation.ts
|
|
27160
27161
|
init_zod();
|
|
27161
27162
|
var CriterionEvaluationSchema = exports_external.object({
|
|
@@ -27419,29 +27420,29 @@ var QuerySwarmContextsArgsSchema = exports_external.object({
|
|
|
27419
27420
|
strategy: SwarmStrategySchema.optional(),
|
|
27420
27421
|
has_errors: exports_external.boolean().optional()
|
|
27421
27422
|
});
|
|
27422
|
-
// src/schemas/
|
|
27423
|
+
// src/schemas/cell-events.ts
|
|
27423
27424
|
init_zod();
|
|
27424
|
-
var
|
|
27425
|
+
var BaseCellEventSchema = exports_external.object({
|
|
27425
27426
|
id: exports_external.number().optional(),
|
|
27426
27427
|
type: exports_external.string(),
|
|
27427
27428
|
project_key: exports_external.string(),
|
|
27428
27429
|
timestamp: exports_external.number(),
|
|
27429
27430
|
sequence: exports_external.number().optional()
|
|
27430
27431
|
});
|
|
27431
|
-
var
|
|
27432
|
-
type: exports_external.literal("
|
|
27433
|
-
|
|
27432
|
+
var CellCreatedEventSchema = BaseCellEventSchema.extend({
|
|
27433
|
+
type: exports_external.literal("cell_created"),
|
|
27434
|
+
cell_id: exports_external.string(),
|
|
27434
27435
|
title: exports_external.string(),
|
|
27435
27436
|
description: exports_external.string().optional(),
|
|
27436
|
-
issue_type:
|
|
27437
|
+
issue_type: CellTypeSchema,
|
|
27437
27438
|
priority: exports_external.number().int().min(0).max(3),
|
|
27438
27439
|
parent_id: exports_external.string().optional(),
|
|
27439
27440
|
created_by: exports_external.string().optional(),
|
|
27440
27441
|
metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
27441
27442
|
});
|
|
27442
|
-
var
|
|
27443
|
-
type: exports_external.literal("
|
|
27444
|
-
|
|
27443
|
+
var CellUpdatedEventSchema = BaseCellEventSchema.extend({
|
|
27444
|
+
type: exports_external.literal("cell_updated"),
|
|
27445
|
+
cell_id: exports_external.string(),
|
|
27445
27446
|
updated_by: exports_external.string().optional(),
|
|
27446
27447
|
changes: exports_external.object({
|
|
27447
27448
|
title: exports_external.object({
|
|
@@ -27458,155 +27459,155 @@ var BeadUpdatedEventSchema = BaseBeadEventSchema.extend({
|
|
|
27458
27459
|
}).optional()
|
|
27459
27460
|
})
|
|
27460
27461
|
});
|
|
27461
|
-
var
|
|
27462
|
-
type: exports_external.literal("
|
|
27463
|
-
|
|
27464
|
-
from_status:
|
|
27465
|
-
to_status:
|
|
27462
|
+
var CellStatusChangedEventSchema = BaseCellEventSchema.extend({
|
|
27463
|
+
type: exports_external.literal("cell_status_changed"),
|
|
27464
|
+
cell_id: exports_external.string(),
|
|
27465
|
+
from_status: CellStatusSchema,
|
|
27466
|
+
to_status: CellStatusSchema,
|
|
27466
27467
|
changed_by: exports_external.string().optional(),
|
|
27467
27468
|
reason: exports_external.string().optional()
|
|
27468
27469
|
});
|
|
27469
|
-
var
|
|
27470
|
-
type: exports_external.literal("
|
|
27471
|
-
|
|
27470
|
+
var CellClosedEventSchema = BaseCellEventSchema.extend({
|
|
27471
|
+
type: exports_external.literal("cell_closed"),
|
|
27472
|
+
cell_id: exports_external.string(),
|
|
27472
27473
|
reason: exports_external.string(),
|
|
27473
27474
|
closed_by: exports_external.string().optional(),
|
|
27474
27475
|
files_touched: exports_external.array(exports_external.string()).optional(),
|
|
27475
27476
|
duration_ms: exports_external.number().optional()
|
|
27476
27477
|
});
|
|
27477
|
-
var
|
|
27478
|
-
type: exports_external.literal("
|
|
27479
|
-
|
|
27478
|
+
var CellReopenedEventSchema = BaseCellEventSchema.extend({
|
|
27479
|
+
type: exports_external.literal("cell_reopened"),
|
|
27480
|
+
cell_id: exports_external.string(),
|
|
27480
27481
|
reason: exports_external.string().optional(),
|
|
27481
27482
|
reopened_by: exports_external.string().optional()
|
|
27482
27483
|
});
|
|
27483
|
-
var
|
|
27484
|
-
type: exports_external.literal("
|
|
27485
|
-
|
|
27484
|
+
var CellDeletedEventSchema = BaseCellEventSchema.extend({
|
|
27485
|
+
type: exports_external.literal("cell_deleted"),
|
|
27486
|
+
cell_id: exports_external.string(),
|
|
27486
27487
|
reason: exports_external.string().optional(),
|
|
27487
27488
|
deleted_by: exports_external.string().optional()
|
|
27488
27489
|
});
|
|
27489
|
-
var
|
|
27490
|
-
type: exports_external.literal("
|
|
27491
|
-
|
|
27492
|
-
dependency:
|
|
27490
|
+
var CellDependencyAddedEventSchema = BaseCellEventSchema.extend({
|
|
27491
|
+
type: exports_external.literal("cell_dependency_added"),
|
|
27492
|
+
cell_id: exports_external.string(),
|
|
27493
|
+
dependency: CellDependencySchema,
|
|
27493
27494
|
added_by: exports_external.string().optional(),
|
|
27494
27495
|
reason: exports_external.string().optional()
|
|
27495
27496
|
});
|
|
27496
|
-
var
|
|
27497
|
-
type: exports_external.literal("
|
|
27498
|
-
|
|
27499
|
-
dependency:
|
|
27497
|
+
var CellDependencyRemovedEventSchema = BaseCellEventSchema.extend({
|
|
27498
|
+
type: exports_external.literal("cell_dependency_removed"),
|
|
27499
|
+
cell_id: exports_external.string(),
|
|
27500
|
+
dependency: CellDependencySchema,
|
|
27500
27501
|
removed_by: exports_external.string().optional(),
|
|
27501
27502
|
reason: exports_external.string().optional()
|
|
27502
27503
|
});
|
|
27503
|
-
var
|
|
27504
|
-
type: exports_external.literal("
|
|
27505
|
-
|
|
27504
|
+
var CellLabelAddedEventSchema = BaseCellEventSchema.extend({
|
|
27505
|
+
type: exports_external.literal("cell_label_added"),
|
|
27506
|
+
cell_id: exports_external.string(),
|
|
27506
27507
|
label: exports_external.string(),
|
|
27507
27508
|
added_by: exports_external.string().optional()
|
|
27508
27509
|
});
|
|
27509
|
-
var
|
|
27510
|
-
type: exports_external.literal("
|
|
27511
|
-
|
|
27510
|
+
var CellLabelRemovedEventSchema = BaseCellEventSchema.extend({
|
|
27511
|
+
type: exports_external.literal("cell_label_removed"),
|
|
27512
|
+
cell_id: exports_external.string(),
|
|
27512
27513
|
label: exports_external.string(),
|
|
27513
27514
|
removed_by: exports_external.string().optional()
|
|
27514
27515
|
});
|
|
27515
|
-
var
|
|
27516
|
-
type: exports_external.literal("
|
|
27517
|
-
|
|
27516
|
+
var CellCommentAddedEventSchema = BaseCellEventSchema.extend({
|
|
27517
|
+
type: exports_external.literal("cell_comment_added"),
|
|
27518
|
+
cell_id: exports_external.string(),
|
|
27518
27519
|
comment_id: exports_external.number().optional(),
|
|
27519
27520
|
author: exports_external.string(),
|
|
27520
27521
|
body: exports_external.string(),
|
|
27521
27522
|
parent_comment_id: exports_external.number().optional(),
|
|
27522
27523
|
metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
27523
27524
|
});
|
|
27524
|
-
var
|
|
27525
|
-
type: exports_external.literal("
|
|
27526
|
-
|
|
27525
|
+
var CellCommentUpdatedEventSchema = BaseCellEventSchema.extend({
|
|
27526
|
+
type: exports_external.literal("cell_comment_updated"),
|
|
27527
|
+
cell_id: exports_external.string(),
|
|
27527
27528
|
comment_id: exports_external.number(),
|
|
27528
27529
|
old_body: exports_external.string(),
|
|
27529
27530
|
new_body: exports_external.string(),
|
|
27530
27531
|
updated_by: exports_external.string()
|
|
27531
27532
|
});
|
|
27532
|
-
var
|
|
27533
|
-
type: exports_external.literal("
|
|
27534
|
-
|
|
27533
|
+
var CellCommentDeletedEventSchema = BaseCellEventSchema.extend({
|
|
27534
|
+
type: exports_external.literal("cell_comment_deleted"),
|
|
27535
|
+
cell_id: exports_external.string(),
|
|
27535
27536
|
comment_id: exports_external.number(),
|
|
27536
27537
|
deleted_by: exports_external.string(),
|
|
27537
27538
|
reason: exports_external.string().optional()
|
|
27538
27539
|
});
|
|
27539
|
-
var
|
|
27540
|
-
type: exports_external.literal("
|
|
27541
|
-
|
|
27540
|
+
var CellEpicChildAddedEventSchema = BaseCellEventSchema.extend({
|
|
27541
|
+
type: exports_external.literal("cell_epic_child_added"),
|
|
27542
|
+
cell_id: exports_external.string(),
|
|
27542
27543
|
child_id: exports_external.string(),
|
|
27543
27544
|
child_index: exports_external.number().optional(),
|
|
27544
27545
|
added_by: exports_external.string().optional()
|
|
27545
27546
|
});
|
|
27546
|
-
var
|
|
27547
|
-
type: exports_external.literal("
|
|
27548
|
-
|
|
27547
|
+
var CellEpicChildRemovedEventSchema = BaseCellEventSchema.extend({
|
|
27548
|
+
type: exports_external.literal("cell_epic_child_removed"),
|
|
27549
|
+
cell_id: exports_external.string(),
|
|
27549
27550
|
child_id: exports_external.string(),
|
|
27550
27551
|
removed_by: exports_external.string().optional(),
|
|
27551
27552
|
reason: exports_external.string().optional()
|
|
27552
27553
|
});
|
|
27553
|
-
var
|
|
27554
|
-
type: exports_external.literal("
|
|
27555
|
-
|
|
27554
|
+
var CellEpicClosureEligibleEventSchema = BaseCellEventSchema.extend({
|
|
27555
|
+
type: exports_external.literal("cell_epic_closure_eligible"),
|
|
27556
|
+
cell_id: exports_external.string(),
|
|
27556
27557
|
child_ids: exports_external.array(exports_external.string()),
|
|
27557
27558
|
total_duration_ms: exports_external.number().optional(),
|
|
27558
27559
|
all_files_touched: exports_external.array(exports_external.string()).optional()
|
|
27559
27560
|
});
|
|
27560
|
-
var
|
|
27561
|
-
type: exports_external.literal("
|
|
27562
|
-
|
|
27561
|
+
var CellAssignedEventSchema = BaseCellEventSchema.extend({
|
|
27562
|
+
type: exports_external.literal("cell_assigned"),
|
|
27563
|
+
cell_id: exports_external.string(),
|
|
27563
27564
|
agent_name: exports_external.string(),
|
|
27564
27565
|
task_description: exports_external.string().optional()
|
|
27565
27566
|
});
|
|
27566
|
-
var
|
|
27567
|
-
type: exports_external.literal("
|
|
27568
|
-
|
|
27567
|
+
var CellWorkStartedEventSchema = BaseCellEventSchema.extend({
|
|
27568
|
+
type: exports_external.literal("cell_work_started"),
|
|
27569
|
+
cell_id: exports_external.string(),
|
|
27569
27570
|
agent_name: exports_external.string(),
|
|
27570
27571
|
reserved_files: exports_external.array(exports_external.string()).optional()
|
|
27571
27572
|
});
|
|
27572
|
-
var
|
|
27573
|
-
type: exports_external.literal("
|
|
27574
|
-
|
|
27573
|
+
var CellCompactedEventSchema = BaseCellEventSchema.extend({
|
|
27574
|
+
type: exports_external.literal("cell_compacted"),
|
|
27575
|
+
cell_id: exports_external.string(),
|
|
27575
27576
|
events_archived: exports_external.number(),
|
|
27576
27577
|
new_start_sequence: exports_external.number()
|
|
27577
27578
|
});
|
|
27578
|
-
var
|
|
27579
|
-
|
|
27580
|
-
|
|
27581
|
-
|
|
27582
|
-
|
|
27583
|
-
|
|
27584
|
-
|
|
27585
|
-
|
|
27586
|
-
|
|
27587
|
-
|
|
27588
|
-
|
|
27589
|
-
|
|
27590
|
-
|
|
27591
|
-
|
|
27592
|
-
|
|
27593
|
-
|
|
27594
|
-
|
|
27595
|
-
|
|
27596
|
-
|
|
27597
|
-
|
|
27579
|
+
var CellEventSchema = exports_external.discriminatedUnion("type", [
|
|
27580
|
+
CellCreatedEventSchema,
|
|
27581
|
+
CellUpdatedEventSchema,
|
|
27582
|
+
CellStatusChangedEventSchema,
|
|
27583
|
+
CellClosedEventSchema,
|
|
27584
|
+
CellReopenedEventSchema,
|
|
27585
|
+
CellDeletedEventSchema,
|
|
27586
|
+
CellDependencyAddedEventSchema,
|
|
27587
|
+
CellDependencyRemovedEventSchema,
|
|
27588
|
+
CellLabelAddedEventSchema,
|
|
27589
|
+
CellLabelRemovedEventSchema,
|
|
27590
|
+
CellCommentAddedEventSchema,
|
|
27591
|
+
CellCommentUpdatedEventSchema,
|
|
27592
|
+
CellCommentDeletedEventSchema,
|
|
27593
|
+
CellEpicChildAddedEventSchema,
|
|
27594
|
+
CellEpicChildRemovedEventSchema,
|
|
27595
|
+
CellEpicClosureEligibleEventSchema,
|
|
27596
|
+
CellAssignedEventSchema,
|
|
27597
|
+
CellWorkStartedEventSchema,
|
|
27598
|
+
CellCompactedEventSchema
|
|
27598
27599
|
]);
|
|
27599
|
-
// src/
|
|
27600
|
+
// src/hive.ts
|
|
27600
27601
|
import { createEvent, appendEvent } from "swarm-mail";
|
|
27601
|
-
var
|
|
27602
|
-
function
|
|
27603
|
-
|
|
27602
|
+
var hiveWorkingDirectory = null;
|
|
27603
|
+
function setHiveWorkingDirectory(directory) {
|
|
27604
|
+
hiveWorkingDirectory = directory;
|
|
27604
27605
|
}
|
|
27605
|
-
function
|
|
27606
|
-
return
|
|
27606
|
+
function getHiveWorkingDirectory() {
|
|
27607
|
+
return hiveWorkingDirectory || process.cwd();
|
|
27607
27608
|
}
|
|
27608
27609
|
async function runGitCommand(args) {
|
|
27609
|
-
const cwd =
|
|
27610
|
+
const cwd = getHiveWorkingDirectory();
|
|
27610
27611
|
const proc = Bun.spawn(["git", ...args], {
|
|
27611
27612
|
cwd,
|
|
27612
27613
|
stdout: "pipe",
|
|
@@ -27620,7 +27621,7 @@ async function runGitCommand(args) {
|
|
|
27620
27621
|
return { exitCode, stdout, stderr };
|
|
27621
27622
|
}
|
|
27622
27623
|
|
|
27623
|
-
class
|
|
27624
|
+
class HiveError extends Error {
|
|
27624
27625
|
command;
|
|
27625
27626
|
exitCode;
|
|
27626
27627
|
stderr;
|
|
@@ -27629,29 +27630,29 @@ class BeadError extends Error {
|
|
|
27629
27630
|
this.command = command;
|
|
27630
27631
|
this.exitCode = exitCode;
|
|
27631
27632
|
this.stderr = stderr;
|
|
27632
|
-
this.name = "
|
|
27633
|
+
this.name = "HiveError";
|
|
27633
27634
|
}
|
|
27634
27635
|
}
|
|
27635
27636
|
var adapterCache = new Map;
|
|
27636
|
-
async function
|
|
27637
|
+
async function getHiveAdapter(projectKey) {
|
|
27637
27638
|
if (adapterCache.has(projectKey)) {
|
|
27638
27639
|
return adapterCache.get(projectKey);
|
|
27639
27640
|
}
|
|
27640
27641
|
const swarmMail = await getSwarmMail(projectKey);
|
|
27641
27642
|
const db = await swarmMail.getDatabase();
|
|
27642
|
-
const adapter =
|
|
27643
|
+
const adapter = createHiveAdapter(db, projectKey);
|
|
27643
27644
|
await adapter.runMigrations();
|
|
27644
27645
|
await autoMigrateFromJSONL(adapter, projectKey);
|
|
27645
27646
|
adapterCache.set(projectKey, adapter);
|
|
27646
27647
|
return adapter;
|
|
27647
27648
|
}
|
|
27648
27649
|
async function autoMigrateFromJSONL(adapter, projectKey) {
|
|
27649
|
-
const jsonlPath = join(projectKey, ".
|
|
27650
|
+
const jsonlPath = join(projectKey, ".hive", "issues.jsonl");
|
|
27650
27651
|
if (!existsSync(jsonlPath)) {
|
|
27651
27652
|
return;
|
|
27652
27653
|
}
|
|
27653
|
-
const
|
|
27654
|
-
if (
|
|
27654
|
+
const existingCells = await adapter.queryCells(projectKey, { limit: 1 });
|
|
27655
|
+
if (existingCells.length > 0) {
|
|
27655
27656
|
return;
|
|
27656
27657
|
}
|
|
27657
27658
|
try {
|
|
@@ -27660,62 +27661,62 @@ async function autoMigrateFromJSONL(adapter, projectKey) {
|
|
|
27660
27661
|
skipExisting: true
|
|
27661
27662
|
});
|
|
27662
27663
|
if (result.created > 0 || result.updated > 0) {
|
|
27663
|
-
console.log(`[
|
|
27664
|
+
console.log(`[hive] Auto-migrated ${result.created} cells from ${jsonlPath} (${result.skipped} skipped, ${result.errors.length} errors)`);
|
|
27664
27665
|
}
|
|
27665
27666
|
if (result.errors.length > 0) {
|
|
27666
|
-
console.warn(`[
|
|
27667
|
+
console.warn(`[hive] Migration errors:`, result.errors.slice(0, 5).map((e) => `${e.cellId}: ${e.error}`));
|
|
27667
27668
|
}
|
|
27668
27669
|
} catch (error45) {
|
|
27669
|
-
console.warn(`[
|
|
27670
|
+
console.warn(`[hive] Failed to auto-migrate from ${jsonlPath}:`, error45 instanceof Error ? error45.message : String(error45));
|
|
27670
27671
|
}
|
|
27671
27672
|
}
|
|
27672
|
-
function
|
|
27673
|
+
function formatCellForOutput(adapterCell) {
|
|
27673
27674
|
return {
|
|
27674
|
-
id:
|
|
27675
|
-
title:
|
|
27676
|
-
description:
|
|
27677
|
-
status:
|
|
27678
|
-
priority:
|
|
27679
|
-
issue_type:
|
|
27680
|
-
created_at: new Date(
|
|
27681
|
-
updated_at: new Date(
|
|
27682
|
-
closed_at:
|
|
27683
|
-
parent_id:
|
|
27675
|
+
id: adapterCell.id,
|
|
27676
|
+
title: adapterCell.title,
|
|
27677
|
+
description: adapterCell.description || "",
|
|
27678
|
+
status: adapterCell.status,
|
|
27679
|
+
priority: adapterCell.priority,
|
|
27680
|
+
issue_type: adapterCell.type,
|
|
27681
|
+
created_at: new Date(adapterCell.created_at).toISOString(),
|
|
27682
|
+
updated_at: new Date(adapterCell.updated_at).toISOString(),
|
|
27683
|
+
closed_at: adapterCell.closed_at ? new Date(adapterCell.closed_at).toISOString() : undefined,
|
|
27684
|
+
parent_id: adapterCell.parent_id || undefined,
|
|
27684
27685
|
dependencies: [],
|
|
27685
27686
|
metadata: {}
|
|
27686
27687
|
};
|
|
27687
27688
|
}
|
|
27688
|
-
var
|
|
27689
|
-
description: "Create a new
|
|
27689
|
+
var hive_create = tool({
|
|
27690
|
+
description: "Create a new cell in the hive with type-safe validation",
|
|
27690
27691
|
args: {
|
|
27691
|
-
title: tool.schema.string().describe("
|
|
27692
|
+
title: tool.schema.string().describe("Cell title"),
|
|
27692
27693
|
type: tool.schema.enum(["bug", "feature", "task", "epic", "chore"]).optional().describe("Issue type (default: task)"),
|
|
27693
27694
|
priority: tool.schema.number().min(0).max(3).optional().describe("Priority 0-3 (default: 2)"),
|
|
27694
|
-
description: tool.schema.string().optional().describe("
|
|
27695
|
-
parent_id: tool.schema.string().optional().describe("Parent
|
|
27695
|
+
description: tool.schema.string().optional().describe("Cell description"),
|
|
27696
|
+
parent_id: tool.schema.string().optional().describe("Parent cell ID for epic children")
|
|
27696
27697
|
},
|
|
27697
27698
|
async execute(args, ctx) {
|
|
27698
|
-
const validated =
|
|
27699
|
-
const projectKey =
|
|
27700
|
-
const adapter = await
|
|
27699
|
+
const validated = CellCreateArgsSchema.parse(args);
|
|
27700
|
+
const projectKey = getHiveWorkingDirectory();
|
|
27701
|
+
const adapter = await getHiveAdapter(projectKey);
|
|
27701
27702
|
try {
|
|
27702
|
-
const
|
|
27703
|
+
const cell = await adapter.createCell(projectKey, {
|
|
27703
27704
|
title: validated.title,
|
|
27704
27705
|
type: validated.type || "task",
|
|
27705
27706
|
priority: validated.priority ?? 2,
|
|
27706
27707
|
description: validated.description,
|
|
27707
27708
|
parent_id: validated.parent_id
|
|
27708
27709
|
});
|
|
27709
|
-
await adapter.markDirty(projectKey,
|
|
27710
|
-
const formatted =
|
|
27710
|
+
await adapter.markDirty(projectKey, cell.id);
|
|
27711
|
+
const formatted = formatCellForOutput(cell);
|
|
27711
27712
|
return JSON.stringify(formatted, null, 2);
|
|
27712
27713
|
} catch (error45) {
|
|
27713
27714
|
const message = error45 instanceof Error ? error45.message : String(error45);
|
|
27714
|
-
throw new
|
|
27715
|
+
throw new HiveError(`Failed to create cell: ${message}`, "hive_create");
|
|
27715
27716
|
}
|
|
27716
27717
|
}
|
|
27717
27718
|
});
|
|
27718
|
-
var
|
|
27719
|
+
var hive_create_epic = tool({
|
|
27719
27720
|
description: "Create epic with subtasks in one atomic operation",
|
|
27720
27721
|
args: {
|
|
27721
27722
|
epic_title: tool.schema.string().describe("Epic title"),
|
|
@@ -27738,11 +27739,11 @@ var beads_create_epic = tool({
|
|
|
27738
27739
|
},
|
|
27739
27740
|
async execute(args, ctx) {
|
|
27740
27741
|
const validated = EpicCreateArgsSchema.parse(args);
|
|
27741
|
-
const projectKey =
|
|
27742
|
-
const adapter = await
|
|
27742
|
+
const projectKey = getHiveWorkingDirectory();
|
|
27743
|
+
const adapter = await getHiveAdapter(projectKey);
|
|
27743
27744
|
const created = [];
|
|
27744
27745
|
try {
|
|
27745
|
-
const epic = await adapter.
|
|
27746
|
+
const epic = await adapter.createCell(projectKey, {
|
|
27746
27747
|
title: validated.epic_title,
|
|
27747
27748
|
type: "epic",
|
|
27748
27749
|
priority: 1,
|
|
@@ -27751,19 +27752,19 @@ var beads_create_epic = tool({
|
|
|
27751
27752
|
await adapter.markDirty(projectKey, epic.id);
|
|
27752
27753
|
created.push(epic);
|
|
27753
27754
|
for (const subtask of validated.subtasks) {
|
|
27754
|
-
const
|
|
27755
|
+
const subtaskCell = await adapter.createCell(projectKey, {
|
|
27755
27756
|
title: subtask.title,
|
|
27756
27757
|
type: "task",
|
|
27757
27758
|
priority: subtask.priority ?? 2,
|
|
27758
27759
|
parent_id: epic.id
|
|
27759
27760
|
});
|
|
27760
|
-
await adapter.markDirty(projectKey,
|
|
27761
|
-
created.push(
|
|
27761
|
+
await adapter.markDirty(projectKey, subtaskCell.id);
|
|
27762
|
+
created.push(subtaskCell);
|
|
27762
27763
|
}
|
|
27763
27764
|
const result = {
|
|
27764
27765
|
success: true,
|
|
27765
|
-
epic:
|
|
27766
|
-
subtasks: created.slice(1).map((
|
|
27766
|
+
epic: formatCellForOutput(epic),
|
|
27767
|
+
subtasks: created.slice(1).map((c) => formatCellForOutput(c))
|
|
27767
27768
|
};
|
|
27768
27769
|
if (args.project_key) {
|
|
27769
27770
|
try {
|
|
@@ -27783,27 +27784,27 @@ var beads_create_epic = tool({
|
|
|
27783
27784
|
});
|
|
27784
27785
|
await appendEvent(event, args.project_key);
|
|
27785
27786
|
} catch (error45) {
|
|
27786
|
-
console.warn("[
|
|
27787
|
+
console.warn("[hive_create_epic] Failed to emit DecompositionGeneratedEvent:", error45);
|
|
27787
27788
|
}
|
|
27788
27789
|
}
|
|
27789
27790
|
return JSON.stringify(result, null, 2);
|
|
27790
27791
|
} catch (error45) {
|
|
27791
27792
|
const rollbackErrors = [];
|
|
27792
|
-
for (const
|
|
27793
|
+
for (const cell of created) {
|
|
27793
27794
|
try {
|
|
27794
|
-
await adapter.
|
|
27795
|
+
await adapter.deleteCell(projectKey, cell.id, {
|
|
27795
27796
|
reason: "Rollback partial epic"
|
|
27796
27797
|
});
|
|
27797
27798
|
} catch (rollbackError) {
|
|
27798
27799
|
const errMsg = rollbackError instanceof Error ? rollbackError.message : String(rollbackError);
|
|
27799
|
-
console.error(`Failed to rollback
|
|
27800
|
-
rollbackErrors.push(`${
|
|
27800
|
+
console.error(`Failed to rollback cell ${cell.id}:`, rollbackError);
|
|
27801
|
+
rollbackErrors.push(`${cell.id}: ${errMsg}`);
|
|
27801
27802
|
}
|
|
27802
27803
|
}
|
|
27803
27804
|
const errorMsg = error45 instanceof Error ? error45.message : String(error45);
|
|
27804
27805
|
let rollbackInfo = `
|
|
27805
27806
|
|
|
27806
|
-
Rolled back ${created.length - rollbackErrors.length}
|
|
27807
|
+
Rolled back ${created.length - rollbackErrors.length} cell(s)`;
|
|
27807
27808
|
if (rollbackErrors.length > 0) {
|
|
27808
27809
|
rollbackInfo += `
|
|
27809
27810
|
|
|
@@ -27811,151 +27812,151 @@ Rollback failures (${rollbackErrors.length}):
|
|
|
27811
27812
|
${rollbackErrors.join(`
|
|
27812
27813
|
`)}`;
|
|
27813
27814
|
}
|
|
27814
|
-
throw new
|
|
27815
|
+
throw new HiveError(`Epic creation failed: ${errorMsg}${rollbackInfo}`, "hive_create_epic", 1);
|
|
27815
27816
|
}
|
|
27816
27817
|
}
|
|
27817
27818
|
});
|
|
27818
|
-
var
|
|
27819
|
-
description: "Query
|
|
27819
|
+
var hive_query = tool({
|
|
27820
|
+
description: "Query hive cells with filters (replaces bd list, bd ready, bd wip)",
|
|
27820
27821
|
args: {
|
|
27821
27822
|
status: tool.schema.enum(["open", "in_progress", "blocked", "closed"]).optional().describe("Filter by status"),
|
|
27822
27823
|
type: tool.schema.enum(["bug", "feature", "task", "epic", "chore"]).optional().describe("Filter by type"),
|
|
27823
|
-
ready: tool.schema.boolean().optional().describe("Only show unblocked
|
|
27824
|
+
ready: tool.schema.boolean().optional().describe("Only show unblocked cells"),
|
|
27824
27825
|
limit: tool.schema.number().optional().describe("Max results to return (default: 20)")
|
|
27825
27826
|
},
|
|
27826
27827
|
async execute(args, ctx) {
|
|
27827
|
-
const validated =
|
|
27828
|
-
const projectKey =
|
|
27829
|
-
const adapter = await
|
|
27828
|
+
const validated = CellQueryArgsSchema.parse(args);
|
|
27829
|
+
const projectKey = getHiveWorkingDirectory();
|
|
27830
|
+
const adapter = await getHiveAdapter(projectKey);
|
|
27830
27831
|
try {
|
|
27831
|
-
let
|
|
27832
|
+
let cells;
|
|
27832
27833
|
if (validated.ready) {
|
|
27833
|
-
const
|
|
27834
|
-
|
|
27834
|
+
const readyCell = await adapter.getNextReadyCell(projectKey);
|
|
27835
|
+
cells = readyCell ? [readyCell] : [];
|
|
27835
27836
|
} else {
|
|
27836
|
-
|
|
27837
|
+
cells = await adapter.queryCells(projectKey, {
|
|
27837
27838
|
status: validated.status,
|
|
27838
27839
|
type: validated.type,
|
|
27839
27840
|
limit: validated.limit || 20
|
|
27840
27841
|
});
|
|
27841
27842
|
}
|
|
27842
|
-
const formatted =
|
|
27843
|
+
const formatted = cells.map((c) => formatCellForOutput(c));
|
|
27843
27844
|
return JSON.stringify(formatted, null, 2);
|
|
27844
27845
|
} catch (error45) {
|
|
27845
27846
|
const message = error45 instanceof Error ? error45.message : String(error45);
|
|
27846
|
-
throw new
|
|
27847
|
+
throw new HiveError(`Failed to query cells: ${message}`, "hive_query");
|
|
27847
27848
|
}
|
|
27848
27849
|
}
|
|
27849
27850
|
});
|
|
27850
|
-
var
|
|
27851
|
-
description: "Update
|
|
27851
|
+
var hive_update = tool({
|
|
27852
|
+
description: "Update cell status/description",
|
|
27852
27853
|
args: {
|
|
27853
|
-
id: tool.schema.string().describe("
|
|
27854
|
+
id: tool.schema.string().describe("Cell ID"),
|
|
27854
27855
|
status: tool.schema.enum(["open", "in_progress", "blocked", "closed"]).optional().describe("New status"),
|
|
27855
27856
|
description: tool.schema.string().optional().describe("New description"),
|
|
27856
27857
|
priority: tool.schema.number().min(0).max(3).optional().describe("New priority")
|
|
27857
27858
|
},
|
|
27858
27859
|
async execute(args, ctx) {
|
|
27859
|
-
const validated =
|
|
27860
|
-
const projectKey =
|
|
27861
|
-
const adapter = await
|
|
27860
|
+
const validated = CellUpdateArgsSchema.parse(args);
|
|
27861
|
+
const projectKey = getHiveWorkingDirectory();
|
|
27862
|
+
const adapter = await getHiveAdapter(projectKey);
|
|
27862
27863
|
try {
|
|
27863
|
-
let
|
|
27864
|
+
let cell;
|
|
27864
27865
|
if (validated.status) {
|
|
27865
|
-
|
|
27866
|
+
cell = await adapter.changeCellStatus(projectKey, validated.id, validated.status);
|
|
27866
27867
|
}
|
|
27867
27868
|
if (validated.description !== undefined || validated.priority !== undefined) {
|
|
27868
|
-
|
|
27869
|
+
cell = await adapter.updateCell(projectKey, validated.id, {
|
|
27869
27870
|
description: validated.description,
|
|
27870
27871
|
priority: validated.priority
|
|
27871
27872
|
});
|
|
27872
27873
|
} else if (!validated.status) {
|
|
27873
|
-
const
|
|
27874
|
-
if (!
|
|
27875
|
-
throw new
|
|
27874
|
+
const existingCell = await adapter.getCell(projectKey, validated.id);
|
|
27875
|
+
if (!existingCell) {
|
|
27876
|
+
throw new HiveError(`Cell not found: ${validated.id}`, "hive_update");
|
|
27876
27877
|
}
|
|
27877
|
-
|
|
27878
|
+
cell = existingCell;
|
|
27878
27879
|
}
|
|
27879
27880
|
await adapter.markDirty(projectKey, validated.id);
|
|
27880
|
-
const formatted =
|
|
27881
|
+
const formatted = formatCellForOutput(cell);
|
|
27881
27882
|
return JSON.stringify(formatted, null, 2);
|
|
27882
27883
|
} catch (error45) {
|
|
27883
27884
|
const message = error45 instanceof Error ? error45.message : String(error45);
|
|
27884
|
-
throw new
|
|
27885
|
+
throw new HiveError(`Failed to update cell: ${message}`, "hive_update");
|
|
27885
27886
|
}
|
|
27886
27887
|
}
|
|
27887
27888
|
});
|
|
27888
|
-
var
|
|
27889
|
-
description: "Close a
|
|
27889
|
+
var hive_close = tool({
|
|
27890
|
+
description: "Close a cell with reason",
|
|
27890
27891
|
args: {
|
|
27891
|
-
id: tool.schema.string().describe("
|
|
27892
|
+
id: tool.schema.string().describe("Cell ID"),
|
|
27892
27893
|
reason: tool.schema.string().describe("Completion reason")
|
|
27893
27894
|
},
|
|
27894
27895
|
async execute(args, ctx) {
|
|
27895
|
-
const validated =
|
|
27896
|
-
const projectKey =
|
|
27897
|
-
const adapter = await
|
|
27896
|
+
const validated = CellCloseArgsSchema.parse(args);
|
|
27897
|
+
const projectKey = getHiveWorkingDirectory();
|
|
27898
|
+
const adapter = await getHiveAdapter(projectKey);
|
|
27898
27899
|
try {
|
|
27899
|
-
const
|
|
27900
|
+
const cell = await adapter.closeCell(projectKey, validated.id, validated.reason);
|
|
27900
27901
|
await adapter.markDirty(projectKey, validated.id);
|
|
27901
|
-
return `Closed ${
|
|
27902
|
+
return `Closed ${cell.id}: ${validated.reason}`;
|
|
27902
27903
|
} catch (error45) {
|
|
27903
27904
|
const message = error45 instanceof Error ? error45.message : String(error45);
|
|
27904
|
-
throw new
|
|
27905
|
+
throw new HiveError(`Failed to close cell: ${message}`, "hive_close");
|
|
27905
27906
|
}
|
|
27906
27907
|
}
|
|
27907
27908
|
});
|
|
27908
|
-
var
|
|
27909
|
-
description: "Mark a
|
|
27909
|
+
var hive_start = tool({
|
|
27910
|
+
description: "Mark a cell as in-progress (shortcut for update --status in_progress)",
|
|
27910
27911
|
args: {
|
|
27911
|
-
id: tool.schema.string().describe("
|
|
27912
|
+
id: tool.schema.string().describe("Cell ID")
|
|
27912
27913
|
},
|
|
27913
27914
|
async execute(args, ctx) {
|
|
27914
|
-
const projectKey =
|
|
27915
|
-
const adapter = await
|
|
27915
|
+
const projectKey = getHiveWorkingDirectory();
|
|
27916
|
+
const adapter = await getHiveAdapter(projectKey);
|
|
27916
27917
|
try {
|
|
27917
|
-
const
|
|
27918
|
+
const cell = await adapter.changeCellStatus(projectKey, args.id, "in_progress");
|
|
27918
27919
|
await adapter.markDirty(projectKey, args.id);
|
|
27919
|
-
return `Started: ${
|
|
27920
|
+
return `Started: ${cell.id}`;
|
|
27920
27921
|
} catch (error45) {
|
|
27921
27922
|
const message = error45 instanceof Error ? error45.message : String(error45);
|
|
27922
|
-
throw new
|
|
27923
|
+
throw new HiveError(`Failed to start cell: ${message}`, "hive_start");
|
|
27923
27924
|
}
|
|
27924
27925
|
}
|
|
27925
27926
|
});
|
|
27926
|
-
var
|
|
27927
|
-
description: "Get the next ready
|
|
27927
|
+
var hive_ready = tool({
|
|
27928
|
+
description: "Get the next ready cell (unblocked, highest priority)",
|
|
27928
27929
|
args: {},
|
|
27929
27930
|
async execute(args, ctx) {
|
|
27930
|
-
const projectKey =
|
|
27931
|
-
const adapter = await
|
|
27931
|
+
const projectKey = getHiveWorkingDirectory();
|
|
27932
|
+
const adapter = await getHiveAdapter(projectKey);
|
|
27932
27933
|
try {
|
|
27933
|
-
const
|
|
27934
|
-
if (!
|
|
27935
|
-
return "No ready
|
|
27934
|
+
const cell = await adapter.getNextReadyCell(projectKey);
|
|
27935
|
+
if (!cell) {
|
|
27936
|
+
return "No ready cells";
|
|
27936
27937
|
}
|
|
27937
|
-
const formatted =
|
|
27938
|
+
const formatted = formatCellForOutput(cell);
|
|
27938
27939
|
return JSON.stringify(formatted, null, 2);
|
|
27939
27940
|
} catch (error45) {
|
|
27940
27941
|
const message = error45 instanceof Error ? error45.message : String(error45);
|
|
27941
|
-
throw new
|
|
27942
|
+
throw new HiveError(`Failed to get ready cells: ${message}`, "hive_ready");
|
|
27942
27943
|
}
|
|
27943
27944
|
}
|
|
27944
27945
|
});
|
|
27945
|
-
var
|
|
27946
|
-
description: "Sync
|
|
27946
|
+
var hive_sync = tool({
|
|
27947
|
+
description: "Sync hive to git and push (MANDATORY at session end)",
|
|
27947
27948
|
args: {
|
|
27948
27949
|
auto_pull: tool.schema.boolean().optional().describe("Pull before sync (default: true)")
|
|
27949
27950
|
},
|
|
27950
27951
|
async execute(args, ctx) {
|
|
27951
27952
|
const autoPull = args.auto_pull ?? true;
|
|
27952
|
-
const projectKey =
|
|
27953
|
-
const adapter = await
|
|
27953
|
+
const projectKey = getHiveWorkingDirectory();
|
|
27954
|
+
const adapter = await getHiveAdapter(projectKey);
|
|
27954
27955
|
const TIMEOUT_MS = 30000;
|
|
27955
27956
|
const withTimeout = async (promise2, timeoutMs, operation) => {
|
|
27956
27957
|
let timeoutId;
|
|
27957
27958
|
const timeoutPromise = new Promise((_, reject) => {
|
|
27958
|
-
timeoutId = setTimeout(() => reject(new
|
|
27959
|
+
timeoutId = setTimeout(() => reject(new HiveError(`Operation timed out after ${timeoutMs}ms`, operation)), timeoutMs);
|
|
27959
27960
|
});
|
|
27960
27961
|
try {
|
|
27961
27962
|
return await Promise.race([promise2, timeoutPromise]);
|
|
@@ -27968,85 +27969,156 @@ var beads_sync = tool({
|
|
|
27968
27969
|
const flushManager = new FlushManager({
|
|
27969
27970
|
adapter,
|
|
27970
27971
|
projectKey,
|
|
27971
|
-
outputPath: `${projectKey}/.
|
|
27972
|
+
outputPath: `${projectKey}/.hive/issues.jsonl`
|
|
27972
27973
|
});
|
|
27973
|
-
const flushResult = await withTimeout(flushManager.flush(), TIMEOUT_MS, "flush
|
|
27974
|
-
if (flushResult.
|
|
27975
|
-
return "No
|
|
27974
|
+
const flushResult = await withTimeout(flushManager.flush(), TIMEOUT_MS, "flush hive");
|
|
27975
|
+
if (flushResult.cellsExported === 0) {
|
|
27976
|
+
return "No cells to sync";
|
|
27976
27977
|
}
|
|
27977
|
-
const
|
|
27978
|
+
const hiveStatusResult = await runGitCommand([
|
|
27978
27979
|
"status",
|
|
27979
27980
|
"--porcelain",
|
|
27980
|
-
".
|
|
27981
|
+
".hive/"
|
|
27981
27982
|
]);
|
|
27982
|
-
const hasChanges =
|
|
27983
|
+
const hasChanges = hiveStatusResult.stdout.trim() !== "";
|
|
27983
27984
|
if (hasChanges) {
|
|
27984
|
-
const addResult = await runGitCommand(["add", ".
|
|
27985
|
+
const addResult = await runGitCommand(["add", ".hive/"]);
|
|
27985
27986
|
if (addResult.exitCode !== 0) {
|
|
27986
|
-
throw new
|
|
27987
|
+
throw new HiveError(`Failed to stage hive: ${addResult.stderr}`, "git add .hive/", addResult.exitCode);
|
|
27987
27988
|
}
|
|
27988
|
-
const commitResult = await withTimeout(runGitCommand(["commit", "-m", "chore: sync
|
|
27989
|
+
const commitResult = await withTimeout(runGitCommand(["commit", "-m", "chore: sync hive"]), TIMEOUT_MS, "git commit");
|
|
27989
27990
|
if (commitResult.exitCode !== 0 && !commitResult.stdout.includes("nothing to commit")) {
|
|
27990
|
-
throw new
|
|
27991
|
+
throw new HiveError(`Failed to commit hive: ${commitResult.stderr}`, "git commit", commitResult.exitCode);
|
|
27991
27992
|
}
|
|
27992
27993
|
}
|
|
27993
27994
|
if (autoPull) {
|
|
27994
27995
|
const pullResult = await withTimeout(runGitCommand(["pull", "--rebase"]), TIMEOUT_MS, "git pull --rebase");
|
|
27995
27996
|
if (pullResult.exitCode !== 0) {
|
|
27996
|
-
throw new
|
|
27997
|
+
throw new HiveError(`Failed to pull: ${pullResult.stderr}`, "git pull --rebase", pullResult.exitCode);
|
|
27997
27998
|
}
|
|
27998
27999
|
}
|
|
27999
28000
|
const pushResult = await withTimeout(runGitCommand(["push"]), TIMEOUT_MS, "git push");
|
|
28000
28001
|
if (pushResult.exitCode !== 0) {
|
|
28001
|
-
throw new
|
|
28002
|
+
throw new HiveError(`Failed to push: ${pushResult.stderr}`, "git push", pushResult.exitCode);
|
|
28002
28003
|
}
|
|
28003
|
-
return "
|
|
28004
|
+
return "Hive synced and pushed successfully";
|
|
28004
28005
|
}
|
|
28005
28006
|
});
|
|
28006
|
-
var
|
|
28007
|
-
description: "Add metadata linking
|
|
28007
|
+
var hive_link_thread = tool({
|
|
28008
|
+
description: "Add metadata linking cell to Agent Mail thread",
|
|
28008
28009
|
args: {
|
|
28009
|
-
|
|
28010
|
+
cell_id: tool.schema.string().describe("Cell ID"),
|
|
28010
28011
|
thread_id: tool.schema.string().describe("Agent Mail thread ID")
|
|
28011
28012
|
},
|
|
28012
28013
|
async execute(args, ctx) {
|
|
28013
|
-
const projectKey =
|
|
28014
|
-
const adapter = await
|
|
28014
|
+
const projectKey = getHiveWorkingDirectory();
|
|
28015
|
+
const adapter = await getHiveAdapter(projectKey);
|
|
28015
28016
|
try {
|
|
28016
|
-
const
|
|
28017
|
-
if (!
|
|
28018
|
-
throw new
|
|
28017
|
+
const cell = await adapter.getCell(projectKey, args.cell_id);
|
|
28018
|
+
if (!cell) {
|
|
28019
|
+
throw new HiveError(`Cell not found: ${args.cell_id}`, "hive_link_thread");
|
|
28019
28020
|
}
|
|
28020
|
-
const existingDesc =
|
|
28021
|
+
const existingDesc = cell.description || "";
|
|
28021
28022
|
const threadMarker = `[thread:${args.thread_id}]`;
|
|
28022
28023
|
if (existingDesc.includes(threadMarker)) {
|
|
28023
|
-
return `
|
|
28024
|
+
return `Cell ${args.cell_id} already linked to thread ${args.thread_id}`;
|
|
28024
28025
|
}
|
|
28025
28026
|
const newDesc = existingDesc ? `${existingDesc}
|
|
28026
28027
|
|
|
28027
28028
|
${threadMarker}` : threadMarker;
|
|
28028
|
-
await adapter.
|
|
28029
|
+
await adapter.updateCell(projectKey, args.cell_id, {
|
|
28029
28030
|
description: newDesc
|
|
28030
28031
|
});
|
|
28031
|
-
await adapter.markDirty(projectKey, args.
|
|
28032
|
-
return `Linked
|
|
28032
|
+
await adapter.markDirty(projectKey, args.cell_id);
|
|
28033
|
+
return `Linked cell ${args.cell_id} to thread ${args.thread_id}`;
|
|
28033
28034
|
} catch (error45) {
|
|
28034
28035
|
const message = error45 instanceof Error ? error45.message : String(error45);
|
|
28035
|
-
throw new
|
|
28036
|
+
throw new HiveError(`Failed to link thread: ${message}`, "hive_link_thread");
|
|
28036
28037
|
}
|
|
28037
28038
|
}
|
|
28038
28039
|
});
|
|
28039
|
-
var
|
|
28040
|
-
|
|
28041
|
-
|
|
28042
|
-
|
|
28043
|
-
|
|
28044
|
-
|
|
28045
|
-
|
|
28046
|
-
|
|
28047
|
-
|
|
28048
|
-
|
|
28040
|
+
var hiveTools = {
|
|
28041
|
+
hive_create,
|
|
28042
|
+
hive_create_epic,
|
|
28043
|
+
hive_query,
|
|
28044
|
+
hive_update,
|
|
28045
|
+
hive_close,
|
|
28046
|
+
hive_start,
|
|
28047
|
+
hive_ready,
|
|
28048
|
+
hive_sync,
|
|
28049
|
+
hive_link_thread
|
|
28049
28050
|
};
|
|
28051
|
+
var warnedTools = new Set;
|
|
28052
|
+
function warnDeprecated(oldName, newName) {
|
|
28053
|
+
if (warnedTools.has(oldName)) {
|
|
28054
|
+
return;
|
|
28055
|
+
}
|
|
28056
|
+
warnedTools.add(oldName);
|
|
28057
|
+
console.warn(`[DEPRECATED] ${oldName} is deprecated, use ${newName} instead. Will be removed in v1.0`);
|
|
28058
|
+
}
|
|
28059
|
+
var beads_create = tool({
|
|
28060
|
+
...hive_create,
|
|
28061
|
+
async execute(args, ctx) {
|
|
28062
|
+
warnDeprecated("beads_create", "hive_create");
|
|
28063
|
+
return hive_create.execute(args, ctx);
|
|
28064
|
+
}
|
|
28065
|
+
});
|
|
28066
|
+
var beads_create_epic = tool({
|
|
28067
|
+
...hive_create_epic,
|
|
28068
|
+
async execute(args, ctx) {
|
|
28069
|
+
warnDeprecated("beads_create_epic", "hive_create_epic");
|
|
28070
|
+
return hive_create_epic.execute(args, ctx);
|
|
28071
|
+
}
|
|
28072
|
+
});
|
|
28073
|
+
var beads_query = tool({
|
|
28074
|
+
...hive_query,
|
|
28075
|
+
async execute(args, ctx) {
|
|
28076
|
+
warnDeprecated("beads_query", "hive_query");
|
|
28077
|
+
return hive_query.execute(args, ctx);
|
|
28078
|
+
}
|
|
28079
|
+
});
|
|
28080
|
+
var beads_update = tool({
|
|
28081
|
+
...hive_update,
|
|
28082
|
+
async execute(args, ctx) {
|
|
28083
|
+
warnDeprecated("beads_update", "hive_update");
|
|
28084
|
+
return hive_update.execute(args, ctx);
|
|
28085
|
+
}
|
|
28086
|
+
});
|
|
28087
|
+
var beads_close = tool({
|
|
28088
|
+
...hive_close,
|
|
28089
|
+
async execute(args, ctx) {
|
|
28090
|
+
warnDeprecated("beads_close", "hive_close");
|
|
28091
|
+
return hive_close.execute(args, ctx);
|
|
28092
|
+
}
|
|
28093
|
+
});
|
|
28094
|
+
var beads_start = tool({
|
|
28095
|
+
...hive_start,
|
|
28096
|
+
async execute(args, ctx) {
|
|
28097
|
+
warnDeprecated("beads_start", "hive_start");
|
|
28098
|
+
return hive_start.execute(args, ctx);
|
|
28099
|
+
}
|
|
28100
|
+
});
|
|
28101
|
+
var beads_ready = tool({
|
|
28102
|
+
...hive_ready,
|
|
28103
|
+
async execute(args, ctx) {
|
|
28104
|
+
warnDeprecated("beads_ready", "hive_ready");
|
|
28105
|
+
return hive_ready.execute(args, ctx);
|
|
28106
|
+
}
|
|
28107
|
+
});
|
|
28108
|
+
var beads_sync = tool({
|
|
28109
|
+
...hive_sync,
|
|
28110
|
+
async execute(args, ctx) {
|
|
28111
|
+
warnDeprecated("beads_sync", "hive_sync");
|
|
28112
|
+
return hive_sync.execute(args, ctx);
|
|
28113
|
+
}
|
|
28114
|
+
});
|
|
28115
|
+
var beads_link_thread = tool({
|
|
28116
|
+
...hive_link_thread,
|
|
28117
|
+
async execute(args, ctx) {
|
|
28118
|
+
warnDeprecated("beads_link_thread", "hive_link_thread");
|
|
28119
|
+
return hive_link_thread.execute(args, ctx);
|
|
28120
|
+
}
|
|
28121
|
+
});
|
|
28050
28122
|
|
|
28051
28123
|
// src/agent-mail.ts
|
|
28052
28124
|
init_dist();
|
|
@@ -28165,6 +28237,29 @@ var toolCheckers = {
|
|
|
28165
28237
|
};
|
|
28166
28238
|
}
|
|
28167
28239
|
},
|
|
28240
|
+
hive: async () => {
|
|
28241
|
+
const exists = await commandExists("hive");
|
|
28242
|
+
if (!exists) {
|
|
28243
|
+
return {
|
|
28244
|
+
available: false,
|
|
28245
|
+
checkedAt: new Date().toISOString(),
|
|
28246
|
+
error: "hive command not found"
|
|
28247
|
+
};
|
|
28248
|
+
}
|
|
28249
|
+
try {
|
|
28250
|
+
const result = await Bun.$`hive --version`.quiet().nothrow();
|
|
28251
|
+
return {
|
|
28252
|
+
available: result.exitCode === 0,
|
|
28253
|
+
checkedAt: new Date().toISOString()
|
|
28254
|
+
};
|
|
28255
|
+
} catch (e) {
|
|
28256
|
+
return {
|
|
28257
|
+
available: false,
|
|
28258
|
+
checkedAt: new Date().toISOString(),
|
|
28259
|
+
error: String(e)
|
|
28260
|
+
};
|
|
28261
|
+
}
|
|
28262
|
+
},
|
|
28168
28263
|
beads: async () => {
|
|
28169
28264
|
const exists = await commandExists("bd");
|
|
28170
28265
|
if (!exists) {
|
|
@@ -28218,7 +28313,8 @@ var fallbackBehaviors = {
|
|
|
28218
28313
|
"semantic-memory": "Learning data stored in-memory only (lost on session end)",
|
|
28219
28314
|
cass: "Decomposition proceeds without historical context from past sessions",
|
|
28220
28315
|
ubs: "Subtask completion skips bug scanning - manual review recommended",
|
|
28221
|
-
|
|
28316
|
+
hive: "Swarm cannot track issues - task coordination will be less reliable",
|
|
28317
|
+
beads: "DEPRECATED: Use hive instead. Swarm cannot track issues - task coordination will be less reliable",
|
|
28222
28318
|
"swarm-mail": "Multi-agent coordination disabled - file conflicts possible if multiple agents active",
|
|
28223
28319
|
"agent-mail": "DEPRECATED: Use swarm-mail instead. Legacy MCP server mode - file conflicts possible if multiple agents active"
|
|
28224
28320
|
};
|
|
@@ -28249,6 +28345,7 @@ async function checkAllTools() {
|
|
|
28249
28345
|
"semantic-memory",
|
|
28250
28346
|
"cass",
|
|
28251
28347
|
"ubs",
|
|
28348
|
+
"hive",
|
|
28252
28349
|
"beads",
|
|
28253
28350
|
"swarm-mail",
|
|
28254
28351
|
"agent-mail"
|
|
@@ -29723,7 +29820,7 @@ function formatZodErrors(error45) {
|
|
|
29723
29820
|
var SCHEMA_REGISTRY = {
|
|
29724
29821
|
evaluation: EvaluationSchema,
|
|
29725
29822
|
task_decomposition: TaskDecompositionSchema,
|
|
29726
|
-
|
|
29823
|
+
cell_tree: CellTreeSchema
|
|
29727
29824
|
};
|
|
29728
29825
|
function getSchemaByName(name) {
|
|
29729
29826
|
const schema = SCHEMA_REGISTRY[name];
|
|
@@ -29859,7 +29956,7 @@ var structured_validate = tool({
|
|
|
29859
29956
|
description: "Validate agent response against a schema. Extracts JSON and validates with Zod. Returns structured errors for retry feedback.",
|
|
29860
29957
|
args: {
|
|
29861
29958
|
response: tool.schema.string().describe("Agent response to validate"),
|
|
29862
|
-
schema_name: tool.schema.enum(["evaluation", "task_decomposition", "
|
|
29959
|
+
schema_name: tool.schema.enum(["evaluation", "task_decomposition", "cell_tree"]).describe("Schema to validate against: " + "evaluation = agent self-eval with criteria, " + "task_decomposition = swarm task breakdown, " + "cell_tree = epic with subtasks"),
|
|
29863
29960
|
max_retries: tool.schema.number().min(1).max(5).optional().describe("Max retries (for tracking - actual retry logic is external)")
|
|
29864
29961
|
},
|
|
29865
29962
|
async execute(args, ctx) {
|
|
@@ -30045,15 +30142,15 @@ var structured_parse_decomposition = tool({
|
|
|
30045
30142
|
}
|
|
30046
30143
|
}
|
|
30047
30144
|
});
|
|
30048
|
-
var
|
|
30049
|
-
description: "Parse and validate bead tree response. Uses
|
|
30145
|
+
var structured_parse_cell_tree = tool({
|
|
30146
|
+
description: "Parse and validate bead tree response. Uses CellTreeSchema. Validates before creating epic with subtasks.",
|
|
30050
30147
|
args: {
|
|
30051
30148
|
response: tool.schema.string().describe("Agent response containing bead tree")
|
|
30052
30149
|
},
|
|
30053
30150
|
async execute(args, ctx) {
|
|
30054
30151
|
try {
|
|
30055
30152
|
const [extracted, method] = extractJsonFromText(args.response);
|
|
30056
|
-
const validated =
|
|
30153
|
+
const validated = CellTreeSchema.parse(extracted);
|
|
30057
30154
|
const allFiles = validated.subtasks.flatMap((s) => s.files);
|
|
30058
30155
|
const uniqueFiles = [...new Set(allFiles)];
|
|
30059
30156
|
return JSON.stringify({
|
|
@@ -30112,7 +30209,7 @@ var structuredTools = {
|
|
|
30112
30209
|
structured_validate,
|
|
30113
30210
|
structured_parse_evaluation,
|
|
30114
30211
|
structured_parse_decomposition,
|
|
30115
|
-
|
|
30212
|
+
structured_parse_cell_tree
|
|
30116
30213
|
};
|
|
30117
30214
|
|
|
30118
30215
|
// src/swarm.ts
|
|
@@ -30135,9 +30232,9 @@ var DECOMPOSITION_PROMPT = `You are decomposing a task into parallelizable subta
|
|
|
30135
30232
|
|
|
30136
30233
|
After decomposition, the coordinator will:
|
|
30137
30234
|
1. Create an epic bead for the overall task
|
|
30138
|
-
2. Create child
|
|
30235
|
+
2. Create child cells for each subtask
|
|
30139
30236
|
3. Track progress through bead status updates
|
|
30140
|
-
4. Close
|
|
30237
|
+
4. Close cells with summaries when complete
|
|
30141
30238
|
|
|
30142
30239
|
Agents MUST update their bead status as they work. No silent progress.
|
|
30143
30240
|
|
|
@@ -30157,7 +30254,7 @@ Respond with a JSON object matching this schema:
|
|
|
30157
30254
|
\`\`\`typescript
|
|
30158
30255
|
{
|
|
30159
30256
|
epic: {
|
|
30160
|
-
title: string, // Epic title for the
|
|
30257
|
+
title: string, // Epic title for the hive tracker
|
|
30161
30258
|
description?: string // Brief description of the overall goal
|
|
30162
30259
|
},
|
|
30163
30260
|
subtasks: [
|
|
@@ -30208,9 +30305,9 @@ var STRATEGY_DECOMPOSITION_PROMPT = `You are decomposing a task into paralleliza
|
|
|
30208
30305
|
|
|
30209
30306
|
After decomposition, the coordinator will:
|
|
30210
30307
|
1. Create an epic bead for the overall task
|
|
30211
|
-
2. Create child
|
|
30308
|
+
2. Create child cells for each subtask
|
|
30212
30309
|
3. Track progress through bead status updates
|
|
30213
|
-
4. Close
|
|
30310
|
+
4. Close cells with summaries when complete
|
|
30214
30311
|
|
|
30215
30312
|
Agents MUST update their bead status as they work. No silent progress.
|
|
30216
30313
|
|
|
@@ -30230,7 +30327,7 @@ Respond with a JSON object matching this schema:
|
|
|
30230
30327
|
\`\`\`typescript
|
|
30231
30328
|
{
|
|
30232
30329
|
epic: {
|
|
30233
|
-
title: string, // Epic title for the
|
|
30330
|
+
title: string, // Epic title for the hive tracker
|
|
30234
30331
|
description?: string // Brief description of the overall goal
|
|
30235
30332
|
},
|
|
30236
30333
|
subtasks: [
|
|
@@ -30420,7 +30517,7 @@ ${fullContext}` : `## Additional Context
|
|
|
30420
30517
|
const prompt = DECOMPOSITION_PROMPT.replace("{task}", args.task).replace("{max_subtasks}", (args.max_subtasks ?? 5).toString()).replace("{context_section}", contextSection);
|
|
30421
30518
|
return JSON.stringify({
|
|
30422
30519
|
prompt,
|
|
30423
|
-
expected_schema: "
|
|
30520
|
+
expected_schema: "CellTree",
|
|
30424
30521
|
schema_hint: {
|
|
30425
30522
|
epic: { title: "string", description: "string?" },
|
|
30426
30523
|
subtasks: [
|
|
@@ -30433,21 +30530,21 @@ ${fullContext}` : `## Additional Context
|
|
|
30433
30530
|
}
|
|
30434
30531
|
]
|
|
30435
30532
|
},
|
|
30436
|
-
validation_note: "Parse agent response as JSON and validate with
|
|
30533
|
+
validation_note: "Parse agent response as JSON and validate with CellTreeSchema from schemas/bead.ts",
|
|
30437
30534
|
cass_history: cassResultInfo,
|
|
30438
30535
|
memory_query: formatMemoryQueryForDecomposition2(args.task, 3)
|
|
30439
30536
|
}, null, 2);
|
|
30440
30537
|
}
|
|
30441
30538
|
});
|
|
30442
30539
|
var swarm_validate_decomposition = tool({
|
|
30443
|
-
description: "Validate a decomposition response against
|
|
30540
|
+
description: "Validate a decomposition response against CellTreeSchema",
|
|
30444
30541
|
args: {
|
|
30445
|
-
response: tool.schema.string().describe("JSON response from agent (
|
|
30542
|
+
response: tool.schema.string().describe("JSON response from agent (CellTree format)")
|
|
30446
30543
|
},
|
|
30447
30544
|
async execute(args) {
|
|
30448
30545
|
try {
|
|
30449
30546
|
const parsed = JSON.parse(args.response);
|
|
30450
|
-
const validated =
|
|
30547
|
+
const validated = CellTreeSchema.parse(parsed);
|
|
30451
30548
|
const conflicts = detectFileConflicts(validated.subtasks);
|
|
30452
30549
|
if (conflicts.length > 0) {
|
|
30453
30550
|
return JSON.stringify({
|
|
@@ -30478,7 +30575,7 @@ var swarm_validate_decomposition = tool({
|
|
|
30478
30575
|
const instructionConflicts = detectInstructionConflicts(validated.subtasks);
|
|
30479
30576
|
return JSON.stringify({
|
|
30480
30577
|
valid: true,
|
|
30481
|
-
|
|
30578
|
+
cell_tree: validated,
|
|
30482
30579
|
stats: {
|
|
30483
30580
|
subtask_count: validated.subtasks.length,
|
|
30484
30581
|
total_files: new Set(validated.subtasks.flatMap((s) => s.files)).size,
|
|
@@ -30580,7 +30677,7 @@ ${args.context}` : `## Additional Context
|
|
|
30580
30677
|
const subagentInstructions = `
|
|
30581
30678
|
## CRITICAL: Output Format
|
|
30582
30679
|
|
|
30583
|
-
You are a planner subagent. Your ONLY output must be valid JSON matching the
|
|
30680
|
+
You are a planner subagent. Your ONLY output must be valid JSON matching the CellTree schema.
|
|
30584
30681
|
|
|
30585
30682
|
DO NOT include:
|
|
30586
30683
|
- Explanatory text before or after the JSON
|
|
@@ -30614,7 +30711,7 @@ OUTPUT ONLY the raw JSON object.
|
|
|
30614
30711
|
]
|
|
30615
30712
|
}
|
|
30616
30713
|
|
|
30617
|
-
Now generate the
|
|
30714
|
+
Now generate the CellTree for the given task.`;
|
|
30618
30715
|
const fullPrompt = `${planningPrompt}
|
|
30619
30716
|
|
|
30620
30717
|
${subagentInstructions}`;
|
|
@@ -30626,12 +30723,12 @@ ${subagentInstructions}`;
|
|
|
30626
30723
|
selected: selectedStrategy,
|
|
30627
30724
|
reasoning: strategyReasoning
|
|
30628
30725
|
},
|
|
30629
|
-
expected_output: "
|
|
30726
|
+
expected_output: "CellTree JSON (raw JSON, no markdown)",
|
|
30630
30727
|
next_steps: [
|
|
30631
30728
|
"1. Spawn subagent with Task tool using returned prompt",
|
|
30632
30729
|
"2. Parse subagent response as JSON",
|
|
30633
30730
|
"3. Validate with swarm_validate_decomposition",
|
|
30634
|
-
"4. Create
|
|
30731
|
+
"4. Create cells with hive_create_epic"
|
|
30635
30732
|
],
|
|
30636
30733
|
cass_history: cassResultInfo,
|
|
30637
30734
|
skills: skillsInfo,
|
|
@@ -30871,17 +30968,17 @@ var STRATEGY_DECOMPOSITION_PROMPT2 = `You are decomposing a task into paralleliz
|
|
|
30871
30968
|
|
|
30872
30969
|
{skills_context}
|
|
30873
30970
|
|
|
30874
|
-
## MANDATORY:
|
|
30971
|
+
## MANDATORY: Hive Issue Tracking
|
|
30875
30972
|
|
|
30876
|
-
**Every subtask MUST become a
|
|
30973
|
+
**Every subtask MUST become a cell.** This is non-negotiable.
|
|
30877
30974
|
|
|
30878
30975
|
After decomposition, the coordinator will:
|
|
30879
|
-
1. Create an epic
|
|
30880
|
-
2. Create child
|
|
30881
|
-
3. Track progress through
|
|
30882
|
-
4. Close
|
|
30976
|
+
1. Create an epic cell for the overall task
|
|
30977
|
+
2. Create child cells for each subtask
|
|
30978
|
+
3. Track progress through cell status updates
|
|
30979
|
+
4. Close cells with summaries when complete
|
|
30883
30980
|
|
|
30884
|
-
Agents MUST update their
|
|
30981
|
+
Agents MUST update their cell status as they work. No silent progress.
|
|
30885
30982
|
|
|
30886
30983
|
## Requirements
|
|
30887
30984
|
|
|
@@ -30899,7 +30996,7 @@ Respond with a JSON object matching this schema:
|
|
|
30899
30996
|
\`\`\`typescript
|
|
30900
30997
|
{
|
|
30901
30998
|
epic: {
|
|
30902
|
-
title: string, // Epic title for the
|
|
30999
|
+
title: string, // Epic title for the hive tracker
|
|
30903
31000
|
description?: string // Brief description of the overall goal
|
|
30904
31001
|
},
|
|
30905
31002
|
subtasks: [
|
|
@@ -30920,7 +31017,7 @@ var SUBTASK_PROMPT = `You are a swarm agent working on a subtask of a larger epi
|
|
|
30920
31017
|
|
|
30921
31018
|
## Your Identity
|
|
30922
31019
|
- **Agent Name**: {agent_name}
|
|
30923
|
-
- **
|
|
31020
|
+
- **Cell ID**: {bead_id}
|
|
30924
31021
|
- **Epic ID**: {epic_id}
|
|
30925
31022
|
|
|
30926
31023
|
## Your Subtask
|
|
@@ -30938,16 +31035,16 @@ send a message to the coordinator requesting the change.
|
|
|
30938
31035
|
## Shared Context
|
|
30939
31036
|
{shared_context}
|
|
30940
31037
|
|
|
30941
|
-
## MANDATORY:
|
|
31038
|
+
## MANDATORY: Hive Tracking
|
|
30942
31039
|
|
|
30943
|
-
You MUST keep your
|
|
31040
|
+
You MUST keep your cell updated as you work:
|
|
30944
31041
|
|
|
30945
|
-
1. **Your
|
|
30946
|
-
2. **If blocked**: \`
|
|
30947
|
-
3. **When done**: Use \`swarm_complete\` - it closes your
|
|
30948
|
-
4. **Discovered issues**: Create new
|
|
31042
|
+
1. **Your cell is already in_progress** - don't change this unless blocked
|
|
31043
|
+
2. **If blocked**: \`hive_update {bead_id} --status blocked\` and message coordinator
|
|
31044
|
+
3. **When done**: Use \`swarm_complete\` - it closes your cell automatically
|
|
31045
|
+
4. **Discovered issues**: Create new cells with \`hive_create "issue" -t bug\`
|
|
30949
31046
|
|
|
30950
|
-
**Never work silently.** Your
|
|
31047
|
+
**Never work silently.** Your cell status is how the swarm tracks progress.
|
|
30951
31048
|
|
|
30952
31049
|
## MANDATORY: Swarm Mail Communication
|
|
30953
31050
|
|
|
@@ -30970,11 +31067,11 @@ swarmmail_send(
|
|
|
30970
31067
|
|
|
30971
31068
|
## Coordination Protocol
|
|
30972
31069
|
|
|
30973
|
-
1. **Start**: Your
|
|
31070
|
+
1. **Start**: Your cell is already marked in_progress
|
|
30974
31071
|
2. **Progress**: Use swarm_progress to report status updates
|
|
30975
31072
|
3. **Blocked**: Report immediately via Swarm Mail - don't spin
|
|
30976
31073
|
4. **Complete**: Use swarm_complete when done - it handles:
|
|
30977
|
-
- Closing your
|
|
31074
|
+
- Closing your cell with a summary
|
|
30978
31075
|
- Releasing file reservations
|
|
30979
31076
|
- Notifying the coordinator
|
|
30980
31077
|
|
|
@@ -31001,7 +31098,7 @@ var SUBTASK_PROMPT_V2 = `You are a swarm agent working on: **{subtask_title}**
|
|
|
31001
31098
|
|
|
31002
31099
|
## [IDENTITY]
|
|
31003
31100
|
Agent: (assigned at spawn)
|
|
31004
|
-
|
|
31101
|
+
Cell: {bead_id}
|
|
31005
31102
|
Epic: {epic_id}
|
|
31006
31103
|
|
|
31007
31104
|
## [TASK]
|
|
@@ -31145,7 +31242,7 @@ swarm_complete(
|
|
|
31145
31242
|
- Records learning signals
|
|
31146
31243
|
- Notifies coordinator
|
|
31147
31244
|
|
|
31148
|
-
**DO NOT manually close the
|
|
31245
|
+
**DO NOT manually close the cell with hive_close.** Use swarm_complete.
|
|
31149
31246
|
|
|
31150
31247
|
## [SWARM MAIL COMMUNICATION]
|
|
31151
31248
|
|
|
@@ -31164,7 +31261,7 @@ swarmmail_send(
|
|
|
31164
31261
|
importance="high",
|
|
31165
31262
|
thread_id="{epic_id}"
|
|
31166
31263
|
)
|
|
31167
|
-
|
|
31264
|
+
hive_update(id="{bead_id}", status="blocked")
|
|
31168
31265
|
\`\`\`
|
|
31169
31266
|
|
|
31170
31267
|
### Report Issues to Other Agents
|
|
@@ -31185,15 +31282,15 @@ swarmmail_release() # Manually release reservations
|
|
|
31185
31282
|
**Note:** \`swarm_complete\` automatically releases reservations. Only use manual release if aborting work.
|
|
31186
31283
|
|
|
31187
31284
|
## [OTHER TOOLS]
|
|
31188
|
-
###
|
|
31189
|
-
You can create new
|
|
31285
|
+
### Hive - You Have Autonomy to File Issues
|
|
31286
|
+
You can create new cells against this epic when you discover:
|
|
31190
31287
|
- **Bugs**: Found a bug while working? File it.
|
|
31191
31288
|
- **Tech debt**: Spotted something that needs cleanup? File it.
|
|
31192
31289
|
- **Follow-up work**: Task needs more work than scoped? File a follow-up.
|
|
31193
31290
|
- **Dependencies**: Need something from another agent? File and link it.
|
|
31194
31291
|
|
|
31195
31292
|
\`\`\`
|
|
31196
|
-
|
|
31293
|
+
hive_create(
|
|
31197
31294
|
title="<descriptive title>",
|
|
31198
31295
|
type="bug", # or "task", "chore"
|
|
31199
31296
|
priority=2,
|
|
@@ -31204,9 +31301,9 @@ beads_create(
|
|
|
31204
31301
|
|
|
31205
31302
|
**Don't silently ignore issues.** File them so they get tracked and addressed.
|
|
31206
31303
|
|
|
31207
|
-
Other
|
|
31208
|
-
-
|
|
31209
|
-
-
|
|
31304
|
+
Other cell operations:
|
|
31305
|
+
- hive_update(id, status) - Mark blocked if stuck
|
|
31306
|
+
- hive_query(status="open") - See what else needs work
|
|
31210
31307
|
|
|
31211
31308
|
### Skills
|
|
31212
31309
|
- skills_list() - Discover available skills
|
|
@@ -31220,7 +31317,7 @@ Other bead operations:
|
|
|
31220
31317
|
2. Step 2 (semantic-memory_find) MUST happen before starting work
|
|
31221
31318
|
3. Step 4 (swarmmail_reserve) - YOU reserve files, not coordinator
|
|
31222
31319
|
4. Step 6 (swarm_progress) - Report at milestones, don't work silently
|
|
31223
|
-
5. Step 9 (swarm_complete) - Use this to close, NOT
|
|
31320
|
+
5. Step 9 (swarm_complete) - Use this to close, NOT hive_close
|
|
31224
31321
|
|
|
31225
31322
|
**If you skip these steps:**
|
|
31226
31323
|
- Your work won't be tracked (swarm_complete will fail)
|
|
@@ -31233,7 +31330,7 @@ Begin now.`;
|
|
|
31233
31330
|
var EVALUATION_PROMPT = `Evaluate the work completed for this subtask.
|
|
31234
31331
|
|
|
31235
31332
|
## Subtask
|
|
31236
|
-
**
|
|
31333
|
+
**Cell ID**: {bead_id}
|
|
31237
31334
|
**Title**: {subtask_title}
|
|
31238
31335
|
|
|
31239
31336
|
## Files Modified
|
|
@@ -31335,7 +31432,7 @@ var swarm_subtask_prompt = tool({
|
|
|
31335
31432
|
}
|
|
31336
31433
|
});
|
|
31337
31434
|
var swarm_spawn_subtask = tool({
|
|
31338
|
-
description: "Prepare a subtask for spawning. Returns prompt with Agent Mail/
|
|
31435
|
+
description: "Prepare a subtask for spawning. Returns prompt with Agent Mail/hive tracking instructions. IMPORTANT: Pass project_path for swarmmail_init.",
|
|
31339
31436
|
args: {
|
|
31340
31437
|
bead_id: tool.schema.string().describe("Subtask bead ID"),
|
|
31341
31438
|
epic_id: tool.schema.string().describe("Parent epic bead ID"),
|
|
@@ -31460,7 +31557,7 @@ ${args.context}` : `## Additional Context
|
|
|
31460
31557
|
guidelines: STRATEGIES2[selectedStrategy].guidelines,
|
|
31461
31558
|
anti_patterns: STRATEGIES2[selectedStrategy].antiPatterns
|
|
31462
31559
|
},
|
|
31463
|
-
expected_schema: "
|
|
31560
|
+
expected_schema: "CellTree",
|
|
31464
31561
|
schema_hint: {
|
|
31465
31562
|
epic: { title: "string", description: "string?" },
|
|
31466
31563
|
subtasks: [
|
|
@@ -31492,12 +31589,672 @@ init_learning();
|
|
|
31492
31589
|
import {
|
|
31493
31590
|
getSwarmInbox as getSwarmInbox2,
|
|
31494
31591
|
releaseSwarmFiles as releaseSwarmFiles2,
|
|
31495
|
-
sendSwarmMessage as
|
|
31592
|
+
sendSwarmMessage as sendSwarmMessage3,
|
|
31496
31593
|
getAgent,
|
|
31497
31594
|
createEvent as createEvent2,
|
|
31498
31595
|
appendEvent as appendEvent2
|
|
31499
31596
|
} from "swarm-mail";
|
|
31500
31597
|
init_skills();
|
|
31598
|
+
|
|
31599
|
+
// src/swarm-worktree.ts
|
|
31600
|
+
init_dist();
|
|
31601
|
+
init_zod();
|
|
31602
|
+
import { join as join6 } from "node:path";
|
|
31603
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
31604
|
+
var WORKTREE_DIR = ".swarm/worktrees";
|
|
31605
|
+
function getWorktreePath(projectPath, taskId) {
|
|
31606
|
+
const safeTaskId = taskId.replace(/[^a-zA-Z0-9.-]/g, "_");
|
|
31607
|
+
return join6(projectPath, WORKTREE_DIR, safeTaskId);
|
|
31608
|
+
}
|
|
31609
|
+
function parseTaskIdFromPath(worktreePath) {
|
|
31610
|
+
const parts = worktreePath.split("/");
|
|
31611
|
+
const worktreesIdx = parts.indexOf("worktrees");
|
|
31612
|
+
if (worktreesIdx >= 0 && worktreesIdx < parts.length - 1) {
|
|
31613
|
+
return parts[worktreesIdx + 1];
|
|
31614
|
+
}
|
|
31615
|
+
return null;
|
|
31616
|
+
}
|
|
31617
|
+
async function isGitRepo(path) {
|
|
31618
|
+
const result = await Bun.$`git -C ${path} rev-parse --git-dir`.quiet().nothrow();
|
|
31619
|
+
return result.exitCode === 0;
|
|
31620
|
+
}
|
|
31621
|
+
async function hasUncommittedChanges(path) {
|
|
31622
|
+
const result = await Bun.$`git -C ${path} status --porcelain`.quiet().nothrow();
|
|
31623
|
+
if (result.exitCode !== 0)
|
|
31624
|
+
return true;
|
|
31625
|
+
return result.stdout.toString().trim().length > 0;
|
|
31626
|
+
}
|
|
31627
|
+
async function getCurrentCommit(path) {
|
|
31628
|
+
const result = await Bun.$`git -C ${path} rev-parse HEAD`.quiet().nothrow();
|
|
31629
|
+
if (result.exitCode !== 0)
|
|
31630
|
+
return null;
|
|
31631
|
+
return result.stdout.toString().trim();
|
|
31632
|
+
}
|
|
31633
|
+
async function getWorktreeCommits(worktreePath, startCommit) {
|
|
31634
|
+
const result = await Bun.$`git -C ${worktreePath} log --format=%H ${startCommit}..HEAD`.quiet().nothrow();
|
|
31635
|
+
if (result.exitCode !== 0)
|
|
31636
|
+
return [];
|
|
31637
|
+
return result.stdout.toString().trim().split(`
|
|
31638
|
+
`).filter((c) => c.length > 0);
|
|
31639
|
+
}
|
|
31640
|
+
async function ensureWorktreeDir(projectPath) {
|
|
31641
|
+
const worktreeDir = join6(projectPath, WORKTREE_DIR);
|
|
31642
|
+
await Bun.$`mkdir -p ${worktreeDir}`.quiet().nothrow();
|
|
31643
|
+
}
|
|
31644
|
+
var swarm_worktree_create = tool({
|
|
31645
|
+
description: "Create a git worktree for isolated task execution. Worker operates in worktree, not main branch.",
|
|
31646
|
+
args: {
|
|
31647
|
+
project_path: exports_external.string().describe("Absolute path to project root"),
|
|
31648
|
+
task_id: exports_external.string().describe("Task/bead ID (e.g., bd-abc123.1)"),
|
|
31649
|
+
start_commit: exports_external.string().describe("Commit SHA to create worktree at (swarm start point)")
|
|
31650
|
+
},
|
|
31651
|
+
async execute(args) {
|
|
31652
|
+
if (!await isGitRepo(args.project_path)) {
|
|
31653
|
+
const result2 = {
|
|
31654
|
+
success: false,
|
|
31655
|
+
error: `${args.project_path} is not a git repository`
|
|
31656
|
+
};
|
|
31657
|
+
return JSON.stringify(result2, null, 2);
|
|
31658
|
+
}
|
|
31659
|
+
const worktreePath = getWorktreePath(args.project_path, args.task_id);
|
|
31660
|
+
const exists = existsSync5(worktreePath);
|
|
31661
|
+
if (exists) {
|
|
31662
|
+
const result2 = {
|
|
31663
|
+
success: false,
|
|
31664
|
+
error: `Worktree already exists for task ${args.task_id}`,
|
|
31665
|
+
worktree_path: worktreePath
|
|
31666
|
+
};
|
|
31667
|
+
return JSON.stringify(result2, null, 2);
|
|
31668
|
+
}
|
|
31669
|
+
await ensureWorktreeDir(args.project_path);
|
|
31670
|
+
const createResult = await Bun.$`git -C ${args.project_path} worktree add --detach ${worktreePath} ${args.start_commit}`.quiet().nothrow();
|
|
31671
|
+
if (createResult.exitCode !== 0) {
|
|
31672
|
+
const result2 = {
|
|
31673
|
+
success: false,
|
|
31674
|
+
error: `Failed to create worktree: ${createResult.stderr.toString()}`
|
|
31675
|
+
};
|
|
31676
|
+
return JSON.stringify(result2, null, 2);
|
|
31677
|
+
}
|
|
31678
|
+
const result = {
|
|
31679
|
+
success: true,
|
|
31680
|
+
worktree_path: worktreePath,
|
|
31681
|
+
task_id: args.task_id,
|
|
31682
|
+
created_at_commit: args.start_commit
|
|
31683
|
+
};
|
|
31684
|
+
return JSON.stringify(result, null, 2);
|
|
31685
|
+
}
|
|
31686
|
+
});
|
|
31687
|
+
var swarm_worktree_merge = tool({
|
|
31688
|
+
description: "Cherry-pick commits from worktree back to main branch. Call after worker completes.",
|
|
31689
|
+
args: {
|
|
31690
|
+
project_path: exports_external.string().describe("Absolute path to project root"),
|
|
31691
|
+
task_id: exports_external.string().describe("Task/bead ID"),
|
|
31692
|
+
start_commit: exports_external.string().optional().describe("Original start commit (to find new commits)")
|
|
31693
|
+
},
|
|
31694
|
+
async execute(args) {
|
|
31695
|
+
const worktreePath = getWorktreePath(args.project_path, args.task_id);
|
|
31696
|
+
const exists = existsSync5(worktreePath);
|
|
31697
|
+
if (!exists) {
|
|
31698
|
+
const result2 = {
|
|
31699
|
+
success: false,
|
|
31700
|
+
error: `Worktree not found for task ${args.task_id}`
|
|
31701
|
+
};
|
|
31702
|
+
return JSON.stringify(result2, null, 2);
|
|
31703
|
+
}
|
|
31704
|
+
let startCommit = args.start_commit;
|
|
31705
|
+
if (!startCommit) {
|
|
31706
|
+
const mergeBaseResult = await Bun.$`git -C ${args.project_path} merge-base HEAD ${worktreePath}`.quiet().nothrow();
|
|
31707
|
+
if (mergeBaseResult.exitCode === 0) {
|
|
31708
|
+
startCommit = mergeBaseResult.stdout.toString().trim();
|
|
31709
|
+
}
|
|
31710
|
+
}
|
|
31711
|
+
if (!startCommit) {
|
|
31712
|
+
const result2 = {
|
|
31713
|
+
success: false,
|
|
31714
|
+
error: "Could not determine start commit for cherry-pick"
|
|
31715
|
+
};
|
|
31716
|
+
return JSON.stringify(result2, null, 2);
|
|
31717
|
+
}
|
|
31718
|
+
const commits = await getWorktreeCommits(worktreePath, startCommit);
|
|
31719
|
+
if (commits.length === 0) {
|
|
31720
|
+
const result2 = {
|
|
31721
|
+
success: false,
|
|
31722
|
+
error: `Worktree has no commits since ${startCommit.slice(0, 7)}`
|
|
31723
|
+
};
|
|
31724
|
+
return JSON.stringify(result2, null, 2);
|
|
31725
|
+
}
|
|
31726
|
+
const reversedCommits = commits.reverse();
|
|
31727
|
+
let lastMergedCommit = null;
|
|
31728
|
+
for (const commit of reversedCommits) {
|
|
31729
|
+
const cherryResult = await Bun.$`git -C ${args.project_path} cherry-pick ${commit}`.quiet().nothrow();
|
|
31730
|
+
if (cherryResult.exitCode !== 0) {
|
|
31731
|
+
const stderr = cherryResult.stderr.toString();
|
|
31732
|
+
if (stderr.includes("conflict") || stderr.includes("CONFLICT")) {
|
|
31733
|
+
const statusResult = await Bun.$`git -C ${args.project_path} status --porcelain`.quiet().nothrow();
|
|
31734
|
+
const conflictingFiles = statusResult.stdout.toString().split(`
|
|
31735
|
+
`).filter((line) => line.startsWith("UU") || line.startsWith("AA")).map((line) => line.slice(3).trim());
|
|
31736
|
+
await Bun.$`git -C ${args.project_path} cherry-pick --abort`.quiet().nothrow();
|
|
31737
|
+
const result3 = {
|
|
31738
|
+
success: false,
|
|
31739
|
+
error: `Merge conflict during cherry-pick of ${commit.slice(0, 7)}`,
|
|
31740
|
+
conflicting_files: conflictingFiles
|
|
31741
|
+
};
|
|
31742
|
+
return JSON.stringify(result3, null, 2);
|
|
31743
|
+
}
|
|
31744
|
+
const result2 = {
|
|
31745
|
+
success: false,
|
|
31746
|
+
error: `Failed to cherry-pick ${commit.slice(0, 7)}: ${stderr}`
|
|
31747
|
+
};
|
|
31748
|
+
return JSON.stringify(result2, null, 2);
|
|
31749
|
+
}
|
|
31750
|
+
lastMergedCommit = commit;
|
|
31751
|
+
}
|
|
31752
|
+
const result = {
|
|
31753
|
+
success: true,
|
|
31754
|
+
task_id: args.task_id,
|
|
31755
|
+
merged_commit: lastMergedCommit || undefined
|
|
31756
|
+
};
|
|
31757
|
+
return JSON.stringify(result, null, 2);
|
|
31758
|
+
}
|
|
31759
|
+
});
|
|
31760
|
+
var swarm_worktree_cleanup = tool({
|
|
31761
|
+
description: "Remove a worktree after completion or abort. Idempotent - safe to call multiple times.",
|
|
31762
|
+
args: {
|
|
31763
|
+
project_path: exports_external.string().describe("Absolute path to project root"),
|
|
31764
|
+
task_id: exports_external.string().optional().describe("Task/bead ID to clean up"),
|
|
31765
|
+
cleanup_all: exports_external.boolean().optional().describe("Remove all worktrees for this project")
|
|
31766
|
+
},
|
|
31767
|
+
async execute(args) {
|
|
31768
|
+
if (args.cleanup_all) {
|
|
31769
|
+
const listResult = await Bun.$`git -C ${args.project_path} worktree list --porcelain`.quiet().nothrow();
|
|
31770
|
+
if (listResult.exitCode !== 0) {
|
|
31771
|
+
const result3 = {
|
|
31772
|
+
success: false,
|
|
31773
|
+
error: `Failed to list worktrees: ${listResult.stderr.toString()}`
|
|
31774
|
+
};
|
|
31775
|
+
return JSON.stringify(result3, null, 2);
|
|
31776
|
+
}
|
|
31777
|
+
const output = listResult.stdout.toString();
|
|
31778
|
+
const worktreeDir = join6(args.project_path, WORKTREE_DIR);
|
|
31779
|
+
const worktrees = output.split(`
|
|
31780
|
+
|
|
31781
|
+
`).filter((block) => block.includes(worktreeDir)).map((block) => {
|
|
31782
|
+
const pathMatch = block.match(/^worktree (.+)$/m);
|
|
31783
|
+
return pathMatch ? pathMatch[1] : null;
|
|
31784
|
+
}).filter((p) => p !== null);
|
|
31785
|
+
let removedCount = 0;
|
|
31786
|
+
for (const wt of worktrees) {
|
|
31787
|
+
const removeResult2 = await Bun.$`git -C ${args.project_path} worktree remove --force ${wt}`.quiet().nothrow();
|
|
31788
|
+
if (removeResult2.exitCode === 0) {
|
|
31789
|
+
removedCount++;
|
|
31790
|
+
}
|
|
31791
|
+
}
|
|
31792
|
+
const result2 = {
|
|
31793
|
+
success: true,
|
|
31794
|
+
removed_count: removedCount
|
|
31795
|
+
};
|
|
31796
|
+
return JSON.stringify(result2, null, 2);
|
|
31797
|
+
}
|
|
31798
|
+
if (!args.task_id) {
|
|
31799
|
+
const result2 = {
|
|
31800
|
+
success: false,
|
|
31801
|
+
error: "Either task_id or cleanup_all must be provided"
|
|
31802
|
+
};
|
|
31803
|
+
return JSON.stringify(result2, null, 2);
|
|
31804
|
+
}
|
|
31805
|
+
const worktreePath = getWorktreePath(args.project_path, args.task_id);
|
|
31806
|
+
const exists = existsSync5(worktreePath);
|
|
31807
|
+
if (!exists) {
|
|
31808
|
+
const result2 = {
|
|
31809
|
+
success: true,
|
|
31810
|
+
already_removed: true,
|
|
31811
|
+
removed_path: worktreePath
|
|
31812
|
+
};
|
|
31813
|
+
return JSON.stringify(result2, null, 2);
|
|
31814
|
+
}
|
|
31815
|
+
const removeResult = await Bun.$`git -C ${args.project_path} worktree remove --force ${worktreePath}`.quiet().nothrow();
|
|
31816
|
+
if (removeResult.exitCode !== 0) {
|
|
31817
|
+
await Bun.$`rm -rf ${worktreePath}`.quiet().nothrow();
|
|
31818
|
+
await Bun.$`git -C ${args.project_path} worktree prune`.quiet().nothrow();
|
|
31819
|
+
}
|
|
31820
|
+
const result = {
|
|
31821
|
+
success: true,
|
|
31822
|
+
removed_path: worktreePath,
|
|
31823
|
+
task_id: args.task_id
|
|
31824
|
+
};
|
|
31825
|
+
return JSON.stringify(result, null, 2);
|
|
31826
|
+
}
|
|
31827
|
+
});
|
|
31828
|
+
var swarm_worktree_list = tool({
|
|
31829
|
+
description: "List all active worktrees for a project",
|
|
31830
|
+
args: {
|
|
31831
|
+
project_path: exports_external.string().describe("Absolute path to project root")
|
|
31832
|
+
},
|
|
31833
|
+
async execute(args) {
|
|
31834
|
+
const listResult = await Bun.$`git -C ${args.project_path} worktree list --porcelain`.quiet().nothrow();
|
|
31835
|
+
if (listResult.exitCode !== 0) {
|
|
31836
|
+
return JSON.stringify({
|
|
31837
|
+
worktrees: [],
|
|
31838
|
+
count: 0,
|
|
31839
|
+
error: `Failed to list worktrees: ${listResult.stderr.toString()}`
|
|
31840
|
+
}, null, 2);
|
|
31841
|
+
}
|
|
31842
|
+
const output = listResult.stdout.toString();
|
|
31843
|
+
const worktreeDir = join6(args.project_path, WORKTREE_DIR);
|
|
31844
|
+
const worktrees = [];
|
|
31845
|
+
const blocks = output.split(`
|
|
31846
|
+
|
|
31847
|
+
`).filter((b) => b.trim());
|
|
31848
|
+
for (const block of blocks) {
|
|
31849
|
+
const pathMatch = block.match(/^worktree (.+)$/m);
|
|
31850
|
+
const commitMatch = block.match(/^HEAD ([a-f0-9]+)$/m);
|
|
31851
|
+
const branchMatch = block.match(/^branch (.+)$/m);
|
|
31852
|
+
if (pathMatch && pathMatch[1].includes(worktreeDir)) {
|
|
31853
|
+
const path = pathMatch[1];
|
|
31854
|
+
const taskId = parseTaskIdFromPath(path);
|
|
31855
|
+
if (taskId) {
|
|
31856
|
+
worktrees.push({
|
|
31857
|
+
task_id: taskId,
|
|
31858
|
+
path,
|
|
31859
|
+
commit: commitMatch ? commitMatch[1] : "unknown",
|
|
31860
|
+
branch: branchMatch ? branchMatch[1] : undefined
|
|
31861
|
+
});
|
|
31862
|
+
}
|
|
31863
|
+
}
|
|
31864
|
+
}
|
|
31865
|
+
return JSON.stringify({
|
|
31866
|
+
worktrees,
|
|
31867
|
+
count: worktrees.length
|
|
31868
|
+
}, null, 2);
|
|
31869
|
+
}
|
|
31870
|
+
});
|
|
31871
|
+
async function canUseWorktreeIsolation(projectPath) {
|
|
31872
|
+
if (!await isGitRepo(projectPath)) {
|
|
31873
|
+
return { canUse: false, reason: "Not a git repository" };
|
|
31874
|
+
}
|
|
31875
|
+
if (await hasUncommittedChanges(projectPath)) {
|
|
31876
|
+
return {
|
|
31877
|
+
canUse: false,
|
|
31878
|
+
reason: "Uncommitted changes exist - commit or stash first"
|
|
31879
|
+
};
|
|
31880
|
+
}
|
|
31881
|
+
return { canUse: true };
|
|
31882
|
+
}
|
|
31883
|
+
async function getStartCommit(projectPath) {
|
|
31884
|
+
return getCurrentCommit(projectPath);
|
|
31885
|
+
}
|
|
31886
|
+
var worktreeTools = {
|
|
31887
|
+
swarm_worktree_create,
|
|
31888
|
+
swarm_worktree_merge,
|
|
31889
|
+
swarm_worktree_cleanup,
|
|
31890
|
+
swarm_worktree_list
|
|
31891
|
+
};
|
|
31892
|
+
|
|
31893
|
+
// src/swarm-review.ts
|
|
31894
|
+
init_dist();
|
|
31895
|
+
init_zod();
|
|
31896
|
+
import { sendSwarmMessage as sendSwarmMessage2 } from "swarm-mail";
|
|
31897
|
+
var ReviewIssueSchema = exports_external.object({
|
|
31898
|
+
file: exports_external.string(),
|
|
31899
|
+
line: exports_external.number().optional(),
|
|
31900
|
+
issue: exports_external.string(),
|
|
31901
|
+
suggestion: exports_external.string().optional()
|
|
31902
|
+
});
|
|
31903
|
+
var ReviewResultSchema = exports_external.object({
|
|
31904
|
+
status: exports_external.enum(["approved", "needs_changes"]),
|
|
31905
|
+
summary: exports_external.string().optional(),
|
|
31906
|
+
issues: exports_external.array(ReviewIssueSchema).optional(),
|
|
31907
|
+
remaining_attempts: exports_external.number().optional()
|
|
31908
|
+
}).refine((data) => {
|
|
31909
|
+
if (data.status === "needs_changes") {
|
|
31910
|
+
return data.issues && data.issues.length > 0;
|
|
31911
|
+
}
|
|
31912
|
+
return true;
|
|
31913
|
+
}, {
|
|
31914
|
+
message: "issues array is required when status is 'needs_changes'"
|
|
31915
|
+
});
|
|
31916
|
+
var reviewAttempts = new Map;
|
|
31917
|
+
var MAX_REVIEW_ATTEMPTS = 3;
|
|
31918
|
+
function getAttemptCount(taskId) {
|
|
31919
|
+
return reviewAttempts.get(taskId) || 0;
|
|
31920
|
+
}
|
|
31921
|
+
function incrementAttempt(taskId) {
|
|
31922
|
+
const current = getAttemptCount(taskId);
|
|
31923
|
+
const newCount = current + 1;
|
|
31924
|
+
reviewAttempts.set(taskId, newCount);
|
|
31925
|
+
return newCount;
|
|
31926
|
+
}
|
|
31927
|
+
function clearAttempts(taskId) {
|
|
31928
|
+
reviewAttempts.delete(taskId);
|
|
31929
|
+
}
|
|
31930
|
+
function getRemainingAttempts(taskId) {
|
|
31931
|
+
return MAX_REVIEW_ATTEMPTS - getAttemptCount(taskId);
|
|
31932
|
+
}
|
|
31933
|
+
function generateReviewPrompt(context) {
|
|
31934
|
+
const sections = [];
|
|
31935
|
+
sections.push(`# Code Review: ${context.task_title}`);
|
|
31936
|
+
sections.push("");
|
|
31937
|
+
sections.push("## Epic Goal");
|
|
31938
|
+
sections.push(`**${context.epic_title}**`);
|
|
31939
|
+
if (context.epic_description) {
|
|
31940
|
+
sections.push(context.epic_description);
|
|
31941
|
+
}
|
|
31942
|
+
sections.push("");
|
|
31943
|
+
sections.push("## Task Requirements");
|
|
31944
|
+
sections.push(`**${context.task_title}**`);
|
|
31945
|
+
if (context.task_description) {
|
|
31946
|
+
sections.push(context.task_description);
|
|
31947
|
+
}
|
|
31948
|
+
sections.push("");
|
|
31949
|
+
if (context.completed_dependencies && context.completed_dependencies.length > 0) {
|
|
31950
|
+
sections.push("## This Task Builds On");
|
|
31951
|
+
for (const dep of context.completed_dependencies) {
|
|
31952
|
+
sections.push(`- **${dep.title}** (${dep.id})`);
|
|
31953
|
+
if (dep.summary) {
|
|
31954
|
+
sections.push(` ${dep.summary}`);
|
|
31955
|
+
}
|
|
31956
|
+
}
|
|
31957
|
+
sections.push("");
|
|
31958
|
+
}
|
|
31959
|
+
if (context.downstream_tasks && context.downstream_tasks.length > 0) {
|
|
31960
|
+
sections.push("## Downstream Tasks (depend on this)");
|
|
31961
|
+
for (const task of context.downstream_tasks) {
|
|
31962
|
+
sections.push(`- **${task.title}** (${task.id})`);
|
|
31963
|
+
}
|
|
31964
|
+
sections.push("");
|
|
31965
|
+
}
|
|
31966
|
+
sections.push("## Files Modified");
|
|
31967
|
+
for (const file2 of context.files_touched) {
|
|
31968
|
+
sections.push(`- \`${file2}\``);
|
|
31969
|
+
}
|
|
31970
|
+
sections.push("");
|
|
31971
|
+
sections.push("## Code Changes");
|
|
31972
|
+
sections.push("```diff");
|
|
31973
|
+
sections.push(context.diff);
|
|
31974
|
+
sections.push("```");
|
|
31975
|
+
sections.push("");
|
|
31976
|
+
sections.push("## Review Criteria");
|
|
31977
|
+
sections.push("");
|
|
31978
|
+
sections.push("Please evaluate the changes against these criteria:");
|
|
31979
|
+
sections.push("");
|
|
31980
|
+
sections.push("1. **Fulfills Requirements**: Does the code implement what the task requires?");
|
|
31981
|
+
sections.push("2. **Serves Epic Goal**: Does this work contribute to the overall epic objective?");
|
|
31982
|
+
sections.push("3. **Enables Downstream**: Can downstream tasks use this work as expected?");
|
|
31983
|
+
sections.push("4. **Type Safety**: Are types correct and complete?");
|
|
31984
|
+
sections.push("5. **No Critical Bugs**: Are there any obvious bugs or issues?");
|
|
31985
|
+
sections.push("6. **Test Coverage**: Are there tests for the new code? (warning only)");
|
|
31986
|
+
sections.push("");
|
|
31987
|
+
sections.push("## Response Format");
|
|
31988
|
+
sections.push("");
|
|
31989
|
+
sections.push("Respond with a JSON object:");
|
|
31990
|
+
sections.push("```json");
|
|
31991
|
+
sections.push(`{
|
|
31992
|
+
"status": "approved" | "needs_changes",
|
|
31993
|
+
"summary": "Brief summary of your review",
|
|
31994
|
+
"issues": [
|
|
31995
|
+
{
|
|
31996
|
+
"file": "path/to/file.ts",
|
|
31997
|
+
"line": 42,
|
|
31998
|
+
"issue": "Description of the problem",
|
|
31999
|
+
"suggestion": "How to fix it"
|
|
32000
|
+
}
|
|
32001
|
+
]
|
|
32002
|
+
}`);
|
|
32003
|
+
sections.push("```");
|
|
32004
|
+
return sections.join(`
|
|
32005
|
+
`);
|
|
32006
|
+
}
|
|
32007
|
+
async function getHiveAdapterSafe(projectPath) {
|
|
32008
|
+
try {
|
|
32009
|
+
return getHiveAdapter(projectPath);
|
|
32010
|
+
} catch {
|
|
32011
|
+
return null;
|
|
32012
|
+
}
|
|
32013
|
+
}
|
|
32014
|
+
async function getCellDependencies(adapter, projectKey, _cellId, epicId) {
|
|
32015
|
+
const completedDependencies = [];
|
|
32016
|
+
const downstreamTasks = [];
|
|
32017
|
+
try {
|
|
32018
|
+
const subtasks = await adapter.queryCells(projectKey, { parent_id: epicId });
|
|
32019
|
+
for (const subtask of subtasks) {
|
|
32020
|
+
if (subtask.id === _cellId)
|
|
32021
|
+
continue;
|
|
32022
|
+
if (subtask.status === "closed") {
|
|
32023
|
+
completedDependencies.push({
|
|
32024
|
+
id: subtask.id,
|
|
32025
|
+
title: subtask.title,
|
|
32026
|
+
summary: subtask.closed_reason ?? undefined
|
|
32027
|
+
});
|
|
32028
|
+
}
|
|
32029
|
+
if (subtask.status !== "closed") {
|
|
32030
|
+
downstreamTasks.push({
|
|
32031
|
+
id: subtask.id,
|
|
32032
|
+
title: subtask.title
|
|
32033
|
+
});
|
|
32034
|
+
}
|
|
32035
|
+
}
|
|
32036
|
+
} catch {}
|
|
32037
|
+
return { completed: completedDependencies, downstream: downstreamTasks };
|
|
32038
|
+
}
|
|
32039
|
+
var swarm_review = tool({
|
|
32040
|
+
description: "Generate a review prompt for a completed subtask. Includes epic context, dependencies, and diff.",
|
|
32041
|
+
args: {
|
|
32042
|
+
project_key: exports_external.string().describe("Project path"),
|
|
32043
|
+
epic_id: exports_external.string().describe("Epic cell ID"),
|
|
32044
|
+
task_id: exports_external.string().describe("Subtask cell ID to review"),
|
|
32045
|
+
files_touched: exports_external.array(exports_external.string()).optional().describe("Files modified (will get diff for these)")
|
|
32046
|
+
},
|
|
32047
|
+
async execute(args) {
|
|
32048
|
+
let epicTitle = args.epic_id;
|
|
32049
|
+
let epicDescription;
|
|
32050
|
+
let taskTitle = args.task_id;
|
|
32051
|
+
let taskDescription;
|
|
32052
|
+
let completedDependencies = [];
|
|
32053
|
+
let downstreamTasks = [];
|
|
32054
|
+
const adapter = await getHiveAdapterSafe(args.project_key);
|
|
32055
|
+
if (adapter) {
|
|
32056
|
+
try {
|
|
32057
|
+
const epic = await adapter.getCell(args.project_key, args.epic_id);
|
|
32058
|
+
if (epic) {
|
|
32059
|
+
epicTitle = epic.title || epicTitle;
|
|
32060
|
+
epicDescription = epic.description ?? undefined;
|
|
32061
|
+
}
|
|
32062
|
+
const task = await adapter.getCell(args.project_key, args.task_id);
|
|
32063
|
+
if (task) {
|
|
32064
|
+
taskTitle = task.title || taskTitle;
|
|
32065
|
+
taskDescription = task.description ?? undefined;
|
|
32066
|
+
}
|
|
32067
|
+
const deps = await getCellDependencies(adapter, args.project_key, args.task_id, args.epic_id);
|
|
32068
|
+
completedDependencies = deps.completed;
|
|
32069
|
+
downstreamTasks = deps.downstream;
|
|
32070
|
+
} catch {}
|
|
32071
|
+
}
|
|
32072
|
+
let diff = "";
|
|
32073
|
+
if (args.files_touched && args.files_touched.length > 0) {
|
|
32074
|
+
try {
|
|
32075
|
+
const diffResult = await Bun.$`git diff HEAD~1 -- ${args.files_touched}`.cwd(args.project_key).quiet().nothrow();
|
|
32076
|
+
if (diffResult.exitCode === 0) {
|
|
32077
|
+
diff = diffResult.stdout.toString();
|
|
32078
|
+
} else {
|
|
32079
|
+
const stagedResult = await Bun.$`git diff --cached -- ${args.files_touched}`.cwd(args.project_key).quiet().nothrow();
|
|
32080
|
+
diff = stagedResult.stdout.toString();
|
|
32081
|
+
}
|
|
32082
|
+
} catch {}
|
|
32083
|
+
}
|
|
32084
|
+
const reviewPrompt = generateReviewPrompt({
|
|
32085
|
+
epic_id: args.epic_id,
|
|
32086
|
+
epic_title: epicTitle,
|
|
32087
|
+
epic_description: epicDescription,
|
|
32088
|
+
task_id: args.task_id,
|
|
32089
|
+
task_title: taskTitle,
|
|
32090
|
+
task_description: taskDescription,
|
|
32091
|
+
files_touched: args.files_touched || [],
|
|
32092
|
+
diff: diff || "(no diff available)",
|
|
32093
|
+
completed_dependencies: completedDependencies.length > 0 ? completedDependencies : undefined,
|
|
32094
|
+
downstream_tasks: downstreamTasks.length > 0 ? downstreamTasks : undefined
|
|
32095
|
+
});
|
|
32096
|
+
return JSON.stringify({
|
|
32097
|
+
review_prompt: reviewPrompt,
|
|
32098
|
+
context: {
|
|
32099
|
+
epic_id: args.epic_id,
|
|
32100
|
+
epic_title: epicTitle,
|
|
32101
|
+
task_id: args.task_id,
|
|
32102
|
+
task_title: taskTitle,
|
|
32103
|
+
files_touched: args.files_touched || [],
|
|
32104
|
+
completed_dependencies: completedDependencies.length,
|
|
32105
|
+
downstream_tasks: downstreamTasks.length,
|
|
32106
|
+
remaining_attempts: getRemainingAttempts(args.task_id)
|
|
32107
|
+
}
|
|
32108
|
+
}, null, 2);
|
|
32109
|
+
}
|
|
32110
|
+
});
|
|
32111
|
+
var swarm_review_feedback = tool({
|
|
32112
|
+
description: "Send review feedback to a worker. Tracks attempts (max 3). Fails task after 3 rejections.",
|
|
32113
|
+
args: {
|
|
32114
|
+
project_key: exports_external.string().describe("Project path"),
|
|
32115
|
+
task_id: exports_external.string().describe("Subtask cell ID"),
|
|
32116
|
+
worker_id: exports_external.string().describe("Worker agent name"),
|
|
32117
|
+
status: exports_external.enum(["approved", "needs_changes"]).describe("Review status"),
|
|
32118
|
+
summary: exports_external.string().optional().describe("Review summary"),
|
|
32119
|
+
issues: exports_external.string().optional().describe("JSON array of ReviewIssue objects (for needs_changes)")
|
|
32120
|
+
},
|
|
32121
|
+
async execute(args) {
|
|
32122
|
+
let parsedIssues = [];
|
|
32123
|
+
if (args.issues) {
|
|
32124
|
+
try {
|
|
32125
|
+
parsedIssues = JSON.parse(args.issues);
|
|
32126
|
+
} catch {
|
|
32127
|
+
return JSON.stringify({
|
|
32128
|
+
success: false,
|
|
32129
|
+
error: "Failed to parse issues JSON"
|
|
32130
|
+
}, null, 2);
|
|
32131
|
+
}
|
|
32132
|
+
}
|
|
32133
|
+
if (args.status === "needs_changes" && parsedIssues.length === 0) {
|
|
32134
|
+
return JSON.stringify({
|
|
32135
|
+
success: false,
|
|
32136
|
+
error: "needs_changes status requires at least one issue"
|
|
32137
|
+
}, null, 2);
|
|
32138
|
+
}
|
|
32139
|
+
const epicId = args.task_id.includes(".") ? args.task_id.split(".")[0] : args.task_id;
|
|
32140
|
+
if (args.status === "approved") {
|
|
32141
|
+
markReviewApproved(args.task_id);
|
|
32142
|
+
await sendSwarmMessage2({
|
|
32143
|
+
projectPath: args.project_key,
|
|
32144
|
+
fromAgent: "coordinator",
|
|
32145
|
+
toAgents: [args.worker_id],
|
|
32146
|
+
subject: `APPROVED: ${args.task_id}`,
|
|
32147
|
+
body: `## Review Approved ✓
|
|
32148
|
+
|
|
32149
|
+
${args.summary || "Your work has been approved."}
|
|
32150
|
+
|
|
32151
|
+
You may now complete the task with \`swarm_complete\`.`,
|
|
32152
|
+
threadId: epicId,
|
|
32153
|
+
importance: "normal"
|
|
32154
|
+
});
|
|
32155
|
+
return JSON.stringify({
|
|
32156
|
+
success: true,
|
|
32157
|
+
status: "approved",
|
|
32158
|
+
task_id: args.task_id,
|
|
32159
|
+
message: "Review approved. Worker can now complete the task."
|
|
32160
|
+
}, null, 2);
|
|
32161
|
+
}
|
|
32162
|
+
const attemptNumber = incrementAttempt(args.task_id);
|
|
32163
|
+
const remaining = MAX_REVIEW_ATTEMPTS - attemptNumber;
|
|
32164
|
+
if (remaining <= 0) {
|
|
32165
|
+
const adapter = await getHiveAdapterSafe(args.project_key);
|
|
32166
|
+
if (adapter) {
|
|
32167
|
+
try {
|
|
32168
|
+
await adapter.changeCellStatus(args.project_key, args.task_id, "blocked");
|
|
32169
|
+
} catch {}
|
|
32170
|
+
}
|
|
32171
|
+
await sendSwarmMessage2({
|
|
32172
|
+
projectPath: args.project_key,
|
|
32173
|
+
fromAgent: "coordinator",
|
|
32174
|
+
toAgents: [args.worker_id],
|
|
32175
|
+
subject: `FAILED: ${args.task_id} - max review attempts reached`,
|
|
32176
|
+
body: `## Task Failed ✗
|
|
32177
|
+
|
|
32178
|
+
Maximum review attempts (${MAX_REVIEW_ATTEMPTS}) reached.
|
|
32179
|
+
|
|
32180
|
+
**Last Issues:**
|
|
32181
|
+
${parsedIssues.map((i) => `- ${i.file}${i.line ? `:${i.line}` : ""}: ${i.issue}`).join(`
|
|
32182
|
+
`)}
|
|
32183
|
+
|
|
32184
|
+
The task has been marked as blocked. A human or different approach is needed.`,
|
|
32185
|
+
threadId: epicId,
|
|
32186
|
+
importance: "urgent"
|
|
32187
|
+
});
|
|
32188
|
+
return JSON.stringify({
|
|
32189
|
+
success: true,
|
|
32190
|
+
status: "needs_changes",
|
|
32191
|
+
task_failed: true,
|
|
32192
|
+
task_id: args.task_id,
|
|
32193
|
+
attempt: attemptNumber,
|
|
32194
|
+
remaining_attempts: 0,
|
|
32195
|
+
message: `Task failed after ${MAX_REVIEW_ATTEMPTS} review attempts`
|
|
32196
|
+
}, null, 2);
|
|
32197
|
+
}
|
|
32198
|
+
const issuesList = parsedIssues.map((i) => {
|
|
32199
|
+
let line = `- **${i.file}**`;
|
|
32200
|
+
if (i.line)
|
|
32201
|
+
line += `:${i.line}`;
|
|
32202
|
+
line += `: ${i.issue}`;
|
|
32203
|
+
if (i.suggestion)
|
|
32204
|
+
line += `
|
|
32205
|
+
→ ${i.suggestion}`;
|
|
32206
|
+
return line;
|
|
32207
|
+
}).join(`
|
|
32208
|
+
`);
|
|
32209
|
+
await sendSwarmMessage2({
|
|
32210
|
+
projectPath: args.project_key,
|
|
32211
|
+
fromAgent: "coordinator",
|
|
32212
|
+
toAgents: [args.worker_id],
|
|
32213
|
+
subject: `NEEDS CHANGES: ${args.task_id} (attempt ${attemptNumber}/${MAX_REVIEW_ATTEMPTS})`,
|
|
32214
|
+
body: `## Review: Changes Needed
|
|
32215
|
+
|
|
32216
|
+
${args.summary || "Please address the following issues:"}
|
|
32217
|
+
|
|
32218
|
+
**Issues:**
|
|
32219
|
+
${issuesList}
|
|
32220
|
+
|
|
32221
|
+
**Remaining attempts:** ${remaining}
|
|
32222
|
+
|
|
32223
|
+
Please fix these issues and request another review.`,
|
|
32224
|
+
threadId: epicId,
|
|
32225
|
+
importance: "high"
|
|
32226
|
+
});
|
|
32227
|
+
return JSON.stringify({
|
|
32228
|
+
success: true,
|
|
32229
|
+
status: "needs_changes",
|
|
32230
|
+
task_id: args.task_id,
|
|
32231
|
+
attempt: attemptNumber,
|
|
32232
|
+
remaining_attempts: remaining,
|
|
32233
|
+
issues: parsedIssues,
|
|
32234
|
+
message: `Feedback sent. ${remaining} attempt(s) remaining.`
|
|
32235
|
+
}, null, 2);
|
|
32236
|
+
}
|
|
32237
|
+
});
|
|
32238
|
+
var reviewStatus = new Map;
|
|
32239
|
+
function markReviewApproved(taskId) {
|
|
32240
|
+
reviewStatus.set(taskId, { approved: true, timestamp: Date.now() });
|
|
32241
|
+
clearAttempts(taskId);
|
|
32242
|
+
}
|
|
32243
|
+
function getReviewStatus(taskId) {
|
|
32244
|
+
const status = reviewStatus.get(taskId);
|
|
32245
|
+
return {
|
|
32246
|
+
reviewed: status !== undefined,
|
|
32247
|
+
approved: status?.approved ?? false,
|
|
32248
|
+
attempt_count: getAttemptCount(taskId),
|
|
32249
|
+
remaining_attempts: getRemainingAttempts(taskId)
|
|
32250
|
+
};
|
|
32251
|
+
}
|
|
32252
|
+
var reviewTools = {
|
|
32253
|
+
swarm_review,
|
|
32254
|
+
swarm_review_feedback
|
|
32255
|
+
};
|
|
32256
|
+
|
|
32257
|
+
// src/swarm-orchestrate.ts
|
|
31501
32258
|
async function queryEpicSubtasks(epicId) {
|
|
31502
32259
|
const beadsAvailable = await isToolAvailable("beads");
|
|
31503
32260
|
if (!beadsAvailable) {
|
|
@@ -31767,7 +32524,8 @@ var globalStrikeStorage = new InMemoryStrikeStorage;
|
|
|
31767
32524
|
var swarm_init = tool({
|
|
31768
32525
|
description: "Initialize swarm session: discovers available skills, checks tool availability. ALWAYS call at swarm start.",
|
|
31769
32526
|
args: {
|
|
31770
|
-
project_path: tool.schema.string().optional().describe("Project path (for Agent Mail init)")
|
|
32527
|
+
project_path: tool.schema.string().optional().describe("Project path (for Agent Mail init)"),
|
|
32528
|
+
isolation: tool.schema.enum(["worktree", "reservation"]).optional().default("reservation").describe("Isolation mode: 'worktree' for git worktree isolation (requires clean git state), 'reservation' for file reservations (default)")
|
|
31771
32529
|
},
|
|
31772
32530
|
async execute(args) {
|
|
31773
32531
|
const availability = await checkAllTools();
|
|
@@ -31809,8 +32567,39 @@ var swarm_init = tool({
|
|
|
31809
32567
|
} else {
|
|
31810
32568
|
skillsGuidance = "No skills found. Add skills to .opencode/skills/ or .claude/skills/ for specialized guidance.";
|
|
31811
32569
|
}
|
|
32570
|
+
const isolationMode = args.isolation ?? "reservation";
|
|
32571
|
+
let isolationInfo = {
|
|
32572
|
+
mode: isolationMode,
|
|
32573
|
+
available: true
|
|
32574
|
+
};
|
|
32575
|
+
if (isolationMode === "worktree" && args.project_path) {
|
|
32576
|
+
const worktreeCheck = await canUseWorktreeIsolation(args.project_path);
|
|
32577
|
+
if (worktreeCheck.canUse) {
|
|
32578
|
+
const startCommit = await getStartCommit(args.project_path);
|
|
32579
|
+
isolationInfo = {
|
|
32580
|
+
mode: "worktree",
|
|
32581
|
+
available: true,
|
|
32582
|
+
start_commit: startCommit ?? undefined
|
|
32583
|
+
};
|
|
32584
|
+
} else {
|
|
32585
|
+
isolationInfo = {
|
|
32586
|
+
mode: "reservation",
|
|
32587
|
+
available: false,
|
|
32588
|
+
reason: `Worktree mode unavailable: ${worktreeCheck.reason}. Falling back to reservation mode.`
|
|
32589
|
+
};
|
|
32590
|
+
warnings.push(`⚠️ Worktree isolation unavailable: ${worktreeCheck.reason}. Using file reservations instead.`);
|
|
32591
|
+
}
|
|
32592
|
+
} else if (isolationMode === "worktree" && !args.project_path) {
|
|
32593
|
+
isolationInfo = {
|
|
32594
|
+
mode: "reservation",
|
|
32595
|
+
available: false,
|
|
32596
|
+
reason: "Worktree mode requires project_path. Falling back to reservation mode."
|
|
32597
|
+
};
|
|
32598
|
+
warnings.push("⚠️ Worktree isolation requires project_path. Using file reservations instead.");
|
|
32599
|
+
}
|
|
31812
32600
|
return JSON.stringify({
|
|
31813
32601
|
ready: true,
|
|
32602
|
+
isolation: isolationInfo,
|
|
31814
32603
|
tool_availability: Object.fromEntries(Array.from(availability.entries()).map(([k, v]) => [
|
|
31815
32604
|
k,
|
|
31816
32605
|
{
|
|
@@ -31824,7 +32613,8 @@ var swarm_init = tool({
|
|
|
31824
32613
|
recommendations: {
|
|
31825
32614
|
skills: skillsGuidance,
|
|
31826
32615
|
beads: beadsAvailable ? "✓ Use beads for all task tracking" : "Install beads: npm i -g @joelhooks/beads",
|
|
31827
|
-
agent_mail: agentMailAvailable2 ? "✓ Use Agent Mail for coordination" : "Start Agent Mail: agent-mail serve"
|
|
32616
|
+
agent_mail: agentMailAvailable2 ? "✓ Use Agent Mail for coordination" : "Start Agent Mail: agent-mail serve",
|
|
32617
|
+
isolation: isolationInfo.mode === "worktree" ? "✓ Using git worktree isolation" : "✓ Using file reservation isolation"
|
|
31828
32618
|
},
|
|
31829
32619
|
report
|
|
31830
32620
|
}, null, 2);
|
|
@@ -31916,7 +32706,7 @@ var swarm_progress = tool({
|
|
|
31916
32706
|
await Bun.$`bd update ${args.bead_id} --status ${beadStatus} --json`.quiet().nothrow();
|
|
31917
32707
|
}
|
|
31918
32708
|
const epicId = args.bead_id.includes(".") ? args.bead_id.split(".")[0] : args.bead_id;
|
|
31919
|
-
await
|
|
32709
|
+
await sendSwarmMessage3({
|
|
31920
32710
|
projectPath: args.project_key,
|
|
31921
32711
|
fromAgent: args.agent_name,
|
|
31922
32712
|
toAgents: [],
|
|
@@ -31984,7 +32774,7 @@ ${args.files_affected.map((f) => `- \`${f}\``).join(`
|
|
|
31984
32774
|
].filter(Boolean).join(`
|
|
31985
32775
|
`);
|
|
31986
32776
|
const mailImportance = args.importance === "blocker" ? "urgent" : args.importance === "warning" ? "high" : "normal";
|
|
31987
|
-
await
|
|
32777
|
+
await sendSwarmMessage3({
|
|
31988
32778
|
projectPath: args.project_path,
|
|
31989
32779
|
fromAgent: args.agent_name,
|
|
31990
32780
|
toAgents: [],
|
|
@@ -32019,10 +32809,42 @@ var swarm_complete = tool({
|
|
|
32019
32809
|
planned_files: tool.schema.array(tool.schema.string()).optional().describe("Files that were originally planned to be modified"),
|
|
32020
32810
|
start_time: tool.schema.number().optional().describe("Task start timestamp (Unix ms) for duration calculation"),
|
|
32021
32811
|
error_count: tool.schema.number().optional().describe("Number of errors encountered during task"),
|
|
32022
|
-
retry_count: tool.schema.number().optional().describe("Number of retry attempts during task")
|
|
32812
|
+
retry_count: tool.schema.number().optional().describe("Number of retry attempts during task"),
|
|
32813
|
+
skip_review: tool.schema.boolean().optional().describe("Skip review gate check (default: false). Use only for tasks that don't require coordinator review.")
|
|
32023
32814
|
},
|
|
32024
32815
|
async execute(args, _ctx) {
|
|
32025
32816
|
const epicId = args.bead_id.includes(".") ? args.bead_id.split(".")[0] : args.bead_id;
|
|
32817
|
+
if (!args.skip_review) {
|
|
32818
|
+
const reviewStatusResult = getReviewStatus(args.bead_id);
|
|
32819
|
+
if (!reviewStatusResult.approved) {
|
|
32820
|
+
if (!reviewStatusResult.reviewed) {
|
|
32821
|
+
return JSON.stringify({
|
|
32822
|
+
success: false,
|
|
32823
|
+
error: "Review required before completion",
|
|
32824
|
+
review_status: reviewStatusResult,
|
|
32825
|
+
hint: `This task requires coordinator review before completion.
|
|
32826
|
+
|
|
32827
|
+
**Next steps:**
|
|
32828
|
+
1. Request review with swarm_review(project_key="${args.project_key}", epic_id="${epicId}", task_id="${args.bead_id}", files_touched=[...])
|
|
32829
|
+
2. Wait for coordinator to review and approve with swarm_review_feedback
|
|
32830
|
+
3. Once approved, call swarm_complete again
|
|
32831
|
+
|
|
32832
|
+
Or use skip_review=true to bypass (not recommended for production work).`
|
|
32833
|
+
}, null, 2);
|
|
32834
|
+
}
|
|
32835
|
+
return JSON.stringify({
|
|
32836
|
+
success: false,
|
|
32837
|
+
error: "Review not approved",
|
|
32838
|
+
review_status: reviewStatusResult,
|
|
32839
|
+
hint: `Task was reviewed but not approved. ${reviewStatusResult.remaining_attempts} attempt(s) remaining.
|
|
32840
|
+
|
|
32841
|
+
**Next steps:**
|
|
32842
|
+
1. Address the feedback from the reviewer
|
|
32843
|
+
2. Request another review with swarm_review
|
|
32844
|
+
3. Once approved, call swarm_complete again`
|
|
32845
|
+
}, null, 2);
|
|
32846
|
+
}
|
|
32847
|
+
}
|
|
32026
32848
|
try {
|
|
32027
32849
|
const projectKey = args.project_key.replace(/\//g, "-").replace(/\\/g, "-");
|
|
32028
32850
|
let agentRegistered = false;
|
|
@@ -32117,7 +32939,7 @@ Continuing with completion, but this should be fixed for future subtasks.`;
|
|
|
32117
32939
|
const isNotFoundError = stderrOutput.includes("not found") || stderrOutput.includes("does not exist");
|
|
32118
32940
|
return JSON.stringify({
|
|
32119
32941
|
success: false,
|
|
32120
|
-
error: "Failed to close
|
|
32942
|
+
error: "Failed to close cell",
|
|
32121
32943
|
failed_step: "bd close",
|
|
32122
32944
|
details: stderrOutput || stdoutOutput || "Unknown error from bd close command",
|
|
32123
32945
|
bead_id: args.bead_id,
|
|
@@ -32126,15 +32948,15 @@ Continuing with completion, but this should be fixed for future subtasks.`;
|
|
|
32126
32948
|
steps: isNoDatabaseError ? [
|
|
32127
32949
|
`1. Verify project_key is correct: "${args.project_key}"`,
|
|
32128
32950
|
`2. Check .beads/ exists in that directory`,
|
|
32129
|
-
`3.
|
|
32130
|
-
`4. Try:
|
|
32951
|
+
`3. Cell ID prefix "${args.bead_id.split("-")[0]}" should match project`,
|
|
32952
|
+
`4. Try: hive_close(id="${args.bead_id}", reason="...")`
|
|
32131
32953
|
] : [
|
|
32132
|
-
`1. Check
|
|
32133
|
-
`2. Check
|
|
32134
|
-
`3. If
|
|
32135
|
-
`4. Try closing directly:
|
|
32954
|
+
`1. Check cell exists: bd show ${args.bead_id}`,
|
|
32955
|
+
`2. Check cell status (might already be closed): hive_query()`,
|
|
32956
|
+
`3. If cell is blocked, unblock first: hive_update(id="${args.bead_id}", status="in_progress")`,
|
|
32957
|
+
`4. Try closing directly: hive_close(id="${args.bead_id}", reason="...")`
|
|
32136
32958
|
],
|
|
32137
|
-
hint: isNoDatabaseError ? `The project_key "${args.project_key}" doesn't have a .beads/ directory. Make sure you're using the correct project path.` : isNotFoundError ? `
|
|
32959
|
+
hint: isNoDatabaseError ? `The project_key "${args.project_key}" doesn't have a .beads/ directory. Make sure you're using the correct project path.` : isNotFoundError ? `Cell "${args.bead_id}" not found. It may have been closed already or the ID is incorrect.` : "If cell is in 'blocked' status, you must change it to 'in_progress' or 'open' before closing."
|
|
32138
32960
|
}
|
|
32139
32961
|
}, null, 2);
|
|
32140
32962
|
}
|
|
@@ -32202,7 +33024,7 @@ Continuing with completion, but this should be fixed for future subtasks.`;
|
|
|
32202
33024
|
let messageSent = false;
|
|
32203
33025
|
let messageError;
|
|
32204
33026
|
try {
|
|
32205
|
-
await
|
|
33027
|
+
await sendSwarmMessage3({
|
|
32206
33028
|
projectPath: args.project_key,
|
|
32207
33029
|
fromAgent: args.agent_name,
|
|
32208
33030
|
toAgents: [],
|
|
@@ -32312,14 +33134,14 @@ ${errorStack.slice(0, 1000)}
|
|
|
32312
33134
|
"",
|
|
32313
33135
|
`### Recovery Actions`,
|
|
32314
33136
|
"1. Check error message for specific issue",
|
|
32315
|
-
"2. Review failed step (UBS scan, typecheck,
|
|
33137
|
+
"2. Review failed step (UBS scan, typecheck, cell close, etc.)",
|
|
32316
33138
|
"3. Fix underlying issue or use skip flags if appropriate",
|
|
32317
33139
|
"4. Retry swarm_complete after fixing"
|
|
32318
33140
|
].filter(Boolean).join(`
|
|
32319
33141
|
`);
|
|
32320
33142
|
let notificationSent = false;
|
|
32321
33143
|
try {
|
|
32322
|
-
await
|
|
33144
|
+
await sendSwarmMessage3({
|
|
32323
33145
|
projectPath: args.project_key,
|
|
32324
33146
|
fromAgent: args.agent_name,
|
|
32325
33147
|
toAgents: [],
|
|
@@ -32357,7 +33179,7 @@ ${errorStack.slice(0, 1000)}
|
|
|
32357
33179
|
common_fixes: {
|
|
32358
33180
|
"Verification Gate": "Use skip_verification=true to bypass (not recommended)",
|
|
32359
33181
|
"UBS scan": "Use skip_ubs_scan=true to bypass",
|
|
32360
|
-
"
|
|
33182
|
+
"Cell close": "Check cell status with hive_query(), may need hive_update() first",
|
|
32361
33183
|
"Self-evaluation": "Check evaluation JSON format matches EvaluationSchema"
|
|
32362
33184
|
}
|
|
32363
33185
|
}
|
|
@@ -32456,7 +33278,7 @@ var swarm_record_outcome = tool({
|
|
|
32456
33278
|
var swarm_accumulate_error = tool({
|
|
32457
33279
|
description: "Record an error during subtask execution. Errors feed into retry prompts.",
|
|
32458
33280
|
args: {
|
|
32459
|
-
bead_id: tool.schema.string().describe("
|
|
33281
|
+
bead_id: tool.schema.string().describe("Cell ID where error occurred"),
|
|
32460
33282
|
error_type: tool.schema.enum(["validation", "timeout", "conflict", "tool_failure", "unknown"]).describe("Category of error"),
|
|
32461
33283
|
message: tool.schema.string().describe("Human-readable error message"),
|
|
32462
33284
|
stack_trace: tool.schema.string().optional().describe("Stack trace for debugging"),
|
|
@@ -32483,7 +33305,7 @@ var swarm_accumulate_error = tool({
|
|
|
32483
33305
|
var swarm_get_error_context = tool({
|
|
32484
33306
|
description: "Get accumulated errors for a bead. Returns formatted context for retry prompts.",
|
|
32485
33307
|
args: {
|
|
32486
|
-
bead_id: tool.schema.string().describe("
|
|
33308
|
+
bead_id: tool.schema.string().describe("Cell ID to get errors for"),
|
|
32487
33309
|
include_resolved: tool.schema.boolean().optional().describe("Include resolved errors (default: false)")
|
|
32488
33310
|
},
|
|
32489
33311
|
async execute(args) {
|
|
@@ -32519,7 +33341,7 @@ var swarm_resolve_error = tool({
|
|
|
32519
33341
|
var swarm_check_strikes = tool({
|
|
32520
33342
|
description: "Check 3-strike status for a bead. Records failures, detects architectural problems, generates architecture review prompts.",
|
|
32521
33343
|
args: {
|
|
32522
|
-
bead_id: tool.schema.string().describe("
|
|
33344
|
+
bead_id: tool.schema.string().describe("Cell ID to check"),
|
|
32523
33345
|
action: tool.schema.enum(["check", "add_strike", "clear", "get_prompt"]).describe("Action: check count, add strike, clear strikes, or get prompt"),
|
|
32524
33346
|
attempt: tool.schema.string().optional().describe("Description of fix attempt (required for add_strike)"),
|
|
32525
33347
|
reason: tool.schema.string().optional().describe("Why the fix failed (required for add_strike)")
|
|
@@ -32784,7 +33606,7 @@ ${args.files_context.map((f) => `- \`${f}\``).join(`
|
|
|
32784
33606
|
*Learned from swarm execution on ${new Date().toISOString().split("T")[0]}*`;
|
|
32785
33607
|
const { getSkill: getSkill2, invalidateSkillsCache: invalidateSkillsCache2 } = await Promise.resolve().then(() => (init_skills(), exports_skills));
|
|
32786
33608
|
const { mkdir: mkdir2, writeFile: writeFile2 } = await import("node:fs/promises");
|
|
32787
|
-
const { join:
|
|
33609
|
+
const { join: join7 } = await import("node:path");
|
|
32788
33610
|
const existing = await getSkill2(args.skill_name);
|
|
32789
33611
|
if (existing) {
|
|
32790
33612
|
return JSON.stringify({
|
|
@@ -32795,8 +33617,8 @@ ${args.files_context.map((f) => `- \`${f}\``).join(`
|
|
|
32795
33617
|
suggestion: "Use skills_update to add to existing skill, or choose a different name"
|
|
32796
33618
|
}, null, 2);
|
|
32797
33619
|
}
|
|
32798
|
-
const skillDir =
|
|
32799
|
-
const skillPath =
|
|
33620
|
+
const skillDir = join7(process.cwd(), ".opencode", "skills", args.skill_name);
|
|
33621
|
+
const skillPath = join7(skillDir, "SKILL.md");
|
|
32800
33622
|
const frontmatter = [
|
|
32801
33623
|
"---",
|
|
32802
33624
|
`name: ${args.skill_name}`,
|
|
@@ -33920,14 +34742,14 @@ var DEFAULT_GUARDRAIL_CONFIG = {
|
|
|
33920
34742
|
cass_stats: 8000
|
|
33921
34743
|
},
|
|
33922
34744
|
skipTools: [
|
|
33923
|
-
"
|
|
33924
|
-
"
|
|
33925
|
-
"
|
|
33926
|
-
"
|
|
33927
|
-
"
|
|
33928
|
-
"
|
|
33929
|
-
"
|
|
33930
|
-
"
|
|
34745
|
+
"hive_create",
|
|
34746
|
+
"hive_create_epic",
|
|
34747
|
+
"hive_query",
|
|
34748
|
+
"hive_update",
|
|
34749
|
+
"hive_close",
|
|
34750
|
+
"hive_start",
|
|
34751
|
+
"hive_ready",
|
|
34752
|
+
"hive_sync",
|
|
33931
34753
|
"agentmail_init",
|
|
33932
34754
|
"agentmail_send",
|
|
33933
34755
|
"agentmail_inbox",
|
|
@@ -33947,7 +34769,7 @@ var DEFAULT_GUARDRAIL_CONFIG = {
|
|
|
33947
34769
|
"structured_validate",
|
|
33948
34770
|
"structured_parse_evaluation",
|
|
33949
34771
|
"structured_parse_decomposition",
|
|
33950
|
-
"
|
|
34772
|
+
"structured_parse_cell_tree",
|
|
33951
34773
|
"swarm_select_strategy",
|
|
33952
34774
|
"swarm_plan_prompt",
|
|
33953
34775
|
"swarm_decompose",
|
|
@@ -34123,7 +34945,7 @@ function analyzeTodoWrite(args) {
|
|
|
34123
34945
|
warning: `⚠️ This looks like a multi-file implementation plan (${fileModificationCount}/${todos.length} items are file modifications).
|
|
34124
34946
|
|
|
34125
34947
|
Consider using swarm instead:
|
|
34126
|
-
swarm_decompose →
|
|
34948
|
+
swarm_decompose → hive_create_epic → parallel task spawns
|
|
34127
34949
|
|
|
34128
34950
|
TodoWrite is for tracking progress, not parallelizable implementation work.
|
|
34129
34951
|
Swarm workers can complete these ${fileModificationCount} tasks in parallel.
|
|
@@ -34277,7 +35099,7 @@ var sessionStats = {
|
|
|
34277
35099
|
init_skills();
|
|
34278
35100
|
var SwarmPlugin = async (input) => {
|
|
34279
35101
|
const { $, directory } = input;
|
|
34280
|
-
|
|
35102
|
+
setHiveWorkingDirectory(directory);
|
|
34281
35103
|
setSkillsProjectDirectory(directory);
|
|
34282
35104
|
setAgentMailProjectDirectory(directory);
|
|
34283
35105
|
setSwarmMailProjectDirectory(directory);
|
|
@@ -34312,10 +35134,12 @@ var SwarmPlugin = async (input) => {
|
|
|
34312
35134
|
}
|
|
34313
35135
|
return {
|
|
34314
35136
|
tool: {
|
|
34315
|
-
...
|
|
35137
|
+
...hiveTools,
|
|
34316
35138
|
...swarmMailTools,
|
|
34317
35139
|
...structuredTools,
|
|
34318
35140
|
...swarmTools,
|
|
35141
|
+
...worktreeTools,
|
|
35142
|
+
...reviewTools,
|
|
34319
35143
|
...repoCrawlTools,
|
|
34320
35144
|
...skillsTools,
|
|
34321
35145
|
...mandateTools
|
|
@@ -34364,17 +35188,19 @@ var SwarmPlugin = async (input) => {
|
|
|
34364
35188
|
if (toolName === "swarm_complete" && activeAgentMailState) {
|
|
34365
35189
|
await releaseReservations();
|
|
34366
35190
|
}
|
|
34367
|
-
if (toolName === "
|
|
35191
|
+
if (toolName === "hive_close" || toolName === "hive_close") {
|
|
34368
35192
|
$`bd sync`.quiet().nothrow();
|
|
34369
35193
|
}
|
|
34370
35194
|
}
|
|
34371
35195
|
};
|
|
34372
35196
|
};
|
|
34373
35197
|
var allTools = {
|
|
34374
|
-
...
|
|
35198
|
+
...hiveTools,
|
|
34375
35199
|
...swarmMailTools,
|
|
34376
35200
|
...structuredTools,
|
|
34377
35201
|
...swarmTools,
|
|
35202
|
+
...worktreeTools,
|
|
35203
|
+
...reviewTools,
|
|
34378
35204
|
...repoCrawlTools,
|
|
34379
35205
|
...skillsTools,
|
|
34380
35206
|
...mandateTools
|