opencode-swarm 6.1.0 → 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/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 +0 -1
- package/dist/index.js +208 -161
- 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
|
|
|
@@ -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
|
@@ -318,7 +318,6 @@ export declare const PluginConfigSchema: z.ZodObject<{
|
|
|
318
318
|
trigger_paths: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
319
319
|
trigger_keywords: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
320
320
|
}, z.core.$strip>>;
|
|
321
|
-
_loadedFromFile: z.ZodDefault<z.ZodBoolean>;
|
|
322
321
|
}, z.core.$strip>;
|
|
323
322
|
export type PluginConfig = z.infer<typeof PluginConfigSchema>;
|
|
324
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(),
|
|
@@ -13798,8 +13949,7 @@ var PluginConfigSchema = exports_external.object({
|
|
|
13798
13949
|
review_passes: ReviewPassesConfigSchema.optional(),
|
|
13799
13950
|
integration_analysis: IntegrationAnalysisConfigSchema.optional(),
|
|
13800
13951
|
docs: DocsConfigSchema.optional(),
|
|
13801
|
-
ui_review: UIReviewConfigSchema.optional()
|
|
13802
|
-
_loadedFromFile: exports_external.boolean().default(false)
|
|
13952
|
+
ui_review: UIReviewConfigSchema.optional()
|
|
13803
13953
|
});
|
|
13804
13954
|
|
|
13805
13955
|
// src/config/loader.ts
|
|
@@ -13818,6 +13968,11 @@ function loadRawConfigFromPath(configPath) {
|
|
|
13818
13968
|
return null;
|
|
13819
13969
|
}
|
|
13820
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
|
+
}
|
|
13821
13976
|
const rawConfig = JSON.parse(content);
|
|
13822
13977
|
if (typeof rawConfig !== "object" || rawConfig === null || Array.isArray(rawConfig)) {
|
|
13823
13978
|
console.warn(`[opencode-swarm] Invalid config at ${configPath}: expected an object`);
|
|
@@ -13833,23 +13988,6 @@ function loadRawConfigFromPath(configPath) {
|
|
|
13833
13988
|
return null;
|
|
13834
13989
|
}
|
|
13835
13990
|
}
|
|
13836
|
-
var MAX_MERGE_DEPTH = 10;
|
|
13837
|
-
function deepMergeInternal(base, override, depth) {
|
|
13838
|
-
if (depth >= MAX_MERGE_DEPTH) {
|
|
13839
|
-
throw new Error(`deepMerge exceeded maximum depth of ${MAX_MERGE_DEPTH}`);
|
|
13840
|
-
}
|
|
13841
|
-
const result = { ...base };
|
|
13842
|
-
for (const key of Object.keys(override)) {
|
|
13843
|
-
const baseVal = base[key];
|
|
13844
|
-
const overrideVal = override[key];
|
|
13845
|
-
if (typeof baseVal === "object" && baseVal !== null && typeof overrideVal === "object" && overrideVal !== null && !Array.isArray(baseVal) && !Array.isArray(overrideVal)) {
|
|
13846
|
-
result[key] = deepMergeInternal(baseVal, overrideVal, depth + 1);
|
|
13847
|
-
} else {
|
|
13848
|
-
result[key] = overrideVal;
|
|
13849
|
-
}
|
|
13850
|
-
}
|
|
13851
|
-
return result;
|
|
13852
|
-
}
|
|
13853
13991
|
function loadPluginConfig(directory) {
|
|
13854
13992
|
const userConfigPath = path.join(getUserConfigDir(), "opencode", CONFIG_FILENAME);
|
|
13855
13993
|
const projectConfigPath = path.join(directory, ".opencode", CONFIG_FILENAME);
|
|
@@ -13858,7 +13996,7 @@ function loadPluginConfig(directory) {
|
|
|
13858
13996
|
const loadedFromFile = rawUserConfig !== null || rawProjectConfig !== null;
|
|
13859
13997
|
let mergedRaw = rawUserConfig ?? {};
|
|
13860
13998
|
if (rawProjectConfig) {
|
|
13861
|
-
mergedRaw =
|
|
13999
|
+
mergedRaw = deepMerge(mergedRaw, rawProjectConfig);
|
|
13862
14000
|
}
|
|
13863
14001
|
const result = PluginConfigSchema.safeParse(mergedRaw);
|
|
13864
14002
|
if (!result.success) {
|
|
@@ -13866,20 +14004,24 @@ function loadPluginConfig(directory) {
|
|
|
13866
14004
|
const userResult = PluginConfigSchema.safeParse(rawUserConfig);
|
|
13867
14005
|
if (userResult.success) {
|
|
13868
14006
|
console.warn("[opencode-swarm] Project config ignored due to validation errors. Using user config.");
|
|
13869
|
-
return
|
|
14007
|
+
return userResult.data;
|
|
13870
14008
|
}
|
|
13871
14009
|
}
|
|
13872
14010
|
console.warn("[opencode-swarm] Merged config validation failed:");
|
|
13873
14011
|
console.warn(result.error.format());
|
|
13874
14012
|
console.warn("[opencode-swarm] \u26A0\uFE0F Guardrails will be DISABLED as a safety precaution. Fix the config file to restore normal operation.");
|
|
13875
|
-
return {
|
|
13876
|
-
max_iterations: 5,
|
|
13877
|
-
qa_retry_limit: 3,
|
|
13878
|
-
inject_phase_reminders: true,
|
|
13879
|
-
_loadedFromFile: false
|
|
13880
|
-
};
|
|
14013
|
+
return PluginConfigSchema.parse({});
|
|
13881
14014
|
}
|
|
13882
|
-
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 };
|
|
13883
14025
|
}
|
|
13884
14026
|
function loadAgentPrompt(agentName) {
|
|
13885
14027
|
const promptsDir = path.join(getUserConfigDir(), "opencode", PROMPTS_DIR_NAME);
|
|
@@ -13902,58 +14044,6 @@ function loadAgentPrompt(agentName) {
|
|
|
13902
14044
|
}
|
|
13903
14045
|
return result;
|
|
13904
14046
|
}
|
|
13905
|
-
|
|
13906
|
-
// src/config/constants.ts
|
|
13907
|
-
var QA_AGENTS = ["reviewer", "critic"];
|
|
13908
|
-
var PIPELINE_AGENTS = ["explorer", "coder", "test_engineer"];
|
|
13909
|
-
var ORCHESTRATOR_NAME = "architect";
|
|
13910
|
-
var ALL_SUBAGENT_NAMES = [
|
|
13911
|
-
"sme",
|
|
13912
|
-
"docs",
|
|
13913
|
-
"designer",
|
|
13914
|
-
...QA_AGENTS,
|
|
13915
|
-
...PIPELINE_AGENTS
|
|
13916
|
-
];
|
|
13917
|
-
var ALL_AGENT_NAMES = [
|
|
13918
|
-
ORCHESTRATOR_NAME,
|
|
13919
|
-
...ALL_SUBAGENT_NAMES
|
|
13920
|
-
];
|
|
13921
|
-
var DEFAULT_MODELS = {
|
|
13922
|
-
architect: "anthropic/claude-sonnet-4-5",
|
|
13923
|
-
explorer: "google/gemini-2.0-flash",
|
|
13924
|
-
coder: "anthropic/claude-sonnet-4-5",
|
|
13925
|
-
test_engineer: "google/gemini-2.0-flash",
|
|
13926
|
-
sme: "google/gemini-2.0-flash",
|
|
13927
|
-
reviewer: "google/gemini-2.0-flash",
|
|
13928
|
-
critic: "google/gemini-2.0-flash",
|
|
13929
|
-
docs: "google/gemini-2.0-flash",
|
|
13930
|
-
designer: "google/gemini-2.0-flash",
|
|
13931
|
-
default: "google/gemini-2.0-flash"
|
|
13932
|
-
};
|
|
13933
|
-
var DEFAULT_SCORING_CONFIG = {
|
|
13934
|
-
enabled: false,
|
|
13935
|
-
max_candidates: 100,
|
|
13936
|
-
weights: {
|
|
13937
|
-
phase: 1,
|
|
13938
|
-
current_task: 2,
|
|
13939
|
-
blocked_task: 1.5,
|
|
13940
|
-
recent_failure: 2.5,
|
|
13941
|
-
recent_success: 0.5,
|
|
13942
|
-
evidence_presence: 1,
|
|
13943
|
-
decision_recency: 1.5,
|
|
13944
|
-
dependency_proximity: 1
|
|
13945
|
-
},
|
|
13946
|
-
decision_decay: {
|
|
13947
|
-
mode: "exponential",
|
|
13948
|
-
half_life_hours: 24
|
|
13949
|
-
},
|
|
13950
|
-
token_ratios: {
|
|
13951
|
-
prose: 0.25,
|
|
13952
|
-
code: 0.4,
|
|
13953
|
-
markdown: 0.3,
|
|
13954
|
-
json: 0.35
|
|
13955
|
-
}
|
|
13956
|
-
};
|
|
13957
14047
|
// src/config/plan-schema.ts
|
|
13958
14048
|
var TaskStatusSchema = exports_external.enum([
|
|
13959
14049
|
"pending",
|
|
@@ -13999,80 +14089,6 @@ var PlanSchema = exports_external.object({
|
|
|
13999
14089
|
phases: exports_external.array(PhaseSchema).min(1),
|
|
14000
14090
|
migration_status: MigrationStatusSchema.optional()
|
|
14001
14091
|
});
|
|
14002
|
-
// src/config/evidence-schema.ts
|
|
14003
|
-
var EVIDENCE_MAX_JSON_BYTES = 500 * 1024;
|
|
14004
|
-
var EVIDENCE_MAX_PATCH_BYTES = 5 * 1024 * 1024;
|
|
14005
|
-
var EVIDENCE_MAX_TASK_BYTES = 20 * 1024 * 1024;
|
|
14006
|
-
var EvidenceTypeSchema = exports_external.enum([
|
|
14007
|
-
"review",
|
|
14008
|
-
"test",
|
|
14009
|
-
"diff",
|
|
14010
|
-
"approval",
|
|
14011
|
-
"note"
|
|
14012
|
-
]);
|
|
14013
|
-
var EvidenceVerdictSchema = exports_external.enum([
|
|
14014
|
-
"pass",
|
|
14015
|
-
"fail",
|
|
14016
|
-
"approved",
|
|
14017
|
-
"rejected",
|
|
14018
|
-
"info"
|
|
14019
|
-
]);
|
|
14020
|
-
var BaseEvidenceSchema = exports_external.object({
|
|
14021
|
-
task_id: exports_external.string().min(1),
|
|
14022
|
-
type: EvidenceTypeSchema,
|
|
14023
|
-
timestamp: exports_external.string().datetime(),
|
|
14024
|
-
agent: exports_external.string().min(1),
|
|
14025
|
-
verdict: EvidenceVerdictSchema,
|
|
14026
|
-
summary: exports_external.string().min(1),
|
|
14027
|
-
metadata: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
|
|
14028
|
-
});
|
|
14029
|
-
var ReviewEvidenceSchema = BaseEvidenceSchema.extend({
|
|
14030
|
-
type: exports_external.literal("review"),
|
|
14031
|
-
risk: exports_external.enum(["low", "medium", "high", "critical"]),
|
|
14032
|
-
issues: exports_external.array(exports_external.object({
|
|
14033
|
-
severity: exports_external.enum(["error", "warning", "info"]),
|
|
14034
|
-
message: exports_external.string().min(1),
|
|
14035
|
-
file: exports_external.string().optional(),
|
|
14036
|
-
line: exports_external.number().int().optional()
|
|
14037
|
-
})).default([])
|
|
14038
|
-
});
|
|
14039
|
-
var TestEvidenceSchema = BaseEvidenceSchema.extend({
|
|
14040
|
-
type: exports_external.literal("test"),
|
|
14041
|
-
tests_passed: exports_external.number().int().min(0),
|
|
14042
|
-
tests_failed: exports_external.number().int().min(0),
|
|
14043
|
-
test_file: exports_external.string().optional(),
|
|
14044
|
-
failures: exports_external.array(exports_external.object({
|
|
14045
|
-
name: exports_external.string().min(1),
|
|
14046
|
-
message: exports_external.string().min(1)
|
|
14047
|
-
})).default([])
|
|
14048
|
-
});
|
|
14049
|
-
var DiffEvidenceSchema = BaseEvidenceSchema.extend({
|
|
14050
|
-
type: exports_external.literal("diff"),
|
|
14051
|
-
files_changed: exports_external.array(exports_external.string()).default([]),
|
|
14052
|
-
additions: exports_external.number().int().min(0).default(0),
|
|
14053
|
-
deletions: exports_external.number().int().min(0).default(0),
|
|
14054
|
-
patch_path: exports_external.string().optional()
|
|
14055
|
-
});
|
|
14056
|
-
var ApprovalEvidenceSchema = BaseEvidenceSchema.extend({
|
|
14057
|
-
type: exports_external.literal("approval")
|
|
14058
|
-
});
|
|
14059
|
-
var NoteEvidenceSchema = BaseEvidenceSchema.extend({
|
|
14060
|
-
type: exports_external.literal("note")
|
|
14061
|
-
});
|
|
14062
|
-
var EvidenceSchema = exports_external.discriminatedUnion("type", [
|
|
14063
|
-
ReviewEvidenceSchema,
|
|
14064
|
-
TestEvidenceSchema,
|
|
14065
|
-
DiffEvidenceSchema,
|
|
14066
|
-
ApprovalEvidenceSchema,
|
|
14067
|
-
NoteEvidenceSchema
|
|
14068
|
-
]);
|
|
14069
|
-
var EvidenceBundleSchema = exports_external.object({
|
|
14070
|
-
schema_version: exports_external.literal("1.0.0"),
|
|
14071
|
-
task_id: exports_external.string().min(1),
|
|
14072
|
-
entries: exports_external.array(EvidenceSchema).default([]),
|
|
14073
|
-
created_at: exports_external.string().datetime(),
|
|
14074
|
-
updated_at: exports_external.string().datetime()
|
|
14075
|
-
});
|
|
14076
14092
|
// src/agents/architect.ts
|
|
14077
14093
|
var ARCHITECT_PROMPT = `You are Architect - orchestrator of a multi-agent swarm.
|
|
14078
14094
|
|
|
@@ -30766,9 +30782,39 @@ var gitingest = tool({
|
|
|
30766
30782
|
return fetchGitingest(args);
|
|
30767
30783
|
}
|
|
30768
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
|
+
});
|
|
30769
30815
|
// src/index.ts
|
|
30770
30816
|
var OpenCodeSwarm = async (ctx) => {
|
|
30771
|
-
const config3 =
|
|
30817
|
+
const { config: config3, loadedFromFile } = loadPluginConfigWithMeta(ctx.directory);
|
|
30772
30818
|
const agents = getAgentConfigs(config3);
|
|
30773
30819
|
const agentDefinitions = createAgents(config3);
|
|
30774
30820
|
const pipelineHook = createPipelineTrackerHook(config3);
|
|
@@ -30778,7 +30824,7 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
30778
30824
|
const commandHandler = createSwarmCommandHandler(ctx.directory, Object.fromEntries(agentDefinitions.map((agent) => [agent.name, agent])));
|
|
30779
30825
|
const activityHooks = createAgentActivityHooks(config3, ctx.directory);
|
|
30780
30826
|
const delegationGateHandler = createDelegationGateHook(config3);
|
|
30781
|
-
const guardrailsFallback =
|
|
30827
|
+
const guardrailsFallback = loadedFromFile ? config3.guardrails ?? {} : { ...config3.guardrails, enabled: false };
|
|
30782
30828
|
const guardrailsConfig = GuardrailsConfigSchema.parse(guardrailsFallback);
|
|
30783
30829
|
const delegationHandler = createDelegationTrackerHook(config3, guardrailsConfig.enabled);
|
|
30784
30830
|
const guardrailsHooks = createGuardrailsHooks(guardrailsConfig);
|
|
@@ -30808,7 +30854,8 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
30808
30854
|
detect_domains,
|
|
30809
30855
|
extract_code_blocks,
|
|
30810
30856
|
gitingest,
|
|
30811
|
-
diff
|
|
30857
|
+
diff,
|
|
30858
|
+
retrieve_summary
|
|
30812
30859
|
},
|
|
30813
30860
|
config: async (opencodeConfig) => {
|
|
30814
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.1.
|
|
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",
|