claude-cli-advanced-starter-pack 1.0.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 (67) hide show
  1. package/LICENSE +21 -0
  2. package/OVERVIEW.md +597 -0
  3. package/README.md +439 -0
  4. package/bin/gtask.js +282 -0
  5. package/bin/postinstall.js +53 -0
  6. package/package.json +69 -0
  7. package/src/agents/phase-dev-templates.js +1011 -0
  8. package/src/agents/templates.js +668 -0
  9. package/src/analysis/checklist-parser.js +414 -0
  10. package/src/analysis/codebase.js +481 -0
  11. package/src/cli/menu.js +958 -0
  12. package/src/commands/claude-audit.js +1482 -0
  13. package/src/commands/claude-settings.js +2243 -0
  14. package/src/commands/create-agent.js +681 -0
  15. package/src/commands/create-command.js +337 -0
  16. package/src/commands/create-hook.js +262 -0
  17. package/src/commands/create-phase-dev/codebase-analyzer.js +813 -0
  18. package/src/commands/create-phase-dev/documentation-generator.js +352 -0
  19. package/src/commands/create-phase-dev/post-completion.js +404 -0
  20. package/src/commands/create-phase-dev/scale-calculator.js +344 -0
  21. package/src/commands/create-phase-dev/wizard.js +492 -0
  22. package/src/commands/create-phase-dev.js +481 -0
  23. package/src/commands/create-skill.js +313 -0
  24. package/src/commands/create.js +446 -0
  25. package/src/commands/decompose.js +392 -0
  26. package/src/commands/detect-tech-stack.js +768 -0
  27. package/src/commands/explore-mcp/claude-md-updater.js +252 -0
  28. package/src/commands/explore-mcp/mcp-installer.js +346 -0
  29. package/src/commands/explore-mcp/mcp-registry.js +438 -0
  30. package/src/commands/explore-mcp.js +638 -0
  31. package/src/commands/gtask-init.js +641 -0
  32. package/src/commands/help.js +128 -0
  33. package/src/commands/init.js +1890 -0
  34. package/src/commands/install.js +250 -0
  35. package/src/commands/list.js +116 -0
  36. package/src/commands/roadmap.js +750 -0
  37. package/src/commands/setup-wizard.js +482 -0
  38. package/src/commands/setup.js +351 -0
  39. package/src/commands/sync.js +534 -0
  40. package/src/commands/test-run.js +456 -0
  41. package/src/commands/test-setup.js +456 -0
  42. package/src/commands/validate.js +67 -0
  43. package/src/config/tech-stack.defaults.json +182 -0
  44. package/src/config/tech-stack.schema.json +502 -0
  45. package/src/github/client.js +359 -0
  46. package/src/index.js +84 -0
  47. package/src/templates/claude-command.js +244 -0
  48. package/src/templates/issue-body.js +284 -0
  49. package/src/testing/config.js +411 -0
  50. package/src/utils/template-engine.js +398 -0
  51. package/src/utils/validate-templates.js +223 -0
  52. package/src/utils.js +396 -0
  53. package/templates/commands/ccasp-setup.template.md +113 -0
  54. package/templates/commands/context-audit.template.md +97 -0
  55. package/templates/commands/create-task-list.template.md +382 -0
  56. package/templates/commands/deploy-full.template.md +261 -0
  57. package/templates/commands/github-task-start.template.md +99 -0
  58. package/templates/commands/github-update.template.md +69 -0
  59. package/templates/commands/happy-start.template.md +117 -0
  60. package/templates/commands/phase-track.template.md +142 -0
  61. package/templates/commands/tunnel-start.template.md +127 -0
  62. package/templates/commands/tunnel-stop.template.md +106 -0
  63. package/templates/hooks/context-guardian.template.js +173 -0
  64. package/templates/hooks/deployment-orchestrator.template.js +219 -0
  65. package/templates/hooks/github-progress-hook.template.js +197 -0
  66. package/templates/hooks/happy-checkpoint-manager.template.js +222 -0
  67. package/templates/hooks/phase-dev-enforcer.template.js +183 -0
