opencode-swarm 6.20.1 → 6.20.3

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
@@ -14186,6 +14186,8 @@ function log(message, data) {
14186
14186
  }
14187
14187
  }
14188
14188
  function warn(message, data) {
14189
+ if (!DEBUG)
14190
+ return;
14189
14191
  const timestamp = new Date().toISOString();
14190
14192
  if (data !== undefined) {
14191
14193
  console.warn(`[opencode-swarm ${timestamp}] WARN: ${message}`, data);
@@ -9,11 +9,11 @@
9
9
  import { type GuardrailsConfig } from '../config/schema';
10
10
  /**
11
11
  * Creates guardrails hooks for circuit breaker protection
12
- * @param directory Working directory (from plugin init context)
13
- * @param config Guardrails configuration
12
+ * @param directoryOrConfig Working directory (from plugin init context) OR legacy config object for backward compatibility
13
+ * @param config Guardrails configuration (optional if first arg is config)
14
14
  * @returns Tool before/after hooks and messages transform hook
15
15
  */
16
- export declare function createGuardrailsHooks(directory: string, config: GuardrailsConfig): {
16
+ export declare function createGuardrailsHooks(directoryOrConfig?: string | GuardrailsConfig, config?: GuardrailsConfig): {
17
17
  toolBefore: (input: {
18
18
  tool: string;
19
19
  sessionID: string;
package/dist/index.js CHANGED
@@ -14248,6 +14248,8 @@ function log(message, data) {
14248
14248
  }
14249
14249
  }
14250
14250
  function warn(message, data) {
14251
+ if (!DEBUG)
14252
+ return;
14251
14253
  const timestamp = new Date().toISOString();
14252
14254
  if (data !== undefined) {
14253
14255
  console.warn(`[opencode-swarm ${timestamp}] WARN: ${message}`, data);
@@ -39101,6 +39103,8 @@ If you are about to edit a source file: STOP. You are violating protocol.
39101
39103
  writeCount > 0 on source files from the Architect is equivalent to GATE_DELEGATION_BYPASS.
39102
39104
 
39103
39105
  PLAN STATE PROTECTION
39106
+ WHY: plan.md is auto-regenerated by PlanSyncWorker from plan.json. Any direct write to plan.md will be silently overwritten within seconds. If you see plan.md reverting after your edit, this is the cause \u2014 the worker detected a plan.json change and regenerated plan.md from it.
39107
+ The correct tools: save_plan to create or restructure a plan (writes plan.json \u2192 triggers regeneration); update_task_status() for task completion status; phase_complete() for phase-level transitions.
39104
39108
  .swarm/plan.md and .swarm/plan.json are READABLE but NOT DIRECTLY WRITABLE for state transitions.
39105
39109
  Task-level status changes (marking individual tasks as "completed") must use update_task_status().
39106
39110
  Phase-level completion (marking an entire phase as done) must use phase_complete().
@@ -47502,14 +47506,24 @@ function getCurrentTaskId(sessionId) {
47502
47506
  const session = swarmState.agentSessions.get(sessionId);
47503
47507
  return session?.currentTaskId ?? `${sessionId}:unknown`;
47504
47508
  }
47505
- function createGuardrailsHooks(directory, config3) {
47506
- if (config3.enabled === false) {
47509
+ function createGuardrailsHooks(directoryOrConfig, config3) {
47510
+ let directory;
47511
+ let guardrailsConfig;
47512
+ if (directoryOrConfig && typeof directoryOrConfig === "object" && "enabled" in directoryOrConfig) {
47513
+ directory = process.cwd();
47514
+ guardrailsConfig = directoryOrConfig;
47515
+ } else {
47516
+ directory = directoryOrConfig ?? process.cwd();
47517
+ guardrailsConfig = config3;
47518
+ }
47519
+ if (guardrailsConfig?.enabled === false) {
47507
47520
  return {
47508
47521
  toolBefore: async () => {},
47509
47522
  toolAfter: async () => {},
47510
47523
  messagesTransform: async () => {}
47511
47524
  };
47512
47525
  }
47526
+ const cfg = guardrailsConfig;
47513
47527
  const inputArgsByCallID = new Map;
47514
47528
  return {
47515
47529
  toolBefore: async (input, output) => {
@@ -47517,6 +47531,13 @@ function createGuardrailsHooks(directory, config3) {
47517
47531
  if (currentSession?.delegationActive) {} else if (isArchitect(input.sessionID) && isWriteTool(input.tool)) {
47518
47532
  const args2 = output.args;
47519
47533
  const targetPath = args2?.filePath ?? args2?.path ?? args2?.file ?? args2?.target;
47534
+ if (typeof targetPath === "string" && targetPath.length > 0) {
47535
+ const resolvedTarget = path25.resolve(directory, targetPath).toLowerCase();
47536
+ const planMdPath = path25.resolve(directory, ".swarm", "plan.md").toLowerCase();
47537
+ if (resolvedTarget === planMdPath) {
47538
+ throw new Error("PLAN STATE VIOLATION: Direct writes to .swarm/plan.md are blocked. " + "plan.md is auto-regenerated from plan.json by PlanSyncWorker. " + "Use update_task_status() to mark tasks complete, " + "phase_complete() for phase transitions, or " + "save_plan to create/restructure plans.");
47539
+ }
47540
+ }
47520
47541
  if (!targetPath && (input.tool === "apply_patch" || input.tool === "patch")) {
47521
47542
  const patchText = args2?.input ?? args2?.patch ?? (Array.isArray(args2?.cmd) ? args2.cmd[1] : undefined);
47522
47543
  if (typeof patchText === "string") {
@@ -47532,6 +47553,11 @@ function createGuardrailsHooks(directory, config3) {
47532
47553
  paths.add(p);
47533
47554
  }
47534
47555
  for (const p of paths) {
47556
+ const resolvedP = path25.resolve(directory, p);
47557
+ const planMdPath = path25.resolve(directory, ".swarm", "plan.md");
47558
+ if (resolvedP.toLowerCase() === planMdPath.toLowerCase()) {
47559
+ throw new Error("PLAN STATE VIOLATION: Direct writes to .swarm/plan.md are blocked. " + "plan.md is auto-regenerated from plan.json by PlanSyncWorker. " + "Use update_task_status() to mark tasks complete, " + "phase_complete() for phase transitions, or " + "save_plan to create/restructure plans.");
47560
+ }
47535
47561
  if (isOutsideSwarmDir(p, directory) && (isSourceCodePath(p) || hasTraversalSegments(p))) {
47536
47562
  const session2 = swarmState.agentSessions.get(input.sessionID);
47537
47563
  if (session2) {
@@ -47548,7 +47574,7 @@ function createGuardrailsHooks(directory, config3) {
47548
47574
  }
47549
47575
  }
47550
47576
  }
47551
- if (typeof targetPath === "string" && isOutsideSwarmDir(targetPath, directory) && (isSourceCodePath(targetPath) || hasTraversalSegments(targetPath))) {
47577
+ if (typeof targetPath === "string" && targetPath.length > 0 && isOutsideSwarmDir(targetPath, directory) && isSourceCodePath(path25.relative(directory, path25.resolve(directory, targetPath)))) {
47552
47578
  const session2 = swarmState.agentSessions.get(input.sessionID);
47553
47579
  if (session2) {
47554
47580
  session2.architectWriteCount++;
@@ -47590,7 +47616,7 @@ function createGuardrailsHooks(directory, config3) {
47590
47616
  if (resolvedName === ORCHESTRATOR_NAME) {
47591
47617
  return;
47592
47618
  }
47593
- const agentConfig = resolveGuardrailsConfig(config3, session.agentName);
47619
+ const agentConfig = resolveGuardrailsConfig(cfg, session.agentName);
47594
47620
  if (agentConfig.max_duration_minutes === 0 && agentConfig.max_tool_calls === 0) {
47595
47621
  return;
47596
47622
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "6.20.1",
3
+ "version": "6.20.3",
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",