@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
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tools Overlay V2
|
|
3
|
+
*
|
|
4
|
+
* Displays available agent tools in a categorized, searchable list.
|
|
5
|
+
* Uses TabbedListOverlayV2 for the new Overlay interface.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Tabs: All, Files, Code, Git, Project, Agent
|
|
9
|
+
* - Search with / toggle
|
|
10
|
+
* - Detail view for full tool information
|
|
11
|
+
* - Works with TerminalUI's overlay management
|
|
12
|
+
*/
|
|
13
|
+
import * as terminal from './terminal.js';
|
|
14
|
+
import { TabbedListOverlayV2, BaseScreen, stay, popScreen, closeOverlay, isEscape, isCtrlC, isClose, renderBorder, wrapText, } from './base/index.js';
|
|
15
|
+
// =============================================================================
|
|
16
|
+
// Tab Definitions & Tool Categories
|
|
17
|
+
// =============================================================================
|
|
18
|
+
const TOOL_TABS = [
|
|
19
|
+
{ id: 'all', label: 'All' },
|
|
20
|
+
{ id: 'files', label: 'Files' },
|
|
21
|
+
{ id: 'code', label: 'Code' },
|
|
22
|
+
{ id: 'git', label: 'Git' },
|
|
23
|
+
{ id: 'project', label: 'Project' },
|
|
24
|
+
{ id: 'agent', label: 'Agent' },
|
|
25
|
+
];
|
|
26
|
+
/**
|
|
27
|
+
* Tool category mappings.
|
|
28
|
+
* Uses exact names or prefix patterns (ending with *).
|
|
29
|
+
*/
|
|
30
|
+
const TOOL_CATEGORIES = {
|
|
31
|
+
all: null, // No filter - show all tools
|
|
32
|
+
files: ['read_file', 'write_file', 'edit', 'glob', 'readFile', 'writeFile'],
|
|
33
|
+
code: ['grep', 'bash', 'bashOutput', 'run_tests', 'run_lint', 'detect_project', 'find_project_root', 'detectProject', 'findProjectRoot'],
|
|
34
|
+
git: ['git_*', 'gitStatus', 'gitDiff', 'gitLog', 'gitCommit', 'gitBranch'],
|
|
35
|
+
project: ['project_*', 'workitem_*', 'document_*', 'anchor_*'],
|
|
36
|
+
agent: ['task', 'todo_write', 'todo_read', 'todoWrite', 'todoRead', 'suggest', 'ask_user', 'ask_user_simple', 'askUser', 'askUserSimple', 'webFetch'],
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Check if a tool matches a category filter.
|
|
40
|
+
*/
|
|
41
|
+
function toolMatchesCategory(toolName, categoryId) {
|
|
42
|
+
const patterns = TOOL_CATEGORIES[categoryId];
|
|
43
|
+
if (patterns === null)
|
|
44
|
+
return true; // 'all' category
|
|
45
|
+
for (const pattern of patterns) {
|
|
46
|
+
if (pattern.endsWith('*')) {
|
|
47
|
+
// Prefix match
|
|
48
|
+
const prefix = pattern.slice(0, -1);
|
|
49
|
+
if (toolName.startsWith(prefix))
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
// Exact match
|
|
54
|
+
if (toolName === pattern)
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
// =============================================================================
|
|
61
|
+
// Constants
|
|
62
|
+
// =============================================================================
|
|
63
|
+
const PAGE_SIZE = 12;
|
|
64
|
+
const NAME_WIDTH = 26;
|
|
65
|
+
const MAX_DESCRIPTION_LENGTH = 300;
|
|
66
|
+
const MAX_PARAMETERS_SHOWN = 5;
|
|
67
|
+
/**
|
|
68
|
+
* Normalize text by replacing newlines with spaces (for single-line display)
|
|
69
|
+
*/
|
|
70
|
+
function normalizeText(text) {
|
|
71
|
+
return text.replace(/\n+/g, ' ').replace(/\s+/g, ' ').trim();
|
|
72
|
+
}
|
|
73
|
+
// =============================================================================
|
|
74
|
+
// Detail Screen
|
|
75
|
+
// =============================================================================
|
|
76
|
+
/**
|
|
77
|
+
* Detail screen - shows full information for selected tool
|
|
78
|
+
*/
|
|
79
|
+
class ToolDetailScreen extends BaseScreen {
|
|
80
|
+
tool;
|
|
81
|
+
styles;
|
|
82
|
+
constructor(tool, styles) {
|
|
83
|
+
super();
|
|
84
|
+
this.tool = tool;
|
|
85
|
+
this.styles = styles;
|
|
86
|
+
}
|
|
87
|
+
render() {
|
|
88
|
+
const s = this.styles;
|
|
89
|
+
const cols = terminal.getTerminalWidth();
|
|
90
|
+
const border = renderBorder(cols, s);
|
|
91
|
+
const lines = [];
|
|
92
|
+
// Header
|
|
93
|
+
lines.push(border);
|
|
94
|
+
lines.push(` ${s.primaryBold('Tool Details')}`);
|
|
95
|
+
lines.push('');
|
|
96
|
+
// Tool name
|
|
97
|
+
lines.push(` ${s.muted('Name:')} ${s.primaryBold(this.tool.name)}`);
|
|
98
|
+
lines.push('');
|
|
99
|
+
// Permission info
|
|
100
|
+
if (this.tool.permission) {
|
|
101
|
+
const levelColor = this.tool.permission.level === 'once' ? s.warning : s.muted;
|
|
102
|
+
lines.push(` ${s.muted('Permission:')} ${levelColor(this.tool.permission.level)} ${s.muted(`(${this.tool.permission.description})`)}`);
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
lines.push(` ${s.muted('Permission:')} ${s.success('always')} ${s.muted('(no approval required)')}`);
|
|
106
|
+
}
|
|
107
|
+
lines.push('');
|
|
108
|
+
// Description (normalize newlines for proper wrapping)
|
|
109
|
+
lines.push(` ${s.muted('Description:')}`);
|
|
110
|
+
let description = normalizeText(this.tool.description ?? 'No description available.');
|
|
111
|
+
if (description.length > MAX_DESCRIPTION_LENGTH) {
|
|
112
|
+
description = description.slice(0, MAX_DESCRIPTION_LENGTH).trim() + '...';
|
|
113
|
+
}
|
|
114
|
+
const wrappedDesc = wrapText(description, cols - 6);
|
|
115
|
+
for (const line of wrappedDesc) {
|
|
116
|
+
lines.push(` ${s.secondary(line)}`);
|
|
117
|
+
}
|
|
118
|
+
lines.push('');
|
|
119
|
+
// Parameters
|
|
120
|
+
if (this.tool.parameters && this.tool.parameters.length > 0) {
|
|
121
|
+
// Sort: required first, then optional
|
|
122
|
+
const sorted = [...this.tool.parameters].sort((a, b) => {
|
|
123
|
+
if (a.required && !b.required)
|
|
124
|
+
return -1;
|
|
125
|
+
if (!a.required && b.required)
|
|
126
|
+
return 1;
|
|
127
|
+
return 0;
|
|
128
|
+
});
|
|
129
|
+
const shown = sorted.slice(0, MAX_PARAMETERS_SHOWN);
|
|
130
|
+
const hidden = sorted.length - shown.length;
|
|
131
|
+
lines.push(` ${s.muted('Parameters:')}`);
|
|
132
|
+
for (const param of shown) {
|
|
133
|
+
const requiredBadge = param.required ? s.warning('*') : ' ';
|
|
134
|
+
const typeStr = s.muted(`(${param.type})`);
|
|
135
|
+
lines.push(` ${requiredBadge} ${s.secondary(param.name)} ${typeStr}`);
|
|
136
|
+
}
|
|
137
|
+
if (hidden > 0) {
|
|
138
|
+
lines.push(` ${s.muted(` + ${String(hidden)} more optional parameters`)}`);
|
|
139
|
+
}
|
|
140
|
+
lines.push('');
|
|
141
|
+
lines.push(` ${s.muted('* = required')}`);
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
lines.push(` ${s.muted('Parameters:')} ${s.muted('None')}`);
|
|
145
|
+
}
|
|
146
|
+
// Footer
|
|
147
|
+
lines.push(border);
|
|
148
|
+
lines.push(` ${s.muted('q/Esc Back')}`);
|
|
149
|
+
lines.push(border);
|
|
150
|
+
return lines;
|
|
151
|
+
}
|
|
152
|
+
handleKey(data) {
|
|
153
|
+
// Ctrl+C closes overlay completely
|
|
154
|
+
if (isCtrlC(data)) {
|
|
155
|
+
return closeOverlay({ dismissed: true });
|
|
156
|
+
}
|
|
157
|
+
// Esc or q goes back to list
|
|
158
|
+
if (isEscape(data) || isClose(data)) {
|
|
159
|
+
return popScreen();
|
|
160
|
+
}
|
|
161
|
+
return stay(false);
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Minimum height for stable rendering.
|
|
165
|
+
*/
|
|
166
|
+
getMinHeight() {
|
|
167
|
+
return 20;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// =============================================================================
|
|
171
|
+
// Tools Overlay V2 Class
|
|
172
|
+
// =============================================================================
|
|
173
|
+
/**
|
|
174
|
+
* Tools overlay using the new Overlay interface.
|
|
175
|
+
* Displays available tools in a searchable, tabbed list.
|
|
176
|
+
*/
|
|
177
|
+
export class ToolsOverlayV2 extends TabbedListOverlayV2 {
|
|
178
|
+
type = 'inline';
|
|
179
|
+
id = 'tools-overlay-v2';
|
|
180
|
+
constructor(options) {
|
|
181
|
+
// Sort tools alphabetically
|
|
182
|
+
const sortedTools = [...options.tools].sort((a, b) => a.name.localeCompare(b.name));
|
|
183
|
+
super({
|
|
184
|
+
title: 'Available Tools',
|
|
185
|
+
tabs: TOOL_TABS,
|
|
186
|
+
items: sortedTools,
|
|
187
|
+
pageSize: PAGE_SIZE,
|
|
188
|
+
filterByTab: (tool, tabId) => toolMatchesCategory(tool.name, tabId),
|
|
189
|
+
getSearchText: (tool) => `${tool.name} ${tool.description ?? ''}`,
|
|
190
|
+
renderItem: (tool, isSelected, styles) => {
|
|
191
|
+
const cols = terminal.getTerminalWidth();
|
|
192
|
+
const descWidth = Math.max(20, cols - NAME_WIDTH - 10);
|
|
193
|
+
const cursor = isSelected ? styles.primary('> ') : ' ';
|
|
194
|
+
const name = isSelected
|
|
195
|
+
? styles.primary(tool.name.padEnd(NAME_WIDTH))
|
|
196
|
+
: styles.muted(tool.name.padEnd(NAME_WIDTH));
|
|
197
|
+
// Normalize and truncate description
|
|
198
|
+
const normalizedDesc = normalizeText(tool.description ?? '');
|
|
199
|
+
const desc = normalizedDesc.length > descWidth
|
|
200
|
+
? normalizedDesc.slice(0, descWidth - 1) + '...'
|
|
201
|
+
: normalizedDesc;
|
|
202
|
+
const descColor = isSelected ? styles.secondary(desc) : styles.muted(desc);
|
|
203
|
+
return ` ${cursor}${name} ${descColor}`;
|
|
204
|
+
},
|
|
205
|
+
footerHints: (searchMode) => {
|
|
206
|
+
if (searchMode) {
|
|
207
|
+
return 'Type to filter · ↑↓/jk Navigate · Enter Details · Esc Exit search';
|
|
208
|
+
}
|
|
209
|
+
return 'Tab Filter · ↑↓/jk · ←→/hl Pages · / Search · Enter Details · q/Esc Close';
|
|
210
|
+
},
|
|
211
|
+
emptyMessage: 'No tools available.',
|
|
212
|
+
noResultsMessage: 'No tools match the current filter.',
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
createDetailScreen(tool) {
|
|
216
|
+
return new ToolDetailScreen(tool, this.getStyles());
|
|
217
|
+
}
|
|
218
|
+
}
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tools Overlay
|
|
3
3
|
*
|
|
4
|
-
* Displays available agent tools in a
|
|
5
|
-
*
|
|
4
|
+
* Displays available agent tools in a categorized, searchable list.
|
|
5
|
+
* Uses TabbedListOverlay for consistent UX patterns.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Tabs: All, Files, Code, Git, Project, Agent
|
|
9
|
+
* - Search with / toggle
|
|
10
|
+
* - Detail view for full tool information
|
|
6
11
|
*/
|
|
7
12
|
export interface ToolParameter {
|
|
8
13
|
name: string;
|
|
@@ -23,4 +28,7 @@ export interface ToolInfo {
|
|
|
23
28
|
export interface ToolsOverlayResult {
|
|
24
29
|
dismissed: boolean;
|
|
25
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Show the tools overlay
|
|
33
|
+
*/
|
|
26
34
|
export declare function showToolsOverlay(tools: ToolInfo[]): Promise<ToolsOverlayResult>;
|
package/dist/ui/tools-overlay.js
CHANGED
|
@@ -1,161 +1,121 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tools Overlay
|
|
3
3
|
*
|
|
4
|
-
* Displays available agent tools in a
|
|
5
|
-
*
|
|
4
|
+
* Displays available agent tools in a categorized, searchable list.
|
|
5
|
+
* Uses TabbedListOverlay for consistent UX patterns.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Tabs: All, Files, Code, Git, Project, Agent
|
|
9
|
+
* - Search with / toggle
|
|
10
|
+
* - Detail view for full tool information
|
|
6
11
|
*/
|
|
7
12
|
import * as terminal from './terminal.js';
|
|
8
|
-
import {
|
|
13
|
+
import { TabbedListOverlay, BaseScreen, stay, popScreen, closeOverlay, isCtrlC, isClose, isEscape, renderBorder, } from './base/index.js';
|
|
14
|
+
// =============================================================================
|
|
15
|
+
// Tab Definitions & Tool Categories
|
|
16
|
+
// =============================================================================
|
|
17
|
+
const TOOL_TABS = [
|
|
18
|
+
{ id: 'all', label: 'All' },
|
|
19
|
+
{ id: 'files', label: 'Files' },
|
|
20
|
+
{ id: 'code', label: 'Code' },
|
|
21
|
+
{ id: 'git', label: 'Git' },
|
|
22
|
+
{ id: 'project', label: 'Project' },
|
|
23
|
+
{ id: 'agent', label: 'Agent' },
|
|
24
|
+
];
|
|
25
|
+
/**
|
|
26
|
+
* Tool category mappings.
|
|
27
|
+
* Uses exact names or prefix patterns (ending with *).
|
|
28
|
+
*/
|
|
29
|
+
const TOOL_CATEGORIES = {
|
|
30
|
+
all: null, // No filter - show all tools
|
|
31
|
+
files: ['read_file', 'write_file', 'edit', 'glob', 'readFile', 'writeFile'],
|
|
32
|
+
code: ['grep', 'bash', 'bashOutput', 'run_tests', 'run_lint', 'detect_project', 'find_project_root', 'detectProject', 'findProjectRoot'],
|
|
33
|
+
git: ['git_*', 'gitStatus', 'gitDiff', 'gitLog', 'gitCommit', 'gitBranch'],
|
|
34
|
+
project: ['project_*', 'workitem_*', 'document_*', 'anchor_*'],
|
|
35
|
+
agent: ['task', 'todo_write', 'todo_read', 'todoWrite', 'todoRead', 'suggest', 'ask_user', 'ask_user_simple', 'askUser', 'askUserSimple', 'webFetch'],
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Check if a tool matches a category filter.
|
|
39
|
+
*/
|
|
40
|
+
function toolMatchesCategory(toolName, categoryId) {
|
|
41
|
+
const patterns = TOOL_CATEGORIES[categoryId];
|
|
42
|
+
if (patterns === null)
|
|
43
|
+
return true; // 'all' category
|
|
44
|
+
for (const pattern of patterns) {
|
|
45
|
+
if (pattern.endsWith('*')) {
|
|
46
|
+
// Prefix match
|
|
47
|
+
const prefix = pattern.slice(0, -1);
|
|
48
|
+
if (toolName.startsWith(prefix))
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
// Exact match
|
|
53
|
+
if (toolName === pattern)
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
9
59
|
// =============================================================================
|
|
10
60
|
// Constants
|
|
11
61
|
// =============================================================================
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
/** Width for tool name column */
|
|
15
|
-
const NAME_WIDTH = 18;
|
|
16
|
-
/** Max description length in detail view */
|
|
62
|
+
const PAGE_SIZE = 12;
|
|
63
|
+
const NAME_WIDTH = 26;
|
|
17
64
|
const MAX_DESCRIPTION_LENGTH = 300;
|
|
18
|
-
/** Max parameters to show in detail view */
|
|
19
65
|
const MAX_PARAMETERS_SHOWN = 5;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
};
|
|
42
|
-
// Helper to get border
|
|
43
|
-
const getBorder = () => {
|
|
44
|
-
return s.muted('─'.repeat(Math.max(1, termWidth - 1)));
|
|
45
|
-
};
|
|
46
|
-
// Helper to wrap text to multiple lines
|
|
47
|
-
const wrapText = (text, maxWidth) => {
|
|
48
|
-
const words = text.split(' ');
|
|
49
|
-
const lines = [];
|
|
50
|
-
let currentLine = '';
|
|
51
|
-
for (const word of words) {
|
|
52
|
-
if (currentLine.length + word.length + 1 <= maxWidth) {
|
|
53
|
-
currentLine += (currentLine ? ' ' : '') + word;
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
if (currentLine)
|
|
57
|
-
lines.push(currentLine);
|
|
58
|
-
currentLine = word;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
if (currentLine)
|
|
62
|
-
lines.push(currentLine);
|
|
63
|
-
return lines;
|
|
64
|
-
};
|
|
65
|
-
// Render list view
|
|
66
|
-
const renderList = () => {
|
|
67
|
-
// Clear previous render
|
|
68
|
-
if (lineCount > 0) {
|
|
69
|
-
terminal.clearLinesAbove(lineCount);
|
|
70
|
-
}
|
|
71
|
-
const lines = [];
|
|
72
|
-
// Header
|
|
73
|
-
lines.push(getBorder());
|
|
74
|
-
const title = `Available Tools`;
|
|
75
|
-
const countBadge = s.muted(`[${String(sortedTools.length)} tools]`);
|
|
76
|
-
lines.push(` ${s.primaryBold(title)} ${countBadge}`);
|
|
77
|
-
lines.push('');
|
|
78
|
-
// Column headers
|
|
79
|
-
const nameHeader = s.muted('Tool'.padEnd(NAME_WIDTH));
|
|
80
|
-
const descHeader = s.muted('Description');
|
|
81
|
-
lines.push(` ${nameHeader} ${descHeader}`);
|
|
82
|
-
lines.push(` ${s.muted('─'.repeat(NAME_WIDTH))} ${s.muted('─'.repeat(Math.min(descWidth, 40)))}`);
|
|
83
|
-
// Visible tools
|
|
84
|
-
const visibleTools = sortedTools.slice(scrollOffset, scrollOffset + VISIBLE_ROWS);
|
|
85
|
-
for (let i = 0; i < visibleTools.length; i++) {
|
|
86
|
-
const tool = visibleTools[i];
|
|
87
|
-
const absoluteIndex = scrollOffset + i;
|
|
88
|
-
const isSelected = absoluteIndex === selectedIndex;
|
|
89
|
-
const cursor = isSelected ? s.primary('❯ ') : ' ';
|
|
90
|
-
const name = isSelected
|
|
91
|
-
? s.primaryBold(tool.name.padEnd(NAME_WIDTH))
|
|
92
|
-
: s.secondary(tool.name.padEnd(NAME_WIDTH));
|
|
93
|
-
const desc = truncate(tool.description ?? '', descWidth);
|
|
94
|
-
const descColor = isSelected ? s.secondary(desc) : s.muted(desc);
|
|
95
|
-
lines.push(` ${cursor}${name} ${descColor}`);
|
|
96
|
-
}
|
|
97
|
-
// Padding if fewer tools than VISIBLE_ROWS
|
|
98
|
-
const emptyRows = VISIBLE_ROWS - visibleTools.length;
|
|
99
|
-
for (let i = 0; i < emptyRows; i++) {
|
|
100
|
-
lines.push('');
|
|
101
|
-
}
|
|
102
|
-
// Scroll indicator
|
|
103
|
-
lines.push('');
|
|
104
|
-
if (sortedTools.length > VISIBLE_ROWS) {
|
|
105
|
-
const scrollInfo = `${String(scrollOffset + 1)}-${String(Math.min(scrollOffset + VISIBLE_ROWS, sortedTools.length))} of ${String(sortedTools.length)}`;
|
|
106
|
-
const canUp = scrollOffset > 0;
|
|
107
|
-
const canDown = scrollOffset + VISIBLE_ROWS < sortedTools.length;
|
|
108
|
-
const arrows = (canUp ? '↑' : ' ') + (canDown ? '↓' : ' ');
|
|
109
|
-
lines.push(` ${s.muted(scrollInfo)} ${s.muted(arrows)}`);
|
|
110
|
-
}
|
|
111
|
-
// Footer
|
|
112
|
-
lines.push(getBorder());
|
|
113
|
-
lines.push(` ${s.muted('↑↓ Navigate · Enter Details · Esc Close')}`);
|
|
114
|
-
lines.push(getBorder());
|
|
115
|
-
// Print all lines
|
|
116
|
-
terminal.write(lines.join('\n'));
|
|
117
|
-
return lines.length;
|
|
118
|
-
};
|
|
119
|
-
// Render detail view
|
|
120
|
-
const renderDetail = () => {
|
|
121
|
-
// Clear previous render
|
|
122
|
-
if (lineCount > 0) {
|
|
123
|
-
terminal.clearLinesAbove(lineCount);
|
|
124
|
-
}
|
|
125
|
-
const tool = sortedTools[selectedIndex];
|
|
66
|
+
/**
|
|
67
|
+
* Normalize text by replacing newlines with spaces (for single-line display)
|
|
68
|
+
*/
|
|
69
|
+
function normalizeText(text) {
|
|
70
|
+
return text.replace(/\n+/g, ' ').replace(/\s+/g, ' ').trim();
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Detail screen - shows full information for selected tool
|
|
74
|
+
*/
|
|
75
|
+
class ToolDetailScreen extends BaseScreen {
|
|
76
|
+
tool;
|
|
77
|
+
styles;
|
|
78
|
+
constructor(tool, styles) {
|
|
79
|
+
super();
|
|
80
|
+
this.tool = tool;
|
|
81
|
+
this.styles = styles;
|
|
82
|
+
}
|
|
83
|
+
render() {
|
|
84
|
+
const s = this.styles;
|
|
85
|
+
const cols = terminal.getTerminalWidth();
|
|
86
|
+
const border = renderBorder(cols, s);
|
|
126
87
|
const lines = [];
|
|
127
88
|
// Header
|
|
128
|
-
lines.push(
|
|
89
|
+
lines.push(border);
|
|
129
90
|
lines.push(` ${s.primaryBold('Tool Details')}`);
|
|
130
91
|
lines.push('');
|
|
131
92
|
// Tool name
|
|
132
|
-
lines.push(` ${s.muted('Name:')} ${s.primaryBold(tool.name)}`);
|
|
93
|
+
lines.push(` ${s.muted('Name:')} ${s.primaryBold(this.tool.name)}`);
|
|
133
94
|
lines.push('');
|
|
134
|
-
// Permission info
|
|
135
|
-
if (tool.permission) {
|
|
136
|
-
const levelColor = tool.permission.level === 'once' ? s.warning : s.muted;
|
|
137
|
-
lines.push(` ${s.muted('Permission:')} ${levelColor(tool.permission.level)} ${s.muted(`(${tool.permission.description})`)}`);
|
|
138
|
-
lines.push('');
|
|
95
|
+
// Permission info
|
|
96
|
+
if (this.tool.permission) {
|
|
97
|
+
const levelColor = this.tool.permission.level === 'once' ? s.warning : s.muted;
|
|
98
|
+
lines.push(` ${s.muted('Permission:')} ${levelColor(this.tool.permission.level)} ${s.muted(`(${this.tool.permission.description})`)}`);
|
|
139
99
|
}
|
|
140
100
|
else {
|
|
141
101
|
lines.push(` ${s.muted('Permission:')} ${s.success('always')} ${s.muted('(no approval required)')}`);
|
|
142
|
-
lines.push('');
|
|
143
102
|
}
|
|
144
|
-
|
|
103
|
+
lines.push('');
|
|
104
|
+
// Description (normalize newlines for proper wrapping)
|
|
145
105
|
lines.push(` ${s.muted('Description:')}`);
|
|
146
|
-
let description = tool.description ?? 'No description available.';
|
|
106
|
+
let description = normalizeText(this.tool.description ?? 'No description available.');
|
|
147
107
|
if (description.length > MAX_DESCRIPTION_LENGTH) {
|
|
148
108
|
description = description.slice(0, MAX_DESCRIPTION_LENGTH).trim() + '...';
|
|
149
109
|
}
|
|
150
|
-
const wrappedDesc = wrapText(description,
|
|
110
|
+
const wrappedDesc = this.wrapText(description, cols - 6);
|
|
151
111
|
for (const line of wrappedDesc) {
|
|
152
112
|
lines.push(` ${s.secondary(line)}`);
|
|
153
113
|
}
|
|
154
114
|
lines.push('');
|
|
155
|
-
// Parameters
|
|
156
|
-
if (tool.parameters && tool.parameters.length > 0) {
|
|
115
|
+
// Parameters
|
|
116
|
+
if (this.tool.parameters && this.tool.parameters.length > 0) {
|
|
157
117
|
// Sort: required first, then optional
|
|
158
|
-
const sorted = [...tool.parameters].sort((a, b) => {
|
|
118
|
+
const sorted = [...this.tool.parameters].sort((a, b) => {
|
|
159
119
|
if (a.required && !b.required)
|
|
160
120
|
return -1;
|
|
161
121
|
if (!a.required && b.required)
|
|
@@ -180,99 +140,91 @@ export async function showToolsOverlay(tools) {
|
|
|
180
140
|
lines.push(` ${s.muted('Parameters:')} ${s.muted('None')}`);
|
|
181
141
|
}
|
|
182
142
|
// Footer
|
|
183
|
-
lines.push(
|
|
184
|
-
lines.push(` ${s.muted('Esc Back
|
|
185
|
-
lines.push(
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
if (mode === 'detail') {
|
|
193
|
-
return renderDetail();
|
|
194
|
-
}
|
|
195
|
-
return renderList();
|
|
196
|
-
};
|
|
197
|
-
// Ensure selected item is visible
|
|
198
|
-
const ensureVisible = () => {
|
|
199
|
-
if (selectedIndex < scrollOffset) {
|
|
200
|
-
scrollOffset = selectedIndex;
|
|
143
|
+
lines.push(border);
|
|
144
|
+
lines.push(` ${s.muted('q/Esc Back')}`);
|
|
145
|
+
lines.push(border);
|
|
146
|
+
return lines;
|
|
147
|
+
}
|
|
148
|
+
handleKey(data) {
|
|
149
|
+
// Ctrl+C closes overlay completely
|
|
150
|
+
if (isCtrlC(data)) {
|
|
151
|
+
return closeOverlay({ dismissed: true });
|
|
201
152
|
}
|
|
202
|
-
|
|
203
|
-
|
|
153
|
+
// Esc or q goes back to list
|
|
154
|
+
if (isEscape(data) || isClose(data)) {
|
|
155
|
+
return popScreen();
|
|
204
156
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
stdin.removeListener('data', handleKey);
|
|
215
|
-
stdin.setRawMode(wasRaw);
|
|
216
|
-
// Clear the overlay
|
|
217
|
-
terminal.clearLinesAbove(lineCount);
|
|
218
|
-
};
|
|
219
|
-
const handleKey = (data) => {
|
|
220
|
-
const key = data.toString();
|
|
221
|
-
// Handle key presses
|
|
222
|
-
const isEscape = key === '\x1B' && data.length === 1;
|
|
223
|
-
const isEnter = key === '\r' || key === '\n';
|
|
224
|
-
const isUpArrow = key === '\x1B[A';
|
|
225
|
-
const isDownArrow = key === '\x1B[B';
|
|
226
|
-
const isPageUp = key === '\x1B[5~';
|
|
227
|
-
const isPageDown = key === '\x1B[6~';
|
|
228
|
-
const isCtrlC = key === '\x03';
|
|
229
|
-
const isQ = key === 'q' || key === 'Q';
|
|
230
|
-
if (isCtrlC) {
|
|
231
|
-
cleanup();
|
|
232
|
-
resolve({ dismissed: true });
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
235
|
-
if (mode === 'detail') {
|
|
236
|
-
// Detail view: Esc goes back to list
|
|
237
|
-
if (isEscape || isQ) {
|
|
238
|
-
mode = 'list';
|
|
239
|
-
lineCount = render();
|
|
240
|
-
}
|
|
241
|
-
return;
|
|
242
|
-
}
|
|
243
|
-
// List view
|
|
244
|
-
if (isEscape || isQ) {
|
|
245
|
-
cleanup();
|
|
246
|
-
resolve({ dismissed: true });
|
|
247
|
-
return;
|
|
248
|
-
}
|
|
249
|
-
if (isEnter) {
|
|
250
|
-
mode = 'detail';
|
|
251
|
-
lineCount = render();
|
|
252
|
-
return;
|
|
253
|
-
}
|
|
254
|
-
// Navigation
|
|
255
|
-
if (isUpArrow && selectedIndex > 0) {
|
|
256
|
-
selectedIndex--;
|
|
257
|
-
ensureVisible();
|
|
258
|
-
lineCount = render();
|
|
259
|
-
}
|
|
260
|
-
else if (isDownArrow && selectedIndex < sortedTools.length - 1) {
|
|
261
|
-
selectedIndex++;
|
|
262
|
-
ensureVisible();
|
|
263
|
-
lineCount = render();
|
|
264
|
-
}
|
|
265
|
-
else if (isPageUp) {
|
|
266
|
-
selectedIndex = Math.max(0, selectedIndex - VISIBLE_ROWS);
|
|
267
|
-
ensureVisible();
|
|
268
|
-
lineCount = render();
|
|
157
|
+
return stay(false);
|
|
158
|
+
}
|
|
159
|
+
wrapText(text, maxWidth) {
|
|
160
|
+
const words = text.split(' ');
|
|
161
|
+
const resultLines = [];
|
|
162
|
+
let currentLine = '';
|
|
163
|
+
for (const word of words) {
|
|
164
|
+
if (currentLine.length + word.length + 1 <= maxWidth) {
|
|
165
|
+
currentLine += (currentLine ? ' ' : '') + word;
|
|
269
166
|
}
|
|
270
|
-
else
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
167
|
+
else {
|
|
168
|
+
if (currentLine)
|
|
169
|
+
resultLines.push(currentLine);
|
|
170
|
+
currentLine = word;
|
|
274
171
|
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
|
|
172
|
+
}
|
|
173
|
+
if (currentLine)
|
|
174
|
+
resultLines.push(currentLine);
|
|
175
|
+
return resultLines;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
// =============================================================================
|
|
179
|
+
// Tools Overlay Class
|
|
180
|
+
// =============================================================================
|
|
181
|
+
class ToolsOverlay extends TabbedListOverlay {
|
|
182
|
+
constructor(tools) {
|
|
183
|
+
// Sort tools alphabetically
|
|
184
|
+
const sortedTools = [...tools].sort((a, b) => a.name.localeCompare(b.name));
|
|
185
|
+
super({
|
|
186
|
+
title: 'Available Tools',
|
|
187
|
+
tabs: TOOL_TABS,
|
|
188
|
+
items: sortedTools,
|
|
189
|
+
pageSize: PAGE_SIZE,
|
|
190
|
+
filterByTab: (tool, tabId) => toolMatchesCategory(tool.name, tabId),
|
|
191
|
+
getSearchText: (tool) => `${tool.name} ${tool.description ?? ''}`,
|
|
192
|
+
renderItem: (tool, isSelected, styles) => {
|
|
193
|
+
const cols = terminal.getTerminalWidth();
|
|
194
|
+
const descWidth = Math.max(20, cols - NAME_WIDTH - 10);
|
|
195
|
+
const cursor = isSelected ? styles.primary('❯ ') : ' ';
|
|
196
|
+
const name = isSelected
|
|
197
|
+
? styles.primaryBold(tool.name.padEnd(NAME_WIDTH))
|
|
198
|
+
: styles.secondary(tool.name.padEnd(NAME_WIDTH));
|
|
199
|
+
// Normalize and truncate description
|
|
200
|
+
const normalizedDesc = normalizeText(tool.description ?? '');
|
|
201
|
+
const desc = normalizedDesc.length > descWidth
|
|
202
|
+
? normalizedDesc.slice(0, descWidth - 1) + '…'
|
|
203
|
+
: normalizedDesc;
|
|
204
|
+
const descColor = isSelected ? styles.secondary(desc) : styles.muted(desc);
|
|
205
|
+
return ` ${cursor}${name} ${descColor}`;
|
|
206
|
+
},
|
|
207
|
+
footerHints: (searchMode) => {
|
|
208
|
+
if (searchMode) {
|
|
209
|
+
return 'Type to filter · ↑↓/jk Navigate · Enter Details · Esc Exit search';
|
|
210
|
+
}
|
|
211
|
+
return 'Tab Filter · ↑↓/jk · ←→/hl Pages · / Search · Enter Details · q/Esc Close';
|
|
212
|
+
},
|
|
213
|
+
emptyMessage: 'No tools available.',
|
|
214
|
+
noResultsMessage: 'No tools match the current filter.',
|
|
215
|
+
detailScreensFullScreen: false,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
createDetailScreen(tool) {
|
|
219
|
+
return new ToolDetailScreen(tool, this.styles);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
// =============================================================================
|
|
223
|
+
// Export Function
|
|
224
|
+
// =============================================================================
|
|
225
|
+
/**
|
|
226
|
+
* Show the tools overlay
|
|
227
|
+
*/
|
|
228
|
+
export async function showToolsOverlay(tools) {
|
|
229
|
+
return new ToolsOverlay(tools).show();
|
|
278
230
|
}
|