@pellux/goodvibes-agent 0.1.116 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +48 -661
- package/README.md +64 -57
- package/bin/goodvibes-agent.ts +16 -2
- package/dist/package/main.js +199180 -192185
- package/docs/README.md +15 -8
- package/docs/channels-remote-and-api.md +50 -0
- package/docs/connected-host.md +59 -0
- package/docs/getting-started.md +61 -50
- package/docs/knowledge-artifacts-and-multimodal.md +91 -0
- package/docs/project-planning.md +79 -0
- package/docs/providers-and-routing.md +46 -0
- package/docs/release-and-publishing.md +48 -11
- package/docs/tools-and-commands.md +123 -0
- package/docs/voice-and-live-tts.md +51 -0
- package/package.json +3 -6
- package/src/agent/behavior-discovery-summary.ts +1 -3
- package/src/agent/channel-delivery.ts +201 -0
- package/src/agent/media-generation.ts +159 -0
- package/src/agent/memory-prompt.ts +0 -1
- package/src/agent/note-registry.ts +329 -0
- package/src/agent/operator-actions.ts +343 -0
- package/src/agent/persona-discovery.ts +1 -3
- package/src/agent/persona-registry.ts +19 -16
- package/src/agent/record-labels.ts +107 -0
- package/src/agent/reminder-schedule-format.ts +33 -24
- package/src/agent/reminder-schedule.ts +27 -26
- package/src/agent/routine-registry.ts +54 -14
- package/src/agent/routine-schedule-args.ts +2 -1
- package/src/agent/routine-schedule-format.ts +77 -53
- package/src/agent/routine-schedule-promotion.ts +35 -33
- package/src/agent/routine-schedule-receipts.ts +29 -27
- package/src/agent/runtime-profile-starters.ts +5 -5
- package/src/agent/runtime-profile.ts +91 -12
- package/src/agent/skill-registry.ts +210 -32
- package/src/cli/agent-knowledge-args.ts +5 -1
- package/src/cli/agent-knowledge-command.ts +40 -34
- package/src/cli/agent-knowledge-format.ts +80 -67
- package/src/cli/agent-knowledge-methods.ts +1 -1
- package/src/cli/agent-knowledge-runtime.ts +32 -26
- package/src/cli/bundle-command.ts +14 -9
- package/src/cli/config-overrides.ts +37 -36
- package/src/cli/entrypoint.ts +16 -7
- package/src/cli/external-runtime.ts +10 -4
- package/src/cli/help.ts +54 -29
- package/src/cli/local-library-command.ts +203 -83
- package/src/cli/management-commands.ts +105 -68
- package/src/cli/management.ts +55 -74
- package/src/cli/memory-command.ts +66 -32
- package/src/cli/parser.ts +37 -3
- package/src/cli/profiles-command.ts +166 -31
- package/src/cli/provider-auth-routes.ts +2 -1
- package/src/cli/routines-command.ts +176 -40
- package/src/cli/service-posture.ts +16 -16
- package/src/cli/status.ts +56 -135
- package/src/core/conversation-message-snapshot.ts +131 -0
- package/src/input/agent-workspace-access-command-editor-submission.ts +149 -0
- package/src/input/agent-workspace-access-command-editors.ts +170 -0
- package/src/input/agent-workspace-activation.ts +35 -8
- package/src/input/agent-workspace-basic-command-editor-submission.ts +351 -94
- package/src/input/agent-workspace-basic-command-editors.ts +502 -9
- package/src/input/agent-workspace-categories.ts +423 -51
- package/src/input/agent-workspace-channel-command-editor-submission.ts +83 -0
- package/src/input/agent-workspace-channel-command-editors.ts +65 -0
- package/src/input/agent-workspace-channels.ts +35 -2
- package/src/input/agent-workspace-command-editor.ts +41 -3
- package/src/input/agent-workspace-config-reader.ts +16 -0
- package/src/input/agent-workspace-delegation-editor-submission.ts +55 -0
- package/src/input/agent-workspace-editors.ts +166 -1
- package/src/input/agent-workspace-knowledge-command-editor-submission.ts +132 -0
- package/src/input/agent-workspace-knowledge-command-editors.ts +110 -0
- package/src/input/agent-workspace-knowledge-query-editor.ts +1 -1
- package/src/input/agent-workspace-learned-behavior.ts +67 -0
- package/src/input/agent-workspace-library-command-editor-submission.ts +50 -0
- package/src/input/agent-workspace-library-command-editors.ts +35 -0
- package/src/input/agent-workspace-local-operations.ts +218 -0
- package/src/input/agent-workspace-local-selection.ts +75 -0
- package/src/input/agent-workspace-mcp-command-editor-submission.ts +95 -0
- package/src/input/agent-workspace-media-command-editor-submission.ts +62 -0
- package/src/input/agent-workspace-media-command-editors.ts +27 -0
- package/src/input/agent-workspace-memory-command-editor-submission.ts +232 -0
- package/src/input/agent-workspace-memory-command-editors.ts +180 -0
- package/src/input/agent-workspace-memory-editor.ts +2 -2
- package/src/input/agent-workspace-navigation.ts +81 -0
- package/src/input/agent-workspace-notify-editor-submission.ts +121 -0
- package/src/input/agent-workspace-operations-command-editor-submission.ts +208 -0
- package/src/input/agent-workspace-operations-command-editors.ts +196 -0
- package/src/input/agent-workspace-panel-route.ts +43 -0
- package/src/input/agent-workspace-provider-command-editor-submission.ts +155 -0
- package/src/input/agent-workspace-provider-command-editors.ts +93 -0
- package/src/input/agent-workspace-reminder-schedule-editor.ts +1 -1
- package/src/input/agent-workspace-requirements.ts +11 -0
- package/src/input/agent-workspace-routine-schedule-editor.ts +2 -2
- package/src/input/agent-workspace-search.ts +169 -0
- package/src/input/agent-workspace-secret-editor-submission.ts +153 -0
- package/src/input/agent-workspace-session-command-editor-submission.ts +199 -0
- package/src/input/agent-workspace-session-command-editors.ts +249 -0
- package/src/input/agent-workspace-setup.ts +37 -16
- package/src/input/agent-workspace-skill-bundle-command-editor-submission.ts +101 -0
- package/src/input/agent-workspace-skill-bundle-command-editors.ts +110 -0
- package/src/input/agent-workspace-snapshot.ts +162 -21
- package/src/input/agent-workspace-task-command-editor-submission.ts +61 -0
- package/src/input/agent-workspace-task-command-editors.ts +47 -0
- package/src/input/agent-workspace-token.ts +18 -2
- package/src/input/agent-workspace-types.ts +212 -4
- package/src/input/agent-workspace-voice-media.ts +4 -7
- package/src/input/agent-workspace-web-research-editor.ts +104 -0
- package/src/input/agent-workspace-workplan-editor-submission.ts +153 -0
- package/src/input/agent-workspace.ts +178 -240
- package/src/input/command-registry.ts +5 -2
- package/src/input/commands/agent-runtime-profile-runtime.ts +126 -37
- package/src/input/commands/agent-skills-runtime.ts +149 -72
- package/src/input/commands/agent-workspace-runtime.ts +23 -6
- package/src/input/commands/brief-runtime.ts +55 -25
- package/src/input/commands/channels-runtime.ts +147 -33
- package/src/input/commands/compat-runtime.ts +32 -0
- package/src/input/commands/delegation-runtime.ts +29 -23
- package/src/input/commands/experience-runtime.ts +6 -4
- package/src/input/commands/guidance-runtime.ts +4 -4
- package/src/input/commands/health-runtime.ts +149 -126
- package/src/input/commands/knowledge.ts +82 -60
- package/src/input/commands/local-provider-runtime.ts +43 -21
- package/src/input/commands/local-runtime.ts +138 -16
- package/src/input/commands/local-setup-review.ts +10 -20
- package/src/input/commands/mcp-runtime.ts +63 -46
- package/src/input/commands/notify-runtime.ts +38 -9
- package/src/input/commands/operator-actions-runtime.ts +138 -0
- package/src/input/commands/operator-runtime.ts +6 -76
- package/src/input/commands/personas-runtime.ts +46 -31
- package/src/input/commands/planning-runtime.ts +1 -1
- package/src/input/commands/platform-access-runtime.ts +35 -98
- package/src/input/commands/product-runtime.ts +2 -2
- package/src/input/commands/provider-accounts-runtime.ts +60 -39
- package/src/input/commands/qrcode-runtime.ts +50 -9
- package/src/input/commands/recall-bundle.ts +11 -11
- package/src/input/commands/recall-capture.ts +13 -11
- package/src/input/commands/recall-query.ts +29 -21
- package/src/input/commands/recall-review.ts +2 -1
- package/src/input/commands/routines-runtime.ts +99 -45
- package/src/input/commands/runtime-services.ts +1 -14
- package/src/input/commands/schedule-runtime.ts +33 -20
- package/src/input/commands/security-runtime.ts +6 -11
- package/src/input/commands/session-content.ts +80 -78
- package/src/input/commands/session-workflow.ts +134 -104
- package/src/input/commands/session.ts +3 -174
- package/src/input/commands/shell-core.ts +38 -17
- package/src/input/commands/subscription-runtime.ts +54 -185
- package/src/input/commands/support-bundle-runtime.ts +53 -0
- package/src/input/commands/tasks-runtime.ts +21 -21
- package/src/input/commands/work-plan-runtime.ts +33 -8
- package/src/input/commands.ts +6 -2
- package/src/input/feed-context-factory.ts +2 -2
- package/src/input/file-picker.ts +3 -2
- package/src/input/handler-command-route.ts +4 -7
- package/src/input/handler-content-actions.ts +89 -26
- package/src/input/handler-feed-routes.ts +19 -12
- package/src/input/handler-feed.ts +6 -5
- package/src/input/handler-interactions.ts +9 -36
- package/src/input/handler-modal-stack.ts +3 -3
- package/src/input/handler-onboarding.ts +52 -91
- package/src/input/handler-shortcuts.ts +16 -7
- package/src/input/handler.ts +50 -23
- package/src/input/input-history.ts +5 -6
- package/src/input/keybindings.ts +27 -16
- package/src/input/mcp-workspace.ts +90 -26
- package/src/input/onboarding/handler-onboarding-routes.ts +3 -1
- package/src/input/onboarding/onboarding-wizard-apply.ts +62 -0
- package/src/input/onboarding/onboarding-wizard-constants.ts +1 -0
- package/src/input/onboarding/onboarding-wizard-helpers.ts +1 -1
- package/src/input/onboarding/onboarding-wizard-operator-steps.ts +223 -55
- package/src/input/onboarding/onboarding-wizard-steps.ts +59 -35
- package/src/input/onboarding/onboarding-wizard-types.ts +4 -1
- package/src/input/onboarding/onboarding-wizard.ts +87 -2
- package/src/input/profile-picker-modal.ts +31 -12
- package/src/input/session-picker-modal.ts +21 -4
- package/src/input/settings-modal-agent-policy.ts +6 -6
- package/src/input/settings-modal-behavior.ts +0 -3
- package/src/input/settings-modal-subscriptions.ts +3 -3
- package/src/input/settings-modal-types.ts +2 -13
- package/src/input/settings-modal.ts +20 -66
- package/src/input/submission-intent.ts +0 -1
- package/src/input/submission-router.ts +3 -3
- package/src/main.ts +18 -10
- package/src/panels/approval-panel.ts +8 -8
- package/src/panels/automation-control-panel.ts +4 -4
- package/src/panels/base-panel.ts +1 -1
- package/src/panels/builtin/agent.ts +1 -1
- package/src/panels/builtin/operations.ts +3 -12
- package/src/panels/builtin/session.ts +32 -24
- package/src/panels/builtin/shared.ts +7 -7
- package/src/panels/cost-tracker-panel.ts +1 -1
- package/src/panels/docs-panel.ts +5 -3
- package/src/panels/index.ts +0 -1
- package/src/panels/knowledge-panel.ts +6 -5
- package/src/panels/memory-panel.ts +7 -6
- package/src/panels/panel-list-panel.ts +36 -80
- package/src/panels/project-planning-panel.ts +19 -12
- package/src/panels/provider-account-snapshot.ts +51 -25
- package/src/panels/provider-accounts-panel.ts +33 -18
- package/src/panels/provider-health-domains.ts +48 -7
- package/src/panels/provider-health-panel.ts +5 -4
- package/src/panels/qr-panel.ts +44 -20
- package/src/panels/schedule-panel.ts +9 -17
- package/src/panels/security-panel.ts +8 -8
- package/src/panels/session-browser-panel.ts +10 -10
- package/src/panels/subscription-panel.ts +6 -6
- package/src/panels/system-messages-panel.ts +3 -3
- package/src/panels/tasks-panel.ts +21 -14
- package/src/panels/tool-inspector-panel.ts +19 -12
- package/src/panels/work-plan-panel.ts +5 -5
- package/src/planning/project-planning-coordinator.ts +3 -3
- package/src/provider-auth-route-display.ts +9 -0
- package/src/renderer/agent-workspace-style.ts +34 -0
- package/src/renderer/agent-workspace.ts +254 -57
- package/src/renderer/autocomplete-overlay.ts +25 -6
- package/src/renderer/block-actions.ts +1 -3
- package/src/renderer/bookmark-modal.ts +19 -4
- package/src/renderer/buffer.ts +4 -2
- package/src/renderer/context-inspector.ts +50 -13
- package/src/renderer/diff.ts +1 -1
- package/src/renderer/file-picker-overlay.ts +19 -6
- package/src/renderer/help-overlay.ts +112 -34
- package/src/renderer/history-search-overlay.ts +19 -4
- package/src/renderer/live-tail-modal.ts +27 -5
- package/src/renderer/mcp-workspace.ts +176 -43
- package/src/renderer/model-picker-overlay.ts +58 -3
- package/src/renderer/model-workspace.ts +104 -22
- package/src/renderer/onboarding/onboarding-wizard.ts +20 -4
- package/src/renderer/process-modal.ts +27 -6
- package/src/renderer/profile-picker-modal.ts +21 -5
- package/src/renderer/search-overlay.ts +25 -5
- package/src/renderer/selection-modal-overlay.ts +46 -14
- package/src/renderer/session-picker-modal.ts +18 -1
- package/src/renderer/settings-modal-helpers.ts +2 -40
- package/src/renderer/settings-modal.ts +88 -55
- package/src/renderer/system-message.ts +1 -1
- package/src/renderer/tool-call.ts +20 -11
- package/src/runtime/agent-runtime-events.ts +129 -0
- package/src/runtime/bootstrap-command-context.ts +7 -1
- package/src/runtime/bootstrap-command-parts.ts +11 -8
- package/src/runtime/bootstrap-core.ts +23 -65
- package/src/runtime/bootstrap-hook-bridge.ts +7 -18
- package/src/runtime/bootstrap-shell.ts +46 -8
- package/src/runtime/bootstrap.ts +36 -46
- package/src/runtime/connected-host-auth.ts +47 -0
- package/src/runtime/diagnostics/panels/index.ts +2 -2
- package/src/runtime/diagnostics/panels/panel-resources.ts +1 -1
- package/src/runtime/diagnostics/panels/policy.ts +7 -7
- package/src/runtime/index.ts +2 -5
- package/src/runtime/onboarding/apply-file-helpers.ts +66 -0
- package/src/runtime/onboarding/apply.ts +288 -74
- package/src/runtime/onboarding/derivation.ts +10 -13
- package/src/runtime/onboarding/snapshot.ts +2 -17
- package/src/runtime/onboarding/types.ts +34 -20
- package/src/runtime/onboarding/verify.ts +105 -4
- package/src/runtime/operator-token-cleanup.ts +3 -3
- package/src/runtime/services.ts +95 -11
- package/src/runtime/store/selectors/index.ts +3 -3
- package/src/runtime/store/state.ts +1 -4
- package/src/runtime/surface-feature-flags.ts +41 -6
- package/src/runtime/ui-read-models.ts +3 -4
- package/src/runtime/ui-services.ts +6 -6
- package/src/shell/blocking-input.ts +2 -1
- package/src/shell/service-settings-sync.ts +7 -7
- package/src/shell/ui-openers.ts +17 -38
- package/src/tools/agent-analysis-registry-policy.ts +0 -1
- package/src/tools/agent-channel-send-tool.ts +133 -0
- package/src/tools/agent-context-policy.ts +1 -1
- package/src/tools/agent-knowledge-ingest-tool.ts +405 -0
- package/src/tools/agent-knowledge-tool.ts +170 -0
- package/src/tools/agent-local-registry-tool.ts +279 -73
- package/src/tools/agent-media-generate-tool.ts +133 -0
- package/src/tools/agent-notify-tool.ts +143 -0
- package/src/tools/agent-operator-action-tool.ts +137 -0
- package/src/tools/agent-operator-briefing-tool.ts +217 -0
- package/src/tools/agent-reminder-schedule-tool.ts +237 -0
- package/src/tools/agent-tool-policy-guard.ts +13 -15
- package/src/tools/agent-work-plan-tool.ts +256 -0
- package/src/version.ts +1 -1
- package/docs/connected-services.md +0 -51
- package/src/cli/package-verification.ts +0 -274
- package/src/input/commands/policy-dispatch.ts +0 -339
- package/src/input/commands/policy.ts +0 -17
- package/src/panels/panel-picker.ts +0 -105
- package/src/panels/policy-panel.ts +0 -308
- package/src/renderer/panel-picker-overlay.ts +0 -202
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpWorkspace, McpWorkspaceRow } from '../input/mcp-workspace.ts';
|
|
1
|
+
import type { McpWorkspace, McpWorkspaceRow, McpWorkspaceServerRow } from '../input/mcp-workspace.ts';
|
|
2
2
|
import type { Line } from '../types/grid.ts';
|
|
3
3
|
import { wrapText } from '../utils/terminal-width.ts';
|
|
4
4
|
import { GLYPHS } from './ui-primitives.ts';
|
|
@@ -11,6 +11,117 @@ import {
|
|
|
11
11
|
type WorkspaceRow,
|
|
12
12
|
} from './fullscreen-workspace.ts';
|
|
13
13
|
|
|
14
|
+
const MCP_WORKSPACE_TITLE = 'MCP Workspace / Servers';
|
|
15
|
+
const MCP_WORKSPACE_LEFT_HEADER = 'Servers';
|
|
16
|
+
const MCP_WORKSPACE_GROUP_SERVERS = 'SERVERS';
|
|
17
|
+
const MCP_WORKSPACE_GROUP_ACTIONS = 'ACTIONS';
|
|
18
|
+
const MCP_WORKSPACE_NO_CONFIGURED_SERVERS = ' No configured servers';
|
|
19
|
+
const MCP_WORKSPACE_FORM_WRITE_CONFIRMATION = 'Workspace writes require explicit confirmation. Type yes on the Confirm field, then save from here.';
|
|
20
|
+
const MCP_WORKSPACE_FORM_CONFIG_LOCATIONS = 'Project/global config locations are shown for review. The workspace dispatches confirmed MCP changes through the TUI command router.';
|
|
21
|
+
const MCP_WORKSPACE_REMOVE_HELP = 'Press Enter or y to remove through the TUI command router.';
|
|
22
|
+
const MCP_WORKSPACE_REMOVE_CANCEL_HELP = 'Press n or Esc to return without changing config.';
|
|
23
|
+
const MCP_WORKSPACE_RELOAD_TITLE = 'Reload MCP runtime';
|
|
24
|
+
const MCP_WORKSPACE_RELOAD_HELP = 'Press Enter or y to reload MCP runtime from the current config through the TUI command router.';
|
|
25
|
+
const MCP_WORKSPACE_RELOAD_CANCEL_HELP = 'Press n or Esc to return without reloading.';
|
|
26
|
+
const MCP_WORKSPACE_NO_ROWS = 'No MCP rows available.';
|
|
27
|
+
const MCP_WORKSPACE_RUNTIME_ONLY_COMMAND = '(runtime only; no launch config found)';
|
|
28
|
+
const MCP_WORKSPACE_NONE = '(none)';
|
|
29
|
+
const MCP_WORKSPACE_STATUS_PREFIX = 'Status:';
|
|
30
|
+
const MCP_WORKSPACE_FORM_HEADER_FIELD = 'Field';
|
|
31
|
+
const MCP_WORKSPACE_FORM_HEADER_VALUE = 'Value';
|
|
32
|
+
const MCP_WORKSPACE_FORM_HEADER_EDIT = 'Edit';
|
|
33
|
+
const MCP_WORKSPACE_FORM_TEXT_EDIT = 'text';
|
|
34
|
+
const MCP_WORKSPACE_FORM_ACTION_EDIT = 'cycle/action';
|
|
35
|
+
const MCP_WORKSPACE_EMPTY_VALUE = '(empty)';
|
|
36
|
+
const MCP_WORKSPACE_TOOL_HEADER_TOOL = 'Tool';
|
|
37
|
+
const MCP_WORKSPACE_TOOL_HEADER_SERVER = 'Server';
|
|
38
|
+
const MCP_WORKSPACE_TOOL_HEADER_DESCRIPTION = 'Description';
|
|
39
|
+
const MCP_WORKSPACE_TOOLS_LOADING = 'Tools: loading...';
|
|
40
|
+
const MCP_WORKSPACE_TOOLS_LOADING_DETAIL = 'Loading tool list from connected MCP servers.';
|
|
41
|
+
const MCP_WORKSPACE_TOOLS_EMPTY = 'No tools cached for the selected server. Press t to refresh.';
|
|
42
|
+
const MCP_WORKSPACE_CONFIRM_CANCEL_ROW = ' Cancel and return to MCP server browser';
|
|
43
|
+
const MCP_WORKSPACE_CONFIRM_RELOAD = 'Confirm MCP runtime reload';
|
|
44
|
+
const MCP_WORKSPACE_FOOTER_FORM = 'Focus MCP server form · Up/Down field · Left/Right cycle · Type edit · Enter save/cancel · Esc back';
|
|
45
|
+
const MCP_WORKSPACE_FOOTER_DELETE = 'Focus remove confirmation · Enter/y remove · n/Esc cancel';
|
|
46
|
+
const MCP_WORKSPACE_FOOTER_RELOAD = 'Focus reload confirmation · Enter/y reload · n/Esc cancel';
|
|
47
|
+
const MCP_WORKSPACE_FOOTER_BROWSE = 'Focus MCP workspace · Up/Down choose · Enter view/action · a add · d remove · r reload · t tools · Esc close';
|
|
48
|
+
|
|
49
|
+
function mcpWorkspaceStateLabel(mode: McpWorkspace['mode']): string {
|
|
50
|
+
return mode === 'browse' ? 'Browse' : mode === 'form' ? 'Server Form' : mode === 'delete-confirm' ? 'Remove Confirm' : 'Reload Confirm';
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function mcpWorkspaceMainHeader(mode: McpWorkspace['mode'], connected: string | number, servers: string | number, tools: string | number): string {
|
|
54
|
+
if (mode === 'form') return 'MCP server form';
|
|
55
|
+
if (mode === 'delete-confirm') return 'MCP remove confirmation';
|
|
56
|
+
if (mode === 'reload-confirm') return 'MCP reload confirmation';
|
|
57
|
+
return `Servers ${connected}/${servers} connected · Tools ${tools}`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function mcpWorkspaceToolsLabel(loading: boolean, server: string | undefined, count: string | number): string {
|
|
61
|
+
if (loading) return MCP_WORKSPACE_TOOLS_LOADING;
|
|
62
|
+
return server ? `Tools for ${server}: ${count}` : `Tools: ${count}`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function renderMcpWorkspacePackageText(): string {
|
|
66
|
+
return [
|
|
67
|
+
MCP_WORKSPACE_TITLE,
|
|
68
|
+
MCP_WORKSPACE_LEFT_HEADER,
|
|
69
|
+
mcpWorkspaceStateLabel('browse'),
|
|
70
|
+
mcpWorkspaceStateLabel('form'),
|
|
71
|
+
mcpWorkspaceStateLabel('delete-confirm'),
|
|
72
|
+
mcpWorkspaceStateLabel('reload-confirm'),
|
|
73
|
+
mcpWorkspaceMainHeader('browse', '<connected>', '<servers>', '<tools>'),
|
|
74
|
+
mcpWorkspaceMainHeader('form', '<connected>', '<servers>', '<tools>'),
|
|
75
|
+
mcpWorkspaceMainHeader('delete-confirm', '<connected>', '<servers>', '<tools>'),
|
|
76
|
+
mcpWorkspaceMainHeader('reload-confirm', '<connected>', '<servers>', '<tools>'),
|
|
77
|
+
MCP_WORKSPACE_GROUP_SERVERS,
|
|
78
|
+
MCP_WORKSPACE_GROUP_ACTIONS,
|
|
79
|
+
MCP_WORKSPACE_NO_CONFIGURED_SERVERS.trim(),
|
|
80
|
+
'project config',
|
|
81
|
+
'global config',
|
|
82
|
+
'external config',
|
|
83
|
+
'runtime',
|
|
84
|
+
'Drafting an MCP server',
|
|
85
|
+
'Editing server <server>',
|
|
86
|
+
MCP_WORKSPACE_FORM_WRITE_CONFIRMATION,
|
|
87
|
+
MCP_WORKSPACE_FORM_CONFIG_LOCATIONS,
|
|
88
|
+
'Remove server: <server>',
|
|
89
|
+
MCP_WORKSPACE_REMOVE_HELP,
|
|
90
|
+
MCP_WORKSPACE_REMOVE_CANCEL_HELP,
|
|
91
|
+
MCP_WORKSPACE_RELOAD_TITLE,
|
|
92
|
+
MCP_WORKSPACE_RELOAD_HELP,
|
|
93
|
+
MCP_WORKSPACE_RELOAD_CANCEL_HELP,
|
|
94
|
+
MCP_WORKSPACE_NO_ROWS,
|
|
95
|
+
'Connected: <yes-no> Origin: <origin> Config: <freshness>',
|
|
96
|
+
'Role: <role> Review policy: <trust-mode>',
|
|
97
|
+
`Command: ${MCP_WORKSPACE_RUNTIME_ONLY_COMMAND}`,
|
|
98
|
+
`Allowed paths: ${MCP_WORKSPACE_NONE}`,
|
|
99
|
+
`Allowed hosts: ${MCP_WORKSPACE_NONE}`,
|
|
100
|
+
`${MCP_WORKSPACE_STATUS_PREFIX} <status>`,
|
|
101
|
+
MCP_WORKSPACE_FORM_HEADER_FIELD,
|
|
102
|
+
MCP_WORKSPACE_FORM_HEADER_VALUE,
|
|
103
|
+
MCP_WORKSPACE_FORM_HEADER_EDIT,
|
|
104
|
+
MCP_WORKSPACE_FORM_TEXT_EDIT,
|
|
105
|
+
MCP_WORKSPACE_FORM_ACTION_EDIT,
|
|
106
|
+
MCP_WORKSPACE_EMPTY_VALUE,
|
|
107
|
+
mcpWorkspaceToolsLabel(true, undefined, '<count>'),
|
|
108
|
+
mcpWorkspaceToolsLabel(false, '<server>', '<count>'),
|
|
109
|
+
mcpWorkspaceToolsLabel(false, undefined, '<count>'),
|
|
110
|
+
MCP_WORKSPACE_TOOL_HEADER_TOOL,
|
|
111
|
+
MCP_WORKSPACE_TOOL_HEADER_SERVER,
|
|
112
|
+
MCP_WORKSPACE_TOOL_HEADER_DESCRIPTION,
|
|
113
|
+
MCP_WORKSPACE_TOOLS_LOADING_DETAIL,
|
|
114
|
+
MCP_WORKSPACE_TOOLS_EMPTY,
|
|
115
|
+
'Confirm remove <server>',
|
|
116
|
+
MCP_WORKSPACE_CONFIRM_RELOAD,
|
|
117
|
+
MCP_WORKSPACE_CONFIRM_CANCEL_ROW.trim(),
|
|
118
|
+
MCP_WORKSPACE_FOOTER_FORM,
|
|
119
|
+
MCP_WORKSPACE_FOOTER_DELETE,
|
|
120
|
+
MCP_WORKSPACE_FOOTER_RELOAD,
|
|
121
|
+
MCP_WORKSPACE_FOOTER_BROWSE,
|
|
122
|
+
].join('\n');
|
|
123
|
+
}
|
|
124
|
+
|
|
14
125
|
function statusColor(text: string): string {
|
|
15
126
|
if (text.includes('failed') || text.includes('Save failed') || text.includes('Remove failed')) return PALETTE.bad;
|
|
16
127
|
if (text.includes('attention') || text.includes('quarantine')) return PALETTE.warn;
|
|
@@ -21,15 +132,28 @@ function connectedColor(connected: boolean): string {
|
|
|
21
132
|
return connected ? PALETTE.good : PALETTE.warn;
|
|
22
133
|
}
|
|
23
134
|
|
|
135
|
+
function serverOriginLabel(source: McpWorkspaceServerRow['source']): string {
|
|
136
|
+
switch (source) {
|
|
137
|
+
case 'project':
|
|
138
|
+
return 'project config';
|
|
139
|
+
case 'global':
|
|
140
|
+
return 'global config';
|
|
141
|
+
case 'external':
|
|
142
|
+
return 'external config';
|
|
143
|
+
case 'runtime':
|
|
144
|
+
return 'runtime';
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
24
148
|
function rowLabel(row: McpWorkspaceRow): string {
|
|
25
|
-
if (row.type === 'server') return `${row.server.name} (${row.server.source})`;
|
|
149
|
+
if (row.type === 'server') return `${row.server.name} (${serverOriginLabel(row.server.source)})`;
|
|
26
150
|
return row.label;
|
|
27
151
|
}
|
|
28
152
|
|
|
29
153
|
function rowDetail(row: McpWorkspaceRow): string {
|
|
30
154
|
if (row.type === 'server') {
|
|
31
155
|
const server = row.server;
|
|
32
|
-
return `${server.connected ? 'connected' : 'offline'} · ${server.role} · ${server.trustMode} ·
|
|
156
|
+
return `${server.connected ? 'connected' : 'offline'} · ${server.role} · ${server.trustMode} · config ${server.freshness}`;
|
|
33
157
|
}
|
|
34
158
|
return row.detail;
|
|
35
159
|
}
|
|
@@ -42,13 +166,13 @@ function buildLeftRows(workspace: McpWorkspace, height: number): WorkspaceRow[]
|
|
|
42
166
|
|
|
43
167
|
workspace.rows.forEach((row, rowIndex) => {
|
|
44
168
|
if (row.type === 'server' && !sawServerGroup) {
|
|
45
|
-
rendered.push({ text:
|
|
169
|
+
rendered.push({ text: MCP_WORKSPACE_GROUP_SERVERS, kind: 'group', bold: true });
|
|
46
170
|
sawServerGroup = true;
|
|
47
171
|
}
|
|
48
172
|
if (row.type === 'action' && !sawActionGroup) {
|
|
49
|
-
if (!sawServerGroup) rendered.push({ text:
|
|
50
|
-
if (workspace.servers.length === 0) rendered.push({ text:
|
|
51
|
-
rendered.push({ text:
|
|
173
|
+
if (!sawServerGroup) rendered.push({ text: MCP_WORKSPACE_GROUP_SERVERS, kind: 'group', bold: true });
|
|
174
|
+
if (workspace.servers.length === 0) rendered.push({ text: MCP_WORKSPACE_NO_CONFIGURED_SERVERS, kind: 'item', fg: PALETTE.dim, dim: true });
|
|
175
|
+
rendered.push({ text: MCP_WORKSPACE_GROUP_ACTIONS, kind: 'group', bold: true });
|
|
52
176
|
sawActionGroup = true;
|
|
53
177
|
}
|
|
54
178
|
|
|
@@ -82,41 +206,47 @@ function selectedDetailLines(workspace: McpWorkspace, width: number): WorkspaceR
|
|
|
82
206
|
if (workspace.mode === 'form') {
|
|
83
207
|
const field = workspace.formFields[workspace.formIndex];
|
|
84
208
|
lines.push(
|
|
85
|
-
workspace.editingServerName ? `
|
|
86
|
-
|
|
209
|
+
workspace.editingServerName ? `Editing server ${workspace.editingServerName}` : 'Drafting an MCP server',
|
|
210
|
+
MCP_WORKSPACE_FORM_WRITE_CONFIRMATION,
|
|
87
211
|
field ? `${field.label}: ${field.help}` : '',
|
|
88
|
-
|
|
212
|
+
MCP_WORKSPACE_FORM_CONFIG_LOCATIONS,
|
|
89
213
|
);
|
|
90
214
|
} else if (workspace.mode === 'delete-confirm') {
|
|
91
215
|
lines.push(
|
|
92
|
-
`
|
|
93
|
-
|
|
94
|
-
|
|
216
|
+
`Remove server: ${workspace.editingServerName ?? '(unknown)'}`,
|
|
217
|
+
MCP_WORKSPACE_REMOVE_HELP,
|
|
218
|
+
MCP_WORKSPACE_REMOVE_CANCEL_HELP,
|
|
219
|
+
);
|
|
220
|
+
} else if (workspace.mode === 'reload-confirm') {
|
|
221
|
+
lines.push(
|
|
222
|
+
MCP_WORKSPACE_RELOAD_TITLE,
|
|
223
|
+
MCP_WORKSPACE_RELOAD_HELP,
|
|
224
|
+
MCP_WORKSPACE_RELOAD_CANCEL_HELP,
|
|
95
225
|
);
|
|
96
226
|
} else {
|
|
97
227
|
const selected = workspace.selectedRow;
|
|
98
|
-
if (!selected) lines.push(
|
|
228
|
+
if (!selected) lines.push(MCP_WORKSPACE_NO_ROWS);
|
|
99
229
|
else if (selected.type === 'action') lines.push(selected.label, selected.detail);
|
|
100
230
|
else {
|
|
101
231
|
const server = selected.server;
|
|
102
232
|
lines.push(
|
|
103
233
|
server.name,
|
|
104
|
-
`Connected: ${server.connected ? 'yes' : 'no'}
|
|
105
|
-
`Role: ${server.role}
|
|
106
|
-
`Command: ${server.command ? `${server.command}${server.args?.length ? ` ${server.args.join(' ')}` : ''}` :
|
|
107
|
-
`Allowed paths: ${server.allowedPaths.length > 0 ? server.allowedPaths.join(', ') :
|
|
108
|
-
`Allowed hosts: ${server.allowedHosts.length > 0 ? server.allowedHosts.join(', ') :
|
|
234
|
+
`Connected: ${server.connected ? 'yes' : 'no'} Origin: ${serverOriginLabel(server.source)} Config: ${server.freshness}`,
|
|
235
|
+
`Role: ${server.role} Review policy: ${server.trustMode}`,
|
|
236
|
+
`Command: ${server.command ? `${server.command}${server.args?.length ? ` ${server.args.join(' ')}` : ''}` : MCP_WORKSPACE_RUNTIME_ONLY_COMMAND}`,
|
|
237
|
+
`Allowed paths: ${server.allowedPaths.length > 0 ? server.allowedPaths.join(', ') : MCP_WORKSPACE_NONE}`,
|
|
238
|
+
`Allowed hosts: ${server.allowedHosts.length > 0 ? server.allowedHosts.join(', ') : MCP_WORKSPACE_NONE}`,
|
|
109
239
|
...(server.quarantineReason ? [`Quarantine: ${server.quarantineReason}${server.quarantineDetail ? ` - ${server.quarantineDetail}` : ''}`] : []),
|
|
110
240
|
);
|
|
111
241
|
}
|
|
112
242
|
}
|
|
113
243
|
|
|
114
|
-
lines.push('',
|
|
244
|
+
lines.push('', `${MCP_WORKSPACE_STATUS_PREFIX} ${workspace.status}`);
|
|
115
245
|
return lines.flatMap((text, index): WorkspaceRow[] => {
|
|
116
246
|
if (text === '') return [{ text: '', dim: true }];
|
|
117
247
|
return wrapText(text, Math.max(1, width)).map((wrapped, wrapIndex): WorkspaceRow => ({
|
|
118
248
|
text: wrapped,
|
|
119
|
-
fg: index === 0 ? PALETTE.title : text.startsWith(
|
|
249
|
+
fg: index === 0 ? PALETTE.title : text.startsWith(MCP_WORKSPACE_STATUS_PREFIX) ? statusColor(workspace.status) : PALETTE.text,
|
|
120
250
|
bold: index === 0 && wrapIndex === 0,
|
|
121
251
|
dim: text.length === 0,
|
|
122
252
|
}));
|
|
@@ -129,7 +259,7 @@ function buildFormRows(workspace: McpWorkspace, width: number, height: number):
|
|
|
129
259
|
const labelWidth = Math.min(24, Math.max(14, Math.floor(width * 0.24)));
|
|
130
260
|
const valueWidth = Math.max(12, width - labelWidth - 20);
|
|
131
261
|
rows.push({
|
|
132
|
-
text: ` ${padDisplay(
|
|
262
|
+
text: ` ${padDisplay(MCP_WORKSPACE_FORM_HEADER_FIELD, labelWidth)} ${padDisplay(MCP_WORKSPACE_FORM_HEADER_VALUE, valueWidth)} ${padDisplay(MCP_WORKSPACE_FORM_HEADER_EDIT, 10)}`,
|
|
133
263
|
fg: PALETTE.muted,
|
|
134
264
|
bold: true,
|
|
135
265
|
});
|
|
@@ -143,9 +273,9 @@ function buildFormRows(workspace: McpWorkspace, width: number, height: number):
|
|
|
143
273
|
const marker = selected ? GLYPHS.navigation.selected : ' ';
|
|
144
274
|
const value = field.id === 'save' || field.id === 'cancel'
|
|
145
275
|
? field.help
|
|
146
|
-
: field.value.length > 0 ? field.value :
|
|
276
|
+
: field.value.length > 0 ? field.value : MCP_WORKSPACE_EMPTY_VALUE;
|
|
147
277
|
rows.push({
|
|
148
|
-
text: `${marker} ${padDisplay(field.label, labelWidth)} ${padDisplay(value, valueWidth)} ${padDisplay(field.editable ?
|
|
278
|
+
text: `${marker} ${padDisplay(field.label, labelWidth)} ${padDisplay(value, valueWidth)} ${padDisplay(field.editable ? MCP_WORKSPACE_FORM_TEXT_EDIT : MCP_WORKSPACE_FORM_ACTION_EDIT, 12)}`,
|
|
149
279
|
selected,
|
|
150
280
|
fg: field.id === 'save' ? PALETTE.good : field.id === 'cancel' ? PALETTE.warn : field.editable ? PALETTE.text : PALETTE.info,
|
|
151
281
|
bold: selected,
|
|
@@ -162,19 +292,15 @@ function buildToolRows(workspace: McpWorkspace, width: number, height: number):
|
|
|
162
292
|
const toolWidth = Math.min(36, Math.max(18, Math.floor(width * 0.34)));
|
|
163
293
|
const serverWidth = Math.min(24, Math.max(12, Math.floor(width * 0.20)));
|
|
164
294
|
const descriptionWidth = Math.max(12, width - toolWidth - serverWidth - 8);
|
|
165
|
-
const label = workspace.loadingTools
|
|
166
|
-
? 'Tools: loading...'
|
|
167
|
-
: server
|
|
168
|
-
? `Tools for ${server}: ${tools.length}`
|
|
169
|
-
: `Tools: ${tools.length}`;
|
|
295
|
+
const label = mcpWorkspaceToolsLabel(workspace.loadingTools, server, tools.length);
|
|
170
296
|
const rows: WorkspaceRow[] = [
|
|
171
297
|
{ text: label, fg: PALETTE.subtitle, bold: true },
|
|
172
|
-
{ text: ` ${padDisplay(
|
|
298
|
+
{ text: ` ${padDisplay(MCP_WORKSPACE_TOOL_HEADER_TOOL, toolWidth)} ${padDisplay(MCP_WORKSPACE_TOOL_HEADER_SERVER, serverWidth)} ${padDisplay(MCP_WORKSPACE_TOOL_HEADER_DESCRIPTION, descriptionWidth)}`, fg: PALETTE.muted, bold: true },
|
|
173
299
|
];
|
|
174
300
|
|
|
175
301
|
if (tools.length === 0) {
|
|
176
302
|
rows.push({
|
|
177
|
-
text: workspace.loadingTools ?
|
|
303
|
+
text: workspace.loadingTools ? MCP_WORKSPACE_TOOLS_LOADING_DETAIL : MCP_WORKSPACE_TOOLS_EMPTY,
|
|
178
304
|
fg: PALETTE.muted,
|
|
179
305
|
dim: true,
|
|
180
306
|
});
|
|
@@ -194,7 +320,16 @@ function buildToolRows(workspace: McpWorkspace, width: number, height: number):
|
|
|
194
320
|
function buildDeleteRows(workspace: McpWorkspace, height: number): WorkspaceRow[] {
|
|
195
321
|
const rows: WorkspaceRow[] = [
|
|
196
322
|
{ text: `${GLYPHS.navigation.selected} Confirm remove ${workspace.editingServerName ?? '(unknown)'}`, selected: true, fg: PALETTE.bad, bold: true },
|
|
197
|
-
{ text:
|
|
323
|
+
{ text: MCP_WORKSPACE_CONFIRM_CANCEL_ROW, fg: PALETTE.muted },
|
|
324
|
+
];
|
|
325
|
+
while (rows.length < height) rows.push({ text: '', kind: 'empty' });
|
|
326
|
+
return rows.slice(0, height);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function buildReloadRows(height: number): WorkspaceRow[] {
|
|
330
|
+
const rows: WorkspaceRow[] = [
|
|
331
|
+
{ text: `${GLYPHS.navigation.selected} ${MCP_WORKSPACE_CONFIRM_RELOAD}`, selected: true, fg: PALETTE.warn, bold: true },
|
|
332
|
+
{ text: MCP_WORKSPACE_CONFIRM_CANCEL_ROW, fg: PALETTE.muted },
|
|
198
333
|
];
|
|
199
334
|
while (rows.length < height) rows.push({ text: '', kind: 'empty' });
|
|
200
335
|
return rows.slice(0, height);
|
|
@@ -203,31 +338,29 @@ function buildDeleteRows(workspace: McpWorkspace, height: number): WorkspaceRow[
|
|
|
203
338
|
function buildControlRows(workspace: McpWorkspace, width: number, height: number): WorkspaceRow[] {
|
|
204
339
|
if (workspace.mode === 'form') return buildFormRows(workspace, width, height);
|
|
205
340
|
if (workspace.mode === 'delete-confirm') return buildDeleteRows(workspace, height);
|
|
341
|
+
if (workspace.mode === 'reload-confirm') return buildReloadRows(height);
|
|
206
342
|
return buildToolRows(workspace, width, height);
|
|
207
343
|
}
|
|
208
344
|
|
|
209
345
|
function footerText(workspace: McpWorkspace): string {
|
|
210
|
-
if (workspace.mode === 'form') return
|
|
211
|
-
if (workspace.mode === 'delete-confirm') return
|
|
212
|
-
|
|
346
|
+
if (workspace.mode === 'form') return MCP_WORKSPACE_FOOTER_FORM;
|
|
347
|
+
if (workspace.mode === 'delete-confirm') return MCP_WORKSPACE_FOOTER_DELETE;
|
|
348
|
+
if (workspace.mode === 'reload-confirm') return MCP_WORKSPACE_FOOTER_RELOAD;
|
|
349
|
+
return MCP_WORKSPACE_FOOTER_BROWSE;
|
|
213
350
|
}
|
|
214
351
|
|
|
215
352
|
export function renderMcpWorkspace(workspace: McpWorkspace, width: number, height: number): Line[] {
|
|
216
353
|
const metrics = getFullscreenWorkspaceMetrics({ width, height });
|
|
217
354
|
const connected = workspace.servers.filter((server) => server.connected).length;
|
|
218
|
-
const stateLabel = workspace.mode
|
|
219
|
-
const mainHeader = workspace.mode
|
|
220
|
-
? 'MCP server command preview'
|
|
221
|
-
: workspace.mode === 'delete-confirm'
|
|
222
|
-
? 'MCP remove command'
|
|
223
|
-
: `Servers ${connected}/${workspace.servers.length} connected · Tools ${workspace.tools.length}`;
|
|
355
|
+
const stateLabel = mcpWorkspaceStateLabel(workspace.mode);
|
|
356
|
+
const mainHeader = mcpWorkspaceMainHeader(workspace.mode, connected, workspace.servers.length, workspace.tools.length);
|
|
224
357
|
|
|
225
358
|
return renderFullscreenWorkspace({
|
|
226
359
|
width,
|
|
227
360
|
height,
|
|
228
|
-
title:
|
|
361
|
+
title: MCP_WORKSPACE_TITLE,
|
|
229
362
|
stateLabel,
|
|
230
|
-
leftHeader:
|
|
363
|
+
leftHeader: MCP_WORKSPACE_LEFT_HEADER,
|
|
231
364
|
mainHeader,
|
|
232
365
|
leftRows: buildLeftRows(workspace, metrics.bodyRows),
|
|
233
366
|
contextRows: selectedDetailLines(workspace, metrics.contextWidth),
|
|
@@ -28,6 +28,22 @@ const MODE_TITLES: Record<string, string> = {
|
|
|
28
28
|
contextCap: 'Set Context Window',
|
|
29
29
|
};
|
|
30
30
|
|
|
31
|
+
const CONTEXT_WINDOW_SOURCE_LABELS = {
|
|
32
|
+
provider_api: 'provider catalog',
|
|
33
|
+
configured_cap: 'configured limit',
|
|
34
|
+
fallback: 'default limit',
|
|
35
|
+
registry: 'model registry',
|
|
36
|
+
} as const satisfies Readonly<Record<string, string>>;
|
|
37
|
+
|
|
38
|
+
type ContextWindowSourceKey = keyof typeof CONTEXT_WINDOW_SOURCE_LABELS;
|
|
39
|
+
|
|
40
|
+
function formatContextWindowSource(value: string | undefined): string {
|
|
41
|
+
const normalized = (value ?? '').trim().toLowerCase();
|
|
42
|
+
if (!normalized) return 'configured limit';
|
|
43
|
+
if (normalized in CONTEXT_WINDOW_SOURCE_LABELS) return CONTEXT_WINDOW_SOURCE_LABELS[normalized as ContextWindowSourceKey];
|
|
44
|
+
return normalized.replace(/[_-]+/g, ' ').replace(/\s+/g, ' ');
|
|
45
|
+
}
|
|
46
|
+
|
|
31
47
|
/**
|
|
32
48
|
* Number of fixed chrome lines in the model-picker overlay (title + search + divider + detail×2 + footer).
|
|
33
49
|
* Used by callers to compute maxVisible item rows.
|
|
@@ -42,6 +58,46 @@ function putRowText(line: Line, startX: number, maxWidth: number, text: string,
|
|
|
42
58
|
putOverlayText(line, startX, maxWidth, text, { fg, bg, bold, dim });
|
|
43
59
|
}
|
|
44
60
|
|
|
61
|
+
export function renderModelPickerPackageText(): string {
|
|
62
|
+
return [
|
|
63
|
+
...Object.values(MODE_TITLES),
|
|
64
|
+
'Search',
|
|
65
|
+
'Filter: All',
|
|
66
|
+
'Filter: Free',
|
|
67
|
+
'Filter: Paid',
|
|
68
|
+
'Filter: Sub',
|
|
69
|
+
'Group: provider',
|
|
70
|
+
'Group: family',
|
|
71
|
+
'Group: pricingTier',
|
|
72
|
+
'Group: qualityTier',
|
|
73
|
+
'No models available',
|
|
74
|
+
'No models match query',
|
|
75
|
+
'No providers available',
|
|
76
|
+
'No providers match query',
|
|
77
|
+
'Provider:',
|
|
78
|
+
'Context:',
|
|
79
|
+
'Reasoning:',
|
|
80
|
+
'Vision:',
|
|
81
|
+
'Tools:',
|
|
82
|
+
'Select a provider to browse its models',
|
|
83
|
+
'Context window (tokens):',
|
|
84
|
+
'Leave blank to use default',
|
|
85
|
+
'Model:',
|
|
86
|
+
'provider catalog',
|
|
87
|
+
'configured limit',
|
|
88
|
+
'default limit',
|
|
89
|
+
'model registry',
|
|
90
|
+
'configured via environment',
|
|
91
|
+
'configured via secret reference',
|
|
92
|
+
'configured via subscription',
|
|
93
|
+
'configured anonymously',
|
|
94
|
+
'[Up/Down] [Enter] [/] Search [Space] Ctx [Esc] [Tab] Filter [G] Group',
|
|
95
|
+
'[Enter] Confirm [Esc] Cancel',
|
|
96
|
+
'[Up/Down] Nav [Enter] Select [Esc] Cancel',
|
|
97
|
+
...Object.entries(EFFORT_DESCRIPTIONS).flatMap(([level, description]) => [level, description]),
|
|
98
|
+
].join('\n');
|
|
99
|
+
}
|
|
100
|
+
|
|
45
101
|
/**
|
|
46
102
|
* Render the model picker modal as Line[] for overlay in the viewport.
|
|
47
103
|
* Handles model, provider, and effort modes.
|
|
@@ -240,7 +296,6 @@ export function renderModelPickerOverlay(
|
|
|
240
296
|
if (caps.reasoning) capParts.push('Reasoning: \u2713');
|
|
241
297
|
if (caps.multimodal) capParts.push('Vision: \u2713');
|
|
242
298
|
if (caps.toolCalling) capParts.push('Tools: \u2713');
|
|
243
|
-
if (caps.codeEditing) capParts.push('Code: \u2713');
|
|
244
299
|
const capText = capParts.join(' ');
|
|
245
300
|
const capLine = createOverlayContentLine(width, layout, borderFg, DEFAULT_OVERLAY_PALETTE.bodyBg);
|
|
246
301
|
putRowText(capLine, layout.margin + 2, contentW, fitDisplay(truncateDisplay(capText, contentW), contentW), '244');
|
|
@@ -339,7 +394,7 @@ export function renderModelPickerOverlay(
|
|
|
339
394
|
const capModel = picker.contextCapPendingModel;
|
|
340
395
|
const modelName = capModel ? capModel.displayName : 'unknown';
|
|
341
396
|
const currentCtx = capModel ? fmtContext(capModel.contextWindow) : '?';
|
|
342
|
-
const
|
|
397
|
+
const sourceLabel = formatContextWindowSource(capModel?.contextWindowProvenance);
|
|
343
398
|
|
|
344
399
|
const promptLabel = 'Context window (tokens):';
|
|
345
400
|
const cursorChar = OVERLAY_GLYPHS.cursor;
|
|
@@ -350,7 +405,7 @@ export function renderModelPickerOverlay(
|
|
|
350
405
|
|
|
351
406
|
lines.push(createOverlayContentLine(width, layout, borderFg, DEFAULT_OVERLAY_PALETTE.bodyBg));
|
|
352
407
|
|
|
353
|
-
const hintText = `Leave blank to use default (current: ${currentCtx},
|
|
408
|
+
const hintText = `Leave blank to use default (current: ${currentCtx}, from ${sourceLabel})`;
|
|
354
409
|
const hintTrunc = getDisplayWidth(hintText) > contentW
|
|
355
410
|
? hintText.slice(0, contentW - 3) + '...'
|
|
356
411
|
: hintText;
|
|
@@ -33,6 +33,31 @@ const PALETTE = {
|
|
|
33
33
|
const renderCache = new WeakMap<ModelPickerModal, { key: string; lines: Line[] }>();
|
|
34
34
|
const objectIds = new WeakMap<object, number>();
|
|
35
35
|
let nextObjectId = 1;
|
|
36
|
+
const MODEL_WORKSPACE_TITLE = ' Model Workspace / Providers And Models ';
|
|
37
|
+
const MODEL_WORKSPACE_TARGETS_TITLE = 'Targets';
|
|
38
|
+
const MODEL_WORKSPACE_MODE_LABELS = {
|
|
39
|
+
provider: 'Provider list',
|
|
40
|
+
model: 'Model list',
|
|
41
|
+
effort: 'Reasoning effort',
|
|
42
|
+
contextCap: 'Context cap',
|
|
43
|
+
} as const;
|
|
44
|
+
const MODEL_WORKSPACE_TABLE_HEADERS = {
|
|
45
|
+
provider: 'Provider Configuration Catalog',
|
|
46
|
+
effort: 'Reasoning effort Meaning',
|
|
47
|
+
contextCap: 'Context cap input',
|
|
48
|
+
modelKey: 'Model key',
|
|
49
|
+
displayName: 'Display name',
|
|
50
|
+
providerColumn: 'Provider',
|
|
51
|
+
context: 'Context',
|
|
52
|
+
tier: 'Tier',
|
|
53
|
+
caps: 'Caps',
|
|
54
|
+
} as const;
|
|
55
|
+
const MODEL_WORKSPACE_REASONING_EFFORT_DETAIL = 'Reasoning effort applies to the main chat model. Select the default effort for this model.';
|
|
56
|
+
const MODEL_WORKSPACE_CONTEXT_CAP_DETAIL = 'Context cap overrides the detected local-model context window for this selection.';
|
|
57
|
+
const MODEL_WORKSPACE_CONTEXT_CAP_INPUT_HELP = 'Type digits to set a cap. Enter confirms; Esc returns to the model list.';
|
|
58
|
+
const MODEL_WORKSPACE_FOOTER_SEARCH_ACTIVE = 'Typing filters search; Esc clears search';
|
|
59
|
+
const MODEL_WORKSPACE_FOOTER_SEARCH_INACTIVE = '/ search';
|
|
60
|
+
const MODEL_WORKSPACE_FOOTER_CONTROLS = 'Up/Down navigate • Left/Right pane • Enter select • <search> • Tab price • C caps • A available • B benchmark • G group • Esc close';
|
|
36
61
|
|
|
37
62
|
function clamp(value: number, min: number, max: number): number {
|
|
38
63
|
return Math.max(min, Math.min(max, value));
|
|
@@ -164,6 +189,65 @@ function targetLabelFor(target: string): string {
|
|
|
164
189
|
return 'Main Chat';
|
|
165
190
|
}
|
|
166
191
|
|
|
192
|
+
function providerSelectionDetail(targetLabel: string): string {
|
|
193
|
+
return `Provider selection: choose a provider, then choose a model for ${targetLabel}.`;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function modelSelectionDetail(targetLabel: string): string {
|
|
197
|
+
return `Model selection: choose the model to store for ${targetLabel}. Use filters to narrow large catalogs.`;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function modelWorkspaceFilterText(
|
|
201
|
+
query: string,
|
|
202
|
+
price: string,
|
|
203
|
+
capability: string,
|
|
204
|
+
group: string,
|
|
205
|
+
availableOnly: string,
|
|
206
|
+
): string {
|
|
207
|
+
return `Search: ${query} | Price: ${price} | Capability: ${capability} | Group: ${group} | Available only: ${availableOnly}`;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function modelWorkspaceFooterControls(searchHint: string): string {
|
|
211
|
+
return MODEL_WORKSPACE_FOOTER_CONTROLS.replace('<search>', searchHint);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export function renderModelWorkspacePackageText(): string {
|
|
215
|
+
return [
|
|
216
|
+
MODEL_WORKSPACE_TITLE.trim(),
|
|
217
|
+
MODEL_WORKSPACE_TARGETS_TITLE,
|
|
218
|
+
MODEL_WORKSPACE_MODE_LABELS.provider,
|
|
219
|
+
MODEL_WORKSPACE_MODE_LABELS.model,
|
|
220
|
+
MODEL_WORKSPACE_MODE_LABELS.effort,
|
|
221
|
+
MODEL_WORKSPACE_MODE_LABELS.contextCap,
|
|
222
|
+
'Target: <target> (<state>)',
|
|
223
|
+
'Current: <route>',
|
|
224
|
+
providerSelectionDetail('<target>'),
|
|
225
|
+
'Selected provider: <provider>',
|
|
226
|
+
modelSelectionDetail('<target>'),
|
|
227
|
+
'Selected: <model> | <display> | context <context> | <capabilities>',
|
|
228
|
+
MODEL_WORKSPACE_REASONING_EFFORT_DETAIL,
|
|
229
|
+
MODEL_WORKSPACE_CONTEXT_CAP_DETAIL,
|
|
230
|
+
modelWorkspaceFilterText('<query>', '<price>', '<capability>', '<group>', '<available-only>'),
|
|
231
|
+
MODEL_WORKSPACE_TABLE_HEADERS.provider,
|
|
232
|
+
MODEL_WORKSPACE_TABLE_HEADERS.effort,
|
|
233
|
+
MODEL_WORKSPACE_TABLE_HEADERS.contextCap,
|
|
234
|
+
MODEL_WORKSPACE_TABLE_HEADERS.modelKey,
|
|
235
|
+
MODEL_WORKSPACE_TABLE_HEADERS.displayName,
|
|
236
|
+
MODEL_WORKSPACE_TABLE_HEADERS.providerColumn,
|
|
237
|
+
MODEL_WORKSPACE_TABLE_HEADERS.context,
|
|
238
|
+
MODEL_WORKSPACE_TABLE_HEADERS.tier,
|
|
239
|
+
MODEL_WORKSPACE_TABLE_HEADERS.caps,
|
|
240
|
+
'Model: <model>',
|
|
241
|
+
'Detected context: <context>',
|
|
242
|
+
'Override: <cap>',
|
|
243
|
+
MODEL_WORKSPACE_CONTEXT_CAP_INPUT_HELP,
|
|
244
|
+
'Focus targets',
|
|
245
|
+
'Focus list',
|
|
246
|
+
modelWorkspaceFooterControls(MODEL_WORKSPACE_FOOTER_SEARCH_ACTIVE),
|
|
247
|
+
modelWorkspaceFooterControls(MODEL_WORKSPACE_FOOTER_SEARCH_INACTIVE),
|
|
248
|
+
].join('\n');
|
|
249
|
+
}
|
|
250
|
+
|
|
167
251
|
function detailLines(picker: ModelPickerModal, width: number): string[] {
|
|
168
252
|
const target = picker.getSelectedTargetInfo();
|
|
169
253
|
const targetLabel = target?.label ?? targetLabelFor(picker.target);
|
|
@@ -174,26 +258,25 @@ function detailLines(picker: ModelPickerModal, width: number): string[] {
|
|
|
174
258
|
if (target) lines.push(`Current: ${targetSummary(target)}`);
|
|
175
259
|
if (picker.mode === 'provider') {
|
|
176
260
|
const provider = picker.getFilteredProviders()[picker.selectedIndex] ?? '';
|
|
177
|
-
lines.push(
|
|
261
|
+
lines.push(providerSelectionDetail(targetLabel));
|
|
178
262
|
if (provider) lines.push(`Selected provider: ${provider}`);
|
|
179
263
|
} else if (picker.mode === 'model') {
|
|
180
|
-
lines.push(
|
|
264
|
+
lines.push(modelSelectionDetail(targetLabel));
|
|
181
265
|
if (selected) {
|
|
182
266
|
const caps = selected.capabilities ?? {};
|
|
183
267
|
const capText = [
|
|
184
268
|
caps.reasoning ? 'reasoning' : '',
|
|
185
269
|
caps.multimodal ? 'vision' : '',
|
|
186
270
|
caps.toolCalling ? 'tools' : '',
|
|
187
|
-
caps.codeEditing ? 'code' : '',
|
|
188
271
|
].filter(Boolean).join(', ') || 'standard';
|
|
189
272
|
lines.push(`Selected: ${modelKey(selected)} | ${selected.displayName} | context ${formatContext(selected.contextWindow)} | ${capText}`);
|
|
190
273
|
}
|
|
191
274
|
} else if (picker.mode === 'effort') {
|
|
192
|
-
lines.push(
|
|
275
|
+
lines.push(MODEL_WORKSPACE_REASONING_EFFORT_DETAIL);
|
|
193
276
|
} else {
|
|
194
|
-
lines.push(
|
|
277
|
+
lines.push(MODEL_WORKSPACE_CONTEXT_CAP_DETAIL);
|
|
195
278
|
}
|
|
196
|
-
const filterText =
|
|
279
|
+
const filterText = modelWorkspaceFilterText(picker.query || '(none)', picker.categoryFilter, picker.capabilityFilter, picker.groupBy, picker.availableOnly ? 'yes' : 'no');
|
|
197
280
|
lines.push(filterText);
|
|
198
281
|
return lines.flatMap((line) => wrapText(line, Math.max(1, width)));
|
|
199
282
|
}
|
|
@@ -261,7 +344,6 @@ function renderModelRows(picker: ModelPickerModal, lines: Line[], rows: number,
|
|
|
261
344
|
caps.reasoning ? 'R' : '-',
|
|
262
345
|
caps.multimodal ? 'V' : '-',
|
|
263
346
|
caps.toolCalling ? 'T' : '-',
|
|
264
|
-
caps.codeEditing ? 'C' : '-',
|
|
265
347
|
].join('');
|
|
266
348
|
let x = startX + 1;
|
|
267
349
|
writeText(line, x, 2, padDisplay(marker, 2), { fg: PALETTE.text, bg, bold: selected }); x += 2;
|
|
@@ -295,7 +377,7 @@ function renderContextCapRows(picker: ModelPickerModal, lines: Line[], rows: num
|
|
|
295
377
|
`Model: ${model ? modelKey(model) : '(none)'}`,
|
|
296
378
|
`Detected context: ${formatContext(model?.contextWindow)}`,
|
|
297
379
|
`Override: ${input}`,
|
|
298
|
-
|
|
380
|
+
MODEL_WORKSPACE_CONTEXT_CAP_INPUT_HELP,
|
|
299
381
|
];
|
|
300
382
|
for (let row = 0; row < Math.min(rows, copy.length); row += 1) {
|
|
301
383
|
const line = lines[row]!;
|
|
@@ -308,15 +390,15 @@ function writeTableHeader(line: Line, picker: ModelPickerModal, startX: number,
|
|
|
308
390
|
fillRange(line, startX, startX + width - 1, PALETTE.footerBg);
|
|
309
391
|
const style = { fg: PALETTE.muted, bg: PALETTE.footerBg, bold: true };
|
|
310
392
|
if (picker.mode === 'provider') {
|
|
311
|
-
writeText(line, startX + 1, width - 2,
|
|
393
|
+
writeText(line, startX + 1, width - 2, MODEL_WORKSPACE_TABLE_HEADERS.provider, style);
|
|
312
394
|
return;
|
|
313
395
|
}
|
|
314
396
|
if (picker.mode === 'effort') {
|
|
315
|
-
writeText(line, startX + 1, width - 2,
|
|
397
|
+
writeText(line, startX + 1, width - 2, MODEL_WORKSPACE_TABLE_HEADERS.effort, style);
|
|
316
398
|
return;
|
|
317
399
|
}
|
|
318
400
|
if (picker.mode === 'contextCap') {
|
|
319
|
-
writeText(line, startX + 1, width - 2,
|
|
401
|
+
writeText(line, startX + 1, width - 2, MODEL_WORKSPACE_TABLE_HEADERS.contextCap, style);
|
|
320
402
|
return;
|
|
321
403
|
}
|
|
322
404
|
const providerW = clamp(Math.floor(width * 0.14), 10, 18);
|
|
@@ -326,12 +408,12 @@ function writeTableHeader(line: Line, picker: ModelPickerModal, startX: number,
|
|
|
326
408
|
const nameW = clamp(Math.floor(width * 0.28), 16, 36);
|
|
327
409
|
const keyW = Math.max(10, width - providerW - ctxW - tierW - capsW - nameW - 10);
|
|
328
410
|
let x = startX + 3;
|
|
329
|
-
writeText(line, x, keyW, padDisplay(
|
|
330
|
-
writeText(line, x, nameW, padDisplay(
|
|
331
|
-
writeText(line, x, providerW, padDisplay(
|
|
332
|
-
writeText(line, x, ctxW, padDisplay(
|
|
333
|
-
writeText(line, x, tierW, padDisplay(
|
|
334
|
-
writeText(line, x, capsW, padDisplay(
|
|
411
|
+
writeText(line, x, keyW, padDisplay(MODEL_WORKSPACE_TABLE_HEADERS.modelKey, keyW), style); x += keyW + 1;
|
|
412
|
+
writeText(line, x, nameW, padDisplay(MODEL_WORKSPACE_TABLE_HEADERS.displayName, nameW), style); x += nameW + 1;
|
|
413
|
+
writeText(line, x, providerW, padDisplay(MODEL_WORKSPACE_TABLE_HEADERS.providerColumn, providerW), style); x += providerW + 1;
|
|
414
|
+
writeText(line, x, ctxW, padDisplay(MODEL_WORKSPACE_TABLE_HEADERS.context, ctxW), style); x += ctxW + 1;
|
|
415
|
+
writeText(line, x, tierW, padDisplay(MODEL_WORKSPACE_TABLE_HEADERS.tier, tierW), style); x += tierW + 1;
|
|
416
|
+
writeText(line, x, capsW, padDisplay(MODEL_WORKSPACE_TABLE_HEADERS.caps, capsW), style);
|
|
335
417
|
}
|
|
336
418
|
|
|
337
419
|
export function renderModelWorkspace(picker: ModelPickerModal, width: number, viewportHeight: number): Line[] {
|
|
@@ -347,13 +429,13 @@ export function renderModelWorkspace(picker: ModelPickerModal, width: number, vi
|
|
|
347
429
|
const contentW = Math.max(1, safeWidth - contentX - 1);
|
|
348
430
|
|
|
349
431
|
const top = borderLine(safeWidth, GLYPHS.frame.topLeft, GLYPHS.frame.horizontal, GLYPHS.frame.topRight);
|
|
350
|
-
writeText(top, 2, safeWidth - 4,
|
|
432
|
+
writeText(top, 2, safeWidth - 4, MODEL_WORKSPACE_TITLE, { fg: PALETTE.title, bold: true });
|
|
351
433
|
lines.push(top);
|
|
352
434
|
|
|
353
435
|
const header = contentLine(safeWidth, PALETTE.footerBg);
|
|
354
|
-
writeText(header, 2, targetW - 2,
|
|
436
|
+
writeText(header, 2, targetW - 2, MODEL_WORKSPACE_TARGETS_TITLE, { fg: PALETTE.subtitle, bold: true, bg: PALETTE.footerBg });
|
|
355
437
|
drawVertical(header, targetW, PALETTE.footerBg);
|
|
356
|
-
const modeLabel = picker.mode
|
|
438
|
+
const modeLabel = MODEL_WORKSPACE_MODE_LABELS[picker.mode];
|
|
357
439
|
writeText(header, contentX + 1, contentW - 2, `${modeLabel} • ${picker.getItemCount()} item(s)`, { fg: PALETTE.subtitle, bold: true, bg: PALETTE.footerBg });
|
|
358
440
|
lines.push(header);
|
|
359
441
|
|
|
@@ -402,8 +484,8 @@ export function renderModelWorkspace(picker: ModelPickerModal, width: number, vi
|
|
|
402
484
|
|
|
403
485
|
const footer = contentLine(safeWidth, PALETTE.footerBg);
|
|
404
486
|
const targetHint = picker.focusPane === 'targets' ? 'Focus targets' : 'Focus list';
|
|
405
|
-
const searchHint = picker.searchFocused ?
|
|
406
|
-
const hints = `${targetHint} •
|
|
487
|
+
const searchHint = picker.searchFocused ? MODEL_WORKSPACE_FOOTER_SEARCH_ACTIVE : MODEL_WORKSPACE_FOOTER_SEARCH_INACTIVE;
|
|
488
|
+
const hints = `${targetHint} • ${modelWorkspaceFooterControls(searchHint)}`;
|
|
407
489
|
writeText(footer, 2, safeWidth - 4, hints, { fg: PALETTE.muted, bg: PALETTE.footerBg });
|
|
408
490
|
lines.push(footer);
|
|
409
491
|
lines.push(borderLine(safeWidth, GLYPHS.frame.bottomLeft, GLYPHS.frame.horizontal, GLYPHS.frame.bottomRight));
|