@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.
Files changed (152) hide show
  1. package/README.md +110 -0
  2. package/dist/agent.d.ts +62 -0
  3. package/dist/agent.js +317 -0
  4. package/dist/agents/registry.d.ts +66 -0
  5. package/dist/agents/registry.js +238 -0
  6. package/dist/agents/types.d.ts +40 -0
  7. package/dist/agents/types.js +94 -0
  8. package/dist/commands/custom-registry.d.ts +69 -0
  9. package/dist/commands/custom-registry.js +246 -0
  10. package/dist/commands/index.d.ts +7 -0
  11. package/dist/commands/index.js +7 -0
  12. package/dist/commands/types.d.ts +31 -0
  13. package/dist/commands/types.js +26 -0
  14. package/dist/commands.d.ts +63 -0
  15. package/dist/commands.js +324 -0
  16. package/dist/db/index.d.ts +42 -0
  17. package/dist/db/index.js +146 -0
  18. package/dist/db/repositories/document-repository.d.ts +63 -0
  19. package/dist/db/repositories/document-repository.js +184 -0
  20. package/dist/db/repositories/index.d.ts +9 -0
  21. package/dist/db/repositories/index.js +6 -0
  22. package/dist/db/repositories/project-repository.d.ts +132 -0
  23. package/dist/db/repositories/project-repository.js +337 -0
  24. package/dist/db/repositories/work-item-repository.d.ts +115 -0
  25. package/dist/db/repositories/work-item-repository.js +389 -0
  26. package/dist/db/schema.d.ts +83 -0
  27. package/dist/db/schema.js +143 -0
  28. package/dist/debug.d.ts +8 -0
  29. package/dist/debug.js +48 -0
  30. package/dist/index.d.ts +2 -0
  31. package/dist/index.js +348 -0
  32. package/dist/index.old.d.ts +7 -0
  33. package/dist/index.old.js +1014 -0
  34. package/dist/repl.d.ts +121 -0
  35. package/dist/repl.js +1878 -0
  36. package/dist/settings/index.d.ts +80 -0
  37. package/dist/settings/index.js +195 -0
  38. package/dist/shared-handlers.d.ts +63 -0
  39. package/dist/shared-handlers.js +57 -0
  40. package/dist/slash-autocomplete.d.ts +41 -0
  41. package/dist/slash-autocomplete.js +638 -0
  42. package/dist/state.d.ts +75 -0
  43. package/dist/state.js +130 -0
  44. package/dist/tabbed-menu.d.ts +11 -0
  45. package/dist/tabbed-menu.js +328 -0
  46. package/dist/templates/backlog-md.d.ts +7 -0
  47. package/dist/templates/backlog-md.js +94 -0
  48. package/dist/templates/claude-md.d.ts +7 -0
  49. package/dist/templates/claude-md.js +189 -0
  50. package/dist/templates/coding-standards.d.ts +7 -0
  51. package/dist/templates/coding-standards.js +299 -0
  52. package/dist/templates/compilr-md.d.ts +7 -0
  53. package/dist/templates/compilr-md.js +189 -0
  54. package/dist/templates/config-json.d.ts +38 -0
  55. package/dist/templates/config-json.js +39 -0
  56. package/dist/templates/gitignore.d.ts +7 -0
  57. package/dist/templates/gitignore.js +85 -0
  58. package/dist/templates/index.d.ts +19 -0
  59. package/dist/templates/index.js +302 -0
  60. package/dist/templates/package-json.d.ts +7 -0
  61. package/dist/templates/package-json.js +111 -0
  62. package/dist/templates/readme-md.d.ts +7 -0
  63. package/dist/templates/readme-md.js +161 -0
  64. package/dist/templates/tsconfig.d.ts +7 -0
  65. package/dist/templates/tsconfig.js +61 -0
  66. package/dist/templates/types.d.ts +33 -0
  67. package/dist/templates/types.js +24 -0
  68. package/dist/test-autocomplete.d.ts +7 -0
  69. package/dist/test-autocomplete.js +85 -0
  70. package/dist/test-tabbed-menu.d.ts +7 -0
  71. package/dist/test-tabbed-menu.js +25 -0
  72. package/dist/themes/colors.d.ts +49 -0
  73. package/dist/themes/colors.js +135 -0
  74. package/dist/themes/index.d.ts +23 -0
  75. package/dist/themes/index.js +24 -0
  76. package/dist/themes/registry.d.ts +60 -0
  77. package/dist/themes/registry.js +195 -0
  78. package/dist/themes/types.d.ts +82 -0
  79. package/dist/themes/types.js +7 -0
  80. package/dist/tool-selector.d.ts +71 -0
  81. package/dist/tool-selector.js +184 -0
  82. package/dist/tools/ask-user-simple.d.ts +19 -0
  83. package/dist/tools/ask-user-simple.js +86 -0
  84. package/dist/tools/ask-user.d.ts +32 -0
  85. package/dist/tools/ask-user.js +113 -0
  86. package/dist/tools/backlog.d.ts +53 -0
  87. package/dist/tools/backlog.js +709 -0
  88. package/dist/tools.d.ts +15 -0
  89. package/dist/tools.js +121 -0
  90. package/dist/ui/agents-overlay.d.ts +12 -0
  91. package/dist/ui/agents-overlay.js +501 -0
  92. package/dist/ui/arch-type-overlay.d.ts +20 -0
  93. package/dist/ui/arch-type-overlay.js +229 -0
  94. package/dist/ui/ask-user-overlay.d.ts +26 -0
  95. package/dist/ui/ask-user-overlay.js +647 -0
  96. package/dist/ui/ask-user-simple-overlay.d.ts +25 -0
  97. package/dist/ui/ask-user-simple-overlay.js +242 -0
  98. package/dist/ui/backlog-overlay.d.ts +17 -0
  99. package/dist/ui/backlog-overlay.js +786 -0
  100. package/dist/ui/commands-overlay.d.ts +11 -0
  101. package/dist/ui/commands-overlay.js +410 -0
  102. package/dist/ui/config-overlay.d.ts +34 -0
  103. package/dist/ui/config-overlay.js +977 -0
  104. package/dist/ui/conversation.d.ts +82 -0
  105. package/dist/ui/conversation.js +508 -0
  106. package/dist/ui/diff.d.ts +38 -0
  107. package/dist/ui/diff.js +182 -0
  108. package/dist/ui/ephemeral.d.ts +111 -0
  109. package/dist/ui/ephemeral.js +413 -0
  110. package/dist/ui/file-autocomplete.d.ts +45 -0
  111. package/dist/ui/file-autocomplete.js +237 -0
  112. package/dist/ui/footer.d.ts +153 -0
  113. package/dist/ui/footer.js +422 -0
  114. package/dist/ui/index.d.ts +12 -0
  115. package/dist/ui/index.js +15 -0
  116. package/dist/ui/init-overlay.d.ts +24 -0
  117. package/dist/ui/init-overlay.js +525 -0
  118. package/dist/ui/input-prompt-v2.d.ts +179 -0
  119. package/dist/ui/input-prompt-v2.js +991 -0
  120. package/dist/ui/input-prompt.d.ts +97 -0
  121. package/dist/ui/input-prompt.js +800 -0
  122. package/dist/ui/iteration-limit-overlay.d.ts +21 -0
  123. package/dist/ui/iteration-limit-overlay.js +150 -0
  124. package/dist/ui/keys-overlay.d.ts +14 -0
  125. package/dist/ui/keys-overlay.js +181 -0
  126. package/dist/ui/model-warning-overlay.d.ts +30 -0
  127. package/dist/ui/model-warning-overlay.js +171 -0
  128. package/dist/ui/overlay-controller.d.ts +25 -0
  129. package/dist/ui/overlay-controller.js +35 -0
  130. package/dist/ui/overlays.d.ts +47 -0
  131. package/dist/ui/overlays.js +627 -0
  132. package/dist/ui/permission-overlay.d.ts +16 -0
  133. package/dist/ui/permission-overlay.js +494 -0
  134. package/dist/ui/terminal.d.ts +117 -0
  135. package/dist/ui/terminal.js +237 -0
  136. package/dist/ui/todo-zone.d.ts +112 -0
  137. package/dist/ui/todo-zone.js +353 -0
  138. package/dist/ui/tools-overlay.d.ts +26 -0
  139. package/dist/ui/tools-overlay.js +278 -0
  140. package/dist/ui/tutorial-overlay.d.ts +10 -0
  141. package/dist/ui/tutorial-overlay.js +936 -0
  142. package/dist/ui/types.d.ts +103 -0
  143. package/dist/ui/types.js +33 -0
  144. package/dist/utils/credentials.d.ts +55 -0
  145. package/dist/utils/credentials.js +268 -0
  146. package/dist/utils/model-tiers.d.ts +37 -0
  147. package/dist/utils/model-tiers.js +118 -0
  148. package/dist/utils/project-memory.d.ts +47 -0
  149. package/dist/utils/project-memory.js +117 -0
  150. package/dist/utils/project-status.d.ts +56 -0
  151. package/dist/utils/project-status.js +237 -0
  152. package/package.json +66 -0
@@ -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>;