mixdog 0.9.65 → 0.9.66
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 +1 -1
- package/src/app.mjs +2 -2
- package/src/cli.mjs +1 -1
- package/src/repl.mjs +72 -6
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +76 -21
- package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +45 -4
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +11 -1
- package/src/runtime/agent/orchestrator/session/store/summary-cache.mjs +36 -13
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +79 -18
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +4 -0
- package/src/runtime/agent/orchestrator/session/store.mjs +37 -2
- package/src/session-runtime/context-status.mjs +2 -1
- package/src/session-runtime/provider-request-tools.mjs +6 -0
- package/src/session-runtime/tool-catalog-schema.mjs +5 -1
- package/src/tui/app/transcript-window.mjs +16 -0
- package/src/tui/app/use-transcript-window.mjs +36 -1
- package/src/tui/components/Markdown.jsx +15 -1
- package/src/tui/components/Message.jsx +1 -1
- package/src/tui/components/PromptInput.jsx +7 -0
- package/src/tui/dist/index.mjs +307 -79
- package/src/tui/engine/frame-batched-store.mjs +5 -3
- package/src/tui/engine/render-timing.mjs +28 -0
- package/src/tui/engine/session-api-ext.mjs +7 -0
- package/src/tui/engine/tui-steering-persist.mjs +25 -4
- package/src/tui/engine.mjs +9 -1
- package/src/tui/index.jsx +11 -3
- package/src/tui/markdown/measure-rendered-rows.mjs +28 -16
- package/src/tui/markdown/render-ansi.mjs +34 -1
- package/src/tui/markdown/stream-fence.mjs +44 -7
- package/src/tui/markdown/streaming-markdown.mjs +95 -27
- package/src/ui/stream-finalize.mjs +45 -0
package/src/tui/dist/index.mjs
CHANGED
|
@@ -2588,7 +2588,7 @@ import { render } from "../../../vendor/ink/build/index.js";
|
|
|
2588
2588
|
import { closeSync as closeSync3, constants as fsConstants, createWriteStream as createWriteStream2, mkdirSync as mkdirSync9, openSync as openSync3, readSync } from "node:fs";
|
|
2589
2589
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
2590
2590
|
import { dirname as dirname12, join as join15 } from "node:path";
|
|
2591
|
-
import { performance as
|
|
2591
|
+
import { performance as performance4 } from "node:perf_hooks";
|
|
2592
2592
|
import { format } from "node:util";
|
|
2593
2593
|
|
|
2594
2594
|
// src/tui/App.jsx
|
|
@@ -7274,6 +7274,7 @@ function PromptInput({
|
|
|
7274
7274
|
if (valueRef) valueRef.current = draftRef.current.value;
|
|
7275
7275
|
const { isRawModeSupported } = useStdin();
|
|
7276
7276
|
const boxRef = useRef4(null);
|
|
7277
|
+
const inkRootRef = useRef4(null);
|
|
7277
7278
|
const cursorEnabledRef = useRef4(false);
|
|
7278
7279
|
const contentWidthRef = useRef4(80);
|
|
7279
7280
|
const preferredColumnRef = useRef4(null);
|
|
@@ -7288,9 +7289,15 @@ function PromptInput({
|
|
|
7288
7289
|
}
|
|
7289
7290
|
const flushThrottleRef = useRef4({ lastAt: 0, timer: null });
|
|
7290
7291
|
const flushImmediate = () => {
|
|
7292
|
+
const cachedRoot = inkRootRef.current;
|
|
7293
|
+
if (typeof cachedRoot?.onImmediateRender === "function") {
|
|
7294
|
+
cachedRoot.onImmediateRender();
|
|
7295
|
+
return;
|
|
7296
|
+
}
|
|
7291
7297
|
let node = boxRef.current;
|
|
7292
7298
|
for (let i = 0; node && i < 64; i++) {
|
|
7293
7299
|
if (node.nodeName === "ink-root") {
|
|
7300
|
+
inkRootRef.current = node;
|
|
7294
7301
|
if (typeof node.onImmediateRender === "function") node.onImmediateRender();
|
|
7295
7302
|
return;
|
|
7296
7303
|
}
|
|
@@ -11289,18 +11296,22 @@ function trimPartialClosingFences(tokens) {
|
|
|
11289
11296
|
}
|
|
11290
11297
|
var OPEN_FENCE_RE = /^( {0,3})(`{3,}|~{3,})(.*)$/;
|
|
11291
11298
|
var CLOSE_FENCE_RE = /^ {0,3}([`~]+)[ \t]*$/;
|
|
11299
|
+
var OPEN_FENCE_SCAN_LRU_MAX = 32;
|
|
11300
|
+
var openFenceScanByStreamKey = /* @__PURE__ */ new Map();
|
|
11292
11301
|
function isClosingFence(line, char, openLen) {
|
|
11293
11302
|
const m = CLOSE_FENCE_RE.exec(line);
|
|
11294
11303
|
if (!m) return false;
|
|
11295
11304
|
const run = m[1];
|
|
11296
11305
|
return run.startsWith(char.repeat(openLen));
|
|
11297
11306
|
}
|
|
11298
|
-
function
|
|
11299
|
-
|
|
11300
|
-
let
|
|
11301
|
-
|
|
11302
|
-
|
|
11307
|
+
function scanOpenFence(value, startAt = 0, initialOpen = null) {
|
|
11308
|
+
let open = initialOpen;
|
|
11309
|
+
let start = startAt;
|
|
11310
|
+
const checkpointIndex = value.lastIndexOf("\n") + 1;
|
|
11311
|
+
let openBeforeCheckpoint = start === checkpointIndex ? open : null;
|
|
11312
|
+
for (let i = startAt; i <= value.length; i++) {
|
|
11303
11313
|
if (i !== value.length && value[i] !== "\n") continue;
|
|
11314
|
+
if (start === checkpointIndex) openBeforeCheckpoint = open;
|
|
11304
11315
|
const line = value.slice(start, i);
|
|
11305
11316
|
if (!open) {
|
|
11306
11317
|
const m = OPEN_FENCE_RE.exec(line);
|
|
@@ -11316,13 +11327,42 @@ function findOpenFenceStart(text) {
|
|
|
11316
11327
|
}
|
|
11317
11328
|
start = i + 1;
|
|
11318
11329
|
}
|
|
11319
|
-
|
|
11320
|
-
|
|
11330
|
+
return { open, checkpointIndex, openBeforeCheckpoint };
|
|
11331
|
+
}
|
|
11332
|
+
function touchOpenFenceScan(key, entry) {
|
|
11333
|
+
if (openFenceScanByStreamKey.has(key)) openFenceScanByStreamKey.delete(key);
|
|
11334
|
+
openFenceScanByStreamKey.set(key, entry);
|
|
11335
|
+
while (openFenceScanByStreamKey.size > OPEN_FENCE_SCAN_LRU_MAX) {
|
|
11336
|
+
const oldest = openFenceScanByStreamKey.keys().next().value;
|
|
11337
|
+
if (oldest === void 0) break;
|
|
11338
|
+
openFenceScanByStreamKey.delete(oldest);
|
|
11339
|
+
}
|
|
11340
|
+
}
|
|
11341
|
+
function resetOpenFenceScan(streamKey) {
|
|
11342
|
+
if (streamKey == null || streamKey === "") return;
|
|
11343
|
+
openFenceScanByStreamKey.delete(String(streamKey));
|
|
11344
|
+
}
|
|
11345
|
+
function resetAllOpenFenceScans() {
|
|
11346
|
+
openFenceScanByStreamKey.clear();
|
|
11347
|
+
}
|
|
11348
|
+
function findOpenFenceStart(text, streamKey = null) {
|
|
11349
|
+
const value = String(text ?? "");
|
|
11350
|
+
const key = streamKey == null || streamKey === "" ? null : String(streamKey);
|
|
11351
|
+
const cached = key ? openFenceScanByStreamKey.get(key) : null;
|
|
11352
|
+
if (cached?.text === value) return cached.result;
|
|
11353
|
+
const scanned = cached && value.startsWith(cached.text) ? scanOpenFence(value, cached.checkpointIndex, cached.openBeforeCheckpoint) : scanOpenFence(value);
|
|
11354
|
+
const result = !scanned.open || scanned.open.indent !== 0 ? null : { index: scanned.open.index, lang: scanned.open.lang };
|
|
11355
|
+
if (key) touchOpenFenceScan(key, { text: value, ...scanned, result });
|
|
11356
|
+
return result;
|
|
11321
11357
|
}
|
|
11322
11358
|
|
|
11323
11359
|
// src/tui/markdown/render-ansi.mjs
|
|
11324
11360
|
var TOKEN_CACHE_MAX = 500;
|
|
11325
11361
|
var tokenCache = /* @__PURE__ */ new Map();
|
|
11362
|
+
var renderedSegmentCache = [];
|
|
11363
|
+
var RENDERED_SEGMENT_CACHE_MAX = 12;
|
|
11364
|
+
var RENDERED_SEGMENT_CACHE_MAX_CHARS = 256 * 1024;
|
|
11365
|
+
var renderedSegmentCacheChars = 0;
|
|
11326
11366
|
var MD_SYNTAX_RE = /[#*`|[>\-_~]|\n\n|^\d+\. |\n\d+\. /;
|
|
11327
11367
|
var _configured = false;
|
|
11328
11368
|
function configureMarked() {
|
|
@@ -11384,8 +11424,19 @@ function lexMarkdown(content, { trimPartialFences = false } = {}) {
|
|
|
11384
11424
|
return tokens;
|
|
11385
11425
|
}
|
|
11386
11426
|
function renderTokenAnsiSegments(content, opts = {}) {
|
|
11387
|
-
const
|
|
11427
|
+
const text = String(content ?? "");
|
|
11388
11428
|
const width = Number(opts.width) || 0;
|
|
11429
|
+
const trimPartialFences = opts.trimPartialFences === true;
|
|
11430
|
+
const themeVersion = getThemeVersion();
|
|
11431
|
+
for (let index = renderedSegmentCache.length - 1; index >= 0; index -= 1) {
|
|
11432
|
+
const entry = renderedSegmentCache[index];
|
|
11433
|
+
if (entry.text === text && entry.width === width && entry.trimPartialFences === trimPartialFences && entry.themeVersion === themeVersion) {
|
|
11434
|
+
renderedSegmentCache.splice(index, 1);
|
|
11435
|
+
renderedSegmentCache.push(entry);
|
|
11436
|
+
return entry.segments;
|
|
11437
|
+
}
|
|
11438
|
+
}
|
|
11439
|
+
const tokens = lexMarkdown(text, opts);
|
|
11389
11440
|
const segments = [];
|
|
11390
11441
|
for (const token of tokens) {
|
|
11391
11442
|
if (token.type === "table") {
|
|
@@ -11398,55 +11449,104 @@ function renderTokenAnsiSegments(content, opts = {}) {
|
|
|
11398
11449
|
segments.push({ type: "ansi", ansi, token });
|
|
11399
11450
|
}
|
|
11400
11451
|
}
|
|
11452
|
+
if (text.length <= RENDERED_SEGMENT_CACHE_MAX_CHARS) {
|
|
11453
|
+
const entry = { text, width, trimPartialFences, themeVersion, segments };
|
|
11454
|
+
renderedSegmentCache.push(entry);
|
|
11455
|
+
renderedSegmentCacheChars += text.length;
|
|
11456
|
+
while (renderedSegmentCache.length > RENDERED_SEGMENT_CACHE_MAX || renderedSegmentCacheChars > RENDERED_SEGMENT_CACHE_MAX_CHARS) {
|
|
11457
|
+
const removed = renderedSegmentCache.shift();
|
|
11458
|
+
renderedSegmentCacheChars -= removed?.text.length || 0;
|
|
11459
|
+
}
|
|
11460
|
+
}
|
|
11401
11461
|
return segments;
|
|
11402
11462
|
}
|
|
11403
11463
|
|
|
11404
11464
|
// src/tui/markdown/streaming-markdown.mjs
|
|
11405
11465
|
import { marked as marked2 } from "marked";
|
|
11406
11466
|
var stablePrefixByStreamKey = /* @__PURE__ */ new Map();
|
|
11467
|
+
var markdownSyntaxByStreamKey = /* @__PURE__ */ new Map();
|
|
11468
|
+
var plainWindowSyntaxByStreamKey = /* @__PURE__ */ new Map();
|
|
11407
11469
|
var resolvedPartsByStreamKey = /* @__PURE__ */ new Map();
|
|
11408
11470
|
var STABLE_PREFIX_LRU_MAX = 32;
|
|
11409
11471
|
function streamingLayoutText(text) {
|
|
11410
11472
|
return String(text ?? "").replace(/^\n+|\n+$/g, "");
|
|
11411
11473
|
}
|
|
11412
|
-
function windowPlainStreamingText(text, columns, maxRows) {
|
|
11474
|
+
function windowPlainStreamingText(text, columns, maxRows, streamKey = null) {
|
|
11413
11475
|
const value = streamingLayoutText(text);
|
|
11414
11476
|
const rowBudget = Math.max(0, Math.floor(Number(maxRows) || 0));
|
|
11415
|
-
|
|
11416
|
-
|
|
11477
|
+
const key = streamKey == null || streamKey === "" ? null : String(streamKey);
|
|
11478
|
+
if (!value || rowBudget <= 0 || cachedStreamingHasMarkdownSyntax(
|
|
11479
|
+
plainWindowSyntaxByStreamKey,
|
|
11480
|
+
value,
|
|
11481
|
+
key
|
|
11482
|
+
)) return value;
|
|
11417
11483
|
const width = Math.max(1, Math.floor(Number(columns) || 80));
|
|
11418
11484
|
let rows = 0;
|
|
11419
|
-
let
|
|
11420
|
-
|
|
11421
|
-
|
|
11485
|
+
let end = value.length;
|
|
11486
|
+
let start = end;
|
|
11487
|
+
while (end >= 0) {
|
|
11488
|
+
const newline = value.lastIndexOf("\n", end - 1);
|
|
11489
|
+
const lineStart2 = newline + 1;
|
|
11490
|
+
const line = value.slice(lineStart2, end);
|
|
11422
11491
|
const lineRows = Math.max(1, Math.ceil(displayWidth(line) / width));
|
|
11423
11492
|
if (rows > 0 && rows + lineRows > rowBudget) break;
|
|
11424
11493
|
rows += lineRows;
|
|
11425
|
-
start
|
|
11426
|
-
if (rows >= rowBudget) break;
|
|
11494
|
+
start = lineStart2;
|
|
11495
|
+
if (rows >= rowBudget || newline < 0) break;
|
|
11496
|
+
end = newline;
|
|
11427
11497
|
}
|
|
11428
|
-
return start > 0 ?
|
|
11498
|
+
return start > 0 ? value.slice(start) : value;
|
|
11429
11499
|
}
|
|
11430
11500
|
function isWhitespaceOnlyText(text) {
|
|
11431
11501
|
return !String(text ?? "").trim();
|
|
11432
11502
|
}
|
|
11433
|
-
function
|
|
11503
|
+
function touchLruKey(cache, key, value) {
|
|
11434
11504
|
if (!key) return;
|
|
11435
|
-
if (
|
|
11436
|
-
|
|
11437
|
-
while (
|
|
11438
|
-
const oldest =
|
|
11505
|
+
if (cache.has(key)) cache.delete(key);
|
|
11506
|
+
cache.set(key, value);
|
|
11507
|
+
while (cache.size > STABLE_PREFIX_LRU_MAX) {
|
|
11508
|
+
const oldest = cache.keys().next().value;
|
|
11439
11509
|
if (oldest === void 0) break;
|
|
11440
|
-
|
|
11510
|
+
cache.delete(oldest);
|
|
11441
11511
|
}
|
|
11442
11512
|
}
|
|
11513
|
+
function touchStablePrefixKey(key, value) {
|
|
11514
|
+
touchLruKey(stablePrefixByStreamKey, key, value);
|
|
11515
|
+
}
|
|
11443
11516
|
function getStablePrefixKey(key) {
|
|
11444
|
-
if (!key || !stablePrefixByStreamKey.has(key)) return "";
|
|
11517
|
+
if (!key || !stablePrefixByStreamKey.has(key)) return { text: "", chunks: [] };
|
|
11445
11518
|
const value = stablePrefixByStreamKey.get(key);
|
|
11446
|
-
|
|
11447
|
-
|
|
11519
|
+
touchStablePrefixKey(key, value);
|
|
11520
|
+
return value;
|
|
11521
|
+
}
|
|
11522
|
+
function stableStateForText(text, previous) {
|
|
11523
|
+
if (!text) return { text: "", chunks: [] };
|
|
11524
|
+
if (text.startsWith(previous.text)) {
|
|
11525
|
+
const appended = text.substring(previous.text.length);
|
|
11526
|
+
return appended ? { text, chunks: [...previous.chunks, appended] } : previous;
|
|
11527
|
+
}
|
|
11528
|
+
return { text, chunks: [text] };
|
|
11529
|
+
}
|
|
11530
|
+
function cachedStreamingHasMarkdownSyntax(cache, text, key) {
|
|
11531
|
+
if (!key) return hasMarkdownSyntax(text);
|
|
11532
|
+
const previous = cache.get(key);
|
|
11533
|
+
let value;
|
|
11534
|
+
if (previous && text.startsWith(previous.text)) {
|
|
11535
|
+
if (previous.value) {
|
|
11536
|
+
value = true;
|
|
11537
|
+
} else {
|
|
11538
|
+
const lineStart2 = previous.text.lastIndexOf("\n") + 1;
|
|
11539
|
+
value = hasMarkdownSyntax(text.substring(Math.max(0, lineStart2 - 1)));
|
|
11540
|
+
}
|
|
11541
|
+
} else {
|
|
11542
|
+
value = hasMarkdownSyntax(text);
|
|
11543
|
+
}
|
|
11544
|
+
touchLruKey(cache, key, { text, value });
|
|
11448
11545
|
return value;
|
|
11449
11546
|
}
|
|
11547
|
+
function streamingHasMarkdownSyntax(text, key) {
|
|
11548
|
+
return cachedStreamingHasMarkdownSyntax(markdownSyntaxByStreamKey, text, key);
|
|
11549
|
+
}
|
|
11450
11550
|
function getResolvedPartsKey(key, text) {
|
|
11451
11551
|
if (!key) return null;
|
|
11452
11552
|
const entry = resolvedPartsByStreamKey.get(key);
|
|
@@ -11518,11 +11618,17 @@ function resetStreamingMarkdownStablePrefix(streamKey) {
|
|
|
11518
11618
|
if (streamKey == null || streamKey === "") return;
|
|
11519
11619
|
const key = String(streamKey);
|
|
11520
11620
|
stablePrefixByStreamKey.delete(key);
|
|
11621
|
+
markdownSyntaxByStreamKey.delete(key);
|
|
11622
|
+
plainWindowSyntaxByStreamKey.delete(key);
|
|
11521
11623
|
resolvedPartsByStreamKey.delete(key);
|
|
11624
|
+
resetOpenFenceScan(key);
|
|
11522
11625
|
}
|
|
11523
11626
|
function resetAllStreamingMarkdownStablePrefixes() {
|
|
11524
11627
|
stablePrefixByStreamKey.clear();
|
|
11628
|
+
markdownSyntaxByStreamKey.clear();
|
|
11629
|
+
plainWindowSyntaxByStreamKey.clear();
|
|
11525
11630
|
resolvedPartsByStreamKey.clear();
|
|
11631
|
+
resetAllOpenFenceScans();
|
|
11526
11632
|
}
|
|
11527
11633
|
function resolveStreamingMarkdownParts(text, streamKey) {
|
|
11528
11634
|
const t = streamingLayoutText(text);
|
|
@@ -11534,34 +11640,39 @@ function resolveStreamingMarkdownParts(text, streamKey) {
|
|
|
11534
11640
|
return cacheResolvedPartsKey(key, t, {
|
|
11535
11641
|
plain: true,
|
|
11536
11642
|
stablePrefix: "",
|
|
11643
|
+
stableChunks: [],
|
|
11537
11644
|
unstableSuffix: "",
|
|
11538
11645
|
unstableForRender: ""
|
|
11539
11646
|
});
|
|
11540
11647
|
}
|
|
11541
|
-
if (!
|
|
11648
|
+
if (!streamingHasMarkdownSyntax(t, key)) {
|
|
11542
11649
|
if (key) stablePrefixByStreamKey.delete(key);
|
|
11543
11650
|
return cacheResolvedPartsKey(key, t, {
|
|
11544
11651
|
plain: true,
|
|
11545
11652
|
stablePrefix: "",
|
|
11653
|
+
stableChunks: [],
|
|
11546
11654
|
unstableSuffix: t,
|
|
11547
11655
|
unstableForRender: t
|
|
11548
11656
|
});
|
|
11549
11657
|
}
|
|
11550
|
-
let
|
|
11551
|
-
if (!t.startsWith(
|
|
11552
|
-
|
|
11658
|
+
let stableState = key ? getStablePrefixKey(key) : { text: "", chunks: [] };
|
|
11659
|
+
if (!t.startsWith(stableState.text)) {
|
|
11660
|
+
stableState = { text: "", chunks: [] };
|
|
11553
11661
|
}
|
|
11554
|
-
|
|
11662
|
+
let stablePrefix = stableState.text;
|
|
11663
|
+
const open = findOpenFenceStart(t, key);
|
|
11555
11664
|
if (open) {
|
|
11556
11665
|
let openPrefix = t.substring(0, open.index);
|
|
11557
11666
|
if (isWhitespaceOnlyText(openPrefix)) openPrefix = "";
|
|
11558
|
-
|
|
11667
|
+
stableState = stableStateForText(openPrefix, stableState);
|
|
11668
|
+
if (key && openPrefix) touchStablePrefixKey(key, stableState);
|
|
11559
11669
|
else if (key) stablePrefixByStreamKey.delete(key);
|
|
11560
11670
|
const unstableSuffix2 = t.substring(openPrefix.length);
|
|
11561
11671
|
return cacheResolvedPartsKey(key, t, {
|
|
11562
11672
|
plain: false,
|
|
11563
11673
|
openFence: true,
|
|
11564
11674
|
stablePrefix: openPrefix,
|
|
11675
|
+
stableChunks: stableState.chunks,
|
|
11565
11676
|
unstableSuffix: unstableSuffix2,
|
|
11566
11677
|
unstableForRender: unstableSuffix2
|
|
11567
11678
|
});
|
|
@@ -11584,18 +11695,24 @@ function resolveStreamingMarkdownParts(text, streamKey) {
|
|
|
11584
11695
|
if (advance > 0) {
|
|
11585
11696
|
stablePrefix = t.substring(0, boundary + advance);
|
|
11586
11697
|
if (isWhitespaceOnlyText(stablePrefix)) stablePrefix = "";
|
|
11587
|
-
|
|
11698
|
+
stableState = stableStateForText(stablePrefix, stableState);
|
|
11699
|
+
if (key && stablePrefix) touchStablePrefixKey(key, stableState);
|
|
11588
11700
|
else if (key && !stablePrefix) stablePrefixByStreamKey.delete(key);
|
|
11589
11701
|
}
|
|
11590
11702
|
} catch {
|
|
11591
11703
|
stablePrefix = "";
|
|
11704
|
+
stableState = { text: "", chunks: [] };
|
|
11592
11705
|
if (key) stablePrefixByStreamKey.delete(key);
|
|
11593
11706
|
}
|
|
11594
|
-
if (isWhitespaceOnlyText(stablePrefix))
|
|
11707
|
+
if (isWhitespaceOnlyText(stablePrefix)) {
|
|
11708
|
+
stablePrefix = "";
|
|
11709
|
+
stableState = { text: "", chunks: [] };
|
|
11710
|
+
}
|
|
11595
11711
|
const unstableSuffix = t.substring(stablePrefix.length);
|
|
11596
11712
|
return cacheResolvedPartsKey(key, t, {
|
|
11597
11713
|
plain: false,
|
|
11598
11714
|
stablePrefix,
|
|
11715
|
+
stableChunks: stableState.chunks,
|
|
11599
11716
|
unstableSuffix,
|
|
11600
11717
|
unstableForRender: balanceStreamingMarkdown(unstableSuffix)
|
|
11601
11718
|
});
|
|
@@ -11721,22 +11838,31 @@ function measureStreamingMarkdownRenderedRows(text, columns, streamKey) {
|
|
|
11721
11838
|
let rows = 0;
|
|
11722
11839
|
let childCount = 0;
|
|
11723
11840
|
let stableRows = 0;
|
|
11724
|
-
|
|
11725
|
-
|
|
11726
|
-
|
|
11727
|
-
|
|
11728
|
-
|
|
11841
|
+
const stableChunks = parts.stableChunks?.length ? parts.stableChunks : parts.stablePrefix ? [parts.stablePrefix] : [];
|
|
11842
|
+
const reusableChunks = cached && cached.mode === "markdown" && cached.columns === columns && Array.isArray(cached.stableChunks) && cached.stableChunks.length <= stableChunks.length && cached.stableChunks.every((chunk, index) => chunk === stableChunks[index]);
|
|
11843
|
+
let measuredStableChunks = 0;
|
|
11844
|
+
if (reusableChunks) {
|
|
11845
|
+
stableRows = cached.stableRows;
|
|
11846
|
+
measuredStableChunks = cached.stableChunks.length;
|
|
11847
|
+
}
|
|
11848
|
+
for (let index = measuredStableChunks; index < stableChunks.length; index += 1) {
|
|
11849
|
+
if (index > 0) stableRows += 1;
|
|
11850
|
+
stableRows += measureMarkdownRenderedRows(stableChunks[index], columns, { trimPartialFences: false });
|
|
11851
|
+
}
|
|
11852
|
+
rows += stableRows;
|
|
11853
|
+
childCount = stableChunks.length;
|
|
11729
11854
|
if (parts.unstableSuffix) {
|
|
11855
|
+
if (childCount > 0) rows += 1;
|
|
11730
11856
|
rows += measureMarkdownRenderedRows(parts.unstableForRender, columns, { trimPartialFences: true });
|
|
11731
11857
|
childCount += 1;
|
|
11732
11858
|
}
|
|
11733
|
-
if (childCount === 2) rows += 1;
|
|
11734
11859
|
const measuredRows = childCount === 0 ? 1 : Math.max(1, rows);
|
|
11735
11860
|
cacheStreamingRows(key, {
|
|
11736
11861
|
text: value,
|
|
11737
11862
|
columns,
|
|
11738
11863
|
mode: "markdown",
|
|
11739
11864
|
stablePrefix: parts.stablePrefix,
|
|
11865
|
+
stableChunks: stableChunks.slice(),
|
|
11740
11866
|
stableRows,
|
|
11741
11867
|
rows: measuredRows
|
|
11742
11868
|
});
|
|
@@ -12818,6 +12944,9 @@ function cacheStreamingTailEstimate(id, entry) {
|
|
|
12818
12944
|
function hasStreamingRowStateToPrune() {
|
|
12819
12945
|
return streamingMeasuredRowsById.size > 0 || streamingEstimateHighWaterById.size > 0 || streamingTailEstimateById.size > 0;
|
|
12820
12946
|
}
|
|
12947
|
+
function transcriptHarvestInputsEqual(left, right) {
|
|
12948
|
+
return !!left && !!right && left.revision === right.revision && left.settledItems === right.settledItems && left.streamingTailItem === right.streamingTailItem && left.startIndex === right.startIndex && left.endIndex === right.endIndex && left.frameColumns === right.frameColumns && left.toolOutputExpanded === right.toolOutputExpanded && left.transcriptContentHeight === right.transcriptContentHeight && left.floatingPanelRows === right.floatingPanelRows && left.overlayHintRequested === right.overlayHintRequested && left.transcriptGuardRows === right.transcriptGuardRows && left.themeEpoch === right.themeEpoch;
|
|
12949
|
+
}
|
|
12821
12950
|
function pruneStreamingMeasuredRowsById(liveIds) {
|
|
12822
12951
|
if (!liveIds) return;
|
|
12823
12952
|
if (streamingMeasuredRowsById.size > 0) {
|
|
@@ -13632,13 +13761,30 @@ import { useCallback as useCallback3, useEffect as useEffect8, useRef as useRef8
|
|
|
13632
13761
|
// src/tui/engine/render-timing.mjs
|
|
13633
13762
|
var RENDER_ACK_HANG_GUARD_MS = 250;
|
|
13634
13763
|
var RENDER_SETTLE_IDLE_MS = 64;
|
|
13764
|
+
var TUI_RENDER_FPS = 60;
|
|
13765
|
+
var TUI_FRAME_MS = Math.ceil(1e3 / TUI_RENDER_FPS);
|
|
13635
13766
|
var pendingRenderAcks = [];
|
|
13636
13767
|
var renderAckSeq = 0;
|
|
13768
|
+
var lastRenderFrameAt = 0;
|
|
13769
|
+
var renderFrameDelay = (lastFrameAt, currentTime, frameMs = TUI_FRAME_MS) => {
|
|
13770
|
+
if (!(lastFrameAt > 0)) return frameMs;
|
|
13771
|
+
return Math.max(0, frameMs - Math.max(0, currentTime - lastFrameAt));
|
|
13772
|
+
};
|
|
13773
|
+
var scheduleRenderAlignedStoreFlush = (callback, frameMs = TUI_FRAME_MS) => {
|
|
13774
|
+
const timer2 = setTimeout(
|
|
13775
|
+
callback,
|
|
13776
|
+
renderFrameDelay(lastRenderFrameAt, performance.now(), frameMs)
|
|
13777
|
+
);
|
|
13778
|
+
timer2.unref?.();
|
|
13779
|
+
return timer2;
|
|
13780
|
+
};
|
|
13781
|
+
var cancelRenderAlignedStoreFlush = (timer2) => clearTimeout(timer2);
|
|
13637
13782
|
var scheduleRenderFrameAck = () => {
|
|
13638
13783
|
const seq = ++renderAckSeq;
|
|
13639
13784
|
setImmediate(() => notifyRenderFrame(seq));
|
|
13640
13785
|
};
|
|
13641
13786
|
var notifyRenderFrame = (seq = ++renderAckSeq) => {
|
|
13787
|
+
lastRenderFrameAt = performance.now();
|
|
13642
13788
|
if (pendingRenderAcks.length === 0) return;
|
|
13643
13789
|
const acks = pendingRenderAcks;
|
|
13644
13790
|
pendingRenderAcks = [];
|
|
@@ -14285,6 +14431,11 @@ function useTranscriptWindow({
|
|
|
14285
14431
|
const prevViewportGeomRef = useRef9({ contentHeight: 0, floatingPanelRows: 0 });
|
|
14286
14432
|
const transcriptItemElsRef = useRef9(/* @__PURE__ */ new Map());
|
|
14287
14433
|
const transcriptMeasureRefCache = useRef9(/* @__PURE__ */ new Map());
|
|
14434
|
+
const harvestGateRef = useRef9({
|
|
14435
|
+
inputs: null,
|
|
14436
|
+
skippedForDrag: false,
|
|
14437
|
+
forceNext: false
|
|
14438
|
+
});
|
|
14288
14439
|
const transcriptMeasureItemsRef = useRef9(/* @__PURE__ */ new Map());
|
|
14289
14440
|
const transcriptMeasureRef = useCallback4((item) => {
|
|
14290
14441
|
if (!TRANSCRIPT_MEASURED_ROWS || !item || item.id == null) return void 0;
|
|
@@ -14516,11 +14667,33 @@ function useTranscriptWindow({
|
|
|
14516
14667
|
const transcriptTailPinned = Math.max(0, Number(transcriptWindow.effectiveScrollOffset) || 0) === 0;
|
|
14517
14668
|
const overlayHintOnLastItem = overlayHintRequested && floatingPanelRows <= 0 && transcriptWindow.bottomSpacerRows === 0 && transcriptTailPinned && overlayHintAttachItemIndex >= 0;
|
|
14518
14669
|
const overlayHintFallbackRow = overlayHintRequested && floatingPanelRows <= 0 && transcriptGuardRows > 0 && !overlayHintOnLastItem;
|
|
14670
|
+
const harvestInputs = {
|
|
14671
|
+
revision,
|
|
14672
|
+
settledItems,
|
|
14673
|
+
streamingTailItem,
|
|
14674
|
+
startIndex: transcriptWindow.startIndex,
|
|
14675
|
+
endIndex: transcriptWindow.endIndex,
|
|
14676
|
+
frameColumns,
|
|
14677
|
+
toolOutputExpanded,
|
|
14678
|
+
transcriptContentHeight,
|
|
14679
|
+
floatingPanelRows,
|
|
14680
|
+
overlayHintRequested,
|
|
14681
|
+
transcriptGuardRows,
|
|
14682
|
+
themeEpoch
|
|
14683
|
+
};
|
|
14519
14684
|
useLayoutEffect3(() => {
|
|
14520
14685
|
if (!TRANSCRIPT_MEASURED_ROWS) return;
|
|
14521
|
-
|
|
14686
|
+
const gate = harvestGateRef.current;
|
|
14687
|
+
if (dragRef.current.active) {
|
|
14688
|
+
gate.skippedForDrag = true;
|
|
14689
|
+
return;
|
|
14690
|
+
}
|
|
14691
|
+
if (!gate.skippedForDrag && !gate.forceNext && transcriptHarvestInputsEqual(gate.inputs, harvestInputs)) return;
|
|
14522
14692
|
const els = transcriptItemElsRef.current;
|
|
14523
14693
|
if (!els || els.size === 0) return;
|
|
14694
|
+
gate.inputs = harvestInputs;
|
|
14695
|
+
gate.skippedForDrag = false;
|
|
14696
|
+
gate.forceNext = false;
|
|
14524
14697
|
const liveItems = transcriptMeasureItemsRef.current;
|
|
14525
14698
|
const toolExpandedFlag = toolOutputExpanded ? 1 : 0;
|
|
14526
14699
|
let changed = false;
|
|
@@ -14595,6 +14768,7 @@ function useTranscriptWindow({
|
|
|
14595
14768
|
}, 0);
|
|
14596
14769
|
if (typeof streak.timer?.unref === "function") streak.timer.unref();
|
|
14597
14770
|
}
|
|
14771
|
+
gate.forceNext = true;
|
|
14598
14772
|
setMeasuredRowsVersion((v) => (v + 1) % 1e6);
|
|
14599
14773
|
}
|
|
14600
14774
|
}
|
|
@@ -20156,13 +20330,29 @@ function Markdown({ children, themeEpoch = 0, trimPartialFences = false, columns
|
|
|
20156
20330
|
}, [children, themeEpoch, trimPartialFences, columns]);
|
|
20157
20331
|
return /* @__PURE__ */ jsx13(Box11, { flexDirection: "column", gap: 1, children: elements });
|
|
20158
20332
|
}
|
|
20333
|
+
var StableMarkdownChunk = React13.memo(function StableMarkdownChunk2({
|
|
20334
|
+
text,
|
|
20335
|
+
themeEpoch,
|
|
20336
|
+
columns
|
|
20337
|
+
}) {
|
|
20338
|
+
return /* @__PURE__ */ jsx13(Markdown, { themeEpoch, columns, children: text });
|
|
20339
|
+
});
|
|
20159
20340
|
function StreamingMarkdown({ children, themeEpoch = 0, columns, streamKey }) {
|
|
20160
20341
|
const parts = resolveStreamingMarkdownParts(children, streamKey);
|
|
20161
20342
|
if (parts.plain) {
|
|
20162
20343
|
return /* @__PURE__ */ jsx13(Text13, { color: theme.text, wrap: "wrap", children: parts.unstableForRender });
|
|
20163
20344
|
}
|
|
20345
|
+
const stableChunks = parts.stableChunks?.length ? parts.stableChunks : parts.stablePrefix ? [parts.stablePrefix] : [];
|
|
20164
20346
|
return /* @__PURE__ */ jsxs9(Box11, { flexDirection: "column", gap: 1, children: [
|
|
20165
|
-
|
|
20347
|
+
stableChunks.map((text, index) => /* @__PURE__ */ jsx13(
|
|
20348
|
+
StableMarkdownChunk,
|
|
20349
|
+
{
|
|
20350
|
+
text,
|
|
20351
|
+
themeEpoch,
|
|
20352
|
+
columns
|
|
20353
|
+
},
|
|
20354
|
+
`stable-${index}`
|
|
20355
|
+
)),
|
|
20166
20356
|
parts.unstableSuffix ? /* @__PURE__ */ jsx13(Markdown, { themeEpoch, columns, trimPartialFences: true, children: parts.unstableForRender }) : null
|
|
20167
20357
|
] });
|
|
20168
20358
|
}
|
|
@@ -20181,7 +20371,7 @@ var AssistantMessage = React14.memo(function AssistantMessage2({
|
|
|
20181
20371
|
if (!streaming && assistantId) resetStreamingMarkdownStablePrefix(assistantId);
|
|
20182
20372
|
}, [streaming, assistantId]);
|
|
20183
20373
|
const bodyWidth = assistantBodyWidth(columns);
|
|
20184
|
-
const renderText = streaming && streamingWindowRows > 0 ? windowPlainStreamingText(text, bodyWidth, streamingWindowRows) : text;
|
|
20374
|
+
const renderText = streaming && streamingWindowRows > 0 ? windowPlainStreamingText(text, bodyWidth, streamingWindowRows, assistantId) : text;
|
|
20185
20375
|
return /* @__PURE__ */ jsxs10(Box12, { flexDirection: "row", marginTop: 1, children: [
|
|
20186
20376
|
/* @__PURE__ */ jsx14(Box12, { flexShrink: 0, minWidth: 2, children: /* @__PURE__ */ jsx14(Text14, { color: theme.text, children: TURN_MARKER }) }),
|
|
20187
20377
|
/* @__PURE__ */ jsx14(Box12, { flexDirection: "column", flexShrink: 0, width: bodyWidth, children: streaming ? /* @__PURE__ */ jsx14(StreamingMarkdown, { themeEpoch, columns: bodyWidth, streamKey: assistantId, children: renderText }) : /* @__PURE__ */ jsx14(Markdown, { themeEpoch, columns: bodyWidth, children: text }) })
|
|
@@ -23633,7 +23823,7 @@ function App({ store, initialStatusLine = "", forceOnboarding = false }) {
|
|
|
23633
23823
|
}
|
|
23634
23824
|
|
|
23635
23825
|
// src/tui/engine.mjs
|
|
23636
|
-
import { performance as
|
|
23826
|
+
import { performance as performance3 } from "node:perf_hooks";
|
|
23637
23827
|
import { mkdtempSync as mkdtempSync2, readFileSync as readFileSync11, readdirSync as readdirSync5, rmSync as rmSync4, statSync as statSync7, watch as watch2, writeFileSync as writeFileSync8 } from "node:fs";
|
|
23638
23828
|
import { basename as basename7, dirname as dirname11, join as join14 } from "node:path";
|
|
23639
23829
|
|
|
@@ -23916,12 +24106,12 @@ function sessionPath(id) {
|
|
|
23916
24106
|
}
|
|
23917
24107
|
|
|
23918
24108
|
// src/tui/engine/boot-profile.mjs
|
|
23919
|
-
import { performance } from "node:perf_hooks";
|
|
24109
|
+
import { performance as performance2 } from "node:perf_hooks";
|
|
23920
24110
|
var BOOT_PROFILE_ENABLED = /^(1|true|yes|on)$/i.test(String(process.env.MIXDOG_BOOT_PROFILE || ""));
|
|
23921
|
-
var BOOT_PROFILE_START = globalThis.__mixdogBootProfileStart || (globalThis.__mixdogBootProfileStart =
|
|
24111
|
+
var BOOT_PROFILE_START = globalThis.__mixdogBootProfileStart || (globalThis.__mixdogBootProfileStart = performance2.now());
|
|
23922
24112
|
function bootProfile(event, fields = {}) {
|
|
23923
24113
|
if (!BOOT_PROFILE_ENABLED) return;
|
|
23924
|
-
const elapsedMs =
|
|
24114
|
+
const elapsedMs = performance2.now() - BOOT_PROFILE_START;
|
|
23925
24115
|
const parts = [`[mixdog-boot] +${elapsedMs.toFixed(1)}ms`, `tui:${event}`];
|
|
23926
24116
|
for (const [key, value] of Object.entries(fields || {})) {
|
|
23927
24117
|
if (value === void 0 || value === null || value === "") continue;
|
|
@@ -25611,6 +25801,7 @@ import { randomBytes as randomBytes3 } from "crypto";
|
|
|
25611
25801
|
import { join as join10 } from "path";
|
|
25612
25802
|
var PENDING_MESSAGES_FILE = "session-pending-messages.json";
|
|
25613
25803
|
var PENDING_MESSAGES_MODE = 384;
|
|
25804
|
+
var STALE_STEERING_RESTORE_TTL_MS = 30 * 60 * 1e3;
|
|
25614
25805
|
var _persistChain = Promise.resolve();
|
|
25615
25806
|
function _serialize(task) {
|
|
25616
25807
|
const run = _persistChain.then(task, task);
|
|
@@ -25637,7 +25828,9 @@ function normalizeTuiSteeringQueueEntry(entry) {
|
|
|
25637
25828
|
if (typeof entry.text === "string" && entry.text.trim()) {
|
|
25638
25829
|
const text = entry.text.trim();
|
|
25639
25830
|
const id = typeof entry.id === "string" && entry.id.trim() ? entry.id.trim() : null;
|
|
25640
|
-
|
|
25831
|
+
if (!id) return text;
|
|
25832
|
+
const at = Number(entry.at);
|
|
25833
|
+
return Number.isFinite(at) && at > 0 ? { id, text, at } : { id, text };
|
|
25641
25834
|
}
|
|
25642
25835
|
return null;
|
|
25643
25836
|
}
|
|
@@ -25689,7 +25882,7 @@ function appendTuiSteeringPersist(leadSessionId, entry) {
|
|
|
25689
25882
|
const key = tuiSteeringSessionKey(leadSessionId);
|
|
25690
25883
|
if (!key) return Promise.resolve();
|
|
25691
25884
|
if (!entry.steeringPersistId) entry.steeringPersistId = newSteeringPersistId();
|
|
25692
|
-
const record = { id: entry.steeringPersistId, text };
|
|
25885
|
+
const record = { id: entry.steeringPersistId, text, at: Date.now() };
|
|
25693
25886
|
return _serialize(async () => {
|
|
25694
25887
|
try {
|
|
25695
25888
|
await updateJsonAtomic(pendingMessagesPath(), (raw) => {
|
|
@@ -25761,12 +25954,21 @@ function drainTuiSteeringPersist(leadSessionId) {
|
|
|
25761
25954
|
if (!key) return Promise.resolve([]);
|
|
25762
25955
|
return _serialize(async () => {
|
|
25763
25956
|
let drained = [];
|
|
25957
|
+
let droppedStale = 0;
|
|
25764
25958
|
try {
|
|
25765
25959
|
await updateJsonAtomic(pendingMessagesPath(), (raw) => {
|
|
25766
25960
|
const next = normalizePendingStore(raw);
|
|
25767
25961
|
const q = Array.isArray(next.sessions[key]) ? next.sessions[key] : [];
|
|
25768
|
-
|
|
25769
|
-
|
|
25962
|
+
const now = Date.now();
|
|
25963
|
+
const touchedAt = Number(next.sessionTouchedAt?.[key]) || 0;
|
|
25964
|
+
const fresh = q.filter((row) => {
|
|
25965
|
+
const at = Number(row?.at) || touchedAt;
|
|
25966
|
+
const stale = at > 0 && now - at > STALE_STEERING_RESTORE_TTL_MS;
|
|
25967
|
+
if (stale) droppedStale += 1;
|
|
25968
|
+
return !stale;
|
|
25969
|
+
});
|
|
25970
|
+
drained = fresh.map(drainedRowToRestore).filter(Boolean);
|
|
25971
|
+
if (drained.length === 0 && droppedStale === 0) return void 0;
|
|
25770
25972
|
delete next.sessions[key];
|
|
25771
25973
|
if (next.sessionTouchedAt) delete next.sessionTouchedAt[key];
|
|
25772
25974
|
next.updatedAt = Date.now();
|
|
@@ -25775,6 +25977,13 @@ function drainTuiSteeringPersist(leadSessionId) {
|
|
|
25775
25977
|
} catch (err) {
|
|
25776
25978
|
try {
|
|
25777
25979
|
process.stderr.write(`[tui] steering-queue drain failed sessionId=${leadSessionId}: ${err?.message || err}
|
|
25980
|
+
`);
|
|
25981
|
+
} catch {
|
|
25982
|
+
}
|
|
25983
|
+
}
|
|
25984
|
+
if (droppedStale > 0) {
|
|
25985
|
+
try {
|
|
25986
|
+
process.stderr.write(`[tui] dropped ${droppedStale} stale steering row(s) sessionId=${leadSessionId}
|
|
25778
25987
|
`);
|
|
25779
25988
|
} catch {
|
|
25780
25989
|
}
|
|
@@ -28276,6 +28485,17 @@ function createEngineApiB(bag) {
|
|
|
28276
28485
|
listSessions: (options) => {
|
|
28277
28486
|
return runtime.listSessions(options);
|
|
28278
28487
|
},
|
|
28488
|
+
// Desktop sidebar watcher hook: EngineHost fs.watches this directory so
|
|
28489
|
+
// heartbeat sidecar create/delete pushes instant working/dot updates.
|
|
28490
|
+
// Without it the watcher silently no-ops and the sidebar falls back to
|
|
28491
|
+
// the 60s safety poll (user: spinner kept spinning after the turn ended).
|
|
28492
|
+
sessionStoreDir: () => {
|
|
28493
|
+
try {
|
|
28494
|
+
return runtime.sessionStoreDir?.() || null;
|
|
28495
|
+
} catch {
|
|
28496
|
+
return null;
|
|
28497
|
+
}
|
|
28498
|
+
},
|
|
28279
28499
|
deleteSession: async (id) => {
|
|
28280
28500
|
if (getState().commandBusy) return false;
|
|
28281
28501
|
const deletingCurrent = String(runtime.session?.id || getState().sessionId || "") === String(id || "");
|
|
@@ -29247,7 +29467,9 @@ function createFrameBatchedStorePublisher({
|
|
|
29247
29467
|
frameMs = 16,
|
|
29248
29468
|
setTimer = setTimeout,
|
|
29249
29469
|
clearTimer = clearTimeout,
|
|
29250
|
-
enqueueMicrotask = queueMicrotask
|
|
29470
|
+
enqueueMicrotask = queueMicrotask,
|
|
29471
|
+
scheduleFrame = (callback, delay2) => setTimer(callback, delay2),
|
|
29472
|
+
cancelFrame = (handle) => clearTimer(handle)
|
|
29251
29473
|
}) {
|
|
29252
29474
|
let timer2 = null;
|
|
29253
29475
|
let emitPending = false;
|
|
@@ -29255,7 +29477,7 @@ function createFrameBatchedStorePublisher({
|
|
|
29255
29477
|
let immediatePending = false;
|
|
29256
29478
|
const flush = () => {
|
|
29257
29479
|
if (timer2 !== null) {
|
|
29258
|
-
|
|
29480
|
+
cancelFrame(timer2);
|
|
29259
29481
|
timer2 = null;
|
|
29260
29482
|
}
|
|
29261
29483
|
immediatePending = false;
|
|
@@ -29277,7 +29499,7 @@ function createFrameBatchedStorePublisher({
|
|
|
29277
29499
|
const emit = () => {
|
|
29278
29500
|
emitPending = true;
|
|
29279
29501
|
if (timer2 !== null || isDisposed()) return;
|
|
29280
|
-
timer2 =
|
|
29502
|
+
timer2 = scheduleFrame(flush, frameMs);
|
|
29281
29503
|
timer2?.unref?.();
|
|
29282
29504
|
};
|
|
29283
29505
|
const markStructureChange = () => {
|
|
@@ -29291,7 +29513,7 @@ function createFrameBatchedStorePublisher({
|
|
|
29291
29513
|
};
|
|
29292
29514
|
const dispose = () => {
|
|
29293
29515
|
if (emitPending && !isDisposed()) flush();
|
|
29294
|
-
else if (timer2 !== null)
|
|
29516
|
+
else if (timer2 !== null) cancelFrame(timer2);
|
|
29295
29517
|
timer2 = null;
|
|
29296
29518
|
emitPending = false;
|
|
29297
29519
|
structureChangePending = false;
|
|
@@ -30313,16 +30535,16 @@ async function createEngineSession({
|
|
|
30313
30535
|
cwd,
|
|
30314
30536
|
desktopSession
|
|
30315
30537
|
} = {}) {
|
|
30316
|
-
const startedAt =
|
|
30538
|
+
const startedAt = performance3.now();
|
|
30317
30539
|
bootProfile("engine:create:start", { provider: providerName, model, toolMode, remote });
|
|
30318
30540
|
process.env.MIXDOG_QUIET_PROVIDER_LOG = "1";
|
|
30319
30541
|
process.env.MIXDOG_QUIET_SESSION_LOG = "1";
|
|
30320
30542
|
process.env.MIXDOG_QUIET_MCP_LOG = "1";
|
|
30321
30543
|
process.env.MIXDOG_QUIET_MEMORY_LOG = "1";
|
|
30322
30544
|
process.env.MIXDOG_PATCH_NATIVE_PREWARM ??= "0";
|
|
30323
|
-
const importStartedAt =
|
|
30545
|
+
const importStartedAt = performance3.now();
|
|
30324
30546
|
const { createMixdogSessionRuntime } = await import(SESSION_RUNTIME_MODULE);
|
|
30325
|
-
bootProfile("session-runtime:imported", { ms: (
|
|
30547
|
+
bootProfile("session-runtime:imported", { ms: (performance3.now() - importStartedAt).toFixed(1) });
|
|
30326
30548
|
const runtime = await createMixdogSessionRuntime({
|
|
30327
30549
|
provider: providerName,
|
|
30328
30550
|
model,
|
|
@@ -30331,9 +30553,9 @@ async function createEngineSession({
|
|
|
30331
30553
|
...cwd ? { cwd } : {},
|
|
30332
30554
|
...desktopSession ? { desktopSession } : {}
|
|
30333
30555
|
});
|
|
30334
|
-
bootProfile("engine:create:runtime-ready", { ms: (
|
|
30556
|
+
bootProfile("engine:create:runtime-ready", { ms: (performance3.now() - startedAt).toFixed(1) });
|
|
30335
30557
|
const runtimeCwd = runtime.cwd || process.cwd();
|
|
30336
|
-
const stateStartedAt =
|
|
30558
|
+
const stateStartedAt = performance3.now();
|
|
30337
30559
|
const flags = {
|
|
30338
30560
|
disposed: false,
|
|
30339
30561
|
draining: false,
|
|
@@ -30409,11 +30631,11 @@ async function createEngineSession({
|
|
|
30409
30631
|
cwd: runtimeCwd,
|
|
30410
30632
|
themeEpoch: 0
|
|
30411
30633
|
};
|
|
30412
|
-
bootProfile("engine:route-state-ready", { ms: (
|
|
30413
|
-
bootProfile("engine:state-ready", { ms: (
|
|
30414
|
-
const contextStartedAt =
|
|
30634
|
+
bootProfile("engine:route-state-ready", { ms: (performance3.now() - stateStartedAt).toFixed(1) });
|
|
30635
|
+
bootProfile("engine:state-ready", { ms: (performance3.now() - stateStartedAt).toFixed(1) });
|
|
30636
|
+
const contextStartedAt = performance3.now();
|
|
30415
30637
|
syncContextStats({ allowEstimated: true });
|
|
30416
|
-
bootProfile("engine:context-ready", { ms: (
|
|
30638
|
+
bootProfile("engine:context-ready", { ms: (performance3.now() - contextStartedAt).toFixed(1) });
|
|
30417
30639
|
const listeners = /* @__PURE__ */ new Set();
|
|
30418
30640
|
let publishedState = process.env.NODE_ENV === "production" ? state : Object.freeze(state);
|
|
30419
30641
|
state = { ...state, stats: { ...state.stats } };
|
|
@@ -30424,7 +30646,10 @@ async function createEngineSession({
|
|
|
30424
30646
|
state = { ...next, stats: { ...next.stats } };
|
|
30425
30647
|
},
|
|
30426
30648
|
listeners,
|
|
30427
|
-
isDisposed: () => flags.disposed
|
|
30649
|
+
isDisposed: () => flags.disposed,
|
|
30650
|
+
frameMs: TUI_FRAME_MS,
|
|
30651
|
+
scheduleFrame: scheduleRenderAlignedStoreFlush,
|
|
30652
|
+
cancelFrame: cancelRenderAlignedStoreFlush
|
|
30428
30653
|
});
|
|
30429
30654
|
const emit = publisher.emit;
|
|
30430
30655
|
const flushEmit = publisher.flush;
|
|
@@ -31100,7 +31325,7 @@ var XTSHIFTESCAPE_ON = process.env.WT_SESSION ? "" : "\x1B[>1s";
|
|
|
31100
31325
|
var MOUSE_TRACKING_ON2 = `\x1B[?1000h\x1B[?1002h\x1B[?1006h\x1B[?1007l${XTSHIFTESCAPE_ON}`;
|
|
31101
31326
|
var ALT_SCROLL_RESTORE = "\x1B[?1007h";
|
|
31102
31327
|
var BOOT_PROFILE_ENABLED2 = /^(1|true|yes|on)$/i.test(String(process.env.MIXDOG_BOOT_PROFILE || ""));
|
|
31103
|
-
var BOOT_PROFILE_START2 = globalThis.__mixdogBootProfileStart || (globalThis.__mixdogBootProfileStart =
|
|
31328
|
+
var BOOT_PROFILE_START2 = globalThis.__mixdogBootProfileStart || (globalThis.__mixdogBootProfileStart = performance4.now());
|
|
31104
31329
|
var EXIT_WAIT_TIMEOUT_MS = positiveIntEnv2("MIXDOG_TUI_EXIT_WAIT_MS", 2500);
|
|
31105
31330
|
var EXIT_HARD_DELAY_MS = positiveIntEnv2("MIXDOG_TUI_HARD_EXIT_DELAY_MS", 500);
|
|
31106
31331
|
var EXIT_HARD_ENABLED = !/^(0|false|no|off)$/i.test(String(process.env.MIXDOG_TUI_HARD_EXIT || "1"));
|
|
@@ -31116,9 +31341,9 @@ function positiveIntEnv2(name, fallback) {
|
|
|
31116
31341
|
function installTuiLoopProbe() {
|
|
31117
31342
|
if (!LOOP_PROBE_ENABLED) return () => {
|
|
31118
31343
|
};
|
|
31119
|
-
let last =
|
|
31344
|
+
let last = performance4.now();
|
|
31120
31345
|
const timer2 = setInterval(() => {
|
|
31121
|
-
const now =
|
|
31346
|
+
const now = performance4.now();
|
|
31122
31347
|
const drift = now - last - LOOP_PROBE_INTERVAL_MS;
|
|
31123
31348
|
last = now;
|
|
31124
31349
|
if (drift > LOOP_PROBE_DRIFT_THRESHOLD_MS) {
|
|
@@ -31143,7 +31368,7 @@ var PERF_STALL_THRESHOLD_MS = positiveIntEnv2("MIXDOG_TUI_PERF_STALL_MS", 80);
|
|
|
31143
31368
|
var PERF_RENDER_GAP_MS = positiveIntEnv2("MIXDOG_TUI_PERF_RENDER_GAP_MS", 120);
|
|
31144
31369
|
function perfLog(event, fields = {}) {
|
|
31145
31370
|
if (!PERF_ENABLED) return;
|
|
31146
|
-
const elapsedMs =
|
|
31371
|
+
const elapsedMs = performance4.now() - BOOT_PROFILE_START2;
|
|
31147
31372
|
const parts = [`[mixdog-perf] +${elapsedMs.toFixed(1)}ms`, event];
|
|
31148
31373
|
for (const [key, value] of Object.entries(fields || {})) {
|
|
31149
31374
|
if (value === void 0 || value === null || value === "") continue;
|
|
@@ -31158,7 +31383,7 @@ function perfLog(event, fields = {}) {
|
|
|
31158
31383
|
function installTuiPerfProbe() {
|
|
31159
31384
|
if (!PERF_ENABLED) return () => {
|
|
31160
31385
|
};
|
|
31161
|
-
let last =
|
|
31386
|
+
let last = performance4.now();
|
|
31162
31387
|
let lastCpu = process.cpuUsage();
|
|
31163
31388
|
perfLog("probe:start", {
|
|
31164
31389
|
intervalMs: PERF_STALL_INTERVAL_MS,
|
|
@@ -31166,7 +31391,7 @@ function installTuiPerfProbe() {
|
|
|
31166
31391
|
renderGapMs: PERF_RENDER_GAP_MS
|
|
31167
31392
|
});
|
|
31168
31393
|
const timer2 = setInterval(() => {
|
|
31169
|
-
const now =
|
|
31394
|
+
const now = performance4.now();
|
|
31170
31395
|
const elapsed = now - last;
|
|
31171
31396
|
const lagMs = elapsed - PERF_STALL_INTERVAL_MS;
|
|
31172
31397
|
const cpu = process.cpuUsage(lastCpu);
|
|
@@ -31204,7 +31429,7 @@ function makeRenderProfiler() {
|
|
|
31204
31429
|
let lastFrameAt = 0;
|
|
31205
31430
|
return ({ renderTime } = {}) => {
|
|
31206
31431
|
ackRenderedFrame();
|
|
31207
|
-
const now =
|
|
31432
|
+
const now = performance4.now();
|
|
31208
31433
|
const ms = Number(renderTime) || 0;
|
|
31209
31434
|
const gap = lastFrameAt ? now - lastFrameAt : 0;
|
|
31210
31435
|
lastFrameAt = now;
|
|
@@ -31238,7 +31463,7 @@ function makeRenderProfiler() {
|
|
|
31238
31463
|
}
|
|
31239
31464
|
function bootProfile2(event, fields = {}) {
|
|
31240
31465
|
if (!BOOT_PROFILE_ENABLED2) return;
|
|
31241
|
-
const elapsedMs =
|
|
31466
|
+
const elapsedMs = performance4.now() - BOOT_PROFILE_START2;
|
|
31242
31467
|
const parts = [`[mixdog-boot] +${elapsedMs.toFixed(1)}ms`, `tui:${event}`];
|
|
31243
31468
|
for (const [key, value] of Object.entries(fields || {})) {
|
|
31244
31469
|
if (value === void 0 || value === null || value === "") continue;
|
|
@@ -31456,7 +31681,7 @@ function installTuiConsoleGuard() {
|
|
|
31456
31681
|
};
|
|
31457
31682
|
}
|
|
31458
31683
|
async function runTui({ provider, model, toolMode, remote, forceOnboarding } = {}) {
|
|
31459
|
-
const startedAt =
|
|
31684
|
+
const startedAt = performance4.now();
|
|
31460
31685
|
bootProfile2("run:start", { provider, model, toolMode, remote });
|
|
31461
31686
|
if (!process.stdin.isTTY) {
|
|
31462
31687
|
process.stderr.write(
|
|
@@ -31487,6 +31712,7 @@ async function runTui({ provider, model, toolMode, remote, forceOnboarding } = {
|
|
|
31487
31712
|
process.stdout.write(`${TERMINAL_MODE_RESET_HIDDEN_CURSOR}\x1B[?1049h${TERMINAL_MODE_RESET_HIDDEN_CURSOR}\x1B[2J\x1B[H`);
|
|
31488
31713
|
process.stdout.write("\x1B[5 q");
|
|
31489
31714
|
process.on("exit", restoreTerminal);
|
|
31715
|
+
const storeOutcomePromise = createEngineSession({ provider, model, toolMode, remote }).then((store2) => ({ store: store2, error: null }), (error) => ({ store: null, error }));
|
|
31490
31716
|
try {
|
|
31491
31717
|
await loadThemeSettingFromConfig();
|
|
31492
31718
|
} catch {
|
|
@@ -31496,8 +31722,10 @@ async function runTui({ provider, model, toolMode, remote, forceOnboarding } = {
|
|
|
31496
31722
|
} };
|
|
31497
31723
|
let store;
|
|
31498
31724
|
try {
|
|
31499
|
-
|
|
31500
|
-
|
|
31725
|
+
const outcome = await storeOutcomePromise;
|
|
31726
|
+
if (outcome.error) throw outcome.error;
|
|
31727
|
+
store = outcome.store;
|
|
31728
|
+
bootProfile2("store:ready", { ms: (performance4.now() - startedAt).toFixed(1) });
|
|
31501
31729
|
} catch (error) {
|
|
31502
31730
|
splash.stop();
|
|
31503
31731
|
stopPerfProbe();
|
|
@@ -31562,8 +31790,8 @@ async function runTui({ provider, model, toolMode, remote, forceOnboarding } = {
|
|
|
31562
31790
|
registerStdioDeath(process.stderr, "error", { requireCode: true });
|
|
31563
31791
|
registerStdioDeath(process.stderr, "close");
|
|
31564
31792
|
try {
|
|
31565
|
-
const instance = render(/* @__PURE__ */ jsx21(App, { store, forceOnboarding: forceOnboarding === true }), { exitOnCtrlC: false, maxFps:
|
|
31566
|
-
bootProfile2("render:mounted", { ms: (
|
|
31793
|
+
const instance = render(/* @__PURE__ */ jsx21(App, { store, forceOnboarding: forceOnboarding === true }), { exitOnCtrlC: false, maxFps: TUI_RENDER_FPS, incrementalRendering: true, patchConsole: false, onRender: makeRenderProfiler() });
|
|
31794
|
+
bootProfile2("render:mounted", { ms: (performance4.now() - startedAt).toFixed(1) });
|
|
31567
31795
|
const { waitUntilExit } = instance;
|
|
31568
31796
|
if (mouseTracking && typeof instance.setSelection === "function") {
|
|
31569
31797
|
store.setRenderSelection = instance.setSelection;
|