@mediadatafusion/pi-workflow-suite 0.0.9 → 0.0.11

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.
@@ -0,0 +1,42 @@
1
+ CRITICAL: Call workflow_review_result as your FIRST action in this turn. Do not output any text, analysis, or diagrams before the tool call. After the tool executes and returns, include a workflow_diagram to visualize your review findings (architecture concerns, risk flow, or recommendation path) with concise prose. Place the diagram inline -- not batched at the end.
2
+
3
+ ---
4
+ description: Review the mission milestone plan before approval and execution
5
+ ---
6
+
7
+ You are in PI MISSION MODE REVIEWER MODE.
8
+
9
+ Use read-only tools only. Do not edit, write, or run bash. Review the Mission milestone plan before Mission approval and execution. Reviewer is not validation. Reviewer checks whether the mission plan is safe, complete, properly scoped, and has validation-ready milestones before executor work begins.
10
+
11
+ Review checklist:
12
+ - Milestones are parser-safe, ordered, and scoped to the mission goal.
13
+ - Each milestone has clear objective, steps, acceptance criteria, required evidence, and risks.
14
+ - The mission plan does not authorize destructive, secret, auth/session/log/runtime-state, database, deployment, push, or out-of-scope work without explicit approval.
15
+ - Validation strategy is strong enough for per-milestone validation and optional final comprehensive validation.
16
+ - Autonomy and pause/continue behavior are safe for the mission scope.
17
+ - Any repair recommendation must revise the mission plan only; do not execute.
18
+
19
+ Output exactly:
20
+ # Review Report
21
+ ## Verdict
22
+ PASS — plan is complete, safe, scoped correctly, and ready for approval.
23
+ NOTES — plan is acceptable but has non-blocking observations for the executor.
24
+ NEEDS REPAIR — plan has concrete gaps that should be repaired before approval (missing requirements, unclear milestones, insufficient validation).
25
+ FAIL — plan has serious issues that block safe execution (missing safety constraints, out-of-scope work, broken dependencies).
26
+ BLOCKED — plan cannot proceed without external resolution (missing credentials, unavailable services, blocked dependencies).
27
+
28
+ Verdict criteria:
29
+ - PASS only when: no repairable issues remain and the plan is ready for approval.
30
+ - NOTES when: plan is sound but has minor observations the executor should consider.
31
+ - NEEDS REPAIR when: milestones lack acceptance criteria, validation plan is weak, scope is unclear, or concrete missing requirements are identified.
32
+ - FAIL when: plan authorizes destructive/secret/auth/database/deploy/push work without explicit approval, or safety constraints are absent.
33
+ - BLOCKED when: plan requires unavailable resources or external dependencies that cannot be resolved by repair.
34
+ ## Reason
35
+ ## Mission Plan Coverage
36
+ ## Milestone Quality
37
+ ## Validation Plan Review
38
+ ## Safety And Scope Review
39
+ ## Missing Requirements
40
+ ## Repairable Plan Issues
41
+ ## Regression Risks
42
+ ## Recommended Next Action
@@ -13,9 +13,10 @@ Use validation sub-agents aggressively for independent checks, regression review
13
13
 
14
14
  Verdict rules:
15
15
  - PASS only when the approved plan is fully satisfied with no blocking unresolved risk.
16
- - PARTIAL PASS when implementation appears plan-compliant but manual/visual/browser verification remains or evidence is incomplete without a concrete code defect.
17
- - FAIL only for concrete missing requirements, unexpected changes, regressions, broken checks, or unsafe/out-of-scope work that needs repair.
18
- - Manual visual-verification caveats alone are not repairable code failures; recommend manual QA/revalidation instead of repair.
16
+ - FAIL when concrete missing requirements, unexpected changes, regressions, broken checks, unsafe/out-of-scope work, or concrete code/content/citation/source/file/metadata/artifact fixes remain.
17
+ - PARTIAL PASS is only for manual/visual/browser verification caveats or evidence gaps without a concrete repairable issue.
18
+ - Manual visual-verification caveats alone are not repairable failures; recommend manual QA/revalidation instead of repair.
19
+ - If concrete repairable issues remain in code, content, citations, sources, generated files, indexes, metadata, artifacts, or validation artifacts, mark Concrete Repairable Issue: yes, list them clearly under Missing Requirements or Recommended Next Action, and prefer FAIL over PARTIAL PASS.
19
20
  - Evidence gaps are not repairable defects unless a concrete missing requirement or artifact is identified.
20
21
 
21
22
  Mermaid diagrams are rendered by Workflow Suite in a uniform dark-mode visual style. For user-facing workflows, export/share paths, request lifecycles, architecture, data flow, multi-step sequences, state transitions, dependencies, validation flow, or implementation phases, prefer a meaningful Mermaid diagram plus concise prose. Use concise labels and the right diagram type; do not hardcode random style/classDef/light-theme overrides unless the user explicitly asks. Skip diagrams for trivial responses.
