wiggum-cli 0.5.0 → 0.5.1

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 (41) hide show
  1. package/dist/ai/agents/codebase-analyzer.d.ts.map +1 -1
  2. package/dist/ai/agents/codebase-analyzer.js +9 -2
  3. package/dist/ai/agents/codebase-analyzer.js.map +1 -1
  4. package/dist/ai/agents/mcp-detector.d.ts +4 -2
  5. package/dist/ai/agents/mcp-detector.d.ts.map +1 -1
  6. package/dist/ai/agents/mcp-detector.js +9 -6
  7. package/dist/ai/agents/mcp-detector.js.map +1 -1
  8. package/dist/ai/agents/types.d.ts +12 -2
  9. package/dist/ai/agents/types.d.ts.map +1 -1
  10. package/dist/ai/enhancer.d.ts +27 -1
  11. package/dist/ai/enhancer.d.ts.map +1 -1
  12. package/dist/ai/enhancer.js +52 -7
  13. package/dist/ai/enhancer.js.map +1 -1
  14. package/dist/ai/index.d.ts +1 -1
  15. package/dist/ai/index.d.ts.map +1 -1
  16. package/dist/ai/index.js.map +1 -1
  17. package/dist/commands/init.d.ts.map +1 -1
  18. package/dist/commands/init.js +113 -112
  19. package/dist/commands/init.js.map +1 -1
  20. package/dist/utils/colors.d.ts +47 -0
  21. package/dist/utils/colors.d.ts.map +1 -1
  22. package/dist/utils/colors.js +108 -0
  23. package/dist/utils/colors.js.map +1 -1
  24. package/dist/utils/header.d.ts.map +1 -1
  25. package/dist/utils/header.js +19 -2
  26. package/dist/utils/header.js.map +1 -1
  27. package/dist/utils/spinner.d.ts +74 -0
  28. package/dist/utils/spinner.d.ts.map +1 -0
  29. package/dist/utils/spinner.js +208 -0
  30. package/dist/utils/spinner.js.map +1 -0
  31. package/package.json +1 -1
  32. package/src/ai/agents/codebase-analyzer.ts +12 -3
  33. package/src/ai/agents/mcp-detector.test.ts +30 -7
  34. package/src/ai/agents/mcp-detector.ts +10 -7
  35. package/src/ai/agents/types.ts +13 -2
  36. package/src/ai/enhancer.ts +88 -9
  37. package/src/ai/index.ts +2 -0
  38. package/src/commands/init.ts +129 -124
  39. package/src/utils/colors.ts +139 -0
  40. package/src/utils/header.ts +19 -2
  41. package/src/utils/spinner.ts +262 -0
