claude-cli-advanced-starter-pack 1.0.11 → 1.0.13

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.
@@ -1,16 +1,65 @@
1
1
  /**
2
2
  * Testing Configuration Module
3
3
  *
4
- * Manages testing modes, credentials, and environment configuration
4
+ * Manages testing modes, credentials, and environment configuration.
5
+ * Testing config is stored in tech-stack.json under the `testing` section
6
+ * for unified configuration management.
5
7
  */
6
8
 
7
9
  import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
8
- import { join } from 'path';
9
-
10
- // Default paths
11
- const CONFIG_DIR = join(process.cwd(), '.gtask');
10
+ import { join, dirname } from 'path';
11
+
12
+ // Default paths - now uses tech-stack.json
13
+ const TECH_STACK_PATHS = [
14
+ join(process.cwd(), '.claude', 'tech-stack.json'),
15
+ join(process.cwd(), 'tech-stack.json'),
16
+ ];
17
+ const RULES_DIR = join(process.cwd(), '.claude', 'task-lists');
12
18
  const TESTING_RULES_FILE = 'TESTING_RULES.md';
13
19
 
20
+ /**
21
+ * Get path to tech-stack.json (prefers .claude/tech-stack.json)
22
+ */
23
+ function getTechStackPath() {
24
+ for (const path of TECH_STACK_PATHS) {
25
+ if (existsSync(path)) {
26
+ return path;
27
+ }
28
+ }
29
+ return TECH_STACK_PATHS[0];
30
+ }
31
+
32
+ /**
33
+ * Load tech-stack.json
34
+ */
35
+ function loadTechStackJson() {
36
+ const techStackPath = getTechStackPath();
37
+ if (existsSync(techStackPath)) {
38
+ try {
39
+ return JSON.parse(readFileSync(techStackPath, 'utf8'));
40
+ } catch {
41
+ return null;
42
+ }
43
+ }
44
+ return null;
45
+ }
46
+
47
+ /**
48
+ * Save tech-stack.json
49
+ */
50
+ function saveTechStackJson(techStack) {
51
+ const techStackPath = getTechStackPath();
52
+ const configDir = dirname(techStackPath);
53
+
54
+ if (!existsSync(configDir)) {
55
+ mkdirSync(configDir, { recursive: true });
56
+ }
57
+
58
+ techStack._lastModified = new Date().toISOString();
59
+ writeFileSync(techStackPath, JSON.stringify(techStack, null, 2), 'utf8');
60
+ return techStackPath;
61
+ }
62
+
14
63
  /**
15
64
  * Testing mode definitions
16
65
  */
@@ -99,107 +148,155 @@ export const CREDENTIAL_SOURCES = {
99
148
  };
100
149
 
101
150
  /**
102
- * Testing configuration structure
151
+ * Testing configuration structure (compatible with tech-stack.json `testing` section)
152
+ *
153
+ * This structure maps to tech-stack.json testing fields:
154
+ * - testing.e2e.framework -> e2e framework
155
+ * - testing.e2e.configFile -> playwright config
156
+ * - testing.selectors.* -> login selectors
157
+ * - testing.credentials.* -> env var names
103
158
  */
