opencode-swarm 6.1.1 → 6.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -3
- package/dist/config/evidence-schema.d.ts +94 -0
- package/dist/config/schema.d.ts +11 -0
- package/dist/index.js +209 -51
- package/dist/state.d.ts +2 -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.2.0-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
5
|
<img src="https://img.shields.io/badge/agents-9-orange" alt="Agents">
|
|
6
|
-
<img src="https://img.shields.io/badge/tests-
|
|
6
|
+
<img src="https://img.shields.io/badge/tests-1391-brightgreen" alt="Tests">
|
|
7
7
|
</p>
|
|
8
8
|
|
|
9
9
|
<h1 align="center">🐝 OpenCode Swarm</h1>
|
|
@@ -233,6 +233,21 @@ Current Phase: 2
|
|
|
233
233
|
|
|
234
234
|
**Start a new session tomorrow?** The Architect reads these files and picks up exactly where you left off.
|
|
235
235
|
|
|
236
|
+
### Evidence Types
|
|
237
|
+
|
|
238
|
+
Each task in `.swarm/evidence/` contains structured evidence bundles with typed entries:
|
|
239
|
+
|
|
240
|
+
| Type | Purpose | Key Fields |
|
|
241
|
+
|------|---------|------------|
|
|
242
|
+
| `review` | Code review verdict | `verdict`, `risk`, `issues[]` |
|
|
243
|
+
| `test` | Test run results | `verdict`, `tests_passed`, `tests_failed`, `coverage` |
|
|
244
|
+
| `diff` | Git diff summary | `files_changed[]`, `additions`, `deletions` |
|
|
245
|
+
| `approval` | Stakeholder sign-off | `approver`, `notes` |
|
|
246
|
+
| `note` | General observations | `content` |
|
|
247
|
+
| `retrospective` | Phase metrics & lessons | `phase_number`, `total_tool_calls`, `coder_revisions`, `reviewer_rejections`, `test_failures`, `security_findings`, `task_count`, `task_complexity`, `top_rejection_reasons[]`, `lessons_learned[]` |
|
|
248
|
+
|
|
249
|
+
**Retrospective Evidence** (v6.2.0+): After each phase completes, the architect writes a retrospective evidence bundle capturing what went well and what didn't. The system enhancer injects the most recent retrospective as a `[SWARM RETROSPECTIVE]` hint at the start of the next phase, enabling continuous improvement across phases.
|
|
250
|
+
|
|
236
251
|
---
|
|
237
252
|
|
|
238
253
|
## Heterogeneous Models = Better Code
|
|
@@ -343,6 +358,18 @@ bunx opencode-swarm uninstall --clean
|
|
|
343
358
|
|
|
344
359
|
## What's New
|
|
345
360
|
|
|
361
|
+
### v6.2.0 — System Intelligence
|
|
362
|
+
- **Retrospective evidence** — New evidence type that captures phase metrics (tool calls, revisions, rejections, test failures, security findings) and lessons learned. Architect writes it after each phase; system enhancer injects the most recent one as a `[SWARM RETROSPECTIVE]` hint for the next phase, enabling continuous improvement across phases.
|
|
363
|
+
- **Soft compaction advisory** — System enhancer injects a `[SWARM HINT]` when the architect's tool-call count crosses configurable thresholds (default 50/75/100/125/150). A `lastCompactionHint` guard prevents re-injection at the same threshold. Configurable via `compaction_advisory` block.
|
|
364
|
+
- **Coverage reporting** — Test engineer now reports line/branch/function coverage percentages and flags files below 70%. Architect uses this in Phase 5 step 5d to request additional test passes when coverage is insufficient.
|
|
365
|
+
- **111 new tests** — 1391 total tests across 62+ files (up from 1280 in v6.1.2).
|
|
366
|
+
|
|
367
|
+
### v6.1.2 — Guardrails Remediation
|
|
368
|
+
- **Fail-safe config validation** — Config validation failures now disable guardrails as a safety precaution (previously Zod defaults could silently re-enable them).
|
|
369
|
+
- **Architect exemption fix** — Architect/orchestrator sessions can no longer inherit 30-minute base limits during delegation race conditions.
|
|
370
|
+
- **Explicit disable always wins** — `guardrails.enabled: false` in config is now always honored, even when the config was loaded from file.
|
|
371
|
+
- **Internal map synchronization** — `startAgentSession()` now keeps `activeAgent` and `agentSessions` maps in sync for consistent state tracking.
|
|
372
|
+
|
|
346
373
|
### v6.1.1 — Security Fix & Tech Debt
|
|
347
374
|
- **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
375
|
- **TOCTOU protection** — Added atomic-style content checks in the config loader to prevent race conditions during file reads.
|
|
@@ -587,6 +614,22 @@ Control whether contract change detection triggers impact analysis:
|
|
|
587
614
|
}
|
|
588
615
|
```
|
|
589
616
|
|
|
617
|
+
### Compaction Advisory
|
|
618
|
+
|
|
619
|
+
Control when the system hints about context compaction thresholds:
|
|
620
|
+
|
|
621
|
+
```jsonc
|
|
622
|
+
{
|
|
623
|
+
"compaction_advisory": {
|
|
624
|
+
"enabled": true, // default: true
|
|
625
|
+
"thresholds": [50, 75, 100, 125, 150], // tool-call counts that trigger hints
|
|
626
|
+
"message": "Large context may benefit from compaction" // custom message
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
When the architect's tool-call count crosses a threshold, the system enhancer injects a `[SWARM HINT]` suggesting context management. Each threshold fires only once per session (tracked via `lastCompactionHint`).
|
|
632
|
+
|
|
590
633
|
> **Architect is exempt/unlimited by default:** The architect agent has no guardrail limits by default. To override, add a `profiles.architect` entry in your guardrails config.
|
|
591
634
|
|
|
592
635
|
### Per-Invocation Budgets
|
|
@@ -653,7 +696,7 @@ bun test
|
|
|
653
696
|
bun test tests/unit/config/schema.test.ts
|
|
654
697
|
```
|
|
655
698
|
|
|
656
|
-
|
|
699
|
+
1391 tests across 62+ 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.
|
|
657
700
|
|
|
658
701
|
## Troubleshooting
|
|
659
702
|
|
|
@@ -8,6 +8,7 @@ export declare const EvidenceTypeSchema: z.ZodEnum<{
|
|
|
8
8
|
diff: "diff";
|
|
9
9
|
approval: "approval";
|
|
10
10
|
note: "note";
|
|
11
|
+
retrospective: "retrospective";
|
|
11
12
|
}>;
|
|
12
13
|
export type EvidenceType = z.infer<typeof EvidenceTypeSchema>;
|
|
13
14
|
export declare const EvidenceVerdictSchema: z.ZodEnum<{
|
|
@@ -26,6 +27,7 @@ export declare const BaseEvidenceSchema: z.ZodObject<{
|
|
|
26
27
|
diff: "diff";
|
|
27
28
|
approval: "approval";
|
|
28
29
|
note: "note";
|
|
30
|
+
retrospective: "retrospective";
|
|
29
31
|
}>;
|
|
30
32
|
timestamp: z.ZodString;
|
|
31
33
|
agent: z.ZodString;
|
|
@@ -147,6 +149,38 @@ export declare const NoteEvidenceSchema: z.ZodObject<{
|
|
|
147
149
|
type: z.ZodLiteral<"note">;
|
|
148
150
|
}, z.core.$strip>;
|
|
149
151
|
export type NoteEvidence = z.infer<typeof NoteEvidenceSchema>;
|
|
152
|
+
export declare const RetrospectiveEvidenceSchema: z.ZodObject<{
|
|
153
|
+
task_id: z.ZodString;
|
|
154
|
+
timestamp: z.ZodString;
|
|
155
|
+
agent: z.ZodString;
|
|
156
|
+
verdict: z.ZodEnum<{
|
|
157
|
+
pass: "pass";
|
|
158
|
+
fail: "fail";
|
|
159
|
+
approved: "approved";
|
|
160
|
+
rejected: "rejected";
|
|
161
|
+
info: "info";
|
|
162
|
+
}>;
|
|
163
|
+
summary: z.ZodString;
|
|
164
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
165
|
+
type: z.ZodLiteral<"retrospective">;
|
|
166
|
+
phase_number: z.ZodNumber;
|
|
167
|
+
total_tool_calls: z.ZodNumber;
|
|
168
|
+
coder_revisions: z.ZodNumber;
|
|
169
|
+
reviewer_rejections: z.ZodNumber;
|
|
170
|
+
test_failures: z.ZodNumber;
|
|
171
|
+
security_findings: z.ZodNumber;
|
|
172
|
+
integration_issues: z.ZodNumber;
|
|
173
|
+
task_count: z.ZodNumber;
|
|
174
|
+
task_complexity: z.ZodEnum<{
|
|
175
|
+
trivial: "trivial";
|
|
176
|
+
simple: "simple";
|
|
177
|
+
moderate: "moderate";
|
|
178
|
+
complex: "complex";
|
|
179
|
+
}>;
|
|
180
|
+
top_rejection_reasons: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
181
|
+
lessons_learned: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
182
|
+
}, z.core.$strip>;
|
|
183
|
+
export type RetrospectiveEvidence = z.infer<typeof RetrospectiveEvidenceSchema>;
|
|
150
184
|
export declare const EvidenceSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
151
185
|
task_id: z.ZodString;
|
|
152
186
|
timestamp: z.ZodString;
|
|
@@ -244,6 +278,36 @@ export declare const EvidenceSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
244
278
|
summary: z.ZodString;
|
|
245
279
|
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
246
280
|
type: z.ZodLiteral<"note">;
|
|
281
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
282
|
+
task_id: z.ZodString;
|
|
283
|
+
timestamp: z.ZodString;
|
|
284
|
+
agent: z.ZodString;
|
|
285
|
+
verdict: z.ZodEnum<{
|
|
286
|
+
pass: "pass";
|
|
287
|
+
fail: "fail";
|
|
288
|
+
approved: "approved";
|
|
289
|
+
rejected: "rejected";
|
|
290
|
+
info: "info";
|
|
291
|
+
}>;
|
|
292
|
+
summary: z.ZodString;
|
|
293
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
294
|
+
type: z.ZodLiteral<"retrospective">;
|
|
295
|
+
phase_number: z.ZodNumber;
|
|
296
|
+
total_tool_calls: z.ZodNumber;
|
|
297
|
+
coder_revisions: z.ZodNumber;
|
|
298
|
+
reviewer_rejections: z.ZodNumber;
|
|
299
|
+
test_failures: z.ZodNumber;
|
|
300
|
+
security_findings: z.ZodNumber;
|
|
301
|
+
integration_issues: z.ZodNumber;
|
|
302
|
+
task_count: z.ZodNumber;
|
|
303
|
+
task_complexity: z.ZodEnum<{
|
|
304
|
+
trivial: "trivial";
|
|
305
|
+
simple: "simple";
|
|
306
|
+
moderate: "moderate";
|
|
307
|
+
complex: "complex";
|
|
308
|
+
}>;
|
|
309
|
+
top_rejection_reasons: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
310
|
+
lessons_learned: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
247
311
|
}, z.core.$strip>], "type">;
|
|
248
312
|
export type Evidence = z.infer<typeof EvidenceSchema>;
|
|
249
313
|
export declare const EvidenceBundleSchema: z.ZodObject<{
|
|
@@ -346,6 +410,36 @@ export declare const EvidenceBundleSchema: z.ZodObject<{
|
|
|
346
410
|
summary: z.ZodString;
|
|
347
411
|
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
348
412
|
type: z.ZodLiteral<"note">;
|
|
413
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
414
|
+
task_id: z.ZodString;
|
|
415
|
+
timestamp: z.ZodString;
|
|
416
|
+
agent: z.ZodString;
|
|
417
|
+
verdict: z.ZodEnum<{
|
|
418
|
+
pass: "pass";
|
|
419
|
+
fail: "fail";
|
|
420
|
+
approved: "approved";
|
|
421
|
+
rejected: "rejected";
|
|
422
|
+
info: "info";
|
|
423
|
+
}>;
|
|
424
|
+
summary: z.ZodString;
|
|
425
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
426
|
+
type: z.ZodLiteral<"retrospective">;
|
|
427
|
+
phase_number: z.ZodNumber;
|
|
428
|
+
total_tool_calls: z.ZodNumber;
|
|
429
|
+
coder_revisions: z.ZodNumber;
|
|
430
|
+
reviewer_rejections: z.ZodNumber;
|
|
431
|
+
test_failures: z.ZodNumber;
|
|
432
|
+
security_findings: z.ZodNumber;
|
|
433
|
+
integration_issues: z.ZodNumber;
|
|
434
|
+
task_count: z.ZodNumber;
|
|
435
|
+
task_complexity: z.ZodEnum<{
|
|
436
|
+
trivial: "trivial";
|
|
437
|
+
simple: "simple";
|
|
438
|
+
moderate: "moderate";
|
|
439
|
+
complex: "complex";
|
|
440
|
+
}>;
|
|
441
|
+
top_rejection_reasons: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
442
|
+
lessons_learned: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
349
443
|
}, z.core.$strip>], "type">>>;
|
|
350
444
|
created_at: z.ZodString;
|
|
351
445
|
updated_at: z.ZodString;
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -148,6 +148,12 @@ export declare const UIReviewConfigSchema: z.ZodObject<{
|
|
|
148
148
|
trigger_keywords: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
149
149
|
}, z.core.$strip>;
|
|
150
150
|
export type UIReviewConfig = z.infer<typeof UIReviewConfigSchema>;
|
|
151
|
+
export declare const CompactionAdvisoryConfigSchema: z.ZodObject<{
|
|
152
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
153
|
+
thresholds: z.ZodDefault<z.ZodArray<z.ZodNumber>>;
|
|
154
|
+
message: z.ZodDefault<z.ZodString>;
|
|
155
|
+
}, z.core.$strip>;
|
|
156
|
+
export type CompactionAdvisoryConfig = z.infer<typeof CompactionAdvisoryConfigSchema>;
|
|
151
157
|
export declare const GuardrailsProfileSchema: z.ZodObject<{
|
|
152
158
|
max_tool_calls: z.ZodOptional<z.ZodNumber>;
|
|
153
159
|
max_duration_minutes: z.ZodOptional<z.ZodNumber>;
|
|
@@ -318,6 +324,11 @@ export declare const PluginConfigSchema: z.ZodObject<{
|
|
|
318
324
|
trigger_paths: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
319
325
|
trigger_keywords: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
320
326
|
}, z.core.$strip>>;
|
|
327
|
+
compaction_advisory: z.ZodOptional<z.ZodObject<{
|
|
328
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
329
|
+
thresholds: z.ZodDefault<z.ZodArray<z.ZodNumber>>;
|
|
330
|
+
message: z.ZodDefault<z.ZodString>;
|
|
331
|
+
}, z.core.$strip>>;
|
|
321
332
|
}, z.core.$strip>;
|
|
322
333
|
export type PluginConfig = z.infer<typeof PluginConfigSchema>;
|
|
323
334
|
export type { AgentName, PipelineAgentName, QAAgentName, } from './constants';
|
package/dist/index.js
CHANGED
|
@@ -1,20 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
4
2
|
var __defProp = Object.defineProperty;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __toESM = (mod, isNodeMode, target) => {
|
|
8
|
-
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
9
|
-
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
10
|
-
for (let key of __getOwnPropNames(mod))
|
|
11
|
-
if (!__hasOwnProp.call(to, key))
|
|
12
|
-
__defProp(to, key, {
|
|
13
|
-
get: () => mod[key],
|
|
14
|
-
enumerable: true
|
|
15
|
-
});
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
3
|
var __export = (target, all) => {
|
|
19
4
|
for (var name in all)
|
|
20
5
|
__defProp(target, name, {
|
|
@@ -13644,7 +13629,8 @@ var EvidenceTypeSchema = exports_external.enum([
|
|
|
13644
13629
|
"test",
|
|
13645
13630
|
"diff",
|
|
13646
13631
|
"approval",
|
|
13647
|
-
"note"
|
|
13632
|
+
"note",
|
|
13633
|
+
"retrospective"
|
|
13648
13634
|
]);
|
|
13649
13635
|
var EvidenceVerdictSchema = exports_external.enum([
|
|
13650
13636
|
"pass",
|
|
@@ -13695,12 +13681,27 @@ var ApprovalEvidenceSchema = BaseEvidenceSchema.extend({
|
|
|
13695
13681
|
var NoteEvidenceSchema = BaseEvidenceSchema.extend({
|
|
13696
13682
|
type: exports_external.literal("note")
|
|
13697
13683
|
});
|
|
13684
|
+
var RetrospectiveEvidenceSchema = BaseEvidenceSchema.extend({
|
|
13685
|
+
type: exports_external.literal("retrospective"),
|
|
13686
|
+
phase_number: exports_external.number().int().min(0),
|
|
13687
|
+
total_tool_calls: exports_external.number().int().min(0),
|
|
13688
|
+
coder_revisions: exports_external.number().int().min(0),
|
|
13689
|
+
reviewer_rejections: exports_external.number().int().min(0),
|
|
13690
|
+
test_failures: exports_external.number().int().min(0),
|
|
13691
|
+
security_findings: exports_external.number().int().min(0),
|
|
13692
|
+
integration_issues: exports_external.number().int().min(0),
|
|
13693
|
+
task_count: exports_external.number().int().min(1),
|
|
13694
|
+
task_complexity: exports_external.enum(["trivial", "simple", "moderate", "complex"]),
|
|
13695
|
+
top_rejection_reasons: exports_external.array(exports_external.string()).default([]),
|
|
13696
|
+
lessons_learned: exports_external.array(exports_external.string()).max(5).default([])
|
|
13697
|
+
});
|
|
13698
13698
|
var EvidenceSchema = exports_external.discriminatedUnion("type", [
|
|
13699
13699
|
ReviewEvidenceSchema,
|
|
13700
13700
|
TestEvidenceSchema,
|
|
13701
13701
|
DiffEvidenceSchema,
|
|
13702
13702
|
ApprovalEvidenceSchema,
|
|
13703
|
-
NoteEvidenceSchema
|
|
13703
|
+
NoteEvidenceSchema,
|
|
13704
|
+
RetrospectiveEvidenceSchema
|
|
13704
13705
|
]);
|
|
13705
13706
|
var EvidenceBundleSchema = exports_external.object({
|
|
13706
13707
|
schema_version: exports_external.literal("1.0.0"),
|
|
@@ -13836,6 +13837,11 @@ var UIReviewConfigSchema = exports_external.object({
|
|
|
13836
13837
|
"profile page"
|
|
13837
13838
|
])
|
|
13838
13839
|
});
|
|
13840
|
+
var CompactionAdvisoryConfigSchema = exports_external.object({
|
|
13841
|
+
enabled: exports_external.boolean().default(true),
|
|
13842
|
+
thresholds: exports_external.array(exports_external.number().int().min(10).max(500)).default([50, 75, 100, 125, 150]),
|
|
13843
|
+
message: exports_external.string().default("[SWARM HINT] Session has ${totalToolCalls} tool calls. Consider compacting at next phase boundary to maintain context quality.")
|
|
13844
|
+
});
|
|
13839
13845
|
var GuardrailsProfileSchema = exports_external.object({
|
|
13840
13846
|
max_tool_calls: exports_external.number().min(0).max(1000).optional(),
|
|
13841
13847
|
max_duration_minutes: exports_external.number().min(0).max(480).optional(),
|
|
@@ -13949,7 +13955,8 @@ var PluginConfigSchema = exports_external.object({
|
|
|
13949
13955
|
review_passes: ReviewPassesConfigSchema.optional(),
|
|
13950
13956
|
integration_analysis: IntegrationAnalysisConfigSchema.optional(),
|
|
13951
13957
|
docs: DocsConfigSchema.optional(),
|
|
13952
|
-
ui_review: UIReviewConfigSchema.optional()
|
|
13958
|
+
ui_review: UIReviewConfigSchema.optional(),
|
|
13959
|
+
compaction_advisory: CompactionAdvisoryConfigSchema.optional()
|
|
13953
13960
|
});
|
|
13954
13961
|
|
|
13955
13962
|
// src/config/loader.ts
|
|
@@ -14010,7 +14017,9 @@ function loadPluginConfig(directory) {
|
|
|
14010
14017
|
console.warn("[opencode-swarm] Merged config validation failed:");
|
|
14011
14018
|
console.warn(result.error.format());
|
|
14012
14019
|
console.warn("[opencode-swarm] \u26A0\uFE0F Guardrails will be DISABLED as a safety precaution. Fix the config file to restore normal operation.");
|
|
14013
|
-
return PluginConfigSchema.parse({
|
|
14020
|
+
return PluginConfigSchema.parse({
|
|
14021
|
+
guardrails: { enabled: false }
|
|
14022
|
+
});
|
|
14014
14023
|
}
|
|
14015
14024
|
return result.data;
|
|
14016
14025
|
}
|
|
@@ -14130,6 +14139,7 @@ You THINK. Subagents DO. You have the largest context window and strongest reaso
|
|
|
14130
14139
|
- Target file is in: pages/, components/, views/, screens/, ui/, layouts/
|
|
14131
14140
|
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
14141
|
If not triggered: delegate directly to {{AGENT_PREFIX}}coder as normal.
|
|
14142
|
+
10. **RETROSPECTIVE TRACKING**: At the end of every phase, record phase metrics in .swarm/context.md under "## Phase Metrics" and write a retrospective evidence entry via the evidence manager. Track: phase_number, total_tool_calls, coder_revisions, reviewer_rejections, test_failures, security_findings, integration_issues, task_count, task_complexity, top_rejection_reasons, lessons_learned (max 5). Reset Phase Metrics to 0 after writing.
|
|
14133
14143
|
|
|
14134
14144
|
## AGENTS
|
|
14135
14145
|
|
|
@@ -14294,7 +14304,8 @@ For each task (respecting dependencies):
|
|
|
14294
14304
|
5e. Security gate: if file matches security globs or content has security keywords \u2192 {{AGENT_PREFIX}}reviewer security-only. REJECTED \u2192 coder retry.
|
|
14295
14305
|
5f. {{AGENT_PREFIX}}test_engineer - Verification tests. FAIL \u2192 coder retry from 5d.
|
|
14296
14306
|
5g. {{AGENT_PREFIX}}test_engineer - Adversarial tests. FAIL \u2192 coder retry from 5d.
|
|
14297
|
-
5h.
|
|
14307
|
+
5h. COVERAGE CHECK: If test_engineer reports coverage < 70% \u2192 delegate {{AGENT_PREFIX}}test_engineer for an additional test pass targeting uncovered paths. This is a soft guideline; use judgment for trivial tasks.
|
|
14308
|
+
5i. Update plan.md [x], proceed to next task.
|
|
14298
14309
|
|
|
14299
14310
|
### Phase 6: Phase Complete
|
|
14300
14311
|
1. {{AGENT_PREFIX}}explorer - Rescan
|
|
@@ -14303,8 +14314,9 @@ For each task (respecting dependencies):
|
|
|
14303
14314
|
- Summary of what was added/modified/removed
|
|
14304
14315
|
- List of doc files that may need updating (README.md, CONTRIBUTING.md, docs/)
|
|
14305
14316
|
3. Update context.md
|
|
14306
|
-
4.
|
|
14307
|
-
5.
|
|
14317
|
+
4. Write retrospective evidence: record phase_number, total_tool_calls, coder_revisions, reviewer_rejections, test_failures, security_findings, integration_issues, task_count, task_complexity, top_rejection_reasons, lessons_learned to .swarm/evidence/ via the evidence manager. Reset Phase Metrics in context.md to 0.
|
|
14318
|
+
5. Summarize to user
|
|
14319
|
+
6. Ask: "Ready for Phase [N+1]?"
|
|
14308
14320
|
|
|
14309
14321
|
### Blockers
|
|
14310
14322
|
Mark [BLOCKED] in plan.md, skip to next unblocked task, inform user.
|
|
@@ -14904,7 +14916,13 @@ OUTPUT FORMAT:
|
|
|
14904
14916
|
VERDICT: PASS | FAIL
|
|
14905
14917
|
TESTS: [total count] tests, [pass count] passed, [fail count] failed
|
|
14906
14918
|
FAILURES: [list of failed test names + error messages, if any]
|
|
14907
|
-
COVERAGE: [areas covered]
|
|
14919
|
+
COVERAGE: [areas covered]
|
|
14920
|
+
|
|
14921
|
+
COVERAGE REPORTING:
|
|
14922
|
+
- After running tests, report the line/branch coverage percentage if the test runner provides it.
|
|
14923
|
+
- Format: COVERAGE_PCT: [N]% (or "N/A" if not available)
|
|
14924
|
+
- If COVERAGE_PCT < 70%, add a note: "COVERAGE_WARNING: Below 70% threshold \u2014 consider additional test cases for uncovered paths."
|
|
14925
|
+
- The architect uses this to decide whether to request an additional test pass (Rule 10 / Phase 5 step 5h).`;
|
|
14908
14926
|
function createTestEngineerAgent(model, customPrompt, customAppendPrompt) {
|
|
14909
14927
|
let prompt = TEST_ENGINEER_PROMPT;
|
|
14910
14928
|
if (customPrompt) {
|
|
@@ -15447,9 +15465,11 @@ function startAgentSession(sessionId, agentName, staleDurationMs = 7200000) {
|
|
|
15447
15465
|
delegationActive: false,
|
|
15448
15466
|
activeInvocationId: 0,
|
|
15449
15467
|
lastInvocationIdByAgent: {},
|
|
15450
|
-
windows: {}
|
|
15468
|
+
windows: {},
|
|
15469
|
+
lastCompactionHint: 0
|
|
15451
15470
|
};
|
|
15452
15471
|
swarmState.agentSessions.set(sessionId, sessionState);
|
|
15472
|
+
swarmState.activeAgent.set(sessionId, agentName);
|
|
15453
15473
|
}
|
|
15454
15474
|
function ensureAgentSession(sessionId, agentName) {
|
|
15455
15475
|
const now = Date.now();
|
|
@@ -15470,6 +15490,9 @@ function ensureAgentSession(sessionId, agentName) {
|
|
|
15470
15490
|
session.lastInvocationIdByAgent = {};
|
|
15471
15491
|
session.windows = {};
|
|
15472
15492
|
}
|
|
15493
|
+
if (session.lastCompactionHint === undefined) {
|
|
15494
|
+
session.lastCompactionHint = 0;
|
|
15495
|
+
}
|
|
15473
15496
|
session.lastToolCallTime = now;
|
|
15474
15497
|
return session;
|
|
15475
15498
|
}
|
|
@@ -17268,7 +17291,7 @@ function createGuardrailsHooks(config2) {
|
|
|
17268
17291
|
return;
|
|
17269
17292
|
}
|
|
17270
17293
|
}
|
|
17271
|
-
const agentName = swarmState.activeAgent.get(input.sessionID);
|
|
17294
|
+
const agentName = swarmState.activeAgent.get(input.sessionID) ?? ORCHESTRATOR_NAME;
|
|
17272
17295
|
const session = ensureAgentSession(input.sessionID, agentName);
|
|
17273
17296
|
const resolvedName = stripKnownSwarmPrefix(session.agentName);
|
|
17274
17297
|
if (resolvedName === ORCHESTRATOR_NAME) {
|
|
@@ -17491,6 +17514,10 @@ ${originalText}`;
|
|
|
17491
17514
|
})
|
|
17492
17515
|
};
|
|
17493
17516
|
}
|
|
17517
|
+
// src/hooks/system-enhancer.ts
|
|
17518
|
+
import * as fs3 from "fs";
|
|
17519
|
+
import * as path7 from "path";
|
|
17520
|
+
|
|
17494
17521
|
// src/hooks/context-scoring.ts
|
|
17495
17522
|
function calculateAgeFactor(ageHours, config2) {
|
|
17496
17523
|
if (ageHours <= 0) {
|
|
@@ -17626,6 +17653,66 @@ function createSystemEnhancerHook(config2, directory) {
|
|
|
17626
17653
|
if (config2.docs?.enabled === false) {
|
|
17627
17654
|
tryInject("[SWARM CONFIG] Docs agent is DISABLED. Skip docs delegation in Phase 6.");
|
|
17628
17655
|
}
|
|
17656
|
+
const sessionId_retro = _input.sessionID;
|
|
17657
|
+
const activeAgent_retro = swarmState.activeAgent.get(sessionId_retro ?? "");
|
|
17658
|
+
const isArchitect = !activeAgent_retro || stripKnownSwarmPrefix(activeAgent_retro) === "architect";
|
|
17659
|
+
if (isArchitect) {
|
|
17660
|
+
try {
|
|
17661
|
+
const evidenceDir = path7.join(directory, ".swarm", "evidence");
|
|
17662
|
+
if (fs3.existsSync(evidenceDir)) {
|
|
17663
|
+
const files = fs3.readdirSync(evidenceDir).filter((f) => f.endsWith(".json")).sort().reverse();
|
|
17664
|
+
for (const file2 of files.slice(0, 5)) {
|
|
17665
|
+
const content = JSON.parse(fs3.readFileSync(path7.join(evidenceDir, file2), "utf-8"));
|
|
17666
|
+
if (content.type === "retrospective") {
|
|
17667
|
+
const retro = content;
|
|
17668
|
+
const hints = [];
|
|
17669
|
+
if (retro.reviewer_rejections > 2) {
|
|
17670
|
+
hints.push(`Phase ${retro.phase_number} had ${retro.reviewer_rejections} reviewer rejections.`);
|
|
17671
|
+
}
|
|
17672
|
+
if (retro.top_rejection_reasons.length > 0) {
|
|
17673
|
+
hints.push(`Common rejection reasons: ${retro.top_rejection_reasons.join(", ")}.`);
|
|
17674
|
+
}
|
|
17675
|
+
if (retro.lessons_learned.length > 0) {
|
|
17676
|
+
hints.push(`Lessons: ${retro.lessons_learned.join("; ")}.`);
|
|
17677
|
+
}
|
|
17678
|
+
if (hints.length > 0) {
|
|
17679
|
+
const retroHint = `[SWARM RETROSPECTIVE] From Phase ${retro.phase_number}: ${hints.join(" ")}`;
|
|
17680
|
+
if (retroHint.length <= 800) {
|
|
17681
|
+
tryInject(retroHint);
|
|
17682
|
+
} else {
|
|
17683
|
+
tryInject(retroHint.substring(0, 800) + "...");
|
|
17684
|
+
}
|
|
17685
|
+
}
|
|
17686
|
+
break;
|
|
17687
|
+
}
|
|
17688
|
+
}
|
|
17689
|
+
}
|
|
17690
|
+
} catch {}
|
|
17691
|
+
const compactionConfig = config2.compaction_advisory;
|
|
17692
|
+
if (compactionConfig?.enabled !== false && sessionId_retro) {
|
|
17693
|
+
const session = swarmState.agentSessions.get(sessionId_retro);
|
|
17694
|
+
if (session) {
|
|
17695
|
+
const totalToolCalls = Array.from(swarmState.toolAggregates.values()).reduce((sum, agg) => sum + agg.count, 0);
|
|
17696
|
+
const thresholds = compactionConfig?.thresholds ?? [
|
|
17697
|
+
50,
|
|
17698
|
+
75,
|
|
17699
|
+
100,
|
|
17700
|
+
125,
|
|
17701
|
+
150
|
|
17702
|
+
];
|
|
17703
|
+
const lastHint = session.lastCompactionHint || 0;
|
|
17704
|
+
for (const threshold of thresholds) {
|
|
17705
|
+
if (totalToolCalls >= threshold && lastHint < threshold) {
|
|
17706
|
+
const messageTemplate = compactionConfig?.message ?? "[SWARM HINT] Session has ${totalToolCalls} tool calls. Consider compacting at next phase boundary to maintain context quality.";
|
|
17707
|
+
const message = messageTemplate.replace("${totalToolCalls}", String(totalToolCalls));
|
|
17708
|
+
tryInject(message);
|
|
17709
|
+
session.lastCompactionHint = threshold;
|
|
17710
|
+
break;
|
|
17711
|
+
}
|
|
17712
|
+
}
|
|
17713
|
+
}
|
|
17714
|
+
}
|
|
17715
|
+
}
|
|
17629
17716
|
return;
|
|
17630
17717
|
}
|
|
17631
17718
|
const userScoringConfig = config2.context_budget?.scoring;
|
|
@@ -17749,6 +17836,77 @@ function createSystemEnhancerHook(config2, directory) {
|
|
|
17749
17836
|
metadata: { contentType: "prose" }
|
|
17750
17837
|
});
|
|
17751
17838
|
}
|
|
17839
|
+
const sessionId_retro_b = _input.sessionID;
|
|
17840
|
+
const activeAgent_retro_b = swarmState.activeAgent.get(sessionId_retro_b ?? "");
|
|
17841
|
+
const isArchitect_b = !activeAgent_retro_b || stripKnownSwarmPrefix(activeAgent_retro_b) === "architect";
|
|
17842
|
+
if (isArchitect_b) {
|
|
17843
|
+
try {
|
|
17844
|
+
const evidenceDir_b = path7.join(directory, ".swarm", "evidence");
|
|
17845
|
+
if (fs3.existsSync(evidenceDir_b)) {
|
|
17846
|
+
const files_b = fs3.readdirSync(evidenceDir_b).filter((f) => f.endsWith(".json")).sort().reverse();
|
|
17847
|
+
for (const file2 of files_b.slice(0, 5)) {
|
|
17848
|
+
const content_b = JSON.parse(fs3.readFileSync(path7.join(evidenceDir_b, file2), "utf-8"));
|
|
17849
|
+
if (content_b.type === "retrospective") {
|
|
17850
|
+
const retro_b = content_b;
|
|
17851
|
+
const hints_b = [];
|
|
17852
|
+
if (retro_b.reviewer_rejections > 2) {
|
|
17853
|
+
hints_b.push(`Phase ${retro_b.phase_number} had ${retro_b.reviewer_rejections} reviewer rejections.`);
|
|
17854
|
+
}
|
|
17855
|
+
if (retro_b.top_rejection_reasons.length > 0) {
|
|
17856
|
+
hints_b.push(`Common rejection reasons: ${retro_b.top_rejection_reasons.join(", ")}.`);
|
|
17857
|
+
}
|
|
17858
|
+
if (retro_b.lessons_learned.length > 0) {
|
|
17859
|
+
hints_b.push(`Lessons: ${retro_b.lessons_learned.join("; ")}.`);
|
|
17860
|
+
}
|
|
17861
|
+
if (hints_b.length > 0) {
|
|
17862
|
+
const retroHint_b = `[SWARM RETROSPECTIVE] From Phase ${retro_b.phase_number}: ${hints_b.join(" ")}`;
|
|
17863
|
+
const retroText = retroHint_b.length <= 800 ? retroHint_b : retroHint_b.substring(0, 800) + "...";
|
|
17864
|
+
candidates.push({
|
|
17865
|
+
id: `candidate-${idCounter++}`,
|
|
17866
|
+
kind: "phase",
|
|
17867
|
+
text: retroText,
|
|
17868
|
+
tokens: estimateTokens(retroText),
|
|
17869
|
+
priority: 2,
|
|
17870
|
+
metadata: { contentType: "prose" }
|
|
17871
|
+
});
|
|
17872
|
+
}
|
|
17873
|
+
break;
|
|
17874
|
+
}
|
|
17875
|
+
}
|
|
17876
|
+
}
|
|
17877
|
+
} catch {}
|
|
17878
|
+
const compactionConfig_b = config2.compaction_advisory;
|
|
17879
|
+
if (compactionConfig_b?.enabled !== false && sessionId_retro_b) {
|
|
17880
|
+
const session_b = swarmState.agentSessions.get(sessionId_retro_b);
|
|
17881
|
+
if (session_b) {
|
|
17882
|
+
const totalToolCalls_b = Array.from(swarmState.toolAggregates.values()).reduce((sum, agg) => sum + agg.count, 0);
|
|
17883
|
+
const thresholds_b = compactionConfig_b?.thresholds ?? [
|
|
17884
|
+
50,
|
|
17885
|
+
75,
|
|
17886
|
+
100,
|
|
17887
|
+
125,
|
|
17888
|
+
150
|
|
17889
|
+
];
|
|
17890
|
+
const lastHint_b = session_b.lastCompactionHint || 0;
|
|
17891
|
+
for (const threshold of thresholds_b) {
|
|
17892
|
+
if (totalToolCalls_b >= threshold && lastHint_b < threshold) {
|
|
17893
|
+
const messageTemplate_b = compactionConfig_b?.message ?? "[SWARM HINT] Session has ${totalToolCalls} tool calls. Consider compacting at next phase boundary to maintain context quality.";
|
|
17894
|
+
const compactionText = messageTemplate_b.replace("${totalToolCalls}", String(totalToolCalls_b));
|
|
17895
|
+
candidates.push({
|
|
17896
|
+
id: `candidate-${idCounter++}`,
|
|
17897
|
+
kind: "phase",
|
|
17898
|
+
text: compactionText,
|
|
17899
|
+
tokens: estimateTokens(compactionText),
|
|
17900
|
+
priority: 1,
|
|
17901
|
+
metadata: { contentType: "prose" }
|
|
17902
|
+
});
|
|
17903
|
+
session_b.lastCompactionHint = threshold;
|
|
17904
|
+
break;
|
|
17905
|
+
}
|
|
17906
|
+
}
|
|
17907
|
+
}
|
|
17908
|
+
}
|
|
17909
|
+
}
|
|
17752
17910
|
const ranked = rankCandidates(candidates, effectiveConfig);
|
|
17753
17911
|
for (const candidate of ranked) {
|
|
17754
17912
|
if (injectedTokens + candidate.tokens > maxInjectionTokens) {
|
|
@@ -18675,10 +18833,10 @@ function mergeDefs2(...defs) {
|
|
|
18675
18833
|
function cloneDef2(schema) {
|
|
18676
18834
|
return mergeDefs2(schema._zod.def);
|
|
18677
18835
|
}
|
|
18678
|
-
function getElementAtPath2(obj,
|
|
18679
|
-
if (!
|
|
18836
|
+
function getElementAtPath2(obj, path8) {
|
|
18837
|
+
if (!path8)
|
|
18680
18838
|
return obj;
|
|
18681
|
-
return
|
|
18839
|
+
return path8.reduce((acc, key) => acc?.[key], obj);
|
|
18682
18840
|
}
|
|
18683
18841
|
function promiseAllObject2(promisesObj) {
|
|
18684
18842
|
const keys = Object.keys(promisesObj);
|
|
@@ -19037,11 +19195,11 @@ function aborted2(x, startIndex = 0) {
|
|
|
19037
19195
|
}
|
|
19038
19196
|
return false;
|
|
19039
19197
|
}
|
|
19040
|
-
function prefixIssues2(
|
|
19198
|
+
function prefixIssues2(path8, issues) {
|
|
19041
19199
|
return issues.map((iss) => {
|
|
19042
19200
|
var _a2;
|
|
19043
19201
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
19044
|
-
iss.path.unshift(
|
|
19202
|
+
iss.path.unshift(path8);
|
|
19045
19203
|
return iss;
|
|
19046
19204
|
});
|
|
19047
19205
|
}
|
|
@@ -19209,7 +19367,7 @@ function treeifyError2(error49, _mapper) {
|
|
|
19209
19367
|
return issue3.message;
|
|
19210
19368
|
};
|
|
19211
19369
|
const result = { errors: [] };
|
|
19212
|
-
const processError = (error50,
|
|
19370
|
+
const processError = (error50, path8 = []) => {
|
|
19213
19371
|
var _a2, _b;
|
|
19214
19372
|
for (const issue3 of error50.issues) {
|
|
19215
19373
|
if (issue3.code === "invalid_union" && issue3.errors.length) {
|
|
@@ -19219,7 +19377,7 @@ function treeifyError2(error49, _mapper) {
|
|
|
19219
19377
|
} else if (issue3.code === "invalid_element") {
|
|
19220
19378
|
processError({ issues: issue3.issues }, issue3.path);
|
|
19221
19379
|
} else {
|
|
19222
|
-
const fullpath = [...
|
|
19380
|
+
const fullpath = [...path8, ...issue3.path];
|
|
19223
19381
|
if (fullpath.length === 0) {
|
|
19224
19382
|
result.errors.push(mapper(issue3));
|
|
19225
19383
|
continue;
|
|
@@ -19251,8 +19409,8 @@ function treeifyError2(error49, _mapper) {
|
|
|
19251
19409
|
}
|
|
19252
19410
|
function toDotPath2(_path) {
|
|
19253
19411
|
const segs = [];
|
|
19254
|
-
const
|
|
19255
|
-
for (const seg of
|
|
19412
|
+
const path8 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
19413
|
+
for (const seg of path8) {
|
|
19256
19414
|
if (typeof seg === "number")
|
|
19257
19415
|
segs.push(`[${seg}]`);
|
|
19258
19416
|
else if (typeof seg === "symbol")
|
|
@@ -30292,14 +30450,14 @@ function validateBase(base) {
|
|
|
30292
30450
|
function validatePaths(paths) {
|
|
30293
30451
|
if (!paths)
|
|
30294
30452
|
return null;
|
|
30295
|
-
for (const
|
|
30296
|
-
if (!
|
|
30453
|
+
for (const path8 of paths) {
|
|
30454
|
+
if (!path8 || path8.length === 0) {
|
|
30297
30455
|
return "empty path not allowed";
|
|
30298
30456
|
}
|
|
30299
|
-
if (
|
|
30457
|
+
if (path8.length > MAX_PATH_LENGTH) {
|
|
30300
30458
|
return `path exceeds maximum length of ${MAX_PATH_LENGTH}`;
|
|
30301
30459
|
}
|
|
30302
|
-
if (SHELL_METACHARACTERS.test(
|
|
30460
|
+
if (SHELL_METACHARACTERS.test(path8)) {
|
|
30303
30461
|
return "path contains shell metacharacters";
|
|
30304
30462
|
}
|
|
30305
30463
|
}
|
|
@@ -30362,8 +30520,8 @@ var diff = tool({
|
|
|
30362
30520
|
if (parts.length >= 3) {
|
|
30363
30521
|
const additions = parseInt(parts[0]) || 0;
|
|
30364
30522
|
const deletions = parseInt(parts[1]) || 0;
|
|
30365
|
-
const
|
|
30366
|
-
files.push({ path:
|
|
30523
|
+
const path8 = parts[2];
|
|
30524
|
+
files.push({ path: path8, additions, deletions });
|
|
30367
30525
|
}
|
|
30368
30526
|
}
|
|
30369
30527
|
const contractChanges = [];
|
|
@@ -30589,8 +30747,8 @@ Use these as DOMAIN values when delegating to @sme.`;
|
|
|
30589
30747
|
}
|
|
30590
30748
|
});
|
|
30591
30749
|
// src/tools/file-extractor.ts
|
|
30592
|
-
import * as
|
|
30593
|
-
import * as
|
|
30750
|
+
import * as fs4 from "fs";
|
|
30751
|
+
import * as path8 from "path";
|
|
30594
30752
|
var EXT_MAP = {
|
|
30595
30753
|
python: ".py",
|
|
30596
30754
|
py: ".py",
|
|
@@ -30652,8 +30810,8 @@ var extract_code_blocks = tool({
|
|
|
30652
30810
|
execute: async (args) => {
|
|
30653
30811
|
const { content, output_dir, prefix } = args;
|
|
30654
30812
|
const targetDir = output_dir || process.cwd();
|
|
30655
|
-
if (!
|
|
30656
|
-
|
|
30813
|
+
if (!fs4.existsSync(targetDir)) {
|
|
30814
|
+
fs4.mkdirSync(targetDir, { recursive: true });
|
|
30657
30815
|
}
|
|
30658
30816
|
const pattern = /```(\w*)\n([\s\S]*?)```/g;
|
|
30659
30817
|
const matches = [...content.matchAll(pattern)];
|
|
@@ -30668,16 +30826,16 @@ var extract_code_blocks = tool({
|
|
|
30668
30826
|
if (prefix) {
|
|
30669
30827
|
filename = `${prefix}_${filename}`;
|
|
30670
30828
|
}
|
|
30671
|
-
let filepath =
|
|
30672
|
-
const base =
|
|
30673
|
-
const ext =
|
|
30829
|
+
let filepath = path8.join(targetDir, filename);
|
|
30830
|
+
const base = path8.basename(filepath, path8.extname(filepath));
|
|
30831
|
+
const ext = path8.extname(filepath);
|
|
30674
30832
|
let counter = 1;
|
|
30675
|
-
while (
|
|
30676
|
-
filepath =
|
|
30833
|
+
while (fs4.existsSync(filepath)) {
|
|
30834
|
+
filepath = path8.join(targetDir, `${base}_${counter}${ext}`);
|
|
30677
30835
|
counter++;
|
|
30678
30836
|
}
|
|
30679
30837
|
try {
|
|
30680
|
-
|
|
30838
|
+
fs4.writeFileSync(filepath, code.trim(), "utf-8");
|
|
30681
30839
|
savedFiles.push(filepath);
|
|
30682
30840
|
} catch (error93) {
|
|
30683
30841
|
errors5.push(`Failed to save ${filename}: ${error93 instanceof Error ? error93.message : String(error93)}`);
|
|
@@ -30824,7 +30982,7 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
30824
30982
|
const commandHandler = createSwarmCommandHandler(ctx.directory, Object.fromEntries(agentDefinitions.map((agent) => [agent.name, agent])));
|
|
30825
30983
|
const activityHooks = createAgentActivityHooks(config3, ctx.directory);
|
|
30826
30984
|
const delegationGateHandler = createDelegationGateHook(config3);
|
|
30827
|
-
const guardrailsFallback = loadedFromFile ? config3.guardrails ?? {} : { ...config3.guardrails, enabled: false };
|
|
30985
|
+
const guardrailsFallback = config3.guardrails?.enabled === false ? { ...config3.guardrails, enabled: false } : loadedFromFile ? config3.guardrails ?? {} : { ...config3.guardrails, enabled: false };
|
|
30828
30986
|
const guardrailsConfig = GuardrailsConfigSchema.parse(guardrailsFallback);
|
|
30829
30987
|
const delegationHandler = createDelegationTrackerHook(config3, guardrailsConfig.enabled);
|
|
30830
30988
|
const guardrailsHooks = createGuardrailsHooks(guardrailsConfig);
|
package/dist/state.d.ts
CHANGED
|
@@ -53,6 +53,8 @@ export interface AgentSessionState {
|
|
|
53
53
|
lastInvocationIdByAgent: Record<string, number>;
|
|
54
54
|
/** Active invocation windows keyed by "${agentName}:${invId}" */
|
|
55
55
|
windows: Record<string, InvocationWindow>;
|
|
56
|
+
/** Last tool-call threshold at which a compaction hint was issued */
|
|
57
|
+
lastCompactionHint: number;
|
|
56
58
|
}
|
|
57
59
|
/**
|
|
58
60
|
* Represents a single agent invocation window with isolated guardrail budgets.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-swarm",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.2.0",
|
|
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",
|