wtf-p 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 +338 -0
- package/bin/install.js +358 -0
- package/bin/uninstall.js +485 -0
- package/commands/wtfp/analyze-bib.md +326 -0
- package/commands/wtfp/check-refs.md +205 -0
- package/commands/wtfp/create-outline.md +275 -0
- package/commands/wtfp/discuss-section.md +71 -0
- package/commands/wtfp/export-latex.md +216 -0
- package/commands/wtfp/help.md +342 -0
- package/commands/wtfp/insert-section.md +130 -0
- package/commands/wtfp/list-assumptions.md +109 -0
- package/commands/wtfp/map-project.md +197 -0
- package/commands/wtfp/new-paper.md +443 -0
- package/commands/wtfp/pause-writing.md +145 -0
- package/commands/wtfp/plan-revision.md +180 -0
- package/commands/wtfp/plan-section.md +247 -0
- package/commands/wtfp/polish-prose.md +177 -0
- package/commands/wtfp/progress.md +325 -0
- package/commands/wtfp/remove-section.md +147 -0
- package/commands/wtfp/research-gap.md +235 -0
- package/commands/wtfp/resume-writing.md +142 -0
- package/commands/wtfp/review-section.md +409 -0
- package/commands/wtfp/submit-milestone.md +211 -0
- package/commands/wtfp/write-section.md +273 -0
- package/package.json +40 -0
- package/write-the-f-paper/references/checkpoints.md +213 -0
- package/write-the-f-paper/references/continuation-format.md +223 -0
- package/write-the-f-paper/references/git-integration.md +241 -0
- package/write-the-f-paper/references/imrad-structure.md +212 -0
- package/write-the-f-paper/references/length-estimation.md +148 -0
- package/write-the-f-paper/references/plan-format.md +361 -0
- package/write-the-f-paper/references/principles.md +158 -0
- package/write-the-f-paper/references/questioning.md +132 -0
- package/write-the-f-paper/references/research-pitfalls.md +208 -0
- package/write-the-f-paper/templates/config.json +30 -0
- package/write-the-f-paper/templates/context.md +179 -0
- package/write-the-f-paper/templates/continue-here.md +142 -0
- package/write-the-f-paper/templates/data-inventory.md +142 -0
- package/write-the-f-paper/templates/discovery.md +146 -0
- package/write-the-f-paper/templates/issues.md +59 -0
- package/write-the-f-paper/templates/manuscript.md +253 -0
- package/write-the-f-paper/templates/narrative-arc.md +227 -0
- package/write-the-f-paper/templates/outline.md +274 -0
- package/write-the-f-paper/templates/phase-prompt.md +348 -0
- package/write-the-f-paper/templates/prior-drafts.md +204 -0
- package/write-the-f-paper/templates/project-context/argument-structure.md +267 -0
- package/write-the-f-paper/templates/project-context/bibliography.md +152 -0
- package/write-the-f-paper/templates/project-context/gaps.md +122 -0
- package/write-the-f-paper/templates/project-context/imrad.md +140 -0
- package/write-the-f-paper/templates/project-context/peer-review.md +152 -0
- package/write-the-f-paper/templates/project-context/style-guide.md +198 -0
- package/write-the-f-paper/templates/project-context/tools.md +170 -0
- package/write-the-f-paper/templates/project.md +185 -0
- package/write-the-f-paper/templates/research.md +384 -0
- package/write-the-f-paper/templates/review-comments.md +253 -0
- package/write-the-f-paper/templates/revision-issues.md +169 -0
- package/write-the-f-paper/templates/roadmap.md +187 -0
- package/write-the-f-paper/templates/section-archive.md +178 -0
- package/write-the-f-paper/templates/section-context.md +114 -0
- package/write-the-f-paper/templates/section.md +128 -0
- package/write-the-f-paper/templates/state.md +244 -0
- package/write-the-f-paper/templates/summary.md +277 -0
- package/write-the-f-paper/venues/acm-cs.yaml +102 -0
- package/write-the-f-paper/venues/arxiv-ml.yaml +103 -0
- package/write-the-f-paper/venues/ieee-cs.yaml +100 -0
- package/write-the-f-paper/venues/nature.yaml +81 -0
- package/write-the-f-paper/venues/thesis-chapter.yaml +101 -0
- package/write-the-f-paper/workflows/create-outline.md +462 -0
- package/write-the-f-paper/workflows/create-outline.wcn.md +194 -0
- package/write-the-f-paper/workflows/discuss-section.md +249 -0
- package/write-the-f-paper/workflows/discuss-section.wcn.md +63 -0
- package/write-the-f-paper/workflows/execute-section.md +704 -0
- package/write-the-f-paper/workflows/execute-section.wcn.md +219 -0
- package/write-the-f-paper/workflows/list-assumptions.md +183 -0
- package/write-the-f-paper/workflows/list-assumptions.wcn.md +42 -0
- package/write-the-f-paper/workflows/lit-review-phase.md +281 -0
- package/write-the-f-paper/workflows/lit-review-phase.wcn.md +92 -0
- package/write-the-f-paper/workflows/map-project.md +359 -0
- package/write-the-f-paper/workflows/map-project.wcn.md +73 -0
- package/write-the-f-paper/workflows/plan-section.md +409 -0
- package/write-the-f-paper/workflows/plan-section.wcn.md +236 -0
- package/write-the-f-paper/workflows/research-gap.md +469 -0
- package/write-the-f-paper/workflows/research-gap.wcn.md +119 -0
- package/write-the-f-paper/workflows/resume-paper.md +274 -0
- package/write-the-f-paper/workflows/resume-paper.wcn.md +93 -0
- package/write-the-f-paper/workflows/review-section.md +329 -0
- package/write-the-f-paper/workflows/review-section.wcn.md +91 -0
- package/write-the-f-paper/workflows/submit-draft.md +368 -0
- package/write-the-f-paper/workflows/submit-draft.wcn.md +69 -0
- package/write-the-f-paper/workflows/transition.md +375 -0
- package/write-the-f-paper/workflows/transition.wcn.md +113 -0
package/bin/install.js
ADDED
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
const readline = require('readline');
|
|
7
|
+
|
|
8
|
+
// Colors
|
|
9
|
+
const cyan = '\x1b[36m';
|
|
10
|
+
const green = '\x1b[32m';
|
|
11
|
+
const yellow = '\x1b[33m';
|
|
12
|
+
const red = '\x1b[31m';
|
|
13
|
+
const magenta = '\x1b[35m';
|
|
14
|
+
const dim = '\x1b[2m';
|
|
15
|
+
const reset = '\x1b[0m';
|
|
16
|
+
|
|
17
|
+
// Get version from package.json
|
|
18
|
+
const pkg = require('../package.json');
|
|
19
|
+
|
|
20
|
+
const banner = `
|
|
21
|
+
${magenta}██╗ ██╗████████╗███████╗ ██████╗
|
|
22
|
+
██║ ██║╚══██╔══╝██╔════╝ ██╔══██╗
|
|
23
|
+
██║ █╗ ██║ ██║ █████╗ █████╗██████╔╝
|
|
24
|
+
██║███╗██║ ██║ ██╔══╝ ╚════╝██╔═══╝
|
|
25
|
+
╚███╔███╔╝ ██║ ██║ ██║
|
|
26
|
+
╚══╝╚══╝ ╚═╝ ╚═╝ ╚═╝${reset}
|
|
27
|
+
|
|
28
|
+
${cyan}Write The F***ing Paper${reset} ${dim}v${pkg.version}${reset}
|
|
29
|
+
Context engineering for academic writing.
|
|
30
|
+
Ship papers, not excuses.
|
|
31
|
+
`;
|
|
32
|
+
|
|
33
|
+
// Parse args
|
|
34
|
+
const args = process.argv.slice(2);
|
|
35
|
+
const hasGlobal = args.includes('--global') || args.includes('-g');
|
|
36
|
+
const hasLocal = args.includes('--local') || args.includes('-l');
|
|
37
|
+
const hasForce = args.includes('--force') || args.includes('-f');
|
|
38
|
+
const hasBackupAll = args.includes('--backup-all') || args.includes('-b');
|
|
39
|
+
|
|
40
|
+
// Parse --config-dir argument
|
|
41
|
+
function parseConfigDirArg() {
|
|
42
|
+
const configDirIndex = args.findIndex(arg => arg === '--config-dir' || arg === '-c');
|
|
43
|
+
if (configDirIndex !== -1) {
|
|
44
|
+
const nextArg = args[configDirIndex + 1];
|
|
45
|
+
if (!nextArg || nextArg.startsWith('-')) {
|
|
46
|
+
console.error(` ${yellow}--config-dir requires a path argument${reset}`);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
return nextArg;
|
|
50
|
+
}
|
|
51
|
+
const configDirArg = args.find(arg => arg.startsWith('--config-dir=') || arg.startsWith('-c='));
|
|
52
|
+
if (configDirArg) {
|
|
53
|
+
return configDirArg.split('=')[1];
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
const explicitConfigDir = parseConfigDirArg();
|
|
58
|
+
const hasHelp = args.includes('--help') || args.includes('-h');
|
|
59
|
+
|
|
60
|
+
console.log(banner);
|
|
61
|
+
|
|
62
|
+
// Show help if requested
|
|
63
|
+
if (hasHelp) {
|
|
64
|
+
console.log(` ${yellow}Usage:${reset} npx wtf-p [options]
|
|
65
|
+
|
|
66
|
+
${yellow}Options:${reset}
|
|
67
|
+
${cyan}-g, --global${reset} Install globally (to Claude config directory)
|
|
68
|
+
${cyan}-l, --local${reset} Install locally (to ./.claude in current directory)
|
|
69
|
+
${cyan}-c, --config-dir <path>${reset} Specify custom Claude config directory
|
|
70
|
+
${cyan}-f, --force${reset} Overwrite all existing files without prompting
|
|
71
|
+
${cyan}-b, --backup-all${reset} Backup all existing files before overwriting
|
|
72
|
+
${cyan}-h, --help${reset} Show this help message
|
|
73
|
+
|
|
74
|
+
${yellow}Conflict Resolution:${reset}
|
|
75
|
+
When existing WTF-P files are detected, you'll be prompted for each:
|
|
76
|
+
${dim}[o]verwrite${reset} - Replace with new version
|
|
77
|
+
${dim}[s]kip${reset} - Keep existing file
|
|
78
|
+
${dim}[b]ackup${reset} - Backup existing, then install new
|
|
79
|
+
${dim}[a]ll${reset} - Apply same choice to remaining conflicts
|
|
80
|
+
|
|
81
|
+
${yellow}Examples:${reset}
|
|
82
|
+
${dim}# Install with prompts for conflicts${reset}
|
|
83
|
+
npx wtf-p --global
|
|
84
|
+
|
|
85
|
+
${dim}# Force overwrite all existing files${reset}
|
|
86
|
+
npx wtf-p --global --force
|
|
87
|
+
|
|
88
|
+
${dim}# Backup all existing files before installing${reset}
|
|
89
|
+
npx wtf-p --global --backup-all
|
|
90
|
+
|
|
91
|
+
${dim}# Install to custom config directory${reset}
|
|
92
|
+
npx wtf-p --global --config-dir ~/.claude-research
|
|
93
|
+
|
|
94
|
+
${yellow}Uninstall:${reset}
|
|
95
|
+
npx wtf-p-uninstall [--global|--local] [--config-dir <path>]
|
|
96
|
+
|
|
97
|
+
${yellow}After installation:${reset}
|
|
98
|
+
Run ${cyan}/wtfp:help${reset} in Claude Code to get started.
|
|
99
|
+
`);
|
|
100
|
+
process.exit(0);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Expand ~ to home directory
|
|
105
|
+
*/
|
|
106
|
+
function expandTilde(filePath) {
|
|
107
|
+
if (filePath && filePath.startsWith('~/')) {
|
|
108
|
+
return path.join(os.homedir(), filePath.slice(2));
|
|
109
|
+
}
|
|
110
|
+
return filePath;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Create readline interface for prompts
|
|
115
|
+
*/
|
|
116
|
+
function createRL() {
|
|
117
|
+
return readline.createInterface({
|
|
118
|
+
input: process.stdin,
|
|
119
|
+
output: process.stdout
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Prompt user with a question
|
|
125
|
+
*/
|
|
126
|
+
function prompt(rl, question) {
|
|
127
|
+
return new Promise(resolve => {
|
|
128
|
+
rl.question(question, answer => resolve(answer.trim().toLowerCase()));
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Generate backup path with timestamp
|
|
134
|
+
*/
|
|
135
|
+
function getBackupPath(filePath) {
|
|
136
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
|
137
|
+
const dir = path.dirname(filePath);
|
|
138
|
+
const ext = path.extname(filePath);
|
|
139
|
+
const base = path.basename(filePath, ext);
|
|
140
|
+
return path.join(dir, `${base}.backup-${timestamp}${ext}`);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Collect all files that would be installed
|
|
145
|
+
*/
|
|
146
|
+
function collectFiles(srcDir, destDir, pathPrefix, files = []) {
|
|
147
|
+
if (!fs.existsSync(srcDir)) return files;
|
|
148
|
+
|
|
149
|
+
const entries = fs.readdirSync(srcDir, { withFileTypes: true });
|
|
150
|
+
|
|
151
|
+
for (const entry of entries) {
|
|
152
|
+
const srcPath = path.join(srcDir, entry.name);
|
|
153
|
+
const destPath = path.join(destDir, entry.name);
|
|
154
|
+
|
|
155
|
+
if (entry.isDirectory()) {
|
|
156
|
+
collectFiles(srcPath, destPath, pathPrefix, files);
|
|
157
|
+
} else {
|
|
158
|
+
files.push({ src: srcPath, dest: destPath, name: entry.name });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return files;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Process file content with path replacement
|
|
167
|
+
*/
|
|
168
|
+
function processContent(srcPath, pathPrefix) {
|
|
169
|
+
if (srcPath.endsWith('.md') || srcPath.endsWith('.json')) {
|
|
170
|
+
let content = fs.readFileSync(srcPath, 'utf8');
|
|
171
|
+
return content.replace(/~\/\.claude\//g, pathPrefix);
|
|
172
|
+
}
|
|
173
|
+
return null; // Binary copy
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Install files with conflict resolution
|
|
178
|
+
*/
|
|
179
|
+
async function installWithConflictResolution(files, pathPrefix, claudeDir) {
|
|
180
|
+
const rl = createRL();
|
|
181
|
+
let globalChoice = null; // 'overwrite', 'skip', 'backup'
|
|
182
|
+
const stats = { installed: 0, skipped: 0, backed: 0 };
|
|
183
|
+
|
|
184
|
+
// Check for existing installation
|
|
185
|
+
const existingFiles = files.filter(f => fs.existsSync(f.dest));
|
|
186
|
+
|
|
187
|
+
if (existingFiles.length > 0 && !hasForce && !hasBackupAll) {
|
|
188
|
+
const relPath = claudeDir.replace(os.homedir(), '~');
|
|
189
|
+
console.log(` ${yellow}Found ${existingFiles.length} existing WTF-P file(s) in ${relPath}${reset}\n`);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
for (const file of files) {
|
|
193
|
+
const exists = fs.existsSync(file.dest);
|
|
194
|
+
const relDest = file.dest.replace(os.homedir(), '~').replace(process.cwd(), '.');
|
|
195
|
+
|
|
196
|
+
// Ensure directory exists
|
|
197
|
+
fs.mkdirSync(path.dirname(file.dest), { recursive: true });
|
|
198
|
+
|
|
199
|
+
if (exists && !hasForce && !hasBackupAll) {
|
|
200
|
+
let choice = globalChoice;
|
|
201
|
+
|
|
202
|
+
if (!choice) {
|
|
203
|
+
const answer = await prompt(rl,
|
|
204
|
+
` ${yellow}?${reset} ${dim}${relDest}${reset} exists. [o]verwrite/[s]kip/[b]ackup/[a]ll: `
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
if (answer.startsWith('a')) {
|
|
208
|
+
// Apply to all: ask which action
|
|
209
|
+
const allAnswer = await prompt(rl,
|
|
210
|
+
` Apply to all: [o]verwrite/[s]kip/[b]ackup: `
|
|
211
|
+
);
|
|
212
|
+
if (allAnswer.startsWith('o')) globalChoice = 'overwrite';
|
|
213
|
+
else if (allAnswer.startsWith('b')) globalChoice = 'backup';
|
|
214
|
+
else globalChoice = 'skip';
|
|
215
|
+
choice = globalChoice;
|
|
216
|
+
} else if (answer.startsWith('o')) {
|
|
217
|
+
choice = 'overwrite';
|
|
218
|
+
} else if (answer.startsWith('b')) {
|
|
219
|
+
choice = 'backup';
|
|
220
|
+
} else {
|
|
221
|
+
choice = 'skip';
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (choice === 'skip') {
|
|
226
|
+
console.log(` ${dim}○${reset} Skipped ${dim}${relDest}${reset}`);
|
|
227
|
+
stats.skipped++;
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (choice === 'backup') {
|
|
232
|
+
const backupPath = getBackupPath(file.dest);
|
|
233
|
+
fs.copyFileSync(file.dest, backupPath);
|
|
234
|
+
console.log(` ${cyan}↻${reset} Backed up to ${dim}${path.basename(backupPath)}${reset}`);
|
|
235
|
+
stats.backed++;
|
|
236
|
+
}
|
|
237
|
+
} else if (exists && hasBackupAll) {
|
|
238
|
+
const backupPath = getBackupPath(file.dest);
|
|
239
|
+
fs.copyFileSync(file.dest, backupPath);
|
|
240
|
+
console.log(` ${cyan}↻${reset} Backed up ${dim}${relDest}${reset}`);
|
|
241
|
+
stats.backed++;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Install the file
|
|
245
|
+
const content = processContent(file.src, pathPrefix);
|
|
246
|
+
if (content !== null) {
|
|
247
|
+
fs.writeFileSync(file.dest, content);
|
|
248
|
+
} else {
|
|
249
|
+
fs.copyFileSync(file.src, file.dest);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (!exists) {
|
|
253
|
+
console.log(` ${green}+${reset} ${dim}${relDest}${reset}`);
|
|
254
|
+
} else {
|
|
255
|
+
console.log(` ${green}✓${reset} ${dim}${relDest}${reset}`);
|
|
256
|
+
}
|
|
257
|
+
stats.installed++;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
rl.close();
|
|
261
|
+
return stats;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Install to the specified directory
|
|
266
|
+
*/
|
|
267
|
+
async function install(isGlobal) {
|
|
268
|
+
const src = path.join(__dirname, '..');
|
|
269
|
+
const configDir = expandTilde(explicitConfigDir) || expandTilde(process.env.CLAUDE_CONFIG_DIR);
|
|
270
|
+
const defaultGlobalDir = configDir || path.join(os.homedir(), '.claude');
|
|
271
|
+
const claudeDir = isGlobal
|
|
272
|
+
? defaultGlobalDir
|
|
273
|
+
: path.join(process.cwd(), '.claude');
|
|
274
|
+
|
|
275
|
+
const locationLabel = isGlobal
|
|
276
|
+
? claudeDir.replace(os.homedir(), '~')
|
|
277
|
+
: claudeDir.replace(process.cwd(), '.');
|
|
278
|
+
|
|
279
|
+
const pathPrefix = isGlobal
|
|
280
|
+
? (configDir ? `${claudeDir}/` : '~/.claude/')
|
|
281
|
+
: './.claude/';
|
|
282
|
+
|
|
283
|
+
console.log(` Installing to ${cyan}${locationLabel}${reset}\n`);
|
|
284
|
+
|
|
285
|
+
// Collect all files to install
|
|
286
|
+
const wtfpSrc = path.join(src, 'commands', 'wtfp');
|
|
287
|
+
const wtfpDest = path.join(claudeDir, 'commands', 'wtfp');
|
|
288
|
+
const skillSrc = path.join(src, 'write-the-f-paper');
|
|
289
|
+
const skillDest = path.join(claudeDir, 'write-the-f-paper');
|
|
290
|
+
|
|
291
|
+
const allFiles = [
|
|
292
|
+
...collectFiles(wtfpSrc, wtfpDest, pathPrefix),
|
|
293
|
+
...collectFiles(skillSrc, skillDest, pathPrefix)
|
|
294
|
+
];
|
|
295
|
+
|
|
296
|
+
// Install with conflict resolution
|
|
297
|
+
const stats = await installWithConflictResolution(allFiles, pathPrefix, claudeDir);
|
|
298
|
+
|
|
299
|
+
console.log(`
|
|
300
|
+
${green}Done!${reset} Installed: ${stats.installed}, Skipped: ${stats.skipped}, Backed up: ${stats.backed}
|
|
301
|
+
|
|
302
|
+
Run ${cyan}/wtfp:help${reset} in Claude Code to get started.
|
|
303
|
+
|
|
304
|
+
${yellow}Quick Start:${reset}
|
|
305
|
+
${cyan}/wtfp:new-paper${reset} Start a new academic paper
|
|
306
|
+
${cyan}/wtfp:progress${reset} Check your writing status
|
|
307
|
+
${cyan}/wtfp:help${reset} Show all commands
|
|
308
|
+
`);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Prompt for install location
|
|
313
|
+
*/
|
|
314
|
+
async function promptLocation() {
|
|
315
|
+
const rl = createRL();
|
|
316
|
+
|
|
317
|
+
const configDir = expandTilde(explicitConfigDir) || expandTilde(process.env.CLAUDE_CONFIG_DIR);
|
|
318
|
+
const globalPath = configDir || path.join(os.homedir(), '.claude');
|
|
319
|
+
const globalLabel = globalPath.replace(os.homedir(), '~');
|
|
320
|
+
|
|
321
|
+
console.log(` ${yellow}Where would you like to install?${reset}
|
|
322
|
+
|
|
323
|
+
${cyan}1${reset}) Global ${dim}(${globalLabel})${reset} - available in all projects
|
|
324
|
+
${cyan}2${reset}) Local ${dim}(./.claude)${reset} - this project only
|
|
325
|
+
`);
|
|
326
|
+
|
|
327
|
+
const answer = await prompt(rl, ` Choice ${dim}[1]${reset}: `);
|
|
328
|
+
rl.close();
|
|
329
|
+
|
|
330
|
+
const choice = answer || '1';
|
|
331
|
+
const isGlobal = choice !== '2';
|
|
332
|
+
await install(isGlobal);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Main
|
|
336
|
+
async function main() {
|
|
337
|
+
if (hasGlobal && hasLocal) {
|
|
338
|
+
console.error(` ${yellow}Cannot specify both --global and --local${reset}`);
|
|
339
|
+
process.exit(1);
|
|
340
|
+
} else if (explicitConfigDir && hasLocal) {
|
|
341
|
+
console.error(` ${yellow}Cannot use --config-dir with --local${reset}`);
|
|
342
|
+
process.exit(1);
|
|
343
|
+
} else if (hasForce && hasBackupAll) {
|
|
344
|
+
console.error(` ${yellow}Cannot use both --force and --backup-all${reset}`);
|
|
345
|
+
process.exit(1);
|
|
346
|
+
} else if (hasGlobal) {
|
|
347
|
+
await install(true);
|
|
348
|
+
} else if (hasLocal) {
|
|
349
|
+
await install(false);
|
|
350
|
+
} else {
|
|
351
|
+
await promptLocation();
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
main().catch(err => {
|
|
356
|
+
console.error(` ${red}Error:${reset} ${err.message}`);
|
|
357
|
+
process.exit(1);
|
|
358
|
+
});
|