104
159
  export function createTestingConfig(options = {}) {
105
160
  return {
106
- version: '1.0.0',
107
- createdAt: new Date().toISOString(),
108
- updatedAt: new Date().toISOString(),
161
+ // E2E testing configuration
162
+ e2e: {
163
+ framework: options.playwrightEnabled ? 'playwright' : 'none',
164
+ configFile: options.playwrightConfig || 'playwright.config.ts',
165
+ testCommand: 'npx playwright test',
166
+ browser: options.browser || 'chromium',
167
+ headless: options.headless ?? true,
168
+ timeout: options.timeout || 30000,
169
+ },
109
170
 
110
- // Testing mode
111
- mode: options.mode || 'manual',
112
- ralphConfig: options.mode === 'ralph' ? {
113
- maxIterations: options.maxIterations || 10,
114
- completionPromise: options.completionPromise || 'all tasks complete and tests passing',
115
- autoRetry: true,
116
- } : null,
171
+ // Unit testing (preserved from existing config)
172
+ unit: {
173
+ framework: 'none',
174
+ testCommand: 'npm test',
175
+ },
117
176
 
118
- // Environment
119
- environment: {
120
- type: options.envType || 'localhost',
121
- baseUrl: options.baseUrl || 'http://localhost:5173',
122
- port: options.port || 5173,
123
- requiresSetup: options.requiresSetup || [],
177
+ // Test selectors for login flow
178
+ selectors: {
179
+ strategy: 'data-testid',
180
+ username: options.usernameSelector || '[data-testid="username-input"]',
181
+ password: options.passwordSelector || '[data-testid="password-input"]',
182
+ loginButton: options.loginButtonSelector || '[data-testid="login-submit"]',
183
+ loginSuccess: options.loginSuccessSelector || '[data-testid="dashboard"]',
124
184
  },
125
185
 
126
- // Credentials
186
+ // Credentials (env var names, never actual credentials)
127
187
  credentials: {
188
+ usernameEnvVar: options.envVars?.username || 'TEST_USER_USERNAME',
189
+ passwordEnvVar: options.envVars?.password || 'TEST_USER_PASSWORD',
128
190
  source: options.credentialSource || 'env',
129
- envVars: options.envVars || {
130
- username: 'TEST_USER_USERNAME',
131
- password: 'TEST_USER_PASSWORD',
132
- },
133
- // Only stored if source is 'config'
134
- username: options.credentialSource === 'config' ? options.username : undefined,
135
- password: options.credentialSource === 'config' ? options.password : undefined,
136
191
  },
137
192
 
138
- // Playwright configuration
139
- playwright: {
140
- enabled: options.playwrightEnabled ?? true,
141
- configPath: options.playwrightConfig || 'playwright.config.ts',
142
- browser: options.browser || 'chromium',
143
- headless: options.headless ?? true,
144
- timeout: options.timeout || 30000,
193
+ // Environment configuration
194
+ environment: {
195
+ type: options.envType || 'localhost',
196
+ baseUrl: options.baseUrl || 'http://localhost:5173',
197
+ port: options.port || 5173,
198
+ requiresSetup: options.requiresSetup || [],
145
199
  },
146
200
 
147
- // Test selectors (for login flow)
148
- selectors: {
149
- usernameInput: options.usernameSelector || '[data-testid="username-input"]',
150
- passwordInput: options.passwordSelector || '[data-testid="password-input"]',
151
- loginButton: options.loginButtonSelector || '[data-testid="login-submit"]',
152
- loginSuccessIndicator: options.loginSuccessSelector || '[data-testid="dashboard"]',
153
- },
201
+ // Testing mode (ralph loop, manual, minimal)
202
+ mode: options.mode || 'manual',
203
+ ralphConfig: options.mode === 'ralph' ? {
204
+ maxIterations: options.maxIterations || 10,
205
+ completionPromise: options.completionPromise || 'all tasks complete and tests passing',
206
+ autoRetry: true,
207
+ } : null,
154
208
 
155
209
  // Persistent rules file path
156
210
  rulesFile: options.rulesFile || null,
211
+
212
+ // Configuration metadata
213
+ _configuredAt: new Date().toISOString(),
214
+ _configuredBy: 'ccasp-test-setup',
157
215
  };
158
216
  }
159
217
 
160
218
  /**
161
- * Save testing configuration
219
+ * Save testing configuration to tech-stack.json
162
220
  */
163
221
  export function saveTestingConfig(config) {
164
- if (!existsSync(CONFIG_DIR)) {
165
- mkdirSync(CONFIG_DIR, { recursive: true });
166
- }
167
-
168
- const configPath = join(CONFIG_DIR, 'testing.json');
169
- config.updatedAt = new Date().toISOString();
222
+ // Load existing tech-stack or create default
223
+ let techStack = loadTechStackJson() || {
224
+ version: '2.0.0',
225
+ project: { name: 'unnamed', description: '' },
226
+ frontend: {},
227
+ backend: {},
228
+ testing: {},
229
+ };
170
230
 
171
- writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf8');
231
+ // Merge testing config into tech-stack
232
+ techStack.testing = {
233
+ ...techStack.testing,
234
+ ...config,
235
+ };
172
236
 
173
- // Add to .gitignore if credentials are stored
174
- if (config.credentials.source === 'config') {
175
- ensureGitignore('.gtask/testing.json');
237
+ const configPath = saveTechStackJson(techStack);
238
+
239
+ // Also save to legacy location for backwards compatibility
240
+ // (will be removed in future version)
241
+ const legacyDir = join(process.cwd(), '.gtask');
242
+ if (existsSync(legacyDir)) {
243
+ try {
244
+ writeFileSync(
245
+ join(legacyDir, 'testing.json'),
246
+ JSON.stringify(config, null, 2),
247
+ 'utf8'
248
+ );
249
+ } catch {
250
+ // Ignore legacy save errors
251
+ }
176
252
  }
177
253
 
178
254
  return configPath;
179
255
  }
180
256
 
181
257
  /**
182
- * Load testing configuration
258
+ * Load testing configuration from tech-stack.json
183
259
  */
184
260
  export function loadTestingConfig() {
185
- const configPath = join(CONFIG_DIR, 'testing.json');
261
+ const techStack = loadTechStackJson();
186
262
 
187
- if (!existsSync(configPath)) {
188
- return null;
263
+ if (techStack?.testing && Object.keys(techStack.testing).length > 0) {
264
+ return techStack.testing;
189
265
  }
190
266
 
191
- try {
192
- return JSON.parse(readFileSync(configPath, 'utf8'));
193
- } catch {
194
- return null;
267
+ // Fallback to legacy .gtask/testing.json for backwards compatibility
268
+ const legacyPath = join(process.cwd(), '.gtask', 'testing.json');
269
+ if (existsSync(legacyPath)) {
270
+ try {
271
+ return JSON.parse(readFileSync(legacyPath, 'utf8'));
272
+ } catch {
273
+ return null;
274
+ }
195
275
  }
276
+
277
+ return null;
196
278
  }
197
279
 
198
280
  /**
199
- * Check if testing is configured
281
+ * Check if testing is configured (checks tech-stack.json and legacy location)
200
282
  */
201
283
  export function hasTestingConfig() {
202
- return existsSync(join(CONFIG_DIR, 'testing.json'));
284
+ const techStack = loadTechStackJson();
285
+
286
+ // Check if tech-stack.json has meaningful testing config
287
+ if (techStack?.testing) {
288
+ const testing = techStack.testing;
289
+ // Consider configured if has e2e framework or selectors
290
+ if (testing.e2e?.framework && testing.e2e.framework !== 'none') {
291
+ return true;
292
+ }
293
+ if (testing.selectors?.username) {
294
+ return true;
295
+ }
296
+ }
297
+
298
+ // Fallback to legacy location
299
+ return existsSync(join(process.cwd(), '.gtask', 'testing.json'));
203
300
  }
204
301
 
205
302
  /**
@@ -320,14 +417,14 @@ npx playwright test --ui
320
417
  }
321
418
 
322
419
  /**
323
- * Save testing rules markdown file
420
+ * Save testing rules markdown file to .claude/task-lists/
324
421
  */
325
422
  export function saveTestingRules(config, filename = TESTING_RULES_FILE) {
326
- if (!existsSync(CONFIG_DIR)) {
327
- mkdirSync(CONFIG_DIR, { recursive: true });
423
+ if (!existsSync(RULES_DIR)) {
424
+ mkdirSync(RULES_DIR, { recursive: true });
328
425
  }
329
426
 
330
- const rulesPath = join(CONFIG_DIR, filename);
427
+ const rulesPath = join(RULES_DIR, filename);
331
428
  const content = generateTestingRules(config);
332
429
 
333
430
  writeFileSync(rulesPath, content, 'utf8');
@@ -356,24 +453,19 @@ function ensureGitignore(pattern) {
356
453
  }
357
454
 
358
455
  /**
359
- * Get credentials based on config
456
+ * Get credentials based on config (uses new tech-stack.json structure)
360
457
  */
361
458
  export function getCredentials(config) {
362
- if (!config || config.credentials.source === 'none') {
459
+ if (!config || config.credentials?.source === 'none') {
363
460
  return null;
364
461
  }
365
462
 
366
- if (config.credentials.source === 'env') {
367
- return {
368
- username: process.env[config.credentials.envVars.username] || null,
369
- password: process.env[config.credentials.envVars.password] || null,
370
- };
371
- }
372
-
373
- if (config.credentials.source === 'config') {
463
+ if (config.credentials?.source === 'env') {
464
+ const usernameVar = config.credentials.usernameEnvVar || config.credentials.envVars?.username;
465
+ const passwordVar = config.credentials.passwordEnvVar || config.credentials.envVars?.password;
374
466
  return {
375
- username: config.credentials.username,
376
- password: config.credentials.password,
467
+ username: process.env[usernameVar] || null,
468
+ password: process.env[passwordVar] || null,
377
469
  };
378
470
  }
379
471
 
@@ -382,10 +474,11 @@ export function getCredentials(config) {
382
474
  }
383
475
 
384
476
  /**
385
- * Validate testing configuration
477
+ * Validate testing configuration (works with tech-stack.json structure)
386
478
  */
387
479
  export function validateConfig(config) {
388
480
  const errors = [];
481
+ const warnings = [];
389
482
 
390
483
  if (!config.environment?.baseUrl) {
391
484
  errors.push('Base URL is required');
@@ -393,9 +486,12 @@ export function validateConfig(config) {
393
486
 
394
487
  if (config.credentials?.source === 'env') {
395
488
  const creds = getCredentials(config);
489
+ const usernameVar = config.credentials.usernameEnvVar || config.credentials.envVars?.username;
490
+ const passwordVar = config.credentials.passwordEnvVar || config.credentials.envVars?.password;
491
+
396
492
  if (!creds?.username || !creds?.password) {
397
- errors.push(
398
- `Environment variables not set: ${config.credentials.envVars.username}, ${config.credentials.envVars.password}`
493
+ warnings.push(
494
+ `Environment variables not set: ${usernameVar}, ${passwordVar}`
399
495
  );
400
496
  }
401
497
  }
@@ -404,8 +500,41 @@ export function validateConfig(config) {
404
500
  errors.push('Ralph configuration missing');
405
501
  }
406
502
 
503
+ if (config.e2e?.framework === 'none') {
504
+ warnings.push('No E2E testing framework configured');
505
+ }
506
+
407
507
  return {
408
508
  valid: errors.length === 0,
409
509
  errors,
510
+ warnings,
511
+ };
512
+ }
513
+
514
+ /**
515
+ * Get a summary of what testing features are configured
516
+ */
517
+ export function getTestingConfigSummary() {
518
+ const config = loadTestingConfig();
519
+
520
+ if (!config) {
521
+ return {
522
+ configured: false,
523
+ e2eFramework: null,
524
+ hasSelectors: false,
525
+ hasCredentials: false,
526
+ environment: null,
527
+ mode: null,
528
+ };
529
+ }
530
+
531
+ return {
532
+ configured: true,
533
+ e2eFramework: config.e2e?.framework || config.playwright?.enabled ? 'playwright' : null,
534
+ hasSelectors: !!(config.selectors?.username || config.selectors?.usernameInput),
535
+ hasCredentials: !!(config.credentials?.usernameEnvVar || config.credentials?.envVars?.username),
536
+ environment: config.environment?.type || 'localhost',
537
+ baseUrl: config.environment?.baseUrl,
538
+ mode: config.mode || 'manual',
410
539
  };
411
540
  }