mastracode 0.48.0-alpha.8 → 0.48.0

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.
@@ -1,8 +1,9 @@
1
+ import { createRequire } from "module";
1
2
  import { execFile, execFileSync, spawn } from "child_process";
2
3
  import * as fs$1 from "fs";
3
4
  import fs, { existsSync, readFileSync, statSync, unlinkSync } from "fs";
4
5
  import { activateModePackInSettings, listResolvableModePacks, resolvePackSelection } from "@mastra/code-sdk/onboarding/pack-activation";
5
- import { MASTRA_GATEWAY_DEFAULT_URL, MASTRA_GATEWAY_PROVIDER, OBSERVABILITY_AUTH_PREFIX, THREAD_ACTIVE_MODEL_PACK_ID_KEY, THREAD_FALLBACK_STATUS_KEY, VIEWPORT_PRESETS, checkProfileProviderMismatch, createBrowserFromSettings, getCustomProviderId, loadSettings, migrateAccountPreferences, parseThreadSettings, parseViewportInput, pruneRemovedAccountPreferences, resolveDefaultThinkingLevel, resolveModePackModels, resolveStagehandModel, resolveThreadActiveModelPackId, saveSettings, setProfileProvider, stripMastraCodeCustomProviderPrefix, toActiveBrowserSettings, toCustomProviderModelId } from "@mastra/code-sdk/onboarding/settings";
6
+ import { MASTRA_GATEWAY_DEFAULT_URL, MASTRA_GATEWAY_PROVIDER, OBSERVABILITY_AUTH_PREFIX, STAGEHAND_PROVIDER_ENV_VARS, THREAD_ACTIVE_MODEL_PACK_ID_KEY, THREAD_FALLBACK_STATUS_KEY, VIEWPORT_PRESETS, checkProfileProviderMismatch, createBrowserFromSettings, getCustomProviderId, loadSettings, migrateAccountPreferences, parseThreadSettings, parseViewportInput, pruneRemovedAccountPreferences, resolveDefaultThinkingLevel, resolveModePackModels, resolveStagehandModel, resolveThreadActiveModelPackId, saveSettings, setProfileProvider, stripMastraCodeCustomProviderPrefix, toActiveBrowserSettings, toCustomProviderModelId } from "@mastra/code-sdk/onboarding/settings";
6
7
  import { fetchPlatformEnvironments, fetchPlatformOrgs, fetchPlatformProjects, getPlatformSession, loginToPlatform, resolveFactoryUrl } from "@mastra/code-sdk/platform/index";
7
8
  import { ThreadLockError } from "@mastra/code-sdk/utils/thread-lock";
8
9
  import { Box, CombinedAutocompleteProvider, Container, Editor, Input, Markdown, ProcessTerminal, SelectList, SettingsList, Spacer, TUI, Text, fuzzyFilter, getKeybindings, matchesKey, parseKey, truncateToWidth, visibleWidth, wrapTextWithAnsi } from "@earendil-works/pi-tui";
@@ -27,8 +28,6 @@ import { getDynamicInstructionSections } from "@mastra/code-sdk/agents/instructi
27
28
  import { formatSkillsCatalog } from "@mastra/core/processors";
28
29
  import { DEFAULT_STT_MODEL, defaultModelForProvider, resolveSTTModel, sttModelsForProvider, sttProviders } from "@mastra/code-sdk/voice/stt-registry";
29
30
  import { Readable } from "stream";
30
- import { DeepgramVoice } from "@mastra/voice-deepgram";
31
- import { OpenAIVoice } from "@mastra/voice-openai";
32
31
  import { THINK_COMMAND_DESCRIPTOR, isThinkingLevelSetting, parseThinkCommand } from "@mastra/code-sdk/thinking";
33
32
  import { getCatalogThinkingLevels, runCatalogThinkingLevel } from "@mastra/code-sdk/thinking-catalog";
34
33
  import { VALID_EVENTS } from "@mastra/code-sdk/hooks/index";
@@ -42,7 +41,6 @@ import { generatePlanDiff, shouldShowDiff } from "@mastra/code-sdk/utils/plan-di
42
41
  import { safeStringify } from "@mastra/core/utils";
43
42
  import process$1 from "process";
44
43
  import { MC_TOOLS } from "@mastra/code-sdk/tool-names";
45
- import { highlight } from "cli-highlight";
46
44
  import { TOOL_CATEGORIES, getToolCategory } from "@mastra/code-sdk/permissions";
47
45
  import { parse } from "jsonriver";
48
46
  import { detectProject, getCurrentGitBranchAsync, getUserName } from "@mastra/code-sdk/utils/project";
@@ -52,11 +50,10 @@ import { access, mkdir, mkdtemp, readFile, rm, stat, writeFile } from "fs/promis
52
50
  import { stripVTControlCharacters } from "util";
53
51
  import { getAvailableModePacks as getAvailableModePacks$1, getBuiltinModePack, resolveAutoOMModelId, resolveModePackFallbackChain } from "@mastra/code-sdk/onboarding/packs";
54
52
  import { removeCustomPackFromSettings } from "@mastra/code-sdk/onboarding/custom-packs";
55
- import { getActiveRouteMemoryModelId } from "@mastra/code-sdk/agents/model";
53
+ import { canUseProvider, getActiveRouteMemoryModelId } from "@mastra/code-sdk/agents/model";
56
54
  import { removeCustomProviderFromSettings, upsertCustomProviderInSettings } from "@mastra/code-sdk/onboarding/custom-providers";
57
55
  import { applyOmRoleAuto, applyOmRoleOverride, persistOmObserveAttachments } from "@mastra/code-sdk/onboarding/om-settings";
58
56
  import { getCredentialProviderId, remapOpenAIModelForCodexOAuth } from "@mastra/code-sdk/providers/model-ids";
