claude-code-remote-pilot 0.5.2 → 0.5.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.
- package/CHANGELOG.md +9 -0
- package/lib/ui.html +30 -8
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.3 — 2026-05-06
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- **Auto-resume respects clock reset time**: limit recovery now waits until the parsed `resets at HH:MM` timestamp (with next-day rollover) before sending the resume command.
|
|
7
|
+
- **Web UI respawn completed**: offline session respawn now has loading/error feedback and immediately updates session detail state after success.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
3
11
|
## 0.5.2 — 2026-05-06
|
|
4
12
|
|
|
5
13
|
### Fixed
|
|
6
14
|
- **Auto-resume now waits for reset time**: when Claude shows an explicit `resets at HH:MM` clock time, `Watcher` now resumes at that exact reset timestamp (including next-day rollover) instead of relying only on relative wait parsing.
|
|
15
|
+
- **Web UI respawn flow completed**: offline session respawn now shows in-button loading, inline errors, and immediately updates the detail view to the newly active session after successful `POST /api/sessions/:name/respawn`.
|
|
7
16
|
|
|
8
17
|
---
|
|
9
18
|
|
package/lib/ui.html
CHANGED
|
@@ -574,11 +574,13 @@ function DashboardScreen({ onNavigate, sessions, activity, serverStatus }) {
|
|
|
574
574
|
}
|
|
575
575
|
|
|
576
576
|
/* --- Session Detail --- */
|
|
577
|
-
function SessionDetailScreen({ session, onBack, onKilled }) {
|
|
577
|
+
function SessionDetailScreen({ session, onBack, onKilled, onRespawned }) {
|
|
578
578
|
const [output, setOutput] = useState('');
|
|
579
579
|
const [msg, setMsg] = useState('');
|
|
580
580
|
const [sending, setSending] = useState(false);
|
|
581
581
|
const [killing, setKilling] = useState(false);
|
|
582
|
+
const [respawning, setRespawning] = useState(false);
|
|
583
|
+
const [respawnError, setRespawnError] = useState('');
|
|
582
584
|
const [copyOk, setCopyOk] = useState(false);
|
|
583
585
|
const terminalRef = useRef(null);
|
|
584
586
|
const inputRef = useRef(null);
|
|
@@ -661,14 +663,21 @@ function SessionDetailScreen({ session, onBack, onKilled }) {
|
|
|
661
663
|
};
|
|
662
664
|
|
|
663
665
|
const handleRespawn = async () => {
|
|
666
|
+
if (respawning) return;
|
|
667
|
+
setRespawning(true);
|
|
668
|
+
setRespawnError('');
|
|
664
669
|
try {
|
|
665
670
|
const res = await apiFetch(`/api/sessions/${encodeURIComponent(session.name)}/respawn`, { method: 'POST' });
|
|
671
|
+
const data = await res.json();
|
|
666
672
|
if (!res.ok) {
|
|
667
|
-
|
|
668
|
-
|
|
673
|
+
setRespawnError(data.error || 'Failed to respawn');
|
|
674
|
+
return;
|
|
669
675
|
}
|
|
676
|
+
onRespawned(data);
|
|
670
677
|
} catch (e) {
|
|
671
|
-
if (e.message !== 'Unauthorized')
|
|
678
|
+
if (e.message !== 'Unauthorized') setRespawnError('Network error');
|
|
679
|
+
} finally {
|
|
680
|
+
setRespawning(false);
|
|
672
681
|
}
|
|
673
682
|
};
|
|
674
683
|
|
|
@@ -700,9 +709,16 @@ function SessionDetailScreen({ session, onBack, onKilled }) {
|
|
|
700
709
|
</div>
|
|
701
710
|
<div className="detail-actions">
|
|
702
711
|
{isOffline && (
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
712
|
+
<>
|
|
713
|
+
<button className="btn btn-sm btn-primary" onClick={handleRespawn} disabled={respawning}>
|
|
714
|
+
{respawning ? 'Respawning…' : '↺ Respawn'}
|
|
715
|
+
</button>
|
|
716
|
+
{respawnError && (
|
|
717
|
+
<span style={{ color: 'var(--error)', fontSize: 12, alignSelf: 'center' }}>
|
|
718
|
+
{respawnError}
|
|
719
|
+
</span>
|
|
720
|
+
)}
|
|
721
|
+
</>
|
|
706
722
|
)}
|
|
707
723
|
{!isOffline && (
|
|
708
724
|
<button className="btn btn-sm" onClick={copyAttachCmd} title={`tmux attach -t ${session.name}`}>
|
|
@@ -1047,7 +1063,13 @@ function App() {
|
|
|
1047
1063
|
case 'dashboard': return <DashboardScreen onNavigate={navigate} sessions={sessions} activity={activity} serverStatus={serverStatus} />;
|
|
1048
1064
|
case 'sessions': return <SessionsScreen sessions={sessions} onNavigate={navigate} />;
|
|
1049
1065
|
case 'create': return <CreateSessionScreen onBack={() => navigate('dashboard')} onCreated={s => navigate('detail', s)} />;
|
|
1050
|
-
case 'detail': return <SessionDetailScreen session={selectedSession} onBack={() => navigate('dashboard')} onKilled={() => navigate('sessions')}
|
|
1066
|
+
case 'detail': return <SessionDetailScreen session={selectedSession} onBack={() => navigate('dashboard')} onKilled={() => navigate('sessions')} onRespawned={(respawned) => {
|
|
1067
|
+
setSessions(prev => {
|
|
1068
|
+
const next = prev.filter(s => s.name !== respawned.name);
|
|
1069
|
+
return [{ ...respawned, id: respawned.name }, ...next];
|
|
1070
|
+
});
|
|
1071
|
+
setSelectedSession({ ...respawned, id: respawned.name });
|
|
1072
|
+
}} />;
|
|
1051
1073
|
default: return <DashboardScreen onNavigate={navigate} sessions={sessions} activity={activity} serverStatus={serverStatus} />;
|
|
1052
1074
|
}
|
|
1053
1075
|
};
|
package/package.json
CHANGED