mastracode 0.22.3 → 0.23.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.
Files changed (181) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/dist/HarnessCompat.d.ts +2 -2
  3. package/dist/HarnessCompat.d.ts.map +1 -1
  4. package/dist/agents/mastracode-gateway.d.ts +58 -0
  5. package/dist/agents/mastracode-gateway.d.ts.map +1 -0
  6. package/dist/agents/model.d.ts +26 -28
  7. package/dist/agents/model.d.ts.map +1 -1
  8. package/dist/agents/{subagents/execute.d.ts → modes/build.d.ts} +3 -3
  9. package/dist/agents/modes/build.d.ts.map +1 -0
  10. package/dist/agents/{subagents → modes}/explore.d.ts +2 -2
  11. package/dist/agents/modes/explore.d.ts.map +1 -0
  12. package/dist/agents/modes/plan.d.ts +6 -0
  13. package/dist/agents/modes/plan.d.ts.map +1 -0
  14. package/dist/{chunk-EATS4KOR.cjs → chunk-3CO7PY6M.cjs} +1094 -239
  15. package/dist/chunk-3CO7PY6M.cjs.map +1 -0
  16. package/dist/{chunk-DJEQBK7L.cjs → chunk-CBPEMMRV.cjs} +1659 -2010
  17. package/dist/chunk-CBPEMMRV.cjs.map +1 -0
  18. package/dist/{chunk-W7Y7QIJA.js → chunk-FXYM4OEI.js} +14 -805
  19. package/dist/chunk-FXYM4OEI.js.map +1 -0
  20. package/dist/{chunk-OXYE6SUY.js → chunk-GKGPZBID.js} +836 -1187
  21. package/dist/chunk-GKGPZBID.js.map +1 -0
  22. package/dist/{chunk-FDDVVRPH.js → chunk-RDIIIT54.js} +1076 -221
  23. package/dist/chunk-RDIIIT54.js.map +1 -0
  24. package/dist/{chunk-NKTZDFIU.cjs → chunk-XPPJHUAD.cjs} +12 -809
  25. package/dist/chunk-XPPJHUAD.cjs.map +1 -0
  26. package/dist/cli.cjs +18 -18
  27. package/dist/cli.js +3 -3
  28. package/dist/index.cjs +3 -3
  29. package/dist/index.d.ts +4 -5
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +1 -1
  32. package/dist/mcp/manager.d.ts.map +1 -1
  33. package/dist/onboarding/onboarding-inline.d.ts +2 -2
  34. package/dist/onboarding/onboarding-inline.d.ts.map +1 -1
  35. package/dist/onboarding/settings.d.ts.map +1 -1
  36. package/dist/providers/claude-max.d.ts.map +1 -1
  37. package/dist/tui/chat-boundary-reconciliation.d.ts +18 -1
  38. package/dist/tui/chat-boundary-reconciliation.d.ts.map +1 -1
  39. package/dist/tui/command-dispatch.d.ts.map +1 -1
  40. package/dist/tui/commands/browser.d.ts.map +1 -1
  41. package/dist/tui/commands/goal.d.ts.map +1 -1
  42. package/dist/tui/commands/mode.d.ts.map +1 -1
  43. package/dist/tui/commands/new.d.ts.map +1 -1
  44. package/dist/tui/commands/settings.d.ts.map +1 -1
  45. package/dist/tui/commands/skills.d.ts.map +1 -1
  46. package/dist/tui/components/api-key-dialog.d.ts +2 -2
  47. package/dist/tui/components/api-key-dialog.d.ts.map +1 -1
  48. package/dist/tui/components/ask-question-dialog.d.ts +2 -2
  49. package/dist/tui/components/ask-question-dialog.d.ts.map +1 -1
  50. package/dist/tui/components/ask-question-inline.d.ts +4 -2
  51. package/dist/tui/components/ask-question-inline.d.ts.map +1 -1
  52. package/dist/tui/components/assistant-message.d.ts +2 -2
  53. package/dist/tui/components/assistant-message.d.ts.map +1 -1
  54. package/dist/tui/components/chat-boundary-spacer.d.ts +9 -9
  55. package/dist/tui/components/chat-boundary-spacer.d.ts.map +1 -1
  56. package/dist/tui/components/chat-spacing.d.ts +1 -1
  57. package/dist/tui/components/chat-spacing.d.ts.map +1 -1
  58. package/dist/tui/components/collapsible.d.ts +2 -2
  59. package/dist/tui/components/collapsible.d.ts.map +1 -1
  60. package/dist/tui/components/custom-editor.d.ts +2 -2
  61. package/dist/tui/components/custom-editor.d.ts.map +1 -1
  62. package/dist/tui/components/diff-output.d.ts +3 -1
  63. package/dist/tui/components/diff-output.d.ts.map +1 -1
  64. package/dist/tui/components/error-display.d.ts +4 -2
  65. package/dist/tui/components/error-display.d.ts.map +1 -1
  66. package/dist/tui/components/goal-cycles-dialog.d.ts +2 -2
  67. package/dist/tui/components/goal-cycles-dialog.d.ts.map +1 -1
  68. package/dist/tui/components/idle-counter.d.ts +1 -1
  69. package/dist/tui/components/idle-counter.d.ts.map +1 -1
  70. package/dist/tui/components/judge-display.d.ts +14 -2
  71. package/dist/tui/components/judge-display.d.ts.map +1 -1
  72. package/dist/tui/components/login-dialog.d.ts +2 -2
  73. package/dist/tui/components/login-dialog.d.ts.map +1 -1
  74. package/dist/tui/components/login-mode-selector.d.ts +2 -2
  75. package/dist/tui/components/login-mode-selector.d.ts.map +1 -1
  76. package/dist/tui/components/login-selector.d.ts +1 -1
  77. package/dist/tui/components/login-selector.d.ts.map +1 -1
  78. package/dist/tui/components/masked-input.d.ts +1 -1
  79. package/dist/tui/components/masked-input.d.ts.map +1 -1
  80. package/dist/tui/components/mcp-selector.d.ts +2 -2
  81. package/dist/tui/components/mcp-selector.d.ts.map +1 -1
  82. package/dist/tui/components/model-selector.d.ts +2 -2
  83. package/dist/tui/components/model-selector.d.ts.map +1 -1
  84. package/dist/tui/components/multi-step-progress.d.ts +3 -1
  85. package/dist/tui/components/multi-step-progress.d.ts.map +1 -1
  86. package/dist/tui/components/multiline-input.d.ts +1 -1
  87. package/dist/tui/components/multiline-input.d.ts.map +1 -1
  88. package/dist/tui/components/notification-summary.d.ts +1 -1
  89. package/dist/tui/components/notification-summary.d.ts.map +1 -1
  90. package/dist/tui/components/notification.d.ts +1 -1
  91. package/dist/tui/components/notification.d.ts.map +1 -1
  92. package/dist/tui/components/om-marker.d.ts +3 -1
  93. package/dist/tui/components/om-marker.d.ts.map +1 -1
  94. package/dist/tui/components/om-output.d.ts +3 -1
  95. package/dist/tui/components/om-output.d.ts.map +1 -1
  96. package/dist/tui/components/om-progress.d.ts +1 -1
  97. package/dist/tui/components/om-progress.d.ts.map +1 -1
  98. package/dist/tui/components/om-settings.d.ts +2 -2
  99. package/dist/tui/components/om-settings.d.ts.map +1 -1
  100. package/dist/tui/components/plan-approval-inline.d.ts +2 -2
  101. package/dist/tui/components/plan-approval-inline.d.ts.map +1 -1
  102. package/dist/tui/components/reactive-signal.d.ts +1 -1
  103. package/dist/tui/components/reactive-signal.d.ts.map +1 -1
  104. package/dist/tui/components/settings.d.ts +2 -2
  105. package/dist/tui/components/settings.d.ts.map +1 -1
  106. package/dist/tui/components/shell-output.d.ts +3 -1
  107. package/dist/tui/components/shell-output.d.ts.map +1 -1
  108. package/dist/tui/components/simple-progress.d.ts +1 -1
  109. package/dist/tui/components/simple-progress.d.ts.map +1 -1
  110. package/dist/tui/components/slash-command.d.ts +3 -1
  111. package/dist/tui/components/slash-command.d.ts.map +1 -1
  112. package/dist/tui/components/state-signal.d.ts +1 -1
  113. package/dist/tui/components/state-signal.d.ts.map +1 -1
  114. package/dist/tui/components/subagent-execution.d.ts +2 -2
  115. package/dist/tui/components/subagent-execution.d.ts.map +1 -1
  116. package/dist/tui/components/system-reminder.d.ts +1 -1
  117. package/dist/tui/components/system-reminder.d.ts.map +1 -1
  118. package/dist/tui/components/task-progress.d.ts +1 -1
  119. package/dist/tui/components/task-progress.d.ts.map +1 -1
  120. package/dist/tui/components/temporal-gap.d.ts +3 -1
  121. package/dist/tui/components/temporal-gap.d.ts.map +1 -1
  122. package/dist/tui/components/thinking-settings.d.ts +2 -2
  123. package/dist/tui/components/thinking-settings.d.ts.map +1 -1
  124. package/dist/tui/components/thread-selector.d.ts +2 -2
  125. package/dist/tui/components/thread-selector.d.ts.map +1 -1
  126. package/dist/tui/components/tool-approval-dialog.d.ts +2 -2
  127. package/dist/tui/components/tool-approval-dialog.d.ts.map +1 -1
  128. package/dist/tui/components/tool-execution-enhanced.d.ts +2 -2
  129. package/dist/tui/components/tool-execution-enhanced.d.ts.map +1 -1
  130. package/dist/tui/components/tool-validation-error.d.ts +2 -2
  131. package/dist/tui/components/tool-validation-error.d.ts.map +1 -1
  132. package/dist/tui/components/user-message.d.ts +2 -2
  133. package/dist/tui/components/user-message.d.ts.map +1 -1
  134. package/dist/tui/components/wrapping-autocomplete-list.d.ts +1 -1
  135. package/dist/tui/components/wrapping-autocomplete-list.d.ts.map +1 -1
  136. package/dist/tui/components/wrapping-select-list.d.ts +1 -1
  137. package/dist/tui/components/wrapping-select-list.d.ts.map +1 -1
  138. package/dist/tui/display.d.ts.map +1 -1
  139. package/dist/tui/event-dispatch.d.ts.map +1 -1
  140. package/dist/tui/goal-manager.d.ts +48 -40
  141. package/dist/tui/goal-manager.d.ts.map +1 -1
  142. package/dist/tui/handlers/agent-lifecycle.d.ts +13 -0
  143. package/dist/tui/handlers/agent-lifecycle.d.ts.map +1 -1
  144. package/dist/tui/handlers/index.d.ts +1 -1
  145. package/dist/tui/handlers/index.d.ts.map +1 -1
  146. package/dist/tui/handlers/message.d.ts.map +1 -1
  147. package/dist/tui/handlers/om.d.ts.map +1 -1
  148. package/dist/tui/handlers/tool.d.ts.map +1 -1
  149. package/dist/tui/handlers/types.d.ts +1 -1
  150. package/dist/tui/handlers/types.d.ts.map +1 -1
  151. package/dist/tui/mastra-tui.d.ts.map +1 -1
  152. package/dist/tui/modal-question.d.ts +1 -1
  153. package/dist/tui/modal-question.d.ts.map +1 -1
  154. package/dist/tui/overlay.d.ts +1 -1
  155. package/dist/tui/overlay.d.ts.map +1 -1
  156. package/dist/tui/prompt-api-key.d.ts +1 -1
  157. package/dist/tui/prompt-api-key.d.ts.map +1 -1
  158. package/dist/tui/render-messages.d.ts +1 -1
  159. package/dist/tui/render-messages.d.ts.map +1 -1
  160. package/dist/tui/setup.d.ts.map +1 -1
  161. package/dist/tui/shell.d.ts.map +1 -1
  162. package/dist/tui/state.d.ts +2 -2
  163. package/dist/tui/state.d.ts.map +1 -1
  164. package/dist/tui/status-line.d.ts.map +1 -1
  165. package/dist/tui/theme.d.ts +1 -1
  166. package/dist/tui/theme.d.ts.map +1 -1
  167. package/dist/tui.cjs +19 -19
  168. package/dist/tui.js +2 -2
  169. package/package.json +20 -20
  170. package/dist/agents/coding.d.ts +0 -2
  171. package/dist/agents/coding.d.ts.map +0 -1
  172. package/dist/agents/subagents/execute.d.ts.map +0 -1
  173. package/dist/agents/subagents/explore.d.ts.map +0 -1
  174. package/dist/agents/subagents/plan.d.ts +0 -10
  175. package/dist/agents/subagents/plan.d.ts.map +0 -1
  176. package/dist/chunk-DJEQBK7L.cjs.map +0 -1
  177. package/dist/chunk-EATS4KOR.cjs.map +0 -1
  178. package/dist/chunk-FDDVVRPH.js.map +0 -1
  179. package/dist/chunk-NKTZDFIU.cjs.map +0 -1
  180. package/dist/chunk-OXYE6SUY.js.map +0 -1
  181. package/dist/chunk-W7Y7QIJA.js.map +0 -1
@@ -1,23 +1,20 @@
1
- import { tintHex, mastra, theme, getMarkdownTheme, CHAT_INDENT, BOX_INDENT, getTermWidth, ensureTerminalGlyphContrast, TERM_WIDTH_BUFFER, getEditorTheme, loadSettings, MEMORY_GATEWAY_PROVIDER, getAvailableModePacks, resolveThreadActiveModelPackId, saveSettings, getAvailableOmPacks, ONBOARDING_VERSION, THREAD_ACTIVE_MODEL_PACK_ID_KEY, BOX_INDENT_STR, resolveModel, ThreadLockError, getSelectListTheme, luminance, extendedColors, MEMORY_GATEWAY_DEFAULT_URL, getThemeMode, applyThemeMode, createBrowserFromSettings, setProfileProvider, getCustomProviderId, OBSERVABILITY_AUTH_PREFIX, checkProfileProviderMismatch, getSettingsListTheme, mastraBrand, toCustomProviderModelId } from './chunk-W7Y7QIJA.js';
1
+ import { tintHex, mastra, theme, getMarkdownTheme, CHAT_INDENT, BOX_INDENT, getTermWidth, ensureTerminalGlyphContrast, TERM_WIDTH_BUFFER, getEditorTheme, loadSettings, MEMORY_GATEWAY_PROVIDER, getAvailableModePacks, resolveThreadActiveModelPackId, saveSettings, getAvailableOmPacks, ONBOARDING_VERSION, THREAD_ACTIVE_MODEL_PACK_ID_KEY, BOX_INDENT_STR, ThreadLockError, getSelectListTheme, luminance, extendedColors, MEMORY_GATEWAY_DEFAULT_URL, getThemeMode, applyThemeMode, createBrowserFromSettings, setProfileProvider, getCustomProviderId, mastraBrand, OBSERVABILITY_AUTH_PREFIX, checkProfileProviderMismatch, getSettingsListTheme, toCustomProviderModelId } from './chunk-FXYM4OEI.js';
2
2
  import { getOAuthProviders, detectProject, DEFAULT_CONFIG_DIR, getUserId, getCurrentGitBranchAsync, getUserName, PROVIDER_DEFAULT_MODELS, getAppDataDir } from './chunk-5FT2NNFO.js';
3
3
  import { MC_TOOLS, getToolCategory, TOOL_CATEGORIES } from './chunk-UOFNLVKF.js';
4
4
  import { exec, spawn, execFile, execSync, execFileSync } from 'child_process';
5
- import { visibleWidth, Box, Text, Spacer, Input, Container, fuzzyFilter, getKeybindings, Markdown, ProcessTerminal, TUI, truncateToWidth, Editor, matchesKey, CombinedAutocompleteProvider, SelectList, wrapTextWithAnsi, SettingsList, parseKey } from '@mariozechner/pi-tui';
6
- import chalk14 from 'chalk';
5
+ import { visibleWidth, Box, Text, Spacer, Input, Container, fuzzyFilter, getKeybindings, Markdown, ProcessTerminal, TUI, truncateToWidth, Editor, matchesKey, CombinedAutocompleteProvider, SelectList, wrapTextWithAnsi, SettingsList, parseKey } from '@earendil-works/pi-tui';
6
+ import chalk12 from 'chalk';
7
7
  import fs2, { statSync, readFileSync, realpathSync, promises, unlinkSync } from 'fs';
8
8
  import * as path5 from 'path';
9
9
  import path5__default, { extname, join } from 'path';
10
10
  import { fileURLToPath } from 'url';
11
- import stripAnsi2 from 'strip-ansi';
12
11
  import { randomUUID } from 'crypto';
13
- import { Agent } from '@mastra/core/agent';
14
- import { StreamErrorRetryProcessor, PrefillErrorHandler, ProviderHistoryCompat } from '@mastra/core/processors';
15
- import { createWorkspaceTools, formatSkillActivation } from '@mastra/core/workspace';
16
- import { z } from 'zod';
12
+ import { formatSkillActivation } from '@mastra/core/workspace';
17
13
  import { defaultOMProgressState, parseSubagentMeta, assignTaskIds } from '@mastra/core/harness';
18
14
  import { TASKS_STATE_ID } from '@mastra/core/tools';
19
15
  import { safeStringify } from '@mastra/core/utils';
20
16
  import process2 from 'process';
17
+ import stripAnsi from 'strip-ansi';
21
18
  import * as os from 'os';
22
19
  import { tmpdir, homedir } from 'os';
23
20
  import { highlight } from 'cli-highlight';
@@ -480,7 +477,6 @@ var AskQuestionInlineComponent = class _AskQuestionInlineComponent extends Conta
480
477
  this.borderedBox = new AskQuestionBorderedBox([], "", [], void 0, void 0, true);
481
478
  }
482
479
  this.addChild(this.borderedBox);
483
- this.addChild(new Spacer(1));
484
480
  }