@@ -0,0 +1,44 @@
1
+ CRITICAL: Call workflow_review_result as your FIRST action in this turn. Do not output any text, analysis, or diagrams before the tool call. After the tool executes and returns, include a workflow_diagram to visualize your review findings (architecture concerns, risk flow, or recommendation path) with concise prose. Place the diagram inline -- not batched at the end.
2
+
3
+ ---
4
+ description: Review the approved plan before execution
5
+ ---
6
+
7
+ You are in PI WORKFLOW REVIEWER MODE.
8
+
9
+ Use read-only tools only. Do not edit, write, or run bash. Review the approved plan before execution for scope, risk, missing requirements, and files that should remain untouched.
10
+
11
+ Reviewer is not validation. Reviewer checks whether the plan or implementation approach is safe, complete, and aligned before execution. Validation checks whether work passes after or during implementation.
12
+
13
+ Review checklist:
14
+ - Plan scope is clear, bounded, and aligned with the user's request.
15
+ - Implementation steps are ordered correctly with no circular dependencies.
16
+ - Required files are identified and files to avoid are listed.
17
+ - Validation strategy covers all deliverables with concrete acceptance criteria.
18
+ - Risk assessment covers security, data loss, breaking changes, and deployment concerns.
19
+ - The plan does not authorize destructive, secret, auth/session/log/runtime-state, database, deployment, push, or out-of-scope work without explicit approval.
20
+ - Test and build verification is included where applicable.
21
+
22
+ Output exactly:
23
+ # Reviewer Report
24
+ ## Verdict
25
+ PASS — plan is complete, safe, properly scoped, and ready for execution.
26
+ NOTES — plan is sound with non-blocking observations for the executor.
27
+ NEEDS REPAIR — plan has concrete gaps (missing steps, unclear files, weak validation, scope creep, risks not addressed).
28
+ FAIL — plan has serious blockers (safety violations, missing security constraints, broken dependencies, impossible steps).
29
+ BLOCKED — plan cannot proceed without external resolution.
30
+
31
+ Do not write APPROVED, APPROVE, OK, or PROCEED as the verdict label.
32
+
33
+ Verdict criteria:
34
+ - PASS only when: all checklist items are satisfied and no repairable issues remain.
35
+ - NOTES when: minor observations exist (suggested file order, additional test ideas, optional improvements).
36
+ - NEEDS REPAIR when: concrete missing requirements, unclear scope boundaries, insufficient validation, or unaddressed risks.
37
+ - FAIL when: safety/security violations, circular dependencies, impossible steps, or work that exceeds approved scope without authorization.
38
+ - BLOCKED when: plan requires unavailable resources or external dependencies that cannot be resolved by repair.
39
+ ## Reason
40
+ ## Scope Risks
41
+ ## Missing Information
42
+ ## Files To Be Careful With
43
+ ## Required Plan Revisions
44
+ ## Recommended Execution Notes
@@ -15,7 +15,7 @@
15
15
  * Uses JSON mode to capture structured output from subagents.
16
16
  */
17
17
 
18
- import { spawn } from "node:child_process";
18
+ import { execFileSync, spawn } from "node:child_process";
19
19
  import { createRequire } from "node:module";
20
20
  import * as fs from "node:fs";
21
21
  import * as os from "node:os";
