mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-08 16:39:42 +02:00
feat(session,mobile): auto-resume on usage limit + mobile view fixes
Auto-resume on usage limit ("token pause" control, opt-in checkbox at the
top of the Respawn tab, off by default):
- usage-limit-patterns.ts (new, pure): detects all Claude Code limit
messages (1.0.x-2.1.x eras incl. "5-hour limit reached - resets 8pm",
"You've hit your limit - resets 1:40pm (TZ)", weekly date forms, raw
"usage limit reached|<epoch>") and parses the reset time. Conservative:
no parseable future reset time, no action.
- SessionAutoOps: arms a timer at reset+2min, sends Esc (dismisses the
rate-limit dialog) + "continue"; dedups footer redraws, retries every
5min on stale times, cancels when Claude starts working, persists and
re-arms across Codeman restarts (SessionState.autoResumeEnabled/At).
- Respawn guard: cycles are blocked while limit-paused so /clear cannot
wipe the paused conversation (respawnBlocked reason 'usage_limit').
- POST /api/sessions/:id/auto-resume; SSE session:limitPauseScheduled/
limitResume/limitResumeCancelled; toasts + status line in the modal.
- Respawn tab tidied: single-row prompt fields, merged behavior row.
Mobile fixes (0.9.8 regressions, user-reported):
- Resize arbitration is now activity-based: a desktop sizing claim only
blocks phone resizes while the desktop typed within 90s
(Session.DESKTOP_CLAIM_IDLE_MS). Idle desktop -> phone takes the pane;
next desktop keystroke re-asserts the desktop layout server-side
(noteDesktopActivity via ws-routes input). Phones re-send dims every
30s (visible tab only, skipped while the keyboard is open) so attaching
under a hot claim self-corrects. Fixes the desktop-width-stream-in-
narrow-xterm soup (mid-word wraps, tmux dot fill, Ink overdraw).
- Cross-device reflows (takeover/re-assert) emit a debounced needsRefresh
so all clients reload the buffer instead of stacking ghost Ink frames.
- Keyboard accessory/toolbar lift restored: measure keyboardOffset
against window.innerHeight (layout viewport), not the shrunken .app -
on iOS the offset computed to 0, leaving both bars hidden behind the
OS keyboard with a dead gap above.
- Removed the mobile header utility ("three dots") toggle entirely;
the headerRight tray stays collapsed on small viewports.
Tests: usage-limit-patterns (36), session-auto-resume (21), resize
arbitration (+6), session routes (+4), respawn guard (+2); MockSession
auto-resume/sizing stubs; mobile tabs test updated for toggle removal.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -690,6 +690,10 @@ Object.assign(CodemanApp.prototype, {
|
||||
document.getElementById('modalAutoCompactPrompt').value = session.autoCompactPrompt ?? '';
|
||||
document.getElementById('modalAutoClearEnabled').checked = session.autoClearEnabled ?? false;
|
||||
document.getElementById('modalAutoClearThreshold').value = session.autoClearThreshold ?? 140000;
|
||||
|
||||
// Populate auto-resume on usage limit (token pause control)
|
||||
document.getElementById('modalAutoResumeEnabled').checked = session.autoResumeEnabled ?? false;
|
||||
this.updateAutoResumeStatus(sessionId);
|
||||
document.getElementById('modalImageWatcherEnabled').checked = session.imageWatcherEnabled ?? true;
|
||||
document.getElementById('modalFlickerFilterEnabled').checked = session.flickerFilterEnabled ?? false;
|
||||
|
||||
@@ -790,6 +794,39 @@ Object.assign(CodemanApp.prototype, {
|
||||
} catch { /* silent */ }
|
||||
},
|
||||
|
||||
async autoSaveAutoResume() {
|
||||
if (!this.editingSessionId) return;
|
||||
const enabled = document.getElementById('modalAutoResumeEnabled').checked;
|
||||
try {
|
||||
await this._apiPost(`/api/sessions/${this.editingSessionId}/auto-resume`, { enabled });
|
||||
const session = this.sessions.get(this.editingSessionId);
|
||||
if (session) {
|
||||
session.autoResumeEnabled = enabled;
|
||||
if (!enabled) session.autoResumeAt = undefined;
|
||||
}
|
||||
this.updateAutoResumeStatus(this.editingSessionId);
|
||||
this.showToast(`Auto-resume on usage limit ${enabled ? 'enabled' : 'disabled'}`, 'success');
|
||||
} catch (err) {
|
||||
this.showToast('Failed to toggle auto-resume: ' + err.message, 'error');
|
||||
}
|
||||
},
|
||||
|
||||
// Show "resumes at HH:MM" in the session options modal while a usage-limit
|
||||
// pause is armed for the session being edited
|
||||
updateAutoResumeStatus(sessionId) {
|
||||
const el = document.getElementById('autoResumeStatus');
|
||||
if (!el || this.editingSessionId !== sessionId) return;
|
||||
const session = this.sessions.get(sessionId);
|
||||
if (session?.autoResumeAt && session.autoResumeAt > Date.now()) {
|
||||
const at = new Date(session.autoResumeAt).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
||||
el.textContent = `Usage limit pause active — resumes at ${at}`;
|
||||
el.classList.add('active');
|
||||
} else {
|
||||
el.textContent = '';
|
||||
el.classList.remove('active');
|
||||
}
|
||||
},
|
||||
|
||||
async toggleSessionImageWatcher() {
|
||||
if (!this.editingSessionId) return;
|
||||
const enabled = document.getElementById('modalImageWatcherEnabled').checked;
|
||||
|
||||
Reference in New Issue
Block a user