485
481
  /**
486
482
  * Update the question text and options from streaming partial args.
@@ -639,6 +635,9 @@ var AskQuestionInlineComponent = class _AskQuestionInlineComponent extends Conta
639
635
  this.input.handleInput(data);
640
636
  }
641
637
  }
638
+ getChatSpacingKind() {
639
+ return "other";
640
+ }
642
641
  };
643
642
 
644
643
  // src/onboarding/onboarding-inline.ts
@@ -751,7 +750,7 @@ var OnboardingInlineComponent = class extends Box {
751
750
  box.addChild(new Text(theme.bold(theme.fg("accent", "\u{1F44B} Welcome to Mastra Code")), 0, 0));
752
751
  box.addChild(new Spacer(1));
753
752
  box.addChild(new Text(theme.fg("text", "Let's configure your models and preferences."), 0, 0));
754
- box.addChild(new Text(chalk14.white("You can re-run this anytime with /setup."), 0, 0));
753
+ box.addChild(new Text(chalk12.white("You can re-run this anytime with /setup."), 0, 0));
755
754
  box.addChild(new Spacer(1));
756
755
  const items = [
757
756
  { value: "continue", label: ` ${theme.fg("success", "Continue")}` },
@@ -886,9 +885,9 @@ var OnboardingInlineComponent = class extends Box {
886
885
  this.modePackDetail.setText(theme.fg("dim", " You'll pick a model for each mode in the next steps."));
887
886
  } else {
888
887
  const detail = [
889
- ` ${chalk14.hex(mastra.blue)("plan")} \u2192 ${theme.fg("text", pack.models.plan)}`,
890
- ` ${chalk14.hex(mastra.purple)("build")} \u2192 ${theme.fg("text", pack.models.build)}`,
891
- ` ${chalk14.hex(mastra.green)("fast")} \u2192 ${theme.fg("text", pack.models.fast)}`
888
+ ` ${chalk12.hex(mastra.blue)("plan")} \u2192 ${theme.fg("text", pack.models.plan)}`,
889
+ ` ${chalk12.hex(mastra.purple)("build")} \u2192 ${theme.fg("text", pack.models.build)}`,
890
+ ` ${chalk12.hex(mastra.green)("fast")} \u2192 ${theme.fg("text", pack.models.fast)}`
892
891
  ].join("\n");
893
892
  this.modePackDetail.setText(detail);
894
893
  }
@@ -959,7 +958,7 @@ var OnboardingInlineComponent = class extends Box {
959
958
  models: { build: models.build, plan: models.plan, fast: models.fast }
960
959
  };
961
960
  this.collapseStep(
962
- `Model pack \u2192 ${theme.bold(packName)} ${chalk14.hex(mastra.blue)("plan")} ${models.plan} ${chalk14.hex(mastra.purple)("build")} ${models.build} ${chalk14.hex(mastra.green)("fast")} ${models.fast}`
961
+ `Model pack \u2192 ${theme.bold(packName)} ${chalk12.hex(mastra.blue)("plan")} ${models.plan} ${chalk12.hex(mastra.purple)("build")} ${models.build} ${chalk12.hex(mastra.green)("fast")} ${models.fast}`
963
962
  );
964
963
  this.renderStep("omPack");
965
964
  this.tui.requestRender();
@@ -1073,9 +1072,9 @@ var OnboardingInlineComponent = class extends Box {
1073
1072
  box.addChild(new Spacer(1));
1074
1073
  const lines = [
1075
1074
  `Model pack: ${theme.bold(this.selectedModePack.name)}`,
1076
- ` ${chalk14.hex(mastra.blue)("plan")} \u2192 ${this.selectedModePack.models.plan}`,
1077
- ` ${chalk14.hex(mastra.purple)("build")} \u2192 ${this.selectedModePack.models.build}`,
1078
- ` ${chalk14.hex(mastra.green)("fast")} \u2192 ${this.selectedModePack.models.fast}`,
1075
+ ` ${chalk12.hex(mastra.blue)("plan")} \u2192 ${this.selectedModePack.models.plan}`,
1076
+ ` ${chalk12.hex(mastra.purple)("build")} \u2192 ${this.selectedModePack.models.build}`,
1077
+ ` ${chalk12.hex(mastra.green)("fast")} \u2192 ${this.selectedModePack.models.fast}`,
1079
1078
  `Observational memory: ${theme.bold(this.selectedOmPack.name)}`,
1080
1079
  `YOLO mode: ${theme.bold(this.selectedYolo ? "enabled" : "disabled")}`
1081
1080
  ];
@@ -1175,7 +1174,7 @@ function getInstallCommand(pm, version) {
1175
1174
  }
1176
1175
  function getCurrentVersion() {
1177
1176
  {
1178
- return "0.22.3";
1177
+ return "0.23.0";
1179
1178
  }
1180
1179
  }
1181
1180
  async function fetchLatestVersion() {
@@ -1274,6 +1273,15 @@ function buildInstallArgs(pm, version) {
1274
1273
  return ["install", "-g", pkg];
1275
1274
  }
1276
1275
  }
1276
+ var ChatBoundarySpacer = class extends Spacer {
1277
+ isChatBoundarySpacer = true;
1278
+ constructor(lines = 1) {
1279
+ super(lines);
1280
+ }
1281
+ };
1282
+ function isChatBoundarySpacer(component) {
1283
+ return !!component && component.isChatBoundarySpacer === true;
1284
+ }
1277
1285
 
1278
1286
  // src/tui/components/chat-spacing.ts
1279
1287
  function getChatSpacingKind(component) {
@@ -1309,84 +1317,13 @@ function isToolSpacingKind(kind) {
1309
1317
  return kind === "quiet-compact-tool" || kind === "quiet-shell-tool" || kind === "normal-tool";
1310
1318
  }
1311
1319
 
1312
- // src/tui/components/chat-boundary-spacer.ts
1313
- var ChatBoundarySpacer = class {
1314
- constructor(getPrev, getNext, getPrevPrev = () => void 0, getNextNext = () => void 0) {
1315
- this.getPrev = getPrev;
1316
- this.getNext = getNext;
1317
- this.getPrevPrev = getPrevPrev;
1318
- this.getNextNext = getNextNext;
1319
- }
1320
- getPrev;
1321
- getNext;
1322
- getPrevPrev;
1323
- getNextNext;
1324
- isChatBoundarySpacer = true;
1325
- invalidate() {
1326
- }
1327
- render() {
1328
- const spacing = getSpacingBetweenComponents(this.getPrev(), this.getNext(), this.getPrevPrev(), this.getNextNext());
1329
- return Array.from({ length: spacing }, () => "");
1330
- }
1331
- };
1332
- function isChatBoundarySpacer(component) {
1333
- return !!component && component.isChatBoundarySpacer === true;
1334
- }
1335
-
1336
1320
  // src/tui/chat-boundary-reconciliation.ts
1337
1321
  function insertChatComponentWithBoundarySpacing(chatContainer, child, index = chatContainer.children.length) {
1338
1322
  const children = chatContainer.children;
1339
1323
  const boundedIndex = Math.max(0, Math.min(index, children.length));
1340
- const previous = findPreviousSpacingComponent(children, boundedIndex);
1341
- const previousPrevious = findPreviousSpacingComponent(children, previous ? children.indexOf(previous) : -1);
1342
- const next = findNextSpacingComponent(children, boundedIndex);
1343
- const nextNext = findNextSpacingComponent(children, next ? children.indexOf(next) + 1 : children.length);
1344
- const inserted = [];
1345
- if (previous) {
1346
- inserted.push(
1347
- new ChatBoundarySpacer(
1348
- () => previous,
1349
- () => child,
1350
- () => previousPrevious,
1351
- () => next
1352
- )
1353
- );
1354
- }
1355
- inserted.push(child);
1356
- if (next) {
1357
- inserted.push(
1358
- new ChatBoundarySpacer(
1359
- () => child,
1360
- () => next,
1361
- () => previous,
1362
- () => nextNext
1363
- )
1364
- );
1365
- }
1366
- children.splice(boundedIndex, 0, ...inserted);
1324
+ children.splice(boundedIndex, 0, child);
1367
1325
  reconcileChatBoundarySpacers(chatContainer);
1368
1326
  }
1369
- function findPreviousSpacingComponent(children, index) {
1370
- for (let i = index - 1; i >= 0; i--) {
1371
- const child = children[i];
1372
- if (child && !isChatBoundarySpacer(child) && getChatSpacingKind(child)) return child;
1373
- }
1374
- return void 0;
1375
- }
1376
- function findNextSpacingComponent(children, index) {
1377
- for (let i = index; i < children.length; i++) {
1378
- const child = children[i];
1379
- if (child && !isChatBoundarySpacer(child) && getChatSpacingKind(child)) return child;
1380
- }
1381
- return void 0;
1382
- }
1383
- function findPreviousSpacingComponentInList(components, index) {
1384
- for (let i = index - 1; i >= 0; i--) {
1385
- const child = components[i];
1386
- if (child && getChatSpacingKind(child)) return child;
1387
- }
1388
- return void 0;
1389
- }
1390
1327
  function findNextSpacingComponentInList(components, index) {
1391
1328
  for (let i = index + 1; i < components.length; i++) {
1392
1329
  const child = components[i];
@@ -1395,11 +1332,15 @@ function findNextSpacingComponentInList(components, index) {
1395
1332
  return void 0;
1396
1333
  }
1397
1334
  function reconcileChatBoundarySpacers(chatContainer) {
1398
- const components = chatContainer.children.filter((child) => !isChatBoundarySpacer(child));
1335
+ const children = chatContainer.children;
1336
+ const components = children.filter((child) => !isChatBoundarySpacer(child));
1337
+ const spacerPool = children.filter(isChatBoundarySpacer);
1338
+ let poolIndex = 0;
1399
1339
  const nextChildren = [];
1400
1340
  let previousCompactToolGroupKey;
1401
1341
  let previousCompactToolSummary;
1402
1342
  let currentCompactRun = [];
1343
+ let previousSpacingComponent;
1403
1344
  const flushCompactRunColor = () => {
1404
1345
  const color = getCompactRunLabelColor(currentCompactRun);
1405
1346
  for (const participant of currentCompactRun) {
@@ -1431,22 +1372,24 @@ function reconcileChatBoundarySpacers(chatContainer) {
1431
1372
  previousCompactToolGroupKey = compactToolGroupKey;
1432
1373
  previousCompactToolSummary = compactToolGroupSummary;
1433
1374
  }
1434
- nextChildren.push(component);
1435
- if (getChatSpacingKind(component)) {
1436
- const previous = findPreviousSpacingComponentInList(components, i);
1437
- const nextIndex = next ? components.indexOf(next) : -1;
1438
- const nextNext = nextIndex >= 0 ? findNextSpacingComponentInList(components, nextIndex) : void 0;
1439
- if (next) {
1440
- nextChildren.push(
1441
- new ChatBoundarySpacer(
1442
- () => component,
1443
- () => next,
1444
- () => previous,
1445
- () => nextNext
1446
- )
1447
- );
1375
+ if (getChatSpacingKind(component) && previousSpacingComponent) {
1376
+ const spacing = getSpacingBetweenComponents(previousSpacingComponent, component);
1377
+ if (spacing > 0) {
1378
+ let spacer;
1379
+ if (poolIndex < spacerPool.length) {
1380
+ spacer = spacerPool[poolIndex];
1381
+ spacer.setLines(spacing);
1382
+ poolIndex++;
1383
+ } else {
1384
+ spacer = new ChatBoundarySpacer(spacing);
1385
+ }
1386
+ nextChildren.push(spacer);
1448
1387
  }
1449
1388
  }
1389
+ if (getChatSpacingKind(component)) {
1390
+ previousSpacingComponent = component;
1391
+ }
1392
+ nextChildren.push(component);
1450
1393
  }
1451
1394
  flushCompactRunColor();
1452
1395
  chatContainer.children = nextChildren;
@@ -1569,116 +1512,6 @@ var GoalCyclesDialogComponent = class extends Box {
1569
1512
  this.input.handleInput(data);
1570
1513
  }
1571
1514
  };
1572
- var JUDGE_COLOR = mastraBrand.blue;
1573
- var MUTED_COLOR = "#8a8a8a";
1574
- var PAUSED_COLOR = "#f5a524";
1575
- var WAITING_COLOR = "#8a8a8a";
1576
- var JudgeDisplayComponent = class extends Container {
1577
- result;
1578
- turnsUsed;
1579
- maxTurns;
1580
- activity = [];
1581
- constructor(result = null, turnsUsed = 0, maxTurns = 0) {
1582
- super();
1583
- this.result = result;
1584
- this.turnsUsed = turnsUsed;
1585
- this.maxTurns = maxTurns;
1586
- this.renderContent();
1587
- }
1588
- addActivity(line) {
1589
- if (this.activity[this.activity.length - 1] !== line) {
1590
- this.activity.push(line);
1591
- }
1592
- if (this.activity.length > 6) {
1593
- this.activity = this.activity.slice(-6);
1594
- }
1595
- this.renderContent();
1596
- }
1597
- setResult(result, turnsUsed, maxTurns) {
1598
- this.result = result;
1599
- this.turnsUsed = turnsUsed;
1600
- this.maxTurns = maxTurns;
1601
- this.renderContent();
1602
- }
1603
- setInterrupted() {
1604
- this.setResult({ decision: "paused", reason: "Judge evaluation was interrupted." }, this.turnsUsed, this.maxTurns);
1605
- }
1606
- renderContent() {
1607
- this.clear();
1608
- const border = (char) => chalk14.hex(JUDGE_COLOR)(char);
1609
- const title = chalk14.hex(JUDGE_COLOR).bold("Goal");
1610
- const termWidth = getTermWidth();
1611
- const innerWidth = Math.max(20, termWidth - BOX_INDENT * 2 - 4);
1612
- const horizontal = "\u2500".repeat(innerWidth + 1);
1613
- this.addChild(new Spacer(1));
1614
- this.addChild(new Text(`${border("\u256D")}${border(horizontal)}${border("\u256E")}`, BOX_INDENT, 0));
1615
- this.addChild(new Text(this.renderRow(this.renderHeader(title), innerWidth, border), BOX_INDENT, 0));
1616
- if (!this.result && this.activity.length === 0) {
1617
- this.addChild(new Text(this.renderRow(chalk14.dim("evaluating\u2026"), innerWidth, border), BOX_INDENT, 0));
1618
- }
1619
- for (const line of this.activity) {
1620
- this.addChild(new Text(this.renderRow(this.renderActivityLine(line), innerWidth, border), BOX_INDENT, 0));
1621
- }
1622
- if (this.activity.length > 0 && this.result) {
1623
- this.addChild(new Text(this.renderRow("", innerWidth, border), BOX_INDENT, 0));
1624
- }
1625
- if (this.result) {
1626
- for (const line of this.wrapLine(this.result.reason, innerWidth)) {
1627
- this.addChild(new Text(this.renderRow(chalk14.dim(line), innerWidth, border), BOX_INDENT, 0));
1628
- }
1629
- }
1630
- this.addChild(new Text(`${border("\u2570")}${border(horizontal)}${border("\u256F")}`, BOX_INDENT, 0));
1631
- }
1632
- renderActivityLine(line) {
1633
- const toolName = getActivityToolName(line);
1634
- if (!toolName) return theme.fg("dim", `\u2022 ${line}`);
1635
- const rest = line.slice(toolName.length);
1636
- return `${theme.fg("dim", "\u2022 ")}${theme.fg("dim", theme.italic(toolName))}${theme.fg("dim", rest)}`;
1637
- }
1638
- renderHeader(title) {
1639
- if (!this.result) {
1640
- return `${title} \u25CC ${chalk14.hex(WAITING_COLOR).bold("evaluating")}`;
1641
- }
1642
- const decisionIcon = this.result.decision === "done" ? "\u25CF" : this.result.decision === "paused" ? "!" : this.result.decision === "waiting" ? "\u25CC" : "\u25CB";
1643
- const decisionText = getDecisionText(this.result.decision);
1644
- const turnInfo = this.maxTurns > 0 ? chalk14.hex(MUTED_COLOR)(`(${this.turnsUsed}/${this.maxTurns})`) : "";
1645
- return `${title} ${decisionIcon} ${decisionText}${turnInfo ? ` ${turnInfo}` : ""}`;
1646
- }
1647
- renderRow(text, width, border) {
1648
- const content = this.padLine(text, width);
1649
- return `${border("\u2502")} ${content}${border("\u2502")}`;
1650
- }
1651
- wrapLine(text, width) {
1652
- const lines = [];
1653
- let remaining = text;
1654
- while (remaining.length > width) {
1655
- const breakAt = remaining.lastIndexOf(" ", width);
1656
- const splitAt = breakAt > 0 ? breakAt : width;
1657
- lines.push(remaining.slice(0, splitAt));
1658
- remaining = remaining.slice(splitAt).trimStart();
1659
- }
1660
- lines.push(remaining);
1661
- return lines;
1662
- }
1663
- padLine(text, width) {
1664
- const visibleLength = stripAnsi2(text).length;
1665
- if (visibleLength >= width) {
1666
- return stripAnsi2(text).slice(0, width);
1667
- }
1668
- return text + " ".repeat(width - visibleLength);
1669
- }
1670
- };
1671
- function getActivityToolName(line) {
1672
- if (line.startsWith("find files ")) return "find files";
1673
- const [toolName] = line.split(" ");
1674
- return toolName || null;
1675
- }
1676
- function getDecisionText(decision) {
1677
- if (decision === "done") return chalk14.hex("#16c858").bold("done");
1678
- if (decision === "paused") return chalk14.hex(PAUSED_COLOR).bold("paused");
1679
- if (decision === "waiting") return chalk14.hex(WAITING_COLOR).bold("waiting");
1680
- return chalk14.hex(JUDGE_COLOR).bold("continue");
1681
- }
1682
1515
  function makeCustomModelItem(id, models) {
1683
1516
  const parts = id.split("/");
1684
1517
  const provider = parts.length > 1 ? parts[0] : "custom";
@@ -1726,7 +1559,7 @@ var ModelSelectorComponent = class extends Box {
1726
1559
  this.buildUI();
1727
1560
  }
1728
1561
  buildUI() {
1729
- const titleText = this.titleColor ? chalk14.bgHex(this.titleColor).white.bold(` ${this.title} `) : theme.bold(theme.fg("accent", this.title));
1562
+ const titleText = this.titleColor ? chalk12.bgHex(this.titleColor).white.bold(` ${this.title} `) : theme.bold(theme.fg("accent", this.title));
1730
1563
  this.addChild(new Text(titleText, 0, 0));
1731
1564
  this.addChild(new Spacer(1));
1732
1565
  this.addChild(new Text(theme.fg("muted", "Type to search \u2022 \u2191\u2193 navigate \u2022 Enter select \u2022 Esc cancel"), 0, 0));
@@ -1854,173 +1687,35 @@ var ModelSelectorComponent = class extends Box {
1854
1687
  return this.searchInput;
1855
1688
  }
1856
1689
  };
1857
- var GRADIENT_WIDTH = 30;
1858
- var BASE_COLOR = [22, 200, 88];
1859
- function getMinBrightness() {
1860
- return getThemeMode() === "dark" ? 0.45 : 0.55;
1861
- }
1862
- function hexToRgb(hex) {
1863
- const h = hex.replace("#", "");
1864
- return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)];
1865
- }
1866
- var IDLE_BRIGHTNESS = 0.8;
1867
- function applyGradientSweep(text, offset, color, fadeProgress = 0) {
1868
- const chars = [...text];
1869
- const totalChars = chars.length;
1870
- if (totalChars === 0) return text;
1871
- const baseColor = color ? hexToRgb(color) : BASE_COLOR;
1872
- const gradientCenter = offset % 1 * 100;
1873
- const halfGradient = GRADIENT_WIDTH / 2;
1874
- const minBrightness = getMinBrightness();
1875
- const brightnessRange = 1 - minBrightness;
1876
- let result = "";
1877
- let batchChars = "";
1878
- let batchR = -1, batchG = -1, batchB = -1;
1879
- for (let i = 0; i < totalChars; i++) {
1880
- const char = chars[i];
1881
- if (char === " ") {
1882
- if (batchChars) {
1883
- result += chalk14.rgb(batchR, batchG, batchB)(batchChars);
1884
- batchChars = "";
1885
- }
1886
- result += " ";
1887
- continue;
1888
- }
1889
- const charPosition = i / totalChars * 100;
1890
- let distance = Math.abs(charPosition - gradientCenter);
1891
- if (distance > 50) distance = 100 - distance;
1892
- const normalizedDistance = Math.min(distance / halfGradient, 1);
1893
- const animBrightness = minBrightness + brightnessRange * (1 - normalizedDistance);
1894
- const brightness = animBrightness + (IDLE_BRIGHTNESS - animBrightness) * fadeProgress;
1895
- const r = Math.floor(baseColor[0] * brightness);
1896
- const g = Math.floor(baseColor[1] * brightness);
1897
- const b = Math.floor(baseColor[2] * brightness);
1898
- if (r === batchR && g === batchG && b === batchB) {
1899
- batchChars += char;
1900
- } else {
1901
- if (batchChars) {
1902
- result += chalk14.rgb(batchR, batchG, batchB)(batchChars);
1903
- }
1904
- batchChars = char;
1905
- batchR = r;
1906
- batchG = g;
1907
- batchB = b;
1908
- }
1909
- }
1910
- if (batchChars) {
1911
- result += chalk14.rgb(batchR, batchG, batchB)(batchChars);
1912
- }
1913
- return result;
1914
- }
1915
- var GradientAnimator = class {
1916
- offset = 0;
1917
- intervalId = null;
1918
- onTick;
1919
- _isFadingOut = false;
1920
- _isFadingIn = false;
1921
- _fadeProgress = 0;
1922
- // 0 = full animation, 1 = fully idle
1923
- constructor(onTick) {
1924
- this.onTick = onTick;
1925
- }
1926
- start() {
1927
- if (this.intervalId && !this._isFadingOut) return;
1928
- if (this.intervalId) {
1929
- clearInterval(this.intervalId);
1930
- this.intervalId = null;
1931
- }
1932
- this._isFadingOut = false;
1933
- this._isFadingIn = true;
1934
- this._fadeProgress = 1;
1935
- this.offset = 0;
1936
- this.intervalId = setInterval(() => {
1937
- this.offset += 0.03;
1938
- if (this._isFadingIn) {
1939
- this._fadeProgress -= 0.06;
1940
- if (this._fadeProgress <= 0) {
1941
- this._fadeProgress = 0;
1942
- this._isFadingIn = false;
1943
- }
1944
- }
1945
- this.onTick();
1946
- }, 80);
1947
- }
1948
- /**
1949
- * Smoothly fade the gradient to idle state over ~500ms.
1950
- */
1951
- fadeOut() {
1952
- if (!this.intervalId) return;
1953
- if (this._isFadingOut) return;
1954
- this._isFadingOut = true;
1955
- this._isFadingIn = false;
1956
- this._fadeProgress = 0;
1957
- clearInterval(this.intervalId);
1958
- this.intervalId = setInterval(() => {
1959
- this._fadeProgress += 0.08;
1960
- if (this._fadeProgress >= 1) {
1961
- this._fadeProgress = 1;
1962
- this.stop();
1963
- }
1964
- this.onTick();
1965
- }, 40);
1966
- }
1967
- stop() {
1968
- if (this.intervalId) {
1969
- clearInterval(this.intervalId);
1970
- this.intervalId = null;
1971
- }
1972
- this._isFadingOut = false;
1973
- this._isFadingIn = false;
1974
- this._fadeProgress = 0;
1975
- this.offset = 0;
1976
- }
1977
- getOffset() {
1978
- return this.offset;
1979
- }
1980
- /** 0 = full animation, 1 = fully idle. Use to interpolate colors. */
1981
- getFadeProgress() {
1982
- return this._fadeProgress;
1983
- }
1984
- isFadingOut() {
1985
- return this._isFadingOut;
1986
- }
1987
- isFadingIn() {
1988
- return this._isFadingIn;
1989
- }
1990
- isRunning() {
1991
- return this.intervalId !== null;
1992
- }
1993
- };
1994
1690
  var DEFAULT_MAX_TURNS = 50;
1995
1691
  var THREAD_GOAL_KEY = "goal";
