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/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/tools/tool-names.ts
38110
- var TOOL_NAMES = [
38111
- "diff",
38112
- "syntax_check",
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
- import { execSync } from "child_process";
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
- function extractTaskLine(text) {
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
- ${text}`;
47405
- }
47406
- }
47407
- {
47408
- const deliberationSessionID = lastUserMessage.info?.sessionID;
47409
- if (deliberationSessionID) {
47410
- if (!/^[a-zA-Z0-9_-]{1,128}$/.test(deliberationSessionID)) {} else {
47411
- const deliberationSession = ensureAgentSession(deliberationSessionID);
47412
- const lastGate = deliberationSession.lastGateOutcome;
47413
- let preamble;
47414
- if (lastGate) {
47415
- const gateResult = lastGate.passed ? "PASSED" : "FAILED";
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 isGateAgentMessage(agentName) {
47535
- const gateAgents = ["reviewer", "test_engineer", "critic", "test-engineer"];
47536
- const normalized = agentName.toLowerCase().replace(/-/g, "_");
47537
- return gateAgents.includes(normalized);
47338
+ function getStoredInputArgs(callID) {
47339
+ debugStoredArgs("get", callID);
47340
+ return storedInputArgs.get(callID);
47538
47341
  }
47539
- function createDelegationSanitizerHook(directory) {
47540
- const hook = async (_input, output) => {
47541
- const messages = output?.messages;
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
- // src/hooks/delegation-tracker.ts
47584
- function createDelegationTrackerHook(config3, guardrailsEnabled = true) {
47585
- return async (input, _output) => {
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
- inputArgsByCallID.set(input.callID, output.args);
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 = inputArgsByCallID.get(input.callID);
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 curatorConfig = CuratorConfigSchema.parse({});
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
- import * as fs16 from "fs";
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 hasActivity = hasRecentToolCalls || hasRecentDelegations;
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),