prjct-cli 0.5.0 → 0.6.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 +169 -1
- package/CLAUDE.md +43 -28
- package/README.md +4 -4
- package/bin/prjct +78 -63
- package/core/agent-generator.js +19 -10
- package/core/ascii-graphics.js +433 -0
- package/core/command-registry.js +553 -0
- package/core/commands.js +274 -62
- package/core/task-schema.js +342 -0
- package/package.json +4 -3
- package/templates/agents/AGENTS.md +79 -101
- package/templates/agents/be.template.md +14 -29
- package/templates/agents/coordinator.template.md +34 -0
- package/templates/agents/data.template.md +14 -28
- package/templates/agents/devops.template.md +14 -28
- package/templates/agents/fe.template.md +14 -29
- package/templates/agents/mobile.template.md +14 -28
- package/templates/agents/qa.template.md +14 -41
- package/templates/agents/scribe.template.md +15 -81
- package/templates/agents/security.template.md +14 -28
- package/templates/agents/ux.template.md +14 -36
- package/templates/commands/analyze.md +36 -239
- package/templates/commands/build.md +41 -0
- package/templates/commands/cleanup.md +24 -87
- package/templates/commands/context.md +24 -93
- package/templates/commands/design.md +20 -98
- package/templates/commands/done.md +16 -181
- package/templates/commands/fix.md +27 -66
- package/templates/commands/git.md +33 -60
- package/templates/commands/help.md +18 -52
- package/templates/commands/idea.md +11 -36
- package/templates/commands/init.md +30 -277
- package/templates/commands/next.md +20 -62
- package/templates/commands/now.md +18 -22
- package/templates/commands/progress.md +23 -78
- package/templates/commands/recap.md +22 -74
- package/templates/commands/roadmap.md +21 -90
- package/templates/commands/ship.md +26 -161
- package/templates/commands/status.md +40 -0
- package/templates/commands/stuck.md +21 -33
- package/templates/commands/sync.md +19 -209
- package/templates/commands/task.md +18 -80
- package/templates/commands/test.md +23 -72
- package/templates/commands/workflow.md +20 -212
- package/templates/agents/pm.template.md +0 -84
|
@@ -0,0 +1,433 @@
|
|
|
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
|