prjct-cli 0.6.0 → 0.7.1
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 +67 -6
- package/CLAUDE.md +442 -36
- package/README.md +47 -54
- package/bin/prjct +174 -240
- package/core/agentic/command-executor.js +113 -0
- package/core/agentic/context-builder.js +85 -0
- package/core/agentic/prompt-builder.js +86 -0
- package/core/agentic/template-loader.js +104 -0
- package/core/agentic/tool-registry.js +117 -0
- package/core/command-registry.js +109 -65
- package/core/commands.js +2213 -2173
- package/core/domain/agent-generator.js +118 -0
- package/core/domain/analyzer.js +211 -0
- package/core/domain/architect-session.js +300 -0
- package/core/{agents → infrastructure/agents}/claude-agent.js +16 -13
- package/core/{author-detector.js → infrastructure/author-detector.js} +3 -1
- package/core/{capability-installer.js → infrastructure/capability-installer.js} +3 -6
- package/core/{command-installer.js → infrastructure/command-installer.js} +5 -3
- package/core/{config-manager.js → infrastructure/config-manager.js} +4 -4
- package/core/{editors-config.js → infrastructure/editors-config.js} +2 -10
- package/core/{migrator.js → infrastructure/migrator.js} +34 -19
- package/core/{path-manager.js → infrastructure/path-manager.js} +20 -44
- package/core/{session-manager.js → infrastructure/session-manager.js} +45 -105
- package/core/{update-checker.js → infrastructure/update-checker.js} +67 -67
- package/core/{animations-simple.js → utils/animations.js} +3 -23
- package/core/utils/date-helper.js +238 -0
- package/core/utils/file-helper.js +327 -0
- package/core/utils/jsonl-helper.js +206 -0
- package/core/{project-capabilities.js → utils/project-capabilities.js} +21 -22
- package/core/utils/session-helper.js +277 -0
- package/core/{version.js → utils/version.js} +1 -1
- package/package.json +4 -12
- package/templates/agents/AGENTS.md +101 -27
- package/templates/analysis/analyze.md +84 -0
- package/templates/commands/analyze.md +9 -2
- package/templates/commands/bug.md +79 -0
- package/templates/commands/build.md +5 -2
- package/templates/commands/cleanup.md +5 -2
- package/templates/commands/design.md +5 -2
- package/templates/commands/done.md +4 -2
- package/templates/commands/feature.md +113 -0
- package/templates/commands/fix.md +41 -10
- package/templates/commands/git.md +7 -2
- package/templates/commands/help.md +2 -2
- package/templates/commands/idea.md +14 -5
- package/templates/commands/init.md +62 -7
- package/templates/commands/next.md +4 -2
- package/templates/commands/now.md +4 -2
- package/templates/commands/progress.md +27 -5
- package/templates/commands/recap.md +39 -10
- package/templates/commands/roadmap.md +19 -5
- package/templates/commands/ship.md +118 -16
- package/templates/commands/status.md +4 -2
- package/templates/commands/sync.md +19 -15
- package/templates/commands/task.md +4 -2
- package/templates/commands/test.md +5 -2
- package/templates/commands/workflow.md +4 -2
- package/core/agent-generator.js +0 -525
- package/core/analyzer.js +0 -600
- package/core/animations.js +0 -277
- package/core/ascii-graphics.js +0 -433
- package/core/git-integration.js +0 -401
- package/core/task-schema.js +0 -342
- package/core/workflow-engine.js +0 -213
- package/core/workflow-prompts.js +0 -192
- package/core/workflow-rules.js +0 -147
- package/scripts/post-install.js +0 -121
- package/scripts/preuninstall.js +0 -94
- package/scripts/verify-installation.sh +0 -158
- package/templates/agents/be.template.md +0 -27
- package/templates/agents/coordinator.template.md +0 -34
- package/templates/agents/data.template.md +0 -27
- package/templates/agents/devops.template.md +0 -27
- package/templates/agents/fe.template.md +0 -27
- package/templates/agents/mobile.template.md +0 -27
- package/templates/agents/qa.template.md +0 -27
- package/templates/agents/scribe.template.md +0 -29
- package/templates/agents/security.template.md +0 -27
- package/templates/agents/ux.template.md +0 -27
- package/templates/commands/context.md +0 -36
- package/templates/commands/stuck.md +0 -36
- package/templates/examples/natural-language-examples.md +0 -532
- /package/core/{agent-detector.js → infrastructure/agent-detector.js} +0 -0
package/core/animations.js
DELETED
|
@@ -1,277 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cool animations and visual effects for prjct
|
|
3
|
-
* Using Catppuccin color palette
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const chalk = require('chalk')
|
|
7
|
-
|
|
8
|
-
if (!chalk.supportsColor) {
|
|
9
|
-
chalk.level = 3 // Full RGB color support
|
|
10
|
-
process.env.FORCE_COLOR = '3'
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const catppuccin = {
|
|
14
|
-
|
|
15
|
-
rosewater: '#f5e0dc',
|
|
16
|
-
flamingo: '#f2cdcd',
|
|
17
|
-
pink: '#f5c2e7',
|
|
18
|
-
mauve: '#cba6f7',
|
|
19
|
-
red: '#f38ba8',
|
|
20
|
-
maroon: '#eba0ac',
|
|
21
|
-
peach: '#fab387',
|
|
22
|
-
yellow: '#f9e2af',
|
|
23
|
-
green: '#a6e3a1',
|
|
24
|
-
teal: '#94e2d5',
|
|
25
|
-
sky: '#89dceb',
|
|
26
|
-
sapphire: '#74c7ec',
|
|
27
|
-
blue: '#89b4fa',
|
|
28
|
-
lavender: '#b4befe',
|
|
29
|
-
|
|
30
|
-
text: '#cdd6f4',
|
|
31
|
-
subtext1: '#bac2de',
|
|
32
|
-
subtext0: '#a6adc8',
|
|
33
|
-
overlay2: '#9399b2',
|
|
34
|
-
overlay1: '#7f849c',
|
|
35
|
-
overlay0: '#6c7086',
|
|
36
|
-
surface2: '#585b70',
|
|
37
|
-
surface1: '#45475a',
|
|
38
|
-
surface0: '#313244',
|
|
39
|
-
base: '#1e1e2e',
|
|
40
|
-
mantle: '#181825',
|
|
41
|
-
crust: '#11111b',
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const colors = {
|
|
45
|
-
success: chalk.hex(catppuccin.green),
|
|
46
|
-
error: chalk.hex(catppuccin.red),
|
|
47
|
-
warning: chalk.hex(catppuccin.yellow),
|
|
48
|
-
info: chalk.hex(catppuccin.blue),
|
|
49
|
-
ship: chalk.hex(catppuccin.sapphire),
|
|
50
|
-
celebrate: chalk.hex(catppuccin.pink),
|
|
51
|
-
focus: chalk.hex(catppuccin.teal),
|
|
52
|
-
idea: chalk.hex(catppuccin.yellow),
|
|
53
|
-
progress: chalk.hex(catppuccin.lavender),
|
|
54
|
-
task: chalk.hex(catppuccin.mauve),
|
|
55
|
-
primary: chalk.hex(catppuccin.mauve),
|
|
56
|
-
secondary: chalk.hex(catppuccin.sky),
|
|
57
|
-
text: chalk.hex(catppuccin.text),
|
|
58
|
-
subtext: chalk.hex(catppuccin.subtext1),
|
|
59
|
-
dim: chalk.hex(catppuccin.overlay1),
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const frames = {
|
|
63
|
-
rocket: [
|
|
64
|
-
' 🚀 ',
|
|
65
|
-
' 🚀 ',
|
|
66
|
-
' 🚀 ',
|
|
67
|
-
' 🚀 ',
|
|
68
|
-
' 🚀 ',
|
|
69
|
-
'🚀 ',
|
|
70
|
-
],
|
|
71
|
-
sparkles: [
|
|
72
|
-
'✨ ・ 。゚☆: *.☽ .* :☆゚. ✨',
|
|
73
|
-
'・ 。゚☆: *.☽ .* :☆゚. ✨ ・',
|
|
74
|
-
'。゚☆: *.☽ .* :☆゚. ✨ ・ 。゚',
|
|
75
|
-
'☆: *.☽ .* :☆゚. ✨ ・ 。゚☆:',
|
|
76
|
-
],
|
|
77
|
-
loading: [
|
|
78
|
-
'⠋',
|
|
79
|
-
'⠙',
|
|
80
|
-
'⠹',
|
|
81
|
-
'⠸',
|
|
82
|
-
'⠼',
|
|
83
|
-
'⠴',
|
|
84
|
-
'⠦',
|
|
85
|
-
'⠧',
|
|
86
|
-
'⠇',
|
|
87
|
-
'⠏',
|
|
88
|
-
],
|
|
89
|
-
progress: [
|
|
90
|
-
'[ ]',
|
|
91
|
-
'[▓ ]',
|
|
92
|
-
'[▓▓ ]',
|
|
93
|
-
'[▓▓▓ ]',
|
|
94
|
-
'[▓▓▓▓ ]',
|
|
95
|
-
'[▓▓▓▓▓ ]',
|
|
96
|
-
'[▓▓▓▓▓▓ ]',
|
|
97
|
-
'[▓▓▓▓▓▓▓ ]',
|
|
98
|
-
'[▓▓▓▓▓▓▓▓ ]',
|
|
99
|
-
'[▓▓▓▓▓▓▓▓▓ ]',
|
|
100
|
-
'[▓▓▓▓▓▓▓▓▓▓]',
|
|
101
|
-
],
|
|
102
|
-
celebration: [
|
|
103
|
-
'🎉',
|
|
104
|
-
'🎊',
|
|
105
|
-
'✨',
|
|
106
|
-
'🌟',
|
|
107
|
-
'⭐',
|
|
108
|
-
'💫',
|
|
109
|
-
'🎆',
|
|
110
|
-
'🎇',
|
|
111
|
-
],
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const banners = {
|
|
115
|
-
ship: `
|
|
116
|
-
╔════════════════════════════════════════════╗
|
|
117
|
-
║ 🚀 ${colors.ship.bold('S H I P P E D !')} 🚀 ║
|
|
118
|
-
╚════════════════════════════════════════════╝`,
|
|
119
|
-
|
|
120
|
-
success: `
|
|
121
|
-
✨ ${colors.success.bold('Success!')} ✨`,
|
|
122
|
-
|
|
123
|
-
error: `
|
|
124
|
-
❌ ${colors.error.bold('Error')} ❌`,
|
|
125
|
-
|
|
126
|
-
welcome: `
|
|
127
|
-
${colors.primary('╔══════════════════════════════════════════════════╗')}
|
|
128
|
-
${colors.primary('║')} ${colors.text.bold('🚀 prjct')}${colors.primary('/')}${colors.secondary.bold('cli')} ${colors.primary('║')}
|
|
129
|
-
${colors.primary('║')} ${colors.dim('Ship faster with zero friction')} ${colors.primary('║')}
|
|
130
|
-
${colors.primary('╚══════════════════════════════════════════════════╝')}`,
|
|
131
|
-
|
|
132
|
-
cleanup: `
|
|
133
|
-
${colors.focus('🧹 ✨ Cleanup Magic ✨ 🧹')}`,
|
|
134
|
-
|
|
135
|
-
focus: `
|
|
136
|
-
${colors.focus('━━━━━━━━━━━━━━━━━━━━━━━')}
|
|
137
|
-
${colors.focus.bold(' 🎯 FOCUS MODE 🎯 ')}
|
|
138
|
-
${colors.focus('━━━━━━━━━━━━━━━━━━━━━━━')}`,
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
async function animate(frames, duration = 100) {
|
|
142
|
-
for (const frame of frames) {
|
|
143
|
-
process.stdout.write('\r' + frame)
|
|
144
|
-
await sleep(duration)
|
|
145
|
-
}
|
|
146
|
-
process.stdout.write('\r' + ' '.repeat(30) + '\r')
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
async function typeWriter(text, delay = 30) {
|
|
150
|
-
for (let i = 0; i <= text.length; i++) {
|
|
151
|
-
process.stdout.write('\r' + text.slice(0, i) + (i < text.length ? '▋' : ''))
|
|
152
|
-
await sleep(delay)
|
|
153
|
-
}
|
|
154
|
-
process.stdout.write('\n')
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
async function progressBar(duration = 1000, label = 'Processing') {
|
|
158
|
-
const steps = 20
|
|
159
|
-
const stepDuration = duration / steps
|
|
160
|
-
|
|
161
|
-
for (let i = 0; i <= steps; i++) {
|
|
162
|
-
const percent = Math.round((i / steps) * 100)
|
|
163
|
-
const filled = '▓'.repeat(i)
|
|
164
|
-
const empty = '░'.repeat(steps - i)
|
|
165
|
-
const bar = `${colors.dim(label)} [${colors.primary(filled)}${colors.dim(empty)}] ${colors.text(percent + '%')}`
|
|
166
|
-
process.stdout.write('\r' + bar)
|
|
167
|
-
await sleep(stepDuration)
|
|
168
|
-
}
|
|
169
|
-
process.stdout.write('\n')
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
async function sparkle(message) {
|
|
173
|
-
const sparkles = ['✨', '⭐', '💫', '🌟']
|
|
174
|
-
let output = ''
|
|
175
|
-
|
|
176
|
-
for (let i = 0; i < 3; i++) {
|
|
177
|
-
const spark = sparkles[Math.floor(Math.random() * sparkles.length)]
|
|
178
|
-
output = `${spark} ${message} ${spark}`
|
|
179
|
-
process.stdout.write('\r' + output)
|
|
180
|
-
await sleep(200)
|
|
181
|
-
process.stdout.write('\r' + ' '.repeat(output.length))
|
|
182
|
-
await sleep(100)
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
console.log(output)
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
function sleep(ms) {
|
|
189
|
-
return new Promise(resolve => setTimeout(resolve, ms))
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
function formatShip(feature, count) {
|
|
193
|
-
const banner = banners.ship
|
|
194
|
-
const stats = `
|
|
195
|
-
${colors.text('Feature:')} ${colors.ship.bold(feature)}
|
|
196
|
-
${colors.text('Total shipped:')} ${colors.success.bold(count)}
|
|
197
|
-
${colors.text('Velocity:')} ${colors.celebrate('🔥 On fire!')}
|
|
198
|
-
`
|
|
199
|
-
|
|
200
|
-
return banner + stats
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
function formatFocus(task, timestamp) {
|
|
204
|
-
const banner = banners.focus
|
|
205
|
-
const info = `
|
|
206
|
-
${colors.text('Current task:')} ${colors.focus.bold(task)}
|
|
207
|
-
${colors.dim('Started:')} ${colors.subtext(timestamp)}
|
|
208
|
-
`
|
|
209
|
-
|
|
210
|
-
return banner + info
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
function formatSuccess(message) {
|
|
214
|
-
return `${colors.success('✅')} ${colors.text(message)}`
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
function formatError(message) {
|
|
218
|
-
return `${colors.error('❌')} ${colors.text(message)}`
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
function formatIdea(idea) {
|
|
222
|
-
return `
|
|
223
|
-
${colors.idea('💡 Idea captured!')}
|
|
224
|
-
${colors.text('―'.repeat(30))}
|
|
225
|
-
${colors.subtext(idea)}
|
|
226
|
-
${colors.text('―'.repeat(30))}
|
|
227
|
-
${colors.dim('Added to your ideas backlog')}
|
|
228
|
-
`
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
function formatCleanup(filesRemoved, tasksArchived, spaceFeed) {
|
|
232
|
-
return `
|
|
233
|
-
${banners.cleanup}
|
|
234
|
-
|
|
235
|
-
${colors.text('🗑️ Files removed:')} ${colors.success.bold(filesRemoved)}
|
|
236
|
-
${colors.text('📦 Tasks archived:')} ${colors.success.bold(tasksArchived)}
|
|
237
|
-
${colors.text('💾 Space freed:')} ${colors.success.bold(spaceFeed + ' MB')}
|
|
238
|
-
|
|
239
|
-
${colors.celebrate('✨ Your project is clean and lean!')}
|
|
240
|
-
`
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
function formatRecap(data) {
|
|
244
|
-
const divider = colors.primary('━'.repeat(40))
|
|
245
|
-
|
|
246
|
-
return `
|
|
247
|
-
${divider}
|
|
248
|
-
${colors.primary.bold('📊 PROJECT RECAP')}
|
|
249
|
-
${divider}
|
|
250
|
-
|
|
251
|
-
${colors.text('🎯 Current focus:')} ${data.currentTask || colors.dim('No active task')}
|
|
252
|
-
${colors.text('🚀 Shipped this week:')} ${colors.success.bold(data.shippedCount)}
|
|
253
|
-
${colors.text('📝 Queued tasks:')} ${colors.info.bold(data.queuedCount)}
|
|
254
|
-
${colors.text('💡 Ideas captured:')} ${colors.idea.bold(data.ideasCount)}
|
|
255
|
-
|
|
256
|
-
${divider}
|
|
257
|
-
${colors.dim('Keep shipping! 🚀')}
|
|
258
|
-
`
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
module.exports = {
|
|
262
|
-
colors,
|
|
263
|
-
frames,
|
|
264
|
-
banners,
|
|
265
|
-
animate,
|
|
266
|
-
typeWriter,
|
|
267
|
-
progressBar,
|
|
268
|
-
sparkle,
|
|
269
|
-
formatShip,
|
|
270
|
-
formatFocus,
|
|
271
|
-
formatSuccess,
|
|
272
|
-
formatError,
|
|
273
|
-
formatIdea,
|
|
274
|
-
formatCleanup,
|
|
275
|
-
formatRecap,
|
|
276
|
-
catppuccin,
|
|
277
|
-
}
|
package/core/ascii-graphics.js
DELETED
|
@@ -1,433 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ASCII Graphics Utilities
|
|
3
|
-
*
|
|
4
|
-
* Creates visual dashboards and progress bars in terminal
|
|
5
|
-
* using ASCII characters with Catppuccin Mocha color scheme.
|
|
6
|
-
*
|
|
7
|
-
* @version 0.6.0
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
const chalk = require('chalk')
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Catppuccin Mocha Color Palette
|
|
14
|
-
* https://github.com/catppuccin/catppuccin
|
|
15
|
-
*/
|
|
16
|
-
const CATPPUCCIN = {
|
|
17
|
-
// Base colors
|
|
18
|
-
base: '#1e1e2e',
|
|
19
|
-
mantle: '#181825',
|
|
20
|
-
crust: '#11111b',
|
|
21
|
-
|
|
22
|
-
// Text colors
|
|
23
|
-
text: '#cdd6f4',
|
|
24
|
-
subtext1: '#bac2de',
|
|
25
|
-
subtext0: '#a6adc8',
|
|
26
|
-
|
|
27
|
-
// Overlay colors
|
|
28
|
-
overlay2: '#9399b2',
|
|
29
|
-
overlay1: '#7f849c',
|
|
30
|
-
overlay0: '#6c7086',
|
|
31
|
-
surface2: '#585b70',
|
|
32
|
-
surface1: '#45475a',
|
|
33
|
-
surface0: '#313244',
|
|
34
|
-
|
|
35
|
-
// Accent colors
|
|
36
|
-
rosewater: '#f5e0dc',
|
|
37
|
-
flamingo: '#f2cdcd',
|
|
38
|
-
pink: '#f5c2e7',
|
|
39
|
-
mauve: '#cba6f7',
|
|
40
|
-
red: '#f38ba8',
|
|
41
|
-
maroon: '#eba0ac',
|
|
42
|
-
peach: '#fab387',
|
|
43
|
-
yellow: '#f9e2af',
|
|
44
|
-
green: '#a6e3a1',
|
|
45
|
-
teal: '#94e2d5',
|
|
46
|
-
sky: '#89dceb',
|
|
47
|
-
sapphire: '#74c7ec',
|
|
48
|
-
blue: '#89b4fa',
|
|
49
|
-
lavender: '#b4befe',
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Semantic color mapping
|
|
54
|
-
*/
|
|
55
|
-
const COLORS = {
|
|
56
|
-
// Status colors
|
|
57
|
-
success: chalk.hex(CATPPUCCIN.green),
|
|
58
|
-
warning: chalk.hex(CATPPUCCIN.yellow),
|
|
59
|
-
error: chalk.hex(CATPPUCCIN.red),
|
|
60
|
-
info: chalk.hex(CATPPUCCIN.blue),
|
|
61
|
-
|
|
62
|
-
// UI colors
|
|
63
|
-
primary: chalk.hex(CATPPUCCIN.mauve),
|
|
64
|
-
secondary: chalk.hex(CATPPUCCIN.lavender),
|
|
65
|
-
accent: chalk.hex(CATPPUCCIN.peach),
|
|
66
|
-
muted: chalk.hex(CATPPUCCIN.overlay0),
|
|
67
|
-
|
|
68
|
-
// Progress colors
|
|
69
|
-
progress: chalk.hex(CATPPUCCIN.teal),
|
|
70
|
-
complete: chalk.hex(CATPPUCCIN.green),
|
|
71
|
-
pending: chalk.hex(CATPPUCCIN.overlay1),
|
|
72
|
-
|
|
73
|
-
// Text colors
|
|
74
|
-
bold: chalk.hex(CATPPUCCIN.text).bold,
|
|
75
|
-
dim: chalk.hex(CATPPUCCIN.overlay0),
|
|
76
|
-
highlight: chalk.hex(CATPPUCCIN.sapphire),
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Box Drawing Characters
|
|
81
|
-
*/
|
|
82
|
-
const BOX = {
|
|
83
|
-
topLeft: '┌',
|
|
84
|
-
topRight: '┐',
|
|
85
|
-
bottomLeft: '└',
|
|
86
|
-
bottomRight: '┘',
|
|
87
|
-
horizontal: '─',
|
|
88
|
-
vertical: '│',
|
|
89
|
-
verticalRight: '├',
|
|
90
|
-
verticalLeft: '┤',
|
|
91
|
-
cross: '┼',
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Progress Bar Characters
|
|
96
|
-
*/
|
|
97
|
-
const PROGRESS = {
|
|
98
|
-
filled: '█',
|
|
99
|
-
empty: '░',
|
|
100
|
-
partial: ['▏', '▎', '▍', '▌', '▋', '▊', '▉'],
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* ASCII Graphics Generator
|
|
105
|
-
*/
|
|
106
|
-
class ASCIIGraphics {
|
|
107
|
-
/**
|
|
108
|
-
* Create a status dashboard
|
|
109
|
-
*/
|
|
110
|
-
static createDashboard(data) {
|
|
111
|
-
const width = 50
|
|
112
|
-
const lines = []
|
|
113
|
-
|
|
114
|
-
// Top border
|
|
115
|
-
lines.push(
|
|
116
|
-
COLORS.primary(
|
|
117
|
-
`${BOX.topLeft}${BOX.horizontal} Project Status ${BOX.horizontal.repeat(width - 17)}${BOX.topRight}`,
|
|
118
|
-
),
|
|
119
|
-
)
|
|
120
|
-
|
|
121
|
-
// Sprint Progress
|
|
122
|
-
const sprintProgress = data.sprintProgress || 0
|
|
123
|
-
lines.push(
|
|
124
|
-
`${COLORS.primary(BOX.vertical)} ${COLORS.bold('Sprint Progress')} ${this.createProgressBar(sprintProgress, 10)} ${COLORS.highlight(Math.round(sprintProgress) + '%')} ${' '.repeat(width - 38)}${COLORS.primary(BOX.vertical)}`,
|
|
125
|
-
)
|
|
126
|
-
|
|
127
|
-
// Tasks Complete
|
|
128
|
-
const tasksComplete = data.tasksComplete || 0
|
|
129
|
-
const tasksTotal = data.tasksTotal || 0
|
|
130
|
-
lines.push(
|
|
131
|
-
`${COLORS.primary(BOX.vertical)} ${COLORS.bold('Tasks Complete')} ${COLORS.complete(tasksComplete)}/${COLORS.info(tasksTotal)}${' '.repeat(width - 28)}${COLORS.primary(BOX.vertical)}`,
|
|
132
|
-
)
|
|
133
|
-
|
|
134
|
-
// Ideas in Backlog
|
|
135
|
-
const ideasCount = data.ideasCount || 0
|
|
136
|
-
lines.push(
|
|
137
|
-
`${COLORS.primary(BOX.vertical)} ${COLORS.bold('Ideas in Backlog')} ${COLORS.accent(ideasCount)}${' '.repeat(width - 28)}${COLORS.primary(BOX.vertical)}`,
|
|
138
|
-
)
|
|
139
|
-
|
|
140
|
-
// Days Since Ship
|
|
141
|
-
const daysSinceShip = data.daysSinceShip || 0
|
|
142
|
-
const shipColor =
|
|
143
|
-
daysSinceShip > 7 ? COLORS.error : daysSinceShip > 3 ? COLORS.warning : COLORS.success
|
|
144
|
-
lines.push(
|
|
145
|
-
`${COLORS.primary(BOX.vertical)} ${COLORS.bold('Days Since Ship')} ${shipColor(daysSinceShip)}${' '.repeat(width - 28)}${COLORS.primary(BOX.vertical)}`,
|
|
146
|
-
)
|
|
147
|
-
|
|
148
|
-
// Middle separator
|
|
149
|
-
lines.push(
|
|
150
|
-
COLORS.primary(
|
|
151
|
-
`${BOX.verticalRight}${BOX.horizontal} Current Focus ${BOX.horizontal.repeat(width - 17)}${BOX.verticalLeft}`,
|
|
152
|
-
),
|
|
153
|
-
)
|
|
154
|
-
|
|
155
|
-
// Current Task
|
|
156
|
-
const currentTask = data.currentTask || 'No active task'
|
|
157
|
-
const taskTime = data.taskTime || ''
|
|
158
|
-
lines.push(
|
|
159
|
-
`${COLORS.primary(BOX.vertical)} ${COLORS.highlight('→')} ${COLORS.bold(this.truncate(currentTask, width - 5))}${' '.repeat(Math.max(0, width - currentTask.length - 4))}${COLORS.primary(BOX.vertical)}`,
|
|
160
|
-
)
|
|
161
|
-
|
|
162
|
-
if (taskTime) {
|
|
163
|
-
lines.push(
|
|
164
|
-
`${COLORS.primary(BOX.vertical)} ${COLORS.dim(`Started: ${taskTime}`)}${' '.repeat(Math.max(0, width - taskTime.length - 13))}${COLORS.primary(BOX.vertical)}`,
|
|
165
|
-
)
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Bottom border
|
|
169
|
-
lines.push(COLORS.primary(`${BOX.bottomLeft}${BOX.horizontal.repeat(width)}${BOX.bottomRight}`))
|
|
170
|
-
|
|
171
|
-
return lines.join('\n')
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Create a progress bar
|
|
176
|
-
*/
|
|
177
|
-
static createProgressBar(percentage, width = 20) {
|
|
178
|
-
const filled = Math.floor((percentage / 100) * width)
|
|
179
|
-
const empty = width - filled
|
|
180
|
-
|
|
181
|
-
return COLORS.progress(PROGRESS.filled.repeat(filled)) + COLORS.pending(PROGRESS.empty.repeat(empty))
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Create a horizontal bar chart
|
|
186
|
-
*/
|
|
187
|
-
static createBarChart(data, maxWidth = 30) {
|
|
188
|
-
const lines = []
|
|
189
|
-
const maxValue = Math.max(...data.map((d) => d.value))
|
|
190
|
-
|
|
191
|
-
for (const item of data) {
|
|
192
|
-
const barWidth = Math.round((item.value / maxValue) * maxWidth)
|
|
193
|
-
const bar = PROGRESS.filled.repeat(barWidth)
|
|
194
|
-
const label = item.label.padEnd(15)
|
|
195
|
-
const value = String(item.value).padStart(3)
|
|
196
|
-
|
|
197
|
-
lines.push(`${label} ${COLORS.progress(bar)} ${COLORS.bold(value)}`)
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
return lines.join('\n')
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Create a vertical progress indicator
|
|
205
|
-
*/
|
|
206
|
-
static createVerticalProgress(percentage, height = 10) {
|
|
207
|
-
const filled = Math.floor((percentage / 100) * height)
|
|
208
|
-
const empty = height - filled
|
|
209
|
-
|
|
210
|
-
const lines = []
|
|
211
|
-
lines.push(COLORS.primary('┌─┐'))
|
|
212
|
-
|
|
213
|
-
for (let i = 0; i < empty; i++) {
|
|
214
|
-
lines.push(`${COLORS.primary('│')}${COLORS.pending(PROGRESS.empty)}${COLORS.primary('│')}`)
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
for (let i = 0; i < filled; i++) {
|
|
218
|
-
lines.push(`${COLORS.primary('│')}${COLORS.progress(PROGRESS.filled)}${COLORS.primary('│')}`)
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
lines.push(COLORS.primary('└─┘'))
|
|
222
|
-
lines.push(` ${COLORS.highlight(percentage + '%')}`)
|
|
223
|
-
|
|
224
|
-
return lines.join('\n')
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* Create a timeline view
|
|
229
|
-
*/
|
|
230
|
-
static createTimeline(events) {
|
|
231
|
-
const lines = []
|
|
232
|
-
|
|
233
|
-
for (let i = 0; i < events.length; i++) {
|
|
234
|
-
const event = events[i]
|
|
235
|
-
const isLast = i === events.length - 1
|
|
236
|
-
|
|
237
|
-
// Event marker
|
|
238
|
-
const marker = event.completed ? COLORS.complete('●') : COLORS.pending('○')
|
|
239
|
-
const connector = isLast ? ' ' : COLORS.muted('│')
|
|
240
|
-
|
|
241
|
-
lines.push(`${marker} ${COLORS.bold(event.title)}`)
|
|
242
|
-
|
|
243
|
-
if (event.description) {
|
|
244
|
-
lines.push(`${connector} ${COLORS.dim(event.description)}`)
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
if (event.time) {
|
|
248
|
-
lines.push(`${connector} ${COLORS.info(event.time)}`)
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
if (!isLast) {
|
|
252
|
-
lines.push(connector)
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
return lines.join('\n')
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
/**
|
|
260
|
-
* Create a table
|
|
261
|
-
*/
|
|
262
|
-
static createTable(headers, rows) {
|
|
263
|
-
const columnWidths = headers.map((h, i) => {
|
|
264
|
-
const maxRowWidth = Math.max(...rows.map((r) => String(r[i] || '').length))
|
|
265
|
-
return Math.max(h.length, maxRowWidth) + 2
|
|
266
|
-
})
|
|
267
|
-
|
|
268
|
-
const lines = []
|
|
269
|
-
|
|
270
|
-
// Top border
|
|
271
|
-
const topBorder =
|
|
272
|
-
BOX.topLeft +
|
|
273
|
-
columnWidths.map((w) => BOX.horizontal.repeat(w)).join(BOX.cross) +
|
|
274
|
-
BOX.topRight
|
|
275
|
-
lines.push(topBorder)
|
|
276
|
-
|
|
277
|
-
// Headers
|
|
278
|
-
const headerRow =
|
|
279
|
-
BOX.vertical +
|
|
280
|
-
headers
|
|
281
|
-
.map((h, i) => chalk.bold(h.padEnd(columnWidths[i])))
|
|
282
|
-
.join(BOX.vertical) +
|
|
283
|
-
BOX.vertical
|
|
284
|
-
lines.push(headerRow)
|
|
285
|
-
|
|
286
|
-
// Header separator
|
|
287
|
-
const headerSep =
|
|
288
|
-
BOX.verticalRight +
|
|
289
|
-
columnWidths.map((w) => BOX.horizontal.repeat(w)).join(BOX.cross) +
|
|
290
|
-
BOX.verticalLeft
|
|
291
|
-
lines.push(headerSep)
|
|
292
|
-
|
|
293
|
-
// Rows
|
|
294
|
-
for (const row of rows) {
|
|
295
|
-
const rowStr =
|
|
296
|
-
BOX.vertical +
|
|
297
|
-
row
|
|
298
|
-
.map((cell, i) => String(cell || '').padEnd(columnWidths[i]))
|
|
299
|
-
.join(BOX.vertical) +
|
|
300
|
-
BOX.vertical
|
|
301
|
-
lines.push(rowStr)
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
// Bottom border
|
|
305
|
-
const bottomBorder =
|
|
306
|
-
BOX.bottomLeft +
|
|
307
|
-
columnWidths.map((w) => BOX.horizontal.repeat(w)).join(BOX.cross) +
|
|
308
|
-
BOX.bottomRight
|
|
309
|
-
lines.push(bottomBorder)
|
|
310
|
-
|
|
311
|
-
return lines.join('\n')
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
/**
|
|
315
|
-
* Create a sparkline (mini chart)
|
|
316
|
-
*/
|
|
317
|
-
static createSparkline(values) {
|
|
318
|
-
const chars = ['▁', '▂', '▃', '▄', '▅', '▆', '▇', '█']
|
|
319
|
-
const max = Math.max(...values)
|
|
320
|
-
const min = Math.min(...values)
|
|
321
|
-
const range = max - min
|
|
322
|
-
|
|
323
|
-
if (range === 0) {
|
|
324
|
-
return chars[0].repeat(values.length)
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
return values
|
|
328
|
-
.map((v) => {
|
|
329
|
-
const normalized = (v - min) / range
|
|
330
|
-
const index = Math.floor(normalized * (chars.length - 1))
|
|
331
|
-
return chars[index]
|
|
332
|
-
})
|
|
333
|
-
.join('')
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
/**
|
|
337
|
-
* Create a gauge/meter
|
|
338
|
-
*/
|
|
339
|
-
static createGauge(value, max, label = '') {
|
|
340
|
-
const percentage = (value / max) * 100
|
|
341
|
-
const width = 30
|
|
342
|
-
|
|
343
|
-
const filled = Math.floor((percentage / 100) * width)
|
|
344
|
-
const empty = width - filled
|
|
345
|
-
|
|
346
|
-
let color = COLORS.success
|
|
347
|
-
if (percentage > 75) color = COLORS.error
|
|
348
|
-
else if (percentage > 50) color = COLORS.warning
|
|
349
|
-
|
|
350
|
-
const bar = color(PROGRESS.filled.repeat(filled)) + COLORS.pending(PROGRESS.empty.repeat(empty))
|
|
351
|
-
|
|
352
|
-
const labelStr = label ? `${COLORS.bold(label.padEnd(15))} ` : ''
|
|
353
|
-
const valueStr = `${COLORS.info(value)}/${COLORS.muted(max)} (${COLORS.highlight(Math.round(percentage) + '%')})`
|
|
354
|
-
|
|
355
|
-
return `${labelStr}[${bar}] ${valueStr}`
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
/**
|
|
359
|
-
* Create ASCII art number (for big stats)
|
|
360
|
-
*/
|
|
361
|
-
static createBigNumber(num) {
|
|
362
|
-
const digits = {
|
|
363
|
-
0: ['███', '█ █', '█ █', '█ █', '███'],
|
|
364
|
-
1: [' █', ' █', ' █', ' █', ' █'],
|
|
365
|
-
2: ['███', ' █', '███', '█ ', '███'],
|
|
366
|
-
3: ['███', ' █', '███', ' █', '███'],
|
|
367
|
-
4: ['█ █', '█ █', '███', ' █', ' █'],
|
|
368
|
-
5: ['███', '█ ', '███', ' █', '███'],
|
|
369
|
-
6: ['███', '█ ', '███', '█ █', '███'],
|
|
370
|
-
7: ['███', ' █', ' █', ' █', ' █'],
|
|
371
|
-
8: ['███', '█ █', '███', '█ █', '███'],
|
|
372
|
-
9: ['███', '█ █', '███', ' █', '███'],
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
const numStr = String(num)
|
|
376
|
-
const lines = ['', '', '', '', '']
|
|
377
|
-
|
|
378
|
-
for (const char of numStr) {
|
|
379
|
-
if (digits[char]) {
|
|
380
|
-
for (let i = 0; i < 5; i++) {
|
|
381
|
-
lines[i] += digits[char][i] + ' '
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
return lines.join('\n')
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
/**
|
|
390
|
-
* Truncate text to fit width
|
|
391
|
-
*/
|
|
392
|
-
static truncate(text, maxWidth) {
|
|
393
|
-
if (text.length <= maxWidth) {
|
|
394
|
-
return text
|
|
395
|
-
}
|
|
396
|
-
return text.substring(0, maxWidth - 3) + '...'
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
/**
|
|
400
|
-
* Create a loading spinner frame
|
|
401
|
-
*/
|
|
402
|
-
static getSpinnerFrame(index) {
|
|
403
|
-
const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']
|
|
404
|
-
return frames[index % frames.length]
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
/**
|
|
408
|
-
* Create a status indicator
|
|
409
|
-
*/
|
|
410
|
-
static statusIndicator(status) {
|
|
411
|
-
const indicators = {
|
|
412
|
-
success: COLORS.success('✓'),
|
|
413
|
-
error: COLORS.error('✗'),
|
|
414
|
-
warning: COLORS.warning('⚠'),
|
|
415
|
-
info: COLORS.info('ℹ'),
|
|
416
|
-
pending: COLORS.pending('○'),
|
|
417
|
-
active: COLORS.highlight('●'),
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
return indicators[status] || indicators.info
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
/**
|
|
424
|
-
* Create a divider line
|
|
425
|
-
*/
|
|
426
|
-
static divider(width = 50, char = '─') {
|
|
427
|
-
return COLORS.muted(char.repeat(width))
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
module.exports = ASCIIGraphics
|
|
432
|
-
module.exports.COLORS = COLORS
|
|
433
|
-
module.exports.CATPPUCCIN = CATPPUCCIN
|