opencode-swarm 6.23.1 → 6.23.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/dist/cli/index.js CHANGED
@@ -16215,6 +16215,39 @@ async function savePlan(directory, plan) {
16215
16215
  throw new Error(`Invalid directory: directory must be a non-empty string`);
16216
16216
  }
16217
16217
  const validated = PlanSchema.parse(plan);
16218
+ try {
16219
+ const currentPlan = await loadPlanJsonOnly(directory);
16220
+ if (currentPlan) {
16221
+ const completedTaskIds = new Set;
16222
+ for (const phase of currentPlan.phases) {
16223
+ for (const task of phase.tasks) {
16224
+ if (task.status === "completed")
16225
+ completedTaskIds.add(task.id);
16226
+ }
16227
+ }
16228
+ if (completedTaskIds.size > 0) {
16229
+ for (const phase of validated.phases) {
16230
+ for (const task of phase.tasks) {
16231
+ if (completedTaskIds.has(task.id) && task.status !== "completed") {
16232
+ task.status = "completed";
16233
+ }
16234
+ }
16235
+ }
16236
+ }
16237
+ }
16238
+ } catch {}
16239
+ for (const phase of validated.phases) {
16240
+ const tasks = phase.tasks;
16241
+ if (tasks.length > 0 && tasks.every((t) => t.status === "completed")) {
16242
+ phase.status = "complete";
16243
+ } else if (tasks.some((t) => t.status === "in_progress")) {
16244
+ phase.status = "in_progress";
16245
+ } else if (tasks.some((t) => t.status === "blocked")) {
16246
+ phase.status = "blocked";
16247
+ } else {
16248
+ phase.status = "pending";
16249
+ }
16250
+ }
16218
16251
  const swarmDir = path7.resolve(directory, ".swarm");
16219
16252
  const planPath = path7.join(swarmDir, "plan.json");
16220
16253
  const tempPath = path7.join(swarmDir, `plan.json.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
@@ -201,8 +201,8 @@ export declare const PhaseCompleteConfigSchema: z.ZodObject<{
201
201
  enabled: z.ZodDefault<z.ZodBoolean>;
202
202
  required_agents: z.ZodDefault<z.ZodArray<z.ZodEnum<{
203
203
  reviewer: "reviewer";
204
- coder: "coder";
205
204
  test_engineer: "test_engineer";
205
+ coder: "coder";
206
206
  }>>>;
207
207
  require_docs: z.ZodDefault<z.ZodBoolean>;
208
208
  policy: z.ZodDefault<z.ZodEnum<{
@@ -447,8 +447,8 @@ export declare const PluginConfigSchema: z.ZodObject<{
447
447
  enabled: z.ZodDefault<z.ZodBoolean>;
448
448
  required_agents: z.ZodDefault<z.ZodArray<z.ZodEnum<{
449
449
  reviewer: "reviewer";
450
- coder: "coder";
451
450
  test_engineer: "test_engineer";
451
+ coder: "coder";
452
452
  }>>>;
453
453
  require_docs: z.ZodDefault<z.ZodBoolean>;
454
454
  policy: z.ZodDefault<z.ZodEnum<{
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Gate Evidence Store
3
+ *
4
+ * Durable, task-scoped evidence for QA gate completion.
5
+ * Evidence is recorded on disk (.swarm/evidence/{taskId}.json) by the
6
+ * delegation-gate toolAfter hook and read by checkReviewerGate at
7
+ * update_task_status(completed) time.
8
+ *
9
+ * Evidence files survive session restarts (unlike in-memory state).
10
+ * Agents never write these files directly — only the hook does.
11
+ * Gates are append-only: required_gates can only grow, never shrink.
12
+ */
13
+ export interface GateEvidence {
14
+ sessionId: string;
15
+ timestamp: string;
16
+ agent: string;
17
+ }
18
+ export interface TaskEvidence {
19
+ taskId: string;
20
+ required_gates: string[];
21
+ gates: Record<string, GateEvidence>;
22
+ }
23
+ export declare const DEFAULT_REQUIRED_GATES: string[];
24
+ /**
25
+ * Maps the first-dispatched agent type to the initial required_gates array.
26
+ * Unknown agent types fall back to the safe default ["reviewer", "test_engineer"].
27
+ */
28
+ export declare function deriveRequiredGates(agentType: string): string[];
29
+ /**
30
+ * Returns the union of existingGates and deriveRequiredGates(newAgentType).
31
+ * Sorted, deduplicated. Gates can only grow, never shrink.
32
+ */
33
+ export declare function expandRequiredGates(existingGates: string[], newAgentType: string): string[];
34
+ /**
35
+ * Creates or updates .swarm/evidence/{taskId}.json with a gate pass entry.
36
+ * If file doesn't exist: creates with required_gates from deriveRequiredGates(gate).
37
+ * If file exists: merges gate entry, expands required_gates via expandRequiredGates.
38
+ * Atomic write: temp file + rename.
39
+ */
40
+ export declare function recordGateEvidence(directory: string, taskId: string, gate: string, sessionId: string): Promise<void>;
41
+ /**
42
+ * Sets or expands required_gates WITHOUT recording a gate pass.
43
+ * Used when non-gate agents are dispatched (coder, explorer, sme, etc.).
44
+ * Creates evidence file if it doesn't exist yet.
45
+ */
46
+ export declare function recordAgentDispatch(directory: string, taskId: string, agentType: string): Promise<void>;
47
+ /**
48
+ * Returns the TaskEvidence for a task, or null if file missing or parse error.
49
+ * Never throws.
50
+ */
51
+ export declare function readTaskEvidence(directory: string, taskId: string): Promise<TaskEvidence | null>;
52
+ /**
53
+ * Returns true only when every required_gate has a matching gates entry.
54
+ * Returns false if no evidence file exists.
55
+ */
56
+ export declare function hasPassedAllGates(directory: string, taskId: string): Promise<boolean>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Integration tests for evidence recording in delegation-gate.ts toolAfter.
3
+ */
4
+ export {};