@howlil/ez-agents 3.4.1 → 3.5.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.
- package/LICENSE +21 -21
- package/README.md +84 -20
- package/agents/ez-observer-agent.md +260 -0
- package/agents/ez-release-agent.md +333 -0
- package/agents/ez-requirements-agent.md +377 -0
- package/agents/ez-scrum-master-agent.md +242 -0
- package/agents/ez-tech-lead-agent.md +267 -0
- package/bin/install.js +3221 -3230
- package/commands/ez/arch-review.md +102 -0
- package/commands/ez/execute-phase.md +11 -0
- package/commands/ez/export-session.md +79 -0
- package/commands/ez/gather-requirements.md +117 -0
- package/commands/ez/git-workflow.md +72 -0
- package/commands/ez/hotfix.md +120 -0
- package/commands/ez/import-session.md +82 -0
- package/commands/ez/join-discord.md +18 -18
- package/commands/ez/list-sessions.md +96 -0
- package/commands/ez/package-manager.md +316 -0
- package/commands/ez/plan-phase.md +9 -1
- package/commands/ez/preflight.md +79 -0
- package/commands/ez/progress.md +13 -1
- package/commands/ez/release.md +153 -0
- package/commands/ez/resume.md +107 -0
- package/commands/ez/standup.md +85 -0
- package/ez-agents/bin/ez-tools.cjs +1095 -716
- package/ez-agents/bin/lib/assistant-adapter.cjs +264 -264
- package/ez-agents/bin/lib/audit-exec.cjs +7 -2
- package/ez-agents/bin/lib/bdd-validator.cjs +622 -0
- package/ez-agents/bin/lib/circuit-breaker.cjs +118 -118
- package/ez-agents/bin/lib/config.cjs +190 -190
- package/ez-agents/bin/lib/content-scanner.cjs +238 -0
- package/ez-agents/bin/lib/context-cache.cjs +154 -0
- package/ez-agents/bin/lib/context-errors.cjs +71 -0
- package/ez-agents/bin/lib/context-manager.cjs +220 -0
- package/ez-agents/bin/lib/discussion-synthesizer.cjs +458 -0
- package/ez-agents/bin/lib/file-access.cjs +207 -0
- package/ez-agents/bin/lib/file-lock.cjs +236 -236
- package/ez-agents/bin/lib/frontmatter.cjs +299 -299
- package/ez-agents/bin/lib/fs-utils.cjs +153 -153
- package/ez-agents/bin/lib/git-errors.cjs +83 -0
- package/ez-agents/bin/lib/git-utils.cjs +118 -0
- package/ez-agents/bin/lib/git-workflow-engine.cjs +1157 -0
- package/ez-agents/bin/lib/index.cjs +157 -113
- package/ez-agents/bin/lib/init.cjs +757 -757
- package/ez-agents/bin/lib/lockfile-validator.cjs +227 -0
- package/ez-agents/bin/lib/logger.cjs +124 -124
- package/ez-agents/bin/lib/memory-compression.cjs +256 -0
- package/ez-agents/bin/lib/metrics-tracker.cjs +406 -0
- package/ez-agents/bin/lib/milestone.cjs +241 -241
- package/ez-agents/bin/lib/model-provider.cjs +241 -241
- package/ez-agents/bin/lib/package-manager-detector.cjs +203 -0
- package/ez-agents/bin/lib/package-manager-executor.cjs +385 -0
- package/ez-agents/bin/lib/package-manager-service.cjs +216 -0
- package/ez-agents/bin/lib/phase.cjs +925 -925
- package/ez-agents/bin/lib/planning-write.cjs +107 -107
- package/ez-agents/bin/lib/release-validator.cjs +614 -0
- package/ez-agents/bin/lib/retry.cjs +119 -119
- package/ez-agents/bin/lib/roadmap.cjs +306 -306
- package/ez-agents/bin/lib/safe-exec.cjs +128 -128
- package/ez-agents/bin/lib/safe-path.cjs +130 -130
- package/ez-agents/bin/lib/session-chain.cjs +304 -0
- package/ez-agents/bin/lib/session-errors.cjs +81 -0
- package/ez-agents/bin/lib/session-export.cjs +251 -0
- package/ez-agents/bin/lib/session-import.cjs +262 -0
- package/ez-agents/bin/lib/session-manager.cjs +280 -0
- package/ez-agents/bin/lib/state.cjs +736 -736
- package/ez-agents/bin/lib/temp-file.cjs +239 -239
- package/ez-agents/bin/lib/template.cjs +223 -223
- package/ez-agents/bin/lib/test-file-lock.cjs +112 -112
- package/ez-agents/bin/lib/test-graceful.cjs +93 -93
- package/ez-agents/bin/lib/test-logger.cjs +60 -60
- package/ez-agents/bin/lib/test-safe-exec.cjs +38 -38
- package/ez-agents/bin/lib/test-safe-path.cjs +33 -33
- package/ez-agents/bin/lib/test-temp-file.cjs +125 -125
- package/ez-agents/bin/lib/tier-manager.cjs +428 -0
- package/ez-agents/bin/lib/timeout-exec.cjs +63 -63
- package/ez-agents/bin/lib/url-fetch.cjs +170 -0
- package/ez-agents/bin/lib/verify.cjs +15 -1
- package/ez-agents/references/checkpoints.md +776 -776
- package/ez-agents/references/continuation-format.md +249 -249
- package/ez-agents/references/metrics-schema.md +118 -0
- package/ez-agents/references/planning-config.md +140 -0
- package/ez-agents/references/questioning.md +162 -162
- package/ez-agents/references/tdd.md +263 -263
- package/ez-agents/references/tier-strategy.md +103 -0
- package/ez-agents/templates/bdd-feature.md +173 -0
- package/ez-agents/templates/codebase/concerns.md +310 -310
- package/ez-agents/templates/codebase/conventions.md +307 -307
- package/ez-agents/templates/codebase/integrations.md +280 -280
- package/ez-agents/templates/codebase/stack.md +186 -186
- package/ez-agents/templates/codebase/testing.md +480 -480
- package/ez-agents/templates/config.json +37 -37
- package/ez-agents/templates/continue-here.md +78 -78
- package/ez-agents/templates/discussion.md +68 -0
- package/ez-agents/templates/incident-runbook.md +205 -0
- package/ez-agents/templates/milestone-archive.md +123 -123
- package/ez-agents/templates/milestone.md +115 -115
- package/ez-agents/templates/release-checklist.md +133 -0
- package/ez-agents/templates/requirements.md +231 -231
- package/ez-agents/templates/research-project/ARCHITECTURE.md +204 -204
- package/ez-agents/templates/research-project/FEATURES.md +147 -147
- package/ez-agents/templates/research-project/PITFALLS.md +200 -200
- package/ez-agents/templates/research-project/STACK.md +120 -120
- package/ez-agents/templates/research-project/SUMMARY.md +170 -170
- package/ez-agents/templates/retrospective.md +54 -54
- package/ez-agents/templates/roadmap.md +202 -202
- package/ez-agents/templates/rollback-plan.md +201 -0
- package/ez-agents/templates/summary-minimal.md +41 -41
- package/ez-agents/templates/summary-standard.md +48 -48
- package/ez-agents/templates/summary.md +248 -248
- package/ez-agents/templates/user-setup.md +311 -311
- package/ez-agents/templates/verification-report.md +322 -322
- package/ez-agents/workflows/add-phase.md +112 -112
- package/ez-agents/workflows/add-tests.md +351 -351
- package/ez-agents/workflows/add-todo.md +158 -158
- package/ez-agents/workflows/arch-review.md +54 -0
- package/ez-agents/workflows/audit-milestone.md +332 -332
- package/ez-agents/workflows/autonomous.md +131 -30
- package/ez-agents/workflows/check-todos.md +177 -177
- package/ez-agents/workflows/cleanup.md +152 -152
- package/ez-agents/workflows/complete-milestone.md +766 -766
- package/ez-agents/workflows/diagnose-issues.md +219 -219
- package/ez-agents/workflows/discovery-phase.md +289 -289
- package/ez-agents/workflows/discuss-phase.md +762 -762
- package/ez-agents/workflows/execute-phase.md +513 -468
- package/ez-agents/workflows/execute-plan.md +483 -483
- package/ez-agents/workflows/export-session.md +255 -0
- package/ez-agents/workflows/gather-requirements.md +206 -0
- package/ez-agents/workflows/health.md +159 -159
- package/ez-agents/workflows/help.md +584 -492
- package/ez-agents/workflows/hotfix.md +291 -0
- package/ez-agents/workflows/import-session.md +303 -0
- package/ez-agents/workflows/insert-phase.md +130 -130
- package/ez-agents/workflows/list-phase-assumptions.md +178 -178
- package/ez-agents/workflows/map-codebase.md +316 -316
- package/ez-agents/workflows/new-milestone.md +339 -10
- package/ez-agents/workflows/new-project.md +293 -299
- package/ez-agents/workflows/node-repair.md +92 -92
- package/ez-agents/workflows/pause-work.md +122 -122
- package/ez-agents/workflows/plan-milestone-gaps.md +274 -274
- package/ez-agents/workflows/plan-phase.md +673 -651
- package/ez-agents/workflows/progress.md +372 -382
- package/ez-agents/workflows/quick.md +610 -610
- package/ez-agents/workflows/release.md +253 -0
- package/ez-agents/workflows/remove-phase.md +155 -155
- package/ez-agents/workflows/research-phase.md +74 -74
- package/ez-agents/workflows/resume-project.md +307 -307
- package/ez-agents/workflows/resume-session.md +215 -0
- package/ez-agents/workflows/set-profile.md +81 -81
- package/ez-agents/workflows/settings.md +242 -242
- package/ez-agents/workflows/standup.md +64 -0
- package/ez-agents/workflows/stats.md +57 -57
- package/ez-agents/workflows/transition.md +544 -544
- package/ez-agents/workflows/ui-phase.md +290 -290
- package/ez-agents/workflows/ui-review.md +157 -157
- package/ez-agents/workflows/update.md +320 -320
- package/ez-agents/workflows/validate-phase.md +167 -167
- package/ez-agents/workflows/verify-phase.md +243 -243
- package/ez-agents/workflows/verify-work.md +584 -584
- package/package.json +10 -4
- package/scripts/build-hooks.js +43 -43
- package/scripts/run-tests.cjs +29 -29
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Lockfile Validator — Validate package manager lockfiles
|
|
5
|
+
*
|
|
6
|
+
* Validates lockfile integrity for npm, yarn, and pnpm:
|
|
7
|
+
* - npm: package-lock.json (JSON format with lockfileVersion)
|
|
8
|
+
* - yarn: yarn.lock (YAML-like format with metadata header)
|
|
9
|
+
* - pnpm: pnpm-lock.yaml (YAML format with lockfileVersion)
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* const LockfileValidator = require('./lockfile-validator.cjs');
|
|
13
|
+
* const validator = new LockfileValidator(cwd);
|
|
14
|
+
* const result = validator.validate('npm');
|
|
15
|
+
* // Returns: { valid, reason, lockfileVersion?, packageCount? }
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const fs = require('fs');
|
|
19
|
+
const path = require('path');
|
|
20
|
+
const Logger = require('./logger.cjs');
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Lockfile Validator class
|
|
24
|
+
* Validates lockfile integrity for different package managers
|
|
25
|
+
*/
|
|
26
|
+
class LockfileValidator {
|
|
27
|
+
/**
|
|
28
|
+
* Create a LockfileValidator instance
|
|
29
|
+
* @param {string} cwd - Working directory (default: process.cwd())
|
|
30
|
+
*/
|
|
31
|
+
constructor(cwd = process.cwd()) {
|
|
32
|
+
this.cwd = cwd;
|
|
33
|
+
this.logger = new Logger();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Validate lockfile for a specific package manager
|
|
38
|
+
* @param {string} manager - Package manager name ('npm', 'yarn', or 'pnpm')
|
|
39
|
+
* @returns {Object} Validation result
|
|
40
|
+
* - {boolean} valid - Whether lockfile is valid
|
|
41
|
+
* - {string} reason - Reason code if invalid
|
|
42
|
+
* - {string} message - Human-readable message if invalid
|
|
43
|
+
* - {number} lockfileVersion - Lockfile version (if valid)
|
|
44
|
+
* - {number} packageCount - Number of packages (if valid)
|
|
45
|
+
*/
|
|
46
|
+
validate(manager) {
|
|
47
|
+
const lockfilePath = this.getLockfilePath(manager);
|
|
48
|
+
|
|
49
|
+
this.logger.debug('Validating lockfile', {
|
|
50
|
+
manager,
|
|
51
|
+
lockfilePath,
|
|
52
|
+
cwd: this.cwd
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Check file existence
|
|
56
|
+
if (!fs.existsSync(lockfilePath)) {
|
|
57
|
+
this.logger.debug('Lockfile not found', { lockfilePath });
|
|
58
|
+
return {
|
|
59
|
+
valid: false,
|
|
60
|
+
reason: 'lockfile_missing',
|
|
61
|
+
message: `No ${path.basename(lockfilePath)} found`
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
const content = fs.readFileSync(lockfilePath, 'utf-8');
|
|
67
|
+
|
|
68
|
+
switch (manager) {
|
|
69
|
+
case 'npm':
|
|
70
|
+
return this.validateNpmLockfile(content);
|
|
71
|
+
case 'yarn':
|
|
72
|
+
return this.validateYarnLockfile(content);
|
|
73
|
+
case 'pnpm':
|
|
74
|
+
return this.validatePnpmLockfile(content);
|
|
75
|
+
default:
|
|
76
|
+
return {
|
|
77
|
+
valid: false,
|
|
78
|
+
reason: 'unknown_manager',
|
|
79
|
+
message: `Unknown package manager: ${manager}`
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
} catch (err) {
|
|
83
|
+
this.logger.error('Lockfile read error', {
|
|
84
|
+
manager,
|
|
85
|
+
lockfilePath,
|
|
86
|
+
error: err.message
|
|
87
|
+
});
|
|
88
|
+
return {
|
|
89
|
+
valid: false,
|
|
90
|
+
reason: 'read_error',
|
|
91
|
+
message: err.message
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Validate npm lockfile (package-lock.json)
|
|
98
|
+
* @param {string} content - Lockfile content
|
|
99
|
+
* @returns {Object} Validation result
|
|
100
|
+
*/
|
|
101
|
+
validateNpmLockfile(content) {
|
|
102
|
+
try {
|
|
103
|
+
const lockfile = JSON.parse(content);
|
|
104
|
+
|
|
105
|
+
// Check required fields
|
|
106
|
+
if (!lockfile.lockfileVersion) {
|
|
107
|
+
return {
|
|
108
|
+
valid: false,
|
|
109
|
+
reason: 'invalid_format',
|
|
110
|
+
message: 'Missing lockfileVersion field'
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (!lockfile.packages && !lockfile.dependencies) {
|
|
115
|
+
return {
|
|
116
|
+
valid: false,
|
|
117
|
+
reason: 'empty_lockfile',
|
|
118
|
+
message: 'Lockfile has no dependencies'
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const packageCount = Object.keys(lockfile.packages || lockfile.dependencies || {}).length;
|
|
123
|
+
|
|
124
|
+
this.logger.debug('npm lockfile valid', {
|
|
125
|
+
lockfileVersion: lockfile.lockfileVersion,
|
|
126
|
+
packageCount
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
valid: true,
|
|
131
|
+
lockfileVersion: lockfile.lockfileVersion,
|
|
132
|
+
packageCount
|
|
133
|
+
};
|
|
134
|
+
} catch (err) {
|
|
135
|
+
this.logger.debug('npm lockfile invalid JSON', { error: err.message });
|
|
136
|
+
return {
|
|
137
|
+
valid: false,
|
|
138
|
+
reason: 'invalid_json',
|
|
139
|
+
message: `Invalid JSON: ${err.message}`
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Validate yarn lockfile (yarn.lock)
|
|
146
|
+
* @param {string} content - Lockfile content
|
|
147
|
+
* @returns {Object} Validation result
|
|
148
|
+
*/
|
|
149
|
+
validateYarnLockfile(content) {
|
|
150
|
+
// Yarn lockfile is YAML-like format
|
|
151
|
+
// Check for basic structure: __metadata__ (Yarn 2+) or "# yarn lockfile v" (Yarn 1)
|
|
152
|
+
const hasYarn2Metadata = content.includes('__metadata:');
|
|
153
|
+
const hasYarn1Header = content.match(/^# yarn lockfile v/i);
|
|
154
|
+
|
|
155
|
+
if (!hasYarn2Metadata && !hasYarn1Header) {
|
|
156
|
+
this.logger.debug('yarn lockfile invalid format');
|
|
157
|
+
return {
|
|
158
|
+
valid: false,
|
|
159
|
+
reason: 'invalid_format',
|
|
160
|
+
message: 'Invalid yarn.lock format'
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Count dependency entries (lines starting with package name pattern)
|
|
165
|
+
const entryCount = (content.match(/^"?[^@\s]+@/gm) || []).length;
|
|
166
|
+
|
|
167
|
+
this.logger.debug('yarn lockfile valid', {
|
|
168
|
+
version: hasYarn2Metadata ? '2+' : '1',
|
|
169
|
+
entryCount
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
valid: true,
|
|
174
|
+
entryCount
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Validate pnpm lockfile (pnpm-lock.yaml)
|
|
180
|
+
* @param {string} content - Lockfile content
|
|
181
|
+
* @returns {Object} Validation result
|
|
182
|
+
*/
|
|
183
|
+
validatePnpmLockfile(content) {
|
|
184
|
+
// Check for lockfileVersion
|
|
185
|
+
const versionMatch = content.match(/^lockfileVersion:\s*(\d+)/m);
|
|
186
|
+
if (!versionMatch) {
|
|
187
|
+
this.logger.debug('pnpm lockfile missing lockfileVersion');
|
|
188
|
+
return {
|
|
189
|
+
valid: false,
|
|
190
|
+
reason: 'invalid_format',
|
|
191
|
+
message: 'Missing lockfileVersion in pnpm-lock.yaml'
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const lockfileVersion = parseInt(versionMatch[1], 10);
|
|
196
|
+
|
|
197
|
+
// Count dependency entries (lines starting with " /" which are package specs)
|
|
198
|
+
const entryCount = (content.match(/^ \/[^:]+:/gm) || []).length;
|
|
199
|
+
|
|
200
|
+
this.logger.debug('pnpm lockfile valid', {
|
|
201
|
+
lockfileVersion,
|
|
202
|
+
entryCount
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
valid: true,
|
|
207
|
+
lockfileVersion,
|
|
208
|
+
entryCount
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Get the lockfile path for a specific package manager
|
|
214
|
+
* @param {string} manager - Package manager name
|
|
215
|
+
* @returns {string} Full path to lockfile
|
|
216
|
+
*/
|
|
217
|
+
getLockfilePath(manager) {
|
|
218
|
+
const lockfiles = {
|
|
219
|
+
'npm': 'package-lock.json',
|
|
220
|
+
'yarn': 'yarn.lock',
|
|
221
|
+
'pnpm': 'pnpm-lock.yaml'
|
|
222
|
+
};
|
|
223
|
+
return path.join(this.cwd, lockfiles[manager] || 'package-lock.json');
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
module.exports = LockfileValidator;
|
|
@@ -1,124 +1,124 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* EZ Logger — Centralized logging module for EZ workflow
|
|
5
|
-
*
|
|
6
|
-
* Provides structured logging with levels (ERROR, WARN, INFO, DEBUG)
|
|
7
|
-
* Writes to .planning/logs/ez-{timestamp}.log
|
|
8
|
-
* Replaces silent catch {} blocks with proper error logging
|
|
9
|
-
*
|
|
10
|
-
* Usage:
|
|
11
|
-
* const Logger = require('./logger.cjs');
|
|
12
|
-
* const logger = new Logger();
|
|
13
|
-
* logger.error('Something failed', { context: 'details' });
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
const fs = require('fs');
|
|
17
|
-
const path = require('path');
|
|
18
|
-
|
|
19
|
-
class Logger {
|
|
20
|
-
/**
|
|
21
|
-
* Create a Logger instance
|
|
22
|
-
* @param {string} logDir - Directory for log files (default: .planning/logs)
|
|
23
|
-
*/
|
|
24
|
-
constructor(logDir = '.planning/logs') {
|
|
25
|
-
this.logDir = logDir;
|
|
26
|
-
this.logFile = null;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Ensure log directory exists and initialize log file
|
|
31
|
-
*/
|
|
32
|
-
_ensureLogDir() {
|
|
33
|
-
if (!fs.existsSync(this.logDir)) {
|
|
34
|
-
fs.mkdirSync(this.logDir, { recursive: true });
|
|
35
|
-
}
|
|
36
|
-
this.logFile = path.join(this.logDir, `ez-${Date.now()}.log`);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Get current log file path
|
|
41
|
-
* @returns {string} - Path to log file
|
|
42
|
-
*/
|
|
43
|
-
getLogFile() {
|
|
44
|
-
if (!this.logFile) {
|
|
45
|
-
this._ensureLogDir();
|
|
46
|
-
}
|
|
47
|
-
return this.logFile;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Write a log entry
|
|
52
|
-
* @param {string} level - Log level (ERROR, WARN, INFO, DEBUG)
|
|
53
|
-
* @param {string} message - Log message
|
|
54
|
-
* @param {Object} context - Additional context data
|
|
55
|
-
*/
|
|
56
|
-
log(level, message, context = {}) {
|
|
57
|
-
// Ensure log directory exists before first write
|
|
58
|
-
if (!this.logFile) {
|
|
59
|
-
this._ensureLogDir();
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const entry = {
|
|
63
|
-
timestamp: new Date().toISOString(),
|
|
64
|
-
level,
|
|
65
|
-
message,
|
|
66
|
-
context,
|
|
67
|
-
pid: process.pid
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
try {
|
|
71
|
-
fs.appendFileSync(this.logFile, JSON.stringify(entry) + '\n');
|
|
72
|
-
|
|
73
|
-
// Always output ERROR level to console for visibility
|
|
74
|
-
if (level === 'ERROR') {
|
|
75
|
-
console.error(`[EZ ${level}] ${message}`);
|
|
76
|
-
}
|
|
77
|
-
} catch (err) {
|
|
78
|
-
// Fallback: log to console if file write fails
|
|
79
|
-
console.error(`[EZ ${level}] ${message} (file write failed: ${err.message})`);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Log an ERROR level message
|
|
85
|
-
* @param {string} msg - Error message
|
|
86
|
-
* @param {Object} ctx - Additional context
|
|
87
|
-
*/
|
|
88
|
-
error(msg, ctx) {
|
|
89
|
-
this.log('ERROR', msg, ctx);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Log a WARN level message
|
|
94
|
-
* @param {string} msg - Warning message
|
|
95
|
-
* @param {Object} ctx - Additional context
|
|
96
|
-
*/
|
|
97
|
-
warn(msg, ctx) {
|
|
98
|
-
this.log('WARN', msg, ctx);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Log an INFO level message
|
|
103
|
-
* @param {string} msg - Info message
|
|
104
|
-
* @param {Object} ctx - Additional context
|
|
105
|
-
*/
|
|
106
|
-
info(msg, ctx) {
|
|
107
|
-
this.log('INFO', msg, ctx);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Log a DEBUG level message
|
|
112
|
-
* @param {string} msg - Debug message
|
|
113
|
-
* @param {Object} ctx - Additional context
|
|
114
|
-
*/
|
|
115
|
-
debug(msg, ctx) {
|
|
116
|
-
this.log('DEBUG', msg, ctx);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Singleton instance for default usage
|
|
121
|
-
const defaultLogger = new Logger();
|
|
122
|
-
|
|
123
|
-
module.exports = Logger;
|
|
124
|
-
module.exports.defaultLogger = defaultLogger;
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* EZ Logger — Centralized logging module for EZ workflow
|
|
5
|
+
*
|
|
6
|
+
* Provides structured logging with levels (ERROR, WARN, INFO, DEBUG)
|
|
7
|
+
* Writes to .planning/logs/ez-{timestamp}.log
|
|
8
|
+
* Replaces silent catch {} blocks with proper error logging
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* const Logger = require('./logger.cjs');
|
|
12
|
+
* const logger = new Logger();
|
|
13
|
+
* logger.error('Something failed', { context: 'details' });
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
|
|
19
|
+
class Logger {
|
|
20
|
+
/**
|
|
21
|
+
* Create a Logger instance
|
|
22
|
+
* @param {string} logDir - Directory for log files (default: .planning/logs)
|
|
23
|
+
*/
|
|
24
|
+
constructor(logDir = '.planning/logs') {
|
|
25
|
+
this.logDir = logDir;
|
|
26
|
+
this.logFile = null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Ensure log directory exists and initialize log file
|
|
31
|
+
*/
|
|
32
|
+
_ensureLogDir() {
|
|
33
|
+
if (!fs.existsSync(this.logDir)) {
|
|
34
|
+
fs.mkdirSync(this.logDir, { recursive: true });
|
|
35
|
+
}
|
|
36
|
+
this.logFile = path.join(this.logDir, `ez-${Date.now()}.log`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Get current log file path
|
|
41
|
+
* @returns {string} - Path to log file
|
|
42
|
+
*/
|
|
43
|
+
getLogFile() {
|
|
44
|
+
if (!this.logFile) {
|
|
45
|
+
this._ensureLogDir();
|
|
46
|
+
}
|
|
47
|
+
return this.logFile;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Write a log entry
|
|
52
|
+
* @param {string} level - Log level (ERROR, WARN, INFO, DEBUG)
|
|
53
|
+
* @param {string} message - Log message
|
|
54
|
+
* @param {Object} context - Additional context data
|
|
55
|
+
*/
|
|
56
|
+
log(level, message, context = {}) {
|
|
57
|
+
// Ensure log directory exists before first write
|
|
58
|
+
if (!this.logFile) {
|
|
59
|
+
this._ensureLogDir();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const entry = {
|
|
63
|
+
timestamp: new Date().toISOString(),
|
|
64
|
+
level,
|
|
65
|
+
message,
|
|
66
|
+
context,
|
|
67
|
+
pid: process.pid
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
fs.appendFileSync(this.logFile, JSON.stringify(entry) + '\n');
|
|
72
|
+
|
|
73
|
+
// Always output ERROR level to console for visibility
|
|
74
|
+
if (level === 'ERROR') {
|
|
75
|
+
console.error(`[EZ ${level}] ${message}`);
|
|
76
|
+
}
|
|
77
|
+
} catch (err) {
|
|
78
|
+
// Fallback: log to console if file write fails
|
|
79
|
+
console.error(`[EZ ${level}] ${message} (file write failed: ${err.message})`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Log an ERROR level message
|
|
85
|
+
* @param {string} msg - Error message
|
|
86
|
+
* @param {Object} ctx - Additional context
|
|
87
|
+
*/
|
|
88
|
+
error(msg, ctx) {
|
|
89
|
+
this.log('ERROR', msg, ctx);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Log a WARN level message
|
|
94
|
+
* @param {string} msg - Warning message
|
|
95
|
+
* @param {Object} ctx - Additional context
|
|
96
|
+
*/
|
|
97
|
+
warn(msg, ctx) {
|
|
98
|
+
this.log('WARN', msg, ctx);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Log an INFO level message
|
|
103
|
+
* @param {string} msg - Info message
|
|
104
|
+
* @param {Object} ctx - Additional context
|
|
105
|
+
*/
|
|
106
|
+
info(msg, ctx) {
|
|
107
|
+
this.log('INFO', msg, ctx);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Log a DEBUG level message
|
|
112
|
+
* @param {string} msg - Debug message
|
|
113
|
+
* @param {Object} ctx - Additional context
|
|
114
|
+
*/
|
|
115
|
+
debug(msg, ctx) {
|
|
116
|
+
this.log('DEBUG', msg, ctx);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Singleton instance for default usage
|
|
121
|
+
const defaultLogger = new Logger();
|
|
122
|
+
|
|
123
|
+
module.exports = Logger;
|
|
124
|
+
module.exports.defaultLogger = defaultLogger;
|