@@ -109,6 +109,42 @@ class SafeContainer {
109
109
  const MAX_PARALLEL_TASKS = 8;
110
110
  const MAX_CONCURRENCY = 4;
111
111
  const COLLAPSED_ITEM_COUNT = 10;
112
+ const REPOLOCK_GUARD_EXTENSION = path.join(path.dirname(new URL(import.meta.url).pathname), "repolock-guard.ts");
113
+
114
+ function safeRealpath(candidate: string): string {
115
+ try {
116
+ return fs.realpathSync(candidate);
117
+ } catch {
118
+ return candidate;
119
+ }
120
+ }
121
+
122
+ function pathInsideRoot(candidate: string, root: string): boolean {
123
+ return candidate === root || candidate.startsWith(`${root}${path.sep}`);
124
+ }
125
+
126
+ function resolveSubagentCwd(candidate: string | undefined, defaultCwd: string): string {
127
+ return safeRealpath(path.resolve(defaultCwd, candidate || "."));
128
+ }
129
+
130
+ function repoRootForCwd(cwd: string): string {
131
+ try {
132
+ const root = execFileSync("git", ["rev-parse", "--show-toplevel"], { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
133
+ return safeRealpath(root || cwd);
134
+ } catch {
135
+ return safeRealpath(cwd);
136
+ }
137
+ }
138
+
139
+ function repoLockRootForSubagent(defaultCwd: string, settings: ReturnType<typeof loadWorkflowSettings>): string | undefined {
140
+ if (process.env.PI_WORKFLOW_REPO_LOCK_ENABLED === "1" && process.env.PI_WORKFLOW_REPO_LOCK_ROOT) return safeRealpath(process.env.PI_WORKFLOW_REPO_LOCK_ROOT);
141
+ return settings.safety.repoLockEnabled === true ? repoRootForCwd(defaultCwd) : undefined;
142
+ }
143
+
144
+ function repoLockCwdError(candidate: string | undefined, defaultCwd: string, root: string): string | undefined {
145
+ const resolved = resolveSubagentCwd(candidate, defaultCwd);
146
+ return pathInsideRoot(resolved, root) ? undefined : `Repo Lock blocked sub-agent cwd outside current repository: ${resolved} (repo root: ${root})`;
147
+ }
112
148
 
113
149
  function formatTokens(count: number): string {
114
150
  if (count < 1000) return count.toString();
@@ -345,7 +381,23 @@ async function runSingleAgent(
345
381
  };
346
382
  }
347
383
 
348
- const args: string[] = ["--no-extensions", "--mode", "json", "-p", "--no-session"];
384
+ const settings = loadWorkflowSettings(defaultCwd);
385
+ const lockRoot = repoLockRootForSubagent(defaultCwd, settings);
386
+ const effectiveCwd = resolveSubagentCwd(cwd, defaultCwd);
387
+ if (lockRoot && !pathInsideRoot(effectiveCwd, lockRoot)) {
388
+ return {
389
+ agent: agentName,
390
+ agentSource: agent.source,
391
+ task,
392
+ exitCode: 1,
393
+ messages: [],
394
+ stderr: `Repo Lock blocked sub-agent cwd outside current repository: ${effectiveCwd} (repo root: ${lockRoot})`,
395
+ usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, contextTokens: 0, turns: 0 },
396
+ step,
397
+ };
398
+ }
399
+
400
+ const args: string[] = ["--no-extensions", "--extension", REPOLOCK_GUARD_EXTENSION, "--mode", "json", "-p", "--no-session"];
349
401
  if (agent.model) args.push("--model", agent.model);
350
402
  if (agent.tools && agent.tools.length > 0) args.push("--tools", agent.tools.join(","));
351
403
 
@@ -390,13 +442,14 @@ async function runSingleAgent(
390
442
  const exitCode = await new Promise<number>((resolve) => {
391
443
  const invocation = getPiInvocation(args);
392
444
  const proc = spawn(invocation.command, invocation.args, {
393
- cwd: cwd ?? defaultCwd,
445
+ cwd: effectiveCwd,
394
446
  shell: false,
395
447
  stdio: ["ignore", "pipe", "pipe"],
396
448
  env: {
397
449
  ...process.env,
398
450
  PI_SUBAGENT_WORKER: "1",
399
451
  PI_SUBAGENT_NAME: agent.name,
452
+ ...(lockRoot ? { PI_WORKFLOW_REPO_LOCK_ENABLED: "1", PI_WORKFLOW_REPO_LOCK_ROOT: lockRoot } : {}),
400
453
  },
401
454
  });
402
455
  let buffer = "";
@@ -562,6 +615,19 @@ export default function (pi: ExtensionAPI) {
562
615
 
563
616
  async execute(_toolCallId, params, signal, onUpdate, ctx) {
564
617
  const settings = loadWorkflowSettings(ctx.cwd);
618
+ const lockRoot = repoLockRootForSubagent(ctx.cwd, settings);
619
+ if (lockRoot) {
620
+ const cwdErrors = [params.cwd, ...(params.tasks ?? []).map((task) => task.cwd), ...(params.chain ?? []).map((step) => step.cwd)]
621
+ .map((cwdValue) => repoLockCwdError(cwdValue, ctx.cwd, lockRoot))
622
+ .filter((error): error is string => Boolean(error));
623
+ if (cwdErrors.length) {
624
+ return {
625
+ content: [{ type: "text", text: cwdErrors[0] }],
626
+ details: { mode: "single", agentScope: params.agentScope ?? "user", projectAgentsDir: null, results: [] },
627
+ isError: true,
628
+ };
629
+ }
630
+ }
565
631
  const subagentLimits = { timeoutMinutes: settings.subagents.subagentTimeoutMinutes, staleMinutes: settings.subagents.subagentStaleMinutes };
566
632
  if (settings.subagents.requireApprovalBeforeRun === true) {
567
633
  const requested = params.tasks?.length
@@ -0,0 +1,111 @@
1
+ import { existsSync, realpathSync } from "node:fs";
2
+ import { isAbsolute, resolve } from "node:path";
3
+ import { getAgentDir, type ExtensionAPI } from "@earendil-works/pi-coding-agent";
4
+
5
+ const PATH_SCOPED_TOOLS = new Set(["read", "grep", "find", "ls", "edit", "write"]);
6
+
7
+ function safeRealpath(path: string): string {
8
+ try {
9
+ return realpathSync(path);
10
+ } catch {
11
+ return path;
12
+ }
13
+ }
14
+
15
+ function resolveCandidatePath(pathValue: string, cwd: string): string {
16
+ const expanded = pathValue === "~" || pathValue.startsWith("~/") ? resolve(process.env.HOME || cwd, pathValue.slice(2)) : pathValue;
17
+ const resolved = isAbsolute(expanded) ? resolve(expanded) : resolve(cwd, expanded || ".");
18
+ if (existsSync(resolved)) return safeRealpath(resolved);
19
+ const existingParent = safeRealpath(resolve(resolved, ".."));
20
+ return resolve(existingParent, resolved.split(/[\\/]/).pop() || "");
21
+ }
22
+
23
+ function pathInsideRoot(candidate: string, root: string): boolean {
24
+ return candidate === root || candidate.startsWith(`${root}/`);
25
+ }
26
+
27
+ function protectedRepoPath(candidate: string, root: string): boolean {
28
+ const rel = candidate === root ? "" : candidate.slice(root.length + 1);
29
+ return rel === ".pi" || rel.startsWith(".pi/");
30
+ }
31
+
32
+ function piRuntimeInstructionPath(candidate: string): boolean {
33
+ const root = safeRealpath(getAgentDir());
34
+ if (!pathInsideRoot(candidate, root)) return false;
35
+ const rel = candidate === root ? "" : candidate.slice(root.length + 1);
36
+ return rel === "skills" || rel.startsWith("skills/")
37
+ || rel === "agents" || rel.startsWith("agents/")
38
+ || rel === "config/prompts" || rel.startsWith("config/prompts/")
39
+ || rel === "prompts" || rel.startsWith("prompts/")
40
+ || rel === "themes" || rel.startsWith("themes/");
41
+ }
42
+
43
+ function repoLockPathBlock(pathValue: unknown, cwd: string, tool: string): string | undefined {
44
+ if (process.env.PI_WORKFLOW_REPO_LOCK_ENABLED !== "1") return undefined;
45
+ const root = safeRealpath(process.env.PI_WORKFLOW_REPO_LOCK_ROOT || cwd);
46
+ const candidate = resolveCandidatePath(typeof pathValue === "string" && pathValue.trim() ? pathValue.trim() : ".", cwd);
47
+ if (!pathInsideRoot(candidate, root)) {
48
+ if ((tool === "read" || tool === "grep" || tool === "find" || tool === "ls") && piRuntimeInstructionPath(candidate)) return undefined;
49
+ return `Repo Lock blocked sub-agent path outside current repository: ${candidate} (repo root: ${root})`;
50
+ }
51
+ if ((tool === "edit" || tool === "write") && protectedRepoPath(candidate, root)) return `Repo Lock blocked sub-agent ${tool} for protected project control path: ${candidate}`;
52
+ return undefined;
53
+ }
54
+
55
+ function stripHereDocBodies(command: string): string {
56
+ const lines = command.split("\n");
57
+ const kept: string[] = [];
58
+ for (let i = 0; i < lines.length; i++) {
59
+ const line = lines[i];
60
+ kept.push(line);
61
+ const match = line.match(/<<[-]?\s*['\"]?([A-Za-z_][A-Za-z0-9_]*)['\"]?/);
62
+ if (!match) continue;
63
+ const marker = match[1];
64
+ i++;
65
+ while (i < lines.length && lines[i].trim() !== marker) i++;
66
+ }
67
+ return kept.join("\n");
68
+ }
69
+
70
+ function stripUriTokens(command: string): string {
71
+ return command.replace(/\b[A-Za-z][A-Za-z0-9+.-]*:\/\/[^\s'"`;&|)]*/g, " ");
72
+ }
73
+
74
+ function bashPathCandidates(command: string): string[] {
75
+ const trimmed = stripUriTokens(stripHereDocBodies(command)).trim();
76
+ if (!trimmed) return [];
77
+ return Array.from(trimmed.matchAll(/(?:^|[\s=:'"`])((?:\.{1,2}|~|\/)[^\s'"`;&|)]*)/g)).map((match) => match[1]).filter(Boolean);
78
+ }
79
+
80
+ function repoLockBashBlock(command: string, cwd: string): string | undefined {
81
+ if (process.env.PI_WORKFLOW_REPO_LOCK_ENABLED !== "1") return undefined;
82
+ const root = safeRealpath(process.env.PI_WORKFLOW_REPO_LOCK_ROOT || cwd);
83
+ const candidates = bashPathCandidates(command);
84
+ for (const raw of candidates) {
85
+ if (raw === "." || raw === "./" || raw === "/") continue;
86
+ const cleaned = raw.replace(/[),]+$/, "");
87
+ if (!cleaned || cleaned.startsWith("./node_modules/.bin")) continue;
88
+ const candidate = resolveCandidatePath(cleaned, cwd);
89
+ if (!pathInsideRoot(candidate, root)) return `Repo Lock blocked sub-agent bash path outside current repository: ${cleaned} -> ${candidate} (repo root: ${root})`;
90
+ }
91
+ return undefined;
92
+ }
93
+
94
+ export default function repoLockSubagentGuard(pi: ExtensionAPI): void {
95
+ pi.on("tool_call", (event, ctx) => {
96
+ if (PATH_SCOPED_TOOLS.has(event.toolName)) {
97
+ const reason = repoLockPathBlock((event.input as { path?: unknown; file_path?: unknown }).path ?? (event.input as { file_path?: unknown }).file_path, ctx.cwd, event.toolName);
98
+ if (reason) return { block: true, reason };
99
+ }
100
+ if (event.toolName === "bash") {
101
+ const command = String((event.input as { command?: unknown }).command ?? "");
102
+ const reason = repoLockBashBlock(command, ctx.cwd);
103
+ if (reason) return { block: true, reason };
104
+ }
105
+ });
106
+
107
+ pi.on("user_bash", (event, ctx) => {
108
+ const reason = repoLockBashBlock(event.command, ctx.cwd);
109
+ if (reason) return { result: { output: reason, exitCode: 1, cancelled: false, truncated: false } };
110
+ });
111
+ }
@@ -5,12 +5,13 @@
5
5
  * sub-agent policy before the main planner/executor/reviewer/validator turn.
6
6
  */
7
7
 
8
- import { spawn } from "node:child_process";
8
+ import { execFileSync, spawn } from "node:child_process";
9
9
  import * as fs from "node:fs";
10
10
  import * as os from "node:os";
11
11
  import * as path from "node:path";
12
12
  import type { Message } from "@earendil-works/pi-ai";
13
13
  import { withFileMutationQueue } from "@earendil-works/pi-coding-agent";
14
+ import { loadWorkflowSettings } from "../workflow-model-router.js";
14
15
  import { type AgentConfig, type AgentScope, type AgentSource, discoverAgents } from "./agents.js";
15
16
 
16
17
  export interface WorkflowSubagentTask {
@@ -60,6 +61,37 @@ export interface WorkflowSubagentRunOptions {
60
61
  }
61
62
 
62
63
  const MAX_CONCURRENCY = 4;
64
+ const REPOLOCK_GUARD_EXTENSION = path.join(path.dirname(new URL(import.meta.url).pathname), "repolock-guard.ts");
65
+
66
+ function safeRealpath(candidate: string): string {
67
+ try {
68
+ return fs.realpathSync(candidate);
69
+ } catch {
70
+ return candidate;
71
+ }
72
+ }
73
+
74
+ function pathInsideRoot(candidate: string, root: string): boolean {
75
+ return candidate === root || candidate.startsWith(`${root}${path.sep}`);
76
+ }
77
+
78
+ function resolveSubagentCwd(candidate: string | undefined, defaultCwd: string): string {
79
+ return safeRealpath(path.resolve(defaultCwd, candidate || "."));
80
+ }
81
+
82
+ function repoRootForCwd(cwd: string): string {
83
+ try {
84
+ const root = execFileSync("git", ["rev-parse", "--show-toplevel"], { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
85
+ return safeRealpath(root || cwd);
86
+ } catch {
87
+ return safeRealpath(cwd);
88
+ }
89
+ }
90
+
91
+ function repoLockRootForSubagent(defaultCwd: string): string | undefined {
92
+ if (process.env.PI_WORKFLOW_REPO_LOCK_ENABLED === "1" && process.env.PI_WORKFLOW_REPO_LOCK_ROOT) return safeRealpath(process.env.PI_WORKFLOW_REPO_LOCK_ROOT);
93
+ return loadWorkflowSettings(defaultCwd).safety.repoLockEnabled === true ? repoRootForCwd(defaultCwd) : undefined;
94
+ }
63
95
 
64
96
  function finalOutput(messages: Message[]): string {
65
97
  for (let i = messages.length - 1; i >= 0; i--) {
@@ -132,7 +164,22 @@ async function runSingleWorkflowSubagent(
132
164
  };
133
165
  }
134
166
 
135
- const args: string[] = ["--no-extensions", "--mode", "json", "-p", "--no-session"];
167
+ const lockRoot = repoLockRootForSubagent(defaultCwd);
168
+ const effectiveCwd = resolveSubagentCwd(task.cwd, defaultCwd);
169
+ if (lockRoot && !pathInsideRoot(effectiveCwd, lockRoot)) {
170
+ return {
171
+ agent: task.agent,
172
+ agentSource: agent.source,
173
+ agentTools: agent.tools,
174
+ task: task.task,
175
+ exitCode: 1,
176
+ output: "",
177
+ stderr: `Repo Lock blocked sub-agent cwd outside current repository: ${effectiveCwd} (repo root: ${lockRoot})`,
178
+ usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, contextTokens: 0, turns: 0 },
179
+ };
180
+ }
181
+
182
+ const args: string[] = ["--no-extensions", "--extension", REPOLOCK_GUARD_EXTENSION, "--mode", "json", "-p", "--no-session"];
136
183
  if (agent.model) args.push("--model", agent.model);
137
184
  if (agent.tools && agent.tools.length > 0) args.push("--tools", agent.tools.join(","));
138
185
 
@@ -162,13 +209,14 @@ async function runSingleWorkflowSubagent(
162
209
  const exitCode = await new Promise<number>((resolve) => {
163
210
  const invocation = getPiInvocation(args);
164
211
  const proc = spawn(invocation.command, invocation.args, {
165
- cwd: task.cwd ?? defaultCwd,
212
+ cwd: effectiveCwd,
166
213
  shell: false,
167
214
  stdio: ["ignore", "pipe", "pipe"],
168
215
  env: {
169
216
  ...process.env,
170
217
  PI_SUBAGENT_WORKER: "1",
171
218
  PI_SUBAGENT_NAME: agent.name,
219
+ ...(lockRoot ? { PI_WORKFLOW_REPO_LOCK_ENABLED: "1", PI_WORKFLOW_REPO_LOCK_ROOT: lockRoot } : {}),
172
220
  },
173
221
  });
174
222
  let buffer = "";
@@ -106,6 +106,8 @@ export interface WorkflowSettings {
106
106
  clarificationQualityGate?: boolean;
107
107
  allowClarificationWithoutAnalysis?: boolean;
108
108
  useSubagentsBeforeClarification?: boolean;
109
+ maxTokens?: number;
110
+ maxRuntimeHours?: number;
109
111
  };
110
112
  workflow: {
111
113
  requirePlanApprovalBeforeExecute: boolean;
@@ -138,6 +140,7 @@ export interface WorkflowSettings {
138
140
  planHistoryLimit?: number;
139
141
  planProgressEnabled?: boolean;
140
142
  planRuntimeEnabled?: boolean;
143
+ planShowProgressBar?: boolean;
141
144
  };
142
145
  standard: {
143
146
  enabled: boolean;
@@ -160,11 +163,13 @@ export interface WorkflowSettings {
160
163
  useStandardSpecificModels?: boolean;
161
164
  modelRole?: StandardModelRole;
162
165
  models?: Record<WorkflowRole, RoleModelSettings>;
166
+ maxTokens?: number;
163
167
  };
164
168
  missions: {
165
169
  enabled: boolean;
166
170
  defaultAutonomy: MissionAutonomy;
167
171
  maxRuntimeHours: number;
172
+ maxTokens?: number;
168
173
  checkpointIntervalMinutes: number;
169
174
  requireApprovalForDestructiveActions: boolean;
170
175
  requireValidationPerMilestone: boolean;
@@ -214,6 +219,7 @@ export interface WorkflowSettings {
214
219
  disableBashInPlanMode: boolean;
215
220
  disableBashInValidatorMode: boolean;
216
221
  blockDestructiveCommands: boolean;
222
+ allowPackageInstallInExecution: boolean;
217
223
  };
218
224
  ui: {
219
225
  showWorkflowStatus: boolean;
@@ -242,6 +248,7 @@ export interface WorkflowSettings {
242
248
  customBrandEnabled?: boolean;
243
249
  customBrandText?: string;
244
250
  customBrandBaseVisual?: CustomBrandBaseVisual;
251
+ debugPlanStepTracking?: boolean;
245
252
  };
246
253
  subagents: WorkflowSubagentSettings;
247
254
  context: {
@@ -365,6 +372,7 @@ const BUILTIN_DEFAULT_WORKFLOW_SETTINGS = {
365
372
  "planHistoryLimit": 50,
366
373
  "planProgressEnabled": true,
367
374
  "planRuntimeEnabled": true,
375
+ "planShowProgressBar": true,
368
376
  "requireApprovalBeforeExecution": true,
369
377
  "requireApprovalPerStep": false,
370
378
  "validateAfterEachStep": false,
@@ -415,7 +423,8 @@ const BUILTIN_DEFAULT_WORKFLOW_SETTINGS = {
415
423
  "model": null,
416
424
  "thinkingLevel": "xhigh"
417
425
  }
418
- }
426
+ },
427
+ "maxTokens": 0
419
428
  },
420
429
  "missions": {
421
430
  "enabled": true,
@@ -429,9 +438,9 @@ const BUILTIN_DEFAULT_WORKFLOW_SETTINGS = {
429
438
  "autoRunAfterApproval": true,
430
439
  "offerReviewerBeforeApprove": false,
431
440
  "autoRunReviewerBeforeApprove": false,
432
- "autoRepairReviewFailures": false,
433
- "reviewRetryMode": "off",
434
- "maxReviewRetriesPerMission": 0,
441
+ "autoRepairReviewFailures": true,
442
+ "reviewRetryMode": "safe_only",
443
+ "maxReviewRetriesPerMission": 2,
435
444
  "continueAcrossMilestones": true,
436
445
  "pauseBetweenMilestones": false,
437
446
  "progressWidgetEnabled": true,
@@ -488,13 +497,15 @@ const BUILTIN_DEFAULT_WORKFLOW_SETTINGS = {
488
497
  "clarificationTiming": "after_initial_analysis",
489
498
  "clarificationQualityGate": true,
490
499
  "allowClarificationWithoutAnalysis": false,
491
- "useSubagentsBeforeClarification": true
500
+ "useSubagentsBeforeClarification": true,
501
+ "maxTokens": 0
492
502
  },
493
503
  "safety": {
494
- "repoLockEnabled": false,
495
- "disableBashInPlanMode": true,
504
+ "repoLockEnabled": true,
505
+ "disableBashInPlanMode": false,
496
506
  "disableBashInValidatorMode": true,
497
- "blockDestructiveCommands": true
507
+ "blockDestructiveCommands": true,
508
+ "allowPackageInstallInExecution": true
498
509
  },
499
510
  "ui": {
500
511
  "showWorkflowStatus": true,
@@ -522,7 +533,8 @@ const BUILTIN_DEFAULT_WORKFLOW_SETTINGS = {
522
533
  "startupVisualOnSessionStart": true,
523
534
  "customBrandEnabled": false,
524
535
  "customBrandText": "",
525
- "customBrandBaseVisual": "mission_control"
536
+ "customBrandBaseVisual": "mission_control",
537
+ "debugPlanStepTracking": false
526
538
  },
527
539
  "shortcuts": {
528
540
  "planMode": null
@@ -572,7 +584,9 @@ const BUILTIN_DEFAULT_WORKFLOW_SETTINGS = {
572
584
  "clarificationTiming": "after_initial_analysis",
573
585
  "clarificationQualityGate": true,
574
586
  "allowClarificationWithoutAnalysis": false,
575
- "useSubagentsBeforeClarification": true
587
+ "useSubagentsBeforeClarification": true,
588
+ "maxTokens": 0,
589
+ "maxRuntimeHours": 0
576
590
  },
577
591
  "context": {
578
592
  "compactionMode": "pi_default",
@@ -869,7 +883,7 @@ export function builtInWorkflowPresets(): Record<string, WorkflowPresetBundle> {
869
883
  displayName: "Simple",
870
884
  description: "Fast end-to-end Plan/Mission/Standard workflow with minimal ceremony, automatic validation when work runs, low safe repair retries, and one-worker sub-agent support.",
871
885
  planning: { depth: "fast", clarificationMode: "auto", maxClarificationQuestions: 2, interactiveClarificationEnabled: true, clarificationQualityGate: false, useSubagentsBeforeClarification: true },
872
- workflow: { offerReviewerBeforeExecute: false, autoRunReviewerBeforeExecute: false, offerValidationAfterExecute: true, autoRunValidationAfterExecute: true, validateAfterExecution: true, requirePlanApprovalBeforeExecute: false, requireApprovalBeforeExecution: false, autoRepairReviewFailures: false, autoRepairValidationFailures: true, reviewRetryMode: "off", validationRetryMode: "safe_only", maxReviewRetriesPerPlan: 0, maxReviewRetriesPerWorkflow: 0, maxValidationRetriesPerPlan: 1, maxValidationRetriesPerWorkflow: 2, pauseAfterReviewFailure: true, pauseAfterValidationFailure: false, planProgressEnabled: true, planRuntimeEnabled: true },
886
+ workflow: { offerReviewerBeforeExecute: false, autoRunReviewerBeforeExecute: false, offerValidationAfterExecute: true, autoRunValidationAfterExecute: true, validateAfterExecution: true, requirePlanApprovalBeforeExecute: false, requireApprovalBeforeExecution: false, autoRepairReviewFailures: false, autoRepairValidationFailures: true, reviewRetryMode: "off", validationRetryMode: "safe_only", maxReviewRetriesPerPlan: 0, maxReviewRetriesPerWorkflow: 0, maxValidationRetriesPerPlan: 1, maxValidationRetriesPerWorkflow: 2, pauseAfterReviewFailure: true, pauseAfterValidationFailure: false, planProgressEnabled: true, planRuntimeEnabled: true, planShowProgressBar: true },
873
887
  standard: { enabled: true, autoTodoEnabled: true, todoProgressVisible: true, todoTriggerMode: "auto", clarificationEnabled: true, clarificationMode: "auto", maxClarificationQuestions: 1, interactiveClarificationEnabled: true, clarificationTiming: "after_initial_analysis", clarificationQualityGate: false, allowClarificationWithoutAnalysis: false, useSubagentsBeforeClarification: false, allowSubagents: true, subagentScope: "user", subagents: { planningPolicy: "forced", executionPolicy: "forced", repairPolicy: "forced", reviewPolicy: "auto", validationPolicy: "forced", autoUseDuringPlanning: true, autoUseDuringExecution: true, autoUseDuringRepair: true, autoUseDuringReview: true, autoUseDuringValidation: true, minPlanningWorkersForDeep: 1, minPlanningWorkersForMaximum: 1, minExecutionWorkersForDeep: 1, minExecutionWorkersForMaximum: 1, minRepairWorkersForDeep: 1, minRepairWorkersForMaximum: 1, minReviewWorkersForDeep: 1, minReviewWorkersForMaximum: 1, minValidationWorkersForDeep: 1, minValidationWorkersForMaximum: 1 }, statusWidgetVisible: true, useSharedExecutorModel: true, useStandardSpecificModels: false, modelRole: "executor" },
874
888
  missions: { defaultAutonomy: "approval_gated", requireValidationPerMilestone: true, autoRunAfterApproval: true, continueAcrossMilestones: true, pauseBetweenMilestones: false, clarificationMode: "auto", maxClarificationQuestions: 2, planningDepth: "fast", useSubagentsBeforeClarification: true, autoRepairValidationFailures: true, validationRetryMode: "safe_only", maxValidationRetriesPerMilestone: 1, maxValidationRetriesPerMission: 2, finalValidationEnabled: false, autoRepairFinalValidationFailures: false, maxFinalValidationRetries: 0, subagentPolicy: "forced", minWorkersForDeep: 1, minWorkersForMaximum: 1 },
875
889
  subagents: { planningPolicy: "forced", executionPolicy: "forced", repairPolicy: "forced", reviewPolicy: "auto", validationPolicy: "forced", autoUseDuringPlanning: true, autoUseDuringExecution: true, autoUseDuringRepair: true, autoUseDuringReview: true, autoUseDuringValidation: true, minPlanningWorkersForDeep: 1, minPlanningWorkersForMaximum: 1, minExecutionWorkersForDeep: 1, minExecutionWorkersForMaximum: 1, minRepairWorkersForDeep: 1, minRepairWorkersForMaximum: 1, minReviewWorkersForDeep: 1, minReviewWorkersForMaximum: 1, minValidationWorkersForDeep: 1, minValidationWorkersForMaximum: 1 },
@@ -878,7 +892,7 @@ export function builtInWorkflowPresets(): Record<string, WorkflowPresetBundle> {
878
892
  displayName: "Standard",
879
893
  description: "Default end-to-end workflow with useful clarification, automatic execution/validation after approval, safe repair retries, and balanced worker support.",
880
894
  planning: { depth: "standard", clarificationMode: "auto", maxClarificationQuestions: 3, interactiveClarificationEnabled: true, clarificationQualityGate: true, useSubagentsBeforeClarification: true },
881
- workflow: { offerReviewerBeforeExecute: false, autoRunReviewerBeforeExecute: false, offerValidationAfterExecute: true, autoRunValidationAfterExecute: true, validateAfterExecution: true, requirePlanApprovalBeforeExecute: false, requireApprovalBeforeExecution: false, autoRepairReviewFailures: true, autoRepairValidationFailures: true, reviewRetryMode: "safe_only", validationRetryMode: "safe_only", maxReviewRetriesPerPlan: 2, maxReviewRetriesPerWorkflow: 4, maxValidationRetriesPerPlan: 2, maxValidationRetriesPerWorkflow: 4, pauseAfterReviewFailure: false, pauseAfterValidationFailure: false, planProgressEnabled: true, planRuntimeEnabled: true },
895
+ workflow: { offerReviewerBeforeExecute: false, autoRunReviewerBeforeExecute: false, offerValidationAfterExecute: true, autoRunValidationAfterExecute: true, validateAfterExecution: true, requirePlanApprovalBeforeExecute: false, requireApprovalBeforeExecution: false, autoRepairReviewFailures: true, autoRepairValidationFailures: true, reviewRetryMode: "safe_only", validationRetryMode: "safe_only", maxReviewRetriesPerPlan: 2, maxReviewRetriesPerWorkflow: 4, maxValidationRetriesPerPlan: 2, maxValidationRetriesPerWorkflow: 4, pauseAfterReviewFailure: false, pauseAfterValidationFailure: false, planProgressEnabled: true, planRuntimeEnabled: true, planShowProgressBar: true },
882
896
  standard: { enabled: true, autoTodoEnabled: true, todoProgressVisible: true, todoTriggerMode: "auto", clarificationEnabled: true, clarificationMode: "auto", maxClarificationQuestions: 1, interactiveClarificationEnabled: true, clarificationTiming: "after_initial_analysis", clarificationQualityGate: true, allowClarificationWithoutAnalysis: false, useSubagentsBeforeClarification: false, allowSubagents: true, subagentScope: "user", subagents: { planningPolicy: "forced", executionPolicy: "forced", repairPolicy: "forced", reviewPolicy: "forced", validationPolicy: "forced", autoUseDuringPlanning: true, autoUseDuringExecution: true, autoUseDuringRepair: true, autoUseDuringReview: true, autoUseDuringValidation: true, minPlanningWorkersForDeep: 1, minPlanningWorkersForMaximum: 1, minExecutionWorkersForDeep: 2, minExecutionWorkersForMaximum: 2, minRepairWorkersForDeep: 2, minRepairWorkersForMaximum: 2, minReviewWorkersForDeep: 2, minReviewWorkersForMaximum: 2, minValidationWorkersForDeep: 2, minValidationWorkersForMaximum: 2 }, statusWidgetVisible: true, useSharedExecutorModel: true, useStandardSpecificModels: false, modelRole: "executor" },
883
897
  missions: { defaultAutonomy: "approval_gated", requireValidationPerMilestone: true, autoRunAfterApproval: true, continueAcrossMilestones: true, pauseBetweenMilestones: false, clarificationMode: "auto", maxClarificationQuestions: 3, planningDepth: "standard", useSubagentsBeforeClarification: true, autoRepairValidationFailures: true, validationRetryMode: "safe_only", maxValidationRetriesPerMilestone: 2, maxValidationRetriesPerMission: 6, finalValidationEnabled: false, autoRepairFinalValidationFailures: false, maxFinalValidationRetries: 1, subagentPolicy: "forced", minWorkersForDeep: 1, minWorkersForMaximum: 1 },
884
898
  subagents: { planningPolicy: "forced", executionPolicy: "forced", repairPolicy: "forced", reviewPolicy: "forced", validationPolicy: "forced", autoUseDuringPlanning: true, autoUseDuringExecution: true, autoUseDuringRepair: true, autoUseDuringReview: true, autoUseDuringValidation: true, minPlanningWorkersForDeep: 1, minPlanningWorkersForMaximum: 1, minExecutionWorkersForDeep: 2, minExecutionWorkersForMaximum: 2, minRepairWorkersForDeep: 2, minRepairWorkersForMaximum: 2, minReviewWorkersForDeep: 2, minReviewWorkersForMaximum: 2, minValidationWorkersForDeep: 2, minValidationWorkersForMaximum: 2 },
@@ -887,7 +901,7 @@ export function builtInWorkflowPresets(): Record<string, WorkflowPresetBundle> {
887
901
  displayName: "Deep",
888
902
  description: "Careful end-to-end workflow for risky or codebase-heavy work with stronger clarification, automatic review/validation, final mission validation, and larger worker teams.",
889
903
  planning: { depth: "deep", clarificationMode: "always_for_nontrivial", maxClarificationQuestions: 5, interactiveClarificationEnabled: true, clarificationQualityGate: true, useSubagentsBeforeClarification: true },
890
- workflow: { offerReviewerBeforeExecute: false, autoRunReviewerBeforeExecute: true, offerValidationAfterExecute: true, autoRunValidationAfterExecute: true, validateAfterExecution: true, requirePlanApprovalBeforeExecute: false, requireApprovalBeforeExecution: false, autoRepairReviewFailures: true, autoRepairValidationFailures: true, reviewRetryMode: "safe_only", validationRetryMode: "safe_only", maxReviewRetriesPerPlan: 3, maxReviewRetriesPerWorkflow: 6, maxValidationRetriesPerPlan: 3, maxValidationRetriesPerWorkflow: 6, pauseAfterReviewFailure: false, pauseAfterValidationFailure: false, planProgressEnabled: true, planRuntimeEnabled: true },
904
+ workflow: { offerReviewerBeforeExecute: false, autoRunReviewerBeforeExecute: true, offerValidationAfterExecute: true, autoRunValidationAfterExecute: true, validateAfterExecution: true, requirePlanApprovalBeforeExecute: false, requireApprovalBeforeExecution: false, autoRepairReviewFailures: true, autoRepairValidationFailures: true, reviewRetryMode: "safe_only", validationRetryMode: "safe_only", maxReviewRetriesPerPlan: 3, maxReviewRetriesPerWorkflow: 6, maxValidationRetriesPerPlan: 3, maxValidationRetriesPerWorkflow: 6, pauseAfterReviewFailure: false, pauseAfterValidationFailure: false, planProgressEnabled: true, planRuntimeEnabled: true, planShowProgressBar: true },
891
905
  standard: { enabled: true, autoTodoEnabled: true, todoProgressVisible: true, todoTriggerMode: "required", clarificationEnabled: true, clarificationMode: "always_for_nontrivial", maxClarificationQuestions: 2, interactiveClarificationEnabled: true, clarificationTiming: "after_initial_analysis", clarificationQualityGate: true, allowClarificationWithoutAnalysis: false, useSubagentsBeforeClarification: true, allowSubagents: true, subagentScope: "user", subagents: { planningPolicy: "forced", executionPolicy: "forced", repairPolicy: "forced", reviewPolicy: "forced", validationPolicy: "forced", autoUseDuringPlanning: true, autoUseDuringExecution: true, autoUseDuringRepair: true, autoUseDuringReview: true, autoUseDuringValidation: true, minPlanningWorkersForDeep: 2, minPlanningWorkersForMaximum: 2, minExecutionWorkersForDeep: 3, minExecutionWorkersForMaximum: 3, minRepairWorkersForDeep: 2, minRepairWorkersForMaximum: 2, minReviewWorkersForDeep: 3, minReviewWorkersForMaximum: 3, minValidationWorkersForDeep: 3, minValidationWorkersForMaximum: 3 }, statusWidgetVisible: true, useSharedExecutorModel: true, useStandardSpecificModels: false, modelRole: "executor" },
892
906
  missions: { defaultAutonomy: "approval_gated", requireValidationPerMilestone: true, autoRunAfterApproval: true, continueAcrossMilestones: true, pauseBetweenMilestones: false, clarificationMode: "always_for_nontrivial", maxClarificationQuestions: 5, planningDepth: "deep", useSubagentsBeforeClarification: true, autoRepairValidationFailures: true, validationRetryMode: "safe_only", maxValidationRetriesPerMilestone: 3, maxValidationRetriesPerMission: 8, finalValidationEnabled: true, autoRepairFinalValidationFailures: true, maxFinalValidationRetries: 2, subagentPolicy: "forced", minWorkersForDeep: 3, minWorkersForMaximum: 3 },
893
907
  subagents: { planningPolicy: "forced", executionPolicy: "forced", repairPolicy: "forced", reviewPolicy: "forced", validationPolicy: "forced", autoUseDuringPlanning: true, autoUseDuringExecution: true, autoUseDuringRepair: true, autoUseDuringReview: true, autoUseDuringValidation: true, minPlanningWorkersForDeep: 3, minPlanningWorkersForMaximum: 3, minExecutionWorkersForDeep: 3, minExecutionWorkersForMaximum: 3, minRepairWorkersForDeep: 2, minRepairWorkersForMaximum: 2, minReviewWorkersForDeep: 3, minReviewWorkersForMaximum: 3, minValidationWorkersForDeep: 3, minValidationWorkersForMaximum: 3 },
@@ -896,7 +910,7 @@ export function builtInWorkflowPresets(): Record<string, WorkflowPresetBundle> {
896
910
  displayName: "Maximum",
897
911
  description: "Highest-rigor end-to-end workflow with strongest clarification, automatic review/validation, final mission validation, aggressive in-scope repair, and maximum worker teams.",
898
912
  planning: { depth: "maximum", clarificationMode: "always_for_nontrivial", maxClarificationQuestions: 5, interactiveClarificationEnabled: true, clarificationQualityGate: true, useSubagentsBeforeClarification: true },
899
- workflow: { offerReviewerBeforeExecute: false, autoRunReviewerBeforeExecute: true, offerValidationAfterExecute: true, autoRunValidationAfterExecute: true, validateAfterExecution: true, requirePlanApprovalBeforeExecute: false, requireApprovalBeforeExecution: false, autoRepairReviewFailures: true, autoRepairValidationFailures: true, reviewRetryMode: "aggressive_within_scope", validationRetryMode: "aggressive_within_scope", maxReviewRetriesPerPlan: 5, maxReviewRetriesPerWorkflow: 8, maxValidationRetriesPerPlan: 5, maxValidationRetriesPerWorkflow: 8, pauseAfterReviewFailure: false, pauseAfterValidationFailure: false, planProgressEnabled: true, planRuntimeEnabled: true },
913
+ workflow: { offerReviewerBeforeExecute: false, autoRunReviewerBeforeExecute: true, offerValidationAfterExecute: true, autoRunValidationAfterExecute: true, validateAfterExecution: true, requirePlanApprovalBeforeExecute: false, requireApprovalBeforeExecution: false, autoRepairReviewFailures: true, autoRepairValidationFailures: true, reviewRetryMode: "aggressive_within_scope", validationRetryMode: "aggressive_within_scope", maxReviewRetriesPerPlan: 5, maxReviewRetriesPerWorkflow: 8, maxValidationRetriesPerPlan: 5, maxValidationRetriesPerWorkflow: 8, pauseAfterReviewFailure: false, pauseAfterValidationFailure: false, planProgressEnabled: true, planRuntimeEnabled: true, planShowProgressBar: true },
900
914
  standard: { enabled: true, autoTodoEnabled: true, todoProgressVisible: true, todoTriggerMode: "required", clarificationEnabled: true, clarificationMode: "always_for_nontrivial", maxClarificationQuestions: 2, interactiveClarificationEnabled: true, clarificationTiming: "after_initial_analysis", clarificationQualityGate: true, allowClarificationWithoutAnalysis: false, useSubagentsBeforeClarification: true, allowSubagents: true, subagentScope: "user", subagents: { planningPolicy: "forced", executionPolicy: "forced", repairPolicy: "forced", reviewPolicy: "forced", validationPolicy: "forced", autoUseDuringPlanning: true, autoUseDuringExecution: true, autoUseDuringRepair: true, autoUseDuringReview: true, autoUseDuringValidation: true, minPlanningWorkersForDeep: 3, minPlanningWorkersForMaximum: 3, minExecutionWorkersForDeep: 4, minExecutionWorkersForMaximum: 4, minRepairWorkersForDeep: 3, minRepairWorkersForMaximum: 3, minReviewWorkersForDeep: 4, minReviewWorkersForMaximum: 4, minValidationWorkersForDeep: 4, minValidationWorkersForMaximum: 4 }, statusWidgetVisible: true, useSharedExecutorModel: true, useStandardSpecificModels: false, modelRole: "executor" },
901
915
  missions: { defaultAutonomy: "supervised_auto", requireValidationPerMilestone: true, autoRunAfterApproval: true, continueAcrossMilestones: true, pauseBetweenMilestones: false, clarificationMode: "always_for_nontrivial", maxClarificationQuestions: 6, planningDepth: "maximum", useSubagentsBeforeClarification: true, autoRepairValidationFailures: true, validationRetryMode: "aggressive_within_scope", maxValidationRetriesPerMilestone: 4, maxValidationRetriesPerMission: 12, finalValidationEnabled: true, autoRepairFinalValidationFailures: true, maxFinalValidationRetries: 4, subagentPolicy: "forced", minWorkersForDeep: 4, minWorkersForMaximum: 4 },
902
916
  subagents: { planningPolicy: "forced", executionPolicy: "forced", repairPolicy: "forced", reviewPolicy: "forced", validationPolicy: "forced", autoUseDuringPlanning: true, autoUseDuringExecution: true, autoUseDuringRepair: true, autoUseDuringReview: true, autoUseDuringValidation: true, minPlanningWorkersForDeep: 4, minPlanningWorkersForMaximum: 4, minExecutionWorkersForDeep: 4, minExecutionWorkersForMaximum: 4, minRepairWorkersForDeep: 3, minRepairWorkersForMaximum: 3, minReviewWorkersForDeep: 4, minReviewWorkersForMaximum: 4, minValidationWorkersForDeep: 4, minValidationWorkersForMaximum: 4 },