Skip to content

Commit 5182bd0

Browse files
committed
fix: reset execution state and variables on file switch
- Fixed Run All button stuck in Stop mode when switching .md files - Fixed document variables leaking across files on switch - Added resetFileSessionState() in workspace.js (abort + button + vars + progress cleanup) - Added forceReset() in exec-controller.js for immediate _running hard-reset - Wired into both wsOpenFile() and openDiskFile()
1 parent 9f31dbe commit 5182bd0

File tree

4 files changed

+90
-0
lines changed

4 files changed

+90
-0
lines changed

CHANGELOG-file-switch-reset.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# File-Switch State Reset — Bug Fixes
2+
3+
- Fixed: Run All button stays in "Stop" mode when switching to another .md file while execution is running
4+
- Fixed: Document variables from one file leak into another file's variable panel on file switch
5+
- Added `resetFileSessionState()` helper in `workspace.js` — aborts running execution, force-resets `_running` flag, resets Run All button to default, removes progress bar, clears runtime + manual variables, clears `__API_VARS`, clears SQLite exec context
6+
- Added `forceReset()` to exec-controller for immediate hard-reset of internal state (`_running`, `_currentRun`, abort flags)
7+
- Wired `resetFileSessionState()` into both `wsOpenFile()` and `openDiskFile()` file-switch paths
8+
9+
---
10+
11+
## Summary
12+
When switching between .md files, the Run All execution state and document variables were not reset, causing stale UI (Stop button persisting) and stale data (previous file's variables showing in the new file). Both `wsOpenFile()` and `openDiskFile()` now perform a full session cleanup on file switch.
13+
14+
---
15+
16+
## 1. File-Switch Session Reset
17+
**Files:** `js/workspace.js`
18+
**What:** New `resetFileSessionState()` function (L37-70) called from both `wsOpenFile()` (L636) and `openDiskFile()` (L389). It: (1) calls `abort()` + `forceReset()` on the exec-controller, (2) resets the `#run-all-btn` DOM (removes `fmt-run-active` class, restores innerHTML and title, nulls `onclick`), (3) removes the `.exec-progress-bar` element, (4) calls `clearRuntime()` + `clearManual()` on `M._vars`, (5) clears `window.__API_VARS`, (6) clears the SQLite exec context.
19+
**Impact:** Run All button always shows "▶ Run All" on a fresh file; variable panel starts empty for new files; progress bar is removed on switch.
20+
21+
## 2. Exec-Controller Force Reset
22+
**Files:** `js/exec-controller.js`
23+
**What:** New `forceReset()` function (L1026-1031) immediately sets `_running = false`, `_currentRun = null`, and abort flags. Exposed via `M._execController.forceReset`.
24+
**Impact:** Unlike `abort()` (which only sets `_abortRequested` and waits for the loop to exit), `forceReset()` provides an immediate hard-reset needed when switching files where the execution loop may be blocked awaiting a Promise.
25+
26+
---
27+
28+
## Files Changed (2 total)
29+
30+
| File | Lines Changed | Type |
31+
|------|:---:|------|
32+
| `js/workspace.js` | +44 | New `resetFileSessionState()` helper + wired into `wsOpenFile()` and `openDiskFile()` |
33+
| `js/exec-controller.js` | +12 | New `forceReset()` function + exposed in `M._execController` API |

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,7 @@ TextAgent has undergone significant evolution since its inception. What started
459459

460460
| Date | Commits | Feature / Update |
461461
|------|---------|-----------------|
462+
| **2026-03-16** | | 🐛 **File-Switch State Reset** — fixed Run All button staying in "Stop" mode when switching .md files; fixed document variables leaking across files; new `resetFileSessionState()` in `workspace.js` aborts execution, force-resets `_running` flag, clears Run All button/progress bar/variables/exec context on every file switch; new `forceReset()` in `exec-controller.js` for immediate hard-reset of internal state |
462463
| **2026-03-15** | | 🚀 **Run All Engine & TTS UX** — pre-execution model readiness check auto-loads all required models (AI + Kokoro TTS) before block execution starts; detailed `[RunAll]` console logging with `console.table` block summary, per-block timing, variable resolution status (✅/⚠), and completion summary; Stop button now works during model loading via `M._execAborted` cross-module flag; `ensureModelReadyAsync()` rewritten with fail-fast on missing consent/API key; compact preflight dialog (960px, smaller fonts, all 8 columns visible); `waitForModelReady()` handles Kokoro TTS via `M.tts.isKokoroReady()`; TTS card split into 3 buttons: ▶ Run (generate audio only), ▷ Play (replay stored audio), 💾 Save (download WAV); new `M.tts.generate()`, `playLastAudio()`, `isKokoroReady()`, `initKokoro()` APIs; AI model fallback in `run-requirements.js` correctly defaults to text models |
463464
| **2026-03-14** | | 🔗 **AI Variable Controls** — new unified 🔗 Vars button on AI and Agent cards opens combined dropdown with 📤 Output Variable (text input to name the block's result) and 📥 Input Variables (checkbox picker listing declared `@var:` names from other blocks + runtime vars); variable chaining enables multi-block AI pipelines (`@var: research``@input: research`); declared variables appear before execution with "declared" badge; Doc Variables Panel (`{•} Vars` toolbar button) now shows ⏳ Pending Vars section for declared-but-unexecuted variables; `@var:` and `@input:` directives stripped from displayed prompt text |
464465
| **2026-03-14** | | 🧠 **Think Mode Refinement & Multi-Select Search** — Think mode (`@think: Yes` / 🧠 toggle) now uses two-pass generation: first generates with thinking enabled, then passes the draft back to the model to add important details, examples, and missing information; removed complex ReAct pattern in favor of simple refinement; multi-select search provider dropdown on AI Generate and Agent Flow cards (checkbox pills, activate multiple engines simultaneously); search results fetched in parallel and merged |

js/exec-controller.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,6 +1019,17 @@
10191019
if (M.showToast) M.showToast('⏹ Stopping execution...', 'info');
10201020
}
10211021

1022+
/**
1023+
* Hard-reset all execution state. Used when switching files so
1024+
* the stale running state from the previous file doesn't persist.
1025+
*/
1026+
function forceReset() {
1027+
_abortRequested = true;
1028+
M._execAborted = true;
1029+
_running = false;
1030+
_currentRun = null;
1031+
}
1032+
10221033
// ========================================
10231034
// Progress UI + Log Panel
10241035
// ========================================
@@ -1176,6 +1187,7 @@
11761187
runAll: runAll,
11771188
runSingle: runSingle,
11781189
abort: abort,
1190+
forceReset: forceReset,
11791191
isRunning: function () { return _running; },
11801192
on: on,
11811193
off: off

js/workspace.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,46 @@
2929
return Date.now().toString(36) + Math.random().toString(36).substring(2, 8);
3030
}
3131