1996
- var JUDGE_MAX_STEPS = 50;
1997
- var JUDGE_RETRY_PROMPT = 'You did not produce a structured decision. You MUST respond with a JSON object containing "decision" (one of "done", "continue", or "waiting") and "reason" (a brief explanation). Do not use any tools \u2014 respond with the JSON decision immediately based on what you already know.';
1998
- var JUDGE_SYSTEM_PROMPT = `You are the goal judge. Your decision directly controls whether the assistant continues working toward the goal.
1999
-
2000
- Given a goal and the assistant's latest response, reason about whether the goal's requirements have been satisfied. Compare what the goal asks for against what the assistant has actually produced. Focus on substance, not phrasing.
2001
-
2002
- Use "done" when the goal is fully achieved.
2003
- Use "waiting" when the goal explicitly requires a user checkpoint, user feedback, human verification, human confirmation, or another external event outside the goal-judge loop before the assistant should continue, and the assistant has correctly stopped at that checkpoint.
2004
- Use "waiting" when the latest user message asks a question or requests clarification and the latest assistant message answers it; let the user acknowledge the answer, ask a follow-up, or otherwise return control before continuing goal work. Use common sense and do not wait if the user explicitly asked the assistant to continue autonomously after answering.
2005
- Use "continue" when the goal is not done and the assistant should keep working autonomously, including when it asked for input that the goal did not explicitly require.
2006
- If your previous decision was "waiting" for an explicit user checkpoint, keep choosing "waiting" when the user's latest response asks a question, requests clarification, or otherwise does not satisfy the checkpoint. Do not continue until the required user feedback/confirmation/verification has actually been provided.
2007
- If the goal says to wait for the goal judge, judge, evaluator, or you to respond, approve, verify, validate, tell the assistant to continue, or otherwise provide the next signal, treat your own decision as that judge response. Verification can be performed by you unless the goal explicitly says it needs human/user verification. Choose "continue" when the assistant should proceed to the next step. Do not choose "waiting" for judge-controlled checkpoints, because that would mean waiting for yourself.
2008
-
2009
- Your "reason" field is sent back to the assistant as guidance when the goal is not yet done \u2014 be specific about what still needs to be accomplished. When choosing "continue", write the reason as an instruction for what the assistant should do next. When choosing "waiting", explain what specific user checkpoint is still outstanding.`;
2010
- var judgeSchema = z.object({
2011
- decision: z.enum(["done", "continue", "waiting"]).describe(
2012
- "Whether the goal is done, should continue autonomously, or is at an explicit user checkpoint required by the goal"
2013
- ),
2014
- reason: z.string().describe("Brief explanation of what was accomplished or what remains to be done")
2015
- });
2016
1692
  var GoalManager = class {
2017
- goal = null;
1693
+ /** Synchronous in-memory view of the active objective record (source of truth is ThreadState). */
1694
+ record = null;
1695
+ /** Display-only active-timer accounting (not persisted to the objective record). */
1696
+ activeStartedAt = null;
1697
+ activeDurationMs = 0;
2018
1698
  persistGoalOnNextThreadCreate = false;
1699
+ // ---------------------------------------------------------------------------
1700
+ // Synchronous TUI surface
1701
+ // ---------------------------------------------------------------------------
2019
1702
  getGoal() {
2020
- return this.goal;
1703
+ if (!this.record) return null;
1704
+ const { judgeModelId, maxTurns } = this.effectiveSettings(this.record);
1705
+ return {
1706
+ id: this.record.id,
1707
+ objective: this.record.objective,
1708
+ status: this.record.status,
1709
+ turnsUsed: this.record.runsUsed,
1710
+ maxTurns,
1711
+ judgeModelId,
1712
+ startedAt: new Date(this.record.startedAt).toISOString(),
1713
+ activeStartedAt: this.activeStartedAt ?? void 0,
1714
+ activeDurationMs: this.activeDurationMs
1715
+ };
2021
1716
  }
2022
1717
  isActive() {
2023
- return this.goal?.status === "active";
1718
+ return this.record?.status === "active";
2024
1719
  }
2025
1720
  persistOnNextThreadCreate() {
2026
1721
  this.persistGoalOnNextThreadCreate = true;
@@ -2030,404 +1725,231 @@ var GoalManager = class {
2030
1725
  this.persistGoalOnNextThreadCreate = false;
2031
1726
  return true;
2032
1727
  }
2033
- /**
2034
- * Set a new goal objective. Resets turn counter.
2035
- */
2036
- setGoal(objective, judgeModelId, maxTurns = DEFAULT_MAX_TURNS) {
2037
- const now = (/* @__PURE__ */ new Date()).toISOString();
2038
- this.goal = {
2039
- id: randomUUID(),
2040
- objective,
2041
- status: "active",
2042
- turnsUsed: 0,
2043
- maxTurns,
2044
- judgeModelId,
2045
- startedAt: now,
2046
- activeStartedAt: now,
2047
- activeDurationMs: 0
2048
- };
2049
- return this.goal;
2050
- }
2051
- /**
2052
- * Load goal state from thread metadata (called on thread switch).
2053
- */
2054
- loadFromThreadMetadata(metadata) {
2055
- const saved = metadata?.[THREAD_GOAL_KEY];
2056
- if (saved && saved.objective && saved.status) {
2057
- this.goal = {
2058
- ...saved,
2059
- id: saved.id ?? randomUUID(),
2060
- startedAt: saved.startedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
2061
- activeStartedAt: void 0,
2062
- activeDurationMs: saved.activeDurationMs ?? 0
2063
- };
2064
- } else {
2065
- this.goal = null;
2066
- }
2067
- this.persistGoalOnNextThreadCreate = false;
2068
- }
2069
- /**
2070
- * Persist goal state to thread metadata.
2071
- */
2072
- async saveToThread(state) {
2073
- try {
2074
- if (this.goal) {
2075
- await state.harness.setThreadSetting({ key: THREAD_GOAL_KEY, value: this.goal });
2076
- } else {
2077
- await state.harness.setThreadSetting({ key: THREAD_GOAL_KEY, value: void 0 });
2078
- }
2079
- } catch {
2080
- }
2081
- }
2082
- pause() {
2083
- if (this.goal && this.goal.status === "active") {
2084
- this.stopActiveTimer();
2085
- this.goal.status = "paused";
2086
- }
2087
- return this.goal;
2088
- }
2089
- resume() {
2090
- if (this.goal && this.goal.status === "paused") {
2091
- this.goal.status = "active";
2092
- this.startActiveTimer();
2093
- }
2094
- return this.goal;
2095
- }
2096
1728
  startActiveTimer() {
2097
- if (this.goal?.status === "active" && !this.goal.activeStartedAt) {
2098
- this.goal.activeStartedAt = (/* @__PURE__ */ new Date()).toISOString();
1729
+ if (this.record?.status === "active" && !this.activeStartedAt) {
1730
+ this.activeStartedAt = (/* @__PURE__ */ new Date()).toISOString();
2099
1731
  }
2100
1732
  }
2101
1733
  stopActiveTimer() {
2102
- if (!this.goal?.activeStartedAt) return;
2103
- const activeStartedMs = Date.parse(this.goal.activeStartedAt);
2104
- if (Number.isFinite(activeStartedMs)) {
2105
- this.goal.activeDurationMs = (this.goal.activeDurationMs ?? 0) + Math.max(0, Date.now() - activeStartedMs);
2106
- }
2107
- this.goal.activeStartedAt = void 0;
2108
- }
2109
- updateJudgeDefaults(judgeModelId, maxTurns) {
2110
- if (this.goal) {
2111
- this.goal.judgeModelId = judgeModelId;
2112
- this.goal.maxTurns = maxTurns;
1734
+ if (!this.activeStartedAt) return;
1735
+ const startedMs = Date.parse(this.activeStartedAt);
1736
+ if (Number.isFinite(startedMs)) {
1737
+ this.activeDurationMs += Math.max(0, Date.now() - startedMs);
2113
1738
  }
2114
- return this.goal;
1739
+ this.activeStartedAt = null;
2115
1740
  }
2116
- clear() {
2117
- this.goal = null;
2118
- this.persistGoalOnNextThreadCreate = false;
2119
- }
2120
- markDone() {
2121
- if (this.goal) {
2122
- this.stopActiveTimer();
2123
- this.goal.status = "done";
2124
- }
1741
+ /** Reset active-timer accounting to zero (e.g. for an untriggered plan goal). */
1742
+ resetActiveTimer() {
1743
+ this.activeStartedAt = null;
1744
+ this.activeDurationMs = 0;
2125
1745
  }
1746
+ // ---------------------------------------------------------------------------
1747
+ // Objective lifecycle (ThreadState-backed via the agent)
1748
+ // ---------------------------------------------------------------------------
2126
1749
  /**
2127
- * Called after each agent turn completes. Evaluates whether to continue.
2128
- * Returns a GoalEvaluationResult with continuation prompt and judge result.
1750
+ * Set a new objective. Persists to ThreadState via `agent.setObjective` and
1751
+ * updates the in-memory view. Only the provided settings are persisted into
1752
+ * the record; unset ones fall back to the agent's `goal` config at read time.
2129
1753
  */
2130
- async evaluateAfterTurn(state, options = {}) {
2131
- if (!this.goal || this.goal.status !== "active") {
2132
- return { continuation: null, judgeResult: null };
2133
- }
2134
- const evaluatedGoalId = this.goal.id;
2135
- const context = await this.getRecentConversationContext(state);
2136
- if (!this.goal || this.goal.id !== evaluatedGoalId || this.goal.status !== "active") {
2137
- return { continuation: null, judgeResult: null };
2138
- }
2139
- if (!context.lastAssistantContent) {
2140
- if (options.requireAssistantMessage) {
2141
- const result2 = {
2142
- decision: "paused",
2143
- reason: "Judge could not evaluate this turn: no assistant response."
2144
- };
2145
- this.stopActiveTimer();
2146
- this.goal.status = "paused";
2147
- this.goal.lastPauseWasJudgeFailure = true;
2148
- await this.saveToThread(state);
2149
- return { continuation: null, judgeResult: result2 };
2150
- }
2151
- if (this.goal.turnsUsed >= this.goal.maxTurns) {
2152
- this.stopActiveTimer();
2153
- this.goal.status = "paused";
2154
- this.goal.lastPauseWasJudgeFailure = false;
2155
- await this.saveToThread(state);
2156
- return { continuation: null, judgeResult: null };
2157
- }
2158
- await this.saveToThread(state);
2159
- return { continuation: this.buildContinuationPrompt("No response yet, keep working."), judgeResult: null };
2160
- }
2161
- const result = await this.callJudge(
2162
- state,
2163
- {
2164
- lastUserContent: context.lastUserContent,
2165
- assistantStepsSinceLastUser: context.assistantStepsSinceLastUser,
2166
- lastAssistantContent: context.lastAssistantContent
2167
- },
2168
- options
2169
- );
2170
- if (!this.goal || this.goal.id !== evaluatedGoalId || this.goal.status !== "active") {
2171
- return { continuation: null, judgeResult: null };
2172
- }
2173
- if (result.decision === "continue" || result.decision === "done") {
2174
- this.goal.turnsUsed++;
2175
- this.goal.lastPauseWasJudgeFailure = false;
2176
- }
2177
- if (result.decision === "paused") {
2178
- this.stopActiveTimer();
2179
- this.goal.status = "paused";
2180
- this.goal.lastPauseWasJudgeFailure = isJudgeFailureReason(result.reason);
2181
- await this.saveToThread(state);
2182
- return { continuation: null, judgeResult: result };
2183
- }
2184
- if (result.decision === "done") {
2185
- this.stopActiveTimer();
2186
- this.goal.status = "done";
2187
- await this.saveToThread(state);
2188
- return { continuation: null, judgeResult: result };
2189
- }
2190
- if (result.decision === "waiting") {
2191
- this.stopActiveTimer();
2192
- await this.saveToThread(state);
2193
- return { continuation: null, judgeResult: result };
2194
- }
2195
- if (this.goal.turnsUsed >= this.goal.maxTurns) {
2196
- this.stopActiveTimer();
2197
- this.goal.status = "paused";
2198
- this.goal.lastPauseWasJudgeFailure = false;
2199
- await this.saveToThread(state);
2200
- return { continuation: null, judgeResult: result };
2201
- }
2202
- this.startActiveTimer();
2203
- await this.saveToThread(state);
2204
- return { continuation: this.buildContinuationPrompt(result.reason), judgeResult: result };
2205
- }
2206
- // ===========================================================================
2207
- // Private
2208
- // ===========================================================================
2209
- async getRecentConversationContext(state) {
2210
- try {
2211
- const messages = await state.harness.listMessages();
2212
- let lastUserIndex = -1;
2213
- let lastAssistantContent = null;
2214
- for (let i = messages.length - 1; i >= 0; i--) {
2215
- const msg = messages[i];
2216
- if (!lastAssistantContent && msg.role === "assistant") {
2217
- lastAssistantContent = this.extractTextContent(msg.content);
2218
- }
2219
- if (msg.role === "user") {
2220
- lastUserIndex = i;
2221
- break;
2222
- }
2223
- }
2224
- const lastUserContent = lastUserIndex >= 0 ? this.extractTextContent(messages[lastUserIndex].content) : null;
2225
- const assistantStepsSinceLastUser = lastUserIndex >= 0 ? messages.slice(lastUserIndex + 1).filter((msg) => msg.role === "assistant").length : 0;
2226
- return { lastUserContent, assistantStepsSinceLastUser, lastAssistantContent };
2227
- } catch {
2228
- return { lastUserContent: null, assistantStepsSinceLastUser: 0, lastAssistantContent: null };
2229
- }
2230
- }
2231
- extractTextContent(content) {
2232
- if (typeof content === "string") return content;
2233
- if (Array.isArray(content)) {
2234
- return content.map((part) => {
2235
- if (typeof part === "string") return part;
2236
- if (typeof part?.text === "string") return part.text;
2237
- if (typeof part?.content === "string") return part.content;
2238
- return null;
2239
- }).filter((text) => Boolean(text)).join("\n");
2240
- }
2241
- return String(content ?? "");
2242
- }
2243
- async callJudge(state, context, options) {
2244
- try {
2245
- const memory = await this.getJudgeMemory(state);
2246
- const tools = await this.createJudgeTools(state);
2247
- const judgeAgent = this.createJudgeAgent(memory, tools);
2248
- if (!judgeAgent) {
2249
- return { decision: "paused", reason: "Judge model could not be initialized." };
2250
- }
2251
- const recentUser = context.lastUserContent ? `
2252
-
2253
- Latest user message:
2254
- ${truncateForJudge(context.lastUserContent)}
2255
-
2256
- Assistant steps since that user message: ${context.assistantStepsSinceLastUser}` : "";
2257
- const prompt = `Goal: ${this.goal.objective}${recentUser}
2258
-
2259
- Latest assistant message:
2260
- ${context.lastAssistantContent}`;
2261
- const memoryOpts = memory ? { memory: { thread: this.getJudgeThreadId(state), resource: state.harness.getResourceId() } } : {};
2262
- const streamOpts = {
2263
- ...memoryOpts,
2264
- abortSignal: options.abortSignal,
2265
- maxSteps: JUDGE_MAX_STEPS,
2266
- structuredOutput: {
2267
- schema: judgeSchema,
2268
- errorStrategy: "warn"
2269
- }
2270
- };
2271
- const stream = await judgeAgent.stream(prompt, streamOpts);
2272
- await this.consumeJudgeStream(stream, options.onActivity);
2273
- const output = (await stream.getFullOutput()).object;
2274
- if (output) {
2275
- return { decision: output.decision, reason: output.reason };
2276
- }
2277
- if (options.abortSignal?.aborted) {
2278
- return { decision: "paused", reason: "Judge evaluation was interrupted." };
2279
- }
2280
- options.onActivity?.("retrying (no structured decision)");
2281
- const retryStream = await judgeAgent.stream(JUDGE_RETRY_PROMPT, streamOpts);
2282
- await this.consumeJudgeStream(retryStream, options.onActivity);
2283
- const retryOutput = (await retryStream.getFullOutput()).object;
2284
- if (retryOutput) {
2285
- return { decision: retryOutput.decision, reason: retryOutput.reason };
2286
- }
2287
- return { decision: "paused", reason: "Judge returned no structured decision." };
2288
- } catch (error) {
2289
- if (options.abortSignal?.aborted) {
2290
- return { decision: "paused", reason: "Judge evaluation was interrupted." };
2291
- }
2292
- return { decision: "paused", reason: `Judge could not evaluate this turn: ${formatError(error)}` };
1754
+ async setGoal(state, objective, judgeModelId, maxTurns = DEFAULT_MAX_TURNS) {
1755
+ const threadId = state.harness.getCurrentThreadId();
1756
+ const agent = this.getAgent(state);
1757
+ const now = Date.now();
1758
+ const id = randomUUID();
1759
+ if (agent && threadId) {
1760
+ const persisted = await agent.setObjective(objective, {
1761
+ threadId,
1762
+ resourceId: state.harness.getResourceId(),
1763
+ ...judgeModelId ? { judgeModelId } : {},
1764
+ maxRuns: maxTurns
1765
+ });
1766
+ this.record = persisted ? { ...persisted, id } : this.localRecord(objective, judgeModelId, maxTurns, now, id);
1767
+ } else {
1768
+ this.record = this.localRecord(objective, judgeModelId, maxTurns, now, id);
2293
1769
  }
1770
+ this.activeStartedAt = new Date(now).toISOString();
1771
+ this.activeDurationMs = 0;
1772
+ return this.getGoal();
2294
1773
  }
2295
- async createJudgeTools(state) {
2296
- const workspace = state.harness.getWorkspace?.() ?? state.workspace;
2297
- if (!workspace) return {};
2298
- const workspaceTools = await createWorkspaceTools(workspace, {
2299
- requestContext: {},
2300
- workspace
2301
- });
2302
- const allowedTools = /* @__PURE__ */ new Set([
2303
- MC_TOOLS.VIEW,
2304
- MC_TOOLS.SEARCH_CONTENT,
2305
- MC_TOOLS.FIND_FILES,
2306
- MC_TOOLS.FILE_STAT,
2307
- MC_TOOLS.LSP_INSPECT
2308
- ]);
2309
- const tools = {};
2310
- for (const [name, tool] of Object.entries(workspaceTools)) {
2311
- if (!allowedTools.has(name)) continue;
2312
- const { needsApprovalFn: _needsApprovalFn, ...toolWithoutApproval } = tool;
2313
- tools[name] = { ...toolWithoutApproval, requireApproval: false };
1774
+ /**
1775
+ * Update the judge model / max-runs defaults. Persists into the active record
1776
+ * (so the override is remembered in thread state) when a goal is set.
1777
+ */
1778
+ async updateJudgeDefaults(state, judgeModelId, maxTurns) {
1779
+ if (!this.record) return null;
1780
+ const threadId = state.harness.getCurrentThreadId();
1781
+ const agent = this.getAgent(state);
1782
+ if (agent && threadId) {
1783
+ const updated = await agent.updateObjectiveOptions({
1784
+ threadId,
1785
+ ...judgeModelId ? { judgeModelId } : {},
1786
+ maxRuns: maxTurns
1787
+ });
1788
+ if (updated) this.record = { ...updated, id: this.record.id };
1789
+ } else {
1790
+ this.record = {
1791
+ ...this.record,
1792
+ ...judgeModelId ? { judgeModelId } : {},
1793
+ maxRuns: maxTurns,
1794
+ updatedAt: Date.now()
1795
+ };
2314
1796
  }
2315
- return tools;
1797
+ return this.getGoal();
2316
1798
  }
2317
- async consumeJudgeStream(stream, onActivity) {
2318
- if (!stream.fullStream) {
2319
- await stream.consumeStream();
2320
- return;
1799
+ pause() {
1800
+ if (this.record && this.record.status === "active") {
1801
+ this.stopActiveTimer();
1802
+ this.record = { ...this.record, status: "paused", updatedAt: Date.now() };
2321
1803
  }
2322
- for await (const chunk of stream.fullStream) {
2323
- if (chunk?.type === "tool-call") {
2324
- const toolName = getToolName(chunk);
2325
- if (!toolName) continue;
2326
- const line = formatJudgeActivity(toolName, parseToolInput(chunk));
2327
- if (line) onActivity?.(line);
2328
- }
1804
+ return this.getGoal();
1805
+ }
1806
+ resume() {
1807
+ if (this.record && this.record.status === "paused") {
1808
+ this.record = { ...this.record, status: "active", updatedAt: Date.now() };
1809
+ this.startActiveTimer();
2329
1810
  }
1811
+ return this.getGoal();
2330
1812
  }
2331
- async getJudgeMemory(state) {
2332
- const harness = state.harness;
2333
- const memory = await harness.getResolvedMemory?.() ?? null;
2334
- if (!memory || !this.goal) return memory;
2335
- const threadId = this.getJudgeThreadId(state);
2336
- const existing = await memory.getThreadById({ threadId });
2337
- if (!existing) {
2338
- await memory.createThread({
2339
- threadId,
2340
- resourceId: state.harness.getResourceId(),
2341
- title: `Goal judge: ${this.goal.objective.slice(0, 80)}`,
2342
- metadata: {
2343
- forkedSubagent: true,
2344
- goalJudge: true,
2345
- parentThreadId: state.harness.getCurrentThreadId(),
2346
- goalId: this.goal.id
2347
- }
2348
- });
1813
+ markDone() {
1814
+ if (this.record) {
1815
+ this.stopActiveTimer();
1816
+ this.record = { ...this.record, status: "done", updatedAt: Date.now() };
2349
1817
  }
2350
- return memory;
2351
1818
  }
2352
- getJudgeThreadId(state) {
2353
- return `${state.harness.getCurrentThreadId() ?? "no-thread"}-${this.goal.id}`;
1819
+ clear() {
1820
+ this.record = null;
1821
+ this.activeStartedAt = null;
1822
+ this.activeDurationMs = 0;
1823
+ this.persistGoalOnNextThreadCreate = false;
1824
+ }
1825
+ /**
1826
+ * Sync the latest objective record from ThreadState into the in-memory view.
1827
+ * Called from the `goal` stream-chunk handler after each evaluation.
1828
+ */
1829
+ applyEvaluation(update) {
1830
+ if (!this.record) return null;
1831
+ this.record = { ...this.record, runsUsed: update.runsUsed, status: update.status, updatedAt: Date.now() };
1832
+ if (update.status !== "active") this.stopActiveTimer();
1833
+ return this.getGoal();
2354
1834
  }
2355
- createJudgeAgent(memory, tools) {
2356
- if (!this.goal?.judgeModelId) return null;
1835
+ // ---------------------------------------------------------------------------
1836
+ // Persistence
1837
+ // ---------------------------------------------------------------------------
1838
+ /**
1839
+ * Persist the active objective to ThreadState via the agent. The objective
1840
+ * record is the source of truth; the legacy thread-metadata key is cleared so
1841
+ * stale state from older sessions does not resurface.
1842
+ */
1843
+ async saveToThread(state) {
1844
+ const threadId = state.harness.getCurrentThreadId();
1845
+ const agent = this.getAgent(state);
2357
1846
  try {
2358
- const model = resolveModel(this.goal.judgeModelId);
2359
- return new Agent({
2360
- id: "goal-judge",
2361
- name: "Goal Judge",
2362
- instructions: JUDGE_SYSTEM_PROMPT,
2363
- model,
2364
- tools,
2365
- ...memory ? { memory } : {},
2366
- inputProcessors: [new ProviderHistoryCompat()],
2367
- errorProcessors: [new StreamErrorRetryProcessor(), new PrefillErrorHandler(), new ProviderHistoryCompat()]
2368
- });
1847
+ if (agent && threadId) {
1848
+ if (this.record) {
1849
+ const updated = await agent.updateObjectiveOptions({
1850
+ threadId,
1851
+ status: this.record.status,
1852
+ ...this.record.judgeModelId ? { judgeModelId: this.record.judgeModelId } : {},
1853
+ ...this.record.maxRuns !== void 0 ? { maxRuns: this.record.maxRuns } : {}
1854
+ });
1855
+ if (!updated) {
1856
+ const desiredStatus = this.record.status;
1857
+ await agent.setObjective(this.record.objective, {
1858
+ threadId,
1859
+ resourceId: state.harness.getResourceId(),
1860
+ ...this.record.judgeModelId ? { judgeModelId: this.record.judgeModelId } : {},
1861
+ ...this.record.maxRuns !== void 0 ? { maxRuns: this.record.maxRuns } : {}
1862
+ });
1863
+ if (desiredStatus !== "active") {
1864
+ await agent.updateObjectiveOptions({ threadId, status: desiredStatus });
1865
+ }
1866
+ }
1867
+ } else {
1868
+ await agent.clearObjective({ threadId });
1869
+ }
1870
+ }
1871
+ await state.harness.setThreadSetting({ key: THREAD_GOAL_KEY, value: void 0 });
2369
1872
  } catch {
2370
- return null;
2371
1873
  }
2372
1874
  }
2373
- buildContinuationPrompt(judgeReason) {
2374
- const turn = this.goal.turnsUsed;
2375
- const max = this.goal.maxTurns;
2376
- return `[Goal attempt ${turn}/${max}] The goal is not yet complete. Judge feedback: ${judgeReason}
2377
-
2378
- Continue working toward the goal: ${this.goal.objective}`;
1875
+ /**
1876
+ * Load the objective from ThreadState (called on thread switch). Falls back to
1877
+ * the legacy thread-metadata goal for threads created before this migration.
1878
+ */
1879
+ async loadFromThread(state) {
1880
+ this.persistGoalOnNextThreadCreate = false;
1881
+ this.activeStartedAt = null;
1882
+ this.activeDurationMs = 0;
1883
+ const threadId = state.harness.getCurrentThreadId();
1884
+ const agent = this.getAgent(state);
1885
+ if (agent && threadId) {
1886
+ try {
1887
+ const record = await agent.getObjective({ threadId });
1888
+ if (record) {
1889
+ this.record = { ...record, id: randomUUID() };
1890
+ return;
1891
+ }
1892
+ } catch {
1893
+ }
1894
+ }
1895
+ this.record = null;
2379
1896
  }
2380
- };
2381
- function truncateForJudge(value) {
2382
- return value.length > 4e3 ? value.slice(0, 4e3) + "\n...[truncated]" : value;
2383
- }
2384
- function getToolName(chunk) {
2385
- const toolName = chunk.payload?.toolName ?? chunk.toolName;
2386
- return typeof toolName === "string" ? toolName : null;
2387
- }
2388
- function parseToolInput(chunk) {
2389
- const input = chunk.payload?.args ?? chunk.input ?? chunk.args ?? chunk.toolInput;
2390
- if (!input) return {};
2391
- if (typeof input === "string") {
1897
+ /**
1898
+ * Legacy entry point retained for thread-switch call sites that only have the
1899
+ * thread metadata available. Hydrates from a previously-persisted GoalState.
1900
+ */
1901
+ loadFromThreadMetadata(metadata) {
1902
+ const saved = metadata?.[THREAD_GOAL_KEY];
1903
+ this.persistGoalOnNextThreadCreate = false;
1904
+ this.activeStartedAt = null;
1905
+ this.activeDurationMs = 0;
1906
+ if (saved && saved.objective && saved.status) {
1907
+ this.record = {
1908
+ objective: saved.objective,
1909
+ status: saved.status,
1910
+ runsUsed: saved.turnsUsed ?? 0,
1911
+ maxRuns: saved.maxTurns ?? DEFAULT_MAX_TURNS,
1912
+ judgeModelId: saved.judgeModelId ?? "",
1913
+ startedAt: saved.startedAt ? Date.parse(saved.startedAt) || Date.now() : Date.now(),
1914
+ updatedAt: Date.now(),
1915
+ id: saved.id ?? randomUUID()
1916
+ };
1917
+ this.activeDurationMs = saved.activeDurationMs ?? 0;
1918
+ } else {
1919
+ this.record = null;
1920
+ }
1921
+ }
1922
+ // ---------------------------------------------------------------------------
1923
+ // Private
1924
+ // ---------------------------------------------------------------------------
1925
+ getAgent(state) {
2392
1926
  try {
2393
- return JSON.parse(input);
1927
+ return state.harness.getCurrentAgent();
2394
1928
  } catch {
2395
- return { input };
1929
+ return void 0;
2396
1930
  }
2397
1931
  }
2398
- return input;
2399
- }
2400
- function formatJudgeActivity(toolName, input) {
2401
- if (toolName === MC_TOOLS.VIEW) return `read ${formatActivityValue(input.path)}`;
2402
- if (toolName === MC_TOOLS.SEARCH_CONTENT) return `search ${formatQuotedActivityValue(input.pattern)}`;
2403
- if (toolName === MC_TOOLS.FIND_FILES) return `find files ${formatActivityValue(input.pattern ?? input.path)}`;
2404
- if (toolName === MC_TOOLS.FILE_STAT) return `stat ${formatActivityValue(input.path)}`;
2405
- if (toolName === MC_TOOLS.LSP_INSPECT) return `inspect ${formatActivityValue(input.path)}`;
2406
- return null;
2407
- }
2408
- function formatActivityValue(value) {
2409
- if (typeof value === "string" && value.length > 0) {
2410
- return value.length > 80 ? value.slice(0, 77) + "..." : value;
1932
+ /** Resolve effective judge model + max runs (record value → settings default). */
1933
+ effectiveSettings(record) {
1934
+ const settings = loadSettings();
1935
+ return {
1936
+ judgeModelId: record.judgeModelId ?? settings.models.goalJudgeModel ?? "",
1937
+ maxTurns: record.maxRuns ?? settings.models.goalMaxTurns ?? DEFAULT_MAX_TURNS
1938
+ };
2411
1939
  }
2412
- return "workspace";
2413
- }
2414
- function formatQuotedActivityValue(value) {
2415
- const formatted = formatActivityValue(value);
2416
- return formatted === "workspace" ? formatted : JSON.stringify(formatted);
2417
- }
2418
- function formatError(error) {
2419
- return error instanceof Error ? error.message : String(error);
2420
- }
2421
- var JUDGE_FAILURE_PATTERNS = [
2422
- "no structured decision",
2423
- "could not be initialized",
2424
- "could not evaluate",
2425
- "was interrupted"
2426
- ];
2427
- function isJudgeFailureReason(reason) {
2428
- const lower = reason.toLowerCase();
2429
- return JUDGE_FAILURE_PATTERNS.some((p) => lower.includes(p));
2430
- }
1940
+ localRecord(objective, judgeModelId, maxTurns, now, id) {
1941
+ return {
1942
+ objective,
1943
+ status: "active",
1944
+ runsUsed: 0,
1945
+ maxRuns: maxTurns,
1946
+ ...judgeModelId ? { judgeModelId } : {},
1947
+ startedAt: now,
1948
+ updatedAt: now,
1949
+ id
1950
+ };
1951
+ }
1952
+ };
2431
1953
  function parseSizeValue(value, total) {
2432
1954
  if (typeof value === "number") return value;
2433
1955
  const match = value?.match(/^(\d+(?:\.\d+)?)%$/);
@@ -2647,14 +2169,8 @@ async function handleGoalCommand(ctx, args) {
2647
2169
  ctx.showInfo("Goal is already done. Use /goal <text> to set a new goal.");
2648
2170
  return;
2649
2171
  }
2650
- const wasJudgeFailure = goal.lastPauseWasJudgeFailure;
2651
2172
  goalManager.resume();
2652
2173
  await goalManager.saveToThread(state);
2653
- if (wasJudgeFailure) {
2654
- ctx.showInfo(`Goal resumed: "${goal.objective}" \u2014 retriggering judge evaluation...`);
2655
- triggerGoalJudge(ctx, { requireAssistantMessage: true });
2656
- return;
2657
- }
2658
2174
  ctx.showInfo(
2659
2175
  `Goal resumed: "${goal.objective}" \u2014 ${goal.turnsUsed}/${goal.maxTurns} turns used. Sending continuation...`
2660
2176
  );
@@ -2676,6 +2192,10 @@ async function handleGoalCommand(ctx, args) {
2676
2192
  ctx.showInfo("Goal cleared.");
2677
2193
  return;
2678
2194
  }
2195
+ if (subCommand === "judge") {
2196
+ await handleJudgeCommand(ctx);
2197
+ return;
2198
+ }
2679
2199
  const objective = args.join(" ");
2680
2200
  await startGoalWithDefaults(ctx, objective);
2681
2201
  }
@@ -2746,9 +2266,12 @@ async function showGoalActionModal(ctx) {
2746
2266
  async function handleJudgeCommand(ctx) {
2747
2267
  const defaults = await promptForJudgeDefaults(ctx, "Judge settings unchanged.");
2748
2268
  if (!defaults) return;
2749
- const activeGoal = ctx.state.goalManager.updateJudgeDefaults(defaults.judgeModelId, defaults.maxTurns);
2269
+ const activeGoal = await ctx.state.goalManager.updateJudgeDefaults(
2270
+ ctx.state,
2271
+ defaults.judgeModelId,
2272
+ defaults.maxTurns
2273
+ );
2750
2274
  if (activeGoal) {
2751
- await ctx.state.goalManager.saveToThread(ctx.state);
2752
2275
  ctx.showInfo(
2753
2276
  `Judge defaults set: ${defaults.judgeModelId}, ${defaults.maxTurns} max attempts. Current goal updated.`
2754
2277
  );
@@ -2825,105 +2348,6 @@ async function promptForJudgeDefaults(ctx, cancelMessage) {
2825
2348
  selector.focused = true;
2826
2349
  });
2827
2350
  }
2828
- function triggerGoalJudge(ctx, options = {}) {
2829
- const { state } = ctx;
2830
- const goal = state.goalManager.getGoal();
2831
- if (!goal) return;
2832
- const evaluatedGoalId = goal.id;
2833
- if (!state.gradientAnimator) {
2834
- state.gradientAnimator = new GradientAnimator(() => {
2835
- ctx.updateStatusLine();
2836
- });
2837
- }
2838
- const abortController = new AbortController();
2839
- const judgeComponent = new JudgeDisplayComponent(null, goal.turnsUsed, goal.maxTurns);
2840
- const activeGoalJudge = { modelId: goal.judgeModelId, abortController, component: judgeComponent };
2841
- state.activeGoalJudge = activeGoalJudge;
2842
- state.chatContainer.addChild(judgeComponent);
2843
- state.gradientAnimator.start();
2844
- ctx.updateStatusLine();
2845
- state.ui.requestRender();
2846
- state.goalManager.evaluateAfterTurn(state, {
2847
- abortSignal: abortController.signal,
2848
- requireAssistantMessage: options.requireAssistantMessage,
2849
- onActivity: (line) => {
2850
- if (state.activeGoalJudge === activeGoalJudge) {
2851
- judgeComponent.addActivity(line);
2852
- state.ui.requestRender();
2853
- }
2854
- }
2855
- }).then(async ({ continuation, judgeResult }) => {
2856
- if (state.activeGoalJudge !== activeGoalJudge) return;
2857
- const currentGoal = state.goalManager.getGoal();
2858
- if (!currentGoal || currentGoal.id !== evaluatedGoalId) return;
2859
- if (judgeResult) {
2860
- judgeComponent.setResult(judgeResult, currentGoal.turnsUsed, currentGoal.maxTurns);
2861
- state.ui.requestRender();
2862
- }
2863
- if (abortController.signal.aborted) {
2864
- state.userInitiatedAbort = false;
2865
- return;
2866
- }
2867
- if (continuation) {
2868
- if (currentGoal.status !== "active") return;
2869
- try {
2870
- await state.harness.sendSignal({
2871
- type: "system-reminder",
2872
- contents: continuation,
2873
- attributes: { type: "goal-judge" },
2874
- metadata: {
2875
- goalId: currentGoal.id,
2876
- turnsUsed: currentGoal.turnsUsed,
2877
- maxTurns: currentGoal.maxTurns,
2878
- judgeModelId: currentGoal.judgeModelId
2879
- }
2880
- }).accepted;
2881
- } catch (error) {
2882
- state.goalManager.pause();
2883
- await state.goalManager.saveToThread(state);
2884
- ctx.showError(`Failed to send goal continuation: ${error instanceof Error ? error.message : String(error)}`);
2885
- }
2886
- } else {
2887
- if (judgeResult) {
2888
- const harness = state.harness;
2889
- try {
2890
- await harness.saveSystemReminderMessage?.({
2891
- reminderType: "goal-judge",
2892
- message: `${judgeResult.decision} (${currentGoal.turnsUsed}/${currentGoal.maxTurns})
2893
- ${judgeResult.reason}`
2894
- });
2895
- } catch (error) {
2896
- ctx.showError(
2897
- `Failed to persist goal judge result: ${error instanceof Error ? error.message : String(error)}`
2898
- );
2899
- }
2900
- }
2901
- if (currentGoal.status === "paused") {
2902
- ctx.showInfo(
2903
- `Goal paused (attempt ${currentGoal.turnsUsed}/${currentGoal.maxTurns}). Use /goal resume to continue.`
2904
- );
2905
- }
2906
- if (judgeResult?.decision === "done" && currentGoal.id === state.planStartedGoalId) {
2907
- const goalId = state.planStartedGoalId;
2908
- state.planStartedGoalId = void 0;
2909
- try {
2910
- await state.harness.switchMode({ modeId: "plan" });
2911
- } catch (error) {
2912
- ctx.showError(`Failed to switch to Plan mode: ${error instanceof Error ? error.message : String(error)}`);
2913
- state.planStartedGoalId = goalId;
2914
- }
2915
- }
2916
- }
2917
- }).catch(() => {
2918
- }).finally(() => {
2919
- if (state.activeGoalJudge === activeGoalJudge) {
2920
- state.activeGoalJudge = void 0;
2921
- }
2922
- state.gradientAnimator?.fadeOut();
2923
- ctx.updateStatusLine();
2924
- state.ui.requestRender();
2925
- });
2926
- }
2927
2351
  async function startGoal(ctx, objective, judgeModelId, maxTurns, options = {}) {
2928
2352
  const { state } = ctx;
2929
2353
  const goalManager = state.goalManager;
@@ -2932,11 +2356,14 @@ async function startGoal(ctx, objective, judgeModelId, maxTurns, options = {}) {
2932
2356
  state.pendingNewThread = false;
2933
2357
  }
2934
2358
  const shouldPersistToCreatedThread = !state.harness.getCurrentThreadId();
2935
- const goal = goalManager.setGoal(objective, judgeModelId, maxTurns);
2359
+ const goal = await goalManager.setGoal(state, objective, judgeModelId, maxTurns);
2360
+ if (!goal) {
2361
+ ctx.showError("Failed to set goal.");
2362
+ return;
2363
+ }
2936
2364
  state.planStartedGoalId = void 0;
2937
2365
  if (options.trigger === "none") {
2938
- goal.activeStartedAt = void 0;
2939
- goal.activeDurationMs = 0;
2366
+ goalManager.resetActiveTimer();
2940
2367
  }
2941
2368
  if (shouldPersistToCreatedThread) {
2942
2369
  goalManager.persistOnNextThreadCreate();
@@ -3000,7 +2427,7 @@ function getCommands(modes) {
3000
2427
  { key: "/observability", description: "Configure cloud observability" },
3001
2428
  { key: "/github", description: "Subscribe/sync GitHub PR signals" },
3002
2429
  { key: "/goal", description: "Set/manage persistent goal (Ralph loop)" },
3003
- { key: "/judge", description: "Set goal judge defaults" }
2430
+ { key: "/goal judge", description: "Set the goal judge model and max attempts" }
3004
2431
  ];
3005
2432
  if (modes > 1) {
3006
2433
  cmds.push({ key: "/mode", description: "Switch or list modes" });
@@ -3563,7 +2990,7 @@ var McpSelectorComponent = class extends Box {
3563
2990
  this.startPollingIfNeeded();
3564
2991
  }
3565
2992
  buildUI() {
3566
- const titleText = chalk14.bgHex("#16c858").white.bold(" Manage MCP servers ");
2993
+ const titleText = chalk12.bgHex("#16c858").white.bold(" Manage MCP servers ");
3567
2994
  this.addChild(new Text(titleText, 0, 0));
3568
2995
  this.addChild(new Spacer(1));
3569
2996
  this.listContainer = new Container();
@@ -4102,20 +3529,30 @@ function reasonToMessage(reason) {
4102
3529
  }
4103
3530
 
4104
3531
  // src/tui/display.ts
3532
+ var InfoMessageComponent = class extends Container {
3533
+ constructor(lines) {
3534
+ super();
3535
+ for (const line of lines) {
3536
+ this.addChild(line);
3537
+ }
3538
+ }
3539
+ getChatSpacingKind() {
3540
+ return "system";
3541
+ }
3542
+ };
4105
3543
  function showError(state, message) {
4106
- state.chatContainer.addChild(new Spacer(1));
4107
- state.chatContainer.addChild(new Text(theme.fg("error", `Error: ${message}`), 1, 0));
3544
+ const component = new InfoMessageComponent([new Text(theme.fg("error", `Error: ${message}`), 1, 0)]);
3545
+ insertChatComponentWithBoundarySpacing(state.chatContainer, component);
4108
3546
  state.ui.requestRender();
4109
3547
  }
4110
3548
  function showInfo(state, message) {
4111
- state.chatContainer.addChild(new Spacer(1));
4112
- state.chatContainer.addChild(new Text(theme.fg("muted", message), 1, 0));
3549
+ const component = new InfoMessageComponent([new Text(theme.fg("muted", message), 1, 0)]);
3550
+ insertChatComponentWithBoundarySpacing(state.chatContainer, component);
4113
3551
  state.ui.requestRender();
4114
3552
  }
4115
3553
  function showFormattedError(state, event) {
4116
3554
  const error = "error" in event ? event.error : event;
4117
3555
  const parsed = parseError(error);
4118
- state.chatContainer.addChild(new Spacer(1));
4119
3556
  let errorText = `Error: ${parsed.message}`;
4120
3557
  if (parsed.detail && parsed.detail !== parsed.message) {
4121
3558
  errorText += theme.fg("muted", ` (${parsed.detail})`);
@@ -4129,11 +3566,13 @@ function showFormattedError(state, event) {
4129
3566
  const seconds = Math.ceil(retryDelay / 1e3);
4130
3567
  errorText += theme.fg("muted", ` (retry in ${seconds}s)`);
4131
3568
  }
4132
- state.chatContainer.addChild(new Text(theme.fg("error", errorText), 1, 0));
3569
+ const lines = [new Text(theme.fg("error", errorText), 1, 0)];
4133
3570
  const hint = getErrorHint(parsed.type);
4134
3571
  if (hint) {
4135
- state.chatContainer.addChild(new Text(theme.fg("muted", ` Hint: ${hint}`), 1, 0));
3572
+ lines.push(new Text(theme.fg("muted", ` Hint: ${hint}`), 1, 0));
4136
3573
  }
3574
+ const component = new InfoMessageComponent(lines);
3575
+ insertChatComponentWithBoundarySpacing(state.chatContainer, component);
4137
3576
  state.ui.requestRender();
4138
3577
  }
4139
3578
  function getErrorHint(errorType) {
@@ -4294,7 +3733,8 @@ function showTextStatus(ctx) {
4294
3733
 
4295
3734
  // src/tui/commands/mode.ts
4296
3735
  function applyCurrentModeColorToRenderedTools(ctx) {
4297
- const modeColor = ctx.harness.getCurrentMode?.()?.color;
3736
+ const color = ctx.harness.getCurrentMode?.()?.metadata?.color;
3737
+ const modeColor = typeof color === "string" ? color : void 0;
4298
3738
  for (const tool of ctx.state.allToolComponents) {
4299
3739
  tool.setCompactToolModeColor?.(modeColor);
4300
3740
  }
@@ -4315,7 +3755,7 @@ async function handleModeCommand(ctx, args) {
4315
3755
  }
4316
3756
  } else {
4317
3757
  const currentMode = ctx.harness.getCurrentMode();
4318
- const modeList = modes.map((m) => ` ${m.id === currentMode?.id ? "* " : " "}${m.id}${m.name ? ` - ${m.name}` : ""}`).join("\n");
3758
+ const modeList = modes.map((m) => ` ${m.id === currentMode?.id ? "* " : " "}${m.name}${m.description ? ` - ${m.description}` : ""}`).join("\n");
4319
3759
  ctx.showInfo(`Modes:
4320
3760
  ${modeList}`);
4321
3761
  }
@@ -4342,10 +3782,10 @@ var SlashCommandComponent = class extends Container {
4342
3782
  }
4343
3783
  rebuild() {
4344
3784
  this.clear();
4345
- const border = (char) => chalk14.bold.hex(getBorderColor())(char);
3785
+ const border = (char) => chalk12.bold.hex(getBorderColor())(char);
4346
3786
  const termWidth = getTermWidth();
4347
3787
  const maxLineWidth = termWidth - 6 - BOX_INDENT * 2;
4348
- const heading = chalk14.hex(mastra.specialGray)(`/${this.commandName}`);
3788
+ const heading = chalk12.hex(mastra.specialGray)(`/${this.commandName}`);
4349
3789
  if (this.contentLines.length === 0) {
4350
3790
  this.addChild(new Text(`${border("\u2570\u2500\u2500")} ${heading}`, BOX_INDENT, 0));
4351
3791
  return;
@@ -4369,17 +3809,19 @@ var SlashCommandComponent = class extends Container {
4369
3809
  const truncated = !this.expanded && wrappedLines.length > MAX_COLLAPSED_LINES + 1;
4370
3810
  const displayLines = truncated ? wrappedLines.slice(0, MAX_COLLAPSED_LINES) : wrappedLines;
4371
3811
  const contentText = displayLines.map(
4372
- (line) => `${border("\u2502")} ${chalk14.hex(mastra.mainGray)(line.length > maxLineWidth ? line.slice(0, maxLineWidth - 1) + "\u2026" : line)}`
3812
+ (line) => `${border("\u2502")} ${chalk12.hex(mastra.mainGray)(line.length > maxLineWidth ? line.slice(0, maxLineWidth - 1) + "\u2026" : line)}`
4373
3813
  ).join("\n");
4374
3814
  this.addChild(new Text(contentText, BOX_INDENT, 0));
4375
3815
  if (truncated) {
4376
- const moreText = chalk14.hex(mastra.darkGray)(
3816
+ const moreText = chalk12.hex(mastra.darkGray)(
4377
3817
  `... ${wrappedLines.length - MAX_COLLAPSED_LINES} more lines (ctrl+e to expand)`
4378
3818
  );
4379
3819
  this.addChild(new Text(`${border("\u2502")} ${moreText}`, BOX_INDENT, 0));
4380
3820
  }
4381
3821
  this.addChild(new Text(`${border("\u2570\u2500\u2500")} ${heading}`, BOX_INDENT, 0));
4382
- this.addChild(new Spacer(1));
3822
+ }
3823
+ getChatSpacingKind() {
3824
+ return "other";
4383
3825
  }
4384
3826
  };
4385
3827
  var _compId = 0;
@@ -4472,7 +3914,7 @@ var AssistantMessageComponent = class extends Container {
4472
3914
  var NotificationSummaryComponent = class extends Container {
4473
3915
  constructor(options) {
4474
3916
  super();
4475
- const title = chalk14.hex(mastra.orange).bold(`Notification summary: ${options.pending} pending`);
3917
+ const title = chalk12.hex(mastra.orange).bold(`Notification summary: ${options.pending} pending`);
4476
3918
  this.addChild(new Text(title, BOX_INDENT, 0));
4477
3919
  const sourceSummary = Object.entries(options.bySource).sort(([a], [b]) => a.localeCompare(b)).map(([source, count]) => `${source}: ${count}`).join(", ");
4478
3920
  const message = sourceSummary || options.message.trim();
@@ -4482,7 +3924,6 @@ var NotificationSummaryComponent = class extends Container {
4482
3924
  this.addChild(
4483
3925
  new Text(theme.fg("dim", "Use notification_inbox to inspect pending notifications."), BOX_INDENT + 2, 0)
4484
3926
  );
4485
- this.addChild(new Spacer(1));
4486
3927
  }
4487
3928
  getChatSpacingKind() {
4488
3929
  return "system";
@@ -4552,14 +3993,14 @@ var NotificationComponent = class extends Container {
4552
3993
  const messageLines = message ? wrapText(message, maxContentWidth) : [];
4553
3994
  const allLines = [...titleLines, ...detailLines, ...messageLines];
4554
3995
  const contentWidth = Math.max(...allLines.map((line) => visibleWidth(line)), 1);
4555
- const borderColor = chalk14.hex(mastra.blue);
3996
+ const borderColor = chalk12.hex(mastra.blue);
4556
3997
  const top = `\u256D${"\u2500".repeat(contentWidth + 2)}\u256E`;
4557
3998
  const bottom = `\u2570${"\u2500".repeat(contentWidth + 2)}\u256F`;
4558
3999
  this.addChild(new Text(borderColor(top), BOX_INDENT, 0));
4559
4000
  for (const line of titleLines) {
4560
4001
  this.addChild(
4561
4002
  new Text(
4562
- `${borderColor("\u2502")} ${chalk14.hex(priorityColor(options.priority)).bold(padLine(line, contentWidth))} ${borderColor("\u2502")}`,
4003
+ `${borderColor("\u2502")} ${chalk12.hex(priorityColor(options.priority)).bold(padLine(line, contentWidth))} ${borderColor("\u2502")}`,
4563
4004
  BOX_INDENT,
4564
4005
  0
4565
4006
  )
@@ -4578,7 +4019,6 @@ var NotificationComponent = class extends Container {
4578
4019
  this.addChild(new Text(`${borderColor("\u2502")} ${padLine(line, contentWidth)} ${borderColor("\u2502")}`, BOX_INDENT, 0));
4579
4020
  }
4580
4021
  this.addChild(new Text(borderColor(bottom), BOX_INDENT, 0));
4581
- this.addChild(new Spacer(1));
4582
4022
  }
4583
4023
  getChatSpacingKind() {
4584
4024
  return "system";
@@ -4606,7 +4046,6 @@ var OMMarkerComponent = class extends Container {
4606
4046
  super();
4607
4047
  this.textChild = new Text(formatMarker(data), BOX_INDENT, 0);
4608
4048
  this.addChild(this.textChild);
4609
- this.addChild(new Spacer(1));
4610
4049
  }
4611
4050
  /**
4612
4051
  * Update the marker in-place (e.g., from start → end).
@@ -4614,6 +4053,9 @@ var OMMarkerComponent = class extends Container {
4614
4053
  update(data) {
4615
4054
  this.textChild.setText(formatMarker(data));
4616
4055
  }
4056
+ getChatSpacingKind() {
4057
+ return "other";
4058
+ }
4617
4059
  };
4618
4060
  function formatMarker(data) {
4619
4061
  const isReflection = "operationType" in data && data.operationType === "reflection";
@@ -4758,7 +4200,7 @@ var OMOutputComponent = class extends Container {
4758
4200
  this.clear();
4759
4201
  const isReflection = this.data.type === "reflection";
4760
4202
  const color = isReflection ? getReflectorColor() : getObserverColor();
4761
- const border = (char) => chalk14.bold.hex(color)(char);
4203
+ const border = (char) => chalk12.bold.hex(color)(char);
4762
4204
  const termWidth = getTermWidth();
4763
4205
  const maxLineWidth = termWidth - 6 - BOX_INDENT * 2;
4764
4206
  const originalLines = this.data.observations.split("\n");
@@ -4790,22 +4232,22 @@ var OMOutputComponent = class extends Container {
4790
4232
  truncated = hiddenGroups > 0;
4791
4233
  if (truncated) {
4792
4234
  for (const line of headLines) {
4793
- borderedLines.push(border("\u2502") + " " + chalk14.hex(mastra.specialGray)(line));
4235
+ borderedLines.push(border("\u2502") + " " + chalk12.hex(mastra.specialGray)(line));
4794
4236
  }
4795
4237
  borderedLines.push(
4796
- border("\u2502") + " " + chalk14.hex(mastra.mainGray)(`... ${originalLineCount} lines total (ctrl+e to expand)`)
4238
+ border("\u2502") + " " + chalk12.hex(mastra.mainGray)(`... ${originalLineCount} lines total (ctrl+e to expand)`)
4797
4239
  );
4798
4240
  for (const line of tailLines) {
4799
- borderedLines.push(border("\u2502") + " " + chalk14.hex(mastra.specialGray)(line));
4241
+ borderedLines.push(border("\u2502") + " " + chalk12.hex(mastra.specialGray)(line));
4800
4242
  }
4801
4243
  } else {
4802
4244
  for (const line of wrappedLines) {
4803
- borderedLines.push(border("\u2502") + " " + chalk14.hex(mastra.specialGray)(line));
4245
+ borderedLines.push(border("\u2502") + " " + chalk12.hex(mastra.specialGray)(line));
4804
4246
  }
4805
4247
  }
4806
4248
  } else {
4807
4249
  for (const line of wrappedLines) {
4808
- borderedLines.push(border("\u2502") + " " + chalk14.hex(mastra.specialGray)(line));
4250
+ borderedLines.push(border("\u2502") + " " + chalk12.hex(mastra.specialGray)(line));
4809
4251
  }
4810
4252
  }
4811
4253
  const displayOutput = borderedLines.join("\n");
@@ -4813,15 +4255,14 @@ var OMOutputComponent = class extends Container {
4813
4255
  this.addChild(new Text(displayOutput, BOX_INDENT, 0));
4814
4256
  }
4815
4257
  if (this.data.currentTask && (this.expanded || !truncated)) {
4816
- const taskLine = border("\u2502") + " " + chalk14.hex(color).bold("Current task: ") + chalk14.hex(mastra.specialGray)(this.data.currentTask);
4258
+ const taskLine = border("\u2502") + " " + chalk12.hex(color).bold("Current task: ") + chalk12.hex(mastra.specialGray)(this.data.currentTask);
4817
4259
  this.addChild(new Text(truncateAnsi(taskLine, termWidth - 2 - BOX_INDENT * 2), BOX_INDENT, 0));
4818
4260
  }
4819
4261
  if (this.data.suggestedResponse && (this.expanded || !truncated)) {
4820
- const sugLine = border("\u2502") + " " + chalk14.hex(color).bold("Suggested response: ") + chalk14.hex(mastra.specialGray)(this.data.suggestedResponse);
4262
+ const sugLine = border("\u2502") + " " + chalk12.hex(color).bold("Suggested response: ") + chalk12.hex(mastra.specialGray)(this.data.suggestedResponse);
4821
4263
  this.addChild(new Text(truncateAnsi(sugLine, termWidth - 2 - BOX_INDENT * 2), BOX_INDENT, 0));
4822
4264
  }
4823
4265
  this.addChild(new Text(`${border("\u2570\u2500\u2500")} ${footerText}`, BOX_INDENT, 0));
4824
- this.addChild(new Spacer(1));
4825
4266
  }
4826
4267
  buildFooterText(color) {
4827
4268
  const isReflection = this.data.type === "reflection";
@@ -4832,16 +4273,19 @@ var OMOutputComponent = class extends Container {
4832
4273
  const ratio = (this.data.tokensObserved ?? 0) > 0 && (this.data.compressedTokens ?? this.data.observationTokens ?? 0) > 0 ? `${Math.round((this.data.tokensObserved ?? 0) / (this.data.compressedTokens ?? this.data.observationTokens ?? 1))}x` : "";
4833
4274
  const durationStr = this.data.durationMs ? ` in ${(this.data.durationMs / 1e3).toFixed(1)}s` : "";
4834
4275
  const ratioStr = ratio ? ` (${ratio} compression)` : "";
4835
- return `${emoji} ${chalk14.hex(color)(`Reflected: ${observed} \u2192 ${compressed} tokens${ratioStr}${durationStr}`)} ${chalk14.hex(mastra.green)("\u2713")}`;
4276
+ return `${emoji} ${chalk12.hex(color)(`Reflected: ${observed} \u2192 ${compressed} tokens${ratioStr}${durationStr}`)} ${chalk12.hex(mastra.green)("\u2713")}`;
4836
4277
  } else {
4837
4278
  const observed = formatTokens2(this.data.tokensObserved ?? 0);
4838
4279
  const compressed = formatTokens2(this.data.observationTokens ?? 0);
4839
4280
  const ratio = (this.data.tokensObserved ?? 0) > 0 && (this.data.observationTokens ?? 0) > 0 ? `${Math.round((this.data.tokensObserved ?? 0) / (this.data.observationTokens ?? 1))}x` : "";
4840
4281
  const durationStr = this.data.durationMs ? ` in ${(this.data.durationMs / 1e3).toFixed(1)}s` : "";
4841
4282
  const ratioStr = ratio ? ` (${ratio} compression)` : "";
4842
- return `${emoji} ${chalk14.hex(color)(`Observed: ${observed} \u2192 ${compressed} tokens${ratioStr}${durationStr}`)} ${chalk14.hex(mastra.green)("\u2713")}`;
4283
+ return `${emoji} ${chalk12.hex(color)(`Observed: ${observed} \u2192 ${compressed} tokens${ratioStr}${durationStr}`)} ${chalk12.hex(mastra.green)("\u2713")}`;
4843
4284
  }
4844
4285
  }
4286
+ getChatSpacingKind() {
4287
+ return "other";
4288
+ }
4845
4289
  };
4846
4290
  var PlanContentBox = class {
4847
4291
  constructor(plan) {
@@ -4857,7 +4301,7 @@ var PlanContentBox = class {
4857
4301
  color: (text) => theme.fg("text", text)
4858
4302
  });
4859
4303
  const rendered = markdown.render(innerWidth).flatMap((line) => line.length > 0 ? [line] : [""]);
4860
- const border = (text) => chalk14.hex(mastra.purple)(text);
4304
+ const border = (text) => chalk12.hex(mastra.purple)(text);
4861
4305
  const top = `${border("\u256D")}${border("\u2500".repeat(innerWidth + 2))}${border("\u256E")}`;
4862
4306
  const bottom = `${border("\u2570")}${border("\u2500".repeat(innerWidth + 2))}${border("\u256F")}`;
4863
4307
  const body = rendered.map((line) => {
@@ -5113,11 +4557,10 @@ var PlanResultComponent = class extends Container {
5113
4557
  var ReactiveSignalComponent = class extends Container {
5114
4558
  constructor(options) {
5115
4559
  super();
5116
- this.addChild(new Text(chalk14.hex(mastra.orange).bold(`Signal: ${options.tagName}`), BOX_INDENT, 0));
4560
+ this.addChild(new Text(chalk12.hex(mastra.orange).bold(`Signal: ${options.tagName}`), BOX_INDENT, 0));
5117
4561
  if (options.message?.trim()) {
5118
4562
  this.addChild(new Text(theme.fg("dim", options.message.trim()), BOX_INDENT + 2, 0));
5119
4563
  }
5120
- this.addChild(new Spacer(1));
5121
4564
  }
5122
4565
  getChatSpacingKind() {
5123
4566
  return "system";
@@ -5126,14 +4569,13 @@ var ReactiveSignalComponent = class extends Container {
5126
4569
  var StateSignalComponent = class extends Container {
5127
4570
  constructor(options) {
5128
4571
  super();
5129
- const title = chalk14.hex(mastra.blue).bold(`State ${options.mode}: ${options.stateId}`);
4572
+ const title = chalk12.hex(mastra.blue).bold(`State ${options.mode}: ${options.stateId}`);
5130
4573
  this.addChild(new Text(title, BOX_INDENT, 0));
5131
4574
  const message = options.message?.trim();
5132
4575
  if (message) {
5133
4576
  const preview = message.length > 180 ? `${message.slice(0, 177)}...` : message;
5134
4577
  this.addChild(new Text(theme.fg("dim", preview), BOX_INDENT + 2, 0));
5135
4578
  }
5136
- this.addChild(new Spacer(1));
5137
4579
  }
5138
4580
  getChatSpacingKind() {
5139
4581
  return "system";
@@ -5295,7 +4737,6 @@ var SubagentExecutionComponent = class extends Container {
5295
4737
  }
5296
4738
  }
5297
4739
  this.addChild(new Text(`${border("\u2570\u2500\u2500")} ${footerText}`, BOX_INDENT, 0));
5298
- this.addChild(new Spacer(1));
5299
4740
  this.invalidate();
5300
4741
  this.ui.requestRender();
5301
4742
  }
@@ -5384,12 +4825,12 @@ var SystemReminderComponent = class extends Container {
5384
4825
  return;
5385
4826
  }
5386
4827
  const accent = getReminderAccent(this.reminderType);
5387
- const border = (char) => accent ? chalk14.hex(accent).bold(char) : theme.bold(theme.fg("toolTitle", char));
4828
+ const border = (char) => accent ? chalk12.hex(accent).bold(char) : theme.bold(theme.fg("toolTitle", char));
5388
4829
  const titleText = getReminderTitle(this.reminderType, this.path, {
5389
4830
  goalMaxTurns: this.goalMaxTurns,
5390
4831
  judgeModelId: this.judgeModelId
5391
4832
  });
5392
- const title = accent ? chalk14.hex(accent).bold(titleText) : theme.bold(theme.fg("toolTitle", titleText));
4833
+ const title = accent ? chalk12.hex(accent).bold(titleText) : theme.bold(theme.fg("toolTitle", titleText));
5393
4834
  const metadataColor = (text) => theme.fg("dim", text);
5394
4835
  const bodyColor = (text) => theme.fg("text", text);
5395
4836
  const hintColor = (text) => theme.fg("dim", text);
@@ -5419,12 +4860,11 @@ var SystemReminderComponent = class extends Container {
5419
4860
  this.addChild(new Text(renderRow(hint, innerWidth, border), BOX_INDENT, 0));
5420
4861
  }
5421
4862
  this.addChild(new Text(`${border("\u2570")}${border(horizontal)}${border("\u256F")}`, BOX_INDENT, 0));
5422
- this.addChild(new Spacer(1));
5423
4863
  }
5424
4864
  };
5425
4865
  function renderRow(text, width, border) {
5426
4866
  const content = padLine2(text, width);
5427
- const rightPadding = hasWideGlyph(stripAnsi2(text)) ? " " : "";
4867
+ const rightPadding = hasWideGlyph(stripAnsi(text)) ? " " : "";
5428
4868
  return `${border("\u2502")} ${content}${rightPadding}${border("\u2502")}`;
5429
4869
  }
5430
4870
  function splitMessageLines(message) {
@@ -5493,7 +4933,7 @@ function wrapLines(lines, maxLineWidth) {
5493
4933
  return wrappedLines;
5494
4934
  }
5495
4935
  function padLine2(text, width) {
5496
- const visibleLength = stripAnsi2(text).length;
4936
+ const visibleLength = stripAnsi(text).length;
5497
4937
  if (visibleLength === width) {
5498
4938
  return text;
5499
4939
  }
@@ -5503,17 +4943,19 @@ function padLine2(text, width) {
5503
4943
  return text + " ".repeat(width - visibleLength);
5504
4944
  }
5505
4945
  function truncateLine(text, width) {
5506
- const plain = stripAnsi2(text);
4946
+ const plain = stripAnsi(text);
5507
4947
  return plain.length <= width ? text : plain.slice(0, Math.max(0, width - 1)) + "\u2026";
5508
4948
  }
5509
4949
  var TemporalGapComponent = class extends Container {
5510
4950
  constructor(options) {
5511
4951
  super();
5512
4952
  this.addChild(new Text(theme.fg("dim", ` \u23F3 ${resolveGapText(options)}`), BOX_INDENT, 0));
5513
- this.addChild(new Spacer(1));
5514
4953
  }
5515
4954
  setExpanded(_expanded) {
5516
4955
  }
4956
+ getChatSpacingKind() {
4957
+ return "other";
4958
+ }
5517
4959
  };
5518
4960
  function resolveGapText(options) {
5519
4961
  const gapText = options.gapText?.trim();
@@ -5766,7 +5208,9 @@ var ErrorDisplayComponent = class extends Container {
5766
5208
  }
5767
5209
  const borderBottom = new Text(theme.fg("error", "\u2570" + "\u2500".repeat(59) + "\u256F"), 0, 0);
5768
5210
  box.addChild(borderBottom);
5769
- this.addChild(new Spacer(1));
5211
+ }
5212
+ getChatSpacingKind() {
5213
+ return "other";
5770
5214
  }
5771
5215
  createCodeContext(context, errorLine) {
5772
5216
  const container = new Container();
@@ -5940,22 +5384,22 @@ var ToolValidationErrorComponent = class extends Container {
5940
5384
  // src/tui/components/tool-execution-enhanced.ts
5941
5385
  var CODE_HIGHLIGHT_THEME = {
5942
5386
  default: (text) => theme.fg("toolArgs", text),
5943
- keyword: chalk14.hex("#c084fc"),
5944
- built_in: chalk14.hex("#93c5fd"),
5945
- type: chalk14.hex("#93c5fd"),
5946
- literal: chalk14.hex("#fca5a5"),
5947
- number: chalk14.hex("#fbbf24"),
5948
- string: chalk14.hex("#86efac"),
5949
- regexp: chalk14.hex("#fca5a5"),
5950
- title: chalk14.hex("#93c5fd"),
5951
- function: chalk14.hex("#93c5fd"),
5952
- params: chalk14.hex("#d4d4d8"),
5953
- comment: chalk14.hex("#71717a"),
5954
- meta: chalk14.hex("#a1a1aa"),
5955
- attr: chalk14.hex("#fbbf24"),
5956
- variable: chalk14.hex("#d4d4d8"),
5957
- tag: chalk14.hex("#c084fc"),
5958
- name: chalk14.hex("#c084fc")
5387
+ keyword: chalk12.hex("#c084fc"),
5388
+ built_in: chalk12.hex("#93c5fd"),
5389
+ type: chalk12.hex("#93c5fd"),
5390
+ literal: chalk12.hex("#fca5a5"),
5391
+ number: chalk12.hex("#fbbf24"),
5392
+ string: chalk12.hex("#86efac"),
5393
+ regexp: chalk12.hex("#fca5a5"),
5394
+ title: chalk12.hex("#93c5fd"),
5395
+ function: chalk12.hex("#93c5fd"),
5396
+ params: chalk12.hex("#d4d4d8"),
5397
+ comment: chalk12.hex("#71717a"),
5398
+ meta: chalk12.hex("#a1a1aa"),
5399
+ attr: chalk12.hex("#fbbf24"),
5400
+ variable: chalk12.hex("#d4d4d8"),
5401
+ tag: chalk12.hex("#c084fc"),
5402
+ name: chalk12.hex("#c084fc")
5959
5403
  };
5960
5404
  var COMPACT_TOOL_COLOR = mastra.orange;
5961
5405
  var COMPACT_TOOL_ARGS_BG = "#141414";
@@ -5965,23 +5409,23 @@ function normalizeHexColor(color) {
5965
5409
  return color;
5966
5410
  }
5967
5411
  var QUIET_CODE_HIGHLIGHT_THEME = {
5968
- default: chalk14.hex("#b4b4bd"),
5969
- keyword: chalk14.hex("#c4b5fd"),
5970
- built_in: chalk14.hex("#93c5fd"),
5971
- type: chalk14.hex("#93c5fd"),
5972
- literal: chalk14.hex("#fca5a5"),
5973
- number: chalk14.hex("#fbbf24"),
5974
- string: chalk14.hex("#9ecfa9"),
5975
- regexp: chalk14.hex("#fca5a5"),
5976
- title: chalk14.hex("#93c5fd"),
5977
- function: chalk14.hex("#7dd3fc"),
5978
- params: chalk14.hex("#b4b4bd"),
5979
- comment: chalk14.hex("#71717a"),
5980
- meta: chalk14.hex("#71717a"),
5981
- attr: chalk14.hex("#fbbf24"),
5982
- variable: chalk14.hex("#d4d4d8"),
5983
- tag: chalk14.hex("#c4b5fd"),
5984
- name: chalk14.hex("#c4b5fd")
5412
+ default: chalk12.hex("#b4b4bd"),
5413
+ keyword: chalk12.hex("#c4b5fd"),
5414
+ built_in: chalk12.hex("#93c5fd"),
5415
+ type: chalk12.hex("#93c5fd"),
5416
+ literal: chalk12.hex("#fca5a5"),
5417
+ number: chalk12.hex("#fbbf24"),
5418
+ string: chalk12.hex("#9ecfa9"),
5419
+ regexp: chalk12.hex("#fca5a5"),
5420
+ title: chalk12.hex("#93c5fd"),
5421
+ function: chalk12.hex("#7dd3fc"),
5422
+ params: chalk12.hex("#b4b4bd"),
5423
+ comment: chalk12.hex("#71717a"),
5424
+ meta: chalk12.hex("#71717a"),
5425
+ attr: chalk12.hex("#fbbf24"),
5426
+ variable: chalk12.hex("#d4d4d8"),
5427
+ tag: chalk12.hex("#c4b5fd"),
5428
+ name: chalk12.hex("#c4b5fd")
5985
5429
  };
5986
5430
  var SHELL_CONTROL_WORDS = /* @__PURE__ */ new Set([
5987
5431
  "if",
@@ -6273,22 +5717,22 @@ var ToolExecutionComponentEnhanced = class extends Container {
6273
5717
  -this.quietPreviewLineLimit
6274
5718
  );
6275
5719
  return wrapped.map((line) => {
6276
- const linePrefix = ` ${chalk14.hex(this.getQuietToolRailColor())("\u2502")} `;
5720
+ const linePrefix = ` ${chalk12.hex(this.getQuietToolRailColor())("\u2502")} `;
6277
5721
  return truncateAnsi2(`${linePrefix}${this.formatQuietActivePreview(line)}`, maxLineWidth);
6278
5722
  });
6279
5723
  }
6280
5724
  getQuietCodePreviewLines(preview, maxLineWidth) {
6281
- const linePrefix = ` ${chalk14.hex(this.getQuietToolRailColor())("\u2502")} `;
5725
+ const linePrefix = ` ${chalk12.hex(this.getQuietToolRailColor())("\u2502")} `;
6282
5726
  return this.highlightQuietCodePreview(preview).split("\n").slice(-this.quietPreviewLineLimit).map((line) => truncateAnsi2(`${linePrefix}${line}`, maxLineWidth));
6283
5727
  }
6284
5728
  isQuietCodePreviewTool() {
6285
5729
  return this.toolName === MC_TOOLS.VIEW || this.toolName === MC_TOOLS.WRITE_FILE || this.toolName === MC_TOOLS.STRING_REPLACE_LSP;
6286
5730
  }
6287
5731
  getQuietPreviewCapLine() {
6288
- return ` ${chalk14.hex(this.getQuietToolRailColor())("\u2570\u2500\u2500")}`;
5732
+ return ` ${chalk12.hex(this.getQuietToolRailColor())("\u2570\u2500\u2500")}`;
6289
5733
  }
6290
5734
  getQuietPreviewSpacerLine() {
6291
- return ` ${chalk14.hex(this.getQuietToolRailColor())("\u2502")}`;
5735
+ return ` ${chalk12.hex(this.getQuietToolRailColor())("\u2502")}`;
6292
5736
  }
6293
5737
  shouldCloseQuietPreview() {
6294
5738
  return !this.compactToolHasFollowingContinuation;
@@ -6316,7 +5760,7 @@ var ToolExecutionComponentEnhanced = class extends Container {
6316
5760
  return tokens.map((token) => {
6317
5761
  if (/^\s+$/.test(token)) return { text: token, color: (value) => value };
6318
5762
  if (token.startsWith('"') && token.endsWith('"') || token.startsWith("'") && token.endsWith("'")) {
6319
- return { text: token, color: chalk14.white };
5763
+ return { text: token, color: chalk12.white };
6320
5764
  }
6321
5765
  if (token === "&&" || token === "||" || token === "|" || token === ";" || token === "&") {
6322
5766
  return { text: token, color: (value) => theme.fg("muted", value) };
@@ -6325,7 +5769,7 @@ var ToolExecutionComponentEnhanced = class extends Container {
6325
5769
  return { text: token, color: (value) => theme.fg("muted", value) };
6326
5770
  }
6327
5771
  if (SHELL_CONTROL_WORDS.has(token)) {
6328
- return { text: token, color: chalk14.blue };
5772
+ return { text: token, color: chalk12.blue };
6329
5773
  }
6330
5774
  return { text: token, color: (value) => theme.fg("toolArgs", value) };
6331
5775
  });
@@ -6425,11 +5869,11 @@ var ToolExecutionComponentEnhanced = class extends Container {
6425
5869
  const color = this.getCompactToolAccentColor(toolLabelColor);
6426
5870
  const argsBg = this.getCompactToolArgsBg(toolLabelColor);
6427
5871
  const argsColor = this.getCompactToolArgsColor(toolLabelColor);
6428
- const leftHalf = chalk14.hex(color)("\u2590");
6429
- const rightHalf = summary ? chalk14.hex(color).bgHex(argsBg)("\u258C") : chalk14.hex(color)("\u258C");
6430
- const label = `${leftHalf}${chalk14.bgHex(color).hex("#000000").bold(toolLabel)}${rightHalf}`;
5872
+ const leftHalf = chalk12.hex(color)("\u2590");
5873
+ const rightHalf = summary ? chalk12.hex(color).bgHex(argsBg)("\u258C") : chalk12.hex(color)("\u258C");
5874
+ const label = `${leftHalf}${chalk12.bgHex(color).hex("#000000").bold(toolLabel)}${rightHalf}`;
6431
5875
  const args = summary ? this.formatCompactSummaryBadge(summary, argsBg, argsColor) : "";
6432
- const trail = summary ? chalk14.hex(argsBg)("\u258C") : "";
5876
+ const trail = summary ? chalk12.hex(argsBg)("\u258C") : "";
6433
5877
  return `${label}${args}${trail}`;
6434
5878
  }
6435
5879
  getCompactToolAccentColor(toolLabelColor) {
@@ -6452,7 +5896,7 @@ var ToolExecutionComponentEnhanced = class extends Container {
6452
5896
  return ensureTerminalGlyphContrast(color);
6453
5897
  }
6454
5898
  formatToolBorder(char) {
6455
- return theme.bold(chalk14.hex(ensureTerminalGlyphContrast(theme.getTheme().toolBorderSuccess))(char));
5899
+ return theme.bold(chalk12.hex(ensureTerminalGlyphContrast(theme.getTheme().toolBorderSuccess))(char));
6456
5900
  }
6457
5901
  getCompactToolLabelColor() {
6458
5902
  if (this.compactToolGroupLabelColor) return this.compactToolGroupLabelColor;
@@ -6620,9 +6064,9 @@ var ToolExecutionComponentEnhanced = class extends Container {
6620
6064
  const isStreamingContinuation = !this.isComplete() && this.quietPreviewLineLimit > 0;
6621
6065
  if (isStreamingContinuation) {
6622
6066
  const circleColor = this.getQuietToolCircleColor(this.getCompactToolAccentColor(this.getCompactToolLabelColor()));
6623
- return `${chalk14.hex(circleColor)("\u25CF")}${chalk14.hex(railColor)("\u2500")}`;
6067
+ return `${chalk12.hex(circleColor)("\u25CF")}${chalk12.hex(railColor)("\u2500")}`;
6624
6068
  }
6625
- return chalk14.hex(railColor)(this.compactToolHasFollowingContinuation ? "\u251C\u2500" : "\u2570\u2500");
6069
+ return chalk12.hex(railColor)(this.compactToolHasFollowingContinuation ? "\u251C\u2500" : "\u2570\u2500");
6626
6070
  }
6627
6071
  formatCompactContinuationLine(summary) {
6628
6072
  const lineMatch = summary.match(/^─+/);
@@ -6637,17 +6081,17 @@ var ToolExecutionComponentEnhanced = class extends Container {
6637
6081
  const railColor = this.getQuietToolRailColor();
6638
6082
  const circleColor = this.getQuietToolCircleColor(color);
6639
6083
  const isStreamingContinuation = this.compactToolContinuation && !this.isComplete() && this.quietPreviewLineLimit > 0;
6640
- const branch = hasFollowing || isStreamingContinuation ? `${hasPreview || isStreamingContinuation ? chalk14.hex(circleColor)("\u25CF") : chalk14.hex(railColor)("\u251C")}${chalk14.hex(railColor)(`\u2500${separator}${linePrefix}`)}` : chalk14.hex(railColor)(`\u2570\u2500${separator}${linePrefix}`);
6084
+ const branch = hasFollowing || isStreamingContinuation ? `${hasPreview || isStreamingContinuation ? chalk12.hex(circleColor)("\u25CF") : chalk12.hex(railColor)("\u251C")}${chalk12.hex(railColor)(`\u2500${separator}${linePrefix}`)}` : chalk12.hex(railColor)(`\u2570\u2500${separator}${linePrefix}`);
6641
6085
  const continuationSummary = ` ${summary.slice(linePrefix.length)}`;
6642
- const trail = continuationSummary ? chalk14.hex(argsBg)("\u258C") : "";
6086
+ const trail = continuationSummary ? chalk12.hex(argsBg)("\u258C") : "";
6643
6087
  return `${branch}${this.formatCompactSummaryBadge(continuationSummary, argsBg, argsColor)}${trail}`;
6644
6088
  }
6645
6089
  formatCompactSummaryBadge(summary, argsBg, argsColor) {
6646
- const styleText = (text) => argsColor ? chalk14.hex(argsColor)(text) : theme.fg("text", text);
6090
+ const styleText = (text) => argsColor ? chalk12.hex(argsColor)(text) : theme.fg("text", text);
6647
6091
  const rangeMatch = summary.match(/(:\d+(?:-\d+)?)$/);
6648
- if (!rangeMatch?.[1]) return chalk14.bgHex(argsBg)(styleText(summary));
6092
+ if (!rangeMatch?.[1]) return chalk12.bgHex(argsBg)(styleText(summary));
6649
6093
  const rangeStart = summary.length - rangeMatch[1].length;
6650
- return `${chalk14.bgHex(argsBg)(styleText(summary.slice(0, rangeStart)))}${chalk14.bgHex(argsBg)(theme.fg("dim", rangeMatch[1]))}`;
6094
+ return `${chalk12.bgHex(argsBg)(styleText(summary.slice(0, rangeStart)))}${chalk12.bgHex(argsBg)(theme.fg("dim", rangeMatch[1]))}`;
6651
6095
  }
6652
6096
  getCompactContinuationSummary() {
6653
6097
  const summary = this.getCompactToolSummary();
@@ -7243,8 +6687,8 @@ var ToolExecutionComponentEnhanced = class extends Container {
7243
6687
  const t = theme.getTheme();
7244
6688
  const color = diag.severity === "error" ? t.error : diag.severity === "warning" ? t.warning : t.muted;
7245
6689
  const icon = diag.severity === "error" ? "\u2717" : diag.severity === "warning" ? "\u26A0" : "\u2139";
7246
- const location = diag.location ? chalk14.hex(color)(diag.location) + " " : "";
7247
- const line = ` ${chalk14.hex(color)(icon)} ${location}${theme.fg("thinkingText", diag.message)}`;
6690
+ const location = diag.location ? chalk12.hex(color)(diag.location) + " " : "";
6691
+ const line = ` ${chalk12.hex(color)(icon)} ${location}${theme.fg("thinkingText", diag.message)}`;
7248
6692
  this.contentBox.addChild(new Text(line, 0, 0));
7249
6693
  }
7250
6694
  if (shouldCollapse) {
@@ -7298,8 +6742,8 @@ var ToolExecutionComponentEnhanced = class extends Container {
7298
6742
  const newLines = newStr.split("\n");
7299
6743
  const lines = [];
7300
6744
  let firstChangeIndex = -1;
7301
- const removedColor = chalk14.hex(mastra.red);
7302
- const addedColor = chalk14.hex(theme.getTheme().success);
6745
+ const removedColor = chalk12.hex(mastra.red);
6746
+ const addedColor = chalk12.hex(theme.getTheme().success);
7303
6747
  const maxLines = Math.max(oldLines.length, newLines.length);
7304
6748
  for (let i = 0; i < maxLines; i++) {
7305
6749
  if (i >= oldLines.length) {
@@ -8033,7 +7477,7 @@ ${stackMatch.join("\n")}`;
8033
7477
  }
8034
7478
  return err;
8035
7479
  }
8036
- function stripAnsi3(s) {
7480
+ function stripAnsi2(s) {
8037
7481
  return s.replace(/\x1b\[[0-9;]*m/g, "");
8038
7482
  }
8039
7483
  var BorderedBox = class {
@@ -8051,7 +7495,7 @@ var BorderedBox = class {
8051
7495
  this.child.invalidate?.();
8052
7496
  }
8053
7497
  render(width) {
8054
- const borderColor = (s) => this.borderColor ? chalk14.hex(this.borderColor)(s) : this.pending ? chalk14.hex(theme.getTheme().dim)(s) : chalk14.hex(tintHex(mastra.green, 1))(s);
7498
+ const borderColor = (s) => this.borderColor ? chalk12.hex(this.borderColor)(s) : this.pending ? chalk12.hex(theme.getTheme().dim)(s) : chalk12.hex(tintHex(mastra.green, 1))(s);
8055
7499
  const maxInnerWidth = Math.max(1, width - 6 - 2 - BOX_INDENT_STR.length - 1);
8056
7500
  const childLines = this.child.render(maxInnerWidth);
8057
7501
  if (childLines.length === 0) {
@@ -8062,7 +7506,7 @@ var BorderedBox = class {
8062
7506
  for (const line of childLines) {
8063
7507
  const trimmed = line.replace(/\s+$/, "");
8064
7508
  trimmedLines.push(trimmed);
8065
- const w = visibleWidth(stripAnsi3(trimmed));
7509
+ const w = visibleWidth(stripAnsi2(trimmed));
8066
7510
  if (w > maxContentWidth) maxContentWidth = w;
8067
7511
  }
8068
7512
  const maxAllowedContent = maxInnerWidth;
@@ -8075,25 +7519,25 @@ var BorderedBox = class {
8075
7519
  }
8076
7520
  const boxWidth = boxInner + 4;
8077
7521
  const lines = [];
8078
- const promptPrefix = chalk14.hex(tintHex(mastra.green, 1))("\xBB") + " ";
7522
+ const promptPrefix = chalk12.hex(tintHex(mastra.green, 1))("\xBB") + " ";
8079
7523
  const promptWidth = 2;
8080
7524
  if (this.label) {
8081
7525
  const labelText = ` ${this.label} `;
8082
7526
  const labelLen = labelText.length;
8083
7527
  const remaining = Math.max(0, boxWidth - 2 - labelLen);
8084
7528
  lines.push(
8085
- borderColor("\u256D") + chalk14.hex(theme.getTheme().dim)(labelText) + borderColor(`${"\u2500".repeat(remaining)}\u256E`)
7529
+ borderColor("\u256D") + chalk12.hex(theme.getTheme().dim)(labelText) + borderColor(`${"\u2500".repeat(remaining)}\u256E`)
8086
7530
  );
8087
7531
  } else {
8088
7532
  lines.push(borderColor(`\u256D${"\u2500".repeat(boxWidth - 2)}\u256E`));
8089
7533
  }
8090
7534
  for (let i = 0; i < trimmedLines.length; i++) {
8091
7535
  let trimmed = trimmedLines[i];
8092
- let vis = visibleWidth(stripAnsi3(trimmed));
7536
+ let vis = visibleWidth(stripAnsi2(trimmed));
8093
7537
  const lineMaxWidth = i === 0 ? boxInner - promptWidth : boxInner;
8094
7538
  if (vis > lineMaxWidth) {
8095
7539
  trimmed = truncateToWidth(trimmed, lineMaxWidth);
8096
- vis = visibleWidth(stripAnsi3(trimmed));
7540
+ vis = visibleWidth(stripAnsi2(trimmed));
8097
7541
  }
8098
7542
  if (i === 0) {
8099
7543
  const padNeeded = Math.max(0, boxInner - vis - promptWidth);
@@ -8128,7 +7572,6 @@ var PendingUserMessageComponent = class extends Container {
8128
7572
  const prefix = imageCount > 0 ? `[${imageCount} image${imageCount > 1 ? "s" : ""}] ` : "";
8129
7573
  const displayText = `${prefix}${text.replace(/\[image\]\s*/g, "").trim()}`.trim();
8130
7574
  this.addChild(new Text(theme.fg("dim", `\u21B3 ${displayText || "Message"} pending\u2026`), BOX_INDENT_STR.length, 0));
8131
- this.addChild(new Spacer(1));
8132
7575
  }
8133
7576
  getChatSpacingKind() {
8134
7577
  return "user-message";
@@ -8174,8 +7617,8 @@ var ToolApprovalDialogComponent = class extends Box {
8174
7617
  }
8175
7618
  this.addChild(new Spacer(1));
8176
7619
  const categoryHint = this.categoryLabel ? `lways allow ${this.categoryLabel.toLowerCase()}` : "lways allow category";
8177
- const dimColor = chalk14.hex(theme.getTheme().dim);
8178
- const key = chalk14.hex(theme.getTheme().text).bold;
7620
+ const dimColor = chalk12.hex(theme.getTheme().dim);
7621
+ const key = chalk12.hex(theme.getTheme().text).bold;
8179
7622
  this.addChild(
8180
7623
  new Text(
8181
7624
  theme.fg("accent", "Allow? ") + key("y") + dimColor("es ") + key("n") + dimColor("o ") + key("a") + dimColor(categoryHint + " ") + key("Y") + dimColor("olo"),
@@ -8244,7 +7687,8 @@ var ToolApprovalDialogComponent = class extends Box {
8244
7687
 
8245
7688
  // src/tui/handlers/tool.ts
8246
7689
  function getCurrentModeColor(ctx) {
8247
- return ctx.state.harness.getCurrentMode?.()?.color;
7690
+ const color = ctx.state.harness.getCurrentMode?.()?.metadata?.color;
7691
+ return typeof color === "string" ? color : void 0;
8248
7692
  }
8249
7693
  function isTaskMutationTool(toolName) {
8250
7694
  return toolName === "task_write" || toolName === "task_update" || toolName === "task_complete";
@@ -8575,6 +8019,7 @@ function handleToolEnd(ctx, toolCallId, result, isError) {
8575
8019
  // src/tui/render-messages.ts
8576
8020
  var WHILE_ACTIVE_USER_MESSAGE_LABEL = "steer";
8577
8021
  var HIDDEN_REACTIVE_SIGNAL_TAGS = /* @__PURE__ */ new Set(["github-subscribe-pr", "github-unsubscribe-pr"]);
8022
+ var GOAL_STATE_SIGNAL_ID = "goal";
8578
8023
  function shouldRenderReactiveSignal(tagName) {
8579
8024
  return !HIDDEN_REACTIVE_SIGNAL_TAGS.has(tagName);
8580
8025
  }
@@ -8586,7 +8031,8 @@ function getPendingUserMessageLabel(isInterjection) {
8586
8031
  return isInterjection ? WHILE_ACTIVE_USER_MESSAGE_LABEL : void 0;
8587
8032
  }
8588
8033
  function getCurrentModeColor2(state) {
8589
- return state.harness.getCurrentMode?.()?.color;
8034
+ const color = state.harness.getCurrentMode?.()?.metadata?.color;
8035
+ return typeof color === "string" ? color : void 0;
8590
8036
  }
8591
8037
  var TaskHistoryComponent = class extends Container {
8592
8038
  getChatSpacingKind() {
@@ -8606,11 +8052,10 @@ function renderClearedTasksInline(state, clearedTasks, insertIndex = -1) {
8606
8052
  const label = count === 1 ? "Task" : "Tasks";
8607
8053
  container.addChild(new Text(theme.fg("accent", `${label} cleared`), BOX_INDENT, 0));
8608
8054
  for (const task of clearedTasks) {
8609
- const icon = task.status === "completed" ? chalk14.hex(mastra.green)("\u2713") : chalk14.hex(mastra.darkGray)("\u25CB");
8610
- const text = chalk14.hex(theme.getTheme().dim).strikethrough(task.content);
8055
+ const icon = task.status === "completed" ? chalk12.hex(mastra.green)("\u2713") : chalk12.hex(mastra.darkGray)("\u25CB");
8056
+ const text = chalk12.hex(theme.getTheme().dim).strikethrough(task.content);
8611
8057
  container.addChild(new Text(` ${icon} ${text}`, BOX_INDENT, 0));
8612
8058
  }
8613
- container.addChild(new Spacer(1));
8614
8059
  insertTaskHistoryComponent(state, container, insertIndex);
8615
8060
  }
8616
8061
  function renderTaskTransitionFromHistory(state, previousTasks, nextTasks) {
@@ -8779,7 +8224,7 @@ function addUserMessage(state, message, options) {
8779
8224
  return;
8780
8225
  }
8781
8226
  const stateSignalPart = message.content.find((content) => content.type === "state_signal");
8782
- if (stateSignalPart && stateSignalPart.stateId === TASKS_STATE_ID) {
8227
+ if (stateSignalPart && (stateSignalPart.stateId === TASKS_STATE_ID || stateSignalPart.stateId === GOAL_STATE_SIGNAL_ID)) {
8783
8228
  return;
8784
8229
  }
8785
8230
  if (stateSignalPart) {
@@ -8860,7 +8305,7 @@ function addUserMessage(state, message, options) {
8860
8305
  }
8861
8306
  const slashComp = new SlashCommandComponent(commandName, commandContent);
8862
8307
  state.allSlashCommandComponents.push(slashComp);
8863
- state.chatContainer.addChild(slashComp);
8308
+ insertChatComponentWithBoundarySpacing(state.chatContainer, slashComp);
8864
8309
  state.ui.requestRender();
8865
8310
  return;
8866
8311
  }
@@ -8884,7 +8329,7 @@ function addUserMessage(state, message, options) {
8884
8329
  }
8885
8330
  const skillComp = new SlashCommandComponent(commandName, skillContent);
8886
8331
  state.allSlashCommandComponents.push(skillComp);
8887
- state.chatContainer.addChild(skillComp);
8332
+ insertChatComponentWithBoundarySpacing(state.chatContainer, skillComp);
8888
8333
  state.ui.requestRender();
8889
8334
  return;
8890
8335
  }
@@ -9338,7 +8783,7 @@ ARGUMENTS: ${trimmedArgs}` : ""}`.trim();
9338
8783
  if (!isCurrentThreadActive(ctx)) {
9339
8784
  const component = new SlashCommandComponent(`skill/${skill.name}`, content);
9340
8785
  ctx.state.allSlashCommandComponents.push(component);
9341
- ctx.state.chatContainer.addChild(component);
8786
+ insertChatComponentWithBoundarySpacing(ctx.state.chatContainer, component);
9342
8787
  ctx.state.ui.requestRender();
9343
8788
  }
9344
8789
  const displayText = `/skill/${skill.name}${trimmedArgs ? ` ${trimmedArgs}` : ""}`;
@@ -9362,7 +8807,7 @@ ${escapeSkillBoundary(content)}
9362
8807
  // src/tui/commands/new.ts
9363
8808
  async function handleNewCommand(ctx) {
9364
8809
  const { state } = ctx;
9365
- state.harness.abort();
8810
+ state.harness.detachFromCurrentThread();
9366
8811
  state.pendingNewThread = true;
9367
8812
  state.chatContainer.clear();
9368
8813
  state.pendingTools.clear();
@@ -9690,11 +9135,11 @@ async function handleResourceCommand(ctx, args) {
9690
9135
  }
9691
9136
  function colorizeDiffLine(line) {
9692
9137
  const t = theme.getTheme();
9693
- const addedColor = chalk14.hex(t.success);
9694
- const hunkHeaderColor = chalk14.hex(t.toolBorderPending);
9695
- const fileHeaderColor = chalk14.bold.hex(t.accent);
9696
- const removedColor = chalk14.hex(mastra.red);
9697
- const metaColor = chalk14.hex(mastra.mainGray);
9138
+ const addedColor = chalk12.hex(t.success);
9139
+ const hunkHeaderColor = chalk12.hex(t.toolBorderPending);
9140
+ const fileHeaderColor = chalk12.bold.hex(t.accent);
9141
+ const removedColor = chalk12.hex(mastra.red);
9142
+ const metaColor = chalk12.hex(mastra.mainGray);
9698
9143
  if (line.startsWith("+++") || line.startsWith("---")) {
9699
9144
  return fileHeaderColor(line);
9700
9145
  }
@@ -9719,7 +9164,6 @@ function colorizeDiffLine(line) {
9719
9164
  var DiffOutputComponent = class extends Container {
9720
9165
  constructor(command, diffOutput) {
9721
9166
  super();
9722
- this.addChild(new Spacer(1));
9723
9167
  this.addChild(
9724
9168
  new Text(
9725
9169
  `${theme.fg("success", "\u2713")} ${theme.bold(theme.fg("muted", "$"))} ${theme.fg("text", command)}`,
@@ -9735,6 +9179,9 @@ var DiffOutputComponent = class extends Container {
9735
9179
  }
9736
9180
  }
9737
9181
  }
9182
+ getChatSpacingKind() {
9183
+ return "other";
9184
+ }
9738
9185
  };
9739
9186
 
9740
9187
  // src/tui/commands/diff.ts
@@ -10547,33 +9994,170 @@ function getLinuxClipboardImageXclip() {
10547
9994
  } catch {
10548
9995
  return null;
10549
9996
  }
10550
- }
10551
- function getLinuxClipboardImageWlPaste() {
10552
- try {
10553
- const types = execSync("wl-paste --list-types", {
10554
- encoding: "utf-8",
10555
- timeout: 3e3,
10556
- stdio: ["pipe", "pipe", "pipe"]
10557
- });
10558
- if (!types.includes("image/png")) {
10559
- return null;
9997
+ }
9998
+ function getLinuxClipboardImageWlPaste() {
9999
+ try {
10000
+ const types = execSync("wl-paste --list-types", {
10001
+ encoding: "utf-8",
10002
+ timeout: 3e3,
10003
+ stdio: ["pipe", "pipe", "pipe"]
10004
+ });
10005
+ if (!types.includes("image/png")) {
10006
+ return null;
10007
+ }
10008
+ const buffer = execSync("wl-paste --type image/png", {
10009
+ timeout: 5e3,
10010
+ stdio: ["pipe", "pipe", "pipe"],
10011
+ maxBuffer: 50 * 1024 * 1024
10012
+ });
10013
+ if (!Buffer.isBuffer(buffer) || buffer.length === 0) {
10014
+ return null;
10015
+ }
10016
+ return {
10017
+ data: buffer.toString("base64"),
10018
+ mimeType: "image/png"
10019
+ };
10020
+ } catch {
10021
+ return null;
10022
+ }
10023
+ }
10024
+ var GRADIENT_WIDTH = 30;
10025
+ var BASE_COLOR = [22, 200, 88];
10026
+ function getMinBrightness() {
10027
+ return getThemeMode() === "dark" ? 0.45 : 0.55;
10028
+ }
10029
+ function hexToRgb(hex) {
10030
+ const h = hex.replace("#", "");
10031
+ return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)];
10032
+ }
10033
+ var IDLE_BRIGHTNESS = 0.8;
10034
+ function applyGradientSweep(text, offset, color, fadeProgress = 0) {
10035
+ const chars = [...text];
10036
+ const totalChars = chars.length;
10037
+ if (totalChars === 0) return text;
10038
+ const baseColor = color ? hexToRgb(color) : BASE_COLOR;
10039
+ const gradientCenter = offset % 1 * 100;
10040
+ const halfGradient = GRADIENT_WIDTH / 2;
10041
+ const minBrightness = getMinBrightness();
10042
+ const brightnessRange = 1 - minBrightness;
10043
+ let result = "";
10044
+ let batchChars = "";
10045
+ let batchR = -1, batchG = -1, batchB = -1;
10046
+ for (let i = 0; i < totalChars; i++) {
10047
+ const char = chars[i];
10048
+ if (char === " ") {
10049
+ if (batchChars) {
10050
+ result += chalk12.rgb(batchR, batchG, batchB)(batchChars);
10051
+ batchChars = "";
10052
+ }
10053
+ result += " ";
10054
+ continue;
10055
+ }
10056
+ const charPosition = i / totalChars * 100;
10057
+ let distance = Math.abs(charPosition - gradientCenter);
10058
+ if (distance > 50) distance = 100 - distance;
10059
+ const normalizedDistance = Math.min(distance / halfGradient, 1);
10060
+ const animBrightness = minBrightness + brightnessRange * (1 - normalizedDistance);
10061
+ const brightness = animBrightness + (IDLE_BRIGHTNESS - animBrightness) * fadeProgress;
10062
+ const r = Math.floor(baseColor[0] * brightness);
10063
+ const g = Math.floor(baseColor[1] * brightness);
10064
+ const b = Math.floor(baseColor[2] * brightness);
10065
+ if (r === batchR && g === batchG && b === batchB) {
10066
+ batchChars += char;
10067
+ } else {
10068
+ if (batchChars) {
10069
+ result += chalk12.rgb(batchR, batchG, batchB)(batchChars);
10070
+ }
10071
+ batchChars = char;
10072
+ batchR = r;
10073
+ batchG = g;
10074
+ batchB = b;
10075
+ }
10076
+ }
10077
+ if (batchChars) {
10078
+ result += chalk12.rgb(batchR, batchG, batchB)(batchChars);
10079
+ }
10080
+ return result;
10081
+ }
10082
+ var GradientAnimator = class {
10083
+ offset = 0;
10084
+ intervalId = null;
10085
+ onTick;
10086
+ _isFadingOut = false;
10087
+ _isFadingIn = false;
10088
+ _fadeProgress = 0;
10089
+ // 0 = full animation, 1 = fully idle
10090
+ constructor(onTick) {
10091
+ this.onTick = onTick;
10092
+ }
10093
+ start() {
10094
+ if (this.intervalId && !this._isFadingOut) return;
10095
+ if (this.intervalId) {
10096
+ clearInterval(this.intervalId);
10097
+ this.intervalId = null;
10560
10098
  }
10561
- const buffer = execSync("wl-paste --type image/png", {
10562
- timeout: 5e3,
10563
- stdio: ["pipe", "pipe", "pipe"],
10564
- maxBuffer: 50 * 1024 * 1024
10565
- });
10566
- if (!Buffer.isBuffer(buffer) || buffer.length === 0) {
10567
- return null;
10099
+ this._isFadingOut = false;
10100
+ this._isFadingIn = true;
10101
+ this._fadeProgress = 1;
10102
+ this.offset = 0;
10103
+ this.intervalId = setInterval(() => {
10104
+ this.offset += 0.03;
10105
+ if (this._isFadingIn) {
10106
+ this._fadeProgress -= 0.06;
10107
+ if (this._fadeProgress <= 0) {
10108
+ this._fadeProgress = 0;
10109
+ this._isFadingIn = false;
10110
+ }
10111
+ }
10112
+ this.onTick();
10113
+ }, 80);
10114
+ }
10115
+ /**
10116
+ * Smoothly fade the gradient to idle state over ~500ms.
10117
+ */
10118
+ fadeOut() {
10119
+ if (!this.intervalId) return;
10120
+ if (this._isFadingOut) return;
10121
+ this._isFadingOut = true;
10122
+ this._isFadingIn = false;
10123
+ this._fadeProgress = 0;
10124
+ clearInterval(this.intervalId);
10125
+ this.intervalId = setInterval(() => {
10126
+ this._fadeProgress += 0.08;
10127
+ if (this._fadeProgress >= 1) {
10128
+ this._fadeProgress = 1;
10129
+ this.stop();
10130
+ }
10131
+ this.onTick();
10132
+ }, 40);
10133
+ }
10134
+ stop() {
10135
+ if (this.intervalId) {
10136
+ clearInterval(this.intervalId);
10137
+ this.intervalId = null;
10568
10138
  }
10569
- return {
10570
- data: buffer.toString("base64"),
10571
- mimeType: "image/png"
10572
- };
10573
- } catch {
10574
- return null;
10139
+ this._isFadingOut = false;
10140
+ this._isFadingIn = false;
10141
+ this._fadeProgress = 0;
10142
+ this.offset = 0;
10575
10143
  }
10576
- }
10144
+ getOffset() {
10145
+ return this.offset;
10146
+ }
10147
+ /** 0 = full animation, 1 = fully idle. Use to interpolate colors. */
10148
+ getFadeProgress() {
10149
+ return this._fadeProgress;
10150
+ }
10151
+ isFadingOut() {
10152
+ return this._isFadingOut;
10153
+ }
10154
+ isFadingIn() {
10155
+ return this._isFadingIn;
10156
+ }
10157
+ isRunning() {
10158
+ return this.intervalId !== null;
10159
+ }
10160
+ };
10577
10161
  var OMProgressComponent = class extends Container {
10578
10162
  state = defaultOMProgressState();
10579
10163
  statusText;
@@ -10636,11 +10220,11 @@ var OMProgressComponent = class extends Container {
10636
10220
  } else if (this.state.status === "observing") {
10637
10221
  const elapsed = this.state.startTime ? Math.round((Date.now() - this.state.startTime) / 1e3) : 0;
10638
10222
  const spinner = this.getSpinner();
10639
- this.statusText.setText(chalk14.hex(mastra.orange)(`${spinner} Observing... ${elapsed}s`));
10223
+ this.statusText.setText(chalk12.hex(mastra.orange)(`${spinner} Observing... ${elapsed}s`));
10640
10224
  } else if (this.state.status === "reflecting") {
10641
10225
  const elapsed = this.state.startTime ? Math.round((Date.now() - this.state.startTime) / 1e3) : 0;
10642
10226
  const spinner = this.getSpinner();
10643
- this.statusText.setText(chalk14.hex(mastra.pink)(`${spinner} Reflecting... ${elapsed}s`));
10227
+ this.statusText.setText(chalk12.hex(mastra.pink)(`${spinner} Reflecting... ${elapsed}s`));
10644
10228
  }
10645
10229
  }
10646
10230
  renderProgressBar(percent, width) {
@@ -10648,11 +10232,11 @@ var OMProgressComponent = class extends Container {
10648
10232
  const empty = width - filled;
10649
10233
  const bar = "\u2501".repeat(filled) + "\u2500".repeat(empty);
10650
10234
  if (percent >= 90) {
10651
- return chalk14.hex(mastra.red)(bar);
10235
+ return chalk12.hex(mastra.red)(bar);
10652
10236
  } else if (percent >= 70) {
10653
- return chalk14.hex(mastra.orange)(bar);
10237
+ return chalk12.hex(mastra.orange)(bar);
10654
10238
  } else {
10655
- return chalk14.hex(mastra.darkGray)(bar);
10239
+ return chalk12.hex(mastra.darkGray)(bar);
10656
10240
  }
10657
10241
  }
10658
10242
  spinnerFrame = 0;
@@ -10678,21 +10262,21 @@ function formatTokensThreshold(n) {
10678
10262
  return (s.endsWith(".0") ? s.slice(0, -2) : s) + "k";
10679
10263
  }
10680
10264
  function colorByPercent(text, percent) {
10681
- if (percent >= 90) return chalk14.hex(mastra.red)(text);
10682
- if (percent >= 70) return chalk14.hex(mastra.orange)(text);
10683
- return chalk14.hex("#71717a")(text);
10265
+ if (percent >= 90) return chalk12.hex(mastra.red)(text);
10266
+ if (percent >= 70) return chalk12.hex(mastra.orange)(text);
10267
+ return chalk12.hex("#71717a")(text);
10684
10268
  }
10685
10269
  function formatObservationStatus(state, compact, labelStyler) {
10686
10270
  const percent = Math.round(state.thresholdPercent);
10687
10271
  const pct = colorByPercent(`${percent}%`, percent);
10688
- const defaultStyler = (s) => chalk14.hex(mastra.specialGray)(s);
10272
+ const defaultStyler = (s) => chalk12.hex(mastra.specialGray)(s);
10689
10273
  const styleLabel = labelStyler ?? defaultStyler;
10690
10274
  if (compact === "percentOnly") {
10691
10275
  return styleLabel("msg ") + pct;
10692
10276
  }
10693
10277
  const label = compact === "full" ? "messages" : "msg";
10694
10278
  const fraction = `${formatTokensValue(state.pendingTokens)}/${formatTokensThreshold(state.threshold)}`;
10695
- const buffered = compact !== "noBuffer" && state.buffered.observations.projectedMessageRemoval > 0 ? chalk14.italic(
10279
+ const buffered = compact !== "noBuffer" && state.buffered.observations.projectedMessageRemoval > 0 ? chalk12.italic(
10696
10280
  theme.fg("muted", ` \u2193${formatTokensThreshold(state.buffered.observations.projectedMessageRemoval)}`)
10697
10281
  ) : "";
10698
10282
  return styleLabel(`${label} `) + colorByPercent(fraction, percent) + buffered;
@@ -10700,7 +10284,7 @@ function formatObservationStatus(state, compact, labelStyler) {
10700
10284
  function formatReflectionStatus(state, compact, labelStyler) {
10701
10285
  const percent = Math.round(state.reflectionThresholdPercent);
10702
10286
  const pct = colorByPercent(`${percent}%`, percent);
10703
- const defaultStyler = (s) => chalk14.hex(mastra.specialGray)(s);
10287
+ const defaultStyler = (s) => chalk12.hex(mastra.specialGray)(s);
10704
10288
  const styleLabel = labelStyler ?? defaultStyler;
10705
10289
  const label = styleLabel(compact === "full" ? "memory" : "mem") + " ";
10706
10290
  if (compact === "percentOnly") {
@@ -10708,7 +10292,7 @@ function formatReflectionStatus(state, compact, labelStyler) {
10708
10292
  }
10709
10293
  const fraction = `${formatTokensValue(state.observationTokens)}/${formatTokensThreshold(state.reflectionThreshold)}`;
10710
10294
  const savings = state.buffered.reflection.inputObservationTokens - state.buffered.reflection.observationTokens;
10711
- const buffered = compact !== "noBuffer" && state.buffered.reflection.status === "complete" && savings > 0 ? chalk14.italic(theme.fg("muted", ` \u2193${formatTokensThreshold(savings)}`)) : "";
10295
+ const buffered = compact !== "noBuffer" && state.buffered.reflection.status === "complete" && savings > 0 ? chalk12.italic(theme.fg("muted", ` \u2193${formatTokensThreshold(savings)}`)) : "";
10712
10296
  return label + colorByPercent(fraction, percent) + buffered;
10713
10297
  }
10714
10298
  function formatOMStatus(state) {
@@ -10737,7 +10321,7 @@ function formatGithubPrLabel(state, subscription) {
10737
10321
  )
10738
10322
  };
10739
10323
  }
10740
- return { plain: label, styled: chalk14.hex(color)(label) };
10324
+ return { plain: label, styled: chalk12.hex(color)(label) };
10741
10325
  }
10742
10326
  function formatGoalDuration(goal) {
10743
10327
  const activeStartedAt = goal.activeStartedAt ?? (goal.activeDurationMs === void 0 ? goal.startedAt : void 0);
@@ -10766,7 +10350,8 @@ function updateStatusLine(state) {
10766
10350
  const modes = state.harness.listModes();
10767
10351
  const currentMode = modes.length > 1 ? state.harness.getCurrentMode() : void 0;
10768
10352
  const judgeModeColor = mastra.blue;
10769
- const mainModeColor = currentMode?.color;
10353
+ const currentModeColor = currentMode?.metadata?.color;
10354
+ const mainModeColor = typeof currentModeColor === "string" ? currentModeColor : void 0;
10770
10355
  const modeColor = isJudging ? judgeModeColor : showOMMode ? isObserving ? getObserverColor2() : getReflectorColor2() : mainModeColor;
10771
10356
  const tintBg = modeColor ? tintHex(modeColor, 0.15) : void 0;
10772
10357
  const badgeName = isJudging ? "judge" : showOMMode ? isObserving ? "observe" : "reflect" : currentMode ? currentMode.name || currentMode.id || "unknown" : void 0;
@@ -10787,8 +10372,8 @@ function updateStatusLine(state) {
10787
10372
  const mr = Math.floor(mcr * badgeBrightness);
10788
10373
  const mg = Math.floor(mcg * badgeBrightness);
10789
10374
  const mb = Math.floor(mcb * badgeBrightness);
10790
- const rightHalf = tintBg ? chalk14.rgb(mr, mg, mb).bgHex(tintBg)("\u258C") : chalk14.rgb(mr, mg, mb)("\u258C");
10791
- modeBadge = chalk14.rgb(mr, mg, mb)("\u2590") + chalk14.bgRgb(mr, mg, mb).hex("#000000").bold(badgeName.toLowerCase()) + rightHalf;
10375
+ const rightHalf = tintBg ? chalk12.rgb(mr, mg, mb).bgHex(tintBg)("\u258C") : chalk12.rgb(mr, mg, mb)("\u258C");
10376
+ modeBadge = chalk12.rgb(mr, mg, mb)("\u2590") + chalk12.bgRgb(mr, mg, mb).hex("#000000").bold(badgeName.toLowerCase()) + rightHalf;
10792
10377
  modeBadgeWidth = badgeName.length + 2;
10793
10378
  } else if (badgeName) {
10794
10379
  modeBadge = " " + theme.fg("dim", badgeName) + " ";
@@ -10834,7 +10419,7 @@ function updateStatusLine(state) {
10834
10419
  const dirFull = !threadTitle && branch ? `${displayPath} (${branch})` : displayPath;
10835
10420
  const dirBranchOnly = !threadTitle && branch ? branch : null;
10836
10421
  const dirBranchShort = !threadTitle && branch && branch.length > 24 ? branch.slice(0, 12) + ".." + branch.slice(-8) : dirBranchOnly;
10837
- const modelTrail = tintBg ? chalk14.hex(tintBg)("\u258C") : "";
10422
+ const modelTrail = tintBg ? chalk12.hex(tintBg)("\u258C") : "";
10838
10423
  const styleModelId = (id) => {
10839
10424
  if (!state.modelAuthStatus.hasAuth) {
10840
10425
  const envVar = state.modelAuthStatus.apiKeyEnvVar;
@@ -10844,8 +10429,8 @@ function updateStatusLine(state) {
10844
10429
  const fade = state.gradientAnimator.getFadeProgress();
10845
10430
  const easedFade = fade * fade * (3 - 2 * fade);
10846
10431
  const text = applyGradientSweep(id, state.gradientAnimator.getOffset(), modeColor, easedFade);
10847
- const styled = chalk14.italic(text);
10848
- const bg = tintBg ? chalk14.bgHex(tintBg)(styled) : styled;
10432
+ const styled = chalk12.italic(text);
10433
+ const bg = tintBg ? chalk12.bgHex(tintBg)(styled) : styled;
10849
10434
  return bg + modelTrail;
10850
10435
  }
10851
10436
  if (modeColor) {
@@ -10855,11 +10440,11 @@ function updateStatusLine(state) {
10855
10440
  parseInt(modeColor.slice(5, 7), 16)
10856
10441
  ];
10857
10442
  const idleBright = 0.8;
10858
- const fgStyled = chalk14.rgb(Math.floor(cr * idleBright), Math.floor(cg * idleBright), Math.floor(cb * idleBright)).bold.italic(id);
10859
- const bg = tintBg ? chalk14.bgHex(tintBg)(fgStyled) : fgStyled;
10443
+ const fgStyled = chalk12.rgb(Math.floor(cr * idleBright), Math.floor(cg * idleBright), Math.floor(cb * idleBright)).bold.italic(id);
10444
+ const bg = tintBg ? chalk12.bgHex(tintBg)(fgStyled) : fgStyled;
10860
10445
  return bg + modelTrail;
10861
10446
  }
10862
- return chalk14.hex(mastra.specialGray).bold.italic(id);
10447
+ return chalk12.hex(mastra.specialGray).bold.italic(id);
10863
10448
  };
10864
10449
  let shortModeBadge = "";
10865
10450
  let shortModeBadgeWidth = 0;
@@ -10882,8 +10467,8 @@ function updateStatusLine(state) {
10882
10467
  const sr = Math.floor(mcr * sBadgeBrightness);
10883
10468
  const sg = Math.floor(mcg * sBadgeBrightness);
10884
10469
  const sb = Math.floor(mcb * sBadgeBrightness);
10885
- const shortRightHalf = tintBg ? chalk14.rgb(sr, sg, sb).bgHex(tintBg)("\u258C") : chalk14.rgb(sr, sg, sb)("\u258C");
10886
- shortModeBadge = chalk14.rgb(sr, sg, sb)("\u2590") + chalk14.bgRgb(sr, sg, sb).hex("#000000").bold(shortName) + shortRightHalf;
10470
+ const shortRightHalf = tintBg ? chalk12.rgb(sr, sg, sb).bgHex(tintBg)("\u258C") : chalk12.rgb(sr, sg, sb)("\u258C");
10471
+ shortModeBadge = chalk12.rgb(sr, sg, sb)("\u2590") + chalk12.bgRgb(sr, sg, sb).hex("#000000").bold(shortName) + shortRightHalf;
10887
10472
  shortModeBadgeWidth = shortName.length + 2;
10888
10473
  } else if (badgeName) {
10889
10474
  const shortName = badgeName.toLowerCase().charAt(0);
@@ -11198,9 +10783,9 @@ async function askCustomPackEditTarget(ctx, pack) {
11198
10783
  const selectList = new SelectList(
11199
10784
  [
11200
10785
  { value: "rename", label: ` Rename \u2192 ${theme.fg("text", pack.name)}` },
11201
- { value: "plan", label: ` ${chalk14.hex(mastra.purple)("plan")} \u2192 ${theme.fg("text", pack.models.plan)}` },
11202
- { value: "build", label: ` ${chalk14.hex(mastra.green)("build")} \u2192 ${theme.fg("text", pack.models.build)}` },
11203
- { value: "fast", label: ` ${chalk14.hex(mastra.orange)("fast")} \u2192 ${theme.fg("text", pack.models.fast)}` },
10786
+ { value: "plan", label: ` ${chalk12.hex(mastra.purple)("plan")} \u2192 ${theme.fg("text", pack.models.plan)}` },
10787
+ { value: "build", label: ` ${chalk12.hex(mastra.green)("build")} \u2192 ${theme.fg("text", pack.models.build)}` },
10788
+ { value: "fast", label: ` ${chalk12.hex(mastra.orange)("fast")} \u2192 ${theme.fg("text", pack.models.fast)}` },
11204
10789
  { value: "save", label: ` ${theme.fg("success", "Save")}` }
11205
10790
  ],
11206
10791
  5,
@@ -11227,9 +10812,9 @@ async function askCustomPackEditTarget(ctx, pack) {
11227
10812
  }
11228
10813
  async function runCustomFlow(ctx, options) {
11229
10814
  const modes = [
11230
- { id: "plan", label: "plan", color: mastra.purple },
11231
- { id: "build", label: "build", color: mastra.green },
11232
- { id: "fast", label: "fast", color: mastra.orange }
10815
+ { id: "plan", label: "plan", metadata: { color: mastra.purple } },
10816
+ { id: "build", label: "build", metadata: { color: mastra.green } },
10817
+ { id: "fast", label: "fast", metadata: { color: mastra.orange } }
11233
10818
  ];
11234
10819
  const name = options?.skipNamePrompt ? options?.name : await askCustomPackName(ctx, void 0);
11235
10820
  if (!name) return null;
@@ -11243,7 +10828,7 @@ async function runCustomFlow(ctx, options) {
11243
10828
  const modelId = await selectModel(
11244
10829
  ctx,
11245
10830
  `Select model for ${mode.label} mode`,
11246
- mode.color,
10831
+ mode.metadata.color,
11247
10832
  models[mode.id] || void 0
11248
10833
  );
11249
10834
  if (!modelId) return null;
@@ -11380,9 +10965,9 @@ function getPackDetail(pack) {
11380
10965
  return theme.fg("dim", " Create a named custom pack and pick a model for each mode.");
11381
10966
  }
11382
10967
  return [
11383
- ` ${chalk14.hex(mastra.purple)("plan")} \u2192 ${theme.fg("text", pack.models.plan)}`,
11384
- ` ${chalk14.hex(mastra.green)("build")} \u2192 ${theme.fg("text", pack.models.build)}`,
11385
- ` ${chalk14.hex(mastra.orange)("fast")} \u2192 ${theme.fg("text", pack.models.fast)}`
10968
+ ` ${chalk12.hex(mastra.purple)("plan")} \u2192 ${theme.fg("text", pack.models.plan)}`,
10969
+ ` ${chalk12.hex(mastra.green)("build")} \u2192 ${theme.fg("text", pack.models.build)}`,
10970
+ ` ${chalk12.hex(mastra.orange)("fast")} \u2192 ${theme.fg("text", pack.models.fast)}`
11386
10971
  ].join("\n");
11387
10972
  }
11388
10973
  async function saveCustomPackEdits(ctx, pack, previousPackId) {
@@ -12879,7 +12464,8 @@ async function handleApiKeysCommand(ctx) {
12879
12464
 
12880
12465
  // src/tui/commands/settings.ts
12881
12466
  function getCurrentModeColor3(ctx) {
12882
- return ctx.state.harness.getCurrentMode?.()?.color;
12467
+ const color = ctx.state.harness.getCurrentMode?.()?.metadata?.color;
12468
+ return typeof color === "string" ? color : void 0;
12883
12469
  }
12884
12470
  function commandExists(command) {
12885
12471
  return new Promise((resolve3) => {
@@ -13140,9 +12726,11 @@ Using the same profile across different providers can cause compatibility issues
13140
12726
  }
13141
12727
  function applyBrowserToAgents(ctx, browser, browserSettings) {
13142
12728
  const modes = ctx.harness.listModes();
12729
+ let harnessState;
13143
12730
  for (const mode of modes) {
13144
- const agent = typeof mode.agent === "function" ? mode.agent(ctx.state.harness.getState()) : mode.agent;
13145
- agent.setBrowser(browser);
12731
+ const modeAgent = mode.agent;
12732
+ const agent = typeof modeAgent === "function" ? modeAgent(harnessState ??= ctx.state.harness.getState()) : modeAgent;
12733
+ agent?.setBrowser?.(browser);
13146
12734
  }
13147
12735
  ctx.harness.setState({ [ACTIVE_BROWSER_KEY]: browserSettings });
13148
12736
  }
@@ -13404,8 +12992,7 @@ Run /browser on to apply.`);
13404
12992
  return;
13405
12993
  }
13406
12994
  const currentMode = ctx.harness.getCurrentMode();
13407
- const agent = typeof currentMode.agent === "function" ? currentMode.agent(ctx.state.harness.getState()) : currentMode.agent;
13408
- const browserInstance = agent.browser;
12995
+ const browserInstance = currentMode.agent?.browser;
13409
12996
  if (!browserInstance) {
13410
12997
  ctx.showError("Browser not enabled. Run /browser on first.");
13411
12998
  return;
@@ -13415,9 +13002,10 @@ Run /browser on to apply.`);
13415
13002
  ctx.showError("Current browser instance does not support exporting storage state.");
13416
13003
  return;
13417
13004
  }
13005
+ const exportableBrowser = browserInstance;
13418
13006
  const expandedPath = exportPath.replace(/^~/, process.env.HOME || "~");
13419
13007
  try {
13420
- await browserInstance.exportStorageState(expandedPath);
13008
+ await exportableBrowser.exportStorageState(expandedPath);
13421
13009
  ctx.showInfo(`Storage state exported to: ${expandedPath}`);
13422
13010
  } catch (error) {
13423
13011
  ctx.showError(`Failed to export storage state: ${error instanceof Error ? error.message : String(error)}`);
@@ -14977,9 +14565,6 @@ async function dispatchSlashCommand(input, state, buildCtx) {
14977
14565
  case "goal":
14978
14566
  await handleGoalCommand(buildCtx(), args);
14979
14567
  return true;
14980
- case "judge":
14981
- await handleJudgeCommand(buildCtx());
14982
- return true;
14983
14568
  default: {
14984
14569
  const customCommand = state.customSlashCommands.find((cmd) => cmd.name === command);
14985
14570
  if (customCommand) {
@@ -15053,7 +14638,7 @@ async function handleCustomSlashCommand(state, command, args, ctx, displayText)
15053
14638
  if (!isCurrentThreadActive(commandCtx)) {
15054
14639
  const slashComp = new SlashCommandComponent(command.name, processedContent.trim());
15055
14640
  state.allSlashCommandComponents.push(slashComp);
15056
- state.chatContainer.addChild(slashComp);
14641
+ insertChatComponentWithBoundarySpacing(state.chatContainer, slashComp);
15057
14642
  state.ui.requestRender();
15058
14643
  }
15059
14644
  const wrapped = `<slash-command name="${command.name}">
@@ -15067,6 +14652,126 @@ ${processedContent.trim()}
15067
14652
  showError(state, `Error executing //${command.name}: ${error instanceof Error ? error.message : String(error)}`);
15068
14653
  }
15069
14654
  }
14655
+ function evaluationToJudgeResult(payload) {
14656
+ const decision = payload.passed ? "done" : payload.status === "paused" ? "paused" : "continue";
14657
+ return { decision, reason: payload.reason ?? "" };
14658
+ }
14659
+ var JUDGE_COLOR = mastraBrand.blue;
14660
+ var MUTED_COLOR = "#8a8a8a";
14661
+ var PAUSED_COLOR = "#f5a524";
14662
+ var WAITING_COLOR = "#8a8a8a";
14663
+ var JudgeDisplayComponent = class extends Container {
14664
+ result;
14665
+ turnsUsed;
14666
+ maxTurns;
14667
+ activity = [];
14668
+ constructor(result = null, turnsUsed = 0, maxTurns = 0) {
14669
+ super();
14670
+ this.result = result;
14671
+ this.turnsUsed = turnsUsed;
14672
+ this.maxTurns = maxTurns;
14673
+ this.renderContent();
14674
+ }
14675
+ addActivity(line) {
14676
+ if (this.activity[this.activity.length - 1] !== line) {
14677
+ this.activity.push(line);
14678
+ }
14679
+ if (this.activity.length > 6) {
14680
+ this.activity = this.activity.slice(-6);
14681
+ }
14682
+ this.renderContent();
14683
+ }
14684
+ setResult(result, turnsUsed, maxTurns) {
14685
+ this.result = result;
14686
+ this.turnsUsed = turnsUsed;
14687
+ this.maxTurns = maxTurns;
14688
+ this.renderContent();
14689
+ }
14690
+ /** Render the result of an in-loop goal evaluation chunk. */
14691
+ setEvaluation(payload) {
14692
+ this.setResult(evaluationToJudgeResult(payload), payload.iteration, payload.maxRuns);
14693
+ }
14694
+ setInterrupted() {
14695
+ this.setResult({ decision: "paused", reason: "Judge evaluation was interrupted." }, this.turnsUsed, this.maxTurns);
14696
+ }
14697
+ renderContent() {
14698
+ this.clear();
14699
+ const border = (char) => chalk12.hex(JUDGE_COLOR)(char);
14700
+ const title = chalk12.hex(JUDGE_COLOR).bold("Goal");
14701
+ const termWidth = getTermWidth();
14702
+ const innerWidth = Math.max(20, termWidth - BOX_INDENT * 2 - 4);
14703
+ const horizontal = "\u2500".repeat(innerWidth + 1);
14704
+ this.addChild(new Text(`${border("\u256D")}${border(horizontal)}${border("\u256E")}`, BOX_INDENT, 0));
14705
+ this.addChild(new Text(this.renderRow(this.renderHeader(title), innerWidth, border), BOX_INDENT, 0));
14706
+ if (!this.result && this.activity.length === 0) {
14707
+ this.addChild(new Text(this.renderRow(chalk12.dim("evaluating\u2026"), innerWidth, border), BOX_INDENT, 0));
14708
+ }
14709
+ for (const line of this.activity) {
14710
+ this.addChild(new Text(this.renderRow(this.renderActivityLine(line), innerWidth, border), BOX_INDENT, 0));
14711
+ }
14712
+ if (this.activity.length > 0 && this.result) {
14713
+ this.addChild(new Text(this.renderRow("", innerWidth, border), BOX_INDENT, 0));
14714
+ }
14715
+ if (this.result) {
14716
+ for (const line of this.wrapLine(this.result.reason, innerWidth)) {
14717
+ this.addChild(new Text(this.renderRow(chalk12.dim(line), innerWidth, border), BOX_INDENT, 0));
14718
+ }
14719
+ }
14720
+ this.addChild(new Text(`${border("\u2570")}${border(horizontal)}${border("\u256F")}`, BOX_INDENT, 0));
14721
+ }
14722
+ renderActivityLine(line) {
14723
+ const toolName = getActivityToolName(line);
14724
+ if (!toolName) return theme.fg("dim", `\u2022 ${line}`);
14725
+ const rest = line.slice(toolName.length);
14726
+ return `${theme.fg("dim", "\u2022 ")}${theme.fg("dim", theme.italic(toolName))}${theme.fg("dim", rest)}`;
14727
+ }
14728
+ renderHeader(title) {
14729
+ if (!this.result) {
14730
+ return `${title} \u25CC ${chalk12.hex(WAITING_COLOR).bold("evaluating")}`;
14731
+ }
14732
+ const decisionIcon = this.result.decision === "done" ? "\u25CF" : this.result.decision === "paused" ? "!" : this.result.decision === "waiting" ? "\u25CC" : "\u25CB";
14733
+ const decisionText = getDecisionText(this.result.decision);
14734
+ const turnInfo = this.maxTurns > 0 ? chalk12.hex(MUTED_COLOR)(`(${this.turnsUsed}/${this.maxTurns})`) : "";
14735
+ return `${title} ${decisionIcon} ${decisionText}${turnInfo ? ` ${turnInfo}` : ""}`;
14736
+ }
14737
+ renderRow(text, width, border) {
14738
+ const content = this.padLine(text, width);
14739
+ return `${border("\u2502")} ${content}${border("\u2502")}`;
14740
+ }
14741
+ wrapLine(text, width) {
14742
+ const lines = [];
14743
+ let remaining = text;
14744
+ while (remaining.length > width) {
14745
+ const breakAt = remaining.lastIndexOf(" ", width);
14746
+ const splitAt = breakAt > 0 ? breakAt : width;
14747
+ lines.push(remaining.slice(0, splitAt));
14748
+ remaining = remaining.slice(splitAt).trimStart();
14749
+ }
14750
+ lines.push(remaining);
14751
+ return lines;
14752
+ }
14753
+ padLine(text, width) {
14754
+ const visibleLength = stripAnsi(text).length;
14755
+ if (visibleLength >= width) {
14756
+ return stripAnsi(text).slice(0, width);
14757
+ }
14758
+ return text + " ".repeat(width - visibleLength);
14759
+ }
14760
+ getChatSpacingKind() {
14761
+ return "other";
14762
+ }
14763
+ };
14764
+ function getActivityToolName(line) {
14765
+ if (line.startsWith("find files ")) return "find files";
14766
+ const [toolName] = line.split(" ");
14767
+ return toolName || null;
14768
+ }
14769
+ function getDecisionText(decision) {
14770
+ if (decision === "done") return chalk12.hex("#16c858").bold("done");
14771
+ if (decision === "paused") return chalk12.hex(PAUSED_COLOR).bold("paused");
14772
+ if (decision === "waiting") return chalk12.hex(WAITING_COLOR).bold("waiting");
14773
+ return chalk12.hex(JUDGE_COLOR).bold("continue");
14774
+ }
15070
14775
 
15071
14776
  // src/tui/prune-chat.ts
15072
14777
  var MAX_CHILDREN = 5e3;
@@ -15114,6 +14819,7 @@ function handleAgentStart(ctx) {
15114
14819
  }
15115
14820
  function handleAgentEnd(ctx) {
15116
14821
  const { state } = ctx;
14822
+ state.goalManager.stopActiveTimer();
15117
14823
  if (state.gradientAnimator) {
15118
14824
  state.gradientAnimator.fadeOut();
15119
14825
  }
@@ -15134,10 +14840,7 @@ function handleAgentEnd(ctx) {
15134
14840
  ctx.updateStatusLine();
15135
14841
  state.ui.requestRender();
15136
14842
  ctx.notify("agent_done");
15137
- if (drainQueuedAction(ctx)) {
15138
- return;
15139
- }
15140
- maybeGoalContinuation(ctx);
14843
+ drainQueuedAction(ctx);
15141
14844
  }
15142
14845
  function drainQueuedAction(ctx) {
15143
14846
  const { state } = ctx;
@@ -15203,8 +14906,7 @@ function handleAgentAborted(ctx) {
15203
14906
  state.streamingComponent = void 0;
15204
14907
  state.streamingMessage = void 0;
15205
14908
  } else if (state.userInitiatedAbort) {
15206
- state.chatContainer.addChild(new Text(theme.fg("error", "Interrupted"), BOX_INDENT, 0));
15207
- state.chatContainer.addChild(new Spacer(1));
14909
+ showError(state, "Interrupted");
15208
14910
  }
15209
14911
  state.userInitiatedAbort = false;
15210
14912
  if (state.activeGoalJudge) {
@@ -15250,117 +14952,46 @@ function handleAgentError(ctx) {
15250
14952
  state.ui.requestRender();
15251
14953
  }
15252
14954
  function removeJudgeComponent(state, component) {
15253
- const children = state.chatContainer.children;
15254
- const index = children.indexOf(component);
15255
- if (index >= 0) {
15256
- children.splice(index, 1);
15257
- state.chatContainer.invalidate?.();
14955
+ if (state.chatContainer.children.includes(component)) {
14956
+ state.chatContainer.removeChild(component);
15258
14957
  }
15259
14958
  }
15260
- function maybeGoalContinuation(ctx) {
14959
+ function handleGoalEvaluation(ctx, payload) {
15261
14960
  const { state } = ctx;
15262
- if (!state.goalManager.isActive()) return;
15263
- const goal = state.goalManager.getGoal();
15264
- if (!goal) return;
15265
- const evaluatedGoalId = goal.id;
15266
- if (!state.gradientAnimator) {
15267
- state.gradientAnimator = new GradientAnimator(() => {
15268
- ctx.updateStatusLine();
15269
- });
14961
+ let activeGoalJudge = state.activeGoalJudge;
14962
+ if (!activeGoalJudge) {
14963
+ const goal = state.goalManager.getGoal();
14964
+ const component = new JudgeDisplayComponent(null, payload.iteration, payload.maxRuns);
14965
+ activeGoalJudge = {
14966
+ modelId: goal?.judgeModelId ?? "",
14967
+ abortController: new AbortController(),
14968
+ component
14969
+ };
14970
+ state.activeGoalJudge = activeGoalJudge;
14971
+ insertChatComponentWithBoundarySpacing(state.chatContainer, component);
15270
14972
  }
15271
- const abortController = new AbortController();
15272
- const judgeComponent = new JudgeDisplayComponent(null, goal.turnsUsed, goal.maxTurns);
15273
- const activeGoalJudge = { modelId: goal.judgeModelId, abortController, component: judgeComponent };
15274
- state.activeGoalJudge = activeGoalJudge;
15275
- state.chatContainer.addChild(judgeComponent);
15276
- state.gradientAnimator.start();
14973
+ activeGoalJudge.component.setEvaluation(payload);
14974
+ state.goalManager.applyEvaluation({ runsUsed: payload.iteration, status: payload.status });
15277
14975
  ctx.updateStatusLine();
15278
14976
  state.ui.requestRender();
15279
- state.goalManager.evaluateAfterTurn(state, {
15280
- abortSignal: abortController.signal,
15281
- onActivity: (line) => {
15282
- if (state.activeGoalJudge === activeGoalJudge) {
15283
- judgeComponent.addActivity(line);
15284
- state.ui.requestRender();
15285
- }
15286
- }
15287
- }).then(async ({ continuation, judgeResult }) => {
15288
- if (state.activeGoalJudge !== activeGoalJudge) {
15289
- return;
15290
- }
15291
- const currentGoal = state.goalManager.getGoal();
15292
- if (!currentGoal || currentGoal.id !== evaluatedGoalId) {
15293
- removeJudgeComponent(state, judgeComponent);
15294
- return;
15295
- }
15296
- if (judgeResult) {
15297
- judgeComponent.setResult(judgeResult, currentGoal.turnsUsed, currentGoal.maxTurns);
15298
- state.ui.requestRender();
15299
- }
15300
- if (abortController.signal.aborted) {
15301
- state.userInitiatedAbort = false;
15302
- return;
15303
- }
15304
- if (continuation) {
15305
- if (currentGoal.status !== "active") {
15306
- return;
15307
- }
15308
- if (drainQueuedAction(ctx)) {
15309
- return;
15310
- }
15311
- try {
15312
- await state.harness.sendSignal({
15313
- type: "system-reminder",
15314
- contents: continuation,
15315
- attributes: { type: "goal-judge" },
15316
- metadata: {
15317
- goalId: currentGoal.id,
15318
- turnsUsed: currentGoal.turnsUsed,
15319
- maxTurns: currentGoal.maxTurns,
15320
- judgeModelId: currentGoal.judgeModelId
15321
- }
15322
- }).accepted;
15323
- } catch (error) {
15324
- ctx.showError(`Failed to send goal continuation: ${error instanceof Error ? error.message : String(error)}`);
15325
- }
15326
- } else {
15327
- if (judgeResult) {
15328
- const harness = state.harness;
15329
- await harness.saveSystemReminderMessage?.({
15330
- reminderType: "goal-judge",
15331
- message: `${judgeResult.decision} (${currentGoal.turnsUsed}/${currentGoal.maxTurns})
15332
- ${judgeResult.reason}`
15333
- });
15334
- }
15335
- if (currentGoal.status === "paused") {
15336
- showInfo(
15337
- state,
15338
- `Goal paused (attempt ${currentGoal.turnsUsed}/${currentGoal.maxTurns}). Use /goal resume to continue.`
15339
- );
15340
- }
15341
- if (judgeResult?.decision === "done" && currentGoal.id === state.planStartedGoalId) {
15342
- const goalId = state.planStartedGoalId;
15343
- state.planStartedGoalId = void 0;
15344
- try {
15345
- await state.harness.switchMode({ modeId: "plan" });
15346
- } catch (error) {
15347
- ctx.showError(`Failed to switch to Plan mode: ${error instanceof Error ? error.message : String(error)}`);
15348
- state.planStartedGoalId = goalId;
15349
- }
15350
- }
15351
- }
15352
- }).catch(() => {
15353
- }).finally(() => {
15354
- if (state.activeGoalJudge === activeGoalJudge) {
15355
- state.activeGoalJudge = void 0;
14977
+ if (payload.status !== "active") {
14978
+ state.activeGoalJudge = void 0;
14979
+ }
14980
+ if (payload.status === "done") {
14981
+ const goal = state.goalManager.getGoal();
14982
+ if (goal && goal.id === state.planStartedGoalId) {
14983
+ const goalId = state.planStartedGoalId;
14984
+ state.planStartedGoalId = void 0;
14985
+ state.harness.switchMode({ modeId: "plan" }).catch((error) => {
14986
+ ctx.showError(`Failed to switch to Plan mode: ${error instanceof Error ? error.message : String(error)}`);
14987
+ state.planStartedGoalId = goalId;
14988
+ });
15356
14989
  }
15357
- state.gradientAnimator?.fadeOut();
15358
- ctx.updateStatusLine();
15359
- state.ui.requestRender();
15360
- });
14990
+ }
15361
14991
  }
15362
14992
  function getCurrentModeColor4(ctx) {
15363
- return ctx.state.harness.getCurrentMode?.()?.color;
14993
+ const color = ctx.state.harness.getCurrentMode?.()?.metadata?.color;
14994
+ return typeof color === "string" ? color : void 0;
15364
14995
  }
15365
14996
  function getTrailingContentParts(message) {
15366
14997
  let lastToolIndex = -1;
@@ -15377,6 +15008,7 @@ function getTrailingContentParts(message) {
15377
15008
  return message.content.slice(lastToolIndex + 1);
15378
15009
  }
15379
15010
  var HIDDEN_REACTIVE_SIGNAL_TAGS2 = /* @__PURE__ */ new Set(["github-subscribe-pr", "github-unsubscribe-pr"]);
15011
+ var GOAL_STATE_SIGNAL_ID2 = "goal";
15380
15012
  function shouldRenderReactiveSignal2(tagName) {
15381
15013
  return !HIDDEN_REACTIVE_SIGNAL_TAGS2.has(tagName);
15382
15014
  }
@@ -15585,7 +15217,7 @@ function handleMessageUpdate(ctx, message) {
15585
15217
  const notificationSummaryParts = message.content.map(toStreamedNotificationSummaryPart).filter((part) => part !== void 0);
15586
15218
  const notificationParts = message.content.map(toStreamedNotificationPart).filter((part) => part !== void 0);
15587
15219
  for (const stateSignal of stateSignalParts) {
15588
- if (stateSignal.stateId === TASKS_STATE_ID) continue;
15220
+ if (stateSignal.stateId === TASKS_STATE_ID || stateSignal.stateId === GOAL_STATE_SIGNAL_ID2) continue;
15589
15221
  const stateSignalKey = `state:${message.id}:${stateSignal.cacheKey ?? ""}:${stateSignal.stateId}:${stateSignal.mode}:${stateSignal.version ?? ""}:${stateSignal.message ?? ""}`;
15590
15222
  if (!state.currentRunSystemReminderKeys.has(stateSignalKey)) {
15591
15223
  state.currentRunSystemReminderKeys.add(stateSignalKey);
@@ -15744,23 +15376,23 @@ function getInsertIndexBeforeStreaming(ctx) {
15744
15376
  }
15745
15377
  function addChildBeforeStreaming(ctx, child) {
15746
15378
  const insertIndex = getInsertIndexBeforeStreaming(ctx);
15747
- if (insertIndex < ctx.state.chatContainer.children.length) {
15748
- ctx.state.chatContainer.children.splice(insertIndex, 0, child);
15749
- ctx.state.chatContainer.invalidate();
15750
- return;
15751
- }
15752
- ctx.state.chatContainer.addChild(child);
15379
+ insertChatComponentWithBoundarySpacing(ctx.state.chatContainer, child, insertIndex);
15753
15380
  }
15754
15381
  function isImmediatelyBeforeStreamingInsert(ctx, child) {
15755
15382
  const insertIndex = getInsertIndexBeforeStreaming(ctx);
15756
- return insertIndex > 0 && ctx.state.chatContainer.children[insertIndex - 1] === child;
15383
+ for (let i = insertIndex - 1; i >= 0; i--) {
15384
+ if (!isChatBoundarySpacer(ctx.state.chatContainer.children[i])) {
15385
+ return ctx.state.chatContainer.children[i] === child;
15386
+ }
15387
+ }
15388
+ return false;
15757
15389
  }
15758
15390
  function removeChatChild(ctx, child) {
15759
15391
  if (!child) return;
15760
15392
  const idx = ctx.state.chatContainer.children.indexOf(child);
15761
15393
  if (idx >= 0) {
15762
15394
  ctx.state.chatContainer.children.splice(idx, 1);
15763
- ctx.state.chatContainer.invalidate();
15395
+ reconcileChatBoundarySpacers(ctx.state.chatContainer);
15764
15396
  }
15765
15397
  }
15766
15398
  function handleOMObservationStart(ctx, cycleId, tokensToObserve) {
@@ -16552,12 +16184,12 @@ var CustomEditor = class extends Editor {
16552
16184
  const promptBrightness = isPromptAnimated ? Math.max(chevronBrightness, dotBrightness) : 1;
16553
16185
  if (this._cachedModeColorHex !== color) {
16554
16186
  this._cachedModeColorHex = color;
16555
- this._cachedColorFn = chalk14.hex(color);
16187
+ this._cachedColorFn = chalk12.hex(color);
16556
16188
  }
16557
16189
  const colorFn = this._cachedColorFn;
16558
16190
  const b = colorFn;
16559
16191
  const [r, g, bValue] = parseHex(color);
16560
- const prompt = chalk14.bold.rgb(
16192
+ const prompt = chalk12.bold.rgb(
16561
16193
  Math.round(r * promptBrightness),
16562
16194
  Math.round(g * promptBrightness),
16563
16195
  Math.round(bValue * promptBrightness)
@@ -16988,7 +16620,8 @@ function createTUIState(options) {
16988
16620
  if (result.activeGoalJudge) {
16989
16621
  return mastra.blue;
16990
16622
  }
16991
- return options.harness.getCurrentMode()?.color;
16623
+ const color = options.harness.getCurrentMode()?.metadata?.color;
16624
+ return typeof color === "string" ? color : void 0;
16992
16625
  };
16993
16626
  return result;
16994
16627
  }
@@ -17091,7 +16724,10 @@ async function dispatchEvent(event, ectx, state) {
17091
16724
  state.activeGithubPrSubscriptions = getGithubPrSubscriptionsFromMetadata(metadata);
17092
16725
  state.githubPrPollingActive = false;
17093
16726
  state.githubPrGradientAnimator?.stop();
17094
- state.goalManager?.loadFromThreadMetadata(metadata);
16727
+ await state.goalManager.loadFromThread(state);
16728
+ if (!state.goalManager.getGoal()) {
16729
+ state.goalManager.loadFromThreadMetadata(metadata);
16730
+ }
17095
16731
  }
17096
16732
  break;
17097
16733
  }
@@ -17237,6 +16873,10 @@ async function dispatchEvent(event, ectx, state) {
17237
16873
  }
17238
16874
  break;
17239
16875
  }
16876
+ case "goal_evaluation": {
16877
+ handleGoalEvaluation(ectx, event.payload);
16878
+ break;
16879
+ }
17240
16880
  case "tool_suspended": {
17241
16881
  const payload = event.suspendPayload ?? {};
17242
16882
  if (event.toolName === "request_access" || payload.kind === "sandbox_access_request") {
@@ -17399,7 +17039,7 @@ function gradientChar(ch, colIdx, totalCols) {
17399
17039
  const segment = Math.min(Math.floor(t * segmentCount), segmentCount - 1);
17400
17040
  const frac = t * segmentCount - segment;
17401
17041
  const [r, g, b] = lerpColor(GRADIENT_STOPS[segment], GRADIENT_STOPS[segment + 1], frac);
17402
- return chalk14.rgb(r, g, b)(ch);
17042
+ return chalk12.rgb(r, g, b)(ch);
17403
17043
  }
17404
17044
  function colorLine(line) {
17405
17045
  const chars = [...line];
@@ -17550,7 +17190,7 @@ var TaskProgressComponent = class extends Container {
17550
17190
  switch (task.status) {
17551
17191
  case "completed": {
17552
17192
  const icon = theme.fg("dim", "\u2713");
17553
- const text = chalk14.strikethrough(theme.fg("dim", task.content));
17193
+ const text = chalk12.strikethrough(theme.fg("dim", task.content));
17554
17194
  return `${icon} ${text}`;
17555
17195
  }
17556
17196
  case "in_progress": {
@@ -17570,7 +17210,7 @@ var TaskProgressComponent = class extends Container {
17570
17210
  switch (task.status) {
17571
17211
  case "completed": {
17572
17212
  const icon = theme.fg("success", "\u2713");
17573
- const text = chalk14.hex(theme.getTheme().success).strikethrough(task.content);
17213
+ const text = chalk12.hex(theme.getTheme().success).strikethrough(task.content);
17574
17214
  return `${indent}${icon} ${text}`;
17575
17215
  }
17576
17216
  case "in_progress": {
@@ -17731,6 +17371,9 @@ function abortActiveGoalJudge(state) {
17731
17371
  state.userInitiatedAbort = true;
17732
17372
  activeGoalJudge.abortController.abort();
17733
17373
  activeGoalJudge.component.setInterrupted();
17374
+ state.goalManager.pause();
17375
+ void state.goalManager.saveToThread(state);
17376
+ state.activeGoalJudge = void 0;
17734
17377
  state.ui.requestRender();
17735
17378
  return true;
17736
17379
  }
@@ -17855,10 +17498,10 @@ function setupAutocomplete(state) {
17855
17498
  { value: "status", label: "status", description: "Show current goal status" },
17856
17499
  { value: "pause", label: "pause", description: "Pause the goal continuation loop" },
17857
17500
  { value: "resume", label: "resume", description: "Resume the current goal" },
17858
- { value: "clear", label: "clear", description: "Clear the current goal" }
17501
+ { value: "clear", label: "clear", description: "Clear the current goal" },
17502
+ { value: "judge", label: "judge", description: "Set the goal judge model and max attempts" }
17859
17503
  ].filter((command) => command.value.startsWith(argumentPrefix.toLowerCase()))
17860
17504
  },
17861
- { name: "judge", description: "Set goal judge defaults" },
17862
17505
  { name: "exit", description: "Exit the TUI" },
17863
17506
  { name: "help", description: "Show available commands" }
17864
17507
  ];
@@ -18087,7 +17730,6 @@ var ShellStreamComponent = class extends Container {
18087
17730
  }
18088
17731
  rebuild() {
18089
17732
  this.clear();
18090
- this.addChild(new Spacer(1));
18091
17733
  const border = (char) => theme.bold(theme.fg("accent", char));
18092
17734
  const termWidth = getTermWidth();
18093
17735
  const maxLineWidth = termWidth - 6;
@@ -18125,6 +17767,9 @@ var ShellStreamComponent = class extends Container {
18125
17767
  }
18126
17768
  this.invalidate();
18127
17769
  }
17770
+ getChatSpacingKind() {
17771
+ return "other";
17772
+ }
18128
17773
  };
18129
17774
 
18130
17775
  // src/tui/shell-result.ts
@@ -18188,7 +17833,7 @@ async function handleShellPassthrough(state, command) {
18188
17833
  component.setExpanded(true);
18189
17834
  }
18190
17835
  state.allShellComponents.push(component);
18191
- state.chatContainer.addChild(component);
17836
+ insertChatComponentWithBoundarySpacing(state.chatContainer, component);
18192
17837
  state.ui.requestRender();
18193
17838
  try {
18194
17839
  const { invocation, subprocess } = await createShellPassthroughSubprocess(command, loadSettings().shellPassthrough);
@@ -18242,7 +17887,10 @@ async function syncInitialThreadState(state) {
18242
17887
  }
18243
17888
  const metadata = initThread?.metadata;
18244
17889
  state.activeGithubPrSubscriptions = getGithubPrSubscriptionsFromMetadata(metadata);
18245
- state.goalManager.loadFromThreadMetadata(metadata);
17890
+ await state.goalManager.loadFromThread(state);
17891
+ if (!state.goalManager.getGoal()) {
17892
+ state.goalManager.loadFromThreadMetadata(metadata);
17893
+ }
18246
17894
  }
18247
17895
  function shouldUseCaffeinate() {
18248
17896
  return process.platform === "darwin" && process.env.MASTRACODE_DISABLE_CAFFEINATE !== "1";
@@ -19129,7 +18777,7 @@ var MastraTUI = class _MastraTUI {
19129
18777
  onSelectModel: async (title, modeColor) => {
19130
18778
  const availableModels = await this.state.harness.listAvailableModels();
19131
18779
  if (availableModels.length === 0) return void 0;
19132
- return new Promise((resolveModel2) => {
18780
+ return new Promise((resolveModel) => {
19133
18781
  const selector = new ModelSelectorComponent({
19134
18782
  tui: this.state.ui,
19135
18783
  models: availableModels,
@@ -19139,11 +18787,11 @@ var MastraTUI = class _MastraTUI {
19139
18787
  onSelect: async (model) => {
19140
18788
  this.state.ui.hideOverlay();
19141
18789
  await promptForApiKeyIfNeeded(this.state.ui, model, this.state.authStorage);
19142
- resolveModel2(model.id);
18790
+ resolveModel(model.id);
19143
18791
  },
19144
18792
  onCancel: () => {
19145
18793
  this.state.ui.hideOverlay();
19146
- resolveModel2(void 0);
18794
+ resolveModel(void 0);
19147
18795
  }
19148
18796
  });
19149
18797
  showModalOverlay(this.state.ui, selector, { maxHeight: "75%" });
@@ -19245,7 +18893,8 @@ var MastraTUI = class _MastraTUI {
19245
18893
  const tools = this.state.allToolComponents.filter(
19246
18894
  (tool) => typeof tool.setQuietModeDisplay === "function"
19247
18895
  );
19248
- const modeColor = this.state.harness?.getCurrentMode?.()?.color;
18896
+ const color = this.state.harness?.getCurrentMode?.()?.metadata?.color;
18897
+ const modeColor = typeof color === "string" ? color : void 0;
19249
18898
  for (const tool of tools) {
19250
18899
  tool.setCompactToolModeColor?.(modeColor);
19251
18900
  tool.setQuietModeDisplay?.(enabled ? "quiet" : "normal");
@@ -19363,7 +19012,7 @@ Would you like to update now?`;
19363
19012
  },
19364
19013
  this.state.ui
19365
19014
  );
19366
- this.state.chatContainer.addChild(component);
19015
+ insertChatComponentWithBoundarySpacing(this.state.chatContainer, component);
19367
19016
  this.state.activeInlineQuestion = component;
19368
19017
  component.focused = true;
19369
19018
  this.state.ui.requestRender();
@@ -19391,5 +19040,5 @@ Would you like to update now?`;
19391
19040
  };
19392
19041
 
19393
19042
  export { AssistantMessageComponent, LoginDialogComponent, LoginSelectorComponent, MastraTUI, ModelSelectorComponent, OMProgressComponent, ToolExecutionComponentEnhanced, UserMessageComponent, createTUIState, detectTerminalTheme, formatOMStatus, getCurrentVersion };
19394
- //# sourceMappingURL=chunk-OXYE6SUY.js.map
19395
- //# sourceMappingURL=chunk-OXYE6SUY.js.map
19043
+ //# sourceMappingURL=chunk-GKGPZBID.js.map
19044
+ //# sourceMappingURL=chunk-GKGPZBID.js.map