opencode-swarm 6.33.1 → 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 CHANGED
@@ -252,6 +252,55 @@ For production use, mix providers to maximize quality across writing vs. reviewi
252
252
  | MiniMax | `minimax-coding-plan/<model>` | `minimax-coding-plan/MiniMax-M2.5` |
253
253
  | Kimi | `kimi-for-coding/<model>` | `kimi-for-coding/k2p5` |
254
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
+
255
304
  ## Useful Commands
256
305
 
257
306
  | Command | What It Does |
@@ -419,7 +468,8 @@ Every completed task writes structured evidence to `.swarm/evidence/`:
419
468
  | review | Verdict, risk level, specific issues |
420
469
  | test | Pass/fail counts, coverage %, failure messages |
421
470
  | diff | Files changed, additions/deletions |
422
- | 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) |
423
473
 
424
474
  </details>
425
475
 
@@ -659,11 +709,11 @@ Config file location: `~/.config/opencode/opencode-swarm.json` (global) or `.ope
659
709
  {
660
710
  "agents": {
661
711
  "architect": { "model": "anthropic/claude-opus-4-6" },
662
- "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"] },
663
713
  "explorer": { "model": "minimax-coding-plan/MiniMax-M2.1" },
664
714
  "sme": { "model": "kimi-for-coding/k2p5" },
665
715
  "critic": { "model": "zai-coding-plan/glm-5" },
666
- "reviewer": { "model": "zai-coding-plan/glm-5" },
716
+ "reviewer": { "model": "zai-coding-plan/glm-5", "fallback_models": ["opencode/big-pickle"] },
667
717
  "test_engineer": { "model": "minimax-coding-plan/MiniMax-M2.5" },
668
718
  "docs": { "model": "zai-coding-plan/glm-4.7-flash" },
669
719
  "designer": { "model": "kimi-for-coding/k2p5" }
@@ -857,14 +907,14 @@ Swarm limits which tools each agent can access based on their role. This prevent
857
907
 
858
908
  | Agent | Tools | Count | Rationale |
859
909
  |-------|-------|:---:|-----------|
860
- | **architect** | All 21 tools | 21 | Orchestrator needs full visibility |
910
+ | **architect** | All 23 tools | 23 | Orchestrator needs full visibility |
861
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 |
862
912
  | **coder** | diff, imports, lint, symbols, extract_code_blocks, retrieve_summary | 6 | Write-focused, minimal read tools |
863
913
  | **test_engineer** | test_runner, diff, symbols, extract_code_blocks, retrieve_summary, imports, complexity_hotspots, pkg_audit | 8 | Testing and verification |
864
914
  | **explorer** | complexity_hotspots, detect_domains, extract_code_blocks, gitingest, imports, retrieve_summary, schema_drift, symbols, todo_extract | 9 | Discovery and analysis |
865
915
  | **sme** | complexity_hotspots, detect_domains, extract_code_blocks, imports, retrieve_summary, schema_drift, symbols | 7 | Domain expertise research |
866
916
  | **critic** | complexity_hotspots, detect_domains, imports, retrieve_summary, symbols | 5 | Plan review, minimal toolset |
867
- | **docs** | detect_domains, extract_code_blocks, gitingest, imports, retrieve_summary, schema_drift, symbols, todo_extract | 8 | Documentation synthesis |
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 |
868
918
  | **designer** | extract_code_blocks, retrieve_summary, symbols | 3 | UI-focused, minimal toolset |
869
919
 
870
920
  ### Configuration
@@ -924,13 +974,17 @@ The following tools can be assigned to agents via overrides:
924
974
  | `checkpoint` | Save/restore git checkpoints |
925
975
  | `check_gate_status` | Read-only query of task gate status |
926
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 |
927
978
  | `detect_domains` | Detect SME domains from text |
928
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) |
929
982
  | `evidence_check` | Verify task evidence |
930
983
  | `extract_code_blocks` | Extract code from markdown |
931
984
  | `gitingest` | Ingest external repositories |
932
985
  | `imports` | Analyze import relationships |
933
986
  | `lint` | Run project linters |
987
+ | `phase_complete` | Enforces phase completion, verifies required agents, logs events, resets state |
934
988
  | `pkg_audit` | Security audit of dependencies |
935
989
  | `pre_check_batch` | Parallel pre-checks (lint, secrets, SAST, quality) |
936
990
  | `retrieve_summary` | Retrieve summarized tool outputs |
@@ -941,8 +995,6 @@ The following tools can be assigned to agents via overrides:
941
995
  | `update_task_status` | Mark plan tasks as pending/in_progress/completed/blocked; track phase progress |
942
996
  | `todo_extract` | Extract TODO/FIXME comments |
943
997
  | `write_retro` | Document phase retrospectives via the phase_complete workflow; capture lessons learned |
944
- | `phase_complete` | Enforces phase completion, verifies required agents, logs events, resets state |
945
- | `declare_scope` | Pre-declare the file scope for the next coder delegation (architect-only); violations trigger warnings |
946
998
 
947
999
  ---
948
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",
@@ -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(),
@@ -18064,6 +18082,7 @@ var GuardrailsConfigSchema = exports_external.object({
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),
18066
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),
18067
18086
  qa_gates: exports_external.object({
18068
18087
  required_tools: exports_external.array(exports_external.string().min(1)).default([
18069
18088
  "diff",
@@ -33996,7 +34015,11 @@ function serializeAgentSession(s) {
33996
34015
  taskWorkflowStates: Object.fromEntries(s.taskWorkflowStates ?? new Map),
33997
34016
  ...s.scopeViolationDetected !== undefined && {
33998
34017
  scopeViolationDetected: s.scopeViolationDetected
33999
- }
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
34000
34023
  };
34001
34024
  }
34002
34025
  async function writeSnapshot(directory, state) {
@@ -34020,7 +34043,9 @@ async function writeSnapshot(directory, state) {
34020
34043
  await Bun.write(tempPath, content);
34021
34044
  renameSync4(tempPath, resolvedPath);
34022
34045
  } catch (error93) {
34023
- console.warn("[snapshot-writer] write failed:", error93 instanceof Error ? error93.message : String(error93));
34046
+ if (process.env.DEBUG_SWARM) {
34047
+ console.warn("[snapshot-writer] write failed:", error93 instanceof Error ? error93.message : String(error93));
34048
+ }
34024
34049
  }
34025
34050
  }
34026
34051
  async function flushPendingSnapshot(directory) {
@@ -40040,8 +40065,46 @@ async function executeWriteRetro(args, directory) {
40040
40065
  top_rejection_reasons: args.top_rejection_reasons ?? [],
40041
40066
  lessons_learned: (args.lessons_learned ?? []).slice(0, 5),
40042
40067
  user_directives: [],
40043
- approaches_tried: []
40068
+ approaches_tried: [],
40069
+ error_taxonomy: []
40044
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)];
40045
40108
  try {
40046
40109
  await saveEvidence(directory, taskId, retroEntry);
40047
40110
  return JSON.stringify({
@@ -4,6 +4,7 @@ export declare const EVIDENCE_MAX_PATCH_BYTES: number;
4
4
  export declare const EVIDENCE_MAX_TASK_BYTES: number;
5
5
  export declare const EvidenceTypeSchema: z.ZodEnum<{
6
6
  diff: "diff";
7
+ secretscan: "secretscan";
7
8
  quality_budget: "quality_budget";
8
9
  placeholder: "placeholder";
9
10
  test: "test";
@@ -29,6 +30,7 @@ export declare const BaseEvidenceSchema: z.ZodObject<{
29
30
  task_id: z.ZodString;
30
31
  type: z.ZodEnum<{
31
32
  diff: "diff";
33
+ secretscan: "secretscan";
32
34
  quality_budget: "quality_budget";
33
35
  placeholder: "placeholder";
34
36
  test: "test";
@@ -217,6 +219,13 @@ export declare const RetrospectiveEvidenceSchema: z.ZodObject<{
217
219
  }>;
218
220
  abandoned_reason: z.ZodOptional<z.ZodString>;
219
221
  }, z.core.$strip>>>;
222
+ error_taxonomy: z.ZodDefault<z.ZodArray<z.ZodEnum<{
223
+ planning_error: "planning_error";
224
+ interface_mismatch: "interface_mismatch";
225
+ logic_error: "logic_error";
226
+ scope_creep: "scope_creep";
227
+ gate_evasion: "gate_evasion";
228
+ }>>>;
220
229
  }, z.core.$strip>;
221
230
  export type RetrospectiveEvidence = z.infer<typeof RetrospectiveEvidenceSchema>;
222
231
  export declare const SyntaxEvidenceSchema: z.ZodObject<{
@@ -434,6 +443,26 @@ export declare const QualityBudgetEvidenceSchema: z.ZodObject<{
434
443
  files_analyzed: z.ZodArray<z.ZodString>;
435
444
  }, z.core.$strip>;
436
445
  export type QualityBudgetEvidence = z.infer<typeof QualityBudgetEvidenceSchema>;
446
+ export declare const SecretscanEvidenceSchema: z.ZodObject<{
447
+ task_id: z.ZodString;
448
+ timestamp: z.ZodString;
449
+ agent: z.ZodString;
450
+ verdict: z.ZodEnum<{
451
+ pass: "pass";
452
+ fail: "fail";
453
+ approved: "approved";
454
+ rejected: "rejected";
455
+ info: "info";
456
+ }>;
457
+ summary: z.ZodString;
458
+ metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
459
+ type: z.ZodLiteral<"secretscan">;
460
+ findings_count: z.ZodDefault<z.ZodNumber>;
461
+ scan_directory: z.ZodOptional<z.ZodString>;
462
+ files_scanned: z.ZodDefault<z.ZodNumber>;
463
+ skipped_files: z.ZodDefault<z.ZodNumber>;
464
+ }, z.core.$strip>;
465
+ export type SecretscanEvidence = z.infer<typeof SecretscanEvidenceSchema>;
437
466
  export declare const EvidenceSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
438
467
  task_id: z.ZodString;
439
468
  timestamp: z.ZodString;
@@ -587,6 +616,13 @@ export declare const EvidenceSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
587
616
  }>;
588
617
  abandoned_reason: z.ZodOptional<z.ZodString>;
589
618
  }, z.core.$strip>>>;
619
+ error_taxonomy: z.ZodDefault<z.ZodArray<z.ZodEnum<{
620
+ planning_error: "planning_error";
621
+ interface_mismatch: "interface_mismatch";
622
+ logic_error: "logic_error";
623
+ scope_creep: "scope_creep";
624
+ gate_evasion: "gate_evasion";
625
+ }>>>;
590
626
  }, z.core.$strip>, z.ZodObject<{
591
627
  task_id: z.ZodString;
592
628
  timestamp: z.ZodString;
@@ -790,6 +826,24 @@ export declare const EvidenceSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
790
826
  files: z.ZodArray<z.ZodString>;
791
827
  }, z.core.$strip>>>;
792
828
  files_analyzed: z.ZodArray<z.ZodString>;
829
+ }, z.core.$strip>, z.ZodObject<{
830
+ task_id: z.ZodString;
831
+ timestamp: z.ZodString;
832
+ agent: z.ZodString;
833
+ verdict: z.ZodEnum<{
834
+ pass: "pass";
835
+ fail: "fail";
836
+ approved: "approved";
837
+ rejected: "rejected";
838
+ info: "info";
839
+ }>;
840
+ summary: z.ZodString;
841
+ metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
842
+ type: z.ZodLiteral<"secretscan">;
843
+ findings_count: z.ZodDefault<z.ZodNumber>;
844
+ scan_directory: z.ZodOptional<z.ZodString>;
845
+ files_scanned: z.ZodDefault<z.ZodNumber>;
846
+ skipped_files: z.ZodDefault<z.ZodNumber>;
793
847
  }, z.core.$strip>], "type">;
794
848
  export type Evidence = z.infer<typeof EvidenceSchema>;
795
849
  export declare const EvidenceBundleSchema: z.ZodObject<{
@@ -948,6 +1002,13 @@ export declare const EvidenceBundleSchema: z.ZodObject<{
948
1002
  }>;
949
1003
  abandoned_reason: z.ZodOptional<z.ZodString>;
950
1004
  }, z.core.$strip>>>;
1005
+ error_taxonomy: z.ZodDefault<z.ZodArray<z.ZodEnum<{
1006
+ planning_error: "planning_error";
1007
+ interface_mismatch: "interface_mismatch";
1008
+ logic_error: "logic_error";
1009
+ scope_creep: "scope_creep";
1010
+ gate_evasion: "gate_evasion";
1011
+ }>>>;
951
1012
  }, z.core.$strip>, z.ZodObject<{
952
1013
  task_id: z.ZodString;
953
1014
  timestamp: z.ZodString;
@@ -1151,6 +1212,24 @@ export declare const EvidenceBundleSchema: z.ZodObject<{
1151
1212
  files: z.ZodArray<z.ZodString>;
1152
1213
  }, z.core.$strip>>>;
1153
1214
  files_analyzed: z.ZodArray<z.ZodString>;
1215
+ }, z.core.$strip>, z.ZodObject<{
1216
+ task_id: z.ZodString;
1217
+ timestamp: z.ZodString;
1218
+ agent: z.ZodString;
1219
+ verdict: z.ZodEnum<{
1220
+ pass: "pass";
1221
+ fail: "fail";
1222
+ approved: "approved";
1223
+ rejected: "rejected";
1224
+ info: "info";
1225
+ }>;
1226
+ summary: z.ZodString;
1227
+ metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
1228
+ type: z.ZodLiteral<"secretscan">;
1229
+ findings_count: z.ZodDefault<z.ZodNumber>;
1230
+ scan_directory: z.ZodOptional<z.ZodString>;
1231
+ files_scanned: z.ZodDefault<z.ZodNumber>;
1232
+ skipped_files: z.ZodDefault<z.ZodNumber>;
1154
1233
  }, z.core.$strip>], "type">>>;
1155
1234
  created_at: z.ZodString;
1156
1235
  updated_at: z.ZodString;
@@ -18,6 +18,7 @@ export declare const AgentOverrideConfigSchema: z.ZodObject<{
18
18
  model: z.ZodOptional<z.ZodString>;
19
19
  temperature: z.ZodOptional<z.ZodNumber>;
20
20
  disabled: z.ZodOptional<z.ZodBoolean>;
21
+ fallback_models: z.ZodOptional<z.ZodArray<z.ZodString>>;
21
22
  }, z.core.$strip>;
22
23
  export type AgentOverrideConfig = z.infer<typeof AgentOverrideConfigSchema>;
23
24
  export declare const SwarmConfigSchema: z.ZodObject<{
@@ -26,6 +27,7 @@ export declare const SwarmConfigSchema: z.ZodObject<{
26
27
  model: z.ZodOptional<z.ZodString>;
27
28
  temperature: z.ZodOptional<z.ZodNumber>;
28
29
  disabled: z.ZodOptional<z.ZodBoolean>;
30
+ fallback_models: z.ZodOptional<z.ZodArray<z.ZodString>>;
29
31
  }, z.core.$strip>>>;
30
32
  }, z.core.$strip>;
31
33
  export type SwarmConfig = z.infer<typeof SwarmConfigSchema>;
@@ -314,6 +316,7 @@ export declare const GuardrailsConfigSchema: z.ZodObject<{
314
316
  warning_threshold: z.ZodDefault<z.ZodNumber>;
315
317
  idle_timeout_minutes: z.ZodDefault<z.ZodNumber>;
316
318
  no_op_warning_threshold: z.ZodDefault<z.ZodNumber>;
319
+ max_coder_revisions: z.ZodDefault<z.ZodNumber>;
317
320
  qa_gates: z.ZodOptional<z.ZodObject<{
318
321
  required_tools: z.ZodDefault<z.ZodArray<z.ZodString>>;
319
322
  require_reviewer_test_engineer: z.ZodDefault<z.ZodBoolean>;
@@ -468,6 +471,7 @@ export declare const PluginConfigSchema: z.ZodObject<{
468
471
  model: z.ZodOptional<z.ZodString>;
469
472
  temperature: z.ZodOptional<z.ZodNumber>;
470
473
  disabled: z.ZodOptional<z.ZodBoolean>;
474
+ fallback_models: z.ZodOptional<z.ZodArray<z.ZodString>>;
471
475
  }, z.core.$strip>>>;
472
476
  swarms: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
473
477
  name: z.ZodOptional<z.ZodString>;
@@ -475,6 +479,7 @@ export declare const PluginConfigSchema: z.ZodObject<{
475
479
  model: z.ZodOptional<z.ZodString>;
476
480
  temperature: z.ZodOptional<z.ZodNumber>;
477
481
  disabled: z.ZodOptional<z.ZodBoolean>;
482
+ fallback_models: z.ZodOptional<z.ZodArray<z.ZodString>>;
478
483
  }, z.core.$strip>>>;
479
484
  }, z.core.$strip>>>;
480
485
  max_iterations: z.ZodDefault<z.ZodNumber>;
@@ -592,6 +597,7 @@ export declare const PluginConfigSchema: z.ZodObject<{
592
597
  warning_threshold: z.ZodDefault<z.ZodNumber>;
593
598
  idle_timeout_minutes: z.ZodDefault<z.ZodNumber>;
594
599
  no_op_warning_threshold: z.ZodDefault<z.ZodNumber>;
600
+ max_coder_revisions: z.ZodDefault<z.ZodNumber>;
595
601
  qa_gates: z.ZodOptional<z.ZodObject<{
596
602
  required_tools: z.ZodDefault<z.ZodArray<z.ZodString>>;
597
603
  require_reviewer_test_engineer: z.ZodDefault<z.ZodBoolean>;
@@ -1,4 +1,4 @@
1
- import { type BuildEvidence, type Evidence, type EvidenceBundle, type PlaceholderEvidence, type QualityBudgetEvidence, type SastEvidence, type SbomEvidence, type SyntaxEvidence } from '../config/evidence-schema';
1
+ import { type BuildEvidence, type Evidence, type EvidenceBundle, type PlaceholderEvidence, type QualityBudgetEvidence, type SastEvidence, type SbomEvidence, type SecretscanEvidence, type SyntaxEvidence } from '../config/evidence-schema';
2
2
  /**
3
3
  * Discriminated union returned by loadEvidence.
4
4
  * - 'found': file exists and passed Zod schema validation
@@ -15,9 +15,9 @@ export type LoadEvidenceResult = {
15
15
  errors: string[];
16
16
  };
17
17
  /**
18
- * All valid evidence types (12 total)
18
+ * All valid evidence types (13 total)
19
19
  */
20
- export declare const VALID_EVIDENCE_TYPES: readonly ["review", "test", "diff", "approval", "note", "retrospective", "syntax", "placeholder", "sast", "sbom", "build", "quality_budget"];
20
+ export declare const VALID_EVIDENCE_TYPES: readonly ["review", "test", "diff", "approval", "note", "retrospective", "syntax", "placeholder", "sast", "sbom", "build", "quality_budget", "secretscan"];
21
21
  /**
22
22
  * Check if a string is a valid evidence type.
23
23
  * Returns true if the type is recognized, false otherwise.
@@ -32,12 +32,16 @@ export declare function isSastEvidence(evidence: Evidence): evidence is SastEvid
32
32
  export declare function isSbomEvidence(evidence: Evidence): evidence is SbomEvidence;
33
33
  export declare function isBuildEvidence(evidence: Evidence): evidence is BuildEvidence;
34
34
  export declare function isQualityBudgetEvidence(evidence: Evidence): evidence is QualityBudgetEvidence;
35
+ /**
36
+ * Type guard for secretscan evidence
37
+ */
38
+ export declare function isSecretscanEvidence(evidence: Evidence): evidence is SecretscanEvidence;
35
39
  /**
36
40
  * Validate and sanitize task ID.
37
41
  * Accepts three formats:
38
42
  * 1. Canonical N.M or N.M.P numeric format (matches TASK_ID_REGEX)
39
43
  * 2. Retrospective format: retro-<number> (matches RETRO_TASK_ID_REGEX)
40
- * 3. Internal automated-tool format: specific tool IDs (sast_scan, quality_budget, syntax_check, placeholder_scan, sbom_generate, build)
44
+ * 3. Internal automated-tool format: specific tool IDs (sast_scan, quality_budget, syntax_check, placeholder_scan, sbom_generate, build, secretscan)
41
45
  * Rejects: .., ../, null bytes, control characters, empty string, other non-numeric IDs
42
46
  * @throws Error with descriptive message on failure
43
47
  */
@@ -0,0 +1,20 @@
1
+ /**
2
+ * delegation-gate.getEvidenceTaskId.test.ts
3
+ *
4
+ * Verification tests for the async conversion of getEvidenceTaskId.
5
+ * Tests the function behavior by recreating its logic in isolation since
6
+ * the function is private (not exported) and depends on fs.promises.
7
+ *
8
+ * Covers:
9
+ * 1. Function returns a Promise (is async)
10
+ * 2. Function resolves to correct task ID when currentTaskId is set
11
+ * 3. Function resolves to correct task ID when lastCoderDelegationTaskId is set
12
+ * 4. Function falls back to taskWorkflowStates when above are null
13
+ * 5. Function returns null when plan.json doesn't exist (ENOENT)
14
+ * 6. Function returns null when plan.json has no in_progress tasks
15
+ * 7. Function returns null when session has direct task_id (early return path via currentTaskId)
16
+ * 8. Path traversal is blocked (security hardening)
17
+ * 9. Malformed JSON returns null
18
+ * 10. Empty/invalid directory returns null
19
+ */
20
+ export {};