tweakidea 0.1.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/LICENSE +21 -0
- package/README.md +95 -0
- package/agents/ti-evaluator.md +162 -0
- package/agents/ti-extractor.md +84 -0
- package/agents/ti-merger.md +179 -0
- package/agents/ti-researcher.md +99 -0
- package/bin/install.js +449 -0
- package/commands/tweak/evaluate.md +632 -0
- package/package.json +31 -0
- package/skills/ti-founder/SKILL.md +186 -0
- package/skills/ti-html-report/SKILL.md +352 -0
- package/skills/ti-scoring/EVALUATION.md +63 -0
- package/skills/ti-scoring/SKILL.md +7 -0
- package/skills/ti-scoring/dimensions/behavior-change-required.md +54 -0
- package/skills/ti-scoring/dimensions/clarity-of-target-customer.md +49 -0
- package/skills/ti-scoring/dimensions/defensibility.md +50 -0
- package/skills/ti-scoring/dimensions/founder-market-fit.md +51 -0
- package/skills/ti-scoring/dimensions/frequency.md +44 -0
- package/skills/ti-scoring/dimensions/incumbent-indifference.md +50 -0
- package/skills/ti-scoring/dimensions/mandatory-nature.md +43 -0
- package/skills/ti-scoring/dimensions/market-growth.md +47 -0
- package/skills/ti-scoring/dimensions/market-size.md +50 -0
- package/skills/ti-scoring/dimensions/pain-intensity.md +48 -0
- package/skills/ti-scoring/dimensions/scalability.md +48 -0
- package/skills/ti-scoring/dimensions/solution-gap.md +55 -0
- package/skills/ti-scoring/dimensions/urgency.md +46 -0
- package/skills/ti-scoring/dimensions/willingness-to-pay.md +53 -0
package/bin/install.js
ADDED
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const os = require('os');
|
|
8
|
+
const readline = require('readline');
|
|
9
|
+
|
|
10
|
+
const pkg = require('../package.json');
|
|
11
|
+
|
|
12
|
+
// ── ANSI helpers ────────────────────────────────────────────────────────────────
|
|
13
|
+
|
|
14
|
+
const cyan = '\x1b[36m';
|
|
15
|
+
const green = '\x1b[32m';
|
|
16
|
+
const yellow = '\x1b[33m';
|
|
17
|
+
const red = '\x1b[31m';
|
|
18
|
+
const dim = '\x1b[2m';
|
|
19
|
+
const bold = '\x1b[1m';
|
|
20
|
+
const reset = '\x1b[0m';
|
|
21
|
+
|
|
22
|
+
// ── File manifest ───────────────────────────────────────────────────────────────
|
|
23
|
+
|
|
24
|
+
const AGENT_FILES = [
|
|
25
|
+
'ti-evaluator.md',
|
|
26
|
+
'ti-extractor.md',
|
|
27
|
+
'ti-merger.md',
|
|
28
|
+
'ti-researcher.md',
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
const SKILL_DIRS = [
|
|
32
|
+
'ti-scoring',
|
|
33
|
+
'ti-founder',
|
|
34
|
+
'ti-html-report',
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
const COMMAND_SRC = 'commands/tweak/evaluate.md';
|
|
38
|
+
|
|
39
|
+
// ── CLI argument parsing ────────────────────────────────────────────────────────
|
|
40
|
+
|
|
41
|
+
const args = process.argv.slice(2);
|
|
42
|
+
|
|
43
|
+
function hasFlag(...flags) {
|
|
44
|
+
return flags.some((f) => args.includes(f));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const wantGlobal = hasFlag('--global', '-g');
|
|
48
|
+
const wantLocal = hasFlag('--local', '-l');
|
|
49
|
+
const wantUninstall = hasFlag('--uninstall', '-u');
|
|
50
|
+
const wantHelp = hasFlag('--help', '-h');
|
|
51
|
+
const wantVersion = hasFlag('--version', '-v');
|
|
52
|
+
|
|
53
|
+
// ── Path resolution ─────────────────────────────────────────────────────────────
|
|
54
|
+
|
|
55
|
+
function getGlobalDir() {
|
|
56
|
+
return path.join(os.homedir(), '.claude');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function getLocalDir() {
|
|
60
|
+
return path.join(process.cwd(), '.claude');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function resolveTargetDir(isGlobal) {
|
|
64
|
+
return isGlobal ? getGlobalDir() : getLocalDir();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function getSourceDir() {
|
|
68
|
+
return path.join(__dirname, '..');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ── File utilities ──────────────────────────────────────────────────────────────
|
|
72
|
+
|
|
73
|
+
function mkdirp(dir) {
|
|
74
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function copyFileSync(src, dest) {
|
|
78
|
+
mkdirp(path.dirname(dest));
|
|
79
|
+
fs.copyFileSync(src, dest);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function copyDirSync(src, dest) {
|
|
83
|
+
mkdirp(dest);
|
|
84
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
85
|
+
for (const entry of entries) {
|
|
86
|
+
const srcPath = path.join(src, entry.name);
|
|
87
|
+
const destPath = path.join(dest, entry.name);
|
|
88
|
+
if (entry.isDirectory()) {
|
|
89
|
+
copyDirSync(srcPath, destPath);
|
|
90
|
+
} else {
|
|
91
|
+
fs.copyFileSync(srcPath, destPath);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function rmrf(target) {
|
|
97
|
+
if (!fs.existsSync(target)) return;
|
|
98
|
+
fs.rmSync(target, { recursive: true, force: true });
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ── Cleanup ─────────────────────────────────────────────────────────────────────
|
|
102
|
+
|
|
103
|
+
function cleanupPreviousInstall(targetDir) {
|
|
104
|
+
let removed = 0;
|
|
105
|
+
|
|
106
|
+
// Remove agents
|
|
107
|
+
for (const file of AGENT_FILES) {
|
|
108
|
+
const p = path.join(targetDir, 'agents', file);
|
|
109
|
+
if (fs.existsSync(p)) {
|
|
110
|
+
fs.unlinkSync(p);
|
|
111
|
+
removed++;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Remove skill directories
|
|
116
|
+
for (const dir of SKILL_DIRS) {
|
|
117
|
+
const p = path.join(targetDir, 'skills', dir);
|
|
118
|
+
if (fs.existsSync(p)) {
|
|
119
|
+
rmrf(p);
|
|
120
|
+
removed++;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Remove command (local install format)
|
|
125
|
+
const cmdPath = path.join(targetDir, 'commands', 'tweak', 'evaluate.md');
|
|
126
|
+
if (fs.existsSync(cmdPath)) {
|
|
127
|
+
fs.unlinkSync(cmdPath);
|
|
128
|
+
// Clean empty parent dirs
|
|
129
|
+
const tweakDir = path.join(targetDir, 'commands', 'tweak');
|
|
130
|
+
if (fs.existsSync(tweakDir) && fs.readdirSync(tweakDir).length === 0) {
|
|
131
|
+
fs.rmdirSync(tweakDir);
|
|
132
|
+
}
|
|
133
|
+
removed++;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Remove skill (global install format)
|
|
137
|
+
const skillPath = path.join(targetDir, 'skills', 'tweak-evaluate');
|
|
138
|
+
if (fs.existsSync(skillPath)) {
|
|
139
|
+
rmrf(skillPath);
|
|
140
|
+
removed++;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Remove version tracking
|
|
144
|
+
const versionDir = path.join(targetDir, 'tweakidea');
|
|
145
|
+
if (fs.existsSync(versionDir)) {
|
|
146
|
+
rmrf(versionDir);
|
|
147
|
+
removed++;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return removed;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// ── Settings merger ─────────────────────────────────────────────────────────────
|
|
154
|
+
|
|
155
|
+
function mergeSettings(targetDir) {
|
|
156
|
+
const settingsPath = path.join(targetDir, 'settings.json');
|
|
157
|
+
let settings = {};
|
|
158
|
+
|
|
159
|
+
if (fs.existsSync(settingsPath)) {
|
|
160
|
+
try {
|
|
161
|
+
settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
|
|
162
|
+
} catch {
|
|
163
|
+
// If settings.json is malformed, start fresh
|
|
164
|
+
settings = {};
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Ensure permissions structure
|
|
169
|
+
if (!settings.permissions) settings.permissions = {};
|
|
170
|
+
if (!Array.isArray(settings.permissions.allow)) settings.permissions.allow = [];
|
|
171
|
+
if (!Array.isArray(settings.permissions.additionalDirectories)) {
|
|
172
|
+
settings.permissions.additionalDirectories = [];
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Add required permissions (deduplicated)
|
|
176
|
+
const requiredAllow = ['WebSearch', 'WebFetch'];
|
|
177
|
+
for (const perm of requiredAllow) {
|
|
178
|
+
if (!settings.permissions.allow.includes(perm)) {
|
|
179
|
+
settings.permissions.allow.push(perm);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const requiredDirs = ['~/.tweakidea/*'];
|
|
184
|
+
for (const dir of requiredDirs) {
|
|
185
|
+
if (!settings.permissions.additionalDirectories.includes(dir)) {
|
|
186
|
+
settings.permissions.additionalDirectories.push(dir);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
mkdirp(targetDir);
|
|
191
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function removeSettingsEntries(targetDir) {
|
|
195
|
+
const settingsPath = path.join(targetDir, 'settings.json');
|
|
196
|
+
if (!fs.existsSync(settingsPath)) return;
|
|
197
|
+
|
|
198
|
+
let settings;
|
|
199
|
+
try {
|
|
200
|
+
settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
|
|
201
|
+
} catch {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (settings.permissions) {
|
|
206
|
+
if (Array.isArray(settings.permissions.allow)) {
|
|
207
|
+
settings.permissions.allow = settings.permissions.allow.filter(
|
|
208
|
+
(p) => p !== 'WebSearch' && p !== 'WebFetch'
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
if (Array.isArray(settings.permissions.additionalDirectories)) {
|
|
212
|
+
settings.permissions.additionalDirectories =
|
|
213
|
+
settings.permissions.additionalDirectories.filter(
|
|
214
|
+
(d) => d !== '~/.tweakidea/*'
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// ── Version tracking ────────────────────────────────────────────────────────────
|
|
223
|
+
|
|
224
|
+
function writeVersion(targetDir, version) {
|
|
225
|
+
const versionDir = path.join(targetDir, 'tweakidea');
|
|
226
|
+
mkdirp(versionDir);
|
|
227
|
+
fs.writeFileSync(path.join(versionDir, 'VERSION'), version + '\n');
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function readInstalledVersion(targetDir) {
|
|
231
|
+
const versionFile = path.join(targetDir, 'tweakidea', 'VERSION');
|
|
232
|
+
if (!fs.existsSync(versionFile)) return null;
|
|
233
|
+
return fs.readFileSync(versionFile, 'utf8').trim();
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// ── Install ─────────────────────────────────────────────────────────────────────
|
|
237
|
+
|
|
238
|
+
function install(isGlobal) {
|
|
239
|
+
const targetDir = resolveTargetDir(isGlobal);
|
|
240
|
+
const sourceDir = getSourceDir();
|
|
241
|
+
const location = isGlobal ? 'global' : 'local';
|
|
242
|
+
const displayPath = isGlobal
|
|
243
|
+
? '~/.claude'
|
|
244
|
+
: path.relative(process.cwd(), targetDir) || '.claude';
|
|
245
|
+
|
|
246
|
+
// Check existing version
|
|
247
|
+
const existingVersion = readInstalledVersion(targetDir);
|
|
248
|
+
if (existingVersion) {
|
|
249
|
+
if (existingVersion === pkg.version) {
|
|
250
|
+
console.log(
|
|
251
|
+
`\n${dim}TweakIdea v${existingVersion} already installed. Reinstalling...${reset}`
|
|
252
|
+
);
|
|
253
|
+
} else {
|
|
254
|
+
console.log(
|
|
255
|
+
`\n${cyan}Upgrading TweakIdea from v${existingVersion} to v${pkg.version}...${reset}`
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Clean previous install
|
|
261
|
+
const removed = cleanupPreviousInstall(targetDir);
|
|
262
|
+
if (removed > 0) {
|
|
263
|
+
console.log(`${dim}Cleaned ${removed} previous TweakIdea file(s).${reset}`);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Copy agents
|
|
267
|
+
mkdirp(path.join(targetDir, 'agents'));
|
|
268
|
+
for (const file of AGENT_FILES) {
|
|
269
|
+
copyFileSync(
|
|
270
|
+
path.join(sourceDir, 'agents', file),
|
|
271
|
+
path.join(targetDir, 'agents', file)
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Copy skills
|
|
276
|
+
for (const dir of SKILL_DIRS) {
|
|
277
|
+
copyDirSync(
|
|
278
|
+
path.join(sourceDir, 'skills', dir),
|
|
279
|
+
path.join(targetDir, 'skills', dir)
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Copy command/skill
|
|
284
|
+
if (isGlobal) {
|
|
285
|
+
// Global: install as skill (Claude Code discovers skills/*/SKILL.md)
|
|
286
|
+
const skillDir = path.join(targetDir, 'skills', 'tweak-evaluate');
|
|
287
|
+
mkdirp(skillDir);
|
|
288
|
+
copyFileSync(
|
|
289
|
+
path.join(sourceDir, COMMAND_SRC),
|
|
290
|
+
path.join(skillDir, 'SKILL.md')
|
|
291
|
+
);
|
|
292
|
+
} else {
|
|
293
|
+
// Local: install as command (Claude Code discovers commands/**/*.md)
|
|
294
|
+
copyFileSync(
|
|
295
|
+
path.join(sourceDir, COMMAND_SRC),
|
|
296
|
+
path.join(targetDir, 'commands', 'tweak', 'evaluate.md')
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Merge settings
|
|
301
|
+
mergeSettings(targetDir);
|
|
302
|
+
|
|
303
|
+
// Write version
|
|
304
|
+
writeVersion(targetDir, pkg.version);
|
|
305
|
+
|
|
306
|
+
// Verify
|
|
307
|
+
const agentCount = AGENT_FILES.filter((f) =>
|
|
308
|
+
fs.existsSync(path.join(targetDir, 'agents', f))
|
|
309
|
+
).length;
|
|
310
|
+
const skillCount = SKILL_DIRS.filter((d) =>
|
|
311
|
+
fs.existsSync(path.join(targetDir, 'skills', d))
|
|
312
|
+
).length;
|
|
313
|
+
const hasCommand = isGlobal
|
|
314
|
+
? fs.existsSync(path.join(targetDir, 'skills', 'tweak-evaluate', 'SKILL.md'))
|
|
315
|
+
: fs.existsSync(path.join(targetDir, 'commands', 'tweak', 'evaluate.md'));
|
|
316
|
+
|
|
317
|
+
console.log('');
|
|
318
|
+
console.log(`${green}${bold}TweakIdea v${pkg.version} installed successfully!${reset}`);
|
|
319
|
+
console.log('');
|
|
320
|
+
console.log(` ${dim}Location:${reset} ${displayPath} (${location})`);
|
|
321
|
+
console.log(` ${dim}Agents:${reset} ${agentCount} installed`);
|
|
322
|
+
console.log(` ${dim}Skills:${reset} ${skillCount} installed`);
|
|
323
|
+
console.log(` ${dim}Command:${reset} ${hasCommand ? 'yes' : 'MISSING'}`);
|
|
324
|
+
console.log('');
|
|
325
|
+
console.log(`${cyan}Get started:${reset}`);
|
|
326
|
+
console.log(` ${bold}/tweak:evaluate${reset} ${dim}"Your startup idea description"${reset}`);
|
|
327
|
+
console.log('');
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// ── Uninstall ───────────────────────────────────────────────────────────────────
|
|
331
|
+
|
|
332
|
+
function uninstall(isGlobal) {
|
|
333
|
+
const targetDir = resolveTargetDir(isGlobal);
|
|
334
|
+
const displayPath = isGlobal ? '~/.claude' : '.claude';
|
|
335
|
+
|
|
336
|
+
const existingVersion = readInstalledVersion(targetDir);
|
|
337
|
+
if (!existingVersion) {
|
|
338
|
+
console.log(`\n${yellow}TweakIdea is not installed in ${displayPath}.${reset}\n`);
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
cleanupPreviousInstall(targetDir);
|
|
343
|
+
removeSettingsEntries(targetDir);
|
|
344
|
+
|
|
345
|
+
console.log('');
|
|
346
|
+
console.log(
|
|
347
|
+
`${green}TweakIdea v${existingVersion} uninstalled from ${displayPath}.${reset}`
|
|
348
|
+
);
|
|
349
|
+
console.log(`${dim}Your evaluation data in ~/.tweakidea/ was not removed.${reset}`);
|
|
350
|
+
console.log('');
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// ── Interactive prompts ─────────────────────────────────────────────────────────
|
|
354
|
+
|
|
355
|
+
function prompt(question) {
|
|
356
|
+
return new Promise((resolve) => {
|
|
357
|
+
const rl = readline.createInterface({
|
|
358
|
+
input: process.stdin,
|
|
359
|
+
output: process.stdout,
|
|
360
|
+
});
|
|
361
|
+
rl.question(question, (answer) => {
|
|
362
|
+
rl.close();
|
|
363
|
+
resolve(answer.trim());
|
|
364
|
+
});
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
async function promptLocation() {
|
|
369
|
+
console.log('');
|
|
370
|
+
console.log(` ${bold}Where should TweakIdea be installed?${reset}`);
|
|
371
|
+
console.log('');
|
|
372
|
+
console.log(` ${cyan}1)${reset} Global ${dim}(~/.claude)${reset} - available in all projects`);
|
|
373
|
+
console.log(` ${cyan}2)${reset} Local ${dim}(./.claude)${reset} - this project only`);
|
|
374
|
+
console.log('');
|
|
375
|
+
|
|
376
|
+
const answer = await prompt(` ${bold}Select [1]:${reset} `);
|
|
377
|
+
return answer === '2' ? false : true;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// ── Help ────────────────────────────────────────────────────────────────────────
|
|
381
|
+
|
|
382
|
+
function printHelp() {
|
|
383
|
+
console.log(`
|
|
384
|
+
${bold}TweakIdea v${pkg.version}${reset}
|
|
385
|
+
14-dimension startup idea evaluator for Claude Code
|
|
386
|
+
|
|
387
|
+
${bold}Usage:${reset}
|
|
388
|
+
npx tweakidea [options]
|
|
389
|
+
|
|
390
|
+
${bold}Options:${reset}
|
|
391
|
+
-g, --global Install globally (~/.claude)
|
|
392
|
+
-l, --local Install locally (./.claude)
|
|
393
|
+
-u, --uninstall Remove TweakIdea files
|
|
394
|
+
-v, --version Show version
|
|
395
|
+
-h, --help Show this help
|
|
396
|
+
|
|
397
|
+
${bold}Examples:${reset}
|
|
398
|
+
npx tweakidea Interactive install
|
|
399
|
+
npx tweakidea -g Global install (no prompt)
|
|
400
|
+
npx tweakidea -l Local install (no prompt)
|
|
401
|
+
npx tweakidea -u -g Uninstall from global
|
|
402
|
+
`);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// ── Entry point ─────────────────────────────────────────────────────────────────
|
|
406
|
+
|
|
407
|
+
async function main() {
|
|
408
|
+
// Banner
|
|
409
|
+
console.log('');
|
|
410
|
+
console.log(
|
|
411
|
+
`${cyan}${bold}TweakIdea${reset} ${dim}v${pkg.version}${reset}`
|
|
412
|
+
);
|
|
413
|
+
|
|
414
|
+
if (wantHelp) {
|
|
415
|
+
printHelp();
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
if (wantVersion) {
|
|
420
|
+
console.log(pkg.version);
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
if (wantUninstall) {
|
|
425
|
+
const isGlobal = wantLocal ? false : true; // default to global for uninstall
|
|
426
|
+
uninstall(isGlobal);
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// Determine install location
|
|
431
|
+
let isGlobal;
|
|
432
|
+
if (wantGlobal) {
|
|
433
|
+
isGlobal = true;
|
|
434
|
+
} else if (wantLocal) {
|
|
435
|
+
isGlobal = false;
|
|
436
|
+
} else if (!process.stdin.isTTY) {
|
|
437
|
+
// Non-interactive: default to global
|
|
438
|
+
isGlobal = true;
|
|
439
|
+
} else {
|
|
440
|
+
isGlobal = await promptLocation();
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
install(isGlobal);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
main().catch((err) => {
|
|
447
|
+
console.error(`\n${red}Error: ${err.message}${reset}\n`);
|
|
448
|
+
process.exit(1);
|
|
449
|
+
});
|