qodfy 0.1.0 → 0.1.2
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 +104 -0
- package/dist/index.js +77 -5
- package/package.json +4 -3
package/README.md
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Qodfy
|
|
2
|
+
|
|
3
|
+
AI built it fast. Qodfy checks if it's ready.
|
|
4
|
+
|
|
5
|
+
Qodfy is an open-source launch-readiness scanner for AI-built apps. The first product is a local CLI focused on Next.js projects built with TypeScript, Vercel AI SDK, Cursor, Claude Code, v0, Lovable, Bolt, Replit, and similar AI coding workflows.
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
Run Qodfy in any local project:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx qodfy scan
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Scan a specific folder:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx qodfy scan --path apps/web
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## What Qodfy Checks Today
|
|
22
|
+
|
|
23
|
+
Qodfy v0.1 scans locally and looks for common launch-readiness risks:
|
|
24
|
+
|
|
25
|
+
- Next.js project detection
|
|
26
|
+
- missing `.env.example`
|
|
27
|
+
- API routes in `app/api` and `pages/api`
|
|
28
|
+
- API routes that may be missing auth/session checks
|
|
29
|
+
- AI-related files using keywords like `openai`, `@ai-sdk`, `anthropic`, `gemini`, `generateText`, `streamText`, and `useChat`
|
|
30
|
+
- AI routes/files that may be missing rate limiting
|
|
31
|
+
- large generated files
|
|
32
|
+
- a simple launch readiness score from `0` to `100`
|
|
33
|
+
|
|
34
|
+
Qodfy does not send your code to any external server.
|
|
35
|
+
|
|
36
|
+
## Example Output
|
|
37
|
+
|
|
38
|
+
```txt
|
|
39
|
+
Qodfy is scanning your project...
|
|
40
|
+
|
|
41
|
+
Qodfy Report
|
|
42
|
+
|
|
43
|
+
Launch Readiness: 72/100
|
|
44
|
+
|
|
45
|
+
Stats
|
|
46
|
+
Files scanned: 42
|
|
47
|
+
API routes: 3
|
|
48
|
+
AI-related files: 2
|
|
49
|
+
Large files: 1
|
|
50
|
+
|
|
51
|
+
Issues
|
|
52
|
+
|
|
53
|
+
CRITICAL AI route may be missing rate limiting
|
|
54
|
+
AI routes can create real API costs. Add rate limiting or usage limits before launch.
|
|
55
|
+
File: app/api/chat/route.ts
|
|
56
|
+
|
|
57
|
+
WARNING API route may be missing authentication
|
|
58
|
+
This API route does not appear to contain an auth/session check.
|
|
59
|
+
File: app/api/admin/route.ts
|
|
60
|
+
|
|
61
|
+
Recommended next step:
|
|
62
|
+
Fix critical issues first, then warnings, then cleanup items.
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Commands
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
qodfy scan
|
|
69
|
+
qodfy scan --path <project-path>
|
|
70
|
+
qodfy --help
|
|
71
|
+
qodfy --version
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Scoring
|
|
75
|
+
|
|
76
|
+
Qodfy starts at `100`.
|
|
77
|
+
|
|
78
|
+
- Critical issue: `-20`
|
|
79
|
+
- Warning: `-8`
|
|
80
|
+
- Info: no major score penalty
|
|
81
|
+
|
|
82
|
+
The score is intentionally simple in v0.1 and will become more precise as the rule set improves.
|
|
83
|
+
|
|
84
|
+
## Roadmap
|
|
85
|
+
|
|
86
|
+
Near-term priorities:
|
|
87
|
+
|
|
88
|
+
- JSON and Markdown output
|
|
89
|
+
- `.env.example` coverage for `process.env.*`
|
|
90
|
+
- exposed secret detection
|
|
91
|
+
- Stripe webhook signature checks
|
|
92
|
+
- better auth and rate-limit heuristics
|
|
93
|
+
- `--ci` and `--min-score`
|
|
94
|
+
- GitHub Action
|
|
95
|
+
|
|
96
|
+
## Repository
|
|
97
|
+
|
|
98
|
+
GitHub: https://github.com/yassinifguisse1/qodfy
|
|
99
|
+
|
|
100
|
+
Issues and feedback: https://github.com/yassinifguisse1/qodfy/issues
|
|
101
|
+
|
|
102
|
+
## License
|
|
103
|
+
|
|
104
|
+
MIT
|
package/dist/index.js
CHANGED
|
@@ -1,17 +1,65 @@
|
|
|
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.
|
|
10
|
+
program.name("qodfy").description("Launch readiness scanner for AI-built apps.").version("0.1.2");
|
|
9
11
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
printScanError(getErrorMessage(error));
|
|
24
|
+
process.exitCode = 1;
|
|
25
|
+
}
|
|
13
26
|
});
|
|
14
|
-
program.
|
|
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
|
+
}
|
|
15
63
|
function printReport(report) {
|
|
16
64
|
console.log(pc.bold("Qodfy Report"));
|
|
17
65
|
console.log("");
|
|
@@ -37,8 +85,32 @@ ${label} ${pc.bold(issue.title)}`);
|
|
|
37
85
|
if (issue.file) {
|
|
38
86
|
console.log(pc.dim(`File: ${issue.file}`));
|
|
39
87
|
}
|
|
88
|
+
if (issue.suggestion) {
|
|
89
|
+
console.log(pc.dim(`Suggestion: ${issue.suggestion}`));
|
|
90
|
+
}
|
|
40
91
|
}
|
|
41
92
|
console.log("");
|
|
42
93
|
console.log(pc.bold("Recommended next step:"));
|
|
43
94
|
console.log("Fix critical issues first, then warnings, then cleanup items.");
|
|
44
95
|
}
|
|
96
|
+
function printScanError(reason) {
|
|
97
|
+
console.error(pc.red("Qodfy could not scan this project."));
|
|
98
|
+
console.error("");
|
|
99
|
+
console.error(pc.bold("Reason:"));
|
|
100
|
+
console.error(reason);
|
|
101
|
+
console.error("");
|
|
102
|
+
console.error(pc.bold("Try:"));
|
|
103
|
+
console.error("qodfy scan --path ./my-next-app");
|
|
104
|
+
}
|
|
105
|
+
function getErrorMessage(error) {
|
|
106
|
+
if (error instanceof Error && error.message) {
|
|
107
|
+
return error.message;
|
|
108
|
+
}
|
|
109
|
+
return "An unexpected error occurred while scanning the project.";
|
|
110
|
+
}
|
|
111
|
+
function getErrorCode(error) {
|
|
112
|
+
if (error && typeof error === "object" && "code" in error && typeof error.code === "string") {
|
|
113
|
+
return error.code;
|
|
114
|
+
}
|
|
115
|
+
return void 0;
|
|
116
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "qodfy",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
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.
|
|
54
|
+
"@qodfy/core": "^0.1.2"
|
|
54
55
|
},
|
|
55
56
|
"devDependencies": {
|
|
56
57
|
"@types/node": "^25.7.0",
|