opencode-workflow-guard 1.9.1 → 1.9.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.
@@ -100,7 +100,7 @@ When the root session reaches idle, the checkpoint records the resulting workspa
100
100
 
101
101
  With the optional TUI companion installed, open the command palette and choose **Workflow Guard: Project Options** (or run `/guard-options`) to toggle recovery checkpoints, project memory, learner mode, Ralph mode, or the title-settle workaround for the current project. The command writes the existing Workflow Guard project config location, defaulting to `.opencode/workflow-guard.json`; restart OpenCode after changing a setting so the server plugin can expose the matching tools.
102
102
 
103
- The title-settle workaround is off by default. When enabled with `titleSettleWorkaround: true`, Workflow Guard briefly waits for OpenCode's asynchronous native title generation before sending an automatic continuation for unfinished root-session work. The wait is bounded, applies only when that session owns unfinished todos, and never changes the title or provider/model parameters itself.
103
+ The title-settle workaround is on by default because Workflow Guard's automatic continuation can race OpenCode's asynchronous native title generation. Workflow Guard briefly waits for native title generation before sending an automatic continuation for unfinished root-session work; set `titleSettleWorkaround: false` to opt out. The wait is bounded, applies only when that session owns unfinished todos, and never changes the title or provider/model parameters itself.
104
104
 
105
105
  Ralph mode is also off by default, including under the `autonomous` profile. Enable it explicitly with `ralphMode: true`; `ralphMaxIterations` sets its positive integer continuation budget from 1 through 100 (default 10; invalid values use the default). Ralph only continues a root session while that session already owns unfinished native todos. It does not create, prioritize, select, sequence, or delegate work, and every resumed run remains subject to the normal guardrails. Genuine user input stops an active Ralph run instead of resetting its budget. Reaching the budget with unfinished work reports `budget_exhausted`; completion is reported only when owned todos are actually finished. A `blocked` outcome is reserved for a demonstrable guard state and is never inferred merely from repeated idle events. `guard_status` exposes the effective Ralph configuration and current calling-session outcome.
106
106
 
package/docs/policies.md CHANGED
@@ -83,7 +83,7 @@ It is a policy and enforcement layer, not an agent harness. Policies may constra
83
83
  - Verification (`WORKFLOW_GUARD_VERIFY` env, project `verifyCommand`, or auto-detected test/typecheck runner across ecosystems: `package.json` (`npm test`, `npm run typecheck`, `npm run check`, `npm run build`), `Cargo.toml` (`cargo test`), `go.mod` (`go test ./...`), `pytest.ini`/`pyproject.toml` (`pytest`), or `deno.json` (`deno test`)) executes in an isolated environment with scrubbed credentials, output caps, token-efficient stdout/stderr snipping, and strict timeout protection. Environment configuration takes precedence over project configuration.
84
84
  - Project `postEditValidators` can run faster targeted checks after a direct file edit actually changes the target. Each entry accepts a workspace-relative glob `pattern` (`*`, `**`, and `?` wildcards; brace expansion and character classes are not supported), a non-empty `command`, and an optional positive `timeoutMs`; invalid entries are reported as advisory feedback rather than silently ignored. Matching commands run from the workspace root with the same scrubbed verification environment. Validator failures and timeouts are appended to the edit result as advisory feedback and do not replace the blocking whole-project finalization verification. Multi-file `apply_patch` calls validate every changed target.
85
85
  - With project `recoveryCheckpoints: true`, or the `autonomous` operation profile unless explicitly overridden, genuine root-session user runs capture a private Git checkpoint before agent work starts. Checkpoints preserve tracked and untracked state without using the user's stash list; subagents and generated continuation prompts do not replace them. At `session.idle`, the run's resulting workspace fingerprint is recorded before automatic continuation. `guard_recovery_restore` is provenance-bound to the same root session and refuses restoration after any intervening workspace change. Operation profiles only set optional workflow defaults and cannot weaken core safety policies.
