myrlin-workbook 0.9.21 → 0.9.22

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
- 54288
1
+ 67796
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myrlin-workbook",
3
- "version": "0.9.21",
3
+ "version": "0.9.22",
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": {
@@ -9058,6 +9058,36 @@ class CWMApp {
9058
9058
  TERMINAL GRID VIEW
9059
9059
  ═══════════════════════════════════════════════════════════ */
9060
9060
 
9061
+ /**
9062
+ * Show a disconnected placeholder in a terminal pane slot.
9063
+ * Preserves session info in terminalPanes[] for layout saves.
9064
+ * Click reconnects via openTerminalInPane().
9065
+ */
9066
+ _showDisconnectedPlaceholder(slotIdx, sessionId, sessionName, spawnOpts) {
9067
+ // Store placeholder so saveCurrentGroupPanes preserves the mapping
9068
+ this.terminalPanes[slotIdx] = { sessionId, sessionName, spawnOpts: spawnOpts || {}, _disconnected: true };
9069
+ const paneEl = document.getElementById(`term-pane-${slotIdx}`);
9070
+ if (!paneEl) return;
9071
+ paneEl.hidden = false;
9072
+ paneEl.classList.remove('terminal-pane-empty');
9073
+ const titleEl = paneEl.querySelector('.terminal-pane-title');
9074
+ if (titleEl) titleEl.textContent = sessionName || sessionId;
9075
+ const closeBtn = paneEl.querySelector('.terminal-pane-close');
9076
+ if (closeBtn) closeBtn.hidden = false;
9077
+ const container = document.getElementById(`term-container-${slotIdx}`);
9078
+ if (container) {
9079
+ 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">
9080
+ <span style="font-size:20px;">&#x1F50C;</span>
9081
+ <span>${this.escapeHtml(sessionName || sessionId)}</span>
9082
+ <span style="font-size:11px;opacity:0.7;">Click to connect</span>
9083
+ </div>`;
9084
+ container.querySelector('.reconnect-prompt').addEventListener('click', () => {
9085
+ this.openTerminalInPane(slotIdx, sessionId, sessionName, spawnOpts);
9086
+ });
9087
+ }
9088
+ this.updateTerminalGridLayout();
9089
+ }
9090
+
9061
9091
  openTerminalInPane(slotIdx, sessionId, sessionName, spawnOpts) {
9062
9092
  // Check localStorage for a previously saved name for this session
9063
9093
  const savedTitle = this.getProjectSessionTitle(sessionId);
@@ -12048,10 +12078,12 @@ class CWMApp {
12048
12078
  const uploadBtn = paneEl.querySelector('.terminal-pane-upload');
12049
12079
  if (uploadBtn) uploadBtn.hidden = false;
12050
12080
  }
12051
- // Reattach xterm DOM
12081
+ // Reattach xterm DOM, or re-render placeholder for disconnected panes
12052
12082
  if (cached.domFragments[i]) {
12053
12083
  const termContainer = document.getElementById(`term-container-${i}`);
12054
12084
  if (termContainer) termContainer.appendChild(cached.domFragments[i]);
12085
+ } else if (cached.panes[i]._disconnected) {
12086
+ this._showDisconnectedPlaceholder(i, cached.panes[i].sessionId, cached.panes[i].sessionName, cached.panes[i].spawnOpts);
12055
12087
  }
12056
12088
  }
12057
12089
  }
@@ -12071,12 +12103,15 @@ class CWMApp {
12071
12103
  }
12072
12104
  });
12073
12105
  } else {
12074
- // No cache, create fresh connections (first time opening this group)
12106
+ // No cache: show disconnected placeholders instead of spawning all PTYs.
12107
+ // Each PTY spawns a Claude process (~150MB), so eagerly connecting all
12108
+ // panes across all tab groups would consume gigabytes of system memory.
12109
+ // Users click a pane to connect on demand.
12075
12110
  const group = this._tabGroups.find(g => g.id === groupId);
12076
12111
  if (group && group.panes) {
12077
12112
  group.panes.forEach(p => {
12078
12113
  if (p.sessionId && !this.terminalPanes[p.slot]) {
12079
- this.openTerminalInPane(p.slot, p.sessionId, p.sessionName || 'Terminal', p.spawnOpts || {});
12114
+ this._showDisconnectedPlaceholder(p.slot, p.sessionId, p.sessionName || 'Terminal', p.spawnOpts || {});
12080
12115
  }
12081
12116
  });
12082
12117
  }