@oh-my-pi/pi-coding-agent 5.5.0 → 5.6.7
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 +98 -0
- package/docs/python-repl.md +77 -0
- package/examples/hooks/snake.ts +7 -7
- package/package.json +5 -5
- package/src/bun-imports.d.ts +6 -0
- package/src/cli/args.ts +7 -0
- package/src/cli/setup-cli.ts +231 -0
- package/src/cli.ts +2 -0
- package/src/core/agent-session.ts +118 -15
- package/src/core/bash-executor.ts +3 -84
- package/src/core/compaction/compaction.ts +10 -5
- package/src/core/extensions/index.ts +2 -0
- package/src/core/extensions/loader.ts +13 -1
- package/src/core/extensions/runner.ts +50 -2
- package/src/core/extensions/types.ts +67 -2
- package/src/core/keybindings.ts +51 -1
- package/src/core/prompt-templates.ts +15 -0
- package/src/core/python-executor-display.test.ts +42 -0
- package/src/core/python-executor-lifecycle.test.ts +99 -0
- package/src/core/python-executor-mapping.test.ts +41 -0
- package/src/core/python-executor-per-call.test.ts +49 -0
- package/src/core/python-executor-session.test.ts +103 -0
- package/src/core/python-executor-streaming.test.ts +77 -0
- package/src/core/python-executor-timeout.test.ts +35 -0
- package/src/core/python-executor.lifecycle.test.ts +139 -0
- package/src/core/python-executor.result.test.ts +49 -0
- package/src/core/python-executor.test.ts +180 -0
- package/src/core/python-executor.ts +313 -0
- package/src/core/python-gateway-coordinator.ts +832 -0
- package/src/core/python-kernel-display.test.ts +54 -0
- package/src/core/python-kernel-env.test.ts +138 -0
- package/src/core/python-kernel-session.test.ts +87 -0
- package/src/core/python-kernel-ws.test.ts +104 -0
- package/src/core/python-kernel.lifecycle.test.ts +249 -0
- package/src/core/python-kernel.test.ts +549 -0
- package/src/core/python-kernel.ts +1178 -0
- package/src/core/python-prelude.py +889 -0
- package/src/core/python-prelude.test.ts +140 -0
- package/src/core/python-prelude.ts +3 -0
- package/src/core/sdk.ts +24 -6
- package/src/core/session-manager.ts +174 -82
- package/src/core/settings-manager-python.test.ts +23 -0
- package/src/core/settings-manager.ts +202 -0
- package/src/core/streaming-output.test.ts +26 -0
- package/src/core/streaming-output.ts +100 -0
- package/src/core/system-prompt.python.test.ts +17 -0
- package/src/core/system-prompt.ts +3 -1
- package/src/core/timings.ts +1 -1
- package/src/core/tools/bash.ts +13 -2
- package/src/core/tools/edit-diff.ts +9 -1
- package/src/core/tools/index.test.ts +50 -23
- package/src/core/tools/index.ts +83 -1
- package/src/core/tools/python-execution.test.ts +68 -0
- package/src/core/tools/python-fallback.test.ts +72 -0
- package/src/core/tools/python-renderer.test.ts +36 -0
- package/src/core/tools/python-tool-mode.test.ts +43 -0
- package/src/core/tools/python.test.ts +121 -0
- package/src/core/tools/python.ts +760 -0
- package/src/core/tools/renderers.ts +2 -0
- package/src/core/tools/schema-validation.test.ts +1 -0
- package/src/core/tools/task/executor.ts +146 -3
- package/src/core/tools/task/worker-protocol.ts +32 -2
- package/src/core/tools/task/worker.ts +182 -15
- package/src/index.ts +6 -0
- package/src/main.ts +136 -40
- package/src/modes/interactive/components/custom-editor.ts +16 -31
- package/src/modes/interactive/components/extensions/extension-dashboard.ts +5 -16
- package/src/modes/interactive/components/extensions/extension-list.ts +5 -13
- package/src/modes/interactive/components/history-search.ts +5 -8
- package/src/modes/interactive/components/hook-editor.ts +3 -4
- package/src/modes/interactive/components/hook-input.ts +3 -3
- package/src/modes/interactive/components/hook-selector.ts +5 -15
- package/src/modes/interactive/components/index.ts +1 -0
- package/src/modes/interactive/components/keybinding-hints.ts +66 -0
- package/src/modes/interactive/components/model-selector.ts +53 -66
- package/src/modes/interactive/components/oauth-selector.ts +5 -5
- package/src/modes/interactive/components/session-selector.ts +29 -23
- package/src/modes/interactive/components/settings-defs.ts +404 -196
- package/src/modes/interactive/components/settings-selector.ts +14 -10
- package/src/modes/interactive/components/status-line-segment-editor.ts +7 -7
- package/src/modes/interactive/components/tool-execution.ts +8 -0
- package/src/modes/interactive/components/tree-selector.ts +29 -23
- package/src/modes/interactive/components/user-message-selector.ts +6 -17
- package/src/modes/interactive/controllers/command-controller.ts +86 -37
- package/src/modes/interactive/controllers/event-controller.ts +8 -0
- package/src/modes/interactive/controllers/extension-ui-controller.ts +51 -0
- package/src/modes/interactive/controllers/input-controller.ts +42 -6
- package/src/modes/interactive/interactive-mode.ts +56 -30
- package/src/modes/interactive/theme/theme-schema.json +2 -2
- package/src/modes/interactive/types.ts +6 -1
- package/src/modes/interactive/utils/ui-helpers.ts +2 -1
- package/src/modes/print-mode.ts +23 -0
- package/src/modes/rpc/rpc-mode.ts +21 -0
- package/src/prompts/agents/reviewer.md +1 -1
- package/src/prompts/system/system-prompt.md +32 -1
- package/src/prompts/tools/python.md +91 -0
|
@@ -13,6 +13,8 @@ import { getCapabilities } from "@oh-my-pi/pi-tui";
|
|
|
13
13
|
import type {
|
|
14
14
|
ImageProviderOption,
|
|
15
15
|
NotificationMethod,
|
|
16
|
+
PythonKernelMode,
|
|
17
|
+
PythonToolMode,
|
|
16
18
|
SettingsManager,
|
|
17
19
|
StatusLinePreset,
|
|
18
20
|
StatusLineSeparatorStyle,
|
|
@@ -76,21 +78,32 @@ const THINKING_DESCRIPTIONS: Record<ThinkingLevel, string> = {
|
|
|
76
78
|
/**
|
|
77
79
|
* All settings definitions.
|
|
78
80
|
* Order determines display order within each tab.
|
|
81
|
+
*
|
|
82
|
+
* Tabs:
|
|
83
|
+
* - behavior: Core agent behavior (compaction, modes, retries, notifications)
|
|
84
|
+
* - tools: Tool-specific settings (bash, git, python, edit, MCP, skills)
|
|
85
|
+
* - display: Visual/UI settings (theme, images, thinking)
|
|
86
|
+
* - voice: Voice mode and TTSR settings
|
|
87
|
+
* - status: Status line configuration
|
|
88
|
+
* - lsp: LSP integration settings
|
|
89
|
+
* - exa: Exa search tool settings
|
|
79
90
|
*/
|
|
80
91
|
export const SETTINGS_DEFS: SettingDef[] = [
|
|
81
|
-
//
|
|
92
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
93
|
+
// Behavior tab - Core agent behavior
|
|
94
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
82
95
|
{
|
|
83
96
|
id: "autoCompact",
|
|
84
|
-
tab: "
|
|
97
|
+
tab: "behavior",
|
|
85
98
|
type: "boolean",
|
|
86
99
|
label: "Auto-compact",
|
|
87
100
|
description: "Automatically compact context when it gets too large",
|
|
88
101
|
get: (sm) => sm.getCompactionEnabled(),
|
|
89
|
-
set: (sm, v) => sm.setCompactionEnabled(v),
|
|
102
|
+
set: (sm, v) => sm.setCompactionEnabled(v),
|
|
90
103
|
},
|
|
91
104
|
{
|
|
92
105
|
id: "branchSummaries",
|
|
93
|
-
tab: "
|
|
106
|
+
tab: "behavior",
|
|
94
107
|
type: "boolean",
|
|
95
108
|
label: "Branch summaries",
|
|
96
109
|
description: "Prompt to summarize when leaving a branch",
|
|
@@ -99,102 +112,96 @@ export const SETTINGS_DEFS: SettingDef[] = [
|
|
|
99
112
|
},
|
|
100
113
|
{
|
|
101
114
|
id: "todoCompletion",
|
|
102
|
-
tab: "
|
|
115
|
+
tab: "behavior",
|
|
103
116
|
type: "boolean",
|
|
104
117
|
label: "Todo completion",
|
|
105
|
-
description: "Remind agent to complete todos before stopping
|
|
118
|
+
description: "Remind agent to complete todos before stopping",
|
|
106
119
|
get: (sm) => sm.getTodoCompletionEnabled(),
|
|
107
120
|
set: (sm, v) => sm.setTodoCompletionEnabled(v),
|
|
108
121
|
},
|
|
109
122
|
{
|
|
110
|
-
id: "
|
|
111
|
-
tab: "
|
|
112
|
-
type: "
|
|
113
|
-
label: "
|
|
114
|
-
description: "
|
|
115
|
-
get: (sm) => sm.
|
|
116
|
-
set: (sm, v) => sm.
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
label: "Voice mode",
|
|
124
|
-
description: "Enable realtime voice input/output (Ctrl+Y toggle, auto-send on silence)",
|
|
125
|
-
get: (sm) => sm.getVoiceEnabled(),
|
|
126
|
-
set: (sm, v) => sm.setVoiceEnabled(v),
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
id: "completionNotification",
|
|
130
|
-
tab: "config",
|
|
131
|
-
type: "enum",
|
|
132
|
-
label: "Completion notification",
|
|
133
|
-
description: "Notify when the agent completes",
|
|
134
|
-
values: ["auto", "bell", "osc99", "osc9", "off"],
|
|
135
|
-
get: (sm) => sm.getNotificationOnComplete(),
|
|
136
|
-
set: (sm, v) => sm.setNotificationOnComplete(v as NotificationMethod),
|
|
137
|
-
},
|
|
138
|
-
{
|
|
139
|
-
id: "autoResizeImages",
|
|
140
|
-
tab: "config",
|
|
141
|
-
type: "boolean",
|
|
142
|
-
label: "Auto-resize images",
|
|
143
|
-
description: "Resize large images to 2000x2000 max for better model compatibility",
|
|
144
|
-
get: (sm) => sm.getImageAutoResize(),
|
|
145
|
-
set: (sm, v) => sm.setImageAutoResize(v),
|
|
146
|
-
},
|
|
147
|
-
{
|
|
148
|
-
id: "blockImages",
|
|
149
|
-
tab: "config",
|
|
150
|
-
type: "boolean",
|
|
151
|
-
label: "Block images",
|
|
152
|
-
description: "Prevent images from being sent to LLM providers",
|
|
153
|
-
get: (sm) => sm.getBlockImages(),
|
|
154
|
-
set: (sm, v) => sm.setBlockImages(v),
|
|
123
|
+
id: "todoCompletionMaxReminders",
|
|
124
|
+
tab: "behavior",
|
|
125
|
+
type: "submenu",
|
|
126
|
+
label: "Todo max reminders",
|
|
127
|
+
description: "Maximum reminders to complete todos before giving up",
|
|
128
|
+
get: (sm) => String(sm.getTodoCompletionMaxReminders()),
|
|
129
|
+
set: (sm, v) => sm.setTodoCompletionMaxReminders(Number.parseInt(v, 10)),
|
|
130
|
+
getOptions: () => [
|
|
131
|
+
{ value: "1", label: "1 reminder" },
|
|
132
|
+
{ value: "2", label: "2 reminders" },
|
|
133
|
+
{ value: "3", label: "3 reminders" },
|
|
134
|
+
{ value: "5", label: "5 reminders" },
|
|
135
|
+
],
|
|
155
136
|
},
|
|
156
137
|
{
|
|
157
138
|
id: "steeringMode",
|
|
158
|
-
tab: "
|
|
139
|
+
tab: "behavior",
|
|
159
140
|
type: "enum",
|
|
160
141
|
label: "Steering mode",
|
|
161
142
|
description: "How to process queued messages while agent is working",
|
|
162
143
|
values: ["one-at-a-time", "all"],
|
|
163
144
|
get: (sm) => sm.getSteeringMode(),
|
|
164
|
-
set: (sm, v) => sm.setSteeringMode(v as "all" | "one-at-a-time"),
|
|
145
|
+
set: (sm, v) => sm.setSteeringMode(v as "all" | "one-at-a-time"),
|
|
165
146
|
},
|
|
166
147
|
{
|
|
167
148
|
id: "followUpMode",
|
|
168
|
-
tab: "
|
|
149
|
+
tab: "behavior",
|
|
169
150
|
type: "enum",
|
|
170
151
|
label: "Follow-up mode",
|
|
171
152
|
description: "How to drain follow-up messages after a turn completes",
|
|
172
153
|
values: ["one-at-a-time", "all"],
|
|
173
154
|
get: (sm) => sm.getFollowUpMode(),
|
|
174
|
-
set: (sm, v) => sm.setFollowUpMode(v as "one-at-a-time" | "all"),
|
|
155
|
+
set: (sm, v) => sm.setFollowUpMode(v as "one-at-a-time" | "all"),
|
|
175
156
|
},
|
|
176
157
|
{
|
|
177
158
|
id: "interruptMode",
|
|
178
|
-
tab: "
|
|
159
|
+
tab: "behavior",
|
|
179
160
|
type: "enum",
|
|
180
161
|
label: "Interrupt mode",
|
|
181
162
|
description: "When steering messages interrupt tool execution",
|
|
182
163
|
values: ["immediate", "wait"],
|
|
183
164
|
get: (sm) => sm.getInterruptMode(),
|
|
184
|
-
set: (sm, v) => sm.setInterruptMode(v as "immediate" | "wait"),
|
|
165
|
+
set: (sm, v) => sm.setInterruptMode(v as "immediate" | "wait"),
|
|
185
166
|
},
|
|
186
167
|
{
|
|
187
|
-
id: "
|
|
188
|
-
tab: "
|
|
168
|
+
id: "retryMaxRetries",
|
|
169
|
+
tab: "behavior",
|
|
170
|
+
type: "submenu",
|
|
171
|
+
label: "Retry max attempts",
|
|
172
|
+
description: "Maximum retry attempts on API errors",
|
|
173
|
+
get: (sm) => String(sm.getRetryMaxRetries()),
|
|
174
|
+
set: (sm, v) => sm.setRetryMaxRetries(Number.parseInt(v, 10)),
|
|
175
|
+
getOptions: () => [
|
|
176
|
+
{ value: "1", label: "1 retry" },
|
|
177
|
+
{ value: "2", label: "2 retries" },
|
|
178
|
+
{ value: "3", label: "3 retries" },
|
|
179
|
+
{ value: "5", label: "5 retries" },
|
|
180
|
+
{ value: "10", label: "10 retries" },
|
|
181
|
+
],
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
id: "completionNotification",
|
|
185
|
+
tab: "behavior",
|
|
186
|
+
type: "enum",
|
|
187
|
+
label: "Completion notification",
|
|
188
|
+
description: "Notify when the agent completes",
|
|
189
|
+
values: ["auto", "bell", "osc99", "osc9", "off"],
|
|
190
|
+
get: (sm) => sm.getNotificationOnComplete(),
|
|
191
|
+
set: (sm, v) => sm.setNotificationOnComplete(v as NotificationMethod),
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
id: "startupQuiet",
|
|
195
|
+
tab: "behavior",
|
|
189
196
|
type: "boolean",
|
|
190
|
-
label: "
|
|
191
|
-
description: "
|
|
192
|
-
get: (sm) => sm.
|
|
193
|
-
set: (sm, v) => sm.
|
|
197
|
+
label: "Startup quiet",
|
|
198
|
+
description: "Skip welcome screen and startup status messages",
|
|
199
|
+
get: (sm) => sm.getStartupQuiet(),
|
|
200
|
+
set: (sm, v) => sm.setStartupQuiet(v),
|
|
194
201
|
},
|
|
195
202
|
{
|
|
196
203
|
id: "collapseChangelog",
|
|
197
|
-
tab: "
|
|
204
|
+
tab: "behavior",
|
|
198
205
|
type: "boolean",
|
|
199
206
|
label: "Collapse changelog",
|
|
200
207
|
description: "Show condensed changelog after updates",
|
|
@@ -203,7 +210,7 @@ export const SETTINGS_DEFS: SettingDef[] = [
|
|
|
203
210
|
},
|
|
204
211
|
{
|
|
205
212
|
id: "doubleEscapeAction",
|
|
206
|
-
tab: "
|
|
213
|
+
tab: "behavior",
|
|
207
214
|
type: "enum",
|
|
208
215
|
label: "Double-escape action",
|
|
209
216
|
description: "Action when pressing Escape twice with empty editor",
|
|
@@ -211,18 +218,31 @@ export const SETTINGS_DEFS: SettingDef[] = [
|
|
|
211
218
|
get: (sm) => sm.getDoubleEscapeAction(),
|
|
212
219
|
set: (sm, v) => sm.setDoubleEscapeAction(v as "branch" | "tree"),
|
|
213
220
|
},
|
|
221
|
+
|
|
222
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
223
|
+
// Tools tab - Tool-specific settings
|
|
224
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
214
225
|
{
|
|
215
226
|
id: "bashInterceptor",
|
|
216
|
-
tab: "
|
|
227
|
+
tab: "tools",
|
|
217
228
|
type: "boolean",
|
|
218
229
|
label: "Bash interceptor",
|
|
219
230
|
description: "Block shell commands that have dedicated tools (grep, cat, etc.)",
|
|
220
231
|
get: (sm) => sm.getBashInterceptorEnabled(),
|
|
221
232
|
set: (sm, v) => sm.setBashInterceptorEnabled(v),
|
|
222
233
|
},
|
|
234
|
+
{
|
|
235
|
+
id: "bashInterceptorSimpleLs",
|
|
236
|
+
tab: "tools",
|
|
237
|
+
type: "boolean",
|
|
238
|
+
label: "Intercept simple ls",
|
|
239
|
+
description: "Intercept bare ls commands (when bash interceptor is enabled)",
|
|
240
|
+
get: (sm) => sm.getBashInterceptorSimpleLsEnabled(),
|
|
241
|
+
set: (sm, v) => sm.setBashInterceptorSimpleLsEnabled(v),
|
|
242
|
+
},
|
|
223
243
|
{
|
|
224
244
|
id: "gitTool",
|
|
225
|
-
tab: "
|
|
245
|
+
tab: "tools",
|
|
226
246
|
type: "boolean",
|
|
227
247
|
label: "Git tool",
|
|
228
248
|
description: "Enable structured Git tool",
|
|
@@ -230,17 +250,37 @@ export const SETTINGS_DEFS: SettingDef[] = [
|
|
|
230
250
|
set: (sm, v) => sm.setGitToolEnabled(v),
|
|
231
251
|
},
|
|
232
252
|
{
|
|
233
|
-
id: "
|
|
234
|
-
tab: "
|
|
253
|
+
id: "pythonToolMode",
|
|
254
|
+
tab: "tools",
|
|
255
|
+
type: "enum",
|
|
256
|
+
label: "Python tool mode",
|
|
257
|
+
description: "How Python code is executed",
|
|
258
|
+
values: ["ipy-only", "bash-only", "both"],
|
|
259
|
+
get: (sm) => sm.getPythonToolMode(),
|
|
260
|
+
set: (sm, v) => sm.setPythonToolMode(v as PythonToolMode),
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
id: "pythonKernelMode",
|
|
264
|
+
tab: "tools",
|
|
265
|
+
type: "enum",
|
|
266
|
+
label: "Python kernel mode",
|
|
267
|
+
description: "Whether to keep IPython kernel alive across calls",
|
|
268
|
+
values: ["session", "per-call"],
|
|
269
|
+
get: (sm) => sm.getPythonKernelMode(),
|
|
270
|
+
set: (sm, v) => sm.setPythonKernelMode(v as PythonKernelMode),
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
id: "pythonSharedGateway",
|
|
274
|
+
tab: "tools",
|
|
235
275
|
type: "boolean",
|
|
236
|
-
label: "
|
|
237
|
-
description: "
|
|
238
|
-
get: (sm) => sm.
|
|
239
|
-
set: (sm, v) => sm.
|
|
276
|
+
label: "Python shared gateway",
|
|
277
|
+
description: "Share IPython kernel gateway across pi instances",
|
|
278
|
+
get: (sm) => sm.getPythonSharedGateway(),
|
|
279
|
+
set: (sm, v) => sm.setPythonSharedGateway(v),
|
|
240
280
|
},
|
|
241
281
|
{
|
|
242
282
|
id: "editFuzzyMatch",
|
|
243
|
-
tab: "
|
|
283
|
+
tab: "tools",
|
|
244
284
|
type: "boolean",
|
|
245
285
|
label: "Edit fuzzy match",
|
|
246
286
|
description: "Accept high-confidence fuzzy matches for whitespace/indentation differences",
|
|
@@ -248,76 +288,44 @@ export const SETTINGS_DEFS: SettingDef[] = [
|
|
|
248
288
|
set: (sm, v) => sm.setEditFuzzyMatch(v),
|
|
249
289
|
},
|
|
250
290
|
{
|
|
251
|
-
id: "
|
|
252
|
-
tab: "
|
|
291
|
+
id: "mcpProjectConfig",
|
|
292
|
+
tab: "tools",
|
|
253
293
|
type: "boolean",
|
|
254
|
-
label: "
|
|
255
|
-
description: "
|
|
256
|
-
get: (sm) => sm.
|
|
257
|
-
set: (sm, v) => sm.
|
|
258
|
-
},
|
|
259
|
-
{
|
|
260
|
-
id: "ttsrContextMode",
|
|
261
|
-
tab: "config",
|
|
262
|
-
type: "enum",
|
|
263
|
-
label: "TTSR context mode",
|
|
264
|
-
description: "What to do with partial output when TTSR triggers",
|
|
265
|
-
values: ["discard", "keep"],
|
|
266
|
-
get: (sm) => sm.getTtsrContextMode(),
|
|
267
|
-
set: (sm, v) => sm.setTtsrContextMode(v as "keep" | "discard"),
|
|
268
|
-
},
|
|
269
|
-
{
|
|
270
|
-
id: "ttsrRepeatMode",
|
|
271
|
-
tab: "config",
|
|
272
|
-
type: "enum",
|
|
273
|
-
label: "TTSR repeat mode",
|
|
274
|
-
description: "How rules can repeat: once per session or after a message gap",
|
|
275
|
-
values: ["once", "after-gap"],
|
|
276
|
-
get: (sm) => sm.getTtsrRepeatMode(),
|
|
277
|
-
set: (sm, v) => sm.setTtsrRepeatMode(v as "once" | "after-gap"),
|
|
294
|
+
label: "MCP project config",
|
|
295
|
+
description: "Load .mcp.json/mcp.json from project root",
|
|
296
|
+
get: (sm) => sm.getMCPProjectConfigEnabled(),
|
|
297
|
+
set: (sm, v) => sm.setMCPProjectConfigEnabled(v),
|
|
278
298
|
},
|
|
279
299
|
{
|
|
280
|
-
id: "
|
|
281
|
-
tab: "
|
|
282
|
-
type: "
|
|
283
|
-
label: "
|
|
284
|
-
description: "
|
|
285
|
-
get: (sm) => sm.
|
|
286
|
-
set: (sm, v) => sm.
|
|
287
|
-
getOptions: () =>
|
|
288
|
-
(["off", "minimal", "low", "medium", "high", "xhigh"] as ThinkingLevel[]).map((level) => ({
|
|
289
|
-
value: level,
|
|
290
|
-
label: level,
|
|
291
|
-
description: THINKING_DESCRIPTIONS[level],
|
|
292
|
-
})),
|
|
300
|
+
id: "skillCommands",
|
|
301
|
+
tab: "tools",
|
|
302
|
+
type: "boolean",
|
|
303
|
+
label: "Skill commands",
|
|
304
|
+
description: "Register skills as /skill:name commands",
|
|
305
|
+
get: (sm) => sm.getEnableSkillCommands(),
|
|
306
|
+
set: (sm, v) => sm.setEnableSkillCommands(v),
|
|
293
307
|
},
|
|
294
308
|
{
|
|
295
|
-
id: "
|
|
296
|
-
tab: "
|
|
297
|
-
type: "
|
|
298
|
-
label: "
|
|
299
|
-
description: "
|
|
300
|
-
get: (sm) => sm.
|
|
301
|
-
set: (sm, v) => sm.
|
|
302
|
-
getOptions: () => [], // Filled dynamically from context
|
|
309
|
+
id: "claudeUserCommands",
|
|
310
|
+
tab: "tools",
|
|
311
|
+
type: "boolean",
|
|
312
|
+
label: "Claude user commands",
|
|
313
|
+
description: "Load commands from ~/.claude/commands/",
|
|
314
|
+
get: (sm) => sm.getCommandsEnableClaudeUser(),
|
|
315
|
+
set: (sm, v) => sm.setCommandsEnableClaudeUser(v),
|
|
303
316
|
},
|
|
304
317
|
{
|
|
305
|
-
id: "
|
|
306
|
-
tab: "
|
|
307
|
-
type: "
|
|
308
|
-
label: "
|
|
309
|
-
description: "
|
|
310
|
-
get: (sm) => sm.
|
|
311
|
-
set: (sm, v) => sm.
|
|
312
|
-
getOptions: () => [
|
|
313
|
-
{ value: "unicode", label: "Unicode", description: "Standard Unicode symbols (default)" },
|
|
314
|
-
{ value: "nerd", label: "Nerd Font", description: "Nerd Font icons (requires Nerd Font)" },
|
|
315
|
-
{ value: "ascii", label: "ASCII", description: "ASCII-only characters (maximum compatibility)" },
|
|
316
|
-
],
|
|
318
|
+
id: "claudeProjectCommands",
|
|
319
|
+
tab: "tools",
|
|
320
|
+
type: "boolean",
|
|
321
|
+
label: "Claude project commands",
|
|
322
|
+
description: "Load commands from .claude/commands/",
|
|
323
|
+
get: (sm) => sm.getCommandsEnableClaudeProject(),
|
|
324
|
+
set: (sm, v) => sm.setCommandsEnableClaudeProject(v),
|
|
317
325
|
},
|
|
318
326
|
{
|
|
319
327
|
id: "webSearchProvider",
|
|
320
|
-
tab: "
|
|
328
|
+
tab: "tools",
|
|
321
329
|
type: "submenu",
|
|
322
330
|
label: "Web search provider",
|
|
323
331
|
description: "Provider for web search tool",
|
|
@@ -332,7 +340,7 @@ export const SETTINGS_DEFS: SettingDef[] = [
|
|
|
332
340
|
},
|
|
333
341
|
{
|
|
334
342
|
id: "imageProvider",
|
|
335
|
-
tab: "
|
|
343
|
+
tab: "tools",
|
|
336
344
|
type: "submenu",
|
|
337
345
|
label: "Image provider",
|
|
338
346
|
description: "Provider for image generation tool",
|
|
@@ -345,92 +353,203 @@ export const SETTINGS_DEFS: SettingDef[] = [
|
|
|
345
353
|
],
|
|
346
354
|
},
|
|
347
355
|
|
|
348
|
-
//
|
|
356
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
357
|
+
// Display tab - Visual/UI settings
|
|
358
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
349
359
|
{
|
|
350
|
-
id: "
|
|
351
|
-
tab: "
|
|
352
|
-
type: "
|
|
353
|
-
label: "
|
|
354
|
-
description: "
|
|
355
|
-
get: (sm) => sm.
|
|
356
|
-
set: (sm, v) => sm.
|
|
360
|
+
id: "theme",
|
|
361
|
+
tab: "display",
|
|
362
|
+
type: "submenu",
|
|
363
|
+
label: "Theme",
|
|
364
|
+
description: "Color theme for the interface",
|
|
365
|
+
get: (sm) => sm.getTheme() ?? "dark",
|
|
366
|
+
set: (sm, v) => sm.setTheme(v),
|
|
367
|
+
getOptions: () => [], // Filled dynamically from context
|
|
357
368
|
},
|
|
358
369
|
{
|
|
359
|
-
id: "
|
|
360
|
-
tab: "
|
|
361
|
-
type: "
|
|
362
|
-
label: "
|
|
363
|
-
description: "
|
|
364
|
-
get: (sm) => sm.
|
|
365
|
-
set: (sm, v) => sm.
|
|
370
|
+
id: "symbolPreset",
|
|
371
|
+
tab: "display",
|
|
372
|
+
type: "submenu",
|
|
373
|
+
label: "Symbol preset",
|
|
374
|
+
description: "Icon/symbol style (overrides theme default)",
|
|
375
|
+
get: (sm) => sm.getSymbolPreset() ?? "unicode",
|
|
376
|
+
set: (sm, v) => sm.setSymbolPreset(v as SymbolPreset),
|
|
377
|
+
getOptions: () => [
|
|
378
|
+
{ value: "unicode", label: "Unicode", description: "Standard Unicode symbols (default)" },
|
|
379
|
+
{ value: "nerd", label: "Nerd Font", description: "Nerd Font icons (requires Nerd Font)" },
|
|
380
|
+
{ value: "ascii", label: "ASCII", description: "ASCII-only characters (maximum compatibility)" },
|
|
381
|
+
],
|
|
366
382
|
},
|
|
367
383
|
{
|
|
368
|
-
id: "
|
|
369
|
-
tab: "
|
|
384
|
+
id: "thinkingLevel",
|
|
385
|
+
tab: "display",
|
|
386
|
+
type: "submenu",
|
|
387
|
+
label: "Thinking level",
|
|
388
|
+
description: "Reasoning depth for thinking-capable models",
|
|
389
|
+
get: (sm) => sm.getDefaultThinkingLevel() ?? "off",
|
|
390
|
+
set: (sm, v) => sm.setDefaultThinkingLevel(v as ThinkingLevel),
|
|
391
|
+
getOptions: () =>
|
|
392
|
+
(["off", "minimal", "low", "medium", "high", "xhigh"] as ThinkingLevel[]).map((level) => ({
|
|
393
|
+
value: level,
|
|
394
|
+
label: level,
|
|
395
|
+
description: THINKING_DESCRIPTIONS[level],
|
|
396
|
+
})),
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
id: "hideThinking",
|
|
400
|
+
tab: "display",
|
|
370
401
|
type: "boolean",
|
|
371
|
-
label: "
|
|
372
|
-
description: "
|
|
373
|
-
get: (sm) => sm.
|
|
374
|
-
set: (sm, v) => sm.
|
|
402
|
+
label: "Hide thinking",
|
|
403
|
+
description: "Hide thinking blocks in assistant responses",
|
|
404
|
+
get: (sm) => sm.getHideThinkingBlock(),
|
|
405
|
+
set: (sm, v) => sm.setHideThinkingBlock(v),
|
|
375
406
|
},
|
|
376
|
-
|
|
377
|
-
// Exa tab
|
|
378
407
|
{
|
|
379
|
-
id: "
|
|
380
|
-
tab: "
|
|
408
|
+
id: "showImages",
|
|
409
|
+
tab: "display",
|
|
381
410
|
type: "boolean",
|
|
382
|
-
label: "
|
|
383
|
-
description: "
|
|
384
|
-
get: (sm) => sm.
|
|
385
|
-
set: (sm, v) => sm.
|
|
411
|
+
label: "Show images",
|
|
412
|
+
description: "Render images inline in terminal",
|
|
413
|
+
get: (sm) => sm.getShowImages(),
|
|
414
|
+
set: (sm, v) => sm.setShowImages(v),
|
|
415
|
+
condition: () => !!getCapabilities().images,
|
|
386
416
|
},
|
|
387
417
|
{
|
|
388
|
-
id: "
|
|
389
|
-
tab: "
|
|
418
|
+
id: "autoResizeImages",
|
|
419
|
+
tab: "display",
|
|
390
420
|
type: "boolean",
|
|
391
|
-
label: "
|
|
392
|
-
description: "
|
|
393
|
-
get: (sm) => sm.
|
|
394
|
-
set: (sm, v) => sm.
|
|
421
|
+
label: "Auto-resize images",
|
|
422
|
+
description: "Resize large images to 2000x2000 max for better model compatibility",
|
|
423
|
+
get: (sm) => sm.getImageAutoResize(),
|
|
424
|
+
set: (sm, v) => sm.setImageAutoResize(v),
|
|
395
425
|
},
|
|
396
426
|
{
|
|
397
|
-
id: "
|
|
398
|
-
tab: "
|
|
427
|
+
id: "blockImages",
|
|
428
|
+
tab: "display",
|
|
399
429
|
type: "boolean",
|
|
400
|
-
label: "
|
|
401
|
-
description: "
|
|
402
|
-
get: (sm) => sm.
|
|
403
|
-
set: (sm, v) => sm.
|
|
430
|
+
label: "Block images",
|
|
431
|
+
description: "Prevent images from being sent to LLM providers",
|
|
432
|
+
get: (sm) => sm.getBlockImages(),
|
|
433
|
+
set: (sm, v) => sm.setBlockImages(v),
|
|
404
434
|
},
|
|
405
435
|
{
|
|
406
|
-
id: "
|
|
407
|
-
tab: "
|
|
436
|
+
id: "showHardwareCursor",
|
|
437
|
+
tab: "display",
|
|
408
438
|
type: "boolean",
|
|
409
|
-
label: "
|
|
410
|
-
description: "
|
|
411
|
-
get: (sm) => sm.
|
|
412
|
-
set: (sm, v) => sm.
|
|
439
|
+
label: "Hardware cursor",
|
|
440
|
+
description: "Show terminal cursor for IME support (default: on for Linux/macOS)",
|
|
441
|
+
get: (sm) => sm.getShowHardwareCursor(),
|
|
442
|
+
set: (sm, v) => sm.setShowHardwareCursor(v),
|
|
413
443
|
},
|
|
444
|
+
|
|
445
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
446
|
+
// Voice tab - Voice mode and TTSR settings
|
|
447
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
414
448
|
{
|
|
415
|
-
id: "
|
|
416
|
-
tab: "
|
|
449
|
+
id: "voiceEnabled",
|
|
450
|
+
tab: "voice",
|
|
417
451
|
type: "boolean",
|
|
418
|
-
label: "
|
|
419
|
-
description: "
|
|
420
|
-
get: (sm) => sm.
|
|
421
|
-
set: (sm, v) => sm.
|
|
452
|
+
label: "Voice mode",
|
|
453
|
+
description: "Enable realtime voice input/output (Ctrl+Y toggle, auto-send on silence)",
|
|
454
|
+
get: (sm) => sm.getVoiceEnabled(),
|
|
455
|
+
set: (sm, v) => sm.setVoiceEnabled(v),
|
|
422
456
|
},
|
|
423
457
|
{
|
|
424
|
-
id: "
|
|
425
|
-
tab: "
|
|
458
|
+
id: "voiceTtsModel",
|
|
459
|
+
tab: "voice",
|
|
460
|
+
type: "submenu",
|
|
461
|
+
label: "TTS model",
|
|
462
|
+
description: "Text-to-speech model for voice output",
|
|
463
|
+
get: (sm) => sm.getVoiceTtsModel(),
|
|
464
|
+
set: (sm, v) => sm.setVoiceTtsModel(v),
|
|
465
|
+
getOptions: () => [
|
|
466
|
+
{ value: "gpt-4o-mini-tts", label: "GPT-4o Mini TTS", description: "Fast and efficient" },
|
|
467
|
+
{ value: "tts-1", label: "TTS-1", description: "Standard quality" },
|
|
468
|
+
{ value: "tts-1-hd", label: "TTS-1 HD", description: "Higher quality" },
|
|
469
|
+
],
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
id: "voiceTtsVoice",
|
|
473
|
+
tab: "voice",
|
|
474
|
+
type: "submenu",
|
|
475
|
+
label: "TTS voice",
|
|
476
|
+
description: "Voice for text-to-speech output",
|
|
477
|
+
get: (sm) => sm.getVoiceTtsVoice(),
|
|
478
|
+
set: (sm, v) => sm.setVoiceTtsVoice(v),
|
|
479
|
+
getOptions: () => [
|
|
480
|
+
{ value: "alloy", label: "Alloy", description: "Neutral" },
|
|
481
|
+
{ value: "echo", label: "Echo", description: "Male" },
|
|
482
|
+
{ value: "fable", label: "Fable", description: "British" },
|
|
483
|
+
{ value: "onyx", label: "Onyx", description: "Deep male" },
|
|
484
|
+
{ value: "nova", label: "Nova", description: "Female" },
|
|
485
|
+
{ value: "shimmer", label: "Shimmer", description: "Female" },
|
|
486
|
+
],
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
id: "voiceTtsFormat",
|
|
490
|
+
tab: "voice",
|
|
491
|
+
type: "submenu",
|
|
492
|
+
label: "TTS format",
|
|
493
|
+
description: "Audio format for voice output",
|
|
494
|
+
get: (sm) => sm.getVoiceTtsFormat(),
|
|
495
|
+
set: (sm, v) => sm.setVoiceTtsFormat(v as "wav" | "mp3" | "opus" | "aac" | "flac"),
|
|
496
|
+
getOptions: () => [
|
|
497
|
+
{ value: "wav", label: "WAV", description: "Uncompressed, best quality" },
|
|
498
|
+
{ value: "mp3", label: "MP3", description: "Compressed, widely compatible" },
|
|
499
|
+
{ value: "opus", label: "Opus", description: "Efficient compression" },
|
|
500
|
+
{ value: "aac", label: "AAC", description: "Apple-friendly" },
|
|
501
|
+
{ value: "flac", label: "FLAC", description: "Lossless compression" },
|
|
502
|
+
],
|
|
503
|
+
},
|
|
504
|
+
{
|
|
505
|
+
id: "ttsrEnabled",
|
|
506
|
+
tab: "voice",
|
|
426
507
|
type: "boolean",
|
|
427
|
-
label: "
|
|
428
|
-
description: "
|
|
429
|
-
get: (sm) => sm.
|
|
430
|
-
set: (sm, v) => sm.
|
|
508
|
+
label: "TTSR enabled",
|
|
509
|
+
description: "Time Traveling Stream Rules: interrupt agent when output matches patterns",
|
|
510
|
+
get: (sm) => sm.getTtsrEnabled(),
|
|
511
|
+
set: (sm, v) => sm.setTtsrEnabled(v),
|
|
512
|
+
},
|
|
513
|
+
{
|
|
514
|
+
id: "ttsrContextMode",
|
|
515
|
+
tab: "voice",
|
|
516
|
+
type: "enum",
|
|
517
|
+
label: "TTSR context mode",
|
|
518
|
+
description: "What to do with partial output when TTSR triggers",
|
|
519
|
+
values: ["discard", "keep"],
|
|
520
|
+
get: (sm) => sm.getTtsrContextMode(),
|
|
521
|
+
set: (sm, v) => sm.setTtsrContextMode(v as "keep" | "discard"),
|
|
522
|
+
},
|
|
523
|
+
{
|
|
524
|
+
id: "ttsrRepeatMode",
|
|
525
|
+
tab: "voice",
|
|
526
|
+
type: "enum",
|
|
527
|
+
label: "TTSR repeat mode",
|
|
528
|
+
description: "How rules can repeat: once per session or after a message gap",
|
|
529
|
+
values: ["once", "after-gap"],
|
|
530
|
+
get: (sm) => sm.getTtsrRepeatMode(),
|
|
531
|
+
set: (sm, v) => sm.setTtsrRepeatMode(v as "once" | "after-gap"),
|
|
532
|
+
},
|
|
533
|
+
{
|
|
534
|
+
id: "ttsrRepeatGap",
|
|
535
|
+
tab: "voice",
|
|
536
|
+
type: "submenu",
|
|
537
|
+
label: "TTSR repeat gap",
|
|
538
|
+
description: "Messages before a rule can trigger again (when repeat mode is after-gap)",
|
|
539
|
+
get: (sm) => String(sm.getTtsrRepeatGap()),
|
|
540
|
+
set: (sm, v) => sm.setTtsrRepeatGap(Number.parseInt(v, 10)),
|
|
541
|
+
getOptions: () => [
|
|
542
|
+
{ value: "5", label: "5 messages" },
|
|
543
|
+
{ value: "10", label: "10 messages" },
|
|
544
|
+
{ value: "15", label: "15 messages" },
|
|
545
|
+
{ value: "20", label: "20 messages" },
|
|
546
|
+
{ value: "30", label: "30 messages" },
|
|
547
|
+
],
|
|
431
548
|
},
|
|
432
549
|
|
|
433
|
-
//
|
|
550
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
551
|
+
// Status tab - Status line configuration
|
|
552
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
434
553
|
{
|
|
435
554
|
id: "statusLinePreset",
|
|
436
555
|
tab: "status",
|
|
@@ -487,7 +606,7 @@ export const SETTINGS_DEFS: SettingDef[] = [
|
|
|
487
606
|
label: "Configure segments",
|
|
488
607
|
description: "Choose and arrange status line segments",
|
|
489
608
|
get: () => "configure...",
|
|
490
|
-
set: () => {},
|
|
609
|
+
set: () => {},
|
|
491
610
|
getOptions: () => [{ value: "open", label: "Open segment editor..." }],
|
|
492
611
|
},
|
|
493
612
|
{
|
|
@@ -693,6 +812,95 @@ export const SETTINGS_DEFS: SettingDef[] = [
|
|
|
693
812
|
}
|
|
694
813
|
},
|
|
695
814
|
},
|
|
815
|
+
|
|
816
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
817
|
+
// LSP tab - LSP integration settings
|
|
818
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
819
|
+
{
|
|
820
|
+
id: "lspFormatOnWrite",
|
|
821
|
+
tab: "lsp",
|
|
822
|
+
type: "boolean",
|
|
823
|
+
label: "Format on write",
|
|
824
|
+
description: "Automatically format code files using LSP after writing",
|
|
825
|
+
get: (sm) => sm.getLspFormatOnWrite(),
|
|
826
|
+
set: (sm, v) => sm.setLspFormatOnWrite(v),
|
|
827
|
+
},
|
|
828
|
+
{
|
|
829
|
+
id: "lspDiagnosticsOnWrite",
|
|
830
|
+
tab: "lsp",
|
|
831
|
+
type: "boolean",
|
|
832
|
+
label: "Diagnostics on write",
|
|
833
|
+
description: "Return LSP diagnostics (errors/warnings) after writing code files",
|
|
834
|
+
get: (sm) => sm.getLspDiagnosticsOnWrite(),
|
|
835
|
+
set: (sm, v) => sm.setLspDiagnosticsOnWrite(v),
|
|
836
|
+
},
|
|
837
|
+
{
|
|
838
|
+
id: "lspDiagnosticsOnEdit",
|
|
839
|
+
tab: "lsp",
|
|
840
|
+
type: "boolean",
|
|
841
|
+
label: "Diagnostics on edit",
|
|
842
|
+
description: "Return LSP diagnostics (errors/warnings) after editing code files",
|
|
843
|
+
get: (sm) => sm.getLspDiagnosticsOnEdit(),
|
|
844
|
+
set: (sm, v) => sm.setLspDiagnosticsOnEdit(v),
|
|
845
|
+
},
|
|
846
|
+
|
|
847
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
848
|
+
// Exa tab - Exa search tool settings
|
|
849
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
850
|
+
{
|
|
851
|
+
id: "exaEnabled",
|
|
852
|
+
tab: "exa",
|
|
853
|
+
type: "boolean",
|
|
854
|
+
label: "Exa enabled",
|
|
855
|
+
description: "Master toggle for all Exa search tools",
|
|
856
|
+
get: (sm) => sm.getExaSettings().enabled,
|
|
857
|
+
set: (sm, v) => sm.setExaEnabled(v),
|
|
858
|
+
},
|
|
859
|
+
{
|
|
860
|
+
id: "exaSearch",
|
|
861
|
+
tab: "exa",
|
|
862
|
+
type: "boolean",
|
|
863
|
+
label: "Exa search",
|
|
864
|
+
description: "Basic search, deep search, code search, crawl",
|
|
865
|
+
get: (sm) => sm.getExaSettings().enableSearch,
|
|
866
|
+
set: (sm, v) => sm.setExaSearchEnabled(v),
|
|
867
|
+
},
|
|
868
|
+
{
|
|
869
|
+
id: "exaLinkedin",
|
|
870
|
+
tab: "exa",
|
|
871
|
+
type: "boolean",
|
|
872
|
+
label: "Exa LinkedIn",
|
|
873
|
+
description: "Search LinkedIn for people and companies",
|
|
874
|
+
get: (sm) => sm.getExaSettings().enableLinkedin,
|
|
875
|
+
set: (sm, v) => sm.setExaLinkedinEnabled(v),
|
|
876
|
+
},
|
|
877
|
+
{
|
|
878
|
+
id: "exaCompany",
|
|
879
|
+
tab: "exa",
|
|
880
|
+
type: "boolean",
|
|
881
|
+
label: "Exa company",
|
|
882
|
+
description: "Comprehensive company research tool",
|
|
883
|
+
get: (sm) => sm.getExaSettings().enableCompany,
|
|
884
|
+
set: (sm, v) => sm.setExaCompanyEnabled(v),
|
|
885
|
+
},
|
|
886
|
+
{
|
|
887
|
+
id: "exaResearcher",
|
|
888
|
+
tab: "exa",
|
|
889
|
+
type: "boolean",
|
|
890
|
+
label: "Exa researcher",
|
|
891
|
+
description: "AI-powered deep research tasks",
|
|
892
|
+
get: (sm) => sm.getExaSettings().enableResearcher,
|
|
893
|
+
set: (sm, v) => sm.setExaResearcherEnabled(v),
|
|
894
|
+
},
|
|
895
|
+
{
|
|
896
|
+
id: "exaWebsets",
|
|
897
|
+
tab: "exa",
|
|
898
|
+
type: "boolean",
|
|
899
|
+
label: "Exa websets",
|
|
900
|
+
description: "Webset management and enrichment tools",
|
|
901
|
+
get: (sm) => sm.getExaSettings().enableWebsets,
|
|
902
|
+
set: (sm, v) => sm.setExaWebsetsEnabled(v),
|
|
903
|
+
},
|
|
696
904
|
];
|
|
697
905
|
|
|
698
906
|
/**
|