@compilr-dev/cli 0.4.0 → 0.5.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/README.md +30 -12
- package/dist/agent.d.ts +74 -1
- package/dist/agent.js +259 -76
- package/dist/anchors/index.d.ts +9 -0
- package/dist/anchors/index.js +9 -0
- package/dist/anchors/project-anchors.d.ts +79 -0
- package/dist/anchors/project-anchors.js +202 -0
- package/dist/commands/handler-types.d.ts +68 -0
- package/dist/commands/handler-types.js +8 -0
- package/dist/commands/handlers/agent-commands.d.ts +13 -0
- package/dist/commands/handlers/agent-commands.js +305 -0
- package/dist/commands/handlers/design-commands.d.ts +15 -0
- package/dist/commands/handlers/design-commands.js +334 -0
- package/dist/commands/handlers/index.d.ts +20 -0
- package/dist/commands/handlers/index.js +43 -0
- package/dist/commands/handlers/overlay-commands.d.ts +21 -0
- package/dist/commands/handlers/overlay-commands.js +287 -0
- package/dist/commands/handlers/project-commands.d.ts +11 -0
- package/dist/commands/handlers/project-commands.js +167 -0
- package/dist/commands/handlers/simple-commands.d.ts +19 -0
- package/dist/commands/handlers/simple-commands.js +144 -0
- package/dist/commands/index.d.ts +2 -1
- package/dist/commands/registry.d.ts +50 -0
- package/dist/commands/registry.js +75 -0
- package/dist/commands-v2/handlers/context.d.ts +13 -0
- package/dist/commands-v2/handlers/context.js +348 -0
- package/dist/commands-v2/handlers/core.d.ts +13 -0
- package/dist/commands-v2/handlers/core.js +165 -0
- package/dist/commands-v2/handlers/debug.d.ts +11 -0
- package/dist/commands-v2/handlers/debug.js +159 -0
- package/dist/commands-v2/handlers/index.d.ts +12 -0
- package/dist/commands-v2/handlers/index.js +24 -0
- package/dist/commands-v2/handlers/project.d.ts +22 -0
- package/dist/commands-v2/handlers/project.js +814 -0
- package/dist/commands-v2/handlers/settings.d.ts +15 -0
- package/dist/commands-v2/handlers/settings.js +235 -0
- package/dist/commands-v2/index.d.ts +13 -0
- package/dist/commands-v2/index.js +15 -0
- package/dist/commands-v2/registry.d.ts +37 -0
- package/dist/commands-v2/registry.js +80 -0
- package/dist/commands-v2/types.d.ts +75 -0
- package/dist/commands-v2/types.js +7 -0
- package/dist/commands.js +110 -7
- package/dist/index.js +288 -29
- package/dist/input-handlers/index.d.ts +7 -0
- package/dist/input-handlers/index.js +7 -0
- package/dist/input-handlers/memory-handler.d.ts +26 -0
- package/dist/input-handlers/memory-handler.js +68 -0
- package/dist/repl-helpers.d.ts +63 -0
- package/dist/repl-helpers.js +318 -0
- package/dist/repl-v2.d.ts +155 -0
- package/dist/repl-v2.js +774 -0
- package/dist/repl.d.ts +32 -4
- package/dist/repl.js +250 -977
- package/dist/settings/index.d.ts +23 -0
- package/dist/settings/index.js +48 -0
- package/dist/settings/paths.d.ts +110 -0
- package/dist/settings/paths.js +264 -0
- package/dist/templates/compilr-md.js +7 -4
- package/dist/templates/index.js +3 -4
- package/dist/themes/colors.js +3 -1
- package/dist/themes/registry.d.ts +5 -36
- package/dist/themes/registry.js +11 -95
- package/dist/themes/types.d.ts +3 -38
- package/dist/themes/types.js +2 -2
- package/dist/tools/anchor-tools.d.ts +31 -0
- package/dist/tools/anchor-tools.js +255 -0
- package/dist/tools/backlog-wrappers.d.ts +54 -0
- package/dist/tools/backlog-wrappers.js +338 -0
- package/dist/tools/backlog.js +1 -1
- package/dist/tools/db-tools.d.ts +65 -0
- package/dist/tools/db-tools.js +19 -0
- package/dist/tools/document-db.d.ts +43 -0
- package/dist/tools/document-db.js +220 -0
- package/dist/tools/project-db.d.ts +102 -0
- package/dist/tools/project-db.js +370 -0
- package/dist/tools/workitem-db.d.ts +103 -0
- package/dist/tools/workitem-db.js +549 -0
- package/dist/tools.js +13 -3
- package/dist/ui/agents-overlay-v2.d.ts +43 -0
- package/dist/ui/agents-overlay-v2.js +809 -0
- package/dist/ui/agents-overlay.d.ts +5 -5
- package/dist/ui/agents-overlay.js +782 -420
- package/dist/ui/anchors-overlay.d.ts +12 -0
- package/dist/ui/anchors-overlay.js +775 -0
- package/dist/ui/arch-type-overlay.d.ts +1 -6
- package/dist/ui/arch-type-overlay.js +175 -203
- package/dist/ui/ask-user-overlay-v2.d.ts +26 -0
- package/dist/ui/ask-user-overlay-v2.js +555 -0
- package/dist/ui/ask-user-overlay.d.ts +2 -2
- package/dist/ui/ask-user-overlay.js +443 -535
- package/dist/ui/ask-user-simple-overlay-v2.d.ts +25 -0
- package/dist/ui/ask-user-simple-overlay-v2.js +215 -0
- package/dist/ui/ask-user-simple-overlay.d.ts +2 -2
- package/dist/ui/ask-user-simple-overlay.js +182 -209
- package/dist/ui/backlog-overlay.d.ts +16 -1
- package/dist/ui/backlog-overlay.js +525 -659
- package/dist/ui/base/index.d.ts +26 -0
- package/dist/ui/base/index.js +33 -0
- package/dist/ui/base/inline-overlay-utils.d.ts +217 -0
- package/dist/ui/base/inline-overlay-utils.js +320 -0
- package/dist/ui/base/inline-overlay.d.ts +159 -0
- package/dist/ui/base/inline-overlay.js +257 -0
- package/dist/ui/base/key-utils.d.ts +15 -0
- package/dist/ui/base/key-utils.js +30 -0
- package/dist/ui/base/overlay-base-v2.d.ts +193 -0
- package/dist/ui/base/overlay-base-v2.js +246 -0
- package/dist/ui/base/overlay-base.d.ts +156 -0
- package/dist/ui/base/overlay-base.js +238 -0
- package/dist/ui/base/overlay-lifecycle.d.ts +65 -0
- package/dist/ui/base/overlay-lifecycle.js +159 -0
- package/dist/ui/base/overlay-types.d.ts +185 -0
- package/dist/ui/base/overlay-types.js +7 -0
- package/dist/ui/base/render-utils.d.ts +8 -0
- package/dist/ui/base/render-utils.js +11 -0
- package/dist/ui/base/screen-stack.d.ts +148 -0
- package/dist/ui/base/screen-stack.js +184 -0
- package/dist/ui/base/tabbed-list-overlay-v2.d.ts +103 -0
- package/dist/ui/base/tabbed-list-overlay-v2.js +317 -0
- package/dist/ui/base/tabbed-list-overlay.d.ts +153 -0
- package/dist/ui/base/tabbed-list-overlay.js +369 -0
- package/dist/ui/commands-overlay-v2.d.ts +33 -0
- package/dist/ui/commands-overlay-v2.js +441 -0
- package/dist/ui/commands-overlay.d.ts +7 -2
- package/dist/ui/commands-overlay.js +384 -355
- package/dist/ui/config-overlay.d.ts +5 -4
- package/dist/ui/config-overlay.js +243 -513
- package/dist/ui/conversation.d.ts +75 -4
- package/dist/ui/conversation.js +374 -161
- package/dist/ui/docs-overlay.d.ts +17 -0
- package/dist/ui/docs-overlay.js +303 -0
- package/dist/ui/ephemeral.d.ts +1 -1
- package/dist/ui/ephemeral.js +1 -1
- package/dist/ui/features/index.d.ts +34 -0
- package/dist/ui/features/index.js +34 -0
- package/dist/ui/features/input-feature.d.ts +85 -0
- package/dist/ui/features/input-feature.js +238 -0
- package/dist/ui/features/list-feature.d.ts +155 -0
- package/dist/ui/features/list-feature.js +244 -0
- package/dist/ui/features/pagination-feature.d.ts +154 -0
- package/dist/ui/features/pagination-feature.js +238 -0
- package/dist/ui/features/search-feature.d.ts +148 -0
- package/dist/ui/features/search-feature.js +185 -0
- package/dist/ui/features/tab-feature.d.ts +194 -0
- package/dist/ui/features/tab-feature.js +307 -0
- package/dist/ui/footer-v2.d.ts +222 -0
- package/dist/ui/footer-v2.js +1349 -0
- package/dist/ui/footer.d.ts +107 -0
- package/dist/ui/footer.js +359 -67
- package/dist/ui/guardrail-overlay.d.ts +29 -0
- package/dist/ui/guardrail-overlay.js +145 -0
- package/dist/ui/help-overlay-v2.d.ts +34 -0
- package/dist/ui/help-overlay-v2.js +309 -0
- package/dist/ui/help-overlay.d.ts +16 -0
- package/dist/ui/help-overlay.js +316 -0
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.js +1 -3
- package/dist/ui/init-overlay-v2.d.ts +34 -0
- package/dist/ui/init-overlay-v2.js +600 -0
- package/dist/ui/init-overlay.d.ts +12 -2
- package/dist/ui/init-overlay.js +349 -270
- package/dist/ui/input-prompt-v2.d.ts +1 -0
- package/dist/ui/input-prompt-v2.js +14 -6
- package/dist/ui/input-prompt.d.ts +116 -33
- package/dist/ui/input-prompt.js +536 -337
- package/dist/ui/iteration-limit-overlay-v2.d.ts +21 -0
- package/dist/ui/iteration-limit-overlay-v2.js +114 -0
- package/dist/ui/iteration-limit-overlay.d.ts +2 -2
- package/dist/ui/iteration-limit-overlay.js +92 -128
- package/dist/ui/keys-overlay-v2.d.ts +41 -0
- package/dist/ui/keys-overlay-v2.js +248 -0
- package/dist/ui/keys-overlay.d.ts +1 -0
- package/dist/ui/keys-overlay.js +203 -141
- package/dist/ui/line-utils.d.ts +88 -0
- package/dist/ui/line-utils.js +150 -0
- package/dist/ui/live-region.d.ts +161 -0
- package/dist/ui/live-region.js +387 -0
- package/dist/ui/mascot/expressions.d.ts +32 -0
- package/dist/ui/mascot/expressions.js +213 -0
- package/dist/ui/mascot/index.d.ts +8 -0
- package/dist/ui/mascot/index.js +8 -0
- package/dist/ui/mascot/renderer.d.ts +19 -0
- package/dist/ui/mascot/renderer.js +97 -0
- package/dist/ui/mascot-overlay-v2.d.ts +41 -0
- package/dist/ui/mascot-overlay-v2.js +138 -0
- package/dist/ui/mascot-overlay.d.ts +21 -0
- package/dist/ui/mascot-overlay.js +146 -0
- package/dist/ui/model-overlay-v2.d.ts +49 -0
- package/dist/ui/model-overlay-v2.js +118 -0
- package/dist/ui/model-overlay.d.ts +27 -0
- package/dist/ui/model-overlay.js +221 -0
- package/dist/ui/model-warning-overlay.js +3 -5
- package/dist/ui/new-overlay.d.ts +34 -0
- package/dist/ui/new-overlay.js +604 -0
- package/dist/ui/overlay/impl/agents-overlay-v2.d.ts +45 -0
- package/dist/ui/overlay/impl/agents-overlay-v2.js +825 -0
- package/dist/ui/overlay/impl/anchors-overlay-v2.d.ts +47 -0
- package/dist/ui/overlay/impl/anchors-overlay-v2.js +783 -0
- package/dist/ui/overlay/impl/arch-type-overlay-v2.d.ts +37 -0
- package/dist/ui/overlay/impl/arch-type-overlay-v2.js +240 -0
- package/dist/ui/overlay/impl/ask-user-overlay-v2.d.ts +72 -0
- package/dist/ui/overlay/impl/ask-user-overlay-v2.js +584 -0
- package/dist/ui/overlay/impl/ask-user-simple-overlay-v2.d.ts +46 -0
- package/dist/ui/overlay/impl/ask-user-simple-overlay-v2.js +204 -0
- package/dist/ui/overlay/impl/backlog-overlay-v2.d.ts +49 -0
- package/dist/ui/overlay/impl/backlog-overlay-v2.js +642 -0
- package/dist/ui/overlay/impl/commands-overlay-v2.d.ts +33 -0
- package/dist/ui/overlay/impl/commands-overlay-v2.js +441 -0
- package/dist/ui/overlay/impl/config-overlay-v2.d.ts +100 -0
- package/dist/ui/overlay/impl/config-overlay-v2.js +654 -0
- package/dist/ui/overlay/impl/dashboard-overlay-v2.d.ts +55 -0
- package/dist/ui/overlay/impl/dashboard-overlay-v2.js +359 -0
- package/dist/ui/overlay/impl/docs-overlay-v2.d.ts +45 -0
- package/dist/ui/overlay/impl/docs-overlay-v2.js +114 -0
- package/dist/ui/overlay/impl/document-detail-overlay-v2.d.ts +77 -0
- package/dist/ui/overlay/impl/document-detail-overlay-v2.js +1071 -0
- package/dist/ui/overlay/impl/guardrail-overlay-v2.d.ts +43 -0
- package/dist/ui/overlay/impl/guardrail-overlay-v2.js +114 -0
- package/dist/ui/overlay/impl/help-overlay-v2.d.ts +34 -0
- package/dist/ui/overlay/impl/help-overlay-v2.js +309 -0
- package/dist/ui/overlay/impl/init-overlay-v2.d.ts +77 -0
- package/dist/ui/overlay/impl/init-overlay-v2.js +593 -0
- package/dist/ui/overlay/impl/init-setup-overlay-v2.d.ts +25 -0
- package/dist/ui/overlay/impl/init-setup-overlay-v2.js +97 -0
- package/dist/ui/overlay/impl/iteration-limit-overlay-v2.d.ts +35 -0
- package/dist/ui/overlay/impl/iteration-limit-overlay-v2.js +105 -0
- package/dist/ui/overlay/impl/keys-overlay-v2.d.ts +41 -0
- package/dist/ui/overlay/impl/keys-overlay-v2.js +248 -0
- package/dist/ui/overlay/impl/mascot-overlay-v2.d.ts +41 -0
- package/dist/ui/overlay/impl/mascot-overlay-v2.js +138 -0
- package/dist/ui/overlay/impl/model-overlay-v2.d.ts +49 -0
- package/dist/ui/overlay/impl/model-overlay-v2.js +118 -0
- package/dist/ui/overlay/impl/model-warning-overlay-v2.d.ts +46 -0
- package/dist/ui/overlay/impl/model-warning-overlay-v2.js +132 -0
- package/dist/ui/overlay/impl/new-overlay-v2.d.ts +77 -0
- package/dist/ui/overlay/impl/new-overlay-v2.js +593 -0
- package/dist/ui/overlay/impl/permission-overlay-v2.d.ts +36 -0
- package/dist/ui/overlay/impl/permission-overlay-v2.js +380 -0
- package/dist/ui/overlay/impl/projects-overlay-v2.d.ts +36 -0
- package/dist/ui/overlay/impl/projects-overlay-v2.js +499 -0
- package/dist/ui/overlay/impl/theme-overlay-v2.d.ts +42 -0
- package/dist/ui/overlay/impl/theme-overlay-v2.js +135 -0
- package/dist/ui/overlay/impl/tools-overlay-v2.d.ts +47 -0
- package/dist/ui/overlay/impl/tools-overlay-v2.js +218 -0
- package/dist/ui/overlay/impl/tutorial-overlay-v2.d.ts +31 -0
- package/dist/ui/overlay/impl/tutorial-overlay-v2.js +1035 -0
- package/dist/ui/overlay/impl/workflow-overlay-v2.d.ts +80 -0
- package/dist/ui/overlay/impl/workflow-overlay-v2.js +637 -0
- package/dist/ui/overlay/index.d.ts +33 -0
- package/dist/ui/overlay/index.js +35 -0
- package/dist/ui/overlay/key-utils.d.ts +6 -0
- package/dist/ui/overlay/key-utils.js +6 -0
- package/dist/ui/overlay/overlay-types.d.ts +128 -0
- package/dist/ui/overlay/overlay-types.js +22 -0
- package/dist/ui/overlay/types.d.ts +135 -0
- package/dist/ui/overlay/types.js +22 -0
- package/dist/ui/overlays/help-overlay-v2.d.ts +28 -0
- package/dist/ui/overlays/help-overlay-v2.js +198 -0
- package/dist/ui/overlays/index.d.ts +11 -0
- package/dist/ui/overlays/index.js +11 -0
- package/dist/ui/overlays.d.ts +0 -4
- package/dist/ui/overlays.js +0 -444
- package/dist/ui/permission-overlay-v2.d.ts +36 -0
- package/dist/ui/permission-overlay-v2.js +380 -0
- package/dist/ui/permission-overlay.d.ts +1 -1
- package/dist/ui/permission-overlay.js +186 -298
- package/dist/ui/projects-overlay.d.ts +19 -0
- package/dist/ui/projects-overlay.js +484 -0
- package/dist/ui/providers/types.d.ts +178 -0
- package/dist/ui/providers/types.js +9 -0
- package/dist/ui/render-modes.d.ts +36 -0
- package/dist/ui/render-modes.js +44 -0
- package/dist/ui/startup-menu.d.ts +36 -0
- package/dist/ui/startup-menu.js +236 -0
- package/dist/ui/subagent-renderer.d.ts +117 -0
- package/dist/ui/subagent-renderer.js +334 -0
- package/dist/ui/terminal-codes.d.ts +94 -0
- package/dist/ui/terminal-codes.js +124 -0
- package/dist/ui/terminal-renderer.d.ts +221 -0
- package/dist/ui/terminal-renderer.js +751 -0
- package/dist/ui/terminal-ui.d.ts +463 -0
- package/dist/ui/terminal-ui.js +2296 -0
- package/dist/ui/terminal.d.ts +20 -0
- package/dist/ui/terminal.js +72 -0
- package/dist/ui/theme-overlay-v2.d.ts +42 -0
- package/dist/ui/theme-overlay-v2.js +135 -0
- package/dist/ui/theme-overlay.d.ts +24 -0
- package/dist/ui/theme-overlay.js +127 -0
- package/dist/ui/todo-zone.js +53 -25
- package/dist/ui/tool-formatters.d.ts +16 -0
- package/dist/ui/tool-formatters.js +516 -0
- package/dist/ui/tools-overlay-v2.d.ts +47 -0
- package/dist/ui/tools-overlay-v2.js +218 -0
- package/dist/ui/tools-overlay.d.ts +10 -2
- package/dist/ui/tools-overlay.js +172 -220
- package/dist/ui/tutorial-overlay-v2.d.ts +31 -0
- package/dist/ui/tutorial-overlay-v2.js +1035 -0
- package/dist/ui/tutorial-overlay.d.ts +1 -0
- package/dist/ui/tutorial-overlay.js +400 -302
- package/dist/ui/workflow-overlay.d.ts +22 -0
- package/dist/ui/workflow-overlay.js +636 -0
- package/dist/utils/debug-log.d.ts +28 -0
- package/dist/utils/debug-log.js +57 -0
- package/dist/utils/model-tiers.js +1 -1
- package/dist/utils/path-safety.d.ts +56 -0
- package/dist/utils/path-safety.js +239 -0
- package/dist/workflow/guided-mode-injector.d.ts +42 -0
- package/dist/workflow/guided-mode-injector.js +191 -0
- package/dist/workflow/index.d.ts +8 -0
- package/dist/workflow/index.js +8 -0
- package/dist/workflow/step-criteria.d.ts +62 -0
- package/dist/workflow/step-criteria.js +150 -0
- package/dist/workflow/step-tracker.d.ts +92 -0
- package/dist/workflow/step-tracker.js +141 -0
- package/package.json +12 -5
|
@@ -1,37 +1,34 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Config Overlay
|
|
3
3
|
*
|
|
4
|
-
* Claude Code-style settings overlay with
|
|
4
|
+
* Claude Code-style settings overlay with 4 tabs:
|
|
5
5
|
* - Status: Read-only info (version, model, provider, cwd, session)
|
|
6
6
|
* - Config: Interactive settings (toggle/cycle with Enter/Space)
|
|
7
|
-
* -
|
|
7
|
+
* - Paths: Path configuration and safety settings
|
|
8
|
+
* - Usage: Usage statistics with progress bars
|
|
8
9
|
*
|
|
9
|
-
*
|
|
10
|
+
* Theme, Model, and Mascot selection are delegated to standalone overlays.
|
|
10
11
|
*/
|
|
11
12
|
import chalk from 'chalk';
|
|
12
13
|
import * as fs from 'fs';
|
|
13
14
|
import * as path from 'path';
|
|
14
15
|
import * as terminal from './terminal.js';
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
16
|
+
import { isEscape, isTab, isShiftTab, isEnter, isSpace, isCtrlC, isQuit, isNavigateUp, isNavigateDown, isBackspace, getNumberKey, isPrintable, extractPrintable, } from './base/key-utils.js';
|
|
17
|
+
import { getCurrentTheme, getStyles, } from '../themes/index.js';
|
|
18
|
+
import { getSettings, setSetting, permissionModeToDisplay, displayToPermissionMode, notificationModeToDisplay, displayToNotificationMode, projectStartupModeToDisplay, displayToProjectStartupMode, } from '../settings/index.js';
|
|
19
|
+
import { getResolvedPathConfig, setDeleteProtection, setProjectMatchRequired, setWorkspacePath, setProjectsPath, setDataPath, } from '../settings/paths.js';
|
|
20
|
+
import { pauseForOverlay, resumeAfterOverlay } from './overlay-controller.js';
|
|
21
|
+
import { MASCOT_LABELS, } from './mascot/index.js';
|
|
18
22
|
// =============================================================================
|
|
19
23
|
// Constants
|
|
20
24
|
// =============================================================================
|
|
21
|
-
const VERSION = '
|
|
22
|
-
const THEME_PAGE_SIZE = 12;
|
|
25
|
+
const VERSION = '0.4.0';
|
|
23
26
|
const TABS = [
|
|
24
27
|
{ id: 'status', label: 'Status' },
|
|
25
28
|
{ id: 'config', label: 'Config' },
|
|
29
|
+
{ id: 'paths', label: 'Paths' },
|
|
26
30
|
{ id: 'usage', label: 'Usage' },
|
|
27
31
|
];
|
|
28
|
-
// Provider tabs for model selector
|
|
29
|
-
const MODEL_PROVIDER_TABS = [
|
|
30
|
-
{ id: 'claude', label: 'Claude' },
|
|
31
|
-
{ id: 'openai', label: 'OpenAI' },
|
|
32
|
-
{ id: 'gemini', label: 'Gemini' },
|
|
33
|
-
{ id: 'ollama', label: 'Ollama' },
|
|
34
|
-
];
|
|
35
32
|
const MODEL_OPTIONS = [
|
|
36
33
|
// Claude
|
|
37
34
|
{ id: 'claude-sonnet-4-20250514', name: 'Sonnet 4', description: 'Best for everyday tasks', provider: 'claude' },
|
|
@@ -49,9 +46,6 @@ const MODEL_OPTIONS = [
|
|
|
49
46
|
{ id: 'mistral', name: 'Mistral', description: 'Local model', provider: 'ollama' },
|
|
50
47
|
{ id: 'codellama', name: 'Code Llama', description: 'Code-focused local model', provider: 'ollama' },
|
|
51
48
|
];
|
|
52
|
-
function getModelsForProvider(providerId) {
|
|
53
|
-
return MODEL_OPTIONS.filter(m => m.provider === providerId);
|
|
54
|
-
}
|
|
55
49
|
// =============================================================================
|
|
56
50
|
// Config Items (loaded from settings)
|
|
57
51
|
// =============================================================================
|
|
@@ -99,6 +93,21 @@ function getConfigItems(currentModel) {
|
|
|
99
93
|
options: ['normal', 'vim', 'emacs'],
|
|
100
94
|
},
|
|
101
95
|
{ id: 'autoInstall', label: 'Auto-install IDE extension', type: 'boolean', value: settings.autoInstall },
|
|
96
|
+
{
|
|
97
|
+
id: 'startupMode',
|
|
98
|
+
label: 'Startup behavior',
|
|
99
|
+
type: 'cycle',
|
|
100
|
+
value: settings.startupMode === 'menu' ? 'Show menu' : 'Direct to REPL',
|
|
101
|
+
options: ['Show menu', 'Direct to REPL'],
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
id: 'projectStartup',
|
|
105
|
+
label: 'Auto-open project',
|
|
106
|
+
type: 'cycle',
|
|
107
|
+
value: projectStartupModeToDisplay(settings.projectStartup),
|
|
108
|
+
options: ['Last opened', 'Off'],
|
|
109
|
+
},
|
|
110
|
+
{ id: 'mascot', label: 'Mascot', type: 'submenu', value: MASCOT_LABELS[settings.mascot] },
|
|
102
111
|
];
|
|
103
112
|
}
|
|
104
113
|
// Unused helper function - removed to fix lint error
|
|
@@ -131,7 +140,7 @@ function renderHeader(state) {
|
|
|
131
140
|
tabLine += s.muted(` ${tab.label} `) + ' ';
|
|
132
141
|
}
|
|
133
142
|
}
|
|
134
|
-
tabLine += s.muted('(
|
|
143
|
+
tabLine += s.muted('(Tab · 1-4)');
|
|
135
144
|
lines.push(tabLine);
|
|
136
145
|
lines.push('');
|
|
137
146
|
return lines;
|
|
@@ -233,216 +242,93 @@ function renderProgressBar(value, width) {
|
|
|
233
242
|
return color('█'.repeat(filled)) + s.muted('░'.repeat(empty));
|
|
234
243
|
}
|
|
235
244
|
// =============================================================================
|
|
236
|
-
// Rendering -
|
|
245
|
+
// Rendering - Paths Tab
|
|
237
246
|
// =============================================================================
|
|
238
|
-
function
|
|
239
|
-
const s = getStyles();
|
|
240
|
-
const lines = [];
|
|
241
|
-
lines.push('');
|
|
242
|
-
if (state.currentTab === 1) {
|
|
243
|
-
// Config tab
|
|
244
|
-
lines.push(s.muted(' Enter/Space to change · Esc to exit'));
|
|
245
|
-
}
|
|
246
|
-
else {
|
|
247
|
-
lines.push(s.muted(' Esc to exit'));
|
|
248
|
-
}
|
|
249
|
-
return lines;
|
|
250
|
-
}
|
|
251
|
-
// =============================================================================
|
|
252
|
-
// Rendering - Theme Selector (Curated)
|
|
253
|
-
// =============================================================================
|
|
254
|
-
function buildThemeCuratedLines(state) {
|
|
247
|
+
function renderPathsTab(state) {
|
|
255
248
|
const s = getStyles();
|
|
256
249
|
const lines = [];
|
|
250
|
+
const pathConfig = getResolvedPathConfig();
|
|
257
251
|
const cols = terminal.getTerminalWidth();
|
|
258
|
-
|
|
259
|
-
const
|
|
260
|
-
|
|
252
|
+
// Layout constants
|
|
253
|
+
const labelWidth = 24;
|
|
254
|
+
const valueWidth = Math.max(30, cols - labelWidth - 8);
|
|
255
|
+
lines.push(chalk.bold(' Path Configuration'));
|
|
261
256
|
lines.push('');
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
lines.push('');
|
|
266
|
-
// Show curated themes
|
|
267
|
-
for (let i = 0; i < state.curatedThemes.length; i++) {
|
|
268
|
-
const theme = state.curatedThemes[i];
|
|
269
|
-
const isSelected = i === state.themeSelectedIndex;
|
|
270
|
-
const isCurrent = theme.id === currentTheme.id;
|
|
257
|
+
// Helper to render a path item
|
|
258
|
+
const renderPathItem = (index, label, value) => {
|
|
259
|
+
const isSelected = state.pathSelectedItem === index;
|
|
271
260
|
const prefix = isSelected ? s.primary(' ❯ ') : ' ';
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
const previewTheme = state.themeSelectedIndex < state.curatedThemes.length
|
|
291
|
-
? state.curatedThemes[state.themeSelectedIndex]
|
|
292
|
-
: currentTheme;
|
|
293
|
-
lines.push(...renderThemePreview(previewTheme));
|
|
294
|
-
lines.push('');
|
|
295
|
-
lines.push(s.muted(' ↑↓ Navigate · 1-9,0 Quick select · Enter Select · Esc Back'));
|
|
296
|
-
return lines;
|
|
297
|
-
}
|
|
298
|
-
// =============================================================================
|
|
299
|
-
// Rendering - Theme Selector (Browse All)
|
|
300
|
-
// =============================================================================
|
|
301
|
-
function buildThemeBrowseLines(state) {
|
|
302
|
-
const s = getStyles();
|
|
303
|
-
const lines = [];
|
|
304
|
-
const cols = terminal.getTerminalWidth();
|
|
305
|
-
const currentTheme = getCurrentTheme();
|
|
306
|
-
const counts = getThemeCount();
|
|
307
|
-
lines.push(s.muted('─'.repeat(Math.max(1, cols - 1))));
|
|
261
|
+
if (state.pathEditMode && isSelected) {
|
|
262
|
+
// Edit mode - show input field
|
|
263
|
+
const labelStyled = s.primary(label.padEnd(labelWidth));
|
|
264
|
+
const inputDisplay = state.pathEditInput + '█';
|
|
265
|
+
lines.push(`${prefix}${labelStyled}${inputDisplay}`);
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
// Normal mode - show value
|
|
269
|
+
const labelStyled = isSelected ? s.primary(label.padEnd(labelWidth)) : label.padEnd(labelWidth);
|
|
270
|
+
const valueStyled = isSelected ? s.primary(value) : s.muted(value);
|
|
271
|
+
const truncatedValue = value.length > valueWidth ? value.slice(0, valueWidth - 3) + '...' : value;
|
|
272
|
+
lines.push(`${prefix}${labelStyled}${valueStyled === s.primary(value) ? s.primary(truncatedValue) : s.muted(truncatedValue)}`);
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
// Path items (0-2)
|
|
276
|
+
renderPathItem(0, 'Workspace path', pathConfig.workspacePath);
|
|
277
|
+
renderPathItem(1, 'Projects path', pathConfig.projectsPath);
|
|
278
|
+
renderPathItem(2, 'Data path', pathConfig.dataPath);
|
|
308
279
|
lines.push('');
|
|
309
|
-
lines.push(chalk.bold(
|
|
280
|
+
lines.push(chalk.bold(' Safety Settings'));
|
|
310
281
|
lines.push('');
|
|
311
|
-
//
|
|
312
|
-
const
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
282
|
+
// Helper to render a toggle item with consistent alignment
|
|
283
|
+
const renderToggleItem = (index, label, enabled, hint) => {
|
|
284
|
+
const isSelected = state.pathSelectedItem === index;
|
|
285
|
+
const prefix = isSelected ? s.primary(' ❯ ') : ' ';
|
|
286
|
+
const labelStyled = isSelected ? s.primary(label.padEnd(labelWidth)) : label.padEnd(labelWidth);
|
|
287
|
+
const valueStyled = enabled ? s.success('enabled'.padStart(10)) : s.warning('disabled'.padStart(10));
|
|
288
|
+
lines.push(`${prefix}${labelStyled}${valueStyled}`);
|
|
289
|
+
lines.push(s.muted(` ${hint}`));
|
|
290
|
+
};
|
|
291
|
+
// Toggle items (3-4)
|
|
292
|
+
renderToggleItem(3, 'Delete protection', pathConfig.deleteProtection, 'Only allow file deletion within projects path');
|
|
293
|
+
renderToggleItem(4, 'CWD mismatch warning', pathConfig.requireProjectMatch, 'Warn when current directory differs from active project');
|
|
319
294
|
lines.push('');
|
|
320
|
-
//
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
const pageResults = state.browseResults.slice(startIndex, endIndex);
|
|
326
|
-
if (totalResults === 0) {
|
|
327
|
-
lines.push(s.muted(' No themes found'));
|
|
328
|
-
}
|
|
329
|
-
else {
|
|
330
|
-
lines.push(s.muted(` Showing ${String(startIndex + 1)}-${String(endIndex)} of ${String(totalResults)}:`));
|
|
331
|
-
lines.push('');
|
|
332
|
-
for (let i = 0; i < pageResults.length; i++) {
|
|
333
|
-
const theme = pageResults[i];
|
|
334
|
-
const isSelected = i === state.browseSelectedIndex;
|
|
335
|
-
const isCurrent = theme.id === currentTheme.id;
|
|
336
|
-
const prefix = isSelected ? s.primary(' ❯ ') : ' ';
|
|
337
|
-
const icon = theme.type === 'dark' ? '🌙' : '☀️';
|
|
338
|
-
const checkmark = isCurrent ? s.success(' ✓') : '';
|
|
339
|
-
const label = isSelected ? s.primary(theme.name) : theme.name;
|
|
340
|
-
lines.push(prefix + label.padEnd(35) + icon + checkmark);
|
|
295
|
+
// Allowed paths (if any)
|
|
296
|
+
if (pathConfig.allowedPaths.length > 0) {
|
|
297
|
+
lines.push(chalk.bold(' Additional Allowed Paths'));
|
|
298
|
+
for (const allowed of pathConfig.allowedPaths) {
|
|
299
|
+
lines.push(` ${s.muted('•')} ${allowed}`);
|
|
341
300
|
}
|
|
301
|
+
lines.push('');
|
|
342
302
|
}
|
|
343
|
-
lines.push('');
|
|
344
|
-
// Pagination
|
|
345
|
-
if (totalPages > 1) {
|
|
346
|
-
const pageInfo = `Page ${String(state.browseCurrentPage + 1)} of ${String(totalPages)}`;
|
|
347
|
-
const prevHint = state.browseCurrentPage > 0 ? '← ' : ' ';
|
|
348
|
-
const nextHint = state.browseCurrentPage < totalPages - 1 ? ' →' : '';
|
|
349
|
-
lines.push(s.muted(` ${prevHint}${pageInfo}${nextHint}`));
|
|
350
|
-
}
|
|
351
|
-
// Separator
|
|
352
|
-
lines.push(s.muted(' ────────────────────────────────────'));
|
|
353
|
-
// Back option
|
|
354
|
-
lines.push(s.muted(' ← Back to curated themes'));
|
|
355
|
-
lines.push('');
|
|
356
|
-
// Preview
|
|
357
|
-
if (pageResults.length > 0 && state.browseSelectedIndex < pageResults.length) {
|
|
358
|
-
lines.push(...renderThemePreview(pageResults[state.browseSelectedIndex]));
|
|
359
|
-
}
|
|
360
|
-
lines.push('');
|
|
361
|
-
lines.push(s.muted(' Type to search · ↑↓ Navigate · ←→ Pages · Tab Filter · Enter Select · Esc Back'));
|
|
362
|
-
return lines;
|
|
363
|
-
}
|
|
364
|
-
// =============================================================================
|
|
365
|
-
// Rendering - Theme Preview
|
|
366
|
-
// =============================================================================
|
|
367
|
-
function renderThemePreview(theme) {
|
|
368
|
-
const s = getStyles();
|
|
369
|
-
const lines = [];
|
|
370
|
-
const colors = theme.colors;
|
|
371
|
-
lines.push(s.muted(' Preview:'));
|
|
372
|
-
// Use chalk for hex colors in preview
|
|
373
|
-
const primary = chalk.hex(colors.primary);
|
|
374
|
-
const secondary = chalk.hex(colors.secondary || colors.primary);
|
|
375
|
-
const muted = chalk.hex(colors.muted);
|
|
376
|
-
const fg = chalk.hex(colors.foreground);
|
|
377
|
-
lines.push(' ' + primary.bold('function') + ' ' + secondary('greet') + fg('() {'));
|
|
378
|
-
lines.push(' ' + muted('// Say hello'));
|
|
379
|
-
lines.push(' ' + fg('console.') + secondary('log') + fg('("Hello, ') + primary('World') + fg('!");'));
|
|
380
|
-
lines.push(' ' + fg('}'));
|
|
381
303
|
return lines;
|
|
382
304
|
}
|
|
383
305
|
// =============================================================================
|
|
384
|
-
// Rendering -
|
|
306
|
+
// Rendering - Footer
|
|
385
307
|
// =============================================================================
|
|
386
|
-
function
|
|
308
|
+
function renderFooter(state) {
|
|
387
309
|
const s = getStyles();
|
|
388
310
|
const lines = [];
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
tabLine += s.selected(` ${tab.label}${indicator} `) + ' ';
|
|
311
|
+
lines.push('');
|
|
312
|
+
const tabId = TABS[state.currentTab].id;
|
|
313
|
+
if (tabId === 'config') {
|
|
314
|
+
// Config tab
|
|
315
|
+
lines.push(s.muted(' ↑↓/jk Navigate · Enter/Space Change · q/Esc Close'));
|
|
316
|
+
}
|
|
317
|
+
else if (tabId === 'paths') {
|
|
318
|
+
// Paths tab
|
|
319
|
+
if (state.pathEditMode) {
|
|
320
|
+
lines.push(s.muted(' Type path · Enter Save · Esc Cancel'));
|
|
400
321
|
}
|
|
401
322
|
else {
|
|
402
|
-
|
|
323
|
+
lines.push(s.muted(' ↑↓/jk Navigate · Enter Edit/Toggle · q/Esc Close'));
|
|
403
324
|
}
|
|
404
325
|
}
|
|
405
|
-
tabLine += s.muted('(tab to switch)');
|
|
406
|
-
lines.push(tabLine);
|
|
407
|
-
lines.push('');
|
|
408
|
-
// Current provider info
|
|
409
|
-
const selectedProviderTab = MODEL_PROVIDER_TABS[state.modelProviderTab];
|
|
410
|
-
const isHotSwappable = selectedProviderTab.id === state.currentProvider;
|
|
411
|
-
if (isHotSwappable) {
|
|
412
|
-
lines.push(s.success(' Current provider - changes apply immediately'));
|
|
413
|
-
}
|
|
414
326
|
else {
|
|
415
|
-
lines.push(s.
|
|
416
|
-
}
|
|
417
|
-
// Check if API key is configured for selected provider
|
|
418
|
-
if (selectedProviderTab.id !== 'ollama') {
|
|
419
|
-
const credKey = settingsProviderToCredentialKey(selectedProviderTab.id);
|
|
420
|
-
if (!hasApiKey(credKey)) {
|
|
421
|
-
lines.push(s.error(' ⚠ No API key configured - use /keys to set it'));
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
lines.push('');
|
|
425
|
-
// Models for selected provider
|
|
426
|
-
const models = getModelsForProvider(selectedProviderTab.id);
|
|
427
|
-
for (let i = 0; i < models.length; i++) {
|
|
428
|
-
const model = models[i];
|
|
429
|
-
const isSelected = i === state.modelSelectedIndex;
|
|
430
|
-
const isCurrentModel = model.id === state.statusInfo.model;
|
|
431
|
-
const prefix = isSelected ? s.primary(' ❯ ') : ' ';
|
|
432
|
-
const checkmark = isCurrentModel ? s.success(' ✓') : '';
|
|
433
|
-
const label = isSelected ? s.primary(model.name) : model.name;
|
|
434
|
-
const desc = s.muted(` · ${model.description}`);
|
|
435
|
-
lines.push(prefix + label.padEnd(20) + desc + checkmark);
|
|
327
|
+
lines.push(s.muted(' q/Esc Close'));
|
|
436
328
|
}
|
|
437
|
-
lines.push('');
|
|
438
|
-
// Footer
|
|
439
|
-
lines.push(s.muted(' Tab Provider · ↑↓ Model · Enter Select · Esc Back'));
|
|
440
329
|
return lines;
|
|
441
330
|
}
|
|
442
|
-
//
|
|
443
|
-
// Unified Rendering
|
|
444
|
-
// =============================================================================
|
|
445
|
-
// Target height for consistent screen sizes (model selector is tallest at ~25 lines)
|
|
331
|
+
// Target height for consistent screen sizes
|
|
446
332
|
const TARGET_HEIGHT = 25;
|
|
447
333
|
function padToHeight(lines, targetHeight) {
|
|
448
334
|
while (lines.length < targetHeight) {
|
|
@@ -451,15 +337,6 @@ function padToHeight(lines, targetHeight) {
|
|
|
451
337
|
return lines;
|
|
452
338
|
}
|
|
453
339
|
function buildLines(state) {
|
|
454
|
-
if (state.mode === 'theme-curated') {
|
|
455
|
-
return padToHeight(buildThemeCuratedLines(state), TARGET_HEIGHT);
|
|
456
|
-
}
|
|
457
|
-
if (state.mode === 'theme-browse') {
|
|
458
|
-
return padToHeight(buildThemeBrowseLines(state), TARGET_HEIGHT);
|
|
459
|
-
}
|
|
460
|
-
if (state.mode === 'model-selector') {
|
|
461
|
-
return padToHeight(buildModelSelectorLines(state), TARGET_HEIGHT);
|
|
462
|
-
}
|
|
463
340
|
const allLines = [];
|
|
464
341
|
allLines.push(...renderHeader(state));
|
|
465
342
|
switch (TABS[state.currentTab].id) {
|
|
@@ -469,6 +346,9 @@ function buildLines(state) {
|
|
|
469
346
|
case 'config':
|
|
470
347
|
allLines.push(...renderConfigTab(state));
|
|
471
348
|
break;
|
|
349
|
+
case 'paths':
|
|
350
|
+
allLines.push(...renderPathsTab(state));
|
|
351
|
+
break;
|
|
472
352
|
case 'usage':
|
|
473
353
|
allLines.push(...renderUsageTab(state));
|
|
474
354
|
break;
|
|
@@ -537,82 +417,41 @@ function toggleOrCycleItem(state) {
|
|
|
537
417
|
case 'editorMode':
|
|
538
418
|
setSetting('editorMode', item.value);
|
|
539
419
|
break;
|
|
420
|
+
case 'startupMode':
|
|
421
|
+
setSetting('startupMode', item.value === 'Show menu' ? 'menu' : 'repl');
|
|
422
|
+
break;
|
|
423
|
+
case 'projectStartup':
|
|
424
|
+
setSetting('projectStartup', displayToProjectStartupMode(item.value));
|
|
425
|
+
break;
|
|
540
426
|
// 'model' is not persisted (would need provider integration)
|
|
541
427
|
}
|
|
542
428
|
}
|
|
543
429
|
else if (item.type === 'submenu' && item.id === 'theme') {
|
|
544
|
-
//
|
|
545
|
-
state.
|
|
546
|
-
state.themeSelectedIndex = 0;
|
|
547
|
-
// Find current theme in curated list
|
|
548
|
-
const currentTheme = getCurrentTheme();
|
|
549
|
-
const curatedIndex = state.curatedThemes.findIndex((t) => t.id === currentTheme.id);
|
|
550
|
-
if (curatedIndex >= 0) {
|
|
551
|
-
state.themeSelectedIndex = curatedIndex;
|
|
552
|
-
}
|
|
430
|
+
// Request standalone theme overlay
|
|
431
|
+
state.requestSubOverlay = 'theme';
|
|
553
432
|
}
|
|
554
433
|
else if (item.type === 'submenu' && item.id === 'model') {
|
|
555
|
-
//
|
|
556
|
-
state.
|
|
557
|
-
state.modelSelectedIndex = 0;
|
|
558
|
-
state.modelProviderTab = 0;
|
|
559
|
-
// Find current model and set provider tab accordingly
|
|
560
|
-
const currentModel = MODEL_OPTIONS.find((m) => m.id === state.statusInfo.model);
|
|
561
|
-
if (currentModel) {
|
|
562
|
-
const providerTabIndex = MODEL_PROVIDER_TABS.findIndex((p) => p.id === currentModel.provider);
|
|
563
|
-
if (providerTabIndex >= 0) {
|
|
564
|
-
state.modelProviderTab = providerTabIndex;
|
|
565
|
-
}
|
|
566
|
-
// Find model index within that provider's models
|
|
567
|
-
const providerModels = getModelsForProvider(currentModel.provider);
|
|
568
|
-
const modelIndex = providerModels.findIndex((m) => m.id === currentModel.id);
|
|
569
|
-
if (modelIndex >= 0) {
|
|
570
|
-
state.modelSelectedIndex = modelIndex;
|
|
571
|
-
}
|
|
572
|
-
}
|
|
434
|
+
// Request standalone model overlay
|
|
435
|
+
state.requestSubOverlay = 'model';
|
|
573
436
|
}
|
|
574
|
-
|
|
575
|
-
//
|
|
576
|
-
|
|
577
|
-
// =============================================================================
|
|
578
|
-
function selectTheme(state, theme) {
|
|
579
|
-
setCurrentTheme(theme.id);
|
|
580
|
-
clearStyleCache();
|
|
581
|
-
// Update the config item value
|
|
582
|
-
const themeItem = state.configItems.find((item) => item.id === 'theme');
|
|
583
|
-
if (themeItem) {
|
|
584
|
-
themeItem.value = theme.name;
|
|
437
|
+
else if (item.type === 'submenu' && item.id === 'mascot') {
|
|
438
|
+
// Request standalone mascot overlay
|
|
439
|
+
state.requestSubOverlay = 'mascot';
|
|
585
440
|
}
|
|
586
441
|
}
|
|
587
|
-
function updateBrowseResults(state) {
|
|
588
|
-
state.browseResults = searchAndFilterThemes(state.browseSearchQuery, state.browseFilterType);
|
|
589
|
-
state.browseSelectedIndex = 0;
|
|
590
|
-
state.browseCurrentPage = 0;
|
|
591
|
-
}
|
|
592
442
|
/**
|
|
593
443
|
* Show the config overlay
|
|
594
444
|
*/
|
|
595
445
|
export async function showConfigOverlay(options = {}) {
|
|
596
|
-
const curatedThemes = getCuratedThemes();
|
|
597
446
|
const result = {};
|
|
598
447
|
const state = {
|
|
599
|
-
mode: options.initialMode || 'tabs',
|
|
600
448
|
currentTab: 1, // Start on Config tab (like Claude Code)
|
|
601
449
|
selectedItem: 0,
|
|
602
450
|
scrollOffset: 0,
|
|
603
|
-
//
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
browseSearchQuery: '',
|
|
608
|
-
browseFilterType: 'all',
|
|
609
|
-
browseCurrentPage: 0,
|
|
610
|
-
browseSelectedIndex: 0,
|
|
611
|
-
browseResults: [],
|
|
612
|
-
// Model selector state
|
|
613
|
-
modelSelectedIndex: 0,
|
|
614
|
-
modelProviderTab: 0,
|
|
615
|
-
currentProvider: options.provider || 'unknown',
|
|
451
|
+
// Path settings state
|
|
452
|
+
pathSelectedItem: 0,
|
|
453
|
+
pathEditMode: false,
|
|
454
|
+
pathEditInput: '',
|
|
616
455
|
configItems: getConfigItems(options.model),
|
|
617
456
|
statusInfo: {
|
|
618
457
|
version: options.version || VERSION,
|
|
@@ -632,300 +471,191 @@ export async function showConfigOverlay(options = {}) {
|
|
|
632
471
|
contextMax: options.contextMax ?? 200000,
|
|
633
472
|
messageCount: options.messageCount ?? 0,
|
|
634
473
|
},
|
|
635
|
-
onModelChange: options.onModelChange,
|
|
636
474
|
};
|
|
637
|
-
// If starting in model-selector mode, initialize the provider tab and model index
|
|
638
|
-
if (options.initialMode === 'model-selector') {
|
|
639
|
-
// Find current model and set provider tab accordingly
|
|
640
|
-
const currentModel = MODEL_OPTIONS.find((m) => m.id === state.statusInfo.model);
|
|
641
|
-
if (currentModel) {
|
|
642
|
-
const providerTabIndex = MODEL_PROVIDER_TABS.findIndex((p) => p.id === currentModel.provider);
|
|
643
|
-
if (providerTabIndex >= 0) {
|
|
644
|
-
state.modelProviderTab = providerTabIndex;
|
|
645
|
-
}
|
|
646
|
-
// Find model index within that provider's models
|
|
647
|
-
const providerModels = getModelsForProvider(currentModel.provider);
|
|
648
|
-
const modelIndex = providerModels.findIndex((m) => m.id === currentModel.id);
|
|
649
|
-
if (modelIndex >= 0) {
|
|
650
|
-
state.modelSelectedIndex = modelIndex;
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
475
|
let lineCount = 0;
|
|
655
|
-
|
|
476
|
+
let maxLineCount = 0;
|
|
477
|
+
// Pause footer and setup terminal
|
|
478
|
+
pauseForOverlay();
|
|
656
479
|
terminal.hideCursor();
|
|
657
480
|
const wasRawMode = process.stdin.isRaw;
|
|
658
481
|
terminal.enableRawMode();
|
|
659
482
|
lineCount = render(state, 0);
|
|
483
|
+
maxLineCount = lineCount;
|
|
660
484
|
return new Promise((resolve) => {
|
|
661
485
|
const cleanup = () => {
|
|
662
|
-
|
|
663
|
-
|
|
486
|
+
// Remove event listener first
|
|
487
|
+
process.stdin.removeListener('data', onData);
|
|
488
|
+
// Clear all lines (use maxLineCount to ensure complete cleanup)
|
|
489
|
+
if (maxLineCount > 0) {
|
|
490
|
+
terminal.clearLinesAbove(maxLineCount);
|
|
491
|
+
}
|
|
664
492
|
terminal.showCursor();
|
|
665
493
|
if (!wasRawMode) {
|
|
666
494
|
terminal.disableRawMode();
|
|
667
495
|
}
|
|
668
|
-
|
|
496
|
+
// Resume footer
|
|
497
|
+
resumeAfterOverlay();
|
|
669
498
|
};
|
|
670
499
|
const onData = (data) => {
|
|
671
|
-
const
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
const isEnter = data.length === 1 && (data[0] === 0x0d || data[0] === 0x0a);
|
|
679
|
-
const isSpace = data.length === 1 && data[0] === 0x20;
|
|
680
|
-
const isBackspace = data.length === 1 && (data[0] === 0x7f || data[0] === 0x08);
|
|
681
|
-
const char = data.toString();
|
|
682
|
-
const isNumberKey = /^[0-9]$/.test(char);
|
|
683
|
-
const isPrintable = data.length === 1 && data[0] >= 32 && data[0] < 127;
|
|
684
|
-
// ===== TABS MODE =====
|
|
685
|
-
if (state.mode === 'tabs') {
|
|
686
|
-
if (isEscape || isCtrlC) {
|
|
687
|
-
cleanup();
|
|
688
|
-
resolve(result);
|
|
689
|
-
return;
|
|
690
|
-
}
|
|
691
|
-
if (isTab) {
|
|
692
|
-
state.currentTab = (state.currentTab + 1) % TABS.length;
|
|
693
|
-
state.selectedItem = 0;
|
|
500
|
+
const char = extractPrintable(data);
|
|
501
|
+
// Handle path edit mode first (when editing a path in Paths tab)
|
|
502
|
+
if (state.pathEditMode) {
|
|
503
|
+
if (isEscape(data)) {
|
|
504
|
+
// Cancel edit
|
|
505
|
+
state.pathEditMode = false;
|
|
506
|
+
state.pathEditInput = '';
|
|
694
507
|
lineCount = render(state, lineCount);
|
|
508
|
+
maxLineCount = Math.max(maxLineCount, lineCount);
|
|
695
509
|
return;
|
|
696
510
|
}
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
return;
|
|
511
|
+
if (isEnter(data)) {
|
|
512
|
+
// Save the path
|
|
513
|
+
const newPath = state.pathEditInput.trim();
|
|
514
|
+
if (newPath) {
|
|
515
|
+
switch (state.pathSelectedItem) {
|
|
516
|
+
case 0:
|
|
517
|
+
setWorkspacePath(newPath);
|
|
518
|
+
break;
|
|
519
|
+
case 1:
|
|
520
|
+
setProjectsPath(newPath);
|
|
521
|
+
break;
|
|
522
|
+
case 2:
|
|
523
|
+
setDataPath(newPath);
|
|
524
|
+
break;
|
|
525
|
+
}
|
|
713
526
|
}
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
}
|
|
717
|
-
// ===== THEME CURATED MODE =====
|
|
718
|
-
if (state.mode === 'theme-curated') {
|
|
719
|
-
const maxIndex = state.curatedThemes.length; // includes "Browse all" option
|
|
720
|
-
if (isCtrlC) {
|
|
721
|
-
cleanup();
|
|
722
|
-
resolve(result);
|
|
723
|
-
return;
|
|
724
|
-
}
|
|
725
|
-
if (isEscape) {
|
|
726
|
-
state.mode = 'tabs';
|
|
527
|
+
state.pathEditMode = false;
|
|
528
|
+
state.pathEditInput = '';
|
|
727
529
|
lineCount = render(state, lineCount);
|
|
530
|
+
maxLineCount = Math.max(maxLineCount, lineCount);
|
|
728
531
|
return;
|
|
729
532
|
}
|
|
730
|
-
if (
|
|
731
|
-
state.
|
|
533
|
+
if (isBackspace(data)) {
|
|
534
|
+
state.pathEditInput = state.pathEditInput.slice(0, -1);
|
|
732
535
|
lineCount = render(state, lineCount);
|
|
536
|
+
maxLineCount = Math.max(maxLineCount, lineCount);
|
|
733
537
|
return;
|
|
734
538
|
}
|
|
735
|
-
if (
|
|
736
|
-
state.
|
|
539
|
+
if (isPrintable(data)) {
|
|
540
|
+
state.pathEditInput += char;
|
|
737
541
|
lineCount = render(state, lineCount);
|
|
542
|
+
maxLineCount = Math.max(maxLineCount, lineCount);
|
|
738
543
|
return;
|
|
739
544
|
}
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
updateBrowseResults(state);
|
|
747
|
-
lineCount = render(state, lineCount);
|
|
748
|
-
}
|
|
749
|
-
else {
|
|
750
|
-
// Theme selected
|
|
751
|
-
const theme = state.curatedThemes[state.themeSelectedIndex];
|
|
752
|
-
selectTheme(state, theme);
|
|
753
|
-
state.mode = 'tabs';
|
|
754
|
-
lineCount = render(state, lineCount);
|
|
755
|
-
}
|
|
756
|
-
return;
|
|
757
|
-
}
|
|
758
|
-
// Quick select with number keys (1-9 = themes 1-9, 0 = theme 10)
|
|
759
|
-
if (isNumberKey) {
|
|
760
|
-
const num = char === '0' ? 10 : parseInt(char, 10);
|
|
761
|
-
if (num >= 1 && num <= state.curatedThemes.length) {
|
|
762
|
-
const theme = state.curatedThemes[num - 1];
|
|
763
|
-
selectTheme(state, theme);
|
|
764
|
-
state.mode = 'tabs';
|
|
765
|
-
lineCount = render(state, lineCount);
|
|
766
|
-
}
|
|
767
|
-
return;
|
|
768
|
-
}
|
|
545
|
+
return; // Ignore other keys in edit mode
|
|
546
|
+
}
|
|
547
|
+
// q or Esc closes (not in path edit mode)
|
|
548
|
+
if (isEscape(data) || isCtrlC(data) || isQuit(data)) {
|
|
549
|
+
cleanup();
|
|
550
|
+
resolve(result);
|
|
769
551
|
return;
|
|
770
552
|
}
|
|
771
|
-
//
|
|
772
|
-
if (
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
state.browseSelectedIndex++;
|
|
803
|
-
lineCount = render(state, lineCount);
|
|
804
|
-
return;
|
|
805
|
-
}
|
|
806
|
-
// Page navigation
|
|
807
|
-
if (isLeftArrow && state.browseCurrentPage > 0) {
|
|
808
|
-
state.browseCurrentPage--;
|
|
809
|
-
state.browseSelectedIndex = 0;
|
|
810
|
-
lineCount = render(state, lineCount);
|
|
811
|
-
return;
|
|
812
|
-
}
|
|
813
|
-
if (isRightArrow && state.browseCurrentPage < totalPages - 1) {
|
|
814
|
-
state.browseCurrentPage++;
|
|
815
|
-
state.browseSelectedIndex = 0;
|
|
816
|
-
lineCount = render(state, lineCount);
|
|
817
|
-
return;
|
|
818
|
-
}
|
|
819
|
-
// Select theme
|
|
820
|
-
if (isEnter && pageResults.length > 0) {
|
|
821
|
-
const theme = pageResults[state.browseSelectedIndex];
|
|
822
|
-
selectTheme(state, theme);
|
|
823
|
-
state.mode = 'tabs';
|
|
824
|
-
lineCount = render(state, lineCount);
|
|
825
|
-
return;
|
|
826
|
-
}
|
|
827
|
-
// Backspace - delete search char
|
|
828
|
-
if (isBackspace && state.browseSearchQuery.length > 0) {
|
|
829
|
-
state.browseSearchQuery = state.browseSearchQuery.slice(0, -1);
|
|
830
|
-
updateBrowseResults(state);
|
|
553
|
+
// Tab switching: Tab for next, Shift+Tab for previous
|
|
554
|
+
if (isTab(data)) {
|
|
555
|
+
state.currentTab = (state.currentTab + 1) % TABS.length;
|
|
556
|
+
state.selectedItem = 0;
|
|
557
|
+
state.pathSelectedItem = 0;
|
|
558
|
+
lineCount = render(state, lineCount);
|
|
559
|
+
maxLineCount = Math.max(maxLineCount, lineCount);
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
if (isShiftTab(data)) {
|
|
563
|
+
state.currentTab = (state.currentTab - 1 + TABS.length) % TABS.length;
|
|
564
|
+
state.selectedItem = 0;
|
|
565
|
+
state.pathSelectedItem = 0;
|
|
566
|
+
lineCount = render(state, lineCount);
|
|
567
|
+
maxLineCount = Math.max(maxLineCount, lineCount);
|
|
568
|
+
return;
|
|
569
|
+
}
|
|
570
|
+
// Number keys 1-4 to directly select tabs
|
|
571
|
+
const tabNumKey = getNumberKey(data);
|
|
572
|
+
if (tabNumKey !== null && tabNumKey >= 1 && tabNumKey <= TABS.length) {
|
|
573
|
+
state.currentTab = tabNumKey - 1;
|
|
574
|
+
state.selectedItem = 0;
|
|
575
|
+
state.pathSelectedItem = 0;
|
|
576
|
+
lineCount = render(state, lineCount);
|
|
577
|
+
maxLineCount = Math.max(maxLineCount, lineCount);
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
// Navigation only in Config tab (↑↓ or j/k)
|
|
581
|
+
if (TABS[state.currentTab].id === 'config') {
|
|
582
|
+
if (isNavigateUp(data) && state.selectedItem > 0) {
|
|
583
|
+
state.selectedItem--;
|
|
831
584
|
lineCount = render(state, lineCount);
|
|
585
|
+
maxLineCount = Math.max(maxLineCount, lineCount);
|
|
832
586
|
return;
|
|
833
587
|
}
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
state.browseSearchQuery += char;
|
|
837
|
-
updateBrowseResults(state);
|
|
588
|
+
if (isNavigateDown(data) && state.selectedItem < state.configItems.length - 1) {
|
|
589
|
+
state.selectedItem++;
|
|
838
590
|
lineCount = render(state, lineCount);
|
|
591
|
+
maxLineCount = Math.max(maxLineCount, lineCount);
|
|
839
592
|
return;
|
|
840
593
|
}
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
const currentProviderTab = MODEL_PROVIDER_TABS[state.modelProviderTab];
|
|
847
|
-
const providerModels = getModelsForProvider(currentProviderTab.id);
|
|
848
|
-
const maxModelIndex = providerModels.length - 1;
|
|
849
|
-
if (isCtrlC) {
|
|
850
|
-
cleanup();
|
|
851
|
-
resolve(result);
|
|
852
|
-
return;
|
|
853
|
-
}
|
|
854
|
-
if (isEscape) {
|
|
855
|
-
// If we started in model-selector mode (via /model command), close entirely
|
|
856
|
-
if (options.initialMode === 'model-selector') {
|
|
594
|
+
if (isEnter(data) || isSpace(data)) {
|
|
595
|
+
toggleOrCycleItem(state);
|
|
596
|
+
// Check if a sub-overlay was requested
|
|
597
|
+
if (state.requestSubOverlay) {
|
|
598
|
+
result.requestSubOverlay = state.requestSubOverlay;
|
|
857
599
|
cleanup();
|
|
858
600
|
resolve(result);
|
|
859
601
|
return;
|
|
860
602
|
}
|
|
861
|
-
state.mode = 'tabs';
|
|
862
|
-
lineCount = render(state, lineCount);
|
|
863
|
-
return;
|
|
864
|
-
}
|
|
865
|
-
// Tab to switch provider tabs
|
|
866
|
-
if (isTab) {
|
|
867
|
-
state.modelProviderTab = (state.modelProviderTab + 1) % MODEL_PROVIDER_TABS.length;
|
|
868
|
-
state.modelSelectedIndex = 0; // Reset model selection when switching tabs
|
|
869
603
|
lineCount = render(state, lineCount);
|
|
604
|
+
maxLineCount = Math.max(maxLineCount, lineCount);
|
|
870
605
|
return;
|
|
871
606
|
}
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
}
|
|
879
|
-
if (isRightArrow) {
|
|
880
|
-
state.modelProviderTab = (state.modelProviderTab + 1) % MODEL_PROVIDER_TABS.length;
|
|
881
|
-
state.modelSelectedIndex = 0;
|
|
882
|
-
lineCount = render(state, lineCount);
|
|
883
|
-
return;
|
|
884
|
-
}
|
|
885
|
-
if (isUpArrow && state.modelSelectedIndex > 0) {
|
|
886
|
-
state.modelSelectedIndex--;
|
|
607
|
+
}
|
|
608
|
+
// Navigation in Paths tab (5 items: 0-2 paths, 3-4 toggles)
|
|
609
|
+
if (TABS[state.currentTab].id === 'paths') {
|
|
610
|
+
const pathItemCount = 5; // 3 paths + 2 toggles
|
|
611
|
+
if (isNavigateUp(data) && state.pathSelectedItem > 0) {
|
|
612
|
+
state.pathSelectedItem--;
|
|
887
613
|
lineCount = render(state, lineCount);
|
|
614
|
+
maxLineCount = Math.max(maxLineCount, lineCount);
|
|
888
615
|
return;
|
|
889
616
|
}
|
|
890
|
-
if (
|
|
891
|
-
state.
|
|
617
|
+
if (isNavigateDown(data) && state.pathSelectedItem < pathItemCount - 1) {
|
|
618
|
+
state.pathSelectedItem++;
|
|
892
619
|
lineCount = render(state, lineCount);
|
|
620
|
+
maxLineCount = Math.max(maxLineCount, lineCount);
|
|
893
621
|
return;
|
|
894
622
|
}
|
|
895
|
-
if (isEnter) {
|
|
896
|
-
const
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
//
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
623
|
+
if (isEnter(data) || isSpace(data)) {
|
|
624
|
+
const currentConfig = getResolvedPathConfig();
|
|
625
|
+
if (state.pathSelectedItem <= 2) {
|
|
626
|
+
// Path items (0-2) - enter edit mode
|
|
627
|
+
state.pathEditMode = true;
|
|
628
|
+
// Pre-populate with current value
|
|
629
|
+
switch (state.pathSelectedItem) {
|
|
630
|
+
case 0:
|
|
631
|
+
state.pathEditInput = currentConfig.workspacePath;
|
|
632
|
+
break;
|
|
633
|
+
case 1:
|
|
634
|
+
state.pathEditInput = currentConfig.projectsPath;
|
|
635
|
+
break;
|
|
636
|
+
case 2:
|
|
637
|
+
state.pathEditInput = currentConfig.dataPath;
|
|
638
|
+
break;
|
|
904
639
|
}
|
|
905
|
-
// Update status info
|
|
906
|
-
state.statusInfo.model = selectedModel.id;
|
|
907
|
-
// Always persist model selection to settings
|
|
908
|
-
setSetting('defaultProvider', selectedModel.provider);
|
|
909
|
-
setSetting('defaultModel', selectedModel.id);
|
|
910
|
-
if (isCurrentProvider) {
|
|
911
|
-
result.modelChanged = selectedModel.id;
|
|
912
|
-
}
|
|
913
|
-
// Different provider: settings are saved, will take effect on restart
|
|
914
|
-
// If we started in model-selector mode (via /model command), close entirely
|
|
915
|
-
if (options.initialMode === 'model-selector') {
|
|
916
|
-
cleanup();
|
|
917
|
-
resolve(result);
|
|
918
|
-
return;
|
|
919
|
-
}
|
|
920
|
-
// Going back to config tabs - don't call onModelChange callback here
|
|
921
|
-
// as the overlay is still open. The model change will be reflected
|
|
922
|
-
// in the config display, and the actual switch happens when overlay closes.
|
|
923
|
-
state.mode = 'tabs';
|
|
924
640
|
lineCount = render(state, lineCount);
|
|
641
|
+
maxLineCount = Math.max(maxLineCount, lineCount);
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
else if (state.pathSelectedItem === 3) {
|
|
645
|
+
// Toggle delete protection
|
|
646
|
+
setDeleteProtection(!currentConfig.deleteProtection);
|
|
647
|
+
lineCount = render(state, lineCount);
|
|
648
|
+
maxLineCount = Math.max(maxLineCount, lineCount);
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
else if (state.pathSelectedItem === 4) {
|
|
652
|
+
// Toggle CWD match warning
|
|
653
|
+
setProjectMatchRequired(!currentConfig.requireProjectMatch);
|
|
654
|
+
lineCount = render(state, lineCount);
|
|
655
|
+
maxLineCount = Math.max(maxLineCount, lineCount);
|
|
656
|
+
return;
|
|
925
657
|
}
|
|
926
|
-
return;
|
|
927
658
|
}
|
|
928
|
-
return;
|
|
929
659
|
}
|
|
930
660
|
};
|
|
931
661
|
process.stdin.on('data', onData);
|