opencode-swarm-plugin 0.20.0 → 0.22.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/.beads/issues.jsonl +213 -0
- package/INTEGRATION_EXAMPLE.md +66 -0
- package/README.md +352 -522
- package/dist/index.js +2046 -984
- package/dist/plugin.js +2051 -1017
- package/docs/analysis/subagent-coordination-patterns.md +2 -0
- package/docs/semantic-memory-cli-syntax.md +123 -0
- package/docs/swarm-mail-architecture.md +1147 -0
- package/evals/README.md +116 -0
- package/evals/evalite.config.ts +15 -0
- package/evals/example.eval.ts +32 -0
- package/evals/fixtures/decomposition-cases.ts +105 -0
- package/evals/lib/data-loader.test.ts +288 -0
- package/evals/lib/data-loader.ts +111 -0
- package/evals/lib/llm.ts +115 -0
- package/evals/scorers/index.ts +200 -0
- package/evals/scorers/outcome-scorers.test.ts +27 -0
- package/evals/scorers/outcome-scorers.ts +349 -0
- package/evals/swarm-decomposition.eval.ts +112 -0
- package/package.json +8 -1
- package/scripts/cleanup-test-memories.ts +346 -0
- package/src/beads.ts +49 -0
- package/src/eval-capture.ts +487 -0
- package/src/index.ts +45 -3
- package/src/learning.integration.test.ts +19 -4
- package/src/output-guardrails.test.ts +438 -0
- package/src/output-guardrails.ts +381 -0
- package/src/schemas/index.ts +18 -0
- package/src/schemas/swarm-context.ts +115 -0
- package/src/storage.ts +117 -5
- package/src/streams/events.test.ts +296 -0
- package/src/streams/events.ts +93 -0
- package/src/streams/migrations.test.ts +24 -20
- package/src/streams/migrations.ts +51 -0
- package/src/streams/projections.ts +187 -0
- package/src/streams/store.ts +275 -0
- package/src/swarm-orchestrate.ts +771 -189
- package/src/swarm-prompts.ts +84 -12
- package/src/swarm.integration.test.ts +124 -0
- package/vitest.integration.config.ts +6 -0
- package/vitest.integration.setup.ts +48 -0
package/dist/index.js
CHANGED
|
@@ -12675,7 +12675,7 @@ var init_zod = __esm(() => {
|
|
|
12675
12675
|
init_external();
|
|
12676
12676
|
});
|
|
12677
12677
|
|
|
12678
|
-
// node_modules/.pnpm/@opencode-ai+plugin@1.0.
|
|
12678
|
+
// node_modules/.pnpm/@opencode-ai+plugin@1.0.152/node_modules/@opencode-ai/plugin/dist/tool.js
|
|
12679
12679
|
function tool(input) {
|
|
12680
12680
|
return input;
|
|
12681
12681
|
}
|
|
@@ -12684,7 +12684,7 @@ var init_tool = __esm(() => {
|
|
|
12684
12684
|
tool.schema = exports_external;
|
|
12685
12685
|
});
|
|
12686
12686
|
|
|
12687
|
-
// node_modules/.pnpm/@opencode-ai+plugin@1.0.
|
|
12687
|
+
// node_modules/.pnpm/@opencode-ai+plugin@1.0.152/node_modules/@opencode-ai/plugin/dist/index.js
|
|
12688
12688
|
var init_dist = __esm(() => {
|
|
12689
12689
|
init_tool();
|
|
12690
12690
|
});
|
|
@@ -12705,7 +12705,7 @@ function createEvent(type, data) {
|
|
|
12705
12705
|
function isEventType(event, type) {
|
|
12706
12706
|
return event.type === type;
|
|
12707
12707
|
}
|
|
12708
|
-
var BaseEventSchema, AgentRegisteredEventSchema, AgentActiveEventSchema, MessageSentEventSchema, MessageReadEventSchema, MessageAckedEventSchema, FileReservedEventSchema, FileReleasedEventSchema, TaskStartedEventSchema, TaskProgressEventSchema, TaskCompletedEventSchema, TaskBlockedEventSchema, AgentEventSchema;
|
|
12708
|
+
var BaseEventSchema, AgentRegisteredEventSchema, AgentActiveEventSchema, MessageSentEventSchema, MessageReadEventSchema, MessageAckedEventSchema, FileReservedEventSchema, FileReleasedEventSchema, TaskStartedEventSchema, TaskProgressEventSchema, TaskCompletedEventSchema, TaskBlockedEventSchema, DecompositionGeneratedEventSchema, SubtaskOutcomeEventSchema, HumanFeedbackEventSchema, SwarmCheckpointedEventSchema, SwarmRecoveredEventSchema, AgentEventSchema;
|
|
12709
12709
|
var init_events = __esm(() => {
|
|
12710
12710
|
init_zod();
|
|
12711
12711
|
BaseEventSchema = exports_external.object({
|
|
@@ -12791,6 +12791,68 @@ var init_events = __esm(() => {
|
|
|
12791
12791
|
bead_id: exports_external.string(),
|
|
12792
12792
|
reason: exports_external.string()
|
|
12793
12793
|
});
|
|
12794
|
+
DecompositionGeneratedEventSchema = BaseEventSchema.extend({
|
|
12795
|
+
type: exports_external.literal("decomposition_generated"),
|
|
12796
|
+
epic_id: exports_external.string(),
|
|
12797
|
+
task: exports_external.string(),
|
|
12798
|
+
context: exports_external.string().optional(),
|
|
12799
|
+
strategy: exports_external.enum(["file-based", "feature-based", "risk-based"]),
|
|
12800
|
+
epic_title: exports_external.string(),
|
|
12801
|
+
subtasks: exports_external.array(exports_external.object({
|
|
12802
|
+
title: exports_external.string(),
|
|
12803
|
+
files: exports_external.array(exports_external.string()),
|
|
12804
|
+
priority: exports_external.number().min(0).max(3).optional()
|
|
12805
|
+
})),
|
|
12806
|
+
recovery_context: exports_external.object({
|
|
12807
|
+
shared_context: exports_external.string().optional(),
|
|
12808
|
+
skills_to_load: exports_external.array(exports_external.string()).optional(),
|
|
12809
|
+
coordinator_notes: exports_external.string().optional()
|
|
12810
|
+
}).optional()
|
|
12811
|
+
});
|
|
12812
|
+
SubtaskOutcomeEventSchema = BaseEventSchema.extend({
|
|
12813
|
+
type: exports_external.literal("subtask_outcome"),
|
|
12814
|
+
epic_id: exports_external.string(),
|
|
12815
|
+
bead_id: exports_external.string(),
|
|
12816
|
+
planned_files: exports_external.array(exports_external.string()),
|
|
12817
|
+
actual_files: exports_external.array(exports_external.string()),
|
|
12818
|
+
duration_ms: exports_external.number().min(0),
|
|
12819
|
+
error_count: exports_external.number().min(0).default(0),
|
|
12820
|
+
retry_count: exports_external.number().min(0).default(0),
|
|
12821
|
+
success: exports_external.boolean()
|
|
12822
|
+
});
|
|
12823
|
+
HumanFeedbackEventSchema = BaseEventSchema.extend({
|
|
12824
|
+
type: exports_external.literal("human_feedback"),
|
|
12825
|
+
epic_id: exports_external.string(),
|
|
12826
|
+
accepted: exports_external.boolean(),
|
|
12827
|
+
modified: exports_external.boolean().default(false),
|
|
12828
|
+
notes: exports_external.string().optional()
|
|
12829
|
+
});
|
|
12830
|
+
SwarmCheckpointedEventSchema = BaseEventSchema.extend({
|
|
12831
|
+
type: exports_external.literal("swarm_checkpointed"),
|
|
12832
|
+
epic_id: exports_external.string(),
|
|
12833
|
+
bead_id: exports_external.string(),
|
|
12834
|
+
strategy: exports_external.enum(["file-based", "feature-based", "risk-based"]),
|
|
12835
|
+
files: exports_external.array(exports_external.string()),
|
|
12836
|
+
dependencies: exports_external.array(exports_external.string()),
|
|
12837
|
+
directives: exports_external.object({
|
|
12838
|
+
shared_context: exports_external.string().optional(),
|
|
12839
|
+
skills_to_load: exports_external.array(exports_external.string()).optional(),
|
|
12840
|
+
coordinator_notes: exports_external.string().optional()
|
|
12841
|
+
}),
|
|
12842
|
+
recovery: exports_external.object({
|
|
12843
|
+
last_checkpoint: exports_external.number(),
|
|
12844
|
+
files_modified: exports_external.array(exports_external.string()),
|
|
12845
|
+
progress_percent: exports_external.number().min(0).max(100),
|
|
12846
|
+
last_message: exports_external.string().optional(),
|
|
12847
|
+
error_context: exports_external.string().optional()
|
|
12848
|
+
})
|
|
12849
|
+
});
|
|
12850
|
+
SwarmRecoveredEventSchema = BaseEventSchema.extend({
|
|
12851
|
+
type: exports_external.literal("swarm_recovered"),
|
|
12852
|
+
epic_id: exports_external.string(),
|
|
12853
|
+
bead_id: exports_external.string(),
|
|
12854
|
+
recovered_from_checkpoint: exports_external.number()
|
|
12855
|
+
});
|
|
12794
12856
|
AgentEventSchema = exports_external.discriminatedUnion("type", [
|
|
12795
12857
|
AgentRegisteredEventSchema,
|
|
12796
12858
|
AgentActiveEventSchema,
|
|
@@ -12802,609 +12864,206 @@ var init_events = __esm(() => {
|
|
|
12802
12864
|
TaskStartedEventSchema,
|
|
12803
12865
|
TaskProgressEventSchema,
|
|
12804
12866
|
TaskCompletedEventSchema,
|
|
12805
|
-
TaskBlockedEventSchema
|
|
12867
|
+
TaskBlockedEventSchema,
|
|
12868
|
+
DecompositionGeneratedEventSchema,
|
|
12869
|
+
SubtaskOutcomeEventSchema,
|
|
12870
|
+
HumanFeedbackEventSchema,
|
|
12871
|
+
SwarmCheckpointedEventSchema,
|
|
12872
|
+
SwarmRecoveredEventSchema
|
|
12806
12873
|
]);
|
|
12807
12874
|
});
|
|
12808
12875
|
|
|
12809
|
-
//
|
|
12810
|
-
|
|
12811
|
-
const
|
|
12812
|
-
|
|
12813
|
-
|
|
12876
|
+
// node_modules/.pnpm/@isaacs+balanced-match@4.0.1/node_modules/@isaacs/balanced-match/dist/esm/index.js
|
|
12877
|
+
var balanced = (a, b, str2) => {
|
|
12878
|
+
const ma = a instanceof RegExp ? maybeMatch(a, str2) : a;
|
|
12879
|
+
const mb = b instanceof RegExp ? maybeMatch(b, str2) : b;
|
|
12880
|
+
const r = ma !== null && mb != null && range(ma, mb, str2);
|
|
12881
|
+
return r && {
|
|
12882
|
+
start: r[0],
|
|
12883
|
+
end: r[1],
|
|
12884
|
+
pre: str2.slice(0, r[0]),
|
|
12885
|
+
body: str2.slice(r[0] + ma.length, r[1]),
|
|
12886
|
+
post: str2.slice(r[1] + mb.length)
|
|
12887
|
+
};
|
|
12888
|
+
}, maybeMatch = (reg, str2) => {
|
|
12889
|
+
const m = str2.match(reg);
|
|
12890
|
+
return m ? m[0] : null;
|
|
12891
|
+
}, range = (a, b, str2) => {
|
|
12892
|
+
let begs, beg, left, right = undefined, result;
|
|
12893
|
+
let ai = str2.indexOf(a);
|
|
12894
|
+
let bi = str2.indexOf(b, ai + 1);
|
|
12895
|
+
let i = ai;
|
|
12896
|
+
if (ai >= 0 && bi > 0) {
|
|
12897
|
+
if (a === b) {
|
|
12898
|
+
return [ai, bi];
|
|
12899
|
+
}
|
|
12900
|
+
begs = [];
|
|
12901
|
+
left = str2.length;
|
|
12902
|
+
while (i >= 0 && !result) {
|
|
12903
|
+
if (i === ai) {
|
|
12904
|
+
begs.push(i);
|
|
12905
|
+
ai = str2.indexOf(a, i + 1);
|
|
12906
|
+
} else if (begs.length === 1) {
|
|
12907
|
+
const r = begs.pop();
|
|
12908
|
+
if (r !== undefined)
|
|
12909
|
+
result = [r, bi];
|
|
12910
|
+
} else {
|
|
12911
|
+
beg = begs.pop();
|
|
12912
|
+
if (beg !== undefined && beg < left) {
|
|
12913
|
+
left = beg;
|
|
12914
|
+
right = bi;
|
|
12915
|
+
}
|
|
12916
|
+
bi = str2.indexOf(b, i + 1);
|
|
12917
|
+
}
|
|
12918
|
+
i = ai < bi && ai >= 0 ? ai : bi;
|
|
12919
|
+
}
|
|
12920
|
+
if (begs.length && right !== undefined) {
|
|
12921
|
+
result = [left, right];
|
|
12922
|
+
}
|
|
12814
12923
|
}
|
|
12815
|
-
|
|
12816
|
-
|
|
12924
|
+
return result;
|
|
12925
|
+
};
|
|
12926
|
+
|
|
12927
|
+
// node_modules/.pnpm/@isaacs+brace-expansion@5.0.0/node_modules/@isaacs/brace-expansion/dist/esm/index.js
|
|
12928
|
+
function numeric(str2) {
|
|
12929
|
+
return !isNaN(str2) ? parseInt(str2, 10) : str2.charCodeAt(0);
|
|
12930
|
+
}
|
|
12931
|
+
function escapeBraces(str2) {
|
|
12932
|
+
return str2.replace(slashPattern, escSlash).replace(openPattern, escOpen).replace(closePattern, escClose).replace(commaPattern, escComma).replace(periodPattern, escPeriod);
|
|
12933
|
+
}
|
|
12934
|
+
function unescapeBraces(str2) {
|
|
12935
|
+
return str2.replace(escSlashPattern, "\\").replace(escOpenPattern, "{").replace(escClosePattern, "}").replace(escCommaPattern, ",").replace(escPeriodPattern, ".");
|
|
12936
|
+
}
|
|
12937
|
+
function parseCommaParts(str2) {
|
|
12938
|
+
if (!str2) {
|
|
12939
|
+
return [""];
|
|
12817
12940
|
}
|
|
12818
|
-
|
|
12941
|
+
const parts = [];
|
|
12942
|
+
const m = balanced("{", "}", str2);
|
|
12943
|
+
if (!m) {
|
|
12944
|
+
return str2.split(",");
|
|
12945
|
+
}
|
|
12946
|
+
const { pre, body, post } = m;
|
|
12947
|
+
const p = pre.split(",");
|
|
12948
|
+
p[p.length - 1] += "{" + body + "}";
|
|
12949
|
+
const postParts = parseCommaParts(post);
|
|
12950
|
+
if (post.length) {
|
|
12951
|
+
p[p.length - 1] += postParts.shift();
|
|
12952
|
+
p.push.apply(p, postParts);
|
|
12953
|
+
}
|
|
12954
|
+
parts.push.apply(parts, p);
|
|
12955
|
+
return parts;
|
|
12819
12956
|
}
|
|
12820
|
-
|
|
12821
|
-
|
|
12822
|
-
|
|
12823
|
-
console.log("[SwarmMail] Appending event", {
|
|
12824
|
-
type,
|
|
12825
|
-
projectKey: project_key,
|
|
12826
|
-
timestamp
|
|
12827
|
-
});
|
|
12828
|
-
const result = await db.query(`INSERT INTO events (type, project_key, timestamp, data)
|
|
12829
|
-
VALUES ($1, $2, $3, $4)
|
|
12830
|
-
RETURNING id, sequence`, [type, project_key, timestamp, JSON.stringify(rest)]);
|
|
12831
|
-
const row = result.rows[0];
|
|
12832
|
-
if (!row) {
|
|
12833
|
-
throw new Error("Failed to insert event - no row returned");
|
|
12957
|
+
function expand(str2) {
|
|
12958
|
+
if (!str2) {
|
|
12959
|
+
return [];
|
|
12834
12960
|
}
|
|
12835
|
-
|
|
12836
|
-
|
|
12837
|
-
|
|
12838
|
-
|
|
12839
|
-
sequence,
|
|
12840
|
-
projectKey: project_key
|
|
12841
|
-
});
|
|
12842
|
-
console.debug("[SwarmMail] Updating materialized views", { type, id });
|
|
12843
|
-
await updateMaterializedViews(db, { ...event, id, sequence });
|
|
12844
|
-
return { ...event, id, sequence };
|
|
12961
|
+
if (str2.slice(0, 2) === "{}") {
|
|
12962
|
+
str2 = "\\{\\}" + str2.slice(2);
|
|
12963
|
+
}
|
|
12964
|
+
return expand_(escapeBraces(str2), true).map(unescapeBraces);
|
|
12845
12965
|
}
|
|
12846
|
-
|
|
12847
|
-
return
|
|
12848
|
-
|
|
12849
|
-
|
|
12850
|
-
|
|
12851
|
-
|
|
12852
|
-
|
|
12853
|
-
|
|
12854
|
-
|
|
12855
|
-
|
|
12856
|
-
|
|
12857
|
-
|
|
12858
|
-
|
|
12859
|
-
|
|
12966
|
+
function embrace(str2) {
|
|
12967
|
+
return "{" + str2 + "}";
|
|
12968
|
+
}
|
|
12969
|
+
function isPadded(el) {
|
|
12970
|
+
return /^-?0\d/.test(el);
|
|
12971
|
+
}
|
|
12972
|
+
function lte(i, y) {
|
|
12973
|
+
return i <= y;
|
|
12974
|
+
}
|
|
12975
|
+
function gte(i, y) {
|
|
12976
|
+
return i >= y;
|
|
12977
|
+
}
|
|
12978
|
+
function expand_(str2, isTop) {
|
|
12979
|
+
const expansions = [];
|
|
12980
|
+
const m = balanced("{", "}", str2);
|
|
12981
|
+
if (!m)
|
|
12982
|
+
return [str2];
|
|
12983
|
+
const pre = m.pre;
|
|
12984
|
+
const post = m.post.length ? expand_(m.post, false) : [""];
|
|
12985
|
+
if (/\$$/.test(m.pre)) {
|
|
12986
|
+
for (let k = 0;k < post.length; k++) {
|
|
12987
|
+
const expansion = pre + "{" + m.body + "}" + post[k];
|
|
12988
|
+
expansions.push(expansion);
|
|
12989
|
+
}
|
|
12990
|
+
} else {
|
|
12991
|
+
const isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body);
|
|
12992
|
+
const isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body);
|
|
12993
|
+
const isSequence = isNumericSequence || isAlphaSequence;
|
|
12994
|
+
const isOptions = m.body.indexOf(",") >= 0;
|
|
12995
|
+
if (!isSequence && !isOptions) {
|
|
12996
|
+
if (m.post.match(/,(?!,).*\}/)) {
|
|
12997
|
+
str2 = m.pre + "{" + m.body + escClose + m.post;
|
|
12998
|
+
return expand_(str2);
|
|
12999
|
+
}
|
|
13000
|
+
return [str2];
|
|
13001
|
+
}
|
|
13002
|
+
let n;
|
|
13003
|
+
if (isSequence) {
|
|
13004
|
+
n = m.body.split(/\.\./);
|
|
13005
|
+
} else {
|
|
13006
|
+
n = parseCommaParts(m.body);
|
|
13007
|
+
if (n.length === 1 && n[0] !== undefined) {
|
|
13008
|
+
n = expand_(n[0], false).map(embrace);
|
|
13009
|
+
if (n.length === 1) {
|
|
13010
|
+
return post.map((p) => m.pre + n[0] + p);
|
|
12860
13011
|
}
|
|
12861
|
-
const { id, sequence } = row;
|
|
12862
|
-
const enrichedEvent = { ...event, id, sequence };
|
|
12863
|
-
await updateMaterializedViews(db, enrichedEvent);
|
|
12864
|
-
results.push(enrichedEvent);
|
|
12865
13012
|
}
|
|
12866
|
-
|
|
12867
|
-
|
|
12868
|
-
|
|
12869
|
-
|
|
12870
|
-
|
|
12871
|
-
|
|
12872
|
-
|
|
12873
|
-
|
|
13013
|
+
}
|
|
13014
|
+
let N;
|
|
13015
|
+
if (isSequence && n[0] !== undefined && n[1] !== undefined) {
|
|
13016
|
+
const x = numeric(n[0]);
|
|
13017
|
+
const y = numeric(n[1]);
|
|
13018
|
+
const width = Math.max(n[0].length, n[1].length);
|
|
13019
|
+
let incr = n.length === 3 && n[2] !== undefined ? Math.abs(numeric(n[2])) : 1;
|
|
13020
|
+
let test = lte;
|
|
13021
|
+
const reverse = y < x;
|
|
13022
|
+
if (reverse) {
|
|
13023
|
+
incr *= -1;
|
|
13024
|
+
test = gte;
|
|
12874
13025
|
}
|
|
12875
|
-
|
|
12876
|
-
|
|
12877
|
-
|
|
12878
|
-
|
|
12879
|
-
|
|
13026
|
+
const pad = n.some(isPadded);
|
|
13027
|
+
N = [];
|
|
13028
|
+
for (let i = x;test(i, y); i += incr) {
|
|
13029
|
+
let c;
|
|
13030
|
+
if (isAlphaSequence) {
|
|
13031
|
+
c = String.fromCharCode(i);
|
|
13032
|
+
if (c === "\\") {
|
|
13033
|
+
c = "";
|
|
13034
|
+
}
|
|
13035
|
+
} else {
|
|
13036
|
+
c = String(i);
|
|
13037
|
+
if (pad) {
|
|
13038
|
+
const need = width - c.length;
|
|
13039
|
+
if (need > 0) {
|
|
13040
|
+
const z = new Array(need + 1).join("0");
|
|
13041
|
+
if (i < 0) {
|
|
13042
|
+
c = "-" + z + c.slice(1);
|
|
13043
|
+
} else {
|
|
13044
|
+
c = z + c;
|
|
13045
|
+
}
|
|
13046
|
+
}
|
|
13047
|
+
}
|
|
13048
|
+
}
|
|
13049
|
+
N.push(c);
|
|
13050
|
+
}
|
|
13051
|
+
} else {
|
|
13052
|
+
N = [];
|
|
13053
|
+
for (let j = 0;j < n.length; j++) {
|
|
13054
|
+
N.push.apply(N, expand_(n[j], false));
|
|
12880
13055
|
}
|
|
12881
|
-
throw e;
|
|
12882
13056
|
}
|
|
12883
|
-
|
|
12884
|
-
|
|
12885
|
-
|
|
12886
|
-
|
|
12887
|
-
|
|
12888
|
-
|
|
12889
|
-
|
|
12890
|
-
|
|
12891
|
-
|
|
12892
|
-
|
|
12893
|
-
conditions.push(`project_key = $${paramIndex++}`);
|
|
12894
|
-
params.push(options2.projectKey);
|
|
12895
|
-
}
|
|
12896
|
-
if (options2.types && options2.types.length > 0) {
|
|
12897
|
-
conditions.push(`type = ANY($${paramIndex++})`);
|
|
12898
|
-
params.push(options2.types);
|
|
12899
|
-
}
|
|
12900
|
-
if (options2.since !== undefined) {
|
|
12901
|
-
conditions.push(`timestamp >= $${paramIndex++}`);
|
|
12902
|
-
params.push(options2.since);
|
|
12903
|
-
}
|
|
12904
|
-
if (options2.until !== undefined) {
|
|
12905
|
-
conditions.push(`timestamp <= $${paramIndex++}`);
|
|
12906
|
-
params.push(options2.until);
|
|
12907
|
-
}
|
|
12908
|
-
if (options2.afterSequence !== undefined) {
|
|
12909
|
-
conditions.push(`sequence > $${paramIndex++}`);
|
|
12910
|
-
params.push(options2.afterSequence);
|
|
12911
|
-
}
|
|
12912
|
-
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
12913
|
-
let query = `
|
|
12914
|
-
SELECT id, type, project_key, timestamp, sequence, data
|
|
12915
|
-
FROM events
|
|
12916
|
-
${whereClause}
|
|
12917
|
-
ORDER BY sequence ASC
|
|
12918
|
-
`;
|
|
12919
|
-
if (options2.limit) {
|
|
12920
|
-
query += ` LIMIT $${paramIndex++}`;
|
|
12921
|
-
params.push(options2.limit);
|
|
12922
|
-
}
|
|
12923
|
-
if (options2.offset) {
|
|
12924
|
-
query += ` OFFSET $${paramIndex++}`;
|
|
12925
|
-
params.push(options2.offset);
|
|
12926
|
-
}
|
|
12927
|
-
const result = await db.query(query, params);
|
|
12928
|
-
return result.rows.map((row) => {
|
|
12929
|
-
const data = typeof row.data === "string" ? JSON.parse(row.data) : row.data;
|
|
12930
|
-
return {
|
|
12931
|
-
id: row.id,
|
|
12932
|
-
type: row.type,
|
|
12933
|
-
project_key: row.project_key,
|
|
12934
|
-
timestamp: parseTimestamp(row.timestamp),
|
|
12935
|
-
sequence: row.sequence,
|
|
12936
|
-
...data
|
|
12937
|
-
};
|
|
12938
|
-
});
|
|
12939
|
-
});
|
|
12940
|
-
}
|
|
12941
|
-
async function getLatestSequence(projectKey, projectPath) {
|
|
12942
|
-
const db = await getDatabase(projectPath);
|
|
12943
|
-
const query = projectKey ? "SELECT MAX(sequence) as seq FROM events WHERE project_key = $1" : "SELECT MAX(sequence) as seq FROM events";
|
|
12944
|
-
const params = projectKey ? [projectKey] : [];
|
|
12945
|
-
const result = await db.query(query, params);
|
|
12946
|
-
return result.rows[0]?.seq ?? 0;
|
|
12947
|
-
}
|
|
12948
|
-
async function replayEvents(options2 = {}, projectPath) {
|
|
12949
|
-
return withTiming("replayEvents", async () => {
|
|
12950
|
-
const startTime = Date.now();
|
|
12951
|
-
const db = await getDatabase(projectPath);
|
|
12952
|
-
if (options2.clearViews) {
|
|
12953
|
-
if (options2.projectKey) {
|
|
12954
|
-
await db.query(`DELETE FROM message_recipients WHERE message_id IN (
|
|
12955
|
-
SELECT id FROM messages WHERE project_key = $1
|
|
12956
|
-
)`, [options2.projectKey]);
|
|
12957
|
-
await db.query(`DELETE FROM messages WHERE project_key = $1`, [
|
|
12958
|
-
options2.projectKey
|
|
12959
|
-
]);
|
|
12960
|
-
await db.query(`DELETE FROM reservations WHERE project_key = $1`, [
|
|
12961
|
-
options2.projectKey
|
|
12962
|
-
]);
|
|
12963
|
-
await db.query(`DELETE FROM agents WHERE project_key = $1`, [
|
|
12964
|
-
options2.projectKey
|
|
12965
|
-
]);
|
|
12966
|
-
} else {
|
|
12967
|
-
await db.exec(`
|
|
12968
|
-
DELETE FROM message_recipients;
|
|
12969
|
-
DELETE FROM messages;
|
|
12970
|
-
DELETE FROM reservations;
|
|
12971
|
-
DELETE FROM agents;
|
|
12972
|
-
`);
|
|
12973
|
-
}
|
|
12974
|
-
}
|
|
12975
|
-
const events = await readEvents({
|
|
12976
|
-
projectKey: options2.projectKey,
|
|
12977
|
-
afterSequence: options2.fromSequence
|
|
12978
|
-
}, projectPath);
|
|
12979
|
-
for (const event of events) {
|
|
12980
|
-
await updateMaterializedViews(db, event);
|
|
12981
|
-
}
|
|
12982
|
-
return {
|
|
12983
|
-
eventsReplayed: events.length,
|
|
12984
|
-
duration: Date.now() - startTime
|
|
12985
|
-
};
|
|
12986
|
-
});
|
|
12987
|
-
}
|
|
12988
|
-
async function replayEventsBatched(projectKey, onBatch, options2 = {}, projectPath) {
|
|
12989
|
-
return withTiming("replayEventsBatched", async () => {
|
|
12990
|
-
const startTime = Date.now();
|
|
12991
|
-
const batchSize = options2.batchSize ?? 1000;
|
|
12992
|
-
const fromSequence = options2.fromSequence ?? 0;
|
|
12993
|
-
const db = await getDatabase(projectPath);
|
|
12994
|
-
if (options2.clearViews) {
|
|
12995
|
-
await db.query(`DELETE FROM message_recipients WHERE message_id IN (
|
|
12996
|
-
SELECT id FROM messages WHERE project_key = $1
|
|
12997
|
-
)`, [projectKey]);
|
|
12998
|
-
await db.query(`DELETE FROM messages WHERE project_key = $1`, [
|
|
12999
|
-
projectKey
|
|
13000
|
-
]);
|
|
13001
|
-
await db.query(`DELETE FROM reservations WHERE project_key = $1`, [
|
|
13002
|
-
projectKey
|
|
13003
|
-
]);
|
|
13004
|
-
await db.query(`DELETE FROM agents WHERE project_key = $1`, [projectKey]);
|
|
13005
|
-
}
|
|
13006
|
-
const countResult = await db.query(`SELECT COUNT(*) as count FROM events WHERE project_key = $1 AND sequence > $2`, [projectKey, fromSequence]);
|
|
13007
|
-
const total = parseInt(countResult.rows[0]?.count ?? "0");
|
|
13008
|
-
if (total === 0) {
|
|
13009
|
-
return { eventsReplayed: 0, duration: Date.now() - startTime };
|
|
13010
|
-
}
|
|
13011
|
-
let processed = 0;
|
|
13012
|
-
let offset = 0;
|
|
13013
|
-
while (processed < total) {
|
|
13014
|
-
const events = await readEvents({
|
|
13015
|
-
projectKey,
|
|
13016
|
-
afterSequence: fromSequence,
|
|
13017
|
-
limit: batchSize,
|
|
13018
|
-
offset
|
|
13019
|
-
}, projectPath);
|
|
13020
|
-
if (events.length === 0)
|
|
13021
|
-
break;
|
|
13022
|
-
for (const event of events) {
|
|
13023
|
-
await updateMaterializedViews(db, event);
|
|
13024
|
-
}
|
|
13025
|
-
processed += events.length;
|
|
13026
|
-
const percent = Math.round(processed / total * 100);
|
|
13027
|
-
await onBatch(events, { processed, total, percent });
|
|
13028
|
-
console.log(`[SwarmMail] Replaying events: ${processed}/${total} (${percent}%)`);
|
|
13029
|
-
offset += batchSize;
|
|
13030
|
-
}
|
|
13031
|
-
return {
|
|
13032
|
-
eventsReplayed: processed,
|
|
13033
|
-
duration: Date.now() - startTime
|
|
13034
|
-
};
|
|
13035
|
-
});
|
|
13036
|
-
}
|
|
13037
|
-
async function updateMaterializedViews(db, event) {
|
|
13038
|
-
try {
|
|
13039
|
-
switch (event.type) {
|
|
13040
|
-
case "agent_registered":
|
|
13041
|
-
await handleAgentRegistered(db, event);
|
|
13042
|
-
break;
|
|
13043
|
-
case "agent_active":
|
|
13044
|
-
await db.query(`UPDATE agents SET last_active_at = $1 WHERE project_key = $2 AND name = $3`, [event.timestamp, event.project_key, event.agent_name]);
|
|
13045
|
-
break;
|
|
13046
|
-
case "message_sent":
|
|
13047
|
-
await handleMessageSent(db, event);
|
|
13048
|
-
break;
|
|
13049
|
-
case "message_read":
|
|
13050
|
-
await db.query(`UPDATE message_recipients SET read_at = $1 WHERE message_id = $2 AND agent_name = $3`, [event.timestamp, event.message_id, event.agent_name]);
|
|
13051
|
-
break;
|
|
13052
|
-
case "message_acked":
|
|
13053
|
-
await db.query(`UPDATE message_recipients SET acked_at = $1 WHERE message_id = $2 AND agent_name = $3`, [event.timestamp, event.message_id, event.agent_name]);
|
|
13054
|
-
break;
|
|
13055
|
-
case "file_reserved":
|
|
13056
|
-
await handleFileReserved(db, event);
|
|
13057
|
-
break;
|
|
13058
|
-
case "file_released":
|
|
13059
|
-
await handleFileReleased(db, event);
|
|
13060
|
-
break;
|
|
13061
|
-
case "task_started":
|
|
13062
|
-
case "task_progress":
|
|
13063
|
-
case "task_completed":
|
|
13064
|
-
case "task_blocked":
|
|
13065
|
-
break;
|
|
13066
|
-
}
|
|
13067
|
-
} catch (error45) {
|
|
13068
|
-
console.error("[SwarmMail] Failed to update materialized views", {
|
|
13069
|
-
eventType: event.type,
|
|
13070
|
-
eventId: event.id,
|
|
13071
|
-
error: error45
|
|
13072
|
-
});
|
|
13073
|
-
throw error45;
|
|
13074
|
-
}
|
|
13075
|
-
}
|
|
13076
|
-
async function handleAgentRegistered(db, event) {
|
|
13077
|
-
await db.query(`INSERT INTO agents (project_key, name, program, model, task_description, registered_at, last_active_at)
|
|
13078
|
-
VALUES ($1, $2, $3, $4, $5, $6, $6)
|
|
13079
|
-
ON CONFLICT (project_key, name) DO UPDATE SET
|
|
13080
|
-
program = EXCLUDED.program,
|
|
13081
|
-
model = EXCLUDED.model,
|
|
13082
|
-
task_description = EXCLUDED.task_description,
|
|
13083
|
-
last_active_at = EXCLUDED.last_active_at`, [
|
|
13084
|
-
event.project_key,
|
|
13085
|
-
event.agent_name,
|
|
13086
|
-
event.program,
|
|
13087
|
-
event.model,
|
|
13088
|
-
event.task_description || null,
|
|
13089
|
-
event.timestamp
|
|
13090
|
-
]);
|
|
13091
|
-
}
|
|
13092
|
-
async function handleMessageSent(db, event) {
|
|
13093
|
-
console.log("[SwarmMail] Handling message sent event", {
|
|
13094
|
-
from: event.from_agent,
|
|
13095
|
-
to: event.to_agents,
|
|
13096
|
-
subject: event.subject,
|
|
13097
|
-
projectKey: event.project_key
|
|
13098
|
-
});
|
|
13099
|
-
const result = await db.query(`INSERT INTO messages (project_key, from_agent, subject, body, thread_id, importance, ack_required, created_at)
|
|
13100
|
-
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
|
13101
|
-
RETURNING id`, [
|
|
13102
|
-
event.project_key,
|
|
13103
|
-
event.from_agent,
|
|
13104
|
-
event.subject,
|
|
13105
|
-
event.body,
|
|
13106
|
-
event.thread_id || null,
|
|
13107
|
-
event.importance,
|
|
13108
|
-
event.ack_required,
|
|
13109
|
-
event.timestamp
|
|
13110
|
-
]);
|
|
13111
|
-
const msgRow = result.rows[0];
|
|
13112
|
-
if (!msgRow) {
|
|
13113
|
-
throw new Error("Failed to insert message - no row returned");
|
|
13114
|
-
}
|
|
13115
|
-
const messageId = msgRow.id;
|
|
13116
|
-
if (event.to_agents.length > 0) {
|
|
13117
|
-
const values = event.to_agents.map((_, i) => `($1, $${i + 2})`).join(", ");
|
|
13118
|
-
const params = [messageId, ...event.to_agents];
|
|
13119
|
-
await db.query(`INSERT INTO message_recipients (message_id, agent_name)
|
|
13120
|
-
VALUES ${values}
|
|
13121
|
-
ON CONFLICT DO NOTHING`, params);
|
|
13122
|
-
console.log("[SwarmMail] Message recipients inserted", {
|
|
13123
|
-
messageId,
|
|
13124
|
-
recipientCount: event.to_agents.length
|
|
13125
|
-
});
|
|
13126
|
-
}
|
|
13127
|
-
}
|
|
13128
|
-
async function handleFileReserved(db, event) {
|
|
13129
|
-
console.log("[SwarmMail] Handling file reservation event", {
|
|
13130
|
-
agent: event.agent_name,
|
|
13131
|
-
paths: event.paths,
|
|
13132
|
-
exclusive: event.exclusive,
|
|
13133
|
-
projectKey: event.project_key
|
|
13134
|
-
});
|
|
13135
|
-
if (event.paths.length > 0) {
|
|
13136
|
-
const values = event.paths.map((_, i) => `($1, $2, $${i + 3}, $${event.paths.length + 3}, $${event.paths.length + 4}, $${event.paths.length + 5}, $${event.paths.length + 6})`).join(", ");
|
|
13137
|
-
const params = [
|
|
13138
|
-
event.project_key,
|
|
13139
|
-
event.agent_name,
|
|
13140
|
-
...event.paths,
|
|
13141
|
-
event.exclusive,
|
|
13142
|
-
event.reason || null,
|
|
13143
|
-
event.timestamp,
|
|
13144
|
-
event.expires_at
|
|
13145
|
-
];
|
|
13146
|
-
if (event.paths.length > 0) {
|
|
13147
|
-
await db.query(`DELETE FROM reservations
|
|
13148
|
-
WHERE project_key = $1
|
|
13149
|
-
AND agent_name = $2
|
|
13150
|
-
AND path_pattern = ANY($3)
|
|
13151
|
-
AND released_at IS NULL`, [event.project_key, event.agent_name, event.paths]);
|
|
13152
|
-
}
|
|
13153
|
-
await db.query(`INSERT INTO reservations (project_key, agent_name, path_pattern, exclusive, reason, created_at, expires_at)
|
|
13154
|
-
VALUES ${values}`, params);
|
|
13155
|
-
console.log("[SwarmMail] File reservations inserted", {
|
|
13156
|
-
agent: event.agent_name,
|
|
13157
|
-
reservationCount: event.paths.length
|
|
13158
|
-
});
|
|
13159
|
-
}
|
|
13160
|
-
}
|
|
13161
|
-
async function handleFileReleased(db, event) {
|
|
13162
|
-
if (event.type !== "file_released")
|
|
13163
|
-
return;
|
|
13164
|
-
if (event.reservation_ids && event.reservation_ids.length > 0) {
|
|
13165
|
-
await db.query(`UPDATE reservations SET released_at = $1 WHERE id = ANY($2)`, [event.timestamp, event.reservation_ids]);
|
|
13166
|
-
} else if (event.paths && event.paths.length > 0) {
|
|
13167
|
-
await db.query(`UPDATE reservations SET released_at = $1
|
|
13168
|
-
WHERE project_key = $2 AND agent_name = $3 AND path_pattern = ANY($4) AND released_at IS NULL`, [event.timestamp, event.project_key, event.agent_name, event.paths]);
|
|
13169
|
-
} else {
|
|
13170
|
-
await db.query(`UPDATE reservations SET released_at = $1
|
|
13171
|
-
WHERE project_key = $2 AND agent_name = $3 AND released_at IS NULL`, [event.timestamp, event.project_key, event.agent_name]);
|
|
13172
|
-
}
|
|
13173
|
-
}
|
|
13174
|
-
async function registerAgent(projectKey, agentName, options2 = {}, projectPath) {
|
|
13175
|
-
const event = createEvent("agent_registered", {
|
|
13176
|
-
project_key: projectKey,
|
|
13177
|
-
agent_name: agentName,
|
|
13178
|
-
program: options2.program || "opencode",
|
|
13179
|
-
model: options2.model || "unknown",
|
|
13180
|
-
task_description: options2.taskDescription
|
|
13181
|
-
});
|
|
13182
|
-
return appendEvent(event, projectPath);
|
|
13183
|
-
}
|
|
13184
|
-
async function sendMessage(projectKey, fromAgent, toAgents, subject, body, options2 = {}, projectPath) {
|
|
13185
|
-
const event = createEvent("message_sent", {
|
|
13186
|
-
project_key: projectKey,
|
|
13187
|
-
from_agent: fromAgent,
|
|
13188
|
-
to_agents: toAgents,
|
|
13189
|
-
subject,
|
|
13190
|
-
body,
|
|
13191
|
-
thread_id: options2.threadId,
|
|
13192
|
-
importance: options2.importance || "normal",
|
|
13193
|
-
ack_required: options2.ackRequired || false
|
|
13194
|
-
});
|
|
13195
|
-
return appendEvent(event, projectPath);
|
|
13196
|
-
}
|
|
13197
|
-
async function reserveFiles(projectKey, agentName, paths, options2 = {}, projectPath) {
|
|
13198
|
-
const ttlSeconds = options2.ttlSeconds || 3600;
|
|
13199
|
-
const event = createEvent("file_reserved", {
|
|
13200
|
-
project_key: projectKey,
|
|
13201
|
-
agent_name: agentName,
|
|
13202
|
-
paths,
|
|
13203
|
-
reason: options2.reason,
|
|
13204
|
-
exclusive: options2.exclusive ?? true,
|
|
13205
|
-
ttl_seconds: ttlSeconds,
|
|
13206
|
-
expires_at: Date.now() + ttlSeconds * 1000
|
|
13207
|
-
});
|
|
13208
|
-
return appendEvent(event, projectPath);
|
|
13209
|
-
}
|
|
13210
|
-
var TIMESTAMP_SAFE_UNTIL;
|
|
13211
|
-
var init_store = __esm(() => {
|
|
13212
|
-
init_streams();
|
|
13213
|
-
init_events();
|
|
13214
|
-
TIMESTAMP_SAFE_UNTIL = new Date("2286-01-01").getTime();
|
|
13215
|
-
});
|
|
13216
|
-
|
|
13217
|
-
// node_modules/.pnpm/@isaacs+balanced-match@4.0.1/node_modules/@isaacs/balanced-match/dist/esm/index.js
|
|
13218
|
-
var balanced = (a, b, str2) => {
|
|
13219
|
-
const ma = a instanceof RegExp ? maybeMatch(a, str2) : a;
|
|
13220
|
-
const mb = b instanceof RegExp ? maybeMatch(b, str2) : b;
|
|
13221
|
-
const r = ma !== null && mb != null && range(ma, mb, str2);
|
|
13222
|
-
return r && {
|
|
13223
|
-
start: r[0],
|
|
13224
|
-
end: r[1],
|
|
13225
|
-
pre: str2.slice(0, r[0]),
|
|
13226
|
-
body: str2.slice(r[0] + ma.length, r[1]),
|
|
13227
|
-
post: str2.slice(r[1] + mb.length)
|
|
13228
|
-
};
|
|
13229
|
-
}, maybeMatch = (reg, str2) => {
|
|
13230
|
-
const m = str2.match(reg);
|
|
13231
|
-
return m ? m[0] : null;
|
|
13232
|
-
}, range = (a, b, str2) => {
|
|
13233
|
-
let begs, beg, left, right = undefined, result;
|
|
13234
|
-
let ai = str2.indexOf(a);
|
|
13235
|
-
let bi = str2.indexOf(b, ai + 1);
|
|
13236
|
-
let i = ai;
|
|
13237
|
-
if (ai >= 0 && bi > 0) {
|
|
13238
|
-
if (a === b) {
|
|
13239
|
-
return [ai, bi];
|
|
13240
|
-
}
|
|
13241
|
-
begs = [];
|
|
13242
|
-
left = str2.length;
|
|
13243
|
-
while (i >= 0 && !result) {
|
|
13244
|
-
if (i === ai) {
|
|
13245
|
-
begs.push(i);
|
|
13246
|
-
ai = str2.indexOf(a, i + 1);
|
|
13247
|
-
} else if (begs.length === 1) {
|
|
13248
|
-
const r = begs.pop();
|
|
13249
|
-
if (r !== undefined)
|
|
13250
|
-
result = [r, bi];
|
|
13251
|
-
} else {
|
|
13252
|
-
beg = begs.pop();
|
|
13253
|
-
if (beg !== undefined && beg < left) {
|
|
13254
|
-
left = beg;
|
|
13255
|
-
right = bi;
|
|
13256
|
-
}
|
|
13257
|
-
bi = str2.indexOf(b, i + 1);
|
|
13258
|
-
}
|
|
13259
|
-
i = ai < bi && ai >= 0 ? ai : bi;
|
|
13260
|
-
}
|
|
13261
|
-
if (begs.length && right !== undefined) {
|
|
13262
|
-
result = [left, right];
|
|
13263
|
-
}
|
|
13264
|
-
}
|
|
13265
|
-
return result;
|
|
13266
|
-
};
|
|
13267
|
-
|
|
13268
|
-
// node_modules/.pnpm/@isaacs+brace-expansion@5.0.0/node_modules/@isaacs/brace-expansion/dist/esm/index.js
|
|
13269
|
-
function numeric(str2) {
|
|
13270
|
-
return !isNaN(str2) ? parseInt(str2, 10) : str2.charCodeAt(0);
|
|
13271
|
-
}
|
|
13272
|
-
function escapeBraces(str2) {
|
|
13273
|
-
return str2.replace(slashPattern, escSlash).replace(openPattern, escOpen).replace(closePattern, escClose).replace(commaPattern, escComma).replace(periodPattern, escPeriod);
|
|
13274
|
-
}
|
|
13275
|
-
function unescapeBraces(str2) {
|
|
13276
|
-
return str2.replace(escSlashPattern, "\\").replace(escOpenPattern, "{").replace(escClosePattern, "}").replace(escCommaPattern, ",").replace(escPeriodPattern, ".");
|
|
13277
|
-
}
|
|
13278
|
-
function parseCommaParts(str2) {
|
|
13279
|
-
if (!str2) {
|
|
13280
|
-
return [""];
|
|
13281
|
-
}
|
|
13282
|
-
const parts = [];
|
|
13283
|
-
const m = balanced("{", "}", str2);
|
|
13284
|
-
if (!m) {
|
|
13285
|
-
return str2.split(",");
|
|
13286
|
-
}
|
|
13287
|
-
const { pre, body, post } = m;
|
|
13288
|
-
const p = pre.split(",");
|
|
13289
|
-
p[p.length - 1] += "{" + body + "}";
|
|
13290
|
-
const postParts = parseCommaParts(post);
|
|
13291
|
-
if (post.length) {
|
|
13292
|
-
p[p.length - 1] += postParts.shift();
|
|
13293
|
-
p.push.apply(p, postParts);
|
|
13294
|
-
}
|
|
13295
|
-
parts.push.apply(parts, p);
|
|
13296
|
-
return parts;
|
|
13297
|
-
}
|
|
13298
|
-
function expand(str2) {
|
|
13299
|
-
if (!str2) {
|
|
13300
|
-
return [];
|
|
13301
|
-
}
|
|
13302
|
-
if (str2.slice(0, 2) === "{}") {
|
|
13303
|
-
str2 = "\\{\\}" + str2.slice(2);
|
|
13304
|
-
}
|
|
13305
|
-
return expand_(escapeBraces(str2), true).map(unescapeBraces);
|
|
13306
|
-
}
|
|
13307
|
-
function embrace(str2) {
|
|
13308
|
-
return "{" + str2 + "}";
|
|
13309
|
-
}
|
|
13310
|
-
function isPadded(el) {
|
|
13311
|
-
return /^-?0\d/.test(el);
|
|
13312
|
-
}
|
|
13313
|
-
function lte(i, y) {
|
|
13314
|
-
return i <= y;
|
|
13315
|
-
}
|
|
13316
|
-
function gte(i, y) {
|
|
13317
|
-
return i >= y;
|
|
13318
|
-
}
|
|
13319
|
-
function expand_(str2, isTop) {
|
|
13320
|
-
const expansions = [];
|
|
13321
|
-
const m = balanced("{", "}", str2);
|
|
13322
|
-
if (!m)
|
|
13323
|
-
return [str2];
|
|
13324
|
-
const pre = m.pre;
|
|
13325
|
-
const post = m.post.length ? expand_(m.post, false) : [""];
|
|
13326
|
-
if (/\$$/.test(m.pre)) {
|
|
13327
|
-
for (let k = 0;k < post.length; k++) {
|
|
13328
|
-
const expansion = pre + "{" + m.body + "}" + post[k];
|
|
13329
|
-
expansions.push(expansion);
|
|
13330
|
-
}
|
|
13331
|
-
} else {
|
|
13332
|
-
const isNumericSequence = /^-?\d+\.\.-?\d+(?:\.\.-?\d+)?$/.test(m.body);
|
|
13333
|
-
const isAlphaSequence = /^[a-zA-Z]\.\.[a-zA-Z](?:\.\.-?\d+)?$/.test(m.body);
|
|
13334
|
-
const isSequence = isNumericSequence || isAlphaSequence;
|
|
13335
|
-
const isOptions = m.body.indexOf(",") >= 0;
|
|
13336
|
-
if (!isSequence && !isOptions) {
|
|
13337
|
-
if (m.post.match(/,(?!,).*\}/)) {
|
|
13338
|
-
str2 = m.pre + "{" + m.body + escClose + m.post;
|
|
13339
|
-
return expand_(str2);
|
|
13340
|
-
}
|
|
13341
|
-
return [str2];
|
|
13342
|
-
}
|
|
13343
|
-
let n;
|
|
13344
|
-
if (isSequence) {
|
|
13345
|
-
n = m.body.split(/\.\./);
|
|
13346
|
-
} else {
|
|
13347
|
-
n = parseCommaParts(m.body);
|
|
13348
|
-
if (n.length === 1 && n[0] !== undefined) {
|
|
13349
|
-
n = expand_(n[0], false).map(embrace);
|
|
13350
|
-
if (n.length === 1) {
|
|
13351
|
-
return post.map((p) => m.pre + n[0] + p);
|
|
13352
|
-
}
|
|
13353
|
-
}
|
|
13354
|
-
}
|
|
13355
|
-
let N;
|
|
13356
|
-
if (isSequence && n[0] !== undefined && n[1] !== undefined) {
|
|
13357
|
-
const x = numeric(n[0]);
|
|
13358
|
-
const y = numeric(n[1]);
|
|
13359
|
-
const width = Math.max(n[0].length, n[1].length);
|
|
13360
|
-
let incr = n.length === 3 && n[2] !== undefined ? Math.abs(numeric(n[2])) : 1;
|
|
13361
|
-
let test = lte;
|
|
13362
|
-
const reverse = y < x;
|
|
13363
|
-
if (reverse) {
|
|
13364
|
-
incr *= -1;
|
|
13365
|
-
test = gte;
|
|
13366
|
-
}
|
|
13367
|
-
const pad = n.some(isPadded);
|
|
13368
|
-
N = [];
|
|
13369
|
-
for (let i = x;test(i, y); i += incr) {
|
|
13370
|
-
let c;
|
|
13371
|
-
if (isAlphaSequence) {
|
|
13372
|
-
c = String.fromCharCode(i);
|
|
13373
|
-
if (c === "\\") {
|
|
13374
|
-
c = "";
|
|
13375
|
-
}
|
|
13376
|
-
} else {
|
|
13377
|
-
c = String(i);
|
|
13378
|
-
if (pad) {
|
|
13379
|
-
const need = width - c.length;
|
|
13380
|
-
if (need > 0) {
|
|
13381
|
-
const z = new Array(need + 1).join("0");
|
|
13382
|
-
if (i < 0) {
|
|
13383
|
-
c = "-" + z + c.slice(1);
|
|
13384
|
-
} else {
|
|
13385
|
-
c = z + c;
|
|
13386
|
-
}
|
|
13387
|
-
}
|
|
13388
|
-
}
|
|
13389
|
-
}
|
|
13390
|
-
N.push(c);
|
|
13391
|
-
}
|
|
13392
|
-
} else {
|
|
13393
|
-
N = [];
|
|
13394
|
-
for (let j = 0;j < n.length; j++) {
|
|
13395
|
-
N.push.apply(N, expand_(n[j], false));
|
|
13396
|
-
}
|
|
13397
|
-
}
|
|
13398
|
-
for (let j = 0;j < N.length; j++) {
|
|
13399
|
-
for (let k = 0;k < post.length; k++) {
|
|
13400
|
-
const expansion = pre + N[j] + post[k];
|
|
13401
|
-
if (!isTop || isSequence || expansion) {
|
|
13402
|
-
expansions.push(expansion);
|
|
13403
|
-
}
|
|
13404
|
-
}
|
|
13405
|
-
}
|
|
13406
|
-
}
|
|
13407
|
-
return expansions;
|
|
13057
|
+
for (let j = 0;j < N.length; j++) {
|
|
13058
|
+
for (let k = 0;k < post.length; k++) {
|
|
13059
|
+
const expansion = pre + N[j] + post[k];
|
|
13060
|
+
if (!isTop || isSequence || expansion) {
|
|
13061
|
+
expansions.push(expansion);
|
|
13062
|
+
}
|
|
13063
|
+
}
|
|
13064
|
+
}
|
|
13065
|
+
}
|
|
13066
|
+
return expansions;
|
|
13408
13067
|
}
|
|
13409
13068
|
var escSlash, escOpen, escClose, escComma, escPeriod, escSlashPattern, escOpenPattern, escClosePattern, escCommaPattern, escPeriodPattern, slashPattern, openPattern, closePattern, commaPattern, periodPattern;
|
|
13410
13069
|
var init_esm = __esm(() => {
|
|
@@ -14753,6 +14412,79 @@ function pathMatches(path2, pattern) {
|
|
|
14753
14412
|
}
|
|
14754
14413
|
return minimatch(path2, pattern);
|
|
14755
14414
|
}
|
|
14415
|
+
async function getEvalRecords(projectKey, options2, projectPath) {
|
|
14416
|
+
const db = await getDatabase(projectPath);
|
|
14417
|
+
const conditions = ["project_key = $1"];
|
|
14418
|
+
const params = [projectKey];
|
|
14419
|
+
let paramIndex = 2;
|
|
14420
|
+
if (options2?.strategy) {
|
|
14421
|
+
conditions.push(`strategy = $${paramIndex++}`);
|
|
14422
|
+
params.push(options2.strategy);
|
|
14423
|
+
}
|
|
14424
|
+
const whereClause = conditions.join(" AND ");
|
|
14425
|
+
let query = `
|
|
14426
|
+
SELECT id, project_key, task, context, strategy, epic_title, subtasks,
|
|
14427
|
+
outcomes, overall_success, total_duration_ms, total_errors,
|
|
14428
|
+
human_accepted, human_modified, human_notes,
|
|
14429
|
+
file_overlap_count, scope_accuracy, time_balance_ratio,
|
|
14430
|
+
created_at, updated_at
|
|
14431
|
+
FROM eval_records
|
|
14432
|
+
WHERE ${whereClause}
|
|
14433
|
+
ORDER BY created_at DESC
|
|
14434
|
+
`;
|
|
14435
|
+
if (options2?.limit) {
|
|
14436
|
+
query += ` LIMIT $${paramIndex}`;
|
|
14437
|
+
params.push(options2.limit);
|
|
14438
|
+
}
|
|
14439
|
+
const result = await db.query(query, params);
|
|
14440
|
+
return result.rows.map((row) => ({
|
|
14441
|
+
id: row.id,
|
|
14442
|
+
project_key: row.project_key,
|
|
14443
|
+
task: row.task,
|
|
14444
|
+
context: row.context,
|
|
14445
|
+
strategy: row.strategy,
|
|
14446
|
+
epic_title: row.epic_title,
|
|
14447
|
+
subtasks: typeof row.subtasks === "string" ? JSON.parse(row.subtasks) : row.subtasks,
|
|
14448
|
+
outcomes: row.outcomes ? typeof row.outcomes === "string" ? JSON.parse(row.outcomes) : row.outcomes : undefined,
|
|
14449
|
+
overall_success: row.overall_success,
|
|
14450
|
+
total_duration_ms: row.total_duration_ms,
|
|
14451
|
+
total_errors: row.total_errors,
|
|
14452
|
+
human_accepted: row.human_accepted,
|
|
14453
|
+
human_modified: row.human_modified,
|
|
14454
|
+
human_notes: row.human_notes,
|
|
14455
|
+
file_overlap_count: row.file_overlap_count,
|
|
14456
|
+
scope_accuracy: row.scope_accuracy,
|
|
14457
|
+
time_balance_ratio: row.time_balance_ratio,
|
|
14458
|
+
created_at: parseInt(row.created_at),
|
|
14459
|
+
updated_at: parseInt(row.updated_at)
|
|
14460
|
+
}));
|
|
14461
|
+
}
|
|
14462
|
+
async function getEvalStats(projectKey, projectPath) {
|
|
14463
|
+
const db = await getDatabase(projectPath);
|
|
14464
|
+
const overallResult = await db.query(`SELECT
|
|
14465
|
+
COUNT(*) as total_records,
|
|
14466
|
+
COUNT(*) FILTER (WHERE overall_success = true) as success_count,
|
|
14467
|
+
AVG(total_duration_ms) as avg_duration
|
|
14468
|
+
FROM eval_records
|
|
14469
|
+
WHERE project_key = $1`, [projectKey]);
|
|
14470
|
+
const totalRecords = parseInt(overallResult.rows[0]?.total_records || "0");
|
|
14471
|
+
const successCount = parseInt(overallResult.rows[0]?.success_count || "0");
|
|
14472
|
+
const avgDurationMs = parseFloat(overallResult.rows[0]?.avg_duration || "0");
|
|
14473
|
+
const strategyResult = await db.query(`SELECT strategy, COUNT(*) as count
|
|
14474
|
+
FROM eval_records
|
|
14475
|
+
WHERE project_key = $1
|
|
14476
|
+
GROUP BY strategy`, [projectKey]);
|
|
14477
|
+
const byStrategy = {};
|
|
14478
|
+
for (const row of strategyResult.rows) {
|
|
14479
|
+
byStrategy[row.strategy] = parseInt(row.count);
|
|
14480
|
+
}
|
|
14481
|
+
return {
|
|
14482
|
+
totalRecords,
|
|
14483
|
+
successRate: totalRecords > 0 ? successCount / totalRecords : 0,
|
|
14484
|
+
avgDurationMs,
|
|
14485
|
+
byStrategy
|
|
14486
|
+
};
|
|
14487
|
+
}
|
|
14756
14488
|
var init_projections = __esm(() => {
|
|
14757
14489
|
init_streams();
|
|
14758
14490
|
init_esm2();
|
|
@@ -15476,10 +15208,279 @@ var init_migrations = __esm(() => {
|
|
|
15476
15208
|
CREATE INDEX IF NOT EXISTS idx_deferred_resolved ON deferred(resolved);
|
|
15477
15209
|
`,
|
|
15478
15210
|
down: `DROP TABLE IF EXISTS deferred;`
|
|
15211
|
+
},
|
|
15212
|
+
{
|
|
15213
|
+
version: 3,
|
|
15214
|
+
description: "Add eval_records table for learning system",
|
|
15215
|
+
up: `
|
|
15216
|
+
CREATE TABLE IF NOT EXISTS eval_records (
|
|
15217
|
+
id TEXT PRIMARY KEY,
|
|
15218
|
+
project_key TEXT NOT NULL,
|
|
15219
|
+
task TEXT NOT NULL,
|
|
15220
|
+
context TEXT,
|
|
15221
|
+
strategy TEXT NOT NULL,
|
|
15222
|
+
epic_title TEXT NOT NULL,
|
|
15223
|
+
subtasks JSONB NOT NULL,
|
|
15224
|
+
outcomes JSONB,
|
|
15225
|
+
overall_success BOOLEAN,
|
|
15226
|
+
total_duration_ms INTEGER,
|
|
15227
|
+
total_errors INTEGER,
|
|
15228
|
+
human_accepted BOOLEAN,
|
|
15229
|
+
human_modified BOOLEAN,
|
|
15230
|
+
human_notes TEXT,
|
|
15231
|
+
file_overlap_count INTEGER,
|
|
15232
|
+
scope_accuracy REAL,
|
|
15233
|
+
time_balance_ratio REAL,
|
|
15234
|
+
created_at BIGINT NOT NULL,
|
|
15235
|
+
updated_at BIGINT NOT NULL
|
|
15236
|
+
);
|
|
15237
|
+
CREATE INDEX IF NOT EXISTS idx_eval_records_project ON eval_records(project_key);
|
|
15238
|
+
CREATE INDEX IF NOT EXISTS idx_eval_records_strategy ON eval_records(strategy);
|
|
15239
|
+
`,
|
|
15240
|
+
down: `DROP TABLE IF EXISTS eval_records;`
|
|
15241
|
+
},
|
|
15242
|
+
{
|
|
15243
|
+
version: 4,
|
|
15244
|
+
description: "Add swarm_contexts table for context recovery",
|
|
15245
|
+
up: `
|
|
15246
|
+
CREATE TABLE IF NOT EXISTS swarm_contexts (
|
|
15247
|
+
id TEXT PRIMARY KEY,
|
|
15248
|
+
epic_id TEXT NOT NULL,
|
|
15249
|
+
bead_id TEXT NOT NULL,
|
|
15250
|
+
strategy TEXT NOT NULL,
|
|
15251
|
+
files JSONB NOT NULL,
|
|
15252
|
+
dependencies JSONB NOT NULL,
|
|
15253
|
+
directives JSONB NOT NULL,
|
|
15254
|
+
recovery JSONB NOT NULL,
|
|
15255
|
+
created_at BIGINT NOT NULL,
|
|
15256
|
+
updated_at BIGINT NOT NULL
|
|
15257
|
+
);
|
|
15258
|
+
CREATE INDEX IF NOT EXISTS idx_swarm_contexts_epic ON swarm_contexts(epic_id);
|
|
15259
|
+
CREATE INDEX IF NOT EXISTS idx_swarm_contexts_bead ON swarm_contexts(bead_id);
|
|
15260
|
+
`,
|
|
15261
|
+
down: `DROP TABLE IF EXISTS swarm_contexts;`
|
|
15479
15262
|
}
|
|
15480
15263
|
];
|
|
15481
15264
|
});
|
|
15482
15265
|
|
|
15266
|
+
// src/streams/swarm-mail.ts
|
|
15267
|
+
function generateSwarmAgentName() {
|
|
15268
|
+
const adj = ADJECTIVES2[Math.floor(Math.random() * ADJECTIVES2.length)];
|
|
15269
|
+
const noun = NOUNS2[Math.floor(Math.random() * NOUNS2.length)];
|
|
15270
|
+
return `${adj}${noun}`;
|
|
15271
|
+
}
|
|
15272
|
+
async function initSwarmAgent(options2) {
|
|
15273
|
+
const {
|
|
15274
|
+
projectPath,
|
|
15275
|
+
agentName = generateSwarmAgentName(),
|
|
15276
|
+
program = "opencode",
|
|
15277
|
+
model = "unknown",
|
|
15278
|
+
taskDescription
|
|
15279
|
+
} = options2;
|
|
15280
|
+
await registerAgent(projectPath, agentName, { program, model, taskDescription }, projectPath);
|
|
15281
|
+
return {
|
|
15282
|
+
projectKey: projectPath,
|
|
15283
|
+
agentName
|
|
15284
|
+
};
|
|
15285
|
+
}
|
|
15286
|
+
async function sendSwarmMessage(options2) {
|
|
15287
|
+
const {
|
|
15288
|
+
projectPath,
|
|
15289
|
+
fromAgent,
|
|
15290
|
+
toAgents,
|
|
15291
|
+
subject,
|
|
15292
|
+
body,
|
|
15293
|
+
threadId,
|
|
15294
|
+
importance = "normal",
|
|
15295
|
+
ackRequired = false
|
|
15296
|
+
} = options2;
|
|
15297
|
+
await sendMessage(projectPath, fromAgent, toAgents, subject, body, { threadId, importance, ackRequired }, projectPath);
|
|
15298
|
+
const { getDatabase: getDatabase2 } = await Promise.resolve().then(() => (init_streams(), exports_streams));
|
|
15299
|
+
const db = await getDatabase2(projectPath);
|
|
15300
|
+
const result = await db.query(`SELECT id FROM messages
|
|
15301
|
+
WHERE project_key = $1 AND from_agent = $2 AND subject = $3
|
|
15302
|
+
ORDER BY created_at DESC LIMIT 1`, [projectPath, fromAgent, subject]);
|
|
15303
|
+
const messageId = result.rows[0]?.id ?? 0;
|
|
15304
|
+
return {
|
|
15305
|
+
success: true,
|
|
15306
|
+
messageId,
|
|
15307
|
+
threadId,
|
|
15308
|
+
recipientCount: toAgents.length
|
|
15309
|
+
};
|
|
15310
|
+
}
|
|
15311
|
+
async function getSwarmInbox(options2) {
|
|
15312
|
+
const {
|
|
15313
|
+
projectPath,
|
|
15314
|
+
agentName,
|
|
15315
|
+
limit = MAX_INBOX_LIMIT2,
|
|
15316
|
+
urgentOnly = false,
|
|
15317
|
+
unreadOnly = false,
|
|
15318
|
+
includeBodies = false
|
|
15319
|
+
} = options2;
|
|
15320
|
+
const effectiveLimit = Math.min(limit, MAX_INBOX_LIMIT2);
|
|
15321
|
+
const messages = await getInbox(projectPath, agentName, {
|
|
15322
|
+
limit: effectiveLimit,
|
|
15323
|
+
urgentOnly,
|
|
15324
|
+
unreadOnly,
|
|
15325
|
+
includeBodies
|
|
15326
|
+
}, projectPath);
|
|
15327
|
+
return {
|
|
15328
|
+
messages: messages.map((m) => ({
|
|
15329
|
+
id: m.id,
|
|
15330
|
+
from_agent: m.from_agent,
|
|
15331
|
+
subject: m.subject,
|
|
15332
|
+
body: includeBodies ? m.body : undefined,
|
|
15333
|
+
thread_id: m.thread_id,
|
|
15334
|
+
importance: m.importance,
|
|
15335
|
+
created_at: m.created_at
|
|
15336
|
+
})),
|
|
15337
|
+
total: messages.length
|
|
15338
|
+
};
|
|
15339
|
+
}
|
|
15340
|
+
async function readSwarmMessage(options2) {
|
|
15341
|
+
const { projectPath, messageId, agentName, markAsRead = false } = options2;
|
|
15342
|
+
const message = await getMessage(projectPath, messageId, projectPath);
|
|
15343
|
+
if (!message) {
|
|
15344
|
+
return null;
|
|
15345
|
+
}
|
|
15346
|
+
if (markAsRead && agentName) {
|
|
15347
|
+
await appendEvent(createEvent("message_read", {
|
|
15348
|
+
project_key: projectPath,
|
|
15349
|
+
message_id: messageId,
|
|
15350
|
+
agent_name: agentName
|
|
15351
|
+
}), projectPath);
|
|
15352
|
+
}
|
|
15353
|
+
return {
|
|
15354
|
+
id: message.id,
|
|
15355
|
+
from_agent: message.from_agent,
|
|
15356
|
+
subject: message.subject,
|
|
15357
|
+
body: message.body,
|
|
15358
|
+
thread_id: message.thread_id,
|
|
15359
|
+
importance: message.importance,
|
|
15360
|
+
created_at: message.created_at
|
|
15361
|
+
};
|
|
15362
|
+
}
|
|
15363
|
+
async function reserveSwarmFiles(options2) {
|
|
15364
|
+
const {
|
|
15365
|
+
projectPath,
|
|
15366
|
+
agentName,
|
|
15367
|
+
paths,
|
|
15368
|
+
reason,
|
|
15369
|
+
exclusive = true,
|
|
15370
|
+
ttlSeconds = DEFAULT_TTL_SECONDS2
|
|
15371
|
+
} = options2;
|
|
15372
|
+
const conflicts = await checkConflicts(projectPath, agentName, paths, projectPath);
|
|
15373
|
+
await reserveFiles(projectPath, agentName, paths, { reason, exclusive, ttlSeconds }, projectPath);
|
|
15374
|
+
const reservations = await getActiveReservations(projectPath, projectPath, agentName);
|
|
15375
|
+
const granted = reservations.filter((r) => paths.includes(r.path_pattern)).map((r) => ({
|
|
15376
|
+
id: r.id,
|
|
15377
|
+
path_pattern: r.path_pattern,
|
|
15378
|
+
exclusive: r.exclusive,
|
|
15379
|
+
expiresAt: r.expires_at
|
|
15380
|
+
}));
|
|
15381
|
+
return {
|
|
15382
|
+
granted,
|
|
15383
|
+
conflicts: conflicts.map((c) => ({
|
|
15384
|
+
path: c.path,
|
|
15385
|
+
holder: c.holder,
|
|
15386
|
+
pattern: c.pattern
|
|
15387
|
+
}))
|
|
15388
|
+
};
|
|
15389
|
+
}
|
|
15390
|
+
async function releaseSwarmFiles(options2) {
|
|
15391
|
+
const { projectPath, agentName, paths, reservationIds } = options2;
|
|
15392
|
+
const currentReservations = await getActiveReservations(projectPath, projectPath, agentName);
|
|
15393
|
+
let releaseCount = 0;
|
|
15394
|
+
if (paths && paths.length > 0) {
|
|
15395
|
+
releaseCount = currentReservations.filter((r) => paths.includes(r.path_pattern)).length;
|
|
15396
|
+
} else if (reservationIds && reservationIds.length > 0) {
|
|
15397
|
+
releaseCount = currentReservations.filter((r) => reservationIds.includes(r.id)).length;
|
|
15398
|
+
} else {
|
|
15399
|
+
releaseCount = currentReservations.length;
|
|
15400
|
+
}
|
|
15401
|
+
await appendEvent(createEvent("file_released", {
|
|
15402
|
+
project_key: projectPath,
|
|
15403
|
+
agent_name: agentName,
|
|
15404
|
+
paths,
|
|
15405
|
+
reservation_ids: reservationIds
|
|
15406
|
+
}), projectPath);
|
|
15407
|
+
return {
|
|
15408
|
+
released: releaseCount,
|
|
15409
|
+
releasedAt: Date.now()
|
|
15410
|
+
};
|
|
15411
|
+
}
|
|
15412
|
+
async function acknowledgeSwarmMessage(options2) {
|
|
15413
|
+
const { projectPath, messageId, agentName } = options2;
|
|
15414
|
+
const timestamp = Date.now();
|
|
15415
|
+
await appendEvent(createEvent("message_acked", {
|
|
15416
|
+
project_key: projectPath,
|
|
15417
|
+
message_id: messageId,
|
|
15418
|
+
agent_name: agentName
|
|
15419
|
+
}), projectPath);
|
|
15420
|
+
return {
|
|
15421
|
+
acknowledged: true,
|
|
15422
|
+
acknowledgedAt: new Date(timestamp).toISOString()
|
|
15423
|
+
};
|
|
15424
|
+
}
|
|
15425
|
+
async function checkSwarmHealth(projectPath) {
|
|
15426
|
+
const healthy = await isDatabaseHealthy(projectPath);
|
|
15427
|
+
if (!healthy) {
|
|
15428
|
+
return {
|
|
15429
|
+
healthy: false,
|
|
15430
|
+
database: "disconnected"
|
|
15431
|
+
};
|
|
15432
|
+
}
|
|
15433
|
+
const stats = await getDatabaseStats(projectPath);
|
|
15434
|
+
return {
|
|
15435
|
+
healthy: true,
|
|
15436
|
+
database: "connected",
|
|
15437
|
+
stats
|
|
15438
|
+
};
|
|
15439
|
+
}
|
|
15440
|
+
var MAX_INBOX_LIMIT2 = 5, DEFAULT_TTL_SECONDS2 = 3600, ADJECTIVES2, NOUNS2;
|
|
15441
|
+
var init_swarm_mail = __esm(() => {
|
|
15442
|
+
init_events();
|
|
15443
|
+
init_streams();
|
|
15444
|
+
init_projections();
|
|
15445
|
+
init_store();
|
|
15446
|
+
ADJECTIVES2 = [
|
|
15447
|
+
"Blue",
|
|
15448
|
+
"Red",
|
|
15449
|
+
"Green",
|
|
15450
|
+
"Gold",
|
|
15451
|
+
"Silver",
|
|
15452
|
+
"Swift",
|
|
15453
|
+
"Bright",
|
|
15454
|
+
"Dark",
|
|
15455
|
+
"Calm",
|
|
15456
|
+
"Bold",
|
|
15457
|
+
"Wise",
|
|
15458
|
+
"Quick",
|
|
15459
|
+
"Warm",
|
|
15460
|
+
"Cool",
|
|
15461
|
+
"Pure",
|
|
15462
|
+
"Wild"
|
|
15463
|
+
];
|
|
15464
|
+
NOUNS2 = [
|
|
15465
|
+
"Lake",
|
|
15466
|
+
"Stone",
|
|
15467
|
+
"River",
|
|
15468
|
+
"Mountain",
|
|
15469
|
+
"Forest",
|
|
15470
|
+
"Ocean",
|
|
15471
|
+
"Star",
|
|
15472
|
+
"Moon",
|
|
15473
|
+
"Wind",
|
|
15474
|
+
"Fire",
|
|
15475
|
+
"Cloud",
|
|
15476
|
+
"Storm",
|
|
15477
|
+
"Dawn",
|
|
15478
|
+
"Dusk",
|
|
15479
|
+
"Hawk",
|
|
15480
|
+
"Wolf"
|
|
15481
|
+
];
|
|
15482
|
+
});
|
|
15483
|
+
|
|
15483
15484
|
// src/streams/index.ts
|
|
15484
15485
|
var exports_streams = {};
|
|
15485
15486
|
__export(exports_streams, {
|
|
@@ -15494,7 +15495,7 @@ __export(exports_streams, {
|
|
|
15494
15495
|
reserveSwarmFiles: () => reserveSwarmFiles,
|
|
15495
15496
|
reserveFiles: () => reserveFiles,
|
|
15496
15497
|
reserveAgentFiles: () => reserveAgentFiles,
|
|
15497
|
-
replayEventsBatched: () =>
|
|
15498
|
+
replayEventsBatched: () => replayEventsBatched2,
|
|
15498
15499
|
replayEvents: () => replayEvents,
|
|
15499
15500
|
releaseSwarmFiles: () => releaseSwarmFiles,
|
|
15500
15501
|
releaseAgentFiles: () => releaseAgentFiles,
|
|
@@ -15516,6 +15517,8 @@ __export(exports_streams, {
|
|
|
15516
15517
|
getLatestSequence: () => getLatestSequence,
|
|
15517
15518
|
getInbox: () => getInbox,
|
|
15518
15519
|
getEventTimeline: () => getEventTimeline,
|
|
15520
|
+
getEvalStats: () => getEvalStats,
|
|
15521
|
+
getEvalRecords: () => getEvalRecords,
|
|
15519
15522
|
getDatabaseStats: () => getDatabaseStats,
|
|
15520
15523
|
getDatabasePath: () => getDatabasePath,
|
|
15521
15524
|
getDatabase: () => getDatabase,
|
|
@@ -15543,12 +15546,17 @@ __export(exports_streams, {
|
|
|
15543
15546
|
TaskProgressEventSchema: () => TaskProgressEventSchema,
|
|
15544
15547
|
TaskCompletedEventSchema: () => TaskCompletedEventSchema,
|
|
15545
15548
|
TaskBlockedEventSchema: () => TaskBlockedEventSchema,
|
|
15549
|
+
SwarmRecoveredEventSchema: () => SwarmRecoveredEventSchema,
|
|
15550
|
+
SwarmCheckpointedEventSchema: () => SwarmCheckpointedEventSchema,
|
|
15551
|
+
SubtaskOutcomeEventSchema: () => SubtaskOutcomeEventSchema,
|
|
15546
15552
|
PGlite: () => PGlite,
|
|
15547
15553
|
MessageSentEventSchema: () => MessageSentEventSchema,
|
|
15548
15554
|
MessageReadEventSchema: () => MessageReadEventSchema,
|
|
15549
15555
|
MessageAckedEventSchema: () => MessageAckedEventSchema,
|
|
15556
|
+
HumanFeedbackEventSchema: () => HumanFeedbackEventSchema,
|
|
15550
15557
|
FileReservedEventSchema: () => FileReservedEventSchema,
|
|
15551
15558
|
FileReleasedEventSchema: () => FileReleasedEventSchema,
|
|
15559
|
+
DecompositionGeneratedEventSchema: () => DecompositionGeneratedEventSchema,
|
|
15552
15560
|
BaseEventSchema: () => BaseEventSchema,
|
|
15553
15561
|
AgentRegisteredEventSchema: () => AgentRegisteredEventSchema,
|
|
15554
15562
|
AgentEventSchema: () => AgentEventSchema,
|
|
@@ -15829,271 +15837,627 @@ async function isDatabaseHealthy(projectPath) {
|
|
|
15829
15837
|
return false;
|
|
15830
15838
|
}
|
|
15831
15839
|
}
|
|
15832
|
-
async function getDatabaseStats(projectPath) {
|
|
15840
|
+
async function getDatabaseStats(projectPath) {
|
|
15841
|
+
const db = await getDatabase(projectPath);
|
|
15842
|
+
const [events2, agents, messages, reservations] = await Promise.all([
|
|
15843
|
+
db.query("SELECT COUNT(*) as count FROM events"),
|
|
15844
|
+
db.query("SELECT COUNT(*) as count FROM agents"),
|
|
15845
|
+
db.query("SELECT COUNT(*) as count FROM messages"),
|
|
15846
|
+
db.query("SELECT COUNT(*) as count FROM reservations WHERE released_at IS NULL")
|
|
15847
|
+
]);
|
|
15848
|
+
return {
|
|
15849
|
+
events: parseInt(events2.rows[0]?.count || "0"),
|
|
15850
|
+
agents: parseInt(agents.rows[0]?.count || "0"),
|
|
15851
|
+
messages: parseInt(messages.rows[0]?.count || "0"),
|
|
15852
|
+
reservations: parseInt(reservations.rows[0]?.count || "0")
|
|
15853
|
+
};
|
|
15854
|
+
}
|
|
15855
|
+
function handleExit() {
|
|
15856
|
+
const dbsToClose = Array.from(instances.values());
|
|
15857
|
+
for (const db of dbsToClose) {
|
|
15858
|
+
try {
|
|
15859
|
+
db.close().catch(() => {});
|
|
15860
|
+
} catch {}
|
|
15861
|
+
}
|
|
15862
|
+
}
|
|
15863
|
+
var SLOW_QUERY_THRESHOLD_MS = 100, DEBUG_LOG_PATH, instances, pendingInstances, schemaInitialized, degradedInstances, lastAccess, MAX_CACHE_SIZE = 10;
|
|
15864
|
+
var init_streams = __esm(() => {
|
|
15865
|
+
init_agent_mail();
|
|
15866
|
+
init_debug();
|
|
15867
|
+
init_events();
|
|
15868
|
+
init_migrations();
|
|
15869
|
+
init_projections();
|
|
15870
|
+
init_store();
|
|
15871
|
+
init_swarm_mail();
|
|
15872
|
+
DEBUG_LOG_PATH = join(homedir(), ".opencode", "streams-debug.log");
|
|
15873
|
+
instances = new Map;
|
|
15874
|
+
pendingInstances = new Map;
|
|
15875
|
+
schemaInitialized = new Map;
|
|
15876
|
+
degradedInstances = new Map;
|
|
15877
|
+
lastAccess = new Map;
|
|
15878
|
+
process.on("exit", handleExit);
|
|
15879
|
+
process.on("SIGINT", () => {
|
|
15880
|
+
handleExit();
|
|
15881
|
+
process.exit(0);
|
|
15882
|
+
});
|
|
15883
|
+
process.on("SIGTERM", () => {
|
|
15884
|
+
handleExit();
|
|
15885
|
+
process.exit(0);
|
|
15886
|
+
});
|
|
15887
|
+
});
|
|
15888
|
+
|
|
15889
|
+
// src/streams/store.ts
|
|
15890
|
+
function parseTimestamp(timestamp) {
|
|
15891
|
+
const ts = parseInt(timestamp, 10);
|
|
15892
|
+
if (Number.isNaN(ts)) {
|
|
15893
|
+
throw new Error(`[SwarmMail] Invalid timestamp: ${timestamp}`);
|
|
15894
|
+
}
|
|
15895
|
+
if (ts > Number.MAX_SAFE_INTEGER) {
|
|
15896
|
+
console.warn(`[SwarmMail] Timestamp ${timestamp} exceeds MAX_SAFE_INTEGER (year 2286+), precision may be lost`);
|
|
15897
|
+
}
|
|
15898
|
+
return ts;
|
|
15899
|
+
}
|
|
15900
|
+
async function appendEvent(event, projectPath) {
|
|
15901
|
+
const db = await getDatabase(projectPath);
|
|
15902
|
+
const { type, project_key, timestamp, ...rest } = event;
|
|
15903
|
+
console.log("[SwarmMail] Appending event", {
|
|
15904
|
+
type,
|
|
15905
|
+
projectKey: project_key,
|
|
15906
|
+
timestamp
|
|
15907
|
+
});
|
|
15908
|
+
const result = await db.query(`INSERT INTO events (type, project_key, timestamp, data)
|
|
15909
|
+
VALUES ($1, $2, $3, $4)
|
|
15910
|
+
RETURNING id, sequence`, [type, project_key, timestamp, JSON.stringify(rest)]);
|
|
15911
|
+
const row = result.rows[0];
|
|
15912
|
+
if (!row) {
|
|
15913
|
+
throw new Error("Failed to insert event - no row returned");
|
|
15914
|
+
}
|
|
15915
|
+
const { id, sequence } = row;
|
|
15916
|
+
console.log("[SwarmMail] Event appended", {
|
|
15917
|
+
type,
|
|
15918
|
+
id,
|
|
15919
|
+
sequence,
|
|
15920
|
+
projectKey: project_key
|
|
15921
|
+
});
|
|
15922
|
+
console.debug("[SwarmMail] Updating materialized views", { type, id });
|
|
15923
|
+
await updateMaterializedViews(db, { ...event, id, sequence });
|
|
15924
|
+
return { ...event, id, sequence };
|
|
15925
|
+
}
|
|
15926
|
+
async function appendEvents(events2, projectPath) {
|
|
15927
|
+
return withTiming("appendEvents", async () => {
|
|
15928
|
+
const db = await getDatabase(projectPath);
|
|
15929
|
+
const results = [];
|
|
15930
|
+
await db.exec("BEGIN");
|
|
15931
|
+
try {
|
|
15932
|
+
for (const event of events2) {
|
|
15933
|
+
const { type, project_key, timestamp, ...rest } = event;
|
|
15934
|
+
const result = await db.query(`INSERT INTO events (type, project_key, timestamp, data)
|
|
15935
|
+
VALUES ($1, $2, $3, $4)
|
|
15936
|
+
RETURNING id, sequence`, [type, project_key, timestamp, JSON.stringify(rest)]);
|
|
15937
|
+
const row = result.rows[0];
|
|
15938
|
+
if (!row) {
|
|
15939
|
+
throw new Error("Failed to insert event - no row returned");
|
|
15940
|
+
}
|
|
15941
|
+
const { id, sequence } = row;
|
|
15942
|
+
const enrichedEvent = { ...event, id, sequence };
|
|
15943
|
+
await updateMaterializedViews(db, enrichedEvent);
|
|
15944
|
+
results.push(enrichedEvent);
|
|
15945
|
+
}
|
|
15946
|
+
await db.exec("COMMIT");
|
|
15947
|
+
} catch (e) {
|
|
15948
|
+
let rollbackError = null;
|
|
15949
|
+
try {
|
|
15950
|
+
await db.exec("ROLLBACK");
|
|
15951
|
+
} catch (rbErr) {
|
|
15952
|
+
rollbackError = rbErr;
|
|
15953
|
+
console.error("[SwarmMail] ROLLBACK failed:", rbErr);
|
|
15954
|
+
}
|
|
15955
|
+
if (rollbackError) {
|
|
15956
|
+
const compositeError = new Error(`Transaction failed: ${e instanceof Error ? e.message : String(e)}. ` + `ROLLBACK also failed: ${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)}. ` + `Database may be in inconsistent state.`);
|
|
15957
|
+
compositeError.originalError = e;
|
|
15958
|
+
compositeError.rollbackError = rollbackError;
|
|
15959
|
+
throw compositeError;
|
|
15960
|
+
}
|
|
15961
|
+
throw e;
|
|
15962
|
+
}
|
|
15963
|
+
return results;
|
|
15964
|
+
});
|
|
15965
|
+
}
|
|
15966
|
+
async function readEvents(options2 = {}, projectPath) {
|
|
15967
|
+
return withTiming("readEvents", async () => {
|
|
15968
|
+
const db = await getDatabase(projectPath);
|
|
15969
|
+
const conditions = [];
|
|
15970
|
+
const params = [];
|
|
15971
|
+
let paramIndex = 1;
|
|
15972
|
+
if (options2.projectKey) {
|
|
15973
|
+
conditions.push(`project_key = $${paramIndex++}`);
|
|
15974
|
+
params.push(options2.projectKey);
|
|
15975
|
+
}
|
|
15976
|
+
if (options2.types && options2.types.length > 0) {
|
|
15977
|
+
conditions.push(`type = ANY($${paramIndex++})`);
|
|
15978
|
+
params.push(options2.types);
|
|
15979
|
+
}
|
|
15980
|
+
if (options2.since !== undefined) {
|
|
15981
|
+
conditions.push(`timestamp >= $${paramIndex++}`);
|
|
15982
|
+
params.push(options2.since);
|
|
15983
|
+
}
|
|
15984
|
+
if (options2.until !== undefined) {
|
|
15985
|
+
conditions.push(`timestamp <= $${paramIndex++}`);
|
|
15986
|
+
params.push(options2.until);
|
|
15987
|
+
}
|
|
15988
|
+
if (options2.afterSequence !== undefined) {
|
|
15989
|
+
conditions.push(`sequence > $${paramIndex++}`);
|
|
15990
|
+
params.push(options2.afterSequence);
|
|
15991
|
+
}
|
|
15992
|
+
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
15993
|
+
let query = `
|
|
15994
|
+
SELECT id, type, project_key, timestamp, sequence, data
|
|
15995
|
+
FROM events
|
|
15996
|
+
${whereClause}
|
|
15997
|
+
ORDER BY sequence ASC
|
|
15998
|
+
`;
|
|
15999
|
+
if (options2.limit) {
|
|
16000
|
+
query += ` LIMIT $${paramIndex++}`;
|
|
16001
|
+
params.push(options2.limit);
|
|
16002
|
+
}
|
|
16003
|
+
if (options2.offset) {
|
|
16004
|
+
query += ` OFFSET $${paramIndex++}`;
|
|
16005
|
+
params.push(options2.offset);
|
|
16006
|
+
}
|
|
16007
|
+
const result = await db.query(query, params);
|
|
16008
|
+
return result.rows.map((row) => {
|
|
16009
|
+
const data = typeof row.data === "string" ? JSON.parse(row.data) : row.data;
|
|
16010
|
+
return {
|
|
16011
|
+
id: row.id,
|
|
16012
|
+
type: row.type,
|
|
16013
|
+
project_key: row.project_key,
|
|
16014
|
+
timestamp: parseTimestamp(row.timestamp),
|
|
16015
|
+
sequence: row.sequence,
|
|
16016
|
+
...data
|
|
16017
|
+
};
|
|
16018
|
+
});
|
|
16019
|
+
});
|
|
16020
|
+
}
|
|
16021
|
+
async function getLatestSequence(projectKey, projectPath) {
|
|
15833
16022
|
const db = await getDatabase(projectPath);
|
|
15834
|
-
const
|
|
15835
|
-
|
|
15836
|
-
|
|
15837
|
-
|
|
15838
|
-
db.query("SELECT COUNT(*) as count FROM reservations WHERE released_at IS NULL")
|
|
15839
|
-
]);
|
|
15840
|
-
return {
|
|
15841
|
-
events: parseInt(events2.rows[0]?.count || "0"),
|
|
15842
|
-
agents: parseInt(agents.rows[0]?.count || "0"),
|
|
15843
|
-
messages: parseInt(messages.rows[0]?.count || "0"),
|
|
15844
|
-
reservations: parseInt(reservations.rows[0]?.count || "0")
|
|
15845
|
-
};
|
|
15846
|
-
}
|
|
15847
|
-
function handleExit() {
|
|
15848
|
-
const dbsToClose = Array.from(instances.values());
|
|
15849
|
-
for (const db of dbsToClose) {
|
|
15850
|
-
try {
|
|
15851
|
-
db.close().catch(() => {});
|
|
15852
|
-
} catch {}
|
|
15853
|
-
}
|
|
16023
|
+
const query = projectKey ? "SELECT MAX(sequence) as seq FROM events WHERE project_key = $1" : "SELECT MAX(sequence) as seq FROM events";
|
|
16024
|
+
const params = projectKey ? [projectKey] : [];
|
|
16025
|
+
const result = await db.query(query, params);
|
|
16026
|
+
return result.rows[0]?.seq ?? 0;
|
|
15854
16027
|
}
|
|
15855
|
-
|
|
15856
|
-
|
|
15857
|
-
|
|
15858
|
-
|
|
15859
|
-
|
|
15860
|
-
|
|
15861
|
-
|
|
15862
|
-
|
|
15863
|
-
|
|
15864
|
-
|
|
15865
|
-
|
|
15866
|
-
|
|
15867
|
-
|
|
15868
|
-
|
|
15869
|
-
|
|
15870
|
-
|
|
15871
|
-
|
|
15872
|
-
|
|
15873
|
-
|
|
15874
|
-
|
|
15875
|
-
|
|
15876
|
-
|
|
15877
|
-
|
|
16028
|
+
async function replayEvents(options2 = {}, projectPath) {
|
|
16029
|
+
return withTiming("replayEvents", async () => {
|
|
16030
|
+
const startTime = Date.now();
|
|
16031
|
+
const db = await getDatabase(projectPath);
|
|
16032
|
+
if (options2.clearViews) {
|
|
16033
|
+
if (options2.projectKey) {
|
|
16034
|
+
await db.query(`DELETE FROM message_recipients WHERE message_id IN (
|
|
16035
|
+
SELECT id FROM messages WHERE project_key = $1
|
|
16036
|
+
)`, [options2.projectKey]);
|
|
16037
|
+
await db.query(`DELETE FROM messages WHERE project_key = $1`, [
|
|
16038
|
+
options2.projectKey
|
|
16039
|
+
]);
|
|
16040
|
+
await db.query(`DELETE FROM reservations WHERE project_key = $1`, [
|
|
16041
|
+
options2.projectKey
|
|
16042
|
+
]);
|
|
16043
|
+
await db.query(`DELETE FROM agents WHERE project_key = $1`, [
|
|
16044
|
+
options2.projectKey
|
|
16045
|
+
]);
|
|
16046
|
+
} else {
|
|
16047
|
+
await db.exec(`
|
|
16048
|
+
DELETE FROM message_recipients;
|
|
16049
|
+
DELETE FROM messages;
|
|
16050
|
+
DELETE FROM reservations;
|
|
16051
|
+
DELETE FROM agents;
|
|
16052
|
+
`);
|
|
16053
|
+
}
|
|
16054
|
+
}
|
|
16055
|
+
const events2 = await readEvents({
|
|
16056
|
+
projectKey: options2.projectKey,
|
|
16057
|
+
afterSequence: options2.fromSequence
|
|
16058
|
+
}, projectPath);
|
|
16059
|
+
for (const event of events2) {
|
|
16060
|
+
await updateMaterializedViews(db, event);
|
|
16061
|
+
}
|
|
16062
|
+
return {
|
|
16063
|
+
eventsReplayed: events2.length,
|
|
16064
|
+
duration: Date.now() - startTime
|
|
16065
|
+
};
|
|
15878
16066
|
});
|
|
15879
|
-
});
|
|
15880
|
-
|
|
15881
|
-
// src/streams/swarm-mail.ts
|
|
15882
|
-
function generateSwarmAgentName() {
|
|
15883
|
-
const adj = ADJECTIVES2[Math.floor(Math.random() * ADJECTIVES2.length)];
|
|
15884
|
-
const noun = NOUNS2[Math.floor(Math.random() * NOUNS2.length)];
|
|
15885
|
-
return `${adj}${noun}`;
|
|
15886
16067
|
}
|
|
15887
|
-
async function
|
|
15888
|
-
|
|
15889
|
-
|
|
15890
|
-
|
|
15891
|
-
|
|
15892
|
-
|
|
15893
|
-
|
|
15894
|
-
|
|
15895
|
-
|
|
15896
|
-
|
|
15897
|
-
|
|
15898
|
-
|
|
15899
|
-
|
|
16068
|
+
async function replayEventsBatched2(projectKey, onBatch, options2 = {}, projectPath) {
|
|
16069
|
+
return withTiming("replayEventsBatched", async () => {
|
|
16070
|
+
const startTime = Date.now();
|
|
16071
|
+
const batchSize = options2.batchSize ?? 1000;
|
|
16072
|
+
const fromSequence = options2.fromSequence ?? 0;
|
|
16073
|
+
const db = await getDatabase(projectPath);
|
|
16074
|
+
if (options2.clearViews) {
|
|
16075
|
+
await db.query(`DELETE FROM message_recipients WHERE message_id IN (
|
|
16076
|
+
SELECT id FROM messages WHERE project_key = $1
|
|
16077
|
+
)`, [projectKey]);
|
|
16078
|
+
await db.query(`DELETE FROM messages WHERE project_key = $1`, [
|
|
16079
|
+
projectKey
|
|
16080
|
+
]);
|
|
16081
|
+
await db.query(`DELETE FROM reservations WHERE project_key = $1`, [
|
|
16082
|
+
projectKey
|
|
16083
|
+
]);
|
|
16084
|
+
await db.query(`DELETE FROM agents WHERE project_key = $1`, [projectKey]);
|
|
16085
|
+
}
|
|
16086
|
+
const countResult = await db.query(`SELECT COUNT(*) as count FROM events WHERE project_key = $1 AND sequence > $2`, [projectKey, fromSequence]);
|
|
16087
|
+
const total = parseInt(countResult.rows[0]?.count ?? "0");
|
|
16088
|
+
if (total === 0) {
|
|
16089
|
+
return { eventsReplayed: 0, duration: Date.now() - startTime };
|
|
16090
|
+
}
|
|
16091
|
+
let processed = 0;
|
|
16092
|
+
let offset = 0;
|
|
16093
|
+
while (processed < total) {
|
|
16094
|
+
const events2 = await readEvents({
|
|
16095
|
+
projectKey,
|
|
16096
|
+
afterSequence: fromSequence,
|
|
16097
|
+
limit: batchSize,
|
|
16098
|
+
offset
|
|
16099
|
+
}, projectPath);
|
|
16100
|
+
if (events2.length === 0)
|
|
16101
|
+
break;
|
|
16102
|
+
for (const event of events2) {
|
|
16103
|
+
await updateMaterializedViews(db, event);
|
|
16104
|
+
}
|
|
16105
|
+
processed += events2.length;
|
|
16106
|
+
const percent = Math.round(processed / total * 100);
|
|
16107
|
+
await onBatch(events2, { processed, total, percent });
|
|
16108
|
+
console.log(`[SwarmMail] Replaying events: ${processed}/${total} (${percent}%)`);
|
|
16109
|
+
offset += batchSize;
|
|
16110
|
+
}
|
|
16111
|
+
return {
|
|
16112
|
+
eventsReplayed: processed,
|
|
16113
|
+
duration: Date.now() - startTime
|
|
16114
|
+
};
|
|
16115
|
+
});
|
|
15900
16116
|
}
|
|
15901
|
-
async function
|
|
15902
|
-
|
|
15903
|
-
|
|
15904
|
-
|
|
15905
|
-
|
|
15906
|
-
|
|
15907
|
-
|
|
15908
|
-
|
|
15909
|
-
|
|
15910
|
-
|
|
15911
|
-
|
|
15912
|
-
|
|
15913
|
-
|
|
15914
|
-
|
|
15915
|
-
|
|
15916
|
-
|
|
15917
|
-
|
|
15918
|
-
|
|
15919
|
-
|
|
15920
|
-
|
|
15921
|
-
|
|
15922
|
-
|
|
15923
|
-
|
|
15924
|
-
|
|
16117
|
+
async function updateMaterializedViews(db, event) {
|
|
16118
|
+
try {
|
|
16119
|
+
switch (event.type) {
|
|
16120
|
+
case "agent_registered":
|
|
16121
|
+
await handleAgentRegistered(db, event);
|
|
16122
|
+
break;
|
|
16123
|
+
case "agent_active":
|
|
16124
|
+
await db.query(`UPDATE agents SET last_active_at = $1 WHERE project_key = $2 AND name = $3`, [event.timestamp, event.project_key, event.agent_name]);
|
|
16125
|
+
break;
|
|
16126
|
+
case "message_sent":
|
|
16127
|
+
await handleMessageSent(db, event);
|
|
16128
|
+
break;
|
|
16129
|
+
case "message_read":
|
|
16130
|
+
await db.query(`UPDATE message_recipients SET read_at = $1 WHERE message_id = $2 AND agent_name = $3`, [event.timestamp, event.message_id, event.agent_name]);
|
|
16131
|
+
break;
|
|
16132
|
+
case "message_acked":
|
|
16133
|
+
await db.query(`UPDATE message_recipients SET acked_at = $1 WHERE message_id = $2 AND agent_name = $3`, [event.timestamp, event.message_id, event.agent_name]);
|
|
16134
|
+
break;
|
|
16135
|
+
case "file_reserved":
|
|
16136
|
+
await handleFileReserved(db, event);
|
|
16137
|
+
break;
|
|
16138
|
+
case "file_released":
|
|
16139
|
+
await handleFileReleased(db, event);
|
|
16140
|
+
break;
|
|
16141
|
+
case "task_started":
|
|
16142
|
+
case "task_progress":
|
|
16143
|
+
case "task_completed":
|
|
16144
|
+
case "task_blocked":
|
|
16145
|
+
break;
|
|
16146
|
+
case "decomposition_generated":
|
|
16147
|
+
await handleDecompositionGenerated(db, event);
|
|
16148
|
+
break;
|
|
16149
|
+
case "subtask_outcome":
|
|
16150
|
+
await handleSubtaskOutcome(db, event);
|
|
16151
|
+
break;
|
|
16152
|
+
case "human_feedback":
|
|
16153
|
+
await handleHumanFeedback(db, event);
|
|
16154
|
+
break;
|
|
16155
|
+
case "swarm_checkpointed":
|
|
16156
|
+
await handleSwarmCheckpointed(db, event);
|
|
16157
|
+
break;
|
|
16158
|
+
case "swarm_recovered":
|
|
16159
|
+
await handleSwarmRecovered(db, event);
|
|
16160
|
+
break;
|
|
16161
|
+
}
|
|
16162
|
+
} catch (error45) {
|
|
16163
|
+
console.error("[SwarmMail] Failed to update materialized views", {
|
|
16164
|
+
eventType: event.type,
|
|
16165
|
+
eventId: event.id,
|
|
16166
|
+
error: error45
|
|
16167
|
+
});
|
|
16168
|
+
throw error45;
|
|
16169
|
+
}
|
|
15925
16170
|
}
|
|
15926
|
-
async function
|
|
15927
|
-
|
|
15928
|
-
|
|
15929
|
-
|
|
15930
|
-
|
|
15931
|
-
|
|
15932
|
-
|
|
15933
|
-
|
|
15934
|
-
|
|
15935
|
-
|
|
15936
|
-
|
|
15937
|
-
|
|
15938
|
-
|
|
15939
|
-
|
|
15940
|
-
|
|
15941
|
-
}, projectPath);
|
|
15942
|
-
return {
|
|
15943
|
-
messages: messages.map((m) => ({
|
|
15944
|
-
id: m.id,
|
|
15945
|
-
from_agent: m.from_agent,
|
|
15946
|
-
subject: m.subject,
|
|
15947
|
-
body: includeBodies ? m.body : undefined,
|
|
15948
|
-
thread_id: m.thread_id,
|
|
15949
|
-
importance: m.importance,
|
|
15950
|
-
created_at: m.created_at
|
|
15951
|
-
})),
|
|
15952
|
-
total: messages.length
|
|
15953
|
-
};
|
|
16171
|
+
async function handleAgentRegistered(db, event) {
|
|
16172
|
+
await db.query(`INSERT INTO agents (project_key, name, program, model, task_description, registered_at, last_active_at)
|
|
16173
|
+
VALUES ($1, $2, $3, $4, $5, $6, $6)
|
|
16174
|
+
ON CONFLICT (project_key, name) DO UPDATE SET
|
|
16175
|
+
program = EXCLUDED.program,
|
|
16176
|
+
model = EXCLUDED.model,
|
|
16177
|
+
task_description = EXCLUDED.task_description,
|
|
16178
|
+
last_active_at = EXCLUDED.last_active_at`, [
|
|
16179
|
+
event.project_key,
|
|
16180
|
+
event.agent_name,
|
|
16181
|
+
event.program,
|
|
16182
|
+
event.model,
|
|
16183
|
+
event.task_description || null,
|
|
16184
|
+
event.timestamp
|
|
16185
|
+
]);
|
|
15954
16186
|
}
|
|
15955
|
-
async function
|
|
15956
|
-
|
|
15957
|
-
|
|
15958
|
-
|
|
15959
|
-
|
|
16187
|
+
async function handleMessageSent(db, event) {
|
|
16188
|
+
console.log("[SwarmMail] Handling message sent event", {
|
|
16189
|
+
from: event.from_agent,
|
|
16190
|
+
to: event.to_agents,
|
|
16191
|
+
subject: event.subject,
|
|
16192
|
+
projectKey: event.project_key
|
|
16193
|
+
});
|
|
16194
|
+
const result = await db.query(`INSERT INTO messages (project_key, from_agent, subject, body, thread_id, importance, ack_required, created_at)
|
|
16195
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
|
16196
|
+
RETURNING id`, [
|
|
16197
|
+
event.project_key,
|
|
16198
|
+
event.from_agent,
|
|
16199
|
+
event.subject,
|
|
16200
|
+
event.body,
|
|
16201
|
+
event.thread_id || null,
|
|
16202
|
+
event.importance,
|
|
16203
|
+
event.ack_required,
|
|
16204
|
+
event.timestamp
|
|
16205
|
+
]);
|
|
16206
|
+
const msgRow = result.rows[0];
|
|
16207
|
+
if (!msgRow) {
|
|
16208
|
+
throw new Error("Failed to insert message - no row returned");
|
|
15960
16209
|
}
|
|
15961
|
-
|
|
15962
|
-
|
|
15963
|
-
|
|
15964
|
-
|
|
15965
|
-
|
|
15966
|
-
|
|
16210
|
+
const messageId = msgRow.id;
|
|
16211
|
+
if (event.to_agents.length > 0) {
|
|
16212
|
+
const values = event.to_agents.map((_, i) => `($1, $${i + 2})`).join(", ");
|
|
16213
|
+
const params = [messageId, ...event.to_agents];
|
|
16214
|
+
await db.query(`INSERT INTO message_recipients (message_id, agent_name)
|
|
16215
|
+
VALUES ${values}
|
|
16216
|
+
ON CONFLICT DO NOTHING`, params);
|
|
16217
|
+
console.log("[SwarmMail] Message recipients inserted", {
|
|
16218
|
+
messageId,
|
|
16219
|
+
recipientCount: event.to_agents.length
|
|
16220
|
+
});
|
|
15967
16221
|
}
|
|
15968
|
-
return {
|
|
15969
|
-
id: message.id,
|
|
15970
|
-
from_agent: message.from_agent,
|
|
15971
|
-
subject: message.subject,
|
|
15972
|
-
body: message.body,
|
|
15973
|
-
thread_id: message.thread_id,
|
|
15974
|
-
importance: message.importance,
|
|
15975
|
-
created_at: message.created_at
|
|
15976
|
-
};
|
|
15977
16222
|
}
|
|
15978
|
-
async function
|
|
15979
|
-
|
|
15980
|
-
|
|
15981
|
-
|
|
15982
|
-
|
|
15983
|
-
|
|
15984
|
-
|
|
15985
|
-
|
|
15986
|
-
|
|
15987
|
-
|
|
15988
|
-
|
|
15989
|
-
|
|
15990
|
-
|
|
15991
|
-
|
|
15992
|
-
|
|
15993
|
-
|
|
15994
|
-
|
|
15995
|
-
|
|
15996
|
-
|
|
15997
|
-
|
|
15998
|
-
|
|
15999
|
-
|
|
16000
|
-
|
|
16001
|
-
|
|
16002
|
-
}
|
|
16003
|
-
|
|
16223
|
+
async function handleFileReserved(db, event) {
|
|
16224
|
+
console.log("[SwarmMail] Handling file reservation event", {
|
|
16225
|
+
agent: event.agent_name,
|
|
16226
|
+
paths: event.paths,
|
|
16227
|
+
exclusive: event.exclusive,
|
|
16228
|
+
projectKey: event.project_key
|
|
16229
|
+
});
|
|
16230
|
+
if (event.paths.length > 0) {
|
|
16231
|
+
const values = event.paths.map((_, i) => `($1, $2, $${i + 3}, $${event.paths.length + 3}, $${event.paths.length + 4}, $${event.paths.length + 5}, $${event.paths.length + 6})`).join(", ");
|
|
16232
|
+
const params = [
|
|
16233
|
+
event.project_key,
|
|
16234
|
+
event.agent_name,
|
|
16235
|
+
...event.paths,
|
|
16236
|
+
event.exclusive,
|
|
16237
|
+
event.reason || null,
|
|
16238
|
+
event.timestamp,
|
|
16239
|
+
event.expires_at
|
|
16240
|
+
];
|
|
16241
|
+
if (event.paths.length > 0) {
|
|
16242
|
+
await db.query(`DELETE FROM reservations
|
|
16243
|
+
WHERE project_key = $1
|
|
16244
|
+
AND agent_name = $2
|
|
16245
|
+
AND path_pattern = ANY($3)
|
|
16246
|
+
AND released_at IS NULL`, [event.project_key, event.agent_name, event.paths]);
|
|
16247
|
+
}
|
|
16248
|
+
await db.query(`INSERT INTO reservations (project_key, agent_name, path_pattern, exclusive, reason, created_at, expires_at)
|
|
16249
|
+
VALUES ${values}`, params);
|
|
16250
|
+
console.log("[SwarmMail] File reservations inserted", {
|
|
16251
|
+
agent: event.agent_name,
|
|
16252
|
+
reservationCount: event.paths.length
|
|
16253
|
+
});
|
|
16254
|
+
}
|
|
16004
16255
|
}
|
|
16005
|
-
async function
|
|
16006
|
-
|
|
16007
|
-
|
|
16008
|
-
|
|
16009
|
-
|
|
16010
|
-
|
|
16011
|
-
|
|
16012
|
-
|
|
16256
|
+
async function handleFileReleased(db, event) {
|
|
16257
|
+
if (event.type !== "file_released")
|
|
16258
|
+
return;
|
|
16259
|
+
if (event.reservation_ids && event.reservation_ids.length > 0) {
|
|
16260
|
+
await db.query(`UPDATE reservations SET released_at = $1 WHERE id = ANY($2)`, [event.timestamp, event.reservation_ids]);
|
|
16261
|
+
} else if (event.paths && event.paths.length > 0) {
|
|
16262
|
+
await db.query(`UPDATE reservations SET released_at = $1
|
|
16263
|
+
WHERE project_key = $2 AND agent_name = $3 AND path_pattern = ANY($4) AND released_at IS NULL`, [event.timestamp, event.project_key, event.agent_name, event.paths]);
|
|
16013
16264
|
} else {
|
|
16014
|
-
|
|
16265
|
+
await db.query(`UPDATE reservations SET released_at = $1
|
|
16266
|
+
WHERE project_key = $2 AND agent_name = $3 AND released_at IS NULL`, [event.timestamp, event.project_key, event.agent_name]);
|
|
16015
16267
|
}
|
|
16016
|
-
await appendEvent(createEvent("file_released", {
|
|
16017
|
-
project_key: projectPath,
|
|
16018
|
-
agent_name: agentName,
|
|
16019
|
-
paths,
|
|
16020
|
-
reservation_ids: reservationIds
|
|
16021
|
-
}), projectPath);
|
|
16022
|
-
return {
|
|
16023
|
-
released: releaseCount,
|
|
16024
|
-
releasedAt: Date.now()
|
|
16025
|
-
};
|
|
16026
16268
|
}
|
|
16027
|
-
async function
|
|
16028
|
-
|
|
16029
|
-
|
|
16030
|
-
await
|
|
16031
|
-
|
|
16032
|
-
|
|
16033
|
-
|
|
16034
|
-
|
|
16035
|
-
|
|
16036
|
-
|
|
16037
|
-
|
|
16038
|
-
|
|
16269
|
+
async function handleDecompositionGenerated(db, event) {
|
|
16270
|
+
if (event.type !== "decomposition_generated")
|
|
16271
|
+
return;
|
|
16272
|
+
await db.query(`INSERT INTO eval_records (
|
|
16273
|
+
id, project_key, task, context, strategy, epic_title, subtasks,
|
|
16274
|
+
created_at, updated_at
|
|
16275
|
+
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $8)
|
|
16276
|
+
ON CONFLICT (id) DO NOTHING`, [
|
|
16277
|
+
event.epic_id,
|
|
16278
|
+
event.project_key,
|
|
16279
|
+
event.task,
|
|
16280
|
+
event.context || null,
|
|
16281
|
+
event.strategy,
|
|
16282
|
+
event.epic_title,
|
|
16283
|
+
JSON.stringify(event.subtasks),
|
|
16284
|
+
event.timestamp
|
|
16285
|
+
]);
|
|
16039
16286
|
}
|
|
16040
|
-
async function
|
|
16041
|
-
|
|
16042
|
-
|
|
16043
|
-
|
|
16044
|
-
|
|
16045
|
-
|
|
16046
|
-
|
|
16287
|
+
async function handleSubtaskOutcome(db, event) {
|
|
16288
|
+
if (event.type !== "subtask_outcome")
|
|
16289
|
+
return;
|
|
16290
|
+
const result = await db.query(`SELECT outcomes, subtasks FROM eval_records WHERE id = $1`, [
|
|
16291
|
+
event.epic_id
|
|
16292
|
+
]);
|
|
16293
|
+
if (!result.rows[0]) {
|
|
16294
|
+
console.warn(`[SwarmMail] No eval_record found for epic_id ${event.epic_id}`);
|
|
16295
|
+
return;
|
|
16047
16296
|
}
|
|
16048
|
-
const
|
|
16049
|
-
|
|
16050
|
-
|
|
16051
|
-
|
|
16052
|
-
|
|
16053
|
-
|
|
16297
|
+
const row = result.rows[0];
|
|
16298
|
+
const subtasks = typeof row.subtasks === "string" ? JSON.parse(row.subtasks) : row.subtasks;
|
|
16299
|
+
const outcomes = row.outcomes ? typeof row.outcomes === "string" ? JSON.parse(row.outcomes) : row.outcomes : [];
|
|
16300
|
+
const newOutcome = {
|
|
16301
|
+
bead_id: event.bead_id,
|
|
16302
|
+
planned_files: event.planned_files,
|
|
16303
|
+
actual_files: event.actual_files,
|
|
16304
|
+
duration_ms: event.duration_ms,
|
|
16305
|
+
error_count: event.error_count,
|
|
16306
|
+
retry_count: event.retry_count,
|
|
16307
|
+
success: event.success
|
|
16308
|
+
};
|
|
16309
|
+
const updatedOutcomes = [...outcomes, newOutcome];
|
|
16310
|
+
const fileOverlapCount = computeFileOverlap(subtasks);
|
|
16311
|
+
const scopeAccuracy = computeScopeAccuracy(event.planned_files, event.actual_files);
|
|
16312
|
+
const timeBalanceRatio = computeTimeBalanceRatio(updatedOutcomes);
|
|
16313
|
+
const overallSuccess = updatedOutcomes.every((o) => o.success);
|
|
16314
|
+
const totalDurationMs = updatedOutcomes.reduce((sum, o) => sum + o.duration_ms, 0);
|
|
16315
|
+
const totalErrors = updatedOutcomes.reduce((sum, o) => sum + o.error_count, 0);
|
|
16316
|
+
await db.query(`UPDATE eval_records SET
|
|
16317
|
+
outcomes = $1,
|
|
16318
|
+
file_overlap_count = $2,
|
|
16319
|
+
scope_accuracy = $3,
|
|
16320
|
+
time_balance_ratio = $4,
|
|
16321
|
+
overall_success = $5,
|
|
16322
|
+
total_duration_ms = $6,
|
|
16323
|
+
total_errors = $7,
|
|
16324
|
+
updated_at = $8
|
|
16325
|
+
WHERE id = $9`, [
|
|
16326
|
+
JSON.stringify(updatedOutcomes),
|
|
16327
|
+
fileOverlapCount,
|
|
16328
|
+
scopeAccuracy,
|
|
16329
|
+
timeBalanceRatio,
|
|
16330
|
+
overallSuccess,
|
|
16331
|
+
totalDurationMs,
|
|
16332
|
+
totalErrors,
|
|
16333
|
+
event.timestamp,
|
|
16334
|
+
event.epic_id
|
|
16335
|
+
]);
|
|
16054
16336
|
}
|
|
16055
|
-
|
|
16056
|
-
|
|
16057
|
-
|
|
16058
|
-
|
|
16059
|
-
|
|
16060
|
-
|
|
16061
|
-
|
|
16062
|
-
|
|
16063
|
-
|
|
16064
|
-
|
|
16065
|
-
|
|
16066
|
-
|
|
16067
|
-
|
|
16068
|
-
|
|
16069
|
-
|
|
16070
|
-
|
|
16071
|
-
|
|
16072
|
-
|
|
16073
|
-
|
|
16074
|
-
|
|
16075
|
-
|
|
16076
|
-
|
|
16077
|
-
|
|
16078
|
-
|
|
16079
|
-
|
|
16080
|
-
|
|
16081
|
-
|
|
16082
|
-
|
|
16083
|
-
|
|
16084
|
-
|
|
16085
|
-
|
|
16086
|
-
|
|
16087
|
-
|
|
16088
|
-
|
|
16089
|
-
|
|
16090
|
-
|
|
16091
|
-
|
|
16092
|
-
|
|
16093
|
-
|
|
16094
|
-
|
|
16095
|
-
|
|
16096
|
-
|
|
16337
|
+
async function handleHumanFeedback(db, event) {
|
|
16338
|
+
if (event.type !== "human_feedback")
|
|
16339
|
+
return;
|
|
16340
|
+
await db.query(`UPDATE eval_records SET
|
|
16341
|
+
human_accepted = $1,
|
|
16342
|
+
human_modified = $2,
|
|
16343
|
+
human_notes = $3,
|
|
16344
|
+
updated_at = $4
|
|
16345
|
+
WHERE id = $5`, [
|
|
16346
|
+
event.accepted,
|
|
16347
|
+
event.modified,
|
|
16348
|
+
event.notes || null,
|
|
16349
|
+
event.timestamp,
|
|
16350
|
+
event.epic_id
|
|
16351
|
+
]);
|
|
16352
|
+
}
|
|
16353
|
+
async function handleSwarmCheckpointed(db, event) {
|
|
16354
|
+
if (event.type !== "swarm_checkpointed")
|
|
16355
|
+
return;
|
|
16356
|
+
await db.query(`INSERT INTO swarm_contexts (
|
|
16357
|
+
project_key, epic_id, bead_id, strategy, files, dependencies,
|
|
16358
|
+
directives, recovery, checkpointed_at, updated_at
|
|
16359
|
+
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $9)
|
|
16360
|
+
ON CONFLICT (project_key, epic_id, bead_id) DO UPDATE SET
|
|
16361
|
+
strategy = EXCLUDED.strategy,
|
|
16362
|
+
files = EXCLUDED.files,
|
|
16363
|
+
dependencies = EXCLUDED.dependencies,
|
|
16364
|
+
directives = EXCLUDED.directives,
|
|
16365
|
+
recovery = EXCLUDED.recovery,
|
|
16366
|
+
checkpointed_at = EXCLUDED.checkpointed_at,
|
|
16367
|
+
updated_at = EXCLUDED.updated_at`, [
|
|
16368
|
+
event.project_key,
|
|
16369
|
+
event.epic_id,
|
|
16370
|
+
event.bead_id,
|
|
16371
|
+
event.strategy,
|
|
16372
|
+
JSON.stringify(event.files),
|
|
16373
|
+
JSON.stringify(event.dependencies),
|
|
16374
|
+
JSON.stringify(event.directives),
|
|
16375
|
+
JSON.stringify(event.recovery),
|
|
16376
|
+
event.timestamp
|
|
16377
|
+
]);
|
|
16378
|
+
}
|
|
16379
|
+
async function handleSwarmRecovered(db, event) {
|
|
16380
|
+
if (event.type !== "swarm_recovered")
|
|
16381
|
+
return;
|
|
16382
|
+
await db.query(`UPDATE swarm_contexts SET
|
|
16383
|
+
recovered_at = $1,
|
|
16384
|
+
recovered_from_checkpoint = $2,
|
|
16385
|
+
updated_at = $1
|
|
16386
|
+
WHERE project_key = $3 AND epic_id = $4 AND bead_id = $5`, [
|
|
16387
|
+
event.timestamp,
|
|
16388
|
+
event.recovered_from_checkpoint,
|
|
16389
|
+
event.project_key,
|
|
16390
|
+
event.epic_id,
|
|
16391
|
+
event.bead_id
|
|
16392
|
+
]);
|
|
16393
|
+
}
|
|
16394
|
+
function computeFileOverlap(subtasks) {
|
|
16395
|
+
const fileCount = new Map;
|
|
16396
|
+
for (const subtask of subtasks) {
|
|
16397
|
+
for (const file2 of subtask.files) {
|
|
16398
|
+
fileCount.set(file2, (fileCount.get(file2) || 0) + 1);
|
|
16399
|
+
}
|
|
16400
|
+
}
|
|
16401
|
+
return Array.from(fileCount.values()).filter((count) => count > 1).length;
|
|
16402
|
+
}
|
|
16403
|
+
function computeScopeAccuracy(planned, actual) {
|
|
16404
|
+
if (planned.length === 0)
|
|
16405
|
+
return 1;
|
|
16406
|
+
const plannedSet = new Set(planned);
|
|
16407
|
+
const intersection2 = actual.filter((file2) => plannedSet.has(file2));
|
|
16408
|
+
return intersection2.length / planned.length;
|
|
16409
|
+
}
|
|
16410
|
+
function computeTimeBalanceRatio(outcomes) {
|
|
16411
|
+
if (outcomes.length === 0)
|
|
16412
|
+
return null;
|
|
16413
|
+
const durations = outcomes.map((o) => o.duration_ms);
|
|
16414
|
+
const max = Math.max(...durations);
|
|
16415
|
+
const min = Math.min(...durations);
|
|
16416
|
+
if (min === 0)
|
|
16417
|
+
return null;
|
|
16418
|
+
return max / min;
|
|
16419
|
+
}
|
|
16420
|
+
async function registerAgent(projectKey, agentName, options2 = {}, projectPath) {
|
|
16421
|
+
const event = createEvent("agent_registered", {
|
|
16422
|
+
project_key: projectKey,
|
|
16423
|
+
agent_name: agentName,
|
|
16424
|
+
program: options2.program || "opencode",
|
|
16425
|
+
model: options2.model || "unknown",
|
|
16426
|
+
task_description: options2.taskDescription
|
|
16427
|
+
});
|
|
16428
|
+
return appendEvent(event, projectPath);
|
|
16429
|
+
}
|
|
16430
|
+
async function sendMessage(projectKey, fromAgent, toAgents, subject, body, options2 = {}, projectPath) {
|
|
16431
|
+
const event = createEvent("message_sent", {
|
|
16432
|
+
project_key: projectKey,
|
|
16433
|
+
from_agent: fromAgent,
|
|
16434
|
+
to_agents: toAgents,
|
|
16435
|
+
subject,
|
|
16436
|
+
body,
|
|
16437
|
+
thread_id: options2.threadId,
|
|
16438
|
+
importance: options2.importance || "normal",
|
|
16439
|
+
ack_required: options2.ackRequired || false
|
|
16440
|
+
});
|
|
16441
|
+
return appendEvent(event, projectPath);
|
|
16442
|
+
}
|
|
16443
|
+
async function reserveFiles(projectKey, agentName, paths, options2 = {}, projectPath) {
|
|
16444
|
+
const ttlSeconds = options2.ttlSeconds || 3600;
|
|
16445
|
+
const event = createEvent("file_reserved", {
|
|
16446
|
+
project_key: projectKey,
|
|
16447
|
+
agent_name: agentName,
|
|
16448
|
+
paths,
|
|
16449
|
+
reason: options2.reason,
|
|
16450
|
+
exclusive: options2.exclusive ?? true,
|
|
16451
|
+
ttl_seconds: ttlSeconds,
|
|
16452
|
+
expires_at: Date.now() + ttlSeconds * 1000
|
|
16453
|
+
});
|
|
16454
|
+
return appendEvent(event, projectPath);
|
|
16455
|
+
}
|
|
16456
|
+
var TIMESTAMP_SAFE_UNTIL;
|
|
16457
|
+
var init_store = __esm(() => {
|
|
16458
|
+
init_streams();
|
|
16459
|
+
init_events();
|
|
16460
|
+
TIMESTAMP_SAFE_UNTIL = new Date("2286-01-01").getTime();
|
|
16097
16461
|
});
|
|
16098
16462
|
|
|
16099
16463
|
// node_modules/.pnpm/@ioredis+commands@1.4.0/node_modules/@ioredis/commands/built/commands.json
|
|
@@ -30780,7 +31144,58 @@ var mandateSchemas = {
|
|
|
30780
31144
|
QueryMandatesArgsSchema,
|
|
30781
31145
|
ScoreCalculationResultSchema
|
|
30782
31146
|
};
|
|
31147
|
+
// src/schemas/swarm-context.ts
|
|
31148
|
+
init_zod();
|
|
31149
|
+
var SwarmStrategySchema = exports_external.enum([
|
|
31150
|
+
"file-based",
|
|
31151
|
+
"feature-based",
|
|
31152
|
+
"risk-based"
|
|
31153
|
+
]);
|
|
31154
|
+
var SwarmDirectivesSchema = exports_external.object({
|
|
31155
|
+
shared_context: exports_external.string(),
|
|
31156
|
+
skills_to_load: exports_external.array(exports_external.string()).default([]),
|
|
31157
|
+
coordinator_notes: exports_external.string().default("")
|
|
31158
|
+
});
|
|
31159
|
+
var SwarmRecoverySchema = exports_external.object({
|
|
31160
|
+
last_checkpoint: exports_external.string(),
|
|
31161
|
+
files_modified: exports_external.array(exports_external.string()).default([]),
|
|
31162
|
+
progress_percent: exports_external.number().min(0).max(100).default(0),
|
|
31163
|
+
last_message: exports_external.string().default(""),
|
|
31164
|
+
error_context: exports_external.string().optional()
|
|
31165
|
+
});
|
|
31166
|
+
var SwarmBeadContextSchema = exports_external.object({
|
|
31167
|
+
id: exports_external.string(),
|
|
31168
|
+
epic_id: exports_external.string(),
|
|
31169
|
+
bead_id: exports_external.string(),
|
|
31170
|
+
strategy: SwarmStrategySchema,
|
|
31171
|
+
files: exports_external.array(exports_external.string()),
|
|
31172
|
+
dependencies: exports_external.array(exports_external.string()).default([]),
|
|
31173
|
+
directives: SwarmDirectivesSchema,
|
|
31174
|
+
recovery: SwarmRecoverySchema,
|
|
31175
|
+
created_at: exports_external.number().int().positive(),
|
|
31176
|
+
updated_at: exports_external.number().int().positive()
|
|
31177
|
+
});
|
|
31178
|
+
var CreateSwarmContextArgsSchema = SwarmBeadContextSchema.omit({
|
|
31179
|
+
id: true,
|
|
31180
|
+
created_at: true,
|
|
31181
|
+
updated_at: true
|
|
31182
|
+
});
|
|
31183
|
+
var UpdateSwarmContextArgsSchema = exports_external.object({
|
|
31184
|
+
id: exports_external.string(),
|
|
31185
|
+
recovery: SwarmRecoverySchema.partial().optional(),
|
|
31186
|
+
files: exports_external.array(exports_external.string()).optional(),
|
|
31187
|
+
dependencies: exports_external.array(exports_external.string()).optional(),
|
|
31188
|
+
directives: SwarmDirectivesSchema.partial().optional()
|
|
31189
|
+
});
|
|
31190
|
+
var QuerySwarmContextsArgsSchema = exports_external.object({
|
|
31191
|
+
epic_id: exports_external.string().optional(),
|
|
31192
|
+
bead_id: exports_external.string().optional(),
|
|
31193
|
+
strategy: SwarmStrategySchema.optional(),
|
|
31194
|
+
has_errors: exports_external.boolean().optional()
|
|
31195
|
+
});
|
|
30783
31196
|
// src/beads.ts
|
|
31197
|
+
init_events();
|
|
31198
|
+
init_store();
|
|
30784
31199
|
var beadsWorkingDirectory = null;
|
|
30785
31200
|
function setBeadsWorkingDirectory(directory) {
|
|
30786
31201
|
beadsWorkingDirectory = directory;
|
|
@@ -30925,7 +31340,15 @@ var beads_create_epic = tool({
|
|
|
30925
31340
|
priority: tool.schema.number().min(0).max(3).optional(),
|
|
30926
31341
|
files: tool.schema.array(tool.schema.string()).optional(),
|
|
30927
31342
|
id_suffix: tool.schema.string().optional().describe("Custom ID suffix (e.g., 'e2e-test' becomes 'phase-0.e2e-test')")
|
|
30928
|
-
})).describe("Subtasks to create under the epic")
|
|
31343
|
+
})).describe("Subtasks to create under the epic"),
|
|
31344
|
+
strategy: tool.schema.enum(["file-based", "feature-based", "risk-based"]).optional().describe("Decomposition strategy used (default: feature-based)"),
|
|
31345
|
+
task: tool.schema.string().optional().describe("Original task description that was decomposed"),
|
|
31346
|
+
project_key: tool.schema.string().optional().describe("Project path for event emission"),
|
|
31347
|
+
recovery_context: tool.schema.object({
|
|
31348
|
+
shared_context: tool.schema.string().optional(),
|
|
31349
|
+
skills_to_load: tool.schema.array(tool.schema.string()).optional(),
|
|
31350
|
+
coordinator_notes: tool.schema.string().optional()
|
|
31351
|
+
}).optional().describe("Recovery context from checkpoint compaction")
|
|
30929
31352
|
},
|
|
30930
31353
|
async execute(args, ctx) {
|
|
30931
31354
|
const validated = EpicCreateArgsSchema.parse(args);
|
|
@@ -30968,6 +31391,27 @@ var beads_create_epic = tool({
|
|
|
30968
31391
|
epic,
|
|
30969
31392
|
subtasks: created.slice(1)
|
|
30970
31393
|
};
|
|
31394
|
+
if (args.project_key) {
|
|
31395
|
+
try {
|
|
31396
|
+
const event = createEvent("decomposition_generated", {
|
|
31397
|
+
project_key: args.project_key,
|
|
31398
|
+
epic_id: epic.id,
|
|
31399
|
+
task: args.task || validated.epic_title,
|
|
31400
|
+
context: validated.epic_description,
|
|
31401
|
+
strategy: args.strategy || "feature-based",
|
|
31402
|
+
epic_title: validated.epic_title,
|
|
31403
|
+
subtasks: validated.subtasks.map((st) => ({
|
|
31404
|
+
title: st.title,
|
|
31405
|
+
files: st.files || [],
|
|
31406
|
+
priority: st.priority
|
|
31407
|
+
})),
|
|
31408
|
+
recovery_context: args.recovery_context
|
|
31409
|
+
});
|
|
31410
|
+
await appendEvent(event, args.project_key);
|
|
31411
|
+
} catch (error45) {
|
|
31412
|
+
console.warn("[beads_create_epic] Failed to emit DecompositionGeneratedEvent:", error45);
|
|
31413
|
+
}
|
|
31414
|
+
}
|
|
30971
31415
|
return JSON.stringify(result, null, 2);
|
|
30972
31416
|
} catch (error45) {
|
|
30973
31417
|
const rollbackCommands = [];
|
|
@@ -31146,7 +31590,7 @@ var beads_sync = tool({
|
|
|
31146
31590
|
async execute(args, ctx) {
|
|
31147
31591
|
const autoPull = args.auto_pull ?? true;
|
|
31148
31592
|
const TIMEOUT_MS = 30000;
|
|
31149
|
-
const
|
|
31593
|
+
const withTimeout2 = async (promise2, timeoutMs, operation) => {
|
|
31150
31594
|
let timeoutId;
|
|
31151
31595
|
const timeoutPromise = new Promise((_, reject) => {
|
|
31152
31596
|
timeoutId = setTimeout(() => reject(new BeadError(`Operation timed out after ${timeoutMs}ms`, operation)), timeoutMs);
|
|
@@ -31159,7 +31603,7 @@ var beads_sync = tool({
|
|
|
31159
31603
|
}
|
|
31160
31604
|
}
|
|
31161
31605
|
};
|
|
31162
|
-
const flushResult = await
|
|
31606
|
+
const flushResult = await withTimeout2(runBdCommand(["sync", "--flush-only"]), TIMEOUT_MS, "bd sync --flush-only");
|
|
31163
31607
|
if (flushResult.exitCode !== 0) {
|
|
31164
31608
|
throw new BeadError(`Failed to flush beads because bd sync failed: ${flushResult.stderr}. Try: Check if .beads/ directory is writable, verify no corrupted JSONL files, or run 'bd list' to test basic beads functionality.`, "bd sync --flush-only", flushResult.exitCode);
|
|
31165
31609
|
}
|
|
@@ -31174,7 +31618,7 @@ var beads_sync = tool({
|
|
|
31174
31618
|
if (addResult.exitCode !== 0) {
|
|
31175
31619
|
throw new BeadError(`Failed to stage beads because git add failed: ${addResult.stderr}. Try: Check if .beads/ directory exists, verify git is initialized with 'git status', or check for .gitignore patterns blocking .beads/.`, "git add .beads/", addResult.exitCode);
|
|
31176
31620
|
}
|
|
31177
|
-
const commitResult = await
|
|
31621
|
+
const commitResult = await withTimeout2(runGitCommand(["commit", "-m", "chore: sync beads"]), TIMEOUT_MS, "git commit");
|
|
31178
31622
|
if (commitResult.exitCode !== 0 && !commitResult.stdout.includes("nothing to commit")) {
|
|
31179
31623
|
throw new BeadError(`Failed to commit beads because git commit failed: ${commitResult.stderr}. Try: Check git config (user.name, user.email) with 'git config --list', verify working tree is clean, or check for pre-commit hooks blocking commit.`, "git commit", commitResult.exitCode);
|
|
31180
31624
|
}
|
|
@@ -31203,7 +31647,7 @@ var beads_sync = tool({
|
|
|
31203
31647
|
console.warn(`[beads] Stash failed (${stashResult.stderr}), attempting pull anyway...`);
|
|
31204
31648
|
}
|
|
31205
31649
|
}
|
|
31206
|
-
const pullResult = await
|
|
31650
|
+
const pullResult = await withTimeout2(runGitCommand(["pull", "--rebase"]), TIMEOUT_MS, "git pull --rebase");
|
|
31207
31651
|
if (didStash) {
|
|
31208
31652
|
console.warn("[beads] Restoring stashed changes...");
|
|
31209
31653
|
const unstashResult = await runGitCommand(["stash", "pop"]);
|
|
@@ -31217,12 +31661,12 @@ var beads_sync = tool({
|
|
|
31217
31661
|
if (pullResult.exitCode !== 0) {
|
|
31218
31662
|
throw new BeadError(`Failed to pull because git pull --rebase failed: ${pullResult.stderr}. Try: Resolve merge conflicts manually with 'git status', check if remote is accessible with 'git remote -v', or use skip_verification to bypass automatic pull.`, "git pull --rebase", pullResult.exitCode);
|
|
31219
31663
|
}
|
|
31220
|
-
const importResult = await
|
|
31664
|
+
const importResult = await withTimeout2(runBdCommand(["sync", "--import-only"]), TIMEOUT_MS, "bd sync --import-only");
|
|
31221
31665
|
if (importResult.exitCode !== 0) {
|
|
31222
31666
|
console.warn(`[beads] Import warning: ${importResult.stderr}`);
|
|
31223
31667
|
}
|
|
31224
31668
|
}
|
|
31225
|
-
const pushResult = await
|
|
31669
|
+
const pushResult = await withTimeout2(runGitCommand(["push"]), TIMEOUT_MS, "git push");
|
|
31226
31670
|
if (pushResult.exitCode !== 0) {
|
|
31227
31671
|
throw new BeadError(`Failed to push because git push failed: ${pushResult.stderr}. Try: Check if remote branch is up to date with 'git pull --rebase', verify push permissions, check remote URL with 'git remote -v', or force push with 'git push --force-with-lease' if safe.`, "git push", pushResult.exitCode);
|
|
31228
31672
|
}
|
|
@@ -34182,20 +34626,29 @@ Only modify these files. Need others? Message the coordinator.
|
|
|
34182
34626
|
|
|
34183
34627
|
{error_context}
|
|
34184
34628
|
|
|
34185
|
-
## [MANDATORY: SWARM MAIL]
|
|
34629
|
+
## [MANDATORY: SWARM MAIL INITIALIZATION]
|
|
34186
34630
|
|
|
34187
|
-
**YOU MUST
|
|
34631
|
+
**CRITICAL: YOU MUST INITIALIZE SWARM MAIL BEFORE DOING ANY WORK.**
|
|
34188
34632
|
|
|
34189
|
-
|
|
34190
|
-
\`\`\`
|
|
34191
|
-
swarmmail_init(project_path="$PWD", task_description="{subtask_title}")
|
|
34192
|
-
\`\`\`
|
|
34633
|
+
This is your FIRST step - before reading files, before planning, before ANY other action.
|
|
34193
34634
|
|
|
34194
|
-
###
|
|
34635
|
+
### Step 1: Initialize (REQUIRED - DO THIS FIRST)
|
|
34195
34636
|
\`\`\`
|
|
34196
|
-
|
|
34637
|
+
swarmmail_init(project_path="{project_path}", task_description="{bead_id}: {subtask_title}")
|
|
34197
34638
|
\`\`\`
|
|
34198
34639
|
|
|
34640
|
+
**This registers you with the coordination system and enables:**
|
|
34641
|
+
- File reservation tracking
|
|
34642
|
+
- Inter-agent communication
|
|
34643
|
+
- Progress monitoring
|
|
34644
|
+
- Conflict detection
|
|
34645
|
+
|
|
34646
|
+
**If you skip this step, your work will not be tracked and swarm_complete will fail.**
|
|
34647
|
+
|
|
34648
|
+
## [SWARM MAIL USAGE]
|
|
34649
|
+
|
|
34650
|
+
After initialization, use Swarm Mail for coordination:
|
|
34651
|
+
|
|
34199
34652
|
### Check Inbox Regularly
|
|
34200
34653
|
\`\`\`
|
|
34201
34654
|
swarmmail_inbox() # Check for coordinator messages
|
|
@@ -34249,14 +34702,17 @@ As you work, note reusable patterns, best practices, or domain insights:
|
|
|
34249
34702
|
- Skills make swarms smarter over time
|
|
34250
34703
|
|
|
34251
34704
|
## [WORKFLOW]
|
|
34252
|
-
1. **swarmmail_init** - Initialize session FIRST
|
|
34705
|
+
1. **swarmmail_init** - Initialize session (MANDATORY FIRST STEP)
|
|
34253
34706
|
2. Read assigned files
|
|
34254
34707
|
3. Implement changes
|
|
34255
34708
|
4. **swarmmail_send** - Report progress to coordinator
|
|
34256
34709
|
5. Verify (typecheck)
|
|
34257
34710
|
6. **swarm_complete** - Mark done, release reservations
|
|
34258
34711
|
|
|
34259
|
-
**CRITICAL
|
|
34712
|
+
**CRITICAL REQUIREMENTS:**
|
|
34713
|
+
- Step 1 (swarmmail_init) is NON-NEGOTIABLE - do it before anything else
|
|
34714
|
+
- Never work silently - send progress updates via swarmmail_send every significant milestone
|
|
34715
|
+
- If you complete without initializing, swarm_complete will detect this and warn/fail
|
|
34260
34716
|
|
|
34261
34717
|
Begin now.`;
|
|
34262
34718
|
var EVALUATION_PROMPT = `Evaluate the work completed for this subtask.
|
|
@@ -34300,7 +34756,33 @@ function formatSubtaskPromptV2(params) {
|
|
|
34300
34756
|
`) : "(no specific files - use judgment)";
|
|
34301
34757
|
const compressedSection = params.compressed_context ? params.compressed_context : "";
|
|
34302
34758
|
const errorSection = params.error_context ? params.error_context : "";
|
|
34303
|
-
|
|
34759
|
+
let recoverySection = "";
|
|
34760
|
+
if (params.recovery_context) {
|
|
34761
|
+
const sections = [];
|
|
34762
|
+
if (params.recovery_context.shared_context) {
|
|
34763
|
+
sections.push(`### Recovery Context
|
|
34764
|
+
${params.recovery_context.shared_context}`);
|
|
34765
|
+
}
|
|
34766
|
+
if (params.recovery_context.skills_to_load && params.recovery_context.skills_to_load.length > 0) {
|
|
34767
|
+
sections.push(`### Skills to Load
|
|
34768
|
+
Before starting work, load these skills for specialized guidance:
|
|
34769
|
+
${params.recovery_context.skills_to_load.map((s) => `- skills_use(name="${s}")`).join(`
|
|
34770
|
+
`)}`);
|
|
34771
|
+
}
|
|
34772
|
+
if (params.recovery_context.coordinator_notes) {
|
|
34773
|
+
sections.push(`### Coordinator Notes
|
|
34774
|
+
${params.recovery_context.coordinator_notes}`);
|
|
34775
|
+
}
|
|
34776
|
+
if (sections.length > 0) {
|
|
34777
|
+
recoverySection = `
|
|
34778
|
+
## [RECOVERY CONTEXT]
|
|
34779
|
+
|
|
34780
|
+
${sections.join(`
|
|
34781
|
+
|
|
34782
|
+
`)}`;
|
|
34783
|
+
}
|
|
34784
|
+
}
|
|
34785
|
+
return SUBTASK_PROMPT_V2.replace(/{bead_id}/g, params.bead_id).replace(/{epic_id}/g, params.epic_id).replace(/{project_path}/g, params.project_path || "$PWD").replace("{subtask_title}", params.subtask_title).replace("{subtask_description}", params.subtask_description || "(see title)").replace("{file_list}", fileList).replace("{shared_context}", params.shared_context || "(none)").replace("{compressed_context}", compressedSection).replace("{error_context}", errorSection + recoverySection);
|
|
34304
34786
|
}
|
|
34305
34787
|
function formatSubtaskPrompt(params) {
|
|
34306
34788
|
const fileList = params.files.map((f) => `- \`${f}\``).join(`
|
|
@@ -34321,7 +34803,8 @@ var swarm_subtask_prompt = tool({
|
|
|
34321
34803
|
subtask_title: tool.schema.string().describe("Subtask title"),
|
|
34322
34804
|
subtask_description: tool.schema.string().optional().describe("Detailed subtask instructions"),
|
|
34323
34805
|
files: tool.schema.array(tool.schema.string()).describe("Files assigned to this subtask"),
|
|
34324
|
-
shared_context: tool.schema.string().optional().describe("Context shared across all agents")
|
|
34806
|
+
shared_context: tool.schema.string().optional().describe("Context shared across all agents"),
|
|
34807
|
+
project_path: tool.schema.string().optional().describe("Absolute project path for swarmmail_init")
|
|
34325
34808
|
},
|
|
34326
34809
|
async execute(args) {
|
|
34327
34810
|
const prompt = formatSubtaskPrompt({
|
|
@@ -34337,14 +34820,20 @@ var swarm_subtask_prompt = tool({
|
|
|
34337
34820
|
}
|
|
34338
34821
|
});
|
|
34339
34822
|
var swarm_spawn_subtask = tool({
|
|
34340
|
-
description: "Prepare a subtask for spawning. Returns prompt with Agent Mail/beads instructions.",
|
|
34823
|
+
description: "Prepare a subtask for spawning. Returns prompt with Agent Mail/beads instructions. IMPORTANT: Pass project_path for swarmmail_init.",
|
|
34341
34824
|
args: {
|
|
34342
34825
|
bead_id: tool.schema.string().describe("Subtask bead ID"),
|
|
34343
34826
|
epic_id: tool.schema.string().describe("Parent epic bead ID"),
|
|
34344
34827
|
subtask_title: tool.schema.string().describe("Subtask title"),
|
|
34345
34828
|
subtask_description: tool.schema.string().optional().describe("Detailed subtask instructions"),
|
|
34346
34829
|
files: tool.schema.array(tool.schema.string()).describe("Files assigned to this subtask"),
|
|
34347
|
-
shared_context: tool.schema.string().optional().describe("Context shared across all agents")
|
|
34830
|
+
shared_context: tool.schema.string().optional().describe("Context shared across all agents"),
|
|
34831
|
+
project_path: tool.schema.string().optional().describe("Absolute project path for swarmmail_init (REQUIRED for tracking)"),
|
|
34832
|
+
recovery_context: tool.schema.object({
|
|
34833
|
+
shared_context: tool.schema.string().optional(),
|
|
34834
|
+
skills_to_load: tool.schema.array(tool.schema.string()).optional(),
|
|
34835
|
+
coordinator_notes: tool.schema.string().optional()
|
|
34836
|
+
}).optional().describe("Recovery context from checkpoint compaction")
|
|
34348
34837
|
},
|
|
34349
34838
|
async execute(args) {
|
|
34350
34839
|
const prompt = formatSubtaskPromptV2({
|
|
@@ -34353,13 +34842,17 @@ var swarm_spawn_subtask = tool({
|
|
|
34353
34842
|
subtask_title: args.subtask_title,
|
|
34354
34843
|
subtask_description: args.subtask_description || "",
|
|
34355
34844
|
files: args.files,
|
|
34356
|
-
shared_context: args.shared_context
|
|
34845
|
+
shared_context: args.shared_context,
|
|
34846
|
+
project_path: args.project_path,
|
|
34847
|
+
recovery_context: args.recovery_context
|
|
34357
34848
|
});
|
|
34358
34849
|
return JSON.stringify({
|
|
34359
34850
|
prompt,
|
|
34360
34851
|
bead_id: args.bead_id,
|
|
34361
34852
|
epic_id: args.epic_id,
|
|
34362
|
-
files: args.files
|
|
34853
|
+
files: args.files,
|
|
34854
|
+
project_path: args.project_path,
|
|
34855
|
+
recovery_context: args.recovery_context
|
|
34363
34856
|
}, null, 2);
|
|
34364
34857
|
}
|
|
34365
34858
|
});
|
|
@@ -34481,6 +34974,9 @@ var promptTools = {
|
|
|
34481
34974
|
init_dist();
|
|
34482
34975
|
init_zod();
|
|
34483
34976
|
init_swarm_mail();
|
|
34977
|
+
init_projections();
|
|
34978
|
+
init_events();
|
|
34979
|
+
init_store();
|
|
34484
34980
|
init_learning();
|
|
34485
34981
|
init_skills();
|
|
34486
34982
|
async function queryEpicSubtasks(epicId) {
|
|
@@ -34910,7 +35406,57 @@ var swarm_progress = tool({
|
|
|
34910
35406
|
threadId: epicId,
|
|
34911
35407
|
importance: args.status === "blocked" ? "high" : "normal"
|
|
34912
35408
|
});
|
|
34913
|
-
|
|
35409
|
+
let checkpointCreated = false;
|
|
35410
|
+
if (args.progress_percent !== undefined && args.files_touched && args.files_touched.length > 0) {
|
|
35411
|
+
const milestones = [25, 50, 75];
|
|
35412
|
+
if (milestones.includes(args.progress_percent)) {
|
|
35413
|
+
try {
|
|
35414
|
+
const checkpoint = {
|
|
35415
|
+
epic_id: epicId,
|
|
35416
|
+
bead_id: args.bead_id,
|
|
35417
|
+
strategy: "file-based",
|
|
35418
|
+
files: args.files_touched,
|
|
35419
|
+
dependencies: [],
|
|
35420
|
+
directives: {},
|
|
35421
|
+
recovery: {
|
|
35422
|
+
last_checkpoint: Date.now(),
|
|
35423
|
+
files_modified: args.files_touched,
|
|
35424
|
+
progress_percent: args.progress_percent,
|
|
35425
|
+
last_message: args.message
|
|
35426
|
+
}
|
|
35427
|
+
};
|
|
35428
|
+
const event = createEvent("swarm_checkpointed", {
|
|
35429
|
+
project_key: args.project_key,
|
|
35430
|
+
...checkpoint
|
|
35431
|
+
});
|
|
35432
|
+
await appendEvent(event, args.project_key);
|
|
35433
|
+
const { getDatabase: getDatabase2 } = await Promise.resolve().then(() => (init_streams(), exports_streams));
|
|
35434
|
+
const db = await getDatabase2(args.project_key);
|
|
35435
|
+
const now = Date.now();
|
|
35436
|
+
await db.query(`INSERT INTO swarm_contexts (id, epic_id, bead_id, strategy, files, dependencies, directives, recovery, created_at, updated_at)
|
|
35437
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
|
|
35438
|
+
ON CONFLICT (id) DO UPDATE SET
|
|
35439
|
+
files = EXCLUDED.files,
|
|
35440
|
+
recovery = EXCLUDED.recovery,
|
|
35441
|
+
updated_at = EXCLUDED.updated_at`, [
|
|
35442
|
+
args.bead_id,
|
|
35443
|
+
epicId,
|
|
35444
|
+
args.bead_id,
|
|
35445
|
+
checkpoint.strategy,
|
|
35446
|
+
JSON.stringify(checkpoint.files),
|
|
35447
|
+
JSON.stringify(checkpoint.dependencies),
|
|
35448
|
+
JSON.stringify(checkpoint.directives),
|
|
35449
|
+
JSON.stringify(checkpoint.recovery),
|
|
35450
|
+
now,
|
|
35451
|
+
now
|
|
35452
|
+
]);
|
|
35453
|
+
checkpointCreated = true;
|
|
35454
|
+
} catch (error45) {
|
|
35455
|
+
console.warn(`[swarm_progress] Auto-checkpoint failed at ${args.progress_percent}%:`, error45);
|
|
35456
|
+
}
|
|
35457
|
+
}
|
|
35458
|
+
}
|
|
35459
|
+
return `Progress reported: ${args.status}${args.progress_percent !== undefined ? ` (${args.progress_percent}%)` : ""}${checkpointCreated ? " [checkpoint created]" : ""}`;
|
|
34914
35460
|
}
|
|
34915
35461
|
});
|
|
34916
35462
|
var swarm_broadcast = tool({
|
|
@@ -34970,125 +35516,205 @@ var swarm_complete = tool({
|
|
|
34970
35516
|
evaluation: tool.schema.string().optional().describe("Self-evaluation JSON (Evaluation schema)"),
|
|
34971
35517
|
files_touched: tool.schema.array(tool.schema.string()).optional().describe("Files modified - will be verified (UBS, typecheck, tests)"),
|
|
34972
35518
|
skip_ubs_scan: tool.schema.boolean().optional().describe("Skip UBS bug scan (default: false)"),
|
|
34973
|
-
skip_verification: tool.schema.boolean().optional().describe("Skip ALL verification (UBS, typecheck, tests). Use sparingly! (default: false)")
|
|
35519
|
+
skip_verification: tool.schema.boolean().optional().describe("Skip ALL verification (UBS, typecheck, tests). Use sparingly! (default: false)"),
|
|
35520
|
+
planned_files: tool.schema.array(tool.schema.string()).optional().describe("Files that were originally planned to be modified"),
|
|
35521
|
+
start_time: tool.schema.number().optional().describe("Task start timestamp (Unix ms) for duration calculation"),
|
|
35522
|
+
error_count: tool.schema.number().optional().describe("Number of errors encountered during task"),
|
|
35523
|
+
retry_count: tool.schema.number().optional().describe("Number of retry attempts during task")
|
|
34974
35524
|
},
|
|
34975
35525
|
async execute(args) {
|
|
34976
|
-
|
|
34977
|
-
|
|
34978
|
-
|
|
34979
|
-
|
|
34980
|
-
|
|
34981
|
-
|
|
34982
|
-
|
|
34983
|
-
|
|
34984
|
-
|
|
34985
|
-
|
|
34986
|
-
|
|
34987
|
-
|
|
34988
|
-
|
|
34989
|
-
|
|
34990
|
-
|
|
34991
|
-
|
|
34992
|
-
|
|
34993
|
-
|
|
34994
|
-
|
|
34995
|
-
|
|
34996
|
-
|
|
34997
|
-
|
|
35526
|
+
const epicId = args.bead_id.includes(".") ? args.bead_id.split(".")[0] : args.bead_id;
|
|
35527
|
+
try {
|
|
35528
|
+
const projectKey = args.project_key.replace(/\//g, "-").replace(/\\/g, "-");
|
|
35529
|
+
let agentRegistered = false;
|
|
35530
|
+
let registrationWarning = "";
|
|
35531
|
+
try {
|
|
35532
|
+
const agent = await getAgent(projectKey, args.agent_name, args.project_key);
|
|
35533
|
+
agentRegistered = agent !== null;
|
|
35534
|
+
if (!agentRegistered) {
|
|
35535
|
+
registrationWarning = `⚠️ WARNING: Agent '${args.agent_name}' was NOT registered in swarm-mail for project '${projectKey}'.
|
|
35536
|
+
|
|
35537
|
+
This usually means you skipped the MANDATORY swarmmail_init step.
|
|
35538
|
+
|
|
35539
|
+
**Impact:**
|
|
35540
|
+
- Your work was not tracked in the coordination system
|
|
35541
|
+
- File reservations may not have been managed
|
|
35542
|
+
- Other agents couldn't coordinate with you
|
|
35543
|
+
- Learning/eval data may be incomplete
|
|
35544
|
+
|
|
35545
|
+
**Next time:** Run swarmmail_init(project_path="${args.project_key}", task_description="<task>") FIRST, before any other work.
|
|
35546
|
+
|
|
35547
|
+
Continuing with completion, but this should be fixed for future subtasks.`;
|
|
35548
|
+
console.warn(`[swarm_complete] ${registrationWarning}`);
|
|
35549
|
+
}
|
|
35550
|
+
} catch (error45) {
|
|
35551
|
+
console.warn(`[swarm_complete] Could not verify agent registration:`, error45);
|
|
35552
|
+
registrationWarning = `ℹ️ Could not verify swarm-mail registration (database may not be available). Consider running swarmmail_init next time.`;
|
|
34998
35553
|
}
|
|
34999
|
-
|
|
35000
|
-
|
|
35001
|
-
|
|
35002
|
-
|
|
35003
|
-
|
|
35004
|
-
|
|
35005
|
-
|
|
35006
|
-
|
|
35007
|
-
|
|
35008
|
-
|
|
35009
|
-
|
|
35010
|
-
|
|
35011
|
-
|
|
35012
|
-
|
|
35554
|
+
let verificationResult = null;
|
|
35555
|
+
if (!args.skip_verification && args.files_touched?.length) {
|
|
35556
|
+
verificationResult = await runVerificationGate(args.files_touched, args.skip_ubs_scan ?? false);
|
|
35557
|
+
if (!verificationResult.passed) {
|
|
35558
|
+
return JSON.stringify({
|
|
35559
|
+
success: false,
|
|
35560
|
+
error: "Verification Gate FAILED - fix issues before completing",
|
|
35561
|
+
verification: {
|
|
35562
|
+
passed: false,
|
|
35563
|
+
summary: verificationResult.summary,
|
|
35564
|
+
blockers: verificationResult.blockers,
|
|
35565
|
+
steps: verificationResult.steps.map((s) => ({
|
|
35566
|
+
name: s.name,
|
|
35567
|
+
passed: s.passed,
|
|
35568
|
+
skipped: s.skipped,
|
|
35569
|
+
skipReason: s.skipReason,
|
|
35570
|
+
error: s.error?.slice(0, 200)
|
|
35571
|
+
}))
|
|
35572
|
+
},
|
|
35573
|
+
hint: verificationResult.blockers.length > 0 ? `Fix these issues: ${verificationResult.blockers.map((b, i) => `${i + 1}. ${b}`).join(", ")}. Use skip_verification=true only as last resort.` : "Fix the failing checks and try again. Use skip_verification=true only as last resort.",
|
|
35574
|
+
gate_function: "IDENTIFY → RUN → READ → VERIFY → CLAIM (you are at VERIFY, claim blocked)"
|
|
35575
|
+
}, null, 2);
|
|
35576
|
+
}
|
|
35577
|
+
}
|
|
35578
|
+
let ubsResult = null;
|
|
35579
|
+
if (!args.skip_verification && !verificationResult && args.files_touched?.length && !args.skip_ubs_scan) {
|
|
35580
|
+
ubsResult = await runUbsScan(args.files_touched);
|
|
35581
|
+
if (ubsResult && ubsResult.summary.critical > 0) {
|
|
35582
|
+
return JSON.stringify({
|
|
35583
|
+
success: false,
|
|
35584
|
+
error: `UBS found ${ubsResult.summary.critical} critical bug(s) that must be fixed before completing`,
|
|
35585
|
+
ubs_scan: {
|
|
35586
|
+
critical_count: ubsResult.summary.critical,
|
|
35587
|
+
bugs: ubsResult.bugs.filter((b) => b.severity === "critical")
|
|
35588
|
+
},
|
|
35589
|
+
hint: `Fix these critical bugs: ${ubsResult.bugs.filter((b) => b.severity === "critical").map((b) => `${b.file}:${b.line} - ${b.message}`).slice(0, 3).join("; ")}. Try: Run 'ubs scan ${args.files_touched?.join(" ") || "."} --json' for full report, fix reported issues, or use skip_ubs_scan=true to bypass (not recommended).`
|
|
35590
|
+
}, null, 2);
|
|
35591
|
+
}
|
|
35592
|
+
}
|
|
35593
|
+
let parsedEvaluation;
|
|
35594
|
+
if (args.evaluation) {
|
|
35595
|
+
try {
|
|
35596
|
+
parsedEvaluation = EvaluationSchema.parse(JSON.parse(args.evaluation));
|
|
35597
|
+
} catch (error45) {
|
|
35598
|
+
return JSON.stringify({
|
|
35599
|
+
success: false,
|
|
35600
|
+
error: "Invalid evaluation format",
|
|
35601
|
+
details: error45 instanceof exports_external.ZodError ? error45.issues : String(error45)
|
|
35602
|
+
}, null, 2);
|
|
35603
|
+
}
|
|
35604
|
+
if (!parsedEvaluation.passed) {
|
|
35605
|
+
return JSON.stringify({
|
|
35606
|
+
success: false,
|
|
35607
|
+
error: "Self-evaluation failed",
|
|
35608
|
+
retry_suggestion: parsedEvaluation.retry_suggestion,
|
|
35609
|
+
feedback: parsedEvaluation.overall_feedback
|
|
35610
|
+
}, null, 2);
|
|
35611
|
+
}
|
|
35612
|
+
}
|
|
35613
|
+
const closeResult = await Bun.$`bd close ${args.bead_id} --reason ${args.summary} --json`.quiet().nothrow();
|
|
35614
|
+
if (closeResult.exitCode !== 0) {
|
|
35615
|
+
throw new Error(`Failed to close bead because bd close command failed: ${closeResult.stderr.toString()}. Try: Verify bead exists and is not already closed with 'bd show ${args.bead_id}', check if bead ID is correct with 'beads_query()', or use beads_close tool directly.`);
|
|
35013
35616
|
}
|
|
35014
|
-
}
|
|
35015
|
-
let parsedEvaluation;
|
|
35016
|
-
if (args.evaluation) {
|
|
35017
35617
|
try {
|
|
35018
|
-
|
|
35618
|
+
const epicId3 = args.bead_id.includes(".") ? args.bead_id.split(".")[0] : args.bead_id;
|
|
35619
|
+
const durationMs2 = args.start_time ? Date.now() - args.start_time : 0;
|
|
35620
|
+
const event = createEvent("subtask_outcome", {
|
|
35621
|
+
project_key: args.project_key,
|
|
35622
|
+
epic_id: epicId3,
|
|
35623
|
+
bead_id: args.bead_id,
|
|
35624
|
+
planned_files: args.planned_files || [],
|
|
35625
|
+
actual_files: args.files_touched || [],
|
|
35626
|
+
duration_ms: durationMs2,
|
|
35627
|
+
error_count: args.error_count || 0,
|
|
35628
|
+
retry_count: args.retry_count || 0,
|
|
35629
|
+
success: true
|
|
35630
|
+
});
|
|
35631
|
+
await appendEvent(event, args.project_key);
|
|
35019
35632
|
} catch (error45) {
|
|
35020
|
-
|
|
35021
|
-
success: false,
|
|
35022
|
-
error: "Invalid evaluation format",
|
|
35023
|
-
details: error45 instanceof exports_external.ZodError ? error45.issues : String(error45)
|
|
35024
|
-
}, null, 2);
|
|
35633
|
+
console.warn("[swarm_complete] Failed to emit SubtaskOutcomeEvent:", error45);
|
|
35025
35634
|
}
|
|
35026
|
-
|
|
35027
|
-
|
|
35028
|
-
|
|
35029
|
-
|
|
35030
|
-
|
|
35031
|
-
|
|
35032
|
-
|
|
35635
|
+
let capturedStrategy;
|
|
35636
|
+
const durationMs = args.start_time ? Date.now() - args.start_time : 0;
|
|
35637
|
+
const memoryInfo = formatMemoryStoreOnSuccess(args.bead_id, args.summary, args.files_touched || [], capturedStrategy);
|
|
35638
|
+
let memoryStored = false;
|
|
35639
|
+
let memoryError;
|
|
35640
|
+
try {
|
|
35641
|
+
const memoryAvailable = await isToolAvailable("semantic-memory");
|
|
35642
|
+
if (memoryAvailable) {
|
|
35643
|
+
const storeResult = await Bun.$`semantic-memory store ${memoryInfo.information} --metadata ${memoryInfo.metadata}`.quiet().nothrow();
|
|
35644
|
+
if (storeResult.exitCode === 0) {
|
|
35645
|
+
memoryStored = true;
|
|
35646
|
+
console.log(`[swarm_complete] Stored learning for ${args.bead_id} in semantic-memory`);
|
|
35647
|
+
} else {
|
|
35648
|
+
memoryError = `semantic-memory store failed: ${storeResult.stderr.toString().slice(0, 200)}`;
|
|
35649
|
+
console.warn(`[swarm_complete] ${memoryError}`);
|
|
35650
|
+
}
|
|
35651
|
+
} else {
|
|
35652
|
+
memoryError = "semantic-memory not available - learning stored in-memory only";
|
|
35653
|
+
warnMissingTool("semantic-memory");
|
|
35654
|
+
}
|
|
35655
|
+
} catch (error45) {
|
|
35656
|
+
memoryError = `Failed to store memory: ${error45 instanceof Error ? error45.message : String(error45)}`;
|
|
35657
|
+
console.warn(`[swarm_complete] ${memoryError}`);
|
|
35033
35658
|
}
|
|
35034
|
-
|
|
35035
|
-
|
|
35036
|
-
|
|
35037
|
-
|
|
35038
|
-
|
|
35039
|
-
|
|
35040
|
-
|
|
35659
|
+
try {
|
|
35660
|
+
await releaseSwarmFiles({
|
|
35661
|
+
projectPath: args.project_key,
|
|
35662
|
+
agentName: args.agent_name
|
|
35663
|
+
});
|
|
35664
|
+
} catch (error45) {
|
|
35665
|
+
console.warn(`[swarm] Failed to release file reservations for ${args.agent_name}:`, error45);
|
|
35666
|
+
}
|
|
35667
|
+
const epicId2 = args.bead_id.includes(".") ? args.bead_id.split(".")[0] : args.bead_id;
|
|
35668
|
+
const completionBody = [
|
|
35669
|
+
`## Subtask Complete: ${args.bead_id}`,
|
|
35670
|
+
"",
|
|
35671
|
+
`**Summary**: ${args.summary}`,
|
|
35672
|
+
"",
|
|
35673
|
+
parsedEvaluation ? `**Self-Evaluation**: ${parsedEvaluation.passed ? "PASSED" : "FAILED"}` : "",
|
|
35674
|
+
parsedEvaluation?.overall_feedback ? `**Feedback**: ${parsedEvaluation.overall_feedback}` : "",
|
|
35675
|
+
"",
|
|
35676
|
+
`**Memory Capture**: ${memoryStored ? "✓ Stored in semantic-memory" : `✗ ${memoryError || "Failed"}`}`
|
|
35677
|
+
].filter(Boolean).join(`
|
|
35678
|
+
`);
|
|
35679
|
+
await sendSwarmMessage({
|
|
35041
35680
|
projectPath: args.project_key,
|
|
35042
|
-
|
|
35681
|
+
fromAgent: args.agent_name,
|
|
35682
|
+
toAgents: [],
|
|
35683
|
+
subject: `Complete: ${args.bead_id}`,
|
|
35684
|
+
body: completionBody,
|
|
35685
|
+
threadId: epicId2,
|
|
35686
|
+
importance: "normal"
|
|
35043
35687
|
});
|
|
35044
|
-
|
|
35045
|
-
|
|
35046
|
-
|
|
35047
|
-
|
|
35048
|
-
|
|
35049
|
-
|
|
35050
|
-
|
|
35051
|
-
|
|
35052
|
-
|
|
35053
|
-
|
|
35054
|
-
|
|
35055
|
-
|
|
35056
|
-
|
|
35057
|
-
|
|
35058
|
-
|
|
35059
|
-
|
|
35060
|
-
|
|
35061
|
-
|
|
35062
|
-
|
|
35063
|
-
|
|
35064
|
-
|
|
35065
|
-
|
|
35066
|
-
|
|
35067
|
-
|
|
35068
|
-
|
|
35069
|
-
|
|
35070
|
-
|
|
35071
|
-
|
|
35072
|
-
|
|
35073
|
-
|
|
35074
|
-
summary: verificationResult.summary,
|
|
35075
|
-
steps: verificationResult.steps.map((s) => ({
|
|
35076
|
-
name: s.name,
|
|
35077
|
-
passed: s.passed,
|
|
35078
|
-
skipped: s.skipped,
|
|
35079
|
-
skipReason: s.skipReason
|
|
35080
|
-
}))
|
|
35081
|
-
} : args.skip_verification ? { skipped: true, reason: "skip_verification=true" } : { skipped: true, reason: "no files_touched provided" },
|
|
35082
|
-
ubs_scan: ubsResult ? {
|
|
35083
|
-
ran: true,
|
|
35084
|
-
bugs_found: ubsResult.summary.total,
|
|
35085
|
-
summary: ubsResult.summary,
|
|
35086
|
-
warnings: ubsResult.bugs.filter((b) => b.severity !== "critical")
|
|
35087
|
-
} : verificationResult ? { ran: true, included_in_verification_gate: true } : {
|
|
35088
|
-
ran: false,
|
|
35089
|
-
reason: args.skip_ubs_scan ? "skipped" : "no files or ubs unavailable"
|
|
35090
|
-
},
|
|
35091
|
-
learning_prompt: `## Reflection
|
|
35688
|
+
const response = {
|
|
35689
|
+
success: true,
|
|
35690
|
+
bead_id: args.bead_id,
|
|
35691
|
+
closed: true,
|
|
35692
|
+
reservations_released: true,
|
|
35693
|
+
message_sent: true,
|
|
35694
|
+
agent_registration: {
|
|
35695
|
+
verified: agentRegistered,
|
|
35696
|
+
warning: registrationWarning || undefined
|
|
35697
|
+
},
|
|
35698
|
+
verification_gate: verificationResult ? {
|
|
35699
|
+
passed: true,
|
|
35700
|
+
summary: verificationResult.summary,
|
|
35701
|
+
steps: verificationResult.steps.map((s) => ({
|
|
35702
|
+
name: s.name,
|
|
35703
|
+
passed: s.passed,
|
|
35704
|
+
skipped: s.skipped,
|
|
35705
|
+
skipReason: s.skipReason
|
|
35706
|
+
}))
|
|
35707
|
+
} : args.skip_verification ? { skipped: true, reason: "skip_verification=true" } : { skipped: true, reason: "no files_touched provided" },
|
|
35708
|
+
ubs_scan: ubsResult ? {
|
|
35709
|
+
ran: true,
|
|
35710
|
+
bugs_found: ubsResult.summary.total,
|
|
35711
|
+
summary: ubsResult.summary,
|
|
35712
|
+
warnings: ubsResult.bugs.filter((b) => b.severity !== "critical")
|
|
35713
|
+
} : verificationResult ? { ran: true, included_in_verification_gate: true } : {
|
|
35714
|
+
ran: false,
|
|
35715
|
+
reason: args.skip_ubs_scan ? "skipped" : "no files or ubs unavailable"
|
|
35716
|
+
},
|
|
35717
|
+
learning_prompt: `## Reflection
|
|
35092
35718
|
|
|
35093
35719
|
Did you learn anything reusable during this subtask? Consider:
|
|
35094
35720
|
|
|
@@ -35100,9 +35726,81 @@ Did you learn anything reusable during this subtask? Consider:
|
|
|
35100
35726
|
If you discovered something valuable, use \`swarm_learn\` or \`skills_create\` to preserve it as a skill for future swarms.
|
|
35101
35727
|
|
|
35102
35728
|
Files touched: ${args.files_touched?.join(", ") || "none recorded"}`,
|
|
35103
|
-
|
|
35104
|
-
|
|
35105
|
-
|
|
35729
|
+
memory_capture: {
|
|
35730
|
+
attempted: true,
|
|
35731
|
+
stored: memoryStored,
|
|
35732
|
+
error: memoryError,
|
|
35733
|
+
information: memoryInfo.information,
|
|
35734
|
+
metadata: memoryInfo.metadata,
|
|
35735
|
+
note: memoryStored ? "Learning automatically stored in semantic-memory" : `Failed to store: ${memoryError}. Learning lost unless semantic-memory is available.`
|
|
35736
|
+
}
|
|
35737
|
+
};
|
|
35738
|
+
return JSON.stringify(response, null, 2);
|
|
35739
|
+
} catch (error45) {
|
|
35740
|
+
const errorMessage = error45 instanceof Error ? error45.message : String(error45);
|
|
35741
|
+
const errorStack = error45 instanceof Error ? error45.stack : undefined;
|
|
35742
|
+
let failedStep = "unknown";
|
|
35743
|
+
if (errorMessage.includes("verification")) {
|
|
35744
|
+
failedStep = "Verification Gate (UBS/typecheck/tests)";
|
|
35745
|
+
} else if (errorMessage.includes("UBS") || errorMessage.includes("ubs")) {
|
|
35746
|
+
failedStep = "UBS scan";
|
|
35747
|
+
} else if (errorMessage.includes("evaluation")) {
|
|
35748
|
+
failedStep = "Self-evaluation parsing";
|
|
35749
|
+
} else if (errorMessage.includes("bead") || errorMessage.includes("close")) {
|
|
35750
|
+
failedStep = "Bead close";
|
|
35751
|
+
} else if (errorMessage.includes("memory") || errorMessage.includes("semantic")) {
|
|
35752
|
+
failedStep = "Memory storage (non-fatal)";
|
|
35753
|
+
} else if (errorMessage.includes("reservation") || errorMessage.includes("release")) {
|
|
35754
|
+
failedStep = "File reservation release";
|
|
35755
|
+
} else if (errorMessage.includes("message") || errorMessage.includes("mail")) {
|
|
35756
|
+
failedStep = "Swarm mail notification";
|
|
35757
|
+
}
|
|
35758
|
+
const errorBody = [
|
|
35759
|
+
`## ⚠️ SWARM_COMPLETE FAILED`,
|
|
35760
|
+
"",
|
|
35761
|
+
`**Bead**: ${args.bead_id}`,
|
|
35762
|
+
`**Agent**: ${args.agent_name}`,
|
|
35763
|
+
`**Failed Step**: ${failedStep}`,
|
|
35764
|
+
"",
|
|
35765
|
+
`### Error Message`,
|
|
35766
|
+
"```",
|
|
35767
|
+
errorMessage,
|
|
35768
|
+
"```",
|
|
35769
|
+
"",
|
|
35770
|
+
errorStack ? `### Stack Trace
|
|
35771
|
+
\`\`\`
|
|
35772
|
+
${errorStack.slice(0, 1000)}
|
|
35773
|
+
\`\`\`
|
|
35774
|
+
` : "",
|
|
35775
|
+
`### Context`,
|
|
35776
|
+
`- **Summary**: ${args.summary}`,
|
|
35777
|
+
`- **Files touched**: ${args.files_touched?.length ? args.files_touched.join(", ") : "none"}`,
|
|
35778
|
+
`- **Skip UBS**: ${args.skip_ubs_scan ?? false}`,
|
|
35779
|
+
`- **Skip verification**: ${args.skip_verification ?? false}`,
|
|
35780
|
+
"",
|
|
35781
|
+
`### Recovery Actions`,
|
|
35782
|
+
"1. Check error message for specific issue",
|
|
35783
|
+
"2. Review failed step (UBS scan, typecheck, bead close, etc.)",
|
|
35784
|
+
"3. Fix underlying issue or use skip flags if appropriate",
|
|
35785
|
+
"4. Retry swarm_complete after fixing"
|
|
35786
|
+
].filter(Boolean).join(`
|
|
35787
|
+
`);
|
|
35788
|
+
try {
|
|
35789
|
+
await sendSwarmMessage({
|
|
35790
|
+
projectPath: args.project_key,
|
|
35791
|
+
fromAgent: args.agent_name,
|
|
35792
|
+
toAgents: [],
|
|
35793
|
+
subject: `FAILED: swarm_complete for ${args.bead_id}`,
|
|
35794
|
+
body: errorBody,
|
|
35795
|
+
threadId: epicId,
|
|
35796
|
+
importance: "urgent"
|
|
35797
|
+
});
|
|
35798
|
+
} catch (mailError) {
|
|
35799
|
+
console.error(`[swarm_complete] CRITICAL: Failed to notify coordinator of failure for ${args.bead_id}:`, mailError);
|
|
35800
|
+
console.error(`[swarm_complete] Original error:`, error45);
|
|
35801
|
+
}
|
|
35802
|
+
throw error45;
|
|
35803
|
+
}
|
|
35106
35804
|
}
|
|
35107
35805
|
});
|
|
35108
35806
|
var swarm_record_outcome = tool({
|
|
@@ -35330,6 +36028,147 @@ var swarm_check_strikes = tool({
|
|
|
35330
36028
|
}
|
|
35331
36029
|
}
|
|
35332
36030
|
});
|
|
36031
|
+
var swarm_checkpoint = tool({
|
|
36032
|
+
description: "Checkpoint swarm context for recovery. Records current state for crash recovery. Non-fatal errors.",
|
|
36033
|
+
args: {
|
|
36034
|
+
project_key: tool.schema.string().describe("Project path"),
|
|
36035
|
+
agent_name: tool.schema.string().describe("Agent name"),
|
|
36036
|
+
bead_id: tool.schema.string().describe("Subtask bead ID"),
|
|
36037
|
+
epic_id: tool.schema.string().describe("Epic bead ID"),
|
|
36038
|
+
files_modified: tool.schema.array(tool.schema.string()).describe("Files modified so far"),
|
|
36039
|
+
progress_percent: tool.schema.number().min(0).max(100).describe("Current progress"),
|
|
36040
|
+
directives: tool.schema.object({
|
|
36041
|
+
shared_context: tool.schema.string().optional(),
|
|
36042
|
+
skills_to_load: tool.schema.array(tool.schema.string()).optional(),
|
|
36043
|
+
coordinator_notes: tool.schema.string().optional()
|
|
36044
|
+
}).optional().describe("Coordinator directives for this subtask"),
|
|
36045
|
+
error_context: tool.schema.string().optional().describe("Error context if checkpoint is during error handling")
|
|
36046
|
+
},
|
|
36047
|
+
async execute(args) {
|
|
36048
|
+
try {
|
|
36049
|
+
const checkpoint = {
|
|
36050
|
+
epic_id: args.epic_id,
|
|
36051
|
+
bead_id: args.bead_id,
|
|
36052
|
+
strategy: "file-based",
|
|
36053
|
+
files: args.files_modified,
|
|
36054
|
+
dependencies: [],
|
|
36055
|
+
directives: args.directives || {},
|
|
36056
|
+
recovery: {
|
|
36057
|
+
last_checkpoint: Date.now(),
|
|
36058
|
+
files_modified: args.files_modified,
|
|
36059
|
+
progress_percent: args.progress_percent,
|
|
36060
|
+
error_context: args.error_context
|
|
36061
|
+
}
|
|
36062
|
+
};
|
|
36063
|
+
const event = createEvent("swarm_checkpointed", {
|
|
36064
|
+
project_key: args.project_key,
|
|
36065
|
+
epic_id: args.epic_id,
|
|
36066
|
+
bead_id: args.bead_id,
|
|
36067
|
+
strategy: checkpoint.strategy,
|
|
36068
|
+
files: checkpoint.files,
|
|
36069
|
+
dependencies: checkpoint.dependencies,
|
|
36070
|
+
directives: checkpoint.directives,
|
|
36071
|
+
recovery: checkpoint.recovery
|
|
36072
|
+
});
|
|
36073
|
+
await appendEvent(event, args.project_key);
|
|
36074
|
+
const { getDatabase: getDatabase2 } = await Promise.resolve().then(() => (init_streams(), exports_streams));
|
|
36075
|
+
const db = await getDatabase2(args.project_key);
|
|
36076
|
+
const now = Date.now();
|
|
36077
|
+
await db.query(`INSERT INTO swarm_contexts (id, epic_id, bead_id, strategy, files, dependencies, directives, recovery, created_at, updated_at)
|
|
36078
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
|
|
36079
|
+
ON CONFLICT (id) DO UPDATE SET
|
|
36080
|
+
files = EXCLUDED.files,
|
|
36081
|
+
recovery = EXCLUDED.recovery,
|
|
36082
|
+
updated_at = EXCLUDED.updated_at`, [
|
|
36083
|
+
args.bead_id,
|
|
36084
|
+
args.epic_id,
|
|
36085
|
+
args.bead_id,
|
|
36086
|
+
checkpoint.strategy,
|
|
36087
|
+
JSON.stringify(checkpoint.files),
|
|
36088
|
+
JSON.stringify(checkpoint.dependencies),
|
|
36089
|
+
JSON.stringify(checkpoint.directives),
|
|
36090
|
+
JSON.stringify(checkpoint.recovery),
|
|
36091
|
+
now,
|
|
36092
|
+
now
|
|
36093
|
+
]);
|
|
36094
|
+
return JSON.stringify({
|
|
36095
|
+
success: true,
|
|
36096
|
+
checkpoint_timestamp: now,
|
|
36097
|
+
summary: `Checkpoint saved for ${args.bead_id} at ${args.progress_percent}%`,
|
|
36098
|
+
bead_id: args.bead_id,
|
|
36099
|
+
epic_id: args.epic_id,
|
|
36100
|
+
files_tracked: args.files_modified.length
|
|
36101
|
+
}, null, 2);
|
|
36102
|
+
} catch (error45) {
|
|
36103
|
+
console.warn(`[swarm_checkpoint] Failed to checkpoint ${args.bead_id}:`, error45);
|
|
36104
|
+
return JSON.stringify({
|
|
36105
|
+
success: false,
|
|
36106
|
+
warning: "Checkpoint failed but continuing",
|
|
36107
|
+
error: error45 instanceof Error ? error45.message : String(error45),
|
|
36108
|
+
bead_id: args.bead_id,
|
|
36109
|
+
note: "This is non-fatal. Work can continue without checkpoint."
|
|
36110
|
+
}, null, 2);
|
|
36111
|
+
}
|
|
36112
|
+
}
|
|
36113
|
+
});
|
|
36114
|
+
var swarm_recover = tool({
|
|
36115
|
+
description: "Recover swarm context from last checkpoint. Returns context or null if not found.",
|
|
36116
|
+
args: {
|
|
36117
|
+
project_key: tool.schema.string().describe("Project path"),
|
|
36118
|
+
epic_id: tool.schema.string().describe("Epic bead ID to recover")
|
|
36119
|
+
},
|
|
36120
|
+
async execute(args) {
|
|
36121
|
+
try {
|
|
36122
|
+
const { getDatabase: getDatabase2 } = await Promise.resolve().then(() => (init_streams(), exports_streams));
|
|
36123
|
+
const db = await getDatabase2(args.project_key);
|
|
36124
|
+
const result = await db.query(`SELECT * FROM swarm_contexts
|
|
36125
|
+
WHERE epic_id = $1
|
|
36126
|
+
ORDER BY updated_at DESC
|
|
36127
|
+
LIMIT 1`, [args.epic_id]);
|
|
36128
|
+
if (result.rows.length === 0) {
|
|
36129
|
+
return JSON.stringify({
|
|
36130
|
+
found: false,
|
|
36131
|
+
message: `No checkpoint found for epic ${args.epic_id}`,
|
|
36132
|
+
epic_id: args.epic_id
|
|
36133
|
+
}, null, 2);
|
|
36134
|
+
}
|
|
36135
|
+
const row = result.rows[0];
|
|
36136
|
+
const context = {
|
|
36137
|
+
id: row.id,
|
|
36138
|
+
epic_id: row.epic_id,
|
|
36139
|
+
bead_id: row.bead_id,
|
|
36140
|
+
strategy: row.strategy,
|
|
36141
|
+
files: JSON.parse(row.files),
|
|
36142
|
+
dependencies: JSON.parse(row.dependencies),
|
|
36143
|
+
directives: JSON.parse(row.directives),
|
|
36144
|
+
recovery: JSON.parse(row.recovery),
|
|
36145
|
+
created_at: row.created_at,
|
|
36146
|
+
updated_at: row.updated_at
|
|
36147
|
+
};
|
|
36148
|
+
const event = createEvent("swarm_recovered", {
|
|
36149
|
+
project_key: args.project_key,
|
|
36150
|
+
epic_id: args.epic_id,
|
|
36151
|
+
bead_id: context.bead_id,
|
|
36152
|
+
recovered_from_checkpoint: context.recovery.last_checkpoint
|
|
36153
|
+
});
|
|
36154
|
+
await appendEvent(event, args.project_key);
|
|
36155
|
+
return JSON.stringify({
|
|
36156
|
+
found: true,
|
|
36157
|
+
context,
|
|
36158
|
+
summary: `Recovered checkpoint from ${new Date(context.updated_at).toISOString()}`,
|
|
36159
|
+
age_seconds: Math.round((Date.now() - context.updated_at) / 1000)
|
|
36160
|
+
}, null, 2);
|
|
36161
|
+
} catch (error45) {
|
|
36162
|
+
console.warn(`[swarm_recover] Failed to recover context for ${args.epic_id}:`, error45);
|
|
36163
|
+
return JSON.stringify({
|
|
36164
|
+
found: false,
|
|
36165
|
+
error: error45 instanceof Error ? error45.message : String(error45),
|
|
36166
|
+
message: `Recovery failed for epic ${args.epic_id}`,
|
|
36167
|
+
epic_id: args.epic_id
|
|
36168
|
+
}, null, 2);
|
|
36169
|
+
}
|
|
36170
|
+
}
|
|
36171
|
+
});
|
|
35333
36172
|
var swarm_learn = tool({
|
|
35334
36173
|
description: `Analyze completed work and optionally create a skill from learned patterns.
|
|
35335
36174
|
|
|
@@ -35470,6 +36309,8 @@ var orchestrateTools = {
|
|
|
35470
36309
|
swarm_get_error_context,
|
|
35471
36310
|
swarm_resolve_error,
|
|
35472
36311
|
swarm_check_strikes,
|
|
36312
|
+
swarm_checkpoint,
|
|
36313
|
+
swarm_recover,
|
|
35473
36314
|
swarm_learn
|
|
35474
36315
|
};
|
|
35475
36316
|
|
|
@@ -36564,6 +37405,172 @@ var mandateTools = {
|
|
|
36564
37405
|
mandate_list,
|
|
36565
37406
|
mandate_stats
|
|
36566
37407
|
};
|
|
37408
|
+
|
|
37409
|
+
// src/output-guardrails.ts
|
|
37410
|
+
var DEFAULT_GUARDRAIL_CONFIG = {
|
|
37411
|
+
defaultMaxChars: 32000,
|
|
37412
|
+
toolLimits: {
|
|
37413
|
+
"repo-autopsy_file": 64000,
|
|
37414
|
+
"repo-autopsy_search": 64000,
|
|
37415
|
+
"repo-autopsy_exports_map": 64000,
|
|
37416
|
+
"context7_get-library-docs": 64000,
|
|
37417
|
+
cass_view: 64000,
|
|
37418
|
+
cass_search: 48000,
|
|
37419
|
+
skills_read: 48000,
|
|
37420
|
+
"repo-autopsy_structure": 24000,
|
|
37421
|
+
"repo-autopsy_stats": 16000,
|
|
37422
|
+
cass_stats: 8000
|
|
37423
|
+
},
|
|
37424
|
+
skipTools: [
|
|
37425
|
+
"beads_create",
|
|
37426
|
+
"beads_create_epic",
|
|
37427
|
+
"beads_query",
|
|
37428
|
+
"beads_update",
|
|
37429
|
+
"beads_close",
|
|
37430
|
+
"beads_start",
|
|
37431
|
+
"beads_ready",
|
|
37432
|
+
"beads_sync",
|
|
37433
|
+
"agentmail_init",
|
|
37434
|
+
"agentmail_send",
|
|
37435
|
+
"agentmail_inbox",
|
|
37436
|
+
"agentmail_read_message",
|
|
37437
|
+
"agentmail_summarize_thread",
|
|
37438
|
+
"agentmail_reserve",
|
|
37439
|
+
"agentmail_release",
|
|
37440
|
+
"agentmail_ack",
|
|
37441
|
+
"swarmmail_init",
|
|
37442
|
+
"swarmmail_send",
|
|
37443
|
+
"swarmmail_inbox",
|
|
37444
|
+
"swarmmail_read_message",
|
|
37445
|
+
"swarmmail_reserve",
|
|
37446
|
+
"swarmmail_release",
|
|
37447
|
+
"swarmmail_ack",
|
|
37448
|
+
"structured_extract_json",
|
|
37449
|
+
"structured_validate",
|
|
37450
|
+
"structured_parse_evaluation",
|
|
37451
|
+
"structured_parse_decomposition",
|
|
37452
|
+
"structured_parse_bead_tree",
|
|
37453
|
+
"swarm_select_strategy",
|
|
37454
|
+
"swarm_plan_prompt",
|
|
37455
|
+
"swarm_decompose",
|
|
37456
|
+
"swarm_validate_decomposition",
|
|
37457
|
+
"swarm_status",
|
|
37458
|
+
"swarm_progress",
|
|
37459
|
+
"swarm_complete",
|
|
37460
|
+
"swarm_record_outcome",
|
|
37461
|
+
"swarm_subtask_prompt",
|
|
37462
|
+
"swarm_spawn_subtask",
|
|
37463
|
+
"swarm_complete_subtask",
|
|
37464
|
+
"swarm_evaluation_prompt",
|
|
37465
|
+
"mandate_file",
|
|
37466
|
+
"mandate_vote",
|
|
37467
|
+
"mandate_query",
|
|
37468
|
+
"mandate_list",
|
|
37469
|
+
"mandate_stats"
|
|
37470
|
+
]
|
|
37471
|
+
};
|
|
37472
|
+
function findMatchingBrace(text, startIdx) {
|
|
37473
|
+
const openChar = text[startIdx];
|
|
37474
|
+
const closeChar = openChar === "{" ? "}" : "]";
|
|
37475
|
+
let depth = 1;
|
|
37476
|
+
for (let i = startIdx + 1;i < text.length; i++) {
|
|
37477
|
+
if (text[i] === openChar) {
|
|
37478
|
+
depth++;
|
|
37479
|
+
} else if (text[i] === closeChar) {
|
|
37480
|
+
depth--;
|
|
37481
|
+
if (depth === 0) {
|
|
37482
|
+
return i;
|
|
37483
|
+
}
|
|
37484
|
+
}
|
|
37485
|
+
}
|
|
37486
|
+
return -1;
|
|
37487
|
+
}
|
|
37488
|
+
function truncateWithBoundaries(text, maxChars) {
|
|
37489
|
+
if (text.length <= maxChars) {
|
|
37490
|
+
return text;
|
|
37491
|
+
}
|
|
37492
|
+
let truncateAt = maxChars;
|
|
37493
|
+
const beforeTruncate = text.slice(0, maxChars);
|
|
37494
|
+
const lastOpenBrace = Math.max(beforeTruncate.lastIndexOf("{"), beforeTruncate.lastIndexOf("["));
|
|
37495
|
+
const lastCloseBrace = Math.max(beforeTruncate.lastIndexOf("}"), beforeTruncate.lastIndexOf("]"));
|
|
37496
|
+
if (lastOpenBrace > lastCloseBrace) {
|
|
37497
|
+
const matchingClose = findMatchingBrace(text, lastOpenBrace);
|
|
37498
|
+
if (matchingClose !== -1 && matchingClose < maxChars * 1.2) {
|
|
37499
|
+
truncateAt = matchingClose + 1;
|
|
37500
|
+
} else {
|
|
37501
|
+
truncateAt = lastOpenBrace;
|
|
37502
|
+
}
|
|
37503
|
+
}
|
|
37504
|
+
const codeBlockMarker = "```";
|
|
37505
|
+
const beforeTruncateForCode = text.slice(0, truncateAt);
|
|
37506
|
+
const codeBlockCount = (beforeTruncateForCode.match(/```/g) || []).length;
|
|
37507
|
+
if (codeBlockCount % 2 === 1) {
|
|
37508
|
+
const closeMarkerIdx = text.indexOf(codeBlockMarker, truncateAt);
|
|
37509
|
+
if (closeMarkerIdx !== -1 && closeMarkerIdx < maxChars * 1.2) {
|
|
37510
|
+
truncateAt = closeMarkerIdx + codeBlockMarker.length;
|
|
37511
|
+
} else {
|
|
37512
|
+
const lastOpenMarker = beforeTruncateForCode.lastIndexOf(codeBlockMarker);
|
|
37513
|
+
if (lastOpenMarker !== -1) {
|
|
37514
|
+
truncateAt = lastOpenMarker;
|
|
37515
|
+
}
|
|
37516
|
+
}
|
|
37517
|
+
}
|
|
37518
|
+
const headerMatch = text.slice(0, truncateAt).match(/\n#{1,6}\s/g);
|
|
37519
|
+
if (headerMatch && headerMatch.length > 0) {
|
|
37520
|
+
const lastHeaderIdx = beforeTruncateForCode.lastIndexOf(`
|
|
37521
|
+
##`);
|
|
37522
|
+
if (lastHeaderIdx !== -1 && lastHeaderIdx > maxChars * 0.8) {
|
|
37523
|
+
truncateAt = lastHeaderIdx;
|
|
37524
|
+
}
|
|
37525
|
+
}
|
|
37526
|
+
while (truncateAt > 0 && !/\s/.test(text[truncateAt])) {
|
|
37527
|
+
truncateAt--;
|
|
37528
|
+
}
|
|
37529
|
+
const truncated = text.slice(0, truncateAt).trimEnd();
|
|
37530
|
+
const charsRemoved = text.length - truncated.length;
|
|
37531
|
+
return `${truncated}
|
|
37532
|
+
|
|
37533
|
+
[TRUNCATED - ${charsRemoved.toLocaleString()} chars removed]`;
|
|
37534
|
+
}
|
|
37535
|
+
function getToolLimit(toolName, config2 = DEFAULT_GUARDRAIL_CONFIG) {
|
|
37536
|
+
return config2.toolLimits[toolName] ?? config2.defaultMaxChars;
|
|
37537
|
+
}
|
|
37538
|
+
function guardrailOutput(toolName, output, config2 = DEFAULT_GUARDRAIL_CONFIG) {
|
|
37539
|
+
const originalLength = output.length;
|
|
37540
|
+
if (config2.skipTools.includes(toolName)) {
|
|
37541
|
+
return {
|
|
37542
|
+
output,
|
|
37543
|
+
truncated: false,
|
|
37544
|
+
originalLength,
|
|
37545
|
+
truncatedLength: originalLength
|
|
37546
|
+
};
|
|
37547
|
+
}
|
|
37548
|
+
const limit = getToolLimit(toolName, config2);
|
|
37549
|
+
if (originalLength <= limit) {
|
|
37550
|
+
return {
|
|
37551
|
+
output,
|
|
37552
|
+
truncated: false,
|
|
37553
|
+
originalLength,
|
|
37554
|
+
truncatedLength: originalLength
|
|
37555
|
+
};
|
|
37556
|
+
}
|
|
37557
|
+
const truncatedOutput = truncateWithBoundaries(output, limit);
|
|
37558
|
+
const truncatedLength = truncatedOutput.length;
|
|
37559
|
+
return {
|
|
37560
|
+
output: truncatedOutput,
|
|
37561
|
+
truncated: true,
|
|
37562
|
+
originalLength,
|
|
37563
|
+
truncatedLength
|
|
37564
|
+
};
|
|
37565
|
+
}
|
|
37566
|
+
function createMetrics(result, toolName) {
|
|
37567
|
+
return {
|
|
37568
|
+
toolName,
|
|
37569
|
+
originalLength: result.originalLength,
|
|
37570
|
+
truncatedLength: result.truncatedLength,
|
|
37571
|
+
timestamp: Date.now()
|
|
37572
|
+
};
|
|
37573
|
+
}
|
|
36567
37574
|
// src/storage.ts
|
|
36568
37575
|
init_learning();
|
|
36569
37576
|
|
|
@@ -36696,20 +37703,47 @@ async function execSemanticMemory2(args) {
|
|
|
36696
37703
|
};
|
|
36697
37704
|
}
|
|
36698
37705
|
}
|
|
36699
|
-
|
|
36700
|
-
|
|
36701
|
-
collections: {
|
|
37706
|
+
function getCollectionNames() {
|
|
37707
|
+
const base = {
|
|
36702
37708
|
feedback: "swarm-feedback",
|
|
36703
37709
|
patterns: "swarm-patterns",
|
|
36704
37710
|
maturity: "swarm-maturity"
|
|
36705
|
-
}
|
|
37711
|
+
};
|
|
37712
|
+
if (process.env.TEST_MEMORY_COLLECTIONS === "true") {
|
|
37713
|
+
return {
|
|
37714
|
+
feedback: `${base.feedback}-test`,
|
|
37715
|
+
patterns: `${base.patterns}-test`,
|
|
37716
|
+
maturity: `${base.maturity}-test`
|
|
37717
|
+
};
|
|
37718
|
+
}
|
|
37719
|
+
return base;
|
|
37720
|
+
}
|
|
37721
|
+
var DEFAULT_STORAGE_CONFIG = {
|
|
37722
|
+
backend: "semantic-memory",
|
|
37723
|
+
collections: getCollectionNames(),
|
|
36706
37724
|
useSemanticSearch: true
|
|
36707
37725
|
};
|
|
36708
|
-
|
|
37726
|
+
var sessionStats = {
|
|
37727
|
+
storesCount: 0,
|
|
37728
|
+
queriesCount: 0,
|
|
37729
|
+
sessionStart: Date.now(),
|
|
37730
|
+
lastAlertCheck: Date.now()
|
|
37731
|
+
};
|
|
36709
37732
|
class SemanticMemoryStorage {
|
|
36710
37733
|
config;
|
|
36711
37734
|
constructor(config2 = {}) {
|
|
36712
37735
|
this.config = { ...DEFAULT_STORAGE_CONFIG, ...config2 };
|
|
37736
|
+
console.log(`[storage] SemanticMemoryStorage initialized with collections:`, this.config.collections);
|
|
37737
|
+
}
|
|
37738
|
+
async checkLowUsageAlert() {
|
|
37739
|
+
const TEN_MINUTES = 10 * 60 * 1000;
|
|
37740
|
+
const now = Date.now();
|
|
37741
|
+
const sessionDuration = now - sessionStats.sessionStart;
|
|
37742
|
+
const timeSinceLastAlert = now - sessionStats.lastAlertCheck;
|
|
37743
|
+
if (sessionDuration >= TEN_MINUTES && sessionStats.storesCount < 1 && timeSinceLastAlert >= TEN_MINUTES) {
|
|
37744
|
+
console.warn(`[storage] LOW USAGE ALERT: ${sessionStats.storesCount} stores after ${Math.floor(sessionDuration / 60000)} minutes`);
|
|
37745
|
+
sessionStats.lastAlertCheck = now;
|
|
37746
|
+
}
|
|
36713
37747
|
}
|
|
36714
37748
|
async store(collection, data, metadata) {
|
|
36715
37749
|
const content = typeof data === "string" ? data : JSON.stringify(data);
|
|
@@ -36717,7 +37751,13 @@ class SemanticMemoryStorage {
|
|
|
36717
37751
|
if (metadata) {
|
|
36718
37752
|
args.push("--metadata", JSON.stringify(metadata));
|
|
36719
37753
|
}
|
|
36720
|
-
|
|
37754
|
+
console.log(`[storage] store() -> collection="${collection}"`);
|
|
37755
|
+
sessionStats.storesCount++;
|
|
37756
|
+
const result = await execSemanticMemory2(args);
|
|
37757
|
+
if (result.exitCode !== 0) {
|
|
37758
|
+
console.warn(`[storage] semantic-memory store() failed with exit code ${result.exitCode}: ${result.stderr.toString().trim()}`);
|
|
37759
|
+
}
|
|
37760
|
+
await this.checkLowUsageAlert();
|
|
36721
37761
|
}
|
|
36722
37762
|
async find(collection, query, limit = 10, useFts = false) {
|
|
36723
37763
|
const args = [
|
|
@@ -36732,6 +37772,8 @@ class SemanticMemoryStorage {
|
|
|
36732
37772
|
if (useFts) {
|
|
36733
37773
|
args.push("--fts");
|
|
36734
37774
|
}
|
|
37775
|
+
console.log(`[storage] find() -> collection="${collection}", query="${query.slice(0, 50)}${query.length > 50 ? "..." : ""}", limit=${limit}, fts=${useFts}`);
|
|
37776
|
+
sessionStats.queriesCount++;
|
|
36735
37777
|
const result = await execSemanticMemory2(args);
|
|
36736
37778
|
if (result.exitCode !== 0) {
|
|
36737
37779
|
console.warn(`[storage] semantic-memory find() failed with exit code ${result.exitCode}: ${result.stderr.toString().trim()}`);
|
|
@@ -36757,6 +37799,8 @@ class SemanticMemoryStorage {
|
|
|
36757
37799
|
}
|
|
36758
37800
|
}
|
|
36759
37801
|
async list(collection) {
|
|
37802
|
+
console.log(`[storage] list() -> collection="${collection}"`);
|
|
37803
|
+
sessionStats.queriesCount++;
|
|
36760
37804
|
const result = await execSemanticMemory2([
|
|
36761
37805
|
"list",
|
|
36762
37806
|
"--collection",
|
|
@@ -37037,6 +38081,13 @@ var SwarmPlugin = async (input) => {
|
|
|
37037
38081
|
},
|
|
37038
38082
|
"tool.execute.after": async (input2, output) => {
|
|
37039
38083
|
const toolName = input2.tool;
|
|
38084
|
+
if (output.output && typeof output.output === "string") {
|
|
38085
|
+
const guardrailResult = guardrailOutput(toolName, output.output);
|
|
38086
|
+
if (guardrailResult.truncated) {
|
|
38087
|
+
output.output = guardrailResult.output;
|
|
38088
|
+
console.log(`[swarm-plugin] Guardrail truncated ${toolName}: ${guardrailResult.originalLength} → ${guardrailResult.truncatedLength} chars`);
|
|
38089
|
+
}
|
|
38090
|
+
}
|
|
37040
38091
|
if (toolName === "agentmail_init" && output.output) {
|
|
37041
38092
|
try {
|
|
37042
38093
|
const result = JSON.parse(output.output);
|
|
@@ -37083,6 +38134,7 @@ export {
|
|
|
37083
38134
|
warnMissingTool,
|
|
37084
38135
|
updateMandateStatus,
|
|
37085
38136
|
updateAllMandateStatuses,
|
|
38137
|
+
truncateWithBoundaries,
|
|
37086
38138
|
swarmTools,
|
|
37087
38139
|
swarmMailTools,
|
|
37088
38140
|
structuredTools,
|
|
@@ -37111,6 +38163,7 @@ export {
|
|
|
37111
38163
|
isAgentNotFoundError,
|
|
37112
38164
|
invalidateSkillsCache,
|
|
37113
38165
|
ifToolAvailable,
|
|
38166
|
+
guardrailOutput,
|
|
37114
38167
|
groupByTransition,
|
|
37115
38168
|
getToolAvailability,
|
|
37116
38169
|
getSwarmMailProjectDirectory,
|
|
@@ -37137,6 +38190,7 @@ export {
|
|
|
37137
38190
|
src_default as default,
|
|
37138
38191
|
createStorageWithFallback,
|
|
37139
38192
|
createStorage,
|
|
38193
|
+
createMetrics,
|
|
37140
38194
|
createMandateStorage,
|
|
37141
38195
|
createAgentMailError,
|
|
37142
38196
|
clearSessionState,
|
|
@@ -37159,12 +38213,17 @@ export {
|
|
|
37159
38213
|
VoteTypeSchema,
|
|
37160
38214
|
VoteSchema,
|
|
37161
38215
|
ValidationResultSchema,
|
|
38216
|
+
UpdateSwarmContextArgsSchema,
|
|
37162
38217
|
TaskDecompositionSchema,
|
|
38218
|
+
SwarmStrategySchema,
|
|
37163
38219
|
SwarmStatusSchema,
|
|
37164
38220
|
SwarmSpawnResultSchema,
|
|
38221
|
+
SwarmRecoverySchema,
|
|
37165
38222
|
SwarmPlugin,
|
|
37166
38223
|
SwarmEvaluationResultSchema,
|
|
37167
38224
|
SwarmError,
|
|
38225
|
+
SwarmDirectivesSchema,
|
|
38226
|
+
SwarmBeadContextSchema,
|
|
37168
38227
|
SubtaskSpecSchema,
|
|
37169
38228
|
SubtaskDependencySchema,
|
|
37170
38229
|
SpawnedAgentSchema,
|
|
@@ -37174,6 +38233,7 @@ export {
|
|
|
37174
38233
|
SUBTASK_PROMPT_V2,
|
|
37175
38234
|
STRATEGIES,
|
|
37176
38235
|
RepoCrawlError,
|
|
38236
|
+
QuerySwarmContextsArgsSchema,
|
|
37177
38237
|
QueryMandatesArgsSchema,
|
|
37178
38238
|
MandateStatusSchema,
|
|
37179
38239
|
MandateScoreSchema,
|
|
@@ -37195,8 +38255,10 @@ export {
|
|
|
37195
38255
|
DEFAULT_STORAGE_CONFIG,
|
|
37196
38256
|
DEFAULT_MANDATE_STORAGE_CONFIG,
|
|
37197
38257
|
DEFAULT_MANDATE_DECAY_CONFIG,
|
|
38258
|
+
DEFAULT_GUARDRAIL_CONFIG,
|
|
37198
38259
|
DEFAULT_CRITERIA,
|
|
37199
38260
|
CriterionEvaluationSchema,
|
|
38261
|
+
CreateSwarmContextArgsSchema,
|
|
37200
38262
|
CreateMandateArgsSchema,
|
|
37201
38263
|
CastVoteArgsSchema,
|
|
37202
38264
|
BeadValidationError,
|