opencode-swarm 6.0.1 → 6.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -5
- package/dist/agents/designer.d.ts +2 -0
- package/dist/agents/docs.d.ts +2 -0
- package/dist/agents/index.d.ts +2 -0
- package/dist/config/constants.d.ts +2 -2
- package/dist/config/evidence-schema.d.ts +3 -3
- package/dist/config/index.d.ts +3 -3
- package/dist/config/loader.d.ts +10 -5
- package/dist/config/plan-schema.d.ts +4 -4
- package/dist/config/schema.d.ts +20 -1
- package/dist/index.js +564 -167
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/retrieve-summary.d.ts +2 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/merge.d.ts +5 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="https://img.shields.io/badge/version-6.
|
|
2
|
+
<img src="https://img.shields.io/badge/version-6.1.1-blue" alt="Version">
|
|
3
3
|
<img src="https://img.shields.io/badge/license-MIT-green" alt="License">
|
|
4
4
|
<img src="https://img.shields.io/badge/opencode-plugin-purple" alt="OpenCode Plugin">
|
|
5
|
-
<img src="https://img.shields.io/badge/agents-
|
|
6
|
-
<img src="https://img.shields.io/badge/tests-
|
|
5
|
+
<img src="https://img.shields.io/badge/agents-9-orange" alt="Agents">
|
|
6
|
+
<img src="https://img.shields.io/badge/tests-1280-brightgreen" alt="Tests">
|
|
7
7
|
</p>
|
|
8
8
|
|
|
9
9
|
<h1 align="center">🐝 OpenCode Swarm</h1>
|
|
@@ -343,6 +343,17 @@ bunx opencode-swarm uninstall --clean
|
|
|
343
343
|
|
|
344
344
|
## What's New
|
|
345
345
|
|
|
346
|
+
### v6.1.1 — Security Fix & Tech Debt
|
|
347
|
+
- **Security hardening (`_loadedFromFile`)** — Fixed a critical vulnerability where an internal loader flag could be injected via JSON config to bypass guardrails. The flag is now purely internal and no longer part of the public schema.
|
|
348
|
+
- **TOCTOU protection** — Added atomic-style content checks in the config loader to prevent race conditions during file reads.
|
|
349
|
+
- **`retrieve_summary` tool** — Properly registered the retrieval tool, allowing agents to fetch full content from auto-summarized tool outputs.
|
|
350
|
+
- **92 new tests** — 1280 total tests across 57+ files (up from 1188 in v6.0.0).
|
|
351
|
+
|
|
352
|
+
### v6.1.0 — Docs & Design Agents
|
|
353
|
+
- **`docs` agent** — Dedicated documentation synthesizer that automatically updates READMEs, API docs, and guides during Phase 6.
|
|
354
|
+
- **`designer` agent** — UI/UX specification agent that generates component scaffolds before coding begins on UI-heavy tasks.
|
|
355
|
+
- **Heterogeneous model defaults** — Updated default models for new agents to use optimized Gemini models for speed and cost.
|
|
356
|
+
|
|
346
357
|
### v6.0.0 — Core QA & Security Gates
|
|
347
358
|
- **Dual-pass security reviewer** — After the general reviewer APPROVES, the architect automatically triggers a second security-only review pass when the changed file matches security-sensitive paths (`auth`, `crypto`, `session`, `token`, `middleware`, `api`, `security`) or the coder's output contains security keywords. Configurable via `review_passes` config.
|
|
348
359
|
- **Adversarial testing** — After verification tests PASS, the test engineer is re-delegated with adversarial-only framing: attack vectors, boundary violations, and injection attempts. Pure prompt engineering, no new infrastructure.
|
|
@@ -411,6 +422,11 @@ All features are opt-in via configuration. See [Installation Guide](docs/install
|
|
|
411
422
|
|-------|------|
|
|
412
423
|
| `explorer` | Fast codebase scanner. Identifies structure, languages, frameworks, key files. |
|
|
413
424
|
|
|
425
|
+
### 🎨 Design
|
|
426
|
+
| Agent | Role |
|
|
427
|
+
|-------|------|
|
|
428
|
+
| `designer` | UI/UX specification agent. Generates component scaffolds and design tokens before coding begins on UI-heavy tasks. |
|
|
429
|
+
|
|
414
430
|
### 🧠 Domain Expert
|
|
415
431
|
| Agent | Role |
|
|
416
432
|
|-------|------|
|
|
@@ -428,6 +444,11 @@ All features are opt-in via configuration. See [Installation Guide](docs/install
|
|
|
428
444
|
| `reviewer` | Dual-pass review: correctness review first, then automatic security-only pass for security-sensitive files. The architect specifies CHECK dimensions per call. OWASP Top 10 categories built in. |
|
|
429
445
|
| `critic` | Plan review gate. Reviews the architect's plan BEFORE implementation — checks completeness, feasibility, scope, dependencies, and flags AI-slop. |
|
|
430
446
|
|
|
447
|
+
### 📝 Documentation
|
|
448
|
+
| Agent | Role |
|
|
449
|
+
|-------|------|
|
|
450
|
+
| `docs` | Documentation synthesizer. Automatically updates READMEs, API docs, and guides based on implementation changes during Phase 6. |
|
|
451
|
+
|
|
431
452
|
---
|
|
432
453
|
|
|
433
454
|
## Slash Commands
|
|
@@ -462,7 +483,9 @@ Create `~/.config/opencode/opencode-swarm.json`:
|
|
|
462
483
|
"sme": { "model": "google/gemini-2.0-flash" },
|
|
463
484
|
"reviewer": { "model": "openai/gpt-4o" },
|
|
464
485
|
"critic": { "model": "google/gemini-2.0-flash" },
|
|
465
|
-
"test_engineer": { "model": "google/gemini-2.0-flash" }
|
|
486
|
+
"test_engineer": { "model": "google/gemini-2.0-flash" },
|
|
487
|
+
"docs": { "model": "google/gemini-2.0-flash" },
|
|
488
|
+
"designer": { "model": "google/gemini-2.0-flash" }
|
|
466
489
|
}
|
|
467
490
|
}
|
|
468
491
|
```
|
|
@@ -630,7 +653,7 @@ bun test
|
|
|
630
653
|
bun test tests/unit/config/schema.test.ts
|
|
631
654
|
```
|
|
632
655
|
|
|
633
|
-
|
|
656
|
+
1280 tests across 57+ files covering config, tools, agents, hooks, commands, state, guardrails, evidence, plan schemas, circuit breaker race conditions, invocation windows, multi-invocation isolation, security categories, review/integration schemas, and diff tool. Uses Bun's built-in test runner — zero additional test dependencies.
|
|
634
657
|
|
|
635
658
|
## Troubleshooting
|
|
636
659
|
|
package/dist/agents/index.d.ts
CHANGED
|
@@ -19,6 +19,8 @@ export declare function getAgentConfigs(config?: PluginConfig): Record<string, S
|
|
|
19
19
|
export { createArchitectAgent } from './architect';
|
|
20
20
|
export { createCoderAgent } from './coder';
|
|
21
21
|
export { createCriticAgent } from './critic';
|
|
22
|
+
export { createDesignerAgent } from './designer';
|
|
23
|
+
export { createDocsAgent } from './docs';
|
|
22
24
|
export { createExplorerAgent } from './explorer';
|
|
23
25
|
export { createReviewerAgent, SECURITY_CATEGORIES, type SecurityCategory, } from './reviewer';
|
|
24
26
|
export { createSMEAgent } from './sme';
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export declare const QA_AGENTS: readonly ["reviewer", "critic"];
|
|
2
2
|
export declare const PIPELINE_AGENTS: readonly ["explorer", "coder", "test_engineer"];
|
|
3
3
|
export declare const ORCHESTRATOR_NAME: "architect";
|
|
4
|
-
export declare const ALL_SUBAGENT_NAMES: readonly ["sme", "reviewer", "critic", "explorer", "coder", "test_engineer"];
|
|
5
|
-
export declare const ALL_AGENT_NAMES: readonly ["architect", "sme", "reviewer", "critic", "explorer", "coder", "test_engineer"];
|
|
4
|
+
export declare const ALL_SUBAGENT_NAMES: readonly ["sme", "docs", "designer", "reviewer", "critic", "explorer", "coder", "test_engineer"];
|
|
5
|
+
export declare const ALL_AGENT_NAMES: readonly ["architect", "sme", "docs", "designer", "reviewer", "critic", "explorer", "coder", "test_engineer"];
|
|
6
6
|
export type QAAgentName = (typeof QA_AGENTS)[number];
|
|
7
7
|
export type PipelineAgentName = (typeof PIPELINE_AGENTS)[number];
|
|
8
8
|
export type AgentName = (typeof ALL_AGENT_NAMES)[number];
|
|
@@ -55,8 +55,8 @@ export declare const ReviewEvidenceSchema: z.ZodObject<{
|
|
|
55
55
|
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
56
56
|
type: z.ZodLiteral<"review">;
|
|
57
57
|
risk: z.ZodEnum<{
|
|
58
|
-
medium: "medium";
|
|
59
58
|
low: "low";
|
|
59
|
+
medium: "medium";
|
|
60
60
|
high: "high";
|
|
61
61
|
critical: "critical";
|
|
62
62
|
}>;
|
|
@@ -162,8 +162,8 @@ export declare const EvidenceSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
162
162
|
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
163
163
|
type: z.ZodLiteral<"review">;
|
|
164
164
|
risk: z.ZodEnum<{
|
|
165
|
-
medium: "medium";
|
|
166
165
|
low: "low";
|
|
166
|
+
medium: "medium";
|
|
167
167
|
high: "high";
|
|
168
168
|
critical: "critical";
|
|
169
169
|
}>;
|
|
@@ -264,8 +264,8 @@ export declare const EvidenceBundleSchema: z.ZodObject<{
|
|
|
264
264
|
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
265
265
|
type: z.ZodLiteral<"review">;
|
|
266
266
|
risk: z.ZodEnum<{
|
|
267
|
-
medium: "medium";
|
|
268
267
|
low: "low";
|
|
268
|
+
medium: "medium";
|
|
269
269
|
high: "high";
|
|
270
270
|
critical: "critical";
|
|
271
271
|
}>;
|
package/dist/config/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export type { AgentName, PipelineAgentName, QAAgentName, } from './constants';
|
|
2
2
|
export { ALL_AGENT_NAMES, ALL_SUBAGENT_NAMES, DEFAULT_MODELS, isQAAgent, isSubagent, ORCHESTRATOR_NAME, PIPELINE_AGENTS, QA_AGENTS, } from './constants';
|
|
3
|
-
export { loadAgentPrompt, loadPluginConfig, } from './loader';
|
|
4
|
-
export type { MigrationStatus, Phase, PhaseStatus, Plan, Task, TaskSize, TaskStatus, } from './plan-schema';
|
|
5
|
-
export { MigrationStatusSchema, PhaseSchema, PhaseStatusSchema, PlanSchema, TaskSchema, TaskSizeSchema, TaskStatusSchema, } from './plan-schema';
|
|
6
3
|
export type { ApprovalEvidence, BaseEvidence, DiffEvidence, Evidence, EvidenceBundle, EvidenceType, EvidenceVerdict, NoteEvidence, ReviewEvidence, TestEvidence, } from './evidence-schema';
|
|
7
4
|
export { ApprovalEvidenceSchema, BaseEvidenceSchema, DiffEvidenceSchema, EVIDENCE_MAX_JSON_BYTES, EVIDENCE_MAX_PATCH_BYTES, EVIDENCE_MAX_TASK_BYTES, EvidenceBundleSchema, EvidenceSchema, EvidenceTypeSchema, EvidenceVerdictSchema, NoteEvidenceSchema, ReviewEvidenceSchema, TestEvidenceSchema, } from './evidence-schema';
|
|
5
|
+
export { loadAgentPrompt, loadPluginConfig, loadPluginConfigWithMeta, } from './loader';
|
|
6
|
+
export type { MigrationStatus, Phase, PhaseStatus, Plan, Task, TaskSize, TaskStatus, } from './plan-schema';
|
|
7
|
+
export { MigrationStatusSchema, PhaseSchema, PhaseStatusSchema, PlanSchema, TaskSchema, TaskSizeSchema, TaskStatusSchema, } from './plan-schema';
|
|
8
8
|
export type { AgentOverrideConfig, PluginConfig, SwarmConfig, } from './schema';
|
|
9
9
|
export { AgentOverrideConfigSchema, PluginConfigSchema, SwarmConfigSchema, } from './schema';
|
package/dist/config/loader.d.ts
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { type PluginConfig } from './schema';
|
|
2
2
|
export declare const MAX_CONFIG_FILE_BYTES = 102400;
|
|
3
|
-
export
|
|
4
|
-
/**
|
|
5
|
-
* Deep merge two objects, with override values taking precedence.
|
|
6
|
-
*/
|
|
7
|
-
export declare function deepMerge<T extends Record<string, unknown>>(base?: T, override?: T): T | undefined;
|
|
3
|
+
export { deepMerge, MAX_MERGE_DEPTH } from '../utils/merge';
|
|
8
4
|
/**
|
|
9
5
|
* Load plugin configuration from user and project config files.
|
|
10
6
|
*
|
|
@@ -17,6 +13,15 @@ export declare function deepMerge<T extends Record<string, unknown>>(base?: T, o
|
|
|
17
13
|
* Zod defaults don't override explicit user values.
|
|
18
14
|
*/
|
|
19
15
|
export declare function loadPluginConfig(directory: string): PluginConfig;
|
|
16
|
+
/**
|
|
17
|
+
* Internal variant of loadPluginConfig that also returns loader metadata.
|
|
18
|
+
* Used only by src/index.ts to determine guardrails fallback behavior.
|
|
19
|
+
* NOT part of the public API — use loadPluginConfig() for all other callers.
|
|
20
|
+
*/
|
|
21
|
+
export declare function loadPluginConfigWithMeta(directory: string): {
|
|
22
|
+
config: PluginConfig;
|
|
23
|
+
loadedFromFile: boolean;
|
|
24
|
+
};
|
|
20
25
|
/**
|
|
21
26
|
* Load custom prompt for an agent from the prompts directory.
|
|
22
27
|
* Checks for {agent}.md (replaces default) and {agent}_append.md (appends).
|
|
@@ -7,8 +7,8 @@ export declare const TaskStatusSchema: z.ZodEnum<{
|
|
|
7
7
|
}>;
|
|
8
8
|
export type TaskStatus = z.infer<typeof TaskStatusSchema>;
|
|
9
9
|
export declare const TaskSizeSchema: z.ZodEnum<{
|
|
10
|
-
small: "small";
|
|
11
10
|
medium: "medium";
|
|
11
|
+
small: "small";
|
|
12
12
|
large: "large";
|
|
13
13
|
}>;
|
|
14
14
|
export type TaskSize = z.infer<typeof TaskSizeSchema>;
|
|
@@ -35,8 +35,8 @@ export declare const TaskSchema: z.ZodObject<{
|
|
|
35
35
|
blocked: "blocked";
|
|
36
36
|
}>>;
|
|
37
37
|
size: z.ZodDefault<z.ZodEnum<{
|
|
38
|
-
small: "small";
|
|
39
38
|
medium: "medium";
|
|
39
|
+
small: "small";
|
|
40
40
|
large: "large";
|
|
41
41
|
}>>;
|
|
42
42
|
description: z.ZodString;
|
|
@@ -66,8 +66,8 @@ export declare const PhaseSchema: z.ZodObject<{
|
|
|
66
66
|
blocked: "blocked";
|
|
67
67
|
}>>;
|
|
68
68
|
size: z.ZodDefault<z.ZodEnum<{
|
|
69
|
-
small: "small";
|
|
70
69
|
medium: "medium";
|
|
70
|
+
small: "small";
|
|
71
71
|
large: "large";
|
|
72
72
|
}>>;
|
|
73
73
|
description: z.ZodString;
|
|
@@ -103,8 +103,8 @@ export declare const PlanSchema: z.ZodObject<{
|
|
|
103
103
|
blocked: "blocked";
|
|
104
104
|
}>>;
|
|
105
105
|
size: z.ZodDefault<z.ZodEnum<{
|
|
106
|
-
small: "small";
|
|
107
106
|
medium: "medium";
|
|
107
|
+
small: "small";
|
|
108
108
|
large: "large";
|
|
109
109
|
}>>;
|
|
110
110
|
description: z.ZodString;
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -137,6 +137,17 @@ export declare const IntegrationAnalysisConfigSchema: z.ZodObject<{
|
|
|
137
137
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
138
138
|
}, z.core.$strip>;
|
|
139
139
|
export type IntegrationAnalysisConfig = z.infer<typeof IntegrationAnalysisConfigSchema>;
|
|
140
|
+
export declare const DocsConfigSchema: z.ZodObject<{
|
|
141
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
142
|
+
doc_patterns: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
143
|
+
}, z.core.$strip>;
|
|
144
|
+
export type DocsConfig = z.infer<typeof DocsConfigSchema>;
|
|
145
|
+
export declare const UIReviewConfigSchema: z.ZodObject<{
|
|
146
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
147
|
+
trigger_paths: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
148
|
+
trigger_keywords: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
149
|
+
}, z.core.$strip>;
|
|
150
|
+
export type UIReviewConfig = z.infer<typeof UIReviewConfigSchema>;
|
|
140
151
|
export declare const GuardrailsProfileSchema: z.ZodObject<{
|
|
141
152
|
max_tool_calls: z.ZodOptional<z.ZodNumber>;
|
|
142
153
|
max_duration_minutes: z.ZodOptional<z.ZodNumber>;
|
|
@@ -298,7 +309,15 @@ export declare const PluginConfigSchema: z.ZodObject<{
|
|
|
298
309
|
integration_analysis: z.ZodOptional<z.ZodObject<{
|
|
299
310
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
300
311
|
}, z.core.$strip>>;
|
|
301
|
-
|
|
312
|
+
docs: z.ZodOptional<z.ZodObject<{
|
|
313
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
314
|
+
doc_patterns: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
315
|
+
}, z.core.$strip>>;
|
|
316
|
+
ui_review: z.ZodOptional<z.ZodObject<{
|
|
317
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
318
|
+
trigger_paths: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
319
|
+
trigger_keywords: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
320
|
+
}, z.core.$strip>>;
|
|
302
321
|
}, z.core.$strip>;
|
|
303
322
|
export type PluginConfig = z.infer<typeof PluginConfigSchema>;
|
|
304
323
|
export type { AgentName, PipelineAgentName, QAAgentName, } from './constants';
|
package/dist/index.js
CHANGED
|
@@ -26,11 +26,83 @@ var __export = (target, all) => {
|
|
|
26
26
|
};
|
|
27
27
|
var __require = import.meta.require;
|
|
28
28
|
|
|
29
|
-
// src/
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
// src/utils/merge.ts
|
|
30
|
+
var MAX_MERGE_DEPTH = 10;
|
|
31
|
+
function deepMergeInternal(base, override, depth) {
|
|
32
|
+
if (depth >= MAX_MERGE_DEPTH) {
|
|
33
|
+
throw new Error(`deepMerge exceeded maximum depth of ${MAX_MERGE_DEPTH}`);
|
|
34
|
+
}
|
|
35
|
+
const result = { ...base };
|
|
36
|
+
for (const key of Object.keys(override)) {
|
|
37
|
+
const baseVal = base[key];
|
|
38
|
+
const overrideVal = override[key];
|
|
39
|
+
if (typeof baseVal === "object" && baseVal !== null && typeof overrideVal === "object" && overrideVal !== null && !Array.isArray(baseVal) && !Array.isArray(overrideVal)) {
|
|
40
|
+
result[key] = deepMergeInternal(baseVal, overrideVal, depth + 1);
|
|
41
|
+
} else {
|
|
42
|
+
result[key] = overrideVal;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
function deepMerge(base, override) {
|
|
48
|
+
if (!base)
|
|
49
|
+
return override;
|
|
50
|
+
if (!override)
|
|
51
|
+
return base;
|
|
52
|
+
return deepMergeInternal(base, override, 0);
|
|
53
|
+
}
|
|
33
54
|
|
|
55
|
+
// src/config/constants.ts
|
|
56
|
+
var QA_AGENTS = ["reviewer", "critic"];
|
|
57
|
+
var PIPELINE_AGENTS = ["explorer", "coder", "test_engineer"];
|
|
58
|
+
var ORCHESTRATOR_NAME = "architect";
|
|
59
|
+
var ALL_SUBAGENT_NAMES = [
|
|
60
|
+
"sme",
|
|
61
|
+
"docs",
|
|
62
|
+
"designer",
|
|
63
|
+
...QA_AGENTS,
|
|
64
|
+
...PIPELINE_AGENTS
|
|
65
|
+
];
|
|
66
|
+
var ALL_AGENT_NAMES = [
|
|
67
|
+
ORCHESTRATOR_NAME,
|
|
68
|
+
...ALL_SUBAGENT_NAMES
|
|
69
|
+
];
|
|
70
|
+
var DEFAULT_MODELS = {
|
|
71
|
+
architect: "anthropic/claude-sonnet-4-5",
|
|
72
|
+
explorer: "google/gemini-2.0-flash",
|
|
73
|
+
coder: "anthropic/claude-sonnet-4-5",
|
|
74
|
+
test_engineer: "google/gemini-2.0-flash",
|
|
75
|
+
sme: "google/gemini-2.0-flash",
|
|
76
|
+
reviewer: "google/gemini-2.0-flash",
|
|
77
|
+
critic: "google/gemini-2.0-flash",
|
|
78
|
+
docs: "google/gemini-2.0-flash",
|
|
79
|
+
designer: "google/gemini-2.0-flash",
|
|
80
|
+
default: "google/gemini-2.0-flash"
|
|
81
|
+
};
|
|
82
|
+
var DEFAULT_SCORING_CONFIG = {
|
|
83
|
+
enabled: false,
|
|
84
|
+
max_candidates: 100,
|
|
85
|
+
weights: {
|
|
86
|
+
phase: 1,
|
|
87
|
+
current_task: 2,
|
|
88
|
+
blocked_task: 1.5,
|
|
89
|
+
recent_failure: 2.5,
|
|
90
|
+
recent_success: 0.5,
|
|
91
|
+
evidence_presence: 1,
|
|
92
|
+
decision_recency: 1.5,
|
|
93
|
+
dependency_proximity: 1
|
|
94
|
+
},
|
|
95
|
+
decision_decay: {
|
|
96
|
+
mode: "exponential",
|
|
97
|
+
half_life_hours: 24
|
|
98
|
+
},
|
|
99
|
+
token_ratios: {
|
|
100
|
+
prose: 0.25,
|
|
101
|
+
code: 0.4,
|
|
102
|
+
markdown: 0.3,
|
|
103
|
+
json: 0.35
|
|
104
|
+
}
|
|
105
|
+
};
|
|
34
106
|
// node_modules/zod/v4/classic/external.js
|
|
35
107
|
var exports_external = {};
|
|
36
108
|
__export(exports_external, {
|
|
@@ -13563,6 +13635,85 @@ function date4(params) {
|
|
|
13563
13635
|
|
|
13564
13636
|
// node_modules/zod/v4/classic/external.js
|
|
13565
13637
|
config(en_default());
|
|
13638
|
+
// src/config/evidence-schema.ts
|
|
13639
|
+
var EVIDENCE_MAX_JSON_BYTES = 500 * 1024;
|
|
13640
|
+
var EVIDENCE_MAX_PATCH_BYTES = 5 * 1024 * 1024;
|
|
13641
|
+
var EVIDENCE_MAX_TASK_BYTES = 20 * 1024 * 1024;
|
|
13642
|
+
var EvidenceTypeSchema = exports_external.enum([
|
|
13643
|
+
"review",
|
|
13644
|
+
"test",
|
|
13645
|
+
"diff",
|
|
13646
|
+
"approval",
|
|
13647
|
+
"note"
|
|
13648
|
+
]);
|
|
13649
|
+
var EvidenceVerdictSchema = exports_external.enum([
|
|
13650
|
+
"pass",
|
|
13651
|
+
"fail",
|
|
13652
|
+
"approved",
|
|
13653
|
+
"rejected",
|
|
13654
|
+
"info"
|
|
13655
|
+
]);
|
|
13656
|
+
var BaseEvidenceSchema = exports_external.object({
|
|
13657
|
+
task_id: exports_external.string().min(1),
|
|
13658
|
+
type: EvidenceTypeSchema,
|
|
13659
|
+
timestamp: exports_external.string().datetime(),
|
|
13660
|
+
agent: exports_external.string().min(1),
|
|
13661
|
+
verdict: EvidenceVerdictSchema,
|
|
13662
|
+
summary: exports_external.string().min(1),
|
|
13663
|
+
metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
13664
|
+
});
|
|
13665
|
+
var ReviewEvidenceSchema = BaseEvidenceSchema.extend({
|
|
13666
|
+
type: exports_external.literal("review"),
|
|
13667
|
+
risk: exports_external.enum(["low", "medium", "high", "critical"]),
|
|
13668
|
+
issues: exports_external.array(exports_external.object({
|
|
13669
|
+
severity: exports_external.enum(["error", "warning", "info"]),
|
|
13670
|
+
message: exports_external.string().min(1),
|
|
13671
|
+
file: exports_external.string().optional(),
|
|
13672
|
+
line: exports_external.number().int().optional()
|
|
13673
|
+
})).default([])
|
|
13674
|
+
});
|
|
13675
|
+
var TestEvidenceSchema = BaseEvidenceSchema.extend({
|
|
13676
|
+
type: exports_external.literal("test"),
|
|
13677
|
+
tests_passed: exports_external.number().int().min(0),
|
|
13678
|
+
tests_failed: exports_external.number().int().min(0),
|
|
13679
|
+
test_file: exports_external.string().optional(),
|
|
13680
|
+
failures: exports_external.array(exports_external.object({
|
|
13681
|
+
name: exports_external.string().min(1),
|
|
13682
|
+
message: exports_external.string().min(1)
|
|
13683
|
+
})).default([])
|
|
13684
|
+
});
|
|
13685
|
+
var DiffEvidenceSchema = BaseEvidenceSchema.extend({
|
|
13686
|
+
type: exports_external.literal("diff"),
|
|
13687
|
+
files_changed: exports_external.array(exports_external.string()).default([]),
|
|
13688
|
+
additions: exports_external.number().int().min(0).default(0),
|
|
13689
|
+
deletions: exports_external.number().int().min(0).default(0),
|
|
13690
|
+
patch_path: exports_external.string().optional()
|
|
13691
|
+
});
|
|
13692
|
+
var ApprovalEvidenceSchema = BaseEvidenceSchema.extend({
|
|
13693
|
+
type: exports_external.literal("approval")
|
|
13694
|
+
});
|
|
13695
|
+
var NoteEvidenceSchema = BaseEvidenceSchema.extend({
|
|
13696
|
+
type: exports_external.literal("note")
|
|
13697
|
+
});
|
|
13698
|
+
var EvidenceSchema = exports_external.discriminatedUnion("type", [
|
|
13699
|
+
ReviewEvidenceSchema,
|
|
13700
|
+
TestEvidenceSchema,
|
|
13701
|
+
DiffEvidenceSchema,
|
|
13702
|
+
ApprovalEvidenceSchema,
|
|
13703
|
+
NoteEvidenceSchema
|
|
13704
|
+
]);
|
|
13705
|
+
var EvidenceBundleSchema = exports_external.object({
|
|
13706
|
+
schema_version: exports_external.literal("1.0.0"),
|
|
13707
|
+
task_id: exports_external.string().min(1),
|
|
13708
|
+
entries: exports_external.array(EvidenceSchema).default([]),
|
|
13709
|
+
created_at: exports_external.string().datetime(),
|
|
13710
|
+
updated_at: exports_external.string().datetime()
|
|
13711
|
+
});
|
|
13712
|
+
// src/config/loader.ts
|
|
13713
|
+
import * as fs from "fs";
|
|
13714
|
+
import * as os from "os";
|
|
13715
|
+
import * as path from "path";
|
|
13716
|
+
|
|
13566
13717
|
// src/config/schema.ts
|
|
13567
13718
|
var AgentOverrideConfigSchema = exports_external.object({
|
|
13568
13719
|
model: exports_external.string().optional(),
|
|
@@ -13645,6 +13796,46 @@ var ReviewPassesConfigSchema = exports_external.object({
|
|
|
13645
13796
|
var IntegrationAnalysisConfigSchema = exports_external.object({
|
|
13646
13797
|
enabled: exports_external.boolean().default(true)
|
|
13647
13798
|
});
|
|
13799
|
+
var DocsConfigSchema = exports_external.object({
|
|
13800
|
+
enabled: exports_external.boolean().default(true),
|
|
13801
|
+
doc_patterns: exports_external.array(exports_external.string()).default([
|
|
13802
|
+
"README.md",
|
|
13803
|
+
"CONTRIBUTING.md",
|
|
13804
|
+
"docs/**/*.md",
|
|
13805
|
+
"docs/**/*.rst",
|
|
13806
|
+
"**/CHANGELOG.md"
|
|
13807
|
+
])
|
|
13808
|
+
});
|
|
13809
|
+
var UIReviewConfigSchema = exports_external.object({
|
|
13810
|
+
enabled: exports_external.boolean().default(false),
|
|
13811
|
+
trigger_paths: exports_external.array(exports_external.string()).default([
|
|
13812
|
+
"**/pages/**",
|
|
13813
|
+
"**/components/**",
|
|
13814
|
+
"**/views/**",
|
|
13815
|
+
"**/screens/**",
|
|
13816
|
+
"**/ui/**",
|
|
13817
|
+
"**/layouts/**"
|
|
13818
|
+
]),
|
|
13819
|
+
trigger_keywords: exports_external.array(exports_external.string()).default([
|
|
13820
|
+
"new page",
|
|
13821
|
+
"new screen",
|
|
13822
|
+
"new component",
|
|
13823
|
+
"redesign",
|
|
13824
|
+
"layout change",
|
|
13825
|
+
"form",
|
|
13826
|
+
"modal",
|
|
13827
|
+
"dialog",
|
|
13828
|
+
"dropdown",
|
|
13829
|
+
"sidebar",
|
|
13830
|
+
"navbar",
|
|
13831
|
+
"dashboard",
|
|
13832
|
+
"landing page",
|
|
13833
|
+
"signup",
|
|
13834
|
+
"login form",
|
|
13835
|
+
"settings page",
|
|
13836
|
+
"profile page"
|
|
13837
|
+
])
|
|
13838
|
+
});
|
|
13648
13839
|
var GuardrailsProfileSchema = exports_external.object({
|
|
13649
13840
|
max_tool_calls: exports_external.number().min(0).max(1000).optional(),
|
|
13650
13841
|
max_duration_minutes: exports_external.number().min(0).max(480).optional(),
|
|
@@ -13689,6 +13880,16 @@ var DEFAULT_AGENT_PROFILES = {
|
|
|
13689
13880
|
max_tool_calls: 200,
|
|
13690
13881
|
max_duration_minutes: 30,
|
|
13691
13882
|
warning_threshold: 0.65
|
|
13883
|
+
},
|
|
13884
|
+
docs: {
|
|
13885
|
+
max_tool_calls: 200,
|
|
13886
|
+
max_duration_minutes: 30,
|
|
13887
|
+
warning_threshold: 0.75
|
|
13888
|
+
},
|
|
13889
|
+
designer: {
|
|
13890
|
+
max_tool_calls: 150,
|
|
13891
|
+
max_duration_minutes: 20,
|
|
13892
|
+
warning_threshold: 0.75
|
|
13692
13893
|
}
|
|
13693
13894
|
};
|
|
13694
13895
|
var DEFAULT_ARCHITECT_PROFILE = DEFAULT_AGENT_PROFILES.architect;
|
|
@@ -13747,7 +13948,8 @@ var PluginConfigSchema = exports_external.object({
|
|
|
13747
13948
|
summaries: SummaryConfigSchema.optional(),
|
|
13748
13949
|
review_passes: ReviewPassesConfigSchema.optional(),
|
|
13749
13950
|
integration_analysis: IntegrationAnalysisConfigSchema.optional(),
|
|
13750
|
-
|
|
13951
|
+
docs: DocsConfigSchema.optional(),
|
|
13952
|
+
ui_review: UIReviewConfigSchema.optional()
|
|
13751
13953
|
});
|
|
13752
13954
|
|
|
13753
13955
|
// src/config/loader.ts
|
|
@@ -13766,6 +13968,11 @@ function loadRawConfigFromPath(configPath) {
|
|
|
13766
13968
|
return null;
|
|
13767
13969
|
}
|
|
13768
13970
|
const content = fs.readFileSync(configPath, "utf-8");
|
|
13971
|
+
if (content.length > MAX_CONFIG_FILE_BYTES) {
|
|
13972
|
+
console.warn(`[opencode-swarm] Config file too large after read (max 100 KB): ${configPath}`);
|
|
13973
|
+
console.warn("[opencode-swarm] \u26A0\uFE0F Guardrails will be DISABLED as a safety precaution. Fix the config file to restore normal operation.");
|
|
13974
|
+
return null;
|
|
13975
|
+
}
|
|
13769
13976
|
const rawConfig = JSON.parse(content);
|
|
13770
13977
|
if (typeof rawConfig !== "object" || rawConfig === null || Array.isArray(rawConfig)) {
|
|
13771
13978
|
console.warn(`[opencode-swarm] Invalid config at ${configPath}: expected an object`);
|
|
@@ -13781,23 +13988,6 @@ function loadRawConfigFromPath(configPath) {
|
|
|
13781
13988
|
return null;
|
|
13782
13989
|
}
|
|
13783
13990
|
}
|
|
13784
|
-
var MAX_MERGE_DEPTH = 10;
|
|
13785
|
-
function deepMergeInternal(base, override, depth) {
|
|
13786
|
-
if (depth >= MAX_MERGE_DEPTH) {
|
|
13787
|
-
throw new Error(`deepMerge exceeded maximum depth of ${MAX_MERGE_DEPTH}`);
|
|
13788
|
-
}
|
|
13789
|
-
const result = { ...base };
|
|
13790
|
-
for (const key of Object.keys(override)) {
|
|
13791
|
-
const baseVal = base[key];
|
|
13792
|
-
const overrideVal = override[key];
|
|
13793
|
-
if (typeof baseVal === "object" && baseVal !== null && typeof overrideVal === "object" && overrideVal !== null && !Array.isArray(baseVal) && !Array.isArray(overrideVal)) {
|
|
13794
|
-
result[key] = deepMergeInternal(baseVal, overrideVal, depth + 1);
|
|
13795
|
-
} else {
|
|
13796
|
-
result[key] = overrideVal;
|
|
13797
|
-
}
|
|
13798
|
-
}
|
|
13799
|
-
return result;
|
|
13800
|
-
}
|
|
13801
13991
|
function loadPluginConfig(directory) {
|
|
13802
13992
|
const userConfigPath = path.join(getUserConfigDir(), "opencode", CONFIG_FILENAME);
|
|
13803
13993
|
const projectConfigPath = path.join(directory, ".opencode", CONFIG_FILENAME);
|
|
@@ -13806,7 +13996,7 @@ function loadPluginConfig(directory) {
|
|
|
13806
13996
|
const loadedFromFile = rawUserConfig !== null || rawProjectConfig !== null;
|
|
13807
13997
|
let mergedRaw = rawUserConfig ?? {};
|
|
13808
13998
|
if (rawProjectConfig) {
|
|
13809
|
-
mergedRaw =
|
|
13999
|
+
mergedRaw = deepMerge(mergedRaw, rawProjectConfig);
|
|
13810
14000
|
}
|
|
13811
14001
|
const result = PluginConfigSchema.safeParse(mergedRaw);
|
|
13812
14002
|
if (!result.success) {
|
|
@@ -13814,20 +14004,24 @@ function loadPluginConfig(directory) {
|
|
|
13814
14004
|
const userResult = PluginConfigSchema.safeParse(rawUserConfig);
|
|
13815
14005
|
if (userResult.success) {
|
|
13816
14006
|
console.warn("[opencode-swarm] Project config ignored due to validation errors. Using user config.");
|
|
13817
|
-
return
|
|
14007
|
+
return userResult.data;
|
|
13818
14008
|
}
|
|
13819
14009
|
}
|
|
13820
14010
|
console.warn("[opencode-swarm] Merged config validation failed:");
|
|
13821
14011
|
console.warn(result.error.format());
|
|
13822
14012
|
console.warn("[opencode-swarm] \u26A0\uFE0F Guardrails will be DISABLED as a safety precaution. Fix the config file to restore normal operation.");
|
|
13823
|
-
return {
|
|
13824
|
-
max_iterations: 5,
|
|
13825
|
-
qa_retry_limit: 3,
|
|
13826
|
-
inject_phase_reminders: true,
|
|
13827
|
-
_loadedFromFile: false
|
|
13828
|
-
};
|
|
14013
|
+
return PluginConfigSchema.parse({});
|
|
13829
14014
|
}
|
|
13830
|
-
return
|
|
14015
|
+
return result.data;
|
|
14016
|
+
}
|
|
14017
|
+
function loadPluginConfigWithMeta(directory) {
|
|
14018
|
+
const userConfigPath = path.join(getUserConfigDir(), "opencode", CONFIG_FILENAME);
|
|
14019
|
+
const projectConfigPath = path.join(directory, ".opencode", CONFIG_FILENAME);
|
|
14020
|
+
const rawUserConfig = loadRawConfigFromPath(userConfigPath);
|
|
14021
|
+
const rawProjectConfig = loadRawConfigFromPath(projectConfigPath);
|
|
14022
|
+
const loadedFromFile = rawUserConfig !== null || rawProjectConfig !== null;
|
|
14023
|
+
const config2 = loadPluginConfig(directory);
|
|
14024
|
+
return { config: config2, loadedFromFile };
|
|
13831
14025
|
}
|
|
13832
14026
|
function loadAgentPrompt(agentName) {
|
|
13833
14027
|
const promptsDir = path.join(getUserConfigDir(), "opencode", PROMPTS_DIR_NAME);
|
|
@@ -13850,54 +14044,6 @@ function loadAgentPrompt(agentName) {
|
|
|
13850
14044
|
}
|
|
13851
14045
|
return result;
|
|
13852
14046
|
}
|
|
13853
|
-
|
|
13854
|
-
// src/config/constants.ts
|
|
13855
|
-
var QA_AGENTS = ["reviewer", "critic"];
|
|
13856
|
-
var PIPELINE_AGENTS = ["explorer", "coder", "test_engineer"];
|
|
13857
|
-
var ORCHESTRATOR_NAME = "architect";
|
|
13858
|
-
var ALL_SUBAGENT_NAMES = [
|
|
13859
|
-
"sme",
|
|
13860
|
-
...QA_AGENTS,
|
|
13861
|
-
...PIPELINE_AGENTS
|
|
13862
|
-
];
|
|
13863
|
-
var ALL_AGENT_NAMES = [
|
|
13864
|
-
ORCHESTRATOR_NAME,
|
|
13865
|
-
...ALL_SUBAGENT_NAMES
|
|
13866
|
-
];
|
|
13867
|
-
var DEFAULT_MODELS = {
|
|
13868
|
-
architect: "anthropic/claude-sonnet-4-5",
|
|
13869
|
-
explorer: "google/gemini-2.0-flash",
|
|
13870
|
-
coder: "anthropic/claude-sonnet-4-5",
|
|
13871
|
-
test_engineer: "google/gemini-2.0-flash",
|
|
13872
|
-
sme: "google/gemini-2.0-flash",
|
|
13873
|
-
reviewer: "google/gemini-2.0-flash",
|
|
13874
|
-
critic: "google/gemini-2.0-flash",
|
|
13875
|
-
default: "google/gemini-2.0-flash"
|
|
13876
|
-
};
|
|
13877
|
-
var DEFAULT_SCORING_CONFIG = {
|
|
13878
|
-
enabled: false,
|
|
13879
|
-
max_candidates: 100,
|
|
13880
|
-
weights: {
|
|
13881
|
-
phase: 1,
|
|
13882
|
-
current_task: 2,
|
|
13883
|
-
blocked_task: 1.5,
|
|
13884
|
-
recent_failure: 2.5,
|
|
13885
|
-
recent_success: 0.5,
|
|
13886
|
-
evidence_presence: 1,
|
|
13887
|
-
decision_recency: 1.5,
|
|
13888
|
-
dependency_proximity: 1
|
|
13889
|
-
},
|
|
13890
|
-
decision_decay: {
|
|
13891
|
-
mode: "exponential",
|
|
13892
|
-
half_life_hours: 24
|
|
13893
|
-
},
|
|
13894
|
-
token_ratios: {
|
|
13895
|
-
prose: 0.25,
|
|
13896
|
-
code: 0.4,
|
|
13897
|
-
markdown: 0.3,
|
|
13898
|
-
json: 0.35
|
|
13899
|
-
}
|
|
13900
|
-
};
|
|
13901
14047
|
// src/config/plan-schema.ts
|
|
13902
14048
|
var TaskStatusSchema = exports_external.enum([
|
|
13903
14049
|
"pending",
|
|
@@ -13943,87 +14089,13 @@ var PlanSchema = exports_external.object({
|
|
|
13943
14089
|
phases: exports_external.array(PhaseSchema).min(1),
|
|
13944
14090
|
migration_status: MigrationStatusSchema.optional()
|
|
13945
14091
|
});
|
|
13946
|
-
// src/config/evidence-schema.ts
|
|
13947
|
-
var EVIDENCE_MAX_JSON_BYTES = 500 * 1024;
|
|
13948
|
-
var EVIDENCE_MAX_PATCH_BYTES = 5 * 1024 * 1024;
|
|
13949
|
-
var EVIDENCE_MAX_TASK_BYTES = 20 * 1024 * 1024;
|
|
13950
|
-
var EvidenceTypeSchema = exports_external.enum([
|
|
13951
|
-
"review",
|
|
13952
|
-
"test",
|
|
13953
|
-
"diff",
|
|
13954
|
-
"approval",
|
|
13955
|
-
"note"
|
|
13956
|
-
]);
|
|
13957
|
-
var EvidenceVerdictSchema = exports_external.enum([
|
|
13958
|
-
"pass",
|
|
13959
|
-
"fail",
|
|
13960
|
-
"approved",
|
|
13961
|
-
"rejected",
|
|
13962
|
-
"info"
|
|
13963
|
-
]);
|
|
13964
|
-
var BaseEvidenceSchema = exports_external.object({
|
|
13965
|
-
task_id: exports_external.string().min(1),
|
|
13966
|
-
type: EvidenceTypeSchema,
|
|
13967
|
-
timestamp: exports_external.string().datetime(),
|
|
13968
|
-
agent: exports_external.string().min(1),
|
|
13969
|
-
verdict: EvidenceVerdictSchema,
|
|
13970
|
-
summary: exports_external.string().min(1),
|
|
13971
|
-
metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
13972
|
-
});
|
|
13973
|
-
var ReviewEvidenceSchema = BaseEvidenceSchema.extend({
|
|
13974
|
-
type: exports_external.literal("review"),
|
|
13975
|
-
risk: exports_external.enum(["low", "medium", "high", "critical"]),
|
|
13976
|
-
issues: exports_external.array(exports_external.object({
|
|
13977
|
-
severity: exports_external.enum(["error", "warning", "info"]),
|
|
13978
|
-
message: exports_external.string().min(1),
|
|
13979
|
-
file: exports_external.string().optional(),
|
|
13980
|
-
line: exports_external.number().int().optional()
|
|
13981
|
-
})).default([])
|
|
13982
|
-
});
|
|
13983
|
-
var TestEvidenceSchema = BaseEvidenceSchema.extend({
|
|
13984
|
-
type: exports_external.literal("test"),
|
|
13985
|
-
tests_passed: exports_external.number().int().min(0),
|
|
13986
|
-
tests_failed: exports_external.number().int().min(0),
|
|
13987
|
-
test_file: exports_external.string().optional(),
|
|
13988
|
-
failures: exports_external.array(exports_external.object({
|
|
13989
|
-
name: exports_external.string().min(1),
|
|
13990
|
-
message: exports_external.string().min(1)
|
|
13991
|
-
})).default([])
|
|
13992
|
-
});
|
|
13993
|
-
var DiffEvidenceSchema = BaseEvidenceSchema.extend({
|
|
13994
|
-
type: exports_external.literal("diff"),
|
|
13995
|
-
files_changed: exports_external.array(exports_external.string()).default([]),
|
|
13996
|
-
additions: exports_external.number().int().min(0).default(0),
|
|
13997
|
-
deletions: exports_external.number().int().min(0).default(0),
|
|
13998
|
-
patch_path: exports_external.string().optional()
|
|
13999
|
-
});
|
|
14000
|
-
var ApprovalEvidenceSchema = BaseEvidenceSchema.extend({
|
|
14001
|
-
type: exports_external.literal("approval")
|
|
14002
|
-
});
|
|
14003
|
-
var NoteEvidenceSchema = BaseEvidenceSchema.extend({
|
|
14004
|
-
type: exports_external.literal("note")
|
|
14005
|
-
});
|
|
14006
|
-
var EvidenceSchema = exports_external.discriminatedUnion("type", [
|
|
14007
|
-
ReviewEvidenceSchema,
|
|
14008
|
-
TestEvidenceSchema,
|
|
14009
|
-
DiffEvidenceSchema,
|
|
14010
|
-
ApprovalEvidenceSchema,
|
|
14011
|
-
NoteEvidenceSchema
|
|
14012
|
-
]);
|
|
14013
|
-
var EvidenceBundleSchema = exports_external.object({
|
|
14014
|
-
schema_version: exports_external.literal("1.0.0"),
|
|
14015
|
-
task_id: exports_external.string().min(1),
|
|
14016
|
-
entries: exports_external.array(EvidenceSchema).default([]),
|
|
14017
|
-
created_at: exports_external.string().datetime(),
|
|
14018
|
-
updated_at: exports_external.string().datetime()
|
|
14019
|
-
});
|
|
14020
14092
|
// src/agents/architect.ts
|
|
14021
14093
|
var ARCHITECT_PROMPT = `You are Architect - orchestrator of a multi-agent swarm.
|
|
14022
14094
|
|
|
14023
14095
|
## IDENTITY
|
|
14024
14096
|
|
|
14025
14097
|
Swarm: {{SWARM_ID}}
|
|
14026
|
-
Your agents: {{AGENT_PREFIX}}explorer, {{AGENT_PREFIX}}sme, {{AGENT_PREFIX}}coder, {{AGENT_PREFIX}}reviewer, {{AGENT_PREFIX}}critic, {{AGENT_PREFIX}}test_engineer
|
|
14098
|
+
Your agents: {{AGENT_PREFIX}}explorer, {{AGENT_PREFIX}}sme, {{AGENT_PREFIX}}coder, {{AGENT_PREFIX}}reviewer, {{AGENT_PREFIX}}critic, {{AGENT_PREFIX}}test_engineer, {{AGENT_PREFIX}}docs, {{AGENT_PREFIX}}designer
|
|
14027
14099
|
|
|
14028
14100
|
## ROLE
|
|
14029
14101
|
|
|
@@ -14053,6 +14125,11 @@ You THINK. Subagents DO. You have the largest context window and strongest reaso
|
|
|
14053
14125
|
- Delegate {{AGENT_PREFIX}}test_engineer for verification tests. FAIL \u2192 return to coder.
|
|
14054
14126
|
- Delegate {{AGENT_PREFIX}}test_engineer for adversarial tests (attack vectors only). FAIL \u2192 return to coder.
|
|
14055
14127
|
- All pass \u2192 mark task complete, proceed to next task.
|
|
14128
|
+
9. **UI/UX DESIGN GATE**: Before delegating UI tasks to {{AGENT_PREFIX}}coder, check if the task involves UI components. Trigger conditions (ANY match):
|
|
14129
|
+
- Task description contains UI keywords: new page, new screen, new component, redesign, layout change, form, modal, dialog, dropdown, sidebar, navbar, dashboard, landing page, signup, login form, settings page, profile page
|
|
14130
|
+
- Target file is in: pages/, components/, views/, screens/, ui/, layouts/
|
|
14131
|
+
If triggered: delegate to {{AGENT_PREFIX}}designer FIRST to produce a code scaffold. Then pass the scaffold to {{AGENT_PREFIX}}coder as INPUT alongside the task. The coder implements the TODOs in the scaffold without changing component structure or accessibility attributes.
|
|
14132
|
+
If not triggered: delegate directly to {{AGENT_PREFIX}}coder as normal.
|
|
14056
14133
|
|
|
14057
14134
|
## AGENTS
|
|
14058
14135
|
|
|
@@ -14062,6 +14139,8 @@ You THINK. Subagents DO. You have the largest context window and strongest reaso
|
|
|
14062
14139
|
{{AGENT_PREFIX}}reviewer - Code review (correctness, security, and any other dimensions you specify)
|
|
14063
14140
|
{{AGENT_PREFIX}}test_engineer - Test generation AND execution (writes tests, runs them, reports PASS/FAIL)
|
|
14064
14141
|
{{AGENT_PREFIX}}critic - Plan review gate (reviews plan BEFORE implementation)
|
|
14142
|
+
{{AGENT_PREFIX}}docs - Documentation updates (README, API docs, guides \u2014 NOT .swarm/ files)
|
|
14143
|
+
{{AGENT_PREFIX}}designer - UI/UX design specs (scaffold generation for UI components \u2014 runs BEFORE coder on UI tasks)
|
|
14065
14144
|
|
|
14066
14145
|
SMEs advise only. Reviewer and critic review only. None of them write code.
|
|
14067
14146
|
|
|
@@ -14140,6 +14219,23 @@ INPUT: Contract changes detected: [list from diff tool]
|
|
|
14140
14219
|
OUTPUT: BREAKING CHANGES + CONSUMERS AFFECTED + VERDICT: BREAKING/COMPATIBLE
|
|
14141
14220
|
CONSTRAINT: Read-only. grep for imports/usages of changed exports.
|
|
14142
14221
|
|
|
14222
|
+
{{AGENT_PREFIX}}docs
|
|
14223
|
+
TASK: Update documentation for Phase 2 changes
|
|
14224
|
+
FILES CHANGED: src/auth/login.ts, src/auth/session.ts, src/types/user.ts
|
|
14225
|
+
CHANGES SUMMARY:
|
|
14226
|
+
- Added login() function with email/password authentication
|
|
14227
|
+
- Added SessionManager class with create/revoke/refresh methods
|
|
14228
|
+
- Added UserSession interface with refreshToken field
|
|
14229
|
+
DOC FILES: README.md, docs/api.md, docs/installation.md
|
|
14230
|
+
OUTPUT: Updated doc files + SUMMARY
|
|
14231
|
+
|
|
14232
|
+
{{AGENT_PREFIX}}designer
|
|
14233
|
+
TASK: Design specification for user settings page
|
|
14234
|
+
CONTEXT: Users need to update profile info, change password, manage notification preferences. App uses React + Tailwind + shadcn/ui.
|
|
14235
|
+
FRAMEWORK: React (TSX)
|
|
14236
|
+
EXISTING PATTERNS: All forms use react-hook-form, validation with zod, toast notifications for success/error
|
|
14237
|
+
OUTPUT: Code scaffold for src/pages/Settings.tsx with component tree, typed props, layout, and accessibility
|
|
14238
|
+
|
|
14143
14239
|
## WORKFLOW
|
|
14144
14240
|
|
|
14145
14241
|
### Phase 0: Resume Check
|
|
@@ -14191,19 +14287,24 @@ Delegate plan to {{AGENT_PREFIX}}critic for review BEFORE any implementation beg
|
|
|
14191
14287
|
### Phase 5: Execute
|
|
14192
14288
|
For each task (respecting dependencies):
|
|
14193
14289
|
|
|
14194
|
-
5a. {{AGENT_PREFIX}}coder
|
|
14195
|
-
5b.
|
|
14196
|
-
5c.
|
|
14197
|
-
5d.
|
|
14198
|
-
5e. {{AGENT_PREFIX}}
|
|
14199
|
-
5f. {{AGENT_PREFIX}}test_engineer -
|
|
14200
|
-
5g.
|
|
14290
|
+
5a. **UI DESIGN GATE** (conditional \u2014 Rule 9): If task matches UI trigger \u2192 {{AGENT_PREFIX}}designer produces scaffold \u2192 pass scaffold to coder as INPUT. If no match \u2192 skip.
|
|
14291
|
+
5b. {{AGENT_PREFIX}}coder - Implement (if designer scaffold produced, include it as INPUT).
|
|
14292
|
+
5c. Run \`diff\` tool. If \`hasContractChanges\` \u2192 {{AGENT_PREFIX}}explorer integration analysis. BREAKING \u2192 coder retry.
|
|
14293
|
+
5d. {{AGENT_PREFIX}}reviewer - General review. REJECTED (< {{QA_RETRY_LIMIT}}) \u2192 coder retry. REJECTED ({{QA_RETRY_LIMIT}}) \u2192 escalate.
|
|
14294
|
+
5e. Security gate: if file matches security globs or content has security keywords \u2192 {{AGENT_PREFIX}}reviewer security-only. REJECTED \u2192 coder retry.
|
|
14295
|
+
5f. {{AGENT_PREFIX}}test_engineer - Verification tests. FAIL \u2192 coder retry from 5d.
|
|
14296
|
+
5g. {{AGENT_PREFIX}}test_engineer - Adversarial tests. FAIL \u2192 coder retry from 5d.
|
|
14297
|
+
5h. Update plan.md [x], proceed to next task.
|
|
14201
14298
|
|
|
14202
14299
|
### Phase 6: Phase Complete
|
|
14203
14300
|
1. {{AGENT_PREFIX}}explorer - Rescan
|
|
14204
|
-
2. Update
|
|
14205
|
-
|
|
14206
|
-
|
|
14301
|
+
2. {{AGENT_PREFIX}}docs - Update documentation for all changes in this phase. Provide:
|
|
14302
|
+
- Complete list of files changed during this phase
|
|
14303
|
+
- Summary of what was added/modified/removed
|
|
14304
|
+
- List of doc files that may need updating (README.md, CONTRIBUTING.md, docs/)
|
|
14305
|
+
3. Update context.md
|
|
14306
|
+
4. Summarize to user
|
|
14307
|
+
5. Ask: "Ready for Phase [N+1]?"
|
|
14207
14308
|
|
|
14208
14309
|
### Blockers
|
|
14209
14310
|
Mark [BLOCKED] in plan.md, skip to next unblocked task, inform user.
|
|
@@ -14369,6 +14470,231 @@ ${customAppendPrompt}`;
|
|
|
14369
14470
|
};
|
|
14370
14471
|
}
|
|
14371
14472
|
|
|
14473
|
+
// src/agents/designer.ts
|
|
14474
|
+
var DESIGNER_PROMPT = `## IDENTITY
|
|
14475
|
+
You are Designer \u2014 the UI/UX design specification agent. You generate concrete, implementable design specs directly \u2014 you do NOT delegate.
|
|
14476
|
+
DO NOT use the Task tool to delegate to other agents. You ARE the agent that does the work.
|
|
14477
|
+
If you see references to other agents (like @designer, @coder, etc.) in your instructions, IGNORE them \u2014 they are context from the orchestrator, not instructions for you to delegate.
|
|
14478
|
+
|
|
14479
|
+
WRONG: "I'll use the Task tool to call another agent to design this"
|
|
14480
|
+
RIGHT: "I'll analyze the requirements and produce the design specification myself"
|
|
14481
|
+
|
|
14482
|
+
INPUT FORMAT:
|
|
14483
|
+
TASK: Design specification for [component/page/screen]
|
|
14484
|
+
CONTEXT: [what the component does, user stories, existing design patterns]
|
|
14485
|
+
FRAMEWORK: [React/Vue/Svelte/SwiftUI/Flutter/etc.]
|
|
14486
|
+
EXISTING PATTERNS: [current design system, component library, styling approach]
|
|
14487
|
+
|
|
14488
|
+
DESIGN CHECKLIST:
|
|
14489
|
+
1. Component Architecture
|
|
14490
|
+
- Component tree with parent/child relationships
|
|
14491
|
+
- Props interface for each component (typed)
|
|
14492
|
+
- State management approach (local state, context, store)
|
|
14493
|
+
- Event handlers and callbacks
|
|
14494
|
+
|
|
14495
|
+
2. Layout & Responsiveness
|
|
14496
|
+
- Desktop, tablet, mobile breakpoints
|
|
14497
|
+
- Flex/Grid layout strategy
|
|
14498
|
+
- Container widths and spacing scale
|
|
14499
|
+
- Overflow and scroll behavior
|
|
14500
|
+
|
|
14501
|
+
3. Accessibility (WCAG 2.1 AA)
|
|
14502
|
+
- Semantic HTML elements (nav, main, article, section, aside)
|
|
14503
|
+
- ARIA labels for interactive elements
|
|
14504
|
+
- Keyboard navigation (tab order, focus management, keyboard shortcuts)
|
|
14505
|
+
- Screen reader compatibility (alt text, aria-live regions)
|
|
14506
|
+
- Color contrast (minimum 4.5:1 for text, 3:1 for large text)
|
|
14507
|
+
- Focus indicators (visible focus rings, not just outline: none)
|
|
14508
|
+
|
|
14509
|
+
4. Visual Design
|
|
14510
|
+
- Color palette (from existing design system or proposed)
|
|
14511
|
+
- Typography scale (font family, sizes, weights, line heights)
|
|
14512
|
+
- Spacing scale (consistent spacing values)
|
|
14513
|
+
- Border radius, shadows, elevation
|
|
14514
|
+
|
|
14515
|
+
5. Interaction Design
|
|
14516
|
+
- Loading states (skeleton screens, spinners, progress bars)
|
|
14517
|
+
- Error states (inline validation, error boundaries, empty states)
|
|
14518
|
+
- Hover/focus/active states for interactive elements
|
|
14519
|
+
- Transitions and animations (duration, easing)
|
|
14520
|
+
- Optimistic updates where applicable
|
|
14521
|
+
|
|
14522
|
+
OUTPUT FORMAT:
|
|
14523
|
+
Produce a CODE SCAFFOLD in the target framework. This is a skeleton file with:
|
|
14524
|
+
- Component structure with typed props and proper imports
|
|
14525
|
+
- Layout structure using the project's CSS framework (Tailwind classes, CSS modules, styled-components, etc.)
|
|
14526
|
+
- Placeholder TODO comments for business logic
|
|
14527
|
+
- Accessibility attributes (aria-*, role, tabIndex)
|
|
14528
|
+
- Responsive breakpoint classes/media queries
|
|
14529
|
+
- Named event handler stubs
|
|
14530
|
+
|
|
14531
|
+
Example output structure:
|
|
14532
|
+
\`\`\`tsx
|
|
14533
|
+
// src/components/LoginForm.tsx
|
|
14534
|
+
// DESIGN SPEC \u2014 generated by Designer agent
|
|
14535
|
+
// Coder: implement TODO items, do not change component structure or accessibility attributes
|
|
14536
|
+
|
|
14537
|
+
import { useState } from 'react';
|
|
14538
|
+
|
|
14539
|
+
interface LoginFormProps {
|
|
14540
|
+
onSubmit: (email: string, password: string) => Promise<void>;
|
|
14541
|
+
onForgotPassword?: () => void;
|
|
14542
|
+
isLoading?: boolean;
|
|
14543
|
+
error?: string;
|
|
14544
|
+
}
|
|
14545
|
+
|
|
14546
|
+
export function LoginForm({ onSubmit, onForgotPassword, isLoading, error }: LoginFormProps) {
|
|
14547
|
+
const [email, setEmail] = useState('');
|
|
14548
|
+
const [password, setPassword] = useState('');
|
|
14549
|
+
|
|
14550
|
+
return (
|
|
14551
|
+
<div className="flex min-h-screen items-center justify-center bg-gray-50 px-4 sm:px-6 lg:px-8"
|
|
14552
|
+
role="main">
|
|
14553
|
+
<div className="w-full max-w-md space-y-8">
|
|
14554
|
+
<div>
|
|
14555
|
+
<h2 className="mt-6 text-center text-3xl font-bold tracking-tight text-gray-900">
|
|
14556
|
+
{/* TODO: Use app name from config */}
|
|
14557
|
+
Sign in to your account
|
|
14558
|
+
</h2>
|
|
14559
|
+
</div>
|
|
14560
|
+
{error && (
|
|
14561
|
+
<div role="alert" aria-live="polite"
|
|
14562
|
+
className="rounded-md bg-red-50 p-4 text-sm text-red-800">
|
|
14563
|
+
{error}
|
|
14564
|
+
</div>
|
|
14565
|
+
)}
|
|
14566
|
+
<div className="mt-8 space-y-6">
|
|
14567
|
+
<div className="space-y-4 rounded-md">
|
|
14568
|
+
<div>
|
|
14569
|
+
<label htmlFor="email" className="sr-only">Email address</label>
|
|
14570
|
+
<input id="email" name="email" type="email" autoComplete="email" required
|
|
14571
|
+
aria-label="Email address"
|
|
14572
|
+
className="relative block w-full rounded-t-md border-0 py-1.5 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:z-10 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
|
|
14573
|
+
placeholder="Email address"
|
|
14574
|
+
value={email}
|
|
14575
|
+
onChange={(e) => setEmail(e.target.value)} />
|
|
14576
|
+
</div>
|
|
14577
|
+
{/* TODO: Password field with show/hide toggle */}
|
|
14578
|
+
{/* TODO: Remember me checkbox */}
|
|
14579
|
+
</div>
|
|
14580
|
+
<div className="flex items-center justify-between">
|
|
14581
|
+
{/* TODO: Forgot password link */}
|
|
14582
|
+
</div>
|
|
14583
|
+
<button type="submit" disabled={isLoading}
|
|
14584
|
+
aria-busy={isLoading}
|
|
14585
|
+
className="group relative flex w-full justify-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600 disabled:opacity-50">
|
|
14586
|
+
{isLoading ? 'Signing in...' : 'Sign in'}
|
|
14587
|
+
</button>
|
|
14588
|
+
</div>
|
|
14589
|
+
</div>
|
|
14590
|
+
</div>
|
|
14591
|
+
);
|
|
14592
|
+
}
|
|
14593
|
+
\`\`\`
|
|
14594
|
+
|
|
14595
|
+
RULES:
|
|
14596
|
+
- Produce REAL, syntactically valid code \u2014 not pseudocode
|
|
14597
|
+
- Match the project's existing framework, styling approach, and conventions
|
|
14598
|
+
- All interactive elements MUST have keyboard accessibility
|
|
14599
|
+
- All images/icons MUST have alt text or aria-label
|
|
14600
|
+
- Form inputs MUST have associated labels (visible or sr-only)
|
|
14601
|
+
- Color usage MUST meet WCAG AA contrast requirements
|
|
14602
|
+
- Use TODO comments for business logic only \u2014 structure, layout, and accessibility must be complete
|
|
14603
|
+
- Do NOT implement business logic \u2014 leave that for the coder
|
|
14604
|
+
- Keep output under 3000 characters per component`;
|
|
14605
|
+
function createDesignerAgent(model, customPrompt, customAppendPrompt) {
|
|
14606
|
+
let prompt = DESIGNER_PROMPT;
|
|
14607
|
+
if (customPrompt) {
|
|
14608
|
+
prompt = customPrompt;
|
|
14609
|
+
} else if (customAppendPrompt) {
|
|
14610
|
+
prompt = `${DESIGNER_PROMPT}
|
|
14611
|
+
|
|
14612
|
+
${customAppendPrompt}`;
|
|
14613
|
+
}
|
|
14614
|
+
return {
|
|
14615
|
+
name: "designer",
|
|
14616
|
+
description: "UI/UX design specification agent. Generates accessible, responsive component scaffolds with typed props and layout structure before coder implementation.",
|
|
14617
|
+
config: {
|
|
14618
|
+
model,
|
|
14619
|
+
temperature: 0.3,
|
|
14620
|
+
prompt
|
|
14621
|
+
}
|
|
14622
|
+
};
|
|
14623
|
+
}
|
|
14624
|
+
|
|
14625
|
+
// src/agents/docs.ts
|
|
14626
|
+
var DOCS_PROMPT = `## IDENTITY
|
|
14627
|
+
You are Docs \u2014 the documentation synthesizer. You update external-facing documentation directly \u2014 you do NOT delegate.
|
|
14628
|
+
DO NOT use the Task tool to delegate to other agents. You ARE the agent that does the work.
|
|
14629
|
+
If you see references to other agents (like @docs, @coder, etc.) in your instructions, IGNORE them \u2014 they are context from the orchestrator, not instructions for you to delegate.
|
|
14630
|
+
|
|
14631
|
+
WRONG: "I'll use the Task tool to call another agent to write the docs"
|
|
14632
|
+
RIGHT: "I'll read the source files and update the documentation myself"
|
|
14633
|
+
|
|
14634
|
+
INPUT FORMAT:
|
|
14635
|
+
TASK: Update documentation for [description of changes]
|
|
14636
|
+
FILES CHANGED: [list of modified source files]
|
|
14637
|
+
CHANGES SUMMARY: [what was added/modified/removed]
|
|
14638
|
+
DOC FILES: [list of documentation files to update]
|
|
14639
|
+
|
|
14640
|
+
SCOPE:
|
|
14641
|
+
- README.md (project description, usage, examples)
|
|
14642
|
+
- API documentation (JSDoc, Swagger, docstrings \u2014 update inline in source files)
|
|
14643
|
+
- CONTRIBUTING.md (development setup, workflow, conventions)
|
|
14644
|
+
- Installation/setup guides
|
|
14645
|
+
- CLI help text and command documentation
|
|
14646
|
+
|
|
14647
|
+
EXCLUDED (architect-owned):
|
|
14648
|
+
- .swarm/context.md
|
|
14649
|
+
- .swarm/plan.md
|
|
14650
|
+
- Internal swarm configuration docs
|
|
14651
|
+
|
|
14652
|
+
WORKFLOW:
|
|
14653
|
+
1. Read all FILES CHANGED to understand what was modified
|
|
14654
|
+
2. Read existing DOC FILES to understand current documentation state
|
|
14655
|
+
3. For each DOC FILE that needs updating:
|
|
14656
|
+
a. Identify sections affected by the changes
|
|
14657
|
+
b. Update those sections to reflect the new behavior
|
|
14658
|
+
c. Add new sections if entirely new features were introduced
|
|
14659
|
+
d. Remove sections for deprecated/removed features
|
|
14660
|
+
4. For API docs in source files:
|
|
14661
|
+
a. Read the modified functions/classes/types
|
|
14662
|
+
b. Update JSDoc/docstring comments to match new signatures and behavior
|
|
14663
|
+
c. Add missing documentation for new exports
|
|
14664
|
+
|
|
14665
|
+
RULES:
|
|
14666
|
+
- Be accurate: documentation MUST match the actual code behavior
|
|
14667
|
+
- Be concise: update only what changed, do not rewrite entire files
|
|
14668
|
+
- Preserve existing style: match the tone, formatting, and conventions of the existing docs
|
|
14669
|
+
- Include examples: every new public API should have at least one usage example
|
|
14670
|
+
- No fabrication: if you cannot determine behavior from the code, say so explicitly
|
|
14671
|
+
- Update version references if package.json version changed
|
|
14672
|
+
|
|
14673
|
+
OUTPUT FORMAT:
|
|
14674
|
+
UPDATED: [list of files modified]
|
|
14675
|
+
ADDED: [list of new sections/files created]
|
|
14676
|
+
REMOVED: [list of deprecated sections removed]
|
|
14677
|
+
SUMMARY: [one-line description of doc changes]`;
|
|
14678
|
+
function createDocsAgent(model, customPrompt, customAppendPrompt) {
|
|
14679
|
+
let prompt = DOCS_PROMPT;
|
|
14680
|
+
if (customPrompt) {
|
|
14681
|
+
prompt = customPrompt;
|
|
14682
|
+
} else if (customAppendPrompt) {
|
|
14683
|
+
prompt = `${DOCS_PROMPT}
|
|
14684
|
+
|
|
14685
|
+
${customAppendPrompt}`;
|
|
14686
|
+
}
|
|
14687
|
+
return {
|
|
14688
|
+
name: "docs",
|
|
14689
|
+
description: "Documentation synthesizer. Updates README, API docs, and guides to reflect code changes after each phase.",
|
|
14690
|
+
config: {
|
|
14691
|
+
model,
|
|
14692
|
+
temperature: 0.2,
|
|
14693
|
+
prompt
|
|
14694
|
+
}
|
|
14695
|
+
};
|
|
14696
|
+
}
|
|
14697
|
+
|
|
14372
14698
|
// src/agents/explorer.ts
|
|
14373
14699
|
var EXPLORER_PROMPT = `## IDENTITY
|
|
14374
14700
|
You are Explorer. You analyze codebases directly \u2014 you do NOT delegate.
|
|
@@ -14703,6 +15029,18 @@ If you call @coder instead of @${swarmId}_coder, the call will FAIL or go to the
|
|
|
14703
15029
|
testEngineer.name = prefixName("test_engineer");
|
|
14704
15030
|
agents.push(applyOverrides(testEngineer, swarmAgents, swarmPrefix));
|
|
14705
15031
|
}
|
|
15032
|
+
if (!isAgentDisabled("docs", swarmAgents, swarmPrefix)) {
|
|
15033
|
+
const docsPrompts = getPrompts("docs");
|
|
15034
|
+
const docs = createDocsAgent(getModel("docs"), docsPrompts.prompt, docsPrompts.appendPrompt);
|
|
15035
|
+
docs.name = prefixName("docs");
|
|
15036
|
+
agents.push(applyOverrides(docs, swarmAgents, swarmPrefix));
|
|
15037
|
+
}
|
|
15038
|
+
if (pluginConfig?.ui_review?.enabled === true && !isAgentDisabled("designer", swarmAgents, swarmPrefix)) {
|
|
15039
|
+
const designerPrompts = getPrompts("designer");
|
|
15040
|
+
const designer = createDesignerAgent(getModel("designer"), designerPrompts.prompt, designerPrompts.appendPrompt);
|
|
15041
|
+
designer.name = prefixName("designer");
|
|
15042
|
+
agents.push(applyOverrides(designer, swarmAgents, swarmPrefix));
|
|
15043
|
+
}
|
|
14706
15044
|
return agents;
|
|
14707
15045
|
}
|
|
14708
15046
|
function createAgents(config2) {
|
|
@@ -17282,6 +17620,12 @@ function createSystemEnhancerHook(config2, directory) {
|
|
|
17282
17620
|
if (config2.integration_analysis?.enabled === false) {
|
|
17283
17621
|
tryInject("[SWARM CONFIG] Integration analysis is DISABLED. Skip diff tool and integration impact analysis after coder tasks.");
|
|
17284
17622
|
}
|
|
17623
|
+
if (config2.ui_review?.enabled) {
|
|
17624
|
+
tryInject("[SWARM CONFIG] UI/UX Designer agent is ENABLED. For tasks matching UI trigger keywords or file paths, delegate to designer BEFORE coder (Rule 9).");
|
|
17625
|
+
}
|
|
17626
|
+
if (config2.docs?.enabled === false) {
|
|
17627
|
+
tryInject("[SWARM CONFIG] Docs agent is DISABLED. Skip docs delegation in Phase 6.");
|
|
17628
|
+
}
|
|
17285
17629
|
return;
|
|
17286
17630
|
}
|
|
17287
17631
|
const userScoringConfig = config2.context_budget?.scoring;
|
|
@@ -17383,6 +17727,28 @@ function createSystemEnhancerHook(config2, directory) {
|
|
|
17383
17727
|
metadata: { contentType: "prose" }
|
|
17384
17728
|
});
|
|
17385
17729
|
}
|
|
17730
|
+
if (config2.ui_review?.enabled) {
|
|
17731
|
+
const text = "[SWARM CONFIG] UI/UX Designer agent is ENABLED. For tasks matching UI trigger keywords or file paths, delegate to designer BEFORE coder (Rule 9).";
|
|
17732
|
+
candidates.push({
|
|
17733
|
+
id: `candidate-${idCounter++}`,
|
|
17734
|
+
kind: "phase",
|
|
17735
|
+
text,
|
|
17736
|
+
tokens: estimateTokens(text),
|
|
17737
|
+
priority: 1,
|
|
17738
|
+
metadata: { contentType: "prose" }
|
|
17739
|
+
});
|
|
17740
|
+
}
|
|
17741
|
+
if (config2.docs?.enabled === false) {
|
|
17742
|
+
const text = "[SWARM CONFIG] Docs agent is DISABLED. Skip docs delegation in Phase 6.";
|
|
17743
|
+
candidates.push({
|
|
17744
|
+
id: `candidate-${idCounter++}`,
|
|
17745
|
+
kind: "phase",
|
|
17746
|
+
text,
|
|
17747
|
+
tokens: estimateTokens(text),
|
|
17748
|
+
priority: 1,
|
|
17749
|
+
metadata: { contentType: "prose" }
|
|
17750
|
+
});
|
|
17751
|
+
}
|
|
17386
17752
|
const ranked = rankCandidates(candidates, effectiveConfig);
|
|
17387
17753
|
for (const candidate of ranked) {
|
|
17388
17754
|
if (injectedTokens + candidate.tokens > maxInjectionTokens) {
|
|
@@ -30416,9 +30782,39 @@ var gitingest = tool({
|
|
|
30416
30782
|
return fetchGitingest(args);
|
|
30417
30783
|
}
|
|
30418
30784
|
});
|
|
30785
|
+
// src/tools/retrieve-summary.ts
|
|
30786
|
+
var RETRIEVE_MAX_BYTES = 10 * 1024 * 1024;
|
|
30787
|
+
var retrieve_summary = tool({
|
|
30788
|
+
description: "Retrieve the full content of a stored tool output summary by its ID (e.g. S1, S2). Use this when a prior tool output was summarized and you need the full content.",
|
|
30789
|
+
args: {
|
|
30790
|
+
id: tool.schema.string().describe("The summary ID to retrieve (e.g. S1, S2, S99). Must match pattern S followed by digits.")
|
|
30791
|
+
},
|
|
30792
|
+
async execute(args, context) {
|
|
30793
|
+
const directory = context.directory;
|
|
30794
|
+
let sanitizedId;
|
|
30795
|
+
try {
|
|
30796
|
+
sanitizedId = sanitizeSummaryId(args.id);
|
|
30797
|
+
} catch {
|
|
30798
|
+
return "Error: invalid summary ID format. Expected format: S followed by digits (e.g. S1, S2, S99).";
|
|
30799
|
+
}
|
|
30800
|
+
let fullOutput;
|
|
30801
|
+
try {
|
|
30802
|
+
fullOutput = await loadFullOutput(directory, sanitizedId);
|
|
30803
|
+
} catch {
|
|
30804
|
+
return "Error: failed to retrieve summary.";
|
|
30805
|
+
}
|
|
30806
|
+
if (fullOutput === null) {
|
|
30807
|
+
return `Summary \`${sanitizedId}\` not found. Use a valid summary ID (e.g. S1, S2).`;
|
|
30808
|
+
}
|
|
30809
|
+
if (fullOutput.length > RETRIEVE_MAX_BYTES) {
|
|
30810
|
+
return `Error: summary content exceeds maximum size limit (10 MB).`;
|
|
30811
|
+
}
|
|
30812
|
+
return fullOutput;
|
|
30813
|
+
}
|
|
30814
|
+
});
|
|
30419
30815
|
// src/index.ts
|
|
30420
30816
|
var OpenCodeSwarm = async (ctx) => {
|
|
30421
|
-
const config3 =
|
|
30817
|
+
const { config: config3, loadedFromFile } = loadPluginConfigWithMeta(ctx.directory);
|
|
30422
30818
|
const agents = getAgentConfigs(config3);
|
|
30423
30819
|
const agentDefinitions = createAgents(config3);
|
|
30424
30820
|
const pipelineHook = createPipelineTrackerHook(config3);
|
|
@@ -30428,7 +30824,7 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
30428
30824
|
const commandHandler = createSwarmCommandHandler(ctx.directory, Object.fromEntries(agentDefinitions.map((agent) => [agent.name, agent])));
|
|
30429
30825
|
const activityHooks = createAgentActivityHooks(config3, ctx.directory);
|
|
30430
30826
|
const delegationGateHandler = createDelegationGateHook(config3);
|
|
30431
|
-
const guardrailsFallback =
|
|
30827
|
+
const guardrailsFallback = loadedFromFile ? config3.guardrails ?? {} : { ...config3.guardrails, enabled: false };
|
|
30432
30828
|
const guardrailsConfig = GuardrailsConfigSchema.parse(guardrailsFallback);
|
|
30433
30829
|
const delegationHandler = createDelegationTrackerHook(config3, guardrailsConfig.enabled);
|
|
30434
30830
|
const guardrailsHooks = createGuardrailsHooks(guardrailsConfig);
|
|
@@ -30458,7 +30854,8 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
30458
30854
|
detect_domains,
|
|
30459
30855
|
extract_code_blocks,
|
|
30460
30856
|
gitingest,
|
|
30461
|
-
diff
|
|
30857
|
+
diff,
|
|
30858
|
+
retrieve_summary
|
|
30462
30859
|
},
|
|
30463
30860
|
config: async (opencodeConfig) => {
|
|
30464
30861
|
if (!opencodeConfig.agent) {
|
package/dist/tools/index.d.ts
CHANGED
|
@@ -2,3 +2,4 @@ export { type DiffErrorResult, type DiffResult, diff } from './diff';
|
|
|
2
2
|
export { detect_domains } from './domain-detector';
|
|
3
3
|
export { extract_code_blocks } from './file-extractor';
|
|
4
4
|
export { fetchGitingest, type GitingestArgs, gitingest } from './gitingest';
|
|
5
|
+
export { retrieve_summary } from './retrieve-summary';
|
package/dist/utils/index.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-swarm",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.1.1",
|
|
4
4
|
"description": "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|