@howlil/ez-agents 3.5.0 → 4.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.
- package/README.md +735 -537
- package/agents/ez-architect-agent.md +267 -0
- package/agents/ez-backend-agent.md +303 -0
- package/agents/ez-chief-strategist.md +271 -0
- package/agents/ez-codebase-mapper.md +770 -770
- package/agents/ez-context-manager.md +319 -0
- package/agents/ez-debugger.md +1255 -1255
- package/agents/ez-design-expert.md +347 -0
- package/agents/ez-devops-agent.md +331 -0
- package/agents/ez-executor.md +487 -487
- package/agents/ez-frontend-agent.md +322 -0
- package/agents/ez-phase-researcher.md +553 -553
- package/agents/ez-planner.md +1307 -1307
- package/agents/ez-product-engineer.md +435 -0
- package/agents/ez-project-researcher.md +629 -629
- package/agents/ez-qa-agent.md +320 -0
- package/agents/ez-release-agent.md +333 -333
- package/agents/ez-requirements-agent.md +377 -377
- package/agents/ez-roadmapper.md +650 -650
- package/agents/ez-technical-writer.md +551 -0
- package/agents/ez-ux-expert.md +393 -0
- package/agents/ez-verifier.md +579 -579
- package/bin/guards/autonomy-guard.cjs +346 -0
- package/bin/guards/context-budget-guard.cjs +278 -0
- package/bin/guards/hallucination-guard.cjs +380 -0
- package/bin/guards/hidden-state-guard.cjs +182 -0
- package/bin/guards/team-overhead-guard.cjs +266 -0
- package/bin/guards/tool-sprawl-guard.cjs +271 -0
- package/bin/lib/analytics/analytics-collector.cjs +86 -0
- package/bin/lib/analytics/analytics-reporter.cjs +130 -0
- package/bin/lib/analytics/cohort-analyzer.cjs +138 -0
- package/bin/lib/analytics/funnel-analyzer.cjs +147 -0
- package/bin/lib/analytics/nps-tracker.cjs +147 -0
- package/bin/lib/archetype-detector.cjs +289 -0
- package/bin/lib/assistant-adapter.cjs +361 -0
- package/bin/lib/audit-exec.cjs +175 -0
- package/bin/lib/auth.cjs +176 -0
- package/bin/lib/backup-service.cjs +422 -0
- package/bin/lib/bdd-validator.cjs +622 -0
- package/bin/lib/business-flow-mapper.cjs +429 -0
- package/bin/lib/circuit-breaker.cjs +276 -0
- package/bin/lib/code-complexity-analyzer.cjs +360 -0
- package/bin/lib/codebase-analyzer.cjs +241 -0
- package/bin/lib/commands.cjs +691 -0
- package/bin/lib/config.cjs +236 -0
- package/bin/lib/constraint-extractor.cjs +526 -0
- package/bin/lib/content-scanner.cjs +238 -0
- package/bin/lib/context-cache.cjs +154 -0
- package/bin/lib/context-compressor.cjs +102 -0
- package/bin/lib/context-deduplicator.cjs +105 -0
- package/bin/lib/context-errors.cjs +78 -0
- package/bin/lib/context-manager.cjs +338 -0
- package/bin/lib/context-metadata-tracker.cjs +140 -0
- package/bin/lib/context-relevance-scorer.cjs +99 -0
- package/bin/lib/core.cjs +507 -0
- package/bin/lib/cost-alerts.cjs +174 -0
- package/bin/lib/cost-tracker.cjs +275 -0
- package/bin/lib/crash-recovery.cjs +220 -0
- package/bin/lib/dependency-graph.cjs +319 -0
- package/bin/lib/deploy/deploy-audit-log.cjs +76 -0
- package/bin/lib/deploy/deploy-detector.cjs +69 -0
- package/bin/lib/deploy/deploy-env-manager.cjs +109 -0
- package/bin/lib/deploy/deploy-health-check.cjs +88 -0
- package/bin/lib/deploy/deploy-pre-flight.cjs +57 -0
- package/bin/lib/deploy/deploy-rollback.cjs +72 -0
- package/bin/lib/deploy/deploy-runner.cjs +97 -0
- package/bin/lib/deploy/deploy-status.cjs +74 -0
- package/bin/lib/discussion-synthesizer.cjs +439 -0
- package/bin/lib/error-cache.cjs +114 -0
- package/bin/lib/error-registry.cjs +177 -0
- package/bin/lib/file-access.cjs +207 -0
- package/bin/lib/file-lock.cjs +236 -0
- package/bin/lib/finops/budget-enforcer.cjs +126 -0
- package/bin/lib/finops/cost-reporter.cjs +132 -0
- package/bin/lib/finops/finops-analyzer.cjs +112 -0
- package/bin/lib/finops/spot-manager.cjs +118 -0
- package/bin/lib/framework-detector.cjs +396 -0
- package/bin/lib/frontmatter.cjs +313 -0
- package/bin/lib/fs-utils.cjs +153 -0
- package/bin/lib/gate-executor.cjs +272 -0
- package/bin/lib/gates/README.md +374 -0
- package/bin/lib/gates/gate-01-requirement.cjs +303 -0
- package/bin/lib/gates/gate-02-architecture.cjs +555 -0
- package/bin/lib/gates/gate-03-code.cjs +635 -0
- package/bin/lib/gates/gate-04-security.cjs +829 -0
- package/bin/lib/git-errors.cjs +83 -0
- package/bin/lib/git-utils.cjs +321 -0
- package/bin/lib/git-workflow-engine.cjs +1157 -0
- package/bin/lib/health-check.cjs +227 -0
- package/bin/lib/index.cjs +279 -0
- package/bin/lib/init.cjs +725 -0
- package/bin/lib/lock-logger.cjs +194 -0
- package/bin/lib/lock-state.cjs +263 -0
- package/bin/lib/lockfile-validator.cjs +227 -0
- package/bin/lib/log-rotation.cjs +71 -0
- package/bin/lib/logger.cjs +125 -0
- package/bin/lib/memory-compression.cjs +256 -0
- package/bin/lib/milestone.cjs +247 -0
- package/bin/lib/model-provider.cjs +241 -0
- package/bin/lib/package-manager-detector.cjs +203 -0
- package/bin/lib/package-manager-executor.cjs +385 -0
- package/bin/lib/package-manager-service.cjs +216 -0
- package/bin/lib/perf/api-monitor.cjs +88 -0
- package/bin/lib/perf/db-optimizer.cjs +78 -0
- package/bin/lib/perf/frontend-performance.cjs +56 -0
- package/bin/lib/perf/perf-analyzer.cjs +77 -0
- package/bin/lib/perf/perf-baseline.cjs +102 -0
- package/bin/lib/perf/perf-reporter.cjs +117 -0
- package/bin/lib/perf/regression-detector.cjs +92 -0
- package/bin/lib/phase.cjs +963 -0
- package/bin/lib/planning-write.cjs +123 -0
- package/bin/lib/project-reporter.cjs +565 -0
- package/bin/lib/quality-gate.cjs +332 -0
- package/bin/lib/quality-metrics.cjs +324 -0
- package/bin/lib/recovery-manager.cjs +98 -0
- package/bin/lib/release-validator.cjs +617 -0
- package/bin/lib/retry.cjs +119 -0
- package/bin/lib/roadmap.cjs +309 -0
- package/bin/lib/safe-exec.cjs +173 -0
- package/bin/lib/safe-path.cjs +130 -0
- package/bin/lib/security-errors.cjs +62 -0
- package/bin/lib/session-chain.cjs +304 -0
- package/bin/lib/session-errors.cjs +81 -0
- package/bin/lib/session-export.cjs +251 -0
- package/bin/lib/session-import.cjs +262 -0
- package/bin/lib/session-manager.cjs +280 -0
- package/bin/lib/skill-context.cjs +148 -0
- package/bin/lib/skill-matcher.cjs +236 -0
- package/bin/lib/skill-registry.cjs +360 -0
- package/bin/lib/skill-resolver.cjs +449 -0
- package/bin/lib/skill-triggers.cjs +90 -0
- package/bin/lib/skill-validator.cjs +270 -0
- package/bin/lib/skill-versioning.cjs +355 -0
- package/bin/lib/stack-detector.cjs +399 -0
- package/bin/lib/state.cjs +736 -0
- package/bin/lib/tech-debt-analyzer.cjs +309 -0
- package/bin/lib/temp-file.cjs +239 -0
- package/bin/lib/template.cjs +223 -0
- package/bin/lib/test-file-lock.cjs +112 -0
- package/bin/lib/test-graceful.cjs +93 -0
- package/bin/lib/test-logger.cjs +60 -0
- package/bin/lib/test-safe-exec.cjs +38 -0
- package/bin/lib/test-safe-path.cjs +33 -0
- package/bin/lib/test-temp-file.cjs +125 -0
- package/bin/lib/tier-manager.cjs +428 -0
- package/bin/lib/timeout-exec.cjs +63 -0
- package/bin/lib/tradeoff-analyzer.cjs +284 -0
- package/bin/lib/url-fetch.cjs +170 -0
- package/bin/lib/verify.cjs +863 -0
- package/bin/update.js +217 -214
- package/commands/deploy.cjs +53 -0
- package/commands/ez/add-tests.md +41 -41
- package/commands/ez/audit-milestone.md +36 -36
- package/commands/ez/complete-milestone.md +136 -136
- package/commands/ez/discuss-phase.md +90 -90
- package/commands/ez/execute-phase.md +52 -52
- package/commands/ez/help.md +22 -22
- package/commands/ez/map-codebase.md +71 -71
- package/commands/ez/new-milestone.md +44 -44
- package/commands/ez/new-project.md +51 -42
- package/commands/ez/plan-phase.md +53 -53
- package/commands/ez/progress.md +36 -36
- package/commands/ez/quick.md +45 -45
- package/commands/ez/resume-work.md +40 -40
- package/commands/ez/run-phase.md +580 -0
- package/commands/ez/settings.md +36 -36
- package/commands/ez/update.md +37 -37
- package/commands/ez/verify-work.md +402 -38
- package/commands/health-check.cjs +44 -0
- package/commands/rollback.cjs +47 -0
- package/ez-agents/bin/ez-tools.cjs +599 -2
- package/ez-agents/bin/guards/autonomy-guard.cjs +346 -0
- package/ez-agents/bin/guards/context-budget-guard.cjs +247 -0
- package/ez-agents/bin/guards/hallucination-guard.cjs +271 -0
- package/ez-agents/bin/guards/hidden-state-guard.cjs +182 -0
- package/ez-agents/bin/guards/team-overhead-guard.cjs +266 -0
- package/ez-agents/bin/guards/tool-sprawl-guard.cjs +271 -0
- package/ez-agents/bin/lib/analytics/analytics-collector.cjs +86 -0
- package/ez-agents/bin/lib/analytics/analytics-reporter.cjs +130 -0
- package/ez-agents/bin/lib/analytics/cohort-analyzer.cjs +138 -0
- package/ez-agents/bin/lib/analytics/funnel-analyzer.cjs +147 -0
- package/ez-agents/bin/lib/analytics/nps-tracker.cjs +147 -0
- package/ez-agents/bin/lib/archetype-detector.cjs +289 -0
- package/ez-agents/bin/lib/audit-exec.cjs +166 -167
- package/ez-agents/bin/lib/auth.cjs +176 -176
- package/ez-agents/bin/lib/backup-service.cjs +422 -0
- package/ez-agents/bin/lib/bdd-validator.cjs +622 -622
- package/ez-agents/bin/lib/business-flow-mapper.cjs +429 -0
- package/ez-agents/bin/lib/code-complexity-analyzer.cjs +360 -0
- package/ez-agents/bin/lib/codebase-analyzer.cjs +241 -0
- package/ez-agents/bin/lib/commands.cjs +685 -685
- package/ez-agents/bin/lib/config.cjs +41 -1
- package/ez-agents/bin/lib/constraint-extractor.cjs +526 -0
- package/ez-agents/bin/lib/content-scanner.cjs +238 -238
- package/ez-agents/bin/lib/context-cache.cjs +154 -154
- package/ez-agents/bin/lib/context-errors.cjs +71 -71
- package/ez-agents/bin/lib/context-manager.cjs +220 -220
- package/ez-agents/bin/lib/core.cjs +507 -512
- package/ez-agents/bin/lib/cost-tracker.cjs +243 -0
- package/ez-agents/bin/lib/crash-recovery.cjs +172 -0
- package/ez-agents/bin/lib/dependency-graph.cjs +319 -0
- package/ez-agents/bin/lib/deploy/deploy-audit-log.cjs +76 -0
- package/ez-agents/bin/lib/deploy/deploy-detector.cjs +69 -0
- package/ez-agents/bin/lib/deploy/deploy-env-manager.cjs +109 -0
- package/ez-agents/bin/lib/deploy/deploy-health-check.cjs +88 -0
- package/ez-agents/bin/lib/deploy/deploy-pre-flight.cjs +57 -0
- package/ez-agents/bin/lib/deploy/deploy-rollback.cjs +72 -0
- package/ez-agents/bin/lib/deploy/deploy-runner.cjs +97 -0
- package/ez-agents/bin/lib/deploy/deploy-status.cjs +74 -0
- package/ez-agents/bin/lib/file-access.cjs +207 -207
- package/ez-agents/bin/lib/finops/budget-enforcer.cjs +126 -0
- package/ez-agents/bin/lib/finops/cost-reporter.cjs +132 -0
- package/ez-agents/bin/lib/finops/finops-analyzer.cjs +112 -0
- package/ez-agents/bin/lib/finops/spot-manager.cjs +118 -0
- package/ez-agents/bin/lib/framework-detector.cjs +396 -0
- package/ez-agents/bin/lib/frontmatter.cjs +3 -1
- package/ez-agents/bin/lib/gates/README.md +374 -0
- package/ez-agents/bin/lib/gates/gate-01-requirement.cjs +303 -0
- package/ez-agents/bin/lib/gates/gate-02-architecture.cjs +555 -0
- package/ez-agents/bin/lib/gates/gate-03-code.cjs +635 -0
- package/ez-agents/bin/lib/gates/gate-04-security.cjs +829 -0
- package/ez-agents/bin/lib/git-errors.cjs +83 -83
- package/ez-agents/bin/lib/git-utils.cjs +321 -321
- package/ez-agents/bin/lib/git-workflow-engine.cjs +1157 -1157
- package/ez-agents/bin/lib/health-check.cjs +162 -162
- package/ez-agents/bin/lib/index.cjs +2 -8
- package/ez-agents/bin/lib/init.cjs +0 -2
- package/ez-agents/bin/lib/lockfile-validator.cjs +227 -227
- package/ez-agents/bin/lib/log-rotation.cjs +71 -0
- package/ez-agents/bin/lib/logger.cjs +22 -47
- package/ez-agents/bin/lib/memory-compression.cjs +256 -256
- package/ez-agents/bin/lib/package-manager-detector.cjs +203 -203
- package/ez-agents/bin/lib/package-manager-executor.cjs +385 -385
- package/ez-agents/bin/lib/package-manager-service.cjs +216 -216
- package/ez-agents/bin/lib/perf/api-monitor.cjs +88 -0
- package/ez-agents/bin/lib/perf/db-optimizer.cjs +78 -0
- package/ez-agents/bin/lib/perf/frontend-performance.cjs +56 -0
- package/ez-agents/bin/lib/perf/perf-analyzer.cjs +77 -0
- package/ez-agents/bin/lib/perf/perf-baseline.cjs +102 -0
- package/ez-agents/bin/lib/perf/perf-reporter.cjs +117 -0
- package/ez-agents/bin/lib/perf/regression-detector.cjs +92 -0
- package/ez-agents/bin/lib/project-reporter.cjs +502 -0
- package/ez-agents/bin/lib/quality-gate.cjs +332 -0
- package/ez-agents/bin/lib/recovery-manager.cjs +98 -0
- package/ez-agents/bin/lib/release-validator.cjs +617 -614
- package/ez-agents/bin/lib/security-errors.cjs +62 -0
- package/ez-agents/bin/lib/session-chain.cjs +304 -304
- package/ez-agents/bin/lib/session-errors.cjs +81 -81
- package/ez-agents/bin/lib/session-export.cjs +251 -251
- package/ez-agents/bin/lib/session-import.cjs +262 -262
- package/ez-agents/bin/lib/session-manager.cjs +280 -280
- package/ez-agents/bin/lib/skill-context.cjs +148 -0
- package/ez-agents/bin/lib/skill-matcher.cjs +236 -0
- package/ez-agents/bin/lib/skill-registry.cjs +341 -0
- package/ez-agents/bin/lib/skill-resolver.cjs +449 -0
- package/ez-agents/bin/lib/skill-triggers.cjs +90 -0
- package/ez-agents/bin/lib/skill-validator.cjs +270 -0
- package/ez-agents/bin/lib/skill-versioning.cjs +355 -0
- package/ez-agents/bin/lib/stack-detector.cjs +399 -0
- package/ez-agents/bin/lib/tech-debt-analyzer.cjs +309 -0
- package/ez-agents/bin/lib/tier-manager.cjs +428 -428
- package/ez-agents/bin/lib/tradeoff-analyzer.cjs +284 -0
- package/ez-agents/bin/lib/url-fetch.cjs +170 -170
- package/ez-agents/bin/lib/verify.cjs +863 -863
- package/ez-agents/references/decimal-phase-calculation.md +65 -65
- package/ez-agents/references/git-integration.md +248 -248
- package/ez-agents/references/git-planning-commit.md +38 -38
- package/ez-agents/references/metrics-schema.md +118 -118
- package/ez-agents/references/model-profile-resolution.md +34 -34
- package/ez-agents/references/model-profiles.md +93 -93
- package/ez-agents/references/phase-argument-parsing.md +61 -61
- package/ez-agents/references/planning-config.md +340 -340
- package/ez-agents/references/tier-strategy.md +103 -103
- package/ez-agents/references/ui-brand.md +160 -160
- package/ez-agents/references/verification-patterns.md +612 -612
- package/ez-agents/templates/DEBUG.md +164 -164
- package/ez-agents/templates/UAT.md +247 -247
- package/ez-agents/templates/agent-output-format.md +404 -0
- package/ez-agents/templates/bdd-feature.md +173 -173
- package/ez-agents/templates/codebase/architecture.md +255 -255
- package/ez-agents/templates/codebase/structure.md +285 -285
- package/ez-agents/templates/copilot-instructions.md +7 -7
- package/ez-agents/templates/debug-subagent-prompt.md +91 -91
- package/ez-agents/templates/discovery.md +146 -146
- package/ez-agents/templates/discussion.md +68 -68
- package/ez-agents/templates/handoff-protocol.md +294 -0
- package/ez-agents/templates/incident-runbook.md +205 -205
- package/ez-agents/templates/mode-workflow-templates.md +301 -0
- package/ez-agents/templates/phase-prompt.md +610 -610
- package/ez-agents/templates/planner-subagent-prompt.md +117 -117
- package/ez-agents/templates/project.md +184 -184
- package/ez-agents/templates/release-checklist.md +136 -133
- package/ez-agents/templates/research.md +552 -552
- package/ez-agents/templates/rollback-plan.md +201 -201
- package/ez-agents/templates/security-user-setup.md +244 -0
- package/ez-agents/templates/skill-validation-rules.md +476 -0
- package/ez-agents/templates/state.md +180 -176
- package/ez-agents/templates/summary-complex.md +59 -59
- package/ez-agents/tests/gates/gate-01-02.test.cjs +812 -0
- package/ez-agents/tests/gates/gate-03-04.test.cjs +762 -0
- package/ez-agents/tests/gates/gate-05-validator.test.cjs +145 -0
- package/ez-agents/tests/gates/gate-06-docs-validator.test.cjs +244 -0
- package/ez-agents/tests/gates/gate-07-release-validator.test.cjs +219 -0
- package/ez-agents/tests/guards/context-budget-guard.test.cjs +145 -0
- package/ez-agents/tests/guards/edge-case-guards.test.cjs +238 -0
- package/ez-agents/tests/guards/hallucination-guard.test.cjs +124 -0
- package/ez-agents/workflows/audit-milestone.md +1 -1
- package/ez-agents/workflows/autonomous.md +844 -844
- package/ez-agents/workflows/complete-milestone.md +1 -1
- package/ez-agents/workflows/discuss-phase.md +1 -1
- package/ez-agents/workflows/execute-phase.md +124 -3
- package/ez-agents/workflows/help.md +42 -181
- package/ez-agents/workflows/hotfix.md +291 -291
- package/ez-agents/workflows/new-milestone.md +713 -713
- package/ez-agents/workflows/new-project.md +1089 -1107
- package/ez-agents/workflows/plan-phase.md +0 -40
- package/ez-agents/workflows/release.md +253 -253
- package/ez-agents/workflows/resume-session.md +215 -215
- package/ez-agents/workflows/run-phase.md +531 -0
- package/ez-agents/workflows/settings.md +2 -35
- package/hooks/dist/ez-check-update.js +81 -81
- package/hooks/dist/ez-context-monitor.js +148 -141
- package/hooks/dist/ez-statusline.js +115 -115
- package/package.json +78 -71
- package/scripts/fix-qwen-installation.js +144 -144
- package/agents/ez-integration-checker.md +0 -443
- package/agents/ez-nyquist-auditor.md +0 -176
- package/agents/ez-observer-agent.md +0 -260
- package/agents/ez-plan-checker.md +0 -706
- package/agents/ez-research-synthesizer.md +0 -247
- package/agents/ez-scrum-master-agent.md +0 -242
- package/agents/ez-tech-lead-agent.md +0 -267
- package/agents/ez-ui-auditor.md +0 -439
- package/agents/ez-ui-checker.md +0 -300
- package/agents/ez-ui-researcher.md +0 -353
- package/commands/ez/add-phase.md +0 -43
- package/commands/ez/add-todo.md +0 -47
- package/commands/ez/arch-review.md +0 -102
- package/commands/ez/auth.md +0 -87
- package/commands/ez/autonomous.md +0 -41
- package/commands/ez/check-todos.md +0 -45
- package/commands/ez/cleanup.md +0 -18
- package/commands/ez/debug.md +0 -168
- package/commands/ez/export-session.md +0 -79
- package/commands/ez/gather-requirements.md +0 -117
- package/commands/ez/git-workflow.md +0 -72
- package/commands/ez/health.md +0 -22
- package/commands/ez/hotfix.md +0 -120
- package/commands/ez/import-session.md +0 -82
- package/commands/ez/insert-phase.md +0 -32
- package/commands/ez/join-discord.md +0 -18
- package/commands/ez/list-phase-assumptions.md +0 -46
- package/commands/ez/list-sessions.md +0 -96
- package/commands/ez/package-manager.md +0 -316
- package/commands/ez/pause-work.md +0 -38
- package/commands/ez/plan-milestone-gaps.md +0 -34
- package/commands/ez/preflight.md +0 -79
- package/commands/ez/reapply-patches.md +0 -124
- package/commands/ez/release.md +0 -153
- package/commands/ez/remove-phase.md +0 -31
- package/commands/ez/research-phase.md +0 -190
- package/commands/ez/resume.md +0 -107
- package/commands/ez/set-profile.md +0 -34
- package/commands/ez/standup.md +0 -85
- package/commands/ez/stats.md +0 -18
- package/commands/ez/ui-phase.md +0 -34
- package/commands/ez/ui-review.md +0 -32
- package/commands/ez/validate-phase.md +0 -35
- package/ez-agents/bin/lib/metrics-tracker.cjs +0 -406
- package/ez-agents/templates/UI-SPEC.md +0 -100
- package/ez-agents/templates/VALIDATION.md +0 -76
- package/ez-agents/templates/context.md +0 -352
- package/ez-agents/templates/verification-report.md +0 -322
- package/ez-agents/workflows/arch-review.md +0 -54
- package/ez-agents/workflows/export-session.md +0 -255
- package/ez-agents/workflows/gather-requirements.md +0 -206
- package/ez-agents/workflows/import-session.md +0 -303
- package/ez-agents/workflows/research-phase.md +0 -74
- package/ez-agents/workflows/standup.md +0 -64
- package/ez-agents/workflows/ui-phase.md +0 -290
- package/ez-agents/workflows/ui-review.md +0 -157
- package/ez-agents/workflows/validate-phase.md +0 -167
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Planning Write — lock/temp-safe writer for .planning mutations
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const os = require('os');
|
|
8
|
+
const { Worker } = require('worker_threads');
|
|
9
|
+
const { withLock } = require('./file-lock.cjs');
|
|
10
|
+
const { createTempFile, cleanupTemp } = require('./temp-file.cjs');
|
|
11
|
+
|
|
12
|
+
function normalizeTimeoutError(err, filePath) {
|
|
13
|
+
if (!err) return err;
|
|
14
|
+
const message = err.message || '';
|
|
15
|
+
if (message.includes('File locked:')) {
|
|
16
|
+
return err;
|
|
17
|
+
}
|
|
18
|
+
if (message.includes('timed out') || err.code === 'ELOCKED') {
|
|
19
|
+
return new Error(`File locked: ${filePath}`);
|
|
20
|
+
}
|
|
21
|
+
return err;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function safePlanningWrite(filePath, content, options = {}) {
|
|
25
|
+
const {
|
|
26
|
+
timeoutMs = 30000,
|
|
27
|
+
tempPrefix = 'ez-write-',
|
|
28
|
+
} = options;
|
|
29
|
+
|
|
30
|
+
let tempPath = null;
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
await withLock(filePath, async () => {
|
|
34
|
+
tempPath = await createTempFile(tempPrefix, path.dirname(filePath), content);
|
|
35
|
+
await fs.promises.rename(tempPath, filePath);
|
|
36
|
+
}, { timeout: timeoutMs });
|
|
37
|
+
} catch (err) {
|
|
38
|
+
throw normalizeTimeoutError(err, filePath);
|
|
39
|
+
} finally {
|
|
40
|
+
if (tempPath) {
|
|
41
|
+
try {
|
|
42
|
+
await cleanupTemp(tempPath);
|
|
43
|
+
} catch (err) {
|
|
44
|
+
const { defaultLogger: logger } = require('./logger.cjs');
|
|
45
|
+
logger.debug('Temp file cleanup failed', { tempPath, error: err.message });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function safePlanningWriteSync(filePath, content, options = {}) {
|
|
52
|
+
const signalBuffer = new SharedArrayBuffer(4);
|
|
53
|
+
const signal = new Int32Array(signalBuffer);
|
|
54
|
+
const errorPath = path.join(os.tmpdir(), `ez-planning-write-error-${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}.log`);
|
|
55
|
+
const modulePath = __filename;
|
|
56
|
+
|
|
57
|
+
const workerCode = `
|
|
58
|
+
const fs = require('fs');
|
|
59
|
+
const { workerData } = require('worker_threads');
|
|
60
|
+
const signal = new Int32Array(workerData.signalBuffer);
|
|
61
|
+
const { safePlanningWrite } = require(workerData.modulePath);
|
|
62
|
+
(async () => {
|
|
63
|
+
try {
|
|
64
|
+
await safePlanningWrite(workerData.filePath, workerData.content, workerData.options);
|
|
65
|
+
Atomics.store(signal, 0, 1);
|
|
66
|
+
} catch (err) {
|
|
67
|
+
try {
|
|
68
|
+
fs.writeFileSync(workerData.errorPath, err && (err.stack || err.message) ? (err.stack || err.message) : String(err), 'utf-8');
|
|
69
|
+
} catch (writeErr) {
|
|
70
|
+
const { defaultLogger: logger } = require('./logger.cjs');
|
|
71
|
+
logger.debug('Failed to write worker error log', { errorPath: workerData.errorPath, error: writeErr.message });
|
|
72
|
+
}
|
|
73
|
+
Atomics.store(signal, 0, 2);
|
|
74
|
+
} finally {
|
|
75
|
+
Atomics.notify(signal, 0);
|
|
76
|
+
}
|
|
77
|
+
})();
|
|
78
|
+
`;
|
|
79
|
+
|
|
80
|
+
const worker = new Worker(workerCode, {
|
|
81
|
+
eval: true,
|
|
82
|
+
workerData: { modulePath, filePath, content, options, signalBuffer, errorPath },
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
while (Atomics.load(signal, 0) === 0) {
|
|
87
|
+
Atomics.wait(signal, 0, 0, 100);
|
|
88
|
+
}
|
|
89
|
+
} finally {
|
|
90
|
+
worker.terminate().catch(err => {
|
|
91
|
+
const { defaultLogger: logger } = require('./logger.cjs');
|
|
92
|
+
logger.debug('Worker termination failed', { error: err.message });
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const status = Atomics.load(signal, 0);
|
|
97
|
+
if (status === 2) {
|
|
98
|
+
let message = \`safePlanningWriteSync failed for \${filePath}\`;
|
|
99
|
+
try {
|
|
100
|
+
if (fs.existsSync(errorPath)) {
|
|
101
|
+
message = fs.readFileSync(errorPath, 'utf-8') || message;
|
|
102
|
+
}
|
|
103
|
+
} catch (err) {
|
|
104
|
+
const { defaultLogger: logger } = require('./logger.cjs');
|
|
105
|
+
logger.debug('Failed to read worker error log', { errorPath, error: err.message });
|
|
106
|
+
}
|
|
107
|
+
try { fs.rmSync(errorPath, { force: true }); } catch (err) {
|
|
108
|
+
const { defaultLogger: logger } = require('./logger.cjs');
|
|
109
|
+
logger.debug('Failed to cleanup worker error log', { errorPath, error: err.message });
|
|
110
|
+
}
|
|
111
|
+
throw new Error(message);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
try { fs.rmSync(errorPath, { force: true }); } catch (err) {
|
|
115
|
+
const { defaultLogger: logger } = require('./logger.cjs');
|
|
116
|
+
logger.debug('Failed to cleanup worker error log', { errorPath, error: err.message });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
module.exports = {
|
|
121
|
+
safePlanningWrite,
|
|
122
|
+
safePlanningWriteSync,
|
|
123
|
+
};
|
|
@@ -0,0 +1,565 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project Reporter — Aggregates codebase analysis into comprehensive reports
|
|
3
|
+
*
|
|
4
|
+
* Provides:
|
|
5
|
+
* - generate(structure, stack, techDebt): Aggregates all analysis into unified report
|
|
6
|
+
* - buildArchitectureOverview(structure, stack): Creates architecture summary section
|
|
7
|
+
* - buildPainPoints(techDebt): Creates prioritized issues section
|
|
8
|
+
* - buildRecommendations(techDebt, stack): Creates actionable recommendations section
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const path = require('path');
|
|
12
|
+
|
|
13
|
+
class ProjectReporter {
|
|
14
|
+
constructor(rootPath) {
|
|
15
|
+
this.rootPath = rootPath;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Generate comprehensive project report
|
|
20
|
+
* @param {object} structure - Structure from CodebaseAnalyzer
|
|
21
|
+
* @param {object} stack - Stack from StackDetector
|
|
22
|
+
* @param {object} techDebt - Tech debt from TechDebtAnalyzer
|
|
23
|
+
* @param {object} archetype - Archetype from ArchetypeDetector
|
|
24
|
+
* @returns {string} Complete markdown report
|
|
25
|
+
*/
|
|
26
|
+
generate(structure, stack, techDebt, archetype) {
|
|
27
|
+
const sections = [
|
|
28
|
+
this._buildHeader(),
|
|
29
|
+
this.buildArchitectureOverview(structure, stack, archetype),
|
|
30
|
+
this.buildFileStructureSummary(structure),
|
|
31
|
+
this.buildTechStackSummary(stack),
|
|
32
|
+
this.buildPainPoints(techDebt),
|
|
33
|
+
this.buildRecommendations(techDebt, stack, archetype),
|
|
34
|
+
this._buildFooter()
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
return sections.filter(Boolean).join('\n\n');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Build architecture overview section
|
|
42
|
+
* @param {object} structure - Structure from CodebaseAnalyzer
|
|
43
|
+
* @param {object} stack - Stack from StackDetector
|
|
44
|
+
* @param {object} archetype - Archetype from ArchetypeDetector
|
|
45
|
+
* @returns {string} Markdown section
|
|
46
|
+
*/
|
|
47
|
+
buildArchitectureOverview(structure, stack, archetype) {
|
|
48
|
+
const lines = ['## Architecture Overview', ''];
|
|
49
|
+
|
|
50
|
+
// Pattern
|
|
51
|
+
lines.push('## Pattern');
|
|
52
|
+
if (archetype?.archetype) {
|
|
53
|
+
lines.push(`**${archetype.archetype}** — ${archetype.description || 'Detected project type'}`);
|
|
54
|
+
lines.push(`**Confidence:** ${archetype.level || 'Medium'} (${archetype.confidence || 0}%)`);
|
|
55
|
+
} else {
|
|
56
|
+
// Detect pattern from structure and stack
|
|
57
|
+
const pattern = this._detectPattern(structure, stack);
|
|
58
|
+
lines.push(`**${pattern}**`);
|
|
59
|
+
}
|
|
60
|
+
lines.push('');
|
|
61
|
+
|
|
62
|
+
// Layers
|
|
63
|
+
lines.push('## Layers');
|
|
64
|
+
const modules = structure?.modules || [];
|
|
65
|
+
if (modules.length > 0) {
|
|
66
|
+
const layerTypes = [...new Set(modules.map(m => m.type))];
|
|
67
|
+
for (const layerType of layerTypes) {
|
|
68
|
+
const layerModules = modules.filter(m => m.type === layerType);
|
|
69
|
+
lines.push(`- **${layerType}:** ${layerModules.length} module(s)`);
|
|
70
|
+
for (const mod of layerModules.slice(0, 5)) {
|
|
71
|
+
lines.push(` - \`${mod.path.replace(this.rootPath, '')}\` (${mod.fileCount} files)`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
} else {
|
|
75
|
+
lines.push('- Detected from directory structure');
|
|
76
|
+
const sourceDirs = structure?.sourceDirs || [];
|
|
77
|
+
for (const dir of sourceDirs.slice(0, 5)) {
|
|
78
|
+
lines.push(` - \`${dir.replace(this.rootPath, '')}\``);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
lines.push('');
|
|
82
|
+
|
|
83
|
+
// Data Flow
|
|
84
|
+
lines.push('## Data Flow');
|
|
85
|
+
lines.push('- Request → Controller/Route → Service → Model → Database');
|
|
86
|
+
lines.push('- Component → Hook/Context → API → State');
|
|
87
|
+
lines.push('');
|
|
88
|
+
|
|
89
|
+
// Entry Points
|
|
90
|
+
lines.push('## Entry Points');
|
|
91
|
+
const entryPoints = structure?.entryPoints || [];
|
|
92
|
+
if (entryPoints.length > 0) {
|
|
93
|
+
for (const entry of entryPoints.slice(0, 10)) {
|
|
94
|
+
lines.push(`- \`${entry.replace(this.rootPath, '')}\``);
|
|
95
|
+
}
|
|
96
|
+
} else {
|
|
97
|
+
lines.push('- No standard entry points detected');
|
|
98
|
+
}
|
|
99
|
+
lines.push('');
|
|
100
|
+
|
|
101
|
+
// Error Handling
|
|
102
|
+
lines.push('## Error Handling');
|
|
103
|
+
const hasErrorHandling = this._detectErrorHandling(stack);
|
|
104
|
+
if (hasErrorHandling) {
|
|
105
|
+
lines.push('- Error tracking: Sentry or similar detected');
|
|
106
|
+
lines.push('- Logging: Winston/Pino or similar detected');
|
|
107
|
+
} else {
|
|
108
|
+
lines.push('- Standard try/catch patterns expected');
|
|
109
|
+
lines.push('- Error boundaries in React components (if applicable)');
|
|
110
|
+
}
|
|
111
|
+
lines.push('');
|
|
112
|
+
|
|
113
|
+
return lines.join('\n');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Build file structure summary section
|
|
118
|
+
* @param {object} structure - Structure from CodebaseAnalyzer
|
|
119
|
+
* @returns {string} Markdown section
|
|
120
|
+
*/
|
|
121
|
+
buildFileStructureSummary(structure) {
|
|
122
|
+
const lines = ['## File Structure', ''];
|
|
123
|
+
|
|
124
|
+
const directories = structure?.directories || [];
|
|
125
|
+
const entryPoints = structure?.entryPoints || [];
|
|
126
|
+
const configFiles = structure?.configFiles || [];
|
|
127
|
+
const sourceDirs = structure?.sourceDirs || [];
|
|
128
|
+
const testDirs = structure?.testDirs || [];
|
|
129
|
+
|
|
130
|
+
// Directory tree (simplified)
|
|
131
|
+
lines.push('## Directory Layout');
|
|
132
|
+
lines.push('```');
|
|
133
|
+
lines.push('project/');
|
|
134
|
+
|
|
135
|
+
const rootDirs = directories.filter(d => d.depth === 1);
|
|
136
|
+
for (const dir of rootDirs.slice(0, 15)) {
|
|
137
|
+
const prefix = '├── ';
|
|
138
|
+
const name = path.basename(dir.path);
|
|
139
|
+
lines.push(`${prefix}${name}/`);
|
|
140
|
+
}
|
|
141
|
+
if (directories.length > 15) {
|
|
142
|
+
lines.push(`└── ... (${directories.length - 15} more directories)`);
|
|
143
|
+
}
|
|
144
|
+
lines.push('```');
|
|
145
|
+
lines.push('');
|
|
146
|
+
|
|
147
|
+
// Directory purposes
|
|
148
|
+
lines.push('## Directory Purposes');
|
|
149
|
+
for (const dir of rootDirs.slice(0, 10)) {
|
|
150
|
+
const name = path.basename(dir.path);
|
|
151
|
+
const purpose = this._getDirectoryPurpose(name);
|
|
152
|
+
lines.push(`- **${name}/** — ${purpose}`);
|
|
153
|
+
}
|
|
154
|
+
lines.push('');
|
|
155
|
+
|
|
156
|
+
// Key files
|
|
157
|
+
lines.push('## Key Files');
|
|
158
|
+
if (configFiles.length > 0) {
|
|
159
|
+
lines.push('### Configuration');
|
|
160
|
+
for (const file of configFiles.slice(0, 10)) {
|
|
161
|
+
lines.push(`- \`${file.replace(this.rootPath, '')}\``);
|
|
162
|
+
}
|
|
163
|
+
lines.push('');
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Statistics
|
|
167
|
+
lines.push('## Statistics');
|
|
168
|
+
lines.push(`- **Total Directories:** ${directories.length}`);
|
|
169
|
+
lines.push(`- **Total Files:** ${structure?.files?.length || 0}`);
|
|
170
|
+
lines.push(`- **Source Directories:** ${sourceDirs.length}`);
|
|
171
|
+
lines.push(`- **Test Directories:** ${testDirs.length}`);
|
|
172
|
+
lines.push(`- **Entry Points:** ${entryPoints.length}`);
|
|
173
|
+
lines.push('');
|
|
174
|
+
|
|
175
|
+
return lines.join('\n');
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Build technology stack summary section
|
|
180
|
+
* @param {object} stack - Stack from StackDetector
|
|
181
|
+
* @returns {string} Markdown section
|
|
182
|
+
*/
|
|
183
|
+
buildTechStackSummary(stack) {
|
|
184
|
+
const lines = ['## Technology Stack', ''];
|
|
185
|
+
|
|
186
|
+
// Languages
|
|
187
|
+
lines.push('## Languages');
|
|
188
|
+
lines.push(`- **Primary:** ${stack?.language || 'JavaScript/TypeScript'}`);
|
|
189
|
+
lines.push(`- **Runtime:** ${stack?.runtime || 'Node.js'}`);
|
|
190
|
+
if (stack?.runtimeVersion) {
|
|
191
|
+
lines.push(`- **Version:** ${stack.runtimeVersion}`);
|
|
192
|
+
}
|
|
193
|
+
lines.push('');
|
|
194
|
+
|
|
195
|
+
// Package Manager
|
|
196
|
+
lines.push('## Package Manager');
|
|
197
|
+
lines.push(`- **Manager:** ${stack?.packageManager || 'npm'}`);
|
|
198
|
+
lines.push('');
|
|
199
|
+
|
|
200
|
+
// Frameworks
|
|
201
|
+
lines.push('## Frameworks');
|
|
202
|
+
const frameworks = stack?.frameworks || [];
|
|
203
|
+
if (frameworks.length > 0) {
|
|
204
|
+
for (const fw of frameworks) {
|
|
205
|
+
lines.push(`- ${fw}`);
|
|
206
|
+
}
|
|
207
|
+
} else {
|
|
208
|
+
lines.push('- No major frameworks detected');
|
|
209
|
+
}
|
|
210
|
+
lines.push('');
|
|
211
|
+
|
|
212
|
+
// Databases
|
|
213
|
+
lines.push('## Databases');
|
|
214
|
+
const databases = stack?.databases || [];
|
|
215
|
+
if (databases.length > 0) {
|
|
216
|
+
for (const db of databases) {
|
|
217
|
+
lines.push(`- ${db}`);
|
|
218
|
+
}
|
|
219
|
+
} else {
|
|
220
|
+
lines.push('- No database libraries detected');
|
|
221
|
+
}
|
|
222
|
+
lines.push('');
|
|
223
|
+
|
|
224
|
+
// Infrastructure
|
|
225
|
+
lines.push('## Infrastructure');
|
|
226
|
+
const infrastructure = stack?.infrastructure || [];
|
|
227
|
+
if (infrastructure.length > 0) {
|
|
228
|
+
for (const infra of infrastructure) {
|
|
229
|
+
lines.push(`- ${infra}`);
|
|
230
|
+
}
|
|
231
|
+
} else {
|
|
232
|
+
lines.push('- No infrastructure libraries detected');
|
|
233
|
+
}
|
|
234
|
+
lines.push('');
|
|
235
|
+
|
|
236
|
+
return lines.join('\n');
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Build pain points section
|
|
241
|
+
* @param {object} techDebt - Tech debt findings
|
|
242
|
+
* @returns {string} Markdown section
|
|
243
|
+
*/
|
|
244
|
+
buildPainPoints(techDebt) {
|
|
245
|
+
const lines = ['## Pain Points', ''];
|
|
246
|
+
|
|
247
|
+
const findings = techDebt?.findings || [];
|
|
248
|
+
if (findings.length === 0) {
|
|
249
|
+
lines.push('No significant pain points detected.');
|
|
250
|
+
lines.push('');
|
|
251
|
+
return lines.join('\n');
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Group by severity
|
|
255
|
+
const bySeverity = {
|
|
256
|
+
Critical: [],
|
|
257
|
+
High: [],
|
|
258
|
+
Medium: [],
|
|
259
|
+
Low: []
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
for (const finding of findings) {
|
|
263
|
+
const severity = finding.severity || 'Medium';
|
|
264
|
+
if (bySeverity[severity]) {
|
|
265
|
+
bySeverity[severity].push(finding);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Critical Issues
|
|
270
|
+
if (bySeverity.Critical.length > 0) {
|
|
271
|
+
lines.push('## **Critical** Issues');
|
|
272
|
+
for (const issue of bySeverity.Critical.slice(0, 10)) {
|
|
273
|
+
lines.push(`- \`${issue.file?.replace(this.rootPath, '') || 'Unknown'}\`: ${issue.description || issue.content || issue.message}`);
|
|
274
|
+
}
|
|
275
|
+
lines.push('');
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// High Priority
|
|
279
|
+
if (bySeverity.High.length > 0) {
|
|
280
|
+
lines.push('## **High** Priority');
|
|
281
|
+
for (const issue of bySeverity.High.slice(0, 10)) {
|
|
282
|
+
lines.push(`- \`${issue.file?.replace(this.rootPath, '') || 'Unknown'}\`: ${issue.description || issue.content || issue.message}`);
|
|
283
|
+
}
|
|
284
|
+
lines.push('');
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Medium Priority
|
|
288
|
+
if (bySeverity.Medium.length > 0) {
|
|
289
|
+
lines.push('## **Medium** Priority');
|
|
290
|
+
lines.push(`- ${bySeverity.Medium.length} medium priority issues found`);
|
|
291
|
+
lines.push('');
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Low Priority
|
|
295
|
+
if (bySeverity.Low.length > 0) {
|
|
296
|
+
lines.push('## **Low** Priority');
|
|
297
|
+
lines.push(`- ${bySeverity.Low.length} low priority issues found`);
|
|
298
|
+
lines.push('');
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Summary
|
|
302
|
+
lines.push('## Summary');
|
|
303
|
+
lines.push(`- **Total Issues:** ${findings.length}`);
|
|
304
|
+
lines.push(`- **Critical:** ${bySeverity.Critical.length}`);
|
|
305
|
+
lines.push(`- **High:** ${bySeverity.High.length}`);
|
|
306
|
+
lines.push(`- **Medium:** ${bySeverity.Medium.length}`);
|
|
307
|
+
lines.push(`- **Low:** ${bySeverity.Low.length}`);
|
|
308
|
+
lines.push('');
|
|
309
|
+
|
|
310
|
+
return lines.join('\n');
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Build recommendations section
|
|
315
|
+
* @param {object} techDebt - Tech debt findings
|
|
316
|
+
* @param {object} stack - Stack from StackDetector
|
|
317
|
+
* @param {object} archetype - Archetype from ArchetypeDetector
|
|
318
|
+
* @returns {string} Markdown section
|
|
319
|
+
*/
|
|
320
|
+
buildRecommendations(techDebt, stack, archetype) {
|
|
321
|
+
const lines = ['## Recommendations', ''];
|
|
322
|
+
|
|
323
|
+
const findings = techDebt?.findings || [];
|
|
324
|
+
const recommendations = [];
|
|
325
|
+
|
|
326
|
+
// Generate recommendations based on findings
|
|
327
|
+
const byType = {};
|
|
328
|
+
for (const finding of findings) {
|
|
329
|
+
const type = finding.type || 'general';
|
|
330
|
+
if (!byType[type]) {
|
|
331
|
+
byType[type] = [];
|
|
332
|
+
}
|
|
333
|
+
byType[type].push(finding);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Debt marker recommendations
|
|
337
|
+
if (byType.debt_marker?.length > 0) {
|
|
338
|
+
const criticalDebt = byType.debt_marker.filter(f => f.severity === 'Critical');
|
|
339
|
+
if (criticalDebt.length > 0) {
|
|
340
|
+
recommendations.push({
|
|
341
|
+
title: 'Address Critical Tech Debt',
|
|
342
|
+
issue: `${criticalDebt.length} critical debt markers found (DEPRECATED, critical FIXMEs)`,
|
|
343
|
+
files: [...new Set(criticalDebt.map(f => f.file))].slice(0, 5),
|
|
344
|
+
fix: 'Review and resolve deprecated code and critical FIXMEs immediately',
|
|
345
|
+
effort: 'Medium'
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// Large file recommendations
|
|
351
|
+
if (byType.large_file?.length > 0) {
|
|
352
|
+
recommendations.push({
|
|
353
|
+
title: 'Refactor Large Files',
|
|
354
|
+
issue: `${byType.large_file.length} files exceed size thresholds`,
|
|
355
|
+
files: byType.large_file.map(f => f.file).slice(0, 5),
|
|
356
|
+
fix: 'Break down large files into smaller, focused modules',
|
|
357
|
+
effort: 'High'
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Complexity recommendations
|
|
362
|
+
if (byType.complexity?.length > 0) {
|
|
363
|
+
recommendations.push({
|
|
364
|
+
title: 'Reduce Code Complexity',
|
|
365
|
+
issue: `${byType.complexity.length} functions/modules exceed complexity thresholds`,
|
|
366
|
+
files: [...new Set(byType.complexity.map(f => f.file))].slice(0, 5),
|
|
367
|
+
fix: 'Extract helper functions, reduce nesting, simplify logic',
|
|
368
|
+
effort: 'Medium'
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// Duplicate code recommendations
|
|
373
|
+
if (byType.duplicate?.length > 0) {
|
|
374
|
+
recommendations.push({
|
|
375
|
+
title: 'Eliminate Duplicate Code',
|
|
376
|
+
issue: `${byType.duplicate.length} duplicate code blocks detected`,
|
|
377
|
+
files: byType.duplicate.flatMap(d => d.files || []).slice(0, 5),
|
|
378
|
+
fix: 'Extract common logic into shared utilities or base classes',
|
|
379
|
+
effort: 'Medium'
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Dependency risk recommendations
|
|
384
|
+
if (byType.dependency?.length > 0) {
|
|
385
|
+
const criticalDeps = byType.dependency.filter(f => f.severity === 'Critical');
|
|
386
|
+
if (criticalDeps.length > 0) {
|
|
387
|
+
recommendations.push({
|
|
388
|
+
title: 'Update Vulnerable Dependencies',
|
|
389
|
+
issue: `${criticalDeps.length} critical security vulnerabilities in dependencies`,
|
|
390
|
+
files: criticalDeps.map(d => d.package),
|
|
391
|
+
fix: 'Run npm audit fix or manually update vulnerable packages',
|
|
392
|
+
effort: 'Low'
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// Archetype-specific recommendations
|
|
398
|
+
if (archetype?.archetype) {
|
|
399
|
+
const archetypeRecs = this._getArchetypeRecommendations(archetype.archetype);
|
|
400
|
+
recommendations.push(...archetypeRecs);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// Output recommendations
|
|
404
|
+
if (recommendations.length === 0) {
|
|
405
|
+
lines.push('No specific recommendations at this time. The codebase appears to be in good shape.');
|
|
406
|
+
lines.push('');
|
|
407
|
+
} else {
|
|
408
|
+
for (let i = 0; i < recommendations.length && i < 10; i++) {
|
|
409
|
+
const rec = recommendations[i];
|
|
410
|
+
lines.push(`## ${i + 1}. ${rec.title}`);
|
|
411
|
+
lines.push(`**Issue:** ${rec.issue}`);
|
|
412
|
+
if (rec.files?.length > 0) {
|
|
413
|
+
lines.push(`**Files:**`);
|
|
414
|
+
for (const file of rec.files) {
|
|
415
|
+
lines.push(`- \`${file.replace?.(this.rootPath, '') || file}\``);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
lines.push(`**Fix approach:** ${rec.fix}`);
|
|
419
|
+
lines.push(`**Effort:** ${rec.effort}`);
|
|
420
|
+
lines.push('');
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
return lines.join('\n');
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Detect architectural pattern from structure and stack
|
|
429
|
+
* @private
|
|
430
|
+
*/
|
|
431
|
+
_detectPattern(structure, stack) {
|
|
432
|
+
const directories = structure?.directories || [];
|
|
433
|
+
const dirNames = directories.map(d => path.basename(d.path).toLowerCase());
|
|
434
|
+
const frameworks = stack?.frameworks || [];
|
|
435
|
+
|
|
436
|
+
if (dirNames.includes('components') && dirNames.includes('pages')) {
|
|
437
|
+
return frameworks.includes('Next.js') ? 'Next.js Pages/App Router' : 'React Component-based';
|
|
438
|
+
}
|
|
439
|
+
if (dirNames.includes('controllers') && dirNames.includes('models') && dirNames.includes('routes')) {
|
|
440
|
+
return 'MVC (Model-View-Controller)';
|
|
441
|
+
}
|
|
442
|
+
if (dirNames.includes('services') && dirNames.includes('handlers')) {
|
|
443
|
+
return 'Service-Oriented';
|
|
444
|
+
}
|
|
445
|
+
if (dirNames.includes('features') || dirNames.includes('modules')) {
|
|
446
|
+
return 'Feature-based / Domain-driven';
|
|
447
|
+
}
|
|
448
|
+
return 'Standard Layered Architecture';
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Build header
|
|
453
|
+
* @private
|
|
454
|
+
*/
|
|
455
|
+
_buildHeader() {
|
|
456
|
+
const lines = [
|
|
457
|
+
'# Project Analysis Report',
|
|
458
|
+
'',
|
|
459
|
+
`**Generated:** ${new Date().toISOString().split('T')[0]}`,
|
|
460
|
+
`**Root:** ${this.rootPath}`,
|
|
461
|
+
''
|
|
462
|
+
];
|
|
463
|
+
return lines.join('\n');
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Build footer
|
|
468
|
+
* @private
|
|
469
|
+
*/
|
|
470
|
+
_buildFooter() {
|
|
471
|
+
const lines = [
|
|
472
|
+
'---',
|
|
473
|
+
'',
|
|
474
|
+
`*Report generated by EZ Agents Project Reporter*`,
|
|
475
|
+
`*${new Date().toISOString()}*`
|
|
476
|
+
];
|
|
477
|
+
return lines.join('\n');
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Get directory purpose description
|
|
482
|
+
* @private
|
|
483
|
+
*/
|
|
484
|
+
_getDirectoryPurpose(name) {
|
|
485
|
+
const purposes = {
|
|
486
|
+
src: 'Source code',
|
|
487
|
+
app: 'Application code (Next.js App Router)',
|
|
488
|
+
lib: 'Library/utility code',
|
|
489
|
+
components: 'Reusable UI components',
|
|
490
|
+
pages: 'Page components (Next.js Pages Router)',
|
|
491
|
+
api: 'API routes',
|
|
492
|
+
services: 'Business logic services',
|
|
493
|
+
models: 'Data models',
|
|
494
|
+
controllers: 'Request controllers',
|
|
495
|
+
routes: 'Route definitions',
|
|
496
|
+
utils: 'Utility functions',
|
|
497
|
+
helpers: 'Helper functions',
|
|
498
|
+
hooks: 'React hooks',
|
|
499
|
+
stores: 'State management',
|
|
500
|
+
contexts: 'React contexts',
|
|
501
|
+
types: 'Type definitions',
|
|
502
|
+
interfaces: 'Interface definitions',
|
|
503
|
+
config: 'Configuration files',
|
|
504
|
+
tests: 'Test files',
|
|
505
|
+
specs: 'Specification files',
|
|
506
|
+
docs: 'Documentation',
|
|
507
|
+
scripts: 'Build/deployment scripts',
|
|
508
|
+
bin: 'Binary/executable files',
|
|
509
|
+
public: 'Public assets',
|
|
510
|
+
static: 'Static assets',
|
|
511
|
+
assets: 'Application assets'
|
|
512
|
+
};
|
|
513
|
+
return purposes[name.toLowerCase()] || 'Application code';
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Detect error handling from stack
|
|
518
|
+
* @private
|
|
519
|
+
*/
|
|
520
|
+
_detectErrorHandling(stack) {
|
|
521
|
+
const infra = stack?.infrastructure || [];
|
|
522
|
+
return infra.some(i =>
|
|
523
|
+
i.includes('Sentry') ||
|
|
524
|
+
i.includes('logging') ||
|
|
525
|
+
i.includes('Winston') ||
|
|
526
|
+
i.includes('Pino')
|
|
527
|
+
);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* Get archetype-specific recommendations
|
|
532
|
+
* @private
|
|
533
|
+
*/
|
|
534
|
+
_getArchetypeRecommendations(archetype) {
|
|
535
|
+
const recs = {
|
|
536
|
+
dashboard: [{
|
|
537
|
+
title: 'Optimize Dashboard Performance',
|
|
538
|
+
issue: 'Dashboards often have heavy data visualization',
|
|
539
|
+
fix: 'Implement lazy loading, memoization, and efficient chart rendering',
|
|
540
|
+
effort: 'Medium'
|
|
541
|
+
}],
|
|
542
|
+
ecommerce: [{
|
|
543
|
+
title: 'Ensure E-commerce Best Practices',
|
|
544
|
+
issue: 'E-commerce requires robust payment and inventory handling',
|
|
545
|
+
fix: 'Verify payment gateway integration, inventory management, and order processing',
|
|
546
|
+
effort: 'High'
|
|
547
|
+
}],
|
|
548
|
+
SaaS: [{
|
|
549
|
+
title: 'Review Multi-tenancy Implementation',
|
|
550
|
+
issue: 'SaaS applications require proper tenant isolation',
|
|
551
|
+
fix: 'Verify tenant scoping, data isolation, and subscription management',
|
|
552
|
+
effort: 'High'
|
|
553
|
+
}],
|
|
554
|
+
fintech: [{
|
|
555
|
+
title: 'Audit Security and Compliance',
|
|
556
|
+
issue: 'Fintech applications have strict security requirements',
|
|
557
|
+
fix: 'Review authentication, authorization, audit logging, and compliance measures',
|
|
558
|
+
effort: 'High'
|
|
559
|
+
}]
|
|
560
|
+
};
|
|
561
|
+
return recs[archetype] || [];
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
module.exports = { ProjectReporter };
|