cskit-cli 1.0.38 → 1.0.41
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/package.json +1 -1
- package/src/commands/init.js +126 -214
package/package.json
CHANGED
package/src/commands/init.js
CHANGED
|
@@ -45,129 +45,67 @@ const {
|
|
|
45
45
|
// Timeline Display
|
|
46
46
|
// =============================================================================
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
error: chalk.red('◆'),
|
|
53
|
-
skip: chalk.yellow('◇'),
|
|
54
|
-
file: chalk.dim('│ '),
|
|
55
|
-
fileNew: chalk.green('│ + '),
|
|
56
|
-
fileUpdate: chalk.blue('│ ~ '),
|
|
57
|
-
fileSkip: chalk.yellow('│ ! '),
|
|
58
|
-
fileDel: chalk.red('│ - '),
|
|
59
|
-
branch: chalk.dim('├──'),
|
|
60
|
-
branchLast: chalk.dim('└──'),
|
|
61
|
-
indent: ' ',
|
|
62
|
-
};
|
|
63
|
-
|
|
48
|
+
/**
|
|
49
|
+
* Linear Timeline - shows progress step by step
|
|
50
|
+
* Each step prints its header, then children as they happen
|
|
51
|
+
*/
|
|
64
52
|
class Timeline {
|
|
65
53
|
constructor() {
|
|
66
54
|
this.steps = [];
|
|
67
55
|
this.currentStep = -1;
|
|
68
|
-
this.lastLineCount = 0;
|
|
69
|
-
this.paused = false; // After prompt, stop full re-renders
|
|
70
56
|
}
|
|
71
57
|
|
|
72
58
|
addStep(name) {
|
|
73
59
|
this.steps.push({ name, status: 'pending', children: [] });
|
|
74
60
|
}
|
|
75
61
|
|
|
62
|
+
// Print step header when starting
|
|
76
63
|
start(stepIndex) {
|
|
77
64
|
this.currentStep = stepIndex;
|
|
78
65
|
this.steps[stepIndex].status = 'active';
|
|
79
|
-
|
|
66
|
+
const num = chalk.dim(`${stepIndex + 1}.`);
|
|
67
|
+
const name = chalk.cyan(this.steps[stepIndex].name);
|
|
68
|
+
console.log(`\n ${num} ${name}`);
|
|
80
69
|
}
|
|
81
70
|
|
|
71
|
+
// Print completion message
|
|
82
72
|
complete(stepIndex, message = null) {
|
|
83
73
|
this.steps[stepIndex].status = 'done';
|
|
84
|
-
if (message)
|
|
85
|
-
|
|
74
|
+
if (message) {
|
|
75
|
+
console.log(` ${chalk.dim('└──')} ${chalk.green('✓')} ${chalk.dim(message)}`);
|
|
76
|
+
} else {
|
|
77
|
+
console.log(` ${chalk.dim('└──')} ${chalk.green('✓')} Done`);
|
|
78
|
+
}
|
|
86
79
|
}
|
|
87
80
|
|
|
81
|
+
// Print error message
|
|
88
82
|
error(stepIndex, message) {
|
|
89
83
|
this.steps[stepIndex].status = 'error';
|
|
90
|
-
|
|
91
|
-
this.render();
|
|
84
|
+
console.log(` ${chalk.dim('└──')} ${chalk.red('✗')} ${message}`);
|
|
92
85
|
}
|
|
93
86
|
|
|
87
|
+
// Print skip message
|
|
94
88
|
skip(stepIndex, message) {
|
|
95
89
|
this.steps[stepIndex].status = 'skip';
|
|
96
|
-
|
|
97
|
-
this.render();
|
|
90
|
+
console.log(` ${chalk.dim('└──')} ${chalk.yellow('○')} ${message}`);
|
|
98
91
|
}
|
|
99
92
|
|
|
93
|
+
// Print child item immediately
|
|
100
94
|
addChild(stepIndex, text, type = 'info') {
|
|
101
95
|
this.steps[stepIndex].children.push({ text, type });
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
buildStatusLine(stepIndex) {
|
|
116
|
-
const step = this.steps[stepIndex];
|
|
117
|
-
const symbol = SYMBOLS[step.status];
|
|
118
|
-
const num = chalk.dim(`${stepIndex + 1}.`);
|
|
119
|
-
const name = step.status === 'active' ? chalk.cyan(step.name) : step.name;
|
|
120
|
-
const msg = step.message ? chalk.dim(` (${step.message})`) : '';
|
|
121
|
-
return ` ${symbol} ${num} ${name}${msg}`;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
render() {
|
|
125
|
-
// After pause, only print current step status (no full timeline)
|
|
126
|
-
if (this.paused) {
|
|
127
|
-
console.log(this.buildStatusLine(this.currentStep));
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const lines = [];
|
|
132
|
-
for (let i = 0; i < this.steps.length; i++) {
|
|
133
|
-
lines.push(this.buildStatusLine(i));
|
|
134
|
-
|
|
135
|
-
const step = this.steps[i];
|
|
136
|
-
// Children for non-pending steps
|
|
137
|
-
if (step.status !== 'pending') {
|
|
138
|
-
for (let j = 0; j < step.children.length; j++) {
|
|
139
|
-
const child = step.children[j];
|
|
140
|
-
const isLast = j === step.children.length - 1;
|
|
141
|
-
const branch = isLast ? SYMBOLS.branchLast : SYMBOLS.branch;
|
|
142
|
-
const prefix = child.type === 'new' ? chalk.green('+') :
|
|
143
|
-
child.type === 'update' ? chalk.blue('~') :
|
|
144
|
-
child.type === 'skip' ? chalk.yellow('!') :
|
|
145
|
-
child.type === 'delete' ? chalk.red('-') :
|
|
146
|
-
child.type === 'info' ? chalk.cyan('i') :
|
|
147
|
-
chalk.dim('•');
|
|
148
|
-
lines.push(` ${SYMBOLS.indent}${branch} ${prefix} ${child.text}`);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// In-place update if have previous output
|
|
154
|
-
if (this.lastLineCount > 0) {
|
|
155
|
-
process.stdout.write(`\x1b[${this.lastLineCount}A`);
|
|
156
|
-
for (let i = 0; i < this.lastLineCount; i++) {
|
|
157
|
-
process.stdout.write('\x1b[2K\n');
|
|
158
|
-
}
|
|
159
|
-
process.stdout.write(`\x1b[${this.lastLineCount}A`);
|
|
160
|
-
} else {
|
|
161
|
-
console.log('');
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
for (const line of lines) {
|
|
165
|
-
console.log(line);
|
|
166
|
-
}
|
|
167
|
-
console.log('');
|
|
168
|
-
|
|
169
|
-
this.lastLineCount = lines.length + 1;
|
|
170
|
-
}
|
|
96
|
+
const prefix = type === 'new' ? chalk.green('+') :
|
|
97
|
+
type === 'update' ? chalk.blue('~') :
|
|
98
|
+
type === 'skip' ? chalk.yellow('!') :
|
|
99
|
+
type === 'delete' ? chalk.red('-') :
|
|
100
|
+
type === 'info' ? chalk.cyan('i') :
|
|
101
|
+
chalk.dim('•');
|
|
102
|
+
console.log(` ${chalk.dim('├──')} ${prefix} ${text}`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// No-op for compatibility
|
|
106
|
+
pause() {}
|
|
107
|
+
resume() { console.log(''); }
|
|
108
|
+
render() {}
|
|
171
109
|
}
|
|
172
110
|
|
|
173
111
|
// =============================================================================
|
|
@@ -439,7 +377,8 @@ async function initCommand(options) {
|
|
|
439
377
|
timeline.addStep('Scan changes');
|
|
440
378
|
timeline.addStep('Confirm changes');
|
|
441
379
|
timeline.addStep('Apply changes');
|
|
442
|
-
timeline.addStep('
|
|
380
|
+
timeline.addStep('Check dependencies');
|
|
381
|
+
timeline.addStep('Install packages');
|
|
443
382
|
|
|
444
383
|
// Step 1: Authenticate
|
|
445
384
|
timeline.start(0);
|
|
@@ -608,6 +547,7 @@ async function initCommand(options) {
|
|
|
608
547
|
timeline.skip(4, 'User cancelled');
|
|
609
548
|
timeline.skip(5, 'Skipped');
|
|
610
549
|
timeline.skip(6, 'Skipped');
|
|
550
|
+
timeline.skip(7, 'Skipped');
|
|
611
551
|
|
|
612
552
|
// Cleanup
|
|
613
553
|
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
@@ -669,111 +609,43 @@ async function initCommand(options) {
|
|
|
669
609
|
|
|
670
610
|
timeline.complete(5, `${applied} files`);
|
|
671
611
|
|
|
672
|
-
// Step 7:
|
|
612
|
+
// Step 7: Check dependencies
|
|
673
613
|
timeline.start(6);
|
|
674
614
|
|
|
675
615
|
const libPythonDir = path.join(projectDir, 'lib', 'python');
|
|
676
616
|
|
|
677
|
-
//
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
const
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
}
|
|
697
|
-
timeline.resume();
|
|
698
|
-
|
|
699
|
-
const pkgStatus = checkPythonPackages(libPythonDir);
|
|
700
|
-
|
|
701
|
-
// Show Python version in timeline
|
|
702
|
-
timeline.addChild(6, `Python ${pythonCmd === 'python3' ? pythonInfo.version : '3.x'} (${pythonCmd})`, 'update');
|
|
703
|
-
|
|
704
|
-
// Show already installed count
|
|
705
|
-
if (pkgStatus.installed.length > 0) {
|
|
706
|
-
timeline.addChild(6, `${pkgStatus.installed.length} packages already installed`, 'info');
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
const allToInstall = [...pkgStatus.toInstall, ...pkgStatus.toUpdate];
|
|
710
|
-
|
|
711
|
-
if (allToInstall.length === 0) {
|
|
712
|
-
timeline.complete(6, `${pkgStatus.installed.length} packages ready`);
|
|
713
|
-
return;
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
// Show what needs to be installed/updated with tree connector
|
|
717
|
-
console.log(`\n ${pipe}`);
|
|
718
|
-
console.log(` ${branch} ${chalk.cyan('Packages to install/update:')}`);
|
|
719
|
-
|
|
720
|
-
const showPkgs = allToInstall.slice(0, 10);
|
|
721
|
-
const hasMore = allToInstall.length > 10;
|
|
722
|
-
|
|
723
|
-
for (let i = 0; i < showPkgs.length; i++) {
|
|
724
|
-
const pkg = showPkgs[i];
|
|
725
|
-
const isLast = i === showPkgs.length - 1 && !hasMore;
|
|
726
|
-
const prefix = isLast ? corner : branch;
|
|
727
|
-
if (pkg.current) {
|
|
728
|
-
console.log(` ${pipe} ${prefix} ${chalk.blue('~')} ${pkg.name}: ${pkg.current} → ${pkg.required}`);
|
|
729
|
-
} else {
|
|
730
|
-
console.log(` ${pipe} ${prefix} ${chalk.green('+')} ${pkg.name}: ${pkg.required || 'latest'}`);
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
if (hasMore) {
|
|
734
|
-
console.log(` ${pipe} ${corner} ${chalk.dim(`... and ${allToInstall.length - 10} more`)}`);
|
|
735
|
-
}
|
|
736
|
-
console.log(` ${pipe}`);
|
|
737
|
-
|
|
738
|
-
timeline.pause();
|
|
739
|
-
const { confirmPkgs } = await inquirer.prompt([{
|
|
740
|
-
type: 'confirm',
|
|
741
|
-
name: 'confirmPkgs',
|
|
742
|
-
message: `Install/update ${allToInstall.length} packages?`,
|
|
743
|
-
default: true
|
|
744
|
-
}]);
|
|
745
|
-
timeline.resume();
|
|
746
|
-
|
|
747
|
-
if (confirmPkgs) {
|
|
748
|
-
await installPackages(libPythonDir, allToInstall, timeline, 6, pythonCmd);
|
|
749
|
-
timeline.complete(6, `${pkgStatus.installed.length + allToInstall.length} packages`);
|
|
750
|
-
} else {
|
|
751
|
-
timeline.skip(6, 'User skipped');
|
|
752
|
-
}
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
// Check Python availability first
|
|
617
|
+
// Check if lib/python exists
|
|
618
|
+
if (!fs.existsSync(libPythonDir)) {
|
|
619
|
+
timeline.addChild(6, 'No lib/python folder', 'skip');
|
|
620
|
+
timeline.complete(6, 'Skipped');
|
|
621
|
+
timeline.skip(7, 'No dependencies');
|
|
622
|
+
|
|
623
|
+
// Cleanup and finish
|
|
624
|
+
try { fs.rmSync(tempDir, { recursive: true, force: true }); } catch {}
|
|
625
|
+
const ver = selectedVersion.replace(/^v/, '');
|
|
626
|
+
console.log(chalk.green(`\n ✓ CSK v${ver} ${isUpdate ? 'updated' : 'installed'} successfully!\n`));
|
|
627
|
+
console.log(chalk.cyan(' Quick Start\n'));
|
|
628
|
+
console.log(chalk.dim(' 1. Open Claude Code:'));
|
|
629
|
+
console.log(` ${chalk.white('claude')}\n`);
|
|
630
|
+
console.log(chalk.dim(' 2. Start with CSK:'));
|
|
631
|
+
console.log(` ${chalk.white('/csk')}\n`);
|
|
632
|
+
return;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// Check Python availability
|
|
756
636
|
let pythonInfo = detectPython();
|
|
757
637
|
let pythonReady = false;
|
|
758
638
|
|
|
759
639
|
if (!pythonInfo.found) {
|
|
760
|
-
|
|
761
|
-
console.log(chalk.yellow(' Python not found on this system.'));
|
|
762
|
-
console.log(chalk.dim(' Python is required for:'));
|
|
763
|
-
console.log(chalk.dim(' - Data fetching and analysis'));
|
|
764
|
-
console.log(chalk.dim(' - Chart generation'));
|
|
765
|
-
console.log(chalk.dim(' - MCP server tools'));
|
|
766
|
-
console.log('');
|
|
640
|
+
timeline.addChild(6, 'Python not found', 'skip');
|
|
767
641
|
|
|
768
642
|
// Check if we can auto-install
|
|
769
643
|
const autoInstall = canAutoInstall();
|
|
770
644
|
|
|
771
645
|
if (autoInstall.canInstall) {
|
|
646
|
+
console.log('');
|
|
647
|
+
console.log(chalk.yellow(' Python not found on this system.'));
|
|
772
648
|
console.log(chalk.cyan(` Auto-install available via ${autoInstall.manager}`));
|
|
773
|
-
if (autoInstall.needsSudo) {
|
|
774
|
-
console.log(chalk.dim(' (requires sudo password)'));
|
|
775
|
-
}
|
|
776
|
-
console.log(chalk.dim(` Command: ${autoInstall.command}`));
|
|
777
649
|
console.log('');
|
|
778
650
|
|
|
779
651
|
timeline.pause();
|
|
@@ -786,11 +658,9 @@ async function initCommand(options) {
|
|
|
786
658
|
timeline.resume();
|
|
787
659
|
|
|
788
660
|
if (doInstall) {
|
|
789
|
-
console.log('');
|
|
790
661
|
timeline.addChild(6, `Installing via ${autoInstall.manager}...`, 'update');
|
|
791
|
-
|
|
792
662
|
const result = await installPython((msg) => {
|
|
793
|
-
console.log(chalk.dim(`
|
|
663
|
+
console.log(chalk.dim(` ${msg}`));
|
|
794
664
|
});
|
|
795
665
|
|
|
796
666
|
if (result.success) {
|
|
@@ -798,43 +668,85 @@ async function initCommand(options) {
|
|
|
798
668
|
timeline.addChild(6, `Python ${result.version} installed`, 'new');
|
|
799
669
|
pythonReady = true;
|
|
800
670
|
} else {
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
console.log('');
|
|
805
|
-
timeline.skip(6, 'Installation failed');
|
|
671
|
+
timeline.addChild(6, 'Installation failed', 'skip');
|
|
672
|
+
timeline.complete(6, 'Failed');
|
|
673
|
+
timeline.skip(7, 'No Python');
|
|
806
674
|
}
|
|
807
675
|
} else {
|
|
808
|
-
timeline.
|
|
676
|
+
timeline.complete(6, 'Skipped');
|
|
677
|
+
timeline.skip(7, 'No Python');
|
|
809
678
|
}
|
|
810
679
|
} else {
|
|
811
|
-
//
|
|
680
|
+
// Show manual instructions
|
|
812
681
|
const instructions = getInstallInstructions();
|
|
813
|
-
console.log(chalk.bold(` Install via ${instructions.method}:\n`));
|
|
814
|
-
for (const cmd of instructions.commands.slice(0, 4)) {
|
|
815
|
-
if (cmd.startsWith('#')) {
|
|
816
|
-
console.log(chalk.dim(` ${cmd}`));
|
|
817
|
-
} else if (cmd !== '') {
|
|
818
|
-
console.log(chalk.cyan(` ${cmd}`));
|
|
819
|
-
}
|
|
820
|
-
}
|
|
821
682
|
console.log('');
|
|
822
|
-
|
|
683
|
+
console.log(chalk.yellow(' Python not found. Install via:'));
|
|
684
|
+
console.log(chalk.cyan(` ${instructions.commands[0]}`));
|
|
685
|
+
console.log('');
|
|
686
|
+
timeline.complete(6, 'Python needed');
|
|
687
|
+
timeline.skip(7, 'No Python');
|
|
823
688
|
}
|
|
824
689
|
} else if (!pythonInfo.meetsMinimum) {
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
console.log('');
|
|
829
|
-
timeline.skip(6, `Python ${pythonInfo.version} too old`);
|
|
690
|
+
timeline.addChild(6, `Python ${pythonInfo.version} (need 3.8+)`, 'skip');
|
|
691
|
+
timeline.complete(6, 'Upgrade needed');
|
|
692
|
+
timeline.skip(7, 'Python too old');
|
|
830
693
|
} else {
|
|
831
694
|
pythonReady = true;
|
|
695
|
+
timeline.addChild(6, `Python ${pythonInfo.version}`, 'info');
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
// If Python not ready, exit early
|
|
699
|
+
if (!pythonReady) {
|
|
700
|
+
try { fs.rmSync(tempDir, { recursive: true, force: true }); } catch {}
|
|
701
|
+
const ver = selectedVersion.replace(/^v/, '');
|
|
702
|
+
console.log(chalk.green(`\n ✓ CSK v${ver} ${isUpdate ? 'updated' : 'installed'} successfully!\n`));
|
|
703
|
+
console.log(chalk.dim(' Note: Python dependencies not installed.\n'));
|
|
704
|
+
return;
|
|
832
705
|
}
|
|
833
706
|
|
|
834
|
-
//
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
707
|
+
// Check packages
|
|
708
|
+
const pkgStatus = checkPythonPackages(libPythonDir);
|
|
709
|
+
const allToInstall = [...pkgStatus.toInstall, ...pkgStatus.toUpdate];
|
|
710
|
+
|
|
711
|
+
if (pkgStatus.installed.length > 0) {
|
|
712
|
+
timeline.addChild(6, `${pkgStatus.installed.length} packages OK`, 'info');
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
if (allToInstall.length === 0) {
|
|
716
|
+
timeline.complete(6, 'All ready');
|
|
717
|
+
timeline.skip(7, 'Nothing to install');
|
|
718
|
+
} else {
|
|
719
|
+
// Show packages to install/update
|
|
720
|
+
for (const pkg of allToInstall.slice(0, 5)) {
|
|
721
|
+
if (pkg.current) {
|
|
722
|
+
timeline.addChild(6, `${pkg.name}: ${pkg.current} → ${pkg.required}`, 'update');
|
|
723
|
+
} else {
|
|
724
|
+
timeline.addChild(6, `${pkg.name}: ${pkg.required || 'latest'}`, 'new');
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
if (allToInstall.length > 5) {
|
|
728
|
+
timeline.addChild(6, `... and ${allToInstall.length - 5} more`, 'info');
|
|
729
|
+
}
|
|
730
|
+
timeline.complete(6, `${allToInstall.length} to install`);
|
|
731
|
+
|
|
732
|
+
// Step 8: Install packages
|
|
733
|
+
timeline.start(7);
|
|
734
|
+
|
|
735
|
+
timeline.pause();
|
|
736
|
+
const { confirmPkgs } = await inquirer.prompt([{
|
|
737
|
+
type: 'confirm',
|
|
738
|
+
name: 'confirmPkgs',
|
|
739
|
+
message: `Install ${allToInstall.length} packages?`,
|
|
740
|
+
default: true
|
|
741
|
+
}]);
|
|
742
|
+
timeline.resume();
|
|
743
|
+
|
|
744
|
+
if (confirmPkgs) {
|
|
745
|
+
await installPackages(libPythonDir, allToInstall, timeline, 7, pythonInfo.command);
|
|
746
|
+
timeline.complete(7, `${pkgStatus.installed.length + allToInstall.length} packages`);
|
|
747
|
+
} else {
|
|
748
|
+
timeline.skip(7, 'Skipped');
|
|
749
|
+
}
|
|
838
750
|
}
|
|
839
751
|
|
|
840
752
|
// Cleanup temp files
|