@itz4blitz/agentful 1.2.0 → 1.3.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 (59) hide show
  1. package/README.md +28 -1
  2. package/bin/cli.js +11 -1055
  3. package/bin/hooks/block-file-creation.js +271 -0
  4. package/bin/hooks/product-spec-watcher.js +151 -0
  5. package/lib/index.js +0 -11
  6. package/lib/init.js +2 -21
  7. package/lib/parallel-execution.js +235 -0
  8. package/lib/presets.js +26 -4
  9. package/package.json +4 -7
  10. package/template/.claude/agents/architect.md +2 -2
  11. package/template/.claude/agents/backend.md +17 -30
  12. package/template/.claude/agents/frontend.md +17 -39
  13. package/template/.claude/agents/orchestrator.md +63 -4
  14. package/template/.claude/agents/product-analyzer.md +1 -1
  15. package/template/.claude/agents/tester.md +16 -29
  16. package/template/.claude/commands/agentful-generate.md +221 -14
  17. package/template/.claude/commands/agentful-init.md +621 -0
  18. package/template/.claude/commands/agentful-product.md +1 -1
  19. package/template/.claude/commands/agentful-start.md +99 -1
  20. package/template/.claude/product/EXAMPLES.md +2 -2
  21. package/template/.claude/product/index.md +1 -1
  22. package/template/.claude/settings.json +22 -0
  23. package/template/.claude/skills/research/SKILL.md +432 -0
  24. package/template/CLAUDE.md +5 -6
  25. package/template/bin/hooks/architect-drift-detector.js +242 -0
  26. package/template/bin/hooks/product-spec-watcher.js +151 -0
  27. package/version.json +1 -1
  28. package/bin/hooks/post-agent.js +0 -101
  29. package/bin/hooks/post-feature.js +0 -227
  30. package/bin/hooks/pre-agent.js +0 -118
  31. package/bin/hooks/pre-feature.js +0 -138
  32. package/lib/VALIDATION_README.md +0 -455
  33. package/lib/ci/claude-action-integration.js +0 -641
  34. package/lib/ci/index.js +0 -10
  35. package/lib/core/analyzer.js +0 -497
  36. package/lib/core/cli.js +0 -141
  37. package/lib/core/detectors/conventions.js +0 -342
  38. package/lib/core/detectors/framework.js +0 -276
  39. package/lib/core/detectors/index.js +0 -15
  40. package/lib/core/detectors/language.js +0 -199
  41. package/lib/core/detectors/patterns.js +0 -356
  42. package/lib/core/generator.js +0 -626
  43. package/lib/core/index.js +0 -9
  44. package/lib/core/output-parser.js +0 -458
  45. package/lib/core/storage.js +0 -515
  46. package/lib/core/templates.js +0 -556
  47. package/lib/pipeline/cli.js +0 -423
  48. package/lib/pipeline/engine.js +0 -928
  49. package/lib/pipeline/executor.js +0 -440
  50. package/lib/pipeline/index.js +0 -33
  51. package/lib/pipeline/integrations.js +0 -559
  52. package/lib/pipeline/schemas.js +0 -288
  53. package/lib/remote/client.js +0 -361
  54. package/lib/server/auth.js +0 -270
  55. package/lib/server/client-example.js +0 -190
  56. package/lib/server/executor.js +0 -477
  57. package/lib/server/index.js +0 -494
  58. package/lib/update-helpers.js +0 -505
  59. package/lib/validation.js +0 -460
