forgestack-os-cli 0.3.4 → 0.3.5
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 +221 -15
- 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 +14 -0
- package/dist/index.js.map +1 -1
- 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
package/README.md
CHANGED
|
@@ -30,7 +30,6 @@ forgestack-os-cli create my-app
|
|
|
30
30
|
```bash
|
|
31
31
|
npm config get prefix
|
|
32
32
|
```
|
|
33
|
-
|
|
34
33
|
2. Add it to PATH if needed:
|
|
35
34
|
- **Windows (PowerShell):** `[System.Environment]::SetEnvironmentVariable("Path", "$env:Path;C:\Users\YourUsername\AppData\Roaming\npm", [System.EnvironmentVariableTarget]::User)`
|
|
36
35
|
- **macOS/Linux:** Add `export PATH="~/.npm-global/bin:$PATH"` to `~/.bash_profile` or `~/.zshrc`
|
|
@@ -69,20 +68,20 @@ npx forgestack-os-cli create <project-name> [options]
|
|
|
69
68
|
|
|
70
69
|
### Available Options
|
|
71
70
|
|
|
72
|
-
| Option
|
|
73
|
-
|
|
74
|
-
| `--frontend`
|
|
75
|
-
| `--backend`
|
|
76
|
-
| `--auth`
|
|
77
|
-
| `--database`
|
|
78
|
-
| `--api`
|
|
79
|
-
| `--preset`
|
|
80
|
-
| `--stack`
|
|
81
|
-
| `--docker`
|
|
82
|
-
| `--no-docker`
|
|
83
|
-
| `--multi-tenant` | -
|
|
84
|
-
| `--skip-install` | -
|
|
85
|
-
| `--skip-git`
|
|
71
|
+
| Option | Values | Description |
|
|
72
|
+
| ---------------- | --------------------------------------------------------------------------------- | --------------------------------------- |
|
|
73
|
+
| `--frontend` | `react-vite` \| `nextjs` \| `vue-vite` \| `sveltekit` | Frontend framework |
|
|
74
|
+
| `--backend` | `express` \| `fastify` \| `nestjs` \| `bun-elysia` \| `go-fiber` | Backend framework |
|
|
75
|
+
| `--auth` | `jwt` \| `clerk` \| `supabase` \| `authjs` \| `firebase` | Authentication provider |
|
|
76
|
+
| `--database` | `postgresql` \| `mongodb` \| `mysql` \| `sqlite` \| `supabase-db` | Database |
|
|
77
|
+
| `--api` | `rest` \| `graphql` \| `trpc` | API style |
|
|
78
|
+
| `--preset` | `next-nest-clerk-pg` \| `react-express-jwt-mongo` \| `next-fastify-supabase-trpc` | Predefined stack |
|
|
79
|
+
| `--stack` | JSON string | Full stack config as JSON |
|
|
80
|
+
| `--docker` | - | Include Docker configuration |
|
|
81
|
+
| `--no-docker` | - | Skip Docker configuration (default) |
|
|
82
|
+
| `--multi-tenant` | - | Enable multi-tenancy scaffolding |
|
|
83
|
+
| `--skip-install` | - | Skip npm install after project creation |
|
|
84
|
+
| `--skip-git` | - | Skip git initialization |
|
|
86
85
|
|
|
87
86
|
## Examples
|
|
88
87
|
|
|
@@ -97,16 +96,19 @@ You'll be guided through selecting your stack options with interactive prompts.
|
|
|
97
96
|
### Using Presets
|
|
98
97
|
|
|
99
98
|
**Next.js + NestJS + Clerk + PostgreSQL (Full-featured):**
|
|
99
|
+
|
|
100
100
|
```bash
|
|
101
101
|
npx forgestack-os-cli create my-enterprise --preset next-nest-clerk-pg
|
|
102
102
|
```
|
|
103
103
|
|
|
104
104
|
**React + Express + JWT + MongoDB (Simple SPA):**
|
|
105
|
+
|
|
105
106
|
```bash
|
|
106
107
|
npx forgestack-os-cli create my-app --preset react-express-jwt-mongo
|
|
107
108
|
```
|
|
108
109
|
|
|
109
110
|
**Next.js + Fastify + Supabase + tRPC (Modern fullstack):**
|
|
111
|
+
|
|
110
112
|
```bash
|
|
111
113
|
npx forgestack-os-cli create my-trpc-app --preset next-fastify-supabase-trpc
|
|
112
114
|
```
|
|
@@ -114,6 +116,7 @@ npx forgestack-os-cli create my-trpc-app --preset next-fastify-supabase-trpc
|
|
|
114
116
|
### Using Flags
|
|
115
117
|
|
|
116
118
|
**RESTful API with React + Express:**
|
|
119
|
+
|
|
117
120
|
```bash
|
|
118
121
|
npx forgestack-os-cli create my-rest-api \
|
|
119
122
|
--frontend react-vite \
|
|
@@ -124,6 +127,7 @@ npx forgestack-os-cli create my-rest-api \
|
|
|
124
127
|
```
|
|
125
128
|
|
|
126
129
|
**GraphQL Backend with Vue:**
|
|
130
|
+
|
|
127
131
|
```bash
|
|
128
132
|
npx forgestack-os-cli create my-graphql-app \
|
|
129
133
|
--frontend vue-vite \
|
|
@@ -135,6 +139,7 @@ npx forgestack-os-cli create my-graphql-app \
|
|
|
135
139
|
```
|
|
136
140
|
|
|
137
141
|
**Minimal Setup (SQLite + No Docker):**
|
|
142
|
+
|
|
138
143
|
```bash
|
|
139
144
|
npx forgestack-os-cli create my-minimal-app \
|
|
140
145
|
--frontend react-vite \
|
|
@@ -161,6 +166,7 @@ npx forgestack-os-cli create my-custom-stack --stack '{
|
|
|
161
166
|
```
|
|
162
167
|
|
|
163
168
|
**Multi-tenancy with Docker:**
|
|
169
|
+
|
|
164
170
|
```bash
|
|
165
171
|
npx forgestack-os-cli create my-multitenant-app \
|
|
166
172
|
--preset next-nest-clerk-pg \
|
|
@@ -169,14 +175,207 @@ npx forgestack-os-cli create my-multitenant-app \
|
|
|
169
175
|
```
|
|
170
176
|
|
|
171
177
|
**Skip Dependency Installation:**
|
|
178
|
+
|
|
172
179
|
```bash
|
|
173
180
|
npx forgestack-os-cli create my-app --preset next-nest-clerk-pg --skip-install
|
|
174
181
|
cd my-app
|
|
175
182
|
npm install # Install later when you're ready
|
|
176
183
|
```
|
|
177
184
|
|
|
185
|
+
## Additional Commands
|
|
186
|
+
|
|
187
|
+
### `organize` - File Organization Utility
|
|
188
|
+
|
|
189
|
+
Organize files in a folder by type or date, with optional duplicate detection. Supports MD5-based duplicate identification and automatic system folder exclusion for performance.
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
npx forgestack-os-cli organize <folder-path> [options]
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
**Options:**
|
|
196
|
+
- `--strategy <type>` - Organization strategy: `type` (default) or `date`
|
|
197
|
+
- `--duplicates` - Move duplicate files to a `Duplicates` folder
|
|
198
|
+
|
|
199
|
+
**File Categories (when using `--strategy type`):**
|
|
200
|
+
- **Images**: jpg, png, gif, svg, webp, bmp, ico
|
|
201
|
+
- **Documents**: pdf, doc, docx, txt, xlsx, csv, md
|
|
202
|
+
- **Videos**: mp4, mkv, avi, mov, wmv, flv
|
|
203
|
+
- **Audio**: mp3, wav, flac, aac, m4a, ogg
|
|
204
|
+
- **Code**: js, ts, py, java, cpp, go, rs, rb
|
|
205
|
+
- **Archives**: zip, rar, 7z, tar, gz, bz2
|
|
206
|
+
- **Data**: json, xml, yaml, sql, db, sqlite
|
|
207
|
+
- **Executables**: exe, msi, app, deb, rpm
|
|
208
|
+
- **Others**: All other file types
|
|
209
|
+
|
|
210
|
+
**Date Format (when using `--strategy date`):**
|
|
211
|
+
Files organized into folders using format: `YYYY-MM` (e.g., `2026-01`, `2025-12`)
|
|
212
|
+
|
|
213
|
+
**Features:**
|
|
214
|
+
- ✅ Automatically skips system folders (node_modules, .git, dist, build, .next, .env, .DS_Store, .vscode)
|
|
215
|
+
- ✅ MD5-based duplicate detection (prevents moving the same file twice)
|
|
216
|
+
- ✅ Graceful error handling for permission denied or inaccessible files
|
|
217
|
+
- ✅ Summary report showing total files organized and categories
|
|
218
|
+
- ✅ Interactive prompts if options not provided
|
|
219
|
+
|
|
220
|
+
**Examples:**
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
# Organize by file type with duplicate detection
|
|
224
|
+
npx forgestack-os-cli organize ~/Downloads --strategy type --duplicates
|
|
225
|
+
|
|
226
|
+
# Organize photos by month
|
|
227
|
+
npx forgestack-os-cli organize ~/Pictures --strategy date
|
|
228
|
+
|
|
229
|
+
# Interactive mode (prompts for folder and options)
|
|
230
|
+
npx forgestack-os-cli organize
|
|
231
|
+
|
|
232
|
+
# Organize current directory
|
|
233
|
+
npx forgestack-os-cli organize .
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
**Output Example:**
|
|
237
|
+
```
|
|
238
|
+
✓ Found and organized 1,250 files
|
|
239
|
+
✓ Categories:
|
|
240
|
+
- Images: 450 files
|
|
241
|
+
- Documents: 280 files
|
|
242
|
+
- Videos: 320 files
|
|
243
|
+
- Code: 145 files
|
|
244
|
+
- Others: 55 files
|
|
245
|
+
✓ Found 12 set(s) of duplicate files moved to Duplicates folder
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
**Edge Cases Handled:**
|
|
249
|
+
- Empty folders: Displays "No files to organize" message
|
|
250
|
+
- Invalid paths: Shows clear error message with validation
|
|
251
|
+
- Permission errors: Skips files with access denied, continues processing
|
|
252
|
+
- Unreadable files: Skips during hash calculation, no crash
|
|
253
|
+
- Large monorepos: Excludes node_modules, .git, and build folders automatically
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
### `run-tasks` - Batch Task Runner
|
|
258
|
+
|
|
259
|
+
Execute shell commands from a JSON configuration file, sequentially or in parallel. Supports task-specific working directories and comprehensive error handling.
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
npx forgestack-os-cli run-tasks <config-path> [options]
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
**Options:**
|
|
266
|
+
- `--parallel` - Run tasks concurrently instead of sequentially (default: false)
|
|
267
|
+
- `--stop-on-error` - Stop execution on first task failure (default: true)
|
|
268
|
+
|
|
269
|
+
**Config File Format (tasks.json):**
|
|
270
|
+
|
|
271
|
+
```json
|
|
272
|
+
{
|
|
273
|
+
"tasks": [
|
|
274
|
+
{
|
|
275
|
+
"name": "Build",
|
|
276
|
+
"command": "npm run build",
|
|
277
|
+
"cwd": "./"
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
"name": "Test",
|
|
281
|
+
"command": "npm test",
|
|
282
|
+
"cwd": "./"
|
|
283
|
+
}
|
|
284
|
+
],
|
|
285
|
+
"parallel": false,
|
|
286
|
+
"stopOnError": true
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
**Features:**
|
|
291
|
+
- ✅ Cross-platform shell execution (Windows CMD, Unix bash)
|
|
292
|
+
- ✅ Task-specific working directory support
|
|
293
|
+
- ✅ Sequential or parallel execution modes
|
|
294
|
+
- ✅ Configurable failure handling
|
|
295
|
+
- ✅ Comprehensive error reporting
|
|
296
|
+
- ✅ Interactive mode with default config file detection
|
|
297
|
+
- ✅ Proper exit codes for CI/CD integration
|
|
298
|
+
|
|
299
|
+
**Examples:**
|
|
300
|
+
|
|
301
|
+
```bash
|
|
302
|
+
# Run tasks sequentially (stops on first error)
|
|
303
|
+
npx forgestack-os-cli run-tasks ./tasks.json
|
|
304
|
+
|
|
305
|
+
# Run tasks in parallel
|
|
306
|
+
npx forgestack-os-cli run-tasks ./tasks.json --parallel
|
|
307
|
+
|
|
308
|
+
# Continue on errors
|
|
309
|
+
npx forgestack-os-cli run-tasks ./tasks.json --stop-on-error false
|
|
310
|
+
|
|
311
|
+
# Interactive mode (looks for ./tasks.json automatically)
|
|
312
|
+
npx forgestack-os-cli run-tasks
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
**Task Properties:**
|
|
316
|
+
- `name` (required) - Display name for the task (for logging)
|
|
317
|
+
- `command` (required) - Shell command to execute
|
|
318
|
+
- `cwd` (optional) - Working directory for command execution (must exist)
|
|
319
|
+
|
|
320
|
+
**Example: Monorepo Build Pipeline**
|
|
321
|
+
|
|
322
|
+
```json
|
|
323
|
+
{
|
|
324
|
+
"tasks": [
|
|
325
|
+
{
|
|
326
|
+
"name": "Clean Build Artifacts",
|
|
327
|
+
"command": "rm -rf dist"
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
"name": "Build Frontend",
|
|
331
|
+
"command": "npm run build",
|
|
332
|
+
"cwd": "./packages/frontend"
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
"name": "Build Backend",
|
|
336
|
+
"command": "npm run build",
|
|
337
|
+
"cwd": "./packages/backend"
|
|
338
|
+
},
|
|
339
|
+
{
|
|
340
|
+
"name": "Run Tests",
|
|
341
|
+
"command": "npm test",
|
|
342
|
+
"cwd": "./packages/backend"
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
"name": "Generate Docs",
|
|
346
|
+
"command": "npm run docs"
|
|
347
|
+
}
|
|
348
|
+
],
|
|
349
|
+
"parallel": false,
|
|
350
|
+
"stopOnError": true
|
|
351
|
+
}
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
**Output Example:**
|
|
355
|
+
```
|
|
356
|
+
⏳ Running tasks sequentially...
|
|
357
|
+
✓ Task 1/5: Clean Build Artifacts completed
|
|
358
|
+
✓ Task 2/5: Build Frontend completed
|
|
359
|
+
✓ Task 3/5: Build Backend completed
|
|
360
|
+
✓ Task 4/5: Run Tests completed
|
|
361
|
+
✓ Task 5/5: Generate Docs completed
|
|
362
|
+
|
|
363
|
+
✓ All 5 tasks completed successfully
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
**Error Handling:**
|
|
367
|
+
- **Invalid config path**: Shows clear error, no crash
|
|
368
|
+
- **Malformed JSON**: Displays JSON parsing error
|
|
369
|
+
- **Missing command**: Validates all tasks have required fields
|
|
370
|
+
- **Invalid working directory**: Shows warning, continues with project root
|
|
371
|
+
- **Task execution fails**: Respects `stopOnError` flag
|
|
372
|
+
- **Cross-platform compatibility**: Automatically handles Windows vs Unix paths
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
178
376
|
## Features
|
|
179
377
|
|
|
378
|
+
### Project Generation
|
|
180
379
|
- **150+ Stack Combinations** - Frontend (React, Next.js, Vue, Svelte) × Backend (Express, Fastify, NestJS, Bun, Go) × Auth × Database × API Style
|
|
181
380
|
- **Multi-tenancy Ready** - Scaffolding support for SaaS applications
|
|
182
381
|
- **Docker Compose** - Complete Docker setup with frontend and backend services
|
|
@@ -185,6 +384,10 @@ npm install # Install later when you're ready
|
|
|
185
384
|
- **TypeScript First** - Full TypeScript support across all generated code
|
|
186
385
|
- **Production Ready** - Best practices, security headers, error handling
|
|
187
386
|
|
|
387
|
+
### Utility Commands
|
|
388
|
+
- **File Organization** (`organize`) - Sort files by type or date, with MD5-based duplicate detection and automatic system folder exclusion
|
|
389
|
+
- **Batch Task Runner** (`run-tasks`) - Execute complex workflows with sequential or parallel task execution, cross-platform compatibility, and comprehensive error handling
|
|
390
|
+
|
|
188
391
|
## Generated Project Structure
|
|
189
392
|
|
|
190
393
|
```
|
|
@@ -219,11 +422,13 @@ my-app/
|
|
|
219
422
|
### "command not found: forgestack-os-cli"
|
|
220
423
|
|
|
221
424
|
**Using npx?** Make sure you use the full package name:
|
|
425
|
+
|
|
222
426
|
```bash
|
|
223
427
|
npx forgestack-os-cli create my-app
|
|
224
428
|
```
|
|
225
429
|
|
|
226
430
|
**Installed globally?** Try:
|
|
431
|
+
|
|
227
432
|
1. Verify npm global bin is in PATH: `echo $PATH` (Unix) or `$env:Path` (Windows)
|
|
228
433
|
2. Reinstall: `npm install -g forgestack-os-cli@latest`
|
|
229
434
|
3. Check Node.js version: `node --version` (requires 18+)
|
|
@@ -255,6 +460,7 @@ npx forgestack-os-cli init my-app
|
|
|
255
460
|
### Preset not found
|
|
256
461
|
|
|
257
462
|
Available presets:
|
|
463
|
+
|
|
258
464
|
- `next-nest-clerk-pg` - Next.js, NestJS, Clerk, PostgreSQL
|
|
259
465
|
- `react-express-jwt-mongo` - React+Vite, Express, JWT, MongoDB
|
|
260
466
|
- `next-fastify-supabase-trpc` - Next.js, Fastify, Supabase, tRPC
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import inquirer from 'inquirer';
|
|
5
|
+
import { logger } from '../utils/logger.js';
|
|
6
|
+
import { organizeFilesByType, organizeFilesByDate, detectDuplicates } from '../utils/file-organizer.js';
|
|
7
|
+
export async function organizeCommand(folderPath, options, _command) {
|
|
8
|
+
try {
|
|
9
|
+
let targetPath = folderPath || '';
|
|
10
|
+
// If no folder path provided, use interactive prompt
|
|
11
|
+
if (!targetPath) {
|
|
12
|
+
const answers = await inquirer.prompt([
|
|
13
|
+
{
|
|
14
|
+
type: 'input',
|
|
15
|
+
name: 'path',
|
|
16
|
+
message: 'Enter the folder path to organize:',
|
|
17
|
+
default: process.cwd(),
|
|
18
|
+
validate: (input) => {
|
|
19
|
+
if (!input.trim())
|
|
20
|
+
return 'Path cannot be empty';
|
|
21
|
+
return true;
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
]);
|
|
25
|
+
targetPath = answers.path;
|
|
26
|
+
}
|
|
27
|
+
// Resolve to absolute path
|
|
28
|
+
const absolutePath = path.resolve(targetPath);
|
|
29
|
+
// Validate folder exists
|
|
30
|
+
if (!(await fs.pathExists(absolutePath))) {
|
|
31
|
+
logger.error(`Folder does not exist: ${absolutePath}`);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
const stats = await fs.stat(absolutePath);
|
|
35
|
+
if (!stats.isDirectory()) {
|
|
36
|
+
logger.error(`Path is not a directory: ${absolutePath}`);
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
// Get organization strategy
|
|
40
|
+
let strategy = options.strategy || '';
|
|
41
|
+
if (!['type', 'date'].includes(strategy)) {
|
|
42
|
+
const answers = await inquirer.prompt([
|
|
43
|
+
{
|
|
44
|
+
type: 'list',
|
|
45
|
+
name: 'strategy',
|
|
46
|
+
message: 'How would you like to organize files?',
|
|
47
|
+
choices: [
|
|
48
|
+
{ name: 'By File Type (images, documents, etc.)', value: 'type' },
|
|
49
|
+
{ name: 'By Date (YYYY-MM)', value: 'date' },
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
]);
|
|
53
|
+
strategy = answers.strategy;
|
|
54
|
+
}
|
|
55
|
+
// Check if user wants to handle duplicates
|
|
56
|
+
let handleDuplicates = !!options.duplicates;
|
|
57
|
+
if (!options.duplicates) {
|
|
58
|
+
const answers = await inquirer.prompt([
|
|
59
|
+
{
|
|
60
|
+
type: 'confirm',
|
|
61
|
+
name: 'duplicates',
|
|
62
|
+
message: 'Move duplicate files to a "Duplicates" folder?',
|
|
63
|
+
default: false,
|
|
64
|
+
},
|
|
65
|
+
]);
|
|
66
|
+
handleDuplicates = answers.duplicates;
|
|
67
|
+
}
|
|
68
|
+
console.log('');
|
|
69
|
+
logger.title('📁 Organizing files...');
|
|
70
|
+
// Detect duplicates if needed
|
|
71
|
+
let duplicates = new Map();
|
|
72
|
+
if (handleDuplicates) {
|
|
73
|
+
logger.info('Detecting duplicate files...');
|
|
74
|
+
duplicates = await detectDuplicates(absolutePath);
|
|
75
|
+
if (duplicates.size === 0) {
|
|
76
|
+
console.log(chalk.gray('No duplicates found.'));
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
console.log(chalk.gray(`Found ${duplicates.size} set(s) of duplicate files.`));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Organize files
|
|
83
|
+
let result;
|
|
84
|
+
if (strategy === 'type') {
|
|
85
|
+
result = await organizeFilesByType(absolutePath, duplicates);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
result = await organizeFilesByDate(absolutePath, duplicates);
|
|
89
|
+
}
|
|
90
|
+
// Display results
|
|
91
|
+
console.log('');
|
|
92
|
+
logger.success('Organization complete!');
|
|
93
|
+
console.log('');
|
|
94
|
+
console.log(chalk.bold('Summary:'));
|
|
95
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
96
|
+
let totalFilesMoved = 0;
|
|
97
|
+
const categorizedEntries = Object.entries(result.categorized);
|
|
98
|
+
if (categorizedEntries.length === 0) {
|
|
99
|
+
console.log(chalk.gray('No files to organize.'));
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
for (const [folder, count] of categorizedEntries) {
|
|
103
|
+
console.log(`${chalk.cyan('→')} ${folder}: ${chalk.bold(count)} files`);
|
|
104
|
+
totalFilesMoved += count;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (result.duplicates > 0) {
|
|
108
|
+
console.log(`${chalk.cyan('→')} Duplicates: ${chalk.bold(result.duplicates)} files`);
|
|
109
|
+
totalFilesMoved += result.duplicates;
|
|
110
|
+
}
|
|
111
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
112
|
+
console.log(`${chalk.bold('Total files moved:')} ${chalk.green(totalFilesMoved)}`);
|
|
113
|
+
console.log('');
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
logger.error('Failed to organize files');
|
|
117
|
+
if (error instanceof Error) {
|
|
118
|
+
console.error(chalk.red(error.message));
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
console.error(error);
|
|
122
|
+
}
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=organize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"organize.js","sourceRoot":"","sources":["../../src/commands/organize.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
export interface Task {
|
|
3
|
+
name: string;
|
|
4
|
+
command: string;
|
|
5
|
+
cwd?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface TasksConfig {
|
|
8
|
+
tasks: Task[];
|
|
9
|
+
parallel?: boolean;
|
|
10
|
+
stopOnError?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare function runTasksCommand(configPath: string | undefined, options: Record<string, unknown>, _command?: Command): Promise<void>;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import fs from 'fs-extra';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import inquirer from 'inquirer';
|
|
5
|
+
import { logger } from '../utils/logger.js';
|
|
6
|
+
import { executeTasksSequentially, executeTasksInParallel } from '../utils/task-runner.js';
|
|
7
|
+
export async function runTasksCommand(configPath, options, _command) {
|
|
8
|
+
try {
|
|
9
|
+
let tasksFilePath = configPath || '';
|
|
10
|
+
// If no config path provided, use interactive prompt
|
|
11
|
+
if (!tasksFilePath) {
|
|
12
|
+
const answers = await inquirer.prompt([
|
|
13
|
+
{
|
|
14
|
+
type: 'input',
|
|
15
|
+
name: 'path',
|
|
16
|
+
message: 'Enter the path to tasks.json config file:',
|
|
17
|
+
default: './tasks.json',
|
|
18
|
+
validate: (input) => {
|
|
19
|
+
if (!input.trim())
|
|
20
|
+
return 'Path cannot be empty';
|
|
21
|
+
return true;
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
]);
|
|
25
|
+
tasksFilePath = answers.path;
|
|
26
|
+
}
|
|
27
|
+
// Resolve to absolute path
|
|
28
|
+
const absolutePath = path.resolve(tasksFilePath);
|
|
29
|
+
// Validate file exists
|
|
30
|
+
if (!(await fs.pathExists(absolutePath))) {
|
|
31
|
+
logger.error(`Config file not found: ${absolutePath}`);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
// Validate it's a file
|
|
35
|
+
const stats = await fs.stat(absolutePath);
|
|
36
|
+
if (!stats.isFile()) {
|
|
37
|
+
logger.error(`Path is not a file: ${absolutePath}`);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
// Parse config file
|
|
41
|
+
let config;
|
|
42
|
+
try {
|
|
43
|
+
const fileContent = await fs.readFile(absolutePath, 'utf-8');
|
|
44
|
+
config = JSON.parse(fileContent);
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
logger.error(`Failed to parse config file: ${absolutePath}`);
|
|
48
|
+
if (error instanceof SyntaxError) {
|
|
49
|
+
console.error(chalk.red(`JSON Error: ${error.message}`));
|
|
50
|
+
}
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
// Validate config
|
|
54
|
+
if (!config.tasks || !Array.isArray(config.tasks) || config.tasks.length === 0) {
|
|
55
|
+
logger.error('Config file must contain a "tasks" array with at least one task');
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
// Validate each task
|
|
59
|
+
for (const task of config.tasks) {
|
|
60
|
+
if (!task.name || !task.command) {
|
|
61
|
+
logger.error('Each task must have a "name" and "command" field');
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
if (task.cwd && !(await fs.pathExists(task.cwd))) {
|
|
65
|
+
logger.warning(`Working directory does not exist for task "${task.name}": ${task.cwd}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Determine execution mode (CLI options override config file)
|
|
69
|
+
const parallel = options.parallel === true || (config.parallel === true && options.parallel !== false);
|
|
70
|
+
const stopOnError = options.stopOnError !== false && (config.stopOnError !== false || options.stopOnError === true);
|
|
71
|
+
console.log('');
|
|
72
|
+
logger.title('🚀 Running Tasks');
|
|
73
|
+
console.log(chalk.gray(`Total tasks: ${config.tasks.length}`));
|
|
74
|
+
console.log(chalk.gray(`Mode: ${parallel ? 'Parallel' : 'Sequential'}`));
|
|
75
|
+
console.log(chalk.gray(`Stop on error: ${stopOnError ? 'Yes' : 'No'}`));
|
|
76
|
+
console.log('');
|
|
77
|
+
// Execute tasks
|
|
78
|
+
let results;
|
|
79
|
+
if (parallel) {
|
|
80
|
+
results = await executeTasksInParallel(config.tasks, stopOnError);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
results = await executeTasksSequentially(config.tasks, stopOnError);
|
|
84
|
+
}
|
|
85
|
+
// Display results
|
|
86
|
+
console.log('');
|
|
87
|
+
logger.title('📊 Task Results');
|
|
88
|
+
console.log(chalk.gray('─'.repeat(60)));
|
|
89
|
+
let successCount = 0;
|
|
90
|
+
let failureCount = 0;
|
|
91
|
+
for (const result of results) {
|
|
92
|
+
const statusIcon = result.success ? chalk.green('✔') : chalk.red('✖');
|
|
93
|
+
const statusText = result.success ? chalk.green('SUCCESS') : chalk.red('FAILED');
|
|
94
|
+
console.log(`${statusIcon} ${chalk.bold(result.name)}: ${statusText}`);
|
|
95
|
+
if (!result.success) {
|
|
96
|
+
failureCount++;
|
|
97
|
+
if (result.error) {
|
|
98
|
+
console.log(chalk.red(` Error: ${result.error}`));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
successCount++;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
console.log(chalk.gray('─'.repeat(60)));
|
|
106
|
+
console.log('');
|
|
107
|
+
console.log(chalk.bold(`Results: ${chalk.green(`${successCount} succeeded`)} / ${chalk.red(`${failureCount} failed`)}`));
|
|
108
|
+
console.log('');
|
|
109
|
+
// Exit with appropriate code
|
|
110
|
+
if (failureCount > 0 && stopOnError) {
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
logger.error('Failed to run tasks');
|
|
116
|
+
if (error instanceof Error) {
|
|
117
|
+
console.error(chalk.red(error.message));
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
console.error(error);
|
|
121
|
+
}
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=run-tasks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-tasks.js","sourceRoot":"","sources":["../../src/commands/run-tasks.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
import { createRequire } from 'module';
|
|
3
3
|
import { Command } from 'commander';
|
|
4
4
|
import { createCommand } from './commands/create.js';
|
|
5
|
+
import { organizeCommand } from './commands/organize.js';
|
|
6
|
+
import { runTasksCommand } from './commands/run-tasks.js';
|
|
5
7
|
const pkgRequire = createRequire(import.meta.url);
|
|
6
8
|
const { version: CLI_VERSION } = pkgRequire('../package.json');
|
|
7
9
|
const program = new Command();
|
|
@@ -25,5 +27,17 @@ program
|
|
|
25
27
|
.option('--multi-tenant', 'Enable multi-tenancy')
|
|
26
28
|
.option('--skip-install', 'Skip dependency installation')
|
|
27
29
|
.option('--skip-git', 'Skip Git initialization');
|
|
30
|
+
program
|
|
31
|
+
.command('organize [folder-path]')
|
|
32
|
+
.description('Organize files by type or date')
|
|
33
|
+
.action(organizeCommand)
|
|
34
|
+
.option('--strategy <type>', 'Organization strategy: type or date')
|
|
35
|
+
.option('--duplicates', 'Move duplicate files to a Duplicates folder');
|
|
36
|
+
program
|
|
37
|
+
.command('run-tasks [config-path]')
|
|
38
|
+
.description('Run batch tasks from a JSON config file')
|
|
39
|
+
.action(runTasksCommand)
|
|
40
|
+
.option('--parallel', 'Run tasks in parallel instead of sequentially')
|
|
41
|
+
.option('--stop-on-error', 'Stop execution if any task fails');
|
|
28
42
|
program.parse();
|
|
29
43
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE1D,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,UAAU,CAAC,iBAAiB,CAAwB,CAAC;AAEtF,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACF,IAAI,CAAC,YAAY,CAAC;KAClB,WAAW,CAAC,4DAA4D,CAAC;KACzE,OAAO,CAAC,WAAW,CAAC,CAAC;AAE1B,OAAO;KACF,OAAO,CAAC,uBAAuB,CAAC;KAChC,WAAW,CAAC,0CAA0C,CAAC;KACvD,MAAM,CAAC,aAAa,CAAC;KACrB,MAAM,CAAC,wBAAwB,EAAE,oBAAoB,CAAC;KACtD,MAAM,CAAC,uBAAuB,EAAE,mBAAmB,CAAC;KACpD,MAAM,CAAC,mBAAmB,EAAE,eAAe,CAAC;KAC5C,MAAM,CAAC,iBAAiB,EAAE,UAAU,CAAC;KACrC,MAAM,CAAC,eAAe,EAAE,WAAW,CAAC;KACpC,MAAM,CAAC,iBAAiB,EAAE,+BAA+B,CAAC;KAC1D,MAAM,CAAC,gBAAgB,EAAE,mCAAmC,CAAC;KAC7D,MAAM,CAAC,UAAU,EAAE,8BAA8B,CAAC;KAClD,MAAM,CAAC,aAAa,EAAE,2BAA2B,CAAC;KAClD,MAAM,CAAC,gBAAgB,EAAE,sBAAsB,CAAC;KAChD,MAAM,CAAC,gBAAgB,EAAE,8BAA8B,CAAC;KACxD,MAAM,CAAC,YAAY,EAAE,yBAAyB,CAAC,CAAC;AAErD,OAAO;KACF,OAAO,CAAC,wBAAwB,CAAC;KACjC,WAAW,CAAC,gCAAgC,CAAC;KAC7C,MAAM,CAAC,eAAe,CAAC;KACvB,MAAM,CAAC,mBAAmB,EAAE,qCAAqC,CAAC;KAClE,MAAM,CAAC,cAAc,EAAE,6CAA6C,CAAC,CAAC;AAE3E,OAAO;KACF,OAAO,CAAC,yBAAyB,CAAC;KAClC,WAAW,CAAC,yCAAyC,CAAC;KACtD,MAAM,CAAC,eAAe,CAAC;KACvB,MAAM,CAAC,YAAY,EAAE,+CAA+C,CAAC;KACrE,MAAM,CAAC,iBAAiB,EAAE,kCAAkC,CAAC,CAAC;AAEnE,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
interface OrganizeResult {
|
|
2
|
+
categorized: Record<string, number>;
|
|
3
|
+
duplicates: number;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Detect duplicate files by hash
|
|
7
|
+
*/
|
|
8
|
+
export declare function detectDuplicates(folderPath: string): Promise<Map<string, string[]>>;
|
|
9
|
+
/**
|
|
10
|
+
* Organize files by type into categorized folders
|
|
11
|
+
*/
|
|
12
|
+
export declare function organizeFilesByType(folderPath: string, duplicates?: Map<string, string[]>): Promise<OrganizeResult>;
|
|
13
|
+
/**
|
|
14
|
+
* Organize files by date (YYYY-MM format)
|
|
15
|
+
*/
|
|
16
|
+
export declare function organizeFilesByDate(folderPath: string, duplicates?: Map<string, string[]>): Promise<OrganizeResult>;
|
|
17
|
+
export {};
|
|
@@ -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.5",
|
|
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",
|