86
- - Automatic continuation remains synthetic. With the opt-in project setting `titleSettleWorkaround: true`, an eligible root session with unfinished owned todos briefly waits for OpenCode's native asynchronous title generation before that continuation is sent; the bounded wait never rewrites titles or provider/model parameters.
86
+ - Automatic continuation remains synthetic. By default, an eligible root session with unfinished owned todos briefly waits for OpenCode's native asynchronous title generation before that continuation is sent; set `titleSettleWorkaround: false` to opt out. The bounded wait never rewrites titles or provider/model parameters.
87
87
  - **Git State & Snapshot Binding:** Verification evidence records the current git commit hash (`git rev-parse HEAD`) and working tree status. If unverified edits or index modifications occur after verification, fresh verification is enforced.
88
88
  - **Durable Disk Cache:** Passing verification results are cached to `~/.local/state/opencode/workflow-guard/last-verify.json`, allowing session restarts and multi-agent handoffs to retain valid verification evidence without redundant test runs. Durable evidence is **workspace-bound**: a cached result is only accepted for the workspace that produced it, so a passing run in one project can never satisfy finalization in another.
89
89
  - If verification fails, finalization is blocked with a structured summary of error markers, stack traces, and failure output.
@@ -0,0 +1,122 @@
1
+ # Title Settle Default Implementation Plan
2
+
3
+ > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
4
+
5
+ **Goal:** Make Workflow Guard's title-settle behavior enabled by default while preserving `titleSettleWorkaround: false` as an explicit opt-out.
6
+
7
+ **Architecture:** Treat the missing setting consistently as enabled at both consumers: the continuation server hook and TUI project-option reader. Keep the existing bounded title-settle implementation unchanged; only its effective default changes.
8
+
9
+ **Tech Stack:** TypeScript, OpenCode TUI plugin API, Node test harness, jsonc-parser.
10
+
11
+ ---
12
+
13
+ ### Task 1: Lock Down Default And Opt-Out Semantics
14
+
15
+ **Files:**
16
+ - Modify: `test/test.mts:1140-1155,2835-2860`
17
+
18
+ - [ ] **Step 1: Change the TUI regression to expect title settling on without configuration**
19
+
20
+ Before selecting the title-settle option, assert the missing setting reads as enabled. Then select its option callback and assert the persisted effective value becomes false:
21
+
22
+ ```ts
23
+ registeredTuiCommands.find((command) => command.name === "workflow-guard.project-options")?.run?.();
24
+ check("title settle workaround project option defaults on", readProjectOption(tuiCommandOptionsDir, "titleSettleWorkaround") === true);
25
+ tuiDialogSelectProps?.options?.find((option: any) => option.value === "titleSettleWorkaround")?.onSelect?.(fakeTuiApi.ui.dialog);
26
+ check("tui project-options command can disable title settle workaround", readProjectOption(tuiCommandOptionsDir, "titleSettleWorkaround") === false);
27
+ ```
28
+
29
+ - [ ] **Step 2: Change continuation regressions to cover default-on and explicit opt-out**
30
+
31
+ Use the existing title-settle continuation fixture around line 2844. Remove the requirement to write `{ titleSettleWorkaround: true }` for the positive case, and add a sibling case/fixture with `{ titleSettleWorkaround: false }` proving continuation does not wait for title settling when explicitly disabled. Preserve the existing assertions that title generation remains native and the wait remains bounded.
32
+
33
+ - [ ] **Step 3: Run the unit harness to verify the new expectations fail**
34
+
35
+ Run: `npm test`
36
+
37
+ Expected: the new default-on assertions fail against current production code while unrelated checks remain green.
38
+
39
+ ### Task 2: Implement Enabled-Unless-False Semantics
40
+
41
+ **Files:**
42
+ - Modify: `src/workflow-guard-ui.ts:36-43`
43
+ - Modify: `src/workflow-guard.ts:672`
44
+
45
+ - [ ] **Step 1: Make the TUI reader default title settling to enabled**
46
+
47
+ Update `readProjectOption` so both project memory and title settling are enabled unless explicitly false, while the other opt-in settings remain enabled only by explicit true:
48
+
49
+ ```ts
50
+ const enabledByDefault = option === "projectMemory" || option === "titleSettleWorkaround";
51
+ if (!existsSync(path)) return enabledByDefault;
52
+ // parse existing config as before
53
+ return enabledByDefault ? config?.[option] !== false : config?.[option] === true;
54
+ ```
55
+
56
+ - [ ] **Step 2: Make continuation use the same effective default**
57
+
58
+ Change the title-settle gate in `src/workflow-guard.ts` from:
59
+
60
+ ```ts
61
+ const settleTitle = getProjectConfig(effectiveRoot).titleSettleWorkaround === true;
62
+ ```
63
+
64
+ to:
65
+
66
+ ```ts
67
+ const settleTitle = getProjectConfig(effectiveRoot).titleSettleWorkaround !== false;
68
+ ```
69
+
70
+ - [ ] **Step 3: Run the unit harness**
71
+
72
+ Run: `npm test`
73
+
74
+ Expected: all checks pass, including default-enabled and explicit-false regressions.
75
+
76
+ ### Task 3: Document The New Default
77
+
78
+ **Files:**
79
+ - Modify: `docs/installation.md:103`
80
+ - Modify: `docs/policies.md:86`
81
+ - Modify: `.changeset/fix-project-option-toggles.md`
82
+
83
+ - [ ] **Step 1: Update installation guidance**
84
+
85
+ Replace the statement that title settling is off by default with text stating that it is on by default because Workflow Guard's automatic continuation can race OpenCode title generation, and that projects may opt out with `titleSettleWorkaround: false`.
86
+
87
+ - [ ] **Step 2: Update policy documentation**
88
+
89
+ Describe title settling as the default continuation behavior rather than opt-in behavior. Retain the guarantees that the wait is bounded and does not rewrite titles or provider/model parameters.
90
+
91
+ - [ ] **Step 3: Expand the existing patch changeset**
92
+
93
+ Make `.changeset/fix-project-option-toggles.md` mention both user-visible changes: functioning TUI toggles and title settling enabled by default with explicit opt-out.
94
+
95
+ ### Task 4: Verify The Final Tree
96
+
97
+ **Files:**
98
+ - Verify only
99
+
100
+ - [ ] **Step 1: Run type checking**
101
+
102
+ Run: `npm run typecheck`
103
+
104
+ Expected: exit 0 with no TypeScript errors.
105
+
106
+ - [ ] **Step 2: Run the full unit/adversarial harness**
107
+
108
+ Run: `npm test`
109
+
110
+ Expected: all checks pass with 0 failures.
111
+
112
+ - [ ] **Step 3: Run packaged installation verification**
113
+
114
+ Run: `npm run test:install`
115
+
116
+ Expected: all non-model-driven installation/runtime checks pass with 0 failures.
117
+
118
+ - [ ] **Step 4: Check the diff**
119
+
120
+ Run: `git diff --check`
121
+
122
+ Expected: exit 0 with no whitespace errors.
@@ -0,0 +1,25 @@
1
+ # Title Settle Default Design
2
+
3
+ ## Context
4
+
5
+ Workflow Guard can automatically continue a root session that still owns unfinished todos. That synthetic continuation can race OpenCode's asynchronous native session-title generation. The existing `titleSettleWorkaround` behavior avoids the race by briefly waiting for native title generation, but it currently requires explicit opt-in even though Workflow Guard's continuation behavior creates the need for the workaround.
6
+
7
+ ## Decision
8
+
9
+ Enable the title-settle behavior by default. A missing `titleSettleWorkaround` setting means enabled; `titleSettleWorkaround: false` remains an explicit project-level opt-out.
10
+
11
+ The server and TUI must expose the same effective semantics. The project-options menu therefore renders Title settle workaround as On when the setting is absent, and selecting it persists `false`. Selecting it again persists `true`.
12
+
13
+ No configuration migration is required. Existing projects that do not mention the setting acquire the safer default automatically, while projects already configured with `false` retain their behavior.
14
+
15
+ ## Scope
16
+
17
+ - Change effective server behavior from `=== true` to enabled unless explicitly false.
18
+ - Change the TUI project-option reader to report the same enabled-by-default value.
19
+ - Preserve all existing bounded-wait, ownership, title, provider, and model behavior.
20
+ - Update installation and policy documentation to describe the default and opt-out.
21
+ - Update regression coverage for default-enabled behavior and explicit-false opt-out.
22
+
23
+ ## Verification
24
+
25
+ Regression tests must prove that an unconfigured project uses title settling, explicit `false` bypasses title settling, and the TUI reports/toggles the same effective state. The repository typecheck, unit harness, and packaged-install test must remain green.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-workflow-guard",
3
- "version": "1.9.1",
3
+ "version": "1.9.3",
4
4
  "description": "Deterministic workflow and safety policy enforcement for OpenCode",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -35,11 +35,12 @@ type ProjectToggle = "recoveryCheckpoints" | "projectMemory" | "learning" | "tit
