@oh-my-pi/pi-coding-agent 6.8.5 → 6.9.69
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 +51 -0
- package/package.json +6 -6
- package/src/cli/stats-cli.ts +191 -0
- package/src/core/agent-session.ts +103 -1
- package/src/core/extensions/index.ts +2 -0
- package/src/core/extensions/runner.ts +31 -0
- package/src/core/extensions/types.ts +24 -0
- package/src/core/messages.ts +48 -0
- package/src/core/sdk.ts +0 -2
- package/src/core/session-manager.ts +10 -1
- package/src/core/settings-manager.ts +0 -105
- package/src/core/tools/bash.ts +5 -7
- package/src/core/tools/index.ts +1 -5
- package/src/core/tools/patch/applicator.ts +115 -17
- package/src/core/tools/patch/index.ts +1 -1
- package/src/core/tools/patch/normalize.ts +185 -10
- package/src/core/tools/python.ts +444 -86
- package/src/core/tools/task/executor.ts +2 -6
- package/src/core/tools/task/index.ts +30 -12
- package/src/core/tools/task/render.ts +163 -30
- package/src/core/tools/task/template.ts +37 -0
- package/src/core/tools/task/types.ts +6 -2
- package/src/core/tools/task/worker.ts +1 -1
- package/src/index.ts +2 -2
- package/src/main.ts +12 -0
- package/src/modes/interactive/components/python-execution.ts +180 -0
- package/src/modes/interactive/components/settings-defs.ts +0 -70
- package/src/modes/interactive/components/settings-selector.ts +0 -1
- package/src/modes/interactive/components/welcome.ts +1 -0
- package/src/modes/interactive/controllers/command-controller.ts +46 -0
- package/src/modes/interactive/controllers/event-controller.ts +0 -11
- package/src/modes/interactive/controllers/input-controller.ts +28 -1
- package/src/modes/interactive/controllers/selector-controller.ts +0 -9
- package/src/modes/interactive/interactive-mode.ts +10 -58
- package/src/modes/interactive/theme/dark.json +2 -9
- package/src/modes/interactive/theme/defaults/alabaster.json +2 -8
- package/src/modes/interactive/theme/defaults/amethyst.json +2 -9
- package/src/modes/interactive/theme/defaults/anthracite.json +2 -9
- package/src/modes/interactive/theme/defaults/basalt.json +89 -88
- package/src/modes/interactive/theme/defaults/birch.json +2 -8
- package/src/modes/interactive/theme/defaults/dark-abyss.json +2 -8
- package/src/modes/interactive/theme/defaults/dark-arctic.json +2 -9
- package/src/modes/interactive/theme/defaults/dark-aurora.json +3 -2
- package/src/modes/interactive/theme/defaults/dark-catppuccin.json +2 -1
- package/src/modes/interactive/theme/defaults/dark-cavern.json +2 -8
- package/src/modes/interactive/theme/defaults/dark-copper.json +3 -2
- package/src/modes/interactive/theme/defaults/dark-cosmos.json +2 -8
- package/src/modes/interactive/theme/defaults/dark-cyberpunk.json +2 -9
- package/src/modes/interactive/theme/defaults/dark-dracula.json +2 -9
- package/src/modes/interactive/theme/defaults/dark-eclipse.json +2 -8
- package/src/modes/interactive/theme/defaults/dark-ember.json +3 -2
- package/src/modes/interactive/theme/defaults/dark-equinox.json +2 -8
- package/src/modes/interactive/theme/defaults/dark-forest.json +2 -9
- package/src/modes/interactive/theme/defaults/dark-github.json +2 -9
- package/src/modes/interactive/theme/defaults/dark-gruvbox.json +2 -9
- package/src/modes/interactive/theme/defaults/dark-lavender.json +3 -2
- package/src/modes/interactive/theme/defaults/dark-lunar.json +2 -8
- package/src/modes/interactive/theme/defaults/dark-midnight.json +3 -2
- package/src/modes/interactive/theme/defaults/dark-monochrome.json +2 -9
- package/src/modes/interactive/theme/defaults/dark-monokai.json +2 -9
- package/src/modes/interactive/theme/defaults/dark-nebula.json +2 -8
- package/src/modes/interactive/theme/defaults/dark-nord.json +2 -9
- package/src/modes/interactive/theme/defaults/dark-ocean.json +2 -9
- package/src/modes/interactive/theme/defaults/dark-one.json +2 -9
- package/src/modes/interactive/theme/defaults/dark-rainforest.json +2 -8
- package/src/modes/interactive/theme/defaults/dark-reef.json +2 -8
- package/src/modes/interactive/theme/defaults/dark-retro.json +2 -9
- package/src/modes/interactive/theme/defaults/dark-rose-pine.json +2 -1
- package/src/modes/interactive/theme/defaults/dark-sakura.json +3 -2
- package/src/modes/interactive/theme/defaults/dark-slate.json +3 -2
- package/src/modes/interactive/theme/defaults/dark-solarized.json +2 -1
- package/src/modes/interactive/theme/defaults/dark-solstice.json +2 -8
- package/src/modes/interactive/theme/defaults/dark-starfall.json +2 -8
- package/src/modes/interactive/theme/defaults/dark-sunset.json +2 -9
- package/src/modes/interactive/theme/defaults/dark-swamp.json +2 -8
- package/src/modes/interactive/theme/defaults/dark-synthwave.json +2 -1
- package/src/modes/interactive/theme/defaults/dark-taiga.json +2 -8
- package/src/modes/interactive/theme/defaults/dark-terminal.json +3 -2
- package/src/modes/interactive/theme/defaults/dark-tokyo-night.json +2 -9
- package/src/modes/interactive/theme/defaults/dark-tundra.json +2 -8
- package/src/modes/interactive/theme/defaults/dark-twilight.json +2 -8
- package/src/modes/interactive/theme/defaults/dark-volcanic.json +2 -8
- package/src/modes/interactive/theme/defaults/graphite.json +2 -9
- package/src/modes/interactive/theme/defaults/light-arctic.json +2 -1
- package/src/modes/interactive/theme/defaults/light-aurora-day.json +2 -8
- package/src/modes/interactive/theme/defaults/light-canyon.json +2 -8
- package/src/modes/interactive/theme/defaults/light-catppuccin.json +2 -1
- package/src/modes/interactive/theme/defaults/light-cirrus.json +2 -8
- package/src/modes/interactive/theme/defaults/light-coral.json +3 -2
- package/src/modes/interactive/theme/defaults/light-cyberpunk.json +2 -9
- package/src/modes/interactive/theme/defaults/light-dawn.json +2 -8
- package/src/modes/interactive/theme/defaults/light-dunes.json +2 -8
- package/src/modes/interactive/theme/defaults/light-eucalyptus.json +3 -2
- package/src/modes/interactive/theme/defaults/light-forest.json +2 -9
- package/src/modes/interactive/theme/defaults/light-frost.json +3 -2
- package/src/modes/interactive/theme/defaults/light-github.json +2 -1
- package/src/modes/interactive/theme/defaults/light-glacier.json +2 -8
- package/src/modes/interactive/theme/defaults/light-gruvbox.json +2 -9
- package/src/modes/interactive/theme/defaults/light-haze.json +2 -8
- package/src/modes/interactive/theme/defaults/light-honeycomb.json +3 -2
- package/src/modes/interactive/theme/defaults/light-lagoon.json +2 -8
- package/src/modes/interactive/theme/defaults/light-lavender.json +3 -2
- package/src/modes/interactive/theme/defaults/light-meadow.json +2 -8
- package/src/modes/interactive/theme/defaults/light-mint.json +3 -2
- package/src/modes/interactive/theme/defaults/light-monochrome.json +2 -1
- package/src/modes/interactive/theme/defaults/light-ocean.json +2 -9
- package/src/modes/interactive/theme/defaults/light-one.json +2 -8
- package/src/modes/interactive/theme/defaults/light-opal.json +2 -8
- package/src/modes/interactive/theme/defaults/light-orchard.json +2 -8
- package/src/modes/interactive/theme/defaults/light-paper.json +3 -2
- package/src/modes/interactive/theme/defaults/light-prism.json +2 -8
- package/src/modes/interactive/theme/defaults/light-retro.json +2 -9
- package/src/modes/interactive/theme/defaults/light-sand.json +3 -2
- package/src/modes/interactive/theme/defaults/light-savanna.json +2 -8
- package/src/modes/interactive/theme/defaults/light-solarized.json +2 -1
- package/src/modes/interactive/theme/defaults/light-soleil.json +2 -8
- package/src/modes/interactive/theme/defaults/light-sunset.json +2 -9
- package/src/modes/interactive/theme/defaults/light-synthwave.json +2 -9
- package/src/modes/interactive/theme/defaults/light-tokyo-night.json +2 -9
- package/src/modes/interactive/theme/defaults/light-wetland.json +2 -8
- package/src/modes/interactive/theme/defaults/light-zenith.json +2 -8
- package/src/modes/interactive/theme/defaults/limestone.json +2 -8
- package/src/modes/interactive/theme/defaults/mahogany.json +2 -9
- package/src/modes/interactive/theme/defaults/marble.json +2 -8
- package/src/modes/interactive/theme/defaults/obsidian.json +89 -88
- package/src/modes/interactive/theme/defaults/onyx.json +89 -88
- package/src/modes/interactive/theme/defaults/pearl.json +2 -8
- package/src/modes/interactive/theme/defaults/porcelain.json +89 -88
- package/src/modes/interactive/theme/defaults/quartz.json +2 -8
- package/src/modes/interactive/theme/defaults/sandstone.json +2 -8
- package/src/modes/interactive/theme/defaults/titanium.json +88 -87
- package/src/modes/interactive/theme/light.json +2 -8
- package/src/modes/interactive/theme/theme-schema.json +5 -0
- package/src/modes/interactive/theme/theme.ts +7 -0
- package/src/modes/interactive/types.ts +5 -15
- package/src/modes/interactive/utils/ui-helpers.ts +20 -0
- package/src/prompts/system/system-prompt.md +8 -0
- package/src/prompts/tools/python.md +40 -2
- package/src/prompts/tools/task.md +8 -13
- package/src/core/custom-commands/bundled/wt/index.ts +0 -435
- package/src/core/tools/git.ts +0 -213
- package/src/core/voice-controller.ts +0 -135
- package/src/core/voice-supervisor.ts +0 -976
- package/src/core/voice.ts +0 -314
- package/src/lib/worktree/collapse.ts +0 -180
- package/src/lib/worktree/constants.ts +0 -14
- package/src/lib/worktree/errors.ts +0 -23
- package/src/lib/worktree/git.ts +0 -60
- package/src/lib/worktree/index.ts +0 -15
- package/src/lib/worktree/operations.ts +0 -216
- package/src/lib/worktree/session.ts +0 -114
- package/src/lib/worktree/stats.ts +0 -67
- package/src/modes/interactive/utils/voice-manager.ts +0 -96
- package/src/prompts/tools/git.md +0 -9
- package/src/prompts/voice-summary.md +0 -12
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component for displaying user-initiated Python execution with streaming output.
|
|
3
|
+
* Shares the same kernel session as the agent's Python tool.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Container, Loader, Spacer, Text, type TUI } from "@oh-my-pi/pi-tui";
|
|
7
|
+
import stripAnsi from "strip-ansi";
|
|
8
|
+
import {
|
|
9
|
+
DEFAULT_MAX_BYTES,
|
|
10
|
+
DEFAULT_MAX_LINES,
|
|
11
|
+
type TruncationResult,
|
|
12
|
+
truncateTail,
|
|
13
|
+
} from "../../../core/tools/truncate";
|
|
14
|
+
import { getSymbolTheme, highlightCode, theme } from "../theme/theme";
|
|
15
|
+
import { DynamicBorder } from "./dynamic-border";
|
|
16
|
+
import { truncateToVisualLines } from "./visual-truncate";
|
|
17
|
+
|
|
18
|
+
const PREVIEW_LINES = 20;
|
|
19
|
+
|
|
20
|
+
export class PythonExecutionComponent extends Container {
|
|
21
|
+
private code: string;
|
|
22
|
+
private outputLines: string[] = [];
|
|
23
|
+
private status: "running" | "complete" | "cancelled" | "error" = "running";
|
|
24
|
+
private exitCode: number | undefined = undefined;
|
|
25
|
+
private loader: Loader;
|
|
26
|
+
private truncationResult?: TruncationResult;
|
|
27
|
+
private fullOutputPath?: string;
|
|
28
|
+
private expanded = false;
|
|
29
|
+
private contentContainer: Container;
|
|
30
|
+
private excludeFromContext: boolean;
|
|
31
|
+
|
|
32
|
+
private formatHeader(colorKey: "dim" | "pythonMode"): Text {
|
|
33
|
+
const prompt = theme.fg(colorKey, theme.bold(">>>"));
|
|
34
|
+
const continuation = theme.fg(colorKey, " ");
|
|
35
|
+
const codeLines = highlightCode(this.code, "python");
|
|
36
|
+
const headerLines = codeLines.map((line, index) =>
|
|
37
|
+
index === 0 ? `${prompt} ${line}` : `${continuation}${line}`,
|
|
38
|
+
);
|
|
39
|
+
return new Text(headerLines.join("\n"), 1, 0);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
constructor(code: string, ui: TUI, excludeFromContext = false) {
|
|
43
|
+
super();
|
|
44
|
+
this.code = code;
|
|
45
|
+
this.excludeFromContext = excludeFromContext;
|
|
46
|
+
|
|
47
|
+
const colorKey = this.excludeFromContext ? "dim" : "pythonMode";
|
|
48
|
+
const borderColor = (str: string) => theme.fg(colorKey, str);
|
|
49
|
+
|
|
50
|
+
this.addChild(new Spacer(1));
|
|
51
|
+
this.addChild(new DynamicBorder(borderColor));
|
|
52
|
+
|
|
53
|
+
this.contentContainer = new Container();
|
|
54
|
+
this.addChild(this.contentContainer);
|
|
55
|
+
this.contentContainer.addChild(this.formatHeader(colorKey));
|
|
56
|
+
|
|
57
|
+
this.loader = new Loader(
|
|
58
|
+
ui,
|
|
59
|
+
(spinner) => theme.fg(colorKey, spinner),
|
|
60
|
+
(text) => theme.fg("muted", text),
|
|
61
|
+
`Running${theme.format.ellipsis} (esc to cancel)`,
|
|
62
|
+
getSymbolTheme().spinnerFrames,
|
|
63
|
+
);
|
|
64
|
+
this.contentContainer.addChild(this.loader);
|
|
65
|
+
|
|
66
|
+
this.addChild(new DynamicBorder(borderColor));
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
setExpanded(expanded: boolean): void {
|
|
70
|
+
this.expanded = expanded;
|
|
71
|
+
this.updateDisplay();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
override invalidate(): void {
|
|
75
|
+
super.invalidate();
|
|
76
|
+
this.updateDisplay();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
appendOutput(chunk: string): void {
|
|
80
|
+
const clean = stripAnsi(chunk).replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
81
|
+
|
|
82
|
+
const newLines = clean.split("\n");
|
|
83
|
+
if (this.outputLines.length > 0 && newLines.length > 0) {
|
|
84
|
+
this.outputLines[this.outputLines.length - 1] += newLines[0];
|
|
85
|
+
this.outputLines.push(...newLines.slice(1));
|
|
86
|
+
} else {
|
|
87
|
+
this.outputLines.push(...newLines);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
this.updateDisplay();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
setComplete(
|
|
94
|
+
exitCode: number | undefined,
|
|
95
|
+
cancelled: boolean,
|
|
96
|
+
truncationResult?: TruncationResult,
|
|
97
|
+
fullOutputPath?: string,
|
|
98
|
+
): void {
|
|
99
|
+
this.exitCode = exitCode;
|
|
100
|
+
this.status = cancelled
|
|
101
|
+
? "cancelled"
|
|
102
|
+
: exitCode !== 0 && exitCode !== undefined && exitCode !== null
|
|
103
|
+
? "error"
|
|
104
|
+
: "complete";
|
|
105
|
+
this.truncationResult = truncationResult;
|
|
106
|
+
this.fullOutputPath = fullOutputPath;
|
|
107
|
+
|
|
108
|
+
this.loader.stop();
|
|
109
|
+
this.updateDisplay();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private updateDisplay(): void {
|
|
113
|
+
const fullOutput = this.outputLines.join("\n");
|
|
114
|
+
const contextTruncation = truncateTail(fullOutput, {
|
|
115
|
+
maxLines: DEFAULT_MAX_LINES,
|
|
116
|
+
maxBytes: DEFAULT_MAX_BYTES,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
const availableLines = contextTruncation.content ? contextTruncation.content.split("\n") : [];
|
|
120
|
+
const previewLogicalLines = availableLines.slice(-PREVIEW_LINES);
|
|
121
|
+
const hiddenLineCount = availableLines.length - previewLogicalLines.length;
|
|
122
|
+
|
|
123
|
+
this.contentContainer.clear();
|
|
124
|
+
|
|
125
|
+
const colorKey = this.excludeFromContext ? "dim" : "pythonMode";
|
|
126
|
+
this.contentContainer.addChild(this.formatHeader(colorKey));
|
|
127
|
+
|
|
128
|
+
if (availableLines.length > 0) {
|
|
129
|
+
if (this.expanded) {
|
|
130
|
+
const displayText = availableLines.map((line) => theme.fg("muted", line)).join("\n");
|
|
131
|
+
this.contentContainer.addChild(new Text(`\n${displayText}`, 1, 0));
|
|
132
|
+
} else {
|
|
133
|
+
const styledOutput = previewLogicalLines.map((line) => theme.fg("muted", line)).join("\n");
|
|
134
|
+
const previewText = `\n${styledOutput}`;
|
|
135
|
+
this.contentContainer.addChild({
|
|
136
|
+
render: (width: number) => {
|
|
137
|
+
const { visualLines } = truncateToVisualLines(previewText, PREVIEW_LINES, width, 1);
|
|
138
|
+
return visualLines;
|
|
139
|
+
},
|
|
140
|
+
invalidate: () => {},
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (this.status === "running") {
|
|
146
|
+
this.contentContainer.addChild(this.loader);
|
|
147
|
+
} else {
|
|
148
|
+
const statusParts: string[] = [];
|
|
149
|
+
|
|
150
|
+
if (hiddenLineCount > 0) {
|
|
151
|
+
statusParts.push(
|
|
152
|
+
theme.fg("dim", `${theme.format.ellipsis} ${hiddenLineCount} more lines (ctrl+o to expand)`),
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (this.status === "cancelled") {
|
|
157
|
+
statusParts.push(theme.fg("warning", "(cancelled)"));
|
|
158
|
+
} else if (this.status === "error") {
|
|
159
|
+
statusParts.push(theme.fg("error", `(exit ${this.exitCode})`));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const wasTruncated = this.truncationResult?.truncated || contextTruncation.truncated;
|
|
163
|
+
if (wasTruncated && this.fullOutputPath) {
|
|
164
|
+
statusParts.push(theme.fg("warning", `Output truncated. Full output: ${this.fullOutputPath}`));
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (statusParts.length > 0) {
|
|
168
|
+
this.contentContainer.addChild(new Text(`\n${statusParts.join("\n")}`, 1, 0));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
getOutput(): string {
|
|
174
|
+
return this.outputLines.join("\n");
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
getCode(): string {
|
|
178
|
+
return this.code;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
@@ -83,7 +83,6 @@ const THINKING_DESCRIPTIONS: Record<ThinkingLevel, string> = {
|
|
|
83
83
|
* - behavior: Core agent behavior (compaction, modes, retries, notifications)
|
|
84
84
|
* - tools: Tool-specific settings (bash, git, python, edit, MCP, skills)
|
|
85
85
|
* - display: Visual/UI settings (theme, images, thinking)
|
|
86
|
-
* - voice: Voice mode and TTS settings
|
|
87
86
|
* - ttsr: Time Traveling Stream Rules settings
|
|
88
87
|
* - status: Status line configuration
|
|
89
88
|
* - lsp: LSP integration settings
|
|
@@ -250,15 +249,6 @@ export const SETTINGS_DEFS: SettingDef[] = [
|
|
|
250
249
|
get: (sm) => sm.getBashInterceptorSimpleLsEnabled(),
|
|
251
250
|
set: (sm, v) => sm.setBashInterceptorSimpleLsEnabled(v),
|
|
252
251
|
},
|
|
253
|
-
{
|
|
254
|
-
id: "gitTool",
|
|
255
|
-
tab: "tools",
|
|
256
|
-
type: "boolean",
|
|
257
|
-
label: "Git tool",
|
|
258
|
-
description: "Enable structured Git tool",
|
|
259
|
-
get: (sm) => sm.getGitToolEnabled(),
|
|
260
|
-
set: (sm, v) => sm.setGitToolEnabled(v),
|
|
261
|
-
},
|
|
262
252
|
{
|
|
263
253
|
id: "pythonToolMode",
|
|
264
254
|
tab: "tools",
|
|
@@ -494,66 +484,6 @@ export const SETTINGS_DEFS: SettingDef[] = [
|
|
|
494
484
|
set: (sm, v) => sm.setShowHardwareCursor(v),
|
|
495
485
|
},
|
|
496
486
|
|
|
497
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
498
|
-
// Voice tab - Voice mode and TTS settings
|
|
499
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
500
|
-
{
|
|
501
|
-
id: "voiceEnabled",
|
|
502
|
-
tab: "voice",
|
|
503
|
-
type: "boolean",
|
|
504
|
-
label: "Voice mode",
|
|
505
|
-
description: "Enable realtime voice input/output (Ctrl+Y toggle, auto-send on silence)",
|
|
506
|
-
get: (sm) => sm.getVoiceEnabled(),
|
|
507
|
-
set: (sm, v) => sm.setVoiceEnabled(v),
|
|
508
|
-
},
|
|
509
|
-
{
|
|
510
|
-
id: "voiceTtsModel",
|
|
511
|
-
tab: "voice",
|
|
512
|
-
type: "submenu",
|
|
513
|
-
label: "TTS model",
|
|
514
|
-
description: "Text-to-speech model for voice output",
|
|
515
|
-
get: (sm) => sm.getVoiceTtsModel(),
|
|
516
|
-
set: (sm, v) => sm.setVoiceTtsModel(v),
|
|
517
|
-
getOptions: () => [
|
|
518
|
-
{ value: "gpt-4o-mini-tts", label: "GPT-4o Mini TTS", description: "Fast and efficient" },
|
|
519
|
-
{ value: "tts-1", label: "TTS-1", description: "Standard quality" },
|
|
520
|
-
{ value: "tts-1-hd", label: "TTS-1 HD", description: "Higher quality" },
|
|
521
|
-
],
|
|
522
|
-
},
|
|
523
|
-
{
|
|
524
|
-
id: "voiceTtsVoice",
|
|
525
|
-
tab: "voice",
|
|
526
|
-
type: "submenu",
|
|
527
|
-
label: "TTS voice",
|
|
528
|
-
description: "Voice for text-to-speech output",
|
|
529
|
-
get: (sm) => sm.getVoiceTtsVoice(),
|
|
530
|
-
set: (sm, v) => sm.setVoiceTtsVoice(v),
|
|
531
|
-
getOptions: () => [
|
|
532
|
-
{ value: "alloy", label: "Alloy", description: "Neutral" },
|
|
533
|
-
{ value: "echo", label: "Echo", description: "Male" },
|
|
534
|
-
{ value: "fable", label: "Fable", description: "British" },
|
|
535
|
-
{ value: "onyx", label: "Onyx", description: "Deep male" },
|
|
536
|
-
{ value: "nova", label: "Nova", description: "Female" },
|
|
537
|
-
{ value: "shimmer", label: "Shimmer", description: "Female" },
|
|
538
|
-
],
|
|
539
|
-
},
|
|
540
|
-
{
|
|
541
|
-
id: "voiceTtsFormat",
|
|
542
|
-
tab: "voice",
|
|
543
|
-
type: "submenu",
|
|
544
|
-
label: "TTS format",
|
|
545
|
-
description: "Audio format for voice output",
|
|
546
|
-
get: (sm) => sm.getVoiceTtsFormat(),
|
|
547
|
-
set: (sm, v) => sm.setVoiceTtsFormat(v as "wav" | "mp3" | "opus" | "aac" | "flac"),
|
|
548
|
-
getOptions: () => [
|
|
549
|
-
{ value: "wav", label: "WAV", description: "Uncompressed, best quality" },
|
|
550
|
-
{ value: "mp3", label: "MP3", description: "Compressed, widely compatible" },
|
|
551
|
-
{ value: "opus", label: "Opus", description: "Efficient compression" },
|
|
552
|
-
{ value: "aac", label: "AAC", description: "Apple-friendly" },
|
|
553
|
-
{ value: "flac", label: "FLAC", description: "Lossless compression" },
|
|
554
|
-
],
|
|
555
|
-
},
|
|
556
|
-
|
|
557
487
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
558
488
|
// TTSR tab - Time Traveling Stream Rules
|
|
559
489
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -117,7 +117,6 @@ const SETTINGS_TABS: Tab[] = [
|
|
|
117
117
|
{ id: "behavior", label: "Behavior" },
|
|
118
118
|
{ id: "tools", label: "Tools" },
|
|
119
119
|
{ id: "display", label: "Display" },
|
|
120
|
-
{ id: "voice", label: "Voice" },
|
|
121
120
|
{ id: "ttsr", label: "TTSR" },
|
|
122
121
|
{ id: "status", label: "Status" },
|
|
123
122
|
{ id: "lsp", label: "LSP" },
|
|
@@ -117,6 +117,7 @@ export class WelcomeComponent implements Component {
|
|
|
117
117
|
` ${theme.fg("dim", "?")}${theme.fg("muted", " for keyboard shortcuts")}`,
|
|
118
118
|
` ${theme.fg("dim", "/")}${theme.fg("muted", " for commands")}`,
|
|
119
119
|
` ${theme.fg("dim", "!")}${theme.fg("muted", " to run bash")}`,
|
|
120
|
+
` ${theme.fg("dim", "$")}${theme.fg("muted", " to run python")}`,
|
|
120
121
|
separator,
|
|
121
122
|
` ${theme.bold(theme.fg("accent", "LSP Servers"))}`,
|
|
122
123
|
...lspLines,
|
|
@@ -16,6 +16,7 @@ import { ArminComponent } from "../components/armin";
|
|
|
16
16
|
import { BashExecutionComponent } from "../components/bash-execution";
|
|
17
17
|
import { BorderedLoader } from "../components/bordered-loader";
|
|
18
18
|
import { DynamicBorder } from "../components/dynamic-border";
|
|
19
|
+
import { PythonExecutionComponent } from "../components/python-execution";
|
|
19
20
|
import { getMarkdownTheme, getSymbolTheme, theme } from "../theme/theme";
|
|
20
21
|
import type { InteractiveModeContext } from "../types";
|
|
21
22
|
|
|
@@ -344,6 +345,8 @@ export class CommandController {
|
|
|
344
345
|
| \`/\` | Slash commands |
|
|
345
346
|
| \`!\` | Run bash command |
|
|
346
347
|
| \`!!\` | Run bash command (excluded from context) |
|
|
348
|
+
| \`$\` | Run Python in shared kernel |
|
|
349
|
+
| \`$$\` | Run Python (excluded from context) |
|
|
347
350
|
`;
|
|
348
351
|
this.ctx.chatContainer.addChild(new Spacer(1));
|
|
349
352
|
this.ctx.chatContainer.addChild(new DynamicBorder());
|
|
@@ -471,6 +474,49 @@ export class CommandController {
|
|
|
471
474
|
this.ctx.ui.requestRender();
|
|
472
475
|
}
|
|
473
476
|
|
|
477
|
+
async handlePythonCommand(code: string, excludeFromContext = false): Promise<void> {
|
|
478
|
+
const isDeferred = this.ctx.session.isStreaming;
|
|
479
|
+
this.ctx.pythonComponent = new PythonExecutionComponent(code, this.ctx.ui, excludeFromContext);
|
|
480
|
+
|
|
481
|
+
if (isDeferred) {
|
|
482
|
+
this.ctx.pendingMessagesContainer.addChild(this.ctx.pythonComponent);
|
|
483
|
+
this.ctx.pendingPythonComponents.push(this.ctx.pythonComponent);
|
|
484
|
+
} else {
|
|
485
|
+
this.ctx.chatContainer.addChild(this.ctx.pythonComponent);
|
|
486
|
+
}
|
|
487
|
+
this.ctx.ui.requestRender();
|
|
488
|
+
|
|
489
|
+
try {
|
|
490
|
+
const result = await this.ctx.session.executePython(
|
|
491
|
+
code,
|
|
492
|
+
(chunk) => {
|
|
493
|
+
if (this.ctx.pythonComponent) {
|
|
494
|
+
this.ctx.pythonComponent.appendOutput(chunk);
|
|
495
|
+
this.ctx.ui.requestRender();
|
|
496
|
+
}
|
|
497
|
+
},
|
|
498
|
+
{ excludeFromContext },
|
|
499
|
+
);
|
|
500
|
+
|
|
501
|
+
if (this.ctx.pythonComponent) {
|
|
502
|
+
this.ctx.pythonComponent.setComplete(
|
|
503
|
+
result.exitCode,
|
|
504
|
+
result.cancelled,
|
|
505
|
+
result.truncated ? ({ truncated: true, content: result.output } as TruncationResult) : undefined,
|
|
506
|
+
result.fullOutputPath,
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
} catch (error) {
|
|
510
|
+
if (this.ctx.pythonComponent) {
|
|
511
|
+
this.ctx.pythonComponent.setComplete(undefined, false);
|
|
512
|
+
}
|
|
513
|
+
this.ctx.showError(`Python execution failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
this.ctx.pythonComponent = undefined;
|
|
517
|
+
this.ctx.ui.requestRender();
|
|
518
|
+
}
|
|
519
|
+
|
|
474
520
|
async handleCompactCommand(customInstructions?: string): Promise<void> {
|
|
475
521
|
const entries = this.ctx.sessionManager.getEntries();
|
|
476
522
|
const messageCount = entries.filter((e) => e.type === "message").length;
|
|
@@ -68,7 +68,6 @@ export class EventController {
|
|
|
68
68
|
getSymbolTheme().spinnerFrames,
|
|
69
69
|
);
|
|
70
70
|
this.ctx.statusContainer.addChild(this.ctx.loadingAnimation);
|
|
71
|
-
this.ctx.startVoiceProgressTimer();
|
|
72
71
|
this.ctx.ui.requestRender();
|
|
73
72
|
break;
|
|
74
73
|
|
|
@@ -250,7 +249,6 @@ export class EventController {
|
|
|
250
249
|
}
|
|
251
250
|
|
|
252
251
|
case "agent_end":
|
|
253
|
-
this.ctx.stopVoiceProgressTimer();
|
|
254
252
|
if (this.ctx.loadingAnimation) {
|
|
255
253
|
this.ctx.loadingAnimation.stop();
|
|
256
254
|
this.ctx.loadingAnimation = undefined;
|
|
@@ -262,15 +260,6 @@ export class EventController {
|
|
|
262
260
|
this.ctx.streamingMessage = undefined;
|
|
263
261
|
}
|
|
264
262
|
this.ctx.pendingTools.clear();
|
|
265
|
-
if (this.ctx.settingsManager.getVoiceEnabled() && this.ctx.voiceAutoModeEnabled) {
|
|
266
|
-
const lastAssistant = this.ctx.findLastAssistantMessage();
|
|
267
|
-
if (lastAssistant && lastAssistant.stopReason !== "aborted" && lastAssistant.stopReason !== "error") {
|
|
268
|
-
const text = this.ctx.extractAssistantText(lastAssistant);
|
|
269
|
-
if (text) {
|
|
270
|
-
this.ctx.voiceSupervisor.notifyResult(text);
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
263
|
this.ctx.ui.requestRender();
|
|
275
264
|
this.sendCompletionNotification();
|
|
276
265
|
break;
|
|
@@ -31,6 +31,12 @@ export class InputController {
|
|
|
31
31
|
this.ctx.editor.setText("");
|
|
32
32
|
this.ctx.isBashMode = false;
|
|
33
33
|
this.ctx.updateEditorBorderColor();
|
|
34
|
+
} else if (this.ctx.isPythonMode) {
|
|
35
|
+
this.ctx.editor.setText("");
|
|
36
|
+
this.ctx.isPythonMode = false;
|
|
37
|
+
this.ctx.updateEditorBorderColor();
|
|
38
|
+
} else if (this.ctx.session.isPythonRunning) {
|
|
39
|
+
this.ctx.session.abortPython();
|
|
34
40
|
} else if (!this.ctx.editor.getText().trim()) {
|
|
35
41
|
// Double-escape with empty editor triggers /tree or /branch based on setting
|
|
36
42
|
const now = Date.now();
|
|
@@ -83,8 +89,11 @@ export class InputController {
|
|
|
83
89
|
|
|
84
90
|
this.ctx.editor.onChange = (text: string) => {
|
|
85
91
|
const wasBashMode = this.ctx.isBashMode;
|
|
92
|
+
const wasPythonMode = this.ctx.isPythonMode;
|
|
93
|
+
const trimmed = text.trimStart();
|
|
86
94
|
this.ctx.isBashMode = text.trimStart().startsWith("!");
|
|
87
|
-
|
|
95
|
+
this.ctx.isPythonMode = trimmed.startsWith("$") && !trimmed.startsWith("${");
|
|
96
|
+
if (wasBashMode !== this.ctx.isBashMode || wasPythonMode !== this.ctx.isPythonMode) {
|
|
88
97
|
this.ctx.updateEditorBorderColor();
|
|
89
98
|
}
|
|
90
99
|
};
|
|
@@ -309,6 +318,24 @@ export class InputController {
|
|
|
309
318
|
}
|
|
310
319
|
}
|
|
311
320
|
|
|
321
|
+
// Handle python command ($ for normal, $$ for excluded from context)
|
|
322
|
+
if (text.startsWith("$")) {
|
|
323
|
+
const isExcluded = text.startsWith("$$");
|
|
324
|
+
const code = isExcluded ? text.slice(2).trim() : text.slice(1).trim();
|
|
325
|
+
if (code) {
|
|
326
|
+
if (this.ctx.session.isPythonRunning) {
|
|
327
|
+
this.ctx.showWarning("A Python execution is already running. Press Esc to cancel it first.");
|
|
328
|
+
this.ctx.editor.setText(text);
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
this.ctx.editor.addToHistory(text);
|
|
332
|
+
await this.ctx.handlePythonCommand(code, isExcluded);
|
|
333
|
+
this.ctx.isPythonMode = false;
|
|
334
|
+
this.ctx.updateEditorBorderColor();
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
312
339
|
// Queue input during compaction
|
|
313
340
|
if (this.ctx.session.isCompacting) {
|
|
314
341
|
if (this.ctx.pendingImages.length > 0) {
|
|
@@ -199,15 +199,6 @@ export class SelectorController {
|
|
|
199
199
|
this.ctx.ui.invalidate();
|
|
200
200
|
break;
|
|
201
201
|
}
|
|
202
|
-
case "voiceEnabled": {
|
|
203
|
-
if (!value) {
|
|
204
|
-
this.ctx.voiceAutoModeEnabled = false;
|
|
205
|
-
this.ctx.stopVoiceProgressTimer();
|
|
206
|
-
void this.ctx.voiceSupervisor.stop();
|
|
207
|
-
this.ctx.setVoiceStatus(undefined);
|
|
208
|
-
}
|
|
209
|
-
break;
|
|
210
|
-
}
|
|
211
202
|
case "statusLinePreset":
|
|
212
203
|
case "statusLineSeparator":
|
|
213
204
|
case "statusLineShowHooks":
|
|
@@ -28,7 +28,6 @@ import { getRecentSessions } from "../../core/session-manager";
|
|
|
28
28
|
import type { SettingsManager } from "../../core/settings-manager";
|
|
29
29
|
import { loadSlashCommands } from "../../core/slash-commands";
|
|
30
30
|
import { setTerminalTitle } from "../../core/title-generator";
|
|
31
|
-
import { VoiceSupervisor } from "../../core/voice-supervisor";
|
|
32
31
|
import type { AssistantMessageComponent } from "./components/assistant-message";
|
|
33
32
|
import type { BashExecutionComponent } from "./components/bash-execution";
|
|
34
33
|
import { CustomEditor } from "./components/custom-editor";
|
|
@@ -36,6 +35,7 @@ import { DynamicBorder } from "./components/dynamic-border";
|
|
|
36
35
|
import type { HookEditorComponent } from "./components/hook-editor";
|
|
37
36
|
import type { HookInputComponent } from "./components/hook-input";
|
|
38
37
|
import type { HookSelectorComponent } from "./components/hook-selector";
|
|
38
|
+
import type { PythonExecutionComponent } from "./components/python-execution";
|
|
39
39
|
import { StatusLineComponent } from "./components/status-line";
|
|
40
40
|
import type { ToolExecutionHandle } from "./components/tool-execution";
|
|
41
41
|
import { WelcomeComponent } from "./components/welcome";
|
|
@@ -48,7 +48,6 @@ import type { Theme } from "./theme/theme";
|
|
|
48
48
|
import { getEditorTheme, getMarkdownTheme, onThemeChange, theme } from "./theme/theme";
|
|
49
49
|
import type { CompactionQueuedMessage, InteractiveModeContext, TodoItem } from "./types";
|
|
50
50
|
import { UiHelpers } from "./utils/ui-helpers";
|
|
51
|
-
import { VoiceManager } from "./utils/voice-manager";
|
|
52
51
|
|
|
53
52
|
const TODO_FILE_NAME = "todos.json";
|
|
54
53
|
|
|
@@ -72,7 +71,6 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
72
71
|
public settingsManager: SettingsManager;
|
|
73
72
|
public keybindings: KeybindingsManager;
|
|
74
73
|
public agent: AgentSession["agent"];
|
|
75
|
-
public voiceSupervisor: VoiceSupervisor;
|
|
76
74
|
public historyStorage?: HistoryStorage;
|
|
77
75
|
|
|
78
76
|
public ui: TUI;
|
|
@@ -96,6 +94,9 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
96
94
|
public pendingTools = new Map<string, ToolExecutionHandle>();
|
|
97
95
|
public pendingBashComponents: BashExecutionComponent[] = [];
|
|
98
96
|
public bashComponent: BashExecutionComponent | undefined = undefined;
|
|
97
|
+
public pendingPythonComponents: PythonExecutionComponent[] = [];
|
|
98
|
+
public pythonComponent: PythonExecutionComponent | undefined = undefined;
|
|
99
|
+
public isPythonMode = false;
|
|
99
100
|
public streamingComponent: AssistantMessageComponent | undefined = undefined;
|
|
100
101
|
public streamingMessage: AssistantMessage | undefined = undefined;
|
|
101
102
|
public loadingAnimation: Loader | undefined = undefined;
|
|
@@ -107,13 +108,8 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
107
108
|
public onInputCallback?: (input: { text: string; images?: ImageContent[] }) => void;
|
|
108
109
|
public lastSigintTime = 0;
|
|
109
110
|
public lastEscapeTime = 0;
|
|
110
|
-
public lastVoiceInterruptAt = 0;
|
|
111
|
-
public voiceAutoModeEnabled = false;
|
|
112
111
|
public shutdownRequested = false;
|
|
113
112
|
private isShuttingDown = false;
|
|
114
|
-
public voiceProgressTimer: ReturnType<typeof setTimeout> | undefined = undefined;
|
|
115
|
-
public voiceProgressSpoken = false;
|
|
116
|
-
public voiceProgressLastLength = 0;
|
|
117
113
|
public hookSelector: HookSelectorComponent | undefined = undefined;
|
|
118
114
|
public hookInput: HookInputComponent | undefined = undefined;
|
|
119
115
|
public hookEditor: HookEditorComponent | undefined = undefined;
|
|
@@ -137,7 +133,6 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
137
133
|
private readonly inputController: InputController;
|
|
138
134
|
private readonly selectorController: SelectorController;
|
|
139
135
|
private readonly uiHelpers: UiHelpers;
|
|
140
|
-
private readonly voiceManager: VoiceManager;
|
|
141
136
|
|
|
142
137
|
constructor(
|
|
143
138
|
session: AgentSession,
|
|
@@ -180,26 +175,6 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
180
175
|
this.editorContainer.addChild(this.editor);
|
|
181
176
|
this.statusLine = new StatusLineComponent(session);
|
|
182
177
|
this.statusLine.setAutoCompactEnabled(session.autoCompactionEnabled);
|
|
183
|
-
this.voiceSupervisor = new VoiceSupervisor(this.session.modelRegistry, {
|
|
184
|
-
onSendToAgent: async (text) => {
|
|
185
|
-
await this.submitVoiceText(text);
|
|
186
|
-
},
|
|
187
|
-
onInterruptAgent: async (reason) => {
|
|
188
|
-
await this.handleVoiceInterrupt(reason);
|
|
189
|
-
},
|
|
190
|
-
onStatus: (status) => {
|
|
191
|
-
this.setVoiceStatus(status);
|
|
192
|
-
},
|
|
193
|
-
onError: (error) => {
|
|
194
|
-
this.showError(error.message);
|
|
195
|
-
this.voiceAutoModeEnabled = false;
|
|
196
|
-
void this.voiceSupervisor.stop();
|
|
197
|
-
this.setVoiceStatus(undefined);
|
|
198
|
-
},
|
|
199
|
-
onWarning: (message) => {
|
|
200
|
-
this.showWarning(message);
|
|
201
|
-
},
|
|
202
|
-
});
|
|
203
178
|
|
|
204
179
|
this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();
|
|
205
180
|
|
|
@@ -255,7 +230,6 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
255
230
|
this.pendingSlashCommands = [...slashCommands, ...hookCommands, ...customCommands, ...skillCommandList];
|
|
256
231
|
|
|
257
232
|
this.uiHelpers = new UiHelpers(this);
|
|
258
|
-
this.voiceManager = new VoiceManager(this);
|
|
259
233
|
this.extensionUiController = new ExtensionUiController(this);
|
|
260
234
|
this.eventController = new EventController(this);
|
|
261
235
|
this.commandController = new CommandController(this);
|
|
@@ -397,6 +371,8 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
397
371
|
updateEditorBorderColor(): void {
|
|
398
372
|
if (this.isBashMode) {
|
|
399
373
|
this.editor.borderColor = theme.getBashModeBorderColor();
|
|
374
|
+
} else if (this.isPythonMode) {
|
|
375
|
+
this.editor.borderColor = theme.getPythonModeBorderColor();
|
|
400
376
|
} else {
|
|
401
377
|
const level = this.session.thinkingLevel || "off";
|
|
402
378
|
this.editor.borderColor = theme.getThinkingBorderColor(level);
|
|
@@ -511,9 +487,6 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
511
487
|
if (this.isShuttingDown) return;
|
|
512
488
|
this.isShuttingDown = true;
|
|
513
489
|
|
|
514
|
-
this.voiceAutoModeEnabled = false;
|
|
515
|
-
await this.voiceSupervisor.stop();
|
|
516
|
-
|
|
517
490
|
// Flush pending session writes before shutdown
|
|
518
491
|
await this.sessionManager.flush();
|
|
519
492
|
|
|
@@ -664,6 +637,10 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
664
637
|
return this.commandController.handleBashCommand(command, excludeFromContext);
|
|
665
638
|
}
|
|
666
639
|
|
|
640
|
+
handlePythonCommand(code: string, excludeFromContext?: boolean): Promise<void> {
|
|
641
|
+
return this.commandController.handlePythonCommand(code, excludeFromContext);
|
|
642
|
+
}
|
|
643
|
+
|
|
667
644
|
handleCompactCommand(customInstructions?: string): Promise<void> {
|
|
668
645
|
return this.commandController.handleCompactCommand(customInstructions);
|
|
669
646
|
}
|
|
@@ -783,31 +760,6 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
783
760
|
this.inputController.registerExtensionShortcuts();
|
|
784
761
|
}
|
|
785
762
|
|
|
786
|
-
// Voice handling
|
|
787
|
-
setVoiceStatus(text: string | undefined): void {
|
|
788
|
-
this.voiceManager.setVoiceStatus(text);
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
handleVoiceInterrupt(reason?: string): Promise<void> {
|
|
792
|
-
return this.voiceManager.handleVoiceInterrupt(reason);
|
|
793
|
-
}
|
|
794
|
-
|
|
795
|
-
startVoiceProgressTimer(): void {
|
|
796
|
-
this.voiceManager.startVoiceProgressTimer();
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
stopVoiceProgressTimer(): void {
|
|
800
|
-
this.voiceManager.stopVoiceProgressTimer();
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
maybeSpeakProgress(): Promise<void> {
|
|
804
|
-
return this.voiceManager.maybeSpeakProgress();
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
submitVoiceText(text: string): Promise<void> {
|
|
808
|
-
return this.voiceManager.submitVoiceText(text);
|
|
809
|
-
}
|
|
810
|
-
|
|
811
763
|
// Hook UI methods
|
|
812
764
|
initHooksAndCustomTools(): Promise<void> {
|
|
813
765
|
return this.extensionUiController.initHooksAndCustomTools();
|
|
@@ -30,7 +30,6 @@
|
|
|
30
30
|
"dim": "dimGray",
|
|
31
31
|
"text": "",
|
|
32
32
|
"thinkingText": "gray",
|
|
33
|
-
|
|
34
33
|
"selectedBg": "selectedBg",
|
|
35
34
|
"userMessageBg": "userMsgBg",
|
|
36
35
|
"userMessageText": "",
|
|
@@ -42,7 +41,6 @@
|
|
|
42
41
|
"toolErrorBg": "toolErrorBg",
|
|
43
42
|
"toolTitle": "",
|
|
44
43
|
"toolOutput": "gray",
|
|
45
|
-
|
|
46
44
|
"mdHeading": "#febc38",
|
|
47
45
|
"mdLink": "#0088fa",
|
|
48
46
|
"mdLinkUrl": "dimGray",
|
|
@@ -53,13 +51,10 @@
|
|
|
53
51
|
"mdQuoteBorder": "darkGray",
|
|
54
52
|
"mdHr": "darkGray",
|
|
55
53
|
"mdListBullet": "accent",
|
|
56
|
-
|
|
57
54
|
"toolDiffAdded": "green",
|
|
58
55
|
"toolDiffRemoved": "red",
|
|
59
56
|
"toolDiffContext": "gray",
|
|
60
|
-
|
|
61
57
|
"link": "#0088fa",
|
|
62
|
-
|
|
63
58
|
"syntaxComment": "#6A9955",
|
|
64
59
|
"syntaxKeyword": "#569CD6",
|
|
65
60
|
"syntaxFunction": "#DCDCAA",
|
|
@@ -69,16 +64,13 @@
|
|
|
69
64
|
"syntaxType": "#4EC9B0",
|
|
70
65
|
"syntaxOperator": "#D4D4D4",
|
|
71
66
|
"syntaxPunctuation": "#D4D4D4",
|
|
72
|
-
|
|
73
67
|
"thinkingOff": "darkGray",
|
|
74
68
|
"thinkingMinimal": "dimGray",
|
|
75
69
|
"thinkingLow": "#178fb9",
|
|
76
70
|
"thinkingMedium": "#0088fa",
|
|
77
71
|
"thinkingHigh": "#b281d6",
|
|
78
72
|
"thinkingXhigh": "#e5c1ff",
|
|
79
|
-
|
|
80
73
|
"bashMode": "cyan",
|
|
81
|
-
|
|
82
74
|
"statusLineBg": "#121212",
|
|
83
75
|
"statusLineSep": 244,
|
|
84
76
|
"statusLineModel": "#d787af",
|
|
@@ -92,7 +84,8 @@
|
|
|
92
84
|
"statusLineUntracked": 39,
|
|
93
85
|
"statusLineOutput": 205,
|
|
94
86
|
"statusLineCost": 205,
|
|
95
|
-
"statusLineSubagents": "accent"
|
|
87
|
+
"statusLineSubagents": "accent",
|
|
88
|
+
"pythonMode": "yellow"
|
|
96
89
|
},
|
|
97
90
|
"export": {
|
|
98
91
|
"pageBg": "#18181e",
|