qodfy 0.1.1 → 0.1.4

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 (2) hide show
  1. package/dist/index.js +99 -8
  2. package/package.json +4 -3
package/dist/index.js CHANGED
@@ -1,18 +1,66 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
+ import fs from "fs/promises";
5
+ import path from "path";
4
6
  import { Command } from "commander";
5
7
  import pc from "picocolors";
6
8
  import { scanProject } from "@qodfy/core";
7
9
  var program = new Command();
8
- program.name("qodfy").description("Launch readiness scanner for AI-built apps.").version("0.1.1");
9
- program.command("scan").description("Scan a project for launch readiness issues.").option("-p, --path <path>", "Project path to scan", process.cwd()).action(async (options) => {
10
- console.log(pc.cyan("Qodfy is scanning your project...\n"));
11
- const report = await scanProject(options.path);
12
- printReport(report);
10
+ program.name("qodfy").description("Launch readiness scanner for AI-built apps.").version("0.1.4");
11
+ program.command("scan").description("Scan a project for launch readiness issues.").option("-p, --path <path>", "Project path to scan", process.cwd()).option("--max-issues <number>", "Maximum number of issues to display", "50").action(async (options) => {
12
+ const pathResult = await resolveProjectPath(options.path);
13
+ if (!pathResult.ok) {
14
+ printScanError(pathResult.reason);
15
+ process.exitCode = 1;
16
+ return;
17
+ }
18
+ try {
19
+ console.log(pc.cyan("Qodfy is scanning your project...\n"));
20
+ const report = await scanProject(pathResult.projectPath);
21
+ printReport(report, parseMaxIssues(options.maxIssues));
22
+ } catch (error) {
23
+ printScanError(getErrorMessage(error));
24
+ process.exitCode = 1;
25
+ }
13
26
  });
14
- program.parse();
15
- function printReport(report) {
27
+ await program.parseAsync();
28
+ async function resolveProjectPath(projectPath) {
29
+ const inputPath = projectPath.trim() || process.cwd();
30
+ const resolvedPath = path.resolve(inputPath);
31
+ try {
32
+ const stats = await fs.stat(resolvedPath);
33
+ if (!stats.isDirectory()) {
34
+ return {
35
+ ok: false,
36
+ reason: `The path "${inputPath}" is not a directory.`
37
+ };
38
+ }
39
+ return {
40
+ ok: true,
41
+ projectPath: resolvedPath
42
+ };
43
+ } catch (error) {
44
+ const code = getErrorCode(error);
45
+ if (code === "ENOENT") {
46
+ return {
47
+ ok: false,
48
+ reason: `The path "${inputPath}" does not exist.`
49
+ };
50
+ }
51
+ if (code === "ENOTDIR") {
52
+ return {
53
+ ok: false,
54
+ reason: `The path "${inputPath}" is not a directory.`
55
+ };
56
+ }
57
+ return {
58
+ ok: false,
59
+ reason: `Qodfy could not access the path "${inputPath}".`
60
+ };
61
+ }
62
+ }
63
+ function printReport(report, maxIssues) {
16
64
  console.log(pc.bold("Qodfy Report"));
17
65
  console.log("");
18
66
  const scoreColor = report.score >= 80 ? pc.green : report.score >= 60 ? pc.yellow : pc.red;
@@ -23,13 +71,19 @@ function printReport(report) {
23
71
  console.log(`API routes: ${report.stats.apiRoutes}`);
24
72
  console.log(`AI-related files: ${report.stats.aiFiles}`);
25
73
  console.log(`Large files: ${report.stats.largeFiles}`);
74
+ console.log(`Scan duration: ${formatDuration(report.stats.durationMs)}`);
26
75
  console.log("");
27
76
  if (report.issues.length === 0) {
28
77
  console.log(pc.green("No issues found. Your project looks clean."));
29
78
  return;
30
79
  }
31
80
  console.log(pc.bold("Issues"));
32
- for (const issue of report.issues) {
81
+ const issuesToShow = report.issues.slice(0, maxIssues);
82
+ if (report.issues.length > maxIssues) {
83
+ console.log(`Showing ${maxIssues} of ${report.issues.length} issues.`);
84
+ console.log(`Use --max-issues <number> to show more.`);
85
+ }
86
+ for (const issue of issuesToShow) {
33
87
  const label = issue.severity === "critical" ? pc.red("CRITICAL") : issue.severity === "warning" ? pc.yellow("WARNING") : pc.blue("INFO");
34
88
  console.log(`
35
89
  ${label} ${pc.bold(issue.title)}`);
@@ -37,8 +91,45 @@ ${label} ${pc.bold(issue.title)}`);
37
91
  if (issue.file) {
38
92
  console.log(pc.dim(`File: ${issue.file}`));
39
93
  }
94
+ if (issue.suggestion) {
95
+ console.log(pc.dim(`Suggestion: ${issue.suggestion}`));
96
+ }
40
97
  }
41
98
  console.log("");
42
99
  console.log(pc.bold("Recommended next step:"));
43
100
  console.log("Fix critical issues first, then warnings, then cleanup items.");
44
101
  }
102
+ function printScanError(reason) {
103
+ console.error(pc.red("Qodfy could not scan this project."));
104
+ console.error("");
105
+ console.error(pc.bold("Reason:"));
106
+ console.error(reason);
107
+ console.error("");
108
+ console.error(pc.bold("Try:"));
109
+ console.error("qodfy scan --path ./my-next-app");
110
+ }
111
+ function getErrorMessage(error) {
112
+ if (error instanceof Error && error.message) {
113
+ return error.message;
114
+ }
115
+ return "An unexpected error occurred while scanning the project.";
116
+ }
117
+ function parseMaxIssues(maxIssues) {
118
+ const parsedMaxIssues = Number.parseInt(maxIssues, 10);
119
+ if (!Number.isFinite(parsedMaxIssues) || parsedMaxIssues <= 0) {
120
+ return 50;
121
+ }
122
+ return parsedMaxIssues;
123
+ }
124
+ function formatDuration(durationMs) {
125
+ if (durationMs < 1e3) {
126
+ return `${durationMs}ms`;
127
+ }
128
+ return `${(durationMs / 1e3).toFixed(1)}s`;
129
+ }
130
+ function getErrorCode(error) {
131
+ if (error && typeof error === "object" && "code" in error && typeof error.code === "string") {
132
+ return error.code;
133
+ }
134
+ return void 0;
135
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qodfy",
3
- "version": "0.1.1",
3
+ "version": "0.1.4",
4
4
  "description": "Open-source launch readiness scanner for AI-built apps.",
5
5
  "keywords": [
6
6
  "qodfy",
@@ -38,7 +38,8 @@
38
38
  }
39
39
  },
40
40
  "files": [
41
- "dist"
41
+ "dist",
42
+ "README.md"
42
43
  ],
43
44
  "license": "MIT",
44
45
  "engines": {
@@ -50,7 +51,7 @@
50
51
  "dependencies": {
51
52
  "commander": "^14.0.3",
52
53
  "picocolors": "^1.1.1",
53
- "@qodfy/core": "^0.1.1"
54
+ "@qodfy/core": "^0.1.4"
54
55
  },
55
56
  "devDependencies": {
56
57
  "@types/node": "^25.7.0",