35
35
 
36
36
  export function readProjectOption(root: string, option: ProjectToggle): boolean {
37
37
  const path = projectConfigPath(root);
38
- if (!existsSync(path)) return option === "projectMemory";
38
+ const enabledByDefault = option === "projectMemory" || option === "titleSettleWorkaround";
39
+ if (!existsSync(path)) return enabledByDefault;
39
40
  const errors: ParseError[] = [];
40
41
  const config = parse(readFileSync(path, "utf8"), errors, { allowTrailingComma: true });
41
42
  if (errors.length > 0) throw new Error(`Invalid Workflow Guard project config: ${path}`);
42
- return option === "projectMemory" ? config?.projectMemory !== false : config?.[option] === true;
43
+ return enabledByDefault ? config?.[option] !== false : config?.[option] === true;
43
44
  }
44
45
 
45
46
  function writeProjectOption(root: string, option: ProjectToggle, enabled: boolean): string {
@@ -89,23 +90,22 @@ export const WorkflowGuardTui: TuiPlugin = async (api) => {
89
90
  const learning = readProjectOption(root, "learning");
90
91
  const titleSettle = readProjectOption(root, "titleSettleWorkaround");
91
92
  const ralphMode = readProjectOption(root, "ralphMode");
93
+ const toggle = (key: ProjectToggle) => {
94
+ const enabled = !readProjectOption(root, key);
95
+ const path = writeProjectOption(root, key, enabled);
96
+ api.ui.dialog.clear();
97
+ api.ui.toast({ variant: "success", title: "Workflow Guard", message: `Saved ${key} ${enabled ? "on" : "off"} in ${path}. Restart OpenCode to apply.` });
98
+ };
92
99
  api.ui.dialog.replace(() => api.ui.DialogSelect({
93
100
  title: "Workflow Guard Project Options",
94
101
  current: undefined,
95
102
  options: [
96
- { title: `Recovery checkpoints: ${recovery ? "On" : "Off"}`, value: "recoveryCheckpoints", description: "Toggle durable pre-run Git checkpoints" },
97
- { title: `Project memory: ${memory ? "On" : "Off"}`, value: "projectMemory", description: "Toggle durable local project memory" },
98
- { title: `Learner mode: ${learning ? "On" : "Off"}`, value: "learning", description: "Toggle evidence-based learning tools" },
99
- { title: `Title settle workaround: ${titleSettle ? "On" : "Off"}`, value: "titleSettleWorkaround", description: "Delay automatic continuation while OpenCode generates a session title" },
100
- { title: `Ralph mode: ${ralphMode ? "On" : "Off"}`, value: "ralphMode", description: "Opt into bounded autonomous continuation of already-owned todos" },
103
+ { title: `Recovery checkpoints: ${recovery ? "On" : "Off"}`, value: "recoveryCheckpoints", description: "Toggle durable pre-run Git checkpoints", onSelect: () => toggle("recoveryCheckpoints") },
104
+ { title: `Project memory: ${memory ? "On" : "Off"}`, value: "projectMemory", description: "Toggle durable local project memory", onSelect: () => toggle("projectMemory") },
105
+ { title: `Learner mode: ${learning ? "On" : "Off"}`, value: "learning", description: "Toggle evidence-based learning tools", onSelect: () => toggle("learning") },
106
+ { title: `Title settle workaround: ${titleSettle ? "On" : "Off"}`, value: "titleSettleWorkaround", description: "Delay automatic continuation while OpenCode generates a session title", onSelect: () => toggle("titleSettleWorkaround") },
107
+ { title: `Ralph mode: ${ralphMode ? "On" : "Off"}`, value: "ralphMode", description: "Opt into bounded autonomous continuation of already-owned todos", onSelect: () => toggle("ralphMode") },
101
108
  ],
102
- onSelect: (option) => {
103
- const key = option.value as ProjectToggle;
104
- const enabled = !readProjectOption(root, key);
105
- const path = writeProjectOption(root, key, enabled);
106
- api.ui.dialog.clear();
107
- api.ui.toast({ variant: "success", title: "Workflow Guard", message: `Saved ${key} ${enabled ? "on" : "off"} in ${path}. Restart OpenCode to apply.` });
108
- },
109
109
  }));
110
110
  },
111
111
  }],
