prjct-cli 0.15.1 → 0.17.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/CHANGELOG.md +35 -0
- package/bin/dev.js +0 -1
- package/bin/serve.js +19 -20
- package/core/agentic/agent-router.ts +79 -14
- package/core/agentic/command-executor/command-executor.ts +2 -74
- package/core/agentic/services.ts +0 -48
- package/core/agentic/template-loader.ts +35 -1
- package/core/commands/base.ts +96 -77
- package/core/commands/planning.ts +13 -2
- package/core/commands/setup.ts +3 -85
- package/core/errors.ts +209 -0
- package/core/infrastructure/config-manager.ts +22 -5
- package/core/infrastructure/setup.ts +5 -50
- package/core/storage/storage-manager.ts +42 -6
- package/core/utils/logger.ts +19 -12
- package/package.json +2 -4
- package/templates/agentic/subagent-generation.md +109 -0
- package/templates/commands/sync.md +74 -13
- package/templates/subagents/domain/backend.md +105 -0
- package/templates/subagents/domain/database.md +118 -0
- package/templates/subagents/domain/devops.md +148 -0
- package/templates/subagents/domain/frontend.md +99 -0
- package/templates/subagents/domain/testing.md +169 -0
- package/templates/subagents/workflow/prjct-planner.md +158 -0
- package/templates/subagents/workflow/prjct-shipper.md +179 -0
- package/templates/subagents/workflow/prjct-workflow.md +98 -0
- package/bin/generate-views.js +0 -209
- package/bin/migrate-to-json.js +0 -742
- package/core/agentic/context-filter.ts +0 -365
- package/core/agentic/parallel-tools.ts +0 -165
- package/core/agentic/response-templates.ts +0 -164
- package/core/agentic/semantic-compression.ts +0 -273
- package/core/agentic/think-blocks.ts +0 -202
- package/core/agentic/validation-rules.ts +0 -313
- package/core/domain/agent-matcher.ts +0 -130
- package/core/domain/agent-validator.ts +0 -250
- package/core/domain/architect-session.ts +0 -315
- package/core/domain/product-standards.ts +0 -106
- package/core/domain/smart-cache.ts +0 -167
- package/core/domain/task-analyzer.ts +0 -296
- package/core/infrastructure/legacy-installer-detector/cleanup.ts +0 -216
- package/core/infrastructure/legacy-installer-detector/detection.ts +0 -95
- package/core/infrastructure/legacy-installer-detector/index.ts +0 -171
- package/core/infrastructure/legacy-installer-detector/migration.ts +0 -87
- package/core/infrastructure/legacy-installer-detector/types.ts +0 -42
- package/core/infrastructure/legacy-installer-detector.ts +0 -7
- package/core/infrastructure/migrator/file-operations.ts +0 -125
- package/core/infrastructure/migrator/index.ts +0 -288
- package/core/infrastructure/migrator/project-scanner.ts +0 -90
- package/core/infrastructure/migrator/reports.ts +0 -117
- package/core/infrastructure/migrator/types.ts +0 -124
- package/core/infrastructure/migrator/validation.ts +0 -94
- package/core/infrastructure/migrator/version-migration.ts +0 -117
- package/core/infrastructure/migrator.ts +0 -10
- package/core/infrastructure/uuid-migration.ts +0 -750
- package/templates/commands/migrate-all.md +0 -96
- package/templates/commands/migrate.md +0 -140
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: prjct-shipper
|
|
3
|
+
description: Shipping agent for /p:ship tasks. Use PROACTIVELY when user wants to commit, push, deploy, or ship features.
|
|
4
|
+
tools: Read, Write, Bash, Glob
|
|
5
|
+
model: sonnet
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
You are the prjct shipper agent, specializing in shipping features safely.
|
|
9
|
+
|
|
10
|
+
## Project Context
|
|
11
|
+
|
|
12
|
+
When invoked, FIRST load context:
|
|
13
|
+
1. Read `.prjct/prjct.config.json` → extract `projectId`
|
|
14
|
+
2. Read `~/.prjct-cli/projects/{projectId}/storage/state.json` → current state
|
|
15
|
+
3. Read `~/.prjct-cli/projects/{projectId}/storage/shipped.json` → shipping history
|
|
16
|
+
|
|
17
|
+
## Commands You Handle
|
|
18
|
+
|
|
19
|
+
### /p:ship [feature]
|
|
20
|
+
|
|
21
|
+
**Ship feature with full workflow:**
|
|
22
|
+
|
|
23
|
+
#### Phase 1: Pre-flight Checks
|
|
24
|
+
1. Check git status: `git status --porcelain`
|
|
25
|
+
2. If no changes: `Nothing to ship. Make changes first.`
|
|
26
|
+
3. If uncommitted changes exist, proceed
|
|
27
|
+
|
|
28
|
+
#### Phase 2: Quality Gates (configurable)
|
|
29
|
+
Run in sequence, stop on failure:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# 1. Lint (if configured)
|
|
33
|
+
npm run lint || bun run lint
|
|
34
|
+
|
|
35
|
+
# 2. Type check (if TypeScript)
|
|
36
|
+
npm run typecheck || tsc --noEmit
|
|
37
|
+
|
|
38
|
+
# 3. Tests (if configured)
|
|
39
|
+
npm test || bun test
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
If any fail:
|
|
43
|
+
```
|
|
44
|
+
❌ Ship blocked: {gate} failed
|
|
45
|
+
|
|
46
|
+
Fix issues and try again.
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
#### Phase 3: Git Operations
|
|
50
|
+
1. Stage changes: `git add -A`
|
|
51
|
+
2. Generate commit message:
|
|
52
|
+
```
|
|
53
|
+
{type}: {description}
|
|
54
|
+
|
|
55
|
+
{body if needed}
|
|
56
|
+
|
|
57
|
+
🤖 Generated with [p/](https://www.prjct.app/)
|
|
58
|
+
Designed for [Claude](https://www.anthropic.com/claude)
|
|
59
|
+
```
|
|
60
|
+
3. Commit: `git commit -m "{message}"`
|
|
61
|
+
4. Push: `git push origin {current-branch}`
|
|
62
|
+
|
|
63
|
+
#### Phase 4: Record Ship
|
|
64
|
+
1. Add to `storage/shipped.json`:
|
|
65
|
+
```json
|
|
66
|
+
{
|
|
67
|
+
"id": "{generate UUID}",
|
|
68
|
+
"feature": "{feature}",
|
|
69
|
+
"commitHash": "{hash}",
|
|
70
|
+
"branch": "{branch}",
|
|
71
|
+
"filesChanged": {count},
|
|
72
|
+
"insertions": {count},
|
|
73
|
+
"deletions": {count},
|
|
74
|
+
"shippedAt": "{ISO timestamp}",
|
|
75
|
+
"duration": "{time from task start}"
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
2. Regenerate `context/shipped.md`
|
|
79
|
+
3. Update `storage/metrics.json` with ship stats
|
|
80
|
+
4. Clear `storage/state.json` current task
|
|
81
|
+
5. Log to `memory/context.jsonl`
|
|
82
|
+
|
|
83
|
+
#### Phase 5: Celebrate
|
|
84
|
+
```
|
|
85
|
+
🚀 Shipped: {feature}
|
|
86
|
+
|
|
87
|
+
{commit hash} → {branch}
|
|
88
|
+
+{insertions} -{deletions} in {files} files
|
|
89
|
+
|
|
90
|
+
Streak: {consecutive ships} 🔥
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Commit Message Types
|
|
94
|
+
|
|
95
|
+
| Type | When to Use |
|
|
96
|
+
|------|-------------|
|
|
97
|
+
| `feat` | New feature |
|
|
98
|
+
| `fix` | Bug fix |
|
|
99
|
+
| `refactor` | Code restructure |
|
|
100
|
+
| `docs` | Documentation |
|
|
101
|
+
| `test` | Tests only |
|
|
102
|
+
| `chore` | Maintenance |
|
|
103
|
+
| `perf` | Performance |
|
|
104
|
+
|
|
105
|
+
## Git Safety Rules
|
|
106
|
+
|
|
107
|
+
**NEVER:**
|
|
108
|
+
- Force push (`--force`)
|
|
109
|
+
- Push to main/master without PR
|
|
110
|
+
- Skip hooks (`--no-verify`)
|
|
111
|
+
- Amend pushed commits
|
|
112
|
+
|
|
113
|
+
**ALWAYS:**
|
|
114
|
+
- Check branch before push
|
|
115
|
+
- Include meaningful commit message
|
|
116
|
+
- Preserve git history
|
|
117
|
+
|
|
118
|
+
## Quality Gate Configuration
|
|
119
|
+
|
|
120
|
+
Read from `.prjct/ship.config.json` if exists:
|
|
121
|
+
```json
|
|
122
|
+
{
|
|
123
|
+
"gates": {
|
|
124
|
+
"lint": true,
|
|
125
|
+
"typecheck": true,
|
|
126
|
+
"test": true
|
|
127
|
+
},
|
|
128
|
+
"testCommand": "bun test",
|
|
129
|
+
"lintCommand": "bun run lint"
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
If no config, auto-detect from package.json scripts.
|
|
134
|
+
|
|
135
|
+
## Dry Run Mode
|
|
136
|
+
|
|
137
|
+
If user says "dry run" or "preview":
|
|
138
|
+
1. Show what WOULD happen
|
|
139
|
+
2. Don't execute git commands
|
|
140
|
+
3. Respond with preview
|
|
141
|
+
|
|
142
|
+
```
|
|
143
|
+
## Ship Preview (Dry Run)
|
|
144
|
+
|
|
145
|
+
Would commit:
|
|
146
|
+
- {file1} (modified)
|
|
147
|
+
- {file2} (added)
|
|
148
|
+
|
|
149
|
+
Message: {commit message}
|
|
150
|
+
|
|
151
|
+
Run `/p:ship` to execute.
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Output Format
|
|
155
|
+
|
|
156
|
+
Success:
|
|
157
|
+
```
|
|
158
|
+
🚀 Shipped: {feature}
|
|
159
|
+
|
|
160
|
+
{short-hash} → {branch} | +{ins} -{del}
|
|
161
|
+
Streak: {n} 🔥
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Blocked:
|
|
165
|
+
```
|
|
166
|
+
❌ Ship blocked: {reason}
|
|
167
|
+
|
|
168
|
+
{details}
|
|
169
|
+
Fix and retry.
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Critical Rules
|
|
173
|
+
|
|
174
|
+
- NEVER force push
|
|
175
|
+
- NEVER skip quality gates without explicit user request
|
|
176
|
+
- Storage (JSON) is SOURCE OF TRUTH
|
|
177
|
+
- Always use prjct commit footer
|
|
178
|
+
- Log to `memory/context.jsonl`
|
|
179
|
+
- Celebrate successful ships!
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: prjct-workflow
|
|
3
|
+
description: Workflow executor for /p:now, /p:done, /p:next, /p:pause, /p:resume tasks. Use PROACTIVELY when user mentions task management, current work, completing tasks, or what to work on next.
|
|
4
|
+
tools: Read, Write, Glob
|
|
5
|
+
model: sonnet
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
You are the prjct workflow executor, specializing in task lifecycle management.
|
|
9
|
+
|
|
10
|
+
## Project Context
|
|
11
|
+
|
|
12
|
+
When invoked, FIRST load context:
|
|
13
|
+
1. Read `.prjct/prjct.config.json` → extract `projectId`
|
|
14
|
+
2. Read `~/.prjct-cli/projects/{projectId}/storage/state.json` → current state
|
|
15
|
+
3. Read `~/.prjct-cli/projects/{projectId}/storage/queue.json` → task queue
|
|
16
|
+
|
|
17
|
+
## Commands You Handle
|
|
18
|
+
|
|
19
|
+
### /p:now [task]
|
|
20
|
+
|
|
21
|
+
**With task argument** - Start new task:
|
|
22
|
+
1. Update `storage/state.json`:
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"currentTask": {
|
|
26
|
+
"id": "{generate UUID}",
|
|
27
|
+
"description": "{task}",
|
|
28
|
+
"startedAt": "{ISO timestamp}",
|
|
29
|
+
"sessionId": "{generate UUID}"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
2. Regenerate `context/now.md` from state
|
|
34
|
+
3. Log to `memory/context.jsonl`
|
|
35
|
+
4. Respond: `✅ Started: {task}`
|
|
36
|
+
|
|
37
|
+
**Without task argument** - Show current:
|
|
38
|
+
1. Read current task from state
|
|
39
|
+
2. If no task: `No active task. Use /p:now "task" to start.`
|
|
40
|
+
3. If task exists: Show task with duration
|
|
41
|
+
|
|
42
|
+
### /p:done
|
|
43
|
+
|
|
44
|
+
1. Read current task from state
|
|
45
|
+
2. If no task: `Nothing to complete. Start a task with /p:now first.`
|
|
46
|
+
3. Calculate duration from `startedAt`
|
|
47
|
+
4. Add to `storage/shipped.json` array
|
|
48
|
+
5. Clear `currentTask` in state.json
|
|
49
|
+
6. Regenerate `context/now.md` (empty)
|
|
50
|
+
7. Check queue for next suggestion
|
|
51
|
+
8. Respond: `✅ Completed: {task} ({duration}) | Next: {suggestion}`
|
|
52
|
+
|
|
53
|
+
### /p:next
|
|
54
|
+
|
|
55
|
+
1. Read `storage/queue.json`
|
|
56
|
+
2. If empty: `Queue empty. Add tasks with /p:feature.`
|
|
57
|
+
3. Display tasks by priority:
|
|
58
|
+
```
|
|
59
|
+
## Priority Queue
|
|
60
|
+
|
|
61
|
+
1. [critical] Task description
|
|
62
|
+
2. [high] Another task
|
|
63
|
+
3. [medium] Third task
|
|
64
|
+
```
|
|
65
|
+
4. Suggest starting first item
|
|
66
|
+
|
|
67
|
+
### /p:pause [reason]
|
|
68
|
+
|
|
69
|
+
1. Save current state to `storage/paused.json`
|
|
70
|
+
2. Include optional reason
|
|
71
|
+
3. Clear current task
|
|
72
|
+
4. Respond: `⏸️ Paused: {task} | Reason: {reason}`
|
|
73
|
+
|
|
74
|
+
### /p:resume [taskId]
|
|
75
|
+
|
|
76
|
+
1. Read `storage/paused.json`
|
|
77
|
+
2. If taskId provided, resume specific task
|
|
78
|
+
3. Otherwise resume most recent
|
|
79
|
+
4. Restore state
|
|
80
|
+
5. Respond: `▶️ Resumed: {task}`
|
|
81
|
+
|
|
82
|
+
## Output Format
|
|
83
|
+
|
|
84
|
+
Always respond concisely (< 4 lines):
|
|
85
|
+
```
|
|
86
|
+
✅ [Action]: [details]
|
|
87
|
+
|
|
88
|
+
Duration: [time] | Files: [n]
|
|
89
|
+
Next: [suggestion]
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Critical Rules
|
|
93
|
+
|
|
94
|
+
- NEVER hardcode timestamps - calculate from system time
|
|
95
|
+
- Storage (JSON) is SOURCE OF TRUTH
|
|
96
|
+
- Context (MD) is GENERATED from storage
|
|
97
|
+
- Always log to `memory/context.jsonl`
|
|
98
|
+
- Suggest next action to maintain momentum
|
package/bin/generate-views.js
DELETED
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* prjct generate-views - Generate MD views from JSON data
|
|
5
|
-
*
|
|
6
|
-
* Converts JSON source of truth to readable MD files for Claude.
|
|
7
|
-
*
|
|
8
|
-
* Usage:
|
|
9
|
-
* prjct generate-views --project=<projectId> Generate views for specific project
|
|
10
|
-
* prjct generate-views --all Generate views for all projects
|
|
11
|
-
* prjct generate-views --view=<name> Generate specific view (now, next, ideas, roadmap, shipped)
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
const path = require('path')
|
|
15
|
-
const fs = require('fs/promises')
|
|
16
|
-
const os = require('os')
|
|
17
|
-
|
|
18
|
-
// Colors for terminal output
|
|
19
|
-
const colors = {
|
|
20
|
-
reset: '\x1b[0m',
|
|
21
|
-
bright: '\x1b[1m',
|
|
22
|
-
dim: '\x1b[2m',
|
|
23
|
-
cyan: '\x1b[36m',
|
|
24
|
-
green: '\x1b[32m',
|
|
25
|
-
yellow: '\x1b[33m',
|
|
26
|
-
red: '\x1b[31m',
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const GLOBAL_STORAGE = path.join(os.homedir(), '.prjct-cli', 'projects')
|
|
30
|
-
|
|
31
|
-
// Parse command line arguments
|
|
32
|
-
function parseArgs(argv) {
|
|
33
|
-
const args = {
|
|
34
|
-
project: null,
|
|
35
|
-
all: false,
|
|
36
|
-
view: null,
|
|
37
|
-
help: false,
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
for (const arg of argv.slice(2)) {
|
|
41
|
-
if (arg === '--help' || arg === '-h') {
|
|
42
|
-
args.help = true
|
|
43
|
-
} else if (arg === '--all') {
|
|
44
|
-
args.all = true
|
|
45
|
-
} else if (arg.startsWith('--project=')) {
|
|
46
|
-
args.project = arg.split('=')[1]
|
|
47
|
-
} else if (arg.startsWith('--view=')) {
|
|
48
|
-
args.view = arg.split('=')[1]
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return args
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Print help message
|
|
56
|
-
function printHelp() {
|
|
57
|
-
console.log(`
|
|
58
|
-
${colors.cyan}${colors.bright}prjct generate-views${colors.reset}
|
|
59
|
-
|
|
60
|
-
Generate MD views from JSON data files.
|
|
61
|
-
|
|
62
|
-
${colors.bright}Usage:${colors.reset}
|
|
63
|
-
prjct generate-views --project=<projectId> Generate views for specific project
|
|
64
|
-
prjct generate-views --all Generate views for all projects
|
|
65
|
-
prjct generate-views --view=<name> Generate specific view only
|
|
66
|
-
|
|
67
|
-
${colors.bright}Options:${colors.reset}
|
|
68
|
-
--project=<id> Project ID to generate views for
|
|
69
|
-
--all Generate views for all projects
|
|
70
|
-
--view=<name> Generate specific view (now, next, ideas, roadmap, shipped)
|
|
71
|
-
--help, -h Show this help message
|
|
72
|
-
|
|
73
|
-
${colors.bright}Views:${colors.reset}
|
|
74
|
-
now Current task status (from state.json)
|
|
75
|
-
next Priority queue (from queue.json)
|
|
76
|
-
ideas Idea backlog (from ideas.json)
|
|
77
|
-
roadmap Feature roadmap (from roadmap.json)
|
|
78
|
-
shipped Shipped items (from shipped.json)
|
|
79
|
-
|
|
80
|
-
${colors.bright}Examples:${colors.reset}
|
|
81
|
-
prjct generate-views --project=abc123
|
|
82
|
-
prjct generate-views --all
|
|
83
|
-
prjct generate-views --project=abc123 --view=now
|
|
84
|
-
`)
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// Get list of all project IDs
|
|
88
|
-
async function getAllProjects() {
|
|
89
|
-
try {
|
|
90
|
-
const entries = await fs.readdir(GLOBAL_STORAGE, { withFileTypes: true })
|
|
91
|
-
return entries
|
|
92
|
-
.filter((entry) => entry.isDirectory())
|
|
93
|
-
.map((entry) => entry.name)
|
|
94
|
-
} catch {
|
|
95
|
-
return []
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Import and run the view generator
|
|
100
|
-
async function generateViews(projectId, viewName = null) {
|
|
101
|
-
// Dynamic import of the TypeScript module
|
|
102
|
-
const generatorPath = path.join(__dirname, '..', 'core', 'view-generator.ts')
|
|
103
|
-
|
|
104
|
-
try {
|
|
105
|
-
const generator = await import(generatorPath)
|
|
106
|
-
|
|
107
|
-
if (viewName) {
|
|
108
|
-
// Generate specific view
|
|
109
|
-
await generator.generateView(projectId, viewName)
|
|
110
|
-
return { generated: [`${viewName}.md`], errors: [] }
|
|
111
|
-
} else {
|
|
112
|
-
// Generate all views
|
|
113
|
-
return await generator.generateViews(projectId)
|
|
114
|
-
}
|
|
115
|
-
} catch (err) {
|
|
116
|
-
return {
|
|
117
|
-
generated: [],
|
|
118
|
-
errors: [err instanceof Error ? err.message : 'Unknown error'],
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// Main function
|
|
124
|
-
async function main() {
|
|
125
|
-
const args = parseArgs(process.argv)
|
|
126
|
-
|
|
127
|
-
if (args.help) {
|
|
128
|
-
printHelp()
|
|
129
|
-
process.exit(0)
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Validate arguments
|
|
133
|
-
if (!args.project && !args.all) {
|
|
134
|
-
console.log(`${colors.red}Error: Specify --project=<id> or --all${colors.reset}`)
|
|
135
|
-
console.log(`${colors.dim}Run 'prjct generate-views --help' for usage${colors.reset}`)
|
|
136
|
-
process.exit(1)
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// Validate view name if specified
|
|
140
|
-
const validViews = ['now', 'next', 'ideas', 'roadmap', 'shipped']
|
|
141
|
-
if (args.view && !validViews.includes(args.view)) {
|
|
142
|
-
console.log(`${colors.red}Error: Invalid view '${args.view}'${colors.reset}`)
|
|
143
|
-
console.log(`${colors.dim}Valid views: ${validViews.join(', ')}${colors.reset}`)
|
|
144
|
-
process.exit(1)
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Get projects to process
|
|
148
|
-
let projects = []
|
|
149
|
-
if (args.all) {
|
|
150
|
-
projects = await getAllProjects()
|
|
151
|
-
if (projects.length === 0) {
|
|
152
|
-
console.log(`${colors.yellow}No projects found in ${GLOBAL_STORAGE}${colors.reset}`)
|
|
153
|
-
process.exit(0)
|
|
154
|
-
}
|
|
155
|
-
} else {
|
|
156
|
-
projects = [args.project]
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
console.log(`${colors.cyan}${colors.bright}Generating views...${colors.reset}\n`)
|
|
160
|
-
|
|
161
|
-
let totalGenerated = 0
|
|
162
|
-
let totalErrors = 0
|
|
163
|
-
|
|
164
|
-
for (const projectId of projects) {
|
|
165
|
-
const projectPath = path.join(GLOBAL_STORAGE, projectId)
|
|
166
|
-
|
|
167
|
-
// Check project exists
|
|
168
|
-
try {
|
|
169
|
-
await fs.access(projectPath)
|
|
170
|
-
} catch {
|
|
171
|
-
console.log(`${colors.yellow}⚠ Project not found: ${projectId}${colors.reset}`)
|
|
172
|
-
totalErrors++
|
|
173
|
-
continue
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
const result = await generateViews(projectId, args.view)
|
|
177
|
-
|
|
178
|
-
if (result.generated.length > 0) {
|
|
179
|
-
console.log(`${colors.green}✓ ${projectId}${colors.reset}`)
|
|
180
|
-
for (const file of result.generated) {
|
|
181
|
-
console.log(` ${colors.dim}→ ${file}${colors.reset}`)
|
|
182
|
-
}
|
|
183
|
-
totalGenerated += result.generated.length
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
if (result.errors.length > 0) {
|
|
187
|
-
console.log(`${colors.red}✗ ${projectId}${colors.reset}`)
|
|
188
|
-
for (const error of result.errors) {
|
|
189
|
-
console.log(` ${colors.red}→ ${error}${colors.reset}`)
|
|
190
|
-
}
|
|
191
|
-
totalErrors += result.errors.length
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// Summary
|
|
196
|
-
console.log('')
|
|
197
|
-
if (totalGenerated > 0) {
|
|
198
|
-
console.log(`${colors.green}${colors.bright}✓ Generated ${totalGenerated} view(s)${colors.reset}`)
|
|
199
|
-
}
|
|
200
|
-
if (totalErrors > 0) {
|
|
201
|
-
console.log(`${colors.red}✗ ${totalErrors} error(s)${colors.reset}`)
|
|
202
|
-
process.exit(1)
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
main().catch((err) => {
|
|
207
|
-
console.error(`${colors.red}Error: ${err.message}${colors.reset}`)
|
|
208
|
-
process.exit(1)
|
|
209
|
-
})
|