prjct-cli 0.5.1 → 0.7.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 (81) hide show
  1. package/CHANGELOG.md +220 -7
  2. package/CLAUDE.md +476 -55
  3. package/README.md +48 -55
  4. package/bin/prjct +170 -225
  5. package/core/agentic/command-executor.js +113 -0
  6. package/core/agentic/context-builder.js +85 -0
  7. package/core/agentic/prompt-builder.js +86 -0
  8. package/core/agentic/template-loader.js +104 -0
  9. package/core/agentic/tool-registry.js +117 -0
  10. package/core/command-registry.js +597 -0
  11. package/core/commands.js +2046 -2028
  12. package/core/domain/agent-generator.js +118 -0
  13. package/core/domain/analyzer.js +211 -0
  14. package/core/domain/architect-session.js +300 -0
  15. package/core/{agents → infrastructure/agents}/claude-agent.js +16 -13
  16. package/core/{author-detector.js → infrastructure/author-detector.js} +3 -1
  17. package/core/{capability-installer.js → infrastructure/capability-installer.js} +3 -6
  18. package/core/{command-installer.js → infrastructure/command-installer.js} +4 -2
  19. package/core/{config-manager.js → infrastructure/config-manager.js} +4 -4
  20. package/core/{editors-config.js → infrastructure/editors-config.js} +2 -10
  21. package/core/{migrator.js → infrastructure/migrator.js} +34 -19
  22. package/core/{path-manager.js → infrastructure/path-manager.js} +20 -44
  23. package/core/{session-manager.js → infrastructure/session-manager.js} +45 -105
  24. package/core/{update-checker.js → infrastructure/update-checker.js} +67 -67
  25. package/core/{animations-simple.js → utils/animations.js} +3 -23
  26. package/core/utils/date-helper.js +238 -0
  27. package/core/utils/file-helper.js +327 -0
  28. package/core/utils/jsonl-helper.js +206 -0
  29. package/core/{project-capabilities.js → utils/project-capabilities.js} +21 -22
  30. package/core/utils/session-helper.js +277 -0
  31. package/core/{version.js → utils/version.js} +1 -1
  32. package/package.json +5 -12
  33. package/templates/agents/AGENTS.md +151 -99
  34. package/templates/analysis/analyze.md +84 -0
  35. package/templates/commands/analyze.md +37 -233
  36. package/templates/commands/bug.md +79 -0
  37. package/templates/commands/build.md +44 -0
  38. package/templates/commands/cleanup.md +24 -84
  39. package/templates/commands/design.md +20 -95
  40. package/templates/commands/done.md +17 -180
  41. package/templates/commands/feature.md +113 -0
  42. package/templates/commands/fix.md +58 -66
  43. package/templates/commands/git.md +35 -57
  44. package/templates/commands/help.md +18 -52
  45. package/templates/commands/idea.md +18 -34
  46. package/templates/commands/init.md +65 -257
  47. package/templates/commands/next.md +20 -60
  48. package/templates/commands/now.md +21 -23
  49. package/templates/commands/progress.md +40 -73
  50. package/templates/commands/recap.md +52 -75
  51. package/templates/commands/roadmap.md +30 -85
  52. package/templates/commands/ship.md +93 -126
  53. package/templates/commands/status.md +42 -0
  54. package/templates/commands/sync.md +19 -205
  55. package/templates/commands/task.md +19 -79
  56. package/templates/commands/test.md +25 -71
  57. package/templates/commands/workflow.md +20 -210
  58. package/core/agent-generator.js +0 -516
  59. package/core/analyzer.js +0 -600
  60. package/core/animations.js +0 -277
  61. package/core/git-integration.js +0 -401
  62. package/core/workflow-engine.js +0 -213
  63. package/core/workflow-prompts.js +0 -192
  64. package/core/workflow-rules.js +0 -147
  65. package/scripts/post-install.js +0 -121
  66. package/scripts/preuninstall.js +0 -94
  67. package/scripts/verify-installation.sh +0 -158
  68. package/templates/agents/be.template.md +0 -42
  69. package/templates/agents/data.template.md +0 -41
  70. package/templates/agents/devops.template.md +0 -41
  71. package/templates/agents/fe.template.md +0 -42
  72. package/templates/agents/mobile.template.md +0 -41
  73. package/templates/agents/pm.template.md +0 -84
  74. package/templates/agents/qa.template.md +0 -54
  75. package/templates/agents/scribe.template.md +0 -95
  76. package/templates/agents/security.template.md +0 -41
  77. package/templates/agents/ux.template.md +0 -49
  78. package/templates/commands/context.md +0 -105
  79. package/templates/commands/stuck.md +0 -48
  80. package/templates/examples/natural-language-examples.md +0 -532
  81. /package/core/{agent-detector.js → infrastructure/agent-detector.js} +0 -0
