forgestack-os-cli 0.3.4 → 0.3.6
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 +382 -150
- package/dist/commands/doctor.d.ts +12 -0
- package/dist/commands/doctor.js +214 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/organize.d.ts +2 -0
- package/dist/commands/organize.js +126 -0
- package/dist/commands/organize.js.map +1 -0
- package/dist/commands/run-tasks.d.ts +12 -0
- package/dist/commands/run-tasks.js +125 -0
- package/dist/commands/run-tasks.js.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/doctor/check-database.d.ts +8 -0
- package/dist/utils/doctor/check-database.js +271 -0
- package/dist/utils/doctor/check-database.js.map +1 -0
- package/dist/utils/doctor/check-docker.d.ts +8 -0
- package/dist/utils/doctor/check-docker.js +212 -0
- package/dist/utils/doctor/check-docker.js.map +1 -0
- package/dist/utils/doctor/check-env.d.ts +12 -0
- package/dist/utils/doctor/check-env.js +207 -0
- package/dist/utils/doctor/check-env.js.map +1 -0
- package/dist/utils/doctor/check-lint.d.ts +8 -0
- package/dist/utils/doctor/check-lint.js +225 -0
- package/dist/utils/doctor/check-lint.js.map +1 -0
- package/dist/utils/doctor/check-node.d.ts +20 -0
- package/dist/utils/doctor/check-node.js +172 -0
- package/dist/utils/doctor/check-node.js.map +1 -0
- package/dist/utils/doctor/check-ports.d.ts +15 -0
- package/dist/utils/doctor/check-ports.js +166 -0
- package/dist/utils/doctor/check-ports.js.map +1 -0
- package/dist/utils/doctor/check-prisma.d.ts +8 -0
- package/dist/utils/doctor/check-prisma.js +202 -0
- package/dist/utils/doctor/check-prisma.js.map +1 -0
- package/dist/utils/doctor/index.d.ts +14 -0
- package/dist/utils/doctor/index.js +15 -0
- package/dist/utils/doctor/index.js.map +1 -0
- package/dist/utils/doctor/types.d.ts +50 -0
- package/dist/utils/doctor/types.js +5 -0
- package/dist/utils/doctor/types.js.map +1 -0
- package/dist/utils/file-organizer.d.ts +17 -0
- package/dist/utils/file-organizer.js +170 -0
- package/dist/utils/file-organizer.js.map +1 -0
- package/dist/utils/task-runner.d.ts +14 -0
- package/dist/utils/task-runner.js +79 -0
- package/dist/utils/task-runner.js.map +1 -0
- package/package.json +11 -4
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import crypto from 'crypto';
|
|
4
|
+
// File type categories
|
|
5
|
+
const FILE_CATEGORIES = {
|
|
6
|
+
Images: ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.svg', '.webp', '.ico', '.tiff'],
|
|
7
|
+
Documents: ['.pdf', '.doc', '.docx', '.txt', '.xls', '.xlsx', '.ppt', '.pptx', '.odt'],
|
|
8
|
+
Archives: ['.zip', '.rar', '.7z', '.tar', '.gz', '.bz2', '.iso'],
|
|
9
|
+
Videos: ['.mp4', '.avi', '.mkv', '.mov', '.wmv', '.flv', '.webm', '.m4v'],
|
|
10
|
+
Audio: ['.mp3', '.wav', '.flac', '.aac', '.ogg', '.wma', '.m4a'],
|
|
11
|
+
Code: ['.js', '.ts', '.py', '.java', '.cpp', '.c', '.go', '.rs', '.rb', '.php', '.html', '.css', '.json', '.xml', '.yaml', '.yml'],
|
|
12
|
+
Data: ['.csv', '.sql', '.db', '.sqlite', '.json', '.yaml'],
|
|
13
|
+
Executables: ['.exe', '.msi', '.app', '.bin', '.sh', '.bat'],
|
|
14
|
+
Others: [],
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Calculate MD5 hash of a file
|
|
18
|
+
*/
|
|
19
|
+
async function getFileHash(filePath) {
|
|
20
|
+
try {
|
|
21
|
+
const content = await fs.readFile(filePath);
|
|
22
|
+
return crypto.createHash('md5').update(content).digest('hex');
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
// Return empty string for unreadable files
|
|
26
|
+
return '';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Detect duplicate files by hash
|
|
31
|
+
*/
|
|
32
|
+
export async function detectDuplicates(folderPath) {
|
|
33
|
+
const fileHashes = new Map();
|
|
34
|
+
const duplicates = new Map();
|
|
35
|
+
// System folders to skip
|
|
36
|
+
const skipFolders = new Set(['.git', '.env', 'node_modules', '.next', 'dist', 'build', '.DS_Store', '.vscode']);
|
|
37
|
+
async function scanDirectory(dir) {
|
|
38
|
+
try {
|
|
39
|
+
const files = await fs.readdir(dir);
|
|
40
|
+
for (const file of files) {
|
|
41
|
+
if (skipFolders.has(file) || file.startsWith('.')) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
const filePath = path.join(dir, file);
|
|
45
|
+
try {
|
|
46
|
+
const stats = await fs.stat(filePath);
|
|
47
|
+
if (stats.isDirectory()) {
|
|
48
|
+
await scanDirectory(filePath);
|
|
49
|
+
}
|
|
50
|
+
else if (stats.isFile() && stats.size > 0) {
|
|
51
|
+
try {
|
|
52
|
+
const hash = await getFileHash(filePath);
|
|
53
|
+
if (hash) {
|
|
54
|
+
if (!fileHashes.has(hash)) {
|
|
55
|
+
fileHashes.set(hash, []);
|
|
56
|
+
}
|
|
57
|
+
fileHashes.get(hash).push(filePath);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// Skip files that can't be hashed
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// Skip files/folders that can't be accessed
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
// Skip directories that can't be read
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
await scanDirectory(folderPath);
|
|
75
|
+
// Identify actual duplicates
|
|
76
|
+
for (const [hash, files] of fileHashes) {
|
|
77
|
+
if (files.length > 1) {
|
|
78
|
+
duplicates.set(hash, files);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return duplicates;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Organize files by type into categorized folders
|
|
85
|
+
*/
|
|
86
|
+
export async function organizeFilesByType(folderPath, duplicates = new Map()) {
|
|
87
|
+
const result = { categorized: {}, duplicates: 0 };
|
|
88
|
+
const duplicateSet = new Set();
|
|
89
|
+
// Build a set of duplicate files for quick lookup
|
|
90
|
+
for (const files of duplicates.values()) {
|
|
91
|
+
files.forEach(f => duplicateSet.add(f));
|
|
92
|
+
}
|
|
93
|
+
async function scanAndOrganize(dir) {
|
|
94
|
+
const files = await fs.readdir(dir);
|
|
95
|
+
for (const file of files) {
|
|
96
|
+
const filePath = path.join(dir, file);
|
|
97
|
+
const stats = await fs.stat(filePath);
|
|
98
|
+
if (stats.isDirectory()) {
|
|
99
|
+
// Skip special folders
|
|
100
|
+
if (file === 'Duplicates' || file.startsWith('.')) {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
await scanAndOrganize(filePath);
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
const ext = path.extname(file).toLowerCase();
|
|
107
|
+
// Find category
|
|
108
|
+
let category = 'Others';
|
|
109
|
+
for (const [cat, extensions] of Object.entries(FILE_CATEGORIES)) {
|
|
110
|
+
if (extensions.includes(ext)) {
|
|
111
|
+
category = cat;
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const destFolder = path.join(folderPath, duplicateSet.has(filePath) ? 'Duplicates' : category);
|
|
116
|
+
await fs.ensureDir(destFolder);
|
|
117
|
+
await fs.move(filePath, path.join(destFolder, file), { overwrite: true });
|
|
118
|
+
if (duplicateSet.has(filePath)) {
|
|
119
|
+
result.duplicates++;
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
result.categorized[category] = (result.categorized[category] || 0) + 1;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
await scanAndOrganize(folderPath);
|
|
128
|
+
return result;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Organize files by date (YYYY-MM format)
|
|
132
|
+
*/
|
|
133
|
+
export async function organizeFilesByDate(folderPath, duplicates = new Map()) {
|
|
134
|
+
const result = { categorized: {}, duplicates: 0 };
|
|
135
|
+
const duplicateSet = new Set();
|
|
136
|
+
// Build a set of duplicate files
|
|
137
|
+
for (const files of duplicates.values()) {
|
|
138
|
+
files.forEach(f => duplicateSet.add(f));
|
|
139
|
+
}
|
|
140
|
+
async function scanAndOrganize(dir) {
|
|
141
|
+
const files = await fs.readdir(dir);
|
|
142
|
+
for (const file of files) {
|
|
143
|
+
const filePath = path.join(dir, file);
|
|
144
|
+
const stats = await fs.stat(filePath);
|
|
145
|
+
if (stats.isDirectory()) {
|
|
146
|
+
if (file.startsWith('.') || /^\d{4}-\d{2}$/.test(file)) {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
await scanAndOrganize(filePath);
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
// Get file modification date
|
|
153
|
+
const mtime = new Date(stats.mtime);
|
|
154
|
+
const dateFolder = mtime.toISOString().slice(0, 7); // YYYY-MM
|
|
155
|
+
const destFolder = path.join(folderPath, duplicateSet.has(filePath) ? 'Duplicates' : dateFolder);
|
|
156
|
+
await fs.ensureDir(destFolder);
|
|
157
|
+
await fs.move(filePath, path.join(destFolder, file), { overwrite: true });
|
|
158
|
+
if (duplicateSet.has(filePath)) {
|
|
159
|
+
result.duplicates++;
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
result.categorized[dateFolder] = (result.categorized[dateFolder] || 0) + 1;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
await scanAndOrganize(folderPath);
|
|
168
|
+
return result;
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=file-organizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-organizer.js","sourceRoot":"","sources":["../../src/utils/file-organizer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Task } from '../commands/run-tasks.js';
|
|
2
|
+
export interface TaskResult {
|
|
3
|
+
name: string;
|
|
4
|
+
success: boolean;
|
|
5
|
+
error?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Execute tasks sequentially (one after another)
|
|
9
|
+
*/
|
|
10
|
+
export declare function executeTasksSequentially(tasks: Task[], stopOnError?: boolean): Promise<TaskResult[]>;
|
|
11
|
+
/**
|
|
12
|
+
* Execute tasks in parallel
|
|
13
|
+
*/
|
|
14
|
+
export declare function executeTasksInParallel(tasks: Task[], stopOnError?: boolean): Promise<TaskResult[]>;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
/**
|
|
5
|
+
* Execute a single task
|
|
6
|
+
*/
|
|
7
|
+
async function executeTask(task) {
|
|
8
|
+
try {
|
|
9
|
+
console.log(`${chalk.cyan('→')} Running: ${chalk.bold(task.name)}`);
|
|
10
|
+
// Use shell: true for cross-platform command execution
|
|
11
|
+
const options = {
|
|
12
|
+
stdio: 'pipe',
|
|
13
|
+
encoding: 'utf-8',
|
|
14
|
+
shell: true,
|
|
15
|
+
};
|
|
16
|
+
if (task.cwd) {
|
|
17
|
+
options.cwd = task.cwd;
|
|
18
|
+
}
|
|
19
|
+
// Add shell option for cross-platform compatibility
|
|
20
|
+
if (os.platform() === 'win32') {
|
|
21
|
+
options.shell = 'cmd.exe';
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
execSync(task.command, options);
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
// execSync throws on non-zero exit code
|
|
28
|
+
// Extract stderr if available
|
|
29
|
+
if (error instanceof Error) {
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
throw new Error(`Command failed: ${task.command}`);
|
|
33
|
+
}
|
|
34
|
+
console.log(`${chalk.green('✔')} ${task.name} completed`);
|
|
35
|
+
return { name: task.name, success: true };
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
const errorMessage = error instanceof Error ? error.message.split('\n')[0] : String(error);
|
|
39
|
+
console.log(`${chalk.red('✖')} ${task.name} failed`);
|
|
40
|
+
return { name: task.name, success: false, error: errorMessage };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Execute tasks sequentially (one after another)
|
|
45
|
+
*/
|
|
46
|
+
export async function executeTasksSequentially(tasks, stopOnError = true) {
|
|
47
|
+
const results = [];
|
|
48
|
+
for (const task of tasks) {
|
|
49
|
+
console.log('');
|
|
50
|
+
const result = await executeTask(task);
|
|
51
|
+
results.push(result);
|
|
52
|
+
if (!result.success && stopOnError) {
|
|
53
|
+
console.log('');
|
|
54
|
+
console.log(chalk.yellow('⚠ Stopping execution due to task failure'));
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return results;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Execute tasks in parallel
|
|
62
|
+
*/
|
|
63
|
+
export async function executeTasksInParallel(tasks, stopOnError = true) {
|
|
64
|
+
console.log('');
|
|
65
|
+
const promises = tasks.map(task => executeTask(task)
|
|
66
|
+
.catch(error => ({
|
|
67
|
+
name: task.name,
|
|
68
|
+
success: false,
|
|
69
|
+
error: error instanceof Error ? error.message : String(error),
|
|
70
|
+
})));
|
|
71
|
+
const results = await Promise.all(promises);
|
|
72
|
+
// If stopOnError is true and any task failed, we should note this
|
|
73
|
+
if (stopOnError && results.some(r => !r.success)) {
|
|
74
|
+
console.log('');
|
|
75
|
+
console.log(chalk.yellow('⚠ Some tasks failed during parallel execution'));
|
|
76
|
+
}
|
|
77
|
+
return results;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=task-runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-runner.js","sourceRoot":"","sources":["../../src/utils/task-runner.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "forgestack-os-cli",
|
|
3
|
-
"version": "0.3.
|
|
4
|
-
"description": "ForgeStack OS CLI - Generate production-ready full-stack SaaS applications",
|
|
3
|
+
"version": "0.3.6",
|
|
4
|
+
"description": "ForgeStack OS CLI - Generate production-ready full-stack SaaS applications with file organization and batch task execution utilities",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"exports": {
|
|
@@ -32,7 +32,13 @@
|
|
|
32
32
|
"cli",
|
|
33
33
|
"generator",
|
|
34
34
|
"saas",
|
|
35
|
-
"full-stack"
|
|
35
|
+
"full-stack",
|
|
36
|
+
"organize-files",
|
|
37
|
+
"file-organization",
|
|
38
|
+
"task-runner",
|
|
39
|
+
"batch-execution",
|
|
40
|
+
"duplicate-detection",
|
|
41
|
+
"workflow"
|
|
36
42
|
],
|
|
37
43
|
"author": {
|
|
38
44
|
"name": "Sumit Chauhan",
|
|
@@ -48,11 +54,12 @@
|
|
|
48
54
|
},
|
|
49
55
|
"homepage": "https://github.com/halloffame12/forgestack-os#readme",
|
|
50
56
|
"engines": {
|
|
51
|
-
"node": ">=
|
|
57
|
+
"node": ">=18"
|
|
52
58
|
},
|
|
53
59
|
"dependencies": {
|
|
54
60
|
"chalk": "^4.1.2",
|
|
55
61
|
"commander": "^13.0.0",
|
|
62
|
+
"crypto": "^1.0.1",
|
|
56
63
|
"ejs": "^3.1.10",
|
|
57
64
|
"execa": "^5.1.1",
|
|
58
65
|
"fs-extra": "^11.2.0",
|