59
- import { STAGEHAND_MODEL_PROVIDERS } from "@mastra/stagehand";
60
57
  import { getOAuthProviders as getOAuthProviders$1 } from "@mastra/code-sdk/auth/index";
61
58
  import { createFactoryUserSession, listFactoryProjects } from "@mastra/code-sdk/factory/client";
62
59
  import { GatewayRegistry } from "@mastra/core/llm";
@@ -2863,15 +2860,16 @@ var ModelSelectorComponent = class extends Box {
2863
2860
  this.selectedIndex = this.selectedIndex === totalItems - 1 ? 0 : this.selectedIndex + 1;
2864
2861
  this.updateList();
2865
2862
  this.tui.requestRender();
2866
- } else if (kb.matches(keyData, "tui.select.confirm")) if (this.hasCustomItem && this.selectedIndex === 0) {
2867
- const query = this.searchInput.getValue().trim();
2868
- if (query) this.handleSelect(this.makeCustomModelItem(query));
2869
- } else {
2870
- const modelIndex = this.hasCustomItem ? this.selectedIndex - 1 : this.selectedIndex;
2871
- const selected = this.filteredModels[modelIndex];
2872
- if (selected) this.handleSelect(selected);
2873
- }
2874
- else if (kb.matches(keyData, "tui.select.cancel")) this.onCancelCallback();
2863
+ } else if (kb.matches(keyData, "tui.select.confirm")) {
2864
+ if (this.hasCustomItem && this.selectedIndex === 0) {
2865
+ const query = this.searchInput.getValue().trim();
2866
+ if (query) this.handleSelect(this.makeCustomModelItem(query));
2867
+ } else {
2868
+ const modelIndex = this.hasCustomItem ? this.selectedIndex - 1 : this.selectedIndex;
2869
+ const selected = this.filteredModels[modelIndex];
2870
+ if (selected) this.handleSelect(selected);
2871
+ }
2872
+ } else if (kb.matches(keyData, "tui.select.cancel")) this.onCancelCallback();
2875
2873
  else {
2876
2874
  this.searchInput.handleInput(keyData);
2877
2875
  this.filterModels(this.searchInput.getValue());
@@ -3866,7 +3864,8 @@ async function collectSkillsCatalog(ctx) {
3866
3864
  const listed = await workspace.skills.list();
3867
3865
  if (listed.length === 0) return void 0;
3868
3866
  const skills = (await Promise.all(listed.map((meta) => workspace.skills.get(meta.path)))).filter((skill) => !!skill);
3869
- return formatSkillsCatalog(Array.from(new Map(skills.map((skill) => [skill.path, skill])).values()).map((skill) => ({
3867
+ const deduped = Array.from(new Map(skills.map((skill) => [skill.path, skill])).values());
3868
+ return formatSkillsCatalog(deduped.map((skill) => ({
3870
3869
  name: skill.name,
3871
3870
  description: skill.description,
3872
3871
  location: `${skill.path}/SKILL.md`,
@@ -4125,8 +4124,10 @@ var WrappingSelectList = class {
4125
4124
  this.notifySelectionChange();
4126
4125
  } else if (this.multiSelect && keyData === " ") {
4127
4126
  const current = this.filteredItems[this.selectedIndex];
4128
- if (current) if (this.checkedValues.has(current.value)) this.checkedValues.delete(current.value);
4129
- else this.checkedValues.add(current.value);
4127
+ if (current) {
4128
+ if (this.checkedValues.has(current.value)) this.checkedValues.delete(current.value);
4129
+ else this.checkedValues.add(current.value);
4130
+ }
4130
4131
  } else if (kb.matches(keyData, "tui.select.confirm")) {
4131
4132
  if (this.multiSelect) {
4132
4133
  const checked = this.items.filter((item) => this.checkedValues.has(item.value));
@@ -4140,7 +4141,8 @@ var WrappingSelectList = class {
4140
4141
  renderItem(item, isSelected, width) {
4141
4142
  const labelText = this.getDisplayValue(item);
4142
4143
  const checkboxWidth = this.multiSelect ? CHECKBOX_WIDTH : 0;
4143
- const wrapped = wrapTextWithAnsi(labelText, Math.max(1, width - PREFIX_WIDTH - checkboxWidth));
4144
+ const labelWidth = Math.max(1, width - PREFIX_WIDTH - checkboxWidth);
4145
+ const wrapped = wrapTextWithAnsi(labelText, labelWidth);
4144
4146
  const checkbox = this.multiSelect ? this.checkedValues.has(item.value) ? CHECKBOX_CHECKED : CHECKBOX_UNCHECKED : "";
4145
4147
  if (this.cardStyle) {
4146
4148
  const style = this.cardStyle;
@@ -4433,11 +4435,15 @@ function resolveProviderApiKey(provider, authStorage) {
4433
4435
  * - everything else: `OpenAIVoice`, where `listeningModel.name` is the model id
4434
4436
  * and `options.baseURL` redirects OpenAI-compatible hosts at their endpoint.
4435
4437
  */
4436
- function buildVoice(entry, apiKey) {
4437
- if (entry.resolver === "deepgram") return new DeepgramVoice({ listeningModel: {
4438
- name: entry.model,
4439
- apiKey
4440
- } });
4438
+ async function buildVoice(entry, apiKey) {
4439
+ if (entry.resolver === "deepgram") {
4440
+ const { DeepgramVoice } = await import("@mastra/voice-deepgram");
4441
+ return new DeepgramVoice({ listeningModel: {
4442
+ name: entry.model,
4443
+ apiKey
4444
+ } });
4445
+ }
4446
+ const { OpenAIVoice } = await import("@mastra/voice-openai");
4441
4447
  return new OpenAIVoice({ listeningModel: {
4442
4448
  name: entry.model,
4443
4449
  apiKey,
@@ -4455,8 +4461,9 @@ function createTranscriber(options = {}) {
4455
4461
  const apiKey = resolveProviderApiKey(entry.provider, options.authStorage);
4456
4462
  if (!apiKey) throw new VoiceCredentialError(entry.provider);
4457
4463
  const voice = buildVoice(entry, apiKey);
4464
+ voice.catch(() => {});
4458
4465
  return { async transcribe(audio) {
4459
- return normalizeTranscript(await voice.listen(Readable.from(audio), { filetype: "wav" }));
4466
+ return normalizeTranscript(await (await voice).listen(Readable.from(audio), { filetype: "wav" }));
4460
4467
  } };
4461
4468
  }
4462
4469
  /**
@@ -5392,7 +5399,6 @@ var McpSelectorComponent = class extends Box {
5392
5399
  case "inherit":
5393
5400
  this.subMenuOpen = false;
5394
5401
  this.doInheritServer(status);
5395
- break;
5396
5402
  }
5397
5403
  }
5398
5404
  doSetServerDisabled(status, disabled, global) {
@@ -5629,7 +5635,10 @@ function sendNotification(reason, opts) {
5629
5635
  hookManager?.runNotification(reason, message);
5630
5636
  }
5631
5637
  function sendSystemNotification(reason, message) {
5632
- if (process.platform === "darwin") execFile("osascript", ["-e", `display notification "${(message || reasonToMessage(reason)).replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}" with title "Mastra Code"`], () => {});
5638
+ if (process.platform === "darwin") {
5639
+ const script = `display notification "${(message || reasonToMessage(reason)).replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}" with title "Mastra Code"`;
5640
+ execFile("osascript", ["-e", script], () => {});
5641
+ }
5633
5642
  }
5634
5643
  function reasonToMessage(reason) {
5635
5644
  switch (reason) {
@@ -7651,9 +7660,7 @@ var PlanApprovalInlineComponent = class PlanApprovalInlineComponent extends Cont
7651
7660
  case "goal":
7652
7661
  this.handleGoal();
7653
7662
  break;
7654
- case "changes":
7655
- this.handleReject();
7656
- break;
7663
+ case "changes": this.handleReject();
7657
7664
  }
7658
7665
  }
7659
7666
  handleApprove() {
@@ -8394,6 +8401,161 @@ function formatStatusDuration(ms, opts = {}) {
8394
8401
  return `${Math.max(1, minutes)}m`;
8395
8402
  }
8396
8403
  //#endregion
8404
+ //#region src/tui/syntax-highlight.ts
8405
+ /**
8406
+ * Terminal syntax highlighting on highlight.js core.
8407
+ *
8408
+ * `cli-highlight` loads every highlight.js language (192 files) and parse5 up front, about 23 MB per
8409
+ * session. This registers a language (and the languages it embeds) the first time a file of that kind
8410
+ * is shown, and colors highlight.js's HTML with the same rules cli-highlight used, so previews look
8411
+ * the same.
8412
+ */
8413
+ const require = createRequire(import.meta.url);
8414
+ /**
8415
+ * Syntax roles mapped onto the theme's semantic colors. theme.fg resolves the
8416
+ * active theme lazily and contrast-adapts, so code previews recolor with
8417
+ * custom themes and stay readable on any background.
8418
+ */
8419
+ const CODE_HIGHLIGHT_THEME = {
8420
+ default: (text) => theme.fg("toolArgs", text),
8421
+ keyword: (text) => theme.fg("textHighlight", text),
8422
+ built_in: (text) => theme.fg("function", text),
8423
+ type: (text) => theme.fg("function", text),
8424
+ literal: (text) => theme.fg("error", text),
8425
+ number: (text) => theme.fg("number", text),
8426
+ string: (text) => theme.fg("success", text),
8427
+ regexp: (text) => theme.fg("error", text),
8428
+ title: (text) => theme.fg("function", text),
8429
+ function: (text) => theme.fg("function", text),
8430
+ params: (text) => theme.fg("secondary", text),
8431
+ comment: (text) => theme.fg("muted", text),
8432
+ meta: (text) => theme.fg("muted", text),
8433
+ attr: (text) => theme.fg("number", text),
8434
+ variable: (text) => theme.fg("secondary", text),
8435
+ tag: (text) => theme.fg("textHighlight", text),
8436
+ name: (text) => theme.fg("textHighlight", text)
8437
+ };
8438
+ const plain = (text) => text;
8439
+ /** cli-highlight's DEFAULT_THEME: what a scope gets when the theme above doesn't name it. */
8440
+ const FALLBACK_THEME = {
8441
+ keyword: chalk.blue,
8442
+ built_in: chalk.cyan,
8443
+ type: chalk.cyan.dim,
8444
+ literal: chalk.blue,
8445
+ number: chalk.green,
8446
+ regexp: chalk.red,
8447
+ string: chalk.red,
8448
+ class: chalk.blue,
8449
+ function: chalk.yellow,
8450
+ comment: chalk.green,
8451
+ doctag: chalk.green,
8452
+ meta: chalk.grey,
8453
+ tag: chalk.grey,
8454
+ name: chalk.blue,
8455
+ attr: chalk.cyan,
8456
+ emphasis: chalk.italic,
8457
+ strong: chalk.bold,
8458
+ link: chalk.underline,
8459
+ addition: chalk.green,
8460
+ deletion: chalk.red
8461
+ };
8462
+ let hljs;
8463
+ function getHljs() {
8464
+ hljs ??= require("highlight.js/lib/core");
8465
+ return hljs;
8466
+ }
8467
+ /** Names highlight.js only knows as an alias of another language's file. */
8468
+ const LANGUAGE_FILES = { html: "xml" };
8469
+ /** Languages a grammar hands parts of the code to (`<script>` in HTML, `RUN` in a Dockerfile). */
8470
+ function subLanguagesOf(language) {
8471
+ const found = /* @__PURE__ */ new Set();
8472
+ const seen = /* @__PURE__ */ new Set();
8473
+ const visit = (mode) => {
8474
+ if (!mode || typeof mode !== "object" || seen.has(mode)) return;
8475
+ seen.add(mode);
8476
+ const { subLanguage, contains, variants, starts } = mode;
8477
+ for (const name of [subLanguage].flat()) if (typeof name === "string") found.add(name);
8478
+ for (const child of [contains, variants].flat()) visit(child);
8479
+ visit(starts);
8480
+ };
8481
+ visit(language);
8482
+ return [...found];
8483
+ }
8484
+ /**
8485
+ * Register a language on first use, along with the languages it embeds, so they highlight as they
8486
+ * did when every language was loaded. False when highlight.js has no such language.
8487
+ */
8488
+ function ensureLanguage(language) {
8489
+ const core = getHljs();
8490
+ if (core.getLanguage(language)) return true;
8491
+ const file = LANGUAGE_FILES[language] ?? language;
8492
+ try {
8493
+ core.registerLanguage(file, require(`highlight.js/lib/languages/${file}`));
8494
+ } catch {
8495
+ return false;
8496
+ }
8497
+ const registered = core.getLanguage(language);
8498
+ if (!registered) return false;
8499
+ for (const embedded of subLanguagesOf(registered)) ensureLanguage(embedded);
8500
+ return true;
8501
+ }
8502
+ const ENTITIES = {
8503
+ amp: "&",
8504
+ lt: "<",
8505
+ gt: ">",
8506
+ quot: "\"",
8507
+ "#x27": "'",
8508
+ "#39": "'"
8509
+ };
8510
+ /** Parse highlight.js output, which only ever contains `<span class="…">` and escaped text. */
8511
+ function parseHighlightHtml(html) {
8512
+ const root = [];
8513
+ const stack = [root];
8514
+ for (const match of html.matchAll(/<span class="([^"]*)">|<\/span>|&(amp|lt|gt|quot|#x27|#39);|[^<&]+|[<&]/g)) {
8515
+ const children = stack[stack.length - 1];
8516
+ if (match[1] !== void 0) {
8517
+ const span = {
8518
+ className: match[1],
8519
+ children: []
8520
+ };
8521
+ children.push(span);
8522
+ stack.push(span.children);
8523
+ } else if (match[0] === "</span>") {
8524
+ if (stack.length > 1) stack.pop();
8525
+ } else {
8526
+ const text = match[2] ? ENTITIES[match[2]] : match[0];
8527
+ const last = children.length - 1;
8528
+ if (typeof children[last] === "string") children[last] += text;
8529
+ else children.push(text);
8530
+ }
8531
+ }
8532
+ return root;
8533
+ }
8534
+ /**
8535
+ * cli-highlight's colorizer: text outside any scope takes `default`; a scope colors everything
8536
+ * inside it (inner scopes keep their own color); an embedded language's wrapper (`<span
8537
+ * class="javascript">`) starts over as if at the top level.
8538
+ */
8539
+ function colorize(node, colors, insideScope) {
8540
+ if (typeof node === "string") return insideScope ? node : (colors.default ?? plain)(node);
8541
+ const token = /hljs-(\w+)/.exec(node.className)?.[1];
8542
+ if (!token) return node.children.map((child) => colorize(child, colors, false)).join("");
8543
+ const text = node.children.map((child) => colorize(child, colors, true)).join("");
8544
+ return (colors[token] ?? FALLBACK_THEME[token] ?? plain)(text);
8545
+ }
8546
+ /**
8547
+ * Highlight `code` as `language`. Unknown or missing languages come back in the theme's default
8548
+ * color (no auto-detection, which would need every language loaded).
8549
+ */
8550
+ function highlightCode(code, language, colors = CODE_HIGHLIGHT_THEME) {
8551
+ if (!language || !ensureLanguage(language)) return (colors.default ?? plain)(code);
8552
+ const html = getHljs().highlight(code, {
8553
+ language,
8554
+ ignoreIllegals: true
8555
+ }).value;
8556
+ return parseHighlightHtml(html).map((node) => colorize(node, colors, false)).join("");
8557
+ }
8558
+ //#endregion
8397
8559
  //#region src/tui/components/collapsible.ts
8398
8560
  /**
8399
8561
  * Generic collapsible container component.
@@ -8727,31 +8889,6 @@ function normalizeHexColor(color) {
8727
8889
  if (!color || !/^#[0-9a-f]{6}$/i.test(color)) return void 0;
8728
8890
  return color;
8729
8891
  }
8730
- /**
8731
- * Syntax roles mapped onto the theme's semantic colors. theme.fg resolves the
8732
- * active theme lazily and contrast-adapts, so code previews recolor with
8733
- * custom themes and stay readable on any background.
8734
- */
8735
- const CODE_HIGHLIGHT_THEME = {
8736
- default: (text) => theme.fg("toolArgs", text),
8737
- keyword: (text) => theme.fg("textHighlight", text),
8738
- built_in: (text) => theme.fg("function", text),
8739
- type: (text) => theme.fg("function", text),
8740
- literal: (text) => theme.fg("error", text),
8741
- number: (text) => theme.fg("number", text),
8742
- string: (text) => theme.fg("success", text),
8743
- regexp: (text) => theme.fg("error", text),
8744
- title: (text) => theme.fg("function", text),
8745
- function: (text) => theme.fg("function", text),
8746
- params: (text) => theme.fg("secondary", text),
8747
- comment: (text) => theme.fg("muted", text),
8748
- meta: (text) => theme.fg("muted", text),
8749
- attr: (text) => theme.fg("number", text),
8750
- variable: (text) => theme.fg("secondary", text),
8751
- tag: (text) => theme.fg("textHighlight", text),
8752
- name: (text) => theme.fg("textHighlight", text)
8753
- };
8754
- const codeHighlightTheme = () => CODE_HIGHLIGHT_THEME;
8755
8892
  const SHELL_CONTROL_WORDS = /* @__PURE__ */ new Set([
8756
8893
  "if",
8757
8894
  "then",
@@ -9019,7 +9156,8 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
9019
9156
  const { cdPath } = this.parseShellCommand();
9020
9157
  if (!cwd || !cdPath) return cwd || cdPath;
9021
9158
  if (cdPath.startsWith("/") || cdPath === "~" || cdPath.startsWith("~/")) return cdPath;
9022
- return join(cwd === "~" || cwd.startsWith("~/") ? os.homedir() + cwd.slice(1) : cwd, cdPath);
9159
+ const expandedCwd = cwd === "~" || cwd.startsWith("~/") ? os.homedir() + cwd.slice(1) : cwd;
9160
+ return join(expandedCwd, cdPath);
9023
9161
  }
9024
9162
  /** The directory a compact shell group shows in its `$ <path>` header, resolved the way the sandbox resolves it. */
9025
9163
  getShellHeaderPath() {
@@ -9177,13 +9315,15 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
9177
9315
  if (this.fullRender || this.toolName === MC_TOOLS.EXECUTE_COMMAND || this.previewLineLimit <= 0) return [];
9178
9316
  const preview = this.getActivePreview();
9179
9317
  let lines = [];
9180
- if (preview) if (this.isCodePreviewTool()) lines = this.getCodePreviewLines(preview, maxLineWidth);
9181
- else {
9182
- const firstLineWidth = Math.max(10, maxLineWidth - 4);
9183
- const continuationWidth = Math.max(10, maxLineWidth - 4);
9184
- lines = (this.toolName === MC_TOOLS.AGENT_SIGNAL_SEND ? this.wrapAgentSignalMessageLines(preview, Math.max(1, firstLineWidth - 2)).slice(0, this.previewLineLimit) : this.wrapPreviewLines(preview, firstLineWidth, continuationWidth).slice(-this.previewLineLimit)).map((line) => {
9185
- return truncateAnsi(`${` ${chalk.hex(this.getToolRailColor())("│")} `}${this.formatActivePreview(line)}`, maxLineWidth);
9186
- });
9318
+ if (preview) {
9319
+ if (this.isCodePreviewTool()) lines = this.getCodePreviewLines(preview, maxLineWidth);
9320
+ else {
9321
+ const firstLineWidth = Math.max(10, maxLineWidth - 4);
9322
+ const continuationWidth = Math.max(10, maxLineWidth - 4);
9323
+ lines = (this.toolName === MC_TOOLS.AGENT_SIGNAL_SEND ? this.wrapAgentSignalMessageLines(preview, Math.max(1, firstLineWidth - 2)).slice(0, this.previewLineLimit) : this.wrapPreviewLines(preview, firstLineWidth, continuationWidth).slice(-this.previewLineLimit)).map((line) => {
9324
+ return truncateAnsi(`${` ${chalk.hex(this.getToolRailColor())("│")} `}${this.formatActivePreview(line)}`, maxLineWidth);
9325
+ });
9326
+ }
9187
9327
  }
9188
9328
  this.previewRowFloor = Math.min(this.previewLineLimit, Math.max(this.previewRowFloor, lines.length));
9189
9329
  return [...Array.from({ length: this.previewRowFloor - lines.length }, () => {
@@ -9213,11 +9353,7 @@ var ToolExecutionComponentEnhanced = class extends WidthAwareContainer {
9213
9353
  highlightCodePreview(preview) {
9214
9354
  const path = this.getFirstStringArg("path");
9215
9355
  try {
9216
- return highlight(preview, {
9217
- language: getLanguageFromPath(path),
9218
- ignoreIllegals: true,
9219
- theme: codeHighlightTheme()
9220
- });
9356
+ return highlightCode(preview, getLanguageFromPath(path));
9221
9357
  } catch {
9222
9358
  return theme.fg("toolArgs", preview);
9223
9359
  }
@@ -10311,7 +10447,7 @@ var BorderedBox = class {
10311
10447
  renderUncached(width) {
10312
10448
  const prefix = this.label ? theme.fg("dim", `${this.label} · `) : "";
10313
10449
  const prefixWidth = this.label ? visibleWidth(this.label) + 3 : 0;
10314
- const contentWidth = Math.max(1, width - 0 - prefixWidth - PAD * 2);
10450
+ const contentWidth = Math.max(1, width - 0 - prefixWidth - 4);
10315
10451
  const childLines = this.child.render(contentWidth);
10316
10452
  if (childLines.length === 0) return [];
10317
10453
  const rows = childLines.map((line, i) => {
@@ -10513,9 +10649,7 @@ var ToolApprovalDialogComponent = class {
10513
10649
  case "a":
10514
10650
  this.emit({ type: "always_allow_category" });
10515
10651
  break;
10516
- case "Y":
10517
- this.emit({ type: "yolo" });
10518
- break;
10652
+ case "Y": this.emit({ type: "yolo" });
10519
10653
  }
10520
10654
  }
10521
10655
  };
@@ -10833,9 +10967,7 @@ function handleSubagentProgress(ctx, toolCallId, progress) {
10833
10967
  case "tool_end":
10834
10968
  component.addToolEnd(progress.toolName, progress.result, progress.isError ?? false);
10835
10969
  break;
10836
- case "finish":
10837
- component.finish(progress.isError ?? false, progress.durationMs, progress.result);
10838
- break;
10970
+ case "finish": component.finish(progress.isError ?? false, progress.durationMs, progress.result);
10839
10971
  }
10840
10972
  reconcileToolBoundaries(ctx);
10841
10973
  requestRender(state);
@@ -11965,7 +12097,7 @@ var CustomEditor = class extends Editor {
11965
12097
  if (gap <= SPACE_REPEAT_MAX_GAP_MS) this.spaceRepeatCount += 1;
11966
12098
  else this.spaceRepeatCount = 1;
11967
12099
  if (this.spaceRepeatCount >= SPACE_HOLD_REPEAT_THRESHOLD) {
11968
- const typedSpaces = SPACE_HOLD_REPEAT_THRESHOLD - 1;
12100
+ const typedSpaces = 2;
11969
12101
  for (let i = 0; i < typedSpaces; i++) super.handleInput("");
11970
12102
  this.spaceRepeatCount = 0;
11971
12103
  this.voiceRecordingActive = true;
@@ -12169,7 +12301,8 @@ function detectRecorder() {
12169
12301
  }
12170
12302
  function commandExists$1(bin) {
12171
12303
  try {
12172
- execFileSync(process.platform === "win32" ? "where" : "which", [bin], {
12304
+ const probe = process.platform === "win32" ? "where" : "which";
12305
+ execFileSync(probe, [bin], {
12173
12306
  stdio: [
12174
12307
  "ignore",
12175
12308
  "ignore",
@@ -12599,7 +12732,8 @@ const PLIST_PATH = resolveAsset("macos-stt.plist");
12599
12732
  const APP_NAME = "MastraCodeVoice";
12600
12733
  const BUNDLE_ID = "ai.mastra.mastracode.voice";
12601
12734
  function cacheDir() {
12602
- return join(process.env.XDG_CACHE_HOME?.trim() || join(homedir(), "Library", "Caches"), "mastracode", "voice");
12735
+ const base = process.env.XDG_CACHE_HOME?.trim() || join(homedir(), "Library", "Caches");
12736
+ return join(base, "mastracode", "voice");
12603
12737
  }
12604
12738
  async function exists(path) {
12605
12739
  try {
@@ -13029,10 +13163,7 @@ var MacosNativeSession = class {
13029
13163
  this.callbacks.onFinal(event.text ?? "");
13030
13164
  this.settle();
13031
13165
  break;
13032
- case "error":
13033
- this.fail(new Error(event.message ?? "macOS speech recognition failed."));
13034
- break;
13035
- default: break;
13166
+ case "error": this.fail(new Error(event.message ?? "macOS speech recognition failed."));
13036
13167
  }
13037
13168
  }
13038
13169
  fail(error) {
@@ -15540,7 +15671,8 @@ async function handleModelCommand(ctx) {
15540
15671
  });
15541
15672
  const settings = loadSettings();
15542
15673
  const threadId = ctx.state.session.thread.getId?.();
15543
- const activePackId = parseThreadSettings((threadId ? (await ctx.state.session.thread.list()).find((item) => item.id === threadId) : void 0)?.metadata).activeModelPackId ?? settings.models.activeModelPackId;
15674
+ const thread = threadId ? (await ctx.state.session.thread.list()).find((item) => item.id === threadId) : void 0;
15675
+ const activePackId = parseThreadSettings(thread?.metadata).activeModelPackId ?? settings.models.activeModelPackId;
15544
15676
  const builtinPack = activePackId ? getBuiltinModePack(activePackId) : void 0;
15545
15677
  const selectableModels = builtinPack ? connected.filter((model) => model.provider === builtinPack.providerId) : connected;
15546
15678
  if (selectableModels.length === 0) {
@@ -15801,12 +15933,13 @@ var OMProgressComponent = class extends Container {
15801
15933
  return this.state.status;
15802
15934
  }
15803
15935
  updateDisplay() {
15804
- if (this.state.status === "idle") if (this.state.thresholdPercent > 0) {
15805
- const percent = Math.round(this.state.thresholdPercent);
15806
- const bar = this.renderProgressBar(percent, 10);
15807
- this.statusText.setText(theme.fg("muted", `OM ${bar} ${percent}%`));
15808
- } else this.statusText.setText("");
15809
- else if (this.state.status === "observing") {
15936
+ if (this.state.status === "idle") {
15937
+ if (this.state.thresholdPercent > 0) {
15938
+ const percent = Math.round(this.state.thresholdPercent);
15939
+ const bar = this.renderProgressBar(percent, 10);
15940
+ this.statusText.setText(theme.fg("muted", `OM ${bar} ${percent}%`));
15941
+ } else this.statusText.setText("");
15942
+ } else if (this.state.status === "observing") {
15810
15943
  const elapsed = this.state.startTime ? Math.round((Date.now() - this.state.startTime) / 1e3) : 0;
15811
15944
  const spinner = this.getSpinner();
15812
15945
  this.statusText.setText(chalk.hex(mastra.orange)(`${spinner} Observing... ${elapsed}s`));
@@ -15903,7 +16036,7 @@ function formatOMStatus(state) {
15903
16036
  */
15904
16037
  function getEffectiveOMRoleModelId(session, role) {
15905
16038
  const routeMemoryModelId = getActiveRouteMemoryModelId(session.state.get(), session.thread.getId());
15906
- if (routeMemoryModelId === "auto") return resolveAutoOMModelId(session.model.get() ?? void 0);
16039
+ if (routeMemoryModelId === "auto") return resolveAutoOMModelId(session.model.get() ?? void 0, canUseProvider);
15907
16040
  return routeMemoryModelId ?? session.om[role].modelId();
15908
16041
  }
15909
16042
  //#endregion
@@ -16225,7 +16358,7 @@ function updateActivityLine(state, modeColor, now) {
16225
16358
  }
16226
16359
  const spinner = pulseDot(modeColor ?? theme.getTheme().accent, now);
16227
16360
  const elapsed = formatStatusDuration(now - state.agentRunStartedAt, { includeSeconds: true });
16228
- const stale = state.agentRunLastStreamPartAt !== void 0 && now - state.agentRunLastStreamPartAt > 3 * 6e4 ? formatStatusDuration(now - state.agentRunLastStreamPartAt, { includeSeconds: false }) : null;
16361
+ const stale = state.agentRunLastStreamPartAt !== void 0 && now - state.agentRunLastStreamPartAt > 18e4 ? formatStatusDuration(now - state.agentRunLastStreamPartAt, { includeSeconds: false }) : null;
16229
16362
  const parts = [theme.fg(stale ? "error" : "dim", elapsed)];
16230
16363
  if (stale) parts.push(theme.fg("warning", `no output for ${stale}`));
16231
16364
  if (state.tokensPerSec > 0) parts.push(theme.fg("dim", `${state.tokensPerSec} tok/s`));
@@ -17258,7 +17391,8 @@ async function handleModelsPackCommand(ctx) {
17258
17391
  return;
17259
17392
  }
17260
17393
  const threadId = ctx.state.session.thread.getId();
17261
- const currentPackId = resolveThreadActiveModelPackId(settings, packs, (threadId ? (await ctx.state.session.thread.list()).find((t) => t.id === threadId) : void 0)?.metadata);
17394
+ const thread = threadId ? (await ctx.state.session.thread.list()).find((t) => t.id === threadId) : void 0;
17395
+ const currentPackId = resolveThreadActiveModelPackId(settings, packs, thread?.metadata);
17262
17396
  const items = packs.map((p) => ({
17263
17397
  value: p.id,
17264
17398
  label: ` ${p.name}${modifiedPackIds.has(p.id) ? theme.fg("warning", " (modified)") : ""} ${theme.fg("dim", p.description)}${p.id === currentPackId ? theme.fg("dim", " (current)") : ""}`
@@ -17497,10 +17631,11 @@ async function createProviderFlow(ctx) {
17497
17631
  ctx.showError("Invalid URL. Use a full http(s) URL.");
17498
17632
  return;
17499
17633
  }
17634
+ const apiKey = await askOptionalText(ctx, "API key");
17500
17635
  upsertCustomProviderInSettings(settings, {
17501
17636
  name,
17502
17637
  url,
17503
- apiKey: await askOptionalText(ctx, "API key"),
17638
+ apiKey,
17504
17639
  models: []
17505
17640
  });
17506
17641
  saveSettings(settings);
@@ -17626,7 +17761,6 @@ async function manageProviderFlow(ctx, providerId) {
17626
17761
  ctx.showInfo(`Deleted custom provider: ${provider.name}`);
17627
17762
  break;
17628
17763
  }
17629
- default: break;
17630
17764
  }
17631
17765
  }
17632
17766
  async function handleCustomProvidersCommand(ctx) {
@@ -18131,7 +18265,7 @@ async function handleOMCommand(ctx) {
18131
18265
  const observerModelId = getEffectiveOMRoleModelId(session, "observer") ?? "";
18132
18266
  const reflectorModelId = getEffectiveOMRoleModelId(session, "reflector") ?? "";
18133
18267
  const packMemoryModelId = getActiveRouteMemoryModelId(agentControllerState, ctx.state.session.thread.getId());
18134
- const autoModelId = resolveAutoOMModelId(ctx.state.session.model.get() ?? void 0);
18268
+ const autoModelId = resolveAutoOMModelId(ctx.state.session.model.get() ?? void 0, canUseProvider);
18135
18269
  const config = {
18136
18270
  observerModel: session.om.observer.model() ?? "auto",
18137
18271
  observerModelId,
@@ -19557,6 +19691,7 @@ async function handleSettingsCommand(ctx) {
19557
19691
  }
19558
19692
  //#endregion
19559
19693
  //#region src/tui/commands/browser.ts
19694
+ const STAGEHAND_MODEL_PROVIDERS = Object.keys(STAGEHAND_PROVIDER_ENV_VARS).sort();
19560
19695
  /**
19561
19696
  * Key used to store the active browser settings in controller state.
19562
19697
  * This tracks what browser config is actually running in this instance,
@@ -19930,7 +20065,6 @@ async function handleBrowserCommand(ctx, args = []) {
19930
20065
  ctx.showInfo(`Note: Cleared profile and executablePath (ignored when using cdpUrl).`);
19931
20066
  }
19932
20067
  if (settings.browser.agentBrowser?.storageState) delete settings.browser.agentBrowser.storageState;
19933
- break;
19934
20068
  }
19935
20069
  saveSettings(settings);
19936
20070
  ctx.showInfo(`Set ${args[1]} = ${expandedValue}\nRun /browser on to apply.`);
@@ -20500,8 +20634,10 @@ var LoginAccountManagerComponent = class extends Box {
20500
20634
  this.selectedIndex = Math.min(rows.length - 1, this.selectedIndex + 1);
20501
20635
  this.updateList();
20502
20636
  } else if (kb.matches(keyData, "tui.select.confirm")) rows[this.selectedIndex]?.action();
20503
- else if (kb.matches(keyData, "tui.select.cancel")) if (this.mode === "account" || this.mode === "confirm-remove") this.backToMenu();
20504
- else this.callbacks.onBack();
20637
+ else if (kb.matches(keyData, "tui.select.cancel")) {
20638
+ if (this.mode === "account" || this.mode === "confirm-remove") this.backToMenu();
20639
+ else this.callbacks.onBack();
20640
+ }
20505
20641
  }
20506
20642
  };
20507
20643
  //#endregion
@@ -22942,9 +23078,7 @@ async function showGithubActionMenu(ctx) {
22942
23078
  case "Sync now":
22943
23079
  await syncGithubSubscriptions(ctx);
22944
23080
  break;
22945
- case "Debug":
22946
- ctx.showInfo(await describeGithubSubscriptions(ctx));
22947
- break;
23081
+ case "Debug": ctx.showInfo(await describeGithubSubscriptions(ctx));
22948
23082
  }
22949
23083
  }
22950
23084
  async function handleInlineGithubOperation(ctx, input) {
@@ -24714,13 +24848,14 @@ async function handlePackFallbackState(ectx, event) {
24714
24848
  if (!isOriginThreadActive()) return;
24715
24849
  const sessionOverride = ectx.state.session.state.get()?.thinkingLevel;
24716
24850
  const currentModeId = ectx.state.session.mode.get();
24717
- const defaultThinking = resolveDefaultThinkingLevel({
24851
+ const runtimeSettings = {
24718
24852
  ...settings,
24719
24853
  models: {
24720
24854
  ...settings.models,
24721
24855
  activeModelPackId: pending.toEntryId
24722
24856
  }
24723
- }, currentModeId);
24857
+ };
24858
+ const defaultThinking = resolveDefaultThinkingLevel(runtimeSettings, currentModeId);
24724
24859
  const effectiveThinking = sessionOverride ?? defaultThinking.level;
24725
24860
  if (selection.modelRoute.entries.some((entry) => entry.modelId.startsWith("openai/")) && sessionOverride === void 0 && defaultThinking.source === "global" && defaultThinking.level === "off") await ectx.state.session.state.set({ thinkingLevel: "low" });
24726
24861
  else if (selection.modelId.startsWith("openai/") && effectiveThinking === "max") await ectx.state.session.state.set({ thinkingLevel: "xhigh" });
@@ -25687,8 +25822,7 @@ async function dispatchEvent(event, ectx, state) {
25687
25822
  const decodeSec = (state.decodeLastDeltaAt - state.decodeStartedAt) / 1e3;
25688
25823
  if (state.decodeStartedAt > 0 && decodeSec >= MIN_DECODE_WINDOW_SEC && stepTokens > 0) {
25689
25824
  const instantaneous = stepTokens / decodeSec;
25690
- const alpha = .3;
25691
- const ema = state.tokensPerSec > 0 ? alpha * instantaneous + (1 - alpha) * state.tokensPerSec : instantaneous;
25825
+ const ema = state.tokensPerSec > 0 ? .3 * instantaneous + .7 * state.tokensPerSec : instantaneous;
25692
25826
  state.tokensPerSec = Math.round(ema);
25693
25827
  }
25694
25828
  state.decodeMessageId = void 0;
@@ -25798,9 +25932,7 @@ async function dispatchEvent(event, ectx, state) {
25798
25932
  case "state_changed":
25799
25933
  await handlePackFallbackState(ectx, event);
25800
25934
  break;
25801
- case "display_state_changed":
25802
- ectx.updateStatusLine();
25803
- break;
25935
+ case "display_state_changed": ectx.updateStatusLine();
25804
25936
  }
25805
25937
  }
25806
25938
  //#endregion
@@ -27561,7 +27693,7 @@ const USER_MESSAGE_APPROVAL_INTERRUPT = {
27561
27693
  message: "The pending tool approval was declined because the user sent a new message."
27562
27694
  };
27563
27695
  /** How often to recheck for updates during a long-running session (ms). */
27564
- const UPDATE_RECHECK_INTERVAL_MS = 2700 * 1e3;
27696
+ const UPDATE_RECHECK_INTERVAL_MS = 27e5;
27565
27697
  const IMAGE_PLACEHOLDER_PATTERN = /\[image\]\s*/g;
27566
27698
  const CAFFEINATE_ARGS = ["-i", "-m"];
27567
27699
  function fallbackStatusFromMetadata(metadata) {
@@ -28350,9 +28482,7 @@ var MastraTUI = class MastraTUI {
28350
28482
  case "subagent_start":
28351
28483
  hookMgr.runSubagentStart(event.toolCallId, event.agentType, event.task, event.modelId, event.forked).catch(() => {});
28352
28484
  break;
28353
- case "subagent_end":
28354
- hookMgr.runSubagentEnd(event.toolCallId, event.agentType, event.result, event.isError, event.durationMs).catch(() => {});
28355
- break;
28485
+ case "subagent_end": hookMgr.runSubagentEnd(event.toolCallId, event.agentType, event.result, event.isError, event.durationMs).catch(() => {});
28356
28486
  }
28357
28487
  }
28358
28488
  async runAgentEndHook(reason) {
@@ -28757,4 +28887,4 @@ var MastraTUI = class MastraTUI {
28757
28887
  //#endregion
28758
28888
  export { mastraBrand as C, mastra as S, TUI_CO_AUTHOR as T, normalizeThemePreference as _, formatUpdateHeader as a, getMarkdownTheme as b, LoginDialogComponent as c, createTUIState as d, UserMessageComponent as f, applyThemePreference as g, AssistantMessageComponent as h, formatUpToDate as i, OMProgressComponent as l, ModelSelectorComponent as m, formatInstallingLabel as n, formatUpdateOutcome as o, ToolExecutionComponentEnhanced as p, formatRegistryError as r, LoginSelectorComponent as s, MastraTUI as t, formatOMStatus as u, applyThemeMode as v, theme as w, getThemeMode as x, getEditorTheme as y };
28759
28889
 
28760
- //# sourceMappingURL=tui-Bdb-MfGN.js.map
28890
+ //# sourceMappingURL=tui-NWh1Dtvz.js.map