@@ -1 +1 @@
1
- {"version":3,"file":"header.js","sourceRoot":"","sources":["../../src/utils/header.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE/D;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,+BAA+B;IAC/B,MAAM,WAAW,GAAG,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,4CAA4C,CAAC;IACnH,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEhB,mCAAmC;IACnC,MAAM,CAAC,GAAG,CAAC,YAAY,EAAE;QACvB,IAAI,EAAE,OAAO;QACb,MAAM,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC;QAC/B,aAAa,EAAE,CAAC;QAChB,UAAU,EAAE,CAAC;QACb,KAAK,EAAE,KAAK;QACZ,SAAS,EAAE,CAAC;KACb,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB;IAClC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,mCAAmC,CAAC,CAAC;IACvG,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAClB,CAAC"}
1
+ {"version":3,"file":"header.js","sourceRoot":"","sources":["../../src/utils/header.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAErC,gCAAgC;AAChC,SAAS,UAAU;IACjB,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClD,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;QACtC,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;QAChE,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC;QAC3D,OAAO,GAAG,CAAC,OAAO,IAAI,OAAO,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,4CAA4C;IAC5C,MAAM,WAAW,GAAG,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,OAAO,EAAE,CAAC,GAAG,KAAK,CAAC;IACjL,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC;IACrC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEhB,mCAAmC;IACnC,MAAM,CAAC,GAAG,CAAC,YAAY,EAAE;QACvB,IAAI,EAAE,OAAO;QACb,MAAM,EAAE,CAAC,cAAc,CAAC,MAAM,CAAC;QAC/B,aAAa,EAAE,CAAC;QAChB,UAAU,EAAE,CAAC;QACb,KAAK,EAAE,KAAK;QACZ,SAAS,EAAE,CAAC;KACb,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB;IAClC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,mCAAmC,CAAC,CAAC;IACvG,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAClB,CAAC"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Custom Spinner with Shimmer Effect, Timer, and Token Tracking
3
+ * Inspired by Claude Code's loading experience
4
+ */
5
+ export interface ShimmerSpinnerOptions {
6
+ /** Enable shimmer effect (default: true) */
7
+ shimmer?: boolean;
8
+ /** Show elapsed time (default: true) */
9
+ showTimer?: boolean;
10
+ /** Show token usage (default: false) */
11
+ showTokens?: boolean;
12
+ /** Spinner style (default: 'shimmer') */
13
+ style?: 'shimmer' | 'braille' | 'dots';
14
+ }
15
+ export interface TokenUsage {
16
+ inputTokens: number;
17
+ outputTokens: number;
18
+ totalTokens: number;
19
+ }
20
+ /**
21
+ * Custom spinner with shimmer effect, timer, and token tracking
22
+ */
23
+ export declare class ShimmerSpinner {
24
+ private message;
25
+ private isRunning;
26
+ private intervalId;
27
+ private frameIndex;
28
+ private startTime;
29
+ private tokens;
30
+ private options;
31
+ private frames;
32
+ constructor(options?: ShimmerSpinnerOptions);
33
+ /**
34
+ * Start the spinner with a message
35
+ */
36
+ start(message: string): void;
37
+ /**
38
+ * Update the spinner message
39
+ */
40
+ update(message: string): void;
41
+ /**
42
+ * Update token usage (adds to existing)
43
+ */
44
+ updateTokens(usage: TokenUsage): void;
45
+ /**
46
+ * Set token usage directly
47
+ */
48
+ setTokens(usage: TokenUsage): void;
49
+ /**
50
+ * Render the spinner
51
+ */
52
+ private render;
53
+ /**
54
+ * Stop the spinner with a final message
55
+ */
56
+ stop(finalMessage?: string): void;
57
+ /**
58
+ * Stop with error
59
+ */
60
+ fail(message?: string): void;
61
+ /**
62
+ * Get elapsed time in milliseconds
63
+ */
64
+ getElapsed(): number;
65
+ /**
66
+ * Get current token usage
67
+ */
68
+ getTokens(): TokenUsage;
69
+ }
70
+ /**
71
+ * Create a shimmer spinner instance
72
+ */
73
+ export declare function createShimmerSpinner(options?: ShimmerSpinnerOptions): ShimmerSpinner;
74
+ //# sourceMappingURL=spinner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spinner.d.ts","sourceRoot":"","sources":["../../src/utils/spinner.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAkDH,MAAM,WAAW,qBAAqB;IACpC,4CAA4C;IAC5C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,wCAAwC;IACxC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,wCAAwC;IACxC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,yCAAyC;IACzC,KAAK,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;CACxC;AAED,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,SAAS,CAAa;IAC9B,OAAO,CAAC,MAAM,CAAmE;IACjF,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,MAAM,CAAW;gBAEb,OAAO,GAAE,qBAA0B;IAuB/C;;OAEG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAgB5B;;OAEG;IACH,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAI7B;;OAEG;IACH,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAQrC;;OAEG;IACH,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAIlC;;OAEG;IACH,OAAO,CAAC,MAAM;IAgCd;;OAEG;IACH,IAAI,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI;IA4BjC;;OAEG;IACH,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI;IAsB5B;;OAEG;IACH,UAAU,IAAI,MAAM;IAIpB;;OAEG;IACH,SAAS,IAAI,UAAU;CAGxB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,CAAC,EAAE,qBAAqB,GAAG,cAAc,CAEpF"}
@@ -0,0 +1,208 @@
1
+ /**
2
+ * Custom Spinner with Shimmer Effect, Timer, and Token Tracking
3
+ * Inspired by Claude Code's loading experience
4
+ */
5
+ import { simpson } from './colors.js';
6
+ /**
7
+ * Shimmer frames for the spinner animation
8
+ * Creates a wave-like effect similar to Claude Code
9
+ */
10
+ const SHIMMER_FRAMES = [
11
+ '░▒▓█▓▒░',
12
+ '▒▓█▓▒░░',
13
+ '▓█▓▒░░▒',
14
+ '█▓▒░░▒▓',
15
+ '▓▒░░▒▓█',
16
+ '▒░░▒▓█▓',
17
+ '░░▒▓█▓▒',
18
+ '░▒▓█▓▒░',
19
+ ];
20
+ /**
21
+ * Braille spinner frames (alternative style)
22
+ */
23
+ const BRAILLE_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
24
+ /**
25
+ * Dots spinner frames
26
+ */
27
+ const DOTS_FRAMES = ['⠁', '⠂', '⠄', '⡀', '⢀', '⠠', '⠐', '⠈'];
28
+ /**
29
+ * Format milliseconds to human-readable time
30
+ */
31
+ function formatTime(ms) {
32
+ const seconds = Math.floor(ms / 1000);
33
+ const minutes = Math.floor(seconds / 60);
34
+ const remainingSeconds = seconds % 60;
35
+ if (minutes > 0) {
36
+ return `${minutes}m ${remainingSeconds}s`;
37
+ }
38
+ return `${seconds}s`;
39
+ }
40
+ /**
41
+ * Format token count with commas
42
+ */
43
+ function formatTokens(tokens) {
44
+ return tokens.toLocaleString();
45
+ }
46
+ /**
47
+ * Custom spinner with shimmer effect, timer, and token tracking
48
+ */
49
+ export class ShimmerSpinner {
50
+ message = '';
51
+ isRunning = false;
52
+ intervalId = null;
53
+ frameIndex = 0;
54
+ startTime = 0;
55
+ tokens = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
56
+ options;
57
+ frames;
58
+ constructor(options = {}) {
59
+ this.options = {
60
+ shimmer: options.shimmer ?? true,
61
+ showTimer: options.showTimer ?? true,
62
+ showTokens: options.showTokens ?? false,
63
+ style: options.style ?? 'shimmer',
64
+ };
65
+ // Select frames based on style
66
+ switch (this.options.style) {
67
+ case 'braille':
68
+ this.frames = BRAILLE_FRAMES;
69
+ break;
70
+ case 'dots':
71
+ this.frames = DOTS_FRAMES;
72
+ break;
73
+ case 'shimmer':
74
+ default:
75
+ this.frames = SHIMMER_FRAMES;
76
+ break;
77
+ }
78
+ }
79
+ /**
80
+ * Start the spinner with a message
81
+ */
82
+ start(message) {
83
+ this.message = message;
84
+ this.isRunning = true;
85
+ this.startTime = Date.now();
86
+ this.frameIndex = 0;
87
+ // Clear line and hide cursor
88
+ process.stdout.write('\x1B[?25l');
89
+ this.render();
90
+ this.intervalId = setInterval(() => {
91
+ this.frameIndex = (this.frameIndex + 1) % this.frames.length;
92
+ this.render();
93
+ }, 80);
94
+ }
95
+ /**
96
+ * Update the spinner message
97
+ */
98
+ update(message) {
99
+ this.message = message;
100
+ }
101
+ /**
102
+ * Update token usage (adds to existing)
103
+ */
104
+ updateTokens(usage) {
105
+ this.tokens = {
106
+ inputTokens: this.tokens.inputTokens + usage.inputTokens,
107
+ outputTokens: this.tokens.outputTokens + usage.outputTokens,
108
+ totalTokens: this.tokens.totalTokens + usage.totalTokens,
109
+ };
110
+ }
111
+ /**
112
+ * Set token usage directly
113
+ */
114
+ setTokens(usage) {
115
+ this.tokens = usage;
116
+ }
117
+ /**
118
+ * Render the spinner
119
+ */
120
+ render() {
121
+ if (!this.isRunning)
122
+ return;
123
+ const elapsed = Date.now() - this.startTime;
124
+ const frame = this.frames[this.frameIndex];
125
+ let line = '';
126
+ // Shimmer/spinner frame
127
+ if (this.options.shimmer && this.options.style === 'shimmer') {
128
+ line += simpson.yellow(frame) + ' ';
129
+ }
130
+ else {
131
+ line += simpson.yellow(frame) + ' ';
132
+ }
133
+ // Message
134
+ line += this.message;
135
+ // Timer
136
+ if (this.options.showTimer) {
137
+ line += simpson.brown(` [${formatTime(elapsed)}]`);
138
+ }
139
+ // Tokens
140
+ if (this.options.showTokens && this.tokens.totalTokens > 0) {
141
+ line += simpson.pink(` (${formatTokens(this.tokens.totalTokens)} tokens)`);
142
+ }
143
+ // Clear line and write
144
+ process.stdout.write('\r\x1B[K' + line);
145
+ }
146
+ /**
147
+ * Stop the spinner with a final message
148
+ */
149
+ stop(finalMessage) {
150
+ this.isRunning = false;
151
+ if (this.intervalId) {
152
+ clearInterval(this.intervalId);
153
+ this.intervalId = null;
154
+ }
155
+ const elapsed = Date.now() - this.startTime;
156
+ // Build final line
157
+ let line = '';
158
+ line += simpson.yellow('✓') + ' ';
159
+ line += finalMessage || this.message;
160
+ if (this.options.showTimer) {
161
+ line += simpson.brown(` [${formatTime(elapsed)}]`);
162
+ }
163
+ if (this.options.showTokens && this.tokens.totalTokens > 0) {
164
+ line += simpson.pink(` (${formatTokens(this.tokens.totalTokens)} tokens)`);
165
+ }
166
+ // Clear line, show cursor, print final
167
+ process.stdout.write('\r\x1B[K' + line + '\n');
168
+ process.stdout.write('\x1B[?25h');
169
+ }
170
+ /**
171
+ * Stop with error
172
+ */
173
+ fail(message) {
174
+ this.isRunning = false;
175
+ if (this.intervalId) {
176
+ clearInterval(this.intervalId);
177
+ this.intervalId = null;
178
+ }
179
+ const elapsed = Date.now() - this.startTime;
180
+ let line = '';
181
+ line += simpson.pink('✗') + ' ';
182
+ line += message || this.message;
183
+ if (this.options.showTimer) {
184
+ line += simpson.brown(` [${formatTime(elapsed)}]`);
185
+ }
186
+ process.stdout.write('\r\x1B[K' + line + '\n');
187
+ process.stdout.write('\x1B[?25h');
188
+ }
189
+ /**
190
+ * Get elapsed time in milliseconds
191
+ */
192
+ getElapsed() {
193
+ return Date.now() - this.startTime;
194
+ }
195
+ /**
196
+ * Get current token usage
197
+ */
198
+ getTokens() {
199
+ return { ...this.tokens };
200
+ }
201
+ }
202
+ /**
203
+ * Create a shimmer spinner instance
204
+ */
205
+ export function createShimmerSpinner(options) {
206
+ return new ShimmerSpinner(options);
207
+ }
208
+ //# sourceMappingURL=spinner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spinner.js","sourceRoot":"","sources":["../../src/utils/spinner.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wiggum-cli",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "AI-powered feature development loop CLI",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -8,7 +8,7 @@ import { existsSync, readFileSync } from 'node:fs';
8
8
  import { join } from 'node:path';
9
9
  import { stepCountIs, type LanguageModel } from 'ai';
10
10
  import type { ScanResult } from '../../scanner/types.js';
11
- import type { MultiAgentAnalysis, CodebaseAnalysis, StackResearch, RalphMcpServers } from './types.js';
11
+ import type { MultiAgentAnalysis, CodebaseAnalysis, StackResearch, RalphMcpServers, TokenUsage } from './types.js';
12
12
  import { createExplorationTools } from '../tools.js';
13
13
  import { isReasoningModel } from '../providers.js';
14
14
  import { logger } from '../../utils/logger.js';
@@ -193,8 +193,15 @@ After exploring, output your complete analysis as JSON.`;
193
193
  // Detect MCP servers (pure function)
194
194
  const mcpServers = detectRalphMcpServers(stack, analyzerOutput.projectType);
195
195
 
196
+ // Capture token usage from AI response
197
+ const tokenUsage = result.usage ? {
198
+ inputTokens: result.usage.inputTokens ?? 0,
199
+ outputTokens: result.usage.outputTokens ?? 0,
200
+ totalTokens: result.usage.totalTokens ?? 0,
201
+ } : undefined;
202
+
196
203
  // Build full MultiAgentAnalysis
197
- return buildMultiAgentAnalysis(analyzerOutput, mcpServers, input);
204
+ return buildMultiAgentAnalysis(analyzerOutput, mcpServers, input, tokenUsage);
198
205
  } catch (error) {
199
206
  if (verbose) {
200
207
  logger.error(`Codebase Analyzer error: ${error instanceof Error ? error.message : String(error)}`);
@@ -270,7 +277,8 @@ function parseAnalyzerOutput(
270
277
  function buildMultiAgentAnalysis(
271
278
  output: AnalyzerOutput,
272
279
  mcpServers: RalphMcpServers,
273
- input: CodebaseAnalyzerInput
280
+ input: CodebaseAnalyzerInput,
281
+ tokenUsage?: TokenUsage
274
282
  ): MultiAgentAnalysis {
275
283
  const derivedCommands = deriveCommandsFromScripts(input.scanResult.projectRoot);
276
284
 
@@ -316,6 +324,7 @@ function buildMultiAgentAnalysis(
316
324
  codebaseAnalysis,
317
325
  stackResearch,
318
326
  mcpServers: convertToLegacyMcpRecommendations(mcpServers),
327
+ tokenUsage,
319
328
  };
320
329
  }
321
330
 
@@ -33,22 +33,25 @@ describe('detectRalphMcpServers', () => {
33
33
  expect(result.e2eTesting).toBe('playwright');
34
34
  });
35
35
 
36
- it('returns mcp-inspector for MCP projects via stack.mcp.isProject', () => {
36
+ it('returns undefined for MCP projects (use npx @modelcontextprotocol/inspector)', () => {
37
37
  const stack = createStack({
38
38
  mcp: { isProject: true },
39
39
  });
40
40
  const result = detectRalphMcpServers(stack);
41
- expect(result.e2eTesting).toBe('mcp-inspector');
41
+ // MCP Inspector is an npx tool, not an MCP server
42
+ expect(result.e2eTesting).toBeUndefined();
42
43
  });
43
44
 
44
- it('returns mcp-inspector for MCP projects via projectType parameter', () => {
45
+ it('returns undefined for MCP projects via projectType parameter', () => {
45
46
  const result = detectRalphMcpServers(createStack(), 'MCP Server');
46
- expect(result.e2eTesting).toBe('mcp-inspector');
47
+ // MCP Inspector is an npx tool, not an MCP server
48
+ expect(result.e2eTesting).toBeUndefined();
47
49
  });
48
50
 
49
- it('returns mcp-inspector when projectType contains "mcp" (case-insensitive)', () => {
51
+ it('returns undefined when projectType contains "mcp" (case-insensitive)', () => {
50
52
  const result = detectRalphMcpServers(createStack(), 'mcp tool');
51
- expect(result.e2eTesting).toBe('mcp-inspector');
53
+ // MCP Inspector is an npx tool, not an MCP server
54
+ expect(result.e2eTesting).toBeUndefined();
52
55
  });
53
56
 
54
57
  it('returns playwright for Next.js projects', () => {
@@ -81,7 +84,8 @@ describe('detectRalphMcpServers', () => {
81
84
  framework: detection('Next.js'),
82
85
  });
83
86
  const result = detectRalphMcpServers(stack);
84
- expect(result.e2eTesting).toBe('mcp-inspector');
87
+ // MCP Inspector is an npx tool, not an MCP server - no E2E MCP for MCP projects
88
+ expect(result.e2eTesting).toBeUndefined();
85
89
  });
86
90
  });
87
91
 
@@ -313,6 +317,25 @@ describe('convertToLegacyMcpRecommendations', () => {
313
317
  expect(result.essential).toContain('playwright');
314
318
  });
315
319
 
320
+ it('returns empty essential when e2eTesting is undefined (MCP projects)', () => {
321
+ const result = convertToLegacyMcpRecommendations({
322
+ e2eTesting: undefined,
323
+ additional: [],
324
+ });
325
+ // MCP projects use npx @modelcontextprotocol/inspector, not an MCP server
326
+ expect(result.essential).toEqual([]);
327
+ });
328
+
329
+ it('only includes database in essential for MCP projects', () => {
330
+ const result = convertToLegacyMcpRecommendations({
331
+ e2eTesting: undefined,
332
+ database: 'supabase',
333
+ additional: [],
334
+ });
335
+ // MCP projects use npx inspector for testing, but still get database MCP
336
+ expect(result.essential).toEqual(['supabase']);
337
+ });
338
+
316
339
  it('includes database in essential when detected', () => {
317
340
  const result = convertToLegacyMcpRecommendations({
318
341
  e2eTesting: 'playwright',
@@ -66,13 +66,15 @@ const SERVICE_MCP_MAP: Record<string, string> = {
66
66
  * Detect ralph-essential MCP servers from the stack
67
67
  *
68
68
  * Ralph loop essentials:
69
- * - For MCP Server projects: mcp-inspector for testing
70
- * - For web apps with E2E: playwright for E2E testing
69
+ * - For web apps with E2E: playwright MCP server for E2E testing
71
70
  * - Database MCP: If database is detected
72
71
  * - Additional MCPs based on services and deployment
72
+ *
73
+ * Note: MCP Inspector is a debugging TOOL (npx @modelcontextprotocol/inspector),
74
+ * NOT an MCP server. It should be mentioned in implementation guidelines, not here.
73
75
  */
74
76
  export function detectRalphMcpServers(stack: DetectedStack, projectType?: string): RalphMcpServers {
75
- // Determine appropriate E2E testing tool based on project type
77
+ // Determine appropriate E2E testing MCP based on project type
76
78
  const isMcpProject = stack.mcp?.isProject || projectType?.toLowerCase().includes('mcp');
77
79
  const isWebApp = stack.framework?.name?.toLowerCase().includes('next') ||
78
80
  stack.framework?.name?.toLowerCase().includes('react') ||
@@ -81,12 +83,13 @@ export function detectRalphMcpServers(stack: DetectedStack, projectType?: string
81
83
  stack.framework?.name?.toLowerCase().includes('nuxt') ||
82
84
  stack.framework?.name?.toLowerCase().includes('remix');
83
85
 
84
- // Choose E2E testing tool based on project type
85
- let e2eTesting: string;
86
+ // Choose E2E testing MCP based on project type
87
+ // Note: MCP projects don't need an E2E testing MCP server - they use npx @modelcontextprotocol/inspector
88
+ let e2eTesting: string | undefined;
86
89
  if (isMcpProject) {
87
- e2eTesting = 'mcp-inspector'; // MCP projects use MCP Inspector
90
+ e2eTesting = undefined; // MCP projects use npx inspector (not an MCP server)
88
91
  } else if (isWebApp) {
89
- e2eTesting = 'playwright'; // Web apps use Playwright
92
+ e2eTesting = 'playwright'; // Web apps use Playwright MCP
90
93
  } else {
91
94
  e2eTesting = 'playwright'; // Default to Playwright for CLI/other projects
92
95
  }
@@ -82,8 +82,8 @@ export interface TechResearchResult {
82
82
  export interface RalphMcpServers {
83
83
  /** Database MCP server if applicable */
84
84
  database?: string;
85
- /** E2E testing MCP (always playwright for ralph) */
86
- e2eTesting: string;
85
+ /** E2E testing MCP (playwright for web apps, undefined for MCP projects) */
86
+ e2eTesting?: string;
87
87
  /** Any additional recommended MCPs */
88
88
  additional: string[];
89
89
  }
@@ -178,6 +178,15 @@ export interface McpRecommendations {
178
178
  /**
179
179
  * Combined result from all agents
180
180
  */
181
+ /**
182
+ * Token usage from AI calls
183
+ */
184
+ export interface TokenUsage {
185
+ inputTokens: number;
186
+ outputTokens: number;
187
+ totalTokens: number;
188
+ }
189
+
181
190
  export interface MultiAgentAnalysis {
182
191
  /** Codebase analysis from the Codebase Analyst */
183
192
  codebaseAnalysis: CodebaseAnalysis;
@@ -185,6 +194,8 @@ export interface MultiAgentAnalysis {
185
194
  stackResearch: StackResearch;
186
195
  /** MCP server recommendations (merged from both agents) */
187
196
  mcpServers: McpRecommendations;
197
+ /** Token usage from AI calls */
198
+ tokenUsage?: TokenUsage;
188
199
  }
189
200
 
190
201
  /**