@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,525 @@
1
+ /**
2
+ * Init Overlay
3
+ *
4
+ * Modal overlay for the /init wizard - creates new projects with structured workflow.
5
+ * Steps:
6
+ * 0. Project type (new vs existing)
7
+ * 1. Project name
8
+ * 2. Description
9
+ * 3. Repo pattern (single vs two-repo)
10
+ * 4. Tech stack
11
+ * 5. Coding standards
12
+ * 6. Initialize git?
13
+ * 7. Confirmation
14
+ */
15
+ import chalk from 'chalk';
16
+ import * as terminal from './terminal.js';
17
+ import { getStyles } from '../themes/index.js';
18
+ import { TECH_STACK_LABELS, CODING_STANDARDS_LABELS, REPO_PATTERN_LABELS, generateProject, isValidProjectName, projectExists, } from '../templates/index.js';
19
+ // =============================================================================
20
+ // Constants
21
+ // =============================================================================
22
+ const TECH_STACK_OPTIONS = ['react-node-pg', 'react-python-pg', 'vue-node-pg', 'custom'];
23
+ const CODING_STANDARDS_OPTIONS = ['strict', 'relaxed', 'custom'];
24
+ const REPO_PATTERN_OPTIONS = ['single', 'two-repo'];
25
+ // =============================================================================
26
+ // Rendering Helpers
27
+ // =============================================================================
28
+ function renderHeader(step) {
29
+ const s = getStyles();
30
+ const lines = [];
31
+ const cols = terminal.getTerminalWidth();
32
+ lines.push(s.muted('─'.repeat(Math.max(1, cols - 1))));
33
+ lines.push(' ' + s.primaryBold('Initialize New Project') + s.muted(` [${String(step)}/7]`));
34
+ lines.push('');
35
+ return lines;
36
+ }
37
+ function renderFooter(step) {
38
+ const s = getStyles();
39
+ const lines = [];
40
+ lines.push('');
41
+ if (step === 0) {
42
+ lines.push(s.muted(' ↑↓ Navigate · Enter Select · Esc Cancel'));
43
+ }
44
+ else if (step === 7) {
45
+ lines.push(s.muted(' ↑↓ Navigate · Enter Confirm · Esc Go back'));
46
+ }
47
+ else {
48
+ lines.push(s.muted(' Enter Confirm · Esc Go back'));
49
+ }
50
+ return lines;
51
+ }
52
+ function renderSelectionOption(index, selectedIndex, label, disabled = false) {
53
+ const s = getStyles();
54
+ const isSelected = index === selectedIndex;
55
+ const prefix = isSelected ? ' ❯ ' : ' ';
56
+ if (disabled) {
57
+ return s.muted(prefix + label + ' (coming soon)');
58
+ }
59
+ return isSelected ? s.primary(prefix + label) : s.muted(prefix + label);
60
+ }
61
+ // =============================================================================
62
+ // Step Renderers
63
+ // =============================================================================
64
+ function renderStep0(state) {
65
+ const s = getStyles();
66
+ const lines = [];
67
+ lines.push(chalk.bold(' What would you like to do?'));
68
+ lines.push('');
69
+ lines.push(renderSelectionOption(0, state.selectedIndex, '1. Start a new project'));
70
+ lines.push(renderSelectionOption(1, state.selectedIndex, '2. Add workflow to existing project', true));
71
+ lines.push('');
72
+ lines.push(s.muted(' Start fresh with a structured project layout'));
73
+ lines.push(s.muted(' optimized for AI-assisted development.'));
74
+ return lines;
75
+ }
76
+ function renderStep1(state) {
77
+ const s = getStyles();
78
+ const lines = [];
79
+ lines.push(chalk.bold(' Project name'));
80
+ lines.push('');
81
+ lines.push(` > ${state.inputBuffer}█`);
82
+ lines.push('');
83
+ if (state.error) {
84
+ lines.push(s.error(` ${state.error}`));
85
+ }
86
+ else {
87
+ lines.push(s.muted(' Use lowercase letters, numbers, hyphens (e.g., my-saas-app)'));
88
+ lines.push(s.muted(' 2-50 characters, must start with a letter'));
89
+ }
90
+ return lines;
91
+ }
92
+ function renderStep2(state) {
93
+ const s = getStyles();
94
+ const lines = [];
95
+ lines.push(chalk.bold(' What are you building?'));
96
+ lines.push('');
97
+ lines.push(` > ${state.inputBuffer}█`);
98
+ lines.push('');
99
+ if (state.error) {
100
+ lines.push(s.error(` ${state.error}`));
101
+ }
102
+ else {
103
+ lines.push(s.muted(' Brief description (1-2 sentences)'));
104
+ lines.push(s.muted(' Example: "A task management SaaS for small teams"'));
105
+ }
106
+ return lines;
107
+ }
108
+ function renderStep3(state) {
109
+ const s = getStyles();
110
+ const lines = [];
111
+ lines.push(chalk.bold(' Documentation structure'));
112
+ lines.push('');
113
+ for (let i = 0; i < REPO_PATTERN_OPTIONS.length; i++) {
114
+ const pattern = REPO_PATTERN_OPTIONS[i];
115
+ lines.push(renderSelectionOption(i, state.selectedIndex, `${String(i + 1)}. ${REPO_PATTERN_LABELS[pattern]}`));
116
+ }
117
+ lines.push('');
118
+ lines.push(s.muted(' Single repo: All files in one repository'));
119
+ lines.push(s.muted(' Two repos: Code and docs in separate repositories'));
120
+ return lines;
121
+ }
122
+ function renderStep4(state) {
123
+ const s = getStyles();
124
+ const lines = [];
125
+ lines.push(chalk.bold(' Tech stack'));
126
+ lines.push('');
127
+ for (let i = 0; i < TECH_STACK_OPTIONS.length; i++) {
128
+ const stack = TECH_STACK_OPTIONS[i];
129
+ lines.push(renderSelectionOption(i, state.selectedIndex, `${String(i + 1)}. ${TECH_STACK_LABELS[stack]}`));
130
+ }
131
+ lines.push('');
132
+ lines.push(s.muted(' Choose a preset or configure later'));
133
+ return lines;
134
+ }
135
+ function renderStep5(state) {
136
+ const s = getStyles();
137
+ const lines = [];
138
+ lines.push(chalk.bold(' Coding standards preset'));
139
+ lines.push('');
140
+ for (let i = 0; i < CODING_STANDARDS_OPTIONS.length; i++) {
141
+ const standard = CODING_STANDARDS_OPTIONS[i];
142
+ lines.push(renderSelectionOption(i, state.selectedIndex, `${String(i + 1)}. ${CODING_STANDARDS_LABELS[standard]}`));
143
+ }
144
+ lines.push('');
145
+ lines.push(s.muted(' Strict: Full TypeScript with strict mode + ESLint'));
146
+ lines.push(s.muted(' Relaxed: TypeScript with basic strict mode'));
147
+ lines.push(s.muted(' Custom: Configure your own standards later'));
148
+ return lines;
149
+ }
150
+ function renderStep6(state) {
151
+ const s = getStyles();
152
+ const lines = [];
153
+ lines.push(chalk.bold(' Initialize git repository?'));
154
+ lines.push('');
155
+ lines.push(renderSelectionOption(0, state.selectedIndex, 'Yes'));
156
+ lines.push(renderSelectionOption(1, state.selectedIndex, 'No'));
157
+ lines.push('');
158
+ lines.push(s.muted(' Creates git repo with initial commit'));
159
+ return lines;
160
+ }
161
+ function renderStep7(state) {
162
+ const s = getStyles();
163
+ const lines = [];
164
+ lines.push(chalk.bold(' Ready to create project?'));
165
+ lines.push('');
166
+ lines.push(` Project: ${s.primary(state.projectName)}`);
167
+ lines.push(` Location: ${s.primary('./' + state.projectName + '/')}`);
168
+ lines.push(` Structure: ${s.primary(state.repoPattern === 'single' ? 'Single repo' : 'Two repos')}`);
169
+ lines.push(` Tech: ${s.primary(state.techStack ? TECH_STACK_LABELS[state.techStack] : 'Not set')}`);
170
+ lines.push(` Standards: ${s.primary(state.codingStandards ? CODING_STANDARDS_LABELS[state.codingStandards] : 'Not set')}`);
171
+ lines.push(` Git: ${s.primary(state.initGit ? 'Yes' : 'No')}`);
172
+ if (state.repoPattern === 'two-repo') {
173
+ lines.push('');
174
+ lines.push(s.muted(` Docs repo: ./${state.projectName}-docs/`));
175
+ }
176
+ lines.push('');
177
+ if (state.error) {
178
+ lines.push(s.error(` ${state.error}`));
179
+ lines.push('');
180
+ }
181
+ lines.push(renderSelectionOption(0, state.selectedIndex, 'Create'));
182
+ lines.push(renderSelectionOption(1, state.selectedIndex, 'Cancel'));
183
+ return lines;
184
+ }
185
+ // =============================================================================
186
+ // Unified Rendering
187
+ // =============================================================================
188
+ function buildLines(state) {
189
+ const lines = [];
190
+ lines.push(...renderHeader(state.step));
191
+ switch (state.step) {
192
+ case 0:
193
+ lines.push(...renderStep0(state));
194
+ break;
195
+ case 1:
196
+ lines.push(...renderStep1(state));
197
+ break;
198
+ case 2:
199
+ lines.push(...renderStep2(state));
200
+ break;
201
+ case 3:
202
+ lines.push(...renderStep3(state));
203
+ break;
204
+ case 4:
205
+ lines.push(...renderStep4(state));
206
+ break;
207
+ case 5:
208
+ lines.push(...renderStep5(state));
209
+ break;
210
+ case 6:
211
+ lines.push(...renderStep6(state));
212
+ break;
213
+ case 7:
214
+ lines.push(...renderStep7(state));
215
+ break;
216
+ }
217
+ lines.push(...renderFooter(state.step));
218
+ return lines;
219
+ }
220
+ function render(state, prevLineCount) {
221
+ const lines = buildLines(state);
222
+ // Clear previous content
223
+ terminal.clearLinesAbove(prevLineCount);
224
+ // Write new content
225
+ terminal.write(lines.join('\n'));
226
+ return lines.length;
227
+ }
228
+ // =============================================================================
229
+ // Step Navigation
230
+ // =============================================================================
231
+ function getMaxOptionsForStep(step) {
232
+ switch (step) {
233
+ case 0:
234
+ return 2;
235
+ case 3:
236
+ return REPO_PATTERN_OPTIONS.length;
237
+ case 4:
238
+ return TECH_STACK_OPTIONS.length;
239
+ case 5:
240
+ return CODING_STANDARDS_OPTIONS.length;
241
+ case 6:
242
+ return 2;
243
+ case 7:
244
+ return 2;
245
+ default:
246
+ return 0;
247
+ }
248
+ }
249
+ function isSelectionStep(step) {
250
+ return [0, 3, 4, 5, 6, 7].includes(step);
251
+ }
252
+ function isInputStep(step) {
253
+ return [1, 2].includes(step);
254
+ }
255
+ /**
256
+ * Show the init wizard overlay
257
+ */
258
+ export async function showInitOverlay() {
259
+ const state = {
260
+ step: 0,
261
+ projectType: null,
262
+ projectName: '',
263
+ description: '',
264
+ repoPattern: null,
265
+ techStack: null,
266
+ codingStandards: null,
267
+ initGit: true,
268
+ selectedIndex: 0,
269
+ inputBuffer: '',
270
+ error: null,
271
+ };
272
+ let lineCount = 0;
273
+ terminal.writeLine('');
274
+ terminal.hideCursor();
275
+ const wasRawMode = process.stdin.isRaw;
276
+ terminal.enableRawMode();
277
+ lineCount = render(state, 0);
278
+ // Navigate to next step
279
+ const nextStep = () => {
280
+ switch (state.step) {
281
+ case 0:
282
+ // Only "new" option works (index 0)
283
+ if (state.selectedIndex === 0) {
284
+ state.projectType = 'new';
285
+ state.step = 1;
286
+ state.inputBuffer = '';
287
+ state.selectedIndex = 0;
288
+ }
289
+ break;
290
+ case 1:
291
+ state.projectName = state.inputBuffer.trim();
292
+ state.step = 2;
293
+ state.inputBuffer = '';
294
+ break;
295
+ case 2:
296
+ state.description = state.inputBuffer.trim();
297
+ state.step = 3;
298
+ state.selectedIndex = 0;
299
+ break;
300
+ case 3:
301
+ state.repoPattern = REPO_PATTERN_OPTIONS[state.selectedIndex];
302
+ state.step = 4;
303
+ state.selectedIndex = 0;
304
+ break;
305
+ case 4:
306
+ state.techStack = TECH_STACK_OPTIONS[state.selectedIndex];
307
+ state.step = 5;
308
+ state.selectedIndex = 0;
309
+ break;
310
+ case 5:
311
+ state.codingStandards = CODING_STANDARDS_OPTIONS[state.selectedIndex];
312
+ state.step = 6;
313
+ state.selectedIndex = 0;
314
+ break;
315
+ case 6:
316
+ state.initGit = state.selectedIndex === 0;
317
+ state.step = 7;
318
+ state.selectedIndex = 0;
319
+ break;
320
+ }
321
+ state.error = null;
322
+ };
323
+ // Navigate to previous step
324
+ const prevStep = () => {
325
+ switch (state.step) {
326
+ case 1:
327
+ state.step = 0;
328
+ state.selectedIndex = 0;
329
+ break;
330
+ case 2:
331
+ state.step = 1;
332
+ state.inputBuffer = state.projectName;
333
+ break;
334
+ case 3:
335
+ state.step = 2;
336
+ state.inputBuffer = state.description;
337
+ break;
338
+ case 4:
339
+ state.step = 3;
340
+ state.selectedIndex = state.repoPattern ? REPO_PATTERN_OPTIONS.indexOf(state.repoPattern) : 0;
341
+ break;
342
+ case 5:
343
+ state.step = 4;
344
+ state.selectedIndex = state.techStack ? TECH_STACK_OPTIONS.indexOf(state.techStack) : 0;
345
+ break;
346
+ case 6:
347
+ state.step = 5;
348
+ state.selectedIndex = state.codingStandards ? CODING_STANDARDS_OPTIONS.indexOf(state.codingStandards) : 0;
349
+ break;
350
+ case 7:
351
+ state.step = 6;
352
+ state.selectedIndex = state.initGit ? 0 : 1;
353
+ break;
354
+ }
355
+ state.error = null;
356
+ };
357
+ // Validate input for current step
358
+ const validateInput = () => {
359
+ if (state.step === 1) {
360
+ const name = state.inputBuffer.trim();
361
+ if (!name) {
362
+ state.error = 'Project name is required';
363
+ return false;
364
+ }
365
+ if (!isValidProjectName(name)) {
366
+ state.error = 'Invalid name. Use lowercase letters, numbers, hyphens (2-50 chars, start with letter)';
367
+ return false;
368
+ }
369
+ if (projectExists(name)) {
370
+ state.error = `Directory "${name}" already exists`;
371
+ return false;
372
+ }
373
+ }
374
+ if (state.step === 2) {
375
+ const desc = state.inputBuffer.trim();
376
+ if (!desc) {
377
+ state.error = 'Description is required';
378
+ return false;
379
+ }
380
+ if (desc.length < 10) {
381
+ state.error = 'Description too short (min 10 characters)';
382
+ return false;
383
+ }
384
+ }
385
+ return true;
386
+ };
387
+ return new Promise((resolve) => {
388
+ const cleanup = () => {
389
+ terminal.clearLinesAbove(lineCount);
390
+ terminal.writeLine('');
391
+ terminal.showCursor();
392
+ if (!wasRawMode) {
393
+ terminal.disableRawMode();
394
+ }
395
+ process.stdin.removeListener('data', handleData);
396
+ };
397
+ const handleData = (data) => {
398
+ void onData(data);
399
+ };
400
+ const onData = async (data) => {
401
+ const isEscape = data.length === 1 && data[0] === 0x1b;
402
+ const isUpArrow = data.length === 3 && data[0] === 0x1b && data[1] === 0x5b && data[2] === 0x41;
403
+ const isDownArrow = data.length === 3 && data[0] === 0x1b && data[1] === 0x5b && data[2] === 0x42;
404
+ const isCtrlC = data.length === 1 && data[0] === 0x03;
405
+ const isEnter = data.length === 1 && (data[0] === 0x0d || data[0] === 0x0a);
406
+ const isBackspace = data.length === 1 && (data[0] === 0x7f || data[0] === 0x08);
407
+ // Ctrl+C always cancels
408
+ if (isCtrlC) {
409
+ cleanup();
410
+ resolve({ created: false });
411
+ return;
412
+ }
413
+ // Escape on step 0 cancels, otherwise goes back
414
+ if (isEscape) {
415
+ if (state.step === 0) {
416
+ cleanup();
417
+ resolve({ created: false });
418
+ return;
419
+ }
420
+ prevStep();
421
+ lineCount = render(state, lineCount);
422
+ return;
423
+ }
424
+ // Handle selection steps
425
+ if (isSelectionStep(state.step)) {
426
+ const maxOptions = getMaxOptionsForStep(state.step);
427
+ if (isUpArrow && state.selectedIndex > 0) {
428
+ state.selectedIndex--;
429
+ lineCount = render(state, lineCount);
430
+ return;
431
+ }
432
+ if (isDownArrow && state.selectedIndex < maxOptions - 1) {
433
+ state.selectedIndex++;
434
+ lineCount = render(state, lineCount);
435
+ return;
436
+ }
437
+ if (isEnter) {
438
+ // Step 0 - only allow "new" option
439
+ if (state.step === 0 && state.selectedIndex === 1) {
440
+ state.error = 'This option is coming soon';
441
+ lineCount = render(state, lineCount);
442
+ return;
443
+ }
444
+ // Step 7 - confirmation
445
+ if (state.step === 7) {
446
+ if (state.selectedIndex === 1) {
447
+ // Cancel
448
+ cleanup();
449
+ resolve({ created: false });
450
+ return;
451
+ }
452
+ // Verify all required fields are set (they should be by step 7)
453
+ if (!state.repoPattern || !state.techStack || !state.codingStandards) {
454
+ state.error = 'Missing configuration values';
455
+ lineCount = render(state, lineCount);
456
+ return;
457
+ }
458
+ // Create project
459
+ const config = {
460
+ name: state.projectName,
461
+ description: state.description,
462
+ repoPattern: state.repoPattern,
463
+ techStack: state.techStack,
464
+ codingStandards: state.codingStandards,
465
+ initGit: state.initGit,
466
+ };
467
+ cleanup();
468
+ // Show "creating..." message
469
+ terminal.writeLine(chalk.cyan(' Creating project...'));
470
+ try {
471
+ const result = await generateProject(config);
472
+ if (result.success) {
473
+ resolve({
474
+ created: true,
475
+ projectPath: result.projectPath,
476
+ docsPath: result.docsPath,
477
+ filesCreated: result.filesCreated,
478
+ });
479
+ }
480
+ else {
481
+ terminal.writeLine(chalk.red(` Error: ${result.error ?? 'Unknown error'}`));
482
+ resolve({ created: false });
483
+ }
484
+ }
485
+ catch (error) {
486
+ terminal.writeLine(chalk.red(` Error: ${error.message}`));
487
+ resolve({ created: false });
488
+ }
489
+ return;
490
+ }
491
+ nextStep();
492
+ lineCount = render(state, lineCount);
493
+ return;
494
+ }
495
+ }
496
+ // Handle input steps
497
+ if (isInputStep(state.step)) {
498
+ if (isEnter) {
499
+ if (validateInput()) {
500
+ nextStep();
501
+ lineCount = render(state, lineCount);
502
+ }
503
+ else {
504
+ lineCount = render(state, lineCount);
505
+ }
506
+ return;
507
+ }
508
+ if (isBackspace) {
509
+ state.inputBuffer = state.inputBuffer.slice(0, -1);
510
+ state.error = null;
511
+ lineCount = render(state, lineCount);
512
+ return;
513
+ }
514
+ // Regular character input
515
+ const char = data.toString('utf-8');
516
+ if (char.length === 1 && char.charCodeAt(0) >= 32) {
517
+ state.inputBuffer += char;
518
+ state.error = null;
519
+ lineCount = render(state, lineCount);
520
+ }
521
+ }
522
+ };
523
+ process.stdin.on('data', handleData);
524
+ });
525
+ }
@@ -0,0 +1,179 @@
1
+ /**
2
+ * Input Prompt v2 (Event-Driven)
3
+ *
4
+ * Refactored input handling with event-driven architecture.
5
+ * - Emits events instead of blocking with getInput()
6
+ * - Supports queue mode for capturing input during agent execution
7
+ * - Always captures keystrokes (no blocking)
8
+ *
9
+ * Events:
10
+ * - 'submit' - User pressed Enter with input
11
+ * - 'command' - User submitted a slash command
12
+ * - 'cancel' - User pressed Ctrl+C
13
+ * - 'escape' - User pressed Esc (for aborting agent)
14
+ * - 'change' - Input text changed
15
+ */
16
+ import { EventEmitter } from 'events';
17
+ import type { CommandOption } from './types.js';
18
+ export declare const DEFAULT_COMMANDS: CommandOption[];
19
+ /**
20
+ * Strip ANSI codes from string
21
+ */
22
+ export declare function stripAnsi(str: string): string;
23
+ export interface InputPromptEvents {
24
+ submit: (input: string) => void;
25
+ command: (command: string, args: string) => void;
26
+ cancel: () => void;
27
+ escape: () => void;
28
+ change: (input: string) => void;
29
+ modeChange: () => void;
30
+ }
31
+ export interface InputPromptOptions {
32
+ prompt?: string;
33
+ showSeparators?: boolean;
34
+ commands?: CommandOption[];
35
+ }
36
+ export declare class InputPrompt extends EventEmitter {
37
+ private prompt;
38
+ private promptLen;
39
+ private readonly showSeparators;
40
+ private readonly commands;
41
+ private state;
42
+ private autocomplete;
43
+ private fileAutocomplete;
44
+ private readonly history;
45
+ private historyIndex;
46
+ private savedInput;
47
+ private queueMode;
48
+ private queuedInputs;
49
+ private renderedLines;
50
+ private dropdownLines;
51
+ private linesAboveCursor;
52
+ private hasSeparators;
53
+ private isRunning;
54
+ private lastEscTime;
55
+ private readonly DOUBLE_ESC_THRESHOLD_MS;
56
+ private suggestion;
57
+ constructor(options?: InputPromptOptions);
58
+ /**
59
+ * Update the prompt string (for dynamic theme changes)
60
+ */
61
+ setPrompt(prompt: string): void;
62
+ /**
63
+ * Set a suggestion for the next action (ghost text)
64
+ */
65
+ setSuggestion(action: string | null): void;
66
+ /**
67
+ * Get the current suggestion
68
+ */
69
+ getSuggestion(): string | null;
70
+ /**
71
+ * Clear the current suggestion
72
+ */
73
+ clearSuggestion(): void;
74
+ /**
75
+ * Start input capture (non-blocking, event-driven)
76
+ */
77
+ start(): void;
78
+ /**
79
+ * Stop input capture
80
+ */
81
+ stop(): void;
82
+ /**
83
+ * Check if running
84
+ */
85
+ isActive(): boolean;
86
+ /**
87
+ * Enable/disable queue mode
88
+ * In queue mode, Enter adds to queue instead of emitting 'submit'
89
+ */
90
+ setQueueMode(enabled: boolean): void;
91
+ /**
92
+ * Check if in queue mode
93
+ */
94
+ isQueueMode(): boolean;
95
+ /**
96
+ * Get all queued inputs (FIFO order)
97
+ */
98
+ getQueuedInputs(): string[];
99
+ /**
100
+ * Pop the first queued input
101
+ */
102
+ popQueuedInput(): string | null;
103
+ /**
104
+ * Check if there are queued inputs
105
+ */
106
+ hasQueuedInput(): boolean;
107
+ /**
108
+ * Get number of queued inputs
109
+ */
110
+ getQueueLength(): number;
111
+ /**
112
+ * Clear the queue
113
+ */
114
+ clearQueue(): void;
115
+ /**
116
+ * Get current buffer value
117
+ */
118
+ getValue(): string;
119
+ /**
120
+ * Set buffer value
121
+ */
122
+ setValue(value: string): void;
123
+ /**
124
+ * Clear input buffer
125
+ */
126
+ clearInput(): void;
127
+ /**
128
+ * Add command to history
129
+ */
130
+ addToHistory(input: string): void;
131
+ /**
132
+ * Render the input prompt - returns array of lines
133
+ * Does NOT write to terminal (Footer handles that)
134
+ */
135
+ render(): string[];
136
+ /**
137
+ * Get the cursor position info for rendering
138
+ */
139
+ getCursorInfo(): {
140
+ row: number;
141
+ col: number;
142
+ };
143
+ /**
144
+ * Get autocomplete dropdown lines (if active)
145
+ */
146
+ getAutocompleteLines(): string[];
147
+ /**
148
+ * Check if autocomplete is showing
149
+ */
150
+ isAutocompleteActive(): boolean;
151
+ /**
152
+ * Get height of rendered content
153
+ */
154
+ getHeight(): number;
155
+ /**
156
+ * @deprecated Use event-driven start() instead
157
+ * Kept for backwards compatibility during migration
158
+ */
159
+ getInput(): Promise<{
160
+ action: string;
161
+ value?: string;
162
+ command?: string;
163
+ args?: string;
164
+ }>;
165
+ private resetState;
166
+ private updateAutocomplete;
167
+ private getSeparatorLine;
168
+ private readonly handleData;
169
+ private handleKey;
170
+ private handleEnter;
171
+ private handleTab;
172
+ private handleArrowUp;
173
+ private handleArrowDown;
174
+ private handleArrowLeft;
175
+ private handleArrowRight;
176
+ private handleWordLeft;
177
+ private handleWordRight;
178
+ private handleBackspace;
179
+ }