jdi-cli 0.1.3 → 0.1.4
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 +15 -0
- package/bin/jdi.js +29 -26
- package/bin/lib/ui.js +234 -14
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# JDI — Just Do It
|
|
2
2
|
|
|
3
|
+
```
|
|
4
|
+
██╗██████╗ ██╗
|
|
5
|
+
██║██╔══██╗██║
|
|
6
|
+
██║██║ ██║██║
|
|
7
|
+
██ ██║██║ ██║██║
|
|
8
|
+
╚█████╔╝██████╔╝██║
|
|
9
|
+
╚════╝ ╚═════╝ ╚═╝
|
|
10
|
+
|
|
11
|
+
◄══════════════════════════════════════════════|=|◉|=|/////|==
|
|
12
|
+
◄══════════════════════════════════════════════|=|◉|=|/////|==
|
|
13
|
+
◄══════════════════════════════════════════════|=|◉|=|/////|==
|
|
14
|
+
|
|
15
|
+
Cut through the chaos. Ship the work. [Just do it]
|
|
16
|
+
```
|
|
17
|
+
|
|
3
18
|
Lean workflow toolkit for solo dev + AI assistant. Adaptive loop, atomic commits, file-based state, fresh context per agent, wave-based parallelism. Per-project specialists that already know your stack.
|
|
4
19
|
|
|
5
20
|
## Why
|
package/bin/jdi.js
CHANGED
|
@@ -116,14 +116,14 @@ function ensureScope(scope) {
|
|
|
116
116
|
// Commands
|
|
117
117
|
// =================================================================
|
|
118
118
|
|
|
119
|
-
function cmdInstall({ positional, flags }) {
|
|
119
|
+
async function cmdInstall({ positional, flags }) {
|
|
120
120
|
const runtime = positional[0];
|
|
121
121
|
const scope = flags.scope || 'project';
|
|
122
122
|
|
|
123
123
|
ensureRuntime(runtime);
|
|
124
124
|
ensureScope(scope);
|
|
125
125
|
|
|
126
|
-
ui.
|
|
126
|
+
await ui.bannerAnimated();
|
|
127
127
|
|
|
128
128
|
ui.header(`Instalando JDI para ${c.bold}${runtime}${c.reset}`);
|
|
129
129
|
ui.info(`Diretorio: ${c.dim}${process.cwd()}${c.reset}`);
|
|
@@ -163,8 +163,8 @@ function cmdInstall({ positional, flags }) {
|
|
|
163
163
|
}
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
-
function cmdBuild({ flags }) {
|
|
167
|
-
ui.
|
|
166
|
+
async function cmdBuild({ flags }) {
|
|
167
|
+
await ui.bannerAnimated();
|
|
168
168
|
|
|
169
169
|
ui.header('Building JDI runtimes');
|
|
170
170
|
ui.info(`Source: ${c.dim}${PKG_ROOT}/core/${c.reset}`);
|
|
@@ -188,8 +188,8 @@ function cmdBuild({ flags }) {
|
|
|
188
188
|
}
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
-
function cmdUpdate({ flags }) {
|
|
192
|
-
ui.
|
|
191
|
+
async function cmdUpdate({ flags }) {
|
|
192
|
+
await ui.bannerAnimated();
|
|
193
193
|
|
|
194
194
|
ui.header('JDI Update');
|
|
195
195
|
ui.info(`Diretorio: ${c.dim}${process.cwd()}${c.reset}`);
|
|
@@ -213,8 +213,8 @@ function cmdUpdate({ flags }) {
|
|
|
213
213
|
}
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
-
function cmdUninstall({ positional, flags }) {
|
|
217
|
-
ui.
|
|
216
|
+
async function cmdUninstall({ positional, flags }) {
|
|
217
|
+
await ui.bannerAnimated();
|
|
218
218
|
|
|
219
219
|
ui.header('JDI Uninstall');
|
|
220
220
|
ui.info(`Diretorio: ${c.dim}${process.cwd()}${c.reset}`);
|
|
@@ -245,8 +245,8 @@ function cmdUninstall({ positional, flags }) {
|
|
|
245
245
|
}
|
|
246
246
|
}
|
|
247
247
|
|
|
248
|
-
function cmdInstallPlaywright({ flags }) {
|
|
249
|
-
ui.
|
|
248
|
+
async function cmdInstallPlaywright({ flags }) {
|
|
249
|
+
await ui.bannerAnimated();
|
|
250
250
|
|
|
251
251
|
ui.header('JDI: Install Playwright + MCP');
|
|
252
252
|
ui.info(`Directory: ${c.dim}${process.cwd()}${c.reset}`);
|
|
@@ -282,8 +282,8 @@ function cmdInstallPlaywright({ flags }) {
|
|
|
282
282
|
}
|
|
283
283
|
}
|
|
284
284
|
|
|
285
|
-
function cmdInstallCaveman({ flags }) {
|
|
286
|
-
ui.
|
|
285
|
+
async function cmdInstallCaveman({ flags }) {
|
|
286
|
+
await ui.bannerAnimated();
|
|
287
287
|
|
|
288
288
|
ui.header('JDI: Install Caveman plugin');
|
|
289
289
|
ui.info(`Directory: ${c.dim}${process.cwd()}${c.reset}`);
|
|
@@ -317,8 +317,8 @@ function cmdInstallCaveman({ flags }) {
|
|
|
317
317
|
}
|
|
318
318
|
}
|
|
319
319
|
|
|
320
|
-
function cmdDoctor({ flags }) {
|
|
321
|
-
ui.
|
|
320
|
+
async function cmdDoctor({ flags }) {
|
|
321
|
+
await ui.bannerAnimated();
|
|
322
322
|
|
|
323
323
|
ui.header('JDI Doctor');
|
|
324
324
|
ui.info(`Diretorio atual: ${c.dim}${process.cwd()}${c.reset}`);
|
|
@@ -332,8 +332,8 @@ function cmdDoctor({ flags }) {
|
|
|
332
332
|
}
|
|
333
333
|
}
|
|
334
334
|
|
|
335
|
-
function cmdHelp() {
|
|
336
|
-
ui.
|
|
335
|
+
async function cmdHelp() {
|
|
336
|
+
await ui.bannerAnimated();
|
|
337
337
|
|
|
338
338
|
console.log(`${c.bold}Uso:${c.reset}`);
|
|
339
339
|
console.log(` ${c.cyan}npx jdi-cli <comando> [opcoes]${c.reset}`);
|
|
@@ -403,7 +403,7 @@ function cmdVersion() {
|
|
|
403
403
|
// Main dispatcher
|
|
404
404
|
// =================================================================
|
|
405
405
|
|
|
406
|
-
function main() {
|
|
406
|
+
async function main() {
|
|
407
407
|
const parsed = parseArgs(process.argv);
|
|
408
408
|
|
|
409
409
|
if (parsed.flags && parsed.flags.noColor) {
|
|
@@ -417,34 +417,34 @@ function main() {
|
|
|
417
417
|
|
|
418
418
|
switch (parsed.cmd) {
|
|
419
419
|
case 'install':
|
|
420
|
-
cmdInstall(parsed);
|
|
420
|
+
await cmdInstall(parsed);
|
|
421
421
|
break;
|
|
422
422
|
case 'update':
|
|
423
423
|
case 'upgrade':
|
|
424
|
-
cmdUpdate(parsed);
|
|
424
|
+
await cmdUpdate(parsed);
|
|
425
425
|
break;
|
|
426
426
|
case 'uninstall':
|
|
427
427
|
case 'remove':
|
|
428
|
-
cmdUninstall(parsed);
|
|
428
|
+
await cmdUninstall(parsed);
|
|
429
429
|
break;
|
|
430
430
|
case 'build':
|
|
431
|
-
cmdBuild(parsed);
|
|
431
|
+
await cmdBuild(parsed);
|
|
432
432
|
break;
|
|
433
433
|
case 'install-playwright':
|
|
434
434
|
case 'playwright':
|
|
435
|
-
cmdInstallPlaywright(parsed);
|
|
435
|
+
await cmdInstallPlaywright(parsed);
|
|
436
436
|
break;
|
|
437
437
|
case 'install-caveman':
|
|
438
438
|
case 'caveman':
|
|
439
|
-
cmdInstallCaveman(parsed);
|
|
439
|
+
await cmdInstallCaveman(parsed);
|
|
440
440
|
break;
|
|
441
441
|
case 'doctor':
|
|
442
|
-
cmdDoctor(parsed);
|
|
442
|
+
await cmdDoctor(parsed);
|
|
443
443
|
break;
|
|
444
444
|
case 'help':
|
|
445
445
|
case '--help':
|
|
446
446
|
case '-h':
|
|
447
|
-
cmdHelp();
|
|
447
|
+
await cmdHelp();
|
|
448
448
|
break;
|
|
449
449
|
case '--version':
|
|
450
450
|
case '-V':
|
|
@@ -457,4 +457,7 @@ function main() {
|
|
|
457
457
|
}
|
|
458
458
|
}
|
|
459
459
|
|
|
460
|
-
main()
|
|
460
|
+
main().catch((err) => {
|
|
461
|
+
ui.fail(err && err.message ? err.message : String(err));
|
|
462
|
+
process.exit(1);
|
|
463
|
+
});
|
package/bin/lib/ui.js
CHANGED
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
// ANSI escape codes — sem deps externas
|
|
4
4
|
const isTTY = process.stdout.isTTY;
|
|
5
5
|
const supportsColor = isTTY && !process.env.NO_COLOR;
|
|
6
|
+
const supportsTrueColor =
|
|
7
|
+
supportsColor &&
|
|
8
|
+
(process.env.COLORTERM === 'truecolor' ||
|
|
9
|
+
process.env.COLORTERM === '24bit' ||
|
|
10
|
+
process.env.TERM_PROGRAM === 'vscode' ||
|
|
11
|
+
process.env.WT_SESSION); // Windows Terminal
|
|
6
12
|
|
|
7
13
|
const c = {
|
|
8
14
|
reset: supportsColor ? '\x1b[0m' : '',
|
|
@@ -25,22 +31,234 @@ const c = {
|
|
|
25
31
|
bgGreen: supportsColor ? '\x1b[42m' : '',
|
|
26
32
|
};
|
|
27
33
|
|
|
28
|
-
//
|
|
29
|
-
|
|
30
|
-
''
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
// Synthwave palette (truecolor with 256-color fallback)
|
|
35
|
+
function rgb(r, g, b, fallback256) {
|
|
36
|
+
if (!supportsColor) return '';
|
|
37
|
+
if (supportsTrueColor) return `\x1b[38;2;${r};${g};${b}m`;
|
|
38
|
+
return `\x1b[38;5;${fallback256}m`;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const synthwave = {
|
|
42
|
+
hotPink: rgb(255, 27, 141, 199),
|
|
43
|
+
neonYellow: rgb(244, 241, 66, 227),
|
|
44
|
+
cyanNeon: rgb(0, 255, 224, 51),
|
|
45
|
+
magenta: rgb(255, 0, 200, 201),
|
|
46
|
+
purple: rgb(185, 103, 255, 141),
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// ASCII letters J D I in ANSI Shadow font (full glyphs, including J's hook)
|
|
50
|
+
const JDI_LETTERS = [
|
|
51
|
+
' ██╗██████╗ ██╗',
|
|
52
|
+
' ██║██╔══██╗██║',
|
|
53
|
+
' ██║██║ ██║██║',
|
|
54
|
+
'██ ██║██║ ██║██║',
|
|
55
|
+
'╚█████╔╝██████╔╝██║',
|
|
56
|
+
' ╚════╝ ╚═════╝ ╚═╝',
|
|
40
57
|
];
|
|
41
58
|
|
|
59
|
+
// 3 lightsabers stacked, right-anchored hilts, blades ignite leftward.
|
|
60
|
+
// Each saber: [blade plasma extending left]|=|◉|=|/////|==
|
|
61
|
+
// ^^^ ^ ^^^ ^^^^^ ^^
|
|
62
|
+
// emt btn grd grip pommel
|
|
63
|
+
const HILT_STR = '|=|◉|=|/////|=='; // composed hilt, right side
|
|
64
|
+
const HILT_LEN = 15; // visible length of HILT_STR
|
|
65
|
+
const BLADE_CHAR = '═';
|
|
66
|
+
const BLADE_MAX = 47; // blade extends this many chars left
|
|
67
|
+
const BLADE_TIP = '◄'; // tip when fully ignited
|
|
68
|
+
const SABER_INDENTS = [2, 2, 2]; // aligned indents — hilts in same column
|
|
69
|
+
// Jedi blade palette — blue, green, purple
|
|
70
|
+
const SABER_COLORS_TRUE = [
|
|
71
|
+
[46, 170, 251], // Obi-Wan / Luke OG blue
|
|
72
|
+
[55, 251, 58], // Yoda / Luke ROTJ green
|
|
73
|
+
[163, 72, 251], // Mace Windu purple
|
|
74
|
+
];
|
|
75
|
+
const SABER_COLORS_256 = [33, 46, 129];
|
|
76
|
+
function saberColor(idx) {
|
|
77
|
+
if (!supportsColor) return '';
|
|
78
|
+
if (supportsTrueColor) {
|
|
79
|
+
const [r, g, b] = SABER_COLORS_TRUE[idx];
|
|
80
|
+
return `\x1b[38;2;${r};${g};${b}m`;
|
|
81
|
+
}
|
|
82
|
+
return `\x1b[38;5;${SABER_COLORS_256[idx]}m`;
|
|
83
|
+
}
|
|
84
|
+
const TAGLINE = 'Cut through the chaos. Ship the work. [Just do it]';
|
|
85
|
+
|
|
86
|
+
// Build one saber line, blade ignited from right (hilt) extending left to bladeChars.
|
|
87
|
+
// Layout (right-anchored): [spaces if blade incomplete][tip?][blade chars][hilt]
|
|
88
|
+
function buildSaberLine(saberIdx, bladeChars) {
|
|
89
|
+
const yellow = synthwave.neonYellow;
|
|
90
|
+
const red = supportsColor ? '\x1b[38;2;255;40;40m' : '';
|
|
91
|
+
const bladeCol = saberColor(saberIdx);
|
|
92
|
+
const r = c.reset;
|
|
93
|
+
const hiltColor = `${yellow}${c.bold}`;
|
|
94
|
+
const buttonColor = bladeChars > 0 ? `${red}${c.bold}` : hiltColor;
|
|
95
|
+
|
|
96
|
+
// Indent (stagger) + leading spaces to keep hilt at fixed right column
|
|
97
|
+
const indent = ' '.repeat(SABER_INDENTS[saberIdx]);
|
|
98
|
+
const leftPad = ' '.repeat(Math.max(0, BLADE_MAX - bladeChars));
|
|
99
|
+
|
|
100
|
+
let bladeSection = '';
|
|
101
|
+
if (bladeChars > 0) {
|
|
102
|
+
const tip = bladeChars >= BLADE_MAX ? `${bladeCol}${c.bold}${BLADE_TIP}${r}` : '';
|
|
103
|
+
const bladeBody = bladeChars >= BLADE_MAX ? bladeChars - 1 : bladeChars;
|
|
104
|
+
bladeSection = `${tip}${bladeCol}${c.bold}${BLADE_CHAR.repeat(bladeBody)}${r}`;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// HILT_STR has '◉' as 4th char (index 3). Recolor it red when blade active.
|
|
108
|
+
// Render hilt in 3 segments to keep button distinct.
|
|
109
|
+
const before = HILT_STR.slice(0, 3); // |=|
|
|
110
|
+
const button = HILT_STR.slice(3, 4); // ◉
|
|
111
|
+
const after = HILT_STR.slice(4); // |=|/////|==
|
|
112
|
+
const hilt =
|
|
113
|
+
`${hiltColor}${before}${r}` +
|
|
114
|
+
`${buttonColor}${button}${r}` +
|
|
115
|
+
`${hiltColor}${after}${r}`;
|
|
116
|
+
|
|
117
|
+
return `${indent}${leftPad}${bladeSection}${hilt}`;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function buildFrame({ showHilt, sabersBlade, showTagline }) {
|
|
121
|
+
const pink = synthwave.hotPink;
|
|
122
|
+
const purple = synthwave.purple;
|
|
123
|
+
const r = c.reset;
|
|
124
|
+
|
|
125
|
+
const lines = [''];
|
|
126
|
+
|
|
127
|
+
// 6 rows of JDI letters in hot pink
|
|
128
|
+
for (const row of JDI_LETTERS) {
|
|
129
|
+
lines.push(` ${pink}${c.bold}${row}${r}`);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
lines.push('');
|
|
133
|
+
|
|
134
|
+
// 3 stacked sabers
|
|
135
|
+
if (!showHilt) {
|
|
136
|
+
lines.push('');
|
|
137
|
+
lines.push('');
|
|
138
|
+
lines.push('');
|
|
139
|
+
} else {
|
|
140
|
+
for (let i = 0; i < 3; i++) {
|
|
141
|
+
const blade = (sabersBlade && sabersBlade[i] != null) ? sabersBlade[i] : 0;
|
|
142
|
+
lines.push(buildSaberLine(i, blade));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
lines.push('');
|
|
147
|
+
|
|
148
|
+
if (showTagline) {
|
|
149
|
+
lines.push(` ${purple}${c.italic}${TAGLINE}${r}`);
|
|
150
|
+
} else {
|
|
151
|
+
lines.push('');
|
|
152
|
+
}
|
|
153
|
+
lines.push('');
|
|
154
|
+
|
|
155
|
+
return lines;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function moveCursorUp(n) {
|
|
159
|
+
if (n > 0) process.stdout.write(`\x1b[${n}A`);
|
|
160
|
+
}
|
|
161
|
+
function clearLine() {
|
|
162
|
+
process.stdout.write('\x1b[2K');
|
|
163
|
+
}
|
|
164
|
+
function sleep(ms) {
|
|
165
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function writeFrame(lines, isFirst) {
|
|
169
|
+
if (!isFirst) {
|
|
170
|
+
moveCursorUp(lines.length);
|
|
171
|
+
}
|
|
172
|
+
for (const line of lines) {
|
|
173
|
+
clearLine();
|
|
174
|
+
process.stdout.write(`\r${line}\n`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const wantsAnim =
|
|
179
|
+
isTTY &&
|
|
180
|
+
!process.env.NO_COLOR &&
|
|
181
|
+
!process.env.CI &&
|
|
182
|
+
process.env.JDI_ANIMATE !== 'off';
|
|
183
|
+
|
|
184
|
+
async function bannerAnimated() {
|
|
185
|
+
// Non-TTY / CI / NO_COLOR: print static
|
|
186
|
+
if (!wantsAnim) {
|
|
187
|
+
banner();
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Cascade ignition: 3 sabers, each ignites with 80ms stagger.
|
|
192
|
+
// Saber 0 (blue) at t=0, saber 1 (green) at t=80ms, saber 2 (purple) at t=160ms.
|
|
193
|
+
// Each blade extends in 5 steps (~400ms per saber).
|
|
194
|
+
const stepChars = [0, 12, 24, 36, 44, BLADE_MAX];
|
|
195
|
+
|
|
196
|
+
function snapshot(t) {
|
|
197
|
+
const result = [];
|
|
198
|
+
for (let i = 0; i < 3; i++) {
|
|
199
|
+
const elapsed = t - i * 80;
|
|
200
|
+
if (elapsed <= 0) {
|
|
201
|
+
result.push(0);
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
const stepIdx = Math.min(stepChars.length - 1, Math.floor(elapsed / 80));
|
|
205
|
+
result.push(stepChars[stepIdx]);
|
|
206
|
+
}
|
|
207
|
+
return result;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const frames = [];
|
|
211
|
+
// t=0: letters only, no sabers
|
|
212
|
+
frames.push({ showHilt: false, sabersBlade: [0, 0, 0], showTagline: false, delay: 80 });
|
|
213
|
+
// t=80: hilts appear (no blade)
|
|
214
|
+
frames.push({ showHilt: true, sabersBlade: [0, 0, 0], showTagline: false, delay: 80 });
|
|
215
|
+
// Cascade ignition (~480ms)
|
|
216
|
+
for (let t = 80; t <= 560; t += 80) {
|
|
217
|
+
frames.push({ showHilt: true, sabersBlade: snapshot(t), showTagline: false, delay: 80 });
|
|
218
|
+
}
|
|
219
|
+
// Final: all blades full + tagline
|
|
220
|
+
frames.push({
|
|
221
|
+
showHilt: true,
|
|
222
|
+
sabersBlade: [BLADE_MAX, BLADE_MAX, BLADE_MAX],
|
|
223
|
+
showTagline: true,
|
|
224
|
+
delay: 0,
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
let isFirst = true;
|
|
228
|
+
for (const f of frames) {
|
|
229
|
+
const lines = buildFrame(f);
|
|
230
|
+
writeFrame(lines, isFirst);
|
|
231
|
+
isFirst = false;
|
|
232
|
+
if (f.delay > 0) await sleep(f.delay);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Hold the banner for HOLD_MS so the user can see it before the command continues.
|
|
236
|
+
// Use a small spinner under the tagline to signal that the CLI is alive and not frozen.
|
|
237
|
+
const HOLD_MS = 5000;
|
|
238
|
+
const SPIN_INTERVAL = 100;
|
|
239
|
+
const SPIN_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
240
|
+
const purple = synthwave.purple;
|
|
241
|
+
const r = c.reset;
|
|
242
|
+
const start = Date.now();
|
|
243
|
+
let spinIdx = 0;
|
|
244
|
+
while (Date.now() - start < HOLD_MS) {
|
|
245
|
+
const frame = SPIN_FRAMES[spinIdx % SPIN_FRAMES.length];
|
|
246
|
+
process.stdout.write(`\r ${purple}${frame}${r} ${c.dim}igniting...${r} `);
|
|
247
|
+
spinIdx++;
|
|
248
|
+
await sleep(SPIN_INTERVAL);
|
|
249
|
+
}
|
|
250
|
+
// Clear the spinner line so command output starts cleanly
|
|
251
|
+
process.stdout.write('\r' + ' '.repeat(40) + '\r');
|
|
252
|
+
}
|
|
253
|
+
|
|
42
254
|
function banner() {
|
|
43
|
-
|
|
255
|
+
// Static one-shot — final state: all 3 sabers ignited + tagline
|
|
256
|
+
const lines = buildFrame({
|
|
257
|
+
showHilt: true,
|
|
258
|
+
sabersBlade: [BLADE_MAX, BLADE_MAX, BLADE_MAX],
|
|
259
|
+
showTagline: true,
|
|
260
|
+
});
|
|
261
|
+
console.log(lines.join('\n'));
|
|
44
262
|
}
|
|
45
263
|
|
|
46
264
|
// Box drawing
|
|
@@ -120,7 +338,7 @@ function spinner(msg) {
|
|
|
120
338
|
if (!isTTY) {
|
|
121
339
|
console.log(`${sym.arrow} ${msg}...`);
|
|
122
340
|
return {
|
|
123
|
-
stop: () => {},
|
|
341
|
+
stop: () => { },
|
|
124
342
|
success: (s) => ok(s || msg),
|
|
125
343
|
fail: (s) => fail(s || msg),
|
|
126
344
|
};
|
|
@@ -179,7 +397,9 @@ function nextSteps(steps) {
|
|
|
179
397
|
module.exports = {
|
|
180
398
|
c,
|
|
181
399
|
sym,
|
|
400
|
+
synthwave,
|
|
182
401
|
banner,
|
|
402
|
+
bannerAnimated,
|
|
183
403
|
box,
|
|
184
404
|
step,
|
|
185
405
|
ok,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jdi-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "JDI (Just Do It) — lean workflow toolkit for Claude Code, GitHub Copilot, Antigravity, and OpenCode. 10 commands (7 loop + ralph + adopt + meta), 6 core agents + N per-project specialists with file-glob routing. Optional Playwright MCP + Caveman plugin install.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"jdi": "bin/jdi.js"
|