@co0ontty/wand 1.3.3 → 1.3.4
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/dist/process-manager.js +23 -12
- package/dist/web-ui/content/scripts.js +43 -9
- package/package.json +1 -1
package/dist/process-manager.js
CHANGED
|
@@ -499,7 +499,7 @@ function shouldBackfillClaudeSessionId(record) {
|
|
|
499
499
|
function snapshotMessages(record) {
|
|
500
500
|
return record.ptyBridge?.getMessages() ?? record.messages;
|
|
501
501
|
}
|
|
502
|
-
const MAX_SESSIONS =
|
|
502
|
+
const MAX_SESSIONS = 200;
|
|
503
503
|
const ARCHIVE_AFTER_MS = 1000 * 60 * 60 * 24;
|
|
504
504
|
const CONFIRM_WINDOW_SIZE = 800;
|
|
505
505
|
// Claude 会话 ID 格式:UUID v4
|
|
@@ -651,24 +651,33 @@ export class ProcessManager extends EventEmitter {
|
|
|
651
651
|
this.emit("process", event);
|
|
652
652
|
}
|
|
653
653
|
cleanupOldSessions() {
|
|
654
|
-
//
|
|
654
|
+
// Only clean up when well over the limit
|
|
655
655
|
if (this.sessions.size < MAX_SESSIONS)
|
|
656
656
|
return;
|
|
657
|
-
const
|
|
657
|
+
const now = Date.now();
|
|
658
|
+
const STALE_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
659
|
+
const removable = [];
|
|
658
660
|
for (const [id, record] of this.sessions) {
|
|
659
|
-
|
|
660
|
-
|
|
661
|
+
// Only remove archived, non-running sessions older than 7 days
|
|
662
|
+
if (record.status === "running")
|
|
663
|
+
continue;
|
|
664
|
+
if (!record.archived)
|
|
665
|
+
continue;
|
|
666
|
+
const ref = record.endedAt ?? record.startedAt;
|
|
667
|
+
const refMs = Date.parse(ref);
|
|
668
|
+
if (Number.isFinite(refMs) && now - refMs > STALE_MS) {
|
|
669
|
+
removable.push(id);
|
|
661
670
|
}
|
|
662
671
|
}
|
|
663
|
-
//
|
|
664
|
-
|
|
672
|
+
// Sort oldest first and remove enough to get back under the limit
|
|
673
|
+
const toRemove = removable
|
|
665
674
|
.sort((a, b) => {
|
|
666
675
|
const ra = this.sessions.get(a);
|
|
667
676
|
const rb = this.sessions.get(b);
|
|
668
677
|
return (ra?.endedAt || "").localeCompare(rb?.endedAt || "");
|
|
669
678
|
})
|
|
670
|
-
.slice(0, this.sessions.size - MAX_SESSIONS + 1)
|
|
671
|
-
|
|
679
|
+
.slice(0, this.sessions.size - MAX_SESSIONS + 1);
|
|
680
|
+
for (const id of toRemove) {
|
|
672
681
|
const record = this.sessions.get(id);
|
|
673
682
|
if (record) {
|
|
674
683
|
this.logger.deleteSession(id);
|
|
@@ -677,7 +686,7 @@ export class ProcessManager extends EventEmitter {
|
|
|
677
686
|
this.sessions.delete(id);
|
|
678
687
|
this.lastPersistedMessageCount.delete(id);
|
|
679
688
|
this.storage.deleteSession(id);
|
|
680
|
-
}
|
|
689
|
+
}
|
|
681
690
|
}
|
|
682
691
|
start(command, cwd, mode, initialInput, opts) {
|
|
683
692
|
this.assertCommandAllowed(command);
|
|
@@ -989,8 +998,10 @@ export class ProcessManager extends EventEmitter {
|
|
|
989
998
|
get(id) {
|
|
990
999
|
this.archiveExpiredSessions();
|
|
991
1000
|
const record = this.sessions.get(id);
|
|
992
|
-
if (!record)
|
|
993
|
-
|
|
1001
|
+
if (!record) {
|
|
1002
|
+
// Fallback: check SQLite for sessions that were evicted from memory
|
|
1003
|
+
return this.storage.getSession(id) ?? null;
|
|
1004
|
+
}
|
|
994
1005
|
// For sessions loaded from storage on startup, in-memory output starts empty.
|
|
995
1006
|
// Prefer in-memory output (live PTY data), fall back to stored output.
|
|
996
1007
|
if (!record.output && record.storedOutput) {
|
|
@@ -3561,6 +3561,15 @@
|
|
|
3561
3561
|
return fetch("/api/sessions/" + id, { credentials: "same-origin" })
|
|
3562
3562
|
.then(function(res) { return res.json(); })
|
|
3563
3563
|
.then(function(data) {
|
|
3564
|
+
if (data.error) {
|
|
3565
|
+
// Session no longer exists — deselect and refresh list
|
|
3566
|
+
if (state.selectedId === id) {
|
|
3567
|
+
state.selectedId = null;
|
|
3568
|
+
persistSelectedId();
|
|
3569
|
+
}
|
|
3570
|
+
loadSessions();
|
|
3571
|
+
return;
|
|
3572
|
+
}
|
|
3564
3573
|
updateSessionSnapshot(data);
|
|
3565
3574
|
updateShellChrome();
|
|
3566
3575
|
|
|
@@ -5825,11 +5834,26 @@
|
|
|
5825
5834
|
|
|
5826
5835
|
function handleInputBoxBlur() {
|
|
5827
5836
|
resetInputPanelViewportSpacing();
|
|
5828
|
-
// Restore app container height when keyboard closes
|
|
5829
|
-
|
|
5830
|
-
|
|
5831
|
-
|
|
5832
|
-
|
|
5837
|
+
// Restore app container height when keyboard closes.
|
|
5838
|
+
// Use a short delay because on iOS the visualViewport may not
|
|
5839
|
+
// have updated yet at the moment blur fires.
|
|
5840
|
+
setTimeout(function() {
|
|
5841
|
+
var appContainer = document.querySelector('.app-container');
|
|
5842
|
+
if (appContainer) {
|
|
5843
|
+
// Only clear if keyboard is actually closed now
|
|
5844
|
+
var vv = window.visualViewport;
|
|
5845
|
+
if (vv) {
|
|
5846
|
+
var offsetBottom = window.innerHeight - vv.height - vv.offsetTop;
|
|
5847
|
+
if (offsetBottom <= 50) {
|
|
5848
|
+
appContainer.style.height = '';
|
|
5849
|
+
}
|
|
5850
|
+
} else {
|
|
5851
|
+
appContainer.style.height = '';
|
|
5852
|
+
}
|
|
5853
|
+
}
|
|
5854
|
+
// Scroll the window back to top to fix any residual offset
|
|
5855
|
+
window.scrollTo(0, 0);
|
|
5856
|
+
}, 100);
|
|
5833
5857
|
}
|
|
5834
5858
|
|
|
5835
5859
|
function adjustInputBoxSelection(inputBox) {
|
|
@@ -6542,13 +6566,16 @@
|
|
|
6542
6566
|
var isKeyboardOpen = offsetBottom > 50;
|
|
6543
6567
|
var heightChanged = Math.abs(vv.height - lastHeight) > 8;
|
|
6544
6568
|
|
|
6545
|
-
//
|
|
6546
|
-
// because 100dvh does NOT shrink when keyboard
|
|
6569
|
+
// Dynamically resize the app container to match visible viewport.
|
|
6570
|
+
// This is needed because 100dvh does NOT shrink when the keyboard
|
|
6571
|
+
// appears in PWA standalone mode, and on some browsers the layout
|
|
6572
|
+
// viewport doesn't update on keyboard dismiss without this.
|
|
6547
6573
|
var appContainer = document.querySelector('.app-container');
|
|
6548
6574
|
if (appContainer) {
|
|
6549
6575
|
if (isKeyboardOpen) {
|
|
6550
6576
|
appContainer.style.height = vv.height + 'px';
|
|
6551
|
-
} else {
|
|
6577
|
+
} else if (keyboardOpen) {
|
|
6578
|
+
// Keyboard just closed — clear forced height
|
|
6552
6579
|
appContainer.style.height = '';
|
|
6553
6580
|
}
|
|
6554
6581
|
}
|
|
@@ -6571,6 +6598,9 @@
|
|
|
6571
6598
|
}
|
|
6572
6599
|
|
|
6573
6600
|
vv.addEventListener('resize', debouncedUpdate);
|
|
6601
|
+
// Also listen to scroll — on iOS, keyboard dismiss sometimes only
|
|
6602
|
+
// fires a scroll event (viewport scrolls back) without a resize event.
|
|
6603
|
+
vv.addEventListener('scroll', debouncedUpdate);
|
|
6574
6604
|
|
|
6575
6605
|
updateViewport();
|
|
6576
6606
|
}
|
|
@@ -7856,8 +7886,12 @@
|
|
|
7856
7886
|
if (!state.terminalDomView || !state.serializeAddon) return;
|
|
7857
7887
|
|
|
7858
7888
|
try {
|
|
7889
|
+
// Serialize the entire buffer including scrollback history
|
|
7890
|
+
var buf = state.terminal.buffer.active;
|
|
7891
|
+
var totalRows = buf.length;
|
|
7859
7892
|
var html = state.serializeAddon.serializeAsHTML({
|
|
7860
|
-
includeGlobalBackground: true
|
|
7893
|
+
includeGlobalBackground: true,
|
|
7894
|
+
range: { start: 0, end: totalRows }
|
|
7861
7895
|
});
|
|
7862
7896
|
|
|
7863
7897
|
// Extract the <pre>...</pre> portion
|