opencode-swarm-plugin 0.26.0 → 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 +37 -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 +1418 -387
- package/dist/learning.d.ts +9 -9
- package/dist/plugin.js +1240 -386
- 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/hive.ts +1017 -0
- 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 -383
- 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/beads.ts +0 -800
- package/src/schemas/bead-events.ts +0 -583
package/dist/plugin.js
CHANGED
|
@@ -26166,7 +26166,7 @@ __export(exports_skills, {
|
|
|
26166
26166
|
});
|
|
26167
26167
|
import { readdir, readFile, stat, mkdir, writeFile, rm } from "fs/promises";
|
|
26168
26168
|
import {
|
|
26169
|
-
join as
|
|
26169
|
+
join as join5,
|
|
26170
26170
|
basename,
|
|
26171
26171
|
dirname as dirname2,
|
|
26172
26172
|
resolve,
|
|
@@ -26214,19 +26214,19 @@ function validateSkillMetadata(raw, filePath) {
|
|
|
26214
26214
|
}
|
|
26215
26215
|
function getGlobalSkillsDir() {
|
|
26216
26216
|
const home = process.env.HOME || process.env.USERPROFILE || "~";
|
|
26217
|
-
return
|
|
26217
|
+
return join5(home, ".config", "opencode", "skills");
|
|
26218
26218
|
}
|
|
26219
26219
|
function getClaudeGlobalSkillsDir() {
|
|
26220
26220
|
const home = process.env.HOME || process.env.USERPROFILE || "~";
|
|
26221
|
-
return
|
|
26221
|
+
return join5(home, ".claude", "skills");
|
|
26222
26222
|
}
|
|
26223
26223
|
function getPackageSkillsDir() {
|
|
26224
26224
|
try {
|
|
26225
26225
|
const currentFilePath = fileURLToPath(import.meta.url);
|
|
26226
|
-
return
|
|
26226
|
+
return join5(dirname2(currentFilePath), "..", "global-skills");
|
|
26227
26227
|
} catch {
|
|
26228
26228
|
const currentDir = decodeURIComponent(new URL(".", import.meta.url).pathname);
|
|
26229
|
-
return
|
|
26229
|
+
return join5(currentDir, "..", "global-skills");
|
|
26230
26230
|
}
|
|
26231
26231
|
}
|
|
26232
26232
|
async function findSkillFiles(baseDir) {
|
|
@@ -26235,7 +26235,7 @@ async function findSkillFiles(baseDir) {
|
|
|
26235
26235
|
const entries = await readdir(baseDir, { withFileTypes: true });
|
|
26236
26236
|
for (const entry of entries) {
|
|
26237
26237
|
if (entry.isDirectory()) {
|
|
26238
|
-
const skillPath =
|
|
26238
|
+
const skillPath = join5(baseDir, entry.name, "SKILL.md");
|
|
26239
26239
|
try {
|
|
26240
26240
|
const s = await stat(skillPath);
|
|
26241
26241
|
if (s.isFile()) {
|
|
@@ -26249,7 +26249,7 @@ async function findSkillFiles(baseDir) {
|
|
|
26249
26249
|
}
|
|
26250
26250
|
async function findSkillScripts(skillDir) {
|
|
26251
26251
|
const scripts = [];
|
|
26252
|
-
const scriptsDir =
|
|
26252
|
+
const scriptsDir = join5(skillDir, "scripts");
|
|
26253
26253
|
try {
|
|
26254
26254
|
const entries = await readdir(scriptsDir, { withFileTypes: true });
|
|
26255
26255
|
for (const entry of entries) {
|
|
@@ -26297,7 +26297,7 @@ async function discoverSkills(projectDir) {
|
|
|
26297
26297
|
}
|
|
26298
26298
|
}
|
|
26299
26299
|
for (const relPath of PROJECT_SKILL_DIRECTORIES) {
|
|
26300
|
-
await loadSkillsFromDir(
|
|
26300
|
+
await loadSkillsFromDir(join5(dir, relPath));
|
|
26301
26301
|
}
|
|
26302
26302
|
await loadSkillsFromDir(getGlobalSkillsDir());
|
|
26303
26303
|
await loadSkillsFromDir(getClaudeGlobalSkillsDir());
|
|
@@ -26653,7 +26653,7 @@ Scripts run in the skill's directory with the project directory as an argument.`
|
|
|
26653
26653
|
if (!skill.scripts.includes(args.script)) {
|
|
26654
26654
|
return `Script '${args.script}' not found in skill '${args.skill}'. Available: ${skill.scripts.join(", ") || "none"}`;
|
|
26655
26655
|
}
|
|
26656
|
-
const scriptPath =
|
|
26656
|
+
const scriptPath = join5(skill.directory, "scripts", args.script);
|
|
26657
26657
|
const scriptArgs = args.args || [];
|
|
26658
26658
|
try {
|
|
26659
26659
|
const TIMEOUT_MS = 60000;
|
|
@@ -26761,14 +26761,14 @@ Good skills have:
|
|
|
26761
26761
|
const csoWarnings = validateCSOCompliance(args.name, args.description);
|
|
26762
26762
|
let skillDir;
|
|
26763
26763
|
if (args.directory === "global") {
|
|
26764
|
-
skillDir =
|
|
26764
|
+
skillDir = join5(getGlobalSkillsDir(), args.name);
|
|
26765
26765
|
} else if (args.directory === "global-claude") {
|
|
26766
|
-
skillDir =
|
|
26766
|
+
skillDir = join5(getClaudeGlobalSkillsDir(), args.name);
|
|
26767
26767
|
} else {
|
|
26768
26768
|
const baseDir = args.directory || DEFAULT_SKILLS_DIR;
|
|
26769
|
-
skillDir =
|
|
26769
|
+
skillDir = join5(skillsProjectDirectory, baseDir, args.name);
|
|
26770
26770
|
}
|
|
26771
|
-
const skillPath =
|
|
26771
|
+
const skillPath = join5(skillDir, "SKILL.md");
|
|
26772
26772
|
try {
|
|
26773
26773
|
await mkdir(skillDir, { recursive: true });
|
|
26774
26774
|
const content = generateSkillContent(args.name, args.description, args.body, { tags: args.tags, tools: args.tools });
|
|
@@ -26919,8 +26919,8 @@ executed with skills_execute. Use for:
|
|
|
26919
26919
|
if (isAbsolute(args.script_name) || args.script_name.includes("..") || args.script_name.includes("/") || args.script_name.includes("\\") || basename(args.script_name) !== args.script_name) {
|
|
26920
26920
|
return "Invalid script name. Use simple filenames without paths.";
|
|
26921
26921
|
}
|
|
26922
|
-
const scriptsDir =
|
|
26923
|
-
const scriptPath =
|
|
26922
|
+
const scriptsDir = join5(skill.directory, "scripts");
|
|
26923
|
+
const scriptPath = join5(scriptsDir, args.script_name);
|
|
26924
26924
|
try {
|
|
26925
26925
|
await mkdir(scriptsDir, { recursive: true });
|
|
26926
26926
|
await writeFile(scriptPath, args.content, {
|
|
@@ -26969,20 +26969,20 @@ Perfect for learning to create effective skills.`,
|
|
|
26969
26969
|
}
|
|
26970
26970
|
let skillDir;
|
|
26971
26971
|
if (args.directory === "global") {
|
|
26972
|
-
skillDir =
|
|
26972
|
+
skillDir = join5(getGlobalSkillsDir(), args.name);
|
|
26973
26973
|
} else {
|
|
26974
26974
|
const baseDir = args.directory || DEFAULT_SKILLS_DIR;
|
|
26975
|
-
skillDir =
|
|
26975
|
+
skillDir = join5(skillsProjectDirectory, baseDir, args.name);
|
|
26976
26976
|
}
|
|
26977
26977
|
const createdFiles = [];
|
|
26978
26978
|
try {
|
|
26979
26979
|
await mkdir(skillDir, { recursive: true });
|
|
26980
|
-
const skillPath =
|
|
26980
|
+
const skillPath = join5(skillDir, "SKILL.md");
|
|
26981
26981
|
const skillContent = generateSkillTemplate(args.name, args.description);
|
|
26982
26982
|
await writeFile(skillPath, skillContent, "utf-8");
|
|
26983
26983
|
createdFiles.push("SKILL.md");
|
|
26984
26984
|
if (args.include_example_script !== false) {
|
|
26985
|
-
const scriptsDir =
|
|
26985
|
+
const scriptsDir = join5(skillDir, "scripts");
|
|
26986
26986
|
await mkdir(scriptsDir, { recursive: true });
|
|
26987
26987
|
const exampleScript = `#!/usr/bin/env bash
|
|
26988
26988
|
# Example helper script for ${args.name}
|
|
@@ -26996,15 +26996,15 @@ echo "Project directory: $1"
|
|
|
26996
26996
|
|
|
26997
26997
|
# TODO: Add actual script logic
|
|
26998
26998
|
`;
|
|
26999
|
-
const scriptPath =
|
|
26999
|
+
const scriptPath = join5(scriptsDir, "example.sh");
|
|
27000
27000
|
await writeFile(scriptPath, exampleScript, { mode: 493 });
|
|
27001
27001
|
createdFiles.push("scripts/example.sh");
|
|
27002
27002
|
}
|
|
27003
27003
|
if (args.include_reference !== false) {
|
|
27004
|
-
const refsDir =
|
|
27004
|
+
const refsDir = join5(skillDir, "references");
|
|
27005
27005
|
await mkdir(refsDir, { recursive: true });
|
|
27006
27006
|
const refContent = generateReferenceTemplate(args.name);
|
|
27007
|
-
const refPath =
|
|
27007
|
+
const refPath = join5(refsDir, "guide.md");
|
|
27008
27008
|
await writeFile(refPath, refContent, "utf-8");
|
|
27009
27009
|
createdFiles.push("references/guide.md");
|
|
27010
27010
|
}
|
|
@@ -27051,40 +27051,43 @@ 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
|
+
importFromJSONL,
|
|
27059
27060
|
getSwarmMail
|
|
27060
27061
|
} from "swarm-mail";
|
|
27062
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
27063
|
+
import { join } from "node:path";
|
|
27061
27064
|
|
|
27062
|
-
// src/schemas/
|
|
27065
|
+
// src/schemas/cell.ts
|
|
27063
27066
|
init_zod();
|
|
27064
|
-
var
|
|
27067
|
+
var CellStatusSchema = exports_external.enum([
|
|
27065
27068
|
"open",
|
|
27066
27069
|
"in_progress",
|
|
27067
27070
|
"blocked",
|
|
27068
27071
|
"closed"
|
|
27069
27072
|
]);
|
|
27070
|
-
var
|
|
27073
|
+
var CellTypeSchema = exports_external.enum([
|
|
27071
27074
|
"bug",
|
|
27072
27075
|
"feature",
|
|
27073
27076
|
"task",
|
|
27074
27077
|
"epic",
|
|
27075
27078
|
"chore"
|
|
27076
27079
|
]);
|
|
27077
|
-
var
|
|
27080
|
+
var CellDependencySchema = exports_external.object({
|
|
27078
27081
|
id: exports_external.string(),
|
|
27079
27082
|
type: exports_external.enum(["blocks", "blocked-by", "related", "discovered-from"])
|
|
27080
27083
|
});
|
|
27081
|
-
var
|
|
27082
|
-
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)"),
|
|
27083
27086
|
title: exports_external.string().min(1, "Title required"),
|
|
27084
27087
|
description: exports_external.string().optional().default(""),
|
|
27085
|
-
status:
|
|
27088
|
+
status: CellStatusSchema.default("open"),
|
|
27086
27089
|
priority: exports_external.number().int().min(0).max(3).default(2),
|
|
27087
|
-
issue_type:
|
|
27090
|
+
issue_type: CellTypeSchema.default("task"),
|
|
27088
27091
|
created_at: exports_external.string().datetime({
|
|
27089
27092
|
offset: true,
|
|
27090
27093
|
message: "Must be ISO-8601 datetime with timezone (e.g., 2024-01-15T10:30:00Z)"
|
|
@@ -27095,30 +27098,30 @@ var BeadSchema = exports_external.object({
|
|
|
27095
27098
|
}).optional(),
|
|
27096
27099
|
closed_at: exports_external.string().datetime({ offset: true }).optional(),
|
|
27097
27100
|
parent_id: exports_external.string().optional(),
|
|
27098
|
-
dependencies: exports_external.array(
|
|
27101
|
+
dependencies: exports_external.array(CellDependencySchema).default([]),
|
|
27099
27102
|
metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
27100
27103
|
});
|
|
27101
|
-
var
|
|
27104
|
+
var CellCreateArgsSchema = exports_external.object({
|
|
27102
27105
|
title: exports_external.string().min(1, "Title required"),
|
|
27103
|
-
type:
|
|
27106
|
+
type: CellTypeSchema.default("task"),
|
|
27104
27107
|
priority: exports_external.number().int().min(0).max(3).default(2),
|
|
27105
27108
|
description: exports_external.string().optional(),
|
|
27106
27109
|
parent_id: exports_external.string().optional(),
|
|
27107
27110
|
id: exports_external.string().optional()
|
|
27108
27111
|
});
|
|
27109
|
-
var
|
|
27112
|
+
var CellUpdateArgsSchema = exports_external.object({
|
|
27110
27113
|
id: exports_external.string(),
|
|
27111
|
-
status:
|
|
27114
|
+
status: CellStatusSchema.optional(),
|
|
27112
27115
|
description: exports_external.string().optional(),
|
|
27113
27116
|
priority: exports_external.number().int().min(0).max(3).optional()
|
|
27114
27117
|
});
|
|
27115
|
-
var
|
|
27118
|
+
var CellCloseArgsSchema = exports_external.object({
|
|
27116
27119
|
id: exports_external.string(),
|
|
27117
27120
|
reason: exports_external.string().min(1, "Reason required")
|
|
27118
27121
|
});
|
|
27119
|
-
var
|
|
27120
|
-
status:
|
|
27121
|
-
type:
|
|
27122
|
+
var CellQueryArgsSchema = exports_external.object({
|
|
27123
|
+
status: CellStatusSchema.optional(),
|
|
27124
|
+
type: CellTypeSchema.optional(),
|
|
27122
27125
|
ready: exports_external.boolean().optional(),
|
|
27123
27126
|
limit: exports_external.number().int().positive().default(20)
|
|
27124
27127
|
});
|
|
@@ -27129,7 +27132,7 @@ var SubtaskSpecSchema = exports_external.object({
|
|
|
27129
27132
|
dependencies: exports_external.array(exports_external.number().int().min(0)).default([]),
|
|
27130
27133
|
estimated_complexity: exports_external.number().int().min(1).max(5).default(3)
|
|
27131
27134
|
});
|
|
27132
|
-
var
|
|
27135
|
+
var CellTreeSchema = exports_external.object({
|
|
27133
27136
|
epic: exports_external.object({
|
|
27134
27137
|
title: exports_external.string().min(1),
|
|
27135
27138
|
description: exports_external.string().optional().default("")
|
|
@@ -27149,10 +27152,11 @@ var EpicCreateArgsSchema = exports_external.object({
|
|
|
27149
27152
|
});
|
|
27150
27153
|
var EpicCreateResultSchema = exports_external.object({
|
|
27151
27154
|
success: exports_external.boolean(),
|
|
27152
|
-
epic:
|
|
27153
|
-
subtasks: exports_external.array(
|
|
27155
|
+
epic: CellSchema,
|
|
27156
|
+
subtasks: exports_external.array(CellSchema),
|
|
27154
27157
|
rollback_hint: exports_external.string().optional()
|
|
27155
27158
|
});
|
|
27159
|
+
var BeadSchema = CellSchema;
|
|
27156
27160
|
// src/schemas/evaluation.ts
|
|
27157
27161
|
init_zod();
|
|
27158
27162
|
var CriterionEvaluationSchema = exports_external.object({
|
|
@@ -27416,29 +27420,29 @@ var QuerySwarmContextsArgsSchema = exports_external.object({
|
|
|
27416
27420
|
strategy: SwarmStrategySchema.optional(),
|
|
27417
27421
|
has_errors: exports_external.boolean().optional()
|
|
27418
27422
|
});
|
|
27419
|
-
// src/schemas/
|
|
27423
|
+
// src/schemas/cell-events.ts
|
|
27420
27424
|
init_zod();
|
|
27421
|
-
var
|
|
27425
|
+
var BaseCellEventSchema = exports_external.object({
|
|
27422
27426
|
id: exports_external.number().optional(),
|
|
27423
27427
|
type: exports_external.string(),
|
|
27424
27428
|
project_key: exports_external.string(),
|
|
27425
27429
|
timestamp: exports_external.number(),
|
|
27426
27430
|
sequence: exports_external.number().optional()
|
|
27427
27431
|
});
|
|
27428
|
-
var
|
|
27429
|
-
type: exports_external.literal("
|
|
27430
|
-
|
|
27432
|
+
var CellCreatedEventSchema = BaseCellEventSchema.extend({
|
|
27433
|
+
type: exports_external.literal("cell_created"),
|
|
27434
|
+
cell_id: exports_external.string(),
|
|
27431
27435
|
title: exports_external.string(),
|
|
27432
27436
|
description: exports_external.string().optional(),
|
|
27433
|
-
issue_type:
|
|
27437
|
+
issue_type: CellTypeSchema,
|
|
27434
27438
|
priority: exports_external.number().int().min(0).max(3),
|
|
27435
27439
|
parent_id: exports_external.string().optional(),
|
|
27436
27440
|
created_by: exports_external.string().optional(),
|
|
27437
27441
|
metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
27438
27442
|
});
|
|
27439
|
-
var
|
|
27440
|
-
type: exports_external.literal("
|
|
27441
|
-
|
|
27443
|
+
var CellUpdatedEventSchema = BaseCellEventSchema.extend({
|
|
27444
|
+
type: exports_external.literal("cell_updated"),
|
|
27445
|
+
cell_id: exports_external.string(),
|
|
27442
27446
|
updated_by: exports_external.string().optional(),
|
|
27443
27447
|
changes: exports_external.object({
|
|
27444
27448
|
title: exports_external.object({
|
|
@@ -27455,155 +27459,155 @@ var BeadUpdatedEventSchema = BaseBeadEventSchema.extend({
|
|
|
27455
27459
|
}).optional()
|
|
27456
27460
|
})
|
|
27457
27461
|
});
|
|
27458
|
-
var
|
|
27459
|
-
type: exports_external.literal("
|
|
27460
|
-
|
|
27461
|
-
from_status:
|
|
27462
|
-
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,
|
|
27463
27467
|
changed_by: exports_external.string().optional(),
|
|
27464
27468
|
reason: exports_external.string().optional()
|
|
27465
27469
|
});
|
|
27466
|
-
var
|
|
27467
|
-
type: exports_external.literal("
|
|
27468
|
-
|
|
27470
|
+
var CellClosedEventSchema = BaseCellEventSchema.extend({
|
|
27471
|
+
type: exports_external.literal("cell_closed"),
|
|
27472
|
+
cell_id: exports_external.string(),
|
|
27469
27473
|
reason: exports_external.string(),
|
|
27470
27474
|
closed_by: exports_external.string().optional(),
|
|
27471
27475
|
files_touched: exports_external.array(exports_external.string()).optional(),
|
|
27472
27476
|
duration_ms: exports_external.number().optional()
|
|
27473
27477
|
});
|
|
27474
|
-
var
|
|
27475
|
-
type: exports_external.literal("
|
|
27476
|
-
|
|
27478
|
+
var CellReopenedEventSchema = BaseCellEventSchema.extend({
|
|
27479
|
+
type: exports_external.literal("cell_reopened"),
|
|
27480
|
+
cell_id: exports_external.string(),
|
|
27477
27481
|
reason: exports_external.string().optional(),
|
|
27478
27482
|
reopened_by: exports_external.string().optional()
|
|
27479
27483
|
});
|
|
27480
|
-
var
|
|
27481
|
-
type: exports_external.literal("
|
|
27482
|
-
|
|
27484
|
+
var CellDeletedEventSchema = BaseCellEventSchema.extend({
|
|
27485
|
+
type: exports_external.literal("cell_deleted"),
|
|
27486
|
+
cell_id: exports_external.string(),
|
|
27483
27487
|
reason: exports_external.string().optional(),
|
|
27484
27488
|
deleted_by: exports_external.string().optional()
|
|
27485
27489
|
});
|
|
27486
|
-
var
|
|
27487
|
-
type: exports_external.literal("
|
|
27488
|
-
|
|
27489
|
-
dependency:
|
|
27490
|
+
var CellDependencyAddedEventSchema = BaseCellEventSchema.extend({
|
|
27491
|
+
type: exports_external.literal("cell_dependency_added"),
|
|
27492
|
+
cell_id: exports_external.string(),
|
|
27493
|
+
dependency: CellDependencySchema,
|
|
27490
27494
|
added_by: exports_external.string().optional(),
|
|
27491
27495
|
reason: exports_external.string().optional()
|
|
27492
27496
|
});
|
|
27493
|
-
var
|
|
27494
|
-
type: exports_external.literal("
|
|
27495
|
-
|
|
27496
|
-
dependency:
|
|
27497
|
+
var CellDependencyRemovedEventSchema = BaseCellEventSchema.extend({
|
|
27498
|
+
type: exports_external.literal("cell_dependency_removed"),
|
|
27499
|
+
cell_id: exports_external.string(),
|
|
27500
|
+
dependency: CellDependencySchema,
|
|
27497
27501
|
removed_by: exports_external.string().optional(),
|
|
27498
27502
|
reason: exports_external.string().optional()
|
|
27499
27503
|
});
|
|
27500
|
-
var
|
|
27501
|
-
type: exports_external.literal("
|
|
27502
|
-
|
|
27504
|
+
var CellLabelAddedEventSchema = BaseCellEventSchema.extend({
|
|
27505
|
+
type: exports_external.literal("cell_label_added"),
|
|
27506
|
+
cell_id: exports_external.string(),
|
|
27503
27507
|
label: exports_external.string(),
|
|
27504
27508
|
added_by: exports_external.string().optional()
|
|
27505
27509
|
});
|
|
27506
|
-
var
|
|
27507
|
-
type: exports_external.literal("
|
|
27508
|
-
|
|
27510
|
+
var CellLabelRemovedEventSchema = BaseCellEventSchema.extend({
|
|
27511
|
+
type: exports_external.literal("cell_label_removed"),
|
|
27512
|
+
cell_id: exports_external.string(),
|
|
27509
27513
|
label: exports_external.string(),
|
|
27510
27514
|
removed_by: exports_external.string().optional()
|
|
27511
27515
|
});
|
|
27512
|
-
var
|
|
27513
|
-
type: exports_external.literal("
|
|
27514
|
-
|
|
27516
|
+
var CellCommentAddedEventSchema = BaseCellEventSchema.extend({
|
|
27517
|
+
type: exports_external.literal("cell_comment_added"),
|
|
27518
|
+
cell_id: exports_external.string(),
|
|
27515
27519
|
comment_id: exports_external.number().optional(),
|
|
27516
27520
|
author: exports_external.string(),
|
|
27517
27521
|
body: exports_external.string(),
|
|
27518
27522
|
parent_comment_id: exports_external.number().optional(),
|
|
27519
27523
|
metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
27520
27524
|
});
|
|
27521
|
-
var
|
|
27522
|
-
type: exports_external.literal("
|
|
27523
|
-
|
|
27525
|
+
var CellCommentUpdatedEventSchema = BaseCellEventSchema.extend({
|
|
27526
|
+
type: exports_external.literal("cell_comment_updated"),
|
|
27527
|
+
cell_id: exports_external.string(),
|
|
27524
27528
|
comment_id: exports_external.number(),
|
|
27525
27529
|
old_body: exports_external.string(),
|
|
27526
27530
|
new_body: exports_external.string(),
|
|
27527
27531
|
updated_by: exports_external.string()
|
|
27528
27532
|
});
|
|
27529
|
-
var
|
|
27530
|
-
type: exports_external.literal("
|
|
27531
|
-
|
|
27533
|
+
var CellCommentDeletedEventSchema = BaseCellEventSchema.extend({
|
|
27534
|
+
type: exports_external.literal("cell_comment_deleted"),
|
|
27535
|
+
cell_id: exports_external.string(),
|
|
27532
27536
|
comment_id: exports_external.number(),
|
|
27533
27537
|
deleted_by: exports_external.string(),
|
|
27534
27538
|
reason: exports_external.string().optional()
|
|
27535
27539
|
});
|
|
27536
|
-
var
|
|
27537
|
-
type: exports_external.literal("
|
|
27538
|
-
|
|
27540
|
+
var CellEpicChildAddedEventSchema = BaseCellEventSchema.extend({
|
|
27541
|
+
type: exports_external.literal("cell_epic_child_added"),
|
|
27542
|
+
cell_id: exports_external.string(),
|
|
27539
27543
|
child_id: exports_external.string(),
|
|
27540
27544
|
child_index: exports_external.number().optional(),
|
|
27541
27545
|
added_by: exports_external.string().optional()
|
|
27542
27546
|
});
|
|
27543
|
-
var
|
|
27544
|
-
type: exports_external.literal("
|
|
27545
|
-
|
|
27547
|
+
var CellEpicChildRemovedEventSchema = BaseCellEventSchema.extend({
|
|
27548
|
+
type: exports_external.literal("cell_epic_child_removed"),
|
|
27549
|
+
cell_id: exports_external.string(),
|
|
27546
27550
|
child_id: exports_external.string(),
|
|
27547
27551
|
removed_by: exports_external.string().optional(),
|
|
27548
27552
|
reason: exports_external.string().optional()
|
|
27549
27553
|
});
|
|
27550
|
-
var
|
|
27551
|
-
type: exports_external.literal("
|
|
27552
|
-
|
|
27554
|
+
var CellEpicClosureEligibleEventSchema = BaseCellEventSchema.extend({
|
|
27555
|
+
type: exports_external.literal("cell_epic_closure_eligible"),
|
|
27556
|
+
cell_id: exports_external.string(),
|
|
27553
27557
|
child_ids: exports_external.array(exports_external.string()),
|
|
27554
27558
|
total_duration_ms: exports_external.number().optional(),
|
|
27555
27559
|
all_files_touched: exports_external.array(exports_external.string()).optional()
|
|
27556
27560
|
});
|
|
27557
|
-
var
|
|
27558
|
-
type: exports_external.literal("
|
|
27559
|
-
|
|
27561
|
+
var CellAssignedEventSchema = BaseCellEventSchema.extend({
|
|
27562
|
+
type: exports_external.literal("cell_assigned"),
|
|
27563
|
+
cell_id: exports_external.string(),
|
|
27560
27564
|
agent_name: exports_external.string(),
|
|
27561
27565
|
task_description: exports_external.string().optional()
|
|
27562
27566
|
});
|
|
27563
|
-
var
|
|
27564
|
-
type: exports_external.literal("
|
|
27565
|
-
|
|
27567
|
+
var CellWorkStartedEventSchema = BaseCellEventSchema.extend({
|
|
27568
|
+
type: exports_external.literal("cell_work_started"),
|
|
27569
|
+
cell_id: exports_external.string(),
|
|
27566
27570
|
agent_name: exports_external.string(),
|
|
27567
27571
|
reserved_files: exports_external.array(exports_external.string()).optional()
|
|
27568
27572
|
});
|
|
27569
|
-
var
|
|
27570
|
-
type: exports_external.literal("
|
|
27571
|
-
|
|
27573
|
+
var CellCompactedEventSchema = BaseCellEventSchema.extend({
|
|
27574
|
+
type: exports_external.literal("cell_compacted"),
|
|
27575
|
+
cell_id: exports_external.string(),
|
|
27572
27576
|
events_archived: exports_external.number(),
|
|
27573
27577
|
new_start_sequence: exports_external.number()
|
|
27574
27578
|
});
|
|
27575
|
-
var
|
|
27576
|
-
|
|
27577
|
-
|
|
27578
|
-
|
|
27579
|
-
|
|
27580
|
-
|
|
27581
|
-
|
|
27582
|
-
|
|
27583
|
-
|
|
27584
|
-
|
|
27585
|
-
|
|
27586
|
-
|
|
27587
|
-
|
|
27588
|
-
|
|
27589
|
-
|
|
27590
|
-
|
|
27591
|
-
|
|
27592
|
-
|
|
27593
|
-
|
|
27594
|
-
|
|
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
|
|
27595
27599
|
]);
|
|
27596
|
-
// src/
|
|
27600
|
+
// src/hive.ts
|
|
27597
27601
|
import { createEvent, appendEvent } from "swarm-mail";
|
|
27598
|
-
var
|
|
27599
|
-
function
|
|
27600
|
-
|
|
27602
|
+
var hiveWorkingDirectory = null;
|
|
27603
|
+
function setHiveWorkingDirectory(directory) {
|
|
27604
|
+
hiveWorkingDirectory = directory;
|
|
27601
27605
|
}
|
|
27602
|
-
function
|
|
27603
|
-
return
|
|
27606
|
+
function getHiveWorkingDirectory() {
|
|
27607
|
+
return hiveWorkingDirectory || process.cwd();
|
|
27604
27608
|
}
|
|
27605
27609
|
async function runGitCommand(args) {
|
|
27606
|
-
const cwd =
|
|
27610
|
+
const cwd = getHiveWorkingDirectory();
|
|
27607
27611
|
const proc = Bun.spawn(["git", ...args], {
|
|
27608
27612
|
cwd,
|
|
27609
27613
|
stdout: "pipe",
|
|
@@ -27617,7 +27621,7 @@ async function runGitCommand(args) {
|
|
|
27617
27621
|
return { exitCode, stdout, stderr };
|
|
27618
27622
|
}
|
|
27619
27623
|
|
|
27620
|
-
class
|
|
27624
|
+
class HiveError extends Error {
|
|
27621
27625
|
command;
|
|
27622
27626
|
exitCode;
|
|
27623
27627
|
stderr;
|
|
@@ -27626,68 +27630,93 @@ class BeadError extends Error {
|
|
|
27626
27630
|
this.command = command;
|
|
27627
27631
|
this.exitCode = exitCode;
|
|
27628
27632
|
this.stderr = stderr;
|
|
27629
|
-
this.name = "
|
|
27633
|
+
this.name = "HiveError";
|
|
27630
27634
|
}
|
|
27631
27635
|
}
|
|
27632
27636
|
var adapterCache = new Map;
|
|
27633
|
-
async function
|
|
27637
|
+
async function getHiveAdapter(projectKey) {
|
|
27634
27638
|
if (adapterCache.has(projectKey)) {
|
|
27635
27639
|
return adapterCache.get(projectKey);
|
|
27636
27640
|
}
|
|
27637
27641
|
const swarmMail = await getSwarmMail(projectKey);
|
|
27638
27642
|
const db = await swarmMail.getDatabase();
|
|
27639
|
-
const adapter =
|
|
27643
|
+
const adapter = createHiveAdapter(db, projectKey);
|
|
27640
27644
|
await adapter.runMigrations();
|
|
27645
|
+
await autoMigrateFromJSONL(adapter, projectKey);
|
|
27641
27646
|
adapterCache.set(projectKey, adapter);
|
|
27642
27647
|
return adapter;
|
|
27643
27648
|
}
|
|
27644
|
-
function
|
|
27649
|
+
async function autoMigrateFromJSONL(adapter, projectKey) {
|
|
27650
|
+
const jsonlPath = join(projectKey, ".hive", "issues.jsonl");
|
|
27651
|
+
if (!existsSync(jsonlPath)) {
|
|
27652
|
+
return;
|
|
27653
|
+
}
|
|
27654
|
+
const existingCells = await adapter.queryCells(projectKey, { limit: 1 });
|
|
27655
|
+
if (existingCells.length > 0) {
|
|
27656
|
+
return;
|
|
27657
|
+
}
|
|
27658
|
+
try {
|
|
27659
|
+
const jsonlContent = readFileSync(jsonlPath, "utf-8");
|
|
27660
|
+
const result = await importFromJSONL(adapter, projectKey, jsonlContent, {
|
|
27661
|
+
skipExisting: true
|
|
27662
|
+
});
|
|
27663
|
+
if (result.created > 0 || result.updated > 0) {
|
|
27664
|
+
console.log(`[hive] Auto-migrated ${result.created} cells from ${jsonlPath} (${result.skipped} skipped, ${result.errors.length} errors)`);
|
|
27665
|
+
}
|
|
27666
|
+
if (result.errors.length > 0) {
|
|
27667
|
+
console.warn(`[hive] Migration errors:`, result.errors.slice(0, 5).map((e) => `${e.cellId}: ${e.error}`));
|
|
27668
|
+
}
|
|
27669
|
+
} catch (error45) {
|
|
27670
|
+
console.warn(`[hive] Failed to auto-migrate from ${jsonlPath}:`, error45 instanceof Error ? error45.message : String(error45));
|
|
27671
|
+
}
|
|
27672
|
+
}
|
|
27673
|
+
function formatCellForOutput(adapterCell) {
|
|
27645
27674
|
return {
|
|
27646
|
-
id:
|
|
27647
|
-
title:
|
|
27648
|
-
description:
|
|
27649
|
-
status:
|
|
27650
|
-
priority:
|
|
27651
|
-
issue_type:
|
|
27652
|
-
created_at: new Date(
|
|
27653
|
-
updated_at: new Date(
|
|
27654
|
-
closed_at:
|
|
27655
|
-
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,
|
|
27656
27685
|
dependencies: [],
|
|
27657
27686
|
metadata: {}
|
|
27658
27687
|
};
|
|
27659
27688
|
}
|
|
27660
|
-
var
|
|
27661
|
-
description: "Create a new
|
|
27689
|
+
var hive_create = tool({
|
|
27690
|
+
description: "Create a new cell in the hive with type-safe validation",
|
|
27662
27691
|
args: {
|
|
27663
|
-
title: tool.schema.string().describe("
|
|
27692
|
+
title: tool.schema.string().describe("Cell title"),
|
|
27664
27693
|
type: tool.schema.enum(["bug", "feature", "task", "epic", "chore"]).optional().describe("Issue type (default: task)"),
|
|
27665
27694
|
priority: tool.schema.number().min(0).max(3).optional().describe("Priority 0-3 (default: 2)"),
|
|
27666
|
-
description: tool.schema.string().optional().describe("
|
|
27667
|
-
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")
|
|
27668
27697
|
},
|
|
27669
27698
|
async execute(args, ctx) {
|
|
27670
|
-
const validated =
|
|
27671
|
-
const projectKey =
|
|
27672
|
-
const adapter = await
|
|
27699
|
+
const validated = CellCreateArgsSchema.parse(args);
|
|
27700
|
+
const projectKey = getHiveWorkingDirectory();
|
|
27701
|
+
const adapter = await getHiveAdapter(projectKey);
|
|
27673
27702
|
try {
|
|
27674
|
-
const
|
|
27703
|
+
const cell = await adapter.createCell(projectKey, {
|
|
27675
27704
|
title: validated.title,
|
|
27676
27705
|
type: validated.type || "task",
|
|
27677
27706
|
priority: validated.priority ?? 2,
|
|
27678
27707
|
description: validated.description,
|
|
27679
27708
|
parent_id: validated.parent_id
|
|
27680
27709
|
});
|
|
27681
|
-
await adapter.markDirty(projectKey,
|
|
27682
|
-
const formatted =
|
|
27710
|
+
await adapter.markDirty(projectKey, cell.id);
|
|
27711
|
+
const formatted = formatCellForOutput(cell);
|
|
27683
27712
|
return JSON.stringify(formatted, null, 2);
|
|
27684
27713
|
} catch (error45) {
|
|
27685
27714
|
const message = error45 instanceof Error ? error45.message : String(error45);
|
|
27686
|
-
throw new
|
|
27715
|
+
throw new HiveError(`Failed to create cell: ${message}`, "hive_create");
|
|
27687
27716
|
}
|
|
27688
27717
|
}
|
|
27689
27718
|
});
|
|
27690
|
-
var
|
|
27719
|
+
var hive_create_epic = tool({
|
|
27691
27720
|
description: "Create epic with subtasks in one atomic operation",
|
|
27692
27721
|
args: {
|
|
27693
27722
|
epic_title: tool.schema.string().describe("Epic title"),
|
|
@@ -27710,11 +27739,11 @@ var beads_create_epic = tool({
|
|
|
27710
27739
|
},
|
|
27711
27740
|
async execute(args, ctx) {
|
|
27712
27741
|
const validated = EpicCreateArgsSchema.parse(args);
|
|
27713
|
-
const projectKey =
|
|
27714
|
-
const adapter = await
|
|
27742
|
+
const projectKey = getHiveWorkingDirectory();
|
|
27743
|
+
const adapter = await getHiveAdapter(projectKey);
|
|
27715
27744
|
const created = [];
|
|
27716
27745
|
try {
|
|
27717
|
-
const epic = await adapter.
|
|
27746
|
+
const epic = await adapter.createCell(projectKey, {
|
|
27718
27747
|
title: validated.epic_title,
|
|
27719
27748
|
type: "epic",
|
|
27720
27749
|
priority: 1,
|
|
@@ -27723,19 +27752,19 @@ var beads_create_epic = tool({
|
|
|
27723
27752
|
await adapter.markDirty(projectKey, epic.id);
|
|
27724
27753
|
created.push(epic);
|
|
27725
27754
|
for (const subtask of validated.subtasks) {
|
|
27726
|
-
const
|
|
27755
|
+
const subtaskCell = await adapter.createCell(projectKey, {
|
|
27727
27756
|
title: subtask.title,
|
|
27728
27757
|
type: "task",
|
|
27729
27758
|
priority: subtask.priority ?? 2,
|
|
27730
27759
|
parent_id: epic.id
|
|
27731
27760
|
});
|
|
27732
|
-
await adapter.markDirty(projectKey,
|
|
27733
|
-
created.push(
|
|
27761
|
+
await adapter.markDirty(projectKey, subtaskCell.id);
|
|
27762
|
+
created.push(subtaskCell);
|
|
27734
27763
|
}
|
|
27735
27764
|
const result = {
|
|
27736
27765
|
success: true,
|
|
27737
|
-
epic:
|
|
27738
|
-
subtasks: created.slice(1).map((
|
|
27766
|
+
epic: formatCellForOutput(epic),
|
|
27767
|
+
subtasks: created.slice(1).map((c) => formatCellForOutput(c))
|
|
27739
27768
|
};
|
|
27740
27769
|
if (args.project_key) {
|
|
27741
27770
|
try {
|
|
@@ -27755,27 +27784,27 @@ var beads_create_epic = tool({
|
|
|
27755
27784
|
});
|
|
27756
27785
|
await appendEvent(event, args.project_key);
|
|
27757
27786
|
} catch (error45) {
|
|
27758
|
-
console.warn("[
|
|
27787
|
+
console.warn("[hive_create_epic] Failed to emit DecompositionGeneratedEvent:", error45);
|
|
27759
27788
|
}
|
|
27760
27789
|
}
|
|
27761
27790
|
return JSON.stringify(result, null, 2);
|
|
27762
27791
|
} catch (error45) {
|
|
27763
27792
|
const rollbackErrors = [];
|
|
27764
|
-
for (const
|
|
27793
|
+
for (const cell of created) {
|
|
27765
27794
|
try {
|
|
27766
|
-
await adapter.
|
|
27795
|
+
await adapter.deleteCell(projectKey, cell.id, {
|
|
27767
27796
|
reason: "Rollback partial epic"
|
|
27768
27797
|
});
|
|
27769
27798
|
} catch (rollbackError) {
|
|
27770
27799
|
const errMsg = rollbackError instanceof Error ? rollbackError.message : String(rollbackError);
|
|
27771
|
-
console.error(`Failed to rollback
|
|
27772
|
-
rollbackErrors.push(`${
|
|
27800
|
+
console.error(`Failed to rollback cell ${cell.id}:`, rollbackError);
|
|
27801
|
+
rollbackErrors.push(`${cell.id}: ${errMsg}`);
|
|
27773
27802
|
}
|
|
27774
27803
|
}
|
|
27775
27804
|
const errorMsg = error45 instanceof Error ? error45.message : String(error45);
|
|
27776
27805
|
let rollbackInfo = `
|
|
27777
27806
|
|
|
27778
|
-
Rolled back ${created.length - rollbackErrors.length}
|
|
27807
|
+
Rolled back ${created.length - rollbackErrors.length} cell(s)`;
|
|
27779
27808
|
if (rollbackErrors.length > 0) {
|
|
27780
27809
|
rollbackInfo += `
|
|
27781
27810
|
|
|
@@ -27783,151 +27812,151 @@ Rollback failures (${rollbackErrors.length}):
|
|
|
27783
27812
|
${rollbackErrors.join(`
|
|
27784
27813
|
`)}`;
|
|
27785
27814
|
}
|
|
27786
|
-
throw new
|
|
27815
|
+
throw new HiveError(`Epic creation failed: ${errorMsg}${rollbackInfo}`, "hive_create_epic", 1);
|
|
27787
27816
|
}
|
|
27788
27817
|
}
|
|
27789
27818
|
});
|
|
27790
|
-
var
|
|
27791
|
-
description: "Query
|
|
27819
|
+
var hive_query = tool({
|
|
27820
|
+
description: "Query hive cells with filters (replaces bd list, bd ready, bd wip)",
|
|
27792
27821
|
args: {
|
|
27793
27822
|
status: tool.schema.enum(["open", "in_progress", "blocked", "closed"]).optional().describe("Filter by status"),
|
|
27794
27823
|
type: tool.schema.enum(["bug", "feature", "task", "epic", "chore"]).optional().describe("Filter by type"),
|
|
27795
|
-
ready: tool.schema.boolean().optional().describe("Only show unblocked
|
|
27824
|
+
ready: tool.schema.boolean().optional().describe("Only show unblocked cells"),
|
|
27796
27825
|
limit: tool.schema.number().optional().describe("Max results to return (default: 20)")
|
|
27797
27826
|
},
|
|
27798
27827
|
async execute(args, ctx) {
|
|
27799
|
-
const validated =
|
|
27800
|
-
const projectKey =
|
|
27801
|
-
const adapter = await
|
|
27828
|
+
const validated = CellQueryArgsSchema.parse(args);
|
|
27829
|
+
const projectKey = getHiveWorkingDirectory();
|
|
27830
|
+
const adapter = await getHiveAdapter(projectKey);
|
|
27802
27831
|
try {
|
|
27803
|
-
let
|
|
27832
|
+
let cells;
|
|
27804
27833
|
if (validated.ready) {
|
|
27805
|
-
const
|
|
27806
|
-
|
|
27834
|
+
const readyCell = await adapter.getNextReadyCell(projectKey);
|
|
27835
|
+
cells = readyCell ? [readyCell] : [];
|
|
27807
27836
|
} else {
|
|
27808
|
-
|
|
27837
|
+
cells = await adapter.queryCells(projectKey, {
|
|
27809
27838
|
status: validated.status,
|
|
27810
27839
|
type: validated.type,
|
|
27811
27840
|
limit: validated.limit || 20
|
|
27812
27841
|
});
|
|
27813
27842
|
}
|
|
27814
|
-
const formatted =
|
|
27843
|
+
const formatted = cells.map((c) => formatCellForOutput(c));
|
|
27815
27844
|
return JSON.stringify(formatted, null, 2);
|
|
27816
27845
|
} catch (error45) {
|
|
27817
27846
|
const message = error45 instanceof Error ? error45.message : String(error45);
|
|
27818
|
-
throw new
|
|
27847
|
+
throw new HiveError(`Failed to query cells: ${message}`, "hive_query");
|
|
27819
27848
|
}
|
|
27820
27849
|
}
|
|
27821
27850
|
});
|
|
27822
|
-
var
|
|
27823
|
-
description: "Update
|
|
27851
|
+
var hive_update = tool({
|
|
27852
|
+
description: "Update cell status/description",
|
|
27824
27853
|
args: {
|
|
27825
|
-
id: tool.schema.string().describe("
|
|
27854
|
+
id: tool.schema.string().describe("Cell ID"),
|
|
27826
27855
|
status: tool.schema.enum(["open", "in_progress", "blocked", "closed"]).optional().describe("New status"),
|
|
27827
27856
|
description: tool.schema.string().optional().describe("New description"),
|
|
27828
27857
|
priority: tool.schema.number().min(0).max(3).optional().describe("New priority")
|
|
27829
27858
|
},
|
|
27830
27859
|
async execute(args, ctx) {
|
|
27831
|
-
const validated =
|
|
27832
|
-
const projectKey =
|
|
27833
|
-
const adapter = await
|
|
27860
|
+
const validated = CellUpdateArgsSchema.parse(args);
|
|
27861
|
+
const projectKey = getHiveWorkingDirectory();
|
|
27862
|
+
const adapter = await getHiveAdapter(projectKey);
|
|
27834
27863
|
try {
|
|
27835
|
-
let
|
|
27864
|
+
let cell;
|
|
27836
27865
|
if (validated.status) {
|
|
27837
|
-
|
|
27866
|
+
cell = await adapter.changeCellStatus(projectKey, validated.id, validated.status);
|
|
27838
27867
|
}
|
|
27839
27868
|
if (validated.description !== undefined || validated.priority !== undefined) {
|
|
27840
|
-
|
|
27869
|
+
cell = await adapter.updateCell(projectKey, validated.id, {
|
|
27841
27870
|
description: validated.description,
|
|
27842
27871
|
priority: validated.priority
|
|
27843
27872
|
});
|
|
27844
27873
|
} else if (!validated.status) {
|
|
27845
|
-
const
|
|
27846
|
-
if (!
|
|
27847
|
-
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");
|
|
27848
27877
|
}
|
|
27849
|
-
|
|
27878
|
+
cell = existingCell;
|
|
27850
27879
|
}
|
|
27851
27880
|
await adapter.markDirty(projectKey, validated.id);
|
|
27852
|
-
const formatted =
|
|
27881
|
+
const formatted = formatCellForOutput(cell);
|
|
27853
27882
|
return JSON.stringify(formatted, null, 2);
|
|
27854
27883
|
} catch (error45) {
|
|
27855
27884
|
const message = error45 instanceof Error ? error45.message : String(error45);
|
|
27856
|
-
throw new
|
|
27885
|
+
throw new HiveError(`Failed to update cell: ${message}`, "hive_update");
|
|
27857
27886
|
}
|
|
27858
27887
|
}
|
|
27859
27888
|
});
|
|
27860
|
-
var
|
|
27861
|
-
description: "Close a
|
|
27889
|
+
var hive_close = tool({
|
|
27890
|
+
description: "Close a cell with reason",
|
|
27862
27891
|
args: {
|
|
27863
|
-
id: tool.schema.string().describe("
|
|
27892
|
+
id: tool.schema.string().describe("Cell ID"),
|
|
27864
27893
|
reason: tool.schema.string().describe("Completion reason")
|
|
27865
27894
|
},
|
|
27866
27895
|
async execute(args, ctx) {
|
|
27867
|
-
const validated =
|
|
27868
|
-
const projectKey =
|
|
27869
|
-
const adapter = await
|
|
27896
|
+
const validated = CellCloseArgsSchema.parse(args);
|
|
27897
|
+
const projectKey = getHiveWorkingDirectory();
|
|
27898
|
+
const adapter = await getHiveAdapter(projectKey);
|
|
27870
27899
|
try {
|
|
27871
|
-
const
|
|
27900
|
+
const cell = await adapter.closeCell(projectKey, validated.id, validated.reason);
|
|
27872
27901
|
await adapter.markDirty(projectKey, validated.id);
|
|
27873
|
-
return `Closed ${
|
|
27902
|
+
return `Closed ${cell.id}: ${validated.reason}`;
|
|
27874
27903
|
} catch (error45) {
|
|
27875
27904
|
const message = error45 instanceof Error ? error45.message : String(error45);
|
|
27876
|
-
throw new
|
|
27905
|
+
throw new HiveError(`Failed to close cell: ${message}`, "hive_close");
|
|
27877
27906
|
}
|
|
27878
27907
|
}
|
|
27879
27908
|
});
|
|
27880
|
-
var
|
|
27881
|
-
description: "Mark a
|
|
27909
|
+
var hive_start = tool({
|
|
27910
|
+
description: "Mark a cell as in-progress (shortcut for update --status in_progress)",
|
|
27882
27911
|
args: {
|
|
27883
|
-
id: tool.schema.string().describe("
|
|
27912
|
+
id: tool.schema.string().describe("Cell ID")
|
|
27884
27913
|
},
|
|
27885
27914
|
async execute(args, ctx) {
|
|
27886
|
-
const projectKey =
|
|
27887
|
-
const adapter = await
|
|
27915
|
+
const projectKey = getHiveWorkingDirectory();
|
|
27916
|
+
const adapter = await getHiveAdapter(projectKey);
|
|
27888
27917
|
try {
|
|
27889
|
-
const
|
|
27918
|
+
const cell = await adapter.changeCellStatus(projectKey, args.id, "in_progress");
|
|
27890
27919
|
await adapter.markDirty(projectKey, args.id);
|
|
27891
|
-
return `Started: ${
|
|
27920
|
+
return `Started: ${cell.id}`;
|
|
27892
27921
|
} catch (error45) {
|
|
27893
27922
|
const message = error45 instanceof Error ? error45.message : String(error45);
|
|
27894
|
-
throw new
|
|
27923
|
+
throw new HiveError(`Failed to start cell: ${message}`, "hive_start");
|
|
27895
27924
|
}
|
|
27896
27925
|
}
|
|
27897
27926
|
});
|
|
27898
|
-
var
|
|
27899
|
-
description: "Get the next ready
|
|
27927
|
+
var hive_ready = tool({
|
|
27928
|
+
description: "Get the next ready cell (unblocked, highest priority)",
|
|
27900
27929
|
args: {},
|
|
27901
27930
|
async execute(args, ctx) {
|
|
27902
|
-
const projectKey =
|
|
27903
|
-
const adapter = await
|
|
27931
|
+
const projectKey = getHiveWorkingDirectory();
|
|
27932
|
+
const adapter = await getHiveAdapter(projectKey);
|
|
27904
27933
|
try {
|
|
27905
|
-
const
|
|
27906
|
-
if (!
|
|
27907
|
-
return "No ready
|
|
27934
|
+
const cell = await adapter.getNextReadyCell(projectKey);
|
|
27935
|
+
if (!cell) {
|
|
27936
|
+
return "No ready cells";
|
|
27908
27937
|
}
|
|
27909
|
-
const formatted =
|
|
27938
|
+
const formatted = formatCellForOutput(cell);
|
|
27910
27939
|
return JSON.stringify(formatted, null, 2);
|
|
27911
27940
|
} catch (error45) {
|
|
27912
27941
|
const message = error45 instanceof Error ? error45.message : String(error45);
|
|
27913
|
-
throw new
|
|
27942
|
+
throw new HiveError(`Failed to get ready cells: ${message}`, "hive_ready");
|
|
27914
27943
|
}
|
|
27915
27944
|
}
|
|
27916
27945
|
});
|
|
27917
|
-
var
|
|
27918
|
-
description: "Sync
|
|
27946
|
+
var hive_sync = tool({
|
|
27947
|
+
description: "Sync hive to git and push (MANDATORY at session end)",
|
|
27919
27948
|
args: {
|
|
27920
27949
|
auto_pull: tool.schema.boolean().optional().describe("Pull before sync (default: true)")
|
|
27921
27950
|
},
|
|
27922
27951
|
async execute(args, ctx) {
|
|
27923
27952
|
const autoPull = args.auto_pull ?? true;
|
|
27924
|
-
const projectKey =
|
|
27925
|
-
const adapter = await
|
|
27953
|
+
const projectKey = getHiveWorkingDirectory();
|
|
27954
|
+
const adapter = await getHiveAdapter(projectKey);
|
|
27926
27955
|
const TIMEOUT_MS = 30000;
|
|
27927
27956
|
const withTimeout = async (promise2, timeoutMs, operation) => {
|
|
27928
27957
|
let timeoutId;
|
|
27929
27958
|
const timeoutPromise = new Promise((_, reject) => {
|
|
27930
|
-
timeoutId = setTimeout(() => reject(new
|
|
27959
|
+
timeoutId = setTimeout(() => reject(new HiveError(`Operation timed out after ${timeoutMs}ms`, operation)), timeoutMs);
|
|
27931
27960
|
});
|
|
27932
27961
|
try {
|
|
27933
27962
|
return await Promise.race([promise2, timeoutPromise]);
|
|
@@ -27940,85 +27969,156 @@ var beads_sync = tool({
|
|
|
27940
27969
|
const flushManager = new FlushManager({
|
|
27941
27970
|
adapter,
|
|
27942
27971
|
projectKey,
|
|
27943
|
-
outputPath: `${projectKey}/.
|
|
27972
|
+
outputPath: `${projectKey}/.hive/issues.jsonl`
|
|
27944
27973
|
});
|
|
27945
|
-
const flushResult = await withTimeout(flushManager.flush(), TIMEOUT_MS, "flush
|
|
27946
|
-
if (flushResult.
|
|
27947
|
-
return "No
|
|
27974
|
+
const flushResult = await withTimeout(flushManager.flush(), TIMEOUT_MS, "flush hive");
|
|
27975
|
+
if (flushResult.cellsExported === 0) {
|
|
27976
|
+
return "No cells to sync";
|
|
27948
27977
|
}
|
|
27949
|
-
const
|
|
27978
|
+
const hiveStatusResult = await runGitCommand([
|
|
27950
27979
|
"status",
|
|
27951
27980
|
"--porcelain",
|
|
27952
|
-
".
|
|
27981
|
+
".hive/"
|
|
27953
27982
|
]);
|
|
27954
|
-
const hasChanges =
|
|
27983
|
+
const hasChanges = hiveStatusResult.stdout.trim() !== "";
|
|
27955
27984
|
if (hasChanges) {
|
|
27956
|
-
const addResult = await runGitCommand(["add", ".
|
|
27985
|
+
const addResult = await runGitCommand(["add", ".hive/"]);
|
|
27957
27986
|
if (addResult.exitCode !== 0) {
|
|
27958
|
-
throw new
|
|
27987
|
+
throw new HiveError(`Failed to stage hive: ${addResult.stderr}`, "git add .hive/", addResult.exitCode);
|
|
27959
27988
|
}
|
|
27960
|
-
const commitResult = await withTimeout(runGitCommand(["commit", "-m", "chore: sync
|
|
27989
|
+
const commitResult = await withTimeout(runGitCommand(["commit", "-m", "chore: sync hive"]), TIMEOUT_MS, "git commit");
|
|
27961
27990
|
if (commitResult.exitCode !== 0 && !commitResult.stdout.includes("nothing to commit")) {
|
|
27962
|
-
throw new
|
|
27991
|
+
throw new HiveError(`Failed to commit hive: ${commitResult.stderr}`, "git commit", commitResult.exitCode);
|
|
27963
27992
|
}
|
|
27964
27993
|
}
|
|
27965
27994
|
if (autoPull) {
|
|
27966
27995
|
const pullResult = await withTimeout(runGitCommand(["pull", "--rebase"]), TIMEOUT_MS, "git pull --rebase");
|
|
27967
27996
|
if (pullResult.exitCode !== 0) {
|
|
27968
|
-
throw new
|
|
27997
|
+
throw new HiveError(`Failed to pull: ${pullResult.stderr}`, "git pull --rebase", pullResult.exitCode);
|
|
27969
27998
|
}
|
|
27970
27999
|
}
|
|
27971
28000
|
const pushResult = await withTimeout(runGitCommand(["push"]), TIMEOUT_MS, "git push");
|
|
27972
28001
|
if (pushResult.exitCode !== 0) {
|
|
27973
|
-
throw new
|
|
28002
|
+
throw new HiveError(`Failed to push: ${pushResult.stderr}`, "git push", pushResult.exitCode);
|
|
27974
28003
|
}
|
|
27975
|
-
return "
|
|
28004
|
+
return "Hive synced and pushed successfully";
|
|
27976
28005
|
}
|
|
27977
28006
|
});
|
|
27978
|
-
var
|
|
27979
|
-
description: "Add metadata linking
|
|
28007
|
+
var hive_link_thread = tool({
|
|
28008
|
+
description: "Add metadata linking cell to Agent Mail thread",
|
|
27980
28009
|
args: {
|
|
27981
|
-
|
|
28010
|
+
cell_id: tool.schema.string().describe("Cell ID"),
|
|
27982
28011
|
thread_id: tool.schema.string().describe("Agent Mail thread ID")
|
|
27983
28012
|
},
|
|
27984
28013
|
async execute(args, ctx) {
|
|
27985
|
-
const projectKey =
|
|
27986
|
-
const adapter = await
|
|
28014
|
+
const projectKey = getHiveWorkingDirectory();
|
|
28015
|
+
const adapter = await getHiveAdapter(projectKey);
|
|
27987
28016
|
try {
|
|
27988
|
-
const
|
|
27989
|
-
if (!
|
|
27990
|
-
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");
|
|
27991
28020
|
}
|
|
27992
|
-
const existingDesc =
|
|
28021
|
+
const existingDesc = cell.description || "";
|
|
27993
28022
|
const threadMarker = `[thread:${args.thread_id}]`;
|
|
27994
28023
|
if (existingDesc.includes(threadMarker)) {
|
|
27995
|
-
return `
|
|
28024
|
+
return `Cell ${args.cell_id} already linked to thread ${args.thread_id}`;
|
|
27996
28025
|
}
|
|
27997
28026
|
const newDesc = existingDesc ? `${existingDesc}
|
|
27998
28027
|
|
|
27999
28028
|
${threadMarker}` : threadMarker;
|
|
28000
|
-
await adapter.
|
|
28029
|
+
await adapter.updateCell(projectKey, args.cell_id, {
|
|
28001
28030
|
description: newDesc
|
|
28002
28031
|
});
|
|
28003
|
-
await adapter.markDirty(projectKey, args.
|
|
28004
|
-
return `Linked
|
|
28032
|
+
await adapter.markDirty(projectKey, args.cell_id);
|
|
28033
|
+
return `Linked cell ${args.cell_id} to thread ${args.thread_id}`;
|
|
28005
28034
|
} catch (error45) {
|
|
28006
28035
|
const message = error45 instanceof Error ? error45.message : String(error45);
|
|
28007
|
-
throw new
|
|
28036
|
+
throw new HiveError(`Failed to link thread: ${message}`, "hive_link_thread");
|
|
28008
28037
|
}
|
|
28009
28038
|
}
|
|
28010
28039
|
});
|
|
28011
|
-
var
|
|
28012
|
-
|
|
28013
|
-
|
|
28014
|
-
|
|
28015
|
-
|
|
28016
|
-
|
|
28017
|
-
|
|
28018
|
-
|
|
28019
|
-
|
|
28020
|
-
|
|
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
|
|
28021
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
|
+
});
|
|
28022
28122
|
|
|
28023
28123
|
// src/agent-mail.ts
|
|
28024
28124
|
init_dist();
|
|
@@ -28137,6 +28237,29 @@ var toolCheckers = {
|
|
|
28137
28237
|
};
|
|
28138
28238
|
}
|
|
28139
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
|
+
},
|
|
28140
28263
|
beads: async () => {
|
|
28141
28264
|
const exists = await commandExists("bd");
|
|
28142
28265
|
if (!exists) {
|
|
@@ -28190,7 +28313,8 @@ var fallbackBehaviors = {
|
|
|
28190
28313
|
"semantic-memory": "Learning data stored in-memory only (lost on session end)",
|
|
28191
28314
|
cass: "Decomposition proceeds without historical context from past sessions",
|
|
28192
28315
|
ubs: "Subtask completion skips bug scanning - manual review recommended",
|
|
28193
|
-
|
|
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",
|
|
28194
28318
|
"swarm-mail": "Multi-agent coordination disabled - file conflicts possible if multiple agents active",
|
|
28195
28319
|
"agent-mail": "DEPRECATED: Use swarm-mail instead. Legacy MCP server mode - file conflicts possible if multiple agents active"
|
|
28196
28320
|
};
|
|
@@ -28221,6 +28345,7 @@ async function checkAllTools() {
|
|
|
28221
28345
|
"semantic-memory",
|
|
28222
28346
|
"cass",
|
|
28223
28347
|
"ubs",
|
|
28348
|
+
"hive",
|
|
28224
28349
|
"beads",
|
|
28225
28350
|
"swarm-mail",
|
|
28226
28351
|
"agent-mail"
|
|
@@ -28257,8 +28382,8 @@ function formatToolAvailability(availability) {
|
|
|
28257
28382
|
|
|
28258
28383
|
// src/rate-limiter.ts
|
|
28259
28384
|
var import_ioredis = __toESM(require_built3(), 1);
|
|
28260
|
-
import { mkdirSync, existsSync } from "node:fs";
|
|
28261
|
-
import { dirname, join } from "node:path";
|
|
28385
|
+
import { mkdirSync, existsSync as existsSync2 } from "node:fs";
|
|
28386
|
+
import { dirname, join as join2 } from "node:path";
|
|
28262
28387
|
import { homedir } from "node:os";
|
|
28263
28388
|
var sqliteAvailable = false;
|
|
28264
28389
|
var createDatabase = null;
|
|
@@ -28374,7 +28499,7 @@ class SqliteRateLimiter {
|
|
|
28374
28499
|
throw new Error("SQLite is not available in this runtime (requires Bun)");
|
|
28375
28500
|
}
|
|
28376
28501
|
const dir = dirname(dbPath);
|
|
28377
|
-
if (!
|
|
28502
|
+
if (!existsSync2(dir)) {
|
|
28378
28503
|
mkdirSync(dir, { recursive: true });
|
|
28379
28504
|
}
|
|
28380
28505
|
this.db = createDatabase(dbPath);
|
|
@@ -28519,7 +28644,7 @@ async function createRateLimiter(options2) {
|
|
|
28519
28644
|
const {
|
|
28520
28645
|
backend,
|
|
28521
28646
|
redisUrl = process.env.OPENCODE_RATE_LIMIT_REDIS_URL || "redis://localhost:6379",
|
|
28522
|
-
sqlitePath = process.env.OPENCODE_RATE_LIMIT_SQLITE_PATH ||
|
|
28647
|
+
sqlitePath = process.env.OPENCODE_RATE_LIMIT_SQLITE_PATH || join2(homedir(), ".config", "opencode", "rate-limits.db")
|
|
28523
28648
|
} = options2 || {};
|
|
28524
28649
|
if (backend === "memory") {
|
|
28525
28650
|
return new InMemoryRateLimiter;
|
|
@@ -28579,13 +28704,13 @@ async function getRateLimiter() {
|
|
|
28579
28704
|
|
|
28580
28705
|
// src/agent-mail.ts
|
|
28581
28706
|
import {
|
|
28582
|
-
existsSync as
|
|
28707
|
+
existsSync as existsSync3,
|
|
28583
28708
|
mkdirSync as mkdirSync2,
|
|
28584
|
-
readFileSync,
|
|
28709
|
+
readFileSync as readFileSync2,
|
|
28585
28710
|
writeFileSync,
|
|
28586
28711
|
unlinkSync
|
|
28587
28712
|
} from "fs";
|
|
28588
|
-
import { join as
|
|
28713
|
+
import { join as join3 } from "path";
|
|
28589
28714
|
import { tmpdir } from "os";
|
|
28590
28715
|
var AGENT_MAIL_URL = "http://127.0.0.1:8765";
|
|
28591
28716
|
var DEFAULT_TTL_SECONDS = 3600;
|
|
@@ -28609,16 +28734,16 @@ var RECOVERY_CONFIG = {
|
|
|
28609
28734
|
restartCooldownMs: 1e4,
|
|
28610
28735
|
enabled: process.env.OPENCODE_AGENT_MAIL_AUTO_RESTART !== "false"
|
|
28611
28736
|
};
|
|
28612
|
-
var SESSION_STATE_DIR = process.env.SWARM_STATE_DIR ||
|
|
28737
|
+
var SESSION_STATE_DIR = process.env.SWARM_STATE_DIR || join3(tmpdir(), "swarm-sessions");
|
|
28613
28738
|
function getSessionStatePath(sessionID) {
|
|
28614
28739
|
const safeID = sessionID.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
28615
|
-
return
|
|
28740
|
+
return join3(SESSION_STATE_DIR, `${safeID}.json`);
|
|
28616
28741
|
}
|
|
28617
28742
|
function loadSessionState(sessionID) {
|
|
28618
28743
|
const path = getSessionStatePath(sessionID);
|
|
28619
28744
|
try {
|
|
28620
|
-
if (
|
|
28621
|
-
const data =
|
|
28745
|
+
if (existsSync3(path)) {
|
|
28746
|
+
const data = readFileSync2(path, "utf-8");
|
|
28622
28747
|
return JSON.parse(data);
|
|
28623
28748
|
}
|
|
28624
28749
|
} catch (error45) {
|
|
@@ -28628,7 +28753,7 @@ function loadSessionState(sessionID) {
|
|
|
28628
28753
|
}
|
|
28629
28754
|
function saveSessionState(sessionID, state) {
|
|
28630
28755
|
try {
|
|
28631
|
-
if (!
|
|
28756
|
+
if (!existsSync3(SESSION_STATE_DIR)) {
|
|
28632
28757
|
mkdirSync2(SESSION_STATE_DIR, { recursive: true });
|
|
28633
28758
|
}
|
|
28634
28759
|
const path = getSessionStatePath(sessionID);
|
|
@@ -29316,13 +29441,13 @@ import {
|
|
|
29316
29441
|
getActiveReservations
|
|
29317
29442
|
} from "swarm-mail";
|
|
29318
29443
|
import {
|
|
29319
|
-
existsSync as
|
|
29444
|
+
existsSync as existsSync4,
|
|
29320
29445
|
mkdirSync as mkdirSync3,
|
|
29321
|
-
readFileSync as
|
|
29446
|
+
readFileSync as readFileSync3,
|
|
29322
29447
|
writeFileSync as writeFileSync2,
|
|
29323
29448
|
unlinkSync as unlinkSync2
|
|
29324
29449
|
} from "node:fs";
|
|
29325
|
-
import { join as
|
|
29450
|
+
import { join as join4 } from "node:path";
|
|
29326
29451
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
29327
29452
|
var MAX_INBOX_LIMIT2 = 5;
|
|
29328
29453
|
var swarmMailProjectDirectory = null;
|
|
@@ -29332,16 +29457,16 @@ function setSwarmMailProjectDirectory(directory) {
|
|
|
29332
29457
|
function getSwarmMailProjectDirectory() {
|
|
29333
29458
|
return swarmMailProjectDirectory ?? undefined;
|
|
29334
29459
|
}
|
|
29335
|
-
var SESSION_STATE_DIR2 = process.env.SWARM_STATE_DIR ||
|
|
29460
|
+
var SESSION_STATE_DIR2 = process.env.SWARM_STATE_DIR || join4(tmpdir2(), "swarm-sessions");
|
|
29336
29461
|
function getSessionStatePath2(sessionID) {
|
|
29337
29462
|
const safeID = sessionID.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
29338
|
-
return
|
|
29463
|
+
return join4(SESSION_STATE_DIR2, `${safeID}.json`);
|
|
29339
29464
|
}
|
|
29340
29465
|
function loadSessionState2(sessionID) {
|
|
29341
29466
|
const path = getSessionStatePath2(sessionID);
|
|
29342
29467
|
try {
|
|
29343
|
-
if (
|
|
29344
|
-
const data =
|
|
29468
|
+
if (existsSync4(path)) {
|
|
29469
|
+
const data = readFileSync3(path, "utf-8");
|
|
29345
29470
|
return JSON.parse(data);
|
|
29346
29471
|
}
|
|
29347
29472
|
} catch (error45) {
|
|
@@ -29351,7 +29476,7 @@ function loadSessionState2(sessionID) {
|
|
|
29351
29476
|
}
|
|
29352
29477
|
function saveSessionState2(sessionID, state) {
|
|
29353
29478
|
try {
|
|
29354
|
-
if (!
|
|
29479
|
+
if (!existsSync4(SESSION_STATE_DIR2)) {
|
|
29355
29480
|
mkdirSync3(SESSION_STATE_DIR2, { recursive: true });
|
|
29356
29481
|
}
|
|
29357
29482
|
const path = getSessionStatePath2(sessionID);
|
|
@@ -29695,7 +29820,7 @@ function formatZodErrors(error45) {
|
|
|
29695
29820
|
var SCHEMA_REGISTRY = {
|
|
29696
29821
|
evaluation: EvaluationSchema,
|
|
29697
29822
|
task_decomposition: TaskDecompositionSchema,
|
|
29698
|
-
|
|
29823
|
+
cell_tree: CellTreeSchema
|
|
29699
29824
|
};
|
|
29700
29825
|
function getSchemaByName(name) {
|
|
29701
29826
|
const schema = SCHEMA_REGISTRY[name];
|
|
@@ -29831,7 +29956,7 @@ var structured_validate = tool({
|
|
|
29831
29956
|
description: "Validate agent response against a schema. Extracts JSON and validates with Zod. Returns structured errors for retry feedback.",
|
|
29832
29957
|
args: {
|
|
29833
29958
|
response: tool.schema.string().describe("Agent response to validate"),
|
|
29834
|
-
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"),
|
|
29835
29960
|
max_retries: tool.schema.number().min(1).max(5).optional().describe("Max retries (for tracking - actual retry logic is external)")
|
|
29836
29961
|
},
|
|
29837
29962
|
async execute(args, ctx) {
|
|
@@ -30017,15 +30142,15 @@ var structured_parse_decomposition = tool({
|
|
|
30017
30142
|
}
|
|
30018
30143
|
}
|
|
30019
30144
|
});
|
|
30020
|
-
var
|
|
30021
|
-
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.",
|
|
30022
30147
|
args: {
|
|
30023
30148
|
response: tool.schema.string().describe("Agent response containing bead tree")
|
|
30024
30149
|
},
|
|
30025
30150
|
async execute(args, ctx) {
|
|
30026
30151
|
try {
|
|
30027
30152
|
const [extracted, method] = extractJsonFromText(args.response);
|
|
30028
|
-
const validated =
|
|
30153
|
+
const validated = CellTreeSchema.parse(extracted);
|
|
30029
30154
|
const allFiles = validated.subtasks.flatMap((s) => s.files);
|
|
30030
30155
|
const uniqueFiles = [...new Set(allFiles)];
|
|
30031
30156
|
return JSON.stringify({
|
|
@@ -30084,7 +30209,7 @@ var structuredTools = {
|
|
|
30084
30209
|
structured_validate,
|
|
30085
30210
|
structured_parse_evaluation,
|
|
30086
30211
|
structured_parse_decomposition,
|
|
30087
|
-
|
|
30212
|
+
structured_parse_cell_tree
|
|
30088
30213
|
};
|
|
30089
30214
|
|
|
30090
30215
|
// src/swarm.ts
|
|
@@ -30107,9 +30232,9 @@ var DECOMPOSITION_PROMPT = `You are decomposing a task into parallelizable subta
|
|
|
30107
30232
|
|
|
30108
30233
|
After decomposition, the coordinator will:
|
|
30109
30234
|
1. Create an epic bead for the overall task
|
|
30110
|
-
2. Create child
|
|
30235
|
+
2. Create child cells for each subtask
|
|
30111
30236
|
3. Track progress through bead status updates
|
|
30112
|
-
4. Close
|
|
30237
|
+
4. Close cells with summaries when complete
|
|
30113
30238
|
|
|
30114
30239
|
Agents MUST update their bead status as they work. No silent progress.
|
|
30115
30240
|
|
|
@@ -30129,7 +30254,7 @@ Respond with a JSON object matching this schema:
|
|
|
30129
30254
|
\`\`\`typescript
|
|
30130
30255
|
{
|
|
30131
30256
|
epic: {
|
|
30132
|
-
title: string, // Epic title for the
|
|
30257
|
+
title: string, // Epic title for the hive tracker
|
|
30133
30258
|
description?: string // Brief description of the overall goal
|
|
30134
30259
|
},
|
|
30135
30260
|
subtasks: [
|
|
@@ -30180,9 +30305,9 @@ var STRATEGY_DECOMPOSITION_PROMPT = `You are decomposing a task into paralleliza
|
|
|
30180
30305
|
|
|
30181
30306
|
After decomposition, the coordinator will:
|
|
30182
30307
|
1. Create an epic bead for the overall task
|
|
30183
|
-
2. Create child
|
|
30308
|
+
2. Create child cells for each subtask
|
|
30184
30309
|
3. Track progress through bead status updates
|
|
30185
|
-
4. Close
|
|
30310
|
+
4. Close cells with summaries when complete
|
|
30186
30311
|
|
|
30187
30312
|
Agents MUST update their bead status as they work. No silent progress.
|
|
30188
30313
|
|
|
@@ -30202,7 +30327,7 @@ Respond with a JSON object matching this schema:
|
|
|
30202
30327
|
\`\`\`typescript
|
|
30203
30328
|
{
|
|
30204
30329
|
epic: {
|
|
30205
|
-
title: string, // Epic title for the
|
|
30330
|
+
title: string, // Epic title for the hive tracker
|
|
30206
30331
|
description?: string // Brief description of the overall goal
|
|
30207
30332
|
},
|
|
30208
30333
|
subtasks: [
|
|
@@ -30392,7 +30517,7 @@ ${fullContext}` : `## Additional Context
|
|
|
30392
30517
|
const prompt = DECOMPOSITION_PROMPT.replace("{task}", args.task).replace("{max_subtasks}", (args.max_subtasks ?? 5).toString()).replace("{context_section}", contextSection);
|
|
30393
30518
|
return JSON.stringify({
|
|
30394
30519
|
prompt,
|
|
30395
|
-
expected_schema: "
|
|
30520
|
+
expected_schema: "CellTree",
|
|
30396
30521
|
schema_hint: {
|
|
30397
30522
|
epic: { title: "string", description: "string?" },
|
|
30398
30523
|
subtasks: [
|
|
@@ -30405,21 +30530,21 @@ ${fullContext}` : `## Additional Context
|
|
|
30405
30530
|
}
|
|
30406
30531
|
]
|
|
30407
30532
|
},
|
|
30408
|
-
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",
|
|
30409
30534
|
cass_history: cassResultInfo,
|
|
30410
30535
|
memory_query: formatMemoryQueryForDecomposition2(args.task, 3)
|
|
30411
30536
|
}, null, 2);
|
|
30412
30537
|
}
|
|
30413
30538
|
});
|
|
30414
30539
|
var swarm_validate_decomposition = tool({
|
|
30415
|
-
description: "Validate a decomposition response against
|
|
30540
|
+
description: "Validate a decomposition response against CellTreeSchema",
|
|
30416
30541
|
args: {
|
|
30417
|
-
response: tool.schema.string().describe("JSON response from agent (
|
|
30542
|
+
response: tool.schema.string().describe("JSON response from agent (CellTree format)")
|
|
30418
30543
|
},
|
|
30419
30544
|
async execute(args) {
|
|
30420
30545
|
try {
|
|
30421
30546
|
const parsed = JSON.parse(args.response);
|
|
30422
|
-
const validated =
|
|
30547
|
+
const validated = CellTreeSchema.parse(parsed);
|
|
30423
30548
|
const conflicts = detectFileConflicts(validated.subtasks);
|
|
30424
30549
|
if (conflicts.length > 0) {
|
|
30425
30550
|
return JSON.stringify({
|
|
@@ -30450,7 +30575,7 @@ var swarm_validate_decomposition = tool({
|
|
|
30450
30575
|
const instructionConflicts = detectInstructionConflicts(validated.subtasks);
|
|
30451
30576
|
return JSON.stringify({
|
|
30452
30577
|
valid: true,
|
|
30453
|
-
|
|
30578
|
+
cell_tree: validated,
|
|
30454
30579
|
stats: {
|
|
30455
30580
|
subtask_count: validated.subtasks.length,
|
|
30456
30581
|
total_files: new Set(validated.subtasks.flatMap((s) => s.files)).size,
|
|
@@ -30552,7 +30677,7 @@ ${args.context}` : `## Additional Context
|
|
|
30552
30677
|
const subagentInstructions = `
|
|
30553
30678
|
## CRITICAL: Output Format
|
|
30554
30679
|
|
|
30555
|
-
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.
|
|
30556
30681
|
|
|
30557
30682
|
DO NOT include:
|
|
30558
30683
|
- Explanatory text before or after the JSON
|
|
@@ -30586,7 +30711,7 @@ OUTPUT ONLY the raw JSON object.
|
|
|
30586
30711
|
]
|
|
30587
30712
|
}
|
|
30588
30713
|
|
|
30589
|
-
Now generate the
|
|
30714
|
+
Now generate the CellTree for the given task.`;
|
|
30590
30715
|
const fullPrompt = `${planningPrompt}
|
|
30591
30716
|
|
|
30592
30717
|
${subagentInstructions}`;
|
|
@@ -30598,12 +30723,12 @@ ${subagentInstructions}`;
|
|
|
30598
30723
|
selected: selectedStrategy,
|
|
30599
30724
|
reasoning: strategyReasoning
|
|
30600
30725
|
},
|
|
30601
|
-
expected_output: "
|
|
30726
|
+
expected_output: "CellTree JSON (raw JSON, no markdown)",
|
|
30602
30727
|
next_steps: [
|
|
30603
30728
|
"1. Spawn subagent with Task tool using returned prompt",
|
|
30604
30729
|
"2. Parse subagent response as JSON",
|
|
30605
30730
|
"3. Validate with swarm_validate_decomposition",
|
|
30606
|
-
"4. Create
|
|
30731
|
+
"4. Create cells with hive_create_epic"
|
|
30607
30732
|
],
|
|
30608
30733
|
cass_history: cassResultInfo,
|
|
30609
30734
|
skills: skillsInfo,
|
|
@@ -30843,17 +30968,17 @@ var STRATEGY_DECOMPOSITION_PROMPT2 = `You are decomposing a task into paralleliz
|
|
|
30843
30968
|
|
|
30844
30969
|
{skills_context}
|
|
30845
30970
|
|
|
30846
|
-
## MANDATORY:
|
|
30971
|
+
## MANDATORY: Hive Issue Tracking
|
|
30847
30972
|
|
|
30848
|
-
**Every subtask MUST become a
|
|
30973
|
+
**Every subtask MUST become a cell.** This is non-negotiable.
|
|
30849
30974
|
|
|
30850
30975
|
After decomposition, the coordinator will:
|
|
30851
|
-
1. Create an epic
|
|
30852
|
-
2. Create child
|
|
30853
|
-
3. Track progress through
|
|
30854
|
-
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
|
|
30855
30980
|
|
|
30856
|
-
Agents MUST update their
|
|
30981
|
+
Agents MUST update their cell status as they work. No silent progress.
|
|
30857
30982
|
|
|
30858
30983
|
## Requirements
|
|
30859
30984
|
|
|
@@ -30871,7 +30996,7 @@ Respond with a JSON object matching this schema:
|
|
|
30871
30996
|
\`\`\`typescript
|
|
30872
30997
|
{
|
|
30873
30998
|
epic: {
|
|
30874
|
-
title: string, // Epic title for the
|
|
30999
|
+
title: string, // Epic title for the hive tracker
|
|
30875
31000
|
description?: string // Brief description of the overall goal
|
|
30876
31001
|
},
|
|
30877
31002
|
subtasks: [
|
|
@@ -30892,7 +31017,7 @@ var SUBTASK_PROMPT = `You are a swarm agent working on a subtask of a larger epi
|
|
|
30892
31017
|
|
|
30893
31018
|
## Your Identity
|
|
30894
31019
|
- **Agent Name**: {agent_name}
|
|
30895
|
-
- **
|
|
31020
|
+
- **Cell ID**: {bead_id}
|
|
30896
31021
|
- **Epic ID**: {epic_id}
|
|
30897
31022
|
|
|
30898
31023
|
## Your Subtask
|
|
@@ -30910,16 +31035,16 @@ send a message to the coordinator requesting the change.
|
|
|
30910
31035
|
## Shared Context
|
|
30911
31036
|
{shared_context}
|
|
30912
31037
|
|
|
30913
|
-
## MANDATORY:
|
|
31038
|
+
## MANDATORY: Hive Tracking
|
|
30914
31039
|
|
|
30915
|
-
You MUST keep your
|
|
31040
|
+
You MUST keep your cell updated as you work:
|
|
30916
31041
|
|
|
30917
|
-
1. **Your
|
|
30918
|
-
2. **If blocked**: \`
|
|
30919
|
-
3. **When done**: Use \`swarm_complete\` - it closes your
|
|
30920
|
-
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\`
|
|
30921
31046
|
|
|
30922
|
-
**Never work silently.** Your
|
|
31047
|
+
**Never work silently.** Your cell status is how the swarm tracks progress.
|
|
30923
31048
|
|
|
30924
31049
|
## MANDATORY: Swarm Mail Communication
|
|
30925
31050
|
|
|
@@ -30942,11 +31067,11 @@ swarmmail_send(
|
|
|
30942
31067
|
|
|
30943
31068
|
## Coordination Protocol
|
|
30944
31069
|
|
|
30945
|
-
1. **Start**: Your
|
|
31070
|
+
1. **Start**: Your cell is already marked in_progress
|
|
30946
31071
|
2. **Progress**: Use swarm_progress to report status updates
|
|
30947
31072
|
3. **Blocked**: Report immediately via Swarm Mail - don't spin
|
|
30948
31073
|
4. **Complete**: Use swarm_complete when done - it handles:
|
|
30949
|
-
- Closing your
|
|
31074
|
+
- Closing your cell with a summary
|
|
30950
31075
|
- Releasing file reservations
|
|
30951
31076
|
- Notifying the coordinator
|
|
30952
31077
|
|
|
@@ -30973,7 +31098,7 @@ var SUBTASK_PROMPT_V2 = `You are a swarm agent working on: **{subtask_title}**
|
|
|
30973
31098
|
|
|
30974
31099
|
## [IDENTITY]
|
|
30975
31100
|
Agent: (assigned at spawn)
|
|
30976
|
-
|
|
31101
|
+
Cell: {bead_id}
|
|
30977
31102
|
Epic: {epic_id}
|
|
30978
31103
|
|
|
30979
31104
|
## [TASK]
|
|
@@ -31117,7 +31242,7 @@ swarm_complete(
|
|
|
31117
31242
|
- Records learning signals
|
|
31118
31243
|
- Notifies coordinator
|
|
31119
31244
|
|
|
31120
|
-
**DO NOT manually close the
|
|
31245
|
+
**DO NOT manually close the cell with hive_close.** Use swarm_complete.
|
|
31121
31246
|
|
|
31122
31247
|
## [SWARM MAIL COMMUNICATION]
|
|
31123
31248
|
|
|
@@ -31136,7 +31261,7 @@ swarmmail_send(
|
|
|
31136
31261
|
importance="high",
|
|
31137
31262
|
thread_id="{epic_id}"
|
|
31138
31263
|
)
|
|
31139
|
-
|
|
31264
|
+
hive_update(id="{bead_id}", status="blocked")
|
|
31140
31265
|
\`\`\`
|
|
31141
31266
|
|
|
31142
31267
|
### Report Issues to Other Agents
|
|
@@ -31157,15 +31282,15 @@ swarmmail_release() # Manually release reservations
|
|
|
31157
31282
|
**Note:** \`swarm_complete\` automatically releases reservations. Only use manual release if aborting work.
|
|
31158
31283
|
|
|
31159
31284
|
## [OTHER TOOLS]
|
|
31160
|
-
###
|
|
31161
|
-
You can create new
|
|
31285
|
+
### Hive - You Have Autonomy to File Issues
|
|
31286
|
+
You can create new cells against this epic when you discover:
|
|
31162
31287
|
- **Bugs**: Found a bug while working? File it.
|
|
31163
31288
|
- **Tech debt**: Spotted something that needs cleanup? File it.
|
|
31164
31289
|
- **Follow-up work**: Task needs more work than scoped? File a follow-up.
|
|
31165
31290
|
- **Dependencies**: Need something from another agent? File and link it.
|
|
31166
31291
|
|
|
31167
31292
|
\`\`\`
|
|
31168
|
-
|
|
31293
|
+
hive_create(
|
|
31169
31294
|
title="<descriptive title>",
|
|
31170
31295
|
type="bug", # or "task", "chore"
|
|
31171
31296
|
priority=2,
|
|
@@ -31176,9 +31301,9 @@ beads_create(
|
|
|
31176
31301
|
|
|
31177
31302
|
**Don't silently ignore issues.** File them so they get tracked and addressed.
|
|
31178
31303
|
|
|
31179
|
-
Other
|
|
31180
|
-
-
|
|
31181
|
-
-
|
|
31304
|
+
Other cell operations:
|
|
31305
|
+
- hive_update(id, status) - Mark blocked if stuck
|
|
31306
|
+
- hive_query(status="open") - See what else needs work
|
|
31182
31307
|
|
|
31183
31308
|
### Skills
|
|
31184
31309
|
- skills_list() - Discover available skills
|
|
@@ -31192,7 +31317,7 @@ Other bead operations:
|
|
|
31192
31317
|
2. Step 2 (semantic-memory_find) MUST happen before starting work
|
|
31193
31318
|
3. Step 4 (swarmmail_reserve) - YOU reserve files, not coordinator
|
|
31194
31319
|
4. Step 6 (swarm_progress) - Report at milestones, don't work silently
|
|
31195
|
-
5. Step 9 (swarm_complete) - Use this to close, NOT
|
|
31320
|
+
5. Step 9 (swarm_complete) - Use this to close, NOT hive_close
|
|
31196
31321
|
|
|
31197
31322
|
**If you skip these steps:**
|
|
31198
31323
|
- Your work won't be tracked (swarm_complete will fail)
|
|
@@ -31205,7 +31330,7 @@ Begin now.`;
|
|
|
31205
31330
|
var EVALUATION_PROMPT = `Evaluate the work completed for this subtask.
|
|
31206
31331
|
|
|
31207
31332
|
## Subtask
|
|
31208
|
-
**
|
|
31333
|
+
**Cell ID**: {bead_id}
|
|
31209
31334
|
**Title**: {subtask_title}
|
|
31210
31335
|
|
|
31211
31336
|
## Files Modified
|
|
@@ -31307,7 +31432,7 @@ var swarm_subtask_prompt = tool({
|
|
|
31307
31432
|
}
|
|
31308
31433
|
});
|
|
31309
31434
|
var swarm_spawn_subtask = tool({
|
|
31310
|
-
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.",
|
|
31311
31436
|
args: {
|
|
31312
31437
|
bead_id: tool.schema.string().describe("Subtask bead ID"),
|
|
31313
31438
|
epic_id: tool.schema.string().describe("Parent epic bead ID"),
|
|
@@ -31432,7 +31557,7 @@ ${args.context}` : `## Additional Context
|
|
|
31432
31557
|
guidelines: STRATEGIES2[selectedStrategy].guidelines,
|
|
31433
31558
|
anti_patterns: STRATEGIES2[selectedStrategy].antiPatterns
|
|
31434
31559
|
},
|
|
31435
|
-
expected_schema: "
|
|
31560
|
+
expected_schema: "CellTree",
|
|
31436
31561
|
schema_hint: {
|
|
31437
31562
|
epic: { title: "string", description: "string?" },
|
|
31438
31563
|
subtasks: [
|
|
@@ -31464,12 +31589,672 @@ init_learning();
|
|
|
31464
31589
|
import {
|
|
31465
31590
|
getSwarmInbox as getSwarmInbox2,
|
|
31466
31591
|
releaseSwarmFiles as releaseSwarmFiles2,
|
|
31467
|
-
sendSwarmMessage as
|
|
31592
|
+
sendSwarmMessage as sendSwarmMessage3,
|
|
31468
31593
|
getAgent,
|
|
31469
31594
|
createEvent as createEvent2,
|
|
31470
31595
|
appendEvent as appendEvent2
|
|
31471
31596
|
} from "swarm-mail";
|
|
31472
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
|
|
31473
32258
|
async function queryEpicSubtasks(epicId) {
|
|
31474
32259
|
const beadsAvailable = await isToolAvailable("beads");
|
|
31475
32260
|
if (!beadsAvailable) {
|
|
@@ -31739,7 +32524,8 @@ var globalStrikeStorage = new InMemoryStrikeStorage;
|
|
|
31739
32524
|
var swarm_init = tool({
|
|
31740
32525
|
description: "Initialize swarm session: discovers available skills, checks tool availability. ALWAYS call at swarm start.",
|
|
31741
32526
|
args: {
|
|
31742
|
-
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)")
|
|
31743
32529
|
},
|
|
31744
32530
|
async execute(args) {
|
|
31745
32531
|
const availability = await checkAllTools();
|
|
@@ -31781,8 +32567,39 @@ var swarm_init = tool({
|
|
|
31781
32567
|
} else {
|
|
31782
32568
|
skillsGuidance = "No skills found. Add skills to .opencode/skills/ or .claude/skills/ for specialized guidance.";
|
|
31783
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
|
+
}
|
|
31784
32600
|
return JSON.stringify({
|
|
31785
32601
|
ready: true,
|
|
32602
|
+
isolation: isolationInfo,
|
|
31786
32603
|
tool_availability: Object.fromEntries(Array.from(availability.entries()).map(([k, v]) => [
|
|
31787
32604
|
k,
|
|
31788
32605
|
{
|
|
@@ -31796,7 +32613,8 @@ var swarm_init = tool({
|
|
|
31796
32613
|
recommendations: {
|
|
31797
32614
|
skills: skillsGuidance,
|
|
31798
32615
|
beads: beadsAvailable ? "✓ Use beads for all task tracking" : "Install beads: npm i -g @joelhooks/beads",
|
|
31799
|
-
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"
|
|
31800
32618
|
},
|
|
31801
32619
|
report
|
|
31802
32620
|
}, null, 2);
|
|
@@ -31888,7 +32706,7 @@ var swarm_progress = tool({
|
|
|
31888
32706
|
await Bun.$`bd update ${args.bead_id} --status ${beadStatus} --json`.quiet().nothrow();
|
|
31889
32707
|
}
|
|
31890
32708
|
const epicId = args.bead_id.includes(".") ? args.bead_id.split(".")[0] : args.bead_id;
|
|
31891
|
-
await
|
|
32709
|
+
await sendSwarmMessage3({
|
|
31892
32710
|
projectPath: args.project_key,
|
|
31893
32711
|
fromAgent: args.agent_name,
|
|
31894
32712
|
toAgents: [],
|
|
@@ -31956,7 +32774,7 @@ ${args.files_affected.map((f) => `- \`${f}\``).join(`
|
|
|
31956
32774
|
].filter(Boolean).join(`
|
|
31957
32775
|
`);
|
|
31958
32776
|
const mailImportance = args.importance === "blocker" ? "urgent" : args.importance === "warning" ? "high" : "normal";
|
|
31959
|
-
await
|
|
32777
|
+
await sendSwarmMessage3({
|
|
31960
32778
|
projectPath: args.project_path,
|
|
31961
32779
|
fromAgent: args.agent_name,
|
|
31962
32780
|
toAgents: [],
|
|
@@ -31991,10 +32809,42 @@ var swarm_complete = tool({
|
|
|
31991
32809
|
planned_files: tool.schema.array(tool.schema.string()).optional().describe("Files that were originally planned to be modified"),
|
|
31992
32810
|
start_time: tool.schema.number().optional().describe("Task start timestamp (Unix ms) for duration calculation"),
|
|
31993
32811
|
error_count: tool.schema.number().optional().describe("Number of errors encountered during task"),
|
|
31994
|
-
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.")
|
|
31995
32814
|
},
|
|
31996
32815
|
async execute(args, _ctx) {
|
|
31997
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
|
+
}
|
|
31998
32848
|
try {
|
|
31999
32849
|
const projectKey = args.project_key.replace(/\//g, "-").replace(/\\/g, "-");
|
|
32000
32850
|
let agentRegistered = false;
|
|
@@ -32089,7 +32939,7 @@ Continuing with completion, but this should be fixed for future subtasks.`;
|
|
|
32089
32939
|
const isNotFoundError = stderrOutput.includes("not found") || stderrOutput.includes("does not exist");
|
|
32090
32940
|
return JSON.stringify({
|
|
32091
32941
|
success: false,
|
|
32092
|
-
error: "Failed to close
|
|
32942
|
+
error: "Failed to close cell",
|
|
32093
32943
|
failed_step: "bd close",
|
|
32094
32944
|
details: stderrOutput || stdoutOutput || "Unknown error from bd close command",
|
|
32095
32945
|
bead_id: args.bead_id,
|
|
@@ -32098,15 +32948,15 @@ Continuing with completion, but this should be fixed for future subtasks.`;
|
|
|
32098
32948
|
steps: isNoDatabaseError ? [
|
|
32099
32949
|
`1. Verify project_key is correct: "${args.project_key}"`,
|
|
32100
32950
|
`2. Check .beads/ exists in that directory`,
|
|
32101
|
-
`3.
|
|
32102
|
-
`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="...")`
|
|
32103
32953
|
] : [
|
|
32104
|
-
`1. Check
|
|
32105
|
-
`2. Check
|
|
32106
|
-
`3. If
|
|
32107
|
-
`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="...")`
|
|
32108
32958
|
],
|
|
32109
|
-
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."
|
|
32110
32960
|
}
|
|
32111
32961
|
}, null, 2);
|
|
32112
32962
|
}
|
|
@@ -32174,7 +33024,7 @@ Continuing with completion, but this should be fixed for future subtasks.`;
|
|
|
32174
33024
|
let messageSent = false;
|
|
32175
33025
|
let messageError;
|
|
32176
33026
|
try {
|
|
32177
|
-
await
|
|
33027
|
+
await sendSwarmMessage3({
|
|
32178
33028
|
projectPath: args.project_key,
|
|
32179
33029
|
fromAgent: args.agent_name,
|
|
32180
33030
|
toAgents: [],
|
|
@@ -32284,14 +33134,14 @@ ${errorStack.slice(0, 1000)}
|
|
|
32284
33134
|
"",
|
|
32285
33135
|
`### Recovery Actions`,
|
|
32286
33136
|
"1. Check error message for specific issue",
|
|
32287
|
-
"2. Review failed step (UBS scan, typecheck,
|
|
33137
|
+
"2. Review failed step (UBS scan, typecheck, cell close, etc.)",
|
|
32288
33138
|
"3. Fix underlying issue or use skip flags if appropriate",
|
|
32289
33139
|
"4. Retry swarm_complete after fixing"
|
|
32290
33140
|
].filter(Boolean).join(`
|
|
32291
33141
|
`);
|
|
32292
33142
|
let notificationSent = false;
|
|
32293
33143
|
try {
|
|
32294
|
-
await
|
|
33144
|
+
await sendSwarmMessage3({
|
|
32295
33145
|
projectPath: args.project_key,
|
|
32296
33146
|
fromAgent: args.agent_name,
|
|
32297
33147
|
toAgents: [],
|
|
@@ -32329,7 +33179,7 @@ ${errorStack.slice(0, 1000)}
|
|
|
32329
33179
|
common_fixes: {
|
|
32330
33180
|
"Verification Gate": "Use skip_verification=true to bypass (not recommended)",
|
|
32331
33181
|
"UBS scan": "Use skip_ubs_scan=true to bypass",
|
|
32332
|
-
"
|
|
33182
|
+
"Cell close": "Check cell status with hive_query(), may need hive_update() first",
|
|
32333
33183
|
"Self-evaluation": "Check evaluation JSON format matches EvaluationSchema"
|
|
32334
33184
|
}
|
|
32335
33185
|
}
|
|
@@ -32428,7 +33278,7 @@ var swarm_record_outcome = tool({
|
|
|
32428
33278
|
var swarm_accumulate_error = tool({
|
|
32429
33279
|
description: "Record an error during subtask execution. Errors feed into retry prompts.",
|
|
32430
33280
|
args: {
|
|
32431
|
-
bead_id: tool.schema.string().describe("
|
|
33281
|
+
bead_id: tool.schema.string().describe("Cell ID where error occurred"),
|
|
32432
33282
|
error_type: tool.schema.enum(["validation", "timeout", "conflict", "tool_failure", "unknown"]).describe("Category of error"),
|
|
32433
33283
|
message: tool.schema.string().describe("Human-readable error message"),
|
|
32434
33284
|
stack_trace: tool.schema.string().optional().describe("Stack trace for debugging"),
|
|
@@ -32455,7 +33305,7 @@ var swarm_accumulate_error = tool({
|
|
|
32455
33305
|
var swarm_get_error_context = tool({
|
|
32456
33306
|
description: "Get accumulated errors for a bead. Returns formatted context for retry prompts.",
|
|
32457
33307
|
args: {
|
|
32458
|
-
bead_id: tool.schema.string().describe("
|
|
33308
|
+
bead_id: tool.schema.string().describe("Cell ID to get errors for"),
|
|
32459
33309
|
include_resolved: tool.schema.boolean().optional().describe("Include resolved errors (default: false)")
|
|
32460
33310
|
},
|
|
32461
33311
|
async execute(args) {
|
|
@@ -32491,7 +33341,7 @@ var swarm_resolve_error = tool({
|
|
|
32491
33341
|
var swarm_check_strikes = tool({
|
|
32492
33342
|
description: "Check 3-strike status for a bead. Records failures, detects architectural problems, generates architecture review prompts.",
|
|
32493
33343
|
args: {
|
|
32494
|
-
bead_id: tool.schema.string().describe("
|
|
33344
|
+
bead_id: tool.schema.string().describe("Cell ID to check"),
|
|
32495
33345
|
action: tool.schema.enum(["check", "add_strike", "clear", "get_prompt"]).describe("Action: check count, add strike, clear strikes, or get prompt"),
|
|
32496
33346
|
attempt: tool.schema.string().optional().describe("Description of fix attempt (required for add_strike)"),
|
|
32497
33347
|
reason: tool.schema.string().optional().describe("Why the fix failed (required for add_strike)")
|
|
@@ -32756,7 +33606,7 @@ ${args.files_context.map((f) => `- \`${f}\``).join(`
|
|
|
32756
33606
|
*Learned from swarm execution on ${new Date().toISOString().split("T")[0]}*`;
|
|
32757
33607
|
const { getSkill: getSkill2, invalidateSkillsCache: invalidateSkillsCache2 } = await Promise.resolve().then(() => (init_skills(), exports_skills));
|
|
32758
33608
|
const { mkdir: mkdir2, writeFile: writeFile2 } = await import("node:fs/promises");
|
|
32759
|
-
const { join:
|
|
33609
|
+
const { join: join7 } = await import("node:path");
|
|
32760
33610
|
const existing = await getSkill2(args.skill_name);
|
|
32761
33611
|
if (existing) {
|
|
32762
33612
|
return JSON.stringify({
|
|
@@ -32767,8 +33617,8 @@ ${args.files_context.map((f) => `- \`${f}\``).join(`
|
|
|
32767
33617
|
suggestion: "Use skills_update to add to existing skill, or choose a different name"
|
|
32768
33618
|
}, null, 2);
|
|
32769
33619
|
}
|
|
32770
|
-
const skillDir =
|
|
32771
|
-
const skillPath =
|
|
33620
|
+
const skillDir = join7(process.cwd(), ".opencode", "skills", args.skill_name);
|
|
33621
|
+
const skillPath = join7(skillDir, "SKILL.md");
|
|
32772
33622
|
const frontmatter = [
|
|
32773
33623
|
"---",
|
|
32774
33624
|
`name: ${args.skill_name}`,
|
|
@@ -33892,14 +34742,14 @@ var DEFAULT_GUARDRAIL_CONFIG = {
|
|
|
33892
34742
|
cass_stats: 8000
|
|
33893
34743
|
},
|
|
33894
34744
|
skipTools: [
|
|
33895
|
-
"
|
|
33896
|
-
"
|
|
33897
|
-
"
|
|
33898
|
-
"
|
|
33899
|
-
"
|
|
33900
|
-
"
|
|
33901
|
-
"
|
|
33902
|
-
"
|
|
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",
|
|
33903
34753
|
"agentmail_init",
|
|
33904
34754
|
"agentmail_send",
|
|
33905
34755
|
"agentmail_inbox",
|
|
@@ -33919,7 +34769,7 @@ var DEFAULT_GUARDRAIL_CONFIG = {
|
|
|
33919
34769
|
"structured_validate",
|
|
33920
34770
|
"structured_parse_evaluation",
|
|
33921
34771
|
"structured_parse_decomposition",
|
|
33922
|
-
"
|
|
34772
|
+
"structured_parse_cell_tree",
|
|
33923
34773
|
"swarm_select_strategy",
|
|
33924
34774
|
"swarm_plan_prompt",
|
|
33925
34775
|
"swarm_decompose",
|
|
@@ -34095,7 +34945,7 @@ function analyzeTodoWrite(args) {
|
|
|
34095
34945
|
warning: `⚠️ This looks like a multi-file implementation plan (${fileModificationCount}/${todos.length} items are file modifications).
|
|
34096
34946
|
|
|
34097
34947
|
Consider using swarm instead:
|
|
34098
|
-
swarm_decompose →
|
|
34948
|
+
swarm_decompose → hive_create_epic → parallel task spawns
|
|
34099
34949
|
|
|
34100
34950
|
TodoWrite is for tracking progress, not parallelizable implementation work.
|
|
34101
34951
|
Swarm workers can complete these ${fileModificationCount} tasks in parallel.
|
|
@@ -34249,7 +35099,7 @@ var sessionStats = {
|
|
|
34249
35099
|
init_skills();
|
|
34250
35100
|
var SwarmPlugin = async (input) => {
|
|
34251
35101
|
const { $, directory } = input;
|
|
34252
|
-
|
|
35102
|
+
setHiveWorkingDirectory(directory);
|
|
34253
35103
|
setSkillsProjectDirectory(directory);
|
|
34254
35104
|
setAgentMailProjectDirectory(directory);
|
|
34255
35105
|
setSwarmMailProjectDirectory(directory);
|
|
@@ -34284,10 +35134,12 @@ var SwarmPlugin = async (input) => {
|
|
|
34284
35134
|
}
|
|
34285
35135
|
return {
|
|
34286
35136
|
tool: {
|
|
34287
|
-
...
|
|
35137
|
+
...hiveTools,
|
|
34288
35138
|
...swarmMailTools,
|
|
34289
35139
|
...structuredTools,
|
|
34290
35140
|
...swarmTools,
|
|
35141
|
+
...worktreeTools,
|
|
35142
|
+
...reviewTools,
|
|
34291
35143
|
...repoCrawlTools,
|
|
34292
35144
|
...skillsTools,
|
|
34293
35145
|
...mandateTools
|
|
@@ -34336,17 +35188,19 @@ var SwarmPlugin = async (input) => {
|
|
|
34336
35188
|
if (toolName === "swarm_complete" && activeAgentMailState) {
|
|
34337
35189
|
await releaseReservations();
|
|
34338
35190
|
}
|
|
34339
|
-
if (toolName === "
|
|
35191
|
+
if (toolName === "hive_close" || toolName === "hive_close") {
|
|
34340
35192
|
$`bd sync`.quiet().nothrow();
|
|
34341
35193
|
}
|
|
34342
35194
|
}
|
|
34343
35195
|
};
|
|
34344
35196
|
};
|
|
34345
35197
|
var allTools = {
|
|
34346
|
-
...
|
|
35198
|
+
...hiveTools,
|
|
34347
35199
|
...swarmMailTools,
|
|
34348
35200
|
...structuredTools,
|
|
34349
35201
|
...swarmTools,
|
|
35202
|
+
...worktreeTools,
|
|
35203
|
+
...reviewTools,
|
|
34350
35204
|
...repoCrawlTools,
|
|
34351
35205
|
...skillsTools,
|
|
34352
35206
|
...mandateTools
|