32+
/**
33+
* Reset execution and variable state when switching files.
34+
* Fixes: Run All button staying in "Stop" mode across files,
35+
* and variables from previous file leaking into new file.
36+
*/
37+
function resetFileSessionState() {
38+
// Abort any running execution and force-reset internal state
39+
if (M._execController) {
40+
if (M._execController.isRunning()) M._execController.abort();
41+
if (M._execController.forceReset) M._execController.forceReset();
42+
}
43+
44+
// Reset the Run All button to default state
45+
var runAllBtn = document.getElementById('run-all-btn');
46+
if (runAllBtn) {
47+
runAllBtn.classList.remove('fmt-run-active');
48+
runAllBtn.innerHTML = '<i class="bi bi-play-circle"></i> <span>Run All</span>';
49+
runAllBtn.title = 'Run all executable blocks in document order';
50+
runAllBtn.onclick = null;
51+
}
52+
53+
// Remove progress bar if visible
54+
var progressEl = document.querySelector('.exec-progress-bar');
55+
if (progressEl) {
56+
progressEl.remove();
57+
}
58+
59+
// Clear document variables (runtime + manual)
60+
if (M._vars) {
61+
if (M._vars.clearRuntime) M._vars.clearRuntime();
62+
if (M._vars.clearManual) M._vars.clearManual();
63+
}
64+
65+
// Clear legacy __API_VARS
66+
if (window.__API_VARS) window.__API_VARS = {};
67+
68+
// Clear SQLite exec context
69+
if (M._execContext && M._execContext.clear) M._execContext.clear();
70+
}
71+
3272
function saveWorkspace() {
3373
try {
3474
localStorage.setItem(WORKSPACE_KEY, JSON.stringify(workspace));
@@ -345,6 +385,8 @@
345385
else if (M.resetCloudForFileSwitch) M.resetCloudForFileSwitch();
346386
// Save current file
347387
M.wsSaveCurrent();
388+
// Reset execution state & variables for new file
389+
resetFileSessionState();
348390

349391
// Check if this file is already in the workspace manifest
350392
var wsFile = findFileByName(entry.path) || findFileByName(entry.name);
@@ -590,6 +632,8 @@
590632
else if (M.resetCloudForFileSwitch) M.resetCloudForFileSwitch();
591633
// Save current
592634
M.wsSaveCurrent();
635+
// Reset execution state & variables for new file
636+
resetFileSessionState();
593637
// Switch
594638
workspace.activeFileId = id;
595639
M.wsActiveFileId = id;

0 commit comments

Comments
 (0)