mixdog 0.9.74 → 0.9.75
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/package.json
CHANGED
|
@@ -23,6 +23,7 @@ const PERIODIC_SNAPSHOT_INTERVAL_MS = SNAPSHOT_INTERVAL_MS
|
|
|
23
23
|
- SNAPSHOT_INTERVAL_JITTER_MS;
|
|
24
24
|
const SNAPSHOT_RATE_LIMIT_MS = 60 * 1000;
|
|
25
25
|
const SNAPSHOT_LOCK_STALE_MS = 10000;
|
|
26
|
+
const PERIODIC_ATTRIBUTION_FREE_BYTES = 2 * 1024 * 1024 * 1024;
|
|
26
27
|
|
|
27
28
|
let periodicTimer = null;
|
|
28
29
|
let lastPressureSnapshotAt = 0;
|
|
@@ -204,9 +205,20 @@ async function captureMemoryPressureSnapshot(reason = 'memory-pressure') {
|
|
|
204
205
|
return appendSnapshot(entry);
|
|
205
206
|
}
|
|
206
207
|
|
|
208
|
+
/**
|
|
209
|
+
* Periodic samples stay cheap, but once host free memory drops below the
|
|
210
|
+
* attribution threshold the sample upgrades to a full top-process snapshot so
|
|
211
|
+
* post-mortem analysis can name the consumer.
|
|
212
|
+
*/
|
|
207
213
|
async function capturePeriodicMemorySnapshot() {
|
|
208
214
|
if (!enabled()) return false;
|
|
209
|
-
|
|
215
|
+
const entry = baseSnapshot('periodic');
|
|
216
|
+
const freeMemoryBytes = Number(entry.systemMemory?.freeMemoryBytes);
|
|
217
|
+
if (Number.isFinite(freeMemoryBytes) && freeMemoryBytes < PERIODIC_ATTRIBUTION_FREE_BYTES) {
|
|
218
|
+
const processes = await topProcesses();
|
|
219
|
+
if (processes) entry.topProcesses = processes;
|
|
220
|
+
}
|
|
221
|
+
return appendSnapshot(entry);
|
|
210
222
|
}
|
|
211
223
|
|
|
212
224
|
/**
|
|
@@ -183,7 +183,10 @@ export function useTranscriptScroll({
|
|
|
183
183
|
if (Math.abs(target - next) < 0.12) {
|
|
184
184
|
scrollPositionRef.current = target;
|
|
185
185
|
setScrollOffset(Math.max(0, Math.round(target)));
|
|
186
|
-
|
|
186
|
+
// Landing at the true bottom must NOT drop an armed follow: the glide
|
|
187
|
+
// was toward the live tail, and clearing the arm here left auto-scroll
|
|
188
|
+
// off even though the user ended exactly where follow should resume.
|
|
189
|
+
if (target > 0) followingRef.current = false;
|
|
187
190
|
stopSmoothScroll();
|
|
188
191
|
return;
|
|
189
192
|
}
|
|
@@ -483,7 +486,15 @@ export function useTranscriptScroll({
|
|
|
483
486
|
setScrollOffset(anchoredTarget);
|
|
484
487
|
return;
|
|
485
488
|
}
|
|
486
|
-
|
|
489
|
+
let target = Math.max(0, Math.min(maxTarget, scrollTargetRef.current + deltaRows));
|
|
490
|
+
// Bottom snap: while a stream is appending rows, the reading-anchor effect
|
|
491
|
+
// keeps RAISING the bottom-relative target between wheel events, so a
|
|
492
|
+
// 3-row wheel notch could chase the bottom forever and never reach the
|
|
493
|
+
// exact 0 that re-engages auto-follow. A downward scroll that lands within
|
|
494
|
+
// one notch of the bottom is an unambiguous "go back to the tail" intent —
|
|
495
|
+
// snap it to 0 so re-pinning is deterministic.
|
|
496
|
+
const BOTTOM_SNAP_ROWS = 3;
|
|
497
|
+
if (deltaRows < 0 && target > 0 && target <= BOTTOM_SNAP_ROWS) target = 0;
|
|
487
498
|
const appliedDelta = target - scrollTargetRef.current;
|
|
488
499
|
// Before the scroll moves selected rows out of view, snapshot the rows
|
|
489
500
|
// currently under the selection into the stitch buffer keyed by the
|
|
@@ -510,6 +521,10 @@ export function useTranscriptScroll({
|
|
|
510
521
|
if (target === 0) {
|
|
511
522
|
transcriptAnchorRef.current = null;
|
|
512
523
|
transcriptAnchorDirtyRef.current = false;
|
|
524
|
+
// A deliberate downward return to the exact bottom re-arms follow, so
|
|
525
|
+
// the next stream growth pins immediately instead of racing the anchor
|
|
526
|
+
// effect for a target that may already have drifted positive again.
|
|
527
|
+
if (deltaRows < 0) followingRef.current = true;
|
|
513
528
|
} else {
|
|
514
529
|
const geom = transcriptGeomRef.current || {};
|
|
515
530
|
const prefixRows = geom.prefixRows;
|
package/src/tui/dist/index.mjs
CHANGED
|
@@ -13940,7 +13940,7 @@ function useTranscriptScroll({
|
|
|
13940
13940
|
if (Math.abs(target - next) < 0.12) {
|
|
13941
13941
|
scrollPositionRef.current = target;
|
|
13942
13942
|
setScrollOffset(Math.max(0, Math.round(target)));
|
|
13943
|
-
followingRef.current = false;
|
|
13943
|
+
if (target > 0) followingRef.current = false;
|
|
13944
13944
|
stopSmoothScroll();
|
|
13945
13945
|
return;
|
|
13946
13946
|
}
|
|
@@ -14184,7 +14184,9 @@ function useTranscriptScroll({
|
|
|
14184
14184
|
setScrollOffset(anchoredTarget);
|
|
14185
14185
|
return;
|
|
14186
14186
|
}
|
|
14187
|
-
|
|
14187
|
+
let target = Math.max(0, Math.min(maxTarget, scrollTargetRef.current + deltaRows));
|
|
14188
|
+
const BOTTOM_SNAP_ROWS = 3;
|
|
14189
|
+
if (deltaRows < 0 && target > 0 && target <= BOTTOM_SNAP_ROWS) target = 0;
|
|
14188
14190
|
const appliedDelta = target - scrollTargetRef.current;
|
|
14189
14191
|
if (appliedDelta !== 0 && dragRef.current.region === "transcript" && dragRef.current.rect) {
|
|
14190
14192
|
flushPendingSelectionPaint();
|
|
@@ -14196,6 +14198,7 @@ function useTranscriptScroll({
|
|
|
14196
14198
|
if (target === 0) {
|
|
14197
14199
|
transcriptAnchorRef.current = null;
|
|
14198
14200
|
transcriptAnchorDirtyRef.current = false;
|
|
14201
|
+
if (deltaRows < 0) followingRef.current = true;
|
|
14199
14202
|
} else {
|
|
14200
14203
|
const geom = transcriptGeomRef.current || {};
|
|
14201
14204
|
const prefixRows = geom.prefixRows;
|