mixdog 0.9.65 → 0.9.67
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 +83 -18
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +14 -0
- package/src/runtime/agent/orchestrator/session/store.mjs +37 -2
- package/src/runtime/channels/lib/config.mjs +7 -0
- package/src/runtime/channels/lib/status-snapshot.mjs +6 -30
- package/src/runtime/channels/lib/webhook/relay-tunnel.mjs +203 -0
- package/src/runtime/channels/lib/webhook.mjs +23 -201
- package/src/runtime/shared/config.mjs +0 -9
- package/src/runtime/shared/time-format.mjs +56 -0
- package/src/runtime/shared/tool-card-model.mjs +740 -0
- package/src/session-runtime/channel-config-api.mjs +5 -0
- package/src/session-runtime/context-status.mjs +2 -1
- package/src/session-runtime/lifecycle-api.mjs +5 -0
- package/src/session-runtime/prewarm.mjs +13 -7
- package/src/session-runtime/provider-request-tools.mjs +6 -0
- package/src/session-runtime/runtime-core.mjs +28 -9
- package/src/session-runtime/session-text.mjs +6 -0
- package/src/session-runtime/settings-api.mjs +0 -12
- package/src/session-runtime/tool-catalog-schema.mjs +5 -1
- package/src/standalone/channel-admin.mjs +35 -21
- package/src/tui/App.jsx +0 -15
- package/src/tui/app/channel-pickers.mjs +18 -42
- package/src/tui/app/doctor.mjs +0 -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/components/ToolExecution.jsx +47 -196
- package/src/tui/components/tool-execution/surface-detail.mjs +33 -394
- package/src/tui/components/tool-execution/text-format.mjs +27 -104
- package/src/tui/dist/index.mjs +613 -264
- package/src/tui/engine/frame-batched-store.mjs +5 -3
- package/src/tui/engine/live-share.mjs +9 -0
- package/src/tui/engine/render-timing.mjs +28 -0
- package/src/tui/engine/session-api-ext.mjs +7 -10
- 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/tui/time-format.mjs +4 -51
- package/src/ui/stream-finalize.mjs +45 -0
- package/src/runtime/channels/lib/webhook/ngrok.mjs +0 -181
package/src/tui/dist/index.mjs
CHANGED
|
@@ -1246,7 +1246,6 @@ __export(config_exports, {
|
|
|
1246
1246
|
getOpenAIUsageSessionKey: () => getOpenAIUsageSessionKey,
|
|
1247
1247
|
getOpenCodeGoAuthCookie: () => getOpenCodeGoAuthCookie,
|
|
1248
1248
|
getTelegramToken: () => getTelegramToken,
|
|
1249
|
-
getWebhookAuthtoken: () => getWebhookAuthtoken,
|
|
1250
1249
|
hasStoredSecret: () => hasStoredSecret,
|
|
1251
1250
|
invalidateConfigReadCache: () => invalidateConfigReadCache,
|
|
1252
1251
|
invalidateSecretReadCache: () => invalidateSecretReadCache,
|
|
@@ -1563,9 +1562,6 @@ function getDiscordToken() {
|
|
|
1563
1562
|
function getTelegramToken() {
|
|
1564
1563
|
return _readSecret(SECRET_ACCOUNTS.telegramToken);
|
|
1565
1564
|
}
|
|
1566
|
-
function getWebhookAuthtoken() {
|
|
1567
|
-
return _readSecret(SECRET_ACCOUNTS.webhookAuth);
|
|
1568
|
-
}
|
|
1569
1565
|
function getOpenAIUsageSessionKey() {
|
|
1570
1566
|
return process.env.OPENAI_USAGE_SESSION_KEY || process.env.OPENAI_DASHBOARD_SESSION_KEY || process.env.OPENAI_SESSION_KEY || process.env.MIXDOG_OPENAI_USAGE_SESSION_KEY || _readSecret(SECRET_ACCOUNTS.openaiUsageSessionKey);
|
|
1571
1567
|
}
|
|
@@ -1631,7 +1627,6 @@ var init_config = __esm({
|
|
|
1631
1627
|
SECRET_ACCOUNTS = Object.freeze({
|
|
1632
1628
|
discordToken: "discord.token",
|
|
1633
1629
|
telegramToken: "telegram.token",
|
|
1634
|
-
webhookAuth: "webhook.authtoken",
|
|
1635
1630
|
agentApiKey: (provider) => `agent.${provider}.apiKey`,
|
|
1636
1631
|
openaiUsageSessionKey: "agent.openai.usageSessionKey",
|
|
1637
1632
|
opencodeGoAuthCookie: "agent.opencode-go.authCookie"
|
|
@@ -2588,7 +2583,7 @@ import { render } from "../../../vendor/ink/build/index.js";
|
|
|
2588
2583
|
import { closeSync as closeSync3, constants as fsConstants, createWriteStream as createWriteStream2, mkdirSync as mkdirSync9, openSync as openSync3, readSync } from "node:fs";
|
|
2589
2584
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
2590
2585
|
import { dirname as dirname12, join as join15 } from "node:path";
|
|
2591
|
-
import { performance as
|
|
2586
|
+
import { performance as performance4 } from "node:perf_hooks";
|
|
2592
2587
|
import { format } from "node:util";
|
|
2593
2588
|
|
|
2594
2589
|
// src/tui/App.jsx
|
|
@@ -5844,7 +5839,7 @@ var SPINNER_VERBS = [
|
|
|
5844
5839
|
];
|
|
5845
5840
|
var SPINNER_FRAMES = ["\u25C7", "\u25C6", "\u25C8", "\u25C6", "\u25C7"];
|
|
5846
5841
|
|
|
5847
|
-
// src/
|
|
5842
|
+
// src/runtime/shared/time-format.mjs
|
|
5848
5843
|
function formatDuration(ms, options = {}) {
|
|
5849
5844
|
if (!Number.isFinite(Number(ms))) return "";
|
|
5850
5845
|
const value = Math.max(0, Number(ms) || 0);
|
|
@@ -7274,6 +7269,7 @@ function PromptInput({
|
|
|
7274
7269
|
if (valueRef) valueRef.current = draftRef.current.value;
|
|
7275
7270
|
const { isRawModeSupported } = useStdin();
|
|
7276
7271
|
const boxRef = useRef4(null);
|
|
7272
|
+
const inkRootRef = useRef4(null);
|
|
7277
7273
|
const cursorEnabledRef = useRef4(false);
|
|
7278
7274
|
const contentWidthRef = useRef4(80);
|
|
7279
7275
|
const preferredColumnRef = useRef4(null);
|
|
@@ -7288,9 +7284,15 @@ function PromptInput({
|
|
|
7288
7284
|
}
|
|
7289
7285
|
const flushThrottleRef = useRef4({ lastAt: 0, timer: null });
|
|
7290
7286
|
const flushImmediate = () => {
|
|
7287
|
+
const cachedRoot = inkRootRef.current;
|
|
7288
|
+
if (typeof cachedRoot?.onImmediateRender === "function") {
|
|
7289
|
+
cachedRoot.onImmediateRender();
|
|
7290
|
+
return;
|
|
7291
|
+
}
|
|
7291
7292
|
let node = boxRef.current;
|
|
7292
7293
|
for (let i = 0; node && i < 64; i++) {
|
|
7293
7294
|
if (node.nodeName === "ink-root") {
|
|
7295
|
+
inkRootRef.current = node;
|
|
7294
7296
|
if (typeof node.onImmediateRender === "function") node.onImmediateRender();
|
|
7295
7297
|
return;
|
|
7296
7298
|
}
|
|
@@ -11289,18 +11291,22 @@ function trimPartialClosingFences(tokens) {
|
|
|
11289
11291
|
}
|
|
11290
11292
|
var OPEN_FENCE_RE = /^( {0,3})(`{3,}|~{3,})(.*)$/;
|
|
11291
11293
|
var CLOSE_FENCE_RE = /^ {0,3}([`~]+)[ \t]*$/;
|
|
11294
|
+
var OPEN_FENCE_SCAN_LRU_MAX = 32;
|
|
11295
|
+
var openFenceScanByStreamKey = /* @__PURE__ */ new Map();
|
|
11292
11296
|
function isClosingFence(line, char, openLen) {
|
|
11293
11297
|
const m = CLOSE_FENCE_RE.exec(line);
|
|
11294
11298
|
if (!m) return false;
|
|
11295
11299
|
const run = m[1];
|
|
11296
11300
|
return run.startsWith(char.repeat(openLen));
|
|
11297
11301
|
}
|
|
11298
|
-
function
|
|
11299
|
-
|
|
11300
|
-
let
|
|
11301
|
-
|
|
11302
|
-
|
|
11302
|
+
function scanOpenFence(value, startAt = 0, initialOpen = null) {
|
|
11303
|
+
let open = initialOpen;
|
|
11304
|
+
let start = startAt;
|
|
11305
|
+
const checkpointIndex = value.lastIndexOf("\n") + 1;
|
|
11306
|
+
let openBeforeCheckpoint = start === checkpointIndex ? open : null;
|
|
11307
|
+
for (let i = startAt; i <= value.length; i++) {
|
|
11303
11308
|
if (i !== value.length && value[i] !== "\n") continue;
|
|
11309
|
+
if (start === checkpointIndex) openBeforeCheckpoint = open;
|
|
11304
11310
|
const line = value.slice(start, i);
|
|
11305
11311
|
if (!open) {
|
|
11306
11312
|
const m = OPEN_FENCE_RE.exec(line);
|
|
@@ -11316,13 +11322,42 @@ function findOpenFenceStart(text) {
|
|
|
11316
11322
|
}
|
|
11317
11323
|
start = i + 1;
|
|
11318
11324
|
}
|
|
11319
|
-
|
|
11320
|
-
|
|
11325
|
+
return { open, checkpointIndex, openBeforeCheckpoint };
|
|
11326
|
+
}
|
|
11327
|
+
function touchOpenFenceScan(key, entry) {
|
|
11328
|
+
if (openFenceScanByStreamKey.has(key)) openFenceScanByStreamKey.delete(key);
|
|
11329
|
+
openFenceScanByStreamKey.set(key, entry);
|
|
11330
|
+
while (openFenceScanByStreamKey.size > OPEN_FENCE_SCAN_LRU_MAX) {
|
|
11331
|
+
const oldest = openFenceScanByStreamKey.keys().next().value;
|
|
11332
|
+
if (oldest === void 0) break;
|
|
11333
|
+
openFenceScanByStreamKey.delete(oldest);
|
|
11334
|
+
}
|
|
11335
|
+
}
|
|
11336
|
+
function resetOpenFenceScan(streamKey) {
|
|
11337
|
+
if (streamKey == null || streamKey === "") return;
|
|
11338
|
+
openFenceScanByStreamKey.delete(String(streamKey));
|
|
11339
|
+
}
|
|
11340
|
+
function resetAllOpenFenceScans() {
|
|
11341
|
+
openFenceScanByStreamKey.clear();
|
|
11342
|
+
}
|
|
11343
|
+
function findOpenFenceStart(text, streamKey = null) {
|
|
11344
|
+
const value = String(text ?? "");
|
|
11345
|
+
const key = streamKey == null || streamKey === "" ? null : String(streamKey);
|
|
11346
|
+
const cached = key ? openFenceScanByStreamKey.get(key) : null;
|
|
11347
|
+
if (cached?.text === value) return cached.result;
|
|
11348
|
+
const scanned = cached && value.startsWith(cached.text) ? scanOpenFence(value, cached.checkpointIndex, cached.openBeforeCheckpoint) : scanOpenFence(value);
|
|
11349
|
+
const result = !scanned.open || scanned.open.indent !== 0 ? null : { index: scanned.open.index, lang: scanned.open.lang };
|
|
11350
|
+
if (key) touchOpenFenceScan(key, { text: value, ...scanned, result });
|
|
11351
|
+
return result;
|
|
11321
11352
|
}
|
|
11322
11353
|
|
|
11323
11354
|
// src/tui/markdown/render-ansi.mjs
|
|
11324
11355
|
var TOKEN_CACHE_MAX = 500;
|
|
11325
11356
|
var tokenCache = /* @__PURE__ */ new Map();
|
|
11357
|
+
var renderedSegmentCache = [];
|
|
11358
|
+
var RENDERED_SEGMENT_CACHE_MAX = 12;
|
|
11359
|
+
var RENDERED_SEGMENT_CACHE_MAX_CHARS = 256 * 1024;
|
|
11360
|
+
var renderedSegmentCacheChars = 0;
|
|
11326
11361
|
var MD_SYNTAX_RE = /[#*`|[>\-_~]|\n\n|^\d+\. |\n\d+\. /;
|
|
11327
11362
|
var _configured = false;
|
|
11328
11363
|
function configureMarked() {
|
|
@@ -11384,8 +11419,19 @@ function lexMarkdown(content, { trimPartialFences = false } = {}) {
|
|
|
11384
11419
|
return tokens;
|
|
11385
11420
|
}
|
|
11386
11421
|
function renderTokenAnsiSegments(content, opts = {}) {
|
|
11387
|
-
const
|
|
11422
|
+
const text = String(content ?? "");
|
|
11388
11423
|
const width = Number(opts.width) || 0;
|
|
11424
|
+
const trimPartialFences = opts.trimPartialFences === true;
|
|
11425
|
+
const themeVersion = getThemeVersion();
|
|
11426
|
+
for (let index = renderedSegmentCache.length - 1; index >= 0; index -= 1) {
|
|
11427
|
+
const entry = renderedSegmentCache[index];
|
|
11428
|
+
if (entry.text === text && entry.width === width && entry.trimPartialFences === trimPartialFences && entry.themeVersion === themeVersion) {
|
|
11429
|
+
renderedSegmentCache.splice(index, 1);
|
|
11430
|
+
renderedSegmentCache.push(entry);
|
|
11431
|
+
return entry.segments;
|
|
11432
|
+
}
|
|
11433
|
+
}
|
|
11434
|
+
const tokens = lexMarkdown(text, opts);
|
|
11389
11435
|
const segments = [];
|
|
11390
11436
|
for (const token of tokens) {
|
|
11391
11437
|
if (token.type === "table") {
|
|
@@ -11398,55 +11444,104 @@ function renderTokenAnsiSegments(content, opts = {}) {
|
|
|
11398
11444
|
segments.push({ type: "ansi", ansi, token });
|
|
11399
11445
|
}
|
|
11400
11446
|
}
|
|
11447
|
+
if (text.length <= RENDERED_SEGMENT_CACHE_MAX_CHARS) {
|
|
11448
|
+
const entry = { text, width, trimPartialFences, themeVersion, segments };
|
|
11449
|
+
renderedSegmentCache.push(entry);
|
|
11450
|
+
renderedSegmentCacheChars += text.length;
|
|
11451
|
+
while (renderedSegmentCache.length > RENDERED_SEGMENT_CACHE_MAX || renderedSegmentCacheChars > RENDERED_SEGMENT_CACHE_MAX_CHARS) {
|
|
11452
|
+
const removed = renderedSegmentCache.shift();
|
|
11453
|
+
renderedSegmentCacheChars -= removed?.text.length || 0;
|
|
11454
|
+
}
|
|
11455
|
+
}
|
|
11401
11456
|
return segments;
|
|
11402
11457
|
}
|
|
11403
11458
|
|
|
11404
11459
|
// src/tui/markdown/streaming-markdown.mjs
|
|
11405
11460
|
import { marked as marked2 } from "marked";
|
|
11406
11461
|
var stablePrefixByStreamKey = /* @__PURE__ */ new Map();
|
|
11462
|
+
var markdownSyntaxByStreamKey = /* @__PURE__ */ new Map();
|
|
11463
|
+
var plainWindowSyntaxByStreamKey = /* @__PURE__ */ new Map();
|
|
11407
11464
|
var resolvedPartsByStreamKey = /* @__PURE__ */ new Map();
|
|
11408
11465
|
var STABLE_PREFIX_LRU_MAX = 32;
|
|
11409
11466
|
function streamingLayoutText(text) {
|
|
11410
11467
|
return String(text ?? "").replace(/^\n+|\n+$/g, "");
|
|
11411
11468
|
}
|
|
11412
|
-
function windowPlainStreamingText(text, columns, maxRows) {
|
|
11469
|
+
function windowPlainStreamingText(text, columns, maxRows, streamKey = null) {
|
|
11413
11470
|
const value = streamingLayoutText(text);
|
|
11414
11471
|
const rowBudget = Math.max(0, Math.floor(Number(maxRows) || 0));
|
|
11415
|
-
|
|
11416
|
-
|
|
11472
|
+
const key = streamKey == null || streamKey === "" ? null : String(streamKey);
|
|
11473
|
+
if (!value || rowBudget <= 0 || cachedStreamingHasMarkdownSyntax(
|
|
11474
|
+
plainWindowSyntaxByStreamKey,
|
|
11475
|
+
value,
|
|
11476
|
+
key
|
|
11477
|
+
)) return value;
|
|
11417
11478
|
const width = Math.max(1, Math.floor(Number(columns) || 80));
|
|
11418
11479
|
let rows = 0;
|
|
11419
|
-
let
|
|
11420
|
-
|
|
11421
|
-
|
|
11480
|
+
let end = value.length;
|
|
11481
|
+
let start = end;
|
|
11482
|
+
while (end >= 0) {
|
|
11483
|
+
const newline = value.lastIndexOf("\n", end - 1);
|
|
11484
|
+
const lineStart2 = newline + 1;
|
|
11485
|
+
const line = value.slice(lineStart2, end);
|
|
11422
11486
|
const lineRows = Math.max(1, Math.ceil(displayWidth(line) / width));
|
|
11423
11487
|
if (rows > 0 && rows + lineRows > rowBudget) break;
|
|
11424
11488
|
rows += lineRows;
|
|
11425
|
-
start
|
|
11426
|
-
if (rows >= rowBudget) break;
|
|
11489
|
+
start = lineStart2;
|
|
11490
|
+
if (rows >= rowBudget || newline < 0) break;
|
|
11491
|
+
end = newline;
|
|
11427
11492
|
}
|
|
11428
|
-
return start > 0 ?
|
|
11493
|
+
return start > 0 ? value.slice(start) : value;
|
|
11429
11494
|
}
|
|
11430
11495
|
function isWhitespaceOnlyText(text) {
|
|
11431
11496
|
return !String(text ?? "").trim();
|
|
11432
11497
|
}
|
|
11433
|
-
function
|
|
11498
|
+
function touchLruKey(cache, key, value) {
|
|
11434
11499
|
if (!key) return;
|
|
11435
|
-
if (
|
|
11436
|
-
|
|
11437
|
-
while (
|
|
11438
|
-
const oldest =
|
|
11500
|
+
if (cache.has(key)) cache.delete(key);
|
|
11501
|
+
cache.set(key, value);
|
|
11502
|
+
while (cache.size > STABLE_PREFIX_LRU_MAX) {
|
|
11503
|
+
const oldest = cache.keys().next().value;
|
|
11439
11504
|
if (oldest === void 0) break;
|
|
11440
|
-
|
|
11505
|
+
cache.delete(oldest);
|
|
11441
11506
|
}
|
|
11442
11507
|
}
|
|
11508
|
+
function touchStablePrefixKey(key, value) {
|
|
11509
|
+
touchLruKey(stablePrefixByStreamKey, key, value);
|
|
11510
|
+
}
|
|
11443
11511
|
function getStablePrefixKey(key) {
|
|
11444
|
-
if (!key || !stablePrefixByStreamKey.has(key)) return "";
|
|
11512
|
+
if (!key || !stablePrefixByStreamKey.has(key)) return { text: "", chunks: [] };
|
|
11445
11513
|
const value = stablePrefixByStreamKey.get(key);
|
|
11446
|
-
|
|
11447
|
-
|
|
11514
|
+
touchStablePrefixKey(key, value);
|
|
11515
|
+
return value;
|
|
11516
|
+
}
|
|
11517
|
+
function stableStateForText(text, previous) {
|
|
11518
|
+
if (!text) return { text: "", chunks: [] };
|
|
11519
|
+
if (text.startsWith(previous.text)) {
|
|
11520
|
+
const appended = text.substring(previous.text.length);
|
|
11521
|
+
return appended ? { text, chunks: [...previous.chunks, appended] } : previous;
|
|
11522
|
+
}
|
|
11523
|
+
return { text, chunks: [text] };
|
|
11524
|
+
}
|
|
11525
|
+
function cachedStreamingHasMarkdownSyntax(cache, text, key) {
|
|
11526
|
+
if (!key) return hasMarkdownSyntax(text);
|
|
11527
|
+
const previous = cache.get(key);
|
|
11528
|
+
let value;
|
|
11529
|
+
if (previous && text.startsWith(previous.text)) {
|
|
11530
|
+
if (previous.value) {
|
|
11531
|
+
value = true;
|
|
11532
|
+
} else {
|
|
11533
|
+
const lineStart2 = previous.text.lastIndexOf("\n") + 1;
|
|
11534
|
+
value = hasMarkdownSyntax(text.substring(Math.max(0, lineStart2 - 1)));
|
|
11535
|
+
}
|
|
11536
|
+
} else {
|
|
11537
|
+
value = hasMarkdownSyntax(text);
|
|
11538
|
+
}
|
|
11539
|
+
touchLruKey(cache, key, { text, value });
|
|
11448
11540
|
return value;
|
|
11449
11541
|
}
|
|
11542
|
+
function streamingHasMarkdownSyntax(text, key) {
|
|
11543
|
+
return cachedStreamingHasMarkdownSyntax(markdownSyntaxByStreamKey, text, key);
|
|
11544
|
+
}
|
|
11450
11545
|
function getResolvedPartsKey(key, text) {
|
|
11451
11546
|
if (!key) return null;
|
|
11452
11547
|
const entry = resolvedPartsByStreamKey.get(key);
|
|
@@ -11518,11 +11613,17 @@ function resetStreamingMarkdownStablePrefix(streamKey) {
|
|
|
11518
11613
|
if (streamKey == null || streamKey === "") return;
|
|
11519
11614
|
const key = String(streamKey);
|
|
11520
11615
|
stablePrefixByStreamKey.delete(key);
|
|
11616
|
+
markdownSyntaxByStreamKey.delete(key);
|
|
11617
|
+
plainWindowSyntaxByStreamKey.delete(key);
|
|
11521
11618
|
resolvedPartsByStreamKey.delete(key);
|
|
11619
|
+
resetOpenFenceScan(key);
|
|
11522
11620
|
}
|
|
11523
11621
|
function resetAllStreamingMarkdownStablePrefixes() {
|
|
11524
11622
|
stablePrefixByStreamKey.clear();
|
|
11623
|
+
markdownSyntaxByStreamKey.clear();
|
|
11624
|
+
plainWindowSyntaxByStreamKey.clear();
|
|
11525
11625
|
resolvedPartsByStreamKey.clear();
|
|
11626
|
+
resetAllOpenFenceScans();
|
|
11526
11627
|
}
|
|
11527
11628
|
function resolveStreamingMarkdownParts(text, streamKey) {
|
|
11528
11629
|
const t = streamingLayoutText(text);
|
|
@@ -11534,34 +11635,39 @@ function resolveStreamingMarkdownParts(text, streamKey) {
|
|
|
11534
11635
|
return cacheResolvedPartsKey(key, t, {
|
|
11535
11636
|
plain: true,
|
|
11536
11637
|
stablePrefix: "",
|
|
11638
|
+
stableChunks: [],
|
|
11537
11639
|
unstableSuffix: "",
|
|
11538
11640
|
unstableForRender: ""
|
|
11539
11641
|
});
|
|
11540
11642
|
}
|
|
11541
|
-
if (!
|
|
11643
|
+
if (!streamingHasMarkdownSyntax(t, key)) {
|
|
11542
11644
|
if (key) stablePrefixByStreamKey.delete(key);
|
|
11543
11645
|
return cacheResolvedPartsKey(key, t, {
|
|
11544
11646
|
plain: true,
|
|
11545
11647
|
stablePrefix: "",
|
|
11648
|
+
stableChunks: [],
|
|
11546
11649
|
unstableSuffix: t,
|
|
11547
11650
|
unstableForRender: t
|
|
11548
11651
|
});
|
|
11549
11652
|
}
|
|
11550
|
-
let
|
|
11551
|
-
if (!t.startsWith(
|
|
11552
|
-
|
|
11653
|
+
let stableState = key ? getStablePrefixKey(key) : { text: "", chunks: [] };
|
|
11654
|
+
if (!t.startsWith(stableState.text)) {
|
|
11655
|
+
stableState = { text: "", chunks: [] };
|
|
11553
11656
|
}
|
|
11554
|
-
|
|
11657
|
+
let stablePrefix = stableState.text;
|
|
11658
|
+
const open = findOpenFenceStart(t, key);
|
|
11555
11659
|
if (open) {
|
|
11556
11660
|
let openPrefix = t.substring(0, open.index);
|
|
11557
11661
|
if (isWhitespaceOnlyText(openPrefix)) openPrefix = "";
|
|
11558
|
-
|
|
11662
|
+
stableState = stableStateForText(openPrefix, stableState);
|
|
11663
|
+
if (key && openPrefix) touchStablePrefixKey(key, stableState);
|
|
11559
11664
|
else if (key) stablePrefixByStreamKey.delete(key);
|
|
11560
11665
|
const unstableSuffix2 = t.substring(openPrefix.length);
|
|
11561
11666
|
return cacheResolvedPartsKey(key, t, {
|
|
11562
11667
|
plain: false,
|
|
11563
11668
|
openFence: true,
|
|
11564
11669
|
stablePrefix: openPrefix,
|
|
11670
|
+
stableChunks: stableState.chunks,
|
|
11565
11671
|
unstableSuffix: unstableSuffix2,
|
|
11566
11672
|
unstableForRender: unstableSuffix2
|
|
11567
11673
|
});
|
|
@@ -11584,18 +11690,24 @@ function resolveStreamingMarkdownParts(text, streamKey) {
|
|
|
11584
11690
|
if (advance > 0) {
|
|
11585
11691
|
stablePrefix = t.substring(0, boundary + advance);
|
|
11586
11692
|
if (isWhitespaceOnlyText(stablePrefix)) stablePrefix = "";
|
|
11587
|
-
|
|
11693
|
+
stableState = stableStateForText(stablePrefix, stableState);
|
|
11694
|
+
if (key && stablePrefix) touchStablePrefixKey(key, stableState);
|
|
11588
11695
|
else if (key && !stablePrefix) stablePrefixByStreamKey.delete(key);
|
|
11589
11696
|
}
|
|
11590
11697
|
} catch {
|
|
11591
11698
|
stablePrefix = "";
|
|
11699
|
+
stableState = { text: "", chunks: [] };
|
|
11592
11700
|
if (key) stablePrefixByStreamKey.delete(key);
|
|
11593
11701
|
}
|
|
11594
|
-
if (isWhitespaceOnlyText(stablePrefix))
|
|
11702
|
+
if (isWhitespaceOnlyText(stablePrefix)) {
|
|
11703
|
+
stablePrefix = "";
|
|
11704
|
+
stableState = { text: "", chunks: [] };
|
|
11705
|
+
}
|
|
11595
11706
|
const unstableSuffix = t.substring(stablePrefix.length);
|
|
11596
11707
|
return cacheResolvedPartsKey(key, t, {
|
|
11597
11708
|
plain: false,
|
|
11598
11709
|
stablePrefix,
|
|
11710
|
+
stableChunks: stableState.chunks,
|
|
11599
11711
|
unstableSuffix,
|
|
11600
11712
|
unstableForRender: balanceStreamingMarkdown(unstableSuffix)
|
|
11601
11713
|
});
|
|
@@ -11721,22 +11833,31 @@ function measureStreamingMarkdownRenderedRows(text, columns, streamKey) {
|
|
|
11721
11833
|
let rows = 0;
|
|
11722
11834
|
let childCount = 0;
|
|
11723
11835
|
let stableRows = 0;
|
|
11724
|
-
|
|
11725
|
-
|
|
11726
|
-
|
|
11727
|
-
|
|
11728
|
-
|
|
11836
|
+
const stableChunks = parts.stableChunks?.length ? parts.stableChunks : parts.stablePrefix ? [parts.stablePrefix] : [];
|
|
11837
|
+
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]);
|
|
11838
|
+
let measuredStableChunks = 0;
|
|
11839
|
+
if (reusableChunks) {
|
|
11840
|
+
stableRows = cached.stableRows;
|
|
11841
|
+
measuredStableChunks = cached.stableChunks.length;
|
|
11842
|
+
}
|
|
11843
|
+
for (let index = measuredStableChunks; index < stableChunks.length; index += 1) {
|
|
11844
|
+
if (index > 0) stableRows += 1;
|
|
11845
|
+
stableRows += measureMarkdownRenderedRows(stableChunks[index], columns, { trimPartialFences: false });
|
|
11846
|
+
}
|
|
11847
|
+
rows += stableRows;
|
|
11848
|
+
childCount = stableChunks.length;
|
|
11729
11849
|
if (parts.unstableSuffix) {
|
|
11850
|
+
if (childCount > 0) rows += 1;
|
|
11730
11851
|
rows += measureMarkdownRenderedRows(parts.unstableForRender, columns, { trimPartialFences: true });
|
|
11731
11852
|
childCount += 1;
|
|
11732
11853
|
}
|
|
11733
|
-
if (childCount === 2) rows += 1;
|
|
11734
11854
|
const measuredRows = childCount === 0 ? 1 : Math.max(1, rows);
|
|
11735
11855
|
cacheStreamingRows(key, {
|
|
11736
11856
|
text: value,
|
|
11737
11857
|
columns,
|
|
11738
11858
|
mode: "markdown",
|
|
11739
11859
|
stablePrefix: parts.stablePrefix,
|
|
11860
|
+
stableChunks: stableChunks.slice(),
|
|
11740
11861
|
stableRows,
|
|
11741
11862
|
rows: measuredRows
|
|
11742
11863
|
});
|
|
@@ -12818,6 +12939,9 @@ function cacheStreamingTailEstimate(id, entry) {
|
|
|
12818
12939
|
function hasStreamingRowStateToPrune() {
|
|
12819
12940
|
return streamingMeasuredRowsById.size > 0 || streamingEstimateHighWaterById.size > 0 || streamingTailEstimateById.size > 0;
|
|
12820
12941
|
}
|
|
12942
|
+
function transcriptHarvestInputsEqual(left, right) {
|
|
12943
|
+
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;
|
|
12944
|
+
}
|
|
12821
12945
|
function pruneStreamingMeasuredRowsById(liveIds) {
|
|
12822
12946
|
if (!liveIds) return;
|
|
12823
12947
|
if (streamingMeasuredRowsById.size > 0) {
|
|
@@ -13632,13 +13756,30 @@ import { useCallback as useCallback3, useEffect as useEffect8, useRef as useRef8
|
|
|
13632
13756
|
// src/tui/engine/render-timing.mjs
|
|
13633
13757
|
var RENDER_ACK_HANG_GUARD_MS = 250;
|
|
13634
13758
|
var RENDER_SETTLE_IDLE_MS = 64;
|
|
13759
|
+
var TUI_RENDER_FPS = 60;
|
|
13760
|
+
var TUI_FRAME_MS = Math.ceil(1e3 / TUI_RENDER_FPS);
|
|
13635
13761
|
var pendingRenderAcks = [];
|
|
13636
13762
|
var renderAckSeq = 0;
|
|
13763
|
+
var lastRenderFrameAt = 0;
|
|
13764
|
+
var renderFrameDelay = (lastFrameAt, currentTime, frameMs = TUI_FRAME_MS) => {
|
|
13765
|
+
if (!(lastFrameAt > 0)) return frameMs;
|
|
13766
|
+
return Math.max(0, frameMs - Math.max(0, currentTime - lastFrameAt));
|
|
13767
|
+
};
|
|
13768
|
+
var scheduleRenderAlignedStoreFlush = (callback, frameMs = TUI_FRAME_MS) => {
|
|
13769
|
+
const timer2 = setTimeout(
|
|
13770
|
+
callback,
|
|
13771
|
+
renderFrameDelay(lastRenderFrameAt, performance.now(), frameMs)
|
|
13772
|
+
);
|
|
13773
|
+
timer2.unref?.();
|
|
13774
|
+
return timer2;
|
|
13775
|
+
};
|
|
13776
|
+
var cancelRenderAlignedStoreFlush = (timer2) => clearTimeout(timer2);
|
|
13637
13777
|
var scheduleRenderFrameAck = () => {
|
|
13638
13778
|
const seq = ++renderAckSeq;
|
|
13639
13779
|
setImmediate(() => notifyRenderFrame(seq));
|
|
13640
13780
|
};
|
|
13641
13781
|
var notifyRenderFrame = (seq = ++renderAckSeq) => {
|
|
13782
|
+
lastRenderFrameAt = performance.now();
|
|
13642
13783
|
if (pendingRenderAcks.length === 0) return;
|
|
13643
13784
|
const acks = pendingRenderAcks;
|
|
13644
13785
|
pendingRenderAcks = [];
|
|
@@ -14285,6 +14426,11 @@ function useTranscriptWindow({
|
|
|
14285
14426
|
const prevViewportGeomRef = useRef9({ contentHeight: 0, floatingPanelRows: 0 });
|
|
14286
14427
|
const transcriptItemElsRef = useRef9(/* @__PURE__ */ new Map());
|
|
14287
14428
|
const transcriptMeasureRefCache = useRef9(/* @__PURE__ */ new Map());
|
|
14429
|
+
const harvestGateRef = useRef9({
|
|
14430
|
+
inputs: null,
|
|
14431
|
+
skippedForDrag: false,
|
|
14432
|
+
forceNext: false
|
|
14433
|
+
});
|
|
14288
14434
|
const transcriptMeasureItemsRef = useRef9(/* @__PURE__ */ new Map());
|
|
14289
14435
|
const transcriptMeasureRef = useCallback4((item) => {
|
|
14290
14436
|
if (!TRANSCRIPT_MEASURED_ROWS || !item || item.id == null) return void 0;
|
|
@@ -14516,11 +14662,33 @@ function useTranscriptWindow({
|
|
|
14516
14662
|
const transcriptTailPinned = Math.max(0, Number(transcriptWindow.effectiveScrollOffset) || 0) === 0;
|
|
14517
14663
|
const overlayHintOnLastItem = overlayHintRequested && floatingPanelRows <= 0 && transcriptWindow.bottomSpacerRows === 0 && transcriptTailPinned && overlayHintAttachItemIndex >= 0;
|
|
14518
14664
|
const overlayHintFallbackRow = overlayHintRequested && floatingPanelRows <= 0 && transcriptGuardRows > 0 && !overlayHintOnLastItem;
|
|
14665
|
+
const harvestInputs = {
|
|
14666
|
+
revision,
|
|
14667
|
+
settledItems,
|
|
14668
|
+
streamingTailItem,
|
|
14669
|
+
startIndex: transcriptWindow.startIndex,
|
|
14670
|
+
endIndex: transcriptWindow.endIndex,
|
|
14671
|
+
frameColumns,
|
|
14672
|
+
toolOutputExpanded,
|
|
14673
|
+
transcriptContentHeight,
|
|
14674
|
+
floatingPanelRows,
|
|
14675
|
+
overlayHintRequested,
|
|
14676
|
+
transcriptGuardRows,
|
|
14677
|
+
themeEpoch
|
|
14678
|
+
};
|
|
14519
14679
|
useLayoutEffect3(() => {
|
|
14520
14680
|
if (!TRANSCRIPT_MEASURED_ROWS) return;
|
|
14521
|
-
|
|
14681
|
+
const gate = harvestGateRef.current;
|
|
14682
|
+
if (dragRef.current.active) {
|
|
14683
|
+
gate.skippedForDrag = true;
|
|
14684
|
+
return;
|
|
14685
|
+
}
|
|
14686
|
+
if (!gate.skippedForDrag && !gate.forceNext && transcriptHarvestInputsEqual(gate.inputs, harvestInputs)) return;
|
|
14522
14687
|
const els = transcriptItemElsRef.current;
|
|
14523
14688
|
if (!els || els.size === 0) return;
|
|
14689
|
+
gate.inputs = harvestInputs;
|
|
14690
|
+
gate.skippedForDrag = false;
|
|
14691
|
+
gate.forceNext = false;
|
|
14524
14692
|
const liveItems = transcriptMeasureItemsRef.current;
|
|
14525
14693
|
const toolExpandedFlag = toolOutputExpanded ? 1 : 0;
|
|
14526
14694
|
let changed = false;
|
|
@@ -14595,6 +14763,7 @@ function useTranscriptWindow({
|
|
|
14595
14763
|
}, 0);
|
|
14596
14764
|
if (typeof streak.timer?.unref === "function") streak.timer.unref();
|
|
14597
14765
|
}
|
|
14766
|
+
gate.forceNext = true;
|
|
14598
14767
|
setMeasuredRowsVersion((v) => (v + 1) % 1e6);
|
|
14599
14768
|
}
|
|
14600
14769
|
}
|
|
@@ -17227,46 +17396,26 @@ function createChannelPickers({
|
|
|
17227
17396
|
}
|
|
17228
17397
|
if (focus === "webhook-endpoint") {
|
|
17229
17398
|
const returnTo = typeof options.returnTo === "function" ? options.returnTo : () => setPicker(null);
|
|
17230
|
-
const
|
|
17399
|
+
const publicUrl = setup.webhook?.publicUrl || "";
|
|
17231
17400
|
const items2 = [
|
|
17232
17401
|
{
|
|
17233
|
-
value: "endpoint-
|
|
17234
|
-
label: "
|
|
17235
|
-
description:
|
|
17236
|
-
_action: "endpoint-
|
|
17237
|
-
},
|
|
17238
|
-
{
|
|
17239
|
-
value: "endpoint-authtoken",
|
|
17240
|
-
label: "authtoken",
|
|
17241
|
-
description: setup.webhook?.authenticated === true ? "Set" : "Not set \xB7 Enter authtoken",
|
|
17242
|
-
_action: "endpoint-authtoken"
|
|
17402
|
+
value: "endpoint-url",
|
|
17403
|
+
label: "Public URL",
|
|
17404
|
+
description: publicUrl ? `${publicUrl}/webhook/<name>` : "Assigned when the channel worker connects to the relay",
|
|
17405
|
+
_action: "endpoint-url"
|
|
17243
17406
|
}
|
|
17244
17407
|
];
|
|
17245
17408
|
setPicker({
|
|
17246
17409
|
title: "Webhook endpoint",
|
|
17247
|
-
description: "
|
|
17410
|
+
description: "Served through the Mixdog relay \u2014 no tunnel setup needed. Toggle individual webhooks in /webhooks.",
|
|
17248
17411
|
help: "\u2191/\u2193 Select \xB7 Enter Edit \xB7 Esc Back",
|
|
17249
17412
|
indexMode: "always",
|
|
17250
17413
|
labelWidth: 18,
|
|
17251
17414
|
items: items2,
|
|
17252
17415
|
onSelect: (_value, item) => {
|
|
17253
17416
|
try {
|
|
17254
|
-
if (item._action === "endpoint-
|
|
17255
|
-
|
|
17256
|
-
kind: "webhook-domain",
|
|
17257
|
-
label: "ngrok domain",
|
|
17258
|
-
hint: "Paste the reserved ngrok domain (e.g. my-app.ngrok-free.app).",
|
|
17259
|
-
afterSave: () => void openChannelSetupPicker("webhook-endpoint", options)
|
|
17260
|
-
});
|
|
17261
|
-
return;
|
|
17262
|
-
}
|
|
17263
|
-
if (item._action === "endpoint-authtoken") {
|
|
17264
|
-
openChannelPrompt({
|
|
17265
|
-
kind: "webhook-token",
|
|
17266
|
-
label: "Webhook/ngrok authtoken",
|
|
17267
|
-
hint: "Paste the webhook/ngrok authtoken. It is stored in the OS keychain.",
|
|
17268
|
-
afterSave: () => void openChannelSetupPicker("webhook-endpoint", options)
|
|
17269
|
-
});
|
|
17417
|
+
if (item._action === "endpoint-url") {
|
|
17418
|
+
store.pushNotice(publicUrl ? `Webhook base: ${publicUrl}/webhook/<name>` : "URL not assigned yet \u2014 start channels once and reopen.", "info");
|
|
17270
17419
|
}
|
|
17271
17420
|
} catch (e) {
|
|
17272
17421
|
store.pushNotice(`webhook endpoint failed: ${e?.message || e}`, "error");
|
|
@@ -17401,20 +17550,10 @@ function createChannelPickers({
|
|
|
17401
17550
|
{
|
|
17402
17551
|
value: "webhook-endpoint",
|
|
17403
17552
|
label: "Webhook endpoint",
|
|
17404
|
-
|
|
17405
|
-
|
|
17406
|
-
|
|
17407
|
-
|
|
17408
|
-
})(),
|
|
17409
|
-
description: (() => {
|
|
17410
|
-
const hasDomain = Boolean(setup.webhook?.ngrokDomain || setup.webhook?.domain);
|
|
17411
|
-
const hasAuth = setup.webhook?.authenticated === true;
|
|
17412
|
-
const needs = [
|
|
17413
|
-
...hasDomain ? [] : ["domain"],
|
|
17414
|
-
...hasAuth ? [] : ["authtoken"]
|
|
17415
|
-
];
|
|
17416
|
-
return needs.length ? `Needs ${needs.join(" + ")}` : "ngrok domain and authtoken set";
|
|
17417
|
-
})(),
|
|
17553
|
+
// Relay tunnel: public exposure is automatic, so the endpoint is
|
|
17554
|
+
// "On" whenever the webhook server itself is enabled.
|
|
17555
|
+
meta: setup.webhook?.enabled === false ? "Off" : "On",
|
|
17556
|
+
description: setup.webhook?.publicUrl ? setup.webhook.publicUrl : "Mixdog relay tunnel \u2014 URL assigned on first run",
|
|
17418
17557
|
_action: "webhook-endpoint"
|
|
17419
17558
|
}
|
|
17420
17559
|
];
|
|
@@ -20156,13 +20295,29 @@ function Markdown({ children, themeEpoch = 0, trimPartialFences = false, columns
|
|
|
20156
20295
|
}, [children, themeEpoch, trimPartialFences, columns]);
|
|
20157
20296
|
return /* @__PURE__ */ jsx13(Box11, { flexDirection: "column", gap: 1, children: elements });
|
|
20158
20297
|
}
|
|
20298
|
+
var StableMarkdownChunk = React13.memo(function StableMarkdownChunk2({
|
|
20299
|
+
text,
|
|
20300
|
+
themeEpoch,
|
|
20301
|
+
columns
|
|
20302
|
+
}) {
|
|
20303
|
+
return /* @__PURE__ */ jsx13(Markdown, { themeEpoch, columns, children: text });
|
|
20304
|
+
});
|
|
20159
20305
|
function StreamingMarkdown({ children, themeEpoch = 0, columns, streamKey }) {
|
|
20160
20306
|
const parts = resolveStreamingMarkdownParts(children, streamKey);
|
|
20161
20307
|
if (parts.plain) {
|
|
20162
20308
|
return /* @__PURE__ */ jsx13(Text13, { color: theme.text, wrap: "wrap", children: parts.unstableForRender });
|
|
20163
20309
|
}
|
|
20310
|
+
const stableChunks = parts.stableChunks?.length ? parts.stableChunks : parts.stablePrefix ? [parts.stablePrefix] : [];
|
|
20164
20311
|
return /* @__PURE__ */ jsxs9(Box11, { flexDirection: "column", gap: 1, children: [
|
|
20165
|
-
|
|
20312
|
+
stableChunks.map((text, index) => /* @__PURE__ */ jsx13(
|
|
20313
|
+
StableMarkdownChunk,
|
|
20314
|
+
{
|
|
20315
|
+
text,
|
|
20316
|
+
themeEpoch,
|
|
20317
|
+
columns
|
|
20318
|
+
},
|
|
20319
|
+
`stable-${index}`
|
|
20320
|
+
)),
|
|
20166
20321
|
parts.unstableSuffix ? /* @__PURE__ */ jsx13(Markdown, { themeEpoch, columns, trimPartialFences: true, children: parts.unstableForRender }) : null
|
|
20167
20322
|
] });
|
|
20168
20323
|
}
|
|
@@ -20181,7 +20336,7 @@ var AssistantMessage = React14.memo(function AssistantMessage2({
|
|
|
20181
20336
|
if (!streaming && assistantId) resetStreamingMarkdownStablePrefix(assistantId);
|
|
20182
20337
|
}, [streaming, assistantId]);
|
|
20183
20338
|
const bodyWidth = assistantBodyWidth(columns);
|
|
20184
|
-
const renderText = streaming && streamingWindowRows > 0 ? windowPlainStreamingText(text, bodyWidth, streamingWindowRows) : text;
|
|
20339
|
+
const renderText = streaming && streamingWindowRows > 0 ? windowPlainStreamingText(text, bodyWidth, streamingWindowRows, assistantId) : text;
|
|
20185
20340
|
return /* @__PURE__ */ jsxs10(Box12, { flexDirection: "row", marginTop: 1, children: [
|
|
20186
20341
|
/* @__PURE__ */ jsx14(Box12, { flexShrink: 0, minWidth: 2, children: /* @__PURE__ */ jsx14(Text14, { color: theme.text, children: TURN_MARKER }) }),
|
|
20187
20342
|
/* @__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 }) })
|
|
@@ -20210,7 +20365,7 @@ import React16 from "react";
|
|
|
20210
20365
|
import { Box as Box14, Text as Text16 } from "../../../vendor/ink/build/index.js";
|
|
20211
20366
|
import stringWidth9 from "string-width";
|
|
20212
20367
|
|
|
20213
|
-
// src/
|
|
20368
|
+
// src/runtime/shared/tool-card-model.mjs
|
|
20214
20369
|
import stripAnsi6 from "strip-ansi";
|
|
20215
20370
|
|
|
20216
20371
|
// src/runtime/shared/tool-status.mjs
|
|
@@ -20234,7 +20389,7 @@ function toolResultTerminalStatus(text) {
|
|
|
20234
20389
|
return normalizeToolTerminalStatus(inline);
|
|
20235
20390
|
}
|
|
20236
20391
|
|
|
20237
|
-
// src/
|
|
20392
|
+
// src/runtime/shared/tool-card-model.mjs
|
|
20238
20393
|
var MIN_RESULT_LINE_CHARS = 24;
|
|
20239
20394
|
var RESULT_LINE_HARD_MAX = 80;
|
|
20240
20395
|
var SUMMARY_MAX_CHARS = 48;
|
|
@@ -20258,47 +20413,9 @@ function normalizeCountMap(value = {}) {
|
|
|
20258
20413
|
}
|
|
20259
20414
|
return out;
|
|
20260
20415
|
}
|
|
20261
|
-
function deltaColor(token) {
|
|
20262
|
-
return String(token || "").startsWith("+") ? theme.success : theme.error;
|
|
20263
|
-
}
|
|
20264
|
-
function deltaTextParts(text) {
|
|
20265
|
-
const value = String(text ?? "");
|
|
20266
|
-
const parts = [];
|
|
20267
|
-
const re = /(^|[\s([,{·])([+-]\s*\d+)(?=\s+Lines?\b)/gi;
|
|
20268
|
-
let last = 0;
|
|
20269
|
-
let match;
|
|
20270
|
-
while (match = re.exec(value)) {
|
|
20271
|
-
const prefix = match[1] || "";
|
|
20272
|
-
const token = (match[2] || "").replace(/\s+/g, "");
|
|
20273
|
-
const tokenStart = match.index + prefix.length;
|
|
20274
|
-
if (match.index > last) parts.push({ text: value.slice(last, match.index) });
|
|
20275
|
-
if (prefix) parts.push({ text: prefix });
|
|
20276
|
-
if (token) parts.push({ text: token, color: deltaColor(token) });
|
|
20277
|
-
last = tokenStart + (match[2] || "").length;
|
|
20278
|
-
}
|
|
20279
|
-
if (last < value.length) parts.push({ text: value.slice(last) });
|
|
20280
|
-
return parts;
|
|
20281
|
-
}
|
|
20282
20416
|
function plural(count, singular, pluralText = `${singular}s`) {
|
|
20283
20417
|
return count === 1 ? singular : pluralText;
|
|
20284
20418
|
}
|
|
20285
|
-
function fitResultLine(line, columns) {
|
|
20286
|
-
const max = Math.min(RESULT_LINE_HARD_MAX, Math.max(MIN_RESULT_LINE_CHARS, Number(columns || 80) - 7));
|
|
20287
|
-
const text = safeInlineText(line);
|
|
20288
|
-
return displayWidth(text) > max ? truncateToWidth(text, max) : text;
|
|
20289
|
-
}
|
|
20290
|
-
function truncateToWidth(text, maxWidth) {
|
|
20291
|
-
const str = safeInlineText(text);
|
|
20292
|
-
if (maxWidth < 1) return "";
|
|
20293
|
-
if (displayWidth(str) <= maxWidth) return str;
|
|
20294
|
-
const chars = Array.from(str);
|
|
20295
|
-
let out = "";
|
|
20296
|
-
for (const ch of chars) {
|
|
20297
|
-
if (displayWidth(out + ch + "\u2026") > maxWidth) break;
|
|
20298
|
-
out += ch;
|
|
20299
|
-
}
|
|
20300
|
-
return `${out}\u2026`;
|
|
20301
|
-
}
|
|
20302
20419
|
function shellResultStatus(value) {
|
|
20303
20420
|
const match = String(value || "").match(/(?:^|\b)status:\s*(running|pending|queued|completed|failed|cancelled|canceled)\b/im);
|
|
20304
20421
|
return match ? String(match[1] || "").toLowerCase() : "";
|
|
@@ -20334,8 +20451,6 @@ function shellResultElapsed(value) {
|
|
|
20334
20451
|
const elapsedMs = Number(match[1]);
|
|
20335
20452
|
return Number.isFinite(elapsedMs) && elapsedMs >= 1e3 ? formatElapsed(elapsedMs) : "";
|
|
20336
20453
|
}
|
|
20337
|
-
|
|
20338
|
-
// src/tui/components/tool-execution/surface-detail.mjs
|
|
20339
20454
|
function isShellTool(normalizedName, label = "") {
|
|
20340
20455
|
const n = String(normalizedName || "").toLowerCase();
|
|
20341
20456
|
const l = String(label || "").toLowerCase();
|
|
@@ -20667,6 +20782,248 @@ function clampFailureCount(errorCount, groupCount, isError) {
|
|
|
20667
20782
|
if (Number.isFinite(explicit)) return Math.max(0, Math.min(groupCount, Math.floor(explicit)));
|
|
20668
20783
|
return isError ? groupCount : 0;
|
|
20669
20784
|
}
|
|
20785
|
+
function clipPlain(text, maxChars) {
|
|
20786
|
+
const value = safeInlineText(text);
|
|
20787
|
+
const max = Math.max(1, Number(maxChars) || 1);
|
|
20788
|
+
if (value.length <= max) return value;
|
|
20789
|
+
return `${value.slice(0, Math.max(0, max - 1))}\u2026`;
|
|
20790
|
+
}
|
|
20791
|
+
function deriveToolCardModel(input = {}, options = {}) {
|
|
20792
|
+
const {
|
|
20793
|
+
name = "",
|
|
20794
|
+
args = {},
|
|
20795
|
+
result = null,
|
|
20796
|
+
rawResult = null,
|
|
20797
|
+
isError = false,
|
|
20798
|
+
errorCount,
|
|
20799
|
+
callErrorCount,
|
|
20800
|
+
exitErrorCount,
|
|
20801
|
+
count = 1,
|
|
20802
|
+
completedCount,
|
|
20803
|
+
startedAt = 0,
|
|
20804
|
+
completedAt = 0,
|
|
20805
|
+
aggregate = false,
|
|
20806
|
+
categories = {},
|
|
20807
|
+
doneCategories = null,
|
|
20808
|
+
headerFinalized = true
|
|
20809
|
+
} = input;
|
|
20810
|
+
const nowMs = Number(input.nowMs || Date.now());
|
|
20811
|
+
const truncate2 = typeof options.truncate === "function" ? options.truncate : clipPlain;
|
|
20812
|
+
const maxResultChars = Math.max(
|
|
20813
|
+
MIN_RESULT_LINE_CHARS,
|
|
20814
|
+
Math.min(RESULT_LINE_HARD_MAX, Number(options.maxResultChars ?? RESULT_LINE_HARD_MAX))
|
|
20815
|
+
);
|
|
20816
|
+
const groupCount = Math.max(1, Number(count || 1));
|
|
20817
|
+
const doneCount = Math.max(0, Math.min(groupCount, Number(completedCount ?? (result == null ? 0 : groupCount))));
|
|
20818
|
+
const rt = result == null ? null : String(result).replace(/\s+$/, "");
|
|
20819
|
+
const rawRt = rawResult == null ? null : String(rawResult).replace(/\s+$/, "");
|
|
20820
|
+
const pending = doneCount < groupCount;
|
|
20821
|
+
const headerPending = pending || headerFinalized === false;
|
|
20822
|
+
const hasResult = result != null && Boolean(String(rt || "").trim());
|
|
20823
|
+
const hasRawResult = rawResult != null && Boolean(String(rawRt || "").trim());
|
|
20824
|
+
const startedAtMs = Number(startedAt || 0);
|
|
20825
|
+
const completedAtMs = Number(completedAt || 0);
|
|
20826
|
+
const elapsedMs = startedAtMs ? Math.max(0, (pending ? nowMs : completedAtMs || nowMs) - startedAtMs) : 0;
|
|
20827
|
+
const elapsed = elapsedMs >= 1e3 ? formatElapsed(elapsedMs) : "";
|
|
20828
|
+
const failedCount = clampFailureCount(errorCount, groupCount, isError);
|
|
20829
|
+
const callFailedCount = clampFailureCount(callErrorCount, groupCount, false);
|
|
20830
|
+
const exitFailedCount = clampFailureCount(exitErrorCount, groupCount, false);
|
|
20831
|
+
if (aggregate) {
|
|
20832
|
+
const displayCategories = normalizeCountMap(categories || {});
|
|
20833
|
+
const normalizedDone = doneCategories ? normalizeCountMap(doneCategories) : displayCategories;
|
|
20834
|
+
const hasDoneCounts = Object.values(normalizedDone || {}).some(
|
|
20835
|
+
(v) => (v && typeof v === "object" ? Number(v.count || 0) : Number(v || 0)) > 0
|
|
20836
|
+
);
|
|
20837
|
+
const displayDone = hasDoneCounts ? normalizedDone : displayCategories;
|
|
20838
|
+
const headerOrder = Array.isArray(args?.categoryOrder) ? args.categoryOrder : null;
|
|
20839
|
+
const labelText2 = safeInlineText(formatAggregateHeader(
|
|
20840
|
+
(headerPending ? displayCategories : displayDone) || {},
|
|
20841
|
+
{ pending: headerPending, order: headerOrder }
|
|
20842
|
+
));
|
|
20843
|
+
const detailText = hasResult ? safeInlineText(rt) : "";
|
|
20844
|
+
const terminalStatus2 = pending ? "running" : resultTerminalStatus(rt) || (isError || failedCount > 0 ? "failed" : "completed");
|
|
20845
|
+
return {
|
|
20846
|
+
aggregate: true,
|
|
20847
|
+
pending,
|
|
20848
|
+
headerPending,
|
|
20849
|
+
groupCount,
|
|
20850
|
+
doneCount,
|
|
20851
|
+
elapsed,
|
|
20852
|
+
failedCount,
|
|
20853
|
+
callFailedCount,
|
|
20854
|
+
exitFailedCount,
|
|
20855
|
+
terminalStatus: terminalStatus2,
|
|
20856
|
+
labelText: labelText2,
|
|
20857
|
+
summaryText: "",
|
|
20858
|
+
headerFailureText: "",
|
|
20859
|
+
detailLine: detailText || (pending ? "Running" : "Finished"),
|
|
20860
|
+
detailIsPlaceholder: !detailText,
|
|
20861
|
+
hasResult,
|
|
20862
|
+
hasRawResult,
|
|
20863
|
+
displayedResultBodyText: rt || "",
|
|
20864
|
+
firstResultLine: detailText,
|
|
20865
|
+
totalLines: detailText ? 1 : 0,
|
|
20866
|
+
resultSummary: detailText || null,
|
|
20867
|
+
toolArgPath: "",
|
|
20868
|
+
normalizedName: "",
|
|
20869
|
+
label: "",
|
|
20870
|
+
parsedArgs: args,
|
|
20871
|
+
isShellSurface: false,
|
|
20872
|
+
isSkillSurface: false,
|
|
20873
|
+
isAgentSurfaceCard: false,
|
|
20874
|
+
isAgentResponse: false,
|
|
20875
|
+
isBackgroundResponse: false,
|
|
20876
|
+
isBackgroundMetadataResult: false,
|
|
20877
|
+
backgroundMeta: null
|
|
20878
|
+
};
|
|
20879
|
+
}
|
|
20880
|
+
const { label, summary, normalizedName, args: parsedArgs } = formatToolSurface(name, args);
|
|
20881
|
+
const isShellSurface = isShellTool(normalizedName, label);
|
|
20882
|
+
const isSkillSurface = SKILL_SURFACE_NAMES2.has(String(normalizedName || "").toLowerCase());
|
|
20883
|
+
const backgroundMeta = !pending && isBackgroundTaskTool(normalizedName) ? resolveBackgroundTaskMeta(parsedArgs, rt || "") : null;
|
|
20884
|
+
const backgroundError = backgroundMeta?.error || parsedArgs?.error || "";
|
|
20885
|
+
const errorOnlyResult = Boolean(rt) && isBackgroundErrorOnlyBody(rt, backgroundError);
|
|
20886
|
+
const backgroundResultText = backgroundMeta?.hasResponse ? backgroundMeta.body : "";
|
|
20887
|
+
const displayedResultText = backgroundResultText || (errorOnlyResult ? "" : rt || "");
|
|
20888
|
+
const hasDisplayResult = Boolean(String(displayedResultText || "").trim());
|
|
20889
|
+
const displayedResultBodyText = stripLeadingStatusMarkerFromText(displayedResultText);
|
|
20890
|
+
const hasDisplayBody = Boolean(String(displayedResultBodyText || "").trim());
|
|
20891
|
+
const lines = displayedResultBodyText ? displayedResultBodyText.split("\n") : [];
|
|
20892
|
+
const totalLines = lines.length;
|
|
20893
|
+
const resultSummary = !pending && hasDisplayBody ? summarizeToolResult(name, args, displayedResultBodyText, isError) : null;
|
|
20894
|
+
const firstResultLine = hasDisplayResult ? String(lines[0] ?? "") : "";
|
|
20895
|
+
const shellStatus = isShellSurface ? shellDisplayStatus({ pending, failedCount, exitFailedCount, isError, result: displayedResultText }) : "";
|
|
20896
|
+
const shellElapsed = isShellSurface ? shellResultElapsed(displayedResultText) || elapsed : "";
|
|
20897
|
+
const backgroundElapsed = backgroundMeta ? backgroundTaskElapsed(backgroundMeta, elapsed) : isBackgroundTaskTool(normalizedName) ? backgroundTaskElapsed(parsedArgs, elapsed) : "";
|
|
20898
|
+
const toolArgPath = parsedArgs?.path ?? parsedArgs?.file_path ?? parsedArgs?.file ?? "";
|
|
20899
|
+
const imageDetail = normalizedName === "view_image" && toolArgPath && !isError ? String(toolArgPath) : "";
|
|
20900
|
+
const isBackgroundResult = !pending && isBackgroundTaskTool(normalizedName) && Boolean(backgroundMeta);
|
|
20901
|
+
const isBackgroundResponse = isBackgroundResult && (backgroundMeta?.hasResponse || isBackgroundTaskResponseArgs(normalizedName, parsedArgs));
|
|
20902
|
+
const isBackgroundMetadataResult = isBackgroundResult && !isBackgroundResponse && Boolean(backgroundMeta);
|
|
20903
|
+
const backgroundMetadataFailureLabel = isBackgroundMetadataResult ? backgroundTaskFailureDetail(backgroundMeta, parsedArgs) : "";
|
|
20904
|
+
const backgroundMetadataHeaderFailure = Boolean(backgroundMetadataFailureLabel) && !hasDisplayResult ? backgroundMetadataFailureLabel : "";
|
|
20905
|
+
const agentHeaderFailure = !pending && isAgentTool(normalizedName) && isError && parsedArgs?.error && !hasDisplayResult ? backgroundTaskFailureStatusLabel(parsedArgs?.status, parsedArgs?.error, { surface: "agent" }) : "";
|
|
20906
|
+
const headerFailureText = backgroundMetadataHeaderFailure || agentHeaderFailure || "";
|
|
20907
|
+
const agentCompletionDetail = !pending && isAgentTool(normalizedName) && !agentHeaderFailure ? agentTerminalDetail(parsedArgs?.status, isError, elapsed, parsedArgs?.error) : "";
|
|
20908
|
+
const agentDetail = !pending && isAgentTool(normalizedName) && !hasDisplayResult ? agentCompletionDetail : "";
|
|
20909
|
+
const genericDetail = !pending && !isShellSurface && !agentDetail && !imageDetail && !resultSummary ? genericCompletedDetail({ normalizedName, label, hasResult, firstResultLine, isError }) : "";
|
|
20910
|
+
const terminalStatus = pending ? "running" : shellStatus || normalizeTerminalStatus(backgroundMeta?.status) || normalizeTerminalStatus(parsedArgs?.status) || resultTerminalStatus(displayedResultText) || (isError || failedCount > 0 ? "failed" : "completed");
|
|
20911
|
+
const backgroundMetadataDetail = isBackgroundMetadataResult && !backgroundMetadataHeaderFailure ? backgroundTaskDetail(backgroundMeta, backgroundElapsed, parsedArgs) : "";
|
|
20912
|
+
const backgroundResponseDetail = isBackgroundResponse && resultSummary ? prefixElapsed(resultSummary, backgroundElapsed) : resultSummary;
|
|
20913
|
+
const syncElapsedDetail = !isBackgroundResponse && shouldPrefixSyncElapsed(normalizedName, label) ? prefixElapsed(backgroundResponseDetail, elapsed) : backgroundResponseDetail;
|
|
20914
|
+
const nonShellDetail = backgroundMetadataDetail || (/^(Cancelled|Failed|Finished)$/i.test(resultSummary || "") && agentCompletionDetail ? agentCompletionDetail : syncElapsedDetail) || agentDetail || imageDetail || genericDetail;
|
|
20915
|
+
const pendingDetailPlaceholder = pending && !isSkillSurface ? elapsed ? `Running \xB7 ${elapsed}` : "Running" : "";
|
|
20916
|
+
const shellCollapsedSummary = isShellSurface && !pending && hasDisplayResult ? resultSummary || truncate2(firstResultLine, Math.min(120, maxResultChars)) : resultSummary;
|
|
20917
|
+
const collapsedDetail = pending ? pendingDetailPlaceholder : isShellSurface ? prefixElapsed(mergeTerminalDetail(shellStatus, shellCollapsedSummary), shellElapsed) : mergeTerminalDetail(terminalStatus, nonShellDetail);
|
|
20918
|
+
const isAgentResult = !isBackgroundResult && !pending && isAgentTool(normalizedName) && hasDisplayResult;
|
|
20919
|
+
const isAgentResponse = isAgentResult && hasAgentResponseResult(rt);
|
|
20920
|
+
const isAgentSurfaceCard = isAgentTool(normalizedName);
|
|
20921
|
+
const agentSurfaceBriefRaw = isAgentSurfaceCard ? summarizeAgentSurfaceBrief(name, parsedArgs, displayedResultText || "", { isError, isResponse: isAgentResponse }) : "";
|
|
20922
|
+
const agentSurfaceBrief = agentSurfaceBriefRaw ? truncate2(agentSurfaceBriefRaw, Math.min(AGENT_SURFACE_BRIEF_MAX, maxResultChars)) : "";
|
|
20923
|
+
let detailLine = collapsedDetail;
|
|
20924
|
+
if (isSkillSurface) {
|
|
20925
|
+
detailLine = isError && collapsedDetail ? collapsedDetail : "";
|
|
20926
|
+
} else if (isBackgroundMetadataResult && backgroundMetadataHeaderFailure) {
|
|
20927
|
+
detailLine = "";
|
|
20928
|
+
} else if (isAgentSurfaceCard) {
|
|
20929
|
+
const agentDetailFallback = collapsedDetail || (pending ? pendingDetailPlaceholder || "Running" : "Finished");
|
|
20930
|
+
const agentDetailLine = agentSurfaceBrief || truncate2(String(agentDetailFallback), Math.min(AGENT_SURFACE_BRIEF_MAX, maxResultChars));
|
|
20931
|
+
const agentFailureText = /\b(Cancelled|Canceled|Failed)\b/i.test(agentSurfaceBrief || collapsedDetail || "");
|
|
20932
|
+
const keepAgentDetail = (isError || agentFailureText) && !(agentHeaderFailure && !agentSurfaceBrief);
|
|
20933
|
+
detailLine = keepAgentDetail ? agentDetailLine : "";
|
|
20934
|
+
}
|
|
20935
|
+
let labelText;
|
|
20936
|
+
if (isAgentResponse) labelText = agentResponseTitle(parsedArgs, groupCount);
|
|
20937
|
+
else if (isBackgroundResponse) labelText = backgroundTaskResultTitle(normalizedName, backgroundMeta || parsedArgs);
|
|
20938
|
+
else if (isBackgroundMetadataResult) labelText = backgroundTaskActionTitle(normalizedName, backgroundMeta);
|
|
20939
|
+
else if (isShellSurface) labelText = shellHeader(shellStatus, groupCount);
|
|
20940
|
+
else labelText = (isAgentTool(normalizedName) ? agentActionTitle(parsedArgs) : "") || formatToolActionHeader(name, args, { pending: headerPending, count: groupCount });
|
|
20941
|
+
labelText = safeInlineText(labelText);
|
|
20942
|
+
const toolSearchSummary = !pending && normalizedName === "load_tool" && hasResult ? toolSearchLoadedSummary(displayedResultText) : "";
|
|
20943
|
+
const rawSummaryText = safeInlineText(isAgentResponse || isBackgroundResponse ? "" : toolSearchSummary || (isAgentTool(normalizedName) ? agentActionSummary(parsedArgs, summary) : summary));
|
|
20944
|
+
const summaryIsHeaderCount = rawSummaryText && /^\d+\s+\S+$/.test(rawSummaryText) && labelText.endsWith(rawSummaryText);
|
|
20945
|
+
const summaryText = summaryIsHeaderCount ? "" : rawSummaryText;
|
|
20946
|
+
return {
|
|
20947
|
+
aggregate: false,
|
|
20948
|
+
pending,
|
|
20949
|
+
headerPending,
|
|
20950
|
+
groupCount,
|
|
20951
|
+
doneCount,
|
|
20952
|
+
elapsed,
|
|
20953
|
+
failedCount,
|
|
20954
|
+
callFailedCount,
|
|
20955
|
+
exitFailedCount,
|
|
20956
|
+
terminalStatus,
|
|
20957
|
+
labelText,
|
|
20958
|
+
summaryText,
|
|
20959
|
+
headerFailureText,
|
|
20960
|
+
detailLine,
|
|
20961
|
+
detailIsPlaceholder: Boolean(pendingDetailPlaceholder) && detailLine === pendingDetailPlaceholder,
|
|
20962
|
+
hasResult,
|
|
20963
|
+
hasRawResult,
|
|
20964
|
+
hasDisplayResult,
|
|
20965
|
+
hasDisplayBody,
|
|
20966
|
+
displayedResultBodyText,
|
|
20967
|
+
firstResultLine,
|
|
20968
|
+
totalLines,
|
|
20969
|
+
resultSummary,
|
|
20970
|
+
shellCollapsedSummary,
|
|
20971
|
+
agentSurfaceBrief,
|
|
20972
|
+
toolArgPath: String(toolArgPath || ""),
|
|
20973
|
+
normalizedName,
|
|
20974
|
+
label,
|
|
20975
|
+
parsedArgs,
|
|
20976
|
+
isShellSurface,
|
|
20977
|
+
isSkillSurface,
|
|
20978
|
+
isAgentSurfaceCard,
|
|
20979
|
+
isAgentResponse,
|
|
20980
|
+
isBackgroundResponse,
|
|
20981
|
+
isBackgroundMetadataResult,
|
|
20982
|
+
backgroundMeta
|
|
20983
|
+
};
|
|
20984
|
+
}
|
|
20985
|
+
|
|
20986
|
+
// src/tui/components/tool-execution/text-format.mjs
|
|
20987
|
+
function deltaColor(token) {
|
|
20988
|
+
return String(token || "").startsWith("+") ? theme.success : theme.error;
|
|
20989
|
+
}
|
|
20990
|
+
function deltaTextParts(text) {
|
|
20991
|
+
const value = String(text ?? "");
|
|
20992
|
+
const parts = [];
|
|
20993
|
+
const re = /(^|[\s([,{·])([+-]\s*\d+)(?=\s+Lines?\b)/gi;
|
|
20994
|
+
let last = 0;
|
|
20995
|
+
let match;
|
|
20996
|
+
while (match = re.exec(value)) {
|
|
20997
|
+
const prefix = match[1] || "";
|
|
20998
|
+
const token = (match[2] || "").replace(/\s+/g, "");
|
|
20999
|
+
const tokenStart = match.index + prefix.length;
|
|
21000
|
+
if (match.index > last) parts.push({ text: value.slice(last, match.index) });
|
|
21001
|
+
if (prefix) parts.push({ text: prefix });
|
|
21002
|
+
if (token) parts.push({ text: token, color: deltaColor(token) });
|
|
21003
|
+
last = tokenStart + (match[2] || "").length;
|
|
21004
|
+
}
|
|
21005
|
+
if (last < value.length) parts.push({ text: value.slice(last) });
|
|
21006
|
+
return parts;
|
|
21007
|
+
}
|
|
21008
|
+
function fitResultLine(line, columns) {
|
|
21009
|
+
const max = Math.min(RESULT_LINE_HARD_MAX, Math.max(MIN_RESULT_LINE_CHARS, Number(columns || 80) - 7));
|
|
21010
|
+
const text = safeInlineText(line);
|
|
21011
|
+
return displayWidth(text) > max ? truncateToWidth(text, max) : text;
|
|
21012
|
+
}
|
|
21013
|
+
function truncateToWidth(text, maxWidth) {
|
|
21014
|
+
const str = safeInlineText(text);
|
|
21015
|
+
if (maxWidth < 1) return "";
|
|
21016
|
+
if (displayWidth(str) <= maxWidth) return str;
|
|
21017
|
+
const chars = Array.from(str);
|
|
21018
|
+
let out = "";
|
|
21019
|
+
for (const ch of chars) {
|
|
21020
|
+
if (displayWidth(out + ch + "\u2026") > maxWidth) break;
|
|
21021
|
+
out += ch;
|
|
21022
|
+
}
|
|
21023
|
+
return `${out}\u2026`;
|
|
21024
|
+
}
|
|
21025
|
+
|
|
21026
|
+
// src/tui/components/tool-execution/surface-detail.mjs
|
|
20670
21027
|
function toolStatusColor({ pending, groupCount, callFailedCount = 0, exitFailedCount = 0, terminalStatus = "" }) {
|
|
20671
21028
|
if (pending) return theme.text;
|
|
20672
21029
|
const status = normalizeTerminalStatus(terminalStatus);
|
|
@@ -20705,9 +21062,6 @@ import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
|
20705
21062
|
var TOOL_BLINK_MS = 500;
|
|
20706
21063
|
var TOOL_PENDING_SHOW_DELAY_MS = 1e3;
|
|
20707
21064
|
var TOOL_ANIM_TICK_MS = TOOL_BLINK_MS;
|
|
20708
|
-
function statusCopy(name, label, count, doneCount, pending, isError, args = {}) {
|
|
20709
|
-
return formatToolActionHeader(name, args, { pending, count });
|
|
20710
|
-
}
|
|
20711
21065
|
function ToolExecution({ name, args, result, rawResult, isError, errorCount, callErrorCount, exitErrorCount, expanded, columns = 80, attached = false, count = 1, completedCount = 0, startedAt = 0, completedAt = 0, aggregate = false, categories = {}, doneCategories = null, headerFinalized = true, deferredDisplayReady = false, agentResponseAggregate = false }) {
|
|
20712
21066
|
const rowWidth = Math.max(1, Number(columns || 80));
|
|
20713
21067
|
const groupCount = Math.max(1, Number(count || 1));
|
|
@@ -20794,87 +21148,60 @@ function ToolExecution({ name, args, result, rawResult, isError, errorCount, cal
|
|
|
20794
21148
|
)
|
|
20795
21149
|
] });
|
|
20796
21150
|
}
|
|
20797
|
-
const { label, summary, normalizedName, args: parsedArgs } = formatToolSurface(name, args);
|
|
20798
|
-
const isShellSurface = isShellTool(normalizedName, label);
|
|
20799
|
-
const isSkillSurface = SKILL_SURFACE_NAMES2.has(String(normalizedName || "").toLowerCase());
|
|
20800
|
-
const backgroundMeta = !pending && isBackgroundTaskTool(normalizedName) ? resolveBackgroundTaskMeta(parsedArgs, rt || "") : null;
|
|
20801
|
-
const backgroundError = backgroundMeta?.error || parsedArgs?.error || "";
|
|
20802
|
-
const errorOnlyResult = Boolean(rt) && isBackgroundErrorOnlyBody(rt, backgroundError);
|
|
20803
|
-
const backgroundResultText = backgroundMeta?.hasResponse ? backgroundMeta.body : "";
|
|
20804
|
-
const displayedResultText = backgroundResultText || (errorOnlyResult ? "" : rt || "");
|
|
20805
|
-
const hasDisplayResult = Boolean(String(displayedResultText || "").trim());
|
|
20806
|
-
const displayedResultBodyText = stripLeadingStatusMarkerFromText(displayedResultText);
|
|
20807
|
-
const hasDisplayBody = Boolean(String(displayedResultBodyText || "").trim());
|
|
20808
|
-
const lines = displayedResultBodyText ? displayedResultBodyText.split("\n") : [];
|
|
20809
|
-
const totalLines = lines.length;
|
|
20810
|
-
const resultSummary = !pending && hasDisplayBody ? summarizeToolResult(name, args, displayedResultBodyText, isError) : null;
|
|
20811
21151
|
const maxResultChars = Math.min(RESULT_LINE_HARD_MAX, Math.max(MIN_RESULT_LINE_CHARS, Number(columns || 80) - 7));
|
|
21152
|
+
const model = deriveToolCardModel({
|
|
21153
|
+
name,
|
|
21154
|
+
args,
|
|
21155
|
+
result,
|
|
21156
|
+
rawResult,
|
|
21157
|
+
isError,
|
|
21158
|
+
errorCount,
|
|
21159
|
+
callErrorCount,
|
|
21160
|
+
exitErrorCount,
|
|
21161
|
+
count: displayGroupCount,
|
|
21162
|
+
completedCount: doneCount,
|
|
21163
|
+
startedAt,
|
|
21164
|
+
completedAt,
|
|
21165
|
+
headerFinalized,
|
|
21166
|
+
nowMs
|
|
21167
|
+
}, { truncate: truncateToWidth, maxResultChars });
|
|
21168
|
+
const {
|
|
21169
|
+
labelText,
|
|
21170
|
+
summaryText,
|
|
21171
|
+
headerFailureText: headerFailureStatus,
|
|
21172
|
+
detailLine: collapsedDetailLine,
|
|
21173
|
+
detailIsPlaceholder,
|
|
21174
|
+
terminalStatus,
|
|
21175
|
+
normalizedName,
|
|
21176
|
+
isShellSurface,
|
|
21177
|
+
isAgentSurfaceCard,
|
|
21178
|
+
isAgentResponse,
|
|
21179
|
+
isBackgroundMetadataResult,
|
|
21180
|
+
hasDisplayResult,
|
|
21181
|
+
hasDisplayBody,
|
|
21182
|
+
displayedResultBodyText,
|
|
21183
|
+
firstResultLine,
|
|
21184
|
+
totalLines,
|
|
21185
|
+
resultSummary,
|
|
21186
|
+
shellCollapsedSummary,
|
|
21187
|
+
toolArgPath
|
|
21188
|
+
} = model;
|
|
21189
|
+
const lines = displayedResultBodyText ? displayedResultBodyText.split("\n") : [];
|
|
20812
21190
|
const resultColor = theme.text;
|
|
20813
|
-
const firstResultLine = hasDisplayResult ? String(lines[0] ?? "") : "";
|
|
20814
21191
|
const firstResultLineClipped = hasDisplayBody && stringWidth9(firstResultLine) > maxResultChars;
|
|
20815
21192
|
const hasHiddenDetail = !pending && hasDisplayBody && (totalLines > 1 || firstResultLineClipped || Boolean(resultSummary));
|
|
20816
|
-
const shellStatus = isShellSurface ? shellDisplayStatus({ pending, failedCount, exitFailedCount, isError, result: displayedResultText }) : "";
|
|
20817
|
-
const shellElapsed = isShellSurface ? shellResultElapsed(displayedResultText) || elapsed : "";
|
|
20818
|
-
const backgroundElapsed = backgroundMeta ? backgroundTaskElapsed(backgroundMeta, elapsed) : isBackgroundTaskTool(normalizedName) ? backgroundTaskElapsed(parsedArgs, elapsed) : "";
|
|
20819
|
-
const toolArgPath = parsedArgs?.path ?? parsedArgs?.file_path ?? parsedArgs?.file ?? "";
|
|
20820
|
-
const imageDetail = normalizedName === "view_image" && toolArgPath && !isError ? String(toolArgPath) : "";
|
|
20821
|
-
const isBackgroundResult = !pending && isBackgroundTaskTool(normalizedName) && Boolean(backgroundMeta);
|
|
20822
|
-
const isBackgroundResponse = isBackgroundResult && (backgroundMeta?.hasResponse || isBackgroundTaskResponseArgs(normalizedName, parsedArgs));
|
|
20823
|
-
const isBackgroundMetadataResult = isBackgroundResult && !isBackgroundResponse && Boolean(backgroundMeta);
|
|
20824
|
-
const backgroundMetadataFailureLabel = isBackgroundMetadataResult ? backgroundTaskFailureDetail(backgroundMeta, parsedArgs) : "";
|
|
20825
|
-
const backgroundMetadataHeaderFailure = Boolean(backgroundMetadataFailureLabel) && !hasDisplayResult ? backgroundMetadataFailureLabel : "";
|
|
20826
|
-
const agentHeaderFailure = !pending && isAgentTool(normalizedName) && isError && parsedArgs?.error && !hasDisplayResult ? backgroundTaskFailureStatusLabel(parsedArgs?.status, parsedArgs?.error, { surface: "agent" }) : "";
|
|
20827
|
-
const headerFailureStatus = backgroundMetadataHeaderFailure || agentHeaderFailure || "";
|
|
20828
|
-
const agentCompletionDetail = !pending && isAgentTool(normalizedName) && !agentHeaderFailure ? agentTerminalDetail(parsedArgs?.status, isError, elapsed, parsedArgs?.error) : "";
|
|
20829
|
-
const agentDetail = !pending && isAgentTool(normalizedName) && !hasDisplayResult ? agentCompletionDetail : "";
|
|
20830
|
-
const genericDetail = !pending && !isShellSurface && !agentDetail && !imageDetail && !resultSummary ? genericCompletedDetail({ normalizedName, label, hasResult, firstResultLine, isError }) : "";
|
|
20831
|
-
const terminalStatus = pending ? "running" : shellStatus || normalizeTerminalStatus(backgroundMeta?.status) || normalizeTerminalStatus(parsedArgs?.status) || resultTerminalStatus(displayedResultText) || (isError || failedCount > 0 ? "failed" : "completed");
|
|
20832
|
-
const backgroundMetadataDetail = isBackgroundMetadataResult && !backgroundMetadataHeaderFailure ? backgroundTaskDetail(backgroundMeta, backgroundElapsed, parsedArgs) : "";
|
|
20833
|
-
const backgroundResponseDetail = isBackgroundResponse && resultSummary ? prefixElapsed(resultSummary, backgroundElapsed) : resultSummary;
|
|
20834
|
-
const syncElapsedDetail = !isBackgroundResponse && shouldPrefixSyncElapsed(normalizedName, label) ? prefixElapsed(backgroundResponseDetail, elapsed) : backgroundResponseDetail;
|
|
20835
|
-
const nonShellDetail = backgroundMetadataDetail || (/^(Cancelled|Failed|Finished)$/i.test(resultSummary || "") && agentCompletionDetail ? agentCompletionDetail : syncElapsedDetail) || agentDetail || imageDetail || genericDetail;
|
|
20836
|
-
const pendingDetailPlaceholder = pending && !isSkillSurface ? elapsed ? `Running \xB7 ${elapsed}` : "Running" : "";
|
|
20837
|
-
const shellCollapsedSummary = isShellSurface && !pending && hasDisplayResult ? resultSummary || truncateToWidth(firstResultLine, Math.min(120, maxResultChars)) : resultSummary;
|
|
20838
|
-
const collapsedDetail = pending ? pendingDetailPlaceholder : isShellSurface ? prefixElapsed(mergeTerminalDetail(shellStatus, shellCollapsedSummary), shellElapsed) : mergeTerminalDetail(terminalStatus, nonShellDetail);
|
|
20839
21193
|
const backgroundMetadataExpandable = isBackgroundMetadataResult && hasRawResult && !pending;
|
|
20840
21194
|
const showRawResult = expanded && (hasDisplayBody || hasRawResult) && (!isBackgroundMetadataResult || hasRawResult);
|
|
20841
|
-
const detailLines = showRawResult ? agentResponseAggregate && hasRawResult ? stripLeadingStatusMarkerLines(rawRt.split("\n")) : hasDisplayBody ? lines : rawRt ? stripLeadingStatusMarkerLines(rawRt.split("\n")) : [] :
|
|
20842
|
-
const isPendingPlaceholderDetail = !showRawResult &&
|
|
21195
|
+
const detailLines = showRawResult ? agentResponseAggregate && hasRawResult ? stripLeadingStatusMarkerLines(rawRt.split("\n")) : hasDisplayBody ? lines : rawRt ? stripLeadingStatusMarkerLines(rawRt.split("\n")) : [] : collapsedDetailLine ? [collapsedDetailLine] : [];
|
|
21196
|
+
const isPendingPlaceholderDetail = !showRawResult && detailIsPlaceholder;
|
|
20843
21197
|
const detailColor = isPendingPlaceholderDetail ? theme.subtle : theme.text;
|
|
20844
|
-
const
|
|
20845
|
-
const isAgentResponse = isAgentResult && hasAgentResponseResult(rt);
|
|
20846
|
-
const isAgentSurfaceCard = isAgentTool(normalizedName);
|
|
20847
|
-
const agentSurfaceBriefRaw = isAgentSurfaceCard && !showRawResult ? summarizeAgentSurfaceBrief(name, parsedArgs, displayedResultText || "", { isError, isResponse: isAgentResponse }) : "";
|
|
20848
|
-
const agentSurfaceBrief = agentSurfaceBriefRaw ? truncateToWidth(agentSurfaceBriefRaw, Math.min(AGENT_SURFACE_BRIEF_MAX, maxResultChars)) : "";
|
|
20849
|
-
let visibleDetailLines = detailLines;
|
|
20850
|
-
if (isSkillSurface && !showRawResult) {
|
|
20851
|
-
visibleDetailLines = isError && collapsedDetail ? [collapsedDetail] : [];
|
|
20852
|
-
} else if (isBackgroundMetadataResult && backgroundMetadataHeaderFailure && !showRawResult) {
|
|
20853
|
-
visibleDetailLines = [];
|
|
20854
|
-
} else if (isAgentSurfaceCard && !showRawResult) {
|
|
20855
|
-
const agentDetailFallback = collapsedDetail || (pending ? pendingDetailPlaceholder || "Running" : "Finished");
|
|
20856
|
-
const agentDetailLine = agentSurfaceBrief || truncateToWidth(String(agentDetailFallback), Math.min(AGENT_SURFACE_BRIEF_MAX, maxResultChars));
|
|
20857
|
-
const agentFailureText = /\b(Cancelled|Canceled|Failed)\b/i.test(agentSurfaceBrief || collapsedDetail || "");
|
|
20858
|
-
const keepAgentDetail = (isError || agentFailureText) && !(agentHeaderFailure && !agentSurfaceBrief);
|
|
20859
|
-
visibleDetailLines = keepAgentDetail ? [agentDetailLine] : [];
|
|
20860
|
-
}
|
|
21198
|
+
const visibleDetailLines = detailLines;
|
|
20861
21199
|
const finalStatusColor = toolStatusColor({ pending, groupCount, callFailedCount, exitFailedCount, terminalStatus });
|
|
20862
21200
|
const dotColor = finalStatusColor;
|
|
20863
21201
|
const markerGlyph = isAgentResponse ? AGENT_RESPONSE_MARKER : isAgentSurfaceCard ? AGENT_CALL_MARKER : TURN_MARKER;
|
|
20864
21202
|
const isDirectionalMarker = isAgentResponse || isAgentSurfaceCard;
|
|
20865
21203
|
const markerText = isDirectionalMarker ? `${markerGlyph} ` : markerGlyph;
|
|
20866
21204
|
const dotText = pending && !blinkOn ? " " : markerText;
|
|
20867
|
-
let labelText;
|
|
20868
|
-
if (isAgentResponse) labelText = agentResponseTitle(parsedArgs, displayGroupCount);
|
|
20869
|
-
else if (isBackgroundResponse) labelText = backgroundTaskResultTitle(normalizedName, backgroundMeta || parsedArgs);
|
|
20870
|
-
else if (isBackgroundMetadataResult) labelText = backgroundTaskActionTitle(normalizedName, backgroundMeta);
|
|
20871
|
-
else if (isShellSurface) labelText = shellHeader(shellStatus, displayGroupCount);
|
|
20872
|
-
else labelText = (isAgentTool(normalizedName) ? agentActionTitle(parsedArgs) : "") || statusCopy(name, label, displayGroupCount, doneCount, headerPending, isError, parsedArgs);
|
|
20873
|
-
labelText = safeInlineText(labelText);
|
|
20874
|
-
const toolSearchSummary = !pending && normalizedName === "load_tool" && hasResult ? toolSearchLoadedSummary(displayedResultText) : "";
|
|
20875
|
-
const rawSummaryText = safeInlineText(isAgentResponse || isBackgroundResponse ? "" : toolSearchSummary || (isAgentTool(normalizedName) ? agentActionSummary(parsedArgs, summary) : summary));
|
|
20876
|
-
const summaryIsHeaderCount = rawSummaryText && /^\d+\s+\S+$/.test(rawSummaryText) && labelText.endsWith(rawSummaryText);
|
|
20877
|
-
const summaryText = summaryIsHeaderCount ? "" : rawSummaryText;
|
|
20878
21205
|
const agentHasExpandableBody = isAgentSurfaceCard && !pending && hasResult && (isAgentResponse || totalLines > 1 || firstResultLineClipped);
|
|
20879
21206
|
const shellHasExpandableBody = isShellSurface && !pending && hasDisplayResult && hasDisplayBody && (totalLines > 1 || firstResultLineClipped || Boolean(shellCollapsedSummary && shellCollapsedSummary !== firstResultLine));
|
|
20880
21207
|
const showHeaderExpandHint = (isShellSurface ? shellHasExpandableBody : isAgentSurfaceCard ? agentHasExpandableBody : hasHiddenDetail || backgroundMetadataExpandable) && normalizedName !== "load_tool";
|
|
@@ -22491,19 +22818,6 @@ function App({ store, initialStatusLine = "", forceOnboarding = false }) {
|
|
|
22491
22818
|
resumeAfterChannelPrompt(channelPrompt);
|
|
22492
22819
|
return true;
|
|
22493
22820
|
}
|
|
22494
|
-
if (channelPrompt.kind === "webhook-token") {
|
|
22495
|
-
if (!commandText) return false;
|
|
22496
|
-
store.saveWebhookAuthtoken(commandText);
|
|
22497
|
-
resumeAfterChannelPrompt(channelPrompt);
|
|
22498
|
-
return true;
|
|
22499
|
-
}
|
|
22500
|
-
if (channelPrompt.kind === "webhook-domain") {
|
|
22501
|
-
if (!commandText) return false;
|
|
22502
|
-
Promise.resolve(store.setWebhookConfig?.({ ngrokDomain: commandText })).then(() => resumeAfterChannelPrompt(channelPrompt)).catch((e) => {
|
|
22503
|
-
store.pushNotice(`webhook config update failed: ${e?.message || e}`, "error");
|
|
22504
|
-
});
|
|
22505
|
-
return true;
|
|
22506
|
-
}
|
|
22507
22821
|
const parts = commandText.split("|").map((part) => part.trim());
|
|
22508
22822
|
if (channelPrompt.kind === "channel-add") {
|
|
22509
22823
|
const isPipe = parts.length > 1;
|
|
@@ -23633,7 +23947,7 @@ function App({ store, initialStatusLine = "", forceOnboarding = false }) {
|
|
|
23633
23947
|
}
|
|
23634
23948
|
|
|
23635
23949
|
// src/tui/engine.mjs
|
|
23636
|
-
import { performance as
|
|
23950
|
+
import { performance as performance3 } from "node:perf_hooks";
|
|
23637
23951
|
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
23952
|
import { basename as basename7, dirname as dirname11, join as join14 } from "node:path";
|
|
23639
23953
|
|
|
@@ -23786,6 +24100,12 @@ var SYNTHETIC_SESSION_TEXT_PATTERNS = Object.freeze([
|
|
|
23786
24100
|
/^\[mixdog-runtime\]/i,
|
|
23787
24101
|
/^\[(?:truncated|request interrupted by user)\]$/i,
|
|
23788
24102
|
/^a previous model worked on this task and produced the compacted handoff summary below\b/i,
|
|
24103
|
+
// Compact/auto-clear re-seed handoff variants: these lead the FIRST user
|
|
24104
|
+
// message of every post-compaction session, so titling from them painted
|
|
24105
|
+
// "Re-attached after compaction…" rows in Recent (user report). Skipping
|
|
24106
|
+
// them titles the session from its first REAL user message instead.
|
|
24107
|
+
/^re-attached after compaction\b/i,
|
|
24108
|
+
/^reference files:\s/i,
|
|
23789
24109
|
/^the async (?:agent|shell) task\b/i
|
|
23790
24110
|
]);
|
|
23791
24111
|
var LATE_TOOL_ANNOUNCEMENT_SENTINEL = "connected after this session started";
|
|
@@ -23916,12 +24236,12 @@ function sessionPath(id) {
|
|
|
23916
24236
|
}
|
|
23917
24237
|
|
|
23918
24238
|
// src/tui/engine/boot-profile.mjs
|
|
23919
|
-
import { performance } from "node:perf_hooks";
|
|
24239
|
+
import { performance as performance2 } from "node:perf_hooks";
|
|
23920
24240
|
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 =
|
|
24241
|
+
var BOOT_PROFILE_START = globalThis.__mixdogBootProfileStart || (globalThis.__mixdogBootProfileStart = performance2.now());
|
|
23922
24242
|
function bootProfile(event, fields = {}) {
|
|
23923
24243
|
if (!BOOT_PROFILE_ENABLED) return;
|
|
23924
|
-
const elapsedMs =
|
|
24244
|
+
const elapsedMs = performance2.now() - BOOT_PROFILE_START;
|
|
23925
24245
|
const parts = [`[mixdog-boot] +${elapsedMs.toFixed(1)}ms`, `tui:${event}`];
|
|
23926
24246
|
for (const [key, value] of Object.entries(fields || {})) {
|
|
23927
24247
|
if (value === void 0 || value === null || value === "") continue;
|
|
@@ -25611,6 +25931,7 @@ import { randomBytes as randomBytes3 } from "crypto";
|
|
|
25611
25931
|
import { join as join10 } from "path";
|
|
25612
25932
|
var PENDING_MESSAGES_FILE = "session-pending-messages.json";
|
|
25613
25933
|
var PENDING_MESSAGES_MODE = 384;
|
|
25934
|
+
var STALE_STEERING_RESTORE_TTL_MS = 30 * 60 * 1e3;
|
|
25614
25935
|
var _persistChain = Promise.resolve();
|
|
25615
25936
|
function _serialize(task) {
|
|
25616
25937
|
const run = _persistChain.then(task, task);
|
|
@@ -25637,7 +25958,9 @@ function normalizeTuiSteeringQueueEntry(entry) {
|
|
|
25637
25958
|
if (typeof entry.text === "string" && entry.text.trim()) {
|
|
25638
25959
|
const text = entry.text.trim();
|
|
25639
25960
|
const id = typeof entry.id === "string" && entry.id.trim() ? entry.id.trim() : null;
|
|
25640
|
-
|
|
25961
|
+
if (!id) return text;
|
|
25962
|
+
const at = Number(entry.at);
|
|
25963
|
+
return Number.isFinite(at) && at > 0 ? { id, text, at } : { id, text };
|
|
25641
25964
|
}
|
|
25642
25965
|
return null;
|
|
25643
25966
|
}
|
|
@@ -25689,7 +26012,7 @@ function appendTuiSteeringPersist(leadSessionId, entry) {
|
|
|
25689
26012
|
const key = tuiSteeringSessionKey(leadSessionId);
|
|
25690
26013
|
if (!key) return Promise.resolve();
|
|
25691
26014
|
if (!entry.steeringPersistId) entry.steeringPersistId = newSteeringPersistId();
|
|
25692
|
-
const record = { id: entry.steeringPersistId, text };
|
|
26015
|
+
const record = { id: entry.steeringPersistId, text, at: Date.now() };
|
|
25693
26016
|
return _serialize(async () => {
|
|
25694
26017
|
try {
|
|
25695
26018
|
await updateJsonAtomic(pendingMessagesPath(), (raw) => {
|
|
@@ -25761,12 +26084,21 @@ function drainTuiSteeringPersist(leadSessionId) {
|
|
|
25761
26084
|
if (!key) return Promise.resolve([]);
|
|
25762
26085
|
return _serialize(async () => {
|
|
25763
26086
|
let drained = [];
|
|
26087
|
+
let droppedStale = 0;
|
|
25764
26088
|
try {
|
|
25765
26089
|
await updateJsonAtomic(pendingMessagesPath(), (raw) => {
|
|
25766
26090
|
const next = normalizePendingStore(raw);
|
|
25767
26091
|
const q = Array.isArray(next.sessions[key]) ? next.sessions[key] : [];
|
|
25768
|
-
|
|
25769
|
-
|
|
26092
|
+
const now = Date.now();
|
|
26093
|
+
const touchedAt = Number(next.sessionTouchedAt?.[key]) || 0;
|
|
26094
|
+
const fresh = q.filter((row) => {
|
|
26095
|
+
const at = Number(row?.at) || touchedAt;
|
|
26096
|
+
const stale = at > 0 && now - at > STALE_STEERING_RESTORE_TTL_MS;
|
|
26097
|
+
if (stale) droppedStale += 1;
|
|
26098
|
+
return !stale;
|
|
26099
|
+
});
|
|
26100
|
+
drained = fresh.map(drainedRowToRestore).filter(Boolean);
|
|
26101
|
+
if (drained.length === 0 && droppedStale === 0) return void 0;
|
|
25770
26102
|
delete next.sessions[key];
|
|
25771
26103
|
if (next.sessionTouchedAt) delete next.sessionTouchedAt[key];
|
|
25772
26104
|
next.updatedAt = Date.now();
|
|
@@ -25775,6 +26107,13 @@ function drainTuiSteeringPersist(leadSessionId) {
|
|
|
25775
26107
|
} catch (err) {
|
|
25776
26108
|
try {
|
|
25777
26109
|
process.stderr.write(`[tui] steering-queue drain failed sessionId=${leadSessionId}: ${err?.message || err}
|
|
26110
|
+
`);
|
|
26111
|
+
} catch {
|
|
26112
|
+
}
|
|
26113
|
+
}
|
|
26114
|
+
if (droppedStale > 0) {
|
|
26115
|
+
try {
|
|
26116
|
+
process.stderr.write(`[tui] dropped ${droppedStale} stale steering row(s) sessionId=${leadSessionId}
|
|
25778
26117
|
`);
|
|
25779
26118
|
} catch {
|
|
25780
26119
|
}
|
|
@@ -28166,16 +28505,6 @@ function createEngineApiB(bag) {
|
|
|
28166
28505
|
pushNotice("telegram token forgotten", "info");
|
|
28167
28506
|
return result;
|
|
28168
28507
|
},
|
|
28169
|
-
saveWebhookAuthtoken: (token) => {
|
|
28170
|
-
const result = runtime.saveWebhookAuthtoken(token);
|
|
28171
|
-
pushNotice("webhook/ngrok authtoken saved", "info");
|
|
28172
|
-
return result;
|
|
28173
|
-
},
|
|
28174
|
-
forgetWebhookAuthtoken: () => {
|
|
28175
|
-
const result = runtime.forgetWebhookAuthtoken();
|
|
28176
|
-
pushNotice("webhook/ngrok authtoken forgotten", "info");
|
|
28177
|
-
return result;
|
|
28178
|
-
},
|
|
28179
28508
|
setChannel: async (entry) => {
|
|
28180
28509
|
const result = await runtime.setChannel(entry);
|
|
28181
28510
|
pushNotice("channel saved", "info");
|
|
@@ -28276,6 +28605,17 @@ function createEngineApiB(bag) {
|
|
|
28276
28605
|
listSessions: (options) => {
|
|
28277
28606
|
return runtime.listSessions(options);
|
|
28278
28607
|
},
|
|
28608
|
+
// Desktop sidebar watcher hook: EngineHost fs.watches this directory so
|
|
28609
|
+
// heartbeat sidecar create/delete pushes instant working/dot updates.
|
|
28610
|
+
// Without it the watcher silently no-ops and the sidebar falls back to
|
|
28611
|
+
// the 60s safety poll (user: spinner kept spinning after the turn ended).
|
|
28612
|
+
sessionStoreDir: () => {
|
|
28613
|
+
try {
|
|
28614
|
+
return runtime.sessionStoreDir?.() || null;
|
|
28615
|
+
} catch {
|
|
28616
|
+
return null;
|
|
28617
|
+
}
|
|
28618
|
+
},
|
|
28279
28619
|
deleteSession: async (id) => {
|
|
28280
28620
|
if (getState().commandBusy) return false;
|
|
28281
28621
|
const deletingCurrent = String(runtime.session?.id || getState().sessionId || "") === String(id || "");
|
|
@@ -28581,7 +28921,6 @@ async function buildDoctorReport(runtime = {}, getState = () => ({})) {
|
|
|
28581
28921
|
const tokens = [];
|
|
28582
28922
|
if (setup.discord?.authenticated) tokens.push("discord");
|
|
28583
28923
|
if (setup.telegram?.authenticated) tokens.push("telegram");
|
|
28584
|
-
if (setup.webhook?.authenticated) tokens.push("webhook");
|
|
28585
28924
|
const running = worker.running === true;
|
|
28586
28925
|
const detail = `enabled \xB7 worker ${running ? "running" : "stopped"} \xB7 tokens: ${tokens.length ? tokens.join(", ") : "none"}`;
|
|
28587
28926
|
row(running ? "ok" : "warn", detail);
|
|
@@ -29247,7 +29586,9 @@ function createFrameBatchedStorePublisher({
|
|
|
29247
29586
|
frameMs = 16,
|
|
29248
29587
|
setTimer = setTimeout,
|
|
29249
29588
|
clearTimer = clearTimeout,
|
|
29250
|
-
enqueueMicrotask = queueMicrotask
|
|
29589
|
+
enqueueMicrotask = queueMicrotask,
|
|
29590
|
+
scheduleFrame = (callback, delay2) => setTimer(callback, delay2),
|
|
29591
|
+
cancelFrame = (handle) => clearTimer(handle)
|
|
29251
29592
|
}) {
|
|
29252
29593
|
let timer2 = null;
|
|
29253
29594
|
let emitPending = false;
|
|
@@ -29255,7 +29596,7 @@ function createFrameBatchedStorePublisher({
|
|
|
29255
29596
|
let immediatePending = false;
|
|
29256
29597
|
const flush = () => {
|
|
29257
29598
|
if (timer2 !== null) {
|
|
29258
|
-
|
|
29599
|
+
cancelFrame(timer2);
|
|
29259
29600
|
timer2 = null;
|
|
29260
29601
|
}
|
|
29261
29602
|
immediatePending = false;
|
|
@@ -29277,7 +29618,7 @@ function createFrameBatchedStorePublisher({
|
|
|
29277
29618
|
const emit = () => {
|
|
29278
29619
|
emitPending = true;
|
|
29279
29620
|
if (timer2 !== null || isDisposed()) return;
|
|
29280
|
-
timer2 =
|
|
29621
|
+
timer2 = scheduleFrame(flush, frameMs);
|
|
29281
29622
|
timer2?.unref?.();
|
|
29282
29623
|
};
|
|
29283
29624
|
const markStructureChange = () => {
|
|
@@ -29291,7 +29632,7 @@ function createFrameBatchedStorePublisher({
|
|
|
29291
29632
|
};
|
|
29292
29633
|
const dispose = () => {
|
|
29293
29634
|
if (emitPending && !isDisposed()) flush();
|
|
29294
|
-
else if (timer2 !== null)
|
|
29635
|
+
else if (timer2 !== null) cancelFrame(timer2);
|
|
29295
29636
|
timer2 = null;
|
|
29296
29637
|
emitPending = false;
|
|
29297
29638
|
structureChangePending = false;
|
|
@@ -29707,6 +30048,7 @@ function createLiveShare({
|
|
|
29707
30048
|
const stopClient = () => {
|
|
29708
30049
|
const closing = client;
|
|
29709
30050
|
const closingId = clientId;
|
|
30051
|
+
const wasUp = clientUp;
|
|
29710
30052
|
client = null;
|
|
29711
30053
|
clientId = "";
|
|
29712
30054
|
clientUp = false;
|
|
@@ -29718,6 +30060,7 @@ function createLiveShare({
|
|
|
29718
30060
|
} catch {
|
|
29719
30061
|
}
|
|
29720
30062
|
}
|
|
30063
|
+
if (wasUp) clearMirroredLiveState();
|
|
29721
30064
|
};
|
|
29722
30065
|
const startClient = (id) => {
|
|
29723
30066
|
let socket;
|
|
@@ -30313,16 +30656,16 @@ async function createEngineSession({
|
|
|
30313
30656
|
cwd,
|
|
30314
30657
|
desktopSession
|
|
30315
30658
|
} = {}) {
|
|
30316
|
-
const startedAt =
|
|
30659
|
+
const startedAt = performance3.now();
|
|
30317
30660
|
bootProfile("engine:create:start", { provider: providerName, model, toolMode, remote });
|
|
30318
30661
|
process.env.MIXDOG_QUIET_PROVIDER_LOG = "1";
|
|
30319
30662
|
process.env.MIXDOG_QUIET_SESSION_LOG = "1";
|
|
30320
30663
|
process.env.MIXDOG_QUIET_MCP_LOG = "1";
|
|
30321
30664
|
process.env.MIXDOG_QUIET_MEMORY_LOG = "1";
|
|
30322
30665
|
process.env.MIXDOG_PATCH_NATIVE_PREWARM ??= "0";
|
|
30323
|
-
const importStartedAt =
|
|
30666
|
+
const importStartedAt = performance3.now();
|
|
30324
30667
|
const { createMixdogSessionRuntime } = await import(SESSION_RUNTIME_MODULE);
|
|
30325
|
-
bootProfile("session-runtime:imported", { ms: (
|
|
30668
|
+
bootProfile("session-runtime:imported", { ms: (performance3.now() - importStartedAt).toFixed(1) });
|
|
30326
30669
|
const runtime = await createMixdogSessionRuntime({
|
|
30327
30670
|
provider: providerName,
|
|
30328
30671
|
model,
|
|
@@ -30331,9 +30674,9 @@ async function createEngineSession({
|
|
|
30331
30674
|
...cwd ? { cwd } : {},
|
|
30332
30675
|
...desktopSession ? { desktopSession } : {}
|
|
30333
30676
|
});
|
|
30334
|
-
bootProfile("engine:create:runtime-ready", { ms: (
|
|
30677
|
+
bootProfile("engine:create:runtime-ready", { ms: (performance3.now() - startedAt).toFixed(1) });
|
|
30335
30678
|
const runtimeCwd = runtime.cwd || process.cwd();
|
|
30336
|
-
const stateStartedAt =
|
|
30679
|
+
const stateStartedAt = performance3.now();
|
|
30337
30680
|
const flags = {
|
|
30338
30681
|
disposed: false,
|
|
30339
30682
|
draining: false,
|
|
@@ -30409,11 +30752,11 @@ async function createEngineSession({
|
|
|
30409
30752
|
cwd: runtimeCwd,
|
|
30410
30753
|
themeEpoch: 0
|
|
30411
30754
|
};
|
|
30412
|
-
bootProfile("engine:route-state-ready", { ms: (
|
|
30413
|
-
bootProfile("engine:state-ready", { ms: (
|
|
30414
|
-
const contextStartedAt =
|
|
30755
|
+
bootProfile("engine:route-state-ready", { ms: (performance3.now() - stateStartedAt).toFixed(1) });
|
|
30756
|
+
bootProfile("engine:state-ready", { ms: (performance3.now() - stateStartedAt).toFixed(1) });
|
|
30757
|
+
const contextStartedAt = performance3.now();
|
|
30415
30758
|
syncContextStats({ allowEstimated: true });
|
|
30416
|
-
bootProfile("engine:context-ready", { ms: (
|
|
30759
|
+
bootProfile("engine:context-ready", { ms: (performance3.now() - contextStartedAt).toFixed(1) });
|
|
30417
30760
|
const listeners = /* @__PURE__ */ new Set();
|
|
30418
30761
|
let publishedState = process.env.NODE_ENV === "production" ? state : Object.freeze(state);
|
|
30419
30762
|
state = { ...state, stats: { ...state.stats } };
|
|
@@ -30424,7 +30767,10 @@ async function createEngineSession({
|
|
|
30424
30767
|
state = { ...next, stats: { ...next.stats } };
|
|
30425
30768
|
},
|
|
30426
30769
|
listeners,
|
|
30427
|
-
isDisposed: () => flags.disposed
|
|
30770
|
+
isDisposed: () => flags.disposed,
|
|
30771
|
+
frameMs: TUI_FRAME_MS,
|
|
30772
|
+
scheduleFrame: scheduleRenderAlignedStoreFlush,
|
|
30773
|
+
cancelFrame: cancelRenderAlignedStoreFlush
|
|
30428
30774
|
});
|
|
30429
30775
|
const emit = publisher.emit;
|
|
30430
30776
|
const flushEmit = publisher.flush;
|
|
@@ -31100,7 +31446,7 @@ var XTSHIFTESCAPE_ON = process.env.WT_SESSION ? "" : "\x1B[>1s";
|
|
|
31100
31446
|
var MOUSE_TRACKING_ON2 = `\x1B[?1000h\x1B[?1002h\x1B[?1006h\x1B[?1007l${XTSHIFTESCAPE_ON}`;
|
|
31101
31447
|
var ALT_SCROLL_RESTORE = "\x1B[?1007h";
|
|
31102
31448
|
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 =
|
|
31449
|
+
var BOOT_PROFILE_START2 = globalThis.__mixdogBootProfileStart || (globalThis.__mixdogBootProfileStart = performance4.now());
|
|
31104
31450
|
var EXIT_WAIT_TIMEOUT_MS = positiveIntEnv2("MIXDOG_TUI_EXIT_WAIT_MS", 2500);
|
|
31105
31451
|
var EXIT_HARD_DELAY_MS = positiveIntEnv2("MIXDOG_TUI_HARD_EXIT_DELAY_MS", 500);
|
|
31106
31452
|
var EXIT_HARD_ENABLED = !/^(0|false|no|off)$/i.test(String(process.env.MIXDOG_TUI_HARD_EXIT || "1"));
|
|
@@ -31116,9 +31462,9 @@ function positiveIntEnv2(name, fallback) {
|
|
|
31116
31462
|
function installTuiLoopProbe() {
|
|
31117
31463
|
if (!LOOP_PROBE_ENABLED) return () => {
|
|
31118
31464
|
};
|
|
31119
|
-
let last =
|
|
31465
|
+
let last = performance4.now();
|
|
31120
31466
|
const timer2 = setInterval(() => {
|
|
31121
|
-
const now =
|
|
31467
|
+
const now = performance4.now();
|
|
31122
31468
|
const drift = now - last - LOOP_PROBE_INTERVAL_MS;
|
|
31123
31469
|
last = now;
|
|
31124
31470
|
if (drift > LOOP_PROBE_DRIFT_THRESHOLD_MS) {
|
|
@@ -31143,7 +31489,7 @@ var PERF_STALL_THRESHOLD_MS = positiveIntEnv2("MIXDOG_TUI_PERF_STALL_MS", 80);
|
|
|
31143
31489
|
var PERF_RENDER_GAP_MS = positiveIntEnv2("MIXDOG_TUI_PERF_RENDER_GAP_MS", 120);
|
|
31144
31490
|
function perfLog(event, fields = {}) {
|
|
31145
31491
|
if (!PERF_ENABLED) return;
|
|
31146
|
-
const elapsedMs =
|
|
31492
|
+
const elapsedMs = performance4.now() - BOOT_PROFILE_START2;
|
|
31147
31493
|
const parts = [`[mixdog-perf] +${elapsedMs.toFixed(1)}ms`, event];
|
|
31148
31494
|
for (const [key, value] of Object.entries(fields || {})) {
|
|
31149
31495
|
if (value === void 0 || value === null || value === "") continue;
|
|
@@ -31158,7 +31504,7 @@ function perfLog(event, fields = {}) {
|
|
|
31158
31504
|
function installTuiPerfProbe() {
|
|
31159
31505
|
if (!PERF_ENABLED) return () => {
|
|
31160
31506
|
};
|
|
31161
|
-
let last =
|
|
31507
|
+
let last = performance4.now();
|
|
31162
31508
|
let lastCpu = process.cpuUsage();
|
|
31163
31509
|
perfLog("probe:start", {
|
|
31164
31510
|
intervalMs: PERF_STALL_INTERVAL_MS,
|
|
@@ -31166,7 +31512,7 @@ function installTuiPerfProbe() {
|
|
|
31166
31512
|
renderGapMs: PERF_RENDER_GAP_MS
|
|
31167
31513
|
});
|
|
31168
31514
|
const timer2 = setInterval(() => {
|
|
31169
|
-
const now =
|
|
31515
|
+
const now = performance4.now();
|
|
31170
31516
|
const elapsed = now - last;
|
|
31171
31517
|
const lagMs = elapsed - PERF_STALL_INTERVAL_MS;
|
|
31172
31518
|
const cpu = process.cpuUsage(lastCpu);
|
|
@@ -31204,7 +31550,7 @@ function makeRenderProfiler() {
|
|
|
31204
31550
|
let lastFrameAt = 0;
|
|
31205
31551
|
return ({ renderTime } = {}) => {
|
|
31206
31552
|
ackRenderedFrame();
|
|
31207
|
-
const now =
|
|
31553
|
+
const now = performance4.now();
|
|
31208
31554
|
const ms = Number(renderTime) || 0;
|
|
31209
31555
|
const gap = lastFrameAt ? now - lastFrameAt : 0;
|
|
31210
31556
|
lastFrameAt = now;
|
|
@@ -31238,7 +31584,7 @@ function makeRenderProfiler() {
|
|
|
31238
31584
|
}
|
|
31239
31585
|
function bootProfile2(event, fields = {}) {
|
|
31240
31586
|
if (!BOOT_PROFILE_ENABLED2) return;
|
|
31241
|
-
const elapsedMs =
|
|
31587
|
+
const elapsedMs = performance4.now() - BOOT_PROFILE_START2;
|
|
31242
31588
|
const parts = [`[mixdog-boot] +${elapsedMs.toFixed(1)}ms`, `tui:${event}`];
|
|
31243
31589
|
for (const [key, value] of Object.entries(fields || {})) {
|
|
31244
31590
|
if (value === void 0 || value === null || value === "") continue;
|
|
@@ -31456,7 +31802,7 @@ function installTuiConsoleGuard() {
|
|
|
31456
31802
|
};
|
|
31457
31803
|
}
|
|
31458
31804
|
async function runTui({ provider, model, toolMode, remote, forceOnboarding } = {}) {
|
|
31459
|
-
const startedAt =
|
|
31805
|
+
const startedAt = performance4.now();
|
|
31460
31806
|
bootProfile2("run:start", { provider, model, toolMode, remote });
|
|
31461
31807
|
if (!process.stdin.isTTY) {
|
|
31462
31808
|
process.stderr.write(
|
|
@@ -31487,6 +31833,7 @@ async function runTui({ provider, model, toolMode, remote, forceOnboarding } = {
|
|
|
31487
31833
|
process.stdout.write(`${TERMINAL_MODE_RESET_HIDDEN_CURSOR}\x1B[?1049h${TERMINAL_MODE_RESET_HIDDEN_CURSOR}\x1B[2J\x1B[H`);
|
|
31488
31834
|
process.stdout.write("\x1B[5 q");
|
|
31489
31835
|
process.on("exit", restoreTerminal);
|
|
31836
|
+
const storeOutcomePromise = createEngineSession({ provider, model, toolMode, remote }).then((store2) => ({ store: store2, error: null }), (error) => ({ store: null, error }));
|
|
31490
31837
|
try {
|
|
31491
31838
|
await loadThemeSettingFromConfig();
|
|
31492
31839
|
} catch {
|
|
@@ -31496,8 +31843,10 @@ async function runTui({ provider, model, toolMode, remote, forceOnboarding } = {
|
|
|
31496
31843
|
} };
|
|
31497
31844
|
let store;
|
|
31498
31845
|
try {
|
|
31499
|
-
|
|
31500
|
-
|
|
31846
|
+
const outcome = await storeOutcomePromise;
|
|
31847
|
+
if (outcome.error) throw outcome.error;
|
|
31848
|
+
store = outcome.store;
|
|
31849
|
+
bootProfile2("store:ready", { ms: (performance4.now() - startedAt).toFixed(1) });
|
|
31501
31850
|
} catch (error) {
|
|
31502
31851
|
splash.stop();
|
|
31503
31852
|
stopPerfProbe();
|
|
@@ -31562,8 +31911,8 @@ async function runTui({ provider, model, toolMode, remote, forceOnboarding } = {
|
|
|
31562
31911
|
registerStdioDeath(process.stderr, "error", { requireCode: true });
|
|
31563
31912
|
registerStdioDeath(process.stderr, "close");
|
|
31564
31913
|
try {
|
|
31565
|
-
const instance = render(/* @__PURE__ */ jsx21(App, { store, forceOnboarding: forceOnboarding === true }), { exitOnCtrlC: false, maxFps:
|
|
31566
|
-
bootProfile2("render:mounted", { ms: (
|
|
31914
|
+
const instance = render(/* @__PURE__ */ jsx21(App, { store, forceOnboarding: forceOnboarding === true }), { exitOnCtrlC: false, maxFps: TUI_RENDER_FPS, incrementalRendering: true, patchConsole: false, onRender: makeRenderProfiler() });
|
|
31915
|
+
bootProfile2("render:mounted", { ms: (performance4.now() - startedAt).toFixed(1) });
|
|
31567
31916
|
const { waitUntilExit } = instance;
|
|
31568
31917
|
if (mouseTracking && typeof instance.setSelection === "function") {
|
|
31569
31918
|
store.setRenderSelection = instance.setSelection;
|