clevermation-cli 0.3.2
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/.github/workflows/publish.yml +46 -0
- package/CLAUDE.md +167 -0
- package/README.md +211 -0
- package/bin/cl +2 -0
- package/bin/clever +2 -0
- package/bun.lock +361 -0
- package/package.json +43 -0
- package/scripts/setup-team-member.sh +43 -0
- package/src/commands/auth.ts +302 -0
- package/src/commands/config.ts +174 -0
- package/src/commands/doctor.ts +15 -0
- package/src/commands/explain.ts +113 -0
- package/src/commands/init.ts +429 -0
- package/src/commands/open.ts +104 -0
- package/src/commands/sync.ts +181 -0
- package/src/commands/update.ts +90 -0
- package/src/index.ts +44 -0
- package/src/types/config.ts +90 -0
- package/src/utils/auto-update.ts +169 -0
- package/src/utils/config.ts +85 -0
- package/src/utils/logger.ts +49 -0
- package/src/utils/prerequisites.ts +228 -0
- package/tsconfig.json +29 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { execa } from 'execa';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { logger } from './logger.js';
|
|
5
|
+
|
|
6
|
+
interface Prerequisite {
|
|
7
|
+
name: string;
|
|
8
|
+
command: string;
|
|
9
|
+
versionFlag: string;
|
|
10
|
+
installCommand?: string;
|
|
11
|
+
installMessage?: string;
|
|
12
|
+
optional?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const PREREQUISITES: Prerequisite[] = [
|
|
16
|
+
{
|
|
17
|
+
name: 'Bun',
|
|
18
|
+
command: 'bun',
|
|
19
|
+
versionFlag: '--version',
|
|
20
|
+
installCommand: 'curl -fsSL https://bun.sh/install | bash',
|
|
21
|
+
installMessage: 'Installiere Bun...',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: 'Git',
|
|
25
|
+
command: 'git',
|
|
26
|
+
versionFlag: '--version',
|
|
27
|
+
installCommand: 'brew install git',
|
|
28
|
+
installMessage: 'Installiere Git...',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: 'GitHub CLI',
|
|
32
|
+
command: 'gh',
|
|
33
|
+
versionFlag: '--version',
|
|
34
|
+
installCommand: 'brew install gh',
|
|
35
|
+
installMessage: 'Installiere GitHub CLI...',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: 'Claude Code',
|
|
39
|
+
command: 'claude',
|
|
40
|
+
versionFlag: '--version',
|
|
41
|
+
installCommand: 'brew install claude',
|
|
42
|
+
installMessage: 'Installiere Claude Code...',
|
|
43
|
+
optional: true,
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: 'Supabase CLI',
|
|
47
|
+
command: 'supabase',
|
|
48
|
+
versionFlag: '--version',
|
|
49
|
+
installCommand: 'brew install supabase/tap/supabase',
|
|
50
|
+
installMessage: 'Installiere Supabase CLI...',
|
|
51
|
+
optional: true,
|
|
52
|
+
},
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
interface CheckResult {
|
|
56
|
+
name: string;
|
|
57
|
+
installed: boolean;
|
|
58
|
+
version?: string;
|
|
59
|
+
optional: boolean;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Prüft alle Voraussetzungen und installiert fehlende automatisch.
|
|
64
|
+
* Läuft still im Hintergrund - User merkt nichts außer bei Fehlern.
|
|
65
|
+
*/
|
|
66
|
+
export async function ensurePrerequisites(options?: {
|
|
67
|
+
verbose?: boolean;
|
|
68
|
+
requiredOnly?: boolean;
|
|
69
|
+
autoInstall?: boolean;
|
|
70
|
+
}): Promise<CheckResult[]> {
|
|
71
|
+
const { verbose = false, requiredOnly = false, autoInstall = true } = options || {};
|
|
72
|
+
const results: CheckResult[] = [];
|
|
73
|
+
|
|
74
|
+
const prereqs = requiredOnly
|
|
75
|
+
? PREREQUISITES.filter((p) => !p.optional)
|
|
76
|
+
: PREREQUISITES;
|
|
77
|
+
|
|
78
|
+
for (const prereq of prereqs) {
|
|
79
|
+
const result = await checkPrerequisite(prereq);
|
|
80
|
+
results.push(result);
|
|
81
|
+
|
|
82
|
+
// Auto-Install wenn nicht vorhanden und nicht optional
|
|
83
|
+
if (!result.installed && autoInstall && prereq.installCommand && !prereq.optional) {
|
|
84
|
+
await installPrerequisite(prereq, verbose);
|
|
85
|
+
// Erneut prüfen
|
|
86
|
+
const recheck = await checkPrerequisite(prereq);
|
|
87
|
+
results[results.length - 1] = recheck;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return results;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function checkPrerequisite(prereq: Prerequisite): Promise<CheckResult> {
|
|
95
|
+
try {
|
|
96
|
+
const { stdout } = await execa(prereq.command, [prereq.versionFlag], {
|
|
97
|
+
timeout: 5000,
|
|
98
|
+
reject: false,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// Version extrahieren (erstes Match von Zahlen mit Punkten)
|
|
102
|
+
const versionMatch = stdout.match(/\d+\.\d+(\.\d+)?/);
|
|
103
|
+
const version = versionMatch ? versionMatch[0] : undefined;
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
name: prereq.name,
|
|
107
|
+
installed: true,
|
|
108
|
+
version,
|
|
109
|
+
optional: prereq.optional || false,
|
|
110
|
+
};
|
|
111
|
+
} catch {
|
|
112
|
+
return {
|
|
113
|
+
name: prereq.name,
|
|
114
|
+
installed: false,
|
|
115
|
+
optional: prereq.optional || false,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async function installPrerequisite(prereq: Prerequisite, verbose: boolean): Promise<boolean> {
|
|
121
|
+
if (!prereq.installCommand) return false;
|
|
122
|
+
|
|
123
|
+
const spinner = verbose
|
|
124
|
+
? ora(prereq.installMessage || `Installiere ${prereq.name}...`).start()
|
|
125
|
+
: null;
|
|
126
|
+
|
|
127
|
+
try {
|
|
128
|
+
// Führe Install-Command aus
|
|
129
|
+
await execa('sh', ['-c', prereq.installCommand], {
|
|
130
|
+
timeout: 120000, // 2 Minuten Timeout
|
|
131
|
+
stdio: verbose ? 'inherit' : 'pipe',
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
spinner?.succeed(`${prereq.name} installiert`);
|
|
135
|
+
return true;
|
|
136
|
+
} catch (error) {
|
|
137
|
+
spinner?.fail(`${prereq.name} Installation fehlgeschlagen`);
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Zeigt den Status aller Voraussetzungen an (für cl doctor).
|
|
144
|
+
*/
|
|
145
|
+
export async function showPrerequisiteStatus(): Promise<void> {
|
|
146
|
+
logger.title('System-Check');
|
|
147
|
+
|
|
148
|
+
const results = await ensurePrerequisites({ autoInstall: false });
|
|
149
|
+
|
|
150
|
+
for (const result of results) {
|
|
151
|
+
if (result.installed) {
|
|
152
|
+
const version = result.version ? chalk.dim(` v${result.version}`) : '';
|
|
153
|
+
console.log(chalk.green(' ✓'), result.name + version);
|
|
154
|
+
} else if (result.optional) {
|
|
155
|
+
console.log(chalk.yellow(' ○'), result.name, chalk.dim('(optional, nicht installiert)'));
|
|
156
|
+
} else {
|
|
157
|
+
console.log(chalk.red(' ✗'), result.name, chalk.dim('(nicht installiert)'));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
logger.blank();
|
|
162
|
+
|
|
163
|
+
// GitHub Auth Status prüfen
|
|
164
|
+
const ghAuthStatus = await checkGitHubAuth();
|
|
165
|
+
if (ghAuthStatus.authenticated) {
|
|
166
|
+
console.log(chalk.green(' ✓'), `GitHub authentifiziert als ${ghAuthStatus.username}`);
|
|
167
|
+
} else {
|
|
168
|
+
console.log(chalk.red(' ✗'), 'GitHub nicht authentifiziert');
|
|
169
|
+
console.log(chalk.dim(' → gh auth login'));
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Supabase Auth Status prüfen
|
|
173
|
+
const supabaseAuthStatus = await checkSupabaseAuth();
|
|
174
|
+
if (supabaseAuthStatus) {
|
|
175
|
+
console.log(chalk.green(' ✓'), 'Supabase authentifiziert');
|
|
176
|
+
} else {
|
|
177
|
+
console.log(chalk.yellow(' ○'), 'Supabase nicht authentifiziert', chalk.dim('(optional)'));
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
logger.blank();
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Prüft GitHub Authentifizierung.
|
|
185
|
+
*/
|
|
186
|
+
export async function checkGitHubAuth(): Promise<{ authenticated: boolean; username?: string }> {
|
|
187
|
+
try {
|
|
188
|
+
const { stdout } = await execa('gh', ['auth', 'status'], { reject: false });
|
|
189
|
+
const usernameMatch = stdout.match(/Logged in to .+ account (\w+)/);
|
|
190
|
+
return {
|
|
191
|
+
authenticated: stdout.includes('Logged in'),
|
|
192
|
+
username: usernameMatch?.[1],
|
|
193
|
+
};
|
|
194
|
+
} catch {
|
|
195
|
+
return { authenticated: false };
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Prüft Supabase Authentifizierung.
|
|
201
|
+
*/
|
|
202
|
+
export async function checkSupabaseAuth(): Promise<boolean> {
|
|
203
|
+
try {
|
|
204
|
+
const result = await execa('supabase', ['projects', 'list'], {
|
|
205
|
+
timeout: 10000,
|
|
206
|
+
reject: false,
|
|
207
|
+
});
|
|
208
|
+
return result.exitCode === 0;
|
|
209
|
+
} catch {
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Stille Hintergrund-Prüfung beim CLI-Start.
|
|
216
|
+
* Installiert fehlende Required-Tools automatisch.
|
|
217
|
+
*/
|
|
218
|
+
export async function silentPrerequisiteCheck(): Promise<void> {
|
|
219
|
+
try {
|
|
220
|
+
await ensurePrerequisites({
|
|
221
|
+
verbose: false,
|
|
222
|
+
requiredOnly: true,
|
|
223
|
+
autoInstall: true,
|
|
224
|
+
});
|
|
225
|
+
} catch {
|
|
226
|
+
// Fehler ignorieren - soll CLI nicht blockieren
|
|
227
|
+
}
|
|
228
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
// Environment setup & latest features
|
|
4
|
+
"lib": ["ESNext"],
|
|
5
|
+
"target": "ESNext",
|
|
6
|
+
"module": "Preserve",
|
|
7
|
+
"moduleDetection": "force",
|
|
8
|
+
"jsx": "react-jsx",
|
|
9
|
+
"allowJs": true,
|
|
10
|
+
|
|
11
|
+
// Bundler mode
|
|
12
|
+
"moduleResolution": "bundler",
|
|
13
|
+
"allowImportingTsExtensions": true,
|
|
14
|
+
"verbatimModuleSyntax": true,
|
|
15
|
+
"noEmit": true,
|
|
16
|
+
|
|
17
|
+
// Best practices
|
|
18
|
+
"strict": true,
|
|
19
|
+
"skipLibCheck": true,
|
|
20
|
+
"noFallthroughCasesInSwitch": true,
|
|
21
|
+
"noUncheckedIndexedAccess": true,
|
|
22
|
+
"noImplicitOverride": true,
|
|
23
|
+
|
|
24
|
+
// Some stricter flags (disabled by default)
|
|
25
|
+
"noUnusedLocals": false,
|
|
26
|
+
"noUnusedParameters": false,
|
|
27
|
+
"noPropertyAccessFromIndexSignature": false
|
|
28
|
+
}
|
|
29
|
+
}
|