opencode-swarm 6.33.0 → 6.33.2
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 +83 -7
- package/dist/cli/index.js +147 -33
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/registry.d.ts +4 -0
- package/dist/commands/reset-session.d.ts +7 -0
- package/dist/config/evidence-schema.d.ts +79 -0
- package/dist/config/schema.d.ts +13 -0
- package/dist/evidence/manager.d.ts +8 -4
- package/dist/hooks/delegation-gate.d.ts +7 -0
- package/dist/hooks/delegation-gate.getEvidenceTaskId.test.d.ts +20 -0
- package/dist/hooks/scope-guard.d.ts +2 -2
- package/dist/index.js +987 -345
- package/dist/model-fallback.adversarial.test.d.ts +22 -0
- package/dist/model-fallback.test.d.ts +12 -0
- package/dist/session/snapshot-writer.d.ts +14 -0
- package/dist/state.d.ts +8 -0
- package/dist/tools/doc-scan.d.ts +38 -0
- package/dist/tools/index.d.ts +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -142,6 +142,30 @@ You only need to specify the agents you want to override. The `architect` inheri
|
|
|
142
142
|
|
|
143
143
|
See the [full configuration reference](#configuration-reference) and the [free-tier model setup](#free-tier-opencode-zen-models) for more options.
|
|
144
144
|
|
|
145
|
+
### Step 7 — Performance modes (optional)
|
|
146
|
+
|
|
147
|
+
Swarm runs optional quality hooks (slop detection, incremental verification, compaction) on every tool call. For faster iteration, you can skip these:
|
|
148
|
+
|
|
149
|
+
**Via slash command** (session-wide):
|
|
150
|
+
```
|
|
151
|
+
/swarm turbo
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**Via config** (persistent):
|
|
155
|
+
```json
|
|
156
|
+
{
|
|
157
|
+
"execution_mode": "fast"
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
| Mode | Behavior |
|
|
162
|
+
|------|----------|
|
|
163
|
+
| `strict` | Runs all quality hooks (slop detector, incremental verify, compaction). Maximum safety, highest overhead. |
|
|
164
|
+
| `balanced` (default) | Skips optional quality hooks. Recommended for most workflows. |
|
|
165
|
+
| `fast` | Same as balanced. Reserved for future more aggressive optimizations. |
|
|
166
|
+
|
|
167
|
+
Use `strict` mode for critical security-sensitive changes. Switch to `balanced` for routine development.
|
|
168
|
+
|
|
145
169
|
---
|
|
146
170
|
|
|
147
171
|
## Common First-Run Questions
|
|
@@ -228,6 +252,55 @@ For production use, mix providers to maximize quality across writing vs. reviewi
|
|
|
228
252
|
| MiniMax | `minimax-coding-plan/<model>` | `minimax-coding-plan/MiniMax-M2.5` |
|
|
229
253
|
| Kimi | `kimi-for-coding/<model>` | `kimi-for-coding/k2p5` |
|
|
230
254
|
|
|
255
|
+
### Model Fallback (v6.33)
|
|
256
|
+
|
|
257
|
+
When a transient model error occurs (rate limit, 429, 503, timeout, overloaded, model not found), Swarm can automatically switch to a fallback model.
|
|
258
|
+
|
|
259
|
+
**Configuration:**
|
|
260
|
+
|
|
261
|
+
```json
|
|
262
|
+
{
|
|
263
|
+
"agents": {
|
|
264
|
+
"coder": {
|
|
265
|
+
"model": "anthropic/claude-opus-4-6",
|
|
266
|
+
"fallback_models": [
|
|
267
|
+
"anthropic/claude-sonnet-4-5",
|
|
268
|
+
"opencode/gpt-5-nano"
|
|
269
|
+
]
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
- **`fallback_models`** — Optional array of up to 3 fallback model identifiers. When the primary model fails with a transient error, Swarm injects a `MODEL FALLBACK` advisory and the next retry uses the next fallback model in the list.
|
|
276
|
+
- **Advisory injection** — When a transient error is detected, a `MODEL FALLBACK` advisory is injected into the architect's context: *"Transient model error detected (attempt N). The agent model may be rate-limited, overloaded, or temporarily unavailable. Consider retrying with a fallback model or waiting before retrying."*
|
|
277
|
+
- **Exhaustion guard** — After exhausting all fallbacks (`modelFallbackExhausted = true`), further transient errors do not spam additional advisories.
|
|
278
|
+
- **Reset on success** — Both `model_fallback_index` and `modelFallbackExhausted` reset to 0/false on the next successful tool execution.
|
|
279
|
+
|
|
280
|
+
### Bounded Coder Revisions (v6.33)
|
|
281
|
+
|
|
282
|
+
When a task requires multiple coder attempts (e.g., reviewer rejections), Swarm tracks how many times the coder has been re-delegated for the same task and warns when limits are approached.
|
|
283
|
+
|
|
284
|
+
**Configuration:**
|
|
285
|
+
|
|
286
|
+
```json
|
|
287
|
+
{
|
|
288
|
+
"guardrails": {
|
|
289
|
+
"max_coder_revisions": 5
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
| Parameter | Type | Default | Description |
|
|
295
|
+
|-----------|------|---------|-------------|
|
|
296
|
+
| `max_coder_revisions` | integer | `5` | Maximum coder re-delegations per task before advisory warning (1–20) |
|
|
297
|
+
|
|
298
|
+
**Behavior:**
|
|
299
|
+
- **`coderRevisions` counter** — Incremented each time the coder delegation completes for the same task (reset on new task)
|
|
300
|
+
- **`revisionLimitHit` flag** — Set when `coderRevisions >= max_coder_revisions`
|
|
301
|
+
- **Advisory injection** — When the limit is hit, a `CODER REVISION LIMIT` advisory is injected: *"Agent has been revised N times (max: M) for task X. Escalate to user or consider a fundamentally different approach."*
|
|
302
|
+
- **Persistence** — Both `coderRevisions` and `revisionLimitHit` are serialized/deserialized in session snapshots
|
|
303
|
+
|
|
231
304
|
## Useful Commands
|
|
232
305
|
|
|
233
306
|
| Command | What It Does |
|
|
@@ -395,7 +468,8 @@ Every completed task writes structured evidence to `.swarm/evidence/`:
|
|
|
395
468
|
| review | Verdict, risk level, specific issues |
|
|
396
469
|
| test | Pass/fail counts, coverage %, failure messages |
|
|
397
470
|
| diff | Files changed, additions/deletions |
|
|
398
|
-
| retrospective | Phase metrics, lessons learned (injected into next phase) |
|
|
471
|
+
| retrospective | Phase metrics, lessons learned, error taxonomy classification (injected into next phase) |
|
|
472
|
+
| secretscan | Secret scan results: findings count, files scanned, skipped files (v6.33) |
|
|
399
473
|
|
|
400
474
|
</details>
|
|
401
475
|
|
|
@@ -635,11 +709,11 @@ Config file location: `~/.config/opencode/opencode-swarm.json` (global) or `.ope
|
|
|
635
709
|
{
|
|
636
710
|
"agents": {
|
|
637
711
|
"architect": { "model": "anthropic/claude-opus-4-6" },
|
|
638
|
-
"coder": { "model": "minimax-coding-plan/MiniMax-M2.5" },
|
|
712
|
+
"coder": { "model": "minimax-coding-plan/MiniMax-M2.5", "fallback_models": ["minimax-coding-plan/MiniMax-M2.1"] },
|
|
639
713
|
"explorer": { "model": "minimax-coding-plan/MiniMax-M2.1" },
|
|
640
714
|
"sme": { "model": "kimi-for-coding/k2p5" },
|
|
641
715
|
"critic": { "model": "zai-coding-plan/glm-5" },
|
|
642
|
-
"reviewer": { "model": "zai-coding-plan/glm-5" },
|
|
716
|
+
"reviewer": { "model": "zai-coding-plan/glm-5", "fallback_models": ["opencode/big-pickle"] },
|
|
643
717
|
"test_engineer": { "model": "minimax-coding-plan/MiniMax-M2.5" },
|
|
644
718
|
"docs": { "model": "zai-coding-plan/glm-4.7-flash" },
|
|
645
719
|
"designer": { "model": "kimi-for-coding/k2p5" }
|
|
@@ -833,14 +907,14 @@ Swarm limits which tools each agent can access based on their role. This prevent
|
|
|
833
907
|
|
|
834
908
|
| Agent | Tools | Count | Rationale |
|
|
835
909
|
|-------|-------|:---:|-----------|
|
|
836
|
-
| **architect** | All
|
|
910
|
+
| **architect** | All 23 tools | 23 | Orchestrator needs full visibility |
|
|
837
911
|
| **reviewer** | diff, imports, lint, pkg_audit, pre_check_batch, secretscan, symbols, complexity_hotspots, retrieve_summary, extract_code_blocks, test_runner | 11 | Security-focused QA |
|
|
838
912
|
| **coder** | diff, imports, lint, symbols, extract_code_blocks, retrieve_summary | 6 | Write-focused, minimal read tools |
|
|
839
913
|
| **test_engineer** | test_runner, diff, symbols, extract_code_blocks, retrieve_summary, imports, complexity_hotspots, pkg_audit | 8 | Testing and verification |
|
|
840
914
|
| **explorer** | complexity_hotspots, detect_domains, extract_code_blocks, gitingest, imports, retrieve_summary, schema_drift, symbols, todo_extract | 9 | Discovery and analysis |
|
|
841
915
|
| **sme** | complexity_hotspots, detect_domains, extract_code_blocks, imports, retrieve_summary, schema_drift, symbols | 7 | Domain expertise research |
|
|
842
916
|
| **critic** | complexity_hotspots, detect_domains, imports, retrieve_summary, symbols | 5 | Plan review, minimal toolset |
|
|
843
|
-
| **docs** | detect_domains, extract_code_blocks, gitingest, imports, retrieve_summary, schema_drift, symbols, todo_extract |
|
|
917
|
+
| **docs** | detect_domains, doc_extract, doc_scan, extract_code_blocks, gitingest, imports, retrieve_summary, schema_drift, symbols, todo_extract | 10 | Documentation synthesis and discovery |
|
|
844
918
|
| **designer** | extract_code_blocks, retrieve_summary, symbols | 3 | UI-focused, minimal toolset |
|
|
845
919
|
|
|
846
920
|
### Configuration
|
|
@@ -900,13 +974,17 @@ The following tools can be assigned to agents via overrides:
|
|
|
900
974
|
| `checkpoint` | Save/restore git checkpoints |
|
|
901
975
|
| `check_gate_status` | Read-only query of task gate status |
|
|
902
976
|
| `complexity_hotspots` | Identify high-risk code areas |
|
|
977
|
+
| `declare_scope` | Pre-declare the file scope for the next coder delegation (architect-only); violations trigger warnings |
|
|
903
978
|
| `detect_domains` | Detect SME domains from text |
|
|
904
979
|
| `diff` | Analyze git diffs and changes |
|
|
980
|
+
| `doc_extract` | Extract actionable constraints from project documentation relevant to current task (Jaccard bigram scoring + dedup) |
|
|
981
|
+
| `doc_scan` | Scan project documentation and build index manifest at `.swarm/doc-manifest.json` (mtime-based caching) |
|
|
905
982
|
| `evidence_check` | Verify task evidence |
|
|
906
983
|
| `extract_code_blocks` | Extract code from markdown |
|
|
907
984
|
| `gitingest` | Ingest external repositories |
|
|
908
985
|
| `imports` | Analyze import relationships |
|
|
909
986
|
| `lint` | Run project linters |
|
|
987
|
+
| `phase_complete` | Enforces phase completion, verifies required agents, logs events, resets state |
|
|
910
988
|
| `pkg_audit` | Security audit of dependencies |
|
|
911
989
|
| `pre_check_batch` | Parallel pre-checks (lint, secrets, SAST, quality) |
|
|
912
990
|
| `retrieve_summary` | Retrieve summarized tool outputs |
|
|
@@ -917,8 +995,6 @@ The following tools can be assigned to agents via overrides:
|
|
|
917
995
|
| `update_task_status` | Mark plan tasks as pending/in_progress/completed/blocked; track phase progress |
|
|
918
996
|
| `todo_extract` | Extract TODO/FIXME comments |
|
|
919
997
|
| `write_retro` | Document phase retrospectives via the phase_complete workflow; capture lessons learned |
|
|
920
|
-
| `phase_complete` | Enforces phase completion, verifies required agents, logs events, resets state |
|
|
921
|
-
| `declare_scope` | Pre-declare the file scope for the next coder delegation (architect-only); violations trigger warnings |
|
|
922
998
|
|
|
923
999
|
---
|
|
924
1000
|
|
package/dist/cli/index.js
CHANGED
|
@@ -13940,7 +13940,7 @@ function deepMerge(base, override) {
|
|
|
13940
13940
|
var MAX_MERGE_DEPTH = 10;
|
|
13941
13941
|
|
|
13942
13942
|
// src/config/evidence-schema.ts
|
|
13943
|
-
var EVIDENCE_MAX_JSON_BYTES, EVIDENCE_MAX_PATCH_BYTES, EVIDENCE_MAX_TASK_BYTES, EvidenceTypeSchema, EvidenceVerdictSchema, BaseEvidenceSchema, ReviewEvidenceSchema, TestEvidenceSchema, DiffEvidenceSchema, ApprovalEvidenceSchema, NoteEvidenceSchema, RetrospectiveEvidenceSchema, SyntaxEvidenceSchema, PlaceholderEvidenceSchema, SastEvidenceSchema, SbomEvidenceSchema, BuildEvidenceSchema, QualityBudgetEvidenceSchema, EvidenceSchema, EvidenceBundleSchema;
|
|
13943
|
+
var EVIDENCE_MAX_JSON_BYTES, EVIDENCE_MAX_PATCH_BYTES, EVIDENCE_MAX_TASK_BYTES, EvidenceTypeSchema, EvidenceVerdictSchema, BaseEvidenceSchema, ReviewEvidenceSchema, TestEvidenceSchema, DiffEvidenceSchema, ApprovalEvidenceSchema, NoteEvidenceSchema, RetrospectiveEvidenceSchema, SyntaxEvidenceSchema, PlaceholderEvidenceSchema, SastEvidenceSchema, SbomEvidenceSchema, BuildEvidenceSchema, QualityBudgetEvidenceSchema, SecretscanEvidenceSchema, EvidenceSchema, EvidenceBundleSchema;
|
|
13944
13944
|
var init_evidence_schema = __esm(() => {
|
|
13945
13945
|
init_zod();
|
|
13946
13946
|
EVIDENCE_MAX_JSON_BYTES = 500 * 1024;
|
|
@@ -13958,7 +13958,8 @@ var init_evidence_schema = __esm(() => {
|
|
|
13958
13958
|
"sast",
|
|
13959
13959
|
"sbom",
|
|
13960
13960
|
"build",
|
|
13961
|
-
"quality_budget"
|
|
13961
|
+
"quality_budget",
|
|
13962
|
+
"secretscan"
|
|
13962
13963
|
]);
|
|
13963
13964
|
EvidenceVerdictSchema = exports_external.enum([
|
|
13964
13965
|
"pass",
|
|
@@ -14039,7 +14040,14 @@ var init_evidence_schema = __esm(() => {
|
|
|
14039
14040
|
approach: exports_external.string().min(1),
|
|
14040
14041
|
result: exports_external.enum(["success", "failure", "partial"]),
|
|
14041
14042
|
abandoned_reason: exports_external.string().optional()
|
|
14042
|
-
})).max(10).default([])
|
|
14043
|
+
})).max(10).default([]),
|
|
14044
|
+
error_taxonomy: exports_external.array(exports_external.enum([
|
|
14045
|
+
"planning_error",
|
|
14046
|
+
"interface_mismatch",
|
|
14047
|
+
"logic_error",
|
|
14048
|
+
"scope_creep",
|
|
14049
|
+
"gate_evasion"
|
|
14050
|
+
])).default([])
|
|
14043
14051
|
});
|
|
14044
14052
|
SyntaxEvidenceSchema = BaseEvidenceSchema.extend({
|
|
14045
14053
|
type: exports_external.literal("syntax"),
|
|
@@ -14150,6 +14158,13 @@ var init_evidence_schema = __esm(() => {
|
|
|
14150
14158
|
})).default([]),
|
|
14151
14159
|
files_analyzed: exports_external.array(exports_external.string())
|
|
14152
14160
|
});
|
|
14161
|
+
SecretscanEvidenceSchema = BaseEvidenceSchema.extend({
|
|
14162
|
+
type: exports_external.literal("secretscan"),
|
|
14163
|
+
findings_count: exports_external.number().int().min(0).default(0),
|
|
14164
|
+
scan_directory: exports_external.string().optional(),
|
|
14165
|
+
files_scanned: exports_external.number().int().min(0).default(0),
|
|
14166
|
+
skipped_files: exports_external.number().int().min(0).default(0)
|
|
14167
|
+
});
|
|
14153
14168
|
EvidenceSchema = exports_external.discriminatedUnion("type", [
|
|
14154
14169
|
ReviewEvidenceSchema,
|
|
14155
14170
|
TestEvidenceSchema,
|
|
@@ -14162,7 +14177,8 @@ var init_evidence_schema = __esm(() => {
|
|
|
14162
14177
|
SastEvidenceSchema,
|
|
14163
14178
|
SbomEvidenceSchema,
|
|
14164
14179
|
BuildEvidenceSchema,
|
|
14165
|
-
QualityBudgetEvidenceSchema
|
|
14180
|
+
QualityBudgetEvidenceSchema,
|
|
14181
|
+
SecretscanEvidenceSchema
|
|
14166
14182
|
]);
|
|
14167
14183
|
EvidenceBundleSchema = exports_external.object({
|
|
14168
14184
|
schema_version: exports_external.literal("1.0.0"),
|
|
@@ -14517,11 +14533,12 @@ var init_manager = __esm(() => {
|
|
|
14517
14533
|
"sast",
|
|
14518
14534
|
"sbom",
|
|
14519
14535
|
"build",
|
|
14520
|
-
"quality_budget"
|
|
14536
|
+
"quality_budget",
|
|
14537
|
+
"secretscan"
|
|
14521
14538
|
];
|
|
14522
14539
|
TASK_ID_REGEX = /^\d+\.\d+(\.\d+)*$/;
|
|
14523
14540
|
RETRO_TASK_ID_REGEX = /^retro-\d+$/;
|
|
14524
|
-
INTERNAL_TOOL_ID_REGEX = /^(?:sast_scan|quality_budget|syntax_check|placeholder_scan|sbom_generate|build)$/;
|
|
14541
|
+
INTERNAL_TOOL_ID_REGEX = /^(?:sast_scan|quality_budget|syntax_check|placeholder_scan|sbom_generate|build|secretscan)$/;
|
|
14525
14542
|
LEGACY_TASK_COMPLEXITY_MAP = {
|
|
14526
14543
|
low: "simple",
|
|
14527
14544
|
medium: "moderate",
|
|
@@ -17497,7 +17514,7 @@ var init_evidence_summary_service = __esm(() => {
|
|
|
17497
17514
|
});
|
|
17498
17515
|
|
|
17499
17516
|
// src/cli/index.ts
|
|
17500
|
-
import * as
|
|
17517
|
+
import * as fs12 from "fs";
|
|
17501
17518
|
import * as os5 from "os";
|
|
17502
17519
|
import * as path23 from "path";
|
|
17503
17520
|
|
|
@@ -17723,7 +17740,8 @@ for (const [agentName, tools] of Object.entries(AGENT_TOOL_MAP)) {
|
|
|
17723
17740
|
var AgentOverrideConfigSchema = exports_external.object({
|
|
17724
17741
|
model: exports_external.string().optional(),
|
|
17725
17742
|
temperature: exports_external.number().min(0).max(2).optional(),
|
|
17726
|
-
disabled: exports_external.boolean().optional()
|
|
17743
|
+
disabled: exports_external.boolean().optional(),
|
|
17744
|
+
fallback_models: exports_external.array(exports_external.string()).max(3).optional()
|
|
17727
17745
|
});
|
|
17728
17746
|
var SwarmConfigSchema = exports_external.object({
|
|
17729
17747
|
name: exports_external.string().optional(),
|
|
@@ -18063,6 +18081,8 @@ var GuardrailsConfigSchema = exports_external.object({
|
|
|
18063
18081
|
max_consecutive_errors: exports_external.number().min(2).max(20).default(5),
|
|
18064
18082
|
warning_threshold: exports_external.number().min(0.1).max(0.9).default(0.75),
|
|
18065
18083
|
idle_timeout_minutes: exports_external.number().min(5).max(240).default(60),
|
|
18084
|
+
no_op_warning_threshold: exports_external.number().min(1).max(100).default(15),
|
|
18085
|
+
max_coder_revisions: exports_external.number().int().min(1).max(20).default(5),
|
|
18066
18086
|
qa_gates: exports_external.object({
|
|
18067
18087
|
required_tools: exports_external.array(exports_external.string().min(1)).default([
|
|
18068
18088
|
"diff",
|
|
@@ -18178,6 +18198,7 @@ var PluginConfigSchema = exports_external.object({
|
|
|
18178
18198
|
pipeline: PipelineConfigSchema.optional(),
|
|
18179
18199
|
phase_complete: PhaseCompleteConfigSchema.optional(),
|
|
18180
18200
|
qa_retry_limit: exports_external.number().min(1).max(10).default(3),
|
|
18201
|
+
execution_mode: exports_external.enum(["strict", "balanced", "fast"]).default("balanced"),
|
|
18181
18202
|
inject_phase_reminders: exports_external.boolean().default(true),
|
|
18182
18203
|
hooks: HooksConfigSchema.optional(),
|
|
18183
18204
|
gates: GateConfigSchema.optional(),
|
|
@@ -33931,6 +33952,8 @@ function formatHandoffMarkdown(data) {
|
|
|
33931
33952
|
init_utils2();
|
|
33932
33953
|
import { mkdirSync as mkdirSync4, renameSync as renameSync4 } from "fs";
|
|
33933
33954
|
import * as path14 from "path";
|
|
33955
|
+
var pendingWrite = null;
|
|
33956
|
+
var lastWritePromise = Promise.resolve();
|
|
33934
33957
|
function serializeAgentSession(s) {
|
|
33935
33958
|
const gateLog = {};
|
|
33936
33959
|
const rawGateLog = s.gateLog ?? new Map;
|
|
@@ -33992,7 +34015,11 @@ function serializeAgentSession(s) {
|
|
|
33992
34015
|
taskWorkflowStates: Object.fromEntries(s.taskWorkflowStates ?? new Map),
|
|
33993
34016
|
...s.scopeViolationDetected !== undefined && {
|
|
33994
34017
|
scopeViolationDetected: s.scopeViolationDetected
|
|
33995
|
-
}
|
|
34018
|
+
},
|
|
34019
|
+
model_fallback_index: s.model_fallback_index ?? 0,
|
|
34020
|
+
modelFallbackExhausted: s.modelFallbackExhausted ?? false,
|
|
34021
|
+
coderRevisions: s.coderRevisions ?? 0,
|
|
34022
|
+
revisionLimitHit: s.revisionLimitHit ?? false
|
|
33996
34023
|
};
|
|
33997
34024
|
}
|
|
33998
34025
|
async function writeSnapshot(directory, state) {
|
|
@@ -34015,7 +34042,20 @@ async function writeSnapshot(directory, state) {
|
|
|
34015
34042
|
const tempPath = `${resolvedPath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2)}`;
|
|
34016
34043
|
await Bun.write(tempPath, content);
|
|
34017
34044
|
renameSync4(tempPath, resolvedPath);
|
|
34018
|
-
} catch {
|
|
34045
|
+
} catch (error93) {
|
|
34046
|
+
if (process.env.DEBUG_SWARM) {
|
|
34047
|
+
console.warn("[snapshot-writer] write failed:", error93 instanceof Error ? error93.message : String(error93));
|
|
34048
|
+
}
|
|
34049
|
+
}
|
|
34050
|
+
}
|
|
34051
|
+
async function flushPendingSnapshot(directory) {
|
|
34052
|
+
if (pendingWrite) {
|
|
34053
|
+
clearTimeout(pendingWrite);
|
|
34054
|
+
pendingWrite = null;
|
|
34055
|
+
await writeSnapshot(directory, swarmState).catch(() => {});
|
|
34056
|
+
} else {
|
|
34057
|
+
await lastWritePromise;
|
|
34058
|
+
}
|
|
34019
34059
|
}
|
|
34020
34060
|
|
|
34021
34061
|
// src/commands/handoff.ts
|
|
@@ -34027,6 +34067,7 @@ async function handleHandoffCommand(directory, _args) {
|
|
|
34027
34067
|
await Bun.write(tempPath, markdown);
|
|
34028
34068
|
renameSync5(tempPath, resolvedPath);
|
|
34029
34069
|
await writeSnapshot(directory, swarmState);
|
|
34070
|
+
await flushPendingSnapshot(directory);
|
|
34030
34071
|
return `## Handoff Brief Written
|
|
34031
34072
|
|
|
34032
34073
|
Brief written to \`.swarm/handoff.md\`.
|
|
@@ -39322,6 +39363,37 @@ async function handleResetCommand(directory, args) {
|
|
|
39322
39363
|
`);
|
|
39323
39364
|
}
|
|
39324
39365
|
|
|
39366
|
+
// src/commands/reset-session.ts
|
|
39367
|
+
init_utils2();
|
|
39368
|
+
import * as fs10 from "fs";
|
|
39369
|
+
async function handleResetSessionCommand(directory, _args) {
|
|
39370
|
+
const results = [];
|
|
39371
|
+
try {
|
|
39372
|
+
const statePath = validateSwarmPath(directory, "session/state.json");
|
|
39373
|
+
if (fs10.existsSync(statePath)) {
|
|
39374
|
+
fs10.unlinkSync(statePath);
|
|
39375
|
+
results.push("\u2705 Deleted .swarm/session/state.json");
|
|
39376
|
+
} else {
|
|
39377
|
+
results.push("\u23ED\uFE0F state.json not found (already clean)");
|
|
39378
|
+
}
|
|
39379
|
+
} catch {
|
|
39380
|
+
results.push("\u274C Failed to delete state.json");
|
|
39381
|
+
}
|
|
39382
|
+
const sessionCount = swarmState.agentSessions.size;
|
|
39383
|
+
swarmState.agentSessions.clear();
|
|
39384
|
+
results.push(`\u2705 Cleared ${sessionCount} in-memory agent session(s)`);
|
|
39385
|
+
return [
|
|
39386
|
+
"## Session State Reset",
|
|
39387
|
+
"",
|
|
39388
|
+
...results,
|
|
39389
|
+
"",
|
|
39390
|
+
"Session state cleared. Plan, evidence, and knowledge preserved.",
|
|
39391
|
+
"",
|
|
39392
|
+
"**Next step:** Start a new OpenCode session. The plugin will initialize fresh session state on startup."
|
|
39393
|
+
].join(`
|
|
39394
|
+
`);
|
|
39395
|
+
}
|
|
39396
|
+
|
|
39325
39397
|
// src/summaries/manager.ts
|
|
39326
39398
|
init_utils2();
|
|
39327
39399
|
init_utils();
|
|
@@ -39402,18 +39474,18 @@ ${error93 instanceof Error ? error93.message : String(error93)}`;
|
|
|
39402
39474
|
|
|
39403
39475
|
// src/commands/rollback.ts
|
|
39404
39476
|
init_utils2();
|
|
39405
|
-
import * as
|
|
39477
|
+
import * as fs11 from "fs";
|
|
39406
39478
|
import * as path22 from "path";
|
|
39407
39479
|
async function handleRollbackCommand(directory, args) {
|
|
39408
39480
|
const phaseArg = args[0];
|
|
39409
39481
|
if (!phaseArg) {
|
|
39410
39482
|
const manifestPath2 = validateSwarmPath(directory, "checkpoints/manifest.json");
|
|
39411
|
-
if (!
|
|
39483
|
+
if (!fs11.existsSync(manifestPath2)) {
|
|
39412
39484
|
return "No checkpoints found. Use `/swarm checkpoint` to create checkpoints.";
|
|
39413
39485
|
}
|
|
39414
39486
|
let manifest2;
|
|
39415
39487
|
try {
|
|
39416
|
-
manifest2 = JSON.parse(
|
|
39488
|
+
manifest2 = JSON.parse(fs11.readFileSync(manifestPath2, "utf-8"));
|
|
39417
39489
|
} catch {
|
|
39418
39490
|
return "Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.";
|
|
39419
39491
|
}
|
|
@@ -39435,12 +39507,12 @@ async function handleRollbackCommand(directory, args) {
|
|
|
39435
39507
|
return "Error: Phase number must be a positive integer.";
|
|
39436
39508
|
}
|
|
39437
39509
|
const manifestPath = validateSwarmPath(directory, "checkpoints/manifest.json");
|
|
39438
|
-
if (!
|
|
39510
|
+
if (!fs11.existsSync(manifestPath)) {
|
|
39439
39511
|
return `Error: No checkpoints found. Cannot rollback to phase ${targetPhase}.`;
|
|
39440
39512
|
}
|
|
39441
39513
|
let manifest;
|
|
39442
39514
|
try {
|
|
39443
|
-
manifest = JSON.parse(
|
|
39515
|
+
manifest = JSON.parse(fs11.readFileSync(manifestPath, "utf-8"));
|
|
39444
39516
|
} catch {
|
|
39445
39517
|
return `Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.`;
|
|
39446
39518
|
}
|
|
@@ -39450,10 +39522,10 @@ async function handleRollbackCommand(directory, args) {
|
|
|
39450
39522
|
return `Error: Checkpoint for phase ${targetPhase} not found. Available phases: ${available}`;
|
|
39451
39523
|
}
|
|
39452
39524
|
const checkpointDir = validateSwarmPath(directory, `checkpoints/phase-${targetPhase}`);
|
|
39453
|
-
if (!
|
|
39525
|
+
if (!fs11.existsSync(checkpointDir)) {
|
|
39454
39526
|
return `Error: Checkpoint directory for phase ${targetPhase} does not exist.`;
|
|
39455
39527
|
}
|
|
39456
|
-
const checkpointFiles =
|
|
39528
|
+
const checkpointFiles = fs11.readdirSync(checkpointDir);
|
|
39457
39529
|
if (checkpointFiles.length === 0) {
|
|
39458
39530
|
return `Error: Checkpoint for phase ${targetPhase} is empty. Cannot rollback.`;
|
|
39459
39531
|
}
|
|
@@ -39464,7 +39536,7 @@ async function handleRollbackCommand(directory, args) {
|
|
|
39464
39536
|
const src = path22.join(checkpointDir, file3);
|
|
39465
39537
|
const dest = path22.join(swarmDir, file3);
|
|
39466
39538
|
try {
|
|
39467
|
-
|
|
39539
|
+
fs11.cpSync(src, dest, { recursive: true, force: true });
|
|
39468
39540
|
successes.push(file3);
|
|
39469
39541
|
} catch (error93) {
|
|
39470
39542
|
failures.push({ file: file3, error: error93.message });
|
|
@@ -39481,7 +39553,7 @@ async function handleRollbackCommand(directory, args) {
|
|
|
39481
39553
|
timestamp: new Date().toISOString()
|
|
39482
39554
|
};
|
|
39483
39555
|
try {
|
|
39484
|
-
|
|
39556
|
+
fs11.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
|
|
39485
39557
|
`);
|
|
39486
39558
|
} catch (error93) {
|
|
39487
39559
|
console.error("Failed to write rollback event:", error93);
|
|
@@ -39524,11 +39596,11 @@ async function handleSimulateCommand(directory, args) {
|
|
|
39524
39596
|
];
|
|
39525
39597
|
const report = reportLines.filter(Boolean).join(`
|
|
39526
39598
|
`);
|
|
39527
|
-
const
|
|
39599
|
+
const fs12 = await import("fs/promises");
|
|
39528
39600
|
const path23 = await import("path");
|
|
39529
39601
|
const reportPath = path23.join(directory, ".swarm", "simulate-report.md");
|
|
39530
|
-
await
|
|
39531
|
-
await
|
|
39602
|
+
await fs12.mkdir(path23.dirname(reportPath), { recursive: true });
|
|
39603
|
+
await fs12.writeFile(reportPath, report, "utf-8");
|
|
39532
39604
|
return `${darkMatterPairs.length} hidden coupling pairs detected`;
|
|
39533
39605
|
}
|
|
39534
39606
|
|
|
@@ -39993,8 +40065,46 @@ async function executeWriteRetro(args, directory) {
|
|
|
39993
40065
|
top_rejection_reasons: args.top_rejection_reasons ?? [],
|
|
39994
40066
|
lessons_learned: (args.lessons_learned ?? []).slice(0, 5),
|
|
39995
40067
|
user_directives: [],
|
|
39996
|
-
approaches_tried: []
|
|
40068
|
+
approaches_tried: [],
|
|
40069
|
+
error_taxonomy: []
|
|
39997
40070
|
};
|
|
40071
|
+
const taxonomy = [];
|
|
40072
|
+
try {
|
|
40073
|
+
for (const taskSuffix of ["1", "2", "3", "4", "5"]) {
|
|
40074
|
+
const phaseTaskId = `${phase}.${taskSuffix}`;
|
|
40075
|
+
const result = await loadEvidence(directory, phaseTaskId);
|
|
40076
|
+
if (result.status !== "found")
|
|
40077
|
+
continue;
|
|
40078
|
+
const bundle = result.bundle;
|
|
40079
|
+
for (const entry of bundle.entries) {
|
|
40080
|
+
const e = entry;
|
|
40081
|
+
if (e.type === "review" && e.verdict === "fail") {
|
|
40082
|
+
const reasonParts = [];
|
|
40083
|
+
if (typeof e.summary === "string")
|
|
40084
|
+
reasonParts.push(e.summary);
|
|
40085
|
+
if (Array.isArray(e.issues)) {
|
|
40086
|
+
for (const iss of e.issues) {
|
|
40087
|
+
if (typeof iss.message === "string")
|
|
40088
|
+
reasonParts.push(iss.message);
|
|
40089
|
+
}
|
|
40090
|
+
}
|
|
40091
|
+
const reason = reasonParts.join(" ");
|
|
40092
|
+
if (/signature|type|contract|interface/i.test(reason)) {
|
|
40093
|
+
taxonomy.push("interface_mismatch");
|
|
40094
|
+
} else {
|
|
40095
|
+
taxonomy.push("logic_error");
|
|
40096
|
+
}
|
|
40097
|
+
} else if (e.type === "test" && e.verdict === "fail") {
|
|
40098
|
+
taxonomy.push("logic_error");
|
|
40099
|
+
} else if (e.agent === "scope_guard" && e.verdict === "fail") {
|
|
40100
|
+
taxonomy.push("scope_creep");
|
|
40101
|
+
} else if (e.agent === "loop_detector" && e.verdict === "fail") {
|
|
40102
|
+
taxonomy.push("gate_evasion");
|
|
40103
|
+
}
|
|
40104
|
+
}
|
|
40105
|
+
}
|
|
40106
|
+
} catch {}
|
|
40107
|
+
retroEntry.error_taxonomy = [...new Set(taxonomy)];
|
|
39998
40108
|
try {
|
|
39999
40109
|
await saveEvidence(directory, taskId, retroEntry);
|
|
40000
40110
|
return JSON.stringify({
|
|
@@ -40209,6 +40319,10 @@ var COMMAND_REGISTRY = {
|
|
|
40209
40319
|
handler: (ctx) => handleResetCommand(ctx.directory, ctx.args),
|
|
40210
40320
|
description: "Clear swarm state files [--confirm]"
|
|
40211
40321
|
},
|
|
40322
|
+
"reset-session": {
|
|
40323
|
+
handler: (ctx) => handleResetSessionCommand(ctx.directory, ctx.args),
|
|
40324
|
+
description: "Clear session state while preserving plan, evidence, and knowledge"
|
|
40325
|
+
},
|
|
40212
40326
|
rollback: {
|
|
40213
40327
|
handler: (ctx) => handleRollbackCommand(ctx.directory, ctx.args),
|
|
40214
40328
|
description: "Restore swarm state to a checkpoint <phase>"
|
|
@@ -40282,13 +40396,13 @@ var OPENCODE_CONFIG_PATH = path23.join(CONFIG_DIR, "opencode.json");
|
|
|
40282
40396
|
var PLUGIN_CONFIG_PATH = path23.join(CONFIG_DIR, "opencode-swarm.json");
|
|
40283
40397
|
var PROMPTS_DIR = path23.join(CONFIG_DIR, "opencode-swarm");
|
|
40284
40398
|
function ensureDir(dir) {
|
|
40285
|
-
if (!
|
|
40286
|
-
|
|
40399
|
+
if (!fs12.existsSync(dir)) {
|
|
40400
|
+
fs12.mkdirSync(dir, { recursive: true });
|
|
40287
40401
|
}
|
|
40288
40402
|
}
|
|
40289
40403
|
function loadJson(filepath) {
|
|
40290
40404
|
try {
|
|
40291
|
-
const content =
|
|
40405
|
+
const content = fs12.readFileSync(filepath, "utf-8");
|
|
40292
40406
|
const stripped = content.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (match, comment) => comment ? "" : match).replace(/,(\s*[}\]])/g, "$1");
|
|
40293
40407
|
return JSON.parse(stripped);
|
|
40294
40408
|
} catch {
|
|
@@ -40296,7 +40410,7 @@ function loadJson(filepath) {
|
|
|
40296
40410
|
}
|
|
40297
40411
|
}
|
|
40298
40412
|
function saveJson(filepath, data) {
|
|
40299
|
-
|
|
40413
|
+
fs12.writeFileSync(filepath, `${JSON.stringify(data, null, 2)}
|
|
40300
40414
|
`, "utf-8");
|
|
40301
40415
|
}
|
|
40302
40416
|
async function install() {
|
|
@@ -40329,7 +40443,7 @@ async function install() {
|
|
|
40329
40443
|
saveJson(OPENCODE_CONFIG_PATH, opencodeConfig);
|
|
40330
40444
|
console.log("\u2713 Added opencode-swarm to OpenCode plugins");
|
|
40331
40445
|
console.log("\u2713 Disabled default OpenCode agents (explore, general)");
|
|
40332
|
-
if (!
|
|
40446
|
+
if (!fs12.existsSync(PLUGIN_CONFIG_PATH)) {
|
|
40333
40447
|
const defaultConfig = {
|
|
40334
40448
|
agents: {
|
|
40335
40449
|
coder: { model: "opencode/minimax-m2.5-free" },
|
|
@@ -40372,7 +40486,7 @@ async function uninstall() {
|
|
|
40372
40486
|
`);
|
|
40373
40487
|
const opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
|
|
40374
40488
|
if (!opencodeConfig) {
|
|
40375
|
-
if (
|
|
40489
|
+
if (fs12.existsSync(OPENCODE_CONFIG_PATH)) {
|
|
40376
40490
|
console.log(`\u2717 Could not parse opencode config at: ${OPENCODE_CONFIG_PATH}`);
|
|
40377
40491
|
return 1;
|
|
40378
40492
|
} else {
|
|
@@ -40404,13 +40518,13 @@ async function uninstall() {
|
|
|
40404
40518
|
console.log("\u2713 Re-enabled default OpenCode agents (explore, general)");
|
|
40405
40519
|
if (process.argv.includes("--clean")) {
|
|
40406
40520
|
let cleaned = false;
|
|
40407
|
-
if (
|
|
40408
|
-
|
|
40521
|
+
if (fs12.existsSync(PLUGIN_CONFIG_PATH)) {
|
|
40522
|
+
fs12.unlinkSync(PLUGIN_CONFIG_PATH);
|
|
40409
40523
|
console.log(`\u2713 Removed plugin config: ${PLUGIN_CONFIG_PATH}`);
|
|
40410
40524
|
cleaned = true;
|
|
40411
40525
|
}
|
|
40412
|
-
if (
|
|
40413
|
-
|
|
40526
|
+
if (fs12.existsSync(PROMPTS_DIR)) {
|
|
40527
|
+
fs12.rmSync(PROMPTS_DIR, { recursive: true });
|
|
40414
40528
|
console.log(`\u2713 Removed custom prompts: ${PROMPTS_DIR}`);
|
|
40415
40529
|
cleaned = true;
|
|
40416
40530
|
}
|
package/dist/commands/index.d.ts
CHANGED
|
@@ -21,6 +21,7 @@ export { handlePromoteCommand } from './promote';
|
|
|
21
21
|
export type { CommandContext, CommandEntry, RegisteredCommand, } from './registry.js';
|
|
22
22
|
export { COMMAND_REGISTRY, resolveCommand, VALID_COMMANDS, } from './registry.js';
|
|
23
23
|
export { handleResetCommand } from './reset';
|
|
24
|
+
export { handleResetSessionCommand } from './reset-session';
|
|
24
25
|
export { handleRetrieveCommand } from './retrieve';
|
|
25
26
|
export { handleRollbackCommand } from './rollback';
|
|
26
27
|
export { handleSimulateCommand } from './simulate';
|
|
@@ -104,6 +104,10 @@ export declare const COMMAND_REGISTRY: {
|
|
|
104
104
|
readonly handler: (ctx: CommandContext) => Promise<string>;
|
|
105
105
|
readonly description: "Clear swarm state files [--confirm]";
|
|
106
106
|
};
|
|
107
|
+
readonly 'reset-session': {
|
|
108
|
+
readonly handler: (ctx: CommandContext) => Promise<string>;
|
|
109
|
+
readonly description: "Clear session state while preserving plan, evidence, and knowledge";
|
|
110
|
+
};
|
|
107
111
|
readonly rollback: {
|
|
108
112
|
readonly handler: (ctx: CommandContext) => Promise<string>;
|
|
109
113
|
readonly description: "Restore swarm state to a checkpoint <phase>";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handles the /swarm reset-session command.
|
|
3
|
+
* Deletes only the session state file (.swarm/session/state.json)
|
|
4
|
+
* and clears in-memory agent sessions. Preserves plan, evidence,
|
|
5
|
+
* and knowledge for continuity across sessions.
|
|
6
|
+
*/
|
|
7
|
+
export declare function handleResetSessionCommand(directory: string, _args: string[]): Promise<string>;
|