@wundr.io/cli 1.0.11 → 1.0.12

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 (269) hide show
  1. package/bin/wundr.js +8 -4
  2. package/package.json +23 -23
  3. package/src/ai/ai-service.ts +16 -17
  4. package/src/ai/claude-client.ts +16 -16
  5. package/src/ai/conversation-manager.ts +29 -29
  6. package/src/cli.ts +4 -4
  7. package/src/commands/ai.ts +246 -78
  8. package/src/commands/alignment.ts +74 -74
  9. package/src/commands/analyze-optimized.ts +111 -78
  10. package/src/commands/analyze.ts +14 -14
  11. package/src/commands/batch.ts +179 -42
  12. package/src/commands/chat.ts +37 -30
  13. package/src/commands/claude-init.ts +41 -45
  14. package/src/commands/claude-setup.ts +204 -119
  15. package/src/commands/computer-setup.ts +85 -43
  16. package/src/commands/create-command.ts +4 -4
  17. package/src/commands/create.ts +27 -27
  18. package/src/commands/dashboard.ts +24 -24
  19. package/src/commands/govern.ts +25 -25
  20. package/src/commands/governance.ts +34 -34
  21. package/src/commands/guardian.ts +56 -56
  22. package/src/commands/init.ts +25 -22
  23. package/src/commands/orchestrator.ts +68 -41
  24. package/src/commands/performance-optimizer.ts +34 -35
  25. package/src/commands/plugins.ts +27 -27
  26. package/src/commands/project-update.ts +175 -72
  27. package/src/commands/rag.ts +185 -78
  28. package/src/commands/session.ts +35 -35
  29. package/src/commands/setup.ts +40 -344
  30. package/src/commands/test-init.ts +3 -3
  31. package/src/commands/test.ts +4 -4
  32. package/src/commands/watch.ts +28 -29
  33. package/src/commands/worktree.ts +49 -49
  34. package/src/context/context-manager.ts +10 -10
  35. package/src/context/session-manager.ts +41 -41
  36. package/src/framework/command-interface.ts +520 -0
  37. package/src/framework/command-registry.ts +942 -0
  38. package/src/framework/completion-exporter.ts +383 -0
  39. package/src/framework/debug-logger.ts +519 -0
  40. package/src/framework/error-handler.ts +867 -0
  41. package/src/framework/help-generator.ts +540 -0
  42. package/src/framework/index.ts +169 -0
  43. package/src/framework/interactive-repl.ts +703 -0
  44. package/src/framework/output-formatter.ts +834 -0
  45. package/src/framework/progress-manager.ts +539 -0
  46. package/src/index.ts +4 -4
  47. package/src/interactive/interactive-mode.ts +16 -16
  48. package/src/lib/conflict-resolution.ts +799 -9
  49. package/src/lib/merge-strategy.ts +529 -7
  50. package/src/lib/safety-mechanisms.ts +422 -18
  51. package/src/lib/state-detection.ts +1015 -13
  52. package/src/nlp/command-mapper.ts +29 -29
  53. package/src/nlp/command-parser.ts +17 -17
  54. package/src/nlp/intent-classifier.ts +7 -7
  55. package/src/nlp/intent-parser.ts +54 -52
  56. package/src/plugins/plugin-manager.ts +61 -39
  57. package/src/tests/computer-setup-integration.test.ts +46 -15
  58. package/src/types/modules.d.ts +424 -1
  59. package/src/utils/backup-rollback-manager.ts +11 -8
  60. package/src/utils/config-manager.ts +3 -3
  61. package/src/utils/error-handler.ts +2 -2
  62. package/src/utils/logger.ts +22 -22
  63. package/templates/batch/ci-cd.yaml +7 -7
  64. package/test-suites/api/health.spec.ts +20 -23
  65. package/test-suites/helpers/test-config.ts +14 -13
  66. package/test-suites/ui/accessibility.spec.ts +27 -22
  67. package/test-suites/ui/smoke.spec.ts +26 -21
  68. package/LICENSE +0 -21
  69. package/dist/ai/ai-service.d.ts +0 -152
  70. package/dist/ai/ai-service.d.ts.map +0 -1
  71. package/dist/ai/ai-service.js +0 -430
  72. package/dist/ai/ai-service.js.map +0 -1
  73. package/dist/ai/claude-client.d.ts +0 -130
  74. package/dist/ai/claude-client.d.ts.map +0 -1
  75. package/dist/ai/claude-client.js +0 -340
  76. package/dist/ai/claude-client.js.map +0 -1
  77. package/dist/ai/conversation-manager.d.ts +0 -164
  78. package/dist/ai/conversation-manager.d.ts.map +0 -1
  79. package/dist/ai/conversation-manager.js +0 -614
  80. package/dist/ai/conversation-manager.js.map +0 -1
  81. package/dist/ai/index.d.ts +0 -5
  82. package/dist/ai/index.d.ts.map +0 -1
  83. package/dist/ai/index.js +0 -8
  84. package/dist/ai/index.js.map +0 -1
  85. package/dist/cli.d.ts +0 -36
  86. package/dist/cli.d.ts.map +0 -1
  87. package/dist/cli.js +0 -192
  88. package/dist/cli.js.map +0 -1
  89. package/dist/commands/ai.d.ts +0 -89
  90. package/dist/commands/ai.d.ts.map +0 -1
  91. package/dist/commands/ai.js +0 -799
  92. package/dist/commands/ai.js.map +0 -1
  93. package/dist/commands/alignment.d.ts +0 -78
  94. package/dist/commands/alignment.d.ts.map +0 -1
  95. package/dist/commands/alignment.js +0 -817
  96. package/dist/commands/alignment.js.map +0 -1
  97. package/dist/commands/analyze-optimized.d.ts +0 -14
  98. package/dist/commands/analyze-optimized.d.ts.map +0 -1
  99. package/dist/commands/analyze-optimized.js +0 -600
  100. package/dist/commands/analyze-optimized.js.map +0 -1
  101. package/dist/commands/analyze.d.ts +0 -65
  102. package/dist/commands/analyze.d.ts.map +0 -1
  103. package/dist/commands/analyze.js +0 -435
  104. package/dist/commands/analyze.js.map +0 -1
  105. package/dist/commands/batch.d.ts +0 -71
  106. package/dist/commands/batch.d.ts.map +0 -1
  107. package/dist/commands/batch.js +0 -738
  108. package/dist/commands/batch.js.map +0 -1
  109. package/dist/commands/chat.d.ts +0 -71
  110. package/dist/commands/chat.d.ts.map +0 -1
  111. package/dist/commands/chat.js +0 -674
  112. package/dist/commands/chat.js.map +0 -1
  113. package/dist/commands/claude-init.d.ts +0 -28
  114. package/dist/commands/claude-init.d.ts.map +0 -1
  115. package/dist/commands/claude-init.js +0 -591
  116. package/dist/commands/claude-init.js.map +0 -1
  117. package/dist/commands/claude-setup.d.ts +0 -119
  118. package/dist/commands/claude-setup.d.ts.map +0 -1
  119. package/dist/commands/claude-setup.js +0 -1073
  120. package/dist/commands/claude-setup.js.map +0 -1
  121. package/dist/commands/computer-setup-commands.d.ts +0 -53
  122. package/dist/commands/computer-setup-commands.d.ts.map +0 -1
  123. package/dist/commands/computer-setup-commands.js +0 -705
  124. package/dist/commands/computer-setup-commands.js.map +0 -1
  125. package/dist/commands/computer-setup.d.ts +0 -7
  126. package/dist/commands/computer-setup.d.ts.map +0 -1
  127. package/dist/commands/computer-setup.js +0 -849
  128. package/dist/commands/computer-setup.js.map +0 -1
  129. package/dist/commands/create-command.d.ts +0 -7
  130. package/dist/commands/create-command.d.ts.map +0 -1
  131. package/dist/commands/create-command.js +0 -158
  132. package/dist/commands/create-command.js.map +0 -1
  133. package/dist/commands/create.d.ts +0 -74
  134. package/dist/commands/create.d.ts.map +0 -1
  135. package/dist/commands/create.js +0 -556
  136. package/dist/commands/create.js.map +0 -1
  137. package/dist/commands/dashboard.d.ts +0 -91
  138. package/dist/commands/dashboard.d.ts.map +0 -1
  139. package/dist/commands/dashboard.js +0 -538
  140. package/dist/commands/dashboard.js.map +0 -1
  141. package/dist/commands/govern.d.ts +0 -70
  142. package/dist/commands/govern.d.ts.map +0 -1
  143. package/dist/commands/govern.js +0 -481
  144. package/dist/commands/govern.js.map +0 -1
  145. package/dist/commands/governance.d.ts +0 -17
  146. package/dist/commands/governance.d.ts.map +0 -1
  147. package/dist/commands/governance.js +0 -703
  148. package/dist/commands/governance.js.map +0 -1
  149. package/dist/commands/guardian.d.ts +0 -20
  150. package/dist/commands/guardian.d.ts.map +0 -1
  151. package/dist/commands/guardian.js +0 -597
  152. package/dist/commands/guardian.js.map +0 -1
  153. package/dist/commands/init.d.ts +0 -59
  154. package/dist/commands/init.d.ts.map +0 -1
  155. package/dist/commands/init.js +0 -650
  156. package/dist/commands/init.js.map +0 -1
  157. package/dist/commands/orchestrator.d.ts +0 -7
  158. package/dist/commands/orchestrator.d.ts.map +0 -1
  159. package/dist/commands/orchestrator.js +0 -571
  160. package/dist/commands/orchestrator.js.map +0 -1
  161. package/dist/commands/performance-optimizer.d.ts +0 -30
  162. package/dist/commands/performance-optimizer.d.ts.map +0 -1
  163. package/dist/commands/performance-optimizer.js +0 -650
  164. package/dist/commands/performance-optimizer.js.map +0 -1
  165. package/dist/commands/plugins.d.ts +0 -87
  166. package/dist/commands/plugins.d.ts.map +0 -1
  167. package/dist/commands/plugins.js +0 -685
  168. package/dist/commands/plugins.js.map +0 -1
  169. package/dist/commands/rag.d.ts +0 -7
  170. package/dist/commands/rag.d.ts.map +0 -1
  171. package/dist/commands/rag.js +0 -748
  172. package/dist/commands/rag.js.map +0 -1
  173. package/dist/commands/session.d.ts +0 -41
  174. package/dist/commands/session.d.ts.map +0 -1
  175. package/dist/commands/session.js +0 -441
  176. package/dist/commands/session.js.map +0 -1
  177. package/dist/commands/setup.d.ts +0 -29
  178. package/dist/commands/setup.d.ts.map +0 -1
  179. package/dist/commands/setup.js +0 -397
  180. package/dist/commands/setup.js.map +0 -1
  181. package/dist/commands/test-init.d.ts +0 -9
  182. package/dist/commands/test-init.d.ts.map +0 -1
  183. package/dist/commands/test-init.js +0 -222
  184. package/dist/commands/test-init.js.map +0 -1
  185. package/dist/commands/test.d.ts +0 -25
  186. package/dist/commands/test.d.ts.map +0 -1
  187. package/dist/commands/test.js +0 -217
  188. package/dist/commands/test.js.map +0 -1
  189. package/dist/commands/vp.d.ts +0 -7
  190. package/dist/commands/vp.d.ts.map +0 -1
  191. package/dist/commands/vp.js +0 -571
  192. package/dist/commands/vp.js.map +0 -1
  193. package/dist/commands/watch.d.ts +0 -76
  194. package/dist/commands/watch.d.ts.map +0 -1
  195. package/dist/commands/watch.js +0 -613
  196. package/dist/commands/watch.js.map +0 -1
  197. package/dist/commands/worktree.d.ts +0 -63
  198. package/dist/commands/worktree.d.ts.map +0 -1
  199. package/dist/commands/worktree.js +0 -774
  200. package/dist/commands/worktree.js.map +0 -1
  201. package/dist/context/context-manager.d.ts +0 -155
  202. package/dist/context/context-manager.d.ts.map +0 -1
  203. package/dist/context/context-manager.js +0 -383
  204. package/dist/context/context-manager.js.map +0 -1
  205. package/dist/context/index.d.ts +0 -3
  206. package/dist/context/index.d.ts.map +0 -1
  207. package/dist/context/index.js +0 -6
  208. package/dist/context/index.js.map +0 -1
  209. package/dist/context/session-manager.d.ts +0 -207
  210. package/dist/context/session-manager.d.ts.map +0 -1
  211. package/dist/context/session-manager.js +0 -686
  212. package/dist/context/session-manager.js.map +0 -1
  213. package/dist/index.d.ts +0 -8
  214. package/dist/index.d.ts.map +0 -1
  215. package/dist/index.js +0 -51
  216. package/dist/index.js.map +0 -1
  217. package/dist/interactive/interactive-mode.d.ts +0 -76
  218. package/dist/interactive/interactive-mode.d.ts.map +0 -1
  219. package/dist/interactive/interactive-mode.js +0 -732
  220. package/dist/interactive/interactive-mode.js.map +0 -1
  221. package/dist/nlp/command-mapper.d.ts +0 -174
  222. package/dist/nlp/command-mapper.d.ts.map +0 -1
  223. package/dist/nlp/command-mapper.js +0 -624
  224. package/dist/nlp/command-mapper.js.map +0 -1
  225. package/dist/nlp/command-parser.d.ts +0 -106
  226. package/dist/nlp/command-parser.d.ts.map +0 -1
  227. package/dist/nlp/command-parser.js +0 -417
  228. package/dist/nlp/command-parser.js.map +0 -1
  229. package/dist/nlp/index.d.ts +0 -5
  230. package/dist/nlp/index.d.ts.map +0 -1
  231. package/dist/nlp/index.js +0 -8
  232. package/dist/nlp/index.js.map +0 -1
  233. package/dist/nlp/intent-classifier.d.ts +0 -59
  234. package/dist/nlp/intent-classifier.d.ts.map +0 -1
  235. package/dist/nlp/intent-classifier.js +0 -384
  236. package/dist/nlp/intent-classifier.js.map +0 -1
  237. package/dist/nlp/intent-parser.d.ts +0 -152
  238. package/dist/nlp/intent-parser.d.ts.map +0 -1
  239. package/dist/nlp/intent-parser.js +0 -744
  240. package/dist/nlp/intent-parser.js.map +0 -1
  241. package/dist/plugins/plugin-manager.d.ts +0 -120
  242. package/dist/plugins/plugin-manager.d.ts.map +0 -1
  243. package/dist/plugins/plugin-manager.js +0 -595
  244. package/dist/plugins/plugin-manager.js.map +0 -1
  245. package/dist/types/index.d.ts +0 -224
  246. package/dist/types/index.d.ts.map +0 -1
  247. package/dist/types/index.js +0 -3
  248. package/dist/types/index.js.map +0 -1
  249. package/dist/utils/backup-rollback-manager.d.ts +0 -72
  250. package/dist/utils/backup-rollback-manager.d.ts.map +0 -1
  251. package/dist/utils/backup-rollback-manager.js +0 -289
  252. package/dist/utils/backup-rollback-manager.js.map +0 -1
  253. package/dist/utils/claude-config-installer.d.ts +0 -98
  254. package/dist/utils/claude-config-installer.d.ts.map +0 -1
  255. package/dist/utils/claude-config-installer.js +0 -678
  256. package/dist/utils/claude-config-installer.js.map +0 -1
  257. package/dist/utils/config-manager.d.ts +0 -73
  258. package/dist/utils/config-manager.d.ts.map +0 -1
  259. package/dist/utils/config-manager.js +0 -339
  260. package/dist/utils/config-manager.js.map +0 -1
  261. package/dist/utils/error-handler.d.ts +0 -46
  262. package/dist/utils/error-handler.d.ts.map +0 -1
  263. package/dist/utils/error-handler.js +0 -169
  264. package/dist/utils/error-handler.js.map +0 -1
  265. package/dist/utils/logger.d.ts +0 -25
  266. package/dist/utils/logger.d.ts.map +0 -1
  267. package/dist/utils/logger.js +0 -105
  268. package/dist/utils/logger.js.map +0 -1
  269. package/src/commands/computer-setup-commands.ts +0 -872
