mixdog 0.9.66 → 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.
@@ -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"
@@ -5844,7 +5839,7 @@ var SPINNER_VERBS = [
5844
5839
  ];
5845
5840
  var SPINNER_FRAMES = ["\u25C7", "\u25C6", "\u25C8", "\u25C6", "\u25C7"];
5846
5841
 
5847
- // src/tui/time-format.mjs
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);
@@ -17401,46 +17396,26 @@ function createChannelPickers({
17401
17396
  }
17402
17397
  if (focus === "webhook-endpoint") {
17403
17398
  const returnTo = typeof options.returnTo === "function" ? options.returnTo : () => setPicker(null);
17404
- const domain = setup.webhook?.ngrokDomain || setup.webhook?.domain || "";
17399
+ const publicUrl = setup.webhook?.publicUrl || "";
17405
17400
  const items2 = [
17406
17401
  {
17407
- value: "endpoint-domain",
17408
- label: "ngrok domain",
17409
- description: domain ? domain : "Not set \xB7 Enter ngrok domain",
17410
- _action: "endpoint-domain"
17411
- },
17412
- {
17413
- value: "endpoint-authtoken",
17414
- label: "authtoken",
17415
- description: setup.webhook?.authenticated === true ? "Set" : "Not set \xB7 Enter authtoken",
17416
- _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"
17417
17406
  }
17418
17407
  ];
17419
17408
  setPicker({
17420
17409
  title: "Webhook endpoint",
17421
- description: "ngrok domain and authtoken. Toggle individual webhooks in /webhooks.",
17410
+ description: "Served through the Mixdog relay \u2014 no tunnel setup needed. Toggle individual webhooks in /webhooks.",
17422
17411
  help: "\u2191/\u2193 Select \xB7 Enter Edit \xB7 Esc Back",
17423
17412
  indexMode: "always",
17424
17413
  labelWidth: 18,
17425
17414
  items: items2,
17426
17415
  onSelect: (_value, item) => {
17427
17416
  try {
17428
- if (item._action === "endpoint-domain") {
17429
- openChannelPrompt({
17430
- kind: "webhook-domain",
17431
- label: "ngrok domain",
17432
- hint: "Paste the reserved ngrok domain (e.g. my-app.ngrok-free.app).",
17433
- afterSave: () => void openChannelSetupPicker("webhook-endpoint", options)
17434
- });
17435
- return;
17436
- }
17437
- if (item._action === "endpoint-authtoken") {
17438
- openChannelPrompt({
17439
- kind: "webhook-token",
17440
- label: "Webhook/ngrok authtoken",
17441
- hint: "Paste the webhook/ngrok authtoken. It is stored in the OS keychain.",
17442
- afterSave: () => void openChannelSetupPicker("webhook-endpoint", options)
17443
- });
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");
17444
17419
  }
17445
17420
  } catch (e) {
17446
17421
  store.pushNotice(`webhook endpoint failed: ${e?.message || e}`, "error");
@@ -17575,20 +17550,10 @@ function createChannelPickers({
17575
17550
  {
17576
17551
  value: "webhook-endpoint",
17577
17552
  label: "Webhook endpoint",
17578
- meta: (() => {
17579
- const hasDomain = Boolean(setup.webhook?.ngrokDomain || setup.webhook?.domain);
17580
- const hasAuth = setup.webhook?.authenticated === true;
17581
- return hasDomain && hasAuth ? "On" : "Off";
17582
- })(),
17583
- description: (() => {
17584
- const hasDomain = Boolean(setup.webhook?.ngrokDomain || setup.webhook?.domain);
17585
- const hasAuth = setup.webhook?.authenticated === true;
17586
- const needs = [
17587
- ...hasDomain ? [] : ["domain"],
17588
- ...hasAuth ? [] : ["authtoken"]
17589
- ];
17590
- return needs.length ? `Needs ${needs.join(" + ")}` : "ngrok domain and authtoken set";
17591
- })(),
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",
17592
17557
  _action: "webhook-endpoint"
17593
17558
  }
17594
17559
  ];
@@ -20400,7 +20365,7 @@ import React16 from "react";
20400
20365
  import { Box as Box14, Text as Text16 } from "../../../vendor/ink/build/index.js";
20401
20366
  import stringWidth9 from "string-width";
20402
20367
 
20403
- // src/tui/components/tool-execution/text-format.mjs
20368
+ // src/runtime/shared/tool-card-model.mjs
20404
20369
  import stripAnsi6 from "strip-ansi";
20405
20370
 
20406
20371
  // src/runtime/shared/tool-status.mjs
@@ -20424,7 +20389,7 @@ function toolResultTerminalStatus(text) {
20424
20389
  return normalizeToolTerminalStatus(inline);
20425
20390
  }
20426
20391
 
20427
- // src/tui/components/tool-execution/text-format.mjs
20392
+ // src/runtime/shared/tool-card-model.mjs
20428
20393
  var MIN_RESULT_LINE_CHARS = 24;
20429
20394
  var RESULT_LINE_HARD_MAX = 80;
20430
20395
  var SUMMARY_MAX_CHARS = 48;
@@ -20448,47 +20413,9 @@ function normalizeCountMap(value = {}) {
20448
20413
  }
20449
20414
  return out;
20450
20415
  }
20451
- function deltaColor(token) {
20452
- return String(token || "").startsWith("+") ? theme.success : theme.error;
20453
- }
20454
- function deltaTextParts(text) {
20455
- const value = String(text ?? "");
20456
- const parts = [];
20457
- const re = /(^|[\s([,{·])([+-]\s*\d+)(?=\s+Lines?\b)/gi;
20458
- let last = 0;
20459
- let match;
20460
- while (match = re.exec(value)) {
20461
- const prefix = match[1] || "";
20462
- const token = (match[2] || "").replace(/\s+/g, "");
20463
- const tokenStart = match.index + prefix.length;
20464
- if (match.index > last) parts.push({ text: value.slice(last, match.index) });
20465
- if (prefix) parts.push({ text: prefix });
20466
- if (token) parts.push({ text: token, color: deltaColor(token) });
20467
- last = tokenStart + (match[2] || "").length;
20468
- }
20469
- if (last < value.length) parts.push({ text: value.slice(last) });
20470
- return parts;
20471
- }
20472
20416
  function plural(count, singular, pluralText = `${singular}s`) {
20473
20417
  return count === 1 ? singular : pluralText;
20474
20418
  }
20475
- function fitResultLine(line, columns) {
20476
- const max = Math.min(RESULT_LINE_HARD_MAX, Math.max(MIN_RESULT_LINE_CHARS, Number(columns || 80) - 7));
20477
- const text = safeInlineText(line);
20478
- return displayWidth(text) > max ? truncateToWidth(text, max) : text;
20479
- }
20480
- function truncateToWidth(text, maxWidth) {
20481
- const str = safeInlineText(text);
20482
- if (maxWidth < 1) return "";
20483
- if (displayWidth(str) <= maxWidth) return str;
20484
- const chars = Array.from(str);
20485
- let out = "";
20486
- for (const ch of chars) {
20487
- if (displayWidth(out + ch + "\u2026") > maxWidth) break;
20488
- out += ch;
20489
- }
20490
- return `${out}\u2026`;
20491
- }
20492
20419
  function shellResultStatus(value) {
20493
20420
  const match = String(value || "").match(/(?:^|\b)status:\s*(running|pending|queued|completed|failed|cancelled|canceled)\b/im);
20494
20421
  return match ? String(match[1] || "").toLowerCase() : "";
@@ -20524,8 +20451,6 @@ function shellResultElapsed(value) {
20524
20451
  const elapsedMs = Number(match[1]);
20525
20452
  return Number.isFinite(elapsedMs) && elapsedMs >= 1e3 ? formatElapsed(elapsedMs) : "";
20526
20453
  }
20527
-
20528
- // src/tui/components/tool-execution/surface-detail.mjs
20529
20454
  function isShellTool(normalizedName, label = "") {
20530
20455
  const n = String(normalizedName || "").toLowerCase();
20531
20456
  const l = String(label || "").toLowerCase();
@@ -20857,6 +20782,248 @@ function clampFailureCount(errorCount, groupCount, isError) {
20857
20782
  if (Number.isFinite(explicit)) return Math.max(0, Math.min(groupCount, Math.floor(explicit)));
20858
20783
  return isError ? groupCount : 0;
20859
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
20860
21027
  function toolStatusColor({ pending, groupCount, callFailedCount = 0, exitFailedCount = 0, terminalStatus = "" }) {
20861
21028
  if (pending) return theme.text;
20862
21029
  const status = normalizeTerminalStatus(terminalStatus);
@@ -20895,9 +21062,6 @@ import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
20895
21062
  var TOOL_BLINK_MS = 500;
20896
21063
  var TOOL_PENDING_SHOW_DELAY_MS = 1e3;
20897
21064
  var TOOL_ANIM_TICK_MS = TOOL_BLINK_MS;
20898
- function statusCopy(name, label, count, doneCount, pending, isError, args = {}) {
20899
- return formatToolActionHeader(name, args, { pending, count });
20900
- }
20901
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 }) {
20902
21066
  const rowWidth = Math.max(1, Number(columns || 80));
20903
21067
  const groupCount = Math.max(1, Number(count || 1));
@@ -20984,87 +21148,60 @@ function ToolExecution({ name, args, result, rawResult, isError, errorCount, cal
20984
21148
  )
20985
21149
  ] });
20986
21150
  }
20987
- const { label, summary, normalizedName, args: parsedArgs } = formatToolSurface(name, args);
20988
- const isShellSurface = isShellTool(normalizedName, label);
20989
- const isSkillSurface = SKILL_SURFACE_NAMES2.has(String(normalizedName || "").toLowerCase());
20990
- const backgroundMeta = !pending && isBackgroundTaskTool(normalizedName) ? resolveBackgroundTaskMeta(parsedArgs, rt || "") : null;
20991
- const backgroundError = backgroundMeta?.error || parsedArgs?.error || "";
20992
- const errorOnlyResult = Boolean(rt) && isBackgroundErrorOnlyBody(rt, backgroundError);
20993
- const backgroundResultText = backgroundMeta?.hasResponse ? backgroundMeta.body : "";
20994
- const displayedResultText = backgroundResultText || (errorOnlyResult ? "" : rt || "");
20995
- const hasDisplayResult = Boolean(String(displayedResultText || "").trim());
20996
- const displayedResultBodyText = stripLeadingStatusMarkerFromText(displayedResultText);
20997
- const hasDisplayBody = Boolean(String(displayedResultBodyText || "").trim());
20998
- const lines = displayedResultBodyText ? displayedResultBodyText.split("\n") : [];
20999
- const totalLines = lines.length;
21000
- const resultSummary = !pending && hasDisplayBody ? summarizeToolResult(name, args, displayedResultBodyText, isError) : null;
21001
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") : [];
21002
21190
  const resultColor = theme.text;
21003
- const firstResultLine = hasDisplayResult ? String(lines[0] ?? "") : "";
21004
21191
  const firstResultLineClipped = hasDisplayBody && stringWidth9(firstResultLine) > maxResultChars;
21005
21192
  const hasHiddenDetail = !pending && hasDisplayBody && (totalLines > 1 || firstResultLineClipped || Boolean(resultSummary));
21006
- const shellStatus = isShellSurface ? shellDisplayStatus({ pending, failedCount, exitFailedCount, isError, result: displayedResultText }) : "";
21007
- const shellElapsed = isShellSurface ? shellResultElapsed(displayedResultText) || elapsed : "";
21008
- const backgroundElapsed = backgroundMeta ? backgroundTaskElapsed(backgroundMeta, elapsed) : isBackgroundTaskTool(normalizedName) ? backgroundTaskElapsed(parsedArgs, elapsed) : "";
21009
- const toolArgPath = parsedArgs?.path ?? parsedArgs?.file_path ?? parsedArgs?.file ?? "";
21010
- const imageDetail = normalizedName === "view_image" && toolArgPath && !isError ? String(toolArgPath) : "";
21011
- const isBackgroundResult = !pending && isBackgroundTaskTool(normalizedName) && Boolean(backgroundMeta);
21012
- const isBackgroundResponse = isBackgroundResult && (backgroundMeta?.hasResponse || isBackgroundTaskResponseArgs(normalizedName, parsedArgs));
21013
- const isBackgroundMetadataResult = isBackgroundResult && !isBackgroundResponse && Boolean(backgroundMeta);
21014
- const backgroundMetadataFailureLabel = isBackgroundMetadataResult ? backgroundTaskFailureDetail(backgroundMeta, parsedArgs) : "";
21015
- const backgroundMetadataHeaderFailure = Boolean(backgroundMetadataFailureLabel) && !hasDisplayResult ? backgroundMetadataFailureLabel : "";
21016
- const agentHeaderFailure = !pending && isAgentTool(normalizedName) && isError && parsedArgs?.error && !hasDisplayResult ? backgroundTaskFailureStatusLabel(parsedArgs?.status, parsedArgs?.error, { surface: "agent" }) : "";
21017
- const headerFailureStatus = backgroundMetadataHeaderFailure || agentHeaderFailure || "";
21018
- const agentCompletionDetail = !pending && isAgentTool(normalizedName) && !agentHeaderFailure ? agentTerminalDetail(parsedArgs?.status, isError, elapsed, parsedArgs?.error) : "";
21019
- const agentDetail = !pending && isAgentTool(normalizedName) && !hasDisplayResult ? agentCompletionDetail : "";
21020
- const genericDetail = !pending && !isShellSurface && !agentDetail && !imageDetail && !resultSummary ? genericCompletedDetail({ normalizedName, label, hasResult, firstResultLine, isError }) : "";
21021
- const terminalStatus = pending ? "running" : shellStatus || normalizeTerminalStatus(backgroundMeta?.status) || normalizeTerminalStatus(parsedArgs?.status) || resultTerminalStatus(displayedResultText) || (isError || failedCount > 0 ? "failed" : "completed");
21022
- const backgroundMetadataDetail = isBackgroundMetadataResult && !backgroundMetadataHeaderFailure ? backgroundTaskDetail(backgroundMeta, backgroundElapsed, parsedArgs) : "";
21023
- const backgroundResponseDetail = isBackgroundResponse && resultSummary ? prefixElapsed(resultSummary, backgroundElapsed) : resultSummary;
21024
- const syncElapsedDetail = !isBackgroundResponse && shouldPrefixSyncElapsed(normalizedName, label) ? prefixElapsed(backgroundResponseDetail, elapsed) : backgroundResponseDetail;
21025
- const nonShellDetail = backgroundMetadataDetail || (/^(Cancelled|Failed|Finished)$/i.test(resultSummary || "") && agentCompletionDetail ? agentCompletionDetail : syncElapsedDetail) || agentDetail || imageDetail || genericDetail;
21026
- const pendingDetailPlaceholder = pending && !isSkillSurface ? elapsed ? `Running \xB7 ${elapsed}` : "Running" : "";
21027
- const shellCollapsedSummary = isShellSurface && !pending && hasDisplayResult ? resultSummary || truncateToWidth(firstResultLine, Math.min(120, maxResultChars)) : resultSummary;
21028
- const collapsedDetail = pending ? pendingDetailPlaceholder : isShellSurface ? prefixElapsed(mergeTerminalDetail(shellStatus, shellCollapsedSummary), shellElapsed) : mergeTerminalDetail(terminalStatus, nonShellDetail);
21029
21193
  const backgroundMetadataExpandable = isBackgroundMetadataResult && hasRawResult && !pending;
21030
21194
  const showRawResult = expanded && (hasDisplayBody || hasRawResult) && (!isBackgroundMetadataResult || hasRawResult);
21031
- const detailLines = showRawResult ? agentResponseAggregate && hasRawResult ? stripLeadingStatusMarkerLines(rawRt.split("\n")) : hasDisplayBody ? lines : rawRt ? stripLeadingStatusMarkerLines(rawRt.split("\n")) : [] : collapsedDetail ? [collapsedDetail] : [];
21032
- const isPendingPlaceholderDetail = !showRawResult && Boolean(pendingDetailPlaceholder);
21195
+ const detailLines = showRawResult ? agentResponseAggregate && hasRawResult ? stripLeadingStatusMarkerLines(rawRt.split("\n")) : hasDisplayBody ? lines : rawRt ? stripLeadingStatusMarkerLines(rawRt.split("\n")) : [] : collapsedDetailLine ? [collapsedDetailLine] : [];
21196
+ const isPendingPlaceholderDetail = !showRawResult && detailIsPlaceholder;
21033
21197
  const detailColor = isPendingPlaceholderDetail ? theme.subtle : theme.text;
21034
- const isAgentResult = !isBackgroundResult && !pending && isAgentTool(normalizedName) && hasDisplayResult;
21035
- const isAgentResponse = isAgentResult && hasAgentResponseResult(rt);
21036
- const isAgentSurfaceCard = isAgentTool(normalizedName);
21037
- const agentSurfaceBriefRaw = isAgentSurfaceCard && !showRawResult ? summarizeAgentSurfaceBrief(name, parsedArgs, displayedResultText || "", { isError, isResponse: isAgentResponse }) : "";
21038
- const agentSurfaceBrief = agentSurfaceBriefRaw ? truncateToWidth(agentSurfaceBriefRaw, Math.min(AGENT_SURFACE_BRIEF_MAX, maxResultChars)) : "";
21039
- let visibleDetailLines = detailLines;
21040
- if (isSkillSurface && !showRawResult) {
21041
- visibleDetailLines = isError && collapsedDetail ? [collapsedDetail] : [];
21042
- } else if (isBackgroundMetadataResult && backgroundMetadataHeaderFailure && !showRawResult) {
21043
- visibleDetailLines = [];
21044
- } else if (isAgentSurfaceCard && !showRawResult) {
21045
- const agentDetailFallback = collapsedDetail || (pending ? pendingDetailPlaceholder || "Running" : "Finished");
21046
- const agentDetailLine = agentSurfaceBrief || truncateToWidth(String(agentDetailFallback), Math.min(AGENT_SURFACE_BRIEF_MAX, maxResultChars));
21047
- const agentFailureText = /\b(Cancelled|Canceled|Failed)\b/i.test(agentSurfaceBrief || collapsedDetail || "");
21048
- const keepAgentDetail = (isError || agentFailureText) && !(agentHeaderFailure && !agentSurfaceBrief);
21049
- visibleDetailLines = keepAgentDetail ? [agentDetailLine] : [];
21050
- }
21198
+ const visibleDetailLines = detailLines;
21051
21199
  const finalStatusColor = toolStatusColor({ pending, groupCount, callFailedCount, exitFailedCount, terminalStatus });
21052
21200
  const dotColor = finalStatusColor;
21053
21201
  const markerGlyph = isAgentResponse ? AGENT_RESPONSE_MARKER : isAgentSurfaceCard ? AGENT_CALL_MARKER : TURN_MARKER;
21054
21202
  const isDirectionalMarker = isAgentResponse || isAgentSurfaceCard;
21055
21203
  const markerText = isDirectionalMarker ? `${markerGlyph} ` : markerGlyph;
21056
21204
  const dotText = pending && !blinkOn ? " " : markerText;
21057
- let labelText;
21058
- if (isAgentResponse) labelText = agentResponseTitle(parsedArgs, displayGroupCount);
21059
- else if (isBackgroundResponse) labelText = backgroundTaskResultTitle(normalizedName, backgroundMeta || parsedArgs);
21060
- else if (isBackgroundMetadataResult) labelText = backgroundTaskActionTitle(normalizedName, backgroundMeta);
21061
- else if (isShellSurface) labelText = shellHeader(shellStatus, displayGroupCount);
21062
- else labelText = (isAgentTool(normalizedName) ? agentActionTitle(parsedArgs) : "") || statusCopy(name, label, displayGroupCount, doneCount, headerPending, isError, parsedArgs);
21063
- labelText = safeInlineText(labelText);
21064
- const toolSearchSummary = !pending && normalizedName === "load_tool" && hasResult ? toolSearchLoadedSummary(displayedResultText) : "";
21065
- const rawSummaryText = safeInlineText(isAgentResponse || isBackgroundResponse ? "" : toolSearchSummary || (isAgentTool(normalizedName) ? agentActionSummary(parsedArgs, summary) : summary));
21066
- const summaryIsHeaderCount = rawSummaryText && /^\d+\s+\S+$/.test(rawSummaryText) && labelText.endsWith(rawSummaryText);
21067
- const summaryText = summaryIsHeaderCount ? "" : rawSummaryText;
21068
21205
  const agentHasExpandableBody = isAgentSurfaceCard && !pending && hasResult && (isAgentResponse || totalLines > 1 || firstResultLineClipped);
21069
21206
  const shellHasExpandableBody = isShellSurface && !pending && hasDisplayResult && hasDisplayBody && (totalLines > 1 || firstResultLineClipped || Boolean(shellCollapsedSummary && shellCollapsedSummary !== firstResultLine));
21070
21207
  const showHeaderExpandHint = (isShellSurface ? shellHasExpandableBody : isAgentSurfaceCard ? agentHasExpandableBody : hasHiddenDetail || backgroundMetadataExpandable) && normalizedName !== "load_tool";
@@ -22681,19 +22818,6 @@ function App({ store, initialStatusLine = "", forceOnboarding = false }) {
22681
22818
  resumeAfterChannelPrompt(channelPrompt);
22682
22819
  return true;
22683
22820
  }
22684
- if (channelPrompt.kind === "webhook-token") {
22685
- if (!commandText) return false;
22686
- store.saveWebhookAuthtoken(commandText);
22687
- resumeAfterChannelPrompt(channelPrompt);
22688
- return true;
22689
- }
22690
- if (channelPrompt.kind === "webhook-domain") {
22691
- if (!commandText) return false;
22692
- Promise.resolve(store.setWebhookConfig?.({ ngrokDomain: commandText })).then(() => resumeAfterChannelPrompt(channelPrompt)).catch((e) => {
22693
- store.pushNotice(`webhook config update failed: ${e?.message || e}`, "error");
22694
- });
22695
- return true;
22696
- }
22697
22821
  const parts = commandText.split("|").map((part) => part.trim());
22698
22822
  if (channelPrompt.kind === "channel-add") {
22699
22823
  const isPipe = parts.length > 1;
@@ -23976,6 +24100,12 @@ var SYNTHETIC_SESSION_TEXT_PATTERNS = Object.freeze([
23976
24100
  /^\[mixdog-runtime\]/i,
23977
24101
  /^\[(?:truncated|request interrupted by user)\]$/i,
23978
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,
23979
24109
  /^the async (?:agent|shell) task\b/i
23980
24110
  ]);
23981
24111
  var LATE_TOOL_ANNOUNCEMENT_SENTINEL = "connected after this session started";
@@ -28375,16 +28505,6 @@ function createEngineApiB(bag) {
28375
28505
  pushNotice("telegram token forgotten", "info");
28376
28506
  return result;
28377
28507
  },
28378
- saveWebhookAuthtoken: (token) => {
28379
- const result = runtime.saveWebhookAuthtoken(token);
28380
- pushNotice("webhook/ngrok authtoken saved", "info");
28381
- return result;
28382
- },
28383
- forgetWebhookAuthtoken: () => {
28384
- const result = runtime.forgetWebhookAuthtoken();
28385
- pushNotice("webhook/ngrok authtoken forgotten", "info");
28386
- return result;
28387
- },
28388
28508
  setChannel: async (entry) => {
28389
28509
  const result = await runtime.setChannel(entry);
28390
28510
  pushNotice("channel saved", "info");
@@ -28801,7 +28921,6 @@ async function buildDoctorReport(runtime = {}, getState = () => ({})) {
28801
28921
  const tokens = [];
28802
28922
  if (setup.discord?.authenticated) tokens.push("discord");
28803
28923
  if (setup.telegram?.authenticated) tokens.push("telegram");
28804
- if (setup.webhook?.authenticated) tokens.push("webhook");
28805
28924
  const running = worker.running === true;
28806
28925
  const detail = `enabled \xB7 worker ${running ? "running" : "stopped"} \xB7 tokens: ${tokens.length ? tokens.join(", ") : "none"}`;
28807
28926
  row(running ? "ok" : "warn", detail);
@@ -29929,6 +30048,7 @@ function createLiveShare({
29929
30048
  const stopClient = () => {
29930
30049
  const closing = client;
29931
30050
  const closingId = clientId;
30051
+ const wasUp = clientUp;
29932
30052
  client = null;
29933
30053
  clientId = "";
29934
30054
  clientUp = false;
@@ -29940,6 +30060,7 @@ function createLiveShare({
29940
30060
  } catch {
29941
30061
  }
29942
30062
  }
30063
+ if (wasUp) clearMirroredLiveState();
29943
30064
  };
29944
30065
  const startClient = (id) => {
29945
30066
  let socket;