@agi-fans/dsh-tui 0.20.0 → 0.22.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/lib/CHANGELOG.md +249 -3
- package/lib/chrome/box.d.ts +47 -16
- package/lib/chrome/box.js +172 -130
- package/lib/chrome/box.js.map +1 -1
- package/lib/chrome/code-highlight.d.ts +15 -0
- package/lib/chrome/code-highlight.js +60 -4
- package/lib/chrome/code-highlight.js.map +1 -1
- package/lib/chrome/command-output.d.ts +29 -2
- package/lib/chrome/command-output.js +100 -4
- package/lib/chrome/command-output.js.map +1 -1
- package/lib/chrome/main-screen-renderer.d.ts +18 -0
- package/lib/chrome/main-screen-renderer.js +58 -5
- package/lib/chrome/main-screen-renderer.js.map +1 -1
- package/lib/chrome/markdown.js +30 -10
- package/lib/chrome/markdown.js.map +1 -1
- package/lib/chrome/relative-time.d.ts +17 -0
- package/lib/chrome/relative-time.js +36 -0
- package/lib/chrome/relative-time.js.map +1 -1
- package/lib/chrome/renderer.d.ts +9 -0
- package/lib/chrome/renderer.js +1 -1
- package/lib/chrome/renderer.js.map +1 -1
- package/lib/chrome/secret-mask.d.ts +35 -0
- package/lib/chrome/secret-mask.js +180 -0
- package/lib/chrome/secret-mask.js.map +1 -0
- package/lib/chrome/status-config.d.ts +161 -51
- package/lib/chrome/status-config.js +237 -126
- package/lib/chrome/status-config.js.map +1 -1
- package/lib/chrome/status-line.d.ts +3 -2
- package/lib/chrome/status-line.js +105 -63
- package/lib/chrome/status-line.js.map +1 -1
- package/lib/chrome/terminal-colors.d.ts +85 -0
- package/lib/chrome/terminal-colors.js +230 -0
- package/lib/chrome/terminal-colors.js.map +1 -0
- package/lib/chrome/terminal-images.d.ts +9 -1
- package/lib/chrome/terminal-images.js +27 -4
- package/lib/chrome/terminal-images.js.map +1 -1
- package/lib/chrome/theme.d.ts +32 -9
- package/lib/chrome/theme.js +616 -520
- package/lib/chrome/theme.js.map +1 -1
- package/lib/chrome/tool-args.d.ts +1 -1
- package/lib/chrome/tool-args.js +3 -1
- package/lib/chrome/tool-args.js.map +1 -1
- package/lib/chrome/tool-renderers.d.ts +2 -0
- package/lib/chrome/tool-renderers.js +69 -3
- package/lib/chrome/tool-renderers.js.map +1 -1
- package/lib/chrome/tools-list.d.ts +1 -4
- package/lib/chrome/tools-list.js +1 -41
- package/lib/chrome/tools-list.js.map +1 -1
- package/lib/chrome/welcome-tips.d.ts +20 -7
- package/lib/chrome/welcome-tips.js +22 -41
- package/lib/chrome/welcome-tips.js.map +1 -1
- package/lib/commands/auth-ids.d.ts +25 -0
- package/lib/commands/auth-ids.js +27 -0
- package/lib/commands/auth-ids.js.map +1 -0
- package/lib/commands/auth-input.d.ts +34 -0
- package/lib/commands/auth-input.js +96 -0
- package/lib/commands/auth-input.js.map +1 -0
- package/lib/commands/auth-providers.d.ts +39 -0
- package/lib/commands/auth-providers.js +125 -0
- package/lib/commands/auth-providers.js.map +1 -0
- package/lib/commands/auth.d.ts +16 -22
- package/lib/commands/auth.js +346 -299
- package/lib/commands/auth.js.map +1 -1
- package/lib/commands/btw.d.ts +27 -0
- package/lib/commands/btw.js +59 -0
- package/lib/commands/btw.js.map +1 -0
- package/lib/commands/diff.js +30 -5
- package/lib/commands/diff.js.map +1 -1
- package/lib/commands/export.d.ts +1 -1
- package/lib/commands/export.js +5 -3
- package/lib/commands/export.js.map +1 -1
- package/lib/commands/files.d.ts +17 -1
- package/lib/commands/files.js +69 -61
- package/lib/commands/files.js.map +1 -1
- package/lib/commands/integrations.js +18 -6
- package/lib/commands/integrations.js.map +1 -1
- package/lib/commands/jobs.d.ts +19 -4
- package/lib/commands/jobs.js +50 -7
- package/lib/commands/jobs.js.map +1 -1
- package/lib/commands/model.js +109 -76
- package/lib/commands/model.js.map +1 -1
- package/lib/commands/permission.js +46 -13
- package/lib/commands/permission.js.map +1 -1
- package/lib/commands/plugins.js +196 -42
- package/lib/commands/plugins.js.map +1 -1
- package/lib/commands/schedule.d.ts +29 -0
- package/lib/commands/schedule.js +228 -0
- package/lib/commands/schedule.js.map +1 -0
- package/lib/commands/session-configuration.d.ts +1 -1
- package/lib/commands/session-configuration.js +29 -28
- package/lib/commands/session-configuration.js.map +1 -1
- package/lib/commands/session.js +75 -80
- package/lib/commands/session.js.map +1 -1
- package/lib/commands/terminal.d.ts +24 -4
- package/lib/commands/terminal.js +38 -94
- package/lib/commands/terminal.js.map +1 -1
- package/lib/commands/trajectory.js +4 -1
- package/lib/commands/trajectory.js.map +1 -1
- package/lib/definition.d.ts +150 -11
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/input/actions.d.ts +51 -0
- package/lib/input/actions.js +120 -0
- package/lib/input/actions.js.map +1 -0
- package/lib/input/editor-discovery.js +2 -2
- package/lib/input/editor-discovery.js.map +1 -1
- package/lib/input/editor.d.ts +0 -10
- package/lib/input/editor.js +11 -9
- package/lib/input/editor.js.map +1 -1
- package/lib/input/image-paste.d.ts +19 -1
- package/lib/input/image-paste.js +82 -1
- package/lib/input/image-paste.js.map +1 -1
- package/lib/input/keybindings-config.d.ts +15 -4
- package/lib/input/keybindings-config.js +57 -35
- package/lib/input/keybindings-config.js.map +1 -1
- package/lib/input/keys.d.ts +18 -0
- package/lib/input/keys.js +48 -3
- package/lib/input/keys.js.map +1 -1
- package/lib/input/wheel-scroll.d.ts +46 -0
- package/lib/input/wheel-scroll.js +69 -0
- package/lib/input/wheel-scroll.js.map +1 -0
- package/lib/prompt-intents.d.ts +182 -0
- package/lib/prompt-intents.js +127 -0
- package/lib/prompt-intents.js.map +1 -0
- package/lib/runtime/agent-profile.d.ts +5 -0
- package/lib/runtime/agent-profile.js +12 -0
- package/lib/runtime/agent-profile.js.map +1 -1
- package/lib/runtime/approval-rules.d.ts +59 -0
- package/lib/runtime/approval-rules.js +179 -0
- package/lib/runtime/approval-rules.js.map +1 -0
- package/lib/runtime/btw-policy.d.ts +7 -0
- package/lib/runtime/btw-policy.js +18 -0
- package/lib/runtime/btw-policy.js.map +1 -0
- package/lib/runtime/btw.d.ts +47 -0
- package/lib/runtime/btw.js +200 -0
- package/lib/runtime/btw.js.map +1 -0
- package/lib/runtime/cancellable.d.ts +75 -0
- package/lib/runtime/cancellable.js +76 -0
- package/lib/runtime/cancellable.js.map +1 -0
- package/lib/runtime/composer-images.js +5 -4
- package/lib/runtime/composer-images.js.map +1 -1
- package/lib/runtime/composer-shell.d.ts +30 -0
- package/lib/runtime/composer-shell.js +150 -0
- package/lib/runtime/composer-shell.js.map +1 -0
- package/lib/runtime/file-recovery-local.d.ts +73 -0
- package/lib/runtime/file-recovery-local.js +351 -0
- package/lib/runtime/file-recovery-local.js.map +1 -0
- package/lib/runtime/file-recovery-recording.d.ts +23 -0
- package/lib/runtime/file-recovery-recording.js +131 -0
- package/lib/runtime/file-recovery-recording.js.map +1 -0
- package/lib/runtime/file-recovery-review.d.ts +3 -0
- package/lib/runtime/file-recovery-review.js +130 -0
- package/lib/runtime/file-recovery-review.js.map +1 -0
- package/lib/runtime/file-recovery-store.d.ts +83 -0
- package/lib/runtime/file-recovery-store.js +329 -0
- package/lib/runtime/file-recovery-store.js.map +1 -0
- package/lib/runtime/file-recovery-worker.d.ts +22 -0
- package/lib/runtime/file-recovery-worker.js +153 -0
- package/lib/runtime/file-recovery-worker.js.map +1 -0
- package/lib/runtime/file-review.d.ts +6 -3
- package/lib/runtime/file-review.js +44 -7
- package/lib/runtime/file-review.js.map +1 -1
- package/lib/runtime/herdr-agent.d.ts +4 -13
- package/lib/runtime/herdr-agent.js +19 -63
- package/lib/runtime/herdr-agent.js.map +1 -1
- package/lib/runtime/plain-tui.d.ts +2 -0
- package/lib/runtime/plain-tui.js +7 -1
- package/lib/runtime/plain-tui.js.map +1 -1
- package/lib/runtime/plugin-settings.d.ts +25 -2
- package/lib/runtime/plugin-settings.js +329 -31
- package/lib/runtime/plugin-settings.js.map +1 -1
- package/lib/runtime/provider-local.d.ts +81 -24
- package/lib/runtime/provider-local.js +1807 -608
- package/lib/runtime/provider-local.js.map +1 -1
- package/lib/runtime/runner.js +52 -12
- package/lib/runtime/runner.js.map +1 -1
- package/lib/runtime/session-archive.d.ts +6 -0
- package/lib/runtime/session-archive.js +129 -3
- package/lib/runtime/session-archive.js.map +1 -1
- package/lib/runtime/session-runtime.js +1 -1
- package/lib/runtime/session-runtime.js.map +1 -1
- package/lib/runtime/settings-preferences.d.ts +5 -0
- package/lib/runtime/settings-preferences.js +34 -0
- package/lib/runtime/settings-preferences.js.map +1 -0
- package/lib/runtime/startup-notices.js +2 -0
- package/lib/runtime/startup-notices.js.map +1 -1
- package/lib/runtime/terminal-modes.d.ts +47 -0
- package/lib/runtime/terminal-modes.js +86 -0
- package/lib/runtime/terminal-modes.js.map +1 -0
- package/lib/runtime/terminal-notifications.d.ts +3 -5
- package/lib/runtime/terminal-notifications.js +4 -8
- package/lib/runtime/terminal-notifications.js.map +1 -1
- package/lib/runtime/terminal-probe.d.ts +36 -0
- package/lib/runtime/terminal-probe.js +37 -0
- package/lib/runtime/terminal-probe.js.map +1 -0
- package/lib/runtime/terminal-session.d.ts +57 -0
- package/lib/runtime/terminal-session.js +164 -0
- package/lib/runtime/terminal-session.js.map +1 -0
- package/lib/runtime/terminal-state.d.ts +29 -0
- package/lib/runtime/terminal-state.js +62 -0
- package/lib/runtime/terminal-state.js.map +1 -0
- package/lib/runtime/tool-presentation.js +50 -14
- package/lib/runtime/tool-presentation.js.map +1 -1
- package/lib/session/external-agents.d.ts +5 -0
- package/lib/session/external-agents.js +27 -0
- package/lib/session/external-agents.js.map +1 -0
- package/lib/session/feature-toggles.d.ts +1 -1
- package/lib/session/feature-toggles.js +1 -1
- package/lib/session/interaction-adapter.d.ts +1 -6
- package/lib/session/interaction-adapter.js +95 -18
- package/lib/session/interaction-adapter.js.map +1 -1
- package/lib/session/message-queue.js +1 -1
- package/lib/session/message-queue.js.map +1 -1
- package/lib/session/model-readiness.d.ts +16 -0
- package/lib/session/model-readiness.js +43 -0
- package/lib/session/model-readiness.js.map +1 -0
- package/lib/session/package-metadata.d.ts +8 -0
- package/lib/session/package-metadata.js +8 -0
- package/lib/session/package-metadata.js.map +1 -1
- package/lib/session/project-context.d.ts +5 -0
- package/lib/session/project-context.js +36 -0
- package/lib/session/project-context.js.map +1 -1
- package/lib/session/session-controller.d.ts +10 -13
- package/lib/session/session-controller.js +183 -98
- package/lib/session/session-controller.js.map +1 -1
- package/lib/session/session-library.js +2 -0
- package/lib/session/session-library.js.map +1 -1
- package/lib/session/session-tree.d.ts +3 -0
- package/lib/session/session-tree.js +3 -1
- package/lib/session/session-tree.js.map +1 -1
- package/lib/session/subagent-roster.d.ts +2 -1
- package/lib/session/subagent-roster.js +24 -3
- package/lib/session/subagent-roster.js.map +1 -1
- package/lib/session/subagent-tracker.d.ts +6 -2
- package/lib/session/subagent-tracker.js +49 -2
- package/lib/session/subagent-tracker.js.map +1 -1
- package/lib/session/tui-settings.d.ts +47 -13
- package/lib/session/tui-settings.js +76 -34
- package/lib/session/tui-settings.js.map +1 -1
- package/lib/session/working-directory.d.ts +4 -0
- package/lib/session/working-directory.js +4 -0
- package/lib/session/working-directory.js.map +1 -0
- package/lib/session/worktrees.d.ts +13 -0
- package/lib/session/worktrees.js +49 -0
- package/lib/session/worktrees.js.map +1 -0
- package/lib/views/approval-rule.d.ts +3 -0
- package/lib/views/approval-rule.js +4 -0
- package/lib/views/approval-rule.js.map +1 -0
- package/lib/views/at-complete.d.ts +8 -0
- package/lib/views/at-complete.js +64 -2
- package/lib/views/at-complete.js.map +1 -1
- package/lib/views/autocomplete.d.ts +22 -2
- package/lib/views/autocomplete.js +70 -40
- package/lib/views/autocomplete.js.map +1 -1
- package/lib/views/copy-targets.d.ts +13 -14
- package/lib/views/copy-targets.js +42 -54
- package/lib/views/copy-targets.js.map +1 -1
- package/lib/views/document-reader.js +18 -5
- package/lib/views/document-reader.js.map +1 -1
- package/lib/views/event-views.d.ts +1 -1
- package/lib/views/event-views.js +60 -6
- package/lib/views/event-views.js.map +1 -1
- package/lib/views/file-actions.d.ts +12 -0
- package/lib/views/file-actions.js +72 -0
- package/lib/views/file-actions.js.map +1 -0
- package/lib/views/history-search.js +15 -21
- package/lib/views/history-search.js.map +1 -1
- package/lib/views/hotkeys.d.ts +8 -1
- package/lib/views/hotkeys.js +53 -26
- package/lib/views/hotkeys.js.map +1 -1
- package/lib/views/list-navigation.d.ts +62 -0
- package/lib/views/list-navigation.js +73 -0
- package/lib/views/list-navigation.js.map +1 -0
- package/lib/views/list-view.d.ts +99 -0
- package/lib/views/list-view.js +165 -0
- package/lib/views/list-view.js.map +1 -0
- package/lib/views/prompt-selector.d.ts +34 -4
- package/lib/views/prompt-selector.js +270 -134
- package/lib/views/prompt-selector.js.map +1 -1
- package/lib/views/session-files.d.ts +1 -2
- package/lib/views/session-files.js +1 -11
- package/lib/views/session-files.js.map +1 -1
- package/lib/views/settings-list.d.ts +51 -10
- package/lib/views/settings-list.js +267 -315
- package/lib/views/settings-list.js.map +1 -1
- package/lib/views/trajectory-timeline.d.ts +72 -0
- package/lib/views/trajectory-timeline.js +133 -0
- package/lib/views/trajectory-timeline.js.map +1 -0
- package/lib/views/trajectory.d.ts +15 -4
- package/lib/views/trajectory.js +557 -123
- package/lib/views/trajectory.js.map +1 -1
- package/lib/views/transcript-export.js +9 -0
- package/lib/views/transcript-export.js.map +1 -1
- package/lib/views/transcript-render.d.ts +97 -25
- package/lib/views/transcript-render.js +542 -170
- package/lib/views/transcript-render.js.map +1 -1
- package/lib/views/transcript-search.d.ts +39 -6
- package/lib/views/transcript-search.js +46 -11
- package/lib/views/transcript-search.js.map +1 -1
- package/lib/views/transcript-types.d.ts +63 -5
- package/lib/views/transcript-types.js +23 -11
- package/lib/views/transcript-types.js.map +1 -1
- package/package.json +95 -65
- package/lib/commands/loop.d.ts +0 -52
- package/lib/commands/loop.js +0 -307
- package/lib/commands/loop.js.map +0 -1
- package/lib/commands/steer.d.ts +0 -5
- package/lib/commands/steer.js +0 -24
- package/lib/commands/steer.js.map +0 -1
- package/lib/runtime/terminal-reader.d.ts +0 -11
- package/lib/runtime/terminal-reader.js +0 -87
- package/lib/runtime/terminal-reader.js.map +0 -1
- package/lib/views/agent-hub.d.ts +0 -32
- package/lib/views/agent-hub.js +0 -206
- package/lib/views/agent-hub.js.map +0 -1
- package/lib/views/copy-selector.d.ts +0 -51
- package/lib/views/copy-selector.js +0 -139
- package/lib/views/copy-selector.js.map +0 -1
package/lib/runtime/plain-tui.js
CHANGED
|
@@ -101,7 +101,13 @@ export class PlainTui {
|
|
|
101
101
|
let out = '';
|
|
102
102
|
for (const block of blocks.slice(this.#printed)) {
|
|
103
103
|
// Pipe / CI output is not a viewport: print the full tool body.
|
|
104
|
-
for (const line of blockLines(block, theme, width, {
|
|
104
|
+
for (const line of blockLines(block, theme, width, {
|
|
105
|
+
toolsExpanded: true,
|
|
106
|
+
mathMode: this.#deps.mathMode?.() ?? 'auto',
|
|
107
|
+
mermaidMode: this.#deps.mermaidMode?.() ?? 'auto',
|
|
108
|
+
hideThinking: this.#deps.hideThinking?.() === true,
|
|
109
|
+
thinkingOpen: this.#deps.hideThinking?.() !== true,
|
|
110
|
+
}))
|
|
105
111
|
out += line + '\n';
|
|
106
112
|
}
|
|
107
113
|
this.#printed = blocks.length;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plain-tui.js","sourceRoot":"","sources":["../../src/runtime/plain-tui.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAE9D,OAAO,EAAE,eAAe,EAAkB,MAAM,eAAe,CAAA;AAG/D,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;
|
|
1
|
+
{"version":3,"file":"plain-tui.js","sourceRoot":"","sources":["../../src/runtime/plain-tui.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,21 @@
|
|
|
1
1
|
/** Schema-driven configuration using path edits and revision-checked writes. */
|
|
2
2
|
import type { Context } from '@deepseek-ai/cordis';
|
|
3
|
+
import type { BundleInfo } from '@deepseek-ai/dsh-plugin-manager';
|
|
3
4
|
import z from '@deepseek-ai/schemastery';
|
|
4
5
|
import type { PluginSettingsEntry } from '../views/settings-list.ts';
|
|
6
|
+
import type { TuiService } from '../definition.ts';
|
|
7
|
+
interface ProductForm {
|
|
8
|
+
label: string;
|
|
9
|
+
section: NonNullable<PluginSettingsEntry['section']>;
|
|
10
|
+
fields: Record<string, string>;
|
|
11
|
+
inline?: string;
|
|
12
|
+
effect?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function nativeIntegrationId(bundle: string): string | undefined;
|
|
15
|
+
/** A failed user action needs acknowledgement before its covering form reopens. */
|
|
16
|
+
export declare function showSettingsError(tui: Pick<TuiService, 'notice' | 'prompt'>, detail: string, signal?: AbortSignal): Promise<void>;
|
|
17
|
+
/** Diagnostics are a result: they go to the transcript, folded when long. */
|
|
18
|
+
export declare function showIntegrationStatus(ctx: Context, bundle: string, signal: AbortSignal): Promise<void>;
|
|
5
19
|
export interface ConfigField {
|
|
6
20
|
path: string[];
|
|
7
21
|
schema: z;
|
|
@@ -13,5 +27,14 @@ export interface ConfigField {
|
|
|
13
27
|
export declare function configFields(schema: z, path?: string[]): ConfigField[];
|
|
14
28
|
export declare function configValue(value: unknown, path: readonly string[]): unknown;
|
|
15
29
|
export declare function parseConfigValue(field: ConfigField, text: string): unknown;
|
|
16
|
-
|
|
17
|
-
export declare function
|
|
30
|
+
/** Human units are presentation only; owner schemas still validate the stored numbers. */
|
|
31
|
+
export declare function fieldDisplay(field: ConfigField, value: unknown): string;
|
|
32
|
+
export declare function pluginSettingsEntries(ctx: Context, bundles?: readonly BundleInfo[]): PluginSettingsEntry[];
|
|
33
|
+
/** Write the displayed snapshot's revision; a concurrent change must never be silently overwritten. */
|
|
34
|
+
export declare function setSettingsEntry(ctx: Context, entry: PluginSettingsEntry, choice: string, signal: AbortSignal): Promise<void>;
|
|
35
|
+
/** Route a product row to its original owner; installation remains in /plugins. */
|
|
36
|
+
export declare function editSettingsEntry(ctx: Context, id: string, signal: AbortSignal, resetOnly?: boolean): Promise<void>;
|
|
37
|
+
/** Restore only the chosen owner fields, fenced to the configuration shown by the confirmation. */
|
|
38
|
+
export declare function resetSettingsControl(ctx: Context, id: string, entry: PluginSettingsEntry | undefined, signal: AbortSignal, label?: string): Promise<void>;
|
|
39
|
+
export declare function editPluginSettings(ctx: Context, ns: string, signal: AbortSignal, allowedFields?: readonly string[], presentation?: Pick<ProductForm, 'label' | 'fields'>, resetOnly?: boolean): Promise<void>;
|
|
40
|
+
export {};
|
|
@@ -2,6 +2,67 @@
|
|
|
2
2
|
import { randomUUID } from 'node:crypto';
|
|
3
3
|
import { credentialRef } from '@deepseek-ai/dsh-credentials';
|
|
4
4
|
import z from '@deepseek-ai/schemastery';
|
|
5
|
+
import { externalAgentDiagnostic, externalAgentGuide } from "../session/external-agents.js";
|
|
6
|
+
import { preferencePaths } from "./settings-preferences.js";
|
|
7
|
+
import { resolveStatusBarConfig } from "../chrome/status-config.js";
|
|
8
|
+
const SHELL_FORM = { label: 'Shell', section: 'tools', fields: { timeoutMs: 'Default timeout', maxTimeoutMs: 'Maximum timeout', maxOutputBytes: 'Output limit', maxSpillBytes: 'Retained output limit', graceMs: 'Shutdown grace' } };
|
|
9
|
+
// Presentation only: values, validation, inheritance and writes belong to each live schema.
|
|
10
|
+
const PRODUCT_FORMS = {
|
|
11
|
+
'agent-loop': { label: 'Tool parallelism', section: 'tools', fields: { maxParallelToolCalls: 'Parallel tool calls' } },
|
|
12
|
+
subagent: { label: 'Subagents', section: 'agent', fields: { maxDepth: 'Delegation depth', maxActiveSubagents: 'Concurrent subagents' } },
|
|
13
|
+
'subagent-model-selection-settings': { label: 'Subagent models', section: 'agent', fields: { enabled: 'Model selection', allowedModels: 'Allowed models' }, inline: 'enabled', effect: 'Applies to new sessions; existing sessions keep their routes.' },
|
|
14
|
+
bash: SHELL_FORM,
|
|
15
|
+
pwsh: SHELL_FORM,
|
|
16
|
+
'file-recovery': { label: 'File recovery snapshots', section: 'tools', fields: { enabled: 'Snapshots' }, inline: 'enabled', effect: 'Keeps private file contents. Changes apply to the next Turn; existing snapshots remain readable.' },
|
|
17
|
+
'hook-settings': { label: 'Command hooks', section: 'integrations', fields: { bridge: 'Hook compatibility', configPath: 'Configuration file' }, inline: 'bridge' },
|
|
18
|
+
web: { label: 'Web providers', section: 'integrations', fields: { searchProvider: 'Search provider', fetchProvider: 'Fetch provider' },
|
|
19
|
+
effect: 'Default: deepseek-search-api and deepseek-fetch-api. Fallbacks: deepseek-official (Messages) and http (local). With more than one provider installed, an empty value is ambiguous.' },
|
|
20
|
+
'web-deepseek-api': { label: 'Web search · API', section: 'integrations',
|
|
21
|
+
fields: { apiKey: 'API key', apiKeyEnv: 'API key reference', baseURL: 'Endpoint', count: 'Results per search', sendOriginalQuestion: 'Send original question' },
|
|
22
|
+
effect: 'Default search and fetch provider: one direct DeepSeek API request without an auxiliary model turn. /login stores the official key under this reference.' },
|
|
23
|
+
'web-search-deepseek': { label: 'Web search · Messages', section: 'integrations',
|
|
24
|
+
fields: { maxTokens: 'Token limit', maxUses: 'Search limit', apiKey: 'API key', apiKeyEnv: 'API key reference', baseURL: 'Endpoint', model: 'Model', apiVersion: 'API version' },
|
|
25
|
+
effect: 'Fallback search provider: one auxiliary Messages turn. Select it under Web providers.' },
|
|
26
|
+
};
|
|
27
|
+
// Already represented by dedicated controls, or accepted solely for migration.
|
|
28
|
+
const DEDICATED_FIELDS = {
|
|
29
|
+
tui: ['theme', 'colors', 'motion', 'mathMode', 'mermaidMode', 'editor', 'terminalTitle', 'terminalState', 'pasteProtection', 'copyOnSelect', 'mouseInteraction', 'checkUpdates', 'startupChangelog', 'notifications', 'notificationFocus', 'notificationThreshold', 'statusBar', 'foldDensity', 'expandTools', 'statusPreset'],
|
|
30
|
+
'agent-behavior': ['language'],
|
|
31
|
+
// A deployment without the working-directory service may still set these in
|
|
32
|
+
// its profile; normal sessions always run in the Session's current directory.
|
|
33
|
+
bash: ['cwd'],
|
|
34
|
+
pwsh: ['cwd'],
|
|
35
|
+
'subagent-codex': ['model', 'permissionMode', 'env'],
|
|
36
|
+
'subagent-claude-code': ['model', 'permissionMode', 'env'],
|
|
37
|
+
};
|
|
38
|
+
const NATIVE_INTEGRATIONS = [
|
|
39
|
+
{ id: 'integration:codex', label: 'Codex', bundle: '@deepseek-ai/dsh-subagent-codex' },
|
|
40
|
+
{ id: 'integration:claude', label: 'Claude Code', bundle: '@deepseek-ai/dsh-subagent-claude-code' },
|
|
41
|
+
];
|
|
42
|
+
export function nativeIntegrationId(bundle) {
|
|
43
|
+
return NATIVE_INTEGRATIONS.find(item => item.bundle === bundle)?.id;
|
|
44
|
+
}
|
|
45
|
+
/** A failed user action needs acknowledgement before its covering form reopens. */
|
|
46
|
+
export async function showSettingsError(tui, detail, signal) {
|
|
47
|
+
if (signal?.aborted)
|
|
48
|
+
return;
|
|
49
|
+
tui.notice(detail, { level: 'error' });
|
|
50
|
+
await tui.prompt({ title: 'Settings', question: 'Could not change configuration', detail,
|
|
51
|
+
options: [{ label: 'Return to settings' }], allowCustom: false, notify: false,
|
|
52
|
+
...(signal === undefined ? {} : { signal }) });
|
|
53
|
+
}
|
|
54
|
+
/** Diagnostics are a result: they go to the transcript, folded when long. */
|
|
55
|
+
export async function showIntegrationStatus(ctx, bundle, signal) {
|
|
56
|
+
const manager = ctx.get('pluginManager');
|
|
57
|
+
if (manager === undefined || signal.aborted)
|
|
58
|
+
return;
|
|
59
|
+
const row = (await manager.listBundles()).find(row => row.name === bundle);
|
|
60
|
+
const text = row === undefined ? 'This integration is no longer registered in this profile.'
|
|
61
|
+
: externalAgentDiagnostic(row, await manager.listPlugins());
|
|
62
|
+
if (signal.aborted)
|
|
63
|
+
return;
|
|
64
|
+
ctx.tui.commandOutput(`${NATIVE_INTEGRATIONS.find(item => item.bundle === bundle)?.label ?? bundle} · Status`, text);
|
|
65
|
+
}
|
|
5
66
|
function containsSecret(schema, seen = new Set()) {
|
|
6
67
|
if (seen.has(schema))
|
|
7
68
|
return false;
|
|
@@ -11,7 +72,7 @@ function containsSecret(schema, seen = new Set()) {
|
|
|
11
72
|
}
|
|
12
73
|
/** Flatten ordinary objects while retaining arrays and unions as atomic fields. */
|
|
13
74
|
export function configFields(schema, path = []) {
|
|
14
|
-
if (schema.meta.hidden || schema.meta.disabled)
|
|
75
|
+
if (schema.meta.hidden || schema.meta.disabled || schema.meta.badges?.some(badge => badge.text === 'deprecated'))
|
|
15
76
|
return [];
|
|
16
77
|
if (schema.type === 'object')
|
|
17
78
|
return Object.entries(schema.dict ?? {}).flatMap(([key, child]) => configFields(child, [...path, key]));
|
|
@@ -45,12 +106,12 @@ function credentialPath(field, fields) {
|
|
|
45
106
|
const path = [...field.path.slice(0, -1), 'apiKeyEnv'];
|
|
46
107
|
return field.secret && field.path.at(-1) === 'apiKey' && fields.some(item => item.path.join('.') === path.join('.')) ? path : undefined;
|
|
47
108
|
}
|
|
48
|
-
function fieldDescription(section, field, fields) {
|
|
109
|
+
function fieldDescription(section, field, fields, human = false) {
|
|
49
110
|
const refPath = credentialPath(field, fields);
|
|
50
111
|
const reference = refPath === undefined ? undefined : configValue(section.value, refPath);
|
|
51
112
|
const inline = section.secrets?.find(secret => secret.path.join('.') === field.path.join('.'))?.set;
|
|
52
113
|
const value = field.secret ? `secret · ${inline ? 'configured' : typeof reference === 'string' && reference !== '' ? 'credential reference configured' : 'not set'}`
|
|
53
|
-
: field.protected ? 'protected · use /
|
|
114
|
+
: field.protected ? 'protected · use /login or the owner configuration' : human ? fieldDisplay(field, configValue(section.value, field.path)) : display(configValue(section.value, field.path));
|
|
54
115
|
const override = hasOverride(section.user, field.path) || refPath !== undefined && hasOverride(section.user, refPath);
|
|
55
116
|
const help = field.schema.meta.description;
|
|
56
117
|
return `${value} · ${override ? 'profile override' : 'inherited'}${typeof help === 'string' && help !== '' ? ` · ${help}` : ''}`;
|
|
@@ -60,39 +121,221 @@ export function parseConfigValue(field, text) {
|
|
|
60
121
|
field.schema(value);
|
|
61
122
|
return value;
|
|
62
123
|
}
|
|
63
|
-
const list = { presentation: '
|
|
64
|
-
|
|
65
|
-
return
|
|
124
|
+
const list = { presentation: 'card', filterable: true, allowCustom: false, notify: false };
|
|
125
|
+
function constantValues(field) {
|
|
126
|
+
return field.schema.type === 'boolean' ? [true, false] : field.schema.type === 'union'
|
|
127
|
+
&& field.schema.list?.every(child => child.type === 'const') ? field.schema.list.map(child => child.value) : undefined;
|
|
128
|
+
}
|
|
129
|
+
function choiceLabel(value) {
|
|
130
|
+
return typeof value === 'boolean' ? value ? 'On' : 'Off' : display(value);
|
|
131
|
+
}
|
|
132
|
+
/** Human units are presentation only; owner schemas still validate the stored numbers. */
|
|
133
|
+
export function fieldDisplay(field, value) {
|
|
134
|
+
if (value === undefined || value === null)
|
|
135
|
+
return '—';
|
|
136
|
+
if (typeof value === 'boolean')
|
|
137
|
+
return choiceLabel(value);
|
|
138
|
+
if (typeof value !== 'number')
|
|
139
|
+
return display(value);
|
|
140
|
+
const name = field.path.at(-1) ?? '';
|
|
141
|
+
if (name.endsWith('Ms'))
|
|
142
|
+
return value !== 0 && value % 60_000 === 0 ? `${value / 60_000}m` : value !== 0 && value % 1000 === 0 ? `${value / 1000}s` : `${value}ms`;
|
|
143
|
+
if (name.endsWith('Bytes')) {
|
|
144
|
+
for (const [unit, factor] of [['GiB', 1024 ** 3], ['MiB', 1024 ** 2], ['KiB', 1024]])
|
|
145
|
+
if (value !== 0 && value % factor === 0)
|
|
146
|
+
return `${value / factor} ${unit}`;
|
|
147
|
+
return `${value} B`;
|
|
148
|
+
}
|
|
149
|
+
return display(value);
|
|
150
|
+
}
|
|
151
|
+
function parseProductValue(field, text) {
|
|
152
|
+
if (field.schema.type === 'number') {
|
|
153
|
+
const match = /^\s*(\d+(?:\.\d+)?)\s*([a-z]+)\s*$/iu.exec(text);
|
|
154
|
+
const factors = (field.path.at(-1) ?? '').endsWith('Ms') ? { ms: 1, s: 1000, m: 60_000, h: 3_600_000 }
|
|
155
|
+
: (field.path.at(-1) ?? '').endsWith('Bytes') ? { b: 1, kb: 1000, mb: 1000 ** 2, gb: 1000 ** 3, kib: 1024, mib: 1024 ** 2, gib: 1024 ** 3 } : {};
|
|
156
|
+
const factor = match === null ? undefined : factors[match[2].toLowerCase()];
|
|
157
|
+
if (match !== null && factor !== undefined) {
|
|
158
|
+
const value = Number(match[1]) * factor;
|
|
159
|
+
field.schema(value);
|
|
160
|
+
return value;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return parseConfigValue(field, text);
|
|
164
|
+
}
|
|
165
|
+
export function pluginSettingsEntries(ctx, bundles) {
|
|
166
|
+
const entries = ctx.settings.describe({ redactSecrets: true }).flatMap(section => {
|
|
66
167
|
const fields = configFields(new z(section.schema));
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
168
|
+
const ns = String(section.ns), form = Object.hasOwn(PRODUCT_FORMS, ns) ? PRODUCT_FORMS[ns] : undefined;
|
|
169
|
+
const paths = fields.map(field => field.path.join('.'));
|
|
170
|
+
const claimed = [...(Object.hasOwn(DEDICATED_FIELDS, ns) ? DEDICATED_FIELDS[ns] ?? [] : []), ...Object.keys(form?.fields ?? {})];
|
|
171
|
+
const owned = paths.filter(path => Object.hasOwn(form?.fields ?? {}, path));
|
|
172
|
+
const advanced = section.autoGenerate === false ? [] : paths.filter(path => !claimed.includes(path));
|
|
173
|
+
const writable = ctx.settings.writable ? 'Edits apply live to this profile.' : 'This profile is read-only.';
|
|
174
|
+
const summary = fields.filter(field => owned.includes(field.path.join('.')) && !field.secret && !field.protected
|
|
175
|
+
&& configValue(section.value, field.path) !== undefined).slice(0, 2)
|
|
176
|
+
.map(field => `${form?.fields[field.path.join('.')]}: ${Array.isArray(configValue(section.value, field.path)) ? `${configValue(section.value, field.path).length} selected` : fieldDisplay(field, configValue(section.value, field.path))}`).join(' · ');
|
|
177
|
+
const field = fields.find(field => field.path.join('.') === form?.inline);
|
|
178
|
+
const values = field === undefined || field.secret || field.protected ? undefined : constantValues(field);
|
|
179
|
+
// A field with a schema default is already in effect, so the row shows that
|
|
180
|
+
// value rather than "not set": the reader's choice is what the schema says it
|
|
181
|
+
// is, and an unset override is not a third state.
|
|
182
|
+
const effective = field === undefined ? undefined
|
|
183
|
+
: configValue(section.value, field.path) ?? field.schema.meta.default;
|
|
184
|
+
const inline = field === undefined || values === undefined || values.length === 0 ? undefined : {
|
|
185
|
+
path: field.path, revision: section.revision, value: choiceLabel(effective),
|
|
186
|
+
choices: ctx.settings.writable ? values.map(value => ({ label: choiceLabel(value), value: JSON.stringify(value) })) : [],
|
|
187
|
+
};
|
|
188
|
+
return [
|
|
189
|
+
...(form === undefined || owned.length === 0 ? [] : [{ id: ns, namespace: ns, label: form.label, section: form.section, fields: owned,
|
|
190
|
+
...(inline === undefined ? {} : { inline }), summary, keywords: [...owned, ...Object.values(form.fields)],
|
|
191
|
+
description: `${form.effect === undefined ? '' : `${form.effect} `}${field === undefined ? '' : `${fieldDescription(section, field, fields)} · `}${writable}` }]),
|
|
192
|
+
...(advanced.length === 0 ? [] : [{ id: `advanced:${ns}`, namespace: ns,
|
|
193
|
+
label: String(section.ns).replace(/[-_]+/gu, ' ').replace(/^./u, first => first.toUpperCase()), section: 'advanced', fields: advanced,
|
|
194
|
+
summary: `${advanced.length} fields`, keywords: advanced, description: `${ns} · ${advanced.length} fields · ${writable}` }]),
|
|
195
|
+
];
|
|
70
196
|
});
|
|
197
|
+
if (ctx.get('pluginManager') !== undefined)
|
|
198
|
+
entries.push(...NATIVE_INTEGRATIONS.map(item => {
|
|
199
|
+
const bundle = bundles?.find(bundle => bundle.name === item.bundle);
|
|
200
|
+
return { id: item.id, label: item.label, section: 'integrations', fields: [],
|
|
201
|
+
summary: bundles === undefined ? 'Details' : bundle === undefined || bundle.availability === 'missing' ? 'Unavailable' : bundle.error !== undefined ? 'Load error' : bundle.enabled ? 'Enabled' : 'Disabled',
|
|
202
|
+
description: 'Provider model, permissions and profile enablement. Native login has not been checked; Installation status reports registration.' };
|
|
203
|
+
}));
|
|
204
|
+
return entries;
|
|
205
|
+
}
|
|
206
|
+
/** Write the displayed snapshot's revision; a concurrent change must never be silently overwritten. */
|
|
207
|
+
export async function setSettingsEntry(ctx, entry, choice, signal) {
|
|
208
|
+
signal.throwIfAborted();
|
|
209
|
+
const inline = entry.inline;
|
|
210
|
+
if (!ctx.settings.writable)
|
|
211
|
+
throw new Error('This profile is read-only.');
|
|
212
|
+
if (entry.namespace === undefined || inline === undefined || !inline.choices.some(item => item.value === choice))
|
|
213
|
+
throw new Error('This setting is no longer editable. Refresh and retry.');
|
|
214
|
+
const section = ctx.settings.describe({ redactSecrets: true }).find(item => item.ns === entry.namespace);
|
|
215
|
+
if (section === undefined || section.revision !== inline.revision)
|
|
216
|
+
throw new Error('Configuration changed. Refresh and retry.');
|
|
217
|
+
const form = Object.hasOwn(PRODUCT_FORMS, entry.namespace) ? PRODUCT_FORMS[entry.namespace] : undefined;
|
|
218
|
+
const field = configFields(new z(section.schema)).find(field => field.path.join('.') === inline.path.join('.') && field.path.join('.') === form?.inline);
|
|
219
|
+
if (field === undefined || field.secret || field.protected)
|
|
220
|
+
throw new Error('This setting is no longer editable. Refresh and retry.');
|
|
221
|
+
await saveValue(ctx, section, field, parseConfigValue(field, choice));
|
|
222
|
+
ctx.tui.notice(`${form?.fields[field.path.join('.')] ?? entry.label}: saved.`);
|
|
223
|
+
}
|
|
224
|
+
/** Route a product row to its original owner; installation remains in /plugins. */
|
|
225
|
+
export async function editSettingsEntry(ctx, id, signal, resetOnly = false) {
|
|
226
|
+
const native = NATIVE_INTEGRATIONS.find(item => item.id === id);
|
|
227
|
+
if (native !== undefined) {
|
|
228
|
+
const manager = ctx.get('pluginManager');
|
|
229
|
+
if (manager === undefined)
|
|
230
|
+
return;
|
|
231
|
+
while (!signal.aborted) {
|
|
232
|
+
const row = (await manager.listBundles()).find(row => row.name === native.bundle);
|
|
233
|
+
if (row === undefined || row.availability === 'missing') {
|
|
234
|
+
await showSettingsError(ctx.tui, `${native.label} is unavailable. Open /plugins → Bundles to install or repair its package.`, signal);
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
const ns = row.rows.find(item => item.moduleName === row.name)?.rowId;
|
|
238
|
+
const configurable = ns !== undefined && ctx.get('settings')?.describe({ redactSecrets: true }).some(section => section.ns === ns);
|
|
239
|
+
const action = await ctx.tui.prompt({ ...list, title: native.label, question: row.enabled ? 'Enabled' : 'Disabled',
|
|
240
|
+
detail: [row.error === undefined ? undefined : `Load error: ${row.error.diagnostic ?? row.error.code}`, externalAgentGuide(row.name)].filter(Boolean).join('\n\n'), options: [{ label: row.enabled ? 'Disable integration' : 'Enable integration', value: 'toggle' },
|
|
241
|
+
...(configurable ? [{ label: 'Model', value: 'field:model' }, { label: 'Permissions', value: 'field:permissionMode' }] : []), ...(configurable ? [{ label: 'Restore inherited model or permissions…', value: 'restore' }] : []), { label: 'Installation status', value: 'check' }], notify: false, signal });
|
|
242
|
+
if (action === null || signal.aborted)
|
|
243
|
+
return;
|
|
244
|
+
if (action === 'toggle') {
|
|
245
|
+
const result = await manager.setBundleEnabled(row.name, !row.enabled);
|
|
246
|
+
if (result.error !== undefined || result.application === 'failed')
|
|
247
|
+
await showSettingsError(ctx.tui, result.error?.diagnostic ?? result.error?.code ?? 'Could not change integration.', signal);
|
|
248
|
+
else
|
|
249
|
+
ctx.tui.notice(`${native.label}: ${result.application}${result.enabled === undefined ? '' : result.enabled ? ' · enabled' : ' · disabled'}.`);
|
|
250
|
+
}
|
|
251
|
+
if (action.startsWith('field:') && configurable && ns !== undefined)
|
|
252
|
+
await editPluginSettings(ctx, ns, signal, [action.slice(6)], { label: native.label, fields: { model: 'Model', permissionMode: 'Permissions' } });
|
|
253
|
+
if (action === 'restore' && configurable && ns !== undefined)
|
|
254
|
+
await editPluginSettings(ctx, ns, signal, ['model', 'permissionMode'], { label: native.label, fields: { model: 'Model', permissionMode: 'Permissions' } }, true);
|
|
255
|
+
if (action === 'check')
|
|
256
|
+
await showIntegrationStatus(ctx, row.name, signal);
|
|
257
|
+
}
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
const entry = pluginSettingsEntries(ctx).find(entry => entry.id === id);
|
|
261
|
+
if (entry?.namespace === undefined)
|
|
262
|
+
return;
|
|
263
|
+
await editPluginSettings(ctx, entry.namespace, signal, entry.fields, entry.section === 'advanced' ? undefined : PRODUCT_FORMS[entry.namespace], resetOnly);
|
|
264
|
+
}
|
|
265
|
+
/** Restore only the chosen owner fields, fenced to the configuration shown by the confirmation. */
|
|
266
|
+
export async function resetSettingsControl(ctx, id, entry, signal, label = entry?.label ?? id) {
|
|
267
|
+
if (entry !== undefined && entry.inline === undefined) {
|
|
268
|
+
await editSettingsEntry(ctx, entry.id, signal, true);
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
const ns = entry?.namespace ?? (id === 'agentLanguage' ? 'agent-behavior' : 'tui');
|
|
272
|
+
const paths = entry?.inline === undefined ? id === 'agentLanguage' ? [['language']] : preferencePaths(id) : [[...entry.inline.path]];
|
|
273
|
+
if (paths === undefined || !ctx.settings.writable)
|
|
274
|
+
throw new Error('This setting cannot be restored in this profile.');
|
|
275
|
+
const section = ctx.settings.describe({ redactSecrets: true }).find(section => section.ns === ns);
|
|
276
|
+
if (section === undefined || entry?.inline !== undefined && section.revision !== entry.inline.revision)
|
|
277
|
+
throw new Error('Configuration changed. Refresh and retry.');
|
|
278
|
+
const revision = section.revision;
|
|
279
|
+
const fields = configFields(new z(section.schema));
|
|
280
|
+
const status = resolveStatusBarConfig(configValue(section.base, ['statusBar']), configValue(section.base, ['statusPreset']));
|
|
281
|
+
const inherited = id === 'statusReset' ? `Context: ${status.contextStyle}\nTelemetry: ${status.groups.length} items\nHeader: ${status.meta.length} items` : paths.map(path => {
|
|
282
|
+
let value = configValue(section.base, path);
|
|
283
|
+
if (path[0] === 'statusBar')
|
|
284
|
+
value = configValue(status, path.slice(1));
|
|
285
|
+
const field = fields.find(field => field.path.join('.') === path.join('.'));
|
|
286
|
+
if (value === undefined)
|
|
287
|
+
value = field?.schema.meta.default;
|
|
288
|
+
return `${path[0] === 'statusBar' && path.length === 1 ? 'Layout' : label}: ${display(value)}`;
|
|
289
|
+
}).join('\n');
|
|
290
|
+
const choice = await ctx.tui.prompt({ title: 'Restore inherited setting', question: id.startsWith('statusItem:') ? `${label} color` : label,
|
|
291
|
+
detail: `${inherited}\nOnly these Profile overrides will be removed.`, options: [{ label: 'Restore inherited value', value: 'restore' }], allowCustom: false, notify: false, signal });
|
|
292
|
+
if (choice !== 'restore' || signal.aborted)
|
|
293
|
+
return;
|
|
294
|
+
if (entry?.inline !== undefined) {
|
|
295
|
+
const field = configFields(new z(section.schema)).find(field => field.path.join('.') === entry.inline.path.join('.'));
|
|
296
|
+
if (field === undefined || field.secret || field.protected)
|
|
297
|
+
throw new Error('This setting is no longer editable.');
|
|
298
|
+
validateModelSelection(section, field, configValue(section.base, field.path));
|
|
299
|
+
}
|
|
300
|
+
await ctx.settings.mutate(ns, paths.map(path => ({ op: 'unset', path })), revision);
|
|
301
|
+
ctx.tui.notice('Inherited setting restored.');
|
|
71
302
|
}
|
|
72
|
-
export async function editPluginSettings(ctx, ns, signal) {
|
|
303
|
+
export async function editPluginSettings(ctx, ns, signal, allowedFields, presentation, resetOnly = false) {
|
|
304
|
+
let focusedPath;
|
|
305
|
+
const directField = presentation !== undefined && allowedFields?.length === 1 && ['subagent-codex', 'subagent-claude-code'].includes(ns);
|
|
73
306
|
while (!signal.aborted) {
|
|
74
307
|
// Re-read after every write; never carry a stale editor into another field.
|
|
75
|
-
const
|
|
76
|
-
if (
|
|
77
|
-
ctx.tui
|
|
308
|
+
const descriptor = ctx.settings.describe({ redactSecrets: true }).find(item => item.ns === ns);
|
|
309
|
+
if (descriptor === undefined) {
|
|
310
|
+
await showSettingsError(ctx.tui, `No editable configuration for ${ns}.`, signal);
|
|
78
311
|
return;
|
|
79
312
|
}
|
|
80
|
-
const
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
313
|
+
const section = { ...descriptor };
|
|
314
|
+
const fields = configFields(new z(section.schema)).filter(field => allowedFields === undefined || allowedFields.includes(field.path.join('.')));
|
|
315
|
+
const currentIndex = fields.findIndex(field => field.path.join('.') === focusedPath);
|
|
316
|
+
let selected = directField && !resetOnly ? '0' : await ctx.tui.prompt({ ...list, ...(currentIndex < 0 ? {} : { initialValue: String(currentIndex) }), title: presentation?.label ?? String(section.ns), question: resetOnly ? 'Choose a setting to restore' : 'Choose a setting',
|
|
317
|
+
options: fields.map((field, index) => ({ label: presentation?.fields[field.path.join('.')] ?? field.path.join('.'), value: String(index),
|
|
318
|
+
description: fieldDescription(section, field, fields, presentation !== undefined) })).concat(presentation !== undefined && !resetOnly ? [{ label: 'Restore inherited setting…', value: 'restore', description: 'Remove a selected Profile override.' }] : []), signal });
|
|
84
319
|
if (selected === null)
|
|
85
320
|
break;
|
|
321
|
+
const restore = resetOnly || selected === 'restore';
|
|
322
|
+
if (selected === 'restore')
|
|
323
|
+
selected = await ctx.tui.prompt({ ...list, title: presentation?.label ?? ns, question: 'Choose a setting to restore',
|
|
324
|
+
options: fields.map((field, index) => ({ label: presentation?.fields[field.path.join('.')] ?? field.path.join('.'), value: String(index), description: fieldDescription(section, field, fields, presentation !== undefined) })), signal });
|
|
325
|
+
if (selected === null || signal.aborted)
|
|
326
|
+
continue;
|
|
86
327
|
const field = fields[Number(selected)];
|
|
87
328
|
if (field === undefined || field.protected)
|
|
88
329
|
continue;
|
|
330
|
+
focusedPath = field.path.join('.');
|
|
89
331
|
if (!ctx.settings.writable) {
|
|
90
|
-
ctx.tui
|
|
332
|
+
await showSettingsError(ctx.tui, 'This profile is read-only.', signal);
|
|
91
333
|
continue;
|
|
92
334
|
}
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
335
|
+
const label = presentation?.fields[field.path.join('.')] ?? field.path.join('.');
|
|
336
|
+
const action = presentation !== undefined && !restore ? 'set' : await ctx.tui.prompt({ title: label, question: restore ? 'Restore inherited value?' : 'Set a value or restore inheritance',
|
|
337
|
+
detail: field.secret ? 'Secret values are never shown. Reset removes the profile value and its paired credential reference; inherited credentials may still apply.' : `Current: ${presentation === undefined ? display(configValue(section.value, field.path)) : fieldDisplay(field, configValue(section.value, field.path))}\nInherited: ${presentation === undefined ? display(configValue(section.base, field.path)) : fieldDisplay(field, configValue(section.base, field.path))}`,
|
|
338
|
+
options: [...(restore ? [] : [{ label: 'Set value', value: 'set' }]), { label: 'Reset to inherited', value: 'reset' }], allowCustom: false, notify: false, signal });
|
|
96
339
|
if (action === null || signal.aborted)
|
|
97
340
|
continue;
|
|
98
341
|
try {
|
|
@@ -101,31 +344,86 @@ export async function editPluginSettings(ctx, ns, signal) {
|
|
|
101
344
|
const refPath = credentialPath(field, fields);
|
|
102
345
|
await ctx.settings.mutate(ns, [{ op: 'unset', path: field.path }, ...(refPath === undefined ? [] : [{ op: 'unset', path: refPath }])], section.revision);
|
|
103
346
|
}
|
|
347
|
+
else if (section.ns === 'subagent-model-selection-settings' && field.path.join('.') === 'allowedModels') {
|
|
348
|
+
const routes = await chooseSubagentModels(ctx, configValue(section.value, field.path), signal);
|
|
349
|
+
if (routes === null)
|
|
350
|
+
continue;
|
|
351
|
+
field.schema(routes);
|
|
352
|
+
await saveValue(ctx, section, field, routes);
|
|
353
|
+
}
|
|
104
354
|
else {
|
|
105
|
-
const constants = field
|
|
106
|
-
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
355
|
+
const constants = constantValues(field);
|
|
356
|
+
const current = configValue(section.value, field.path);
|
|
357
|
+
const unitHelp = field.schema.type !== 'number' ? '' : (field.path.at(-1) ?? '').endsWith('Ms') ? 'Use milliseconds, or units such as 30s and 2m.'
|
|
358
|
+
: (field.path.at(-1) ?? '').endsWith('Bytes') ? 'Use bytes, or units such as 512 KiB and 2 MiB.' : '';
|
|
359
|
+
const text = await ctx.tui.prompt({ title: label, question: field.schema.type === 'string' || presentation !== undefined && field.schema.type === 'number' ? 'Enter a value' : constants === undefined ? 'Enter a JSON value' : 'Choose a value',
|
|
360
|
+
...(field.secret ? {} : { detail: presentation === undefined ? field.schema.toString() : [`Current: ${fieldDisplay(field, current)}`, field.schema.meta.description, unitHelp].filter(Boolean).join('\n') }), secret: field.secret,
|
|
361
|
+
...(field.secret ? {} : constants === undefined ? { initialInput: current === undefined ? '' : presentation !== undefined && field.schema.type === 'number' ? fieldDisplay(field, current) : field.schema.type === 'string' ? String(current) : JSON.stringify(current) }
|
|
362
|
+
: { initialValue: JSON.stringify(current) }),
|
|
363
|
+
...(constants === undefined ? { allowCustom: true } : { allowCustom: false, options: constants.map(value => ({ label: presentation !== undefined && typeof value === 'boolean' ? value ? 'On' : 'Off' : display(value), value: JSON.stringify(value) })) }), notify: false, signal });
|
|
364
|
+
if (text === null || signal.aborted) {
|
|
365
|
+
if (directField)
|
|
366
|
+
return;
|
|
111
367
|
continue;
|
|
112
|
-
|
|
368
|
+
}
|
|
369
|
+
const value = presentation === undefined ? parseConfigValue(field, text) : parseProductValue(field, text);
|
|
113
370
|
await saveValue(ctx, section, field, value);
|
|
114
371
|
}
|
|
115
|
-
ctx.tui.notice(`${ns}.${field.path.join('.')}: ${action === 'reset' ? 'inherited value restored' : 'saved'}.`);
|
|
372
|
+
ctx.tui.notice(`${presentation === undefined ? `${ns}.${field.path.join('.')}` : label}: ${action === 'reset' ? 'inherited value restored' : 'saved'}.`);
|
|
373
|
+
if (directField && !resetOnly)
|
|
374
|
+
return;
|
|
116
375
|
}
|
|
117
376
|
catch (error) {
|
|
118
377
|
// Secret validation messages may echo their input.
|
|
119
|
-
ctx.tui
|
|
378
|
+
await showSettingsError(ctx.tui, field.secret ? 'Could not save the secret. Refresh the field and check its format or credential storage.' : error instanceof Error ? error.message : String(error), signal);
|
|
120
379
|
}
|
|
121
380
|
}
|
|
122
381
|
}
|
|
382
|
+
async function chooseSubagentModels(ctx, current, signal) {
|
|
383
|
+
const routes = [];
|
|
384
|
+
const key = (route) => JSON.stringify([route.provider, route.model]);
|
|
385
|
+
const existing = Array.isArray(current) ? current.filter((route) => route !== null && typeof route === 'object' && typeof route.provider === 'string' && typeof route.model === 'string') : [];
|
|
386
|
+
const llm = ctx.get('llm');
|
|
387
|
+
const unavailable = [];
|
|
388
|
+
if (llm !== undefined) {
|
|
389
|
+
const providers = llm.listProviders();
|
|
390
|
+
const catalogs = await Promise.allSettled(providers.map(provider => llm.listModels(provider.id)));
|
|
391
|
+
signal.throwIfAborted();
|
|
392
|
+
catalogs.forEach((catalog, index) => {
|
|
393
|
+
const provider = providers[index];
|
|
394
|
+
if (catalog.status === 'rejected') {
|
|
395
|
+
unavailable.push(provider.id);
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
for (const model of catalog.value)
|
|
399
|
+
routes.push({ provider: provider.id, model: model.id, label: `${model.name ?? model.id} · ${provider.id}`, description: model.description ?? model.id });
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
for (const route of existing)
|
|
403
|
+
if (!routes.some(item => key(item) === key(route)))
|
|
404
|
+
routes.push({ ...route, label: `${route.model} · ${route.provider}`, description: 'Configured route · currently outside the model catalog' });
|
|
405
|
+
const unique = routes.filter((route, index) => routes.findIndex(item => key(item) === key(route)) === index);
|
|
406
|
+
const answer = await ctx.tui.prompt({ ...list, title: 'Allowed subagent models', question: 'Choose models for new sessions', detail: `Space toggles a model. Enter saves the selection. Existing sessions keep their routes.${unavailable.length === 0 ? '' : ` Catalog unavailable: ${unavailable.join(', ')}; configured routes are retained.`}`,
|
|
407
|
+
emptyText: 'No models are available. Configure a provider through /login or cancel to keep the current setting.',
|
|
408
|
+
multiSelect: true, allowEmptySelection: true, initialValues: unique.flatMap((route, index) => existing.some(item => key(item) === key(route)) ? [String(index)] : []),
|
|
409
|
+
options: unique.map((route, index) => ({ label: route.label, ...(route.description === undefined ? {} : { description: route.description }), value: String(index) })), signal, notify: false });
|
|
410
|
+
if (answer === null)
|
|
411
|
+
return null;
|
|
412
|
+
if (answer === '')
|
|
413
|
+
return [];
|
|
414
|
+
return answer.split(', ').map(value => {
|
|
415
|
+
const route = unique[Number(value)];
|
|
416
|
+
if (route === undefined || !/^\d+$/u.test(value))
|
|
417
|
+
throw new Error('Model selection changed. Refresh and retry.');
|
|
418
|
+
return { provider: route.provider, model: route.model };
|
|
419
|
+
});
|
|
420
|
+
}
|
|
123
421
|
function validateModelSelection(section, field, value) {
|
|
124
422
|
if (section.ns === 'subagent-model-selection-settings') {
|
|
125
423
|
const enabled = field.path[0] === 'enabled' ? value : configValue(section.value, ['enabled']);
|
|
126
424
|
const models = field.path[0] === 'allowedModels' ? value : configValue(section.value, ['allowedModels']);
|
|
127
425
|
if (enabled === true && (!Array.isArray(models) || models.length === 0))
|
|
128
|
-
throw new Error('
|
|
426
|
+
throw new Error('Choose at least one allowed model before enabling subagent model selection.');
|
|
129
427
|
}
|
|
130
428
|
}
|
|
131
429
|
async function saveValue(ctx, section, field, value) {
|