@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
|
@@ -2,500 +2,862 @@
|
|
|
2
2
|
* Agents Overlay
|
|
3
3
|
*
|
|
4
4
|
* Modal overlay for viewing and managing agent configurations.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* Uses TabbedListOverlay for consistent list/tab/search behavior.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Built-in tab: Lists predefined agent types with detail view
|
|
9
|
+
* - Custom tab: Lists user-defined agents with detail/edit + create new
|
|
7
10
|
* - Wizard mode: Step-by-step agent creation
|
|
8
11
|
*/
|
|
9
12
|
import * as terminal from './terminal.js';
|
|
10
|
-
import {
|
|
13
|
+
import { TabbedListOverlay, BaseScreen, stay, popScreen, closeOverlay, isEscape, isCtrlC, isEnter, isNavigateUp, isNavigateDown, isBackspace, isClose, extractPrintable, renderBorder, } from './base/index.js';
|
|
11
14
|
import { getAgentRegistry } from '../agents/registry.js';
|
|
12
15
|
const TABS = [
|
|
13
|
-
{ id: 'builtin', label: '
|
|
14
|
-
{ id: 'custom', label: '
|
|
16
|
+
{ id: 'builtin', label: 'Built-in' },
|
|
17
|
+
{ id: 'custom', label: 'Custom' },
|
|
15
18
|
];
|
|
16
19
|
// =============================================================================
|
|
17
|
-
//
|
|
20
|
+
// Helper Functions
|
|
18
21
|
// =============================================================================
|
|
19
|
-
function
|
|
20
|
-
|
|
22
|
+
function wrapText(text, maxWidth) {
|
|
23
|
+
if (!text || text.length <= maxWidth)
|
|
24
|
+
return [text || ''];
|
|
25
|
+
const words = text.split(' ');
|
|
21
26
|
const lines = [];
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if (
|
|
28
|
-
|
|
27
|
+
let currentLine = '';
|
|
28
|
+
for (const word of words) {
|
|
29
|
+
if (currentLine.length === 0) {
|
|
30
|
+
currentLine = word;
|
|
31
|
+
}
|
|
32
|
+
else if (currentLine.length + 1 + word.length <= maxWidth) {
|
|
33
|
+
currentLine += ' ' + word;
|
|
29
34
|
}
|
|
30
35
|
else {
|
|
31
|
-
|
|
36
|
+
lines.push(currentLine);
|
|
37
|
+
currentLine = word;
|
|
32
38
|
}
|
|
33
39
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
lines.push('');
|
|
37
|
-
return lines;
|
|
38
|
-
}
|
|
39
|
-
function renderBuiltinTab(state) {
|
|
40
|
-
const s = getStyles();
|
|
41
|
-
const lines = [];
|
|
42
|
-
const agents = state.registry.getBuiltinAgents();
|
|
43
|
-
lines.push(s.secondary(' Built-in agents (via Task tool):'));
|
|
44
|
-
lines.push('');
|
|
45
|
-
for (let i = 0; i < agents.length; i++) {
|
|
46
|
-
const agent = agents[i];
|
|
47
|
-
const isSelected = i === state.selectedIndex;
|
|
48
|
-
const prefix = isSelected ? s.primary(' ❯ ') : ' ';
|
|
49
|
-
const name = `${agent.name} · ${agent.model}`;
|
|
50
|
-
const nameStyled = isSelected ? s.primary(name.padEnd(30)) : s.secondary(name.padEnd(30));
|
|
51
|
-
const desc = s.muted(agent.description);
|
|
52
|
-
lines.push(prefix + nameStyled + desc);
|
|
40
|
+
if (currentLine.length > 0) {
|
|
41
|
+
lines.push(currentLine);
|
|
53
42
|
}
|
|
54
|
-
lines.
|
|
55
|
-
lines.push(s.muted(' These agents are available to the LLM via the Task tool.'));
|
|
56
|
-
return lines;
|
|
43
|
+
return lines.length > 0 ? lines : [''];
|
|
57
44
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
45
|
+
// =============================================================================
|
|
46
|
+
// Detail Screen (View Agent Info)
|
|
47
|
+
// =============================================================================
|
|
48
|
+
/**
|
|
49
|
+
* Screen for viewing agent details.
|
|
50
|
+
* Shows name, model, description, and for custom agents: system prompt.
|
|
51
|
+
* Press 'e' to edit custom agents.
|
|
52
|
+
*/
|
|
53
|
+
class DetailScreen extends BaseScreen {
|
|
54
|
+
item;
|
|
55
|
+
styles;
|
|
56
|
+
editState;
|
|
57
|
+
onEdit;
|
|
58
|
+
constructor(item, styles, editState, onEdit) {
|
|
59
|
+
super();
|
|
60
|
+
this.item = item;
|
|
61
|
+
this.styles = styles;
|
|
62
|
+
this.editState = editState;
|
|
63
|
+
this.onEdit = onEdit;
|
|
64
|
+
}
|
|
65
|
+
render() {
|
|
66
|
+
const s = this.styles;
|
|
67
|
+
const cols = terminal.getTerminalWidth();
|
|
68
|
+
const border = renderBorder(cols, s);
|
|
69
|
+
const lines = [];
|
|
70
|
+
// Header
|
|
71
|
+
lines.push(border);
|
|
72
|
+
lines.push(` ${s.primaryBold('Agent Details')}`);
|
|
64
73
|
lines.push('');
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
74
|
+
// Name and model
|
|
75
|
+
lines.push(` ${s.muted('Name:')} ${s.primary(this.item.name)}`);
|
|
76
|
+
lines.push(` ${s.muted('Model:')} ${s.secondary(this.item.model)}`);
|
|
77
|
+
lines.push(` ${s.muted('Type:')} ${this.item.isBuiltin ? s.muted('Built-in') : s.secondary('Custom')}`);
|
|
78
|
+
// Location for custom agents
|
|
79
|
+
if (!this.item.isBuiltin && this.item.location) {
|
|
80
|
+
const locationLabel = this.item.location === 'project' ? 'Project' : 'Personal';
|
|
81
|
+
lines.push(` ${s.muted('Location:')} ${s.secondary(locationLabel)}`);
|
|
82
|
+
}
|
|
68
83
|
lines.push('');
|
|
69
|
-
|
|
70
|
-
lines.push(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
84
|
+
// Description
|
|
85
|
+
lines.push(` ${s.muted('Description:')}`);
|
|
86
|
+
const descLines = wrapText(this.item.description, cols - 6);
|
|
87
|
+
for (const line of descLines) {
|
|
88
|
+
lines.push(` ${s.secondary(line)}`);
|
|
89
|
+
}
|
|
90
|
+
// System prompt for custom agents
|
|
91
|
+
if (!this.item.isBuiltin && this.item.systemPrompt) {
|
|
92
|
+
lines.push('');
|
|
93
|
+
lines.push(` ${s.muted('System Prompt:')}`);
|
|
94
|
+
// Show first few lines of system prompt
|
|
95
|
+
const promptLines = this.item.systemPrompt.split('\n').slice(0, 5);
|
|
96
|
+
for (const line of promptLines) {
|
|
97
|
+
const truncated = line.length > cols - 6 ? line.slice(0, cols - 9) + '...' : line;
|
|
98
|
+
lines.push(` ${s.secondary(truncated)}`);
|
|
99
|
+
}
|
|
100
|
+
if (this.item.systemPrompt.split('\n').length > 5) {
|
|
101
|
+
lines.push(` ${s.muted('...')}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// File path for custom agents
|
|
105
|
+
if (!this.item.isBuiltin && this.item.filePath) {
|
|
106
|
+
lines.push('');
|
|
107
|
+
lines.push(` ${s.muted('File:')} ${s.secondary(this.item.filePath)}`);
|
|
108
|
+
}
|
|
109
|
+
// Usage hint for built-in agents
|
|
110
|
+
if (this.item.isBuiltin) {
|
|
111
|
+
lines.push('');
|
|
112
|
+
lines.push(` ${s.muted('Usage:')}`);
|
|
113
|
+
lines.push(` ${s.secondary('This agent is invoked via the Task tool.')}`);
|
|
114
|
+
lines.push(` ${s.secondary(`Example: Task(subagent_type="${this.item.name}", prompt="...")`)}`);
|
|
115
|
+
}
|
|
75
116
|
lines.push('');
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
lines
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
117
|
+
lines.push(border);
|
|
118
|
+
// Show edit hint for custom agents
|
|
119
|
+
if (!this.item.isBuiltin) {
|
|
120
|
+
lines.push(` ${s.muted('e Edit · q/Esc Back')}`);
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
lines.push(` ${s.muted('q/Esc Back')}`);
|
|
124
|
+
}
|
|
125
|
+
lines.push(border);
|
|
126
|
+
return lines;
|
|
127
|
+
}
|
|
128
|
+
handleKey(data) {
|
|
129
|
+
// Ctrl+C closes everything
|
|
130
|
+
if (isCtrlC(data)) {
|
|
131
|
+
return closeOverlay(undefined);
|
|
132
|
+
}
|
|
133
|
+
// Escape or q - back to list
|
|
134
|
+
if (isEscape(data) || isClose(data)) {
|
|
135
|
+
return popScreen();
|
|
136
|
+
}
|
|
137
|
+
// 'e' opens edit screen for custom agents
|
|
138
|
+
const char = extractPrintable(data);
|
|
139
|
+
if (char === 'e' && !this.item.isBuiltin) {
|
|
140
|
+
const editScreen = new EditScreen(this.item, this.editState, this.styles);
|
|
141
|
+
this.onEdit(editScreen);
|
|
142
|
+
return stay();
|
|
143
|
+
}
|
|
144
|
+
return stay(false);
|
|
91
145
|
}
|
|
92
|
-
return lines;
|
|
93
|
-
}
|
|
94
|
-
function renderListFooter() {
|
|
95
|
-
const s = getStyles();
|
|
96
|
-
const lines = [];
|
|
97
|
-
lines.push('');
|
|
98
|
-
lines.push(s.muted(' ↑↓ Navigate · Tab Switch · Enter Select · Esc Close'));
|
|
99
|
-
return lines;
|
|
100
146
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
147
|
+
/**
|
|
148
|
+
* Screen for editing an existing custom agent.
|
|
149
|
+
* Allows editing: model, description, system prompt.
|
|
150
|
+
* Also allows deleting the agent.
|
|
151
|
+
*/
|
|
152
|
+
class EditScreen extends BaseScreen {
|
|
153
|
+
originalItem;
|
|
154
|
+
editState;
|
|
155
|
+
styles;
|
|
156
|
+
step = 'field-select';
|
|
157
|
+
selectedOption = 0;
|
|
158
|
+
inputBuffer = '';
|
|
159
|
+
error = null;
|
|
160
|
+
// Working copy of agent data (location is only 'project' | 'personal' since we don't edit built-in)
|
|
161
|
+
editedAgent;
|
|
162
|
+
constructor(originalItem, editState, styles) {
|
|
163
|
+
super();
|
|
164
|
+
this.originalItem = originalItem;
|
|
165
|
+
this.editState = editState;
|
|
166
|
+
this.styles = styles;
|
|
167
|
+
// Initialize with current values
|
|
168
|
+
// Custom agents can only be 'project' or 'personal', never 'builtin'
|
|
169
|
+
const loc = originalItem.location;
|
|
170
|
+
this.editedAgent = {
|
|
171
|
+
name: originalItem.name,
|
|
172
|
+
prompt: originalItem.systemPrompt ?? '',
|
|
173
|
+
description: originalItem.description,
|
|
174
|
+
model: originalItem.model,
|
|
175
|
+
location: (loc === 'project' || loc === 'personal') ? loc : 'project',
|
|
176
|
+
};
|
|
106
177
|
}
|
|
107
|
-
|
|
108
|
-
|
|
178
|
+
render() {
|
|
179
|
+
const s = this.styles;
|
|
180
|
+
const cols = terminal.getTerminalWidth();
|
|
181
|
+
const border = renderBorder(cols, s);
|
|
182
|
+
const lines = [];
|
|
183
|
+
lines.push(border);
|
|
184
|
+
lines.push(` ${s.primaryBold('Edit Agent:')} ${s.primary(this.originalItem.name)}`);
|
|
185
|
+
lines.push('');
|
|
186
|
+
switch (this.step) {
|
|
187
|
+
case 'field-select': {
|
|
188
|
+
lines.push(` ${s.secondary('Select field to edit:')}`);
|
|
189
|
+
lines.push('');
|
|
190
|
+
const fields = [
|
|
191
|
+
{ id: 'model', label: 'Model', value: this.editedAgent.model },
|
|
192
|
+
{ id: 'description', label: 'Description', value: this.truncate(this.editedAgent.description, 40) },
|
|
193
|
+
{ id: 'prompt', label: 'System Prompt', value: this.truncate(this.editedAgent.prompt, 40) },
|
|
194
|
+
{ id: 'save', label: 'Save Changes', value: '' },
|
|
195
|
+
{ id: 'delete', label: 'Delete Agent', value: '' },
|
|
196
|
+
{ id: 'cancel', label: 'Cancel', value: '' },
|
|
197
|
+
];
|
|
198
|
+
for (let i = 0; i < fields.length; i++) {
|
|
199
|
+
const f = fields[i];
|
|
200
|
+
const isSelected = this.selectedOption === i;
|
|
201
|
+
const prefix = isSelected ? s.primary('❯ ') : ' ';
|
|
202
|
+
if (f.id === 'save') {
|
|
203
|
+
const label = s.primary(f.label);
|
|
204
|
+
lines.push(` ${prefix}${isSelected ? label : s.muted(f.label)}`);
|
|
205
|
+
}
|
|
206
|
+
else if (f.id === 'delete') {
|
|
207
|
+
const label = s.error(f.label);
|
|
208
|
+
lines.push(` ${prefix}${isSelected ? label : s.muted(f.label)}`);
|
|
209
|
+
}
|
|
210
|
+
else if (f.id === 'cancel') {
|
|
211
|
+
lines.push(` ${prefix}${isSelected ? s.secondary(f.label) : s.muted(f.label)}`);
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
const label = `${f.label.padEnd(16)}${f.value}`;
|
|
215
|
+
lines.push(` ${prefix}${isSelected ? s.primary(label) : s.muted(label)}`);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
case 'edit-model': {
|
|
221
|
+
lines.push(` ${s.secondary('Select model')}`);
|
|
222
|
+
lines.push('');
|
|
223
|
+
const models = [
|
|
224
|
+
{ id: 'sonnet', label: 'Sonnet', desc: 'Balanced (recommended)' },
|
|
225
|
+
{ id: 'opus', label: 'Opus', desc: 'Most capable' },
|
|
226
|
+
{ id: 'haiku', label: 'Haiku', desc: 'Fast and efficient' },
|
|
227
|
+
{ id: 'inherit', label: 'Inherit', desc: "Use parent's model" },
|
|
228
|
+
];
|
|
229
|
+
for (let i = 0; i < models.length; i++) {
|
|
230
|
+
const m = models[i];
|
|
231
|
+
const isSelected = this.selectedOption === i;
|
|
232
|
+
const prefix = isSelected ? s.primary('❯ ') : ' ';
|
|
233
|
+
const current = this.editedAgent.model === m.id ? s.muted(' (current)') : '';
|
|
234
|
+
const label = `${String(i + 1)}. ${m.label.padEnd(10)} - ${m.desc}${current}`;
|
|
235
|
+
lines.push(` ${prefix}${isSelected ? s.primary(label) : s.muted(label)}`);
|
|
236
|
+
}
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
239
|
+
case 'edit-description':
|
|
240
|
+
lines.push(` ${s.secondary('Edit description')}`);
|
|
241
|
+
lines.push('');
|
|
242
|
+
lines.push(` When should the LLM use this agent?`);
|
|
243
|
+
lines.push(` > ${this.inputBuffer}█`);
|
|
244
|
+
lines.push('');
|
|
245
|
+
if (this.error) {
|
|
246
|
+
lines.push(` ${s.error(this.error)}`);
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
lines.push(` ${s.muted('Press Enter to save, Esc to cancel')}`);
|
|
250
|
+
}
|
|
251
|
+
break;
|
|
252
|
+
case 'edit-prompt':
|
|
253
|
+
lines.push(` ${s.secondary('Edit system prompt')}`);
|
|
254
|
+
lines.push('');
|
|
255
|
+
lines.push(` Enter the agent's instructions:`);
|
|
256
|
+
lines.push(` > ${this.inputBuffer}█`);
|
|
257
|
+
lines.push('');
|
|
258
|
+
if (this.error) {
|
|
259
|
+
lines.push(` ${s.error(this.error)}`);
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
lines.push(` ${s.muted('Press Enter to save, Esc to cancel')}`);
|
|
263
|
+
lines.push(` ${s.muted('(For multiline prompts, edit the .md file directly)')}`);
|
|
264
|
+
}
|
|
265
|
+
break;
|
|
266
|
+
case 'confirm-delete':
|
|
267
|
+
lines.push(` ${s.error('Delete this agent?')}`);
|
|
268
|
+
lines.push('');
|
|
269
|
+
lines.push(` ${s.muted('Name:')} ${s.primary(this.originalItem.name)}`);
|
|
270
|
+
lines.push(` ${s.muted('File:')} ${s.secondary(this.originalItem.filePath ?? 'unknown')}`);
|
|
271
|
+
lines.push('');
|
|
272
|
+
lines.push(this.selectedOption === 0
|
|
273
|
+
? ` ${s.error('❯ Yes, delete')}`
|
|
274
|
+
: ` ${s.muted(' Yes, delete')}`);
|
|
275
|
+
lines.push(this.selectedOption === 1
|
|
276
|
+
? ` ${s.primary('❯ No, cancel')}`
|
|
277
|
+
: ` ${s.muted(' No, cancel')}`);
|
|
278
|
+
break;
|
|
279
|
+
}
|
|
280
|
+
lines.push('');
|
|
281
|
+
lines.push(border);
|
|
282
|
+
lines.push(` ${s.muted('Esc Back')}`);
|
|
283
|
+
lines.push(border);
|
|
284
|
+
return lines;
|
|
109
285
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
lines.push(s.secondary(' Agent name (identifier)'));
|
|
139
|
-
lines.push('');
|
|
140
|
-
lines.push(' Enter a unique identifier:');
|
|
141
|
-
lines.push(` > ${state.wizardInputBuffer}█`);
|
|
142
|
-
lines.push('');
|
|
143
|
-
if (state.wizardError) {
|
|
144
|
-
lines.push(s.error(` ${state.wizardError}`));
|
|
286
|
+
handleKey(data) {
|
|
287
|
+
const char = extractPrintable(data);
|
|
288
|
+
// Ctrl+C closes everything
|
|
289
|
+
if (isCtrlC(data)) {
|
|
290
|
+
return closeOverlay(undefined);
|
|
291
|
+
}
|
|
292
|
+
// Escape goes back
|
|
293
|
+
if (isEscape(data)) {
|
|
294
|
+
return this.handleBack();
|
|
295
|
+
}
|
|
296
|
+
// Text input steps
|
|
297
|
+
if (this.step === 'edit-description' || this.step === 'edit-prompt') {
|
|
298
|
+
if (isEnter(data)) {
|
|
299
|
+
const text = this.inputBuffer.trim();
|
|
300
|
+
if (!text) {
|
|
301
|
+
this.error = 'Cannot be empty';
|
|
302
|
+
return stay();
|
|
303
|
+
}
|
|
304
|
+
if (this.step === 'edit-description') {
|
|
305
|
+
this.editedAgent.description = text;
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
this.editedAgent.prompt = text;
|
|
309
|
+
}
|
|
310
|
+
this.step = 'field-select';
|
|
311
|
+
this.inputBuffer = '';
|
|
312
|
+
this.error = null;
|
|
313
|
+
return stay();
|
|
145
314
|
}
|
|
146
|
-
|
|
147
|
-
|
|
315
|
+
if (isBackspace(data)) {
|
|
316
|
+
this.inputBuffer = this.inputBuffer.slice(0, -1);
|
|
317
|
+
this.error = null;
|
|
318
|
+
return stay();
|
|
148
319
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
lines.push(' Enter the agent\'s instructions:');
|
|
154
|
-
lines.push(` > ${state.wizardInputBuffer}█`);
|
|
155
|
-
lines.push('');
|
|
156
|
-
lines.push(s.muted(' This defines how the agent behaves.'));
|
|
157
|
-
lines.push(s.muted(' Press Enter to continue.'));
|
|
158
|
-
break;
|
|
159
|
-
case 'description':
|
|
160
|
-
lines.push(s.secondary(' Description'));
|
|
161
|
-
lines.push('');
|
|
162
|
-
lines.push(' When should the LLM use this agent?');
|
|
163
|
-
lines.push(` > ${state.wizardInputBuffer}█`);
|
|
164
|
-
lines.push('');
|
|
165
|
-
lines.push(s.muted(' This helps the LLM know when to invoke this agent.'));
|
|
166
|
-
break;
|
|
167
|
-
case 'model': {
|
|
168
|
-
lines.push(s.secondary(' Select model'));
|
|
169
|
-
lines.push('');
|
|
170
|
-
const models = [
|
|
171
|
-
{ id: 'sonnet', label: 'Sonnet', desc: 'Balanced (recommended)' },
|
|
172
|
-
{ id: 'opus', label: 'Opus', desc: 'Most capable' },
|
|
173
|
-
{ id: 'haiku', label: 'Haiku', desc: 'Fast and efficient' },
|
|
174
|
-
{ id: 'inherit', label: 'Inherit', desc: 'Use parent\'s model' },
|
|
175
|
-
];
|
|
176
|
-
for (let i = 0; i < models.length; i++) {
|
|
177
|
-
const m = models[i];
|
|
178
|
-
const isSelected = state.wizardSelectedOption === i;
|
|
179
|
-
const prefix = isSelected ? s.primary(' ❯ ') : ' ';
|
|
180
|
-
const label = isSelected
|
|
181
|
-
? s.primary(`${String(i + 1)}. ${m.label.padEnd(10)} - ${m.desc}`)
|
|
182
|
-
: s.muted(`${String(i + 1)}. ${m.label.padEnd(10)} - ${m.desc}`);
|
|
183
|
-
lines.push(prefix + label);
|
|
320
|
+
if (char) {
|
|
321
|
+
this.inputBuffer += char;
|
|
322
|
+
this.error = null;
|
|
323
|
+
return stay();
|
|
184
324
|
}
|
|
185
|
-
|
|
325
|
+
return stay(false);
|
|
186
326
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
? s.primary(' ❯ Save')
|
|
202
|
-
: s.muted(' Save'));
|
|
203
|
-
lines.push(state.wizardSelectedOption === 1
|
|
204
|
-
? s.primary(' ❯ Cancel')
|
|
205
|
-
: s.muted(' Cancel'));
|
|
206
|
-
break;
|
|
327
|
+
// Selection steps
|
|
328
|
+
const maxOptions = this.step === 'field-select' ? 6 : this.step === 'edit-model' ? 4 : 2;
|
|
329
|
+
if (isNavigateUp(data) && this.selectedOption > 0) {
|
|
330
|
+
this.selectedOption--;
|
|
331
|
+
return stay();
|
|
332
|
+
}
|
|
333
|
+
if (isNavigateDown(data) && this.selectedOption < maxOptions - 1) {
|
|
334
|
+
this.selectedOption++;
|
|
335
|
+
return stay();
|
|
336
|
+
}
|
|
337
|
+
if (isEnter(data)) {
|
|
338
|
+
return this.handleSelect();
|
|
339
|
+
}
|
|
340
|
+
return stay(false);
|
|
207
341
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
342
|
+
handleBack() {
|
|
343
|
+
switch (this.step) {
|
|
344
|
+
case 'field-select':
|
|
345
|
+
return popScreen();
|
|
346
|
+
case 'edit-model':
|
|
347
|
+
case 'edit-description':
|
|
348
|
+
case 'edit-prompt':
|
|
349
|
+
case 'confirm-delete':
|
|
350
|
+
this.step = 'field-select';
|
|
351
|
+
this.selectedOption = 0;
|
|
352
|
+
this.inputBuffer = '';
|
|
353
|
+
this.error = null;
|
|
354
|
+
break;
|
|
355
|
+
}
|
|
356
|
+
return stay();
|
|
357
|
+
}
|
|
358
|
+
handleSelect() {
|
|
359
|
+
switch (this.step) {
|
|
360
|
+
case 'field-select':
|
|
361
|
+
switch (this.selectedOption) {
|
|
362
|
+
case 0: { // Model
|
|
363
|
+
this.step = 'edit-model';
|
|
364
|
+
const models = ['sonnet', 'opus', 'haiku', 'inherit'];
|
|
365
|
+
this.selectedOption = models.indexOf(this.editedAgent.model);
|
|
366
|
+
if (this.selectedOption < 0)
|
|
367
|
+
this.selectedOption = 0;
|
|
368
|
+
break;
|
|
369
|
+
}
|
|
370
|
+
case 1: // Description
|
|
371
|
+
this.step = 'edit-description';
|
|
372
|
+
this.inputBuffer = this.editedAgent.description;
|
|
373
|
+
break;
|
|
374
|
+
case 2: // System Prompt
|
|
375
|
+
this.step = 'edit-prompt';
|
|
376
|
+
this.inputBuffer = this.editedAgent.prompt;
|
|
377
|
+
break;
|
|
378
|
+
case 3: // Save
|
|
379
|
+
return this.saveAgent();
|
|
380
|
+
case 4: // Delete
|
|
381
|
+
this.step = 'confirm-delete';
|
|
382
|
+
this.selectedOption = 1; // Default to "No"
|
|
383
|
+
break;
|
|
384
|
+
case 5: // Cancel
|
|
385
|
+
return popScreen();
|
|
386
|
+
}
|
|
387
|
+
break;
|
|
388
|
+
case 'edit-model': {
|
|
389
|
+
const models = ['sonnet', 'opus', 'haiku', 'inherit'];
|
|
390
|
+
this.editedAgent.model = models[this.selectedOption];
|
|
391
|
+
this.step = 'field-select';
|
|
392
|
+
this.selectedOption = 0;
|
|
393
|
+
break;
|
|
394
|
+
}
|
|
395
|
+
case 'confirm-delete':
|
|
396
|
+
if (this.selectedOption === 0) {
|
|
397
|
+
// Delete
|
|
398
|
+
return this.deleteAgent();
|
|
399
|
+
}
|
|
400
|
+
else {
|
|
401
|
+
// Cancel
|
|
402
|
+
this.step = 'field-select';
|
|
403
|
+
this.selectedOption = 0;
|
|
404
|
+
}
|
|
405
|
+
break;
|
|
406
|
+
}
|
|
407
|
+
return stay();
|
|
408
|
+
}
|
|
409
|
+
saveAgent() {
|
|
410
|
+
try {
|
|
411
|
+
this.editState.registry.saveAgent({
|
|
412
|
+
name: this.editedAgent.name,
|
|
413
|
+
description: this.editedAgent.description,
|
|
414
|
+
model: this.editedAgent.model,
|
|
415
|
+
systemPrompt: this.editedAgent.prompt,
|
|
416
|
+
}, this.editedAgent.location);
|
|
417
|
+
this.editState.registry.load();
|
|
418
|
+
// Pop twice: EditScreen -> DetailScreen -> List
|
|
419
|
+
return popScreen();
|
|
420
|
+
}
|
|
421
|
+
catch (error) {
|
|
422
|
+
this.error = error.message;
|
|
423
|
+
return stay();
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
deleteAgent() {
|
|
427
|
+
try {
|
|
428
|
+
this.editState.registry.deleteAgent(this.originalItem.name);
|
|
429
|
+
this.editState.registry.load();
|
|
430
|
+
// Pop twice: EditScreen -> DetailScreen -> List
|
|
431
|
+
return popScreen();
|
|
432
|
+
}
|
|
433
|
+
catch (error) {
|
|
434
|
+
this.error = error.message;
|
|
435
|
+
return stay();
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
truncate(text, max) {
|
|
439
|
+
if (!text)
|
|
440
|
+
return '';
|
|
441
|
+
if (text.length <= max)
|
|
442
|
+
return text;
|
|
443
|
+
return text.slice(0, max - 3) + '...';
|
|
218
444
|
}
|
|
219
|
-
return buildListLines(state);
|
|
220
|
-
}
|
|
221
|
-
function render(state, prevLineCount) {
|
|
222
|
-
const lines = buildLines(state);
|
|
223
|
-
// Clear previous content
|
|
224
|
-
terminal.clearLinesAbove(prevLineCount);
|
|
225
|
-
// Write new content
|
|
226
|
-
terminal.write(lines.join('\n'));
|
|
227
|
-
return lines.length;
|
|
228
445
|
}
|
|
229
446
|
// =============================================================================
|
|
230
|
-
//
|
|
447
|
+
// Wizard Screen (Multi-Step Agent Creation)
|
|
231
448
|
// =============================================================================
|
|
232
449
|
/**
|
|
233
|
-
*
|
|
450
|
+
* Screen for creating a new agent via multi-step wizard.
|
|
451
|
+
* Steps: location, name, prompt, description, model, confirm
|
|
234
452
|
*/
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
wizardSelectedOption: 0,
|
|
249
|
-
wizardInputBuffer: '',
|
|
250
|
-
wizardError: null,
|
|
251
|
-
registry,
|
|
453
|
+
class WizardScreen extends BaseScreen {
|
|
454
|
+
editState;
|
|
455
|
+
styles;
|
|
456
|
+
step = 'location';
|
|
457
|
+
selectedOption = 0;
|
|
458
|
+
inputBuffer = '';
|
|
459
|
+
error = null;
|
|
460
|
+
newAgent = {
|
|
461
|
+
location: 'project',
|
|
462
|
+
name: '',
|
|
463
|
+
prompt: '',
|
|
464
|
+
description: '',
|
|
465
|
+
model: 'sonnet',
|
|
252
466
|
};
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
// Reset wizard state for a new creation
|
|
268
|
-
const resetWizard = () => {
|
|
269
|
-
state.wizardStep = 'location';
|
|
270
|
-
state.wizardLocation = 'project';
|
|
271
|
-
state.wizardName = '';
|
|
272
|
-
state.wizardPrompt = '';
|
|
273
|
-
state.wizardDescription = '';
|
|
274
|
-
state.wizardModel = 'sonnet';
|
|
275
|
-
state.wizardSelectedOption = 0;
|
|
276
|
-
state.wizardInputBuffer = '';
|
|
277
|
-
state.wizardError = null;
|
|
278
|
-
};
|
|
279
|
-
// Wizard: advance to next step
|
|
280
|
-
const wizardNextStep = () => {
|
|
281
|
-
switch (state.wizardStep) {
|
|
467
|
+
constructor(editState, styles) {
|
|
468
|
+
super();
|
|
469
|
+
this.editState = editState;
|
|
470
|
+
this.styles = styles;
|
|
471
|
+
}
|
|
472
|
+
render() {
|
|
473
|
+
const s = this.styles;
|
|
474
|
+
const cols = terminal.getTerminalWidth();
|
|
475
|
+
const border = renderBorder(cols, s);
|
|
476
|
+
const lines = [];
|
|
477
|
+
lines.push(border);
|
|
478
|
+
lines.push(` ${s.primaryBold('Create New Agent')}`);
|
|
479
|
+
lines.push('');
|
|
480
|
+
switch (this.step) {
|
|
282
481
|
case 'location':
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
482
|
+
lines.push(` ${s.secondary('Choose location')}`);
|
|
483
|
+
lines.push('');
|
|
484
|
+
lines.push(this.selectedOption === 0
|
|
485
|
+
? ` ${s.primary('❯ 1. Project (.compilr-dev/agents/)')}`
|
|
486
|
+
: ` ${s.muted(' 1. Project (.compilr-dev/agents/)')}`);
|
|
487
|
+
lines.push(this.selectedOption === 1
|
|
488
|
+
? ` ${s.primary('❯ 2. Personal (~/.compilr-dev/agents/)')}`
|
|
489
|
+
: ` ${s.muted(' 2. Personal (~/.compilr-dev/agents/)')}`);
|
|
490
|
+
lines.push('');
|
|
491
|
+
lines.push(` ${s.muted('Project agents are shared with your team.')}`);
|
|
492
|
+
lines.push(` ${s.muted('Personal agents apply to all your projects.')}`);
|
|
286
493
|
break;
|
|
287
494
|
case 'name':
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
495
|
+
lines.push(` ${s.secondary('Agent name (identifier)')}`);
|
|
496
|
+
lines.push('');
|
|
497
|
+
lines.push(` Enter a unique identifier:`);
|
|
498
|
+
lines.push(` > ${this.inputBuffer}█`);
|
|
499
|
+
lines.push('');
|
|
500
|
+
if (this.error) {
|
|
501
|
+
lines.push(` ${s.error(this.error)}`);
|
|
502
|
+
}
|
|
503
|
+
else {
|
|
504
|
+
lines.push(` ${s.muted('Use lowercase letters, numbers, hyphens (e.g., code-reviewer)')}`);
|
|
505
|
+
}
|
|
291
506
|
break;
|
|
292
507
|
case 'prompt':
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
508
|
+
lines.push(` ${s.secondary('System prompt')}`);
|
|
509
|
+
lines.push('');
|
|
510
|
+
lines.push(` Enter the agent's instructions:`);
|
|
511
|
+
lines.push(` > ${this.inputBuffer}█`);
|
|
512
|
+
lines.push('');
|
|
513
|
+
lines.push(` ${s.muted('This defines how the agent behaves.')}`);
|
|
514
|
+
lines.push(` ${s.muted('Press Enter to continue.')}`);
|
|
296
515
|
break;
|
|
297
516
|
case 'description':
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
517
|
+
lines.push(` ${s.secondary('Description')}`);
|
|
518
|
+
lines.push('');
|
|
519
|
+
lines.push(` When should the LLM use this agent?`);
|
|
520
|
+
lines.push(` > ${this.inputBuffer}█`);
|
|
521
|
+
lines.push('');
|
|
522
|
+
lines.push(` ${s.muted('This helps the LLM know when to invoke this agent.')}`);
|
|
301
523
|
break;
|
|
302
524
|
case 'model': {
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
525
|
+
lines.push(` ${s.secondary('Select model')}`);
|
|
526
|
+
lines.push('');
|
|
527
|
+
const models = [
|
|
528
|
+
{ id: 'sonnet', label: 'Sonnet', desc: 'Balanced (recommended)' },
|
|
529
|
+
{ id: 'opus', label: 'Opus', desc: 'Most capable' },
|
|
530
|
+
{ id: 'haiku', label: 'Haiku', desc: 'Fast and efficient' },
|
|
531
|
+
{ id: 'inherit', label: 'Inherit', desc: "Use parent's model" },
|
|
532
|
+
];
|
|
533
|
+
for (let i = 0; i < models.length; i++) {
|
|
534
|
+
const m = models[i];
|
|
535
|
+
const isSelected = this.selectedOption === i;
|
|
536
|
+
const prefix = isSelected ? s.primary('❯ ') : ' ';
|
|
537
|
+
const label = `${String(i + 1)}. ${m.label.padEnd(10)} - ${m.desc}`;
|
|
538
|
+
lines.push(` ${prefix}${isSelected ? s.primary(label) : s.muted(label)}`);
|
|
539
|
+
}
|
|
307
540
|
break;
|
|
308
541
|
}
|
|
309
|
-
case 'confirm':
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
542
|
+
case 'confirm': {
|
|
543
|
+
lines.push(` ${s.secondary('Confirm')}`);
|
|
544
|
+
lines.push('');
|
|
545
|
+
lines.push(` Name: ${s.primary(this.newAgent.name)}`);
|
|
546
|
+
lines.push(` Location: ${s.primary(this.newAgent.location === 'project' ? '.compilr-dev/agents/' : '~/.compilr-dev/agents/')}${this.newAgent.name}.md`);
|
|
547
|
+
lines.push(` Model: ${s.primary(this.newAgent.model)}`);
|
|
548
|
+
lines.push('');
|
|
549
|
+
lines.push(` ${s.secondary('Description:')}`);
|
|
550
|
+
const descPreview = this.newAgent.description.length > 60
|
|
551
|
+
? this.newAgent.description.slice(0, 57) + '...'
|
|
552
|
+
: this.newAgent.description;
|
|
553
|
+
lines.push(` ${s.muted(descPreview)}`);
|
|
554
|
+
lines.push('');
|
|
555
|
+
lines.push(` ${s.secondary('System prompt:')}`);
|
|
556
|
+
const promptPreview = this.newAgent.prompt.length > 60
|
|
557
|
+
? this.newAgent.prompt.slice(0, 57) + '...'
|
|
558
|
+
: this.newAgent.prompt;
|
|
559
|
+
lines.push(` ${s.muted(promptPreview)}`);
|
|
560
|
+
lines.push('');
|
|
561
|
+
lines.push(this.selectedOption === 0
|
|
562
|
+
? ` ${s.primary('❯ Save')}`
|
|
563
|
+
: ` ${s.muted(' Save')}`);
|
|
564
|
+
lines.push(this.selectedOption === 1
|
|
565
|
+
? ` ${s.primary('❯ Cancel')}`
|
|
566
|
+
: ` ${s.muted(' Cancel')}`);
|
|
567
|
+
break;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
lines.push('');
|
|
571
|
+
lines.push(border);
|
|
572
|
+
lines.push(` ${s.muted('Esc Back')}`);
|
|
573
|
+
lines.push(border);
|
|
574
|
+
return lines;
|
|
575
|
+
}
|
|
576
|
+
handleKey(data) {
|
|
577
|
+
const char = extractPrintable(data);
|
|
578
|
+
// Ctrl+C closes everything
|
|
579
|
+
if (isCtrlC(data)) {
|
|
580
|
+
return closeOverlay(undefined);
|
|
581
|
+
}
|
|
582
|
+
// Escape goes back
|
|
583
|
+
if (isEscape(data)) {
|
|
584
|
+
return this.handleBack();
|
|
585
|
+
}
|
|
586
|
+
// Input steps: name, prompt, description
|
|
587
|
+
if (this.step === 'name' || this.step === 'prompt' || this.step === 'description') {
|
|
588
|
+
if (isEnter(data)) {
|
|
589
|
+
const text = this.inputBuffer.trim();
|
|
590
|
+
if (!text) {
|
|
591
|
+
return stay(false);
|
|
592
|
+
}
|
|
593
|
+
// Validate name
|
|
594
|
+
if (this.step === 'name') {
|
|
595
|
+
if (!/^[a-z][a-z0-9-]{1,49}$/.test(text)) {
|
|
596
|
+
this.error = 'Invalid name. Use lowercase letters, numbers, hyphens.';
|
|
597
|
+
return stay();
|
|
324
598
|
}
|
|
325
|
-
|
|
326
|
-
|
|
599
|
+
if (this.editState.registry.hasAgent(text)) {
|
|
600
|
+
this.error = `Agent "${text}" already exists.`;
|
|
601
|
+
return stay();
|
|
327
602
|
}
|
|
603
|
+
this.newAgent.name = text;
|
|
604
|
+
this.step = 'prompt';
|
|
605
|
+
this.inputBuffer = '';
|
|
606
|
+
this.error = null;
|
|
607
|
+
}
|
|
608
|
+
else if (this.step === 'prompt') {
|
|
609
|
+
this.newAgent.prompt = text;
|
|
610
|
+
this.step = 'description';
|
|
611
|
+
this.inputBuffer = '';
|
|
328
612
|
}
|
|
329
613
|
else {
|
|
330
|
-
|
|
331
|
-
|
|
614
|
+
this.newAgent.description = text;
|
|
615
|
+
this.step = 'model';
|
|
616
|
+
this.selectedOption = 0;
|
|
332
617
|
}
|
|
333
|
-
|
|
618
|
+
return stay();
|
|
619
|
+
}
|
|
620
|
+
if (isBackspace(data)) {
|
|
621
|
+
this.inputBuffer = this.inputBuffer.slice(0, -1);
|
|
622
|
+
this.error = null;
|
|
623
|
+
return stay();
|
|
624
|
+
}
|
|
625
|
+
if (char) {
|
|
626
|
+
this.inputBuffer += char;
|
|
627
|
+
this.error = null;
|
|
628
|
+
return stay();
|
|
629
|
+
}
|
|
630
|
+
return stay(false);
|
|
334
631
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
632
|
+
// Selection steps: location, model, confirm
|
|
633
|
+
const maxOptions = this.step === 'model' ? 4 : 2;
|
|
634
|
+
if (isNavigateUp(data) && this.selectedOption > 0) {
|
|
635
|
+
this.selectedOption--;
|
|
636
|
+
return stay();
|
|
637
|
+
}
|
|
638
|
+
if (isNavigateDown(data) && this.selectedOption < maxOptions - 1) {
|
|
639
|
+
this.selectedOption++;
|
|
640
|
+
return stay();
|
|
641
|
+
}
|
|
642
|
+
if (isEnter(data)) {
|
|
643
|
+
return this.handleSelect();
|
|
644
|
+
}
|
|
645
|
+
return stay(false);
|
|
646
|
+
}
|
|
647
|
+
handleBack() {
|
|
648
|
+
switch (this.step) {
|
|
341
649
|
case 'location':
|
|
342
|
-
|
|
343
|
-
state.mode = 'list';
|
|
344
|
-
break;
|
|
650
|
+
return popScreen();
|
|
345
651
|
case 'name':
|
|
346
|
-
|
|
347
|
-
|
|
652
|
+
this.step = 'location';
|
|
653
|
+
this.selectedOption = this.newAgent.location === 'project' ? 0 : 1;
|
|
348
654
|
break;
|
|
349
655
|
case 'prompt':
|
|
350
|
-
|
|
351
|
-
|
|
656
|
+
this.step = 'name';
|
|
657
|
+
this.inputBuffer = this.newAgent.name;
|
|
352
658
|
break;
|
|
353
659
|
case 'description':
|
|
354
|
-
|
|
355
|
-
|
|
660
|
+
this.step = 'prompt';
|
|
661
|
+
this.inputBuffer = this.newAgent.prompt;
|
|
356
662
|
break;
|
|
357
663
|
case 'model':
|
|
358
|
-
|
|
359
|
-
|
|
664
|
+
this.step = 'description';
|
|
665
|
+
this.inputBuffer = this.newAgent.description;
|
|
360
666
|
break;
|
|
361
667
|
case 'confirm': {
|
|
362
|
-
|
|
668
|
+
this.step = 'model';
|
|
363
669
|
const models = ['sonnet', 'opus', 'haiku', 'inherit'];
|
|
364
|
-
|
|
670
|
+
this.selectedOption = models.indexOf(this.newAgent.model);
|
|
365
671
|
break;
|
|
366
672
|
}
|
|
367
673
|
}
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
674
|
+
this.error = null;
|
|
675
|
+
return stay();
|
|
676
|
+
}
|
|
677
|
+
handleSelect() {
|
|
678
|
+
switch (this.step) {
|
|
679
|
+
case 'location':
|
|
680
|
+
this.newAgent.location = this.selectedOption === 0 ? 'project' : 'personal';
|
|
681
|
+
this.step = 'name';
|
|
682
|
+
this.inputBuffer = '';
|
|
683
|
+
break;
|
|
684
|
+
case 'model': {
|
|
685
|
+
const models = ['sonnet', 'opus', 'haiku', 'inherit'];
|
|
686
|
+
this.newAgent.model = models[this.selectedOption];
|
|
687
|
+
this.step = 'confirm';
|
|
688
|
+
this.selectedOption = 0;
|
|
689
|
+
break;
|
|
377
690
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
691
|
+
case 'confirm':
|
|
692
|
+
if (this.selectedOption === 0) {
|
|
693
|
+
// Save
|
|
694
|
+
try {
|
|
695
|
+
this.editState.registry.saveAgent({
|
|
696
|
+
name: this.newAgent.name,
|
|
697
|
+
description: this.newAgent.description,
|
|
698
|
+
model: this.newAgent.model,
|
|
699
|
+
systemPrompt: this.newAgent.prompt,
|
|
700
|
+
}, this.newAgent.location);
|
|
701
|
+
this.editState.registry.load();
|
|
702
|
+
return popScreen();
|
|
703
|
+
}
|
|
704
|
+
catch (error) {
|
|
705
|
+
this.error = error.message;
|
|
706
|
+
return stay();
|
|
707
|
+
}
|
|
394
708
|
}
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
lineCount = render(state, lineCount);
|
|
399
|
-
return;
|
|
709
|
+
else {
|
|
710
|
+
// Cancel
|
|
711
|
+
return popScreen();
|
|
400
712
|
}
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
713
|
+
}
|
|
714
|
+
return stay();
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
// =============================================================================
|
|
718
|
+
// Agents Overlay
|
|
719
|
+
// =============================================================================
|
|
720
|
+
class AgentsOverlay extends TabbedListOverlay {
|
|
721
|
+
editState;
|
|
722
|
+
constructor() {
|
|
723
|
+
const registry = getAgentRegistry();
|
|
724
|
+
registry.load();
|
|
725
|
+
// Build items from registry
|
|
726
|
+
const items = AgentsOverlay.buildItems(registry);
|
|
727
|
+
const config = {
|
|
728
|
+
title: 'Agents',
|
|
729
|
+
tabs: TABS,
|
|
730
|
+
items,
|
|
731
|
+
pageSize: 12,
|
|
732
|
+
detailScreensFullScreen: false,
|
|
733
|
+
filterByTab: (item, tabId) => {
|
|
734
|
+
if (tabId === 'builtin')
|
|
735
|
+
return item.isBuiltin;
|
|
736
|
+
return !item.isBuiltin;
|
|
737
|
+
},
|
|
738
|
+
getSearchText: (item) => `${item.name} ${item.description}`,
|
|
739
|
+
renderItem: (item, isSelected, styles) => {
|
|
740
|
+
const prefix = isSelected ? styles.primary('❯ ') : ' ';
|
|
741
|
+
// Special "Create new agent" option
|
|
742
|
+
if (item.isCreateNew) {
|
|
743
|
+
return isSelected
|
|
744
|
+
? `${prefix}${styles.primary('Create new agent')}`
|
|
745
|
+
: `${prefix}${styles.muted('Create new agent')}`;
|
|
405
746
|
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
747
|
+
const name = `${item.name} · ${item.model}`;
|
|
748
|
+
const nameStyled = isSelected
|
|
749
|
+
? styles.primary(name.padEnd(30))
|
|
750
|
+
: styles.secondary(name.padEnd(30));
|
|
751
|
+
if (item.isBuiltin) {
|
|
752
|
+
return `${prefix}${nameStyled}${styles.muted(item.description)}`;
|
|
410
753
|
}
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
return;
|
|
754
|
+
else {
|
|
755
|
+
return `${prefix}${nameStyled}${styles.muted(`(${item.location ?? 'unknown'})`)}`;
|
|
756
|
+
}
|
|
757
|
+
},
|
|
758
|
+
showCount: true,
|
|
759
|
+
emptyMessage: 'No agents found.',
|
|
760
|
+
noResultsMessage: 'No agents match the search.',
|
|
761
|
+
footerHints: (searchMode) => {
|
|
762
|
+
if (searchMode) {
|
|
763
|
+
return 'Type to search · Enter/Esc Exit search · Backspace Delete';
|
|
422
764
|
}
|
|
765
|
+
return '/ Search · ↑↓/jk Navigate · Tab Switch tabs · Enter Details · q/Esc Close';
|
|
766
|
+
},
|
|
767
|
+
};
|
|
768
|
+
super(config);
|
|
769
|
+
this.editState = { registry };
|
|
770
|
+
}
|
|
771
|
+
static buildItems(registry) {
|
|
772
|
+
const items = [];
|
|
773
|
+
// Add built-in agents
|
|
774
|
+
for (const agent of registry.getBuiltinAgents()) {
|
|
775
|
+
items.push(AgentsOverlay.agentToItem(agent, true));
|
|
776
|
+
}
|
|
777
|
+
// Add custom agents
|
|
778
|
+
for (const agent of registry.getCustomAgents()) {
|
|
779
|
+
items.push(AgentsOverlay.agentToItem(agent, false));
|
|
780
|
+
}
|
|
781
|
+
// Add "Create new agent" option for custom tab
|
|
782
|
+
items.push({
|
|
783
|
+
name: '',
|
|
784
|
+
model: '',
|
|
785
|
+
description: '',
|
|
786
|
+
isBuiltin: false,
|
|
787
|
+
isCreateNew: true,
|
|
788
|
+
});
|
|
789
|
+
return items;
|
|
790
|
+
}
|
|
791
|
+
static agentToItem(agent, isBuiltin) {
|
|
792
|
+
return {
|
|
793
|
+
name: agent.name,
|
|
794
|
+
model: agent.model,
|
|
795
|
+
description: agent.description,
|
|
796
|
+
location: agent.location,
|
|
797
|
+
systemPrompt: agent.systemPrompt,
|
|
798
|
+
filePath: agent.filePath,
|
|
799
|
+
isBuiltin,
|
|
800
|
+
};
|
|
801
|
+
}
|
|
802
|
+
createDetailScreen(item) {
|
|
803
|
+
// "Create new agent" opens the wizard
|
|
804
|
+
if (item.isCreateNew) {
|
|
805
|
+
return new WizardScreen(this.editState, this.styles);
|
|
806
|
+
}
|
|
807
|
+
// All other agents open the detail view
|
|
808
|
+
// The onEdit callback pushes the edit screen when user presses 'e'
|
|
809
|
+
return new DetailScreen(item, this.styles, this.editState, (editScreen) => {
|
|
810
|
+
this.screenStack.push(editScreen);
|
|
811
|
+
this.update();
|
|
812
|
+
});
|
|
813
|
+
}
|
|
814
|
+
handleKey(data) {
|
|
815
|
+
// Only intercept when on the main list screen
|
|
816
|
+
if (this.screenStack.size() === 1) {
|
|
817
|
+
// Ctrl+C always closes
|
|
818
|
+
if (isCtrlC(data)) {
|
|
819
|
+
this.close(undefined);
|
|
423
820
|
return;
|
|
424
821
|
}
|
|
425
|
-
//
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
822
|
+
// Only handle custom keys when not in search mode
|
|
823
|
+
if (!this.state.searchMode) {
|
|
824
|
+
const char = extractPrintable(data);
|
|
825
|
+
// 'q' or Esc closes
|
|
826
|
+
if (char === 'q' || isEscape(data)) {
|
|
827
|
+
this.close(undefined);
|
|
431
828
|
return;
|
|
432
829
|
}
|
|
433
|
-
if (isEscape) {
|
|
434
|
-
wizardPrevStep();
|
|
435
|
-
lineCount = render(state, lineCount);
|
|
436
|
-
return;
|
|
437
|
-
}
|
|
438
|
-
// Input steps: name, prompt, description
|
|
439
|
-
if (['name', 'prompt', 'description'].includes(state.wizardStep)) {
|
|
440
|
-
if (isEnter) {
|
|
441
|
-
if (state.wizardInputBuffer.trim()) {
|
|
442
|
-
// Validate name
|
|
443
|
-
if (state.wizardStep === 'name') {
|
|
444
|
-
const name = state.wizardInputBuffer.trim();
|
|
445
|
-
if (!/^[a-z][a-z0-9-]{1,49}$/.test(name)) {
|
|
446
|
-
state.wizardError = 'Invalid name. Use lowercase letters, numbers, hyphens.';
|
|
447
|
-
lineCount = render(state, lineCount);
|
|
448
|
-
return;
|
|
449
|
-
}
|
|
450
|
-
if (registry.hasAgent(name)) {
|
|
451
|
-
state.wizardError = `Agent "${name}" already exists.`;
|
|
452
|
-
lineCount = render(state, lineCount);
|
|
453
|
-
return;
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
wizardNextStep();
|
|
457
|
-
lineCount = render(state, lineCount);
|
|
458
|
-
}
|
|
459
|
-
return;
|
|
460
|
-
}
|
|
461
|
-
if (isBackspace) {
|
|
462
|
-
state.wizardInputBuffer = state.wizardInputBuffer.slice(0, -1);
|
|
463
|
-
state.wizardError = null;
|
|
464
|
-
lineCount = render(state, lineCount);
|
|
465
|
-
return;
|
|
466
|
-
}
|
|
467
|
-
// Regular character input
|
|
468
|
-
const char = data.toString('utf-8');
|
|
469
|
-
if (char.length === 1 && char.charCodeAt(0) >= 32) {
|
|
470
|
-
state.wizardInputBuffer += char;
|
|
471
|
-
state.wizardError = null;
|
|
472
|
-
lineCount = render(state, lineCount);
|
|
473
|
-
}
|
|
474
|
-
return;
|
|
475
|
-
}
|
|
476
|
-
// Selection steps: location, model, confirm
|
|
477
|
-
if (['location', 'model', 'confirm'].includes(state.wizardStep)) {
|
|
478
|
-
let maxOptions = 2;
|
|
479
|
-
if (state.wizardStep === 'model')
|
|
480
|
-
maxOptions = 4;
|
|
481
|
-
if (isUpArrow && state.wizardSelectedOption > 0) {
|
|
482
|
-
state.wizardSelectedOption--;
|
|
483
|
-
lineCount = render(state, lineCount);
|
|
484
|
-
return;
|
|
485
|
-
}
|
|
486
|
-
if (isDownArrow && state.wizardSelectedOption < maxOptions - 1) {
|
|
487
|
-
state.wizardSelectedOption++;
|
|
488
|
-
lineCount = render(state, lineCount);
|
|
489
|
-
return;
|
|
490
|
-
}
|
|
491
|
-
if (isEnter) {
|
|
492
|
-
wizardNextStep();
|
|
493
|
-
lineCount = render(state, lineCount);
|
|
494
|
-
return;
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
830
|
}
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
|
|
831
|
+
}
|
|
832
|
+
// After wizard completes, rebuild items
|
|
833
|
+
const prevStackSize = this.screenStack.size();
|
|
834
|
+
super.handleKey(data);
|
|
835
|
+
// If we just popped from wizard, refresh items
|
|
836
|
+
if (prevStackSize > 1 && this.screenStack.size() === 1) {
|
|
837
|
+
this.refreshItems();
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
refreshItems() {
|
|
841
|
+
this.editState.registry.load();
|
|
842
|
+
const items = AgentsOverlay.buildItems(this.editState.registry);
|
|
843
|
+
this.state.items = items;
|
|
844
|
+
// Re-apply filters
|
|
845
|
+
const currentTabId = this.listConfig.tabs[this.state.currentTab]?.id ?? 'builtin';
|
|
846
|
+
let filtered = items.filter((item) => this.listConfig.filterByTab(item, currentTabId));
|
|
847
|
+
if (this.state.searchQuery) {
|
|
848
|
+
const query = this.state.searchQuery.toLowerCase();
|
|
849
|
+
filtered = filtered.filter((item) => this.listConfig.getSearchText(item).toLowerCase().includes(query));
|
|
850
|
+
}
|
|
851
|
+
this.state.filteredItems = filtered;
|
|
852
|
+
// Clamp selected index
|
|
853
|
+
if (this.state.selectedIndex >= filtered.length) {
|
|
854
|
+
this.state.selectedIndex = Math.max(0, filtered.length - 1);
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
// =============================================================================
|
|
859
|
+
// Export Function (Backward Compatible)
|
|
860
|
+
// =============================================================================
|
|
861
|
+
export async function showAgentsOverlay() {
|
|
862
|
+
return new AgentsOverlay().show();
|
|
501
863
|
}
|