@@ -1,213 +0,0 @@
1
- /**
2
- * Workflow Engine
3
- * Orchestrates adaptive agent workflows based on project capabilities
4
- */
5
-
6
- const fs = require('fs').promises
7
- const path = require('path')
8
- const capabilities = require('./project-capabilities')
9
- const rules = require('./workflow-rules')
10
-
11
- class WorkflowEngine {
12
- /**
13
- * Initialize workflow for task
14
- * @param {string} task - Task description
15
- * @param {string} type - Workflow type (ui, api, bug, refactor, feature)
16
- * @param {string} dataPath - Project data path
17
- * @returns {Promise<Object>} Workflow object
18
- */
19
- async init(task, type, dataPath) {
20
- // Detect project capabilities
21
- const projectPath = path.dirname(path.dirname(dataPath))
22
- const caps = await capabilities.detect(projectPath)
23
-
24
- // Get base workflow
25
- const base = rules[type] || rules.ui
26
-
27
- // Map all steps - mark for prompting if capability missing
28
- const steps = base.map((s, index) => ({
29
- ...s,
30
- index,
31
- status: 'pending',
32
- skipped: false,
33
- needsPrompt: !s.required && s.prompt && !caps[s.needs],
34
- }))
35
-
36
- // Track which capabilities are missing
37
- const missingCapabilities = base
38
- .filter(s => !s.required && s.needs && !caps[s.needs])
39
- .map(s => s.needs)
40
-
41
- const workflow = {
42
- task,
43
- type,
44
- caps,
45
- steps,
46
- missingCapabilities,
47
- current: 0,
48
- active: true,
49
- createdAt: new Date().toISOString(),
50
- }
51
-
52
- await this.save(workflow, dataPath)
53
- return workflow
54
- }
55
-
56
- /**
57
- * Get current step info
58
- */
59
- async getCurrent(dataPath) {
60
- const wf = await this.load(dataPath)
61
- if (!wf || !wf.active) return null
62
-
63
- return wf.steps[wf.current]
64
- }
65
-
66
- /**
67
- * Advance to next step
68
- */
69
- async next(dataPath) {
70
- const wf = await this.load(dataPath)
71
- if (!wf) return null
72
-
73
- // Mark current step as completed
74
- wf.steps[wf.current].status = 'completed'
75
- wf.steps[wf.current].completedAt = new Date().toISOString()
76
-
77
- // Move to next
78
- wf.current++
79
-
80
- // Check if workflow complete
81
- if (wf.current >= wf.steps.length) {
82
- wf.active = false
83
- wf.completedAt = new Date().toISOString()
84
- await this.save(wf, dataPath)
85
- return null
86
- }
87
-
88
- // Mark next step as in progress
89
- wf.steps[wf.current].status = 'in_progress'
90
- wf.steps[wf.current].startedAt = new Date().toISOString()
91
-
92
- await this.save(wf, dataPath)
93
- return wf.steps[wf.current]
94
- }
95
-
96
- /**
97
- * Skip current step
98
- */
99
- async skip(dataPath, reason = 'User skipped') {
100
- const wf = await this.load(dataPath)
101
- if (!wf) return null
102
-
103
- wf.steps[wf.current].skipped = true
104
- wf.steps[wf.current].status = 'skipped'
105
- wf.steps[wf.current].skipReason = reason
106
- wf.steps[wf.current].skippedAt = new Date().toISOString()
107
-
108
- return await this.next(dataPath)
109
- }
110
-
111
- /**
112
- * Insert installation step before current step
113
- */
114
- async insertInstall(dataPath, installTask) {
115
- const wf = await this.load(dataPath)
116
- if (!wf) return null
117
-
118
- const currentIndex = wf.current
119
-
120
- // Insert install task at current position
121
- wf.steps.splice(currentIndex, 0, {
122
- ...installTask,
123
- index: currentIndex,
124
- status: 'in_progress',
125
- insertedAt: new Date().toISOString(),
126
- })
127
-
128
- // Reindex all subsequent steps
129
- for (let i = currentIndex + 1; i < wf.steps.length; i++) {
130
- wf.steps[i].index = i
131
- }
132
-
133
- await this.save(wf, dataPath)
134
- return wf.steps[currentIndex]
135
- }
136
-
137
- /**
138
- * Classify task type from description
139
- * @param {string} text - Task description
140
- * @returns {string} Workflow type
141
- */
142
- classify(text) {
143
- const t = text.toLowerCase()
144
-
145
- if (/button|form|modal|card|component|menu|nav|input/.test(t)) return 'ui'
146
- if (/endpoint|api|service|route|controller/.test(t)) return 'api'
147
- if (/bug|fix|error|issue|broken/.test(t)) return 'bug'
148
- if (/refactor|improve|optimize|clean/.test(t)) return 'refactor'
149
- if (/feature|functionality|module/.test(t)) return 'feature'
150
-
151
- return 'ui' // Default
152
- }
153
-
154
- /**
155
- * Get workflow status
156
- */
157
- async getStatus(dataPath) {
158
- const wf = await this.load(dataPath)
159
- if (!wf) return null
160
-
161
- return {
162
- task: wf.task,
163
- type: wf.type,
164
- active: wf.active,
165
- current: wf.current,
166
- total: wf.steps.length,
167
- steps: wf.steps.map(s => ({
168
- name: s.name,
169
- status: s.status,
170
- agent: s.agent,
171
- })),
172
- skipped: wf.skipped,
173
- }
174
- }
175
-
176
- /**
177
- * Load workflow from file
178
- */
179
- async load(dataPath) {
180
- try {
181
- const workflowPath = path.join(dataPath, 'workflow', 'state.json')
182
- const content = await fs.readFile(workflowPath, 'utf8')
183
- return JSON.parse(content)
184
- } catch {
185
- return null
186
- }
187
- }
188
-
189
- /**
190
- * Save workflow to file
191
- */
192
- async save(workflow, dataPath) {
193
- const workflowDir = path.join(dataPath, 'workflow')
194
- await fs.mkdir(workflowDir, { recursive: true })
195
-
196
- const workflowPath = path.join(workflowDir, 'state.json')
197
- await fs.writeFile(workflowPath, JSON.stringify(workflow, null, 2))
198
- }
199
-
200
- /**
201
- * Clear workflow
202
- */
203
- async clear(dataPath) {
204
- try {
205
- const workflowPath = path.join(dataPath, 'workflow', 'state.json')
206
- await fs.unlink(workflowPath)
207
- } catch {
208
- // Ignore if doesn't exist
209
- }
210
- }
211
- }
212
-
213
- module.exports = new WorkflowEngine()
@@ -1,192 +0,0 @@
1
- /**
2
- * Interactive workflow prompts for missing capabilities
3
- * Asks users before skipping or installing tools
4
- */
5
-
6
- class WorkflowPrompts {
7
- /**
8
- * Get recommendation based on detected stack
9
- */
10
- getRecommendation(stepName, projectInfo = {}) {
11
- const recommendations = {
12
- design: {
13
- tools: ['Figma plugin', 'Storybook', 'Design tokens'],
14
- install: 'npx storybook@latest init',
15
- reason: 'Component documentation and design system',
16
- },
17
- test: {
18
- tools: this.getTestRecommendation(projectInfo),
19
- install: this.getTestInstallCommand(projectInfo),
20
- reason: 'Quality assurance and regression prevention',
21
- },
22
- docs: {
23
- tools: ['JSDoc', 'TypeDoc', 'Docusaurus'],
24
- install: 'npm install -D jsdoc',
25
- reason: 'API documentation and code examples',
26
- },
27
- }
28
-
29
- return recommendations[stepName] || null
30
- }
31
-
32
- /**
33
- * Detect test framework based on project stack
34
- */
35
- getTestRecommendation(projectInfo) {
36
- const { framework, typescript } = projectInfo
37
-
38
- if (framework === 'react') {
39
- return typescript
40
- ? ['Vitest + Testing Library', 'Jest + Testing Library']
41
- : ['Jest + Testing Library', 'Vitest']
42
- }
43
-
44
- if (framework === 'vue') {
45
- return ['Vitest', '@vue/test-utils']
46
- }
47
-
48
- if (framework === 'angular') {
49
- return ['Jasmine + Karma', 'Jest']
50
- }
51
-
52
- // Default Node.js
53
- return typescript
54
- ? ['Vitest', 'Jest with ts-jest']
55
- : ['Jest', 'Vitest', 'Mocha + Chai']
56
- }
57
-
58
- /**
59
- * Get install command based on stack
60
- */
61
- getTestInstallCommand(projectInfo) {
62
- const { framework, typescript } = projectInfo
63
-
64
- if (framework === 'react') {
65
- return typescript
66
- ? 'npm install -D vitest @testing-library/react @testing-library/jest-dom'
67
- : 'npm install -D jest @testing-library/react @testing-library/jest-dom'
68
- }
69
-
70
- if (framework === 'vue') {
71
- return 'npm install -D vitest @vue/test-utils'
72
- }
73
-
74
- if (framework === 'angular') {
75
- return 'npm install -D jest @types/jest ts-jest'
76
- }
77
-
78
- return typescript
79
- ? 'npm install -D vitest'
80
- : 'npm install -D jest'
81
- }
82
-
83
- /**
84
- * Detect project stack from package.json
85
- */
86
- async detectStack(projectPath) {
87
- const fs = require('fs').promises
88
- const path = require('path')
89
-
90
- try {
91
- const pkgPath = path.join(projectPath, 'package.json')
92
- const pkg = JSON.parse(await fs.readFile(pkgPath, 'utf8'))
93
-
94
- const deps = { ...pkg.dependencies, ...pkg.devDependencies }
95
-
96
- return {
97
- framework: this.detectFramework(deps),
98
- typescript: 'typescript' in deps,
99
- bundler: this.detectBundler(deps),
100
- runtime: this.detectRuntime(deps),
101
- }
102
- } catch {
103
- return { framework: 'node', typescript: false }
104
- }
105
- }
106
-
107
- detectFramework(deps) {
108
- if ('react' in deps) return 'react'
109
- if ('vue' in deps) return 'vue'
110
- if ('@angular/core' in deps) return 'angular'
111
- if ('next' in deps) return 'next'
112
- if ('nuxt' in deps) return 'nuxt'
113
- return 'node'
114
- }
115
-
116
- detectBundler(deps) {
117
- if ('vite' in deps) return 'vite'
118
- if ('webpack' in deps) return 'webpack'
119
- if ('esbuild' in deps) return 'esbuild'
120
- return null
121
- }
122
-
123
- detectRuntime(deps) {
124
- if ('bun' in deps) return 'bun'
125
- if ('deno' in deps) return 'deno'
126
- return 'node'
127
- }
128
-
129
- /**
130
- * Build prompt message for missing capability
131
- */
132
- async buildPrompt(step, capabilities, projectPath) {
133
- const stack = await this.detectStack(projectPath)
134
- const rec = this.getRecommendation(step.needs, stack)
135
-
136
- if (!rec) {
137
- return {
138
- message: `⚠️ Step "${step.name}" requires ${step.needs} capability\n\nOptions:\n1. Skip this step\n2. Continue without ${step.needs}\n3. Pause workflow`,
139
- options: ['skip', 'continue', 'pause'],
140
- recommendation: null,
141
- }
142
- }
143
-
144
- const toolsList = rec.tools.join(', ')
145
-
146
- return {
147
- message: `⚠️ Missing ${step.needs} capability for "${step.name}" step\n\n` +
148
- `📋 Recommended: ${toolsList}\n` +
149
- `💡 Reason: ${rec.reason}\n\n` +
150
- 'Options:\n' +
151
- `1. Install recommended (${rec.install})\n` +
152
- '2. Skip this step\n' +
153
- `3. Continue without ${step.needs}\n` +
154
- '4. Pause workflow',
155
- options: ['install', 'skip', 'continue', 'pause'],
156
- recommendation: rec,
157
- stack,
158
- }
159
- }
160
-
161
- /**
162
- * Parse user choice from response
163
- */
164
- parseChoice(response) {
165
- const lower = response.toLowerCase().trim()
166
-
167
- if (lower.match(/^(1|install|yes|y)/)) return 'install'
168
- if (lower.match(/^(2|skip|s)/)) return 'skip'
169
- if (lower.match(/^(3|continue|c)/)) return 'continue'
170
- if (lower.match(/^(4|pause|p)/)) return 'pause'
171
-
172
- return 'skip' // Default to skip if unclear
173
- }
174
-
175
- /**
176
- * Create installation task for workflow
177
- */
178
- createInstallTask(step, recommendation) {
179
- return {
180
- name: `install-${step.needs}`,
181
- agent: 'devops',
182
- action: `Install ${step.needs}: ${recommendation.install}`,
183
- required: true,
184
- type: 'install',
185
- install: recommendation.install,
186
- capability: step.needs,
187
- reason: recommendation.reason,
188
- }
189
- }
190
- }
191
-
192
- module.exports = new WorkflowPrompts()
@@ -1,147 +0,0 @@
1
- /**
2
- * Workflow Rules
3
- * Defines workflows by task type with capability requirements
4
- */
5
-
6
- module.exports = {
7
- // UI Component workflow
8
- ui: [
9
- {
10
- name: 'design',
11
- agent: 'frontend',
12
- action: 'Create component design',
13
- required: false,
14
- needs: 'design',
15
- prompt: true,
16
- },
17
- {
18
- name: 'dev',
19
- agent: 'frontend',
20
- action: 'Implement component',
21
- required: true,
22
- },
23
- {
24
- name: 'test',
25
- agent: 'qa',
26
- action: 'Create tests',
27
- required: false,
28
- needs: 'test',
29
- retry: 3,
30
- prompt: true,
31
- },
32
- {
33
- name: 'docs',
34
- agent: 'scribe',
35
- action: 'Document component',
36
- required: false,
37
- needs: 'docs',
38
- prompt: true,
39
- },
40
- ],
41
-
42
- // API Endpoint workflow
43
- api: [
44
- {
45
- name: 'dev',
46
- agent: 'backend',
47
- action: 'Implement endpoint',
48
- required: true,
49
- },
50
- {
51
- name: 'test',
52
- agent: 'qa',
53
- action: 'Create API tests',
54
- required: false,
55
- needs: 'test',
56
- retry: 3,
57
- prompt: true,
58
- },
59
- {
60
- name: 'docs',
61
- agent: 'scribe',
62
- action: 'Document API',
63
- required: false,
64
- needs: 'docs',
65
- prompt: true,
66
- },
67
- ],
68
-
69
- // Bug Fix workflow
70
- bug: [
71
- {
72
- name: 'analyze',
73
- agent: 'analyzer',
74
- action: 'Analyze bug',
75
- required: true,
76
- },
77
- {
78
- name: 'fix',
79
- agent: 'auto',
80
- action: 'Fix bug',
81
- required: true,
82
- },
83
- {
84
- name: 'test',
85
- agent: 'qa',
86
- action: 'Verify fix',
87
- required: false,
88
- needs: 'test',
89
- retry: 3,
90
- prompt: true,
91
- },
92
- ],
93
-
94
- // Refactor workflow
95
- refactor: [
96
- {
97
- name: 'refactor',
98
- agent: 'refactorer',
99
- action: 'Refactor code',
100
- required: true,
101
- },
102
- {
103
- name: 'test',
104
- agent: 'qa',
105
- action: 'Verify refactor',
106
- required: false,
107
- needs: 'test',
108
- retry: 3,
109
- prompt: true,
110
- },
111
- ],
112
-
113
- // Feature workflow (complete feature)
114
- feature: [
115
- {
116
- name: 'design',
117
- agent: 'architect',
118
- action: 'Design feature',
119
- required: false,
120
- needs: 'design',
121
- prompt: true,
122
- },
123
- {
124
- name: 'dev',
125
- agent: 'auto',
126
- action: 'Implement feature',
127
- required: true,
128
- },
129
- {
130
- name: 'test',
131
- agent: 'qa',
132
- action: 'Test feature',
133
- required: false,
134
- needs: 'test',
135
- retry: 3,
136
- prompt: true,
137
- },
138
- {
139
- name: 'docs',
140
- agent: 'scribe',
141
- action: 'Document feature',
142
- required: false,
143
- needs: 'docs',
144
- prompt: true,
145
- },
146
- ],
147
- }
@@ -1,121 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Post-Install Script
5
- *
6
- * Runs automatically after `npm install -g prjct-cli` or `npm update -g prjct-cli`.
7
- * Auto-updates slash commands in all previously configured editors.
8
- *
9
- * Flow:
10
- * 1. Check if running as global install
11
- * 2. Read tracked editors from ~/.prjct-cli/config/installed-editors.json
12
- * 3. If config exists and version changed, force-update commands in tracked editors
13
- * 4. Update version in config
14
- *
15
- * @version 0.4.4
16
- */
17
-
18
- const path = require('path')
19
- const chalk = require('chalk')
20
- const { execSync } = require('child_process')
21
-
22
- async function main() {
23
- try {
24
- // Get current package version
25
- const packageJson = require('../package.json')
26
- const currentVersion = packageJson.version
27
-
28
- // Check if this is a global installation
29
- const isGlobal = await checkIfGlobalInstall()
30
-
31
- if (!isGlobal) {
32
- // Skip post-install for local/dev installations
33
- if (process.env.DEBUG) {
34
- console.log(chalk.gray('[post-install] Skipping - not a global install'))
35
- }
36
- return
37
- }
38
-
39
- // Load editors config
40
- const editorsConfig = require('../core/editors-config')
41
- const configExists = await editorsConfig.configExists()
42
-
43
- if (!configExists) {
44
- // First-time install - show welcome message
45
- console.log(chalk.cyan('\n✨ prjct-cli installed successfully!\n'))
46
- console.log(chalk.gray('Run: ') + chalk.cyan('prjct start') + chalk.gray(' to get started\n'))
47
- return
48
- }
49
-
50
- // Check if version has changed
51
- const versionChanged = await editorsConfig.hasVersionChanged(currentVersion)
52
-
53
- if (!versionChanged) {
54
- // Same version, no update needed
55
- return
56
- }
57
-
58
- // Get tracked editors
59
- const trackedEditors = await editorsConfig.getTrackedEditors()
60
-
61
- if (trackedEditors.length === 0) {
62
- // No editors tracked yet
63
- return
64
- }
65
-
66
- console.log(chalk.cyan('\n🔄 Updating prjct commands in configured editors...\n'))
67
-
68
- // Load command installer
69
- const commandInstaller = require('../core/command-installer')
70
-
71
- // Force-update commands in all tracked editors
72
- const results = await commandInstaller.installToSelected(trackedEditors, true)
73
-
74
- if (results.success) {
75
- console.log(chalk.green(`✅ Updated commands in: ${results.editors.join(', ')}`))
76
- console.log(chalk.gray(` Commands updated: ${results.totalUpdated}`))
77
- } else {
78
- console.log(chalk.yellow('⚠️ Some editors could not be updated'))
79
- }
80
-
81
- // Update version in config
82
- await editorsConfig.updateVersion(currentVersion)
83
-
84
- console.log(chalk.cyan(`\n✨ prjct-cli ${currentVersion} is ready!\n`))
85
-
86
- } catch (error) {
87
- // Silently fail - don't block npm install
88
- // Only log if explicitly debugging
89
- if (process.env.DEBUG) {
90
- console.error(chalk.red('[post-install] Error:'), error.message)
91
- }
92
- }
93
- }
94
-
95
- /**
96
- * Check if package is being installed globally
97
- * @returns {Promise<boolean>} True if global install
98
- */
99
- async function checkIfGlobalInstall() {
100
- try {
101
- // Get npm global root directory
102
- const globalRoot = execSync('npm root -g', { encoding: 'utf-8' }).trim()
103
-
104
- // Get current package directory
105
- const currentDir = path.resolve(__dirname, '..')
106
-
107
- // Check if current directory is under global node_modules
108
- return currentDir.startsWith(globalRoot)
109
- } catch {
110
- return false
111
- }
112
- }
113
-
114
- // Run main function
115
- main().catch(error => {
116
- // Silently fail - don't block npm install
117
- if (process.env.DEBUG) {
118
- console.error('[post-install] Fatal error:', error)
119
- }
120
- process.exit(0) // Exit with success to not block npm install
121
- })