opencode-swarm 6.25.7 → 6.25.9

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/dist/cli/index.js CHANGED
@@ -14275,10 +14275,16 @@ function sanitizeTaskId(taskId) {
14275
14275
  if (taskId.includes("..") || taskId.includes("../") || taskId.includes("..\\")) {
14276
14276
  throw new Error("Invalid task ID: path traversal detected");
14277
14277
  }
14278
- if (!TASK_ID_REGEX.test(taskId)) {
14279
- throw new Error(`Invalid task ID: must match pattern ^[\\w-]+(\\.[\\w-]+)*$, got "${taskId}"`);
14278
+ if (TASK_ID_REGEX.test(taskId)) {
14279
+ return taskId;
14280
14280
  }
14281
- return taskId;
14281
+ if (RETRO_TASK_ID_REGEX.test(taskId)) {
14282
+ return taskId;
14283
+ }
14284
+ if (INTERNAL_TOOL_ID_REGEX.test(taskId)) {
14285
+ return taskId;
14286
+ }
14287
+ throw new Error(`Invalid task ID: must match pattern ^\\d+\\.\\d+(\\.\\d+)*$, ^retro-\\d+$, or ^(?:sast_scan|quality_budget|syntax_check|placeholder_scan|sbom_generate|build)$, got "${taskId}"`);
14282
14288
  }
14283
14289
  async function saveEvidence(directory, taskId, evidence) {
14284
14290
  const sanitizedTaskId = sanitizeTaskId(taskId);
@@ -14488,13 +14494,15 @@ async function archiveEvidence(directory, maxAgeDays, maxBundles) {
14488
14494
  }
14489
14495
  return archived;
14490
14496
  }
14491
- var TASK_ID_REGEX, LEGACY_TASK_COMPLEXITY_MAP;
14497
+ var TASK_ID_REGEX, RETRO_TASK_ID_REGEX, INTERNAL_TOOL_ID_REGEX, LEGACY_TASK_COMPLEXITY_MAP;
14492
14498
  var init_manager = __esm(() => {
14493
14499
  init_zod();
14494
14500
  init_evidence_schema();
14495
14501
  init_utils2();
14496
14502
  init_utils();
14497
- TASK_ID_REGEX = /^[\w-]+(\.[\w-]+)*$/;
14503
+ TASK_ID_REGEX = /^\d+\.\d+(\.\d+)*$/;
14504
+ RETRO_TASK_ID_REGEX = /^retro-\d+$/;
14505
+ INTERNAL_TOOL_ID_REGEX = /^(?:sast_scan|quality_budget|syntax_check|placeholder_scan|sbom_generate|build)$/;
14498
14506
  LEGACY_TASK_COMPLEXITY_MAP = {
14499
14507
  low: "simple",
14500
14508
  medium: "moderate",
@@ -30959,7 +30967,10 @@ function serializeAgentSession(s) {
30959
30967
  lastCompletedPhaseAgentsDispatched,
30960
30968
  qaSkipCount: s.qaSkipCount ?? 0,
30961
30969
  qaSkipTaskIds: s.qaSkipTaskIds ?? [],
30962
- taskWorkflowStates: Object.fromEntries(s.taskWorkflowStates ?? new Map)
30970
+ taskWorkflowStates: Object.fromEntries(s.taskWorkflowStates ?? new Map),
30971
+ ...s.scopeViolationDetected !== undefined && {
30972
+ scopeViolationDetected: s.scopeViolationDetected
30973
+ }
30963
30974
  };
30964
30975
  }
30965
30976
  async function writeSnapshot(directory, state) {
@@ -34,8 +34,11 @@ export declare function isBuildEvidence(evidence: Evidence): evidence is BuildEv
34
34
  export declare function isQualityBudgetEvidence(evidence: Evidence): evidence is QualityBudgetEvidence;
35
35
  /**
36
36
  * Validate and sanitize task ID.
37
- * Must match regex ^[\w-]+(\.[\w-]+)*$
38
- * Rejects: .., ../, null bytes, control characters, empty string
37
+ * Accepts three formats:
38
+ * 1. Canonical N.M or N.M.P numeric format (matches TASK_ID_REGEX)
39
+ * 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)
41
+ * Rejects: .., ../, null bytes, control characters, empty string, other non-numeric IDs
39
42
  * @throws Error with descriptive message on failure
40
43
  */
41
44
  export declare function sanitizeTaskId(taskId: string): string;
@@ -21,6 +21,19 @@ export interface TaskEvidence {
21
21
  gates: Record<string, GateEvidence>;
22
22
  }
23
23
  export declare const DEFAULT_REQUIRED_GATES: string[];
24
+ /**
25
+ * Canonical task-id validation helper.
26
+ * Returns true if the taskId is a valid numeric format (N.M or N.M.P),
27
+ * false otherwise.
28
+ *
29
+ * Validates:
30
+ * - Non-empty string
31
+ * - Matches N.M or N.M.P numeric pattern (e.g., "1.1", "1.2.3")
32
+ * - No path traversal (..)
33
+ * - No path separators (/, \)
34
+ * - No null bytes
35
+ */
36
+ export declare function isValidTaskId(taskId: string): boolean;
24
37
  /**
25
38
  * Maps the first-dispatched agent type to the initial required_gates array.
26
39
  * Unknown agent types fall back to the safe default ["reviewer", "test_engineer"].
package/dist/index.js CHANGED
@@ -15368,10 +15368,16 @@ function sanitizeTaskId(taskId) {
15368
15368
  if (taskId.includes("..") || taskId.includes("../") || taskId.includes("..\\")) {
15369
15369
  throw new Error("Invalid task ID: path traversal detected");
15370
15370
  }
15371
- if (!TASK_ID_REGEX.test(taskId)) {
15372
- throw new Error(`Invalid task ID: must match pattern ^[\\w-]+(\\.[\\w-]+)*$, got "${taskId}"`);
15371
+ if (TASK_ID_REGEX.test(taskId)) {
15372
+ return taskId;
15373
15373
  }
15374
- return taskId;
15374
+ if (RETRO_TASK_ID_REGEX.test(taskId)) {
15375
+ return taskId;
15376
+ }
15377
+ if (INTERNAL_TOOL_ID_REGEX.test(taskId)) {
15378
+ return taskId;
15379
+ }
15380
+ throw new Error(`Invalid task ID: must match pattern ^\\d+\\.\\d+(\\.\\d+)*$, ^retro-\\d+$, or ^(?:sast_scan|quality_budget|syntax_check|placeholder_scan|sbom_generate|build)$, got "${taskId}"`);
15375
15381
  }
15376
15382
  async function saveEvidence(directory, taskId, evidence) {
15377
15383
  const sanitizedTaskId = sanitizeTaskId(taskId);
@@ -15581,7 +15587,7 @@ async function archiveEvidence(directory, maxAgeDays, maxBundles) {
15581
15587
  }
15582
15588
  return archived;
15583
15589
  }
15584
- var VALID_EVIDENCE_TYPES, TASK_ID_REGEX, LEGACY_TASK_COMPLEXITY_MAP;
15590
+ var VALID_EVIDENCE_TYPES, TASK_ID_REGEX, RETRO_TASK_ID_REGEX, INTERNAL_TOOL_ID_REGEX, LEGACY_TASK_COMPLEXITY_MAP;
15585
15591
  var init_manager = __esm(() => {
15586
15592
  init_zod();
15587
15593
  init_evidence_schema();
@@ -15601,7 +15607,9 @@ var init_manager = __esm(() => {
15601
15607
  "build",
15602
15608
  "quality_budget"
15603
15609
  ];
15604
- TASK_ID_REGEX = /^[\w-]+(\.[\w-]+)*$/;
15610
+ TASK_ID_REGEX = /^\d+\.\d+(\.\d+)*$/;
15611
+ RETRO_TASK_ID_REGEX = /^retro-\d+$/;
15612
+ INTERNAL_TOOL_ID_REGEX = /^(?:sast_scan|quality_budget|syntax_check|placeholder_scan|sbom_generate|build)$/;
15605
15613
  LEGACY_TASK_COMPLEXITY_MAP = {
15606
15614
  low: "simple",
15607
15615
  medium: "moderate",
@@ -35895,6 +35903,7 @@ __export(exports_gate_evidence, {
35895
35903
  recordGateEvidence: () => recordGateEvidence,
35896
35904
  recordAgentDispatch: () => recordAgentDispatch,
35897
35905
  readTaskEvidence: () => readTaskEvidence,
35906
+ isValidTaskId: () => isValidTaskId2,
35898
35907
  hasPassedAllGates: () => hasPassedAllGates,
35899
35908
  expandRequiredGates: () => expandRequiredGates,
35900
35909
  deriveRequiredGates: () => deriveRequiredGates,
@@ -35902,8 +35911,21 @@ __export(exports_gate_evidence, {
35902
35911
  });
35903
35912
  import { mkdirSync as mkdirSync8, readFileSync as readFileSync13, renameSync as renameSync7, unlinkSync as unlinkSync4 } from "fs";
35904
35913
  import * as path27 from "path";
35914
+ function isValidTaskId2(taskId) {
35915
+ if (!taskId)
35916
+ return false;
35917
+ if (taskId.includes(".."))
35918
+ return false;
35919
+ if (taskId.includes("/"))
35920
+ return false;
35921
+ if (taskId.includes("\\"))
35922
+ return false;
35923
+ if (taskId.includes("\x00"))
35924
+ return false;
35925
+ return TASK_ID_PATTERN.test(taskId);
35926
+ }
35905
35927
  function assertValidTaskId(taskId) {
35906
- if (!taskId || taskId.includes("..") || taskId.includes("/") || taskId.includes("\\") || taskId.includes("\x00") || !TASK_ID_PATTERN.test(taskId)) {
35928
+ if (!isValidTaskId2(taskId)) {
35907
35929
  throw new Error(`Invalid taskId: "${taskId}". Must match N.M or N.M.P (e.g. "1.1", "1.2.3").`);
35908
35930
  }
35909
35931
  }
@@ -46050,7 +46072,10 @@ function serializeAgentSession(s) {
46050
46072
  lastCompletedPhaseAgentsDispatched,
46051
46073
  qaSkipCount: s.qaSkipCount ?? 0,
46052
46074
  qaSkipTaskIds: s.qaSkipTaskIds ?? [],
46053
- taskWorkflowStates: Object.fromEntries(s.taskWorkflowStates ?? new Map)
46075
+ taskWorkflowStates: Object.fromEntries(s.taskWorkflowStates ?? new Map),
46076
+ ...s.scopeViolationDetected !== undefined && {
46077
+ scopeViolationDetected: s.scopeViolationDetected
46078
+ }
46054
46079
  };
46055
46080
  }
46056
46081
  async function writeSnapshot(directory, state) {
@@ -52795,6 +52820,7 @@ function deserializeAgentSession(s) {
52795
52820
  lastGateOutcome: null,
52796
52821
  declaredCoderScope: null,
52797
52822
  lastScopeViolation: null,
52823
+ scopeViolationDetected: s.scopeViolationDetected,
52798
52824
  modifiedFilesThisCoderTask: []
52799
52825
  };
52800
52826
  }
@@ -53073,6 +53099,20 @@ init_create_tool();
53073
53099
  import * as fs19 from "fs";
53074
53100
  import * as path32 from "path";
53075
53101
  var EVIDENCE_DIR = ".swarm/evidence";
53102
+ var TASK_ID_PATTERN2 = /^\d+\.\d+(\.\d+)*$/;
53103
+ function isValidTaskId3(taskId) {
53104
+ if (!taskId)
53105
+ return false;
53106
+ if (taskId.includes(".."))
53107
+ return false;
53108
+ if (taskId.includes("/"))
53109
+ return false;
53110
+ if (taskId.includes("\\"))
53111
+ return false;
53112
+ if (taskId.includes("\x00"))
53113
+ return false;
53114
+ return TASK_ID_PATTERN2.test(taskId);
53115
+ }
53076
53116
  function isPathWithinSwarm(filePath, workspaceRoot) {
53077
53117
  const normalizedWorkspace = path32.resolve(workspaceRoot);
53078
53118
  const swarmPath = path32.join(normalizedWorkspace, ".swarm", "evidence");
@@ -53103,7 +53143,7 @@ function readEvidenceFile(evidencePath) {
53103
53143
  var check_gate_status = createSwarmTool({
53104
53144
  description: "Read-only tool to check the gate status of a specific task. Reads .swarm/evidence/{taskId}.json and returns structured JSON describing required, passed, and missing gates.",
53105
53145
  args: {
53106
- task_id: tool.schema.string().min(1).regex(/^\d+\.\d+(\.\d+)?$/, "Task ID must be in N.M or N.M.P format").describe('The task ID to check gate status for (e.g., "1.1", "2.3.1")')
53146
+ task_id: tool.schema.string().min(1).regex(/^\d+\.\d+(\.\d+)*$/, 'Task ID must be in N.M or N.M.P format (e.g., "1.1", "1.2.3", "1.2.3.4")').describe('The task ID to check gate status for (e.g., "1.1", "2.3.1")')
53107
53147
  },
53108
53148
  async execute(args2, directory) {
53109
53149
  let taskIdInput;
@@ -53125,8 +53165,7 @@ var check_gate_status = createSwarmTool({
53125
53165
  };
53126
53166
  return JSON.stringify(errorResult, null, 2);
53127
53167
  }
53128
- const taskIdPattern = /^\d+\.\d+(\.\d+)?$/;
53129
- if (!taskIdPattern.test(taskIdInput)) {
53168
+ if (!isValidTaskId3(taskIdInput)) {
53130
53169
  const errorResult = {
53131
53170
  taskId: taskIdInput,
53132
53171
  status: "no_evidence",
@@ -53134,7 +53173,7 @@ var check_gate_status = createSwarmTool({
53134
53173
  passed_gates: [],
53135
53174
  missing_gates: [],
53136
53175
  gates: {},
53137
- message: `Invalid task_id format: "${taskIdInput}". Must match pattern N.M or N.M.P (e.g., "1.1", "1.2.3")`
53176
+ message: `Invalid task_id format: "${taskIdInput}". Must match N.M or N.M.P (e.g. "1.1", "1.2.3", "1.2.3.4")`
53138
53177
  };
53139
53178
  return JSON.stringify(errorResult, null, 2);
53140
53179
  }
@@ -53846,7 +53885,7 @@ async function executeDeclareScope(args2, fallbackDir) {
53846
53885
  errors: ["Invalid working_directory: null bytes are not allowed"]
53847
53886
  };
53848
53887
  }
53849
- if (process.platform === "win32") {
53888
+ {
53850
53889
  const devicePathPattern = /^\\\\|^(NUL|CON|AUX|COM[1-9]|LPT[1-9])(\..*)?$/i;
53851
53890
  if (devicePathPattern.test(args2.working_directory)) {
53852
53891
  return {
@@ -37,6 +37,8 @@ export interface SerializedAgentSession {
37
37
  qaSkipCount: number;
38
38
  qaSkipTaskIds: string[];
39
39
  taskWorkflowStates?: Record<string, string>;
40
+ /** Flag for one-shot scope violation warning injection (omitted when undefined for additive-only schema) */
41
+ scopeViolationDetected?: boolean;
40
42
  }
41
43
  /**
42
44
  * Minimal interface for serialized InvocationWindow
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "6.25.7",
3
+ "version": "6.25.9",
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",