@@ -669,7 +669,7 @@ export const WorkflowGuard: Plugin = async (ctx) => {
669
669
  if (recoveryRun !== undefined) {
670
670
  finalizeRecoveryCheckpoint(effectiveRoot, sessionID, recoveryRun);
671
671
  }
672
- const settleTitle = getProjectConfig(effectiveRoot).titleSettleWorkaround === true;
672
+ const settleTitle = getProjectConfig(effectiveRoot).titleSettleWorkaround !== false;
673
673
  await runWithRuntimeState(effectiveRoot, ctx.client, () => continueUnfinishedSession(sessionID, settleTitle));
674
674
  }
675
675
  }
package/test/test.mts CHANGED
@@ -1139,20 +1139,21 @@ check("tui plugin registers session_prompt_right slot", typeof registeredSlots.s
1139
1139
  check("tui plugin registers home_prompt_right slot", typeof registeredSlots.home_prompt_right === "function");
1140
1140
  check("tui plugin registers project-options command through keymap", registeredTuiCommands.some((command) => command.name === "workflow-guard.project-options"));
1141
1141
  registeredTuiCommands.find((command) => command.name === "workflow-guard.project-options")?.run?.();
1142
- tuiDialogSelectProps?.onSelect?.({ value: "recoveryCheckpoints" });
1142
+ tuiDialogSelectProps?.options?.find((option: any) => option.value === "recoveryCheckpoints")?.onSelect?.(fakeTuiApi.ui.dialog);
1143
1143
  check("tui project-options command persists selected recovery setting", readRecoveryCheckpointsOption(tuiCommandOptionsDir) === true);
1144
1144
  registeredTuiCommands.find((command) => command.name === "workflow-guard.project-options")?.run?.();
1145
- tuiDialogSelectProps?.onSelect?.({ value: "projectMemory" });
1145
+ tuiDialogSelectProps?.options?.find((option: any) => option.value === "projectMemory")?.onSelect?.(fakeTuiApi.ui.dialog);
1146
1146
  check("tui project-options command can disable project memory", readProjectOption(tuiCommandOptionsDir, "projectMemory") === false);
1147
1147
  registeredTuiCommands.find((command) => command.name === "workflow-guard.project-options")?.run?.();
1148
- tuiDialogSelectProps?.onSelect?.({ value: "learning" });
1148
+ tuiDialogSelectProps?.options?.find((option: any) => option.value === "learning")?.onSelect?.(fakeTuiApi.ui.dialog);
1149
1149
  check("tui project-options command can enable learner mode", readProjectOption(tuiCommandOptionsDir, "learning") === true);
1150
1150
  registeredTuiCommands.find((command) => command.name === "workflow-guard.project-options")?.run?.();
1151
- tuiDialogSelectProps?.onSelect?.({ value: "titleSettleWorkaround" });
1152
- check("tui project-options command can enable title settle workaround", readProjectOption(tuiCommandOptionsDir, "titleSettleWorkaround") === true);
1151
+ check("title settle workaround project option defaults on", readProjectOption(tuiCommandOptionsDir, "titleSettleWorkaround") === true);
1152
+ tuiDialogSelectProps?.options?.find((option: any) => option.value === "titleSettleWorkaround")?.onSelect?.(fakeTuiApi.ui.dialog);
1153
+ check("tui project-options command can disable title settle workaround", readProjectOption(tuiCommandOptionsDir, "titleSettleWorkaround") === false);
1153
1154
  registeredTuiCommands.find((command) => command.name === "workflow-guard.project-options")?.run?.();
1154
1155
  check("ralph mode project option defaults off", readProjectOption(tuiCommandOptionsDir, "ralphMode") === false);
1155
- tuiDialogSelectProps?.onSelect?.({ value: "ralphMode" });
1156
+ tuiDialogSelectProps?.options?.find((option: any) => option.value === "ralphMode")?.onSelect?.(fakeTuiApi.ui.dialog);
1156
1157
  check("tui project-options command can enable ralph mode", readProjectOption(tuiCommandOptionsDir, "ralphMode") === true);
1157
1158
  rmSync(tuiCommandOptionsDir, { recursive: true, force: true });
1158
1159
  const tuiOptionsDir = mkdtempSync(join(tmpdir(), "wg-tui-options-"));
@@ -2841,7 +2842,6 @@ const continuationClient = {
2841
2842
  };
2842
2843
  const continuationRoot = mkdtempSync(join(tmpdir(), "wg-title-settle-"));
2843
2844
  mkdirSync(join(continuationRoot, ".opencode"));
2844
- writeFileSync(join(continuationRoot, ".opencode", "workflow-guard.json"), JSON.stringify({ titleSettleWorkaround: true }));
2845
2845
  const continuationPlugin = await WorkflowGuard({ directory: continuationRoot, worktree: continuationRoot, client: continuationClient as any } as any);
2846
2846
  todo("s-resume", item("finish work", "pending"));
2847
2847
  await continuationPlugin.event?.({ event: { type: "session.idle", properties: { sessionID: "s-resume" } } } as any);
@@ -2849,20 +2849,22 @@ check("session idle auto-continues unfinished owned todos", continuationPrompts.
2849
2849
  check("automatic continuation remains synthetic", continuationParts.get("s-resume")?.every((part) => part.synthetic === true) === true);
2850
2850
  check("title settle workaround waits for OpenCode's native generated title before continuing", continuationTitleReads.get("s-resume") === 2 && continuationTitles.get("s-resume") === "Native generated title");
2851
2851
 
2852
- let defaultOffTitleReads = 0;
2853
- let defaultOffPrompts = 0;
2854
- const defaultOffRoot = mkdtempSync(join(tmpdir(), "wg-title-settle-off-"));
2855
- const defaultOffPlugin = await WorkflowGuard({ directory: defaultOffRoot, worktree: defaultOffRoot, client: {
2852
+ let optOutTitleReads = 0;
2853
+ let optOutPrompts = 0;
2854
+ const optOutRoot = mkdtempSync(join(tmpdir(), "wg-title-settle-off-"));
2855
+ mkdirSync(join(optOutRoot, ".opencode"));
2856
+ writeFileSync(join(optOutRoot, ".opencode", "workflow-guard.json"), JSON.stringify({ titleSettleWorkaround: false }));
2857
+ const optOutPlugin = await WorkflowGuard({ directory: optOutRoot, worktree: optOutRoot, client: {
2856
2858
  session: {
2857
2859
  todo: async ({ path }: { path: { id: string } }) => ({ data: fakeTodos.get(path.id) ?? [] }),
2858
- get: async () => { defaultOffTitleReads++; return { data: { title: "New session - 2026-08-27T12:00:00.000Z" } }; },
2859
- promptAsync: async () => { defaultOffPrompts++; },
2860
+ get: async () => { optOutTitleReads++; return { data: { title: "New session - 2026-08-27T12:00:00.000Z" } }; },
2861
+ promptAsync: async () => { optOutPrompts++; },
2860
2862
  },
2861
2863
  } as any } as any);
2862
- todo("s-resume-default-off", item("finish without title wait", "pending"));
2863
- await defaultOffPlugin.event?.({ event: { type: "session.idle", properties: { sessionID: "s-resume-default-off" } } } as any);
2864
- check("title settle workaround defaults off without suppressing continuation", defaultOffTitleReads === 0 && defaultOffPrompts === 1);
2865
- rmSync(defaultOffRoot, { recursive: true, force: true });
2864
+ todo("s-resume-opt-out", item("finish without title wait", "pending"));
2865
+ await optOutPlugin.event?.({ event: { type: "session.idle", properties: { sessionID: "s-resume-opt-out" } } } as any);
2866
+ check("title settle workaround explicit false skips title wait without suppressing continuation", optOutTitleReads === 0 && optOutPrompts === 1);
2867
+ rmSync(optOutRoot, { recursive: true, force: true });
2866
2868
 
2867
2869
  todo("s-resume-done", item("finished", "completed"));
2868
2870
  await continuationPlugin.event?.({ event: { type: "session.idle", properties: { sessionID: "s-resume-done" } } } as any);