@@ -1,497 +0,0 @@
1
- import fs from 'fs/promises';
2
- import path from 'path';
3
- import { EventEmitter } from 'events';
4
- import {
5
- detectLanguages,
6
- getPrimaryLanguage
7
- } from './detectors/language.js';
8
- import { detectFrameworks } from './detectors/framework.js';
9
- import { detectPatterns } from './detectors/patterns.js';
10
- import { detectConventions } from './detectors/conventions.js';
11
-
12
- /**
13
- * Codebase Analyzer
14
- *
15
- * Analyzes project codebase to detect:
16
- * - Programming languages
17
- * - Frameworks and libraries
18
- * - Architecture patterns
19
- * - Code conventions
20
- * - Project structure
21
- *
22
- * Outputs structured analysis to .agentful/architecture.json
23
- */
24
-
25
- /**
26
- * Default ignore patterns for file scanning
27
- */
28
- const DEFAULT_IGNORE_PATTERNS = [
29
- 'node_modules',
30
- '.git',
31
- '.agentful',
32
- 'dist',
33
- 'build',
34
- 'coverage',
35
- '.next',
36
- '.nuxt',
37
- '.vscode',
38
- '.idea',
39
- '*.log',
40
- '*.lock',
41
- 'package-lock.json',
42
- 'yarn.lock',
43
- 'pnpm-lock.yaml'
44
- ];
45
-
46
- /**
47
- * Codebase Analyzer Class
48
- */
49
- export class CodebaseAnalyzer extends EventEmitter {
50
- constructor(options = {}) {
51
- super();
52
-
53
- this.options = {
54
- projectRoot: options.projectRoot || process.cwd(),
55
- outputPath: options.outputPath || '.agentful/architecture.json',
56
- ignorePatterns: options.ignorePatterns || DEFAULT_IGNORE_PATTERNS,
57
- maxFiles: options.maxFiles || 5000,
58
- timeout: options.timeout || 30000,
59
- ...options
60
- };
61
-
62
- this.startTime = null;
63
- this.analysis = null;
64
- }
65
-
66
- /**
67
- * Run full codebase analysis
68
- *
69
- * @returns {Promise<Object>} Analysis results
70
- */
71
- async analyze() {
72
- this.startTime = Date.now();
73
- this.emit('start', { projectRoot: this.options.projectRoot });
74
-
75
- try {
76
- // Step 1: Scan project files
77
- this.emit('progress', { stage: 'scanning', progress: 0 });
78
- const files = await this.scanFiles();
79
- this.emit('progress', { stage: 'scanning', progress: 100, fileCount: files.length });
80
-
81
- // Step 2: Detect languages
82
- this.emit('progress', { stage: 'languages', progress: 0 });
83
- const languages = await detectLanguages(files, this.options.projectRoot);
84
- this.emit('progress', { stage: 'languages', progress: 100, count: languages.length });
85
-
86
- // Step 3: Detect frameworks
87
- this.emit('progress', { stage: 'frameworks', progress: 0 });
88
- const frameworks = await detectFrameworks(files, this.options.projectRoot);
89
- this.emit('progress', { stage: 'frameworks', progress: 100, count: frameworks.length });
90
-
91
- // Step 4: Detect patterns
92
- this.emit('progress', { stage: 'patterns', progress: 0 });
93
- const patterns = await detectPatterns(files, this.options.projectRoot);
94
- this.emit('progress', { stage: 'patterns', progress: 100 });
95
-
96
- // Step 5: Detect conventions
97
- this.emit('progress', { stage: 'conventions', progress: 0 });
98
- const conventions = await detectConventions(files, this.options.projectRoot);
99
- this.emit('progress', { stage: 'conventions', progress: 100 });
100
-
101
- // Build analysis result
102
- this.analysis = this.buildAnalysisResult(languages, frameworks, patterns, conventions, files);
103
-
104
- // Step 6: Write to file
105
- this.emit('progress', { stage: 'writing', progress: 0 });
106
- await this.writeAnalysis(this.analysis);
107
- this.emit('progress', { stage: 'writing', progress: 100 });
108
-
109
- const duration = Date.now() - this.startTime;
110
- this.emit('complete', { duration, analysis: this.analysis });
111
-
112
- return this.analysis;
113
- } catch (error) {
114
- this.emit('error', error);
115
- throw error;
116
- }
117
- }
118
-
119
- /**
120
- * Scan project files
121
- *
122
- * @returns {Promise<string[]>} Array of relative file paths
123
- */
124
- async scanFiles() {
125
- const files = [];
126
- const ignorePatterns = this.options.ignorePatterns;
127
-
128
- const shouldIgnore = (filePath) => {
129
- return ignorePatterns.some(pattern => {
130
- if (pattern.includes('*')) {
131
- const regex = new RegExp(pattern.replace(/\*/g, '.*'));
132
- return regex.test(filePath);
133
- }
134
- return filePath.includes(pattern);
135
- });
136
- };
137
-
138
- const scanDir = async (dir, basePath = '') => {
139
- if (files.length >= this.options.maxFiles) return;
140
-
141
- try {
142
- const entries = await fs.readdir(dir, { withFileTypes: true });
143
-
144
- // Separate directories and files
145
- const dirs = [];
146
- const fileEntries = [];
147
-
148
- for (const entry of entries) {
149
- const relativePath = path.join(basePath, entry.name);
150
- if (shouldIgnore(relativePath)) continue;
151
-
152
- const fullPath = path.join(dir, entry.name);
153
-
154
- if (entry.isDirectory()) {
155
- dirs.push({ fullPath, relativePath });
156
- } else if (entry.isFile()) {
157
- fileEntries.push(relativePath);
158
- }
159
- }
160
-
161
- // Add files
162
- files.push(...fileEntries);
163
-
164
- if (files.length >= this.options.maxFiles) {
165
- this.emit('warning', {
166
- message: `Max file limit reached (${this.options.maxFiles})`,
167
- partial: true
168
- });
169
- return;
170
- }
171
-
172
- // Scan subdirectories in parallel
173
- if (dirs.length > 0) {
174
- await Promise.all(
175
- dirs.map(({ fullPath, relativePath }) =>
176
- scanDir(fullPath, relativePath)
177
- )
178
- );
179
- }
180
- } catch (error) {
181
- // Skip directories we can't read
182
- this.emit('warning', {
183
- message: `Cannot read directory: ${dir}`,
184
- error: error.message
185
- });
186
- }
187
- };
188
-
189
- await scanDir(this.options.projectRoot);
190
-
191
- return files;
192
- }
193
-
194
- /**
195
- * Build structured analysis result
196
- *
197
- * @param {Object[]} languages - Detected languages
198
- * @param {Object[]} frameworks - Detected frameworks
199
- * @param {Object} patterns - Detected patterns
200
- * @param {Object} conventions - Detected conventions
201
- * @param {string[]} files - Scanned files
202
- * @returns {Object} Structured analysis result
203
- */
204
- buildAnalysisResult(languages, frameworks, patterns, conventions, files) {
205
- const primaryLanguage = getPrimaryLanguage(languages);
206
- const isNewProject = files.length < 10;
207
-
208
- // Calculate overall confidence score
209
- const confidence = this.calculateConfidence(languages, frameworks, patterns, isNewProject);
210
-
211
- return {
212
- version: '1.0.0',
213
- analyzedAt: new Date().toISOString(),
214
- duration: Date.now() - this.startTime,
215
- projectRoot: this.options.projectRoot,
216
- fileCount: files.length,
217
- isNewProject,
218
- confidence,
219
-
220
- languages: languages.map(lang => ({
221
- name: lang.name,
222
- confidence: lang.confidence,
223
- files: lang.files,
224
- percentage: lang.percentage,
225
- extensions: lang.extensions
226
- })),
227
-
228
- primaryLanguage: primaryLanguage ? primaryLanguage.name : null,
229
-
230
- frameworks: frameworks.map(fw => ({
231
- name: fw.name,
232
- version: fw.version || 'unknown',
233
- type: fw.type,
234
- category: fw.category,
235
- confidence: fw.confidence,
236
- source: fw.source
237
- })),
238
-
239
- patterns: {
240
- components: patterns.components || { detected: false },
241
- api: patterns.api || { detected: false },
242
- database: patterns.database || { detected: false },
243
- tests: patterns.tests || { detected: false },
244
- auth: patterns.auth || { detected: false }
245
- },
246
-
247
- conventions: {
248
- naming: conventions.naming,
249
- namingConfidence: conventions.namingConfidence,
250
- fileStructure: conventions.fileStructure,
251
- structureConfidence: conventions.structureConfidence,
252
- codeStyle: conventions.codeStyle,
253
- importStyle: conventions.importStyle,
254
- linting: conventions.linting
255
- },
256
-
257
- recommendations: this.generateRecommendations(
258
- languages,
259
- frameworks,
260
- patterns,
261
- isNewProject,
262
- confidence
263
- )
264
- };
265
- }
266
-
267
- /**
268
- * Calculate overall confidence score
269
- *
270
- * @param {Object[]} languages - Detected languages
271
- * @param {Object[]} frameworks - Detected frameworks
272
- * @param {Object} patterns - Detected patterns
273
- * @param {boolean} isNewProject - Whether this is a new project
274
- * @returns {number} Confidence score 0-100
275
- */
276
- calculateConfidence(languages, frameworks, patterns, isNewProject) {
277
- if (isNewProject) {
278
- // New projects have low confidence by design
279
- return 30;
280
- }
281
-
282
- let score = 0;
283
-
284
- // Language detection confidence (40 points max)
285
- if (languages.length > 0) {
286
- const avgLangConfidence = languages.reduce((sum, l) => sum + l.confidence, 0) / languages.length;
287
- score += (avgLangConfidence / 100) * 40;
288
- }
289
-
290
- // Framework detection confidence (30 points max)
291
- if (frameworks.length > 0) {
292
- const avgFwConfidence = frameworks.reduce((sum, f) => sum + f.confidence, 0) / frameworks.length;
293
- score += (avgFwConfidence / 100) * 30;
294
- }
295
-
296
- // Pattern detection confidence (30 points max)
297
- const detectedPatterns = Object.values(patterns).filter(p => p.detected).length;
298
- const totalPatterns = Object.keys(patterns).length;
299
- score += (detectedPatterns / totalPatterns) * 30;
300
-
301
- return Math.round(score);
302
- }
303
-
304
- /**
305
- * Generate recommendations based on analysis
306
- *
307
- * @param {Object[]} languages - Detected languages
308
- * @param {Object[]} frameworks - Detected frameworks
309
- * @param {Object} patterns - Detected patterns
310
- * @param {boolean} isNewProject - Whether this is a new project
311
- * @param {number} confidence - Overall confidence score
312
- * @returns {Object[]} Array of recommendations
313
- */
314
- generateRecommendations(languages, frameworks, patterns, isNewProject, confidence) {
315
- const recommendations = [];
316
-
317
- // Low confidence warning
318
- if (confidence < 50) {
319
- recommendations.push({
320
- type: 'warning',
321
- priority: 'high',
322
- message: 'Low detection confidence. Consider manually specifying tech stack in product spec.',
323
- action: 'Add explicit tech stack section to .claude/product/index.md'
324
- });
325
- }
326
-
327
- // New project recommendations
328
- if (isNewProject) {
329
- recommendations.push({
330
- type: 'info',
331
- priority: 'medium',
332
- message: 'New project detected. Analyzer will use default configurations.',
333
- action: 'Continue with /agentful-start to generate specialized agents'
334
- });
335
- }
336
-
337
- // No tests detected
338
- if (!patterns.tests || !patterns.tests.detected) {
339
- recommendations.push({
340
- type: 'suggestion',
341
- priority: 'medium',
342
- message: 'No test files detected. Consider setting up testing framework.',
343
- action: 'Add vitest, jest, or other testing framework'
344
- });
345
- }
346
-
347
- // No linting detected
348
- if (!patterns.tests?.detected) {
349
- recommendations.push({
350
- type: 'suggestion',
351
- priority: 'low',
352
- message: 'No linting configuration detected.',
353
- action: 'Consider adding ESLint and Prettier for code quality'
354
- });
355
- }
356
-
357
- // Multiple languages with similar confidence
358
- if (languages.length > 1) {
359
- const topTwo = languages.slice(0, 2);
360
- const diff = topTwo[0].confidence - topTwo[1].confidence;
361
- if (diff < 10) {
362
- recommendations.push({
363
- type: 'info',
364
- priority: 'low',
365
- message: `Multiple primary languages detected: ${topTwo.map(l => l.name).join(', ')}`,
366
- action: 'Agents will be generated for both languages'
367
- });
368
- }
369
- }
370
-
371
- return recommendations;
372
- }
373
-
374
- /**
375
- * Write analysis to file
376
- *
377
- * @param {Object} analysis - Analysis results
378
- * @returns {Promise<void>}
379
- */
380
- async writeAnalysis(analysis) {
381
- const outputPath = path.join(this.options.projectRoot, this.options.outputPath);
382
- const outputDir = path.dirname(outputPath);
383
-
384
- // Ensure output directory exists
385
- await fs.mkdir(outputDir, { recursive: true });
386
-
387
- // Write analysis with pretty formatting
388
- await fs.writeFile(outputPath, JSON.stringify(analysis, null, 2), 'utf-8');
389
-
390
- this.emit('written', { path: outputPath });
391
- }
392
-
393
- /**
394
- * Read existing analysis from file
395
- *
396
- * @returns {Promise<Object|null>} Existing analysis or null if not found
397
- */
398
- async readExistingAnalysis() {
399
- const outputPath = path.join(this.options.projectRoot, this.options.outputPath);
400
-
401
- try {
402
- const content = await fs.readFile(outputPath, 'utf-8');
403
- return JSON.parse(content);
404
- } catch (error) {
405
- return null;
406
- }
407
- }
408
-
409
- /**
410
- * Check if analysis is stale (older than 24 hours or file count changed significantly)
411
- *
412
- * @param {Object} existingAnalysis - Existing analysis to check
413
- * @returns {Promise<boolean>} True if stale, false if fresh
414
- */
415
- async isAnalysisStale(existingAnalysis) {
416
- if (!existingAnalysis) return true;
417
-
418
- // Check age (24 hours)
419
- const age = Date.now() - new Date(existingAnalysis.analyzedAt).getTime();
420
- const maxAge = 24 * 60 * 60 * 1000; // 24 hours
421
- if (age > maxAge) return true;
422
-
423
- // Check if file count changed significantly (>10%)
424
- const currentFiles = await this.scanFiles();
425
- const fileCountDiff = Math.abs(currentFiles.length - existingAnalysis.fileCount);
426
- const fileCountChangePercent = (fileCountDiff / existingAnalysis.fileCount) * 100;
427
- if (fileCountChangePercent > 10) return true;
428
-
429
- return false;
430
- }
431
-
432
- /**
433
- * Analyze with caching - only re-analyze if stale
434
- *
435
- * @param {boolean} force - Force re-analysis even if fresh
436
- * @returns {Promise<Object>} Analysis results
437
- */
438
- async analyzeWithCache(force = false) {
439
- if (!force) {
440
- const existing = await this.readExistingAnalysis();
441
- if (existing) {
442
- const isStale = await this.isAnalysisStale(existing);
443
- if (!isStale) {
444
- this.emit('cached', { analysis: existing });
445
- return existing;
446
- }
447
- }
448
- }
449
-
450
- return this.analyze();
451
- }
452
- }
453
-
454
- /**
455
- * Create analyzer instance
456
- *
457
- * @param {Object} options - Analyzer options
458
- * @returns {CodebaseAnalyzer} Analyzer instance
459
- */
460
- export function createAnalyzer(options = {}) {
461
- return new CodebaseAnalyzer(options);
462
- }
463
-
464
- /**
465
- * Quick analyze function - analyze and return results
466
- *
467
- * @param {Object} options - Analyzer options
468
- * @returns {Promise<Object>} Analysis results
469
- */
470
- export async function analyzeCodebase(options = {}) {
471
- const analyzer = new CodebaseAnalyzer(options);
472
- return analyzer.analyze();
473
- }
474
-
475
- /**
476
- * Analyze with progress logging
477
- *
478
- * @param {Object} options - Analyzer options
479
- * @param {Function} onProgress - Progress callback
480
- * @returns {Promise<Object>} Analysis results
481
- */
482
- export async function analyzeWithProgress(options = {}, onProgress = null) {
483
- const analyzer = new CodebaseAnalyzer(options);
484
-
485
- if (onProgress) {
486
- analyzer.on('progress', onProgress);
487
- }
488
-
489
- return analyzer.analyze();
490
- }
491
-
492
- export default {
493
- CodebaseAnalyzer,
494
- createAnalyzer,
495
- analyzeCodebase,
496
- analyzeWithProgress
497
- };
package/lib/core/cli.js DELETED
@@ -1,141 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Codebase Analyzer CLI
5
- *
6
- * Simple CLI for testing the analyzer
7
- *
8
- * Usage:
9
- * node lib/core/cli.js [options]
10
- *
11
- * Options:
12
- * --project <path> Project root path (default: current directory)
13
- * --output <path> Output file path (default: .agentful/architecture.json)
14
- * --force Force re-analysis even if cache is fresh
15
- * --verbose Show detailed progress
16
- */
17
-
18
- import { CodebaseAnalyzer } from './analyzer.js';
19
-
20
- const args = process.argv.slice(2);
21
-
22
- // Parse CLI arguments
23
- const options = {
24
- projectRoot: process.cwd(),
25
- outputPath: '.agentful/architecture.json',
26
- force: false,
27
- verbose: false
28
- };
29
-
30
- for (let i = 0; i < args.length; i++) {
31
- const arg = args[i];
32
-
33
- if (arg === '--project' && args[i + 1]) {
34
- options.projectRoot = args[++i];
35
- } else if (arg === '--output' && args[i + 1]) {
36
- options.outputPath = args[++i];
37
- } else if (arg === '--force') {
38
- options.force = true;
39
- } else if (arg === '--verbose') {
40
- options.verbose = true;
41
- } else if (arg === '--help' || arg === '-h') {
42
- console.log(`
43
- Codebase Analyzer CLI
44
-
45
- Usage:
46
- node lib/core/cli.js [options]
47
-
48
- Options:
49
- --project <path> Project root path (default: current directory)
50
- --output <path> Output file path (default: .agentful/architecture.json)
51
- --force Force re-analysis even if cache is fresh
52
- --verbose Show detailed progress
53
- --help, -h Show this help message
54
-
55
- Examples:
56
- # Analyze current directory
57
- node lib/core/cli.js
58
-
59
- # Analyze specific project
60
- node lib/core/cli.js --project /path/to/project
61
-
62
- # Force re-analysis
63
- node lib/core/cli.js --force --verbose
64
- `);
65
- process.exit(0);
66
- }
67
- }
68
-
69
- // Create analyzer
70
- const analyzer = new CodebaseAnalyzer(options);
71
-
72
- // Setup event listeners
73
- analyzer.on('start', ({ projectRoot }) => {
74
- console.log(`\nšŸ” Analyzing codebase: ${projectRoot}\n`);
75
- });
76
-
77
- analyzer.on('progress', ({ stage, progress, fileCount, count }) => {
78
- if (options.verbose) {
79
- let message = ` ${stage}: ${progress}%`;
80
- if (fileCount) message += ` (${fileCount} files)`;
81
- if (count) message += ` (${count} detected)`;
82
- console.log(message);
83
- }
84
- });
85
-
86
- analyzer.on('warning', ({ message }) => {
87
- if (options.verbose) {
88
- console.warn(` āš ļø ${message}`);
89
- }
90
- });
91
-
92
- analyzer.on('written', ({ path }) => {
93
- console.log(`\nāœ… Analysis written to: ${path}\n`);
94
- });
95
-
96
- analyzer.on('complete', ({ duration, analysis }) => {
97
- console.log(`ā±ļø Completed in ${duration}ms\n`);
98
-
99
- // Print summary
100
- console.log('šŸ“Š Summary:');
101
- console.log(` Files analyzed: ${analysis.fileCount}`);
102
- console.log(` Confidence: ${analysis.confidence}%`);
103
- console.log(` Primary language: ${analysis.primaryLanguage || 'unknown'}`);
104
- console.log(` Languages: ${analysis.languages.map(l => l.name).join(', ')}`);
105
- console.log(` Frameworks: ${analysis.frameworks.map(f => f.name).join(', ') || 'none'}`);
106
-
107
- if (analysis.recommendations.length > 0) {
108
- console.log(`\nšŸ’” Recommendations:`);
109
- analysis.recommendations.forEach((rec, i) => {
110
- console.log(` ${i + 1}. [${rec.priority}] ${rec.message}`);
111
- console.log(` → ${rec.action}`);
112
- });
113
- }
114
-
115
- console.log('');
116
- });
117
-
118
- analyzer.on('error', (error) => {
119
- console.error(`\nāŒ Analysis failed: ${error.message}\n`);
120
- if (options.verbose) {
121
- console.error(error.stack);
122
- }
123
- process.exit(1);
124
- });
125
-
126
- // Run analysis
127
- (async () => {
128
- try {
129
- if (options.force) {
130
- await analyzer.analyze();
131
- } else {
132
- await analyzer.analyzeWithCache();
133
- }
134
- } catch (error) {
135
- console.error(`\nāŒ Unexpected error: ${error.message}\n`);
136
- if (options.verbose) {
137
- console.error(error.stack);
138
- }
139
- process.exit(1);
140
- }
141
- })();