myrlin-workbook 0.9.19 → 0.9.20

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/logs/server.pid CHANGED
@@ -1 +1 @@
1
- 49156
1
+ 45572
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myrlin-workbook",
3
- "version": "0.9.19",
3
+ "version": "0.9.20",
4
4
  "description": "Browser-based project manager for Claude Code sessions - session discovery, multi-terminal, cost tracking, docs, and kanban board",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -9110,11 +9110,33 @@ class CWMApp {
9110
9110
  });
9111
9111
  };
9112
9112
 
9113
- // Auto-close pane on fatal connection error (max retries exhausted or server error).
9114
- // Prevents dead panes from occupying grid space in the terminal layout.
9115
- tp.onFatalError = () => {
9113
+ // On fatal connection error, show disconnected state but PRESERVE pane info.
9114
+ // The session ID, name, and spawnOpts stay in the layout so the user can
9115
+ // reconnect by clicking, and layout saves don't lose the session mapping.
9116
+ tp.onFatalError = (failedSessionId) => {
9116
9117
  const idx = this.terminalPanes.indexOf(tp);
9117
- if (idx !== -1) this.closeTerminalPane(idx);
9118
+ if (idx === -1) return;
9119
+ // Stash session info before disposing so we can offer reconnect
9120
+ const sid = tp.sessionId;
9121
+ const sName = tp.sessionName;
9122
+ const opts = { ...(tp.spawnOpts || {}) };
9123
+ tp.dispose();
9124
+ // Replace the TerminalPane with a lightweight placeholder that preserves
9125
+ // the session mapping for layout saves (saveCurrentGroupPanes reads these).
9126
+ this.terminalPanes[idx] = { sessionId: sid, sessionName: sName, spawnOpts: opts, _disconnected: true };
9127
+ const paneEl = document.getElementById(`term-pane-${idx}`);
9128
+ if (!paneEl) return;
9129
+ const container = document.getElementById(`term-container-${idx}`);
9130
+ if (container) {
9131
+ container.innerHTML = `<div style="display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;gap:8px;color:var(--overlay0);font-size:13px;cursor:pointer;" class="reconnect-prompt">
9132
+ <span style="font-size:20px;">&#x26A0;</span>
9133
+ <span>${this.escapeHtml(sName || sid)}</span>
9134
+ <span style="font-size:11px;opacity:0.7;">Disconnected. Click to reconnect.</span>
9135
+ </div>`;
9136
+ container.querySelector('.reconnect-prompt').addEventListener('click', () => {
9137
+ this.openTerminalInPane(idx, sid, sName, opts);
9138
+ });
9139
+ }
9118
9140
  };
9119
9141
 
9120
9142
  // Enable auto-trust if the setting is on
@@ -12083,12 +12105,16 @@ class CWMApp {
12083
12105
 
12084
12106
  group.panes = [];
12085
12107
  for (let i = 0; i < CWMApp.MAX_PANES; i++) {
12086
- if (this.terminalPanes[i]) {
12108
+ const tp = this.terminalPanes[i];
12109
+ // Save both live TerminalPanes and disconnected placeholders.
12110
+ // Disconnected placeholders have { sessionId, sessionName, spawnOpts, _disconnected: true }
12111
+ // and MUST be preserved so layout restores don't lose session mappings.
12112
+ if (tp && tp.sessionId) {
12087
12113
  group.panes.push({
12088
12114
  slot: i,
12089
- sessionId: this.terminalPanes[i].sessionId,
12090
- sessionName: this.terminalPanes[i].sessionName,
12091
- spawnOpts: this.terminalPanes[i].spawnOpts || {},
12115
+ sessionId: tp.sessionId,
12116
+ sessionName: tp.sessionName,
12117
+ spawnOpts: tp.spawnOpts || {},
12092
12118
  });
12093
12119
  }
12094
12120
  }