opencode-swarm 6.22.2 → 6.22.4
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/README.md +185 -90
- package/dist/cli/index.js +2 -0
- package/dist/hooks/guardrails.d.ts +19 -0
- package/dist/index.js +1520 -1238
- package/dist/session/snapshot-writer.d.ts +1 -0
- package/dist/state.d.ts +2 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -46,6 +46,42 @@ var __export = (target, all) => {
|
|
|
46
46
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
47
47
|
var __require = import.meta.require;
|
|
48
48
|
|
|
49
|
+
// src/tools/tool-names.ts
|
|
50
|
+
var TOOL_NAMES, TOOL_NAME_SET;
|
|
51
|
+
var init_tool_names = __esm(() => {
|
|
52
|
+
TOOL_NAMES = [
|
|
53
|
+
"diff",
|
|
54
|
+
"syntax_check",
|
|
55
|
+
"placeholder_scan",
|
|
56
|
+
"imports",
|
|
57
|
+
"lint",
|
|
58
|
+
"secretscan",
|
|
59
|
+
"sast_scan",
|
|
60
|
+
"build_check",
|
|
61
|
+
"pre_check_batch",
|
|
62
|
+
"quality_budget",
|
|
63
|
+
"symbols",
|
|
64
|
+
"complexity_hotspots",
|
|
65
|
+
"schema_drift",
|
|
66
|
+
"todo_extract",
|
|
67
|
+
"evidence_check",
|
|
68
|
+
"sbom_generate",
|
|
69
|
+
"checkpoint",
|
|
70
|
+
"pkg_audit",
|
|
71
|
+
"test_runner",
|
|
72
|
+
"detect_domains",
|
|
73
|
+
"gitingest",
|
|
74
|
+
"retrieve_summary",
|
|
75
|
+
"extract_code_blocks",
|
|
76
|
+
"phase_complete",
|
|
77
|
+
"save_plan",
|
|
78
|
+
"update_task_status",
|
|
79
|
+
"write_retro",
|
|
80
|
+
"declare_scope"
|
|
81
|
+
];
|
|
82
|
+
TOOL_NAME_SET = new Set(TOOL_NAMES);
|
|
83
|
+
});
|
|
84
|
+
|
|
49
85
|
// src/utils/merge.ts
|
|
50
86
|
function deepMergeInternal(base, override, depth) {
|
|
51
87
|
if (depth >= MAX_MERGE_DEPTH) {
|
|
@@ -72,6 +108,173 @@ function deepMerge(base, override) {
|
|
|
72
108
|
}
|
|
73
109
|
var MAX_MERGE_DEPTH = 10;
|
|
74
110
|
|
|
111
|
+
// src/config/constants.ts
|
|
112
|
+
function isQAAgent(name2) {
|
|
113
|
+
return QA_AGENTS.includes(name2);
|
|
114
|
+
}
|
|
115
|
+
function isSubagent(name2) {
|
|
116
|
+
return ALL_SUBAGENT_NAMES.includes(name2);
|
|
117
|
+
}
|
|
118
|
+
function isLowCapabilityModel(modelId) {
|
|
119
|
+
if (!modelId)
|
|
120
|
+
return false;
|
|
121
|
+
const lower = modelId.toLowerCase();
|
|
122
|
+
return LOW_CAPABILITY_MODELS.some((substr) => lower.includes(substr));
|
|
123
|
+
}
|
|
124
|
+
var QA_AGENTS, PIPELINE_AGENTS, ORCHESTRATOR_NAME = "architect", ALL_SUBAGENT_NAMES, ALL_AGENT_NAMES, AGENT_TOOL_MAP, DEFAULT_MODELS, DEFAULT_SCORING_CONFIG, LOW_CAPABILITY_MODELS;
|
|
125
|
+
var init_constants = __esm(() => {
|
|
126
|
+
init_tool_names();
|
|
127
|
+
QA_AGENTS = ["reviewer", "critic"];
|
|
128
|
+
PIPELINE_AGENTS = ["explorer", "coder", "test_engineer"];
|
|
129
|
+
ALL_SUBAGENT_NAMES = [
|
|
130
|
+
"sme",
|
|
131
|
+
"docs",
|
|
132
|
+
"designer",
|
|
133
|
+
...QA_AGENTS,
|
|
134
|
+
...PIPELINE_AGENTS
|
|
135
|
+
];
|
|
136
|
+
ALL_AGENT_NAMES = [
|
|
137
|
+
ORCHESTRATOR_NAME,
|
|
138
|
+
...ALL_SUBAGENT_NAMES
|
|
139
|
+
];
|
|
140
|
+
AGENT_TOOL_MAP = {
|
|
141
|
+
architect: [
|
|
142
|
+
"checkpoint",
|
|
143
|
+
"complexity_hotspots",
|
|
144
|
+
"detect_domains",
|
|
145
|
+
"evidence_check",
|
|
146
|
+
"extract_code_blocks",
|
|
147
|
+
"gitingest",
|
|
148
|
+
"imports",
|
|
149
|
+
"lint",
|
|
150
|
+
"diff",
|
|
151
|
+
"pkg_audit",
|
|
152
|
+
"pre_check_batch",
|
|
153
|
+
"retrieve_summary",
|
|
154
|
+
"save_plan",
|
|
155
|
+
"schema_drift",
|
|
156
|
+
"secretscan",
|
|
157
|
+
"symbols",
|
|
158
|
+
"test_runner",
|
|
159
|
+
"todo_extract",
|
|
160
|
+
"update_task_status",
|
|
161
|
+
"write_retro",
|
|
162
|
+
"declare_scope"
|
|
163
|
+
],
|
|
164
|
+
explorer: [
|
|
165
|
+
"complexity_hotspots",
|
|
166
|
+
"detect_domains",
|
|
167
|
+
"extract_code_blocks",
|
|
168
|
+
"gitingest",
|
|
169
|
+
"imports",
|
|
170
|
+
"retrieve_summary",
|
|
171
|
+
"schema_drift",
|
|
172
|
+
"symbols",
|
|
173
|
+
"todo_extract"
|
|
174
|
+
],
|
|
175
|
+
coder: [
|
|
176
|
+
"diff",
|
|
177
|
+
"imports",
|
|
178
|
+
"lint",
|
|
179
|
+
"symbols",
|
|
180
|
+
"extract_code_blocks",
|
|
181
|
+
"retrieve_summary"
|
|
182
|
+
],
|
|
183
|
+
test_engineer: [
|
|
184
|
+
"test_runner",
|
|
185
|
+
"diff",
|
|
186
|
+
"symbols",
|
|
187
|
+
"extract_code_blocks",
|
|
188
|
+
"retrieve_summary",
|
|
189
|
+
"imports",
|
|
190
|
+
"complexity_hotspots",
|
|
191
|
+
"pkg_audit"
|
|
192
|
+
],
|
|
193
|
+
sme: [
|
|
194
|
+
"complexity_hotspots",
|
|
195
|
+
"detect_domains",
|
|
196
|
+
"extract_code_blocks",
|
|
197
|
+
"imports",
|
|
198
|
+
"retrieve_summary",
|
|
199
|
+
"schema_drift",
|
|
200
|
+
"symbols"
|
|
201
|
+
],
|
|
202
|
+
reviewer: [
|
|
203
|
+
"diff",
|
|
204
|
+
"imports",
|
|
205
|
+
"lint",
|
|
206
|
+
"pkg_audit",
|
|
207
|
+
"pre_check_batch",
|
|
208
|
+
"secretscan",
|
|
209
|
+
"symbols",
|
|
210
|
+
"complexity_hotspots",
|
|
211
|
+
"retrieve_summary",
|
|
212
|
+
"extract_code_blocks",
|
|
213
|
+
"test_runner"
|
|
214
|
+
],
|
|
215
|
+
critic: [
|
|
216
|
+
"complexity_hotspots",
|
|
217
|
+
"detect_domains",
|
|
218
|
+
"imports",
|
|
219
|
+
"retrieve_summary",
|
|
220
|
+
"symbols"
|
|
221
|
+
],
|
|
222
|
+
docs: [
|
|
223
|
+
"detect_domains",
|
|
224
|
+
"extract_code_blocks",
|
|
225
|
+
"gitingest",
|
|
226
|
+
"imports",
|
|
227
|
+
"retrieve_summary",
|
|
228
|
+
"schema_drift",
|
|
229
|
+
"symbols",
|
|
230
|
+
"todo_extract"
|
|
231
|
+
],
|
|
232
|
+
designer: ["extract_code_blocks", "retrieve_summary", "symbols"]
|
|
233
|
+
};
|
|
234
|
+
for (const [agentName, tools] of Object.entries(AGENT_TOOL_MAP)) {
|
|
235
|
+
const invalidTools = tools.filter((tool) => !TOOL_NAME_SET.has(tool));
|
|
236
|
+
if (invalidTools.length > 0) {
|
|
237
|
+
throw new Error(`Agent '${agentName}' has invalid tool names: [${invalidTools.join(", ")}]. ` + `All tools must be registered in TOOL_NAME_SET.`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
DEFAULT_MODELS = {
|
|
241
|
+
explorer: "opencode/trinity-large-preview-free",
|
|
242
|
+
coder: "opencode/minimax-m2.5-free",
|
|
243
|
+
reviewer: "opencode/big-pickle",
|
|
244
|
+
test_engineer: "opencode/gpt-5-nano",
|
|
245
|
+
sme: "opencode/trinity-large-preview-free",
|
|
246
|
+
critic: "opencode/trinity-large-preview-free",
|
|
247
|
+
docs: "opencode/trinity-large-preview-free",
|
|
248
|
+
designer: "opencode/trinity-large-preview-free",
|
|
249
|
+
default: "opencode/trinity-large-preview-free"
|
|
250
|
+
};
|
|
251
|
+
DEFAULT_SCORING_CONFIG = {
|
|
252
|
+
enabled: false,
|
|
253
|
+
max_candidates: 100,
|
|
254
|
+
weights: {
|
|
255
|
+
phase: 1,
|
|
256
|
+
current_task: 2,
|
|
257
|
+
blocked_task: 1.5,
|
|
258
|
+
recent_failure: 2.5,
|
|
259
|
+
recent_success: 0.5,
|
|
260
|
+
evidence_presence: 1,
|
|
261
|
+
decision_recency: 1.5,
|
|
262
|
+
dependency_proximity: 1
|
|
263
|
+
},
|
|
264
|
+
decision_decay: {
|
|
265
|
+
mode: "exponential",
|
|
266
|
+
half_life_hours: 24
|
|
267
|
+
},
|
|
268
|
+
token_ratios: {
|
|
269
|
+
prose: 0.25,
|
|
270
|
+
code: 0.4,
|
|
271
|
+
markdown: 0.3,
|
|
272
|
+
json: 0.35
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
LOW_CAPABILITY_MODELS = ["mini", "nano", "small", "free"];
|
|
276
|
+
});
|
|
277
|
+
|
|
75
278
|
// node_modules/zod/v4/core/core.js
|
|
76
279
|
function $constructor(name2, initializer, params) {
|
|
77
280
|
function init2(inst, def) {
|
|
@@ -14170,6 +14373,649 @@ var init_evidence_schema = __esm(() => {
|
|
|
14170
14373
|
});
|
|
14171
14374
|
});
|
|
14172
14375
|
|
|
14376
|
+
// src/config/schema.ts
|
|
14377
|
+
function stripKnownSwarmPrefix(agentName) {
|
|
14378
|
+
if (!agentName)
|
|
14379
|
+
return agentName;
|
|
14380
|
+
const normalized = agentName.toLowerCase();
|
|
14381
|
+
let stripped = normalized;
|
|
14382
|
+
let previous = "";
|
|
14383
|
+
while (stripped !== previous) {
|
|
14384
|
+
previous = stripped;
|
|
14385
|
+
for (const prefix of KNOWN_SWARM_PREFIXES) {
|
|
14386
|
+
for (const sep of SEPARATORS) {
|
|
14387
|
+
const prefixWithSep = prefix + sep;
|
|
14388
|
+
if (stripped.startsWith(prefixWithSep)) {
|
|
14389
|
+
stripped = stripped.slice(prefixWithSep.length);
|
|
14390
|
+
break;
|
|
14391
|
+
}
|
|
14392
|
+
}
|
|
14393
|
+
if (stripped !== previous)
|
|
14394
|
+
break;
|
|
14395
|
+
}
|
|
14396
|
+
}
|
|
14397
|
+
if (ALL_AGENT_NAMES.includes(stripped)) {
|
|
14398
|
+
return stripped;
|
|
14399
|
+
}
|
|
14400
|
+
for (const agent of ALL_AGENT_NAMES) {
|
|
14401
|
+
for (const sep of SEPARATORS) {
|
|
14402
|
+
const suffix = sep + agent;
|
|
14403
|
+
if (normalized.endsWith(suffix)) {
|
|
14404
|
+
return agent;
|
|
14405
|
+
}
|
|
14406
|
+
}
|
|
14407
|
+
if (normalized === agent) {
|
|
14408
|
+
return agent;
|
|
14409
|
+
}
|
|
14410
|
+
}
|
|
14411
|
+
return agentName;
|
|
14412
|
+
}
|
|
14413
|
+
function resolveGuardrailsConfig(config2, agentName) {
|
|
14414
|
+
if (!agentName) {
|
|
14415
|
+
return config2;
|
|
14416
|
+
}
|
|
14417
|
+
const canonicalName = stripKnownSwarmPrefix(agentName);
|
|
14418
|
+
const hasBuiltInProfile = canonicalName in DEFAULT_AGENT_PROFILES;
|
|
14419
|
+
const userProfile = config2.profiles?.[agentName] ?? config2.profiles?.[canonicalName];
|
|
14420
|
+
if (!hasBuiltInProfile) {
|
|
14421
|
+
if (userProfile) {
|
|
14422
|
+
return { ...config2, ...userProfile };
|
|
14423
|
+
}
|
|
14424
|
+
return config2;
|
|
14425
|
+
}
|
|
14426
|
+
const builtInProfile = DEFAULT_AGENT_PROFILES[canonicalName];
|
|
14427
|
+
const resolved = {
|
|
14428
|
+
...config2,
|
|
14429
|
+
...builtInProfile,
|
|
14430
|
+
...userProfile || {}
|
|
14431
|
+
};
|
|
14432
|
+
return resolved;
|
|
14433
|
+
}
|
|
14434
|
+
var KNOWN_SWARM_PREFIXES, SEPARATORS, AgentOverrideConfigSchema, SwarmConfigSchema, HooksConfigSchema, ScoringWeightsSchema, DecisionDecaySchema, TokenRatiosSchema, ScoringConfigSchema, ContextBudgetConfigSchema, EvidenceConfigSchema, GateFeatureSchema, PlaceholderScanConfigSchema, QualityBudgetConfigSchema, GateConfigSchema, PipelineConfigSchema, PhaseCompleteConfigSchema, SummaryConfigSchema, ReviewPassesConfigSchema, AdversarialDetectionConfigSchema, IntegrationAnalysisConfigSchema, DocsConfigSchema, UIReviewConfigSchema, CompactionAdvisoryConfigSchema, LintConfigSchema, SecretscanConfigSchema, GuardrailsProfileSchema, DEFAULT_AGENT_PROFILES, DEFAULT_ARCHITECT_PROFILE, GuardrailsConfigSchema, ToolFilterConfigSchema, PlanCursorConfigSchema, CheckpointConfigSchema, AutomationModeSchema, AutomationCapabilitiesSchema, AutomationConfigSchemaBase, AutomationConfigSchema, KnowledgeConfigSchema, CuratorConfigSchema, PluginConfigSchema;
|
|
14435
|
+
var init_schema = __esm(() => {
|
|
14436
|
+
init_zod();
|
|
14437
|
+
init_constants();
|
|
14438
|
+
KNOWN_SWARM_PREFIXES = [
|
|
14439
|
+
"paid",
|
|
14440
|
+
"local",
|
|
14441
|
+
"cloud",
|
|
14442
|
+
"enterprise",
|
|
14443
|
+
"mega",
|
|
14444
|
+
"default",
|
|
14445
|
+
"custom",
|
|
14446
|
+
"team",
|
|
14447
|
+
"project",
|
|
14448
|
+
"swarm",
|
|
14449
|
+
"synthetic"
|
|
14450
|
+
];
|
|
14451
|
+
SEPARATORS = ["_", "-", " "];
|
|
14452
|
+
AgentOverrideConfigSchema = exports_external.object({
|
|
14453
|
+
model: exports_external.string().optional(),
|
|
14454
|
+
temperature: exports_external.number().min(0).max(2).optional(),
|
|
14455
|
+
disabled: exports_external.boolean().optional()
|
|
14456
|
+
});
|
|
14457
|
+
SwarmConfigSchema = exports_external.object({
|
|
14458
|
+
name: exports_external.string().optional(),
|
|
14459
|
+
agents: exports_external.record(exports_external.string(), AgentOverrideConfigSchema).optional()
|
|
14460
|
+
});
|
|
14461
|
+
HooksConfigSchema = exports_external.object({
|
|
14462
|
+
system_enhancer: exports_external.boolean().default(true),
|
|
14463
|
+
compaction: exports_external.boolean().default(true),
|
|
14464
|
+
agent_activity: exports_external.boolean().default(true),
|
|
14465
|
+
delegation_tracker: exports_external.boolean().default(false),
|
|
14466
|
+
agent_awareness_max_chars: exports_external.number().min(50).max(2000).default(300),
|
|
14467
|
+
delegation_gate: exports_external.boolean().default(true),
|
|
14468
|
+
delegation_max_chars: exports_external.number().min(500).max(20000).default(4000)
|
|
14469
|
+
});
|
|
14470
|
+
ScoringWeightsSchema = exports_external.object({
|
|
14471
|
+
phase: exports_external.number().min(0).max(5).default(1),
|
|
14472
|
+
current_task: exports_external.number().min(0).max(5).default(2),
|
|
14473
|
+
blocked_task: exports_external.number().min(0).max(5).default(1.5),
|
|
14474
|
+
recent_failure: exports_external.number().min(0).max(5).default(2.5),
|
|
14475
|
+
recent_success: exports_external.number().min(0).max(5).default(0.5),
|
|
14476
|
+
evidence_presence: exports_external.number().min(0).max(5).default(1),
|
|
14477
|
+
decision_recency: exports_external.number().min(0).max(5).default(1.5),
|
|
14478
|
+
dependency_proximity: exports_external.number().min(0).max(5).default(1)
|
|
14479
|
+
});
|
|
14480
|
+
DecisionDecaySchema = exports_external.object({
|
|
14481
|
+
mode: exports_external.enum(["linear", "exponential"]).default("exponential"),
|
|
14482
|
+
half_life_hours: exports_external.number().min(1).max(168).default(24)
|
|
14483
|
+
});
|
|
14484
|
+
TokenRatiosSchema = exports_external.object({
|
|
14485
|
+
prose: exports_external.number().min(0.1).max(1).default(0.25),
|
|
14486
|
+
code: exports_external.number().min(0.1).max(1).default(0.4),
|
|
14487
|
+
markdown: exports_external.number().min(0.1).max(1).default(0.3),
|
|
14488
|
+
json: exports_external.number().min(0.1).max(1).default(0.35)
|
|
14489
|
+
});
|
|
14490
|
+
ScoringConfigSchema = exports_external.object({
|
|
14491
|
+
enabled: exports_external.boolean().default(false),
|
|
14492
|
+
max_candidates: exports_external.number().min(10).max(500).default(100),
|
|
14493
|
+
weights: ScoringWeightsSchema.optional(),
|
|
14494
|
+
decision_decay: DecisionDecaySchema.optional(),
|
|
14495
|
+
token_ratios: TokenRatiosSchema.optional()
|
|
14496
|
+
});
|
|
14497
|
+
ContextBudgetConfigSchema = exports_external.object({
|
|
14498
|
+
enabled: exports_external.boolean().default(true),
|
|
14499
|
+
warn_threshold: exports_external.number().min(0).max(1).default(0.7),
|
|
14500
|
+
critical_threshold: exports_external.number().min(0).max(1).default(0.9),
|
|
14501
|
+
model_limits: exports_external.record(exports_external.string(), exports_external.number().min(1000)).default({ default: 128000 }),
|
|
14502
|
+
max_injection_tokens: exports_external.number().min(100).max(50000).default(4000),
|
|
14503
|
+
tracked_agents: exports_external.array(exports_external.string()).default(["architect"]),
|
|
14504
|
+
scoring: ScoringConfigSchema.optional(),
|
|
14505
|
+
enforce: exports_external.boolean().default(true),
|
|
14506
|
+
prune_target: exports_external.number().min(0).max(1).default(0.7),
|
|
14507
|
+
preserve_last_n_turns: exports_external.number().min(0).max(100).default(4),
|
|
14508
|
+
recent_window: exports_external.number().min(1).max(100).default(10),
|
|
14509
|
+
enforce_on_agent_switch: exports_external.boolean().default(true),
|
|
14510
|
+
tool_output_mask_threshold: exports_external.number().min(100).max(1e5).default(2000)
|
|
14511
|
+
});
|
|
14512
|
+
EvidenceConfigSchema = exports_external.object({
|
|
14513
|
+
enabled: exports_external.boolean().default(true),
|
|
14514
|
+
max_age_days: exports_external.number().min(1).max(365).default(90),
|
|
14515
|
+
max_bundles: exports_external.number().min(10).max(1e4).default(1000),
|
|
14516
|
+
auto_archive: exports_external.boolean().default(false)
|
|
14517
|
+
});
|
|
14518
|
+
GateFeatureSchema = exports_external.object({
|
|
14519
|
+
enabled: exports_external.boolean().default(true)
|
|
14520
|
+
});
|
|
14521
|
+
PlaceholderScanConfigSchema = GateFeatureSchema.extend({
|
|
14522
|
+
deny_patterns: exports_external.array(exports_external.string()).default([
|
|
14523
|
+
"TODO",
|
|
14524
|
+
"FIXME",
|
|
14525
|
+
"TBD",
|
|
14526
|
+
"XXX",
|
|
14527
|
+
"placeholder",
|
|
14528
|
+
"stub",
|
|
14529
|
+
"wip",
|
|
14530
|
+
"not implemented"
|
|
14531
|
+
]),
|
|
14532
|
+
allow_globs: exports_external.array(exports_external.string()).default([
|
|
14533
|
+
"docs/**",
|
|
14534
|
+
"examples/**",
|
|
14535
|
+
"tests/**",
|
|
14536
|
+
"**/*.test.*",
|
|
14537
|
+
"**/*.spec.*",
|
|
14538
|
+
"**/mocks/**",
|
|
14539
|
+
"**/__tests__/**"
|
|
14540
|
+
]),
|
|
14541
|
+
max_allowed_findings: exports_external.number().min(0).default(0)
|
|
14542
|
+
});
|
|
14543
|
+
QualityBudgetConfigSchema = GateFeatureSchema.extend({
|
|
14544
|
+
max_complexity_delta: exports_external.number().default(5),
|
|
14545
|
+
max_public_api_delta: exports_external.number().default(10),
|
|
14546
|
+
max_duplication_ratio: exports_external.number().default(0.05),
|
|
14547
|
+
min_test_to_code_ratio: exports_external.number().default(0.3),
|
|
14548
|
+
enforce_on_globs: exports_external.array(exports_external.string()).default(["src/**"]),
|
|
14549
|
+
exclude_globs: exports_external.array(exports_external.string()).default(["docs/**", "tests/**", "**/*.test.*"])
|
|
14550
|
+
});
|
|
14551
|
+
GateConfigSchema = exports_external.object({
|
|
14552
|
+
syntax_check: GateFeatureSchema.default({ enabled: true }),
|
|
14553
|
+
placeholder_scan: PlaceholderScanConfigSchema.default({
|
|
14554
|
+
enabled: true,
|
|
14555
|
+
deny_patterns: [
|
|
14556
|
+
"TODO",
|
|
14557
|
+
"FIXME",
|
|
14558
|
+
"TBD",
|
|
14559
|
+
"XXX",
|
|
14560
|
+
"placeholder",
|
|
14561
|
+
"stub",
|
|
14562
|
+
"wip",
|
|
14563
|
+
"not implemented"
|
|
14564
|
+
],
|
|
14565
|
+
allow_globs: [
|
|
14566
|
+
"docs/**",
|
|
14567
|
+
"examples/**",
|
|
14568
|
+
"tests/**",
|
|
14569
|
+
"**/*.test.*",
|
|
14570
|
+
"**/*.spec.*",
|
|
14571
|
+
"**/mocks/**",
|
|
14572
|
+
"**/__tests__/**"
|
|
14573
|
+
],
|
|
14574
|
+
max_allowed_findings: 0
|
|
14575
|
+
}),
|
|
14576
|
+
sast_scan: GateFeatureSchema.default({ enabled: true }),
|
|
14577
|
+
sbom_generate: GateFeatureSchema.default({ enabled: true }),
|
|
14578
|
+
build_check: GateFeatureSchema.default({ enabled: true }),
|
|
14579
|
+
quality_budget: QualityBudgetConfigSchema
|
|
14580
|
+
});
|
|
14581
|
+
PipelineConfigSchema = exports_external.object({
|
|
14582
|
+
parallel_precheck: exports_external.boolean().default(true)
|
|
14583
|
+
});
|
|
14584
|
+
PhaseCompleteConfigSchema = exports_external.object({
|
|
14585
|
+
enabled: exports_external.boolean().default(true),
|
|
14586
|
+
required_agents: exports_external.array(exports_external.enum(["coder", "reviewer", "test_engineer"])).default(["coder", "reviewer", "test_engineer"]),
|
|
14587
|
+
require_docs: exports_external.boolean().default(true),
|
|
14588
|
+
policy: exports_external.enum(["enforce", "warn"]).default("enforce")
|
|
14589
|
+
});
|
|
14590
|
+
SummaryConfigSchema = exports_external.object({
|
|
14591
|
+
enabled: exports_external.boolean().default(true),
|
|
14592
|
+
threshold_bytes: exports_external.number().min(1024).max(1048576).default(102400),
|
|
14593
|
+
max_summary_chars: exports_external.number().min(100).max(5000).default(1000),
|
|
14594
|
+
max_stored_bytes: exports_external.number().min(10240).max(104857600).default(10485760),
|
|
14595
|
+
retention_days: exports_external.number().min(1).max(365).default(7),
|
|
14596
|
+
exempt_tools: exports_external.array(exports_external.string()).default(["retrieve_summary", "task", "read"])
|
|
14597
|
+
});
|
|
14598
|
+
ReviewPassesConfigSchema = exports_external.object({
|
|
14599
|
+
always_security_review: exports_external.boolean().default(false),
|
|
14600
|
+
security_globs: exports_external.array(exports_external.string()).default([
|
|
14601
|
+
"**/auth/**",
|
|
14602
|
+
"**/api/**",
|
|
14603
|
+
"**/crypto/**",
|
|
14604
|
+
"**/security/**",
|
|
14605
|
+
"**/middleware/**",
|
|
14606
|
+
"**/session/**",
|
|
14607
|
+
"**/token/**"
|
|
14608
|
+
])
|
|
14609
|
+
});
|
|
14610
|
+
AdversarialDetectionConfigSchema = exports_external.object({
|
|
14611
|
+
enabled: exports_external.boolean().default(true),
|
|
14612
|
+
policy: exports_external.enum(["warn", "gate", "ignore"]).default("warn"),
|
|
14613
|
+
pairs: exports_external.array(exports_external.tuple([exports_external.string(), exports_external.string()])).default([["coder", "reviewer"]])
|
|
14614
|
+
});
|
|
14615
|
+
IntegrationAnalysisConfigSchema = exports_external.object({
|
|
14616
|
+
enabled: exports_external.boolean().default(true)
|
|
14617
|
+
});
|
|
14618
|
+
DocsConfigSchema = exports_external.object({
|
|
14619
|
+
enabled: exports_external.boolean().default(true),
|
|
14620
|
+
doc_patterns: exports_external.array(exports_external.string()).default([
|
|
14621
|
+
"README.md",
|
|
14622
|
+
"CONTRIBUTING.md",
|
|
14623
|
+
"docs/**/*.md",
|
|
14624
|
+
"docs/**/*.rst",
|
|
14625
|
+
"**/CHANGELOG.md"
|
|
14626
|
+
])
|
|
14627
|
+
});
|
|
14628
|
+
UIReviewConfigSchema = exports_external.object({
|
|
14629
|
+
enabled: exports_external.boolean().default(false),
|
|
14630
|
+
trigger_paths: exports_external.array(exports_external.string()).default([
|
|
14631
|
+
"**/pages/**",
|
|
14632
|
+
"**/components/**",
|
|
14633
|
+
"**/views/**",
|
|
14634
|
+
"**/screens/**",
|
|
14635
|
+
"**/ui/**",
|
|
14636
|
+
"**/layouts/**"
|
|
14637
|
+
]),
|
|
14638
|
+
trigger_keywords: exports_external.array(exports_external.string()).default([
|
|
14639
|
+
"new page",
|
|
14640
|
+
"new screen",
|
|
14641
|
+
"new component",
|
|
14642
|
+
"redesign",
|
|
14643
|
+
"layout change",
|
|
14644
|
+
"form",
|
|
14645
|
+
"modal",
|
|
14646
|
+
"dialog",
|
|
14647
|
+
"dropdown",
|
|
14648
|
+
"sidebar",
|
|
14649
|
+
"navbar",
|
|
14650
|
+
"dashboard",
|
|
14651
|
+
"landing page",
|
|
14652
|
+
"signup",
|
|
14653
|
+
"login form",
|
|
14654
|
+
"settings page",
|
|
14655
|
+
"profile page"
|
|
14656
|
+
])
|
|
14657
|
+
});
|
|
14658
|
+
CompactionAdvisoryConfigSchema = exports_external.object({
|
|
14659
|
+
enabled: exports_external.boolean().default(true),
|
|
14660
|
+
thresholds: exports_external.array(exports_external.number().int().min(10).max(500)).default([50, 75, 100, 125, 150]),
|
|
14661
|
+
message: exports_external.string().default("[SWARM HINT] Session has " + "$" + "{totalToolCalls} tool calls. Consider compacting at next phase boundary to maintain context quality.")
|
|
14662
|
+
});
|
|
14663
|
+
LintConfigSchema = exports_external.object({
|
|
14664
|
+
enabled: exports_external.boolean().default(true),
|
|
14665
|
+
mode: exports_external.enum(["check", "fix"]).default("check"),
|
|
14666
|
+
linter: exports_external.enum(["biome", "eslint", "auto"]).default("auto"),
|
|
14667
|
+
patterns: exports_external.array(exports_external.string()).default([
|
|
14668
|
+
"**/*.{ts,tsx,js,jsx,mjs,cjs}",
|
|
14669
|
+
"**/biome.json",
|
|
14670
|
+
"**/biome.jsonc"
|
|
14671
|
+
]),
|
|
14672
|
+
exclude: exports_external.array(exports_external.string()).default([
|
|
14673
|
+
"**/node_modules/**",
|
|
14674
|
+
"**/dist/**",
|
|
14675
|
+
"**/.git/**",
|
|
14676
|
+
"**/coverage/**",
|
|
14677
|
+
"**/*.min.js"
|
|
14678
|
+
])
|
|
14679
|
+
});
|
|
14680
|
+
SecretscanConfigSchema = exports_external.object({
|
|
14681
|
+
enabled: exports_external.boolean().default(true),
|
|
14682
|
+
patterns: exports_external.array(exports_external.string()).default([
|
|
14683
|
+
"**/*.{env,properties,yml,yaml,json,js,ts}",
|
|
14684
|
+
"**/.env*",
|
|
14685
|
+
"**/secrets/**",
|
|
14686
|
+
"**/credentials/**",
|
|
14687
|
+
"**/config/**/*.ts",
|
|
14688
|
+
"**/config/**/*.js"
|
|
14689
|
+
]),
|
|
14690
|
+
exclude: exports_external.array(exports_external.string()).default([
|
|
14691
|
+
"**/node_modules/**",
|
|
14692
|
+
"**/dist/**",
|
|
14693
|
+
"**/.git/**",
|
|
14694
|
+
"**/coverage/**",
|
|
14695
|
+
"**/test/**",
|
|
14696
|
+
"**/tests/**",
|
|
14697
|
+
"**/__tests__/**",
|
|
14698
|
+
"**/*.test.ts",
|
|
14699
|
+
"**/*.test.js",
|
|
14700
|
+
"**/*.spec.ts",
|
|
14701
|
+
"**/*.spec.js"
|
|
14702
|
+
]),
|
|
14703
|
+
extensions: exports_external.array(exports_external.string()).default([
|
|
14704
|
+
".env",
|
|
14705
|
+
".properties",
|
|
14706
|
+
".yml",
|
|
14707
|
+
".yaml",
|
|
14708
|
+
".json",
|
|
14709
|
+
".js",
|
|
14710
|
+
".ts",
|
|
14711
|
+
".py",
|
|
14712
|
+
".rb",
|
|
14713
|
+
".go",
|
|
14714
|
+
".java",
|
|
14715
|
+
".cs",
|
|
14716
|
+
".php"
|
|
14717
|
+
])
|
|
14718
|
+
});
|
|
14719
|
+
GuardrailsProfileSchema = exports_external.object({
|
|
14720
|
+
max_tool_calls: exports_external.number().min(0).max(1000).optional(),
|
|
14721
|
+
max_duration_minutes: exports_external.number().min(0).max(480).optional(),
|
|
14722
|
+
max_repetitions: exports_external.number().min(3).max(50).optional(),
|
|
14723
|
+
max_consecutive_errors: exports_external.number().min(2).max(20).optional(),
|
|
14724
|
+
warning_threshold: exports_external.number().min(0.1).max(0.9).optional(),
|
|
14725
|
+
idle_timeout_minutes: exports_external.number().min(5).max(240).optional()
|
|
14726
|
+
});
|
|
14727
|
+
DEFAULT_AGENT_PROFILES = {
|
|
14728
|
+
architect: {
|
|
14729
|
+
max_tool_calls: 0,
|
|
14730
|
+
max_duration_minutes: 0,
|
|
14731
|
+
max_consecutive_errors: 8,
|
|
14732
|
+
warning_threshold: 0.75
|
|
14733
|
+
},
|
|
14734
|
+
coder: {
|
|
14735
|
+
max_tool_calls: 400,
|
|
14736
|
+
max_duration_minutes: 45,
|
|
14737
|
+
warning_threshold: 0.85
|
|
14738
|
+
},
|
|
14739
|
+
test_engineer: {
|
|
14740
|
+
max_tool_calls: 400,
|
|
14741
|
+
max_duration_minutes: 45,
|
|
14742
|
+
warning_threshold: 0.85
|
|
14743
|
+
},
|
|
14744
|
+
explorer: {
|
|
14745
|
+
max_tool_calls: 150,
|
|
14746
|
+
max_duration_minutes: 20,
|
|
14747
|
+
warning_threshold: 0.75
|
|
14748
|
+
},
|
|
14749
|
+
reviewer: {
|
|
14750
|
+
max_tool_calls: 200,
|
|
14751
|
+
max_duration_minutes: 30,
|
|
14752
|
+
warning_threshold: 0.65
|
|
14753
|
+
},
|
|
14754
|
+
critic: {
|
|
14755
|
+
max_tool_calls: 200,
|
|
14756
|
+
max_duration_minutes: 30,
|
|
14757
|
+
warning_threshold: 0.65
|
|
14758
|
+
},
|
|
14759
|
+
sme: {
|
|
14760
|
+
max_tool_calls: 200,
|
|
14761
|
+
max_duration_minutes: 30,
|
|
14762
|
+
warning_threshold: 0.65
|
|
14763
|
+
},
|
|
14764
|
+
docs: {
|
|
14765
|
+
max_tool_calls: 200,
|
|
14766
|
+
max_duration_minutes: 30,
|
|
14767
|
+
warning_threshold: 0.75
|
|
14768
|
+
},
|
|
14769
|
+
designer: {
|
|
14770
|
+
max_tool_calls: 150,
|
|
14771
|
+
max_duration_minutes: 20,
|
|
14772
|
+
warning_threshold: 0.75
|
|
14773
|
+
}
|
|
14774
|
+
};
|
|
14775
|
+
DEFAULT_ARCHITECT_PROFILE = DEFAULT_AGENT_PROFILES.architect;
|
|
14776
|
+
GuardrailsConfigSchema = exports_external.object({
|
|
14777
|
+
enabled: exports_external.boolean().default(true),
|
|
14778
|
+
max_tool_calls: exports_external.number().min(0).max(1000).default(200),
|
|
14779
|
+
max_duration_minutes: exports_external.number().min(0).max(480).default(30),
|
|
14780
|
+
max_repetitions: exports_external.number().min(3).max(50).default(10),
|
|
14781
|
+
max_consecutive_errors: exports_external.number().min(2).max(20).default(5),
|
|
14782
|
+
warning_threshold: exports_external.number().min(0.1).max(0.9).default(0.75),
|
|
14783
|
+
idle_timeout_minutes: exports_external.number().min(5).max(240).default(60),
|
|
14784
|
+
profiles: exports_external.record(exports_external.string(), GuardrailsProfileSchema).optional()
|
|
14785
|
+
});
|
|
14786
|
+
ToolFilterConfigSchema = exports_external.object({
|
|
14787
|
+
enabled: exports_external.boolean().default(true),
|
|
14788
|
+
overrides: exports_external.record(exports_external.string(), exports_external.array(exports_external.string())).default({})
|
|
14789
|
+
});
|
|
14790
|
+
PlanCursorConfigSchema = exports_external.object({
|
|
14791
|
+
enabled: exports_external.boolean().default(true),
|
|
14792
|
+
max_tokens: exports_external.number().min(500).max(4000).default(1500),
|
|
14793
|
+
lookahead_tasks: exports_external.number().min(0).max(5).default(2)
|
|
14794
|
+
});
|
|
14795
|
+
CheckpointConfigSchema = exports_external.object({
|
|
14796
|
+
enabled: exports_external.boolean().default(true),
|
|
14797
|
+
auto_checkpoint_threshold: exports_external.number().min(1).max(20).default(3)
|
|
14798
|
+
});
|
|
14799
|
+
AutomationModeSchema = exports_external.enum(["manual", "hybrid", "auto"]);
|
|
14800
|
+
AutomationCapabilitiesSchema = exports_external.object({
|
|
14801
|
+
plan_sync: exports_external.boolean().default(true),
|
|
14802
|
+
phase_preflight: exports_external.boolean().default(false),
|
|
14803
|
+
config_doctor_on_startup: exports_external.boolean().default(false),
|
|
14804
|
+
config_doctor_autofix: exports_external.boolean().default(false),
|
|
14805
|
+
evidence_auto_summaries: exports_external.boolean().default(true),
|
|
14806
|
+
decision_drift_detection: exports_external.boolean().default(true)
|
|
14807
|
+
});
|
|
14808
|
+
AutomationConfigSchemaBase = exports_external.object({
|
|
14809
|
+
mode: AutomationModeSchema.default("manual"),
|
|
14810
|
+
capabilities: AutomationCapabilitiesSchema.default({
|
|
14811
|
+
plan_sync: true,
|
|
14812
|
+
phase_preflight: false,
|
|
14813
|
+
config_doctor_on_startup: false,
|
|
14814
|
+
config_doctor_autofix: false,
|
|
14815
|
+
evidence_auto_summaries: true,
|
|
14816
|
+
decision_drift_detection: true
|
|
14817
|
+
})
|
|
14818
|
+
});
|
|
14819
|
+
AutomationConfigSchema = AutomationConfigSchemaBase;
|
|
14820
|
+
KnowledgeConfigSchema = exports_external.object({
|
|
14821
|
+
enabled: exports_external.boolean().default(true),
|
|
14822
|
+
swarm_max_entries: exports_external.number().min(1).max(1e4).default(100),
|
|
14823
|
+
hive_max_entries: exports_external.number().min(1).max(1e5).default(200),
|
|
14824
|
+
auto_promote_days: exports_external.number().min(1).max(3650).default(90),
|
|
14825
|
+
max_inject_count: exports_external.number().min(0).max(50).default(5),
|
|
14826
|
+
dedup_threshold: exports_external.number().min(0).max(1).default(0.6),
|
|
14827
|
+
scope_filter: exports_external.array(exports_external.string()).default(["global"]),
|
|
14828
|
+
hive_enabled: exports_external.boolean().default(true),
|
|
14829
|
+
rejected_max_entries: exports_external.number().min(1).max(1000).default(20),
|
|
14830
|
+
validation_enabled: exports_external.boolean().default(true),
|
|
14831
|
+
evergreen_confidence: exports_external.number().min(0).max(1).default(0.9),
|
|
14832
|
+
evergreen_utility: exports_external.number().min(0).max(1).default(0.8),
|
|
14833
|
+
low_utility_threshold: exports_external.number().min(0).max(1).default(0.3),
|
|
14834
|
+
min_retrievals_for_utility: exports_external.number().min(1).max(100).default(3),
|
|
14835
|
+
schema_version: exports_external.number().int().min(1).default(1)
|
|
14836
|
+
});
|
|
14837
|
+
CuratorConfigSchema = exports_external.object({
|
|
14838
|
+
enabled: exports_external.boolean().default(false),
|
|
14839
|
+
init_enabled: exports_external.boolean().default(true),
|
|
14840
|
+
phase_enabled: exports_external.boolean().default(true),
|
|
14841
|
+
max_summary_tokens: exports_external.number().min(500).max(8000).default(2000),
|
|
14842
|
+
min_knowledge_confidence: exports_external.number().min(0).max(1).default(0.7),
|
|
14843
|
+
compliance_report: exports_external.boolean().default(true),
|
|
14844
|
+
suppress_warnings: exports_external.boolean().default(true),
|
|
14845
|
+
drift_inject_max_chars: exports_external.number().min(100).max(2000).default(500)
|
|
14846
|
+
});
|
|
14847
|
+
PluginConfigSchema = exports_external.object({
|
|
14848
|
+
agents: exports_external.record(exports_external.string(), AgentOverrideConfigSchema).optional(),
|
|
14849
|
+
swarms: exports_external.record(exports_external.string(), SwarmConfigSchema).optional(),
|
|
14850
|
+
max_iterations: exports_external.number().min(1).max(10).default(5),
|
|
14851
|
+
pipeline: PipelineConfigSchema.optional(),
|
|
14852
|
+
phase_complete: PhaseCompleteConfigSchema.optional(),
|
|
14853
|
+
qa_retry_limit: exports_external.number().min(1).max(10).default(3),
|
|
14854
|
+
inject_phase_reminders: exports_external.boolean().default(true),
|
|
14855
|
+
hooks: HooksConfigSchema.optional(),
|
|
14856
|
+
gates: GateConfigSchema.optional(),
|
|
14857
|
+
context_budget: ContextBudgetConfigSchema.optional(),
|
|
14858
|
+
guardrails: GuardrailsConfigSchema.optional(),
|
|
14859
|
+
tool_filter: ToolFilterConfigSchema.optional(),
|
|
14860
|
+
plan_cursor: PlanCursorConfigSchema.optional(),
|
|
14861
|
+
evidence: EvidenceConfigSchema.optional(),
|
|
14862
|
+
summaries: SummaryConfigSchema.optional(),
|
|
14863
|
+
review_passes: ReviewPassesConfigSchema.optional(),
|
|
14864
|
+
adversarial_detection: AdversarialDetectionConfigSchema.optional(),
|
|
14865
|
+
integration_analysis: IntegrationAnalysisConfigSchema.optional(),
|
|
14866
|
+
docs: DocsConfigSchema.optional(),
|
|
14867
|
+
ui_review: UIReviewConfigSchema.optional(),
|
|
14868
|
+
compaction_advisory: CompactionAdvisoryConfigSchema.optional(),
|
|
14869
|
+
lint: LintConfigSchema.optional(),
|
|
14870
|
+
secretscan: SecretscanConfigSchema.optional(),
|
|
14871
|
+
checkpoint: CheckpointConfigSchema.optional(),
|
|
14872
|
+
automation: AutomationConfigSchema.optional(),
|
|
14873
|
+
knowledge: KnowledgeConfigSchema.optional(),
|
|
14874
|
+
curator: CuratorConfigSchema.optional(),
|
|
14875
|
+
tool_output: exports_external.object({
|
|
14876
|
+
truncation_enabled: exports_external.boolean().default(true),
|
|
14877
|
+
max_lines: exports_external.number().min(10).max(500).default(150),
|
|
14878
|
+
per_tool: exports_external.record(exports_external.string(), exports_external.number()).optional()
|
|
14879
|
+
}).optional()
|
|
14880
|
+
});
|
|
14881
|
+
});
|
|
14882
|
+
|
|
14883
|
+
// src/config/loader.ts
|
|
14884
|
+
import * as fs2 from "fs";
|
|
14885
|
+
import * as os from "os";
|
|
14886
|
+
import * as path from "path";
|
|
14887
|
+
function getUserConfigDir() {
|
|
14888
|
+
return process.env.XDG_CONFIG_HOME || path.join(os.homedir(), ".config");
|
|
14889
|
+
}
|
|
14890
|
+
function loadRawConfigFromPath(configPath) {
|
|
14891
|
+
try {
|
|
14892
|
+
const stats = fs2.statSync(configPath);
|
|
14893
|
+
if (stats.size > MAX_CONFIG_FILE_BYTES) {
|
|
14894
|
+
console.warn(`[opencode-swarm] Config file too large (max 100 KB): ${configPath}`);
|
|
14895
|
+
console.warn("[opencode-swarm] \u26A0\uFE0F SECURITY: Config file exceeds size limit. Falling back to safe defaults with guardrails ENABLED.");
|
|
14896
|
+
return { config: null, fileExisted: true, hadError: true };
|
|
14897
|
+
}
|
|
14898
|
+
const content = fs2.readFileSync(configPath, "utf-8");
|
|
14899
|
+
if (content.length > MAX_CONFIG_FILE_BYTES) {
|
|
14900
|
+
console.warn(`[opencode-swarm] Config file too large after read (max 100 KB): ${configPath}`);
|
|
14901
|
+
console.warn("[opencode-swarm] \u26A0\uFE0F SECURITY: Config file exceeds size limit. Falling back to safe defaults with guardrails ENABLED.");
|
|
14902
|
+
return { config: null, fileExisted: true, hadError: true };
|
|
14903
|
+
}
|
|
14904
|
+
let sanitizedContent = content;
|
|
14905
|
+
if (content.charCodeAt(0) === 65279) {
|
|
14906
|
+
sanitizedContent = content.slice(1);
|
|
14907
|
+
}
|
|
14908
|
+
const rawConfig = JSON.parse(sanitizedContent);
|
|
14909
|
+
if (typeof rawConfig !== "object" || rawConfig === null || Array.isArray(rawConfig)) {
|
|
14910
|
+
console.warn(`[opencode-swarm] Invalid config at ${configPath}: expected an object`);
|
|
14911
|
+
console.warn("[opencode-swarm] \u26A0\uFE0F SECURITY: Config format invalid. Falling back to safe defaults with guardrails ENABLED.");
|
|
14912
|
+
return { config: null, fileExisted: true, hadError: true };
|
|
14913
|
+
}
|
|
14914
|
+
return {
|
|
14915
|
+
config: rawConfig,
|
|
14916
|
+
fileExisted: true,
|
|
14917
|
+
hadError: false
|
|
14918
|
+
};
|
|
14919
|
+
} catch (error48) {
|
|
14920
|
+
const isFileNotFoundError = error48 instanceof Error && "code" in error48 && error48.code === "ENOENT";
|
|
14921
|
+
if (!isFileNotFoundError) {
|
|
14922
|
+
const errorMessage = error48 instanceof Error ? error48.message : String(error48);
|
|
14923
|
+
console.warn(`[opencode-swarm] \u26A0\uFE0F CONFIG LOAD FAILURE \u2014 config exists at ${configPath} but could not be loaded: ${errorMessage}`);
|
|
14924
|
+
console.warn("[opencode-swarm] \u26A0\uFE0F SECURITY: Config load failed. Falling back to safe defaults with guardrails ENABLED.");
|
|
14925
|
+
return { config: null, fileExisted: true, hadError: true };
|
|
14926
|
+
}
|
|
14927
|
+
return { config: null, fileExisted: false, hadError: false };
|
|
14928
|
+
}
|
|
14929
|
+
}
|
|
14930
|
+
function migratePresetsConfig(raw) {
|
|
14931
|
+
if (raw.presets && typeof raw.presets === "object" && !raw.agents) {
|
|
14932
|
+
const presetName = raw.preset || "remote";
|
|
14933
|
+
const presets = raw.presets;
|
|
14934
|
+
const activePreset = presets[presetName] || Object.values(presets)[0];
|
|
14935
|
+
if (activePreset && typeof activePreset === "object") {
|
|
14936
|
+
const migrated = { ...raw, agents: activePreset };
|
|
14937
|
+
delete migrated.preset;
|
|
14938
|
+
delete migrated.presets;
|
|
14939
|
+
delete migrated.swarm_mode;
|
|
14940
|
+
console.warn("[opencode-swarm] Migrated v6.12 presets config to agents format. Consider updating your opencode-swarm.json.");
|
|
14941
|
+
return migrated;
|
|
14942
|
+
}
|
|
14943
|
+
}
|
|
14944
|
+
return raw;
|
|
14945
|
+
}
|
|
14946
|
+
function loadPluginConfig(directory) {
|
|
14947
|
+
const userConfigPath = path.join(getUserConfigDir(), "opencode", CONFIG_FILENAME);
|
|
14948
|
+
const projectConfigPath = path.join(directory, ".opencode", CONFIG_FILENAME);
|
|
14949
|
+
const userResult = loadRawConfigFromPath(userConfigPath);
|
|
14950
|
+
const projectResult = loadRawConfigFromPath(projectConfigPath);
|
|
14951
|
+
const rawUserConfig = userResult.config;
|
|
14952
|
+
const rawProjectConfig = projectResult.config;
|
|
14953
|
+
const loadedFromFile = userResult.fileExisted || projectResult.fileExisted;
|
|
14954
|
+
const configHadErrors = userResult.hadError || projectResult.hadError;
|
|
14955
|
+
let mergedRaw = rawUserConfig ?? {};
|
|
14956
|
+
if (rawProjectConfig) {
|
|
14957
|
+
mergedRaw = deepMerge(mergedRaw, rawProjectConfig);
|
|
14958
|
+
}
|
|
14959
|
+
mergedRaw = migratePresetsConfig(mergedRaw);
|
|
14960
|
+
const result = PluginConfigSchema.safeParse(mergedRaw);
|
|
14961
|
+
if (!result.success) {
|
|
14962
|
+
if (rawUserConfig) {
|
|
14963
|
+
const userParseResult = PluginConfigSchema.safeParse(rawUserConfig);
|
|
14964
|
+
if (userParseResult.success) {
|
|
14965
|
+
console.warn("[opencode-swarm] Project config ignored due to validation errors. Using user config.");
|
|
14966
|
+
return userParseResult.data;
|
|
14967
|
+
}
|
|
14968
|
+
}
|
|
14969
|
+
console.warn("[opencode-swarm] Merged config validation failed:");
|
|
14970
|
+
console.warn(result.error.format());
|
|
14971
|
+
console.warn("[opencode-swarm] \u26A0\uFE0F SECURITY: Falling back to conservative defaults with guardrails ENABLED. Fix the config file to restore custom configuration.");
|
|
14972
|
+
return PluginConfigSchema.parse({
|
|
14973
|
+
guardrails: { enabled: true }
|
|
14974
|
+
});
|
|
14975
|
+
}
|
|
14976
|
+
if (loadedFromFile && configHadErrors) {
|
|
14977
|
+
return PluginConfigSchema.parse({
|
|
14978
|
+
...mergedRaw,
|
|
14979
|
+
guardrails: { enabled: true }
|
|
14980
|
+
});
|
|
14981
|
+
}
|
|
14982
|
+
return result.data;
|
|
14983
|
+
}
|
|
14984
|
+
function loadPluginConfigWithMeta(directory) {
|
|
14985
|
+
const userConfigPath = path.join(getUserConfigDir(), "opencode", CONFIG_FILENAME);
|
|
14986
|
+
const projectConfigPath = path.join(directory, ".opencode", CONFIG_FILENAME);
|
|
14987
|
+
const userResult = loadRawConfigFromPath(userConfigPath);
|
|
14988
|
+
const projectResult = loadRawConfigFromPath(projectConfigPath);
|
|
14989
|
+
const loadedFromFile = userResult.fileExisted || projectResult.fileExisted;
|
|
14990
|
+
const config2 = loadPluginConfig(directory);
|
|
14991
|
+
return { config: config2, loadedFromFile };
|
|
14992
|
+
}
|
|
14993
|
+
function loadAgentPrompt(agentName) {
|
|
14994
|
+
const promptsDir = path.join(getUserConfigDir(), "opencode", PROMPTS_DIR_NAME);
|
|
14995
|
+
const result = {};
|
|
14996
|
+
const promptPath = path.join(promptsDir, `${agentName}.md`);
|
|
14997
|
+
if (fs2.existsSync(promptPath)) {
|
|
14998
|
+
try {
|
|
14999
|
+
result.prompt = fs2.readFileSync(promptPath, "utf-8");
|
|
15000
|
+
} catch (error48) {
|
|
15001
|
+
console.warn(`[opencode-swarm] Error reading prompt file ${promptPath}:`, error48 instanceof Error ? error48.message : String(error48));
|
|
15002
|
+
}
|
|
15003
|
+
}
|
|
15004
|
+
const appendPromptPath = path.join(promptsDir, `${agentName}_append.md`);
|
|
15005
|
+
if (fs2.existsSync(appendPromptPath)) {
|
|
15006
|
+
try {
|
|
15007
|
+
result.appendPrompt = fs2.readFileSync(appendPromptPath, "utf-8");
|
|
15008
|
+
} catch (error48) {
|
|
15009
|
+
console.warn(`[opencode-swarm] Error reading append prompt ${appendPromptPath}:`, error48 instanceof Error ? error48.message : String(error48));
|
|
15010
|
+
}
|
|
15011
|
+
}
|
|
15012
|
+
return result;
|
|
15013
|
+
}
|
|
15014
|
+
var CONFIG_FILENAME = "opencode-swarm.json", PROMPTS_DIR_NAME = "opencode-swarm", MAX_CONFIG_FILE_BYTES = 102400;
|
|
15015
|
+
var init_loader = __esm(() => {
|
|
15016
|
+
init_schema();
|
|
15017
|
+
});
|
|
15018
|
+
|
|
14173
15019
|
// src/config/plan-schema.ts
|
|
14174
15020
|
var TaskStatusSchema, TaskSizeSchema, PhaseStatusSchema, MigrationStatusSchema, TaskSchema, PhaseSchema, PlanSchema;
|
|
14175
15021
|
var init_plan_schema = __esm(() => {
|
|
@@ -14221,6 +15067,57 @@ var init_plan_schema = __esm(() => {
|
|
|
14221
15067
|
});
|
|
14222
15068
|
});
|
|
14223
15069
|
|
|
15070
|
+
// src/config/index.ts
|
|
15071
|
+
var exports_config = {};
|
|
15072
|
+
__export(exports_config, {
|
|
15073
|
+
loadPluginConfigWithMeta: () => loadPluginConfigWithMeta,
|
|
15074
|
+
loadPluginConfig: () => loadPluginConfig,
|
|
15075
|
+
loadAgentPrompt: () => loadAgentPrompt,
|
|
15076
|
+
isSubagent: () => isSubagent,
|
|
15077
|
+
isQAAgent: () => isQAAgent,
|
|
15078
|
+
TestEvidenceSchema: () => TestEvidenceSchema,
|
|
15079
|
+
TaskStatusSchema: () => TaskStatusSchema,
|
|
15080
|
+
TaskSizeSchema: () => TaskSizeSchema,
|
|
15081
|
+
TaskSchema: () => TaskSchema,
|
|
15082
|
+
SwarmConfigSchema: () => SwarmConfigSchema,
|
|
15083
|
+
ReviewEvidenceSchema: () => ReviewEvidenceSchema,
|
|
15084
|
+
QA_AGENTS: () => QA_AGENTS,
|
|
15085
|
+
PluginConfigSchema: () => PluginConfigSchema,
|
|
15086
|
+
PlanSchema: () => PlanSchema,
|
|
15087
|
+
PipelineConfigSchema: () => PipelineConfigSchema,
|
|
15088
|
+
PhaseStatusSchema: () => PhaseStatusSchema,
|
|
15089
|
+
PhaseSchema: () => PhaseSchema,
|
|
15090
|
+
PhaseCompleteConfigSchema: () => PhaseCompleteConfigSchema,
|
|
15091
|
+
PIPELINE_AGENTS: () => PIPELINE_AGENTS,
|
|
15092
|
+
ORCHESTRATOR_NAME: () => ORCHESTRATOR_NAME,
|
|
15093
|
+
NoteEvidenceSchema: () => NoteEvidenceSchema,
|
|
15094
|
+
MigrationStatusSchema: () => MigrationStatusSchema,
|
|
15095
|
+
EvidenceVerdictSchema: () => EvidenceVerdictSchema,
|
|
15096
|
+
EvidenceTypeSchema: () => EvidenceTypeSchema,
|
|
15097
|
+
EvidenceSchema: () => EvidenceSchema,
|
|
15098
|
+
EvidenceBundleSchema: () => EvidenceBundleSchema,
|
|
15099
|
+
EVIDENCE_MAX_TASK_BYTES: () => EVIDENCE_MAX_TASK_BYTES,
|
|
15100
|
+
EVIDENCE_MAX_PATCH_BYTES: () => EVIDENCE_MAX_PATCH_BYTES,
|
|
15101
|
+
EVIDENCE_MAX_JSON_BYTES: () => EVIDENCE_MAX_JSON_BYTES,
|
|
15102
|
+
DiffEvidenceSchema: () => DiffEvidenceSchema,
|
|
15103
|
+
DEFAULT_MODELS: () => DEFAULT_MODELS,
|
|
15104
|
+
BaseEvidenceSchema: () => BaseEvidenceSchema,
|
|
15105
|
+
AutomationModeSchema: () => AutomationModeSchema,
|
|
15106
|
+
AutomationConfigSchema: () => AutomationConfigSchema,
|
|
15107
|
+
AutomationCapabilitiesSchema: () => AutomationCapabilitiesSchema,
|
|
15108
|
+
ApprovalEvidenceSchema: () => ApprovalEvidenceSchema,
|
|
15109
|
+
AgentOverrideConfigSchema: () => AgentOverrideConfigSchema,
|
|
15110
|
+
ALL_SUBAGENT_NAMES: () => ALL_SUBAGENT_NAMES,
|
|
15111
|
+
ALL_AGENT_NAMES: () => ALL_AGENT_NAMES
|
|
15112
|
+
});
|
|
15113
|
+
var init_config = __esm(() => {
|
|
15114
|
+
init_constants();
|
|
15115
|
+
init_evidence_schema();
|
|
15116
|
+
init_loader();
|
|
15117
|
+
init_plan_schema();
|
|
15118
|
+
init_schema();
|
|
15119
|
+
});
|
|
15120
|
+
|
|
14224
15121
|
// src/utils/errors.ts
|
|
14225
15122
|
var SwarmError;
|
|
14226
15123
|
var init_errors3 = __esm(() => {
|
|
@@ -38106,842 +39003,10 @@ var init_runtime = __esm(() => {
|
|
|
38106
39003
|
// src/index.ts
|
|
38107
39004
|
import * as path48 from "path";
|
|
38108
39005
|
|
|
38109
|
-
// src/
|
|
38110
|
-
|
|
38111
|
-
|
|
38112
|
-
|
|
38113
|
-
"placeholder_scan",
|
|
38114
|
-
"imports",
|
|
38115
|
-
"lint",
|
|
38116
|
-
"secretscan",
|
|
38117
|
-
"sast_scan",
|
|
38118
|
-
"build_check",
|
|
38119
|
-
"pre_check_batch",
|
|
38120
|
-
"quality_budget",
|
|
38121
|
-
"symbols",
|
|
38122
|
-
"complexity_hotspots",
|
|
38123
|
-
"schema_drift",
|
|
38124
|
-
"todo_extract",
|
|
38125
|
-
"evidence_check",
|
|
38126
|
-
"sbom_generate",
|
|
38127
|
-
"checkpoint",
|
|
38128
|
-
"pkg_audit",
|
|
38129
|
-
"test_runner",
|
|
38130
|
-
"detect_domains",
|
|
38131
|
-
"gitingest",
|
|
38132
|
-
"retrieve_summary",
|
|
38133
|
-
"extract_code_blocks",
|
|
38134
|
-
"phase_complete",
|
|
38135
|
-
"save_plan",
|
|
38136
|
-
"update_task_status",
|
|
38137
|
-
"write_retro",
|
|
38138
|
-
"declare_scope"
|
|
38139
|
-
];
|
|
38140
|
-
var TOOL_NAME_SET = new Set(TOOL_NAMES);
|
|
38141
|
-
|
|
38142
|
-
// src/config/constants.ts
|
|
38143
|
-
var QA_AGENTS = ["reviewer", "critic"];
|
|
38144
|
-
var PIPELINE_AGENTS = ["explorer", "coder", "test_engineer"];
|
|
38145
|
-
var ORCHESTRATOR_NAME = "architect";
|
|
38146
|
-
var ALL_SUBAGENT_NAMES = [
|
|
38147
|
-
"sme",
|
|
38148
|
-
"docs",
|
|
38149
|
-
"designer",
|
|
38150
|
-
...QA_AGENTS,
|
|
38151
|
-
...PIPELINE_AGENTS
|
|
38152
|
-
];
|
|
38153
|
-
var ALL_AGENT_NAMES = [
|
|
38154
|
-
ORCHESTRATOR_NAME,
|
|
38155
|
-
...ALL_SUBAGENT_NAMES
|
|
38156
|
-
];
|
|
38157
|
-
var AGENT_TOOL_MAP = {
|
|
38158
|
-
architect: [
|
|
38159
|
-
"checkpoint",
|
|
38160
|
-
"complexity_hotspots",
|
|
38161
|
-
"detect_domains",
|
|
38162
|
-
"evidence_check",
|
|
38163
|
-
"extract_code_blocks",
|
|
38164
|
-
"gitingest",
|
|
38165
|
-
"imports",
|
|
38166
|
-
"lint",
|
|
38167
|
-
"diff",
|
|
38168
|
-
"pkg_audit",
|
|
38169
|
-
"pre_check_batch",
|
|
38170
|
-
"retrieve_summary",
|
|
38171
|
-
"save_plan",
|
|
38172
|
-
"schema_drift",
|
|
38173
|
-
"secretscan",
|
|
38174
|
-
"symbols",
|
|
38175
|
-
"test_runner",
|
|
38176
|
-
"todo_extract",
|
|
38177
|
-
"update_task_status",
|
|
38178
|
-
"write_retro",
|
|
38179
|
-
"declare_scope"
|
|
38180
|
-
],
|
|
38181
|
-
explorer: [
|
|
38182
|
-
"complexity_hotspots",
|
|
38183
|
-
"detect_domains",
|
|
38184
|
-
"extract_code_blocks",
|
|
38185
|
-
"gitingest",
|
|
38186
|
-
"imports",
|
|
38187
|
-
"retrieve_summary",
|
|
38188
|
-
"schema_drift",
|
|
38189
|
-
"symbols",
|
|
38190
|
-
"todo_extract"
|
|
38191
|
-
],
|
|
38192
|
-
coder: [
|
|
38193
|
-
"diff",
|
|
38194
|
-
"imports",
|
|
38195
|
-
"lint",
|
|
38196
|
-
"symbols",
|
|
38197
|
-
"extract_code_blocks",
|
|
38198
|
-
"retrieve_summary"
|
|
38199
|
-
],
|
|
38200
|
-
test_engineer: [
|
|
38201
|
-
"test_runner",
|
|
38202
|
-
"diff",
|
|
38203
|
-
"symbols",
|
|
38204
|
-
"extract_code_blocks",
|
|
38205
|
-
"retrieve_summary",
|
|
38206
|
-
"imports",
|
|
38207
|
-
"complexity_hotspots",
|
|
38208
|
-
"pkg_audit"
|
|
38209
|
-
],
|
|
38210
|
-
sme: [
|
|
38211
|
-
"complexity_hotspots",
|
|
38212
|
-
"detect_domains",
|
|
38213
|
-
"extract_code_blocks",
|
|
38214
|
-
"imports",
|
|
38215
|
-
"retrieve_summary",
|
|
38216
|
-
"schema_drift",
|
|
38217
|
-
"symbols"
|
|
38218
|
-
],
|
|
38219
|
-
reviewer: [
|
|
38220
|
-
"diff",
|
|
38221
|
-
"imports",
|
|
38222
|
-
"lint",
|
|
38223
|
-
"pkg_audit",
|
|
38224
|
-
"pre_check_batch",
|
|
38225
|
-
"secretscan",
|
|
38226
|
-
"symbols",
|
|
38227
|
-
"complexity_hotspots",
|
|
38228
|
-
"retrieve_summary",
|
|
38229
|
-
"extract_code_blocks",
|
|
38230
|
-
"test_runner"
|
|
38231
|
-
],
|
|
38232
|
-
critic: [
|
|
38233
|
-
"complexity_hotspots",
|
|
38234
|
-
"detect_domains",
|
|
38235
|
-
"imports",
|
|
38236
|
-
"retrieve_summary",
|
|
38237
|
-
"symbols"
|
|
38238
|
-
],
|
|
38239
|
-
docs: [
|
|
38240
|
-
"detect_domains",
|
|
38241
|
-
"extract_code_blocks",
|
|
38242
|
-
"gitingest",
|
|
38243
|
-
"imports",
|
|
38244
|
-
"retrieve_summary",
|
|
38245
|
-
"schema_drift",
|
|
38246
|
-
"symbols",
|
|
38247
|
-
"todo_extract"
|
|
38248
|
-
],
|
|
38249
|
-
designer: ["extract_code_blocks", "retrieve_summary", "symbols"]
|
|
38250
|
-
};
|
|
38251
|
-
for (const [agentName, tools] of Object.entries(AGENT_TOOL_MAP)) {
|
|
38252
|
-
const invalidTools = tools.filter((tool) => !TOOL_NAME_SET.has(tool));
|
|
38253
|
-
if (invalidTools.length > 0) {
|
|
38254
|
-
throw new Error(`Agent '${agentName}' has invalid tool names: [${invalidTools.join(", ")}]. ` + `All tools must be registered in TOOL_NAME_SET.`);
|
|
38255
|
-
}
|
|
38256
|
-
}
|
|
38257
|
-
var DEFAULT_MODELS = {
|
|
38258
|
-
explorer: "opencode/trinity-large-preview-free",
|
|
38259
|
-
coder: "opencode/minimax-m2.5-free",
|
|
38260
|
-
reviewer: "opencode/big-pickle",
|
|
38261
|
-
test_engineer: "opencode/gpt-5-nano",
|
|
38262
|
-
sme: "opencode/trinity-large-preview-free",
|
|
38263
|
-
critic: "opencode/trinity-large-preview-free",
|
|
38264
|
-
docs: "opencode/trinity-large-preview-free",
|
|
38265
|
-
designer: "opencode/trinity-large-preview-free",
|
|
38266
|
-
default: "opencode/trinity-large-preview-free"
|
|
38267
|
-
};
|
|
38268
|
-
var DEFAULT_SCORING_CONFIG = {
|
|
38269
|
-
enabled: false,
|
|
38270
|
-
max_candidates: 100,
|
|
38271
|
-
weights: {
|
|
38272
|
-
phase: 1,
|
|
38273
|
-
current_task: 2,
|
|
38274
|
-
blocked_task: 1.5,
|
|
38275
|
-
recent_failure: 2.5,
|
|
38276
|
-
recent_success: 0.5,
|
|
38277
|
-
evidence_presence: 1,
|
|
38278
|
-
decision_recency: 1.5,
|
|
38279
|
-
dependency_proximity: 1
|
|
38280
|
-
},
|
|
38281
|
-
decision_decay: {
|
|
38282
|
-
mode: "exponential",
|
|
38283
|
-
half_life_hours: 24
|
|
38284
|
-
},
|
|
38285
|
-
token_ratios: {
|
|
38286
|
-
prose: 0.25,
|
|
38287
|
-
code: 0.4,
|
|
38288
|
-
markdown: 0.3,
|
|
38289
|
-
json: 0.35
|
|
38290
|
-
}
|
|
38291
|
-
};
|
|
38292
|
-
var LOW_CAPABILITY_MODELS = ["mini", "nano", "small", "free"];
|
|
38293
|
-
function isLowCapabilityModel(modelId) {
|
|
38294
|
-
if (!modelId)
|
|
38295
|
-
return false;
|
|
38296
|
-
const lower = modelId.toLowerCase();
|
|
38297
|
-
return LOW_CAPABILITY_MODELS.some((substr) => lower.includes(substr));
|
|
38298
|
-
}
|
|
38299
|
-
|
|
38300
|
-
// src/config/index.ts
|
|
38301
|
-
init_evidence_schema();
|
|
38302
|
-
|
|
38303
|
-
// src/config/loader.ts
|
|
38304
|
-
import * as fs2 from "fs";
|
|
38305
|
-
import * as os from "os";
|
|
38306
|
-
import * as path from "path";
|
|
38307
|
-
|
|
38308
|
-
// src/config/schema.ts
|
|
38309
|
-
init_zod();
|
|
38310
|
-
var KNOWN_SWARM_PREFIXES = [
|
|
38311
|
-
"paid",
|
|
38312
|
-
"local",
|
|
38313
|
-
"cloud",
|
|
38314
|
-
"enterprise",
|
|
38315
|
-
"mega",
|
|
38316
|
-
"default",
|
|
38317
|
-
"custom",
|
|
38318
|
-
"team",
|
|
38319
|
-
"project",
|
|
38320
|
-
"swarm",
|
|
38321
|
-
"synthetic"
|
|
38322
|
-
];
|
|
38323
|
-
var SEPARATORS = ["_", "-", " "];
|
|
38324
|
-
function stripKnownSwarmPrefix(agentName) {
|
|
38325
|
-
if (!agentName)
|
|
38326
|
-
return agentName;
|
|
38327
|
-
const normalized = agentName.toLowerCase();
|
|
38328
|
-
let stripped = normalized;
|
|
38329
|
-
let previous = "";
|
|
38330
|
-
while (stripped !== previous) {
|
|
38331
|
-
previous = stripped;
|
|
38332
|
-
for (const prefix of KNOWN_SWARM_PREFIXES) {
|
|
38333
|
-
for (const sep of SEPARATORS) {
|
|
38334
|
-
const prefixWithSep = prefix + sep;
|
|
38335
|
-
if (stripped.startsWith(prefixWithSep)) {
|
|
38336
|
-
stripped = stripped.slice(prefixWithSep.length);
|
|
38337
|
-
break;
|
|
38338
|
-
}
|
|
38339
|
-
}
|
|
38340
|
-
if (stripped !== previous)
|
|
38341
|
-
break;
|
|
38342
|
-
}
|
|
38343
|
-
}
|
|
38344
|
-
if (ALL_AGENT_NAMES.includes(stripped)) {
|
|
38345
|
-
return stripped;
|
|
38346
|
-
}
|
|
38347
|
-
for (const agent of ALL_AGENT_NAMES) {
|
|
38348
|
-
for (const sep of SEPARATORS) {
|
|
38349
|
-
const suffix = sep + agent;
|
|
38350
|
-
if (normalized.endsWith(suffix)) {
|
|
38351
|
-
return agent;
|
|
38352
|
-
}
|
|
38353
|
-
}
|
|
38354
|
-
if (normalized === agent) {
|
|
38355
|
-
return agent;
|
|
38356
|
-
}
|
|
38357
|
-
}
|
|
38358
|
-
return agentName;
|
|
38359
|
-
}
|
|
38360
|
-
var AgentOverrideConfigSchema = exports_external.object({
|
|
38361
|
-
model: exports_external.string().optional(),
|
|
38362
|
-
temperature: exports_external.number().min(0).max(2).optional(),
|
|
38363
|
-
disabled: exports_external.boolean().optional()
|
|
38364
|
-
});
|
|
38365
|
-
var SwarmConfigSchema = exports_external.object({
|
|
38366
|
-
name: exports_external.string().optional(),
|
|
38367
|
-
agents: exports_external.record(exports_external.string(), AgentOverrideConfigSchema).optional()
|
|
38368
|
-
});
|
|
38369
|
-
var HooksConfigSchema = exports_external.object({
|
|
38370
|
-
system_enhancer: exports_external.boolean().default(true),
|
|
38371
|
-
compaction: exports_external.boolean().default(true),
|
|
38372
|
-
agent_activity: exports_external.boolean().default(true),
|
|
38373
|
-
delegation_tracker: exports_external.boolean().default(false),
|
|
38374
|
-
agent_awareness_max_chars: exports_external.number().min(50).max(2000).default(300),
|
|
38375
|
-
delegation_gate: exports_external.boolean().default(true),
|
|
38376
|
-
delegation_max_chars: exports_external.number().min(500).max(20000).default(4000)
|
|
38377
|
-
});
|
|
38378
|
-
var ScoringWeightsSchema = exports_external.object({
|
|
38379
|
-
phase: exports_external.number().min(0).max(5).default(1),
|
|
38380
|
-
current_task: exports_external.number().min(0).max(5).default(2),
|
|
38381
|
-
blocked_task: exports_external.number().min(0).max(5).default(1.5),
|
|
38382
|
-
recent_failure: exports_external.number().min(0).max(5).default(2.5),
|
|
38383
|
-
recent_success: exports_external.number().min(0).max(5).default(0.5),
|
|
38384
|
-
evidence_presence: exports_external.number().min(0).max(5).default(1),
|
|
38385
|
-
decision_recency: exports_external.number().min(0).max(5).default(1.5),
|
|
38386
|
-
dependency_proximity: exports_external.number().min(0).max(5).default(1)
|
|
38387
|
-
});
|
|
38388
|
-
var DecisionDecaySchema = exports_external.object({
|
|
38389
|
-
mode: exports_external.enum(["linear", "exponential"]).default("exponential"),
|
|
38390
|
-
half_life_hours: exports_external.number().min(1).max(168).default(24)
|
|
38391
|
-
});
|
|
38392
|
-
var TokenRatiosSchema = exports_external.object({
|
|
38393
|
-
prose: exports_external.number().min(0.1).max(1).default(0.25),
|
|
38394
|
-
code: exports_external.number().min(0.1).max(1).default(0.4),
|
|
38395
|
-
markdown: exports_external.number().min(0.1).max(1).default(0.3),
|
|
38396
|
-
json: exports_external.number().min(0.1).max(1).default(0.35)
|
|
38397
|
-
});
|
|
38398
|
-
var ScoringConfigSchema = exports_external.object({
|
|
38399
|
-
enabled: exports_external.boolean().default(false),
|
|
38400
|
-
max_candidates: exports_external.number().min(10).max(500).default(100),
|
|
38401
|
-
weights: ScoringWeightsSchema.optional(),
|
|
38402
|
-
decision_decay: DecisionDecaySchema.optional(),
|
|
38403
|
-
token_ratios: TokenRatiosSchema.optional()
|
|
38404
|
-
});
|
|
38405
|
-
var ContextBudgetConfigSchema = exports_external.object({
|
|
38406
|
-
enabled: exports_external.boolean().default(true),
|
|
38407
|
-
warn_threshold: exports_external.number().min(0).max(1).default(0.7),
|
|
38408
|
-
critical_threshold: exports_external.number().min(0).max(1).default(0.9),
|
|
38409
|
-
model_limits: exports_external.record(exports_external.string(), exports_external.number().min(1000)).default({ default: 128000 }),
|
|
38410
|
-
max_injection_tokens: exports_external.number().min(100).max(50000).default(4000),
|
|
38411
|
-
tracked_agents: exports_external.array(exports_external.string()).default(["architect"]),
|
|
38412
|
-
scoring: ScoringConfigSchema.optional(),
|
|
38413
|
-
enforce: exports_external.boolean().default(true),
|
|
38414
|
-
prune_target: exports_external.number().min(0).max(1).default(0.7),
|
|
38415
|
-
preserve_last_n_turns: exports_external.number().min(0).max(100).default(4),
|
|
38416
|
-
recent_window: exports_external.number().min(1).max(100).default(10),
|
|
38417
|
-
enforce_on_agent_switch: exports_external.boolean().default(true),
|
|
38418
|
-
tool_output_mask_threshold: exports_external.number().min(100).max(1e5).default(2000)
|
|
38419
|
-
});
|
|
38420
|
-
var EvidenceConfigSchema = exports_external.object({
|
|
38421
|
-
enabled: exports_external.boolean().default(true),
|
|
38422
|
-
max_age_days: exports_external.number().min(1).max(365).default(90),
|
|
38423
|
-
max_bundles: exports_external.number().min(10).max(1e4).default(1000),
|
|
38424
|
-
auto_archive: exports_external.boolean().default(false)
|
|
38425
|
-
});
|
|
38426
|
-
var GateFeatureSchema = exports_external.object({
|
|
38427
|
-
enabled: exports_external.boolean().default(true)
|
|
38428
|
-
});
|
|
38429
|
-
var PlaceholderScanConfigSchema = GateFeatureSchema.extend({
|
|
38430
|
-
deny_patterns: exports_external.array(exports_external.string()).default([
|
|
38431
|
-
"TODO",
|
|
38432
|
-
"FIXME",
|
|
38433
|
-
"TBD",
|
|
38434
|
-
"XXX",
|
|
38435
|
-
"placeholder",
|
|
38436
|
-
"stub",
|
|
38437
|
-
"wip",
|
|
38438
|
-
"not implemented"
|
|
38439
|
-
]),
|
|
38440
|
-
allow_globs: exports_external.array(exports_external.string()).default([
|
|
38441
|
-
"docs/**",
|
|
38442
|
-
"examples/**",
|
|
38443
|
-
"tests/**",
|
|
38444
|
-
"**/*.test.*",
|
|
38445
|
-
"**/*.spec.*",
|
|
38446
|
-
"**/mocks/**",
|
|
38447
|
-
"**/__tests__/**"
|
|
38448
|
-
]),
|
|
38449
|
-
max_allowed_findings: exports_external.number().min(0).default(0)
|
|
38450
|
-
});
|
|
38451
|
-
var QualityBudgetConfigSchema = GateFeatureSchema.extend({
|
|
38452
|
-
max_complexity_delta: exports_external.number().default(5),
|
|
38453
|
-
max_public_api_delta: exports_external.number().default(10),
|
|
38454
|
-
max_duplication_ratio: exports_external.number().default(0.05),
|
|
38455
|
-
min_test_to_code_ratio: exports_external.number().default(0.3),
|
|
38456
|
-
enforce_on_globs: exports_external.array(exports_external.string()).default(["src/**"]),
|
|
38457
|
-
exclude_globs: exports_external.array(exports_external.string()).default(["docs/**", "tests/**", "**/*.test.*"])
|
|
38458
|
-
});
|
|
38459
|
-
var GateConfigSchema = exports_external.object({
|
|
38460
|
-
syntax_check: GateFeatureSchema.default({ enabled: true }),
|
|
38461
|
-
placeholder_scan: PlaceholderScanConfigSchema.default({
|
|
38462
|
-
enabled: true,
|
|
38463
|
-
deny_patterns: [
|
|
38464
|
-
"TODO",
|
|
38465
|
-
"FIXME",
|
|
38466
|
-
"TBD",
|
|
38467
|
-
"XXX",
|
|
38468
|
-
"placeholder",
|
|
38469
|
-
"stub",
|
|
38470
|
-
"wip",
|
|
38471
|
-
"not implemented"
|
|
38472
|
-
],
|
|
38473
|
-
allow_globs: [
|
|
38474
|
-
"docs/**",
|
|
38475
|
-
"examples/**",
|
|
38476
|
-
"tests/**",
|
|
38477
|
-
"**/*.test.*",
|
|
38478
|
-
"**/*.spec.*",
|
|
38479
|
-
"**/mocks/**",
|
|
38480
|
-
"**/__tests__/**"
|
|
38481
|
-
],
|
|
38482
|
-
max_allowed_findings: 0
|
|
38483
|
-
}),
|
|
38484
|
-
sast_scan: GateFeatureSchema.default({ enabled: true }),
|
|
38485
|
-
sbom_generate: GateFeatureSchema.default({ enabled: true }),
|
|
38486
|
-
build_check: GateFeatureSchema.default({ enabled: true }),
|
|
38487
|
-
quality_budget: QualityBudgetConfigSchema
|
|
38488
|
-
});
|
|
38489
|
-
var PipelineConfigSchema = exports_external.object({
|
|
38490
|
-
parallel_precheck: exports_external.boolean().default(true)
|
|
38491
|
-
});
|
|
38492
|
-
var PhaseCompleteConfigSchema = exports_external.object({
|
|
38493
|
-
enabled: exports_external.boolean().default(true),
|
|
38494
|
-
required_agents: exports_external.array(exports_external.enum(["coder", "reviewer", "test_engineer"])).default(["coder", "reviewer", "test_engineer"]),
|
|
38495
|
-
require_docs: exports_external.boolean().default(true),
|
|
38496
|
-
policy: exports_external.enum(["enforce", "warn"]).default("enforce")
|
|
38497
|
-
});
|
|
38498
|
-
var SummaryConfigSchema = exports_external.object({
|
|
38499
|
-
enabled: exports_external.boolean().default(true),
|
|
38500
|
-
threshold_bytes: exports_external.number().min(1024).max(1048576).default(102400),
|
|
38501
|
-
max_summary_chars: exports_external.number().min(100).max(5000).default(1000),
|
|
38502
|
-
max_stored_bytes: exports_external.number().min(10240).max(104857600).default(10485760),
|
|
38503
|
-
retention_days: exports_external.number().min(1).max(365).default(7),
|
|
38504
|
-
exempt_tools: exports_external.array(exports_external.string()).default(["retrieve_summary", "task", "read"])
|
|
38505
|
-
});
|
|
38506
|
-
var ReviewPassesConfigSchema = exports_external.object({
|
|
38507
|
-
always_security_review: exports_external.boolean().default(false),
|
|
38508
|
-
security_globs: exports_external.array(exports_external.string()).default([
|
|
38509
|
-
"**/auth/**",
|
|
38510
|
-
"**/api/**",
|
|
38511
|
-
"**/crypto/**",
|
|
38512
|
-
"**/security/**",
|
|
38513
|
-
"**/middleware/**",
|
|
38514
|
-
"**/session/**",
|
|
38515
|
-
"**/token/**"
|
|
38516
|
-
])
|
|
38517
|
-
});
|
|
38518
|
-
var AdversarialDetectionConfigSchema = exports_external.object({
|
|
38519
|
-
enabled: exports_external.boolean().default(true),
|
|
38520
|
-
policy: exports_external.enum(["warn", "gate", "ignore"]).default("warn"),
|
|
38521
|
-
pairs: exports_external.array(exports_external.tuple([exports_external.string(), exports_external.string()])).default([["coder", "reviewer"]])
|
|
38522
|
-
});
|
|
38523
|
-
var IntegrationAnalysisConfigSchema = exports_external.object({
|
|
38524
|
-
enabled: exports_external.boolean().default(true)
|
|
38525
|
-
});
|
|
38526
|
-
var DocsConfigSchema = exports_external.object({
|
|
38527
|
-
enabled: exports_external.boolean().default(true),
|
|
38528
|
-
doc_patterns: exports_external.array(exports_external.string()).default([
|
|
38529
|
-
"README.md",
|
|
38530
|
-
"CONTRIBUTING.md",
|
|
38531
|
-
"docs/**/*.md",
|
|
38532
|
-
"docs/**/*.rst",
|
|
38533
|
-
"**/CHANGELOG.md"
|
|
38534
|
-
])
|
|
38535
|
-
});
|
|
38536
|
-
var UIReviewConfigSchema = exports_external.object({
|
|
38537
|
-
enabled: exports_external.boolean().default(false),
|
|
38538
|
-
trigger_paths: exports_external.array(exports_external.string()).default([
|
|
38539
|
-
"**/pages/**",
|
|
38540
|
-
"**/components/**",
|
|
38541
|
-
"**/views/**",
|
|
38542
|
-
"**/screens/**",
|
|
38543
|
-
"**/ui/**",
|
|
38544
|
-
"**/layouts/**"
|
|
38545
|
-
]),
|
|
38546
|
-
trigger_keywords: exports_external.array(exports_external.string()).default([
|
|
38547
|
-
"new page",
|
|
38548
|
-
"new screen",
|
|
38549
|
-
"new component",
|
|
38550
|
-
"redesign",
|
|
38551
|
-
"layout change",
|
|
38552
|
-
"form",
|
|
38553
|
-
"modal",
|
|
38554
|
-
"dialog",
|
|
38555
|
-
"dropdown",
|
|
38556
|
-
"sidebar",
|
|
38557
|
-
"navbar",
|
|
38558
|
-
"dashboard",
|
|
38559
|
-
"landing page",
|
|
38560
|
-
"signup",
|
|
38561
|
-
"login form",
|
|
38562
|
-
"settings page",
|
|
38563
|
-
"profile page"
|
|
38564
|
-
])
|
|
38565
|
-
});
|
|
38566
|
-
var CompactionAdvisoryConfigSchema = exports_external.object({
|
|
38567
|
-
enabled: exports_external.boolean().default(true),
|
|
38568
|
-
thresholds: exports_external.array(exports_external.number().int().min(10).max(500)).default([50, 75, 100, 125, 150]),
|
|
38569
|
-
message: exports_external.string().default("[SWARM HINT] Session has " + "$" + "{totalToolCalls} tool calls. Consider compacting at next phase boundary to maintain context quality.")
|
|
38570
|
-
});
|
|
38571
|
-
var LintConfigSchema = exports_external.object({
|
|
38572
|
-
enabled: exports_external.boolean().default(true),
|
|
38573
|
-
mode: exports_external.enum(["check", "fix"]).default("check"),
|
|
38574
|
-
linter: exports_external.enum(["biome", "eslint", "auto"]).default("auto"),
|
|
38575
|
-
patterns: exports_external.array(exports_external.string()).default([
|
|
38576
|
-
"**/*.{ts,tsx,js,jsx,mjs,cjs}",
|
|
38577
|
-
"**/biome.json",
|
|
38578
|
-
"**/biome.jsonc"
|
|
38579
|
-
]),
|
|
38580
|
-
exclude: exports_external.array(exports_external.string()).default([
|
|
38581
|
-
"**/node_modules/**",
|
|
38582
|
-
"**/dist/**",
|
|
38583
|
-
"**/.git/**",
|
|
38584
|
-
"**/coverage/**",
|
|
38585
|
-
"**/*.min.js"
|
|
38586
|
-
])
|
|
38587
|
-
});
|
|
38588
|
-
var SecretscanConfigSchema = exports_external.object({
|
|
38589
|
-
enabled: exports_external.boolean().default(true),
|
|
38590
|
-
patterns: exports_external.array(exports_external.string()).default([
|
|
38591
|
-
"**/*.{env,properties,yml,yaml,json,js,ts}",
|
|
38592
|
-
"**/.env*",
|
|
38593
|
-
"**/secrets/**",
|
|
38594
|
-
"**/credentials/**",
|
|
38595
|
-
"**/config/**/*.ts",
|
|
38596
|
-
"**/config/**/*.js"
|
|
38597
|
-
]),
|
|
38598
|
-
exclude: exports_external.array(exports_external.string()).default([
|
|
38599
|
-
"**/node_modules/**",
|
|
38600
|
-
"**/dist/**",
|
|
38601
|
-
"**/.git/**",
|
|
38602
|
-
"**/coverage/**",
|
|
38603
|
-
"**/test/**",
|
|
38604
|
-
"**/tests/**",
|
|
38605
|
-
"**/__tests__/**",
|
|
38606
|
-
"**/*.test.ts",
|
|
38607
|
-
"**/*.test.js",
|
|
38608
|
-
"**/*.spec.ts",
|
|
38609
|
-
"**/*.spec.js"
|
|
38610
|
-
]),
|
|
38611
|
-
extensions: exports_external.array(exports_external.string()).default([
|
|
38612
|
-
".env",
|
|
38613
|
-
".properties",
|
|
38614
|
-
".yml",
|
|
38615
|
-
".yaml",
|
|
38616
|
-
".json",
|
|
38617
|
-
".js",
|
|
38618
|
-
".ts",
|
|
38619
|
-
".py",
|
|
38620
|
-
".rb",
|
|
38621
|
-
".go",
|
|
38622
|
-
".java",
|
|
38623
|
-
".cs",
|
|
38624
|
-
".php"
|
|
38625
|
-
])
|
|
38626
|
-
});
|
|
38627
|
-
var GuardrailsProfileSchema = exports_external.object({
|
|
38628
|
-
max_tool_calls: exports_external.number().min(0).max(1000).optional(),
|
|
38629
|
-
max_duration_minutes: exports_external.number().min(0).max(480).optional(),
|
|
38630
|
-
max_repetitions: exports_external.number().min(3).max(50).optional(),
|
|
38631
|
-
max_consecutive_errors: exports_external.number().min(2).max(20).optional(),
|
|
38632
|
-
warning_threshold: exports_external.number().min(0.1).max(0.9).optional(),
|
|
38633
|
-
idle_timeout_minutes: exports_external.number().min(5).max(240).optional()
|
|
38634
|
-
});
|
|
38635
|
-
var DEFAULT_AGENT_PROFILES = {
|
|
38636
|
-
architect: {
|
|
38637
|
-
max_tool_calls: 0,
|
|
38638
|
-
max_duration_minutes: 0,
|
|
38639
|
-
max_consecutive_errors: 8,
|
|
38640
|
-
warning_threshold: 0.75
|
|
38641
|
-
},
|
|
38642
|
-
coder: {
|
|
38643
|
-
max_tool_calls: 400,
|
|
38644
|
-
max_duration_minutes: 45,
|
|
38645
|
-
warning_threshold: 0.85
|
|
38646
|
-
},
|
|
38647
|
-
test_engineer: {
|
|
38648
|
-
max_tool_calls: 400,
|
|
38649
|
-
max_duration_minutes: 45,
|
|
38650
|
-
warning_threshold: 0.85
|
|
38651
|
-
},
|
|
38652
|
-
explorer: {
|
|
38653
|
-
max_tool_calls: 150,
|
|
38654
|
-
max_duration_minutes: 20,
|
|
38655
|
-
warning_threshold: 0.75
|
|
38656
|
-
},
|
|
38657
|
-
reviewer: {
|
|
38658
|
-
max_tool_calls: 200,
|
|
38659
|
-
max_duration_minutes: 30,
|
|
38660
|
-
warning_threshold: 0.65
|
|
38661
|
-
},
|
|
38662
|
-
critic: {
|
|
38663
|
-
max_tool_calls: 200,
|
|
38664
|
-
max_duration_minutes: 30,
|
|
38665
|
-
warning_threshold: 0.65
|
|
38666
|
-
},
|
|
38667
|
-
sme: {
|
|
38668
|
-
max_tool_calls: 200,
|
|
38669
|
-
max_duration_minutes: 30,
|
|
38670
|
-
warning_threshold: 0.65
|
|
38671
|
-
},
|
|
38672
|
-
docs: {
|
|
38673
|
-
max_tool_calls: 200,
|
|
38674
|
-
max_duration_minutes: 30,
|
|
38675
|
-
warning_threshold: 0.75
|
|
38676
|
-
},
|
|
38677
|
-
designer: {
|
|
38678
|
-
max_tool_calls: 150,
|
|
38679
|
-
max_duration_minutes: 20,
|
|
38680
|
-
warning_threshold: 0.75
|
|
38681
|
-
}
|
|
38682
|
-
};
|
|
38683
|
-
var DEFAULT_ARCHITECT_PROFILE = DEFAULT_AGENT_PROFILES.architect;
|
|
38684
|
-
var GuardrailsConfigSchema = exports_external.object({
|
|
38685
|
-
enabled: exports_external.boolean().default(true),
|
|
38686
|
-
max_tool_calls: exports_external.number().min(0).max(1000).default(200),
|
|
38687
|
-
max_duration_minutes: exports_external.number().min(0).max(480).default(30),
|
|
38688
|
-
max_repetitions: exports_external.number().min(3).max(50).default(10),
|
|
38689
|
-
max_consecutive_errors: exports_external.number().min(2).max(20).default(5),
|
|
38690
|
-
warning_threshold: exports_external.number().min(0.1).max(0.9).default(0.75),
|
|
38691
|
-
idle_timeout_minutes: exports_external.number().min(5).max(240).default(60),
|
|
38692
|
-
profiles: exports_external.record(exports_external.string(), GuardrailsProfileSchema).optional()
|
|
38693
|
-
});
|
|
38694
|
-
function resolveGuardrailsConfig(config2, agentName) {
|
|
38695
|
-
if (!agentName) {
|
|
38696
|
-
return config2;
|
|
38697
|
-
}
|
|
38698
|
-
const canonicalName = stripKnownSwarmPrefix(agentName);
|
|
38699
|
-
const hasBuiltInProfile = canonicalName in DEFAULT_AGENT_PROFILES;
|
|
38700
|
-
const userProfile = config2.profiles?.[agentName] ?? config2.profiles?.[canonicalName];
|
|
38701
|
-
if (!hasBuiltInProfile) {
|
|
38702
|
-
if (userProfile) {
|
|
38703
|
-
return { ...config2, ...userProfile };
|
|
38704
|
-
}
|
|
38705
|
-
return config2;
|
|
38706
|
-
}
|
|
38707
|
-
const builtInProfile = DEFAULT_AGENT_PROFILES[canonicalName];
|
|
38708
|
-
const resolved = {
|
|
38709
|
-
...config2,
|
|
38710
|
-
...builtInProfile,
|
|
38711
|
-
...userProfile || {}
|
|
38712
|
-
};
|
|
38713
|
-
return resolved;
|
|
38714
|
-
}
|
|
38715
|
-
var ToolFilterConfigSchema = exports_external.object({
|
|
38716
|
-
enabled: exports_external.boolean().default(true),
|
|
38717
|
-
overrides: exports_external.record(exports_external.string(), exports_external.array(exports_external.string())).default({})
|
|
38718
|
-
});
|
|
38719
|
-
var PlanCursorConfigSchema = exports_external.object({
|
|
38720
|
-
enabled: exports_external.boolean().default(true),
|
|
38721
|
-
max_tokens: exports_external.number().min(500).max(4000).default(1500),
|
|
38722
|
-
lookahead_tasks: exports_external.number().min(0).max(5).default(2)
|
|
38723
|
-
});
|
|
38724
|
-
var CheckpointConfigSchema = exports_external.object({
|
|
38725
|
-
enabled: exports_external.boolean().default(true),
|
|
38726
|
-
auto_checkpoint_threshold: exports_external.number().min(1).max(20).default(3)
|
|
38727
|
-
});
|
|
38728
|
-
var AutomationModeSchema = exports_external.enum(["manual", "hybrid", "auto"]);
|
|
38729
|
-
var AutomationCapabilitiesSchema = exports_external.object({
|
|
38730
|
-
plan_sync: exports_external.boolean().default(true),
|
|
38731
|
-
phase_preflight: exports_external.boolean().default(false),
|
|
38732
|
-
config_doctor_on_startup: exports_external.boolean().default(false),
|
|
38733
|
-
config_doctor_autofix: exports_external.boolean().default(false),
|
|
38734
|
-
evidence_auto_summaries: exports_external.boolean().default(true),
|
|
38735
|
-
decision_drift_detection: exports_external.boolean().default(true)
|
|
38736
|
-
});
|
|
38737
|
-
var AutomationConfigSchemaBase = exports_external.object({
|
|
38738
|
-
mode: AutomationModeSchema.default("manual"),
|
|
38739
|
-
capabilities: AutomationCapabilitiesSchema.default({
|
|
38740
|
-
plan_sync: true,
|
|
38741
|
-
phase_preflight: false,
|
|
38742
|
-
config_doctor_on_startup: false,
|
|
38743
|
-
config_doctor_autofix: false,
|
|
38744
|
-
evidence_auto_summaries: true,
|
|
38745
|
-
decision_drift_detection: true
|
|
38746
|
-
})
|
|
38747
|
-
});
|
|
38748
|
-
var AutomationConfigSchema = AutomationConfigSchemaBase;
|
|
38749
|
-
var KnowledgeConfigSchema = exports_external.object({
|
|
38750
|
-
enabled: exports_external.boolean().default(true),
|
|
38751
|
-
swarm_max_entries: exports_external.number().min(1).max(1e4).default(100),
|
|
38752
|
-
hive_max_entries: exports_external.number().min(1).max(1e5).default(200),
|
|
38753
|
-
auto_promote_days: exports_external.number().min(1).max(3650).default(90),
|
|
38754
|
-
max_inject_count: exports_external.number().min(0).max(50).default(5),
|
|
38755
|
-
dedup_threshold: exports_external.number().min(0).max(1).default(0.6),
|
|
38756
|
-
scope_filter: exports_external.array(exports_external.string()).default(["global"]),
|
|
38757
|
-
hive_enabled: exports_external.boolean().default(true),
|
|
38758
|
-
rejected_max_entries: exports_external.number().min(1).max(1000).default(20),
|
|
38759
|
-
validation_enabled: exports_external.boolean().default(true),
|
|
38760
|
-
evergreen_confidence: exports_external.number().min(0).max(1).default(0.9),
|
|
38761
|
-
evergreen_utility: exports_external.number().min(0).max(1).default(0.8),
|
|
38762
|
-
low_utility_threshold: exports_external.number().min(0).max(1).default(0.3),
|
|
38763
|
-
min_retrievals_for_utility: exports_external.number().min(1).max(100).default(3),
|
|
38764
|
-
schema_version: exports_external.number().int().min(1).default(1)
|
|
38765
|
-
});
|
|
38766
|
-
var CuratorConfigSchema = exports_external.object({
|
|
38767
|
-
enabled: exports_external.boolean().default(false),
|
|
38768
|
-
init_enabled: exports_external.boolean().default(true),
|
|
38769
|
-
phase_enabled: exports_external.boolean().default(true),
|
|
38770
|
-
max_summary_tokens: exports_external.number().min(500).max(8000).default(2000),
|
|
38771
|
-
min_knowledge_confidence: exports_external.number().min(0).max(1).default(0.7),
|
|
38772
|
-
compliance_report: exports_external.boolean().default(true),
|
|
38773
|
-
suppress_warnings: exports_external.boolean().default(true),
|
|
38774
|
-
drift_inject_max_chars: exports_external.number().min(100).max(2000).default(500)
|
|
38775
|
-
});
|
|
38776
|
-
var PluginConfigSchema = exports_external.object({
|
|
38777
|
-
agents: exports_external.record(exports_external.string(), AgentOverrideConfigSchema).optional(),
|
|
38778
|
-
swarms: exports_external.record(exports_external.string(), SwarmConfigSchema).optional(),
|
|
38779
|
-
max_iterations: exports_external.number().min(1).max(10).default(5),
|
|
38780
|
-
pipeline: PipelineConfigSchema.optional(),
|
|
38781
|
-
phase_complete: PhaseCompleteConfigSchema.optional(),
|
|
38782
|
-
qa_retry_limit: exports_external.number().min(1).max(10).default(3),
|
|
38783
|
-
inject_phase_reminders: exports_external.boolean().default(true),
|
|
38784
|
-
hooks: HooksConfigSchema.optional(),
|
|
38785
|
-
gates: GateConfigSchema.optional(),
|
|
38786
|
-
context_budget: ContextBudgetConfigSchema.optional(),
|
|
38787
|
-
guardrails: GuardrailsConfigSchema.optional(),
|
|
38788
|
-
tool_filter: ToolFilterConfigSchema.optional(),
|
|
38789
|
-
plan_cursor: PlanCursorConfigSchema.optional(),
|
|
38790
|
-
evidence: EvidenceConfigSchema.optional(),
|
|
38791
|
-
summaries: SummaryConfigSchema.optional(),
|
|
38792
|
-
review_passes: ReviewPassesConfigSchema.optional(),
|
|
38793
|
-
adversarial_detection: AdversarialDetectionConfigSchema.optional(),
|
|
38794
|
-
integration_analysis: IntegrationAnalysisConfigSchema.optional(),
|
|
38795
|
-
docs: DocsConfigSchema.optional(),
|
|
38796
|
-
ui_review: UIReviewConfigSchema.optional(),
|
|
38797
|
-
compaction_advisory: CompactionAdvisoryConfigSchema.optional(),
|
|
38798
|
-
lint: LintConfigSchema.optional(),
|
|
38799
|
-
secretscan: SecretscanConfigSchema.optional(),
|
|
38800
|
-
checkpoint: CheckpointConfigSchema.optional(),
|
|
38801
|
-
automation: AutomationConfigSchema.optional(),
|
|
38802
|
-
knowledge: KnowledgeConfigSchema.optional(),
|
|
38803
|
-
curator: CuratorConfigSchema.optional(),
|
|
38804
|
-
tool_output: exports_external.object({
|
|
38805
|
-
truncation_enabled: exports_external.boolean().default(true),
|
|
38806
|
-
max_lines: exports_external.number().min(10).max(500).default(150),
|
|
38807
|
-
per_tool: exports_external.record(exports_external.string(), exports_external.number()).optional()
|
|
38808
|
-
}).optional()
|
|
38809
|
-
});
|
|
38810
|
-
|
|
38811
|
-
// src/config/loader.ts
|
|
38812
|
-
var CONFIG_FILENAME = "opencode-swarm.json";
|
|
38813
|
-
var PROMPTS_DIR_NAME = "opencode-swarm";
|
|
38814
|
-
var MAX_CONFIG_FILE_BYTES = 102400;
|
|
38815
|
-
function getUserConfigDir() {
|
|
38816
|
-
return process.env.XDG_CONFIG_HOME || path.join(os.homedir(), ".config");
|
|
38817
|
-
}
|
|
38818
|
-
function loadRawConfigFromPath(configPath) {
|
|
38819
|
-
try {
|
|
38820
|
-
const stats = fs2.statSync(configPath);
|
|
38821
|
-
if (stats.size > MAX_CONFIG_FILE_BYTES) {
|
|
38822
|
-
console.warn(`[opencode-swarm] Config file too large (max 100 KB): ${configPath}`);
|
|
38823
|
-
console.warn("[opencode-swarm] \u26A0\uFE0F SECURITY: Config file exceeds size limit. Falling back to safe defaults with guardrails ENABLED.");
|
|
38824
|
-
return { config: null, fileExisted: true, hadError: true };
|
|
38825
|
-
}
|
|
38826
|
-
const content = fs2.readFileSync(configPath, "utf-8");
|
|
38827
|
-
if (content.length > MAX_CONFIG_FILE_BYTES) {
|
|
38828
|
-
console.warn(`[opencode-swarm] Config file too large after read (max 100 KB): ${configPath}`);
|
|
38829
|
-
console.warn("[opencode-swarm] \u26A0\uFE0F SECURITY: Config file exceeds size limit. Falling back to safe defaults with guardrails ENABLED.");
|
|
38830
|
-
return { config: null, fileExisted: true, hadError: true };
|
|
38831
|
-
}
|
|
38832
|
-
let sanitizedContent = content;
|
|
38833
|
-
if (content.charCodeAt(0) === 65279) {
|
|
38834
|
-
sanitizedContent = content.slice(1);
|
|
38835
|
-
}
|
|
38836
|
-
const rawConfig = JSON.parse(sanitizedContent);
|
|
38837
|
-
if (typeof rawConfig !== "object" || rawConfig === null || Array.isArray(rawConfig)) {
|
|
38838
|
-
console.warn(`[opencode-swarm] Invalid config at ${configPath}: expected an object`);
|
|
38839
|
-
console.warn("[opencode-swarm] \u26A0\uFE0F SECURITY: Config format invalid. Falling back to safe defaults with guardrails ENABLED.");
|
|
38840
|
-
return { config: null, fileExisted: true, hadError: true };
|
|
38841
|
-
}
|
|
38842
|
-
return {
|
|
38843
|
-
config: rawConfig,
|
|
38844
|
-
fileExisted: true,
|
|
38845
|
-
hadError: false
|
|
38846
|
-
};
|
|
38847
|
-
} catch (error48) {
|
|
38848
|
-
const isFileNotFoundError = error48 instanceof Error && "code" in error48 && error48.code === "ENOENT";
|
|
38849
|
-
if (!isFileNotFoundError) {
|
|
38850
|
-
const errorMessage = error48 instanceof Error ? error48.message : String(error48);
|
|
38851
|
-
console.warn(`[opencode-swarm] \u26A0\uFE0F CONFIG LOAD FAILURE \u2014 config exists at ${configPath} but could not be loaded: ${errorMessage}`);
|
|
38852
|
-
console.warn("[opencode-swarm] \u26A0\uFE0F SECURITY: Config load failed. Falling back to safe defaults with guardrails ENABLED.");
|
|
38853
|
-
return { config: null, fileExisted: true, hadError: true };
|
|
38854
|
-
}
|
|
38855
|
-
return { config: null, fileExisted: false, hadError: false };
|
|
38856
|
-
}
|
|
38857
|
-
}
|
|
38858
|
-
function migratePresetsConfig(raw) {
|
|
38859
|
-
if (raw.presets && typeof raw.presets === "object" && !raw.agents) {
|
|
38860
|
-
const presetName = raw.preset || "remote";
|
|
38861
|
-
const presets = raw.presets;
|
|
38862
|
-
const activePreset = presets[presetName] || Object.values(presets)[0];
|
|
38863
|
-
if (activePreset && typeof activePreset === "object") {
|
|
38864
|
-
const migrated = { ...raw, agents: activePreset };
|
|
38865
|
-
delete migrated.preset;
|
|
38866
|
-
delete migrated.presets;
|
|
38867
|
-
delete migrated.swarm_mode;
|
|
38868
|
-
console.warn("[opencode-swarm] Migrated v6.12 presets config to agents format. Consider updating your opencode-swarm.json.");
|
|
38869
|
-
return migrated;
|
|
38870
|
-
}
|
|
38871
|
-
}
|
|
38872
|
-
return raw;
|
|
38873
|
-
}
|
|
38874
|
-
function loadPluginConfig(directory) {
|
|
38875
|
-
const userConfigPath = path.join(getUserConfigDir(), "opencode", CONFIG_FILENAME);
|
|
38876
|
-
const projectConfigPath = path.join(directory, ".opencode", CONFIG_FILENAME);
|
|
38877
|
-
const userResult = loadRawConfigFromPath(userConfigPath);
|
|
38878
|
-
const projectResult = loadRawConfigFromPath(projectConfigPath);
|
|
38879
|
-
const rawUserConfig = userResult.config;
|
|
38880
|
-
const rawProjectConfig = projectResult.config;
|
|
38881
|
-
const loadedFromFile = userResult.fileExisted || projectResult.fileExisted;
|
|
38882
|
-
const configHadErrors = userResult.hadError || projectResult.hadError;
|
|
38883
|
-
let mergedRaw = rawUserConfig ?? {};
|
|
38884
|
-
if (rawProjectConfig) {
|
|
38885
|
-
mergedRaw = deepMerge(mergedRaw, rawProjectConfig);
|
|
38886
|
-
}
|
|
38887
|
-
mergedRaw = migratePresetsConfig(mergedRaw);
|
|
38888
|
-
const result = PluginConfigSchema.safeParse(mergedRaw);
|
|
38889
|
-
if (!result.success) {
|
|
38890
|
-
if (rawUserConfig) {
|
|
38891
|
-
const userParseResult = PluginConfigSchema.safeParse(rawUserConfig);
|
|
38892
|
-
if (userParseResult.success) {
|
|
38893
|
-
console.warn("[opencode-swarm] Project config ignored due to validation errors. Using user config.");
|
|
38894
|
-
return userParseResult.data;
|
|
38895
|
-
}
|
|
38896
|
-
}
|
|
38897
|
-
console.warn("[opencode-swarm] Merged config validation failed:");
|
|
38898
|
-
console.warn(result.error.format());
|
|
38899
|
-
console.warn("[opencode-swarm] \u26A0\uFE0F SECURITY: Falling back to conservative defaults with guardrails ENABLED. Fix the config file to restore custom configuration.");
|
|
38900
|
-
return PluginConfigSchema.parse({
|
|
38901
|
-
guardrails: { enabled: true }
|
|
38902
|
-
});
|
|
38903
|
-
}
|
|
38904
|
-
if (loadedFromFile && configHadErrors) {
|
|
38905
|
-
return PluginConfigSchema.parse({
|
|
38906
|
-
...mergedRaw,
|
|
38907
|
-
guardrails: { enabled: true }
|
|
38908
|
-
});
|
|
38909
|
-
}
|
|
38910
|
-
return result.data;
|
|
38911
|
-
}
|
|
38912
|
-
function loadPluginConfigWithMeta(directory) {
|
|
38913
|
-
const userConfigPath = path.join(getUserConfigDir(), "opencode", CONFIG_FILENAME);
|
|
38914
|
-
const projectConfigPath = path.join(directory, ".opencode", CONFIG_FILENAME);
|
|
38915
|
-
const userResult = loadRawConfigFromPath(userConfigPath);
|
|
38916
|
-
const projectResult = loadRawConfigFromPath(projectConfigPath);
|
|
38917
|
-
const loadedFromFile = userResult.fileExisted || projectResult.fileExisted;
|
|
38918
|
-
const config2 = loadPluginConfig(directory);
|
|
38919
|
-
return { config: config2, loadedFromFile };
|
|
38920
|
-
}
|
|
38921
|
-
function loadAgentPrompt(agentName) {
|
|
38922
|
-
const promptsDir = path.join(getUserConfigDir(), "opencode", PROMPTS_DIR_NAME);
|
|
38923
|
-
const result = {};
|
|
38924
|
-
const promptPath = path.join(promptsDir, `${agentName}.md`);
|
|
38925
|
-
if (fs2.existsSync(promptPath)) {
|
|
38926
|
-
try {
|
|
38927
|
-
result.prompt = fs2.readFileSync(promptPath, "utf-8");
|
|
38928
|
-
} catch (error48) {
|
|
38929
|
-
console.warn(`[opencode-swarm] Error reading prompt file ${promptPath}:`, error48 instanceof Error ? error48.message : String(error48));
|
|
38930
|
-
}
|
|
38931
|
-
}
|
|
38932
|
-
const appendPromptPath = path.join(promptsDir, `${agentName}_append.md`);
|
|
38933
|
-
if (fs2.existsSync(appendPromptPath)) {
|
|
38934
|
-
try {
|
|
38935
|
-
result.appendPrompt = fs2.readFileSync(appendPromptPath, "utf-8");
|
|
38936
|
-
} catch (error48) {
|
|
38937
|
-
console.warn(`[opencode-swarm] Error reading append prompt ${appendPromptPath}:`, error48 instanceof Error ? error48.message : String(error48));
|
|
38938
|
-
}
|
|
38939
|
-
}
|
|
38940
|
-
return result;
|
|
38941
|
-
}
|
|
38942
|
-
|
|
38943
|
-
// src/config/index.ts
|
|
38944
|
-
init_plan_schema();
|
|
39006
|
+
// src/agents/index.ts
|
|
39007
|
+
init_config();
|
|
39008
|
+
init_constants();
|
|
39009
|
+
init_schema();
|
|
38945
39010
|
|
|
38946
39011
|
// src/agents/architect.ts
|
|
38947
39012
|
var ARCHITECT_PROMPT = `You are Architect - orchestrator of a multi-agent swarm.
|
|
@@ -41825,6 +41890,7 @@ async function handleAnalyzeCommand(_directory, args2) {
|
|
|
41825
41890
|
}
|
|
41826
41891
|
|
|
41827
41892
|
// src/commands/archive.ts
|
|
41893
|
+
init_loader();
|
|
41828
41894
|
init_manager();
|
|
41829
41895
|
async function handleArchiveCommand(directory, args2) {
|
|
41830
41896
|
const config2 = loadPluginConfig(directory);
|
|
@@ -41899,6 +41965,8 @@ async function handleArchiveCommand(directory, args2) {
|
|
|
41899
41965
|
init_manager();
|
|
41900
41966
|
|
|
41901
41967
|
// src/state.ts
|
|
41968
|
+
init_constants();
|
|
41969
|
+
init_schema();
|
|
41902
41970
|
var swarmState = {
|
|
41903
41971
|
activeToolCalls: new Map,
|
|
41904
41972
|
toolAggregates: new Map,
|
|
@@ -41939,6 +42007,7 @@ function startAgentSession(sessionId, agentName, staleDurationMs = 7200000) {
|
|
|
41939
42007
|
lastPhaseCompleteTimestamp: 0,
|
|
41940
42008
|
lastPhaseCompletePhase: 0,
|
|
41941
42009
|
phaseAgentsDispatched: new Set,
|
|
42010
|
+
lastCompletedPhaseAgentsDispatched: new Set,
|
|
41942
42011
|
qaSkipCount: 0,
|
|
41943
42012
|
qaSkipTaskIds: [],
|
|
41944
42013
|
taskWorkflowStates: new Map,
|
|
@@ -42009,6 +42078,9 @@ function ensureAgentSession(sessionId, agentName) {
|
|
|
42009
42078
|
if (!session.phaseAgentsDispatched) {
|
|
42010
42079
|
session.phaseAgentsDispatched = new Set;
|
|
42011
42080
|
}
|
|
42081
|
+
if (!session.lastCompletedPhaseAgentsDispatched) {
|
|
42082
|
+
session.lastCompletedPhaseAgentsDispatched = new Set;
|
|
42083
|
+
}
|
|
42012
42084
|
if (session.qaSkipCount === undefined) {
|
|
42013
42085
|
session.qaSkipCount = 0;
|
|
42014
42086
|
}
|
|
@@ -42471,6 +42543,7 @@ async function handleClarifyCommand(_directory, args2) {
|
|
|
42471
42543
|
}
|
|
42472
42544
|
|
|
42473
42545
|
// src/commands/config.ts
|
|
42546
|
+
init_loader();
|
|
42474
42547
|
import * as os2 from "os";
|
|
42475
42548
|
import * as path8 from "path";
|
|
42476
42549
|
function getUserConfigDir2() {
|
|
@@ -43029,12 +43102,13 @@ async function handleDarkMatterCommand(directory, args2) {
|
|
|
43029
43102
|
}
|
|
43030
43103
|
|
|
43031
43104
|
// src/services/diagnose-service.ts
|
|
43032
|
-
|
|
43033
|
-
import { existsSync as existsSync6, readdirSync as readdirSync2, readFileSync as readFileSync4, statSync as statSync4 } from "fs";
|
|
43034
|
-
import path12 from "path";
|
|
43105
|
+
init_loader();
|
|
43035
43106
|
init_manager();
|
|
43036
43107
|
init_utils2();
|
|
43037
43108
|
init_manager2();
|
|
43109
|
+
import { execSync } from "child_process";
|
|
43110
|
+
import { existsSync as existsSync6, readdirSync as readdirSync2, readFileSync as readFileSync4, statSync as statSync4 } from "fs";
|
|
43111
|
+
import path12 from "path";
|
|
43038
43112
|
function validateTaskDag(plan) {
|
|
43039
43113
|
const allTaskIds = new Set;
|
|
43040
43114
|
for (const phase of plan.phases) {
|
|
@@ -43663,6 +43737,7 @@ async function handleDiagnoseCommand(directory, _args) {
|
|
|
43663
43737
|
return formatDiagnoseMarkdown(diagnoseData);
|
|
43664
43738
|
}
|
|
43665
43739
|
// src/commands/doctor.ts
|
|
43740
|
+
init_loader();
|
|
43666
43741
|
init_config_doctor();
|
|
43667
43742
|
function formatDoctorMarkdown(result) {
|
|
43668
43743
|
const lines = [
|
|
@@ -44246,6 +44321,7 @@ function serializeAgentSession(s) {
|
|
|
44246
44321
|
const partialGateWarningsIssuedForTask = Array.from(s.partialGateWarningsIssuedForTask ?? new Set);
|
|
44247
44322
|
const catastrophicPhaseWarnings = Array.from(s.catastrophicPhaseWarnings ?? new Set);
|
|
44248
44323
|
const phaseAgentsDispatched = Array.from(s.phaseAgentsDispatched ?? new Set);
|
|
44324
|
+
const lastCompletedPhaseAgentsDispatched = Array.from(s.lastCompletedPhaseAgentsDispatched ?? new Set);
|
|
44249
44325
|
const windows = {};
|
|
44250
44326
|
const rawWindows = s.windows ?? {};
|
|
44251
44327
|
for (const [key, win] of Object.entries(rawWindows)) {
|
|
@@ -44283,6 +44359,7 @@ function serializeAgentSession(s) {
|
|
|
44283
44359
|
lastPhaseCompleteTimestamp: s.lastPhaseCompleteTimestamp ?? 0,
|
|
44284
44360
|
lastPhaseCompletePhase: s.lastPhaseCompletePhase ?? 0,
|
|
44285
44361
|
phaseAgentsDispatched,
|
|
44362
|
+
lastCompletedPhaseAgentsDispatched,
|
|
44286
44363
|
qaSkipCount: s.qaSkipCount ?? 0,
|
|
44287
44364
|
qaSkipTaskIds: s.qaSkipTaskIds ?? [],
|
|
44288
44365
|
taskWorkflowStates: Object.fromEntries(s.taskWorkflowStates ?? new Map)
|
|
@@ -44463,6 +44540,9 @@ async function handleHistoryCommand(directory, _args) {
|
|
|
44463
44540
|
const historyData = await getHistoryData(directory);
|
|
44464
44541
|
return formatHistoryMarkdown(historyData);
|
|
44465
44542
|
}
|
|
44543
|
+
// src/commands/knowledge.ts
|
|
44544
|
+
init_schema();
|
|
44545
|
+
|
|
44466
44546
|
// src/hooks/knowledge-migrator.ts
|
|
44467
44547
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
44468
44548
|
import { existsSync as existsSync8, readFileSync as readFileSync6 } from "fs";
|
|
@@ -46591,6 +46671,11 @@ function createSwarmCommandHandler(directory, agents) {
|
|
|
46591
46671
|
};
|
|
46592
46672
|
}
|
|
46593
46673
|
|
|
46674
|
+
// src/index.ts
|
|
46675
|
+
init_config();
|
|
46676
|
+
init_constants();
|
|
46677
|
+
init_schema();
|
|
46678
|
+
|
|
46594
46679
|
// src/hooks/agent-activity.ts
|
|
46595
46680
|
import { renameSync as renameSync6, unlinkSync as unlinkSync3 } from "fs";
|
|
46596
46681
|
init_utils();
|
|
@@ -46763,6 +46848,7 @@ function createCompactionCustomizerHook(config3, directory) {
|
|
|
46763
46848
|
};
|
|
46764
46849
|
}
|
|
46765
46850
|
// src/hooks/context-budget.ts
|
|
46851
|
+
init_schema();
|
|
46766
46852
|
init_utils();
|
|
46767
46853
|
|
|
46768
46854
|
// src/hooks/message-priority.ts
|
|
@@ -47234,402 +47320,33 @@ function maskToolOutput(msg, _threshold) {
|
|
|
47234
47320
|
return freedTokens;
|
|
47235
47321
|
}
|
|
47236
47322
|
// src/hooks/delegation-gate.ts
|
|
47237
|
-
|
|
47238
|
-
const match = text.match(/TASK:\s*(.+?)(?:\n|$)/i);
|
|
47239
|
-
return match ? match[1].trim() : null;
|
|
47240
|
-
}
|
|
47241
|
-
function createDelegationGateHook(config3) {
|
|
47242
|
-
const enabled = config3.hooks?.delegation_gate !== false;
|
|
47243
|
-
const delegationMaxChars = config3.hooks?.delegation_max_chars ?? 4000;
|
|
47244
|
-
if (!enabled) {
|
|
47245
|
-
return {
|
|
47246
|
-
messagesTransform: async (_input, _output) => {},
|
|
47247
|
-
toolAfter: async () => {}
|
|
47248
|
-
};
|
|
47249
|
-
}
|
|
47250
|
-
const toolAfter = async (input, _output) => {
|
|
47251
|
-
if (!input.sessionID)
|
|
47252
|
-
return;
|
|
47253
|
-
const session = swarmState.agentSessions.get(input.sessionID);
|
|
47254
|
-
if (!session)
|
|
47255
|
-
return;
|
|
47256
|
-
const normalized = input.tool.replace(/^[^:]+[:.]/, "");
|
|
47257
|
-
if (normalized === "Task" || normalized === "task") {
|
|
47258
|
-
const delegationChain = swarmState.delegationChains.get(input.sessionID);
|
|
47259
|
-
if (delegationChain && delegationChain.length > 0) {
|
|
47260
|
-
let lastCoderIndex = -1;
|
|
47261
|
-
for (let i2 = delegationChain.length - 1;i2 >= 0; i2--) {
|
|
47262
|
-
const target = stripKnownSwarmPrefix(delegationChain[i2].to);
|
|
47263
|
-
if (target.includes("coder")) {
|
|
47264
|
-
lastCoderIndex = i2;
|
|
47265
|
-
break;
|
|
47266
|
-
}
|
|
47267
|
-
}
|
|
47268
|
-
if (lastCoderIndex === -1)
|
|
47269
|
-
return;
|
|
47270
|
-
const afterCoder = delegationChain.slice(lastCoderIndex);
|
|
47271
|
-
let hasReviewer = false;
|
|
47272
|
-
let hasTestEngineer = false;
|
|
47273
|
-
for (const delegation of afterCoder) {
|
|
47274
|
-
const target = stripKnownSwarmPrefix(delegation.to);
|
|
47275
|
-
if (target === "reviewer")
|
|
47276
|
-
hasReviewer = true;
|
|
47277
|
-
if (target === "test_engineer")
|
|
47278
|
-
hasTestEngineer = true;
|
|
47279
|
-
}
|
|
47280
|
-
if (hasReviewer && hasTestEngineer) {
|
|
47281
|
-
session.qaSkipCount = 0;
|
|
47282
|
-
session.qaSkipTaskIds = [];
|
|
47283
|
-
}
|
|
47284
|
-
if (hasReviewer && session.taskWorkflowStates) {
|
|
47285
|
-
for (const [taskId, state] of session.taskWorkflowStates) {
|
|
47286
|
-
if (state === "coder_delegated" || state === "pre_check_passed") {
|
|
47287
|
-
try {
|
|
47288
|
-
advanceTaskState(session, taskId, "reviewer_run");
|
|
47289
|
-
} catch {}
|
|
47290
|
-
}
|
|
47291
|
-
}
|
|
47292
|
-
}
|
|
47293
|
-
if (hasReviewer && hasTestEngineer && session.taskWorkflowStates) {
|
|
47294
|
-
for (const [taskId, state] of session.taskWorkflowStates) {
|
|
47295
|
-
if (state === "reviewer_run") {
|
|
47296
|
-
try {
|
|
47297
|
-
advanceTaskState(session, taskId, "tests_run");
|
|
47298
|
-
} catch {}
|
|
47299
|
-
}
|
|
47300
|
-
}
|
|
47301
|
-
}
|
|
47302
|
-
}
|
|
47303
|
-
}
|
|
47304
|
-
};
|
|
47305
|
-
return {
|
|
47306
|
-
messagesTransform: async (_input, output) => {
|
|
47307
|
-
const messages = output.messages;
|
|
47308
|
-
if (!messages || messages.length === 0)
|
|
47309
|
-
return;
|
|
47310
|
-
let lastUserMessageIndex = -1;
|
|
47311
|
-
for (let i2 = messages.length - 1;i2 >= 0; i2--) {
|
|
47312
|
-
if (messages[i2]?.info?.role === "user") {
|
|
47313
|
-
lastUserMessageIndex = i2;
|
|
47314
|
-
break;
|
|
47315
|
-
}
|
|
47316
|
-
}
|
|
47317
|
-
if (lastUserMessageIndex === -1)
|
|
47318
|
-
return;
|
|
47319
|
-
const lastUserMessage = messages[lastUserMessageIndex];
|
|
47320
|
-
if (!lastUserMessage?.parts)
|
|
47321
|
-
return;
|
|
47322
|
-
const agent = lastUserMessage.info?.agent;
|
|
47323
|
-
const strippedAgent = agent ? stripKnownSwarmPrefix(agent) : undefined;
|
|
47324
|
-
if (strippedAgent && strippedAgent !== "architect")
|
|
47325
|
-
return;
|
|
47326
|
-
const textPartIndex = lastUserMessage.parts.findIndex((p) => p?.type === "text" && p.text !== undefined);
|
|
47327
|
-
if (textPartIndex === -1)
|
|
47328
|
-
return;
|
|
47329
|
-
const textPart = lastUserMessage.parts[textPartIndex];
|
|
47330
|
-
const text = textPart.text ?? "";
|
|
47331
|
-
const taskDisclosureSessionID = lastUserMessage.info?.sessionID;
|
|
47332
|
-
if (taskDisclosureSessionID) {
|
|
47333
|
-
const taskSession = ensureAgentSession(taskDisclosureSessionID);
|
|
47334
|
-
const currentTaskIdForWindow = taskSession.currentTaskId;
|
|
47335
|
-
if (currentTaskIdForWindow) {
|
|
47336
|
-
const taskLineRegex = /^[ \t]*-[ \t]*(?:\[[ x]\][ \t]+)?(\d+\.\d+(?:\.\d+)*)[:. ].*/gm;
|
|
47337
|
-
const taskLines = [];
|
|
47338
|
-
taskLineRegex.lastIndex = 0;
|
|
47339
|
-
let regexMatch = taskLineRegex.exec(text);
|
|
47340
|
-
while (regexMatch !== null) {
|
|
47341
|
-
taskLines.push({
|
|
47342
|
-
line: regexMatch[0],
|
|
47343
|
-
taskId: regexMatch[1],
|
|
47344
|
-
index: regexMatch.index
|
|
47345
|
-
});
|
|
47346
|
-
regexMatch = taskLineRegex.exec(text);
|
|
47347
|
-
}
|
|
47348
|
-
if (taskLines.length > 5) {
|
|
47349
|
-
const currentIdx = taskLines.findIndex((t) => t.taskId === currentTaskIdForWindow);
|
|
47350
|
-
const windowStart = Math.max(0, currentIdx - 2);
|
|
47351
|
-
const windowEnd = Math.min(taskLines.length - 1, currentIdx + 3);
|
|
47352
|
-
const visibleTasks = taskLines.slice(windowStart, windowEnd + 1);
|
|
47353
|
-
const hiddenBefore = windowStart;
|
|
47354
|
-
const hiddenAfter = taskLines.length - 1 - windowEnd;
|
|
47355
|
-
const totalTasks = taskLines.length;
|
|
47356
|
-
const visibleCount = visibleTasks.length;
|
|
47357
|
-
const firstTaskIndex = taskLines[0].index;
|
|
47358
|
-
const lastTask = taskLines[taskLines.length - 1];
|
|
47359
|
-
const lastTaskEnd = lastTask.index + lastTask.line.length;
|
|
47360
|
-
const before = text.slice(0, firstTaskIndex);
|
|
47361
|
-
const after = text.slice(lastTaskEnd);
|
|
47362
|
-
const visibleLines = visibleTasks.map((t) => t.line).join(`
|
|
47363
|
-
`);
|
|
47364
|
-
const trimComment = `[Task window: showing ${visibleCount} of ${totalTasks} tasks]`;
|
|
47365
|
-
const trimmedMiddle = (hiddenBefore > 0 ? `[...${hiddenBefore} tasks hidden...]
|
|
47366
|
-
` : "") + visibleLines + (hiddenAfter > 0 ? `
|
|
47367
|
-
[...${hiddenAfter} tasks hidden...]` : "");
|
|
47368
|
-
textPart.text = `${before}${trimmedMiddle}
|
|
47369
|
-
${trimComment}${after}`;
|
|
47370
|
-
}
|
|
47371
|
-
}
|
|
47372
|
-
}
|
|
47373
|
-
const sessionID = lastUserMessage.info?.sessionID;
|
|
47374
|
-
const taskIdMatch = text.match(/TASK:\s*(.+?)(?:\n|$)/i);
|
|
47375
|
-
const currentTaskId = taskIdMatch ? taskIdMatch[1].trim() : null;
|
|
47376
|
-
const coderDelegationPattern = /(?:^|\n)\s*(?:\w+_)?coder\s*\n\s*TASK:/i;
|
|
47377
|
-
const isCoderDelegation = coderDelegationPattern.test(text);
|
|
47378
|
-
const priorCoderTaskId = sessionID ? ensureAgentSession(sessionID).lastCoderDelegationTaskId ?? null : null;
|
|
47379
|
-
if (sessionID && isCoderDelegation && currentTaskId) {
|
|
47380
|
-
const session = ensureAgentSession(sessionID);
|
|
47381
|
-
session.lastCoderDelegationTaskId = currentTaskId;
|
|
47382
|
-
const fileDirPattern = /^FILE:\s*(.+)$/gm;
|
|
47383
|
-
const declaredFiles = [];
|
|
47384
|
-
for (const match of text.matchAll(fileDirPattern)) {
|
|
47385
|
-
const filePath = match[1].trim();
|
|
47386
|
-
if (filePath.length > 0 && !declaredFiles.includes(filePath)) {
|
|
47387
|
-
declaredFiles.push(filePath);
|
|
47388
|
-
}
|
|
47389
|
-
}
|
|
47390
|
-
session.declaredCoderScope = declaredFiles.length > 0 ? declaredFiles : null;
|
|
47391
|
-
try {
|
|
47392
|
-
advanceTaskState(session, currentTaskId, "coder_delegated");
|
|
47393
|
-
} catch (err2) {
|
|
47394
|
-
console.warn(`[delegation-gate] state machine warn: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
47395
|
-
}
|
|
47396
|
-
}
|
|
47397
|
-
if (sessionID && !isCoderDelegation && currentTaskId) {
|
|
47398
|
-
const session = ensureAgentSession(sessionID);
|
|
47399
|
-
if (session.architectWriteCount > 0 && session.lastCoderDelegationTaskId !== currentTaskId) {
|
|
47400
|
-
const warningText2 = `\u26A0\uFE0F DELEGATION VIOLATION: Code modifications detected for task ${currentTaskId} with zero coder delegations.
|
|
47401
|
-
Rule 1: DELEGATE all coding to coder. You do NOT write code.`;
|
|
47402
|
-
textPart.text = `${warningText2}
|
|
47323
|
+
init_schema();
|
|
47403
47324
|
|
|
47404
|
-
|
|
47405
|
-
|
|
47406
|
-
|
|
47407
|
-
|
|
47408
|
-
|
|
47409
|
-
|
|
47410
|
-
|
|
47411
|
-
|
|
47412
|
-
|
|
47413
|
-
|
|
47414
|
-
|
|
47415
|
-
|
|
47416
|
-
const sanitizedGate = lastGate.gate.replace(/\[/g, "(").replace(/\]/g, ")").replace(/[\r\n]/g, " ").slice(0, 64);
|
|
47417
|
-
const sanitizedTaskId = lastGate.taskId.replace(/\[/g, "(").replace(/\]/g, ")").replace(/[\r\n]/g, " ").slice(0, 32);
|
|
47418
|
-
preamble = `[Last gate: ${sanitizedGate} ${gateResult} for task ${sanitizedTaskId}]
|
|
47419
|
-
[DELIBERATE: Before proceeding \u2014 what is the SINGLE next task? What gates must it pass?]`;
|
|
47420
|
-
} else {
|
|
47421
|
-
preamble = `[DELIBERATE: Identify the first task from the plan. What gates must it pass before marking complete?]`;
|
|
47422
|
-
}
|
|
47423
|
-
const currentText = textPart.text ?? "";
|
|
47424
|
-
textPart.text = `${preamble}
|
|
47425
|
-
|
|
47426
|
-
${currentText}`;
|
|
47427
|
-
}
|
|
47428
|
-
}
|
|
47429
|
-
}
|
|
47430
|
-
if (!isCoderDelegation)
|
|
47431
|
-
return;
|
|
47432
|
-
const warnings = [];
|
|
47433
|
-
if (text.length > delegationMaxChars) {
|
|
47434
|
-
warnings.push(`Delegation exceeds recommended size (${text.length} chars, limit ${delegationMaxChars}). Consider splitting into smaller tasks.`);
|
|
47435
|
-
}
|
|
47436
|
-
const fileMatches = text.match(/^FILE:/gm);
|
|
47437
|
-
if (fileMatches && fileMatches.length > 1) {
|
|
47438
|
-
warnings.push(`Multiple FILE: directives detected (${fileMatches.length}). Each coder task should target ONE file.`);
|
|
47439
|
-
}
|
|
47440
|
-
const taskMatches = text.match(/^TASK:/gm);
|
|
47441
|
-
if (taskMatches && taskMatches.length > 1) {
|
|
47442
|
-
warnings.push(`Multiple TASK: sections detected (${taskMatches.length}). Send ONE task per coder call.`);
|
|
47443
|
-
}
|
|
47444
|
-
const batchingPattern = /\b(?:and also|then also|additionally|as well as|along with|while you'?re at it)[.,]?\b/gi;
|
|
47445
|
-
const batchingMatches = text.match(batchingPattern);
|
|
47446
|
-
if (batchingMatches && batchingMatches.length > 0) {
|
|
47447
|
-
warnings.push(`Batching language detected (${batchingMatches.join(", ")}). Break compound objectives into separate coder calls.`);
|
|
47448
|
-
}
|
|
47449
|
-
const taskLine = extractTaskLine(text);
|
|
47450
|
-
if (taskLine) {
|
|
47451
|
-
const andPattern = /\s+and\s+(update|add|remove|modify|refactor|implement|create|delete|fix|change|build|deploy|write|test|move|rename|extend|extract|convert|migrate|upgrade|replace)\b/i;
|
|
47452
|
-
if (andPattern.test(taskLine)) {
|
|
47453
|
-
warnings.push('TASK line contains "and" connecting separate actions');
|
|
47454
|
-
}
|
|
47455
|
-
}
|
|
47456
|
-
if (sessionID) {
|
|
47457
|
-
const delegationChain = swarmState.delegationChains.get(sessionID);
|
|
47458
|
-
if (delegationChain && delegationChain.length >= 2) {
|
|
47459
|
-
const coderIndices = [];
|
|
47460
|
-
for (let i2 = delegationChain.length - 1;i2 >= 0; i2--) {
|
|
47461
|
-
if (stripKnownSwarmPrefix(delegationChain[i2].to).includes("coder")) {
|
|
47462
|
-
coderIndices.unshift(i2);
|
|
47463
|
-
if (coderIndices.length === 2)
|
|
47464
|
-
break;
|
|
47465
|
-
}
|
|
47466
|
-
}
|
|
47467
|
-
if (coderIndices.length === 2) {
|
|
47468
|
-
const prevCoderIndex = coderIndices[0];
|
|
47469
|
-
const betweenCoders = delegationChain.slice(prevCoderIndex + 1);
|
|
47470
|
-
const hasReviewer = betweenCoders.some((d) => stripKnownSwarmPrefix(d.to) === "reviewer");
|
|
47471
|
-
const hasTestEngineer = betweenCoders.some((d) => stripKnownSwarmPrefix(d.to) === "test_engineer");
|
|
47472
|
-
const session = ensureAgentSession(sessionID);
|
|
47473
|
-
const priorTaskStuckAtCoder = priorCoderTaskId !== null && getTaskState(session, priorCoderTaskId) === "coder_delegated";
|
|
47474
|
-
if (!hasReviewer || !hasTestEngineer || priorTaskStuckAtCoder) {
|
|
47475
|
-
if (session.qaSkipCount >= 1) {
|
|
47476
|
-
const skippedTasks = session.qaSkipTaskIds.join(", ");
|
|
47477
|
-
throw new Error(`\uD83D\uDED1 QA GATE ENFORCEMENT: ${session.qaSkipCount + 1} consecutive coder delegations without reviewer/test_engineer. ` + `Skipped tasks: [${skippedTasks}]. ` + `DELEGATE to reviewer and test_engineer NOW before any further coder work.`);
|
|
47478
|
-
}
|
|
47479
|
-
session.qaSkipCount++;
|
|
47480
|
-
session.qaSkipTaskIds.push(currentTaskId ?? "unknown");
|
|
47481
|
-
warnings.push(`\u26A0\uFE0F PROTOCOL VIOLATION: Previous coder task completed, but QA gate was skipped. ` + `You MUST delegate to reviewer (code review) and test_engineer (test execution) ` + `before starting a new coder task. Review RULES 7-8 in your system prompt.`);
|
|
47482
|
-
}
|
|
47483
|
-
}
|
|
47484
|
-
}
|
|
47485
|
-
}
|
|
47486
|
-
if (warnings.length === 0)
|
|
47487
|
-
return;
|
|
47488
|
-
const warningLines = warnings.map((w) => `Detected signal: ${w}`);
|
|
47489
|
-
const warningText = `\u26A0\uFE0F BATCH DETECTED: Your coder delegation appears to contain multiple tasks.
|
|
47490
|
-
Rule 3: ONE task per coder call. Split this into separate delegations.
|
|
47491
|
-
${warningLines.join(`
|
|
47492
|
-
`)}`;
|
|
47493
|
-
const originalText = textPart.text ?? "";
|
|
47494
|
-
textPart.text = `${warningText}
|
|
47495
|
-
|
|
47496
|
-
${originalText}`;
|
|
47497
|
-
},
|
|
47498
|
-
toolAfter
|
|
47499
|
-
};
|
|
47500
|
-
}
|
|
47501
|
-
// src/hooks/delegation-sanitizer.ts
|
|
47502
|
-
init_utils2();
|
|
47503
|
-
import * as fs13 from "fs";
|
|
47504
|
-
var SANITIZATION_PATTERNS = [
|
|
47505
|
-
/\b\d+(st|nd|rd|th)\s+(attempt|try|time)\b/gi,
|
|
47506
|
-
/\b(5th|fifth|final|last)\s+attempt\b/gi,
|
|
47507
|
-
/attempt\s+\d+\s*\/\s*\d+/gi,
|
|
47508
|
-
/\bthis\s+is\s+(the\s+)?(5th|fifth|final|last)\b/gi,
|
|
47509
|
-
/\bwe('re|\s+are)\s+(behind|late)\b/gi,
|
|
47510
|
-
/\buser\s+is\s+waiting\b/gi,
|
|
47511
|
-
/\bship\s+(this|it)\s+now\b/gi,
|
|
47512
|
-
/\bor\s+I('ll|\s+will)\s+(stop|halt|alert)\b/gi,
|
|
47513
|
-
/\bor\s+all\s+work\s+stops\b/gi,
|
|
47514
|
-
/\bthis\s+will\s+(delay|block)\s+everything\b/gi,
|
|
47515
|
-
/\b(I'm|I\s+am)\s+(frustrated|disappointed)\b/gi
|
|
47516
|
-
];
|
|
47517
|
-
function sanitizeMessage(text, patterns = SANITIZATION_PATTERNS) {
|
|
47518
|
-
let sanitized = text;
|
|
47519
|
-
const stripped = [];
|
|
47520
|
-
for (const pattern of patterns) {
|
|
47521
|
-
const matches = sanitized.match(pattern);
|
|
47522
|
-
if (matches) {
|
|
47523
|
-
stripped.push(...matches);
|
|
47524
|
-
sanitized = sanitized.replace(pattern, "");
|
|
47525
|
-
}
|
|
47526
|
-
}
|
|
47527
|
-
sanitized = sanitized.replace(/\s+/g, " ").trim();
|
|
47528
|
-
return {
|
|
47529
|
-
sanitized,
|
|
47530
|
-
modified: stripped.length > 0,
|
|
47531
|
-
stripped
|
|
47532
|
-
};
|
|
47325
|
+
// src/hooks/guardrails.ts
|
|
47326
|
+
init_constants();
|
|
47327
|
+
init_schema();
|
|
47328
|
+
init_manager2();
|
|
47329
|
+
import * as path25 from "path";
|
|
47330
|
+
init_utils();
|
|
47331
|
+
var storedInputArgs = new Map;
|
|
47332
|
+
function debugStoredArgs(action, callID, extra) {
|
|
47333
|
+
const args2 = storedInputArgs.get(callID);
|
|
47334
|
+
const argsObj = args2;
|
|
47335
|
+
const subagentType = argsObj?.subagent_type;
|
|
47336
|
+
console.log(`[swarm-debug-task] stored-args.${action} | callID=${callID} subagent_type=${subagentType ?? "(none)"}`, extra ? JSON.stringify(extra) : "");
|
|
47533
47337
|
}
|
|
47534
|
-
function
|
|
47535
|
-
|
|
47536
|
-
|
|
47537
|
-
return gateAgents.includes(normalized);
|
|
47338
|
+
function getStoredInputArgs(callID) {
|
|
47339
|
+
debugStoredArgs("get", callID);
|
|
47340
|
+
return storedInputArgs.get(callID);
|
|
47538
47341
|
}
|
|
47539
|
-
function
|
|
47540
|
-
|
|
47541
|
-
|
|
47542
|
-
if (!messages || !Array.isArray(messages)) {
|
|
47543
|
-
return;
|
|
47544
|
-
}
|
|
47545
|
-
for (const message of messages) {
|
|
47546
|
-
const info2 = message?.info;
|
|
47547
|
-
if (!info2)
|
|
47548
|
-
continue;
|
|
47549
|
-
const agent = info2.agent;
|
|
47550
|
-
if (!agent || !isGateAgentMessage(agent)) {
|
|
47551
|
-
continue;
|
|
47552
|
-
}
|
|
47553
|
-
if (!message.parts || !Array.isArray(message.parts)) {
|
|
47554
|
-
continue;
|
|
47555
|
-
}
|
|
47556
|
-
for (const part of message.parts) {
|
|
47557
|
-
if (part?.type !== "text" || !part.text) {
|
|
47558
|
-
continue;
|
|
47559
|
-
}
|
|
47560
|
-
const originalText = part.text;
|
|
47561
|
-
const result = sanitizeMessage(originalText);
|
|
47562
|
-
if (result.modified) {
|
|
47563
|
-
part.text = result.sanitized;
|
|
47564
|
-
try {
|
|
47565
|
-
const eventsPath = validateSwarmPath(directory, "events.jsonl");
|
|
47566
|
-
const event = {
|
|
47567
|
-
event: "message_sanitized",
|
|
47568
|
-
agent,
|
|
47569
|
-
original_length: originalText.length,
|
|
47570
|
-
stripped_count: result.stripped.length,
|
|
47571
|
-
stripped_patterns: result.stripped,
|
|
47572
|
-
timestamp: new Date().toISOString()
|
|
47573
|
-
};
|
|
47574
|
-
fs13.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
47575
|
-
`, "utf-8");
|
|
47576
|
-
} catch {}
|
|
47577
|
-
}
|
|
47578
|
-
}
|
|
47579
|
-
}
|
|
47580
|
-
};
|
|
47581
|
-
return safeHook(hook);
|
|
47342
|
+
function setStoredInputArgs(callID, args2) {
|
|
47343
|
+
debugStoredArgs("set", callID);
|
|
47344
|
+
storedInputArgs.set(callID, args2);
|
|
47582
47345
|
}
|
|
47583
|
-
|
|
47584
|
-
|
|
47585
|
-
|
|
47586
|
-
const now = Date.now();
|
|
47587
|
-
if (!input.agent || input.agent === "") {
|
|
47588
|
-
const session2 = swarmState.agentSessions.get(input.sessionID);
|
|
47589
|
-
if (session2?.delegationActive) {
|
|
47590
|
-
session2.delegationActive = false;
|
|
47591
|
-
swarmState.activeAgent.set(input.sessionID, ORCHESTRATOR_NAME);
|
|
47592
|
-
ensureAgentSession(input.sessionID, ORCHESTRATOR_NAME);
|
|
47593
|
-
updateAgentEventTime(input.sessionID);
|
|
47594
|
-
} else if (!session2) {
|
|
47595
|
-
ensureAgentSession(input.sessionID, ORCHESTRATOR_NAME);
|
|
47596
|
-
}
|
|
47597
|
-
return;
|
|
47598
|
-
}
|
|
47599
|
-
const agentName = input.agent;
|
|
47600
|
-
const previousAgent = swarmState.activeAgent.get(input.sessionID);
|
|
47601
|
-
swarmState.activeAgent.set(input.sessionID, agentName);
|
|
47602
|
-
const strippedAgent = stripKnownSwarmPrefix(agentName);
|
|
47603
|
-
const isArchitect = strippedAgent === ORCHESTRATOR_NAME;
|
|
47604
|
-
const session = ensureAgentSession(input.sessionID, agentName);
|
|
47605
|
-
session.delegationActive = !isArchitect;
|
|
47606
|
-
recordPhaseAgentDispatch(input.sessionID, agentName);
|
|
47607
|
-
if (!isArchitect && guardrailsEnabled) {
|
|
47608
|
-
beginInvocation(input.sessionID, agentName);
|
|
47609
|
-
}
|
|
47610
|
-
const delegationTrackerEnabled = config3.hooks?.delegation_tracker === true;
|
|
47611
|
-
const delegationGateEnabled = config3.hooks?.delegation_gate !== false;
|
|
47612
|
-
if ((delegationTrackerEnabled || delegationGateEnabled) && previousAgent && previousAgent !== agentName) {
|
|
47613
|
-
const entry = {
|
|
47614
|
-
from: previousAgent,
|
|
47615
|
-
to: agentName,
|
|
47616
|
-
timestamp: now
|
|
47617
|
-
};
|
|
47618
|
-
if (!swarmState.delegationChains.has(input.sessionID)) {
|
|
47619
|
-
swarmState.delegationChains.set(input.sessionID, []);
|
|
47620
|
-
}
|
|
47621
|
-
const chain = swarmState.delegationChains.get(input.sessionID);
|
|
47622
|
-
chain?.push(entry);
|
|
47623
|
-
if (delegationTrackerEnabled) {
|
|
47624
|
-
swarmState.pendingEvents++;
|
|
47625
|
-
}
|
|
47626
|
-
}
|
|
47627
|
-
};
|
|
47346
|
+
function deleteStoredInputArgs(callID) {
|
|
47347
|
+
debugStoredArgs("delete", callID);
|
|
47348
|
+
storedInputArgs.delete(callID);
|
|
47628
47349
|
}
|
|
47629
|
-
// src/hooks/guardrails.ts
|
|
47630
|
-
import * as path25 from "path";
|
|
47631
|
-
init_manager2();
|
|
47632
|
-
init_utils();
|
|
47633
47350
|
function extractPhaseNumber(phaseString) {
|
|
47634
47351
|
if (!phaseString)
|
|
47635
47352
|
return 1;
|
|
@@ -47763,7 +47480,6 @@ function createGuardrailsHooks(directoryOrConfig, config3) {
|
|
|
47763
47480
|
};
|
|
47764
47481
|
}
|
|
47765
47482
|
const cfg = guardrailsConfig;
|
|
47766
|
-
const inputArgsByCallID = new Map;
|
|
47767
47483
|
return {
|
|
47768
47484
|
toolBefore: async (input, output) => {
|
|
47769
47485
|
const currentSession = swarmState.agentSessions.get(input.sessionID);
|
|
@@ -48015,7 +47731,7 @@ function createGuardrailsHooks(directoryOrConfig, config3) {
|
|
|
48015
47731
|
window2.warningReason = reasons.join(", ");
|
|
48016
47732
|
}
|
|
48017
47733
|
}
|
|
48018
|
-
|
|
47734
|
+
setStoredInputArgs(input.callID, output.args);
|
|
48019
47735
|
},
|
|
48020
47736
|
toolAfter: async (input, output) => {
|
|
48021
47737
|
const session = swarmState.agentSessions.get(input.sessionID);
|
|
@@ -48058,8 +47774,7 @@ function createGuardrailsHooks(directoryOrConfig, config3) {
|
|
|
48058
47774
|
}
|
|
48059
47775
|
}
|
|
48060
47776
|
}
|
|
48061
|
-
const inputArgs =
|
|
48062
|
-
inputArgsByCallID.delete(input.callID);
|
|
47777
|
+
const inputArgs = getStoredInputArgs(input.callID);
|
|
48063
47778
|
const delegation = isAgentDelegation(input.tool, inputArgs);
|
|
48064
47779
|
if (delegation.isDelegation && (delegation.targetAgent === "reviewer" || delegation.targetAgent === "test_engineer")) {
|
|
48065
47780
|
let currentPhase = 1;
|
|
@@ -48267,6 +47982,513 @@ function hashArgs(args2) {
|
|
|
48267
47982
|
return 0;
|
|
48268
47983
|
}
|
|
48269
47984
|
}
|
|
47985
|
+
|
|
47986
|
+
// src/hooks/delegation-gate.ts
|
|
47987
|
+
function extractTaskLine(text) {
|
|
47988
|
+
const match = text.match(/TASK:\s*(.+?)(?:\n|$)/i);
|
|
47989
|
+
return match ? match[1].trim() : null;
|
|
47990
|
+
}
|
|
47991
|
+
function extractPlanTaskId(text) {
|
|
47992
|
+
const taskListMatch = text.match(/^[ \t]*-[ \t]*(?:\[[ x]\][ \t]+)?(\d+\.\d+(?:\.\d+)*)[:. ]/m);
|
|
47993
|
+
if (taskListMatch) {
|
|
47994
|
+
return taskListMatch[1];
|
|
47995
|
+
}
|
|
47996
|
+
const taskLineMatch = text.match(/TASK:\s*(?:.+?\s)?(\d+\.\d+(?:\.\d+)*)(?:\s|$|:)/i);
|
|
47997
|
+
if (taskLineMatch) {
|
|
47998
|
+
return taskLineMatch[1];
|
|
47999
|
+
}
|
|
48000
|
+
return null;
|
|
48001
|
+
}
|
|
48002
|
+
function createDelegationGateHook(config3) {
|
|
48003
|
+
const enabled = config3.hooks?.delegation_gate !== false;
|
|
48004
|
+
const delegationMaxChars = config3.hooks?.delegation_max_chars ?? 4000;
|
|
48005
|
+
if (!enabled) {
|
|
48006
|
+
return {
|
|
48007
|
+
messagesTransform: async (_input, _output) => {},
|
|
48008
|
+
toolAfter: async () => {}
|
|
48009
|
+
};
|
|
48010
|
+
}
|
|
48011
|
+
const toolAfter = async (input, _output) => {
|
|
48012
|
+
if (!input.sessionID)
|
|
48013
|
+
return;
|
|
48014
|
+
const session = swarmState.agentSessions.get(input.sessionID);
|
|
48015
|
+
if (!session)
|
|
48016
|
+
return;
|
|
48017
|
+
const taskStates = session.taskWorkflowStates ? Object.entries(session.taskWorkflowStates) : [];
|
|
48018
|
+
const statesSummary = taskStates.length > 0 ? taskStates.map(([k, v]) => `${k}=${v}`).join(",") : "(none)";
|
|
48019
|
+
console.log(`[swarm-debug-task] delegation-gate.toolAfter | session=${input.sessionID} callID=${input.callID} tool=${input.tool}`);
|
|
48020
|
+
const normalized = input.tool.replace(/^[^:]+[:.]/, "");
|
|
48021
|
+
if (normalized === "Task" || normalized === "task") {
|
|
48022
|
+
const storedArgs = getStoredInputArgs(input.callID);
|
|
48023
|
+
const argsObj = storedArgs;
|
|
48024
|
+
const subagentType = argsObj?.subagent_type;
|
|
48025
|
+
console.log(`[swarm-debug-task] delegation-gate.taskDetected | session=${input.sessionID} subagent_type=${subagentType ?? "(none)"} currentStates=[${statesSummary}]`);
|
|
48026
|
+
let hasReviewer = false;
|
|
48027
|
+
let hasTestEngineer = false;
|
|
48028
|
+
if (typeof subagentType === "string") {
|
|
48029
|
+
const targetAgent = stripKnownSwarmPrefix(subagentType);
|
|
48030
|
+
if (targetAgent === "reviewer")
|
|
48031
|
+
hasReviewer = true;
|
|
48032
|
+
if (targetAgent === "test_engineer")
|
|
48033
|
+
hasTestEngineer = true;
|
|
48034
|
+
if (targetAgent === "reviewer" && session.taskWorkflowStates) {
|
|
48035
|
+
for (const [taskId, state] of session.taskWorkflowStates) {
|
|
48036
|
+
if (state === "coder_delegated" || state === "pre_check_passed") {
|
|
48037
|
+
try {
|
|
48038
|
+
advanceTaskState(session, taskId, "reviewer_run");
|
|
48039
|
+
} catch {}
|
|
48040
|
+
}
|
|
48041
|
+
}
|
|
48042
|
+
}
|
|
48043
|
+
if (targetAgent === "test_engineer" && session.taskWorkflowStates) {
|
|
48044
|
+
for (const [taskId, state] of session.taskWorkflowStates) {
|
|
48045
|
+
if (state === "reviewer_run") {
|
|
48046
|
+
try {
|
|
48047
|
+
advanceTaskState(session, taskId, "tests_run");
|
|
48048
|
+
} catch {}
|
|
48049
|
+
}
|
|
48050
|
+
}
|
|
48051
|
+
}
|
|
48052
|
+
if (targetAgent === "reviewer" || targetAgent === "test_engineer") {
|
|
48053
|
+
for (const [, otherSession] of swarmState.agentSessions) {
|
|
48054
|
+
if (otherSession === session)
|
|
48055
|
+
continue;
|
|
48056
|
+
if (!otherSession.taskWorkflowStates)
|
|
48057
|
+
continue;
|
|
48058
|
+
if (targetAgent === "reviewer") {
|
|
48059
|
+
for (const [taskId, state] of otherSession.taskWorkflowStates) {
|
|
48060
|
+
if (state === "coder_delegated" || state === "pre_check_passed") {
|
|
48061
|
+
try {
|
|
48062
|
+
advanceTaskState(otherSession, taskId, "reviewer_run");
|
|
48063
|
+
} catch {}
|
|
48064
|
+
}
|
|
48065
|
+
}
|
|
48066
|
+
}
|
|
48067
|
+
if (targetAgent === "test_engineer") {
|
|
48068
|
+
for (const [taskId, state] of otherSession.taskWorkflowStates) {
|
|
48069
|
+
if (state === "reviewer_run") {
|
|
48070
|
+
try {
|
|
48071
|
+
advanceTaskState(otherSession, taskId, "tests_run");
|
|
48072
|
+
} catch {}
|
|
48073
|
+
}
|
|
48074
|
+
}
|
|
48075
|
+
}
|
|
48076
|
+
}
|
|
48077
|
+
}
|
|
48078
|
+
}
|
|
48079
|
+
if (argsObj !== undefined) {
|
|
48080
|
+
deleteStoredInputArgs(input.callID);
|
|
48081
|
+
}
|
|
48082
|
+
if (!subagentType || !hasReviewer) {
|
|
48083
|
+
const delegationChain = swarmState.delegationChains.get(input.sessionID);
|
|
48084
|
+
if (delegationChain && delegationChain.length > 0) {
|
|
48085
|
+
let lastCoderIndex = -1;
|
|
48086
|
+
for (let i2 = delegationChain.length - 1;i2 >= 0; i2--) {
|
|
48087
|
+
const target = stripKnownSwarmPrefix(delegationChain[i2].to);
|
|
48088
|
+
if (target.includes("coder")) {
|
|
48089
|
+
lastCoderIndex = i2;
|
|
48090
|
+
break;
|
|
48091
|
+
}
|
|
48092
|
+
}
|
|
48093
|
+
if (lastCoderIndex === -1) {
|
|
48094
|
+
return;
|
|
48095
|
+
}
|
|
48096
|
+
const afterCoder = delegationChain.slice(lastCoderIndex);
|
|
48097
|
+
for (const delegation of afterCoder) {
|
|
48098
|
+
const target = stripKnownSwarmPrefix(delegation.to);
|
|
48099
|
+
if (target === "reviewer")
|
|
48100
|
+
hasReviewer = true;
|
|
48101
|
+
if (target === "test_engineer")
|
|
48102
|
+
hasTestEngineer = true;
|
|
48103
|
+
}
|
|
48104
|
+
if (hasReviewer && hasTestEngineer) {
|
|
48105
|
+
session.qaSkipCount = 0;
|
|
48106
|
+
session.qaSkipTaskIds = [];
|
|
48107
|
+
}
|
|
48108
|
+
if (hasReviewer && session.taskWorkflowStates) {
|
|
48109
|
+
for (const [taskId, state] of session.taskWorkflowStates) {
|
|
48110
|
+
if (state === "coder_delegated" || state === "pre_check_passed") {
|
|
48111
|
+
try {
|
|
48112
|
+
advanceTaskState(session, taskId, "reviewer_run");
|
|
48113
|
+
} catch {}
|
|
48114
|
+
}
|
|
48115
|
+
}
|
|
48116
|
+
}
|
|
48117
|
+
if (hasReviewer && hasTestEngineer && session.taskWorkflowStates) {
|
|
48118
|
+
for (const [taskId, state] of session.taskWorkflowStates) {
|
|
48119
|
+
if (state === "reviewer_run") {
|
|
48120
|
+
try {
|
|
48121
|
+
advanceTaskState(session, taskId, "tests_run");
|
|
48122
|
+
} catch {}
|
|
48123
|
+
}
|
|
48124
|
+
}
|
|
48125
|
+
}
|
|
48126
|
+
if (hasReviewer) {
|
|
48127
|
+
for (const [, otherSession] of swarmState.agentSessions) {
|
|
48128
|
+
if (otherSession === session)
|
|
48129
|
+
continue;
|
|
48130
|
+
if (!otherSession.taskWorkflowStates)
|
|
48131
|
+
continue;
|
|
48132
|
+
for (const [taskId, state] of otherSession.taskWorkflowStates) {
|
|
48133
|
+
if (state === "coder_delegated" || state === "pre_check_passed") {
|
|
48134
|
+
try {
|
|
48135
|
+
advanceTaskState(otherSession, taskId, "reviewer_run");
|
|
48136
|
+
} catch {}
|
|
48137
|
+
}
|
|
48138
|
+
}
|
|
48139
|
+
}
|
|
48140
|
+
}
|
|
48141
|
+
if (hasReviewer && hasTestEngineer) {
|
|
48142
|
+
for (const [, otherSession] of swarmState.agentSessions) {
|
|
48143
|
+
if (otherSession === session)
|
|
48144
|
+
continue;
|
|
48145
|
+
if (!otherSession.taskWorkflowStates)
|
|
48146
|
+
continue;
|
|
48147
|
+
for (const [taskId, state] of otherSession.taskWorkflowStates) {
|
|
48148
|
+
if (state === "reviewer_run") {
|
|
48149
|
+
try {
|
|
48150
|
+
advanceTaskState(otherSession, taskId, "tests_run");
|
|
48151
|
+
} catch {}
|
|
48152
|
+
}
|
|
48153
|
+
}
|
|
48154
|
+
}
|
|
48155
|
+
}
|
|
48156
|
+
}
|
|
48157
|
+
}
|
|
48158
|
+
}
|
|
48159
|
+
};
|
|
48160
|
+
return {
|
|
48161
|
+
messagesTransform: async (_input, output) => {
|
|
48162
|
+
const messages = output.messages;
|
|
48163
|
+
if (!messages || messages.length === 0)
|
|
48164
|
+
return;
|
|
48165
|
+
let lastUserMessageIndex = -1;
|
|
48166
|
+
for (let i2 = messages.length - 1;i2 >= 0; i2--) {
|
|
48167
|
+
if (messages[i2]?.info?.role === "user") {
|
|
48168
|
+
lastUserMessageIndex = i2;
|
|
48169
|
+
break;
|
|
48170
|
+
}
|
|
48171
|
+
}
|
|
48172
|
+
if (lastUserMessageIndex === -1)
|
|
48173
|
+
return;
|
|
48174
|
+
const lastUserMessage = messages[lastUserMessageIndex];
|
|
48175
|
+
if (!lastUserMessage?.parts)
|
|
48176
|
+
return;
|
|
48177
|
+
const agent = lastUserMessage.info?.agent;
|
|
48178
|
+
const strippedAgent = agent ? stripKnownSwarmPrefix(agent) : undefined;
|
|
48179
|
+
if (strippedAgent && strippedAgent !== "architect")
|
|
48180
|
+
return;
|
|
48181
|
+
const textPartIndex = lastUserMessage.parts.findIndex((p) => p?.type === "text" && p.text !== undefined);
|
|
48182
|
+
if (textPartIndex === -1)
|
|
48183
|
+
return;
|
|
48184
|
+
const textPart = lastUserMessage.parts[textPartIndex];
|
|
48185
|
+
const text = textPart.text ?? "";
|
|
48186
|
+
const taskDisclosureSessionID = lastUserMessage.info?.sessionID;
|
|
48187
|
+
if (taskDisclosureSessionID) {
|
|
48188
|
+
const taskSession = ensureAgentSession(taskDisclosureSessionID);
|
|
48189
|
+
const currentTaskIdForWindow = taskSession.currentTaskId;
|
|
48190
|
+
if (currentTaskIdForWindow) {
|
|
48191
|
+
const taskLineRegex = /^[ \t]*-[ \t]*(?:\[[ x]\][ \t]+)?(\d+\.\d+(?:\.\d+)*)[:. ].*/gm;
|
|
48192
|
+
const taskLines = [];
|
|
48193
|
+
taskLineRegex.lastIndex = 0;
|
|
48194
|
+
let regexMatch = taskLineRegex.exec(text);
|
|
48195
|
+
while (regexMatch !== null) {
|
|
48196
|
+
taskLines.push({
|
|
48197
|
+
line: regexMatch[0],
|
|
48198
|
+
taskId: regexMatch[1],
|
|
48199
|
+
index: regexMatch.index
|
|
48200
|
+
});
|
|
48201
|
+
regexMatch = taskLineRegex.exec(text);
|
|
48202
|
+
}
|
|
48203
|
+
if (taskLines.length > 5) {
|
|
48204
|
+
const currentIdx = taskLines.findIndex((t) => t.taskId === currentTaskIdForWindow);
|
|
48205
|
+
const windowStart = Math.max(0, currentIdx - 2);
|
|
48206
|
+
const windowEnd = Math.min(taskLines.length - 1, currentIdx + 3);
|
|
48207
|
+
const visibleTasks = taskLines.slice(windowStart, windowEnd + 1);
|
|
48208
|
+
const hiddenBefore = windowStart;
|
|
48209
|
+
const hiddenAfter = taskLines.length - 1 - windowEnd;
|
|
48210
|
+
const totalTasks = taskLines.length;
|
|
48211
|
+
const visibleCount = visibleTasks.length;
|
|
48212
|
+
const firstTaskIndex = taskLines[0].index;
|
|
48213
|
+
const lastTask = taskLines[taskLines.length - 1];
|
|
48214
|
+
const lastTaskEnd = lastTask.index + lastTask.line.length;
|
|
48215
|
+
const before = text.slice(0, firstTaskIndex);
|
|
48216
|
+
const after = text.slice(lastTaskEnd);
|
|
48217
|
+
const visibleLines = visibleTasks.map((t) => t.line).join(`
|
|
48218
|
+
`);
|
|
48219
|
+
const trimComment = `[Task window: showing ${visibleCount} of ${totalTasks} tasks]`;
|
|
48220
|
+
const trimmedMiddle = (hiddenBefore > 0 ? `[...${hiddenBefore} tasks hidden...]
|
|
48221
|
+
` : "") + visibleLines + (hiddenAfter > 0 ? `
|
|
48222
|
+
[...${hiddenAfter} tasks hidden...]` : "");
|
|
48223
|
+
textPart.text = `${before}${trimmedMiddle}
|
|
48224
|
+
${trimComment}${after}`;
|
|
48225
|
+
}
|
|
48226
|
+
}
|
|
48227
|
+
}
|
|
48228
|
+
const sessionID = lastUserMessage.info?.sessionID;
|
|
48229
|
+
const planTaskId = extractPlanTaskId(text);
|
|
48230
|
+
const taskIdMatch = text.match(/TASK:\s*(.+?)(?:\n|$)/i);
|
|
48231
|
+
const taskIdFromLine = taskIdMatch ? taskIdMatch[1].trim() : null;
|
|
48232
|
+
const currentTaskId = planTaskId ?? taskIdFromLine;
|
|
48233
|
+
const coderDelegationPattern = /(?:^|\n)\s*(?:\w+_)?coder\s*\n\s*TASK:/i;
|
|
48234
|
+
const isCoderDelegation = coderDelegationPattern.test(text);
|
|
48235
|
+
const priorCoderTaskId = sessionID ? ensureAgentSession(sessionID).lastCoderDelegationTaskId ?? null : null;
|
|
48236
|
+
if (sessionID && isCoderDelegation && currentTaskId) {
|
|
48237
|
+
const session = ensureAgentSession(sessionID);
|
|
48238
|
+
session.lastCoderDelegationTaskId = currentTaskId;
|
|
48239
|
+
const fileDirPattern = /^FILE:\s*(.+)$/gm;
|
|
48240
|
+
const declaredFiles = [];
|
|
48241
|
+
for (const match of text.matchAll(fileDirPattern)) {
|
|
48242
|
+
const filePath = match[1].trim();
|
|
48243
|
+
if (filePath.length > 0 && !declaredFiles.includes(filePath)) {
|
|
48244
|
+
declaredFiles.push(filePath);
|
|
48245
|
+
}
|
|
48246
|
+
}
|
|
48247
|
+
session.declaredCoderScope = declaredFiles.length > 0 ? declaredFiles : null;
|
|
48248
|
+
try {
|
|
48249
|
+
advanceTaskState(session, currentTaskId, "coder_delegated");
|
|
48250
|
+
} catch (err2) {
|
|
48251
|
+
console.warn(`[delegation-gate] state machine warn: ${err2 instanceof Error ? err2.message : String(err2)}`);
|
|
48252
|
+
}
|
|
48253
|
+
}
|
|
48254
|
+
if (sessionID && !isCoderDelegation && currentTaskId) {
|
|
48255
|
+
const session = ensureAgentSession(sessionID);
|
|
48256
|
+
if (session.architectWriteCount > 0 && session.lastCoderDelegationTaskId !== currentTaskId) {
|
|
48257
|
+
const warningText2 = `\u26A0\uFE0F DELEGATION VIOLATION: Code modifications detected for task ${currentTaskId} with zero coder delegations.
|
|
48258
|
+
Rule 1: DELEGATE all coding to coder. You do NOT write code.`;
|
|
48259
|
+
textPart.text = `${warningText2}
|
|
48260
|
+
|
|
48261
|
+
${text}`;
|
|
48262
|
+
}
|
|
48263
|
+
}
|
|
48264
|
+
{
|
|
48265
|
+
const deliberationSessionID = lastUserMessage.info?.sessionID;
|
|
48266
|
+
if (deliberationSessionID) {
|
|
48267
|
+
if (!/^[a-zA-Z0-9_-]{1,128}$/.test(deliberationSessionID)) {} else {
|
|
48268
|
+
const deliberationSession = ensureAgentSession(deliberationSessionID);
|
|
48269
|
+
const lastGate = deliberationSession.lastGateOutcome;
|
|
48270
|
+
let preamble;
|
|
48271
|
+
if (lastGate) {
|
|
48272
|
+
const gateResult = lastGate.passed ? "PASSED" : "FAILED";
|
|
48273
|
+
const sanitizedGate = lastGate.gate.replace(/\[/g, "(").replace(/\]/g, ")").replace(/[\r\n]/g, " ").slice(0, 64);
|
|
48274
|
+
const sanitizedTaskId = lastGate.taskId.replace(/\[/g, "(").replace(/\]/g, ")").replace(/[\r\n]/g, " ").slice(0, 32);
|
|
48275
|
+
preamble = `[Last gate: ${sanitizedGate} ${gateResult} for task ${sanitizedTaskId}]
|
|
48276
|
+
[DELIBERATE: Before proceeding \u2014 what is the SINGLE next task? What gates must it pass?]`;
|
|
48277
|
+
} else {
|
|
48278
|
+
preamble = `[DELIBERATE: Identify the first task from the plan. What gates must it pass before marking complete?]`;
|
|
48279
|
+
}
|
|
48280
|
+
const currentText = textPart.text ?? "";
|
|
48281
|
+
textPart.text = `${preamble}
|
|
48282
|
+
|
|
48283
|
+
${currentText}`;
|
|
48284
|
+
}
|
|
48285
|
+
}
|
|
48286
|
+
}
|
|
48287
|
+
if (!isCoderDelegation)
|
|
48288
|
+
return;
|
|
48289
|
+
const warnings = [];
|
|
48290
|
+
if (text.length > delegationMaxChars) {
|
|
48291
|
+
warnings.push(`Delegation exceeds recommended size (${text.length} chars, limit ${delegationMaxChars}). Consider splitting into smaller tasks.`);
|
|
48292
|
+
}
|
|
48293
|
+
const fileMatches = text.match(/^FILE:/gm);
|
|
48294
|
+
if (fileMatches && fileMatches.length > 1) {
|
|
48295
|
+
warnings.push(`Multiple FILE: directives detected (${fileMatches.length}). Each coder task should target ONE file.`);
|
|
48296
|
+
}
|
|
48297
|
+
const taskMatches = text.match(/^TASK:/gm);
|
|
48298
|
+
if (taskMatches && taskMatches.length > 1) {
|
|
48299
|
+
warnings.push(`Multiple TASK: sections detected (${taskMatches.length}). Send ONE task per coder call.`);
|
|
48300
|
+
}
|
|
48301
|
+
const batchingPattern = /\b(?:and also|then also|additionally|as well as|along with|while you'?re at it)[.,]?\b/gi;
|
|
48302
|
+
const batchingMatches = text.match(batchingPattern);
|
|
48303
|
+
if (batchingMatches && batchingMatches.length > 0) {
|
|
48304
|
+
warnings.push(`Batching language detected (${batchingMatches.join(", ")}). Break compound objectives into separate coder calls.`);
|
|
48305
|
+
}
|
|
48306
|
+
const taskLine = extractTaskLine(text);
|
|
48307
|
+
if (taskLine) {
|
|
48308
|
+
const andPattern = /\s+and\s+(update|add|remove|modify|refactor|implement|create|delete|fix|change|build|deploy|write|test|move|rename|extend|extract|convert|migrate|upgrade|replace)\b/i;
|
|
48309
|
+
if (andPattern.test(taskLine)) {
|
|
48310
|
+
warnings.push('TASK line contains "and" connecting separate actions');
|
|
48311
|
+
}
|
|
48312
|
+
}
|
|
48313
|
+
if (sessionID) {
|
|
48314
|
+
const delegationChain = swarmState.delegationChains.get(sessionID);
|
|
48315
|
+
if (delegationChain && delegationChain.length >= 2) {
|
|
48316
|
+
const coderIndices = [];
|
|
48317
|
+
for (let i2 = delegationChain.length - 1;i2 >= 0; i2--) {
|
|
48318
|
+
if (stripKnownSwarmPrefix(delegationChain[i2].to).includes("coder")) {
|
|
48319
|
+
coderIndices.unshift(i2);
|
|
48320
|
+
if (coderIndices.length === 2)
|
|
48321
|
+
break;
|
|
48322
|
+
}
|
|
48323
|
+
}
|
|
48324
|
+
if (coderIndices.length === 2) {
|
|
48325
|
+
const prevCoderIndex = coderIndices[0];
|
|
48326
|
+
const betweenCoders = delegationChain.slice(prevCoderIndex + 1);
|
|
48327
|
+
const hasReviewer = betweenCoders.some((d) => stripKnownSwarmPrefix(d.to) === "reviewer");
|
|
48328
|
+
const hasTestEngineer = betweenCoders.some((d) => stripKnownSwarmPrefix(d.to) === "test_engineer");
|
|
48329
|
+
const session = ensureAgentSession(sessionID);
|
|
48330
|
+
const priorTaskStuckAtCoder = priorCoderTaskId !== null && getTaskState(session, priorCoderTaskId) === "coder_delegated";
|
|
48331
|
+
if (!hasReviewer || !hasTestEngineer || priorTaskStuckAtCoder) {
|
|
48332
|
+
if (session.qaSkipCount >= 1) {
|
|
48333
|
+
const skippedTasks = session.qaSkipTaskIds.join(", ");
|
|
48334
|
+
throw new Error(`\uD83D\uDED1 QA GATE ENFORCEMENT: ${session.qaSkipCount + 1} consecutive coder delegations without reviewer/test_engineer. ` + `Skipped tasks: [${skippedTasks}]. ` + `DELEGATE to reviewer and test_engineer NOW before any further coder work.`);
|
|
48335
|
+
}
|
|
48336
|
+
session.qaSkipCount++;
|
|
48337
|
+
session.qaSkipTaskIds.push(currentTaskId ?? "unknown");
|
|
48338
|
+
warnings.push(`\u26A0\uFE0F PROTOCOL VIOLATION: Previous coder task completed, but QA gate was skipped. ` + `You MUST delegate to reviewer (code review) and test_engineer (test execution) ` + `before starting a new coder task. Review RULES 7-8 in your system prompt.`);
|
|
48339
|
+
}
|
|
48340
|
+
}
|
|
48341
|
+
}
|
|
48342
|
+
}
|
|
48343
|
+
if (warnings.length === 0)
|
|
48344
|
+
return;
|
|
48345
|
+
const warningLines = warnings.map((w) => `Detected signal: ${w}`);
|
|
48346
|
+
const warningText = `\u26A0\uFE0F BATCH DETECTED: Your coder delegation appears to contain multiple tasks.
|
|
48347
|
+
Rule 3: ONE task per coder call. Split this into separate delegations.
|
|
48348
|
+
${warningLines.join(`
|
|
48349
|
+
`)}`;
|
|
48350
|
+
const originalText = textPart.text ?? "";
|
|
48351
|
+
textPart.text = `${warningText}
|
|
48352
|
+
|
|
48353
|
+
${originalText}`;
|
|
48354
|
+
},
|
|
48355
|
+
toolAfter
|
|
48356
|
+
};
|
|
48357
|
+
}
|
|
48358
|
+
// src/hooks/delegation-sanitizer.ts
|
|
48359
|
+
init_utils2();
|
|
48360
|
+
import * as fs13 from "fs";
|
|
48361
|
+
var SANITIZATION_PATTERNS = [
|
|
48362
|
+
/\b\d+(st|nd|rd|th)\s+(attempt|try|time)\b/gi,
|
|
48363
|
+
/\b(5th|fifth|final|last)\s+attempt\b/gi,
|
|
48364
|
+
/attempt\s+\d+\s*\/\s*\d+/gi,
|
|
48365
|
+
/\bthis\s+is\s+(the\s+)?(5th|fifth|final|last)\b/gi,
|
|
48366
|
+
/\bwe('re|\s+are)\s+(behind|late)\b/gi,
|
|
48367
|
+
/\buser\s+is\s+waiting\b/gi,
|
|
48368
|
+
/\bship\s+(this|it)\s+now\b/gi,
|
|
48369
|
+
/\bor\s+I('ll|\s+will)\s+(stop|halt|alert)\b/gi,
|
|
48370
|
+
/\bor\s+all\s+work\s+stops\b/gi,
|
|
48371
|
+
/\bthis\s+will\s+(delay|block)\s+everything\b/gi,
|
|
48372
|
+
/\b(I'm|I\s+am)\s+(frustrated|disappointed)\b/gi
|
|
48373
|
+
];
|
|
48374
|
+
function sanitizeMessage(text, patterns = SANITIZATION_PATTERNS) {
|
|
48375
|
+
let sanitized = text;
|
|
48376
|
+
const stripped = [];
|
|
48377
|
+
for (const pattern of patterns) {
|
|
48378
|
+
const matches = sanitized.match(pattern);
|
|
48379
|
+
if (matches) {
|
|
48380
|
+
stripped.push(...matches);
|
|
48381
|
+
sanitized = sanitized.replace(pattern, "");
|
|
48382
|
+
}
|
|
48383
|
+
}
|
|
48384
|
+
sanitized = sanitized.replace(/\s+/g, " ").trim();
|
|
48385
|
+
return {
|
|
48386
|
+
sanitized,
|
|
48387
|
+
modified: stripped.length > 0,
|
|
48388
|
+
stripped
|
|
48389
|
+
};
|
|
48390
|
+
}
|
|
48391
|
+
function isGateAgentMessage(agentName) {
|
|
48392
|
+
const gateAgents = ["reviewer", "test_engineer", "critic", "test-engineer"];
|
|
48393
|
+
const normalized = agentName.toLowerCase().replace(/-/g, "_");
|
|
48394
|
+
return gateAgents.includes(normalized);
|
|
48395
|
+
}
|
|
48396
|
+
function createDelegationSanitizerHook(directory) {
|
|
48397
|
+
const hook = async (_input, output) => {
|
|
48398
|
+
const messages = output?.messages;
|
|
48399
|
+
if (!messages || !Array.isArray(messages)) {
|
|
48400
|
+
return;
|
|
48401
|
+
}
|
|
48402
|
+
for (const message of messages) {
|
|
48403
|
+
const info2 = message?.info;
|
|
48404
|
+
if (!info2)
|
|
48405
|
+
continue;
|
|
48406
|
+
const agent = info2.agent;
|
|
48407
|
+
if (!agent || !isGateAgentMessage(agent)) {
|
|
48408
|
+
continue;
|
|
48409
|
+
}
|
|
48410
|
+
if (!message.parts || !Array.isArray(message.parts)) {
|
|
48411
|
+
continue;
|
|
48412
|
+
}
|
|
48413
|
+
for (const part of message.parts) {
|
|
48414
|
+
if (part?.type !== "text" || !part.text) {
|
|
48415
|
+
continue;
|
|
48416
|
+
}
|
|
48417
|
+
const originalText = part.text;
|
|
48418
|
+
const result = sanitizeMessage(originalText);
|
|
48419
|
+
if (result.modified) {
|
|
48420
|
+
part.text = result.sanitized;
|
|
48421
|
+
try {
|
|
48422
|
+
const eventsPath = validateSwarmPath(directory, "events.jsonl");
|
|
48423
|
+
const event = {
|
|
48424
|
+
event: "message_sanitized",
|
|
48425
|
+
agent,
|
|
48426
|
+
original_length: originalText.length,
|
|
48427
|
+
stripped_count: result.stripped.length,
|
|
48428
|
+
stripped_patterns: result.stripped,
|
|
48429
|
+
timestamp: new Date().toISOString()
|
|
48430
|
+
};
|
|
48431
|
+
fs13.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
48432
|
+
`, "utf-8");
|
|
48433
|
+
} catch {}
|
|
48434
|
+
}
|
|
48435
|
+
}
|
|
48436
|
+
}
|
|
48437
|
+
};
|
|
48438
|
+
return safeHook(hook);
|
|
48439
|
+
}
|
|
48440
|
+
// src/hooks/delegation-tracker.ts
|
|
48441
|
+
init_constants();
|
|
48442
|
+
init_schema();
|
|
48443
|
+
function createDelegationTrackerHook(config3, guardrailsEnabled = true) {
|
|
48444
|
+
return async (input, _output) => {
|
|
48445
|
+
const now = Date.now();
|
|
48446
|
+
const debugSession = swarmState.agentSessions.get(input.sessionID);
|
|
48447
|
+
const taskStates = debugSession?.taskWorkflowStates ? Object.entries(debugSession.taskWorkflowStates) : [];
|
|
48448
|
+
const statesSummary = taskStates.length > 0 ? taskStates.map(([k, v]) => `${k}=${v}`).join(",") : "(none)";
|
|
48449
|
+
console.log(`[swarm-debug-task] chat.message | session=${input.sessionID} agent=${input.agent ?? "(none)"} prevAgent=${swarmState.activeAgent.get(input.sessionID) ?? "(none)"} taskStates=[${statesSummary}]`);
|
|
48450
|
+
if (!input.agent || input.agent === "") {
|
|
48451
|
+
const session2 = swarmState.agentSessions.get(input.sessionID);
|
|
48452
|
+
if (session2?.delegationActive) {
|
|
48453
|
+
session2.delegationActive = false;
|
|
48454
|
+
swarmState.activeAgent.set(input.sessionID, ORCHESTRATOR_NAME);
|
|
48455
|
+
ensureAgentSession(input.sessionID, ORCHESTRATOR_NAME);
|
|
48456
|
+
updateAgentEventTime(input.sessionID);
|
|
48457
|
+
} else if (!session2) {
|
|
48458
|
+
ensureAgentSession(input.sessionID, ORCHESTRATOR_NAME);
|
|
48459
|
+
}
|
|
48460
|
+
return;
|
|
48461
|
+
}
|
|
48462
|
+
const agentName = input.agent;
|
|
48463
|
+
const previousAgent = swarmState.activeAgent.get(input.sessionID);
|
|
48464
|
+
swarmState.activeAgent.set(input.sessionID, agentName);
|
|
48465
|
+
const strippedAgent = stripKnownSwarmPrefix(agentName);
|
|
48466
|
+
const isArchitect2 = strippedAgent === ORCHESTRATOR_NAME;
|
|
48467
|
+
const session = ensureAgentSession(input.sessionID, agentName);
|
|
48468
|
+
session.delegationActive = !isArchitect2;
|
|
48469
|
+
recordPhaseAgentDispatch(input.sessionID, agentName);
|
|
48470
|
+
if (!isArchitect2 && guardrailsEnabled) {
|
|
48471
|
+
beginInvocation(input.sessionID, agentName);
|
|
48472
|
+
}
|
|
48473
|
+
const delegationTrackerEnabled = config3.hooks?.delegation_tracker === true;
|
|
48474
|
+
const delegationGateEnabled = config3.hooks?.delegation_gate !== false;
|
|
48475
|
+
if ((delegationTrackerEnabled || delegationGateEnabled) && previousAgent && previousAgent !== agentName) {
|
|
48476
|
+
const entry = {
|
|
48477
|
+
from: previousAgent,
|
|
48478
|
+
to: agentName,
|
|
48479
|
+
timestamp: now
|
|
48480
|
+
};
|
|
48481
|
+
if (!swarmState.delegationChains.has(input.sessionID)) {
|
|
48482
|
+
swarmState.delegationChains.set(input.sessionID, []);
|
|
48483
|
+
}
|
|
48484
|
+
const chain = swarmState.delegationChains.get(input.sessionID);
|
|
48485
|
+
chain?.push(entry);
|
|
48486
|
+
if (delegationTrackerEnabled) {
|
|
48487
|
+
swarmState.pendingEvents++;
|
|
48488
|
+
}
|
|
48489
|
+
}
|
|
48490
|
+
};
|
|
48491
|
+
}
|
|
48270
48492
|
// src/hooks/messages-transform.ts
|
|
48271
48493
|
function consolidateSystemMessages(messages) {
|
|
48272
48494
|
if (messages.length > 0 && messages[0].role === "system" && messages[0].content !== undefined && typeof messages[0].content === "string" && messages[0].content.trim().length > 0) {
|
|
@@ -48333,6 +48555,7 @@ function consolidateSystemMessages(messages) {
|
|
|
48333
48555
|
});
|
|
48334
48556
|
}
|
|
48335
48557
|
// src/hooks/phase-monitor.ts
|
|
48558
|
+
init_schema();
|
|
48336
48559
|
init_manager2();
|
|
48337
48560
|
|
|
48338
48561
|
// src/hooks/curator.ts
|
|
@@ -48755,7 +48978,9 @@ function createPhaseMonitorHook(directory, preflightManager) {
|
|
|
48755
48978
|
if (lastKnownPhase === null) {
|
|
48756
48979
|
lastKnownPhase = currentPhase;
|
|
48757
48980
|
try {
|
|
48758
|
-
const
|
|
48981
|
+
const { loadPluginConfigWithMeta: loadPluginConfigWithMeta2 } = await Promise.resolve().then(() => (init_config(), exports_config));
|
|
48982
|
+
const { config: config3 } = loadPluginConfigWithMeta2(directory);
|
|
48983
|
+
const curatorConfig = CuratorConfigSchema.parse(config3.curator ?? {});
|
|
48759
48984
|
if (curatorConfig.enabled && curatorConfig.init_enabled) {
|
|
48760
48985
|
await runCuratorInit(directory, curatorConfig);
|
|
48761
48986
|
}
|
|
@@ -48860,10 +49085,12 @@ ${originalText}`;
|
|
|
48860
49085
|
};
|
|
48861
49086
|
}
|
|
48862
49087
|
// src/hooks/system-enhancer.ts
|
|
48863
|
-
|
|
49088
|
+
init_constants();
|
|
49089
|
+
init_schema();
|
|
48864
49090
|
init_manager();
|
|
48865
49091
|
init_detector();
|
|
48866
49092
|
init_manager2();
|
|
49093
|
+
import * as fs16 from "fs";
|
|
48867
49094
|
|
|
48868
49095
|
// src/services/decision-drift-analyzer.ts
|
|
48869
49096
|
init_utils2();
|
|
@@ -49302,6 +49529,8 @@ init_preflight_service();
|
|
|
49302
49529
|
init_utils();
|
|
49303
49530
|
|
|
49304
49531
|
// src/hooks/adversarial-detector.ts
|
|
49532
|
+
init_constants();
|
|
49533
|
+
init_schema();
|
|
49305
49534
|
function safeGet(obj, key) {
|
|
49306
49535
|
if (!obj || !Object.hasOwn(obj, key))
|
|
49307
49536
|
return;
|
|
@@ -51146,6 +51375,7 @@ function createKnowledgeCuratorHook(directory, config3) {
|
|
|
51146
51375
|
}
|
|
51147
51376
|
|
|
51148
51377
|
// src/hooks/knowledge-injector.ts
|
|
51378
|
+
init_schema();
|
|
51149
51379
|
init_manager2();
|
|
51150
51380
|
|
|
51151
51381
|
// src/services/run-memory.ts
|
|
@@ -51634,6 +51864,7 @@ function deserializeAgentSession(s) {
|
|
|
51634
51864
|
const partialGateWarningsIssuedForTask = new Set(s.partialGateWarningsIssuedForTask ?? []);
|
|
51635
51865
|
const catastrophicPhaseWarnings = new Set(s.catastrophicPhaseWarnings ?? []);
|
|
51636
51866
|
const phaseAgentsDispatched = new Set(s.phaseAgentsDispatched ?? []);
|
|
51867
|
+
const lastCompletedPhaseAgentsDispatched = new Set(s.lastCompletedPhaseAgentsDispatched ?? []);
|
|
51637
51868
|
return {
|
|
51638
51869
|
agentName: s.agentName,
|
|
51639
51870
|
lastToolCallTime: s.lastToolCallTime,
|
|
@@ -51655,6 +51886,7 @@ function deserializeAgentSession(s) {
|
|
|
51655
51886
|
lastPhaseCompleteTimestamp: s.lastPhaseCompleteTimestamp ?? 0,
|
|
51656
51887
|
lastPhaseCompletePhase: s.lastPhaseCompletePhase ?? 0,
|
|
51657
51888
|
phaseAgentsDispatched,
|
|
51889
|
+
lastCompletedPhaseAgentsDispatched,
|
|
51658
51890
|
qaSkipCount: s.qaSkipCount ?? 0,
|
|
51659
51891
|
qaSkipTaskIds: s.qaSkipTaskIds ?? [],
|
|
51660
51892
|
taskWorkflowStates: deserializeTaskWorkflowStates(s.taskWorkflowStates),
|
|
@@ -53823,9 +54055,11 @@ init_lint();
|
|
|
53823
54055
|
|
|
53824
54056
|
// src/tools/phase-complete.ts
|
|
53825
54057
|
init_dist();
|
|
54058
|
+
init_config();
|
|
54059
|
+
init_schema();
|
|
54060
|
+
init_manager();
|
|
53826
54061
|
import * as fs25 from "fs";
|
|
53827
54062
|
import * as path37 from "path";
|
|
53828
|
-
init_manager();
|
|
53829
54063
|
init_utils2();
|
|
53830
54064
|
init_create_tool();
|
|
53831
54065
|
function collectCrossSessionDispatchedAgents(phaseReferenceTimestamp, callerSessionId) {
|
|
@@ -53839,6 +54073,11 @@ function collectCrossSessionDispatchedAgents(phaseReferenceTimestamp, callerSess
|
|
|
53839
54073
|
agents.add(agent);
|
|
53840
54074
|
}
|
|
53841
54075
|
}
|
|
54076
|
+
if (callerSession.lastCompletedPhaseAgentsDispatched) {
|
|
54077
|
+
for (const agent of callerSession.lastCompletedPhaseAgentsDispatched) {
|
|
54078
|
+
agents.add(agent);
|
|
54079
|
+
}
|
|
54080
|
+
}
|
|
53842
54081
|
const callerDelegations = swarmState.delegationChains.get(callerSessionId);
|
|
53843
54082
|
if (callerDelegations) {
|
|
53844
54083
|
for (const delegation of callerDelegations) {
|
|
@@ -53854,7 +54093,8 @@ function collectCrossSessionDispatchedAgents(phaseReferenceTimestamp, callerSess
|
|
|
53854
54093
|
const hasRecentToolCalls = session.lastToolCallTime >= phaseReferenceTimestamp;
|
|
53855
54094
|
const delegations = swarmState.delegationChains.get(sessionId);
|
|
53856
54095
|
const hasRecentDelegations = delegations?.some((d) => d.timestamp >= phaseReferenceTimestamp) ?? false;
|
|
53857
|
-
const
|
|
54096
|
+
const hasRestoredAgents = (session.phaseAgentsDispatched?.size ?? 0) > 0 && session.lastPhaseCompleteTimestamp === phaseReferenceTimestamp;
|
|
54097
|
+
const hasActivity = hasRecentToolCalls || hasRecentDelegations || hasRestoredAgents;
|
|
53858
54098
|
if (hasActivity) {
|
|
53859
54099
|
contributorSessionIds.push(sessionId);
|
|
53860
54100
|
if (session.phaseAgentsDispatched) {
|
|
@@ -53862,6 +54102,11 @@ function collectCrossSessionDispatchedAgents(phaseReferenceTimestamp, callerSess
|
|
|
53862
54102
|
agents.add(agent);
|
|
53863
54103
|
}
|
|
53864
54104
|
}
|
|
54105
|
+
if (session.lastCompletedPhaseAgentsDispatched) {
|
|
54106
|
+
for (const agent of session.lastCompletedPhaseAgentsDispatched) {
|
|
54107
|
+
agents.add(agent);
|
|
54108
|
+
}
|
|
54109
|
+
}
|
|
53865
54110
|
const delegations2 = swarmState.delegationChains.get(sessionId);
|
|
53866
54111
|
if (delegations2) {
|
|
53867
54112
|
for (const delegation of delegations2) {
|
|
@@ -54094,6 +54339,9 @@ async function executePhaseComplete(args2, workingDirectory) {
|
|
|
54094
54339
|
for (const contributorSessionId of crossSessionResult.contributorSessionIds) {
|
|
54095
54340
|
const contributorSession = swarmState.agentSessions.get(contributorSessionId);
|
|
54096
54341
|
if (contributorSession) {
|
|
54342
|
+
if (contributorSession.phaseAgentsDispatched.size > 0) {
|
|
54343
|
+
contributorSession.lastCompletedPhaseAgentsDispatched = new Set(contributorSession.phaseAgentsDispatched);
|
|
54344
|
+
}
|
|
54097
54345
|
contributorSession.phaseAgentsDispatched = new Set;
|
|
54098
54346
|
contributorSession.lastPhaseCompleteTimestamp = now;
|
|
54099
54347
|
contributorSession.lastPhaseCompletePhase = phase;
|
|
@@ -60152,6 +60400,18 @@ function checkReviewerGate(taskId) {
|
|
|
60152
60400
|
if (allIdle) {
|
|
60153
60401
|
console.warn(`[update-task-status] Issue #81 regression detected for task ${taskId}: all ${stateEntries.length} session(s) show idle state. taskWorkflowStates may not be persisting across sessions.`);
|
|
60154
60402
|
}
|
|
60403
|
+
try {
|
|
60404
|
+
const planPath = path47.join(process.cwd(), ".swarm", "plan.json");
|
|
60405
|
+
const planRaw = fs35.readFileSync(planPath, "utf-8");
|
|
60406
|
+
const plan = JSON.parse(planRaw);
|
|
60407
|
+
for (const planPhase of plan.phases ?? []) {
|
|
60408
|
+
for (const task of planPhase.tasks ?? []) {
|
|
60409
|
+
if (task.id === taskId && task.status === "completed") {
|
|
60410
|
+
return { blocked: false, reason: "" };
|
|
60411
|
+
}
|
|
60412
|
+
}
|
|
60413
|
+
}
|
|
60414
|
+
} catch {}
|
|
60155
60415
|
const currentStateStr = stateEntries.length > 0 ? stateEntries.join(", ") : "no active sessions";
|
|
60156
60416
|
return {
|
|
60157
60417
|
blocked: true,
|
|
@@ -60307,6 +60567,13 @@ ${footerLines.join(`
|
|
|
60307
60567
|
}
|
|
60308
60568
|
|
|
60309
60569
|
// src/index.ts
|
|
60570
|
+
function debugTaskLog(hook, ctx, extra) {
|
|
60571
|
+
const activeAgent = swarmState.activeAgent.get(ctx.sessionID);
|
|
60572
|
+
const session = swarmState.agentSessions.get(ctx.sessionID);
|
|
60573
|
+
const taskStates = session?.taskWorkflowStates ? Object.entries(session.taskWorkflowStates) : [];
|
|
60574
|
+
const statesSummary = taskStates.length > 0 ? taskStates.map(([k, v]) => `${k}=${v}`).join(",") : "(none)";
|
|
60575
|
+
console.log(`[swarm-debug-task] ${hook} | session=${ctx.sessionID} callID=${ctx.callID ?? "(n/a)"} agent=${activeAgent ?? "(none)"} taskStates=[${statesSummary}]`, extra ? JSON.stringify(extra) : "");
|
|
60576
|
+
}
|
|
60310
60577
|
var OpenCodeSwarm = async (ctx) => {
|
|
60311
60578
|
const { config: config3, loadedFromFile } = loadPluginConfigWithMeta(ctx.directory);
|
|
60312
60579
|
await loadSnapshot(ctx.directory);
|
|
@@ -60601,6 +60868,10 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
60601
60868
|
"experimental.session.compacting": compactionHook["experimental.session.compacting"],
|
|
60602
60869
|
"command.execute.before": safeHook(commandHandler),
|
|
60603
60870
|
"tool.execute.before": async (input, output) => {
|
|
60871
|
+
debugTaskLog("tool.execute.before", {
|
|
60872
|
+
sessionID: input.sessionID,
|
|
60873
|
+
callID: input.callID
|
|
60874
|
+
}, { tool: input.tool });
|
|
60604
60875
|
if (!swarmState.activeAgent.has(input.sessionID)) {
|
|
60605
60876
|
swarmState.activeAgent.set(input.sessionID, ORCHESTRATOR_NAME);
|
|
60606
60877
|
}
|
|
@@ -60620,6 +60891,10 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
60620
60891
|
await safeHook(activityHooks.toolBefore)(input, output);
|
|
60621
60892
|
},
|
|
60622
60893
|
"tool.execute.after": async (input, output) => {
|
|
60894
|
+
debugTaskLog("tool.execute.after", {
|
|
60895
|
+
sessionID: input.sessionID,
|
|
60896
|
+
callID: input.callID
|
|
60897
|
+
}, { tool: input.tool });
|
|
60623
60898
|
await activityHooks.toolAfter(input, output);
|
|
60624
60899
|
await guardrailsHooks.toolAfter(input, output);
|
|
60625
60900
|
await safeHook(delegationGateHooks.toolAfter)(input, output);
|
|
@@ -60649,6 +60924,9 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
60649
60924
|
}
|
|
60650
60925
|
if (input.tool === "task") {
|
|
60651
60926
|
const sessionId = input.sessionID;
|
|
60927
|
+
const beforeSession = swarmState.agentSessions.get(sessionId);
|
|
60928
|
+
const beforeStates = beforeSession?.taskWorkflowStates ? Object.entries(beforeSession.taskWorkflowStates).map(([k, v]) => `${k}=${v}`).join(",") : "(none)";
|
|
60929
|
+
console.log(`[swarm-debug-task] tool.execute.after.taskHandoff | session=${sessionId} BEFORE: taskStates=[${beforeStates}]`);
|
|
60652
60930
|
swarmState.activeAgent.set(sessionId, ORCHESTRATOR_NAME);
|
|
60653
60931
|
ensureAgentSession(sessionId, ORCHESTRATOR_NAME);
|
|
60654
60932
|
const session = swarmState.agentSessions.get(sessionId);
|
|
@@ -60656,6 +60934,10 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
60656
60934
|
session.delegationActive = false;
|
|
60657
60935
|
session.lastAgentEventTime = Date.now();
|
|
60658
60936
|
}
|
|
60937
|
+
const afterSession = swarmState.agentSessions.get(sessionId);
|
|
60938
|
+
const afterStates = afterSession?.taskWorkflowStates ? Object.entries(afterSession.taskWorkflowStates).map(([k, v]) => `${k}=${v}`).join(",") : "(none)";
|
|
60939
|
+
const afterActive = swarmState.activeAgent.get(sessionId);
|
|
60940
|
+
console.log(`[swarm-debug-task] tool.execute.after.taskHandoff | session=${sessionId} AFTER: activeAgent=${afterActive} delegationActive=${afterSession?.delegationActive} taskStates=[${afterStates}]`);
|
|
60659
60941
|
}
|
|
60660
60942
|
},
|
|
60661
60943
|
"chat.message": safeHook(delegationHandler),
|