@@ -0,0 +1,456 @@
1
+ /**
2
+ * Test Run Command
3
+ *
4
+ * Run tests with support for different modes:
5
+ * - Ralph Loop: Auto-retry until tests pass
6
+ * - Manual: Run once
7
+ * - Watch: Interactive test watching
8
+ */
9
+
10
+ import chalk from 'chalk';
11
+ import inquirer from 'inquirer';
12
+ import ora from 'ora';
13
+ import { spawn } from 'child_process';
14
+ import { existsSync, writeFileSync, readFileSync, unlinkSync } from 'fs';
15
+ import { join } from 'path';
16
+ import { showHeader, showSuccess, showError, showWarning, showInfo } from '../cli/menu.js';
17
+ import {
18
+ loadTestingConfig,
19
+ hasTestingConfig,
20
+ getCredentials,
21
+ validateConfig,
22
+ } from '../testing/config.js';
23
+ import { loadTaskState, updateTaskStatus } from './sync.js';
24
+
25
+ // Ralph loop state file
26
+ const RALPH_STATE_FILE = '.gtask/ralph-loop.json';
27
+
28
+ /**
29
+ * Run tests command
30
+ */
31
+ export async function runTest(options) {
32
+ // Load config
33
+ const config = loadTestingConfig();
34
+
35
+ if (!config) {
36
+ showError('Testing not configured', 'Run "gtask test-setup" first.');
37
+ return;
38
+ }
39
+
40
+ // Validate config
41
+ const validation = validateConfig(config);
42
+ if (!validation.valid) {
43
+ showError('Invalid testing configuration');
44
+ for (const err of validation.errors) {
45
+ console.log(chalk.red(` - ${err}`));
46
+ }
47
+ return;
48
+ }
49
+
50
+ // Determine mode
51
+ const mode = options.mode || config.mode || 'manual';
52
+
53
+ // Get credentials if needed
54
+ let credentials = null;
55
+ if (config.credentials.source !== 'none') {
56
+ credentials = getCredentials(config);
57
+
58
+ if (!credentials && config.credentials.source === 'prompt') {
59
+ credentials = await promptCredentials();
60
+ }
61
+
62
+ if (!credentials?.username || !credentials?.password) {
63
+ if (config.credentials.source === 'env') {
64
+ showWarning('Credentials not found in environment variables.');
65
+ console.log(chalk.dim(`Set ${config.credentials.envVars.username} and ${config.credentials.envVars.password}`));
66
+
67
+ const { continueWithout } = await inquirer.prompt([
68
+ {
69
+ type: 'confirm',
70
+ name: 'continueWithout',
71
+ message: 'Continue without credentials?',
72
+ default: false,
73
+ },
74
+ ]);
75
+
76
+ if (!continueWithout) return;
77
+ }
78
+ }
79
+ }
80
+
81
+ // Run based on mode
82
+ switch (mode) {
83
+ case 'ralph':
84
+ await runRalphLoop(config, credentials, options);
85
+ break;
86
+ case 'watch':
87
+ await runWatchMode(config, credentials, options);
88
+ break;
89
+ case 'manual':
90
+ default:
91
+ await runOnce(config, credentials, options);
92
+ }
93
+ }
94
+
95
+ /**
96
+ * Run tests once
97
+ */
98
+ async function runOnce(config, credentials, options) {
99
+ showHeader('Running Tests');
100
+
101
+ console.log(chalk.dim(`Environment: ${config.environment.baseUrl}`));
102
+ console.log(chalk.dim(`Browser: ${config.playwright.browser}`));
103
+ console.log('');
104
+
105
+ // Build environment variables
106
+ const env = buildTestEnv(config, credentials);
107
+
108
+ // Determine test command
109
+ const testCommand = options.command || 'npx playwright test';
110
+ const testArgs = [];
111
+
112
+ if (options.file) {
113
+ testArgs.push(options.file);
114
+ }
115
+
116
+ if (!config.playwright.headless || options.headed) {
117
+ testArgs.push('--headed');
118
+ }
119
+
120
+ if (options.ui) {
121
+ testArgs.push('--ui');
122
+ }
123
+
124
+ console.log(chalk.dim(`Running: ${testCommand} ${testArgs.join(' ')}`));
125
+ console.log('');
126
+
127
+ const result = await executeTests(testCommand, testArgs, env);
128
+
129
+ if (result.success) {
130
+ showSuccess('All Tests Passed!', [
131
+ `Duration: ${result.duration}s`,
132
+ `Tests: ${result.passed} passed`,
133
+ ]);
134
+ } else {
135
+ showError('Tests Failed', `${result.failed} test(s) failed`);
136
+ if (result.output) {
137
+ console.log(chalk.dim('\nOutput:'));
138
+ console.log(result.output.slice(-2000));
139
+ }
140
+ }
141
+
142
+ return result;
143
+ }
144
+
145
+ /**
146
+ * Run Ralph Loop - continuous test-fix cycle
147
+ */
148
+ async function runRalphLoop(config, credentials, options) {
149
+ showHeader('Ralph Loop - Test-Fix Cycle');
150
+
151
+ const maxIterations = options.max || config.ralphConfig?.maxIterations || 10;
152
+ const completionPromise = config.ralphConfig?.completionPromise || 'all tasks complete';
153
+
154
+ console.log(chalk.cyan(`Max iterations: ${maxIterations}`));
155
+ console.log(chalk.cyan(`Completion phrase: "${completionPromise}"`));
156
+ console.log('');
157
+
158
+ // Initialize state
159
+ const state = {
160
+ iteration: 0,
161
+ maxIterations,
162
+ completionPromise,
163
+ startedAt: new Date().toISOString(),
164
+ history: [],
165
+ };
166
+
167
+ saveRalphState(state);
168
+
169
+ // Build environment
170
+ const env = buildTestEnv(config, credentials);
171
+
172
+ let iteration = 0;
173
+ let allPassed = false;
174
+
175
+ while (iteration < maxIterations && !allPassed) {
176
+ iteration++;
177
+ state.iteration = iteration;
178
+
179
+ console.log(chalk.cyan.bold(`\n═══ Iteration ${iteration}/${maxIterations} ═══\n`));
180
+
181
+ // Run tests
182
+ const result = await executeTests('npx playwright test', [], env);
183
+
184
+ state.history.push({
185
+ iteration,
186
+ timestamp: new Date().toISOString(),
187
+ passed: result.success,
188
+ passedCount: result.passed,
189
+ failedCount: result.failed,
190
+ duration: result.duration,
191
+ });
192
+
193
+ saveRalphState(state);
194
+
195
+ if (result.success) {
196
+ allPassed = true;
197
+ console.log(chalk.green.bold('\n✓ All tests passed!\n'));
198
+ } else {
199
+ console.log(chalk.yellow(`\n✗ ${result.failed} test(s) failed\n`));
200
+
201
+ if (iteration < maxIterations) {
202
+ // Show failures
203
+ if (result.failedTests?.length > 0) {
204
+ console.log(chalk.dim('Failed tests:'));
205
+ for (const test of result.failedTests.slice(0, 5)) {
206
+ console.log(chalk.dim(` - ${test}`));
207
+ }
208
+ }
209
+
210
+ // Prompt for fix or continue
211
+ const { action } = await inquirer.prompt([
212
+ {
213
+ type: 'list',
214
+ name: 'action',
215
+ message: 'What would you like to do?',
216
+ choices: [
217
+ { name: 'Continue - I\'ve made fixes, retry tests', value: 'continue' },
218
+ { name: 'Show errors - View detailed error output', value: 'show' },
219
+ { name: 'Stop - Exit Ralph loop', value: 'stop' },
220
+ ],
221
+ },
222
+ ]);
223
+
224
+ if (action === 'stop') {
225
+ console.log(chalk.yellow('Ralph loop stopped by user.'));
226
+ break;
227
+ } else if (action === 'show') {
228
+ console.log('\n' + chalk.dim('─'.repeat(60)));
229
+ console.log(result.output?.slice(-3000) || 'No output captured');
230
+ console.log(chalk.dim('─'.repeat(60)) + '\n');
231
+
232
+ const { continueAfterShow } = await inquirer.prompt([
233
+ {
234
+ type: 'confirm',
235
+ name: 'continueAfterShow',
236
+ message: 'Continue with next iteration?',
237
+ default: true,
238
+ },
239
+ ]);
240
+
241
+ if (!continueAfterShow) {
242
+ console.log(chalk.yellow('Ralph loop stopped.'));
243
+ break;
244
+ }
245
+ }
246
+
247
+ console.log(chalk.dim('\nWaiting for fixes... Press Enter when ready.\n'));
248
+ await inquirer.prompt([
249
+ {
250
+ type: 'input',
251
+ name: 'ready',
252
+ message: 'Press Enter to continue...',
253
+ },
254
+ ]);
255
+ }
256
+ }
257
+ }
258
+
259
+ // Clean up
260
+ cleanupRalphState();
261
+
262
+ // Summary
263
+ const totalDuration = state.history.reduce((sum, h) => sum + (h.duration || 0), 0);
264
+
265
+ if (allPassed) {
266
+ showSuccess('Ralph Loop Complete!', [
267
+ `Iterations: ${iteration}`,
268
+ `Total duration: ${totalDuration}s`,
269
+ `Final result: All tests passing`,
270
+ ]);
271
+ } else {
272
+ showError('Ralph Loop Stopped', [
273
+ `Iterations: ${iteration}/${maxIterations}`,
274
+ `Total duration: ${totalDuration}s`,
275
+ `Final result: Tests still failing`,
276
+ ]);
277
+ }
278
+
279
+ return { success: allPassed, iterations: iteration, state };
280
+ }
281
+
282
+ /**
283
+ * Run watch mode - interactive test watching
284
+ */
285
+ async function runWatchMode(config, credentials, options) {
286
+ showHeader('Test Watch Mode');
287
+
288
+ console.log(chalk.dim('Tests will re-run on file changes.'));
289
+ console.log(chalk.dim('Press q to quit, r to re-run manually.'));
290
+ console.log('');
291
+
292
+ const env = buildTestEnv(config, credentials);
293
+
294
+ // Use Playwright's built-in watch mode if available
295
+ const args = ['--ui'];
296
+
297
+ console.log(chalk.dim('Starting Playwright UI mode...'));
298
+ console.log(chalk.dim('This opens an interactive test runner.'));
299
+ console.log('');
300
+
301
+ await executeTests('npx playwright test', args, env, { interactive: true });
302
+ }
303
+
304
+ /**
305
+ * Execute tests and capture results
306
+ */
307
+ function executeTests(command, args, env, options = {}) {
308
+ return new Promise((resolve) => {
309
+ const startTime = Date.now();
310
+ let output = '';
311
+ let passed = 0;
312
+ let failed = 0;
313
+ const failedTests = [];
314
+
315
+ const [cmd, ...cmdArgs] = command.split(' ');
316
+ const allArgs = [...cmdArgs, ...args];
317
+
318
+ const proc = spawn(cmd, allArgs, {
319
+ env: { ...process.env, ...env },
320
+ shell: true,
321
+ stdio: options.interactive ? 'inherit' : 'pipe',
322
+ });
323
+
324
+ if (!options.interactive) {
325
+ proc.stdout?.on('data', (data) => {
326
+ const text = data.toString();
327
+ output += text;
328
+ process.stdout.write(text);
329
+
330
+ // Parse test results from output
331
+ const passMatch = text.match(/(\d+) passed/);
332
+ const failMatch = text.match(/(\d+) failed/);
333
+
334
+ if (passMatch) passed = parseInt(passMatch[1], 10);
335
+ if (failMatch) failed = parseInt(failMatch[1], 10);
336
+
337
+ // Capture failed test names
338
+ const failedMatch = text.match(/✘\s+(.+)/g);
339
+ if (failedMatch) {
340
+ failedTests.push(...failedMatch.map((m) => m.replace('✘ ', '')));
341
+ }
342
+ });
343
+
344
+ proc.stderr?.on('data', (data) => {
345
+ const text = data.toString();
346
+ output += text;
347
+ process.stderr.write(text);
348
+ });
349
+ }
350
+
351
+ proc.on('close', (code) => {
352
+ const duration = Math.round((Date.now() - startTime) / 1000);
353
+
354
+ resolve({
355
+ success: code === 0,
356
+ exitCode: code,
357
+ passed,
358
+ failed,
359
+ failedTests,
360
+ duration,
361
+ output,
362
+ });
363
+ });
364
+
365
+ proc.on('error', (err) => {
366
+ resolve({
367
+ success: false,
368
+ error: err.message,
369
+ output,
370
+ duration: Math.round((Date.now() - startTime) / 1000),
371
+ });
372
+ });
373
+ });
374
+ }
375
+
376
+ /**
377
+ * Build environment variables for tests
378
+ */
379
+ function buildTestEnv(config, credentials) {
380
+ const env = {
381
+ BASE_URL: config.environment.baseUrl,
382
+ PLAYWRIGHT_BASE_URL: config.environment.baseUrl,
383
+ };
384
+
385
+ if (credentials) {
386
+ env.TEST_USER_USERNAME = credentials.username;
387
+ env.TEST_USER_PASSWORD = credentials.password;
388
+ }
389
+
390
+ if (config.playwright) {
391
+ if (!config.playwright.headless) {
392
+ env.HEADED = 'true';
393
+ }
394
+ }
395
+
396
+ return env;
397
+ }
398
+
399
+ /**
400
+ * Prompt for credentials
401
+ */
402
+ async function promptCredentials() {
403
+ const { username, password } = await inquirer.prompt([
404
+ {
405
+ type: 'input',
406
+ name: 'username',
407
+ message: 'Test username:',
408
+ },
409
+ {
410
+ type: 'password',
411
+ name: 'password',
412
+ message: 'Test password:',
413
+ mask: '*',
414
+ },
415
+ ]);
416
+
417
+ return { username, password };
418
+ }
419
+
420
+ /**
421
+ * Save Ralph loop state
422
+ */
423
+ function saveRalphState(state) {
424
+ try {
425
+ writeFileSync(RALPH_STATE_FILE, JSON.stringify(state, null, 2), 'utf8');
426
+ } catch {
427
+ // Ignore errors
428
+ }
429
+ }
430
+
431
+ /**
432
+ * Load Ralph loop state
433
+ */
434
+ function loadRalphState() {
435
+ try {
436
+ if (existsSync(RALPH_STATE_FILE)) {
437
+ return JSON.parse(readFileSync(RALPH_STATE_FILE, 'utf8'));
438
+ }
439
+ } catch {
440
+ // Ignore errors
441
+ }
442
+ return null;
443
+ }
444
+
445
+ /**
446
+ * Clean up Ralph loop state
447
+ */
448
+ function cleanupRalphState() {
449
+ try {
450
+ if (existsSync(RALPH_STATE_FILE)) {
451
+ unlinkSync(RALPH_STATE_FILE);
452
+ }
453
+ } catch {
454
+ // Ignore errors
455
+ }
456
+ }