@compilr-dev/cli 0.4.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 +110 -0
- package/dist/agent.d.ts +62 -0
- package/dist/agent.js +317 -0
- package/dist/agents/registry.d.ts +66 -0
- package/dist/agents/registry.js +238 -0
- package/dist/agents/types.d.ts +40 -0
- package/dist/agents/types.js +94 -0
- package/dist/commands/custom-registry.d.ts +69 -0
- package/dist/commands/custom-registry.js +246 -0
- package/dist/commands/index.d.ts +7 -0
- package/dist/commands/index.js +7 -0
- package/dist/commands/types.d.ts +31 -0
- package/dist/commands/types.js +26 -0
- package/dist/commands.d.ts +63 -0
- package/dist/commands.js +324 -0
- package/dist/db/index.d.ts +42 -0
- package/dist/db/index.js +146 -0
- package/dist/db/repositories/document-repository.d.ts +63 -0
- package/dist/db/repositories/document-repository.js +184 -0
- package/dist/db/repositories/index.d.ts +9 -0
- package/dist/db/repositories/index.js +6 -0
- package/dist/db/repositories/project-repository.d.ts +132 -0
- package/dist/db/repositories/project-repository.js +337 -0
- package/dist/db/repositories/work-item-repository.d.ts +115 -0
- package/dist/db/repositories/work-item-repository.js +389 -0
- package/dist/db/schema.d.ts +83 -0
- package/dist/db/schema.js +143 -0
- package/dist/debug.d.ts +8 -0
- package/dist/debug.js +48 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +348 -0
- package/dist/index.old.d.ts +7 -0
- package/dist/index.old.js +1014 -0
- package/dist/repl.d.ts +121 -0
- package/dist/repl.js +1878 -0
- package/dist/settings/index.d.ts +80 -0
- package/dist/settings/index.js +195 -0
- package/dist/shared-handlers.d.ts +63 -0
- package/dist/shared-handlers.js +57 -0
- package/dist/slash-autocomplete.d.ts +41 -0
- package/dist/slash-autocomplete.js +638 -0
- package/dist/state.d.ts +75 -0
- package/dist/state.js +130 -0
- package/dist/tabbed-menu.d.ts +11 -0
- package/dist/tabbed-menu.js +328 -0
- package/dist/templates/backlog-md.d.ts +7 -0
- package/dist/templates/backlog-md.js +94 -0
- package/dist/templates/claude-md.d.ts +7 -0
- package/dist/templates/claude-md.js +189 -0
- package/dist/templates/coding-standards.d.ts +7 -0
- package/dist/templates/coding-standards.js +299 -0
- package/dist/templates/compilr-md.d.ts +7 -0
- package/dist/templates/compilr-md.js +189 -0
- package/dist/templates/config-json.d.ts +38 -0
- package/dist/templates/config-json.js +39 -0
- package/dist/templates/gitignore.d.ts +7 -0
- package/dist/templates/gitignore.js +85 -0
- package/dist/templates/index.d.ts +19 -0
- package/dist/templates/index.js +302 -0
- package/dist/templates/package-json.d.ts +7 -0
- package/dist/templates/package-json.js +111 -0
- package/dist/templates/readme-md.d.ts +7 -0
- package/dist/templates/readme-md.js +161 -0
- package/dist/templates/tsconfig.d.ts +7 -0
- package/dist/templates/tsconfig.js +61 -0
- package/dist/templates/types.d.ts +33 -0
- package/dist/templates/types.js +24 -0
- package/dist/test-autocomplete.d.ts +7 -0
- package/dist/test-autocomplete.js +85 -0
- package/dist/test-tabbed-menu.d.ts +7 -0
- package/dist/test-tabbed-menu.js +25 -0
- package/dist/themes/colors.d.ts +49 -0
- package/dist/themes/colors.js +135 -0
- package/dist/themes/index.d.ts +23 -0
- package/dist/themes/index.js +24 -0
- package/dist/themes/registry.d.ts +60 -0
- package/dist/themes/registry.js +195 -0
- package/dist/themes/types.d.ts +82 -0
- package/dist/themes/types.js +7 -0
- package/dist/tool-selector.d.ts +71 -0
- package/dist/tool-selector.js +184 -0
- package/dist/tools/ask-user-simple.d.ts +19 -0
- package/dist/tools/ask-user-simple.js +86 -0
- package/dist/tools/ask-user.d.ts +32 -0
- package/dist/tools/ask-user.js +113 -0
- package/dist/tools/backlog.d.ts +53 -0
- package/dist/tools/backlog.js +709 -0
- package/dist/tools.d.ts +15 -0
- package/dist/tools.js +121 -0
- package/dist/ui/agents-overlay.d.ts +12 -0
- package/dist/ui/agents-overlay.js +501 -0
- package/dist/ui/arch-type-overlay.d.ts +20 -0
- package/dist/ui/arch-type-overlay.js +229 -0
- package/dist/ui/ask-user-overlay.d.ts +26 -0
- package/dist/ui/ask-user-overlay.js +647 -0
- package/dist/ui/ask-user-simple-overlay.d.ts +25 -0
- package/dist/ui/ask-user-simple-overlay.js +242 -0
- package/dist/ui/backlog-overlay.d.ts +17 -0
- package/dist/ui/backlog-overlay.js +786 -0
- package/dist/ui/commands-overlay.d.ts +11 -0
- package/dist/ui/commands-overlay.js +410 -0
- package/dist/ui/config-overlay.d.ts +34 -0
- package/dist/ui/config-overlay.js +977 -0
- package/dist/ui/conversation.d.ts +82 -0
- package/dist/ui/conversation.js +508 -0
- package/dist/ui/diff.d.ts +38 -0
- package/dist/ui/diff.js +182 -0
- package/dist/ui/ephemeral.d.ts +111 -0
- package/dist/ui/ephemeral.js +413 -0
- package/dist/ui/file-autocomplete.d.ts +45 -0
- package/dist/ui/file-autocomplete.js +237 -0
- package/dist/ui/footer.d.ts +153 -0
- package/dist/ui/footer.js +422 -0
- package/dist/ui/index.d.ts +12 -0
- package/dist/ui/index.js +15 -0
- package/dist/ui/init-overlay.d.ts +24 -0
- package/dist/ui/init-overlay.js +525 -0
- package/dist/ui/input-prompt-v2.d.ts +179 -0
- package/dist/ui/input-prompt-v2.js +991 -0
- package/dist/ui/input-prompt.d.ts +97 -0
- package/dist/ui/input-prompt.js +800 -0
- package/dist/ui/iteration-limit-overlay.d.ts +21 -0
- package/dist/ui/iteration-limit-overlay.js +150 -0
- package/dist/ui/keys-overlay.d.ts +14 -0
- package/dist/ui/keys-overlay.js +181 -0
- package/dist/ui/model-warning-overlay.d.ts +30 -0
- package/dist/ui/model-warning-overlay.js +171 -0
- package/dist/ui/overlay-controller.d.ts +25 -0
- package/dist/ui/overlay-controller.js +35 -0
- package/dist/ui/overlays.d.ts +47 -0
- package/dist/ui/overlays.js +627 -0
- package/dist/ui/permission-overlay.d.ts +16 -0
- package/dist/ui/permission-overlay.js +494 -0
- package/dist/ui/terminal.d.ts +117 -0
- package/dist/ui/terminal.js +237 -0
- package/dist/ui/todo-zone.d.ts +112 -0
- package/dist/ui/todo-zone.js +353 -0
- package/dist/ui/tools-overlay.d.ts +26 -0
- package/dist/ui/tools-overlay.js +278 -0
- package/dist/ui/tutorial-overlay.d.ts +10 -0
- package/dist/ui/tutorial-overlay.js +936 -0
- package/dist/ui/types.d.ts +103 -0
- package/dist/ui/types.js +33 -0
- package/dist/utils/credentials.d.ts +55 -0
- package/dist/utils/credentials.js +268 -0
- package/dist/utils/model-tiers.d.ts +37 -0
- package/dist/utils/model-tiers.js +118 -0
- package/dist/utils/project-memory.d.ts +47 -0
- package/dist/utils/project-memory.js +117 -0
- package/dist/utils/project-status.d.ts +56 -0
- package/dist/utils/project-status.js +237 -0
- package/package.json +66 -0
package/dist/tools.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Registry Setup
|
|
3
|
+
*
|
|
4
|
+
* Configures all available tools from @compilr-dev/agents
|
|
5
|
+
* and @compilr-dev/agents-coding packages.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Creates the tool registry with all available tools.
|
|
9
|
+
* Returns tools as-is - the Agent.registerTools() method handles typing.
|
|
10
|
+
*/
|
|
11
|
+
export declare function createToolRegistry(): unknown[];
|
|
12
|
+
/**
|
|
13
|
+
* Returns a minimal set of tools for basic testing.
|
|
14
|
+
*/
|
|
15
|
+
export declare function createMinimalToolRegistry(): unknown[];
|
package/dist/tools.js
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Registry Setup
|
|
3
|
+
*
|
|
4
|
+
* Configures all available tools from @compilr-dev/agents
|
|
5
|
+
* and @compilr-dev/agents-coding packages.
|
|
6
|
+
*/
|
|
7
|
+
import { readFileTool, writeFileTool, createBashTool, bashOutputTool, killShellTool, grepTool, globTool, editTool, todoWriteTool as originalTodoWriteTool, todoReadTool, defineTool, } from '@compilr-dev/agents';
|
|
8
|
+
const todoWriteTool = defineTool({
|
|
9
|
+
name: 'todo_write',
|
|
10
|
+
description: 'Update the task list. Provide the complete list of todos. ' +
|
|
11
|
+
'Use this to track progress on multi-step tasks.',
|
|
12
|
+
inputSchema: {
|
|
13
|
+
type: 'object',
|
|
14
|
+
properties: {
|
|
15
|
+
todos: {
|
|
16
|
+
type: 'array',
|
|
17
|
+
description: 'The complete list of todos',
|
|
18
|
+
items: {
|
|
19
|
+
type: 'object',
|
|
20
|
+
properties: {
|
|
21
|
+
content: {
|
|
22
|
+
type: 'string',
|
|
23
|
+
description: 'Task description (imperative form, e.g., "Fix bug in login")',
|
|
24
|
+
},
|
|
25
|
+
status: {
|
|
26
|
+
type: 'string',
|
|
27
|
+
enum: ['pending', 'in_progress', 'completed'],
|
|
28
|
+
description: 'Task status',
|
|
29
|
+
},
|
|
30
|
+
activeForm: {
|
|
31
|
+
type: 'string',
|
|
32
|
+
description: 'Active form (present continuous, e.g., "Fixing bug in login")',
|
|
33
|
+
},
|
|
34
|
+
priority: {
|
|
35
|
+
type: 'number',
|
|
36
|
+
description: 'Priority (higher = more important)',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
required: ['content', 'status'],
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
required: ['todos'],
|
|
44
|
+
},
|
|
45
|
+
execute: async (input) => {
|
|
46
|
+
// Normalize todos - accept alternative property names
|
|
47
|
+
const normalizedTodos = input.todos.map((todo) => ({
|
|
48
|
+
content: (todo.content || todo.title || todo.description || todo.task || todo.text || '').trim(),
|
|
49
|
+
status: todo.status,
|
|
50
|
+
activeForm: todo.activeForm,
|
|
51
|
+
priority: todo.priority,
|
|
52
|
+
}));
|
|
53
|
+
// Filter out empty todos and provide fallback
|
|
54
|
+
const validTodos = normalizedTodos.map((todo) => ({
|
|
55
|
+
...todo,
|
|
56
|
+
content: todo.content || 'Untitled task',
|
|
57
|
+
}));
|
|
58
|
+
// Debug: log what we're sending (can be removed later)
|
|
59
|
+
// console.error('[DEBUG todo_write] Input:', JSON.stringify(input, null, 2));
|
|
60
|
+
// console.error('[DEBUG todo_write] Normalized:', JSON.stringify(validTodos, null, 2));
|
|
61
|
+
// Call the original tool with normalized input
|
|
62
|
+
const result = await originalTodoWriteTool.execute({ todos: validTodos });
|
|
63
|
+
// Debug: log result
|
|
64
|
+
// console.error('[DEBUG todo_write] Result:', JSON.stringify(result, null, 2));
|
|
65
|
+
return result;
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
// Create bash tool with longer timeout (2 minutes instead of 30 seconds)
|
|
69
|
+
const bashTool = createBashTool({
|
|
70
|
+
timeout: 120000, // 2 minutes
|
|
71
|
+
});
|
|
72
|
+
import { gitStatusTool, gitDiffTool, gitLogTool, gitCommitTool, gitBranchTool, detectProjectTool, findProjectRootTool, runTestsTool, runLintTool, } from '@compilr-dev/agents-coding';
|
|
73
|
+
// Local tools
|
|
74
|
+
import { backlogReadTool, backlogWriteTool } from './tools/backlog.js';
|
|
75
|
+
import { askUserTool } from './tools/ask-user.js';
|
|
76
|
+
import { askUserSimpleTool } from './tools/ask-user-simple.js';
|
|
77
|
+
/**
|
|
78
|
+
* Creates the tool registry with all available tools.
|
|
79
|
+
* Returns tools as-is - the Agent.registerTools() method handles typing.
|
|
80
|
+
*/
|
|
81
|
+
export function createToolRegistry() {
|
|
82
|
+
return [
|
|
83
|
+
// Built-in tools from @compilr-dev/agents
|
|
84
|
+
readFileTool,
|
|
85
|
+
writeFileTool,
|
|
86
|
+
bashTool,
|
|
87
|
+
bashOutputTool, // Monitor background processes
|
|
88
|
+
killShellTool, // Terminate background processes
|
|
89
|
+
grepTool,
|
|
90
|
+
globTool,
|
|
91
|
+
editTool,
|
|
92
|
+
todoWriteTool,
|
|
93
|
+
todoReadTool,
|
|
94
|
+
// Coding tools from @compilr-dev/agents-coding
|
|
95
|
+
gitStatusTool,
|
|
96
|
+
gitDiffTool,
|
|
97
|
+
gitLogTool,
|
|
98
|
+
gitCommitTool,
|
|
99
|
+
gitBranchTool,
|
|
100
|
+
detectProjectTool,
|
|
101
|
+
findProjectRootTool,
|
|
102
|
+
runTestsTool,
|
|
103
|
+
runLintTool,
|
|
104
|
+
// Local tools
|
|
105
|
+
backlogReadTool,
|
|
106
|
+
backlogWriteTool,
|
|
107
|
+
askUserTool,
|
|
108
|
+
askUserSimpleTool,
|
|
109
|
+
];
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Returns a minimal set of tools for basic testing.
|
|
113
|
+
*/
|
|
114
|
+
export function createMinimalToolRegistry() {
|
|
115
|
+
return [
|
|
116
|
+
readFileTool,
|
|
117
|
+
writeFileTool,
|
|
118
|
+
bashTool,
|
|
119
|
+
globTool,
|
|
120
|
+
];
|
|
121
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agents Overlay
|
|
3
|
+
*
|
|
4
|
+
* Modal overlay for viewing and managing agent configurations.
|
|
5
|
+
* - Built-in tab: Lists 9 predefined agent types
|
|
6
|
+
* - Custom tab: Lists user-defined agents + create new option
|
|
7
|
+
* - Wizard mode: Step-by-step agent creation
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Show the agents overlay
|
|
11
|
+
*/
|
|
12
|
+
export declare function showAgentsOverlay(): Promise<void>;
|
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agents Overlay
|
|
3
|
+
*
|
|
4
|
+
* Modal overlay for viewing and managing agent configurations.
|
|
5
|
+
* - Built-in tab: Lists 9 predefined agent types
|
|
6
|
+
* - Custom tab: Lists user-defined agents + create new option
|
|
7
|
+
* - Wizard mode: Step-by-step agent creation
|
|
8
|
+
*/
|
|
9
|
+
import * as terminal from './terminal.js';
|
|
10
|
+
import { getStyles } from '../themes/index.js';
|
|
11
|
+
import { getAgentRegistry } from '../agents/registry.js';
|
|
12
|
+
const TABS = [
|
|
13
|
+
{ id: 'builtin', label: 'built-in' },
|
|
14
|
+
{ id: 'custom', label: 'custom' },
|
|
15
|
+
];
|
|
16
|
+
// =============================================================================
|
|
17
|
+
// Rendering - List Mode
|
|
18
|
+
// =============================================================================
|
|
19
|
+
function renderListHeader(state) {
|
|
20
|
+
const s = getStyles();
|
|
21
|
+
const lines = [];
|
|
22
|
+
const cols = terminal.getTerminalWidth();
|
|
23
|
+
lines.push(s.muted('─'.repeat(Math.max(1, cols - 1))));
|
|
24
|
+
let tabLine = ' ' + s.primaryBold('Agents') + ' ';
|
|
25
|
+
for (let i = 0; i < TABS.length; i++) {
|
|
26
|
+
const tab = TABS[i];
|
|
27
|
+
if (i === state.currentTab) {
|
|
28
|
+
tabLine += s.selected(` ${tab.label} `) + ' ';
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
tabLine += s.muted(` ${tab.label} `) + ' ';
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
tabLine += s.muted('(Tab to switch)');
|
|
35
|
+
lines.push(tabLine);
|
|
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);
|
|
53
|
+
}
|
|
54
|
+
lines.push('');
|
|
55
|
+
lines.push(s.muted(' These agents are available to the LLM via the Task tool.'));
|
|
56
|
+
return lines;
|
|
57
|
+
}
|
|
58
|
+
function renderCustomTab(state) {
|
|
59
|
+
const s = getStyles();
|
|
60
|
+
const lines = [];
|
|
61
|
+
const agents = state.registry.getCustomAgents();
|
|
62
|
+
if (agents.length === 0) {
|
|
63
|
+
lines.push(s.muted(' No custom agents found'));
|
|
64
|
+
lines.push('');
|
|
65
|
+
lines.push(state.selectedIndex === 0
|
|
66
|
+
? s.primary(' ❯ Create new agent')
|
|
67
|
+
: s.muted(' Create new agent'));
|
|
68
|
+
lines.push('');
|
|
69
|
+
lines.push(s.muted(' Custom agents are stored in:'));
|
|
70
|
+
lines.push(s.muted(` ${state.registry.getProjectDir()}/ (project)`));
|
|
71
|
+
lines.push(s.muted(` ${state.registry.getUserDir()}/ (personal)`));
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
lines.push(s.secondary(' Custom agents:'));
|
|
75
|
+
lines.push('');
|
|
76
|
+
for (let i = 0; i < agents.length; i++) {
|
|
77
|
+
const agent = agents[i];
|
|
78
|
+
const isSelected = i === state.selectedIndex;
|
|
79
|
+
const prefix = isSelected ? s.primary(' ❯ ') : ' ';
|
|
80
|
+
const name = `${agent.name} · ${agent.model}`;
|
|
81
|
+
const nameStyled = isSelected ? s.primary(name.padEnd(30)) : s.secondary(name.padEnd(30));
|
|
82
|
+
const location = s.muted(`(${agent.location})`);
|
|
83
|
+
lines.push(prefix + nameStyled + location);
|
|
84
|
+
}
|
|
85
|
+
lines.push(s.muted(' ──────────────────────────────────'));
|
|
86
|
+
const createIdx = agents.length;
|
|
87
|
+
const isCreateSelected = state.selectedIndex === createIdx;
|
|
88
|
+
lines.push(isCreateSelected
|
|
89
|
+
? s.primary(' ❯ Create new agent')
|
|
90
|
+
: s.muted(' Create new agent'));
|
|
91
|
+
}
|
|
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
|
+
}
|
|
101
|
+
function buildListLines(state) {
|
|
102
|
+
const allLines = [];
|
|
103
|
+
allLines.push(...renderListHeader(state));
|
|
104
|
+
if (TABS[state.currentTab].id === 'builtin') {
|
|
105
|
+
allLines.push(...renderBuiltinTab(state));
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
allLines.push(...renderCustomTab(state));
|
|
109
|
+
}
|
|
110
|
+
allLines.push(...renderListFooter());
|
|
111
|
+
return allLines;
|
|
112
|
+
}
|
|
113
|
+
// =============================================================================
|
|
114
|
+
// Rendering - Wizard Mode
|
|
115
|
+
// =============================================================================
|
|
116
|
+
function buildWizardLines(state) {
|
|
117
|
+
const s = getStyles();
|
|
118
|
+
const lines = [];
|
|
119
|
+
const cols = terminal.getTerminalWidth();
|
|
120
|
+
lines.push(s.muted('─'.repeat(Math.max(1, cols - 1))));
|
|
121
|
+
lines.push(' ' + s.primaryBold('Create new agent'));
|
|
122
|
+
lines.push('');
|
|
123
|
+
switch (state.wizardStep) {
|
|
124
|
+
case 'location':
|
|
125
|
+
lines.push(s.secondary(' Choose location'));
|
|
126
|
+
lines.push('');
|
|
127
|
+
lines.push(state.wizardSelectedOption === 0
|
|
128
|
+
? s.primary(' ❯ 1. Project (.compilr-dev/agents/)')
|
|
129
|
+
: s.muted(' 1. Project (.compilr-dev/agents/)'));
|
|
130
|
+
lines.push(state.wizardSelectedOption === 1
|
|
131
|
+
? s.primary(' ❯ 2. Personal (~/.compilr-dev/agents/)')
|
|
132
|
+
: s.muted(' 2. Personal (~/.compilr-dev/agents/)'));
|
|
133
|
+
lines.push('');
|
|
134
|
+
lines.push(s.muted(' Project agents are shared with your team.'));
|
|
135
|
+
lines.push(s.muted(' Personal agents apply to all your projects.'));
|
|
136
|
+
break;
|
|
137
|
+
case 'name':
|
|
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}`));
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
lines.push(s.muted(' Use lowercase letters, numbers, hyphens (e.g., code-reviewer)'));
|
|
148
|
+
}
|
|
149
|
+
break;
|
|
150
|
+
case 'prompt':
|
|
151
|
+
lines.push(s.secondary(' System prompt'));
|
|
152
|
+
lines.push('');
|
|
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);
|
|
184
|
+
}
|
|
185
|
+
break;
|
|
186
|
+
}
|
|
187
|
+
case 'confirm':
|
|
188
|
+
lines.push(s.secondary(' Confirm'));
|
|
189
|
+
lines.push('');
|
|
190
|
+
lines.push(` Name: ${s.primary(state.wizardName)}`);
|
|
191
|
+
lines.push(` Location: ${s.primary(state.wizardLocation === 'project' ? '.compilr-dev/agents/' : '~/.compilr-dev/agents/')}${state.wizardName}.md`);
|
|
192
|
+
lines.push(` Model: ${s.primary(state.wizardModel)}`);
|
|
193
|
+
lines.push('');
|
|
194
|
+
lines.push(s.secondary(' Description:'));
|
|
195
|
+
lines.push(s.muted(` ${state.wizardDescription.slice(0, 60)}${state.wizardDescription.length > 60 ? '...' : ''}`));
|
|
196
|
+
lines.push('');
|
|
197
|
+
lines.push(s.secondary(' System prompt:'));
|
|
198
|
+
lines.push(s.muted(` ${state.wizardPrompt.slice(0, 60)}${state.wizardPrompt.length > 60 ? '...' : ''}`));
|
|
199
|
+
lines.push('');
|
|
200
|
+
lines.push(state.wizardSelectedOption === 0
|
|
201
|
+
? s.primary(' ❯ Save')
|
|
202
|
+
: s.muted(' Save'));
|
|
203
|
+
lines.push(state.wizardSelectedOption === 1
|
|
204
|
+
? s.primary(' ❯ Cancel')
|
|
205
|
+
: s.muted(' Cancel'));
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
lines.push('');
|
|
209
|
+
lines.push(s.muted(' Esc to go back'));
|
|
210
|
+
return lines;
|
|
211
|
+
}
|
|
212
|
+
// =============================================================================
|
|
213
|
+
// Unified Rendering
|
|
214
|
+
// =============================================================================
|
|
215
|
+
function buildLines(state) {
|
|
216
|
+
if (state.mode === 'wizard') {
|
|
217
|
+
return buildWizardLines(state);
|
|
218
|
+
}
|
|
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
|
+
}
|
|
229
|
+
// =============================================================================
|
|
230
|
+
// Main Export
|
|
231
|
+
// =============================================================================
|
|
232
|
+
/**
|
|
233
|
+
* Show the agents overlay
|
|
234
|
+
*/
|
|
235
|
+
export async function showAgentsOverlay() {
|
|
236
|
+
const registry = getAgentRegistry();
|
|
237
|
+
registry.load();
|
|
238
|
+
const state = {
|
|
239
|
+
mode: 'list',
|
|
240
|
+
currentTab: 0,
|
|
241
|
+
selectedIndex: 0,
|
|
242
|
+
wizardStep: 'location',
|
|
243
|
+
wizardLocation: 'project',
|
|
244
|
+
wizardName: '',
|
|
245
|
+
wizardPrompt: '',
|
|
246
|
+
wizardDescription: '',
|
|
247
|
+
wizardModel: 'sonnet',
|
|
248
|
+
wizardSelectedOption: 0,
|
|
249
|
+
wizardInputBuffer: '',
|
|
250
|
+
wizardError: null,
|
|
251
|
+
registry,
|
|
252
|
+
};
|
|
253
|
+
let lineCount = 0;
|
|
254
|
+
terminal.writeLine('');
|
|
255
|
+
terminal.hideCursor();
|
|
256
|
+
const wasRawMode = process.stdin.isRaw;
|
|
257
|
+
terminal.enableRawMode();
|
|
258
|
+
lineCount = render(state, 0);
|
|
259
|
+
const getMaxIndex = () => {
|
|
260
|
+
if (TABS[state.currentTab].id === 'builtin') {
|
|
261
|
+
return state.registry.getBuiltinAgents().length - 1;
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
return state.registry.getCustomAgents().length; // includes "Create new"
|
|
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) {
|
|
282
|
+
case 'location':
|
|
283
|
+
state.wizardLocation = state.wizardSelectedOption === 0 ? 'project' : 'personal';
|
|
284
|
+
state.wizardStep = 'name';
|
|
285
|
+
state.wizardInputBuffer = '';
|
|
286
|
+
break;
|
|
287
|
+
case 'name':
|
|
288
|
+
state.wizardName = state.wizardInputBuffer.trim();
|
|
289
|
+
state.wizardStep = 'prompt';
|
|
290
|
+
state.wizardInputBuffer = '';
|
|
291
|
+
break;
|
|
292
|
+
case 'prompt':
|
|
293
|
+
state.wizardPrompt = state.wizardInputBuffer.trim();
|
|
294
|
+
state.wizardStep = 'description';
|
|
295
|
+
state.wizardInputBuffer = '';
|
|
296
|
+
break;
|
|
297
|
+
case 'description':
|
|
298
|
+
state.wizardDescription = state.wizardInputBuffer.trim();
|
|
299
|
+
state.wizardStep = 'model';
|
|
300
|
+
state.wizardSelectedOption = 0;
|
|
301
|
+
break;
|
|
302
|
+
case 'model': {
|
|
303
|
+
const models = ['sonnet', 'opus', 'haiku', 'inherit'];
|
|
304
|
+
state.wizardModel = models[state.wizardSelectedOption];
|
|
305
|
+
state.wizardStep = 'confirm';
|
|
306
|
+
state.wizardSelectedOption = 0;
|
|
307
|
+
break;
|
|
308
|
+
}
|
|
309
|
+
case 'confirm':
|
|
310
|
+
if (state.wizardSelectedOption === 0) {
|
|
311
|
+
// Save
|
|
312
|
+
try {
|
|
313
|
+
registry.saveAgent({
|
|
314
|
+
name: state.wizardName,
|
|
315
|
+
description: state.wizardDescription,
|
|
316
|
+
model: state.wizardModel,
|
|
317
|
+
systemPrompt: state.wizardPrompt,
|
|
318
|
+
}, state.wizardLocation);
|
|
319
|
+
// Success - go back to list
|
|
320
|
+
registry.load();
|
|
321
|
+
state.mode = 'list';
|
|
322
|
+
state.selectedIndex = 0;
|
|
323
|
+
return true; // Created successfully
|
|
324
|
+
}
|
|
325
|
+
catch (error) {
|
|
326
|
+
state.wizardError = error.message;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
// Cancel - go back to list
|
|
331
|
+
state.mode = 'list';
|
|
332
|
+
}
|
|
333
|
+
break;
|
|
334
|
+
}
|
|
335
|
+
state.wizardError = null;
|
|
336
|
+
return false;
|
|
337
|
+
};
|
|
338
|
+
// Wizard: go back to previous step (or exit wizard)
|
|
339
|
+
const wizardPrevStep = () => {
|
|
340
|
+
switch (state.wizardStep) {
|
|
341
|
+
case 'location':
|
|
342
|
+
// Exit wizard, go back to list
|
|
343
|
+
state.mode = 'list';
|
|
344
|
+
break;
|
|
345
|
+
case 'name':
|
|
346
|
+
state.wizardStep = 'location';
|
|
347
|
+
state.wizardSelectedOption = state.wizardLocation === 'project' ? 0 : 1;
|
|
348
|
+
break;
|
|
349
|
+
case 'prompt':
|
|
350
|
+
state.wizardStep = 'name';
|
|
351
|
+
state.wizardInputBuffer = state.wizardName;
|
|
352
|
+
break;
|
|
353
|
+
case 'description':
|
|
354
|
+
state.wizardStep = 'prompt';
|
|
355
|
+
state.wizardInputBuffer = state.wizardPrompt;
|
|
356
|
+
break;
|
|
357
|
+
case 'model':
|
|
358
|
+
state.wizardStep = 'description';
|
|
359
|
+
state.wizardInputBuffer = state.wizardDescription;
|
|
360
|
+
break;
|
|
361
|
+
case 'confirm': {
|
|
362
|
+
state.wizardStep = 'model';
|
|
363
|
+
const models = ['sonnet', 'opus', 'haiku', 'inherit'];
|
|
364
|
+
state.wizardSelectedOption = models.indexOf(state.wizardModel);
|
|
365
|
+
break;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
state.wizardError = null;
|
|
369
|
+
};
|
|
370
|
+
return new Promise((resolve) => {
|
|
371
|
+
const cleanup = () => {
|
|
372
|
+
terminal.clearLinesAbove(lineCount);
|
|
373
|
+
terminal.writeLine('');
|
|
374
|
+
terminal.showCursor();
|
|
375
|
+
if (!wasRawMode) {
|
|
376
|
+
terminal.disableRawMode();
|
|
377
|
+
}
|
|
378
|
+
process.stdin.removeListener('data', onData);
|
|
379
|
+
};
|
|
380
|
+
const onData = (data) => {
|
|
381
|
+
const isEscape = data.length === 1 && data[0] === 0x1b;
|
|
382
|
+
const isTab = data.length === 1 && data[0] === 0x09;
|
|
383
|
+
const isUpArrow = data.length === 3 && data[0] === 0x1b && data[1] === 0x5b && data[2] === 0x41;
|
|
384
|
+
const isDownArrow = data.length === 3 && data[0] === 0x1b && data[1] === 0x5b && data[2] === 0x42;
|
|
385
|
+
const isCtrlC = data.length === 1 && data[0] === 0x03;
|
|
386
|
+
const isEnter = data.length === 1 && (data[0] === 0x0d || data[0] === 0x0a);
|
|
387
|
+
const isBackspace = data.length === 1 && (data[0] === 0x7f || data[0] === 0x08);
|
|
388
|
+
// ===== LIST MODE =====
|
|
389
|
+
if (state.mode === 'list') {
|
|
390
|
+
if (isEscape || isCtrlC) {
|
|
391
|
+
cleanup();
|
|
392
|
+
resolve();
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
if (isTab) {
|
|
396
|
+
state.currentTab = (state.currentTab + 1) % TABS.length;
|
|
397
|
+
state.selectedIndex = 0;
|
|
398
|
+
lineCount = render(state, lineCount);
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
if (isUpArrow && state.selectedIndex > 0) {
|
|
402
|
+
state.selectedIndex--;
|
|
403
|
+
lineCount = render(state, lineCount);
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
if (isDownArrow && state.selectedIndex < getMaxIndex()) {
|
|
407
|
+
state.selectedIndex++;
|
|
408
|
+
lineCount = render(state, lineCount);
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
if (isEnter) {
|
|
412
|
+
if (TABS[state.currentTab].id === 'custom') {
|
|
413
|
+
const customAgents = state.registry.getCustomAgents();
|
|
414
|
+
if (state.selectedIndex === customAgents.length) {
|
|
415
|
+
// "Create new agent" selected - enter wizard mode
|
|
416
|
+
resetWizard();
|
|
417
|
+
state.mode = 'wizard';
|
|
418
|
+
lineCount = render(state, lineCount);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
// ===== WIZARD MODE =====
|
|
426
|
+
// Mode is always 'wizard' at this point since we're in the else block
|
|
427
|
+
{
|
|
428
|
+
if (isCtrlC) {
|
|
429
|
+
cleanup();
|
|
430
|
+
resolve();
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
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
|
+
}
|
|
498
|
+
};
|
|
499
|
+
process.stdin.on('data', onData);
|
|
500
|
+
});
|
|
501
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Architecture Type Selection Overlay
|
|
3
|
+
*
|
|
4
|
+
* Shows options for what type of architecture documentation to create.
|
|
5
|
+
* User selects from:
|
|
6
|
+
* - ADR (Architecture Decision Record)
|
|
7
|
+
* - System Diagram
|
|
8
|
+
* - Data Model
|
|
9
|
+
* - API Design
|
|
10
|
+
* - Custom topic
|
|
11
|
+
*/
|
|
12
|
+
export type ArchDocType = 'adr' | 'diagram' | 'data-model' | 'api' | 'custom';
|
|
13
|
+
export interface ArchTypeChoice {
|
|
14
|
+
type: ArchDocType;
|
|
15
|
+
customTopic?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Show the architecture type selection overlay and return the user's choice.
|
|
19
|
+
*/
|
|
20
|
+
export declare function showArchTypeOverlay(): Promise<ArchTypeChoice | null>;
|