@@ -0,0 +1,540 @@
1
+ /**
2
+ * Help Generator - Generates structured help text from command metadata.
3
+ *
4
+ * Produces:
5
+ * - Categorized command listings
6
+ * - Per-command detailed help with examples
7
+ * - Man-page style output for documentation
8
+ * - Markdown help for README generation
9
+ * - Search across all commands
10
+ *
11
+ * @module framework/help-generator
12
+ */
13
+
14
+ import chalk from 'chalk';
15
+
16
+ import type { CommandDefinition, CommandCategory } from './command-interface';
17
+ import { CATEGORY_LABELS } from './command-interface';
18
+ import type { CommandRegistry } from './command-registry';
19
+
20
+ // ---------------------------------------------------------------------------
21
+ // Types
22
+ // ---------------------------------------------------------------------------
23
+
24
+ /**
25
+ * Options for help text generation.
26
+ */
27
+ export interface HelpGeneratorOptions {
28
+ /** Program name. Defaults to 'wundr'. */
29
+ programName?: string;
30
+
31
+ /** Maximum line width. Defaults to terminal width or 80. */
32
+ maxWidth?: number;
33
+
34
+ /** Whether to use colors. Defaults to TTY detection. */
35
+ color?: boolean;
36
+
37
+ /** Output format. */
38
+ format?: 'terminal' | 'markdown' | 'plain';
39
+ }
40
+
41
+ /**
42
+ * Result of a command search.
43
+ */
44
+ export interface SearchResult {
45
+ command: CommandDefinition;
46
+ matchType: 'name' | 'alias' | 'description' | 'category';
47
+ score: number;
48
+ }
49
+
50
+ // ---------------------------------------------------------------------------
51
+ // Help Generator
52
+ // ---------------------------------------------------------------------------
53
+
54
+ export class HelpGenerator {
55
+ private programName: string;
56
+ private maxWidth: number;
57
+ private useColor: boolean;
58
+ private format: 'terminal' | 'markdown' | 'plain';
59
+
60
+ constructor(
61
+ private registry: CommandRegistry,
62
+ options: HelpGeneratorOptions = {}
63
+ ) {
64
+ this.programName = options.programName ?? 'wundr';
65
+ this.maxWidth = options.maxWidth ?? process.stdout.columns ?? 80;
66
+ this.useColor = options.color ?? process.stdout.isTTY === true;
67
+ this.format = options.format ?? 'terminal';
68
+ }
69
+
70
+ // -------------------------------------------------------------------------
71
+ // Main Help
72
+ // -------------------------------------------------------------------------
73
+
74
+ /**
75
+ * Generate the main help text showing all commands grouped by category.
76
+ */
77
+ generateMainHelp(): string {
78
+ if (this.format === 'markdown') {
79
+ return this.generateMarkdownMainHelp();
80
+ }
81
+
82
+ const lines: string[] = [];
83
+
84
+ // Header
85
+ lines.push('');
86
+ lines.push(this.heading(`${this.programName} - CLI Tool`));
87
+ lines.push('');
88
+
89
+ // Usage
90
+ lines.push(this.sectionTitle('Usage'));
91
+ lines.push(` ${this.programName} <command> [options]`);
92
+ lines.push('');
93
+
94
+ // Commands by category
95
+ const grouped = this.registry.grouped();
96
+ const categories = Array.from(grouped.keys()).sort();
97
+
98
+ for (const category of categories) {
99
+ const commands = grouped.get(category);
100
+ if (!commands || commands.length === 0) continue;
101
+
102
+ // Skip hidden commands
103
+ const visible = commands.filter(
104
+ cmd => !cmd.hidden && !cmd.name.includes(':')
105
+ );
106
+ if (visible.length === 0) continue;
107
+
108
+ const label =
109
+ category === 'uncategorized'
110
+ ? 'Other Commands'
111
+ : (CATEGORY_LABELS[category as CommandCategory] ?? category);
112
+
113
+ lines.push(this.sectionTitle(label));
114
+
115
+ // Find max name width for alignment
116
+ const maxNameWidth = Math.max(
117
+ ...visible.map(cmd => {
118
+ const aliases = cmd.aliases ? `, ${cmd.aliases.join(', ')}` : '';
119
+ return cmd.name.length + aliases.length;
120
+ })
121
+ );
122
+
123
+ for (const cmd of visible) {
124
+ const aliases = cmd.aliases ? `, ${cmd.aliases.join(', ')}` : '';
125
+ const nameCol = (cmd.name + aliases).padEnd(maxNameWidth + 2);
126
+ lines.push(` ${this.highlight(nameCol)} ${cmd.description}`);
127
+ }
128
+
129
+ lines.push('');
130
+ }
131
+
132
+ // Global options
133
+ lines.push(this.sectionTitle('Global Options'));
134
+ lines.push(' --verbose Enable verbose logging');
135
+ lines.push(' --quiet Suppress output');
136
+ lines.push(' --json Output as JSON');
137
+ lines.push(' --no-color Disable colored output');
138
+ lines.push(' --dry-run Show what would be done');
139
+ lines.push(' --config <path> Specify config file');
140
+ lines.push(' -h, --help Show help');
141
+ lines.push(' -v, --version Show version');
142
+ lines.push('');
143
+
144
+ // Footer
145
+ lines.push(
146
+ this.dim(
147
+ `Run '${this.programName} <command> --help' for detailed help on a command.`
148
+ )
149
+ );
150
+ lines.push('');
151
+
152
+ return lines.join('\n');
153
+ }
154
+
155
+ // -------------------------------------------------------------------------
156
+ // Command Help
157
+ // -------------------------------------------------------------------------
158
+
159
+ /**
160
+ * Generate detailed help for a specific command.
161
+ */
162
+ generateCommandHelp(command: CommandDefinition): string {
163
+ if (this.format === 'markdown') {
164
+ return this.generateMarkdownCommandHelp(command);
165
+ }
166
+
167
+ const lines: string[] = [];
168
+
169
+ // Header
170
+ lines.push('');
171
+ lines.push(this.heading(command.name));
172
+ lines.push(` ${command.description}`);
173
+ lines.push('');
174
+
175
+ // Aliases
176
+ if (command.aliases && command.aliases.length > 0) {
177
+ lines.push(this.sectionTitle('Aliases'));
178
+ lines.push(` ${command.aliases.join(', ')}`);
179
+ lines.push('');
180
+ }
181
+
182
+ // Usage
183
+ lines.push(this.sectionTitle('Usage'));
184
+ const usage = this.buildUsageLine(command);
185
+ lines.push(` ${usage}`);
186
+ lines.push('');
187
+
188
+ // Arguments
189
+ if (command.arguments && command.arguments.length > 0) {
190
+ lines.push(this.sectionTitle('Arguments'));
191
+ const maxArgWidth = Math.max(
192
+ ...command.arguments.map(a => a.name.length)
193
+ );
194
+
195
+ for (const arg of command.arguments) {
196
+ const nameCol = arg.name.padEnd(maxArgWidth + 2);
197
+ const required = arg.required
198
+ ? this.warn('(required)')
199
+ : this.dim('(optional)');
200
+ const defaultVal = arg.defaultValue
201
+ ? this.dim(` [default: ${arg.defaultValue}]`)
202
+ : '';
203
+ lines.push(
204
+ ` ${this.highlight(nameCol)} ${arg.description} ${required}${defaultVal}`
205
+ );
206
+ }
207
+ lines.push('');
208
+ }
209
+
210
+ // Options
211
+ if (command.options && command.options.length > 0) {
212
+ lines.push(this.sectionTitle('Options'));
213
+ const maxFlagWidth = Math.max(
214
+ ...command.options.map(o => o.flags.length)
215
+ );
216
+
217
+ for (const opt of command.options) {
218
+ const flagCol = opt.flags.padEnd(maxFlagWidth + 2);
219
+ const required = opt.required ? this.warn('(required)') : '';
220
+ const choices = opt.choices
221
+ ? this.dim(` [${opt.choices.join('|')}]`)
222
+ : '';
223
+ const defaultVal =
224
+ opt.defaultValue !== undefined
225
+ ? this.dim(` [default: ${opt.defaultValue}]`)
226
+ : '';
227
+ const envVar = opt.envVar ? this.dim(` [env: ${opt.envVar}]`) : '';
228
+ lines.push(
229
+ ` ${this.highlight(flagCol)} ${opt.description}${required}${choices}${defaultVal}${envVar}`
230
+ );
231
+ }
232
+ lines.push('');
233
+ }
234
+
235
+ // Subcommands
236
+ if (command.subcommands && command.subcommands.length > 0) {
237
+ lines.push(this.sectionTitle('Subcommands'));
238
+ const maxSubWidth = Math.max(
239
+ ...command.subcommands.map(s => s.name.length)
240
+ );
241
+
242
+ for (const sub of command.subcommands) {
243
+ const nameCol = sub.name.padEnd(maxSubWidth + 2);
244
+ lines.push(` ${this.highlight(nameCol)} ${sub.description}`);
245
+ }
246
+ lines.push('');
247
+ }
248
+
249
+ // Examples
250
+ if (command.examples && command.examples.length > 0) {
251
+ lines.push(this.sectionTitle('Examples'));
252
+ for (const ex of command.examples) {
253
+ lines.push(` ${this.highlight(`$ ${ex.command}`)}`);
254
+ lines.push(` ${this.dim(ex.description)}`);
255
+ lines.push('');
256
+ }
257
+ }
258
+
259
+ return lines.join('\n');
260
+ }
261
+
262
+ // -------------------------------------------------------------------------
263
+ // Search
264
+ // -------------------------------------------------------------------------
265
+
266
+ /**
267
+ * Search for commands matching a query string.
268
+ */
269
+ search(query: string): SearchResult[] {
270
+ const normalizedQuery = query.toLowerCase();
271
+ const results: SearchResult[] = [];
272
+
273
+ for (const command of this.registry.list()) {
274
+ if (command.hidden) continue;
275
+
276
+ let bestScore = 0;
277
+ let matchType: SearchResult['matchType'] = 'name';
278
+
279
+ // Name match
280
+ const nameScore = this.fuzzyScore(
281
+ normalizedQuery,
282
+ command.name.toLowerCase()
283
+ );
284
+ if (nameScore > bestScore) {
285
+ bestScore = nameScore;
286
+ matchType = 'name';
287
+ }
288
+
289
+ // Alias match
290
+ if (command.aliases) {
291
+ for (const alias of command.aliases) {
292
+ const aliasScore = this.fuzzyScore(
293
+ normalizedQuery,
294
+ alias.toLowerCase()
295
+ );
296
+ if (aliasScore > bestScore) {
297
+ bestScore = aliasScore;
298
+ matchType = 'alias';
299
+ }
300
+ }
301
+ }
302
+
303
+ // Description match
304
+ const descScore =
305
+ this.fuzzyScore(normalizedQuery, command.description.toLowerCase()) *
306
+ 0.6;
307
+ if (descScore > bestScore) {
308
+ bestScore = descScore;
309
+ matchType = 'description';
310
+ }
311
+
312
+ // Category match
313
+ if (command.category) {
314
+ const catLabel = CATEGORY_LABELS[command.category]?.toLowerCase() ?? '';
315
+ const catScore = this.fuzzyScore(normalizedQuery, catLabel) * 0.4;
316
+ if (catScore > bestScore) {
317
+ bestScore = catScore;
318
+ matchType = 'category';
319
+ }
320
+ }
321
+
322
+ if (bestScore > 0.3) {
323
+ results.push({ command, matchType, score: bestScore });
324
+ }
325
+ }
326
+
327
+ return results.sort((a, b) => b.score - a.score);
328
+ }
329
+
330
+ // -------------------------------------------------------------------------
331
+ // Markdown Output
332
+ // -------------------------------------------------------------------------
333
+
334
+ /**
335
+ * Generate the main help as Markdown.
336
+ */
337
+ private generateMarkdownMainHelp(): string {
338
+ const lines: string[] = [];
339
+
340
+ lines.push(`# ${this.programName} CLI`);
341
+ lines.push('');
342
+ lines.push('## Usage');
343
+ lines.push('');
344
+ lines.push('```');
345
+ lines.push(`${this.programName} <command> [options]`);
346
+ lines.push('```');
347
+ lines.push('');
348
+
349
+ const grouped = this.registry.grouped();
350
+ const categories = Array.from(grouped.keys()).sort();
351
+
352
+ for (const category of categories) {
353
+ const commands = grouped.get(category);
354
+ if (!commands || commands.length === 0) continue;
355
+
356
+ const visible = commands.filter(
357
+ cmd => !cmd.hidden && !cmd.name.includes(':')
358
+ );
359
+ if (visible.length === 0) continue;
360
+
361
+ const label =
362
+ category === 'uncategorized'
363
+ ? 'Other Commands'
364
+ : (CATEGORY_LABELS[category as CommandCategory] ?? category);
365
+
366
+ lines.push(`## ${label}`);
367
+ lines.push('');
368
+ lines.push('| Command | Description |');
369
+ lines.push('|---------|-------------|');
370
+
371
+ for (const cmd of visible) {
372
+ const aliases = cmd.aliases ? ` (${cmd.aliases.join(', ')})` : '';
373
+ lines.push(`| \`${cmd.name}\`${aliases} | ${cmd.description} |`);
374
+ }
375
+ lines.push('');
376
+ }
377
+
378
+ lines.push('## Global Options');
379
+ lines.push('');
380
+ lines.push('| Option | Description |');
381
+ lines.push('|--------|-------------|');
382
+ lines.push('| `--verbose` | Enable verbose logging |');
383
+ lines.push('| `--quiet` | Suppress output |');
384
+ lines.push('| `--json` | Output as JSON |');
385
+ lines.push('| `--no-color` | Disable colored output |');
386
+ lines.push('| `--dry-run` | Show what would be done |');
387
+ lines.push('| `--config <path>` | Specify config file |');
388
+ lines.push('');
389
+
390
+ return lines.join('\n');
391
+ }
392
+
393
+ /**
394
+ * Generate per-command help as Markdown.
395
+ */
396
+ private generateMarkdownCommandHelp(command: CommandDefinition): string {
397
+ const lines: string[] = [];
398
+
399
+ lines.push(`# ${command.name}`);
400
+ lines.push('');
401
+ lines.push(command.description);
402
+ lines.push('');
403
+
404
+ if (command.aliases && command.aliases.length > 0) {
405
+ lines.push(`**Aliases:** ${command.aliases.join(', ')}`);
406
+ lines.push('');
407
+ }
408
+
409
+ lines.push('## Usage');
410
+ lines.push('');
411
+ lines.push('```');
412
+ lines.push(this.buildUsageLine(command));
413
+ lines.push('```');
414
+ lines.push('');
415
+
416
+ if (command.arguments && command.arguments.length > 0) {
417
+ lines.push('## Arguments');
418
+ lines.push('');
419
+ lines.push('| Name | Description | Required | Default |');
420
+ lines.push('|------|-------------|----------|---------|');
421
+ for (const arg of command.arguments) {
422
+ lines.push(
423
+ `| \`${arg.name}\` | ${arg.description} | ${arg.required ? 'Yes' : 'No'} | ${arg.defaultValue ?? '-'} |`
424
+ );
425
+ }
426
+ lines.push('');
427
+ }
428
+
429
+ if (command.options && command.options.length > 0) {
430
+ lines.push('## Options');
431
+ lines.push('');
432
+ lines.push('| Flag | Description | Required | Default |');
433
+ lines.push('|------|-------------|----------|---------|');
434
+ for (const opt of command.options) {
435
+ const defaultVal =
436
+ opt.defaultValue !== undefined ? String(opt.defaultValue) : '-';
437
+ lines.push(
438
+ `| \`${opt.flags}\` | ${opt.description} | ${opt.required ? 'Yes' : 'No'} | ${defaultVal} |`
439
+ );
440
+ }
441
+ lines.push('');
442
+ }
443
+
444
+ if (command.examples && command.examples.length > 0) {
445
+ lines.push('## Examples');
446
+ lines.push('');
447
+ for (const ex of command.examples) {
448
+ lines.push(`**${ex.description}:**`);
449
+ lines.push('```');
450
+ lines.push(ex.command);
451
+ lines.push('```');
452
+ lines.push('');
453
+ }
454
+ }
455
+
456
+ return lines.join('\n');
457
+ }
458
+
459
+ // -------------------------------------------------------------------------
460
+ // Private Helpers
461
+ // -------------------------------------------------------------------------
462
+
463
+ /**
464
+ * Build a usage line from command definition.
465
+ */
466
+ private buildUsageLine(command: CommandDefinition): string {
467
+ const parts = [this.programName, command.name];
468
+
469
+ if (command.arguments) {
470
+ for (const arg of command.arguments) {
471
+ if (arg.required) {
472
+ parts.push(arg.variadic ? `<${arg.name}...>` : `<${arg.name}>`);
473
+ } else {
474
+ parts.push(arg.variadic ? `[${arg.name}...]` : `[${arg.name}]`);
475
+ }
476
+ }
477
+ }
478
+
479
+ if (command.options && command.options.length > 0) {
480
+ parts.push('[options]');
481
+ }
482
+
483
+ return parts.join(' ');
484
+ }
485
+
486
+ /**
487
+ * Simple fuzzy matching score between query and target.
488
+ * Returns 0-1 where 1 is an exact match.
489
+ */
490
+ private fuzzyScore(query: string, target: string): number {
491
+ if (query === target) return 1;
492
+ if (target.startsWith(query)) return 0.9;
493
+ if (target.includes(query)) return 0.7;
494
+
495
+ // Character-by-character fuzzy
496
+ let qi = 0;
497
+ let ti = 0;
498
+ let matched = 0;
499
+
500
+ while (qi < query.length && ti < target.length) {
501
+ if (query[qi] === target[ti]) {
502
+ matched++;
503
+ qi++;
504
+ }
505
+ ti++;
506
+ }
507
+
508
+ if (qi < query.length) return 0;
509
+ return matched / target.length;
510
+ }
511
+
512
+ // -------------------------------------------------------------------------
513
+ // Text formatting helpers
514
+ // -------------------------------------------------------------------------
515
+
516
+ private heading(text: string): string {
517
+ if (!this.useColor) return text;
518
+ return chalk.cyan.bold(text);
519
+ }
520
+
521
+ private sectionTitle(text: string): string {
522
+ if (!this.useColor) return `${text}:`;
523
+ return chalk.white.bold(`${text}:`);
524
+ }
525
+
526
+ private highlight(text: string): string {
527
+ if (!this.useColor) return text;
528
+ return chalk.green(text);
529
+ }
530
+
531
+ private dim(text: string): string {
532
+ if (!this.useColor) return text;
533
+ return chalk.gray(text);
534
+ }
535
+
536
+ private warn(text: string): string {
537
+ if (!this.useColor) return text;
538
+ return chalk.yellow(text);
539
+ }
540
+ }
@@ -0,0 +1,169 @@
1
+ /**
2
+ * Wundr CLI Framework - Public API
3
+ *
4
+ * This module provides the core framework for building CLI commands:
5
+ *
6
+ * - **CommandDefinition**: The interface every command implements
7
+ * - **CommandRegistry**: Auto-discovery and Commander.js integration
8
+ * - **OutputFormatter**: Consistent table, JSON, YAML, status, progress output
9
+ * - **CliErrorHandler**: Typed errors with classification and recovery
10
+ * - **InteractiveRepl**: REPL loop with history, aliases, and tab completion
11
+ * - **HelpGenerator**: Structured help text from command metadata
12
+ * - **CompletionExporter**: Shell completion script generation
13
+ * - **DebugLogger**: Verbose/debug logging with TTY detection
14
+ * - **ProgressBar / StepTracker**: Progress tracking for long operations
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * import {
19
+ * CommandDefinition,
20
+ * CommandRegistry,
21
+ * OutputFormatter,
22
+ * CliErrorHandler,
23
+ * InteractiveRepl,
24
+ * HelpGenerator,
25
+ * CompletionExporter,
26
+ * DebugLogger,
27
+ * ProgressBar,
28
+ * StepTracker,
29
+ * commandSuccess,
30
+ * commandFailure,
31
+ * validationOk,
32
+ * validationFail,
33
+ * } from './framework';
34
+ *
35
+ * const myCommand: CommandDefinition = {
36
+ * name: 'status',
37
+ * description: 'Show system status',
38
+ * category: 'daemon',
39
+ * async execute(args, options, context) {
40
+ * const data = await getStatus();
41
+ * const formatter = new OutputFormatter();
42
+ * const message = formatter.keyValue(data);
43
+ * return commandSuccess(data, message);
44
+ * },
45
+ * };
46
+ *
47
+ * const registry = new CommandRegistry();
48
+ * registry.register(myCommand);
49
+ * ```
50
+ *
51
+ * @module framework
52
+ */
53
+
54
+ // Command Interface - Types and contracts
55
+ export {
56
+ // Core interface
57
+ type CommandDefinition,
58
+ type CommandModule,
59
+ type CommandHook,
60
+
61
+ // Argument/option types
62
+ type ArgumentDefinition,
63
+ type OptionDefinition,
64
+ type CommandExample,
65
+
66
+ // Categories
67
+ type CommandCategory,
68
+ CATEGORY_LABELS,
69
+
70
+ // Validation
71
+ type ValidationResult,
72
+ type ValidationError,
73
+ validationOk,
74
+ validationFail,
75
+
76
+ // Context
77
+ type CommandContext,
78
+ type GlobalOptions,
79
+ type ContextLogger,
80
+ type OutputFormatterInterface,
81
+ type ConfigManagerInterface,
82
+
83
+ // Results
84
+ type CommandResult,
85
+ commandSuccess,
86
+ commandFailure,
87
+
88
+ // Legacy adapter
89
+ wrapLegacyCommand,
90
+ } from './command-interface';
91
+
92
+ // Command Registry
93
+ export {
94
+ CommandRegistry,
95
+ type RegistryOptions,
96
+ type RegisteredCommand,
97
+ } from './command-registry';
98
+
99
+ // Output Formatter
100
+ export {
101
+ OutputFormatter,
102
+ type TableOptions,
103
+ type ColumnDefinition,
104
+ type JsonOptions,
105
+ type KeyValueOptions,
106
+ type ListOptions,
107
+ type TreeNode,
108
+ type TreeOptions,
109
+ type ProgressOptions,
110
+ type StatusState,
111
+ } from './output-formatter';
112
+
113
+ // Error Handler
114
+ export {
115
+ CliErrorHandler,
116
+ CliError,
117
+ type ErrorCode,
118
+ type ErrorDetails,
119
+ type RecoverySuggestion,
120
+ type ErrorRecoveryHandler,
121
+ type ErrorClassification,
122
+ type ClassifiedError,
123
+ classifyError,
124
+ classifyAnyError,
125
+ } from './error-handler';
126
+
127
+ // Interactive REPL
128
+ export {
129
+ InteractiveRepl,
130
+ type ReplOptions,
131
+ type HistoryEntry,
132
+ } from './interactive-repl';
133
+
134
+ // Help Generator
135
+ export {
136
+ HelpGenerator,
137
+ type HelpGeneratorOptions,
138
+ type SearchResult,
139
+ } from './help-generator';
140
+
141
+ // Completion Exporter
142
+ export {
143
+ CompletionExporter,
144
+ type ShellType,
145
+ type CompletionData,
146
+ type CompletionCommand,
147
+ type CompletionArgument,
148
+ type CompletionOption,
149
+ } from './completion-exporter';
150
+
151
+ // Debug Logger
152
+ export {
153
+ DebugLogger,
154
+ TaggedLogger,
155
+ type LogLevel,
156
+ type LogEntry,
157
+ type DebugLoggerOptions,
158
+ } from './debug-logger';
159
+
160
+ // Progress Manager
161
+ export {
162
+ ProgressBar,
163
+ MultiProgressManager,
164
+ StepTracker,
165
+ type ProgressBarOptions,
166
+ type ProgressState,
167
+ type ProgressStep,
168
+ type StepTrackerOptions,
169
+ } from './progress-manager';