mastracode 0.3.0 → 0.4.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.
- package/CHANGELOG.md +132 -0
- package/README.md +60 -12
- package/dist/agents/instructions.d.ts.map +1 -1
- package/dist/agents/model.d.ts +4 -1
- package/dist/agents/model.d.ts.map +1 -1
- package/dist/auth/claude-max-warning.d.ts +9 -0
- package/dist/auth/claude-max-warning.d.ts.map +1 -0
- package/dist/{chunk-7TFV3VBB.cjs → chunk-C4X3C2DL.cjs} +1091 -607
- package/dist/chunk-C4X3C2DL.cjs.map +1 -0
- package/dist/{chunk-7K5VFY2N.cjs → chunk-K4WJUBEC.cjs} +151 -48
- package/dist/chunk-K4WJUBEC.cjs.map +1 -0
- package/dist/{chunk-HHX6BKLR.js → chunk-M5LKPQB4.js} +12 -11
- package/dist/chunk-M5LKPQB4.js.map +1 -0
- package/dist/{chunk-V4HZ2AVV.js → chunk-REVOTI2T.js} +143 -38
- package/dist/chunk-REVOTI2T.js.map +1 -0
- package/dist/{chunk-C6XKRHRK.cjs → chunk-S5ZLN7DR.cjs} +6 -2
- package/dist/chunk-S5ZLN7DR.cjs.map +1 -0
- package/dist/{chunk-VRZZSUQE.js → chunk-SM3QCOA7.js} +6 -3
- package/dist/chunk-SM3QCOA7.js.map +1 -0
- package/dist/{chunk-LYETHS2L.js → chunk-X3BGE7CL.js} +877 -394
- package/dist/chunk-X3BGE7CL.js.map +1 -0
- package/dist/{chunk-VZFPT5N7.cjs → chunk-Z4QRXVST.cjs} +62 -61
- package/dist/chunk-Z4QRXVST.cjs.map +1 -0
- package/dist/cli.cjs +20 -10
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +14 -4
- package/dist/cli.js.map +1 -1
- package/dist/docs/SKILL.md +30 -0
- package/dist/docs/assets/SOURCE_MAP.json +11 -0
- package/dist/docs/references/docs-mastra-code-configuration.md +299 -0
- package/dist/docs/references/docs-mastra-code-customization.md +228 -0
- package/dist/docs/references/docs-mastra-code-modes.md +104 -0
- package/dist/docs/references/docs-mastra-code-overview.md +135 -0
- package/dist/docs/references/docs-mastra-code-tools.md +229 -0
- package/dist/docs/references/reference-mastra-code-createMastraCode.md +108 -0
- package/dist/index.cjs +2 -2
- package/dist/index.js +1 -1
- package/dist/onboarding/onboarding-inline.d.ts +5 -0
- package/dist/onboarding/onboarding-inline.d.ts.map +1 -1
- package/dist/onboarding/settings.d.ts +3 -0
- package/dist/onboarding/settings.d.ts.map +1 -1
- package/dist/providers/openai-codex.d.ts +5 -1
- package/dist/providers/openai-codex.d.ts.map +1 -1
- package/dist/schema.d.ts +7 -1
- package/dist/schema.d.ts.map +1 -1
- package/dist/storage-PO4VN5NF.cjs +24 -0
- package/dist/{storage-JFFX7LJJ.cjs.map → storage-PO4VN5NF.cjs.map} +1 -1
- package/dist/storage-PQOHJLBI.js +3 -0
- package/dist/{storage-52Y5MKTG.js.map → storage-PQOHJLBI.js.map} +1 -1
- package/dist/tui/claude-max-warning.d.ts +18 -0
- package/dist/tui/claude-max-warning.d.ts.map +1 -0
- package/dist/tui/command-dispatch.d.ts.map +1 -1
- package/dist/tui/commands/index.d.ts +1 -0
- package/dist/tui/commands/index.d.ts.map +1 -1
- package/dist/tui/commands/login.d.ts.map +1 -1
- package/dist/tui/commands/models-pack.d.ts.map +1 -1
- package/dist/tui/commands/settings.d.ts.map +1 -1
- package/dist/tui/commands/skills.d.ts.map +1 -1
- package/dist/tui/commands/theme.d.ts +6 -0
- package/dist/tui/commands/theme.d.ts.map +1 -0
- package/dist/tui/commands/think.d.ts +1 -1
- package/dist/tui/commands/think.d.ts.map +1 -1
- package/dist/tui/components/banner.d.ts.map +1 -1
- package/dist/tui/components/diff-output.d.ts.map +1 -1
- package/dist/tui/components/help-overlay.d.ts.map +1 -1
- package/dist/tui/components/obi-loader.d.ts.map +1 -1
- package/dist/tui/components/settings.d.ts +1 -0
- package/dist/tui/components/settings.d.ts.map +1 -1
- package/dist/tui/components/shell-output.d.ts.map +1 -1
- package/dist/tui/components/task-progress.d.ts.map +1 -1
- package/dist/tui/components/thinking-settings.d.ts +11 -22
- package/dist/tui/components/thinking-settings.d.ts.map +1 -1
- package/dist/tui/components/tool-execution-enhanced.d.ts.map +1 -1
- package/dist/tui/detect-theme.d.ts +17 -0
- package/dist/tui/detect-theme.d.ts.map +1 -0
- package/dist/tui/event-dispatch.d.ts.map +1 -1
- package/dist/tui/handlers/agent-lifecycle.d.ts.map +1 -1
- package/dist/tui/index.d.ts +2 -2
- package/dist/tui/index.d.ts.map +1 -1
- package/dist/tui/mastra-tui.d.ts +8 -0
- package/dist/tui/mastra-tui.d.ts.map +1 -1
- package/dist/tui/render-messages.d.ts.map +1 -1
- package/dist/tui/setup.d.ts.map +1 -1
- package/dist/tui/status-line.d.ts.map +1 -1
- package/dist/tui/theme.d.ts +33 -20
- package/dist/tui/theme.d.ts.map +1 -1
- package/dist/tui.cjs +27 -19
- package/dist/tui.js +2 -2
- package/dist/utils/project.d.ts +5 -0
- package/dist/utils/project.d.ts.map +1 -1
- package/dist/utils/slash-command-processor.d.ts.map +1 -1
- package/package.json +8 -8
- package/dist/chunk-7K5VFY2N.cjs.map +0 -1
- package/dist/chunk-7TFV3VBB.cjs.map +0 -1
- package/dist/chunk-C6XKRHRK.cjs.map +0 -1
- package/dist/chunk-HHX6BKLR.js.map +0 -1
- package/dist/chunk-LYETHS2L.js.map +0 -1
- package/dist/chunk-V4HZ2AVV.js.map +0 -1
- package/dist/chunk-VRZZSUQE.js.map +0 -1
- package/dist/chunk-VZFPT5N7.cjs.map +0 -1
- package/dist/storage-52Y5MKTG.js +0 -3
- package/dist/storage-JFFX7LJJ.cjs +0 -24
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getOAuthProviders, detectProject, getUserId, PROVIDER_DEFAULT_MODELS } from './chunk-
|
|
1
|
+
import { theme, mastra, getMarkdownTheme, getEditorTheme, loadSettings, saveSettings, getAvailableModePacks, getAvailableOmPacks, ONBOARDING_VERSION, ThreadLockError, parseSubagentMeta, tintHex, getSelectListTheme, getThemeMode, applyThemeMode, getSettingsListTheme } from './chunk-REVOTI2T.js';
|
|
2
|
+
import { getOAuthProviders, detectProject, getUserId, getCurrentGitBranch, PROVIDER_DEFAULT_MODELS } from './chunk-SM3QCOA7.js';
|
|
3
3
|
import { getToolCategory, TOOL_CATEGORIES } from './chunk-U5A7TFNT.js';
|
|
4
|
-
import { Box, Text, Spacer, Input, Container, fuzzyFilter, getEditorKeybindings, Markdown, ProcessTerminal, TUI, Editor, matchesKey, CombinedAutocompleteProvider, SelectList, visibleWidth, SettingsList } from '@mariozechner/pi-tui';
|
|
4
|
+
import { Box, Text, Spacer, Input, Container, fuzzyFilter, getEditorKeybindings, Markdown, ProcessTerminal, TUI, Editor, matchesKey, CombinedAutocompleteProvider, SelectList, visibleWidth, SettingsList, isKeyRelease } from '@mariozechner/pi-tui';
|
|
5
5
|
import chalk10 from 'chalk';
|
|
6
|
-
import { exec, execSync } from 'child_process';
|
|
6
|
+
import { exec, execFileSync, execSync } from 'child_process';
|
|
7
7
|
import fs2, { readFileSync, unlinkSync, promises } from 'fs';
|
|
8
8
|
import * as path4 from 'path';
|
|
9
9
|
import path4__default, { join } from 'path';
|
|
@@ -14,6 +14,9 @@ import { highlight } from 'cli-highlight';
|
|
|
14
14
|
import { parse } from 'partial-json';
|
|
15
15
|
import * as yaml from 'js-yaml';
|
|
16
16
|
|
|
17
|
+
// src/auth/claude-max-warning.ts
|
|
18
|
+
var ANTHROPIC_OAUTH_PROVIDER_ID = "anthropic";
|
|
19
|
+
var CLAUDE_MAX_OAUTH_WARNING_MESSAGE = "OAuth with a Claude Max plan is a grey area. Anthropic has reportedly banned users for using Claude max credentials outside of Claude Code, and it may violate Anthropic Terms of Service. Proceed at your own risk.";
|
|
17
20
|
var OnboardingInlineComponent = class extends Container {
|
|
18
21
|
tui;
|
|
19
22
|
options;
|
|
@@ -73,6 +76,10 @@ var OnboardingInlineComponent = class extends Container {
|
|
|
73
76
|
this.selectedOmPack = packs[0];
|
|
74
77
|
}
|
|
75
78
|
}
|
|
79
|
+
/** Update whether the user has any provider access (e.g. after a login). */
|
|
80
|
+
updateHasProviderAccess(hasAccess) {
|
|
81
|
+
this.options.hasProviderAccess = hasAccess;
|
|
82
|
+
}
|
|
76
83
|
// ---------------------------------------------------------------------------
|
|
77
84
|
// Rendering helpers
|
|
78
85
|
// ---------------------------------------------------------------------------
|
|
@@ -89,6 +96,8 @@ var OnboardingInlineComponent = class extends Container {
|
|
|
89
96
|
return this.renderWelcome();
|
|
90
97
|
case "auth":
|
|
91
98
|
return this.renderAuth();
|
|
99
|
+
case "claudeMaxWarning":
|
|
100
|
+
return this.renderClaudeMaxWarning();
|
|
92
101
|
case "modePack":
|
|
93
102
|
return this.renderModePack();
|
|
94
103
|
case "omPack":
|
|
@@ -115,14 +124,14 @@ var OnboardingInlineComponent = class extends Container {
|
|
|
115
124
|
// ---------------------------------------------------------------------------
|
|
116
125
|
renderWelcome() {
|
|
117
126
|
const box = this.makeBox();
|
|
118
|
-
box.addChild(new Text(bold(fg("accent", "\u{1F44B} Welcome to Mastra Code")), 0, 0));
|
|
127
|
+
box.addChild(new Text(theme.bold(theme.fg("accent", "\u{1F44B} Welcome to Mastra Code")), 0, 0));
|
|
119
128
|
box.addChild(new Spacer(1));
|
|
120
|
-
box.addChild(new Text(fg("text", "Let's configure your models and preferences."), 0, 0));
|
|
129
|
+
box.addChild(new Text(theme.fg("text", "Let's configure your models and preferences."), 0, 0));
|
|
121
130
|
box.addChild(new Text(chalk10.white("You can re-run this anytime with /setup."), 0, 0));
|
|
122
131
|
box.addChild(new Spacer(1));
|
|
123
132
|
const items = [
|
|
124
|
-
{ value: "continue", label: ` ${fg("success", "Continue")}` },
|
|
125
|
-
{ value: "skip", label: ` ${fg("dim", "Skip")}` }
|
|
133
|
+
{ value: "continue", label: ` ${theme.fg("success", "Continue")}` },
|
|
134
|
+
{ value: "skip", label: ` ${theme.fg("dim", "Skip")}` }
|
|
126
135
|
];
|
|
127
136
|
this.selectList = new SelectList(items, items.length, getSelectListTheme());
|
|
128
137
|
this.selectList.onSelect = (item) => {
|
|
@@ -147,25 +156,31 @@ var OnboardingInlineComponent = class extends Container {
|
|
|
147
156
|
// ---------------------------------------------------------------------------
|
|
148
157
|
renderAuth() {
|
|
149
158
|
const box = this.makeBox();
|
|
150
|
-
box.addChild(new Text(bold(fg("accent", "\u{1F511} Authentication")), 0, 0));
|
|
159
|
+
box.addChild(new Text(theme.bold(theme.fg("accent", "\u{1F511} Authentication")), 0, 0));
|
|
151
160
|
box.addChild(new Spacer(1));
|
|
152
161
|
const providers = this.options.authProviders;
|
|
153
162
|
if (providers.length === 0) {
|
|
154
|
-
box.addChild(new Text(fg("dim", "No OAuth providers available. Skipping."), 0, 0));
|
|
163
|
+
box.addChild(new Text(theme.fg("dim", "No OAuth providers available. Skipping."), 0, 0));
|
|
155
164
|
setTimeout(() => this.renderStep("modePack"), 100);
|
|
156
165
|
return;
|
|
157
166
|
}
|
|
158
|
-
box.addChild(new Text(fg("text", "Log in with an AI provider to use your subscription
|
|
167
|
+
box.addChild(new Text(theme.fg("text", "Log in with an AI provider to use your subscription,"), 0, 0));
|
|
168
|
+
box.addChild(new Text(theme.fg("text", "or skip if you have API keys configured as environment variables."), 0, 0));
|
|
159
169
|
box.addChild(new Spacer(1));
|
|
160
170
|
const items = providers.map((p) => ({
|
|
161
171
|
value: p.value,
|
|
162
|
-
label: p.loggedIn ? ` ${p.label} ${fg("success", "\u2713 logged in")}` : ` ${p.label}`
|
|
172
|
+
label: p.loggedIn ? ` ${p.label} ${theme.fg("success", "\u2713 logged in")}` : ` ${p.label}`
|
|
163
173
|
}));
|
|
164
|
-
items.push({
|
|
174
|
+
items.push({
|
|
175
|
+
value: "__skip",
|
|
176
|
+
label: ` ${theme.fg("dim", "Skip (use API keys or configure later with /login)")}`
|
|
177
|
+
});
|
|
165
178
|
this.selectList = new SelectList(items, Math.min(items.length, 8), getSelectListTheme());
|
|
166
179
|
this.selectList.onSelect = (item) => {
|
|
167
180
|
if (item.value === "__skip") {
|
|
168
181
|
this.renderStep("modePack");
|
|
182
|
+
} else if (item.value === ANTHROPIC_OAUTH_PROVIDER_ID) {
|
|
183
|
+
this.renderStep("claudeMaxWarning");
|
|
169
184
|
} else {
|
|
170
185
|
this.loginRequested = true;
|
|
171
186
|
this.loginProvider = item.value;
|
|
@@ -179,7 +194,39 @@ var OnboardingInlineComponent = class extends Container {
|
|
|
179
194
|
};
|
|
180
195
|
box.addChild(this.selectList);
|
|
181
196
|
box.addChild(new Spacer(1));
|
|
182
|
-
box.addChild(new Text(fg("dim", "\u2191\u2193 navigate \xB7 Enter select \xB7 Esc skip"), 0, 0));
|
|
197
|
+
box.addChild(new Text(theme.fg("dim", "\u2191\u2193 navigate \xB7 Enter select \xB7 Esc skip"), 0, 0));
|
|
198
|
+
}
|
|
199
|
+
// ---------------------------------------------------------------------------
|
|
200
|
+
// Step: Claude Max OAuth Warning
|
|
201
|
+
// ---------------------------------------------------------------------------
|
|
202
|
+
renderClaudeMaxWarning() {
|
|
203
|
+
const box = this.makeBox();
|
|
204
|
+
box.addChild(new Text(theme.bold(theme.fg("warning", "\u26A0 Claude Max OAuth Warning")), 0, 0));
|
|
205
|
+
box.addChild(new Spacer(1));
|
|
206
|
+
box.addChild(new Text(theme.fg("text", CLAUDE_MAX_OAUTH_WARNING_MESSAGE), 0, 0));
|
|
207
|
+
box.addChild(new Spacer(1));
|
|
208
|
+
const items = [
|
|
209
|
+
{ value: "continue", label: ` ${theme.fg("success", "Continue")}` },
|
|
210
|
+
{ value: "cancel", label: ` ${theme.fg("dim", "Cancel")}` }
|
|
211
|
+
];
|
|
212
|
+
this.selectList = new SelectList(items, items.length, getSelectListTheme());
|
|
213
|
+
this.selectList.onSelect = (item) => {
|
|
214
|
+
if (item.value === "continue") {
|
|
215
|
+
this.loginRequested = true;
|
|
216
|
+
this.loginProvider = ANTHROPIC_OAUTH_PROVIDER_ID;
|
|
217
|
+
this.options.onLogin(ANTHROPIC_OAUTH_PROVIDER_ID, () => {
|
|
218
|
+
this.renderStep("modePack");
|
|
219
|
+
});
|
|
220
|
+
} else {
|
|
221
|
+
this.renderStep("auth");
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
this.selectList.onCancel = () => {
|
|
225
|
+
this.renderStep("auth");
|
|
226
|
+
};
|
|
227
|
+
box.addChild(this.selectList);
|
|
228
|
+
box.addChild(new Spacer(1));
|
|
229
|
+
box.addChild(new Text(theme.fg("dim", "\u2191\u2193 navigate \xB7 Enter select \xB7 Esc go back"), 0, 0));
|
|
183
230
|
}
|
|
184
231
|
// ---------------------------------------------------------------------------
|
|
185
232
|
// Step: Mode pack
|
|
@@ -188,32 +235,33 @@ var OnboardingInlineComponent = class extends Container {
|
|
|
188
235
|
modePackDetail;
|
|
189
236
|
renderModePack() {
|
|
190
237
|
const packs = this.options.modePacks;
|
|
191
|
-
|
|
192
|
-
if (!hasProviderPack) {
|
|
238
|
+
if (!this.options.hasProviderAccess) {
|
|
193
239
|
const box2 = this.makeBox();
|
|
194
|
-
box2.addChild(new Text(bold(fg("error", "No model providers configured")), 0, 0));
|
|
240
|
+
box2.addChild(new Text(theme.bold(theme.fg("error", "No model providers configured")), 0, 0));
|
|
195
241
|
box2.addChild(new Spacer(1));
|
|
196
|
-
box2.addChild(new Text(fg("text", "To use Mastra Code you need at least one API key or OAuth login"), 0, 0));
|
|
197
|
-
box2.addChild(new Text(fg("text", "for Anthropic, OpenAI, or another supported provider."), 0, 0));
|
|
242
|
+
box2.addChild(new Text(theme.fg("text", "To use Mastra Code you need at least one API key or OAuth login"), 0, 0));
|
|
243
|
+
box2.addChild(new Text(theme.fg("text", "for Anthropic, OpenAI, or another supported provider."), 0, 0));
|
|
198
244
|
box2.addChild(new Spacer(1));
|
|
199
245
|
box2.addChild(
|
|
200
|
-
new Text(fg("dim", "See https://mastra.ai/
|
|
246
|
+
new Text(theme.fg("dim", "See https://mastra.ai/models for supported providers and API key env vars."), 0, 0)
|
|
201
247
|
);
|
|
202
248
|
box2.addChild(new Spacer(1));
|
|
203
|
-
box2.addChild(
|
|
249
|
+
box2.addChild(
|
|
250
|
+
new Text(theme.fg("dim", "Set an API key and restart, or run /login to authenticate via OAuth."), 0, 0)
|
|
251
|
+
);
|
|
204
252
|
this._finished = true;
|
|
205
253
|
setTimeout(() => process.exit(1), 3e3);
|
|
206
254
|
return;
|
|
207
255
|
}
|
|
208
256
|
const box = this.makeBox();
|
|
209
|
-
box.addChild(new Text(bold(fg("accent", "Model Packs")), 0, 0));
|
|
257
|
+
box.addChild(new Text(theme.bold(theme.fg("accent", "Model Packs")), 0, 0));
|
|
210
258
|
box.addChild(new Spacer(1));
|
|
211
|
-
box.addChild(new Text(fg("text", "Choose default models for each mode (build / plan / fast):"), 0, 0));
|
|
259
|
+
box.addChild(new Text(theme.fg("text", "Choose default models for each mode (build / plan / fast):"), 0, 0));
|
|
212
260
|
box.addChild(new Spacer(1));
|
|
213
261
|
const prevId = this.options.previous?.modePackId ?? null;
|
|
214
262
|
const items = packs.map((p) => ({
|
|
215
263
|
value: p.id,
|
|
216
|
-
label: ` ${p.name} ${fg("dim", p.description)}${p.id === prevId ? fg("dim", " (current)") : ""}`
|
|
264
|
+
label: ` ${p.name} ${theme.fg("dim", p.description)}${p.id === prevId ? theme.fg("dim", " (current)") : ""}`
|
|
217
265
|
}));
|
|
218
266
|
this.selectList = new SelectList(items, items.length, getSelectListTheme());
|
|
219
267
|
const prevIdx = prevId ? packs.findIndex((p) => p.id === prevId) : -1;
|
|
@@ -224,12 +272,12 @@ var OnboardingInlineComponent = class extends Container {
|
|
|
224
272
|
this.runCustomPackFlow();
|
|
225
273
|
} else {
|
|
226
274
|
this.selectedModePack = pack;
|
|
227
|
-
this.collapseStep(`Model pack \u2192 ${bold(this.selectedModePack.name)}`);
|
|
275
|
+
this.collapseStep(`Model pack \u2192 ${theme.bold(this.selectedModePack.name)}`);
|
|
228
276
|
this.renderStep("omPack");
|
|
229
277
|
}
|
|
230
278
|
};
|
|
231
279
|
this.selectList.onCancel = () => {
|
|
232
|
-
this.collapseStep(`Model pack \u2192 ${bold(this.selectedModePack.name)} (default)`);
|
|
280
|
+
this.collapseStep(`Model pack \u2192 ${theme.bold(this.selectedModePack.name)} (default)`);
|
|
233
281
|
this.renderStep("omPack");
|
|
234
282
|
};
|
|
235
283
|
this.selectList.onSelectionChange = (item) => {
|
|
@@ -242,18 +290,18 @@ var OnboardingInlineComponent = class extends Container {
|
|
|
242
290
|
const initialId = prevIdx > 0 ? packs[prevIdx].id : packs[0].id;
|
|
243
291
|
this.updateModePackDetail(packs, initialId);
|
|
244
292
|
box.addChild(new Spacer(1));
|
|
245
|
-
box.addChild(new Text(fg("dim", "\u2191\u2193 navigate \xB7 Enter select \xB7 Esc use default"), 0, 0));
|
|
293
|
+
box.addChild(new Text(theme.fg("dim", "\u2191\u2193 navigate \xB7 Enter select \xB7 Esc use default"), 0, 0));
|
|
246
294
|
}
|
|
247
295
|
updateModePackDetail(packs, highlightedId) {
|
|
248
296
|
const pack = packs.find((p) => p.id === highlightedId);
|
|
249
297
|
if (!pack || !this.modePackDetail) return;
|
|
250
298
|
if (pack.id === "custom") {
|
|
251
|
-
this.modePackDetail.setText(fg("dim", " You'll pick a model for each mode in the next steps."));
|
|
299
|
+
this.modePackDetail.setText(theme.fg("dim", " You'll pick a model for each mode in the next steps."));
|
|
252
300
|
} else {
|
|
253
301
|
const detail = [
|
|
254
|
-
` ${chalk10.hex(mastra.blue)("plan")} \u2192 ${fg("text", pack.models.plan)}`,
|
|
255
|
-
` ${chalk10.hex(mastra.purple)("build")} \u2192 ${fg("text", pack.models.build)}`,
|
|
256
|
-
` ${chalk10.hex(mastra.green)("fast")} \u2192 ${fg("text", pack.models.fast)}`
|
|
302
|
+
` ${chalk10.hex(mastra.blue)("plan")} \u2192 ${theme.fg("text", pack.models.plan)}`,
|
|
303
|
+
` ${chalk10.hex(mastra.purple)("build")} \u2192 ${theme.fg("text", pack.models.build)}`,
|
|
304
|
+
` ${chalk10.hex(mastra.green)("fast")} \u2192 ${theme.fg("text", pack.models.fast)}`
|
|
257
305
|
].join("\n");
|
|
258
306
|
this.modePackDetail.setText(detail);
|
|
259
307
|
}
|
|
@@ -277,7 +325,7 @@ var OnboardingInlineComponent = class extends Container {
|
|
|
277
325
|
if (!modelId) {
|
|
278
326
|
const fallback = this.options.modePacks.find((p) => p.id !== "custom") ?? this.options.modePacks[0];
|
|
279
327
|
this.selectedModePack = fallback;
|
|
280
|
-
this.collapseStep(`Model pack \u2192 ${bold(this.selectedModePack.name)} (cancelled custom)`);
|
|
328
|
+
this.collapseStep(`Model pack \u2192 ${theme.bold(this.selectedModePack.name)} (cancelled custom)`);
|
|
281
329
|
this.renderStep("omPack");
|
|
282
330
|
this.tui.requestRender();
|
|
283
331
|
return;
|
|
@@ -291,7 +339,7 @@ var OnboardingInlineComponent = class extends Container {
|
|
|
291
339
|
models: { build: models.build, plan: models.plan, fast: models.fast }
|
|
292
340
|
};
|
|
293
341
|
this.collapseStep(
|
|
294
|
-
`Model pack \u2192 ${bold("Custom")} ${chalk10.hex(mastra.blue)("plan")} ${models.plan} ${chalk10.hex(mastra.purple)("build")} ${models.build} ${chalk10.hex(mastra.green)("fast")} ${models.fast}`
|
|
342
|
+
`Model pack \u2192 ${theme.bold("Custom")} ${chalk10.hex(mastra.blue)("plan")} ${models.plan} ${chalk10.hex(mastra.purple)("build")} ${models.build} ${chalk10.hex(mastra.green)("fast")} ${models.fast}`
|
|
295
343
|
);
|
|
296
344
|
this.renderStep("omPack");
|
|
297
345
|
this.tui.requestRender();
|
|
@@ -306,15 +354,15 @@ var OnboardingInlineComponent = class extends Container {
|
|
|
306
354
|
return;
|
|
307
355
|
}
|
|
308
356
|
const box = this.makeBox();
|
|
309
|
-
box.addChild(new Text(bold(fg("accent", "\u{1F9E0} Observational Memory")), 0, 0));
|
|
357
|
+
box.addChild(new Text(theme.bold(theme.fg("accent", "\u{1F9E0} Observational Memory")), 0, 0));
|
|
310
358
|
box.addChild(new Spacer(1));
|
|
311
|
-
box.addChild(new Text(fg("text", "Choose the model for observational memory:"), 0, 0));
|
|
312
|
-
box.addChild(new Text(fg("dim", "https://mastra.ai/docs/memory/observational-memory"), 0, 0));
|
|
359
|
+
box.addChild(new Text(theme.fg("text", "Choose the model for observational memory:"), 0, 0));
|
|
360
|
+
box.addChild(new Text(theme.fg("dim", "https://mastra.ai/docs/memory/observational-memory"), 0, 0));
|
|
313
361
|
box.addChild(new Spacer(1));
|
|
314
362
|
const prevOmId = this.options.previous?.omPackId ?? null;
|
|
315
363
|
const items = omPacks.map((p) => ({
|
|
316
364
|
value: p.id,
|
|
317
|
-
label: ` ${p.name} ${fg("dim", p.description)}${p.id === prevOmId ? fg("dim", " (current)") : ""}`
|
|
365
|
+
label: ` ${p.name} ${theme.fg("dim", p.description)}${p.id === prevOmId ? theme.fg("dim", " (current)") : ""}`
|
|
318
366
|
}));
|
|
319
367
|
this.selectList = new SelectList(items, items.length, getSelectListTheme());
|
|
320
368
|
const prevOmIdx = prevOmId ? omPacks.findIndex((p) => p.id === prevOmId) : -1;
|
|
@@ -325,32 +373,32 @@ var OnboardingInlineComponent = class extends Container {
|
|
|
325
373
|
this.runCustomOmFlow();
|
|
326
374
|
} else {
|
|
327
375
|
this.selectedOmPack = pack;
|
|
328
|
-
this.collapseStep(`Observational memory \u2192 ${bold(this.selectedOmPack.name)}`);
|
|
376
|
+
this.collapseStep(`Observational memory \u2192 ${theme.bold(this.selectedOmPack.name)}`);
|
|
329
377
|
this.renderStep("yolo");
|
|
330
378
|
}
|
|
331
379
|
};
|
|
332
380
|
this.selectList.onCancel = () => {
|
|
333
|
-
this.collapseStep(`Observational memory \u2192 ${bold(this.selectedOmPack.name)} (default)`);
|
|
381
|
+
this.collapseStep(`Observational memory \u2192 ${theme.bold(this.selectedOmPack.name)} (default)`);
|
|
334
382
|
this.renderStep("yolo");
|
|
335
383
|
};
|
|
336
384
|
box.addChild(this.selectList);
|
|
337
385
|
box.addChild(new Spacer(1));
|
|
338
|
-
box.addChild(new Text(fg("dim", "\u2191\u2193 navigate \xB7 Enter select \xB7 Esc use default"), 0, 0));
|
|
386
|
+
box.addChild(new Text(theme.fg("dim", "\u2191\u2193 navigate \xB7 Enter select \xB7 Esc use default"), 0, 0));
|
|
339
387
|
}
|
|
340
388
|
async runCustomOmFlow() {
|
|
341
389
|
this.selectList = void 0;
|
|
342
|
-
this.collapseStep(`Observational memory \u2192 ${bold("Custom")}`);
|
|
390
|
+
this.collapseStep(`Observational memory \u2192 ${theme.bold("Custom")}`);
|
|
343
391
|
const modelId = await this.options.onSelectModel("Select model for observational memory");
|
|
344
392
|
if (modelId) {
|
|
345
393
|
this.selectedOmPack = { id: "custom", name: "Custom", description: "User-selected model", modelId };
|
|
346
|
-
this.collapseStep(`Observational memory \u2192 ${bold("Custom")} ${modelId}`);
|
|
394
|
+
this.collapseStep(`Observational memory \u2192 ${theme.bold("Custom")} ${modelId}`);
|
|
347
395
|
} else {
|
|
348
396
|
const fallback = this.options.omPacks.find((p) => p.id !== "custom");
|
|
349
397
|
if (fallback) {
|
|
350
398
|
this.selectedOmPack = fallback;
|
|
351
|
-
this.collapseStep(`Observational memory \u2192 ${bold(fallback.name)} (cancelled custom)`);
|
|
399
|
+
this.collapseStep(`Observational memory \u2192 ${theme.bold(fallback.name)} (cancelled custom)`);
|
|
352
400
|
} else {
|
|
353
|
-
this.collapseStep(`Observational memory \u2192 ${bold("Custom")} (cancelled)`);
|
|
401
|
+
this.collapseStep(`Observational memory \u2192 ${theme.bold("Custom")} (cancelled)`);
|
|
354
402
|
}
|
|
355
403
|
}
|
|
356
404
|
this.renderStep("yolo");
|
|
@@ -361,22 +409,22 @@ var OnboardingInlineComponent = class extends Container {
|
|
|
361
409
|
// ---------------------------------------------------------------------------
|
|
362
410
|
renderYolo() {
|
|
363
411
|
const box = this.makeBox();
|
|
364
|
-
box.addChild(new Text(bold(fg("accent", "\u26A1 Tool Approval")), 0, 0));
|
|
412
|
+
box.addChild(new Text(theme.bold(theme.fg("accent", "\u26A1 Tool Approval")), 0, 0));
|
|
365
413
|
box.addChild(new Spacer(1));
|
|
366
|
-
box.addChild(new Text(fg("text", "YOLO mode auto-approves all tool calls (edits, commands, etc)."), 0, 0));
|
|
367
|
-
box.addChild(new Text(fg("text", "You can toggle this anytime with Ctrl+Y or /yolo."), 0, 0));
|
|
414
|
+
box.addChild(new Text(theme.fg("text", "YOLO mode auto-approves all tool calls (edits, commands, etc)."), 0, 0));
|
|
415
|
+
box.addChild(new Text(theme.fg("text", "You can toggle this anytime with Ctrl+Y or /yolo."), 0, 0));
|
|
368
416
|
box.addChild(new Spacer(1));
|
|
369
417
|
const prevYolo = this.options.previous?.yolo ?? null;
|
|
370
|
-
const currentOn = prevYolo === true ? fg("dim", " (current)") : "";
|
|
371
|
-
const currentOff = prevYolo === false ? fg("dim", " (current)") : "";
|
|
418
|
+
const currentOn = prevYolo === true ? theme.fg("dim", " (current)") : "";
|
|
419
|
+
const currentOff = prevYolo === false ? theme.fg("dim", " (current)") : "";
|
|
372
420
|
const items = [
|
|
373
421
|
{
|
|
374
422
|
value: "on",
|
|
375
|
-
label: ` ${fg("success", "Enable YOLO")} ${fg("dim", "(recommended \u2014 auto-approve everything)")}${currentOn}`
|
|
423
|
+
label: ` ${theme.fg("success", "Enable YOLO")} ${theme.fg("dim", "(recommended \u2014 auto-approve everything)")}${currentOn}`
|
|
376
424
|
},
|
|
377
425
|
{
|
|
378
426
|
value: "off",
|
|
379
|
-
label: ` ${fg("warning", "Disable YOLO")} ${fg("dim", "(ask before each tool call)")}${currentOff}`
|
|
427
|
+
label: ` ${theme.fg("warning", "Disable YOLO")} ${theme.fg("dim", "(ask before each tool call)")}${currentOff}`
|
|
380
428
|
}
|
|
381
429
|
];
|
|
382
430
|
this.selectList = new SelectList(items, items.length, getSelectListTheme());
|
|
@@ -384,16 +432,16 @@ var OnboardingInlineComponent = class extends Container {
|
|
|
384
432
|
this.selectList.onSelect = (item) => {
|
|
385
433
|
this.selectedYolo = item.value === "on";
|
|
386
434
|
const label = this.selectedYolo ? "enabled" : "disabled";
|
|
387
|
-
this.collapseStep(`YOLO mode \u2192 ${bold(label)}`);
|
|
435
|
+
this.collapseStep(`YOLO mode \u2192 ${theme.bold(label)}`);
|
|
388
436
|
this.renderStep("done");
|
|
389
437
|
};
|
|
390
438
|
this.selectList.onCancel = () => {
|
|
391
|
-
this.collapseStep(`YOLO mode \u2192 ${bold("enabled")} (default)`);
|
|
439
|
+
this.collapseStep(`YOLO mode \u2192 ${theme.bold("enabled")} (default)`);
|
|
392
440
|
this.renderStep("done");
|
|
393
441
|
};
|
|
394
442
|
box.addChild(this.selectList);
|
|
395
443
|
box.addChild(new Spacer(1));
|
|
396
|
-
box.addChild(new Text(fg("dim", "\u2191\u2193 navigate \xB7 Enter select \xB7 Esc use default"), 0, 0));
|
|
444
|
+
box.addChild(new Text(theme.fg("dim", "\u2191\u2193 navigate \xB7 Enter select \xB7 Esc use default"), 0, 0));
|
|
397
445
|
}
|
|
398
446
|
// ---------------------------------------------------------------------------
|
|
399
447
|
// Step: Done
|
|
@@ -401,21 +449,21 @@ var OnboardingInlineComponent = class extends Container {
|
|
|
401
449
|
renderDone() {
|
|
402
450
|
this._finished = true;
|
|
403
451
|
const box = this.makeBox();
|
|
404
|
-
box.addChild(new Text(bold(fg("success", "\u2713 Setup complete!")), 0, 0));
|
|
452
|
+
box.addChild(new Text(theme.bold(theme.fg("success", "\u2713 Setup complete!")), 0, 0));
|
|
405
453
|
box.addChild(new Spacer(1));
|
|
406
454
|
const lines = [
|
|
407
|
-
`Model pack: ${bold(this.selectedModePack.name)}`,
|
|
455
|
+
`Model pack: ${theme.bold(this.selectedModePack.name)}`,
|
|
408
456
|
` ${chalk10.hex(mastra.blue)("plan")} \u2192 ${this.selectedModePack.models.plan}`,
|
|
409
457
|
` ${chalk10.hex(mastra.purple)("build")} \u2192 ${this.selectedModePack.models.build}`,
|
|
410
458
|
` ${chalk10.hex(mastra.green)("fast")} \u2192 ${this.selectedModePack.models.fast}`,
|
|
411
|
-
`Observational memory: ${bold(this.selectedOmPack.name)}`,
|
|
412
|
-
`YOLO mode: ${bold(this.selectedYolo ? "enabled" : "disabled")}`
|
|
459
|
+
`Observational memory: ${theme.bold(this.selectedOmPack.name)}`,
|
|
460
|
+
`YOLO mode: ${theme.bold(this.selectedYolo ? "enabled" : "disabled")}`
|
|
413
461
|
];
|
|
414
462
|
for (const line of lines) {
|
|
415
|
-
box.addChild(new Text(fg("text", line), 0, 0));
|
|
463
|
+
box.addChild(new Text(theme.fg("text", line), 0, 0));
|
|
416
464
|
}
|
|
417
465
|
box.addChild(new Spacer(1));
|
|
418
|
-
box.addChild(new Text(fg("dim", "Type a message to start coding, or use /help for commands."), 0, 0));
|
|
466
|
+
box.addChild(new Text(theme.fg("dim", "Type a message to start coding, or use /help for commands."), 0, 0));
|
|
419
467
|
this.options.onComplete({
|
|
420
468
|
modePack: this.selectedModePack,
|
|
421
469
|
omPack: this.selectedOmPack,
|
|
@@ -431,7 +479,7 @@ var OnboardingInlineComponent = class extends Container {
|
|
|
431
479
|
if (!this.stepBox) return;
|
|
432
480
|
this.stepBox.clear();
|
|
433
481
|
this.stepBox.setBgFn((text) => theme.bg("toolSuccessBg", text));
|
|
434
|
-
this.stepBox.addChild(new Text(`${fg("success", "\u2713")} ${fg("text", summary)}`, 0, 0));
|
|
482
|
+
this.stepBox.addChild(new Text(`${theme.fg("success", "\u2713")} ${theme.fg("text", summary)}`, 0, 0));
|
|
435
483
|
this.selectList = void 0;
|
|
436
484
|
}
|
|
437
485
|
// ---------------------------------------------------------------------------
|
|
@@ -445,22 +493,178 @@ var OnboardingInlineComponent = class extends Container {
|
|
|
445
493
|
}
|
|
446
494
|
}
|
|
447
495
|
};
|
|
496
|
+
var AskQuestionInlineComponent = class extends Container {
|
|
497
|
+
contentBox;
|
|
498
|
+
selectList;
|
|
499
|
+
input;
|
|
500
|
+
onSubmit;
|
|
501
|
+
onCancel;
|
|
502
|
+
formatResult;
|
|
503
|
+
isNegativeAnswer;
|
|
504
|
+
answered = false;
|
|
505
|
+
questionText;
|
|
506
|
+
_focused = false;
|
|
507
|
+
get focused() {
|
|
508
|
+
return this._focused;
|
|
509
|
+
}
|
|
510
|
+
set focused(value) {
|
|
511
|
+
this._focused = value;
|
|
512
|
+
if (!this.answered && this.input) {
|
|
513
|
+
this.input.focused = value;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
constructor(options, _ui) {
|
|
517
|
+
super();
|
|
518
|
+
this.onSubmit = options.onSubmit;
|
|
519
|
+
this.onCancel = options.onCancel;
|
|
520
|
+
this.formatResult = options.formatResult;
|
|
521
|
+
this.isNegativeAnswer = options.isNegativeAnswer;
|
|
522
|
+
this.questionText = options.question;
|
|
523
|
+
this.addChild(new Spacer(1));
|
|
524
|
+
this.contentBox = new Box(1, 1, (text) => theme.bg("toolPendingBg", text));
|
|
525
|
+
this.addChild(this.contentBox);
|
|
526
|
+
this.contentBox.addChild(new Text(theme.bold(theme.fg("accent", "\u2753 Question")), 0, 0));
|
|
527
|
+
this.contentBox.addChild(new Spacer(1));
|
|
528
|
+
for (const line of options.question.split("\n")) {
|
|
529
|
+
this.contentBox.addChild(new Text(theme.fg("text", line), 0, 0));
|
|
530
|
+
}
|
|
531
|
+
this.contentBox.addChild(new Spacer(1));
|
|
532
|
+
if (options.options && options.options.length > 0) {
|
|
533
|
+
this.buildSelectMode(options.options);
|
|
534
|
+
} else {
|
|
535
|
+
this.buildInputMode();
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
buildSelectMode(opts) {
|
|
539
|
+
const items = opts.map((opt) => ({
|
|
540
|
+
value: opt.label,
|
|
541
|
+
label: opt.description ? ` ${opt.label} ${theme.fg("dim", opt.description)}` : ` ${opt.label}`
|
|
542
|
+
}));
|
|
543
|
+
this.selectList = new SelectList(items, Math.min(items.length, 8), getSelectListTheme());
|
|
544
|
+
this.selectList.onSelect = (item) => {
|
|
545
|
+
this.handleAnswer(item.value);
|
|
546
|
+
};
|
|
547
|
+
this.selectList.onCancel = () => {
|
|
548
|
+
this.handleCancel();
|
|
549
|
+
};
|
|
550
|
+
this.contentBox.addChild(this.selectList);
|
|
551
|
+
this.contentBox.addChild(new Spacer(1));
|
|
552
|
+
this.contentBox.addChild(new Text(theme.fg("dim", "\u2191\u2193 to navigate \xB7 Enter to select \xB7 Esc to skip"), 0, 0));
|
|
553
|
+
}
|
|
554
|
+
buildInputMode() {
|
|
555
|
+
this.input = new Input();
|
|
556
|
+
this.input.onSubmit = (value) => {
|
|
557
|
+
const trimmed = value.trim();
|
|
558
|
+
if (trimmed) {
|
|
559
|
+
this.handleAnswer(trimmed);
|
|
560
|
+
}
|
|
561
|
+
};
|
|
562
|
+
this.contentBox.addChild(this.input);
|
|
563
|
+
this.contentBox.addChild(new Spacer(1));
|
|
564
|
+
this.contentBox.addChild(new Text(theme.fg("dim", "Enter to submit \xB7 Esc to skip"), 0, 0));
|
|
565
|
+
}
|
|
566
|
+
handleAnswer(answer) {
|
|
567
|
+
if (this.answered) return;
|
|
568
|
+
this.answered = true;
|
|
569
|
+
const isNegative = this.isNegativeAnswer?.(answer) ?? false;
|
|
570
|
+
this.contentBox.clear();
|
|
571
|
+
this.contentBox.setBgFn((text) => theme.bg(isNegative ? "toolErrorBg" : "toolSuccessBg", text));
|
|
572
|
+
const resultText = this.formatResult ? this.formatResult(answer) : `${this.questionText} \u2192 ${answer}`;
|
|
573
|
+
const icon = isNegative ? theme.fg("error", "\u2717") : theme.fg("success", "\u2713");
|
|
574
|
+
this.contentBox.addChild(new Text(theme.fg("text", `${icon} ${resultText}`), 0, 0));
|
|
575
|
+
this.onSubmit(answer);
|
|
576
|
+
}
|
|
577
|
+
handleCancel() {
|
|
578
|
+
if (this.answered) return;
|
|
579
|
+
this.answered = true;
|
|
580
|
+
this.contentBox.clear();
|
|
581
|
+
this.contentBox.setBgFn((text) => theme.bg("toolErrorBg", text));
|
|
582
|
+
this.contentBox.addChild(
|
|
583
|
+
new Text(theme.fg("dim", `${theme.fg("error", "\u2717")} ${this.questionText} (cancelled)`), 0, 0)
|
|
584
|
+
);
|
|
585
|
+
this.onCancel();
|
|
586
|
+
}
|
|
587
|
+
handleInput(data) {
|
|
588
|
+
if (this.answered) return;
|
|
589
|
+
if (this.selectList) {
|
|
590
|
+
this.selectList.handleInput(data);
|
|
591
|
+
} else if (this.input) {
|
|
592
|
+
const kb = getEditorKeybindings();
|
|
593
|
+
if (kb.matches(data, "selectCancel")) {
|
|
594
|
+
this.handleCancel();
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
this.input.handleInput(data);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
};
|
|
601
|
+
|
|
602
|
+
// src/tui/claude-max-warning.ts
|
|
603
|
+
function showClaudeMaxOAuthWarning(state, mode) {
|
|
604
|
+
const options = mode === "login" ? [
|
|
605
|
+
{ label: "Continue", description: "Proceed with Anthropic OAuth" },
|
|
606
|
+
{ label: "Cancel", description: "Go back" }
|
|
607
|
+
] : [
|
|
608
|
+
{ label: "Continue", description: "Keep Anthropic OAuth credentials" },
|
|
609
|
+
{ label: "Remove OAuth", description: "Log out from Anthropic" }
|
|
610
|
+
];
|
|
611
|
+
return new Promise((resolve2) => {
|
|
612
|
+
const questionComponent = new AskQuestionInlineComponent(
|
|
613
|
+
{
|
|
614
|
+
question: CLAUDE_MAX_OAUTH_WARNING_MESSAGE,
|
|
615
|
+
options,
|
|
616
|
+
formatResult: (answer) => `Claude Max OAuth warning \u2192 ${answer}`,
|
|
617
|
+
isNegativeAnswer: (answer) => answer !== "Continue",
|
|
618
|
+
onSubmit: (answer) => {
|
|
619
|
+
state.activeInlineQuestion = void 0;
|
|
620
|
+
if (answer === "Continue") {
|
|
621
|
+
resolve2("continue");
|
|
622
|
+
} else if (answer === "Cancel") {
|
|
623
|
+
resolve2("cancel");
|
|
624
|
+
} else {
|
|
625
|
+
resolve2("remove");
|
|
626
|
+
}
|
|
627
|
+
},
|
|
628
|
+
onCancel: () => {
|
|
629
|
+
state.activeInlineQuestion = void 0;
|
|
630
|
+
resolve2("cancel");
|
|
631
|
+
}
|
|
632
|
+
},
|
|
633
|
+
state.ui
|
|
634
|
+
);
|
|
635
|
+
state.activeInlineQuestion = questionComponent;
|
|
636
|
+
state.chatContainer.addChild(questionComponent);
|
|
637
|
+
state.chatContainer.addChild(new Spacer(1));
|
|
638
|
+
state.ui.requestRender();
|
|
639
|
+
state.chatContainer.invalidate();
|
|
640
|
+
});
|
|
641
|
+
}
|
|
448
642
|
async function processSlashCommand(command, args, workingDir) {
|
|
449
|
-
|
|
450
|
-
result =
|
|
643
|
+
const { result: withArgs, shouldAppendRawArgs } = replaceArguments(command.template, args);
|
|
644
|
+
let result = withArgs;
|
|
451
645
|
result = await replaceShellOutput(result, workingDir);
|
|
452
646
|
result = await replaceFileReferences(result, workingDir);
|
|
647
|
+
if (shouldAppendRawArgs) {
|
|
648
|
+
result = result.trimEnd() + `
|
|
649
|
+
|
|
650
|
+
ARGUMENTS: ${args.join(" ")}`;
|
|
651
|
+
}
|
|
453
652
|
return result;
|
|
454
653
|
}
|
|
455
654
|
function replaceArguments(template, args) {
|
|
456
655
|
let result = template;
|
|
656
|
+
const hasArgumentsVar = /\$ARGUMENTS/.test(template);
|
|
657
|
+
const hasPositionalVar = /\$[1-9]\d*/.test(template);
|
|
457
658
|
result = result.replace(/\$ARGUMENTS/g, args.join(" "));
|
|
458
659
|
args.forEach((arg, index) => {
|
|
459
660
|
const pattern = new RegExp(`\\$${index + 1}`, "g");
|
|
460
661
|
result = result.replace(pattern, arg);
|
|
461
662
|
});
|
|
462
|
-
result = result.replace(
|
|
463
|
-
return
|
|
663
|
+
result = result.replace(/\$[1-9]\d*/g, "");
|
|
664
|
+
return {
|
|
665
|
+
result,
|
|
666
|
+
shouldAppendRawArgs: !hasArgumentsVar && !hasPositionalVar && args.length > 0
|
|
667
|
+
};
|
|
464
668
|
}
|
|
465
669
|
async function replaceShellOutput(template, workingDir) {
|
|
466
670
|
const shellPattern = /!`([^`]+)`/g;
|
|
@@ -525,7 +729,8 @@ function getCommands(modes) {
|
|
|
525
729
|
{ key: "/mcp", description: "Show/reload MCP connections" },
|
|
526
730
|
{ key: "/login", description: "Login with OAuth provider" },
|
|
527
731
|
{ key: "/logout", description: "Logout from OAuth provider" },
|
|
528
|
-
{ key: "/setup", description: "Run the setup wizard" }
|
|
732
|
+
{ key: "/setup", description: "Run the setup wizard" },
|
|
733
|
+
{ key: "/theme", description: "Switch color theme (auto/dark/light)" }
|
|
529
734
|
];
|
|
530
735
|
if (modes > 1) {
|
|
531
736
|
cmds.push({ key: "/mode", description: "Switch or list modes" });
|
|
@@ -605,22 +810,129 @@ function handleYoloCommand(ctx) {
|
|
|
605
810
|
ctx.harness.setState({ yolo: !current });
|
|
606
811
|
ctx.showInfo(!current ? "YOLO mode ON \u2014 tools auto-approved" : "YOLO mode OFF \u2014 tools require approval");
|
|
607
812
|
}
|
|
813
|
+
var BASE_THINKING_LEVELS = [
|
|
814
|
+
{ id: "off", label: "Off", providerValue: "none", description: "Reasoning disabled" },
|
|
815
|
+
{ id: "low", label: "Low", providerValue: "low", description: "Light reasoning" },
|
|
816
|
+
{ id: "medium", label: "Medium", providerValue: "medium", description: "Balanced reasoning" },
|
|
817
|
+
{ id: "high", label: "High", providerValue: "high", description: "Deep reasoning" },
|
|
818
|
+
{ id: "xhigh", label: "Very High", providerValue: "xhigh", description: "Maximum reasoning depth" }
|
|
819
|
+
];
|
|
820
|
+
function isOpenAIModel(modelId) {
|
|
821
|
+
return modelId.startsWith("openai/");
|
|
822
|
+
}
|
|
823
|
+
function getThinkingLevelsForModel(modelId) {
|
|
824
|
+
if (!isOpenAIModel(modelId)) {
|
|
825
|
+
return [...BASE_THINKING_LEVELS];
|
|
826
|
+
}
|
|
827
|
+
return BASE_THINKING_LEVELS.map((level) => ({
|
|
828
|
+
...level,
|
|
829
|
+
label: level.providerValue
|
|
830
|
+
}));
|
|
831
|
+
}
|
|
832
|
+
var THINKING_LEVELS = getThinkingLevelsForModel("");
|
|
833
|
+
function getThinkingLevelForModel(modelId, levelId) {
|
|
834
|
+
return getThinkingLevelsForModel(modelId).find((level) => level.id === levelId) ?? getThinkingLevelsForModel(modelId)[0];
|
|
835
|
+
}
|
|
608
836
|
|
|
609
837
|
// src/tui/commands/think.ts
|
|
610
|
-
|
|
838
|
+
function supportsThinking(modelId) {
|
|
839
|
+
return modelId.startsWith("openai/");
|
|
840
|
+
}
|
|
841
|
+
function getThinkingStatusLine(modelId, levelId) {
|
|
842
|
+
const level = getThinkingLevelForModel(modelId, levelId);
|
|
843
|
+
return `Thinking: ${level.label}`;
|
|
844
|
+
}
|
|
845
|
+
function getModelNote(ctx) {
|
|
846
|
+
const modelId = ctx.state.harness.getCurrentModelId() ?? "";
|
|
847
|
+
if (!modelId) return "No model selected.";
|
|
848
|
+
if (!supportsThinking(modelId)) {
|
|
849
|
+
return `Warning: current model (${modelId}) may not support reasoning effort. Setting will be saved but may not take effect.`;
|
|
850
|
+
}
|
|
851
|
+
return null;
|
|
852
|
+
}
|
|
853
|
+
async function handleThinkCommand(ctx, args = []) {
|
|
611
854
|
const currentLevel = ctx.harness.getState()?.thinkingLevel ?? "off";
|
|
612
|
-
const
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
855
|
+
const modelId = ctx.state.harness.getCurrentModelId() ?? "";
|
|
856
|
+
const thinkingLevels = getThinkingLevelsForModel(modelId);
|
|
857
|
+
const arg = args[0]?.toLowerCase();
|
|
858
|
+
if (arg === "status") {
|
|
859
|
+
ctx.showInfo(getThinkingStatusLine(modelId, currentLevel));
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
862
|
+
if (arg) {
|
|
863
|
+
const selected = thinkingLevels.find((l) => l.id === arg);
|
|
864
|
+
if (!selected) {
|
|
865
|
+
ctx.showInfo(
|
|
866
|
+
`Invalid thinking level: ${arg}. Use one of: ${THINKING_LEVELS.map((l) => l.id).join(", ")} or 'status'.`
|
|
867
|
+
);
|
|
868
|
+
return;
|
|
869
|
+
}
|
|
870
|
+
const note = getModelNote(ctx);
|
|
871
|
+
await ctx.harness.setState({ thinkingLevel: selected.id });
|
|
872
|
+
ctx.showInfo(getThinkingStatusLine(modelId, selected.id) + (note ? ` (${note})` : ""));
|
|
873
|
+
return;
|
|
874
|
+
}
|
|
875
|
+
const items = thinkingLevels.map((l) => ({
|
|
876
|
+
value: l.id,
|
|
877
|
+
label: ` ${l.label} ${theme.fg("dim", l.description)}${l.id === currentLevel ? theme.fg("dim", " (current)") : ""}`
|
|
878
|
+
}));
|
|
879
|
+
const modelNote = getModelNote(ctx);
|
|
880
|
+
return new Promise((resolve2) => {
|
|
881
|
+
const container = new Box(1, 1);
|
|
882
|
+
container.addChild(new Text(theme.bold(theme.fg("accent", "Thinking Level")), 0, 0));
|
|
883
|
+
container.addChild(new Spacer(1));
|
|
884
|
+
if (modelNote) {
|
|
885
|
+
container.addChild(new Text(theme.fg("warning", modelNote), 0, 0));
|
|
886
|
+
container.addChild(new Spacer(1));
|
|
887
|
+
}
|
|
888
|
+
const selectList = new SelectList(items, items.length, getSelectListTheme());
|
|
889
|
+
selectList.onSelect = async (item) => {
|
|
890
|
+
ctx.state.activeInlineQuestion = void 0;
|
|
891
|
+
try {
|
|
892
|
+
await ctx.harness.setState({ thinkingLevel: item.value });
|
|
893
|
+
const selectedLabel = getThinkingLevelForModel(modelId, item.value).label;
|
|
894
|
+
collapseResult(
|
|
895
|
+
`Thinking \u2192 ${theme.bold(item.value === currentLevel ? `${selectedLabel} (unchanged)` : selectedLabel)}`
|
|
896
|
+
);
|
|
897
|
+
} catch {
|
|
898
|
+
collapseResult("cancelled");
|
|
899
|
+
} finally {
|
|
900
|
+
ctx.state.ui.requestRender();
|
|
901
|
+
resolve2();
|
|
902
|
+
}
|
|
903
|
+
};
|
|
904
|
+
selectList.onCancel = () => {
|
|
905
|
+
ctx.state.activeInlineQuestion = void 0;
|
|
906
|
+
collapseResult("cancelled");
|
|
907
|
+
ctx.state.ui.requestRender();
|
|
908
|
+
resolve2();
|
|
909
|
+
};
|
|
910
|
+
container.addChild(selectList);
|
|
911
|
+
container.addChild(new Spacer(1));
|
|
912
|
+
container.addChild(new Text(theme.fg("dim", "\u2191\u2193 navigate \xB7 Enter select \xB7 Esc cancel"), 0, 0));
|
|
913
|
+
const currentIdx = thinkingLevels.findIndex((l) => l.id === currentLevel);
|
|
914
|
+
if (currentIdx > 0) selectList.setSelectedIndex(currentIdx);
|
|
915
|
+
const collapseResult = (result) => {
|
|
916
|
+
container.clear();
|
|
917
|
+
if (result === "cancelled") {
|
|
918
|
+
container.addChild(new Text(theme.fg("dim", `${theme.fg("error", "\u2717")} Thinking level (cancelled)`), 0, 0));
|
|
919
|
+
} else {
|
|
920
|
+
container.addChild(new Text(theme.fg("text", `${theme.fg("success", "\u2713")} ${result}`), 0, 0));
|
|
921
|
+
}
|
|
922
|
+
};
|
|
923
|
+
const inputShim = {
|
|
924
|
+
handleInput: (data) => {
|
|
925
|
+
if (isKeyRelease(data)) return;
|
|
926
|
+
selectList.handleInput(data);
|
|
927
|
+
}
|
|
928
|
+
};
|
|
929
|
+
ctx.state.activeInlineQuestion = inputShim;
|
|
930
|
+
ctx.state.chatContainer.addChild(new Spacer(1));
|
|
931
|
+
ctx.state.chatContainer.addChild(container);
|
|
932
|
+
ctx.state.chatContainer.addChild(new Spacer(1));
|
|
933
|
+
ctx.state.ui.requestRender();
|
|
934
|
+
ctx.state.chatContainer.invalidate();
|
|
935
|
+
});
|
|
624
936
|
}
|
|
625
937
|
|
|
626
938
|
// src/tui/commands/permissions.ts
|
|
@@ -854,7 +1166,15 @@ ${modeList}`);
|
|
|
854
1166
|
|
|
855
1167
|
// src/tui/commands/skills.ts
|
|
856
1168
|
async function handleSkillsCommand(ctx) {
|
|
857
|
-
|
|
1169
|
+
let workspace = ctx.getResolvedWorkspace();
|
|
1170
|
+
if (!workspace && ctx.harness.hasWorkspace()) {
|
|
1171
|
+
try {
|
|
1172
|
+
workspace = await ctx.harness.resolveWorkspace();
|
|
1173
|
+
} catch (error) {
|
|
1174
|
+
ctx.showError(`Failed to resolve workspace: ${error instanceof Error ? error.message : String(error)}`);
|
|
1175
|
+
return;
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
858
1178
|
if (!workspace?.skills) {
|
|
859
1179
|
ctx.showInfo(
|
|
860
1180
|
"No skills configured.\n\nAdd skills to any of these locations:\n .mastracode/skills/ (project-local)\n .claude/skills/ (project-local)\n ~/.mastracode/skills/ (global)\n ~/.claude/skills/ (global)\n\nEach skill is a folder with a SKILL.md file.\nInstall skills: npx add-skill <github-url>"
|
|
@@ -933,12 +1253,13 @@ async function handleResourceCommand(ctx, args) {
|
|
|
933
1253
|
state.ui.requestRender();
|
|
934
1254
|
ctx.showInfo(sub === "reset" ? `Resource ID reset to: ${defaultId}` : `Switched to resource: ${newId}`);
|
|
935
1255
|
}
|
|
936
|
-
var addedColor = chalk10.hex("#5cb85c");
|
|
937
|
-
var hunkHeaderColor = chalk10.hex("#61afef");
|
|
938
|
-
var fileHeaderColor = chalk10.bold.hex("#c678dd");
|
|
939
|
-
var removedColor = chalk10.hex(mastra.red);
|
|
940
|
-
var metaColor = chalk10.hex(mastra.mainGray);
|
|
941
1256
|
function colorizeDiffLine(line) {
|
|
1257
|
+
const t = theme.getTheme();
|
|
1258
|
+
const addedColor = chalk10.hex(t.success);
|
|
1259
|
+
const hunkHeaderColor = chalk10.hex(t.toolBorderPending);
|
|
1260
|
+
const fileHeaderColor = chalk10.bold.hex(t.accent);
|
|
1261
|
+
const removedColor = chalk10.hex(mastra.red);
|
|
1262
|
+
const metaColor = chalk10.hex(mastra.mainGray);
|
|
942
1263
|
if (line.startsWith("+++") || line.startsWith("---")) {
|
|
943
1264
|
return fileHeaderColor(line);
|
|
944
1265
|
}
|
|
@@ -957,7 +1278,7 @@ function colorizeDiffLine(line) {
|
|
|
957
1278
|
if (line.startsWith("index ") || line.startsWith("new file") || line.startsWith("deleted file") || line.startsWith("similarity") || line.startsWith("rename")) {
|
|
958
1279
|
return metaColor(line);
|
|
959
1280
|
}
|
|
960
|
-
const statMatch = line.match(/^(.+\|.+?)(\++)([-]*)$/);
|
|
1281
|
+
const statMatch = line.match(/^(.+\|.+?)(\++)([- ]*)$/);
|
|
961
1282
|
if (statMatch) {
|
|
962
1283
|
return statMatch[1] + addedColor(statMatch[2]) + removedColor(statMatch[3]);
|
|
963
1284
|
}
|
|
@@ -970,7 +1291,9 @@ var DiffOutputComponent = class extends Container {
|
|
|
970
1291
|
constructor(command, diffOutput) {
|
|
971
1292
|
super();
|
|
972
1293
|
this.addChild(new Spacer(1));
|
|
973
|
-
this.addChild(
|
|
1294
|
+
this.addChild(
|
|
1295
|
+
new Text(`${theme.fg("success", "\u2713")} ${theme.bold(theme.fg("muted", "$"))} ${theme.fg("text", command)}`, 1, 0)
|
|
1296
|
+
);
|
|
974
1297
|
const output = diffOutput.trimEnd();
|
|
975
1298
|
if (output) {
|
|
976
1299
|
const lines = output.split("\n");
|
|
@@ -1045,117 +1368,12 @@ async function handleDiffCommand(ctx, filePath) {
|
|
|
1045
1368
|
opCounts.set(op, (opCounts.get(op) || 0) + 1);
|
|
1046
1369
|
}
|
|
1047
1370
|
const ops = Array.from(opCounts.entries()).map(([op, count]) => count > 1 ? `${op}\xD7${count}` : op).join(", ");
|
|
1048
|
-
lines.push(` ${fg("path", fp)} ${fg("muted", `(${ops})`)}`);
|
|
1371
|
+
lines.push(` ${theme.fg("path", fp)} ${theme.fg("muted", `(${ops})`)}`);
|
|
1049
1372
|
}
|
|
1050
1373
|
lines.push("");
|
|
1051
|
-
lines.push(fg("muted", "Use /diff <path> to see the git diff for a specific file."));
|
|
1374
|
+
lines.push(theme.fg("muted", "Use /diff <path> to see the git diff for a specific file."));
|
|
1052
1375
|
ctx.showInfo(lines.join("\n"));
|
|
1053
1376
|
}
|
|
1054
|
-
var AskQuestionInlineComponent = class extends Container {
|
|
1055
|
-
contentBox;
|
|
1056
|
-
selectList;
|
|
1057
|
-
input;
|
|
1058
|
-
onSubmit;
|
|
1059
|
-
onCancel;
|
|
1060
|
-
formatResult;
|
|
1061
|
-
isNegativeAnswer;
|
|
1062
|
-
answered = false;
|
|
1063
|
-
questionText;
|
|
1064
|
-
_focused = false;
|
|
1065
|
-
get focused() {
|
|
1066
|
-
return this._focused;
|
|
1067
|
-
}
|
|
1068
|
-
set focused(value) {
|
|
1069
|
-
this._focused = value;
|
|
1070
|
-
if (!this.answered && this.input) {
|
|
1071
|
-
this.input.focused = value;
|
|
1072
|
-
}
|
|
1073
|
-
}
|
|
1074
|
-
constructor(options, _ui) {
|
|
1075
|
-
super();
|
|
1076
|
-
this.onSubmit = options.onSubmit;
|
|
1077
|
-
this.onCancel = options.onCancel;
|
|
1078
|
-
this.formatResult = options.formatResult;
|
|
1079
|
-
this.isNegativeAnswer = options.isNegativeAnswer;
|
|
1080
|
-
this.questionText = options.question;
|
|
1081
|
-
this.addChild(new Spacer(1));
|
|
1082
|
-
this.contentBox = new Box(1, 1, (text) => theme.bg("toolPendingBg", text));
|
|
1083
|
-
this.addChild(this.contentBox);
|
|
1084
|
-
this.contentBox.addChild(new Text(theme.bold(theme.fg("accent", "\u2753 Question")), 0, 0));
|
|
1085
|
-
this.contentBox.addChild(new Spacer(1));
|
|
1086
|
-
for (const line of options.question.split("\n")) {
|
|
1087
|
-
this.contentBox.addChild(new Text(theme.fg("text", line), 0, 0));
|
|
1088
|
-
}
|
|
1089
|
-
this.contentBox.addChild(new Spacer(1));
|
|
1090
|
-
if (options.options && options.options.length > 0) {
|
|
1091
|
-
this.buildSelectMode(options.options);
|
|
1092
|
-
} else {
|
|
1093
|
-
this.buildInputMode();
|
|
1094
|
-
}
|
|
1095
|
-
}
|
|
1096
|
-
buildSelectMode(opts) {
|
|
1097
|
-
const items = opts.map((opt) => ({
|
|
1098
|
-
value: opt.label,
|
|
1099
|
-
label: opt.description ? ` ${opt.label} ${theme.fg("dim", opt.description)}` : ` ${opt.label}`
|
|
1100
|
-
}));
|
|
1101
|
-
this.selectList = new SelectList(items, Math.min(items.length, 8), getSelectListTheme());
|
|
1102
|
-
this.selectList.onSelect = (item) => {
|
|
1103
|
-
this.handleAnswer(item.value);
|
|
1104
|
-
};
|
|
1105
|
-
this.selectList.onCancel = () => {
|
|
1106
|
-
this.handleCancel();
|
|
1107
|
-
};
|
|
1108
|
-
this.contentBox.addChild(this.selectList);
|
|
1109
|
-
this.contentBox.addChild(new Spacer(1));
|
|
1110
|
-
this.contentBox.addChild(new Text(theme.fg("dim", "\u2191\u2193 to navigate \xB7 Enter to select \xB7 Esc to skip"), 0, 0));
|
|
1111
|
-
}
|
|
1112
|
-
buildInputMode() {
|
|
1113
|
-
this.input = new Input();
|
|
1114
|
-
this.input.onSubmit = (value) => {
|
|
1115
|
-
const trimmed = value.trim();
|
|
1116
|
-
if (trimmed) {
|
|
1117
|
-
this.handleAnswer(trimmed);
|
|
1118
|
-
}
|
|
1119
|
-
};
|
|
1120
|
-
this.contentBox.addChild(this.input);
|
|
1121
|
-
this.contentBox.addChild(new Spacer(1));
|
|
1122
|
-
this.contentBox.addChild(new Text(theme.fg("dim", "Enter to submit \xB7 Esc to skip"), 0, 0));
|
|
1123
|
-
}
|
|
1124
|
-
handleAnswer(answer) {
|
|
1125
|
-
if (this.answered) return;
|
|
1126
|
-
this.answered = true;
|
|
1127
|
-
const isNegative = this.isNegativeAnswer?.(answer) ?? false;
|
|
1128
|
-
this.contentBox.clear();
|
|
1129
|
-
this.contentBox.setBgFn((text) => theme.bg(isNegative ? "toolErrorBg" : "toolSuccessBg", text));
|
|
1130
|
-
const resultText = this.formatResult ? this.formatResult(answer) : `${this.questionText} \u2192 ${answer}`;
|
|
1131
|
-
const icon = isNegative ? theme.fg("error", "\u2717") : theme.fg("success", "\u2713");
|
|
1132
|
-
this.contentBox.addChild(new Text(theme.fg("text", `${icon} ${resultText}`), 0, 0));
|
|
1133
|
-
this.onSubmit(answer);
|
|
1134
|
-
}
|
|
1135
|
-
handleCancel() {
|
|
1136
|
-
if (this.answered) return;
|
|
1137
|
-
this.answered = true;
|
|
1138
|
-
this.contentBox.clear();
|
|
1139
|
-
this.contentBox.setBgFn((text) => theme.bg("toolErrorBg", text));
|
|
1140
|
-
this.contentBox.addChild(
|
|
1141
|
-
new Text(theme.fg("dim", `${theme.fg("error", "\u2717")} ${this.questionText} (cancelled)`), 0, 0)
|
|
1142
|
-
);
|
|
1143
|
-
this.onCancel();
|
|
1144
|
-
}
|
|
1145
|
-
handleInput(data) {
|
|
1146
|
-
if (this.answered) return;
|
|
1147
|
-
if (this.selectList) {
|
|
1148
|
-
this.selectList.handleInput(data);
|
|
1149
|
-
} else if (this.input) {
|
|
1150
|
-
const kb = getEditorKeybindings();
|
|
1151
|
-
if (kb.matches(data, "selectCancel")) {
|
|
1152
|
-
this.handleCancel();
|
|
1153
|
-
return;
|
|
1154
|
-
}
|
|
1155
|
-
this.input.handleInput(data);
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
1158
|
-
};
|
|
1159
1377
|
var ThreadSelectorComponent = class extends Box {
|
|
1160
1378
|
searchInput;
|
|
1161
1379
|
listContainer;
|
|
@@ -1179,7 +1397,7 @@ var ThreadSelectorComponent = class extends Box {
|
|
|
1179
1397
|
this.searchInput.focused = value;
|
|
1180
1398
|
}
|
|
1181
1399
|
constructor(options) {
|
|
1182
|
-
super(2, 1, (text) => bg("overlayBg", text));
|
|
1400
|
+
super(2, 1, (text) => theme.bg("overlayBg", text));
|
|
1183
1401
|
this.tui = options.tui;
|
|
1184
1402
|
this.currentResourceId = options.currentResourceId;
|
|
1185
1403
|
this.allThreads = this.sortThreads(options.threads, options.currentThreadId);
|
|
@@ -1206,9 +1424,9 @@ var ThreadSelectorComponent = class extends Box {
|
|
|
1206
1424
|
this.tui.requestRender();
|
|
1207
1425
|
}
|
|
1208
1426
|
buildUI() {
|
|
1209
|
-
this.addChild(new Text(bold(fg("accent", "Select Thread")), 0, 0));
|
|
1427
|
+
this.addChild(new Text(theme.bold(theme.fg("accent", "Select Thread")), 0, 0));
|
|
1210
1428
|
this.addChild(new Spacer(1));
|
|
1211
|
-
this.addChild(new Text(fg("muted", "Type to search \u2022 \u2191\u2193 navigate \u2022 Enter select \u2022 Esc cancel"), 0, 0));
|
|
1429
|
+
this.addChild(new Text(theme.fg("muted", "Type to search \u2022 \u2191\u2193 navigate \u2022 Enter select \u2022 Esc cancel"), 0, 0));
|
|
1212
1430
|
this.addChild(new Spacer(1));
|
|
1213
1431
|
this.searchInput = new Input();
|
|
1214
1432
|
this.searchInput.onSubmit = () => {
|
|
@@ -1271,33 +1489,33 @@ var ThreadSelectorComponent = class extends Box {
|
|
|
1271
1489
|
if (!thread) continue;
|
|
1272
1490
|
const isSelected = i === this.selectedIndex;
|
|
1273
1491
|
const isCurrent = thread.id === this.currentThreadId;
|
|
1274
|
-
const checkmark = isCurrent ? fg("success", " \u2713") : "";
|
|
1492
|
+
const checkmark = isCurrent ? theme.fg("success", " \u2713") : "";
|
|
1275
1493
|
const shortId = thread.id.slice(-6);
|
|
1276
1494
|
const threadPath = thread.metadata?.projectPath;
|
|
1277
|
-
const pathTag = threadPath ? fg("dim", ` [${threadPath.split("/").pop()}]`) : "";
|
|
1495
|
+
const pathTag = threadPath ? theme.fg("dim", ` [${threadPath.split("/").pop()}]`) : "";
|
|
1278
1496
|
const displayId = `${thread.resourceId}/${shortId}`;
|
|
1279
|
-
const timeAgo = fg("muted", ` (${this.formatTimeAgo(thread.updatedAt)})`);
|
|
1497
|
+
const timeAgo = theme.fg("muted", ` (${this.formatTimeAgo(thread.updatedAt)})`);
|
|
1280
1498
|
const hasCustomTitle = thread.title && thread.title !== "New Thread";
|
|
1281
1499
|
let line = "";
|
|
1282
1500
|
if (isSelected) {
|
|
1283
|
-
line = fg("accent", `\u2192 ${displayId}`) + pathTag + timeAgo + checkmark;
|
|
1501
|
+
line = theme.fg("accent", `\u2192 ${displayId}`) + pathTag + timeAgo + checkmark;
|
|
1284
1502
|
} else {
|
|
1285
1503
|
line = ` ${displayId}` + pathTag + timeAgo + checkmark;
|
|
1286
1504
|
}
|
|
1287
1505
|
this.listContainer.addChild(new Text(line, 0, 0));
|
|
1288
1506
|
const preview = this.messagePreviews.get(thread.id);
|
|
1289
1507
|
if (preview) {
|
|
1290
|
-
this.listContainer.addChild(new Text(` ${fg("muted", `"${preview}"`)}`, 0, 0));
|
|
1508
|
+
this.listContainer.addChild(new Text(` ${theme.fg("muted", `"${preview}"`)}`, 0, 0));
|
|
1291
1509
|
} else if (hasCustomTitle) {
|
|
1292
|
-
this.listContainer.addChild(new Text(` ${fg("muted", `"${thread.title}"`)}`, 0, 0));
|
|
1510
|
+
this.listContainer.addChild(new Text(` ${theme.fg("muted", `"${thread.title}"`)}`, 0, 0));
|
|
1293
1511
|
}
|
|
1294
1512
|
}
|
|
1295
1513
|
if (startIndex > 0 || endIndex < this.filteredThreads.length) {
|
|
1296
|
-
const scrollInfo = fg("muted", `(${this.selectedIndex + 1}/${this.filteredThreads.length})`);
|
|
1514
|
+
const scrollInfo = theme.fg("muted", `(${this.selectedIndex + 1}/${this.filteredThreads.length})`);
|
|
1297
1515
|
this.listContainer.addChild(new Text(scrollInfo, 0, 0));
|
|
1298
1516
|
}
|
|
1299
1517
|
if (this.filteredThreads.length === 0) {
|
|
1300
|
-
this.listContainer.addChild(new Text(fg("muted", "No matching threads"), 0, 0));
|
|
1518
|
+
this.listContainer.addChild(new Text(theme.fg("muted", "No matching threads"), 0, 0));
|
|
1301
1519
|
}
|
|
1302
1520
|
}
|
|
1303
1521
|
handleInput(keyData) {
|
|
@@ -1448,7 +1666,7 @@ async function handleThreadTagDirCommand(ctx) {
|
|
|
1448
1666
|
const questionComponent = new AskQuestionInlineComponent(
|
|
1449
1667
|
{
|
|
1450
1668
|
question: `Tag this thread with directory "${dirName}"?
|
|
1451
|
-
${fg("dim", projectPath)}`,
|
|
1669
|
+
${theme.fg("dim", projectPath)}`,
|
|
1452
1670
|
options: [{ label: "Yes" }, { label: "No" }],
|
|
1453
1671
|
formatResult: (answer) => answer === "Yes" ? `Tagged thread with: ${dirName}` : `Thread not tagged`,
|
|
1454
1672
|
onSubmit: async (answer) => {
|
|
@@ -1618,7 +1836,7 @@ var ModelSelectorComponent = class extends Box {
|
|
|
1618
1836
|
this.searchInput.focused = value;
|
|
1619
1837
|
}
|
|
1620
1838
|
constructor(options) {
|
|
1621
|
-
super(2, 1, (text) => bg("overlayBg", text));
|
|
1839
|
+
super(2, 1, (text) => theme.bg("overlayBg", text));
|
|
1622
1840
|
this.tui = options.tui;
|
|
1623
1841
|
this.title = options.title ?? "Select Model";
|
|
1624
1842
|
this.titleColor = options.titleColor;
|
|
@@ -1630,10 +1848,10 @@ var ModelSelectorComponent = class extends Box {
|
|
|
1630
1848
|
this.buildUI();
|
|
1631
1849
|
}
|
|
1632
1850
|
buildUI() {
|
|
1633
|
-
const titleText = this.titleColor ? chalk10.bgHex(this.titleColor).white.bold(` ${this.title} `) : bold(fg("accent", this.title));
|
|
1851
|
+
const titleText = this.titleColor ? chalk10.bgHex(this.titleColor).white.bold(` ${this.title} `) : theme.bold(theme.fg("accent", this.title));
|
|
1634
1852
|
this.addChild(new Text(titleText, 0, 0));
|
|
1635
1853
|
this.addChild(new Spacer(1));
|
|
1636
|
-
this.addChild(new Text(fg("muted", "Type to search \u2022 \u2191\u2193 navigate \u2022 Enter select \u2022 Esc cancel"), 0, 0));
|
|
1854
|
+
this.addChild(new Text(theme.fg("muted", "Type to search \u2022 \u2191\u2193 navigate \u2022 Enter select \u2022 Esc cancel"), 0, 0));
|
|
1637
1855
|
this.addChild(new Spacer(1));
|
|
1638
1856
|
this.searchInput = new Input();
|
|
1639
1857
|
this.searchInput.onSubmit = () => {
|
|
@@ -1696,7 +1914,7 @@ var ModelSelectorComponent = class extends Box {
|
|
|
1696
1914
|
if (this.hasCustomItem && i === 0) {
|
|
1697
1915
|
const query = this.searchInput.getValue().trim();
|
|
1698
1916
|
const isSelected2 = this.selectedIndex === 0;
|
|
1699
|
-
const line2 = isSelected2 ? fg("accent", "\u2192 ") + bold(fg("accent", `Use: ${query}`)) : " " + fg("muted", `Use: ${query}`);
|
|
1917
|
+
const line2 = isSelected2 ? theme.fg("accent", "\u2192 ") + theme.bold(theme.fg("accent", `Use: ${query}`)) : " " + theme.fg("muted", `Use: ${query}`);
|
|
1700
1918
|
this.listContainer.addChild(new Text(line2, 0, 0));
|
|
1701
1919
|
continue;
|
|
1702
1920
|
}
|
|
@@ -1705,23 +1923,23 @@ var ModelSelectorComponent = class extends Box {
|
|
|
1705
1923
|
if (!item) continue;
|
|
1706
1924
|
const isSelected = i === this.selectedIndex;
|
|
1707
1925
|
const isCurrent = item.id === this.currentModelId;
|
|
1708
|
-
const checkmark = isCurrent ? fg("success", " \u2713") : "";
|
|
1709
|
-
const noKeyIndicator = !item.hasApiKey ? fg("error", " \u2717") + fg("muted", item.apiKeyEnvVar ? ` (${item.apiKeyEnvVar})` : " (no key)") : "";
|
|
1926
|
+
const checkmark = isCurrent ? theme.fg("success", " \u2713") : "";
|
|
1927
|
+
const noKeyIndicator = !item.hasApiKey ? theme.fg("error", " \u2717") + theme.fg("muted", item.apiKeyEnvVar ? ` (${item.apiKeyEnvVar})` : " (no key)") : "";
|
|
1710
1928
|
let line = "";
|
|
1711
1929
|
if (isSelected) {
|
|
1712
|
-
line = fg("accent", "\u2192 " + item.id) + checkmark + noKeyIndicator;
|
|
1930
|
+
line = theme.fg("accent", "\u2192 " + item.id) + checkmark + noKeyIndicator;
|
|
1713
1931
|
} else {
|
|
1714
|
-
const modelText = item.hasApiKey ? item.id : fg("muted", item.id);
|
|
1932
|
+
const modelText = item.hasApiKey ? item.id : theme.fg("muted", item.id);
|
|
1715
1933
|
line = " " + modelText + checkmark + noKeyIndicator;
|
|
1716
1934
|
}
|
|
1717
1935
|
this.listContainer.addChild(new Text(line, 0, 0));
|
|
1718
1936
|
}
|
|
1719
1937
|
if (startIndex > 0 || endIndex < totalItems) {
|
|
1720
|
-
const scrollInfo = fg("muted", `(${this.selectedIndex + 1}/${totalItems})`);
|
|
1938
|
+
const scrollInfo = theme.fg("muted", `(${this.selectedIndex + 1}/${totalItems})`);
|
|
1721
1939
|
this.listContainer.addChild(new Text(scrollInfo, 0, 0));
|
|
1722
1940
|
}
|
|
1723
1941
|
if (totalItems === 0) {
|
|
1724
|
-
this.listContainer.addChild(new Text(fg("muted", "No matching models"), 0, 0));
|
|
1942
|
+
this.listContainer.addChild(new Text(theme.fg("muted", "No matching models"), 0, 0));
|
|
1725
1943
|
}
|
|
1726
1944
|
}
|
|
1727
1945
|
handleInput(keyData) {
|
|
@@ -1906,7 +2124,9 @@ async function handleModelsCommand(ctx) {
|
|
|
1906
2124
|
}
|
|
1907
2125
|
var GRADIENT_WIDTH = 30;
|
|
1908
2126
|
var BASE_COLOR = [124, 58, 237];
|
|
1909
|
-
|
|
2127
|
+
function getMinBrightness() {
|
|
2128
|
+
return getThemeMode() === "dark" ? 0.45 : 0.55;
|
|
2129
|
+
}
|
|
1910
2130
|
function hexToRgb(hex) {
|
|
1911
2131
|
const h = hex.replace("#", "");
|
|
1912
2132
|
return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)];
|
|
@@ -1926,7 +2146,8 @@ function applyGradientSweep(text, offset, color, fadeProgress = 0) {
|
|
|
1926
2146
|
distance = 100 - distance;
|
|
1927
2147
|
}
|
|
1928
2148
|
const normalizedDistance = Math.min(distance / (GRADIENT_WIDTH / 2), 1);
|
|
1929
|
-
const
|
|
2149
|
+
const minBrightness = getMinBrightness();
|
|
2150
|
+
const animBrightness = minBrightness + (1 - minBrightness) * (1 - normalizedDistance);
|
|
1930
2151
|
const brightness = animBrightness + (IDLE_BRIGHTNESS - animBrightness) * fadeProgress;
|
|
1931
2152
|
const r = Math.floor(baseColor[0] * brightness);
|
|
1932
2153
|
const g = Math.floor(baseColor[1] * brightness);
|
|
@@ -2063,7 +2284,7 @@ var OMProgressComponent = class extends Container {
|
|
|
2063
2284
|
if (this.state.thresholdPercent > 0) {
|
|
2064
2285
|
const percent = Math.round(this.state.thresholdPercent);
|
|
2065
2286
|
const bar = this.renderProgressBar(percent, 10);
|
|
2066
|
-
this.statusText.setText(fg("muted", `OM ${bar} ${percent}%`));
|
|
2287
|
+
this.statusText.setText(theme.fg("muted", `OM ${bar} ${percent}%`));
|
|
2067
2288
|
} else {
|
|
2068
2289
|
this.statusText.setText("");
|
|
2069
2290
|
}
|
|
@@ -2126,7 +2347,7 @@ function formatObservationStatus(state, compact, labelStyler) {
|
|
|
2126
2347
|
}
|
|
2127
2348
|
const label = compact === "full" ? "messages" : "msg";
|
|
2128
2349
|
const fraction = `${formatTokensValue(state.pendingTokens)}/${formatTokensThreshold(state.threshold)}`;
|
|
2129
|
-
const buffered = compact !== "noBuffer" && state.buffered.observations.projectedMessageRemoval > 0 ?
|
|
2350
|
+
const buffered = compact !== "noBuffer" && state.buffered.observations.projectedMessageRemoval > 0 ? theme.fg("muted", ` \u2193${formatTokensThreshold(state.buffered.observations.projectedMessageRemoval)}`) : "";
|
|
2130
2351
|
return styleLabel(`${label} `) + colorByPercent(fraction, percent) + buffered;
|
|
2131
2352
|
}
|
|
2132
2353
|
function formatReflectionStatus(state, compact, labelStyler) {
|
|
@@ -2140,7 +2361,7 @@ function formatReflectionStatus(state, compact, labelStyler) {
|
|
|
2140
2361
|
}
|
|
2141
2362
|
const fraction = `${formatTokensValue(state.observationTokens)}/${formatTokensThreshold(state.reflectionThreshold)}`;
|
|
2142
2363
|
const savings = state.buffered.reflection.inputObservationTokens - state.buffered.reflection.observationTokens;
|
|
2143
|
-
const buffered = compact !== "noBuffer" && state.buffered.reflection.status === "complete" ?
|
|
2364
|
+
const buffered = compact !== "noBuffer" && state.buffered.reflection.status === "complete" ? theme.fg("muted", ` \u2193${formatTokensThreshold(savings)}`) : "";
|
|
2144
2365
|
return label + colorByPercent(fraction, percent) + buffered;
|
|
2145
2366
|
}
|
|
2146
2367
|
function formatOMStatus(state) {
|
|
@@ -2150,6 +2371,16 @@ function formatOMStatus(state) {
|
|
|
2150
2371
|
// src/tui/status-line.ts
|
|
2151
2372
|
var OBSERVER_COLOR = mastra.orange;
|
|
2152
2373
|
var REFLECTOR_COLOR = mastra.pink;
|
|
2374
|
+
function lighten(r, g, b, factor) {
|
|
2375
|
+
return [Math.floor(r + (255 - r) * factor), Math.floor(g + (255 - g) * factor), Math.floor(b + (255 - b) * factor)];
|
|
2376
|
+
}
|
|
2377
|
+
function adjustBadgeColor(r, g, b, modeColor) {
|
|
2378
|
+
if (getThemeMode() !== "light") return [r, g, b];
|
|
2379
|
+
if (modeColor === mastra.purple || modeColor === mastra.blue) {
|
|
2380
|
+
return lighten(r, g, b, 0.25);
|
|
2381
|
+
}
|
|
2382
|
+
return [r, g, b];
|
|
2383
|
+
}
|
|
2153
2384
|
function updateStatusLine(state) {
|
|
2154
2385
|
if (!state.statusLine) return;
|
|
2155
2386
|
const termWidth = (process.stdout.columns || 80) - 1;
|
|
@@ -2180,25 +2411,26 @@ function updateStatusLine(state) {
|
|
|
2180
2411
|
badgeBrightness = animBrightness + (0.9 - animBrightness) * fade;
|
|
2181
2412
|
}
|
|
2182
2413
|
}
|
|
2183
|
-
const [mr, mg, mb] =
|
|
2414
|
+
const [mr, mg, mb] = adjustBadgeColor(
|
|
2184
2415
|
Math.floor(mcr * badgeBrightness),
|
|
2185
2416
|
Math.floor(mcg * badgeBrightness),
|
|
2186
|
-
Math.floor(mcb * badgeBrightness)
|
|
2187
|
-
|
|
2188
|
-
|
|
2417
|
+
Math.floor(mcb * badgeBrightness),
|
|
2418
|
+
modeColor
|
|
2419
|
+
);
|
|
2420
|
+
modeBadge = chalk10.bgRgb(mr, mg, mb).hex("#000000").bold(` ${badgeName.toLowerCase()} `);
|
|
2189
2421
|
modeBadgeWidth = badgeName.length + 2;
|
|
2190
2422
|
} else if (badgeName) {
|
|
2191
|
-
modeBadge = fg("dim", badgeName) + " ";
|
|
2423
|
+
modeBadge = theme.fg("dim", badgeName) + " ";
|
|
2192
2424
|
modeBadgeWidth = badgeName.length + 1;
|
|
2193
2425
|
}
|
|
2194
2426
|
if (mainModeColor) {
|
|
2195
|
-
const [br,
|
|
2427
|
+
const [br, bg, bb] = [
|
|
2196
2428
|
parseInt(mainModeColor.slice(1, 3), 16),
|
|
2197
2429
|
parseInt(mainModeColor.slice(3, 5), 16),
|
|
2198
2430
|
parseInt(mainModeColor.slice(5, 7), 16)
|
|
2199
2431
|
];
|
|
2200
2432
|
const dim = 0.35;
|
|
2201
|
-
state.editor.borderColor = (text) => chalk10.rgb(Math.floor(br * dim), Math.floor(
|
|
2433
|
+
state.editor.borderColor = (text) => chalk10.rgb(Math.floor(br * dim), Math.floor(bg * dim), Math.floor(bb * dim))(text);
|
|
2202
2434
|
}
|
|
2203
2435
|
const fullModelId = showOMMode ? isObserving ? state.harness.getObserverModelId() : state.harness.getReflectorModelId() : state.harness.getFullModelId();
|
|
2204
2436
|
const shortModelId = fullModelId.includes("/") ? fullModelId.slice(fullModelId.indexOf("/") + 1) : fullModelId;
|
|
@@ -2208,14 +2440,15 @@ function updateStatusLine(state) {
|
|
|
2208
2440
|
if (homedir2 && displayPath.startsWith(homedir2)) {
|
|
2209
2441
|
displayPath = "~" + displayPath.slice(homedir2.length);
|
|
2210
2442
|
}
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2443
|
+
const branch = state.projectInfo.gitBranch;
|
|
2444
|
+
const dirFull = branch ? `${displayPath} (${branch})` : displayPath;
|
|
2445
|
+
const dirBranchOnly = branch || null;
|
|
2446
|
+
const dirBranchShort = branch && branch.length > 24 ? branch.slice(0, 12) + ".." + branch.slice(-8) : dirBranchOnly;
|
|
2214
2447
|
const isYolo = state.harness.getState().yolo === true;
|
|
2215
2448
|
const styleModelId = (id) => {
|
|
2216
2449
|
if (!state.modelAuthStatus.hasAuth) {
|
|
2217
2450
|
const envVar = state.modelAuthStatus.apiKeyEnvVar;
|
|
2218
|
-
return fg("dim", id) + fg("error", " \u2717") + fg("muted", envVar ? ` (${envVar})` : " (no key)");
|
|
2451
|
+
return theme.fg("dim", id) + theme.fg("error", " \u2717") + theme.fg("muted", envVar ? ` (${envVar})` : " (no key)");
|
|
2219
2452
|
}
|
|
2220
2453
|
const tintBg = modeColor ? tintHex(modeColor, 0.15) : void 0;
|
|
2221
2454
|
const padded = ` ${id} `;
|
|
@@ -2233,11 +2466,12 @@ function updateStatusLine(state) {
|
|
|
2233
2466
|
}
|
|
2234
2467
|
}
|
|
2235
2468
|
if (modeColor) {
|
|
2236
|
-
const [r, g, b] =
|
|
2469
|
+
const [r, g, b] = adjustBadgeColor(
|
|
2237
2470
|
parseInt(modeColor.slice(1, 3), 16),
|
|
2238
2471
|
parseInt(modeColor.slice(3, 5), 16),
|
|
2239
|
-
parseInt(modeColor.slice(5, 7), 16)
|
|
2240
|
-
|
|
2472
|
+
parseInt(modeColor.slice(5, 7), 16),
|
|
2473
|
+
modeColor
|
|
2474
|
+
);
|
|
2241
2475
|
const dim = 0.8;
|
|
2242
2476
|
const fgStyled = chalk10.rgb(Math.floor(r * dim), Math.floor(g * dim), Math.floor(b * dim)).bold(padded);
|
|
2243
2477
|
return tintBg ? chalk10.bgHex(tintBg)(fgStyled) : fgStyled;
|
|
@@ -2262,16 +2496,17 @@ function updateStatusLine(state) {
|
|
|
2262
2496
|
sBadgeBrightness = animBrightness + (0.9 - animBrightness) * fade;
|
|
2263
2497
|
}
|
|
2264
2498
|
}
|
|
2265
|
-
const [sr, sg, sb] =
|
|
2499
|
+
const [sr, sg, sb] = adjustBadgeColor(
|
|
2266
2500
|
Math.floor(mcr * sBadgeBrightness),
|
|
2267
2501
|
Math.floor(mcg * sBadgeBrightness),
|
|
2268
|
-
Math.floor(mcb * sBadgeBrightness)
|
|
2269
|
-
|
|
2270
|
-
|
|
2502
|
+
Math.floor(mcb * sBadgeBrightness),
|
|
2503
|
+
modeColor
|
|
2504
|
+
);
|
|
2505
|
+
shortModeBadge = chalk10.bgRgb(sr, sg, sb).hex("#000000").bold(` ${shortName} `);
|
|
2271
2506
|
shortModeBadgeWidth = shortName.length + 2;
|
|
2272
2507
|
} else if (badgeName) {
|
|
2273
2508
|
const shortName = badgeName.toLowerCase().charAt(0);
|
|
2274
|
-
shortModeBadge = fg("dim", shortName) + " ";
|
|
2509
|
+
shortModeBadge = theme.fg("dim", shortName) + " ";
|
|
2275
2510
|
shortModeBadgeWidth = shortName.length + 1;
|
|
2276
2511
|
}
|
|
2277
2512
|
const buildLine = (opts) => {
|
|
@@ -2312,16 +2547,18 @@ function updateStatusLine(state) {
|
|
|
2312
2547
|
if (ref) {
|
|
2313
2548
|
parts.push({ plain: ref, styled: ref });
|
|
2314
2549
|
}
|
|
2315
|
-
|
|
2550
|
+
const dirText = opts.dir !== void 0 ? opts.dir : opts.showDir ? dirFull : null;
|
|
2551
|
+
if (dirText) {
|
|
2316
2552
|
parts.push({
|
|
2317
|
-
plain:
|
|
2318
|
-
styled: fg("dim",
|
|
2553
|
+
plain: dirText,
|
|
2554
|
+
styled: theme.fg("dim", dirText)
|
|
2319
2555
|
});
|
|
2320
2556
|
}
|
|
2321
2557
|
const totalPlain = useBadgeWidth + parts.reduce((sum, p, i) => sum + visibleWidth(p.plain) + (i > 0 ? SEP.length : 0), 0);
|
|
2322
2558
|
if (totalPlain > termWidth) return null;
|
|
2323
2559
|
let styledLine;
|
|
2324
|
-
|
|
2560
|
+
const hasDir = !!dirText;
|
|
2561
|
+
if (hasDir && parts.length >= 3) {
|
|
2325
2562
|
const leftPart = parts[0];
|
|
2326
2563
|
const centerParts = parts.slice(1, -1);
|
|
2327
2564
|
const dirPart = parts[parts.length - 1];
|
|
@@ -2333,7 +2570,7 @@ function updateStatusLine(state) {
|
|
|
2333
2570
|
const gapLeft = Math.floor(freeSpace / 2);
|
|
2334
2571
|
const gapRight = freeSpace - gapLeft;
|
|
2335
2572
|
styledLine = useBadge + leftPart.styled + " ".repeat(Math.max(gapLeft, 1)) + centerParts.map((p) => p.styled).join(SEP) + " ".repeat(Math.max(gapRight, 1)) + dirPart.styled;
|
|
2336
|
-
} else if (
|
|
2573
|
+
} else if (hasDir && parts.length === 2) {
|
|
2337
2574
|
const mainStr = useBadge + parts[0].styled;
|
|
2338
2575
|
const dirPart = parts[parts.length - 1];
|
|
2339
2576
|
const gap = termWidth - totalPlain;
|
|
@@ -2344,23 +2581,25 @@ function updateStatusLine(state) {
|
|
|
2344
2581
|
return { plain: "", styled: styledLine };
|
|
2345
2582
|
};
|
|
2346
2583
|
const result = (
|
|
2347
|
-
// 1. Full badge + full model + long labels + fractions + buffer + dir
|
|
2348
|
-
buildLine({ modelId: fullModelId, memCompact: "full", showDir:
|
|
2349
|
-
buildLine({ modelId: fullModelId, memCompact: "full", showDir: false }) ?? // 3.
|
|
2350
|
-
buildLine({ modelId:
|
|
2351
|
-
buildLine({ modelId:
|
|
2352
|
-
buildLine({ modelId: tinyModelId,
|
|
2584
|
+
// 1. Full badge + full model + long labels + fractions + buffer + full dir
|
|
2585
|
+
buildLine({ modelId: fullModelId, memCompact: "full", showDir: false, dir: dirFull }) ?? // 2. Full badge + full model + branch only (drop path)
|
|
2586
|
+
buildLine({ modelId: fullModelId, memCompact: "full", showDir: false, dir: dirBranchOnly }) ?? // 3. Full badge + full model + abbreviated branch
|
|
2587
|
+
buildLine({ modelId: fullModelId, memCompact: "full", showDir: false, dir: dirBranchShort }) ?? // 4. Drop directory entirely
|
|
2588
|
+
buildLine({ modelId: fullModelId, memCompact: "full", showDir: false }) ?? // 5. Drop provider + "claude-" prefix, keep full labels + fractions + buffer
|
|
2589
|
+
buildLine({ modelId: tinyModelId, memCompact: "full", showDir: false }) ?? // 6. Short labels (msg/mem) + fractions + buffer
|
|
2590
|
+
buildLine({ modelId: tinyModelId, showDir: false }) ?? // 7. Short badge + short labels + fractions + buffer
|
|
2591
|
+
buildLine({ modelId: tinyModelId, showDir: false, badge: "short" }) ?? // 8. Short badge + fractions (drop buffer indicator)
|
|
2353
2592
|
buildLine({
|
|
2354
2593
|
modelId: tinyModelId,
|
|
2355
2594
|
memCompact: "noBuffer",
|
|
2356
2595
|
showDir: false,
|
|
2357
2596
|
badge: "short"
|
|
2358
|
-
}) ?? //
|
|
2597
|
+
}) ?? // 9. Full badge + percent only
|
|
2359
2598
|
buildLine({
|
|
2360
2599
|
modelId: tinyModelId,
|
|
2361
2600
|
memCompact: "percentOnly",
|
|
2362
2601
|
showDir: false
|
|
2363
|
-
}) ?? //
|
|
2602
|
+
}) ?? // 10. Short badge + percent only
|
|
2364
2603
|
buildLine({
|
|
2365
2604
|
modelId: tinyModelId,
|
|
2366
2605
|
memCompact: "percentOnly",
|
|
@@ -2471,16 +2710,21 @@ function applyPack(ctx, pack) {
|
|
|
2471
2710
|
}
|
|
2472
2711
|
s.models.subagentModels = {};
|
|
2473
2712
|
saveSettings(s);
|
|
2713
|
+
const hasOpenAI = Object.values(pack.models).some((m) => m.startsWith("openai/"));
|
|
2714
|
+
const currentThinking = harness.getState()?.thinkingLevel ?? "off";
|
|
2715
|
+
if (hasOpenAI && currentThinking === "off") {
|
|
2716
|
+
harness.setState({ thinkingLevel: "low" });
|
|
2717
|
+
}
|
|
2474
2718
|
updateStatusLine(ctx.state);
|
|
2475
2719
|
}
|
|
2476
2720
|
function getPackDetail(pack) {
|
|
2477
2721
|
if (pack.id === "custom") {
|
|
2478
|
-
return fg("dim", " You'll pick a model for each mode.");
|
|
2722
|
+
return theme.fg("dim", " You'll pick a model for each mode.");
|
|
2479
2723
|
}
|
|
2480
2724
|
return [
|
|
2481
|
-
` ${chalk10.hex(mastra.blue)("plan")} \u2192 ${fg("text", pack.models.plan)}`,
|
|
2482
|
-
` ${chalk10.hex(mastra.purple)("build")} \u2192 ${fg("text", pack.models.build)}`,
|
|
2483
|
-
` ${chalk10.hex(mastra.green)("fast")} \u2192 ${fg("text", pack.models.fast)}`
|
|
2725
|
+
` ${chalk10.hex(mastra.blue)("plan")} \u2192 ${theme.fg("text", pack.models.plan)}`,
|
|
2726
|
+
` ${chalk10.hex(mastra.purple)("build")} \u2192 ${theme.fg("text", pack.models.build)}`,
|
|
2727
|
+
` ${chalk10.hex(mastra.green)("fast")} \u2192 ${theme.fg("text", pack.models.fast)}`
|
|
2484
2728
|
].join("\n");
|
|
2485
2729
|
}
|
|
2486
2730
|
async function handleModelsPackCommand(ctx) {
|
|
@@ -2508,11 +2752,11 @@ async function handleModelsPackCommand(ctx) {
|
|
|
2508
2752
|
const currentPackId = settings.models.activeModelPackId;
|
|
2509
2753
|
const items = packs.map((p) => ({
|
|
2510
2754
|
value: p.id,
|
|
2511
|
-
label: ` ${p.name} ${fg("dim", p.description)}${p.id === currentPackId ? fg("dim", " (current)") : ""}`
|
|
2755
|
+
label: ` ${p.name} ${theme.fg("dim", p.description)}${p.id === currentPackId ? theme.fg("dim", " (current)") : ""}`
|
|
2512
2756
|
}));
|
|
2513
2757
|
return new Promise((resolve2) => {
|
|
2514
2758
|
const container = new Box(1, 1);
|
|
2515
|
-
container.addChild(new Text(bold(fg("accent", "Switch model pack")), 0, 0));
|
|
2759
|
+
container.addChild(new Text(theme.bold(theme.fg("accent", "Switch model pack")), 0, 0));
|
|
2516
2760
|
container.addChild(new Spacer(1));
|
|
2517
2761
|
const selectList = new SelectList(items, items.length, getSelectListTheme());
|
|
2518
2762
|
const detailText = new Text("", 0, 0);
|
|
@@ -2535,14 +2779,14 @@ async function handleModelsPackCommand(ctx) {
|
|
|
2535
2779
|
const customPack = await runCustomFlow(ctx);
|
|
2536
2780
|
if (customPack) {
|
|
2537
2781
|
applyPack(ctx, customPack);
|
|
2538
|
-
collapseResult(`Model pack \u2192 ${bold("Custom")}`);
|
|
2782
|
+
collapseResult(`Model pack \u2192 ${theme.bold("Custom")}`);
|
|
2539
2783
|
ctx.showInfo("Switched to Custom pack");
|
|
2540
2784
|
} else {
|
|
2541
2785
|
collapseResult("cancelled");
|
|
2542
2786
|
}
|
|
2543
2787
|
} else {
|
|
2544
2788
|
applyPack(ctx, pack);
|
|
2545
|
-
collapseResult(`Model pack \u2192 ${bold(pack.name)}`);
|
|
2789
|
+
collapseResult(`Model pack \u2192 ${theme.bold(pack.name)}`);
|
|
2546
2790
|
ctx.showInfo(`Switched to ${pack.name} pack`);
|
|
2547
2791
|
}
|
|
2548
2792
|
resolve2();
|
|
@@ -2559,7 +2803,7 @@ async function handleModelsPackCommand(ctx) {
|
|
|
2559
2803
|
container.addChild(new Spacer(1));
|
|
2560
2804
|
container.addChild(detailText);
|
|
2561
2805
|
container.addChild(new Spacer(1));
|
|
2562
|
-
container.addChild(new Text(fg("dim", "\u2191\u2193 navigate \xB7 Enter select \xB7 Esc cancel"), 0, 0));
|
|
2806
|
+
container.addChild(new Text(theme.fg("dim", "\u2191\u2193 navigate \xB7 Enter select \xB7 Esc cancel"), 0, 0));
|
|
2563
2807
|
const currentIdx = packs.findIndex((p) => p.id === currentPackId);
|
|
2564
2808
|
const initialIdx = currentIdx >= 0 ? currentIdx : 0;
|
|
2565
2809
|
if (initialIdx > 0) selectList.setSelectedIndex(initialIdx);
|
|
@@ -2569,9 +2813,9 @@ async function handleModelsPackCommand(ctx) {
|
|
|
2569
2813
|
const collapseResult = (result) => {
|
|
2570
2814
|
container.clear();
|
|
2571
2815
|
if (result === "cancelled") {
|
|
2572
|
-
container.addChild(new Text(fg("dim", `${fg("error", "\u2717")} Model pack (cancelled)`), 0, 0));
|
|
2816
|
+
container.addChild(new Text(theme.fg("dim", `${theme.fg("error", "\u2717")} Model pack (cancelled)`), 0, 0));
|
|
2573
2817
|
} else if (result) {
|
|
2574
|
-
container.addChild(new Text(fg("text", `${fg("success", "\u2713")} ${result}`), 0, 0));
|
|
2818
|
+
container.addChild(new Text(theme.fg("text", `${theme.fg("success", "\u2713")} ${result}`), 0, 0));
|
|
2575
2819
|
}
|
|
2576
2820
|
};
|
|
2577
2821
|
ctx.state.chatContainer.addChild(new Spacer(1));
|
|
@@ -2757,13 +3001,13 @@ var ThresholdSubmenu = class extends Container {
|
|
|
2757
3001
|
super();
|
|
2758
3002
|
this.onDone = onDone;
|
|
2759
3003
|
this.onBack = onBack;
|
|
2760
|
-
this.addChild(new Text(bold(fg("accent", title)), 0, 0));
|
|
3004
|
+
this.addChild(new Text(theme.bold(theme.fg("accent", title)), 0, 0));
|
|
2761
3005
|
this.addChild(new Spacer(1));
|
|
2762
|
-
this.addChild(new Text(fg("muted", " _k tokens (type a number, e.g. 30 for 30k):"), 0, 0));
|
|
3006
|
+
this.addChild(new Text(theme.fg("muted", " _k tokens (type a number, e.g. 30 for 30k):"), 0, 0));
|
|
2763
3007
|
this.input = new Input();
|
|
2764
3008
|
this.addChild(this.input);
|
|
2765
3009
|
this.addChild(new Spacer(1));
|
|
2766
|
-
this.addChild(new Text(fg("muted", " Or pick a preset:"), 0, 0));
|
|
3010
|
+
this.addChild(new Text(theme.fg("muted", " Or pick a preset:"), 0, 0));
|
|
2767
3011
|
const items = presets.map((p) => ({
|
|
2768
3012
|
value: String(p),
|
|
2769
3013
|
label: ` ${formatTokens(p)} tokens`
|
|
@@ -2779,7 +3023,7 @@ var ThresholdSubmenu = class extends Container {
|
|
|
2779
3023
|
this.selectList.onCancel = onBack;
|
|
2780
3024
|
this.addChild(this.selectList);
|
|
2781
3025
|
this.addChild(new Spacer(1));
|
|
2782
|
-
this.addChild(new Text(fg("dim", " Enter to confirm \xB7 \u2193 for presets \xB7 Esc to go back"), 0, 0));
|
|
3026
|
+
this.addChild(new Text(theme.fg("dim", " Enter to confirm \xB7 \u2193 for presets \xB7 Esc to go back"), 0, 0));
|
|
2783
3027
|
}
|
|
2784
3028
|
handleInput(data) {
|
|
2785
3029
|
if (this.inInputMode) {
|
|
@@ -2822,9 +3066,9 @@ var ModelSelectSubmenu = class extends Container {
|
|
|
2822
3066
|
this.onSelect = onSelect;
|
|
2823
3067
|
this.onCancel = onCancel;
|
|
2824
3068
|
this.tui = tui;
|
|
2825
|
-
this.addChild(new Text(bold(fg("accent", title)), 0, 0));
|
|
3069
|
+
this.addChild(new Text(theme.bold(theme.fg("accent", title)), 0, 0));
|
|
2826
3070
|
this.addChild(new Spacer(1));
|
|
2827
|
-
this.addChild(new Text(fg("muted", "Type to search \xB7 \u2191\u2193 navigate \xB7 Enter select \xB7 Esc back"), 0, 0));
|
|
3071
|
+
this.addChild(new Text(theme.fg("muted", "Type to search \xB7 \u2191\u2193 navigate \xB7 Enter select \xB7 Esc back"), 0, 0));
|
|
2828
3072
|
this.addChild(new Spacer(1));
|
|
2829
3073
|
this.searchInput = new Input();
|
|
2830
3074
|
this.addChild(this.searchInput);
|
|
@@ -2852,15 +3096,15 @@ var ModelSelectSubmenu = class extends Container {
|
|
|
2852
3096
|
const item = this.filteredModels[i];
|
|
2853
3097
|
const isSelected = i === this.selectedIndex;
|
|
2854
3098
|
const isCurrent = item.id === this.currentModelId;
|
|
2855
|
-
const checkmark = isCurrent ? fg("success", " \u2713") : "";
|
|
2856
|
-
const line = isSelected ? fg("accent", `\u2192 ${item.label}`) + checkmark : ` ${item.label}` + checkmark;
|
|
3099
|
+
const checkmark = isCurrent ? theme.fg("success", " \u2713") : "";
|
|
3100
|
+
const line = isSelected ? theme.fg("accent", `\u2192 ${item.label}`) + checkmark : ` ${item.label}` + checkmark;
|
|
2857
3101
|
this.listContainer.addChild(new Text(line, 0, 0));
|
|
2858
3102
|
}
|
|
2859
3103
|
if (startIndex > 0 || endIndex < total) {
|
|
2860
|
-
this.listContainer.addChild(new Text(fg("muted", `(${this.selectedIndex + 1}/${total})`), 0, 0));
|
|
3104
|
+
this.listContainer.addChild(new Text(theme.fg("muted", `(${this.selectedIndex + 1}/${total})`), 0, 0));
|
|
2861
3105
|
}
|
|
2862
3106
|
if (total === 0) {
|
|
2863
|
-
this.listContainer.addChild(new Text(fg("muted", "No matching models"), 0, 0));
|
|
3107
|
+
this.listContainer.addChild(new Text(theme.fg("muted", "No matching models"), 0, 0));
|
|
2864
3108
|
}
|
|
2865
3109
|
}
|
|
2866
3110
|
handleInput(data) {
|
|
@@ -2899,8 +3143,8 @@ var OMSettingsComponent = class extends Box {
|
|
|
2899
3143
|
this._focused = value;
|
|
2900
3144
|
}
|
|
2901
3145
|
constructor(config, callbacks, models, tui) {
|
|
2902
|
-
super(2, 1, (text) => bg("overlayBg", text));
|
|
2903
|
-
this.addChild(new Text(bold(fg("accent", "Observational Memory Settings")), 0, 0));
|
|
3146
|
+
super(2, 1, (text) => theme.bg("overlayBg", text));
|
|
3147
|
+
this.addChild(new Text(theme.bold(theme.fg("accent", "Observational Memory Settings")), 0, 0));
|
|
2904
3148
|
this.addChild(new Spacer(1));
|
|
2905
3149
|
const items = [
|
|
2906
3150
|
{
|
|
@@ -3096,15 +3340,15 @@ var StorageBackendSubmenu = class extends Container {
|
|
|
3096
3340
|
this.phase = "connection";
|
|
3097
3341
|
this.clear();
|
|
3098
3342
|
if (this.pendingBackend === "pg") {
|
|
3099
|
-
this.addChild(new Text(bold(fg("accent", "PostgreSQL Connection")), 0, 0));
|
|
3343
|
+
this.addChild(new Text(theme.bold(theme.fg("accent", "PostgreSQL Connection")), 0, 0));
|
|
3100
3344
|
this.addChild(new Spacer(1));
|
|
3101
|
-
this.addChild(new Text(fg("muted", "Enter a connection string:"), 0, 0));
|
|
3102
|
-
this.addChild(new Text(fg("dim", "e.g. postgresql://user:pass@localhost:5432/mydb"), 0, 0));
|
|
3345
|
+
this.addChild(new Text(theme.fg("muted", "Enter a connection string:"), 0, 0));
|
|
3346
|
+
this.addChild(new Text(theme.fg("dim", "e.g. postgresql://user:pass@localhost:5432/mydb"), 0, 0));
|
|
3103
3347
|
} else {
|
|
3104
|
-
this.addChild(new Text(bold(fg("accent", "LibSQL Connection")), 0, 0));
|
|
3348
|
+
this.addChild(new Text(theme.bold(theme.fg("accent", "LibSQL Connection")), 0, 0));
|
|
3105
3349
|
this.addChild(new Spacer(1));
|
|
3106
|
-
this.addChild(new Text(fg("muted", "Enter a URL or leave empty for default local file:"), 0, 0));
|
|
3107
|
-
this.addChild(new Text(fg("dim", "e.g. libsql://your-db.turso.io"), 0, 0));
|
|
3350
|
+
this.addChild(new Text(theme.fg("muted", "Enter a URL or leave empty for default local file:"), 0, 0));
|
|
3351
|
+
this.addChild(new Text(theme.fg("dim", "e.g. libsql://your-db.turso.io"), 0, 0));
|
|
3108
3352
|
}
|
|
3109
3353
|
this.addChild(new Spacer(1));
|
|
3110
3354
|
this.input = new Input();
|
|
@@ -3114,7 +3358,7 @@ var StorageBackendSubmenu = class extends Container {
|
|
|
3114
3358
|
}
|
|
3115
3359
|
this.addChild(this.input);
|
|
3116
3360
|
this.addChild(new Spacer(1));
|
|
3117
|
-
this.addChild(new Text(fg("dim", "Enter to save \xB7 Esc to go back"), 0, 0));
|
|
3361
|
+
this.addChild(new Text(theme.fg("dim", "Enter to save \xB7 Esc to go back"), 0, 0));
|
|
3118
3362
|
}
|
|
3119
3363
|
handleInput(data) {
|
|
3120
3364
|
if (this.phase === "select") {
|
|
@@ -3154,8 +3398,8 @@ var SettingsComponent = class extends Box {
|
|
|
3154
3398
|
this._focused = value;
|
|
3155
3399
|
}
|
|
3156
3400
|
constructor(config, callbacks) {
|
|
3157
|
-
super(2, 1, (text) => bg("overlayBg", text));
|
|
3158
|
-
this.addChild(new Text(bold(fg("accent", "Settings")), 0, 0));
|
|
3401
|
+
super(2, 1, (text) => theme.bg("overlayBg", text));
|
|
3402
|
+
this.addChild(new Text(theme.bold(theme.fg("accent", "Settings")), 0, 0));
|
|
3159
3403
|
this.addChild(new Spacer(1));
|
|
3160
3404
|
const notificationModes = [
|
|
3161
3405
|
{ value: "off", label: "Off", desc: "No notifications" },
|
|
@@ -3163,13 +3407,11 @@ var SettingsComponent = class extends Box {
|
|
|
3163
3407
|
{ value: "system", label: "System", desc: "Native OS notification" },
|
|
3164
3408
|
{ value: "both", label: "Both", desc: "Bell + system notification" }
|
|
3165
3409
|
];
|
|
3166
|
-
const thinkingLevels =
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
{ value: "high", label: "High", desc: "~32k budget tokens" }
|
|
3172
|
-
];
|
|
3410
|
+
const thinkingLevels = getThinkingLevelsForModel(config.currentModelId).map((level) => ({
|
|
3411
|
+
value: level.id,
|
|
3412
|
+
label: level.label,
|
|
3413
|
+
desc: level.description
|
|
3414
|
+
}));
|
|
3173
3415
|
const getNotifLabel = (mode) => notificationModes.find((m) => m.value === mode)?.label ?? mode;
|
|
3174
3416
|
const getThinkingLabel = (level) => thinkingLevels.find((l) => l.value === level)?.label ?? level;
|
|
3175
3417
|
const items = [
|
|
@@ -3223,7 +3465,7 @@ var SettingsComponent = class extends Box {
|
|
|
3223
3465
|
{
|
|
3224
3466
|
id: "thinking",
|
|
3225
3467
|
label: "Thinking level",
|
|
3226
|
-
description: "
|
|
3468
|
+
description: "Reasoning depth level",
|
|
3227
3469
|
currentValue: getThinkingLabel(config.thinkingLevel),
|
|
3228
3470
|
submenu: (_currentValue, done) => new SelectSubmenu(
|
|
3229
3471
|
thinkingLevels.map((l) => ({
|
|
@@ -3313,6 +3555,7 @@ async function handleSettingsCommand(ctx) {
|
|
|
3313
3555
|
notifications: state?.notifications ?? "off",
|
|
3314
3556
|
yolo: state?.yolo === true,
|
|
3315
3557
|
thinkingLevel: state?.thinkingLevel ?? "off",
|
|
3558
|
+
currentModelId: ctx.state.harness.getCurrentModelId() ?? "",
|
|
3316
3559
|
escapeAsCancel: ctx.state.editor.escapeEnabled,
|
|
3317
3560
|
storageBackend: globalSettings.storage.backend,
|
|
3318
3561
|
pgConnectionString: globalSettings.storage.pg?.connectionString ?? "",
|
|
@@ -3367,12 +3610,12 @@ Storage backend changed to ${label}. Restarting is required.
|
|
|
3367
3610
|
}
|
|
3368
3611
|
var LoginDialogComponent = class extends Box {
|
|
3369
3612
|
constructor(tui, providerId, onComplete) {
|
|
3370
|
-
super(2, 1, (text) => bg("overlayBg", text));
|
|
3613
|
+
super(2, 1, (text) => theme.bg("overlayBg", text));
|
|
3371
3614
|
this.onComplete = onComplete;
|
|
3372
3615
|
this.tui = tui;
|
|
3373
3616
|
const providerInfo = getOAuthProviders().find((p) => p.id === providerId);
|
|
3374
3617
|
const providerName = providerInfo?.name || providerId;
|
|
3375
|
-
this.addChild(new Text(fg("warning", `Login to ${providerName}`)));
|
|
3618
|
+
this.addChild(new Text(theme.fg("warning", `Login to ${providerName}`)));
|
|
3376
3619
|
this.addChild(new Spacer(1));
|
|
3377
3620
|
this.contentContainer = new Container();
|
|
3378
3621
|
this.addChild(this.contentContainer);
|
|
@@ -3423,13 +3666,13 @@ var LoginDialogComponent = class extends Box {
|
|
|
3423
3666
|
*/
|
|
3424
3667
|
showAuth(url, instructions) {
|
|
3425
3668
|
this.contentContainer.clear();
|
|
3426
|
-
this.contentContainer.addChild(new Text(fg("accent", url)));
|
|
3669
|
+
this.contentContainer.addChild(new Text(theme.fg("accent", url)));
|
|
3427
3670
|
const clickHint = process.platform === "darwin" ? "Cmd+click to open" : "Ctrl+click to open";
|
|
3428
3671
|
const hyperlink = `\x1B]8;;${url}\x07${clickHint}\x1B]8;;\x07`;
|
|
3429
|
-
this.contentContainer.addChild(new Text(fg("muted", hyperlink)));
|
|
3672
|
+
this.contentContainer.addChild(new Text(theme.fg("muted", hyperlink)));
|
|
3430
3673
|
if (instructions) {
|
|
3431
3674
|
this.contentContainer.addChild(new Spacer(1));
|
|
3432
|
-
this.contentContainer.addChild(new Text(fg("warning", instructions)));
|
|
3675
|
+
this.contentContainer.addChild(new Text(theme.fg("warning", instructions)));
|
|
3433
3676
|
}
|
|
3434
3677
|
const openCmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
3435
3678
|
exec(`${openCmd} "${url}"`);
|
|
@@ -3440,12 +3683,12 @@ var LoginDialogComponent = class extends Box {
|
|
|
3440
3683
|
*/
|
|
3441
3684
|
showPrompt(message, placeholder) {
|
|
3442
3685
|
this.contentContainer.addChild(new Spacer(1));
|
|
3443
|
-
this.contentContainer.addChild(new Text(fg("text", message)));
|
|
3686
|
+
this.contentContainer.addChild(new Text(theme.fg("text", message)));
|
|
3444
3687
|
if (placeholder) {
|
|
3445
|
-
this.contentContainer.addChild(new Text(fg("muted", `e.g., ${placeholder}`)));
|
|
3688
|
+
this.contentContainer.addChild(new Text(theme.fg("muted", `e.g., ${placeholder}`)));
|
|
3446
3689
|
}
|
|
3447
3690
|
this.contentContainer.addChild(this.input);
|
|
3448
|
-
this.contentContainer.addChild(new Text(fg("muted", "(Escape to cancel, Enter to submit)")));
|
|
3691
|
+
this.contentContainer.addChild(new Text(theme.fg("muted", "(Escape to cancel, Enter to submit)")));
|
|
3449
3692
|
this.input.setValue("");
|
|
3450
3693
|
this.tui.requestRender();
|
|
3451
3694
|
return new Promise((resolve2, reject) => {
|
|
@@ -3457,7 +3700,7 @@ var LoginDialogComponent = class extends Box {
|
|
|
3457
3700
|
* Show progress message
|
|
3458
3701
|
*/
|
|
3459
3702
|
showProgress(message) {
|
|
3460
|
-
this.contentContainer.addChild(new Text(fg("muted", message)));
|
|
3703
|
+
this.contentContainer.addChild(new Text(theme.fg("muted", message)));
|
|
3461
3704
|
this.tui.requestRender();
|
|
3462
3705
|
}
|
|
3463
3706
|
handleInput(data) {
|
|
@@ -3478,6 +3721,15 @@ async function performLogin(ctx, providerId) {
|
|
|
3478
3721
|
ctx.showError("Auth storage not configured");
|
|
3479
3722
|
return;
|
|
3480
3723
|
}
|
|
3724
|
+
if (providerId === ANTHROPIC_OAUTH_PROVIDER_ID) {
|
|
3725
|
+
const warningResult = await showClaudeMaxOAuthWarning(ctx.state, "login");
|
|
3726
|
+
if (warningResult !== "continue") {
|
|
3727
|
+
return;
|
|
3728
|
+
}
|
|
3729
|
+
const settings = loadSettings();
|
|
3730
|
+
settings.onboarding.claudeMaxOAuthWarningAcknowledgedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3731
|
+
saveSettings(settings);
|
|
3732
|
+
}
|
|
3481
3733
|
return new Promise((resolve2) => {
|
|
3482
3734
|
const dialog = new LoginDialogComponent(ctx.state.ui, providerId, (success, message) => {
|
|
3483
3735
|
ctx.state.ui.hideOverlay();
|
|
@@ -3639,6 +3891,121 @@ Pay special attention to: ${focusArea}
|
|
|
3639
3891
|
async function handleSetupCommand(ctx) {
|
|
3640
3892
|
await ctx.showOnboarding();
|
|
3641
3893
|
}
|
|
3894
|
+
|
|
3895
|
+
// src/tui/detect-theme.ts
|
|
3896
|
+
function queryTerminalBackground(timeoutMs = 200) {
|
|
3897
|
+
return new Promise((resolve2) => {
|
|
3898
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
3899
|
+
resolve2(null);
|
|
3900
|
+
return;
|
|
3901
|
+
}
|
|
3902
|
+
let settled = false;
|
|
3903
|
+
let buffer = "";
|
|
3904
|
+
let wasRaw;
|
|
3905
|
+
let wasResumed = false;
|
|
3906
|
+
let timer;
|
|
3907
|
+
const cleanup = () => {
|
|
3908
|
+
if (settled) return;
|
|
3909
|
+
settled = true;
|
|
3910
|
+
if (timer) {
|
|
3911
|
+
clearTimeout(timer);
|
|
3912
|
+
timer = void 0;
|
|
3913
|
+
}
|
|
3914
|
+
process.stdin.removeListener("data", onData);
|
|
3915
|
+
try {
|
|
3916
|
+
if (process.stdin.isTTY) {
|
|
3917
|
+
process.stdin.setRawMode(wasRaw);
|
|
3918
|
+
}
|
|
3919
|
+
} catch {
|
|
3920
|
+
}
|
|
3921
|
+
if (wasResumed) {
|
|
3922
|
+
process.stdin.pause();
|
|
3923
|
+
}
|
|
3924
|
+
};
|
|
3925
|
+
const onData = (data) => {
|
|
3926
|
+
buffer += data.toString();
|
|
3927
|
+
const match = buffer.match(/\x1b\]11;rgb:([0-9a-fA-F]+)\/([0-9a-fA-F]+)\/([0-9a-fA-F]+)/);
|
|
3928
|
+
if (match) {
|
|
3929
|
+
cleanup();
|
|
3930
|
+
const rHex = match[1];
|
|
3931
|
+
const gHex = match[2];
|
|
3932
|
+
const bHex = match[3];
|
|
3933
|
+
const normalize = (hex) => {
|
|
3934
|
+
const val = parseInt(hex, 16);
|
|
3935
|
+
return hex.length <= 2 ? val / 255 : val / 65535;
|
|
3936
|
+
};
|
|
3937
|
+
const r = normalize(rHex);
|
|
3938
|
+
const g = normalize(gHex);
|
|
3939
|
+
const b = normalize(bHex);
|
|
3940
|
+
const linearize = (c) => c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
|
|
3941
|
+
const luma = 0.2126 * linearize(r) + 0.7152 * linearize(g) + 0.0722 * linearize(b);
|
|
3942
|
+
resolve2(luma >= 0.5 ? "light" : "dark");
|
|
3943
|
+
return;
|
|
3944
|
+
}
|
|
3945
|
+
};
|
|
3946
|
+
timer = setTimeout(() => {
|
|
3947
|
+
cleanup();
|
|
3948
|
+
resolve2(null);
|
|
3949
|
+
}, timeoutMs);
|
|
3950
|
+
if (timer.unref) timer.unref();
|
|
3951
|
+
try {
|
|
3952
|
+
wasRaw = process.stdin.isRaw ?? false;
|
|
3953
|
+
process.stdin.setRawMode(true);
|
|
3954
|
+
if (process.stdin.isPaused()) {
|
|
3955
|
+
process.stdin.resume();
|
|
3956
|
+
wasResumed = true;
|
|
3957
|
+
}
|
|
3958
|
+
process.stdin.on("data", onData);
|
|
3959
|
+
process.stdout.write("\x1B]11;?\x07");
|
|
3960
|
+
} catch {
|
|
3961
|
+
cleanup();
|
|
3962
|
+
resolve2(null);
|
|
3963
|
+
}
|
|
3964
|
+
});
|
|
3965
|
+
}
|
|
3966
|
+
function detectFromColorFgBg() {
|
|
3967
|
+
const colorFgBg = process.env.COLORFGBG;
|
|
3968
|
+
if (!colorFgBg) return null;
|
|
3969
|
+
const parts = colorFgBg.split(";");
|
|
3970
|
+
const bgPart = parts[parts.length - 1];
|
|
3971
|
+
if (bgPart === void 0) return null;
|
|
3972
|
+
const bgIndex = parseInt(bgPart, 10);
|
|
3973
|
+
if (isNaN(bgIndex)) return null;
|
|
3974
|
+
return bgIndex >= 7 ? "light" : "dark";
|
|
3975
|
+
}
|
|
3976
|
+
async function detectTerminalTheme() {
|
|
3977
|
+
const envTheme = process.env.MASTRA_THEME?.toLowerCase();
|
|
3978
|
+
if (envTheme === "light") return "light";
|
|
3979
|
+
if (envTheme === "dark") return "dark";
|
|
3980
|
+
const oscResult = await queryTerminalBackground(200);
|
|
3981
|
+
if (oscResult) return oscResult;
|
|
3982
|
+
const fgbgResult = detectFromColorFgBg();
|
|
3983
|
+
if (fgbgResult) return fgbgResult;
|
|
3984
|
+
return "dark";
|
|
3985
|
+
}
|
|
3986
|
+
|
|
3987
|
+
// src/tui/commands/theme.ts
|
|
3988
|
+
async function handleThemeCommand(ctx, args) {
|
|
3989
|
+
const arg = args[0]?.toLowerCase();
|
|
3990
|
+
if (!arg) {
|
|
3991
|
+
const mode = getThemeMode();
|
|
3992
|
+
const settings2 = loadSettings();
|
|
3993
|
+
const pref = settings2.preferences.theme ?? "auto";
|
|
3994
|
+
ctx.showInfo(`Theme: ${mode} (preference: ${pref})`);
|
|
3995
|
+
return;
|
|
3996
|
+
}
|
|
3997
|
+
if (arg !== "auto" && arg !== "dark" && arg !== "light") {
|
|
3998
|
+
ctx.showError("Usage: /theme [auto|dark|light]");
|
|
3999
|
+
return;
|
|
4000
|
+
}
|
|
4001
|
+
const settings = loadSettings();
|
|
4002
|
+
settings.preferences.theme = arg;
|
|
4003
|
+
saveSettings(settings);
|
|
4004
|
+
const resolved = arg === "auto" ? await detectTerminalTheme() : arg;
|
|
4005
|
+
applyThemeMode(resolved);
|
|
4006
|
+
ctx.showInfo(`Theme set to ${arg}${arg === "auto" ? ` (detected: ${resolved})` : ""}`);
|
|
4007
|
+
ctx.state.ui.requestRender();
|
|
4008
|
+
}
|
|
3642
4009
|
var MAX_COLLAPSED_LINES = 3;
|
|
3643
4010
|
var BORDER_COLOR = mastra.purple;
|
|
3644
4011
|
var SlashCommandComponent = class extends Container {
|
|
@@ -3866,12 +4233,12 @@ function reasonToMessage(reason) {
|
|
|
3866
4233
|
// src/tui/display.ts
|
|
3867
4234
|
function showError(state, message) {
|
|
3868
4235
|
state.chatContainer.addChild(new Spacer(1));
|
|
3869
|
-
state.chatContainer.addChild(new Text(fg("error", `Error: ${message}`), 1, 0));
|
|
4236
|
+
state.chatContainer.addChild(new Text(theme.fg("error", `Error: ${message}`), 1, 0));
|
|
3870
4237
|
state.ui.requestRender();
|
|
3871
4238
|
}
|
|
3872
4239
|
function showInfo(state, message) {
|
|
3873
4240
|
state.chatContainer.addChild(new Spacer(1));
|
|
3874
|
-
state.chatContainer.addChild(new Text(fg("muted", message), 1, 0));
|
|
4241
|
+
state.chatContainer.addChild(new Text(theme.fg("muted", message), 1, 0));
|
|
3875
4242
|
state.ui.requestRender();
|
|
3876
4243
|
}
|
|
3877
4244
|
function showFormattedError(state, event) {
|
|
@@ -3881,9 +4248,9 @@ function showFormattedError(state, event) {
|
|
|
3881
4248
|
const errorMessage = error.message || String(error);
|
|
3882
4249
|
const isValidationError = errorMessage.toLowerCase().includes("validation failed") || errorMessage.toLowerCase().includes("required parameter") || errorMessage.includes("Required");
|
|
3883
4250
|
if (isValidationError) {
|
|
3884
|
-
state.chatContainer.addChild(new Text(fg("error", "Tool validation error - see details above"), 1, 0));
|
|
4251
|
+
state.chatContainer.addChild(new Text(theme.fg("error", "Tool validation error - see details above"), 1, 0));
|
|
3885
4252
|
state.chatContainer.addChild(
|
|
3886
|
-
new Text(fg("muted", " Check the tool execution box for specific parameter requirements"), 1, 0)
|
|
4253
|
+
new Text(theme.fg("muted", " Check the tool execution box for specific parameter requirements"), 1, 0)
|
|
3887
4254
|
);
|
|
3888
4255
|
} else {
|
|
3889
4256
|
let errorText = `Error: ${parsed.message}`;
|
|
@@ -3891,12 +4258,12 @@ function showFormattedError(state, event) {
|
|
|
3891
4258
|
const retryDelay = "retryDelay" in event ? event.retryDelay : parsed.retryDelay;
|
|
3892
4259
|
if (retryable && retryDelay) {
|
|
3893
4260
|
const seconds = Math.ceil(retryDelay / 1e3);
|
|
3894
|
-
errorText += fg("muted", ` (retry in ${seconds}s)`);
|
|
4261
|
+
errorText += theme.fg("muted", ` (retry in ${seconds}s)`);
|
|
3895
4262
|
}
|
|
3896
|
-
state.chatContainer.addChild(new Text(fg("error", errorText), 1, 0));
|
|
4263
|
+
state.chatContainer.addChild(new Text(theme.fg("error", errorText), 1, 0));
|
|
3897
4264
|
const hint = getErrorHint(parsed.type);
|
|
3898
4265
|
if (hint) {
|
|
3899
|
-
state.chatContainer.addChild(new Text(fg("muted", ` Hint: ${hint}`), 1, 0));
|
|
4266
|
+
state.chatContainer.addChild(new Text(theme.fg("muted", ` Hint: ${hint}`), 1, 0));
|
|
3900
4267
|
}
|
|
3901
4268
|
}
|
|
3902
4269
|
state.ui.requestRender();
|
|
@@ -3971,7 +4338,7 @@ async function dispatchSlashCommand(input, state, buildCtx) {
|
|
|
3971
4338
|
await handleOMCommand(buildCtx());
|
|
3972
4339
|
return true;
|
|
3973
4340
|
case "think":
|
|
3974
|
-
await handleThinkCommand(buildCtx());
|
|
4341
|
+
await handleThinkCommand(buildCtx(), args);
|
|
3975
4342
|
return true;
|
|
3976
4343
|
case "permissions":
|
|
3977
4344
|
await handlePermissionsCommand(buildCtx(), args);
|
|
@@ -4018,6 +4385,9 @@ async function dispatchSlashCommand(input, state, buildCtx) {
|
|
|
4018
4385
|
case "setup":
|
|
4019
4386
|
await handleSetupCommand(buildCtx());
|
|
4020
4387
|
return true;
|
|
4388
|
+
case "theme":
|
|
4389
|
+
await handleThemeCommand(buildCtx(), args);
|
|
4390
|
+
return true;
|
|
4021
4391
|
default: {
|
|
4022
4392
|
const customCommand = state.customSlashCommands.find((cmd) => cmd.name === command);
|
|
4023
4393
|
if (customCommand) {
|
|
@@ -4050,6 +4420,10 @@ ${processedContent.trim()}
|
|
|
4050
4420
|
}
|
|
4051
4421
|
function handleAgentStart(ctx) {
|
|
4052
4422
|
const { state } = ctx;
|
|
4423
|
+
const freshBranch = getCurrentGitBranch(state.projectInfo.rootPath);
|
|
4424
|
+
if (freshBranch) {
|
|
4425
|
+
state.projectInfo.gitBranch = freshBranch;
|
|
4426
|
+
}
|
|
4053
4427
|
if (!state.gradientAnimator) {
|
|
4054
4428
|
state.gradientAnimator = new GradientAnimator(() => {
|
|
4055
4429
|
ctx.updateStatusLine();
|
|
@@ -4062,6 +4436,10 @@ function handleAgentEnd(ctx) {
|
|
|
4062
4436
|
if (state.gradientAnimator) {
|
|
4063
4437
|
state.gradientAnimator.fadeOut();
|
|
4064
4438
|
}
|
|
4439
|
+
const freshBranch = getCurrentGitBranch(state.projectInfo.rootPath);
|
|
4440
|
+
if (freshBranch) {
|
|
4441
|
+
state.projectInfo.gitBranch = freshBranch;
|
|
4442
|
+
}
|
|
4065
4443
|
if (state.streamingComponent) {
|
|
4066
4444
|
state.streamingComponent = void 0;
|
|
4067
4445
|
state.streamingMessage = void 0;
|
|
@@ -4316,11 +4694,11 @@ function formatStackTrace(stack) {
|
|
|
4316
4694
|
if (line.match(/^\s*at\s+/)) {
|
|
4317
4695
|
return line.replace(
|
|
4318
4696
|
/(\s+at\s+)([^(]+)(\s*\()([^)]+)(\))/,
|
|
4319
|
-
(match, at, fn, open, loc, close) => `${fg("muted", at)}${fg("function", fn)}${fg("muted", open)}${fg("path", loc)}${fg("muted", close)}`
|
|
4697
|
+
(match, at, fn, open, loc, close) => `${theme.fg("muted", at)}${theme.fg("function", fn)}${theme.fg("muted", open)}${theme.fg("path", loc)}${theme.fg("muted", close)}`
|
|
4320
4698
|
);
|
|
4321
4699
|
}
|
|
4322
4700
|
if (!line.trim() || line.includes("node_modules")) {
|
|
4323
|
-
return fg("muted", line);
|
|
4701
|
+
return theme.fg("muted", line);
|
|
4324
4702
|
}
|
|
4325
4703
|
return line;
|
|
4326
4704
|
});
|
|
@@ -4351,23 +4729,23 @@ var ErrorDisplayComponent = class extends Container {
|
|
|
4351
4729
|
}
|
|
4352
4730
|
build() {
|
|
4353
4731
|
const info = parseErrorInfo(this.error);
|
|
4354
|
-
const borderTop = new Text(fg("error", "\u250C\u2500 Error \u2500" + "\u2500".repeat(50) + "\u2510"), 0, 0);
|
|
4732
|
+
const borderTop = new Text(theme.fg("error", "\u250C\u2500 Error \u2500" + "\u2500".repeat(50) + "\u2510"), 0, 0);
|
|
4355
4733
|
this.addChild(borderTop);
|
|
4356
4734
|
const errorContainer = new Container();
|
|
4357
|
-
const errorBg = (text) => bg("errorBg", text);
|
|
4735
|
+
const errorBg = (text) => theme.bg("errorBg", text);
|
|
4358
4736
|
if (info.name && info.name !== "Error") {
|
|
4359
4737
|
const typeLine = new Container();
|
|
4360
4738
|
typeLine.addChild(new Text("\u2502 ", 0, 0));
|
|
4361
|
-
typeLine.addChild(new Text(errorBg(` ${bold(fg("error", info.name))} `), 0, 0));
|
|
4739
|
+
typeLine.addChild(new Text(errorBg(` ${theme.bold(theme.fg("error", info.name))} `), 0, 0));
|
|
4362
4740
|
errorContainer.addChild(typeLine);
|
|
4363
4741
|
}
|
|
4364
4742
|
const msgLine = new Container();
|
|
4365
4743
|
msgLine.addChild(new Text("\u2502 ", 0, 0));
|
|
4366
|
-
msgLine.addChild(new Text(bold(info.message), 0, 0));
|
|
4744
|
+
msgLine.addChild(new Text(theme.bold(info.message), 0, 0));
|
|
4367
4745
|
errorContainer.addChild(msgLine);
|
|
4368
4746
|
if (info.file && info.line) {
|
|
4369
4747
|
const location = `${info.file}:${info.line}${info.column ? `:${info.column}` : ""}`;
|
|
4370
|
-
errorContainer.addChild(new Text(fg("muted", ` at ${location}`), 0, 0));
|
|
4748
|
+
errorContainer.addChild(new Text(theme.fg("muted", ` at ${location}`), 0, 0));
|
|
4371
4749
|
}
|
|
4372
4750
|
this.addChild(errorContainer);
|
|
4373
4751
|
if (this.options.showContext && info.context) {
|
|
@@ -4378,26 +4756,26 @@ var ErrorDisplayComponent = class extends Container {
|
|
|
4378
4756
|
this.addChild(new Spacer(1));
|
|
4379
4757
|
this.addChild(new CollapsibleStackTrace(info.stack, { expanded: this.options.expanded }, this.ui));
|
|
4380
4758
|
}
|
|
4381
|
-
const borderBottom = new Text(fg("error", "\u2514" + "\u2500".repeat(60) + "\u2518"), 0, 0);
|
|
4759
|
+
const borderBottom = new Text(theme.fg("error", "\u2514" + "\u2500".repeat(60) + "\u2518"), 0, 0);
|
|
4382
4760
|
this.addChild(borderBottom);
|
|
4383
4761
|
}
|
|
4384
4762
|
createCodeContext(context, errorLine) {
|
|
4385
4763
|
const container = new Container();
|
|
4386
4764
|
const codeBlock = new Container();
|
|
4387
|
-
codeBlock.addChild(new Text(fg("muted", "Code context:"), 0, 0));
|
|
4765
|
+
codeBlock.addChild(new Text(theme.fg("muted", "Code context:"), 0, 0));
|
|
4388
4766
|
if (context.before) {
|
|
4389
4767
|
context.before.forEach((line, i) => {
|
|
4390
4768
|
const lineNum = errorLine ? errorLine - context.before.length + i : i + 1;
|
|
4391
|
-
codeBlock.addChild(new Text(fg("muted", `${lineNum.toString().padStart(4)} \u2502 ${line}`), 0, 0));
|
|
4769
|
+
codeBlock.addChild(new Text(theme.fg("muted", `${lineNum.toString().padStart(4)} \u2502 ${line}`), 0, 0));
|
|
4392
4770
|
});
|
|
4393
4771
|
}
|
|
4394
4772
|
if (context.line && errorLine) {
|
|
4395
|
-
codeBlock.addChild(new Text(fg("error", `${errorLine.toString().padStart(4)} \u2502 ${context.line}`), 0, 0));
|
|
4773
|
+
codeBlock.addChild(new Text(theme.fg("error", `${errorLine.toString().padStart(4)} \u2502 ${context.line}`), 0, 0));
|
|
4396
4774
|
}
|
|
4397
4775
|
if (context.after) {
|
|
4398
4776
|
context.after.forEach((line, i) => {
|
|
4399
4777
|
const lineNum = errorLine ? errorLine + i + 1 : i + 1;
|
|
4400
|
-
codeBlock.addChild(new Text(fg("muted", `${lineNum.toString().padStart(4)} \u2502 ${line}`), 0, 0));
|
|
4778
|
+
codeBlock.addChild(new Text(theme.fg("muted", `${lineNum.toString().padStart(4)} \u2502 ${line}`), 0, 0));
|
|
4401
4779
|
});
|
|
4402
4780
|
}
|
|
4403
4781
|
container.addChild(codeBlock);
|
|
@@ -4959,17 +5337,18 @@ var ToolExecutionComponentEnhanced = class extends Container {
|
|
|
4959
5337
|
const maxDiags = shouldCollapse ? COLLAPSED_DIAG_LINES : diagnostics.entries.length;
|
|
4960
5338
|
const entriesToShow = diagnostics.entries.slice(0, maxDiags);
|
|
4961
5339
|
for (const diag of entriesToShow) {
|
|
4962
|
-
const
|
|
5340
|
+
const t = theme.getTheme();
|
|
5341
|
+
const color = diag.severity === "error" ? t.error : diag.severity === "warning" ? t.warning : t.muted;
|
|
4963
5342
|
const icon = diag.severity === "error" ? "\u2717" : diag.severity === "warning" ? "\u26A0" : "\u2139";
|
|
4964
5343
|
const location = diag.location ? chalk10.hex(color)(diag.location) + " " : "";
|
|
4965
|
-
const line = ` ${chalk10.hex(color)(icon)} ${location}${
|
|
5344
|
+
const line = ` ${chalk10.hex(color)(icon)} ${location}${theme.fg("thinkingText", diag.message)}`;
|
|
4966
5345
|
this.contentBox.addChild(new Text(line, 0, 0));
|
|
4967
5346
|
}
|
|
4968
5347
|
if (shouldCollapse) {
|
|
4969
5348
|
const remaining = diagnostics.entries.length - COLLAPSED_DIAG_LINES;
|
|
4970
5349
|
this.contentBox.addChild(
|
|
4971
5350
|
new Text(
|
|
4972
|
-
|
|
5351
|
+
theme.fg("muted", ` ... ${remaining} more diagnostic${remaining > 1 ? "s" : ""} (ctrl+e to expand)`),
|
|
4973
5352
|
0,
|
|
4974
5353
|
0
|
|
4975
5354
|
)
|
|
@@ -5016,20 +5395,20 @@ var ToolExecutionComponentEnhanced = class extends Container {
|
|
|
5016
5395
|
const newLines = newStr.split("\n");
|
|
5017
5396
|
const lines = [];
|
|
5018
5397
|
let firstChangeIndex = -1;
|
|
5019
|
-
const
|
|
5020
|
-
const
|
|
5398
|
+
const removedColor = chalk10.hex(mastra.red);
|
|
5399
|
+
const addedColor = chalk10.hex(theme.getTheme().success);
|
|
5021
5400
|
const maxLines = Math.max(oldLines.length, newLines.length);
|
|
5022
5401
|
for (let i = 0; i < maxLines; i++) {
|
|
5023
5402
|
if (i >= oldLines.length) {
|
|
5024
5403
|
if (firstChangeIndex === -1) firstChangeIndex = lines.length;
|
|
5025
|
-
lines.push(
|
|
5404
|
+
lines.push(addedColor(newLines[i]));
|
|
5026
5405
|
} else if (i >= newLines.length) {
|
|
5027
5406
|
if (firstChangeIndex === -1) firstChangeIndex = lines.length;
|
|
5028
|
-
lines.push(
|
|
5407
|
+
lines.push(removedColor(oldLines[i]));
|
|
5029
5408
|
} else if (oldLines[i] !== newLines[i]) {
|
|
5030
5409
|
if (firstChangeIndex === -1) firstChangeIndex = lines.length;
|
|
5031
|
-
lines.push(
|
|
5032
|
-
lines.push(
|
|
5410
|
+
lines.push(removedColor(oldLines[i]));
|
|
5411
|
+
lines.push(addedColor(newLines[i]));
|
|
5033
5412
|
} else {
|
|
5034
5413
|
lines.push(theme.fg("muted", oldLines[i]));
|
|
5035
5414
|
}
|
|
@@ -5604,7 +5983,7 @@ function formatMarker(data) {
|
|
|
5604
5983
|
switch (data.type) {
|
|
5605
5984
|
case "om_observation_start": {
|
|
5606
5985
|
const tokens = data.tokensToObserve > 0 ? ` ~${formatTokens2(data.tokensToObserve)} tokens` : "";
|
|
5607
|
-
return fg("muted", ` \u{1F9E0} ${label} in progress${tokens}...`);
|
|
5986
|
+
return theme.fg("muted", ` \u{1F9E0} ${label} in progress${tokens}...`);
|
|
5608
5987
|
}
|
|
5609
5988
|
case "om_observation_end": {
|
|
5610
5989
|
const observed = formatTokens2(data.tokensObserved);
|
|
@@ -5612,36 +5991,36 @@ function formatMarker(data) {
|
|
|
5612
5991
|
const ratio = data.tokensObserved > 0 && data.observationTokens > 0 ? `${Math.round(data.tokensObserved / data.observationTokens)}x` : "";
|
|
5613
5992
|
const duration = (data.durationMs / 1e3).toFixed(1);
|
|
5614
5993
|
const ratioStr = ratio ? ` (${ratio} compression)` : "";
|
|
5615
|
-
return fg("success", ` \u{1F9E0} Observed: ${observed} \u2192 ${compressed} tokens${ratioStr} in ${duration}s \u2713`);
|
|
5994
|
+
return theme.fg("success", ` \u{1F9E0} Observed: ${observed} \u2192 ${compressed} tokens${ratioStr} in ${duration}s \u2713`);
|
|
5616
5995
|
}
|
|
5617
5996
|
case "om_observation_failed": {
|
|
5618
5997
|
const tokens = data.tokensAttempted ? ` (${formatTokens2(data.tokensAttempted)} tokens)` : "";
|
|
5619
|
-
return fg("error", ` \u2717 ${label} failed${tokens}: ${data.error}`);
|
|
5998
|
+
return theme.fg("error", ` \u2717 ${label} failed${tokens}: ${data.error}`);
|
|
5620
5999
|
}
|
|
5621
6000
|
case "om_buffering_start": {
|
|
5622
6001
|
const tokens = data.tokensToBuffer > 0 ? ` ~${formatTokens2(data.tokensToBuffer)} tokens` : "";
|
|
5623
|
-
return fg("muted", ` \u27F3 Buffering ${label.toLowerCase()}${tokens}...`);
|
|
6002
|
+
return theme.fg("muted", ` \u27F3 Buffering ${label.toLowerCase()}${tokens}...`);
|
|
5624
6003
|
}
|
|
5625
6004
|
case "om_buffering_end": {
|
|
5626
6005
|
const input = formatTokens2(data.tokensBuffered);
|
|
5627
6006
|
const outputTokens = data.operationType === "observation" && data.observations ? Math.round(data.observations.length / 4) : data.bufferedTokens;
|
|
5628
6007
|
const output = formatTokens2(outputTokens);
|
|
5629
6008
|
const ratio = data.tokensBuffered > 0 && outputTokens > 0 ? ` (${Math.round(data.tokensBuffered / outputTokens)}x)` : "";
|
|
5630
|
-
return fg("success", ` \u2713 Buffered ${label.toLowerCase()}: ${input} \u2192 ${output} tokens${ratio}`);
|
|
6009
|
+
return theme.fg("success", ` \u2713 Buffered ${label.toLowerCase()}: ${input} \u2192 ${output} tokens${ratio}`);
|
|
5631
6010
|
}
|
|
5632
6011
|
case "om_buffering_failed": {
|
|
5633
|
-
return fg("error", ` \u2717 Buffering ${label.toLowerCase()} failed: ${data.error}`);
|
|
6012
|
+
return theme.fg("error", ` \u2717 Buffering ${label.toLowerCase()} failed: ${data.error}`);
|
|
5634
6013
|
}
|
|
5635
6014
|
case "om_activation": {
|
|
5636
6015
|
const kind = data.operationType === "reflection" ? "reflection" : "observations";
|
|
5637
6016
|
const msgTokens = formatTokens2(data.tokensActivated);
|
|
5638
6017
|
const obsTokens = formatTokens2(data.observationTokens);
|
|
5639
|
-
return fg("success", ` \u2713 Activated ${kind}: -${msgTokens} msg tokens, +${obsTokens} obs tokens`);
|
|
6018
|
+
return theme.fg("success", ` \u2713 Activated ${kind}: -${msgTokens} msg tokens, +${obsTokens} obs tokens`);
|
|
5640
6019
|
}
|
|
5641
6020
|
}
|
|
5642
6021
|
}
|
|
5643
|
-
var OBSERVER_COLOR2 =
|
|
5644
|
-
var REFLECTOR_COLOR2 =
|
|
6022
|
+
var OBSERVER_COLOR2 = mastra.orange;
|
|
6023
|
+
var REFLECTOR_COLOR2 = mastra.red;
|
|
5645
6024
|
var COLLAPSED_LINES = 10;
|
|
5646
6025
|
function formatTokens3(tokens) {
|
|
5647
6026
|
if (tokens === 0) return "0";
|
|
@@ -5966,13 +6345,13 @@ var AskQuestionDialogComponent = class extends Box {
|
|
|
5966
6345
|
if (this.input) this.input.focused = value;
|
|
5967
6346
|
}
|
|
5968
6347
|
constructor(options) {
|
|
5969
|
-
super(2, 1, (text) => bg("overlayBg", text));
|
|
6348
|
+
super(2, 1, (text) => theme.bg("overlayBg", text));
|
|
5970
6349
|
this.onSubmit = options.onSubmit;
|
|
5971
6350
|
this.onCancel = options.onCancel;
|
|
5972
|
-
this.addChild(new Text(bold(fg("accent", "Question")), 0, 0));
|
|
6351
|
+
this.addChild(new Text(theme.bold(theme.fg("accent", "Question")), 0, 0));
|
|
5973
6352
|
this.addChild(new Spacer(1));
|
|
5974
6353
|
for (const line of options.question.split("\n")) {
|
|
5975
|
-
this.addChild(new Text(fg("text", line), 0, 0));
|
|
6354
|
+
this.addChild(new Text(theme.fg("text", line), 0, 0));
|
|
5976
6355
|
}
|
|
5977
6356
|
this.addChild(new Spacer(1));
|
|
5978
6357
|
if (options.options && options.options.length > 0) {
|
|
@@ -5984,7 +6363,7 @@ var AskQuestionDialogComponent = class extends Box {
|
|
|
5984
6363
|
buildSelectMode(opts) {
|
|
5985
6364
|
const items = opts.map((opt) => ({
|
|
5986
6365
|
value: opt.label,
|
|
5987
|
-
label: opt.description ? ` ${opt.label} ${fg("dim", opt.description)}` : ` ${opt.label}`
|
|
6366
|
+
label: opt.description ? ` ${opt.label} ${theme.fg("dim", opt.description)}` : ` ${opt.label}`
|
|
5988
6367
|
}));
|
|
5989
6368
|
this.selectList = new SelectList(items, Math.min(items.length, 8), getSelectListTheme());
|
|
5990
6369
|
this.selectList.onSelect = (item) => {
|
|
@@ -5993,7 +6372,7 @@ var AskQuestionDialogComponent = class extends Box {
|
|
|
5993
6372
|
this.selectList.onCancel = this.onCancel;
|
|
5994
6373
|
this.addChild(this.selectList);
|
|
5995
6374
|
this.addChild(new Spacer(1));
|
|
5996
|
-
this.addChild(new Text(fg("dim", " \u2191\u2193 to navigate \xB7 Enter to select \xB7 Esc to skip"), 0, 0));
|
|
6375
|
+
this.addChild(new Text(theme.fg("dim", " \u2191\u2193 to navigate \xB7 Enter to select \xB7 Esc to skip"), 0, 0));
|
|
5997
6376
|
}
|
|
5998
6377
|
buildInputMode() {
|
|
5999
6378
|
this.input = new Input();
|
|
@@ -6005,7 +6384,7 @@ var AskQuestionDialogComponent = class extends Box {
|
|
|
6005
6384
|
};
|
|
6006
6385
|
this.addChild(this.input);
|
|
6007
6386
|
this.addChild(new Spacer(1));
|
|
6008
|
-
this.addChild(new Text(fg("dim", " Enter to submit \xB7 Esc to skip"), 0, 0));
|
|
6387
|
+
this.addChild(new Text(theme.fg("dim", " Enter to submit \xB7 Esc to skip"), 0, 0));
|
|
6009
6388
|
}
|
|
6010
6389
|
handleInput(data) {
|
|
6011
6390
|
if (this.selectList) {
|
|
@@ -6255,7 +6634,7 @@ async function handleSandboxAccessRequest(ctx, questionId, requestedPath, reason
|
|
|
6255
6634
|
const questionComponent = new AskQuestionInlineComponent(
|
|
6256
6635
|
{
|
|
6257
6636
|
question: `Grant sandbox access to "${requestedPath}"?
|
|
6258
|
-
${fg("dim", `Reason: ${reason}`)}`,
|
|
6637
|
+
${theme.fg("dim", `Reason: ${reason}`)}`,
|
|
6259
6638
|
options: [
|
|
6260
6639
|
{ label: "Yes", description: "Allow access to this directory" },
|
|
6261
6640
|
{ label: "No", description: "Deny access" }
|
|
@@ -6603,7 +6982,7 @@ var ToolApprovalDialogComponent = class extends Box {
|
|
|
6603
6982
|
this._focused = value;
|
|
6604
6983
|
}
|
|
6605
6984
|
constructor(options) {
|
|
6606
|
-
super(2, 1, (text) => bg("overlayBg", text));
|
|
6985
|
+
super(2, 1, (text) => theme.bg("overlayBg", text));
|
|
6607
6986
|
this.toolName = options.toolName;
|
|
6608
6987
|
this.args = options.args;
|
|
6609
6988
|
this.categoryLabel = options.categoryLabel;
|
|
@@ -6611,28 +6990,28 @@ var ToolApprovalDialogComponent = class extends Box {
|
|
|
6611
6990
|
this.buildUI();
|
|
6612
6991
|
}
|
|
6613
6992
|
buildUI() {
|
|
6614
|
-
this.addChild(new Text(fg("warning", "\u26A0 Tool Approval Required"), 0, 0));
|
|
6993
|
+
this.addChild(new Text(theme.fg("warning", "\u26A0 Tool Approval Required"), 0, 0));
|
|
6615
6994
|
this.addChild(new Spacer(1));
|
|
6616
|
-
this.addChild(new Text(fg("accent", `Tool: `) + fg("text", this.toolName), 0, 0));
|
|
6995
|
+
this.addChild(new Text(theme.fg("accent", `Tool: `) + theme.fg("text", this.toolName), 0, 0));
|
|
6617
6996
|
if (this.categoryLabel) {
|
|
6618
|
-
this.addChild(new Text(fg("accent", `Category: `) + fg("text", this.categoryLabel), 0, 0));
|
|
6997
|
+
this.addChild(new Text(theme.fg("accent", `Category: `) + theme.fg("text", this.categoryLabel), 0, 0));
|
|
6619
6998
|
}
|
|
6620
6999
|
this.addChild(new Spacer(1));
|
|
6621
|
-
this.addChild(new Text(fg("muted", "Arguments:"), 0, 0));
|
|
7000
|
+
this.addChild(new Text(theme.fg("muted", "Arguments:"), 0, 0));
|
|
6622
7001
|
const argsText = this.formatArgs(this.args);
|
|
6623
7002
|
for (const line of argsText.split("\n").slice(0, 10)) {
|
|
6624
|
-
this.addChild(new Text(fg("text", " " + line), 0, 0));
|
|
7003
|
+
this.addChild(new Text(theme.fg("text", " " + line), 0, 0));
|
|
6625
7004
|
}
|
|
6626
7005
|
if (argsText.split("\n").length > 10) {
|
|
6627
|
-
this.addChild(new Text(fg("muted", " ... (truncated)"), 0, 0));
|
|
7006
|
+
this.addChild(new Text(theme.fg("muted", " ... (truncated)"), 0, 0));
|
|
6628
7007
|
}
|
|
6629
7008
|
this.addChild(new Spacer(1));
|
|
6630
7009
|
const categoryHint = this.categoryLabel ? `lways allow ${this.categoryLabel.toLowerCase()}` : "lways allow category";
|
|
6631
|
-
const
|
|
6632
|
-
const key = chalk10.
|
|
7010
|
+
const dimColor = chalk10.hex(theme.getTheme().dim);
|
|
7011
|
+
const key = chalk10.hex(theme.getTheme().text).bold;
|
|
6633
7012
|
this.addChild(
|
|
6634
7013
|
new Text(
|
|
6635
|
-
fg("accent", "Allow? ") + key("y") +
|
|
7014
|
+
theme.fg("accent", "Allow? ") + key("y") + dimColor("es ") + key("n") + dimColor("o ") + key("a") + dimColor(categoryHint + " ") + key("Y") + dimColor("olo"),
|
|
6636
7015
|
0,
|
|
6637
7016
|
0
|
|
6638
7017
|
)
|
|
@@ -6950,6 +7329,10 @@ async function dispatchEvent(event, ectx, state) {
|
|
|
6950
7329
|
ectx.showInfo(`Switched to thread: ${event.threadId}`);
|
|
6951
7330
|
await ectx.renderExistingMessages();
|
|
6952
7331
|
await state.harness.loadOMProgress();
|
|
7332
|
+
const freshBranch = getCurrentGitBranch(state.projectInfo.rootPath);
|
|
7333
|
+
if (freshBranch) {
|
|
7334
|
+
state.projectInfo.gitBranch = freshBranch;
|
|
7335
|
+
}
|
|
6953
7336
|
const threadState = state.harness.getState();
|
|
6954
7337
|
if (state.taskProgress) {
|
|
6955
7338
|
state.taskProgress.updateTasks(threadState.tasks ?? []);
|
|
@@ -7116,7 +7499,7 @@ var UserMessageComponent = class extends Container {
|
|
|
7116
7499
|
|
|
7117
7500
|
// src/tui/render-messages.ts
|
|
7118
7501
|
function renderCompletedTasksInline(state, tasks, insertIndex = -1, collapsed = false) {
|
|
7119
|
-
const headerText = bold(fg("accent", "Tasks")) + fg("dim", ` [${tasks.length}/${tasks.length} completed]`);
|
|
7502
|
+
const headerText = theme.bold(theme.fg("accent", "Tasks")) + theme.fg("dim", ` [${tasks.length}/${tasks.length} completed]`);
|
|
7120
7503
|
const container = new Container();
|
|
7121
7504
|
container.addChild(new Spacer(1));
|
|
7122
7505
|
container.addChild(new Text(headerText, 0, 0));
|
|
@@ -7131,7 +7514,11 @@ function renderCompletedTasksInline(state, tasks, insertIndex = -1, collapsed =
|
|
|
7131
7514
|
}
|
|
7132
7515
|
if (remaining > 0) {
|
|
7133
7516
|
container.addChild(
|
|
7134
|
-
new Text(
|
|
7517
|
+
new Text(
|
|
7518
|
+
theme.fg("dim", ` ... ${remaining} more completed task${remaining > 1 ? "s" : ""} (ctrl+e to expand)`),
|
|
7519
|
+
0,
|
|
7520
|
+
0
|
|
7521
|
+
)
|
|
7135
7522
|
);
|
|
7136
7523
|
}
|
|
7137
7524
|
if (insertIndex >= 0) {
|
|
@@ -7146,10 +7533,10 @@ function renderClearedTasksInline(state, clearedTasks, insertIndex = -1) {
|
|
|
7146
7533
|
container.addChild(new Spacer(1));
|
|
7147
7534
|
const count = clearedTasks.length;
|
|
7148
7535
|
const label = count === 1 ? "Task" : "Tasks";
|
|
7149
|
-
container.addChild(new Text(fg("accent", `${label} cleared`), 0, 0));
|
|
7536
|
+
container.addChild(new Text(theme.fg("accent", `${label} cleared`), 0, 0));
|
|
7150
7537
|
for (const task of clearedTasks) {
|
|
7151
7538
|
const icon = task.status === "completed" ? chalk10.hex(mastra.green)("\u2713") : chalk10.hex(mastra.darkGray)("\u25CB");
|
|
7152
|
-
const text = chalk10.dim.strikethrough(task.content);
|
|
7539
|
+
const text = chalk10.hex(theme.getTheme().dim).strikethrough(task.content);
|
|
7153
7540
|
container.addChild(new Text(` ${icon} ${text}`, 0, 0));
|
|
7154
7541
|
}
|
|
7155
7542
|
if (insertIndex >= 0) {
|
|
@@ -7511,15 +7898,15 @@ function colorLine(line) {
|
|
|
7511
7898
|
function renderBanner(version, appName) {
|
|
7512
7899
|
const name = appName;
|
|
7513
7900
|
if (name !== "Mastra Code") {
|
|
7514
|
-
return fg("accent", "\u25C6") + " " + bold(fg("accent", name)) + fg("dim", ` v${version}`);
|
|
7901
|
+
return theme.fg("accent", "\u25C6") + " " + theme.bold(theme.fg("accent", name)) + theme.fg("dim", ` v${version}`);
|
|
7515
7902
|
}
|
|
7516
7903
|
const cols = process.stdout.columns || 80;
|
|
7517
7904
|
if (cols < 30) {
|
|
7518
|
-
return fg("accent", "\u25C6") + " " + bold(fg("accent", "Mastra Code")) + fg("dim", ` v${version}`);
|
|
7905
|
+
return theme.fg("accent", "\u25C6") + " " + theme.bold(theme.fg("accent", "Mastra Code")) + theme.fg("dim", ` v${version}`);
|
|
7519
7906
|
}
|
|
7520
7907
|
const art = cols >= 50 ? FULL_ART : SHORT_ART;
|
|
7521
7908
|
const coloredLines = art.map((line) => colorLine(line));
|
|
7522
|
-
coloredLines.push(fg("dim", `v${version}`));
|
|
7909
|
+
coloredLines.push(theme.fg("dim", `v${version}`));
|
|
7523
7910
|
return coloredLines.join("\n");
|
|
7524
7911
|
}
|
|
7525
7912
|
var TaskProgressComponent = class extends Container {
|
|
@@ -7546,7 +7933,7 @@ var TaskProgressComponent = class extends Container {
|
|
|
7546
7933
|
const completed = this.tasks.filter((t) => t.status === "completed").length;
|
|
7547
7934
|
const total = this.tasks.length;
|
|
7548
7935
|
if (completed === total) return;
|
|
7549
|
-
const headerText = " " + bold(fg("accent", "Tasks")) + fg("dim", ` [${completed}/${total} completed]`);
|
|
7936
|
+
const headerText = " " + theme.bold(theme.fg("accent", "Tasks")) + theme.fg("dim", ` [${completed}/${total} completed]`);
|
|
7550
7937
|
this.addChild(new Spacer(1));
|
|
7551
7938
|
this.addChild(new Text(headerText, 0, 0));
|
|
7552
7939
|
for (const task of this.tasks) {
|
|
@@ -7557,18 +7944,18 @@ var TaskProgressComponent = class extends Container {
|
|
|
7557
7944
|
const indent = " ";
|
|
7558
7945
|
switch (task.status) {
|
|
7559
7946
|
case "completed": {
|
|
7560
|
-
const icon =
|
|
7561
|
-
const text = chalk10.
|
|
7947
|
+
const icon = theme.fg("success", "\u2713");
|
|
7948
|
+
const text = chalk10.hex(theme.getTheme().success).strikethrough(task.content);
|
|
7562
7949
|
return `${indent}${icon} ${text}`;
|
|
7563
7950
|
}
|
|
7564
7951
|
case "in_progress": {
|
|
7565
|
-
const icon =
|
|
7566
|
-
const text =
|
|
7952
|
+
const icon = theme.fg("warning", "\u25B6");
|
|
7953
|
+
const text = theme.bold(theme.fg("warning", task.activeForm));
|
|
7567
7954
|
return `${indent}${icon} ${text}`;
|
|
7568
7955
|
}
|
|
7569
7956
|
case "pending": {
|
|
7570
|
-
const icon =
|
|
7571
|
-
const text =
|
|
7957
|
+
const icon = theme.fg("dim", "\u25CB");
|
|
7958
|
+
const text = theme.fg("dim", task.content);
|
|
7572
7959
|
return `${indent}${icon} ${text}`;
|
|
7573
7960
|
}
|
|
7574
7961
|
}
|
|
@@ -7676,13 +8063,13 @@ function buildLayout(state, refreshModelAuthStatus) {
|
|
|
7676
8063
|
state.projectInfo.gitBranch ? `Branch: ${state.projectInfo.gitBranch}` : null,
|
|
7677
8064
|
state.projectInfo.isWorktree ? `Worktree of: ${state.projectInfo.mainRepoPath}` : null,
|
|
7678
8065
|
`User: ${getUserId(state.projectInfo.rootPath)}`
|
|
7679
|
-
].filter(Boolean).map((line) => fg("muted", line)).join("\n");
|
|
7680
|
-
const sep = fg("dim", " \xB7 ");
|
|
8066
|
+
].filter(Boolean).map((line) => theme.fg("muted", line)).join("\n");
|
|
8067
|
+
const sep = theme.fg("dim", " \xB7 ");
|
|
7681
8068
|
const hintParts = [];
|
|
7682
8069
|
if (state.harness.listModes().length > 1) {
|
|
7683
|
-
hintParts.push(`${fg("accent", "\u21E7+Tab")} ${fg("muted", "cycle modes")}`);
|
|
8070
|
+
hintParts.push(`${theme.fg("accent", "\u21E7+Tab")} ${theme.fg("muted", "cycle modes")}`);
|
|
7684
8071
|
}
|
|
7685
|
-
hintParts.push(`${fg("accent", "/help")} ${fg("muted", "info & shortcuts")}`);
|
|
8072
|
+
hintParts.push(`${theme.fg("accent", "/help")} ${theme.fg("muted", "info & shortcuts")}`);
|
|
7686
8073
|
const instructions = ` ${hintParts.join(sep)}`;
|
|
7687
8074
|
state.ui.addChild(new Spacer(1));
|
|
7688
8075
|
state.ui.addChild(new Text(banner, 1, 0));
|
|
@@ -7704,6 +8091,17 @@ function buildLayout(state, refreshModelAuthStatus) {
|
|
|
7704
8091
|
refreshModelAuthStatus();
|
|
7705
8092
|
state.ui.setFocus(state.editor);
|
|
7706
8093
|
}
|
|
8094
|
+
function detectFdPath() {
|
|
8095
|
+
const whichCmd = process.platform === "win32" ? "where" : "which";
|
|
8096
|
+
for (const bin of ["fd", "fdfind"]) {
|
|
8097
|
+
try {
|
|
8098
|
+
const resolved = execFileSync(whichCmd, [bin], { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim().split(/\r?\n/)[0];
|
|
8099
|
+
if (resolved) return resolved;
|
|
8100
|
+
} catch {
|
|
8101
|
+
}
|
|
8102
|
+
}
|
|
8103
|
+
return null;
|
|
8104
|
+
}
|
|
7707
8105
|
function setupAutocomplete(state) {
|
|
7708
8106
|
const slashCommands = [
|
|
7709
8107
|
{ name: "new", description: "Start a new thread" },
|
|
@@ -7712,7 +8110,7 @@ function setupAutocomplete(state) {
|
|
|
7712
8110
|
{ name: "models:pack", description: "Switch model pack" },
|
|
7713
8111
|
{ name: "subagents", description: "Configure subagent model defaults" },
|
|
7714
8112
|
{ name: "om", description: "Configure Observational Memory models" },
|
|
7715
|
-
{ name: "think", description: "Set thinking
|
|
8113
|
+
{ name: "think", description: "Set thinking (off|low|medium|high|xhigh|status)" },
|
|
7716
8114
|
{ name: "login", description: "Login with OAuth provider" },
|
|
7717
8115
|
{ name: "skills", description: "List available skills" },
|
|
7718
8116
|
{ name: "cost", description: "Show token usage and estimated costs" },
|
|
@@ -7747,6 +8145,7 @@ function setupAutocomplete(state) {
|
|
|
7747
8145
|
},
|
|
7748
8146
|
{ name: "review", description: "Review a GitHub pull request" },
|
|
7749
8147
|
{ name: "setup", description: "Re-run the setup wizard" },
|
|
8148
|
+
{ name: "theme", description: "Switch color theme (auto/dark/light)" },
|
|
7750
8149
|
{ name: "exit", description: "Exit the TUI" },
|
|
7751
8150
|
{ name: "help", description: "Show available commands" }
|
|
7752
8151
|
];
|
|
@@ -7760,7 +8159,8 @@ function setupAutocomplete(state) {
|
|
|
7760
8159
|
description: customCmd.description || `Custom: ${customCmd.name}`
|
|
7761
8160
|
});
|
|
7762
8161
|
}
|
|
7763
|
-
|
|
8162
|
+
const fdPath = detectFdPath();
|
|
8163
|
+
state.autocompleteProvider = new CombinedAutocompleteProvider(slashCommands, process.cwd(), fdPath);
|
|
7764
8164
|
state.editor.setAutocompleteProvider(state.autocompleteProvider);
|
|
7765
8165
|
}
|
|
7766
8166
|
async function loadCustomSlashCommands(state) {
|
|
@@ -7862,16 +8262,22 @@ var ShellOutputComponent = class extends Container {
|
|
|
7862
8262
|
this.addChild(new Spacer(1));
|
|
7863
8263
|
const statusIcon = exitCode === 0 ? "\u2713" : "\u2717";
|
|
7864
8264
|
const statusColor = exitCode === 0 ? "success" : "error";
|
|
7865
|
-
this.addChild(
|
|
8265
|
+
this.addChild(
|
|
8266
|
+
new Text(
|
|
8267
|
+
`${theme.fg(statusColor, statusIcon)} ${theme.bold(theme.fg("muted", "$"))} ${theme.fg("text", command)}`,
|
|
8268
|
+
1,
|
|
8269
|
+
0
|
|
8270
|
+
)
|
|
8271
|
+
);
|
|
7866
8272
|
const output = (stdout + (stderr ? (stdout ? "\n" : "") + stderr : "")).trimEnd();
|
|
7867
8273
|
if (output) {
|
|
7868
8274
|
const lines = output.split("\n");
|
|
7869
8275
|
for (const line of lines) {
|
|
7870
|
-
this.addChild(new Text(fg("toolOutput", ` ${line}`), 0, 0));
|
|
8276
|
+
this.addChild(new Text(theme.fg("toolOutput", ` ${line}`), 0, 0));
|
|
7871
8277
|
}
|
|
7872
8278
|
}
|
|
7873
8279
|
if (exitCode !== 0) {
|
|
7874
|
-
this.addChild(new Text(fg("error", ` Exit code: ${exitCode}`), 0, 0));
|
|
8280
|
+
this.addChild(new Text(theme.fg("error", ` Exit code: ${exitCode}`), 0, 0));
|
|
7875
8281
|
}
|
|
7876
8282
|
}
|
|
7877
8283
|
};
|
|
@@ -8260,6 +8666,10 @@ var MastraTUI = class _MastraTUI {
|
|
|
8260
8666
|
showInfo(this.state, "No model selected. Use /models to select a model, or /login to authenticate.");
|
|
8261
8667
|
continue;
|
|
8262
8668
|
}
|
|
8669
|
+
const allowed = await this.runUserPromptHook(userInput);
|
|
8670
|
+
if (!allowed) {
|
|
8671
|
+
continue;
|
|
8672
|
+
}
|
|
8263
8673
|
const images = this.state.pendingImages.length > 0 ? [...this.state.pendingImages] : void 0;
|
|
8264
8674
|
this.state.pendingImages = [];
|
|
8265
8675
|
addUserMessage(this.state, {
|
|
@@ -8334,6 +8744,7 @@ var MastraTUI = class _MastraTUI {
|
|
|
8334
8744
|
updateTerminalTitle(this.state);
|
|
8335
8745
|
await renderExistingMessages(this.state);
|
|
8336
8746
|
await renderExistingTasks(this.state);
|
|
8747
|
+
await this.checkClaudeMaxOAuthWarning();
|
|
8337
8748
|
if (this.state.pendingLockConflict) {
|
|
8338
8749
|
this.showThreadLockPrompt(this.state.pendingLockConflict.threadTitle, this.state.pendingLockConflict.ownerPid);
|
|
8339
8750
|
this.state.pendingLockConflict = null;
|
|
@@ -8358,6 +8769,44 @@ var MastraTUI = class _MastraTUI {
|
|
|
8358
8769
|
}
|
|
8359
8770
|
async handleEvent(event) {
|
|
8360
8771
|
await dispatchEvent(event, this.getEventContext(), this.state);
|
|
8772
|
+
if (event.type === "agent_end") {
|
|
8773
|
+
const stopReason = event.reason === "aborted" ? "aborted" : event.reason === "error" ? "error" : "complete";
|
|
8774
|
+
await this.runStopHook(stopReason);
|
|
8775
|
+
}
|
|
8776
|
+
}
|
|
8777
|
+
showHookWarnings(event, warnings) {
|
|
8778
|
+
for (const warning of warnings) {
|
|
8779
|
+
showInfo(this.state, `[${event}] ${warning}`);
|
|
8780
|
+
}
|
|
8781
|
+
}
|
|
8782
|
+
async runStopHook(stopReason) {
|
|
8783
|
+
const hookMgr = this.state.hookManager;
|
|
8784
|
+
if (!hookMgr) return;
|
|
8785
|
+
try {
|
|
8786
|
+
const result = await hookMgr.runStop(void 0, stopReason);
|
|
8787
|
+
this.showHookWarnings("Stop", result.warnings);
|
|
8788
|
+
if (!result.allowed && result.blockReason) {
|
|
8789
|
+
showError(this.state, `Stop hook blocked: ${result.blockReason}`);
|
|
8790
|
+
}
|
|
8791
|
+
} catch (error) {
|
|
8792
|
+
showError(this.state, `Stop hook failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
8793
|
+
}
|
|
8794
|
+
}
|
|
8795
|
+
async runUserPromptHook(userInput) {
|
|
8796
|
+
const hookMgr = this.state.hookManager;
|
|
8797
|
+
if (!hookMgr) return true;
|
|
8798
|
+
try {
|
|
8799
|
+
const result = await hookMgr.runUserPromptSubmit(userInput);
|
|
8800
|
+
this.showHookWarnings("UserPromptSubmit", result.warnings);
|
|
8801
|
+
if (!result.allowed) {
|
|
8802
|
+
showError(this.state, result.blockReason || "Blocked by UserPromptSubmit hook");
|
|
8803
|
+
return false;
|
|
8804
|
+
}
|
|
8805
|
+
return true;
|
|
8806
|
+
} catch (error) {
|
|
8807
|
+
showError(this.state, `UserPromptSubmit hook failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
8808
|
+
return false;
|
|
8809
|
+
}
|
|
8361
8810
|
}
|
|
8362
8811
|
// ===========================================================================
|
|
8363
8812
|
/**
|
|
@@ -8426,6 +8875,26 @@ var MastraTUI = class _MastraTUI {
|
|
|
8426
8875
|
this.state.ui.requestRender();
|
|
8427
8876
|
this.state.chatContainer.invalidate();
|
|
8428
8877
|
}
|
|
8878
|
+
/**
|
|
8879
|
+
* One-time startup check: if the user has Anthropic OAuth credentials and
|
|
8880
|
+
* hasn't yet acknowledged the Claude Max ToS warning, show it now.
|
|
8881
|
+
*/
|
|
8882
|
+
async checkClaudeMaxOAuthWarning() {
|
|
8883
|
+
const authStorage = this.state.authStorage;
|
|
8884
|
+
if (!authStorage || !authStorage.isLoggedIn(ANTHROPIC_OAUTH_PROVIDER_ID)) return;
|
|
8885
|
+
const settings = loadSettings();
|
|
8886
|
+
if (settings.onboarding.claudeMaxOAuthWarningAcknowledgedAt) return;
|
|
8887
|
+
const result = await showClaudeMaxOAuthWarning(this.state, "startup");
|
|
8888
|
+
if (result === "continue") {
|
|
8889
|
+
settings.onboarding.claudeMaxOAuthWarningAcknowledgedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8890
|
+
saveSettings(settings);
|
|
8891
|
+
} else if (result === "remove") {
|
|
8892
|
+
authStorage.logout(ANTHROPIC_OAUTH_PROVIDER_ID);
|
|
8893
|
+
settings.onboarding.claudeMaxOAuthWarningAcknowledgedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8894
|
+
saveSettings(settings);
|
|
8895
|
+
await this.refreshModelAuthStatus();
|
|
8896
|
+
}
|
|
8897
|
+
}
|
|
8429
8898
|
/**
|
|
8430
8899
|
* Get the workspace, preferring harness-owned workspace over the direct option.
|
|
8431
8900
|
*/
|
|
@@ -8519,7 +8988,7 @@ var MastraTUI = class _MastraTUI {
|
|
|
8519
8988
|
signal: dialog.signal
|
|
8520
8989
|
}).then(async () => {
|
|
8521
8990
|
this.state.ui.hideOverlay();
|
|
8522
|
-
const { PROVIDER_DEFAULT_MODELS: PROVIDER_DEFAULT_MODELS2 } = await import('./storage-
|
|
8991
|
+
const { PROVIDER_DEFAULT_MODELS: PROVIDER_DEFAULT_MODELS2 } = await import('./storage-PQOHJLBI.js');
|
|
8523
8992
|
const defaultModel = PROVIDER_DEFAULT_MODELS2[providerId];
|
|
8524
8993
|
if (defaultModel) {
|
|
8525
8994
|
await this.state.harness.switchModel({ modelId: defaultModel });
|
|
@@ -8564,6 +9033,7 @@ var MastraTUI = class _MastraTUI {
|
|
|
8564
9033
|
};
|
|
8565
9034
|
};
|
|
8566
9035
|
const access = await buildAccess();
|
|
9036
|
+
const hasProviderAccess = Object.values(access).some(Boolean);
|
|
8567
9037
|
const savedSettings = loadSettings();
|
|
8568
9038
|
const modePacks = getAvailableModePacks(access, savedSettings.customModelPacks);
|
|
8569
9039
|
const omPacks = getAvailableOmPacks(access);
|
|
@@ -8582,6 +9052,7 @@ var MastraTUI = class _MastraTUI {
|
|
|
8582
9052
|
authProviders,
|
|
8583
9053
|
modePacks,
|
|
8584
9054
|
omPacks,
|
|
9055
|
+
hasProviderAccess,
|
|
8585
9056
|
previous,
|
|
8586
9057
|
onComplete: async (result) => {
|
|
8587
9058
|
this.state.activeOnboarding = void 0;
|
|
@@ -8599,11 +9070,23 @@ var MastraTUI = class _MastraTUI {
|
|
|
8599
9070
|
resolve2();
|
|
8600
9071
|
},
|
|
8601
9072
|
onLogin: (providerId, done) => {
|
|
9073
|
+
if (providerId === ANTHROPIC_OAUTH_PROVIDER_ID) {
|
|
9074
|
+
const s = loadSettings();
|
|
9075
|
+
s.onboarding.claudeMaxOAuthWarningAcknowledgedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
9076
|
+
saveSettings(s);
|
|
9077
|
+
}
|
|
8602
9078
|
this.performLogin(providerId).then(async () => {
|
|
8603
|
-
|
|
8604
|
-
|
|
8605
|
-
|
|
8606
|
-
|
|
9079
|
+
try {
|
|
9080
|
+
const updatedAccess = await buildAccess();
|
|
9081
|
+
const updatedHasAccess = Object.values(updatedAccess).some(Boolean);
|
|
9082
|
+
component.updateModePacks(getAvailableModePacks(updatedAccess, savedSettings.customModelPacks));
|
|
9083
|
+
component.updateOmPacks(getAvailableOmPacks(updatedAccess));
|
|
9084
|
+
component.updateHasProviderAccess(updatedHasAccess);
|
|
9085
|
+
} catch (err) {
|
|
9086
|
+
console.error("Failed to refresh provider access after login:", err);
|
|
9087
|
+
} finally {
|
|
9088
|
+
done();
|
|
9089
|
+
}
|
|
8607
9090
|
});
|
|
8608
9091
|
},
|
|
8609
9092
|
onSelectModel: async (title, modeColor) => {
|
|
@@ -8725,19 +9208,19 @@ var LoginSelectorComponent = class extends Box {
|
|
|
8725
9208
|
onSelectCallback;
|
|
8726
9209
|
onCancelCallback;
|
|
8727
9210
|
constructor(mode, authSource, onSelect, onCancel) {
|
|
8728
|
-
super(2, 1, (text) => bg("overlayBg", text));
|
|
9211
|
+
super(2, 1, (text) => theme.bg("overlayBg", text));
|
|
8729
9212
|
this.mode = mode;
|
|
8730
9213
|
this.authSource = authSource;
|
|
8731
9214
|
this.onSelectCallback = onSelect;
|
|
8732
9215
|
this.onCancelCallback = onCancel;
|
|
8733
9216
|
this.loadProviders();
|
|
8734
9217
|
const title = mode === "login" ? "Select provider to login:" : "Select provider to logout:";
|
|
8735
|
-
this.addChild(new Text(fg("text", title)));
|
|
9218
|
+
this.addChild(new Text(theme.fg("text", title)));
|
|
8736
9219
|
this.addChild(new Spacer(1));
|
|
8737
9220
|
this.listContainer = new Container();
|
|
8738
9221
|
this.addChild(this.listContainer);
|
|
8739
9222
|
this.addChild(new Spacer(1));
|
|
8740
|
-
this.addChild(new Text(fg("muted", "Press Enter to select, Escape to cancel")));
|
|
9223
|
+
this.addChild(new Text(theme.fg("muted", "Press Enter to select, Escape to cancel")));
|
|
8741
9224
|
this.updateList();
|
|
8742
9225
|
}
|
|
8743
9226
|
loadProviders() {
|
|
@@ -8750,10 +9233,10 @@ var LoginSelectorComponent = class extends Box {
|
|
|
8750
9233
|
if (!provider) continue;
|
|
8751
9234
|
const isSelected = i === this.selectedIndex;
|
|
8752
9235
|
const isLoggedIn = this.authSource.isLoggedIn(provider.id);
|
|
8753
|
-
const statusIndicator = isLoggedIn ? fg("success", " \u2713 logged in") : "";
|
|
9236
|
+
const statusIndicator = isLoggedIn ? theme.fg("success", " \u2713 logged in") : "";
|
|
8754
9237
|
let line = "";
|
|
8755
9238
|
if (isSelected) {
|
|
8756
|
-
line = fg("accent", "\u2192 " + provider.name) + statusIndicator;
|
|
9239
|
+
line = theme.fg("accent", "\u2192 " + provider.name) + statusIndicator;
|
|
8757
9240
|
} else {
|
|
8758
9241
|
line = " " + provider.name + statusIndicator;
|
|
8759
9242
|
}
|
|
@@ -8761,7 +9244,7 @@ var LoginSelectorComponent = class extends Box {
|
|
|
8761
9244
|
}
|
|
8762
9245
|
if (this.allProviders.length === 0) {
|
|
8763
9246
|
const message = this.mode === "login" ? "No OAuth providers available" : "No OAuth providers logged in. Use /login first.";
|
|
8764
|
-
this.listContainer.addChild(new Text(fg("muted", message)));
|
|
9247
|
+
this.listContainer.addChild(new Text(theme.fg("muted", message)));
|
|
8765
9248
|
}
|
|
8766
9249
|
}
|
|
8767
9250
|
handleInput(keyData) {
|
|
@@ -8783,6 +9266,6 @@ var LoginSelectorComponent = class extends Box {
|
|
|
8783
9266
|
}
|
|
8784
9267
|
};
|
|
8785
9268
|
|
|
8786
|
-
export { AssistantMessageComponent, LoginDialogComponent, LoginSelectorComponent, MastraTUI, ModelSelectorComponent, OMProgressComponent, ToolExecutionComponentEnhanced, UserMessageComponent, createTUIState, formatOMStatus };
|
|
8787
|
-
//# sourceMappingURL=chunk-
|
|
8788
|
-
//# sourceMappingURL=chunk-
|
|
9269
|
+
export { AssistantMessageComponent, LoginDialogComponent, LoginSelectorComponent, MastraTUI, ModelSelectorComponent, OMProgressComponent, ToolExecutionComponentEnhanced, UserMessageComponent, createTUIState, detectTerminalTheme, formatOMStatus };
|
|
9270
|
+
//# sourceMappingURL=chunk-X3BGE7CL.js.map
|
|
9271
|
+
//# sourceMappingURL=chunk-X3BGE7CL.js.map
|