project-runner 0.1.2 → 0.2.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.
Files changed (3) hide show
  1. package/README.md +1 -0
  2. package/dist/index.js +193 -103
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -104,6 +104,7 @@ pr info
104
104
  |------|------|
105
105
  | `-v, --verbose` | 显示详细检测过程 |
106
106
  | `-d, --dir <path>` | 指定项目目录(默认:当前目录)|
107
+ | `-i, --install` | 强制执行依赖安装 |
107
108
  | `--no-install` | 跳过依赖安装步骤 |
108
109
  | `-h, --help` | 显示帮助信息 |
109
110
  | `-V, --version` | 显示版本号 |
package/dist/index.js CHANGED
@@ -17,6 +17,13 @@ var colors = {
17
17
  white: "\x1B[37m",
18
18
  gray: "\x1B[90m"
19
19
  };
20
+ var CliError = class extends Error {
21
+ constructor(message, exitCode = 1) {
22
+ super(message);
23
+ this.exitCode = exitCode;
24
+ this.name = "CliError";
25
+ }
26
+ };
20
27
  var isVerbose = false;
21
28
  function setVerbose(verbose) {
22
29
  isVerbose = verbose;
@@ -74,6 +81,34 @@ async function execute(cmd, options = {}) {
74
81
  });
75
82
  });
76
83
  }
84
+ async function executeCapture(cmd, options = {}) {
85
+ const { cwd = process.cwd(), env } = options;
86
+ return new Promise((resolve2, reject) => {
87
+ const isWindows = process.platform === "win32";
88
+ const command = cmd[0] || "";
89
+ const args = cmd.slice(1);
90
+ const proc = spawn(command, args, {
91
+ cwd,
92
+ env: { ...process.env, ...env },
93
+ shell: isWindows,
94
+ stdio: ["pipe", "pipe", "pipe"]
95
+ });
96
+ let stdout = "";
97
+ let stderr = "";
98
+ proc.stdout.on("data", (data) => {
99
+ stdout += data.toString();
100
+ });
101
+ proc.stderr.on("data", (data) => {
102
+ stderr += data.toString();
103
+ });
104
+ proc.on("close", (code) => {
105
+ resolve2({ stdout, stderr, exitCode: code ?? 0 });
106
+ });
107
+ proc.on("error", (err) => {
108
+ reject(err);
109
+ });
110
+ });
111
+ }
77
112
  function setupSignalHandlers() {
78
113
  process.on("SIGINT", () => {
79
114
  if (currentProcess) {
@@ -90,12 +125,32 @@ function setupSignalHandlers() {
90
125
  }
91
126
 
92
127
  // src/analyzer/index.ts
93
- import { readFile as readFile3, stat as stat4 } from "fs/promises";
94
- import { join as join4 } from "path";
128
+ import { readFile } from "fs/promises";
129
+ import { join as join3 } from "path";
95
130
 
96
131
  // src/analyzer/package-manager.ts
97
- import { readFile, stat } from "fs/promises";
98
132
  import { join } from "path";
133
+
134
+ // src/utils/fs.ts
135
+ import { stat } from "fs/promises";
136
+ async function fileExists(path) {
137
+ try {
138
+ const stats = await stat(path);
139
+ return stats.isFile();
140
+ } catch {
141
+ return false;
142
+ }
143
+ }
144
+ async function directoryExists(path) {
145
+ try {
146
+ const stats = await stat(path);
147
+ return stats.isDirectory();
148
+ } catch {
149
+ return false;
150
+ }
151
+ }
152
+
153
+ // src/analyzer/package-manager.ts
99
154
  var LOCKFILE_MAP = {
100
155
  "bun.lockb": "bun",
101
156
  "bun.lock": "bun",
@@ -103,9 +158,7 @@ var LOCKFILE_MAP = {
103
158
  "yarn.lock": "yarn",
104
159
  "package-lock.json": "npm"
105
160
  };
106
- async function detectPackageManager(projectDir) {
107
- const packageJsonPath = join(projectDir, "package.json");
108
- const packageJson = await readPackageJson(packageJsonPath);
161
+ async function detectPackageManager(projectDir, packageJson) {
109
162
  if (!packageJson) {
110
163
  return { name: "npm", source: "default" };
111
164
  }
@@ -164,46 +217,17 @@ function getInstallCommand(pm) {
164
217
  return ["npm", "install"];
165
218
  }
166
219
  }
167
- async function fileExists(path) {
168
- try {
169
- const stats = await stat(path);
170
- return stats.isFile();
171
- } catch {
172
- return false;
173
- }
174
- }
175
- async function readPackageJson(path) {
176
- try {
177
- const content = await readFile(path, "utf-8");
178
- return JSON.parse(content);
179
- } catch {
180
- }
181
- return null;
182
- }
183
220
 
184
221
  // src/analyzer/scripts.ts
185
- import { readFile as readFile2, stat as stat2 } from "fs/promises";
186
- import { join as join2 } from "path";
187
222
  var DEV_PATTERNS = ["dev", "serve", "start:dev", "develop", "watch"];
188
223
  var TEST_PATTERNS = ["test", "test:unit", "test:all", "spec"];
189
224
  var BUILD_PATTERNS = ["build", "compile", "bundle", "dist"];
190
- var START_PATTERNS = ["start", "serve", "preview", "production"];
191
- async function fileExists2(path) {
192
- try {
193
- const stats = await stat2(path);
194
- return stats.isFile();
195
- } catch {
196
- return false;
225
+ var START_PATTERNS = ["start", "preview", "production"];
226
+ function analyzeScripts(packageJson) {
227
+ if (!packageJson) {
228
+ return null;
197
229
  }
198
- }
199
- async function analyzeScripts(projectDir) {
200
- const packageJsonPath = join2(projectDir, "package.json");
201
230
  try {
202
- if (!await fileExists2(packageJsonPath)) {
203
- return null;
204
- }
205
- const content = await readFile2(packageJsonPath, "utf-8");
206
- const packageJson = JSON.parse(content);
207
231
  const scripts = packageJson.scripts || {};
208
232
  const detected = {
209
233
  dev: findMatchingScript(scripts, DEV_PATTERNS),
@@ -242,8 +266,8 @@ function findMatchingScript(scripts, patterns) {
242
266
  }
243
267
 
244
268
  // src/analyzer/dependencies.ts
245
- import { stat as stat3 } from "fs/promises";
246
- import { join as join3 } from "path";
269
+ import { stat as stat2 } from "fs/promises";
270
+ import { join as join2 } from "path";
247
271
  var LOCKFILES = [
248
272
  "bun.lockb",
249
273
  "bun.lock",
@@ -252,7 +276,7 @@ var LOCKFILES = [
252
276
  "package-lock.json"
253
277
  ];
254
278
  async function checkDependencyStatus(projectDir) {
255
- const nodeModulesPath = join3(projectDir, "node_modules");
279
+ const nodeModulesPath = join2(projectDir, "node_modules");
256
280
  const nodeModulesExists = await directoryExists(nodeModulesPath);
257
281
  if (!nodeModulesExists) {
258
282
  return {
@@ -261,11 +285,11 @@ async function checkDependencyStatus(projectDir) {
261
285
  reason: "node_modules \u4E0D\u5B58\u5728"
262
286
  };
263
287
  }
288
+ const nodeModulesMtime = await getModifiedTime(nodeModulesPath);
264
289
  const lockfilePath = await findLockfile(projectDir);
265
290
  if (lockfilePath) {
266
291
  const lockfileMtime = await getModifiedTime(lockfilePath);
267
- const nodeModulesMtime2 = await getModifiedTime(nodeModulesPath);
268
- if (lockfileMtime && nodeModulesMtime2 && lockfileMtime > nodeModulesMtime2) {
292
+ if (lockfileMtime && nodeModulesMtime && lockfileMtime > nodeModulesMtime) {
269
293
  return {
270
294
  hasNodeModules: true,
271
295
  needsInstall: true,
@@ -273,9 +297,8 @@ async function checkDependencyStatus(projectDir) {
273
297
  };
274
298
  }
275
299
  }
276
- const packageJsonPath = join3(projectDir, "package.json");
300
+ const packageJsonPath = join2(projectDir, "package.json");
277
301
  const packageJsonMtime = await getModifiedTime(packageJsonPath);
278
- const nodeModulesMtime = await getModifiedTime(nodeModulesPath);
279
302
  if (packageJsonMtime && nodeModulesMtime && packageJsonMtime > nodeModulesMtime) {
280
303
  return {
281
304
  hasNodeModules: true,
@@ -290,8 +313,8 @@ async function checkDependencyStatus(projectDir) {
290
313
  }
291
314
  async function findLockfile(projectDir) {
292
315
  for (const lockfile of LOCKFILES) {
293
- const lockfilePath = join3(projectDir, lockfile);
294
- if (await fileExists3(lockfilePath)) {
316
+ const lockfilePath = join2(projectDir, lockfile);
317
+ if (await fileExists(lockfilePath)) {
295
318
  return lockfilePath;
296
319
  }
297
320
  }
@@ -299,41 +322,17 @@ async function findLockfile(projectDir) {
299
322
  }
300
323
  async function getModifiedTime(path) {
301
324
  try {
302
- const stats = await stat3(path);
325
+ const stats = await stat2(path);
303
326
  return stats.mtimeMs;
304
327
  } catch {
305
328
  return null;
306
329
  }
307
330
  }
308
- async function directoryExists(path) {
309
- try {
310
- const stats = await stat3(path);
311
- return stats.isDirectory();
312
- } catch {
313
- return false;
314
- }
315
- }
316
- async function fileExists3(path) {
317
- try {
318
- const stats = await stat3(path);
319
- return stats.isFile();
320
- } catch {
321
- return false;
322
- }
323
- }
324
331
 
325
332
  // src/analyzer/index.ts
326
- async function fileExists4(path) {
327
- try {
328
- const stats = await stat4(path);
329
- return stats.isFile();
330
- } catch {
331
- return false;
332
- }
333
- }
334
333
  async function analyzeProject(projectDir) {
335
- const packageJsonPath = join4(projectDir, "package.json");
336
- const hasPackageJson = await fileExists4(packageJsonPath);
334
+ const packageJsonPath = join3(projectDir, "package.json");
335
+ const hasPackageJson = await fileExists(packageJsonPath);
337
336
  if (!hasPackageJson) {
338
337
  return {
339
338
  type: "unknown",
@@ -344,15 +343,15 @@ async function analyzeProject(projectDir) {
344
343
  }
345
344
  let packageJson = {};
346
345
  try {
347
- const content = await readFile3(packageJsonPath, "utf-8");
346
+ const content = await readFile(packageJsonPath, "utf-8");
348
347
  packageJson = JSON.parse(content);
349
348
  } catch {
350
349
  }
351
- const [packageManager, scripts, dependencies] = await Promise.all([
352
- detectPackageManager(projectDir),
353
- analyzeScripts(projectDir),
350
+ const [packageManager, dependencies] = await Promise.all([
351
+ detectPackageManager(projectDir, packageJson),
354
352
  checkDependencyStatus(projectDir)
355
353
  ]);
354
+ const scripts = analyzeScripts(packageJson);
356
355
  return {
357
356
  type: "nodejs",
358
357
  packageManager,
@@ -364,28 +363,115 @@ async function analyzeProject(projectDir) {
364
363
  };
365
364
  }
366
365
 
366
+ // src/utils/pm-availability.ts
367
+ import { createInterface } from "node:readline/promises";
368
+ var availabilityCache = /* @__PURE__ */ new Map();
369
+ async function isPmAvailable(pm) {
370
+ if (availabilityCache.has(pm)) {
371
+ return availabilityCache.get(pm);
372
+ }
373
+ try {
374
+ const result = await executeCapture([pm, "--version"]);
375
+ const available = result.exitCode === 0 && result.stdout.trim().length > 0;
376
+ availabilityCache.set(pm, available);
377
+ return available;
378
+ } catch {
379
+ availabilityCache.set(pm, false);
380
+ return false;
381
+ }
382
+ }
383
+ async function ensurePmAvailable(pm) {
384
+ if (pm === "npm") {
385
+ return pm;
386
+ }
387
+ const available = await isPmAvailable(pm);
388
+ if (available) {
389
+ return pm;
390
+ }
391
+ warn(`\u5305\u7BA1\u7406\u5668 ${pm} \u672A\u5B89\u88C5`);
392
+ if (!process.stdin.isTTY) {
393
+ warn("\u975E\u4EA4\u4E92\u73AF\u5883\uFF0C\u81EA\u52A8\u56DE\u9000\u5230 npm");
394
+ return "npm";
395
+ }
396
+ return await promptPmResolution(pm);
397
+ }
398
+ async function promptPmResolution(pm) {
399
+ console.log();
400
+ console.log(` \u68C0\u6D4B\u5230\u9879\u76EE\u4F7F\u7528 ${colors.cyan}${pm}${colors.reset}\uFF0C\u4F46\u7CFB\u7EDF\u672A\u5B89\u88C5\u3002`);
401
+ console.log();
402
+ console.log(` ${colors.bold}\u8BF7\u9009\u62E9\u64CD\u4F5C:${colors.reset}`);
403
+ console.log(` ${colors.cyan}1${colors.reset}) \u81EA\u52A8\u5B89\u88C5 ${pm} ${colors.dim}(npm install -g ${pm})${colors.reset}`);
404
+ console.log(` ${colors.cyan}2${colors.reset}) \u4F7F\u7528 npm \u4EE3\u66FF`);
405
+ console.log(` ${colors.cyan}3${colors.reset}) \u9000\u51FA\uFF0C\u624B\u52A8\u5904\u7406`);
406
+ console.log();
407
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
408
+ try {
409
+ const answer = await rl.question(` \u8BF7\u8F93\u5165\u9009\u9879 ${colors.dim}[1/2/3]${colors.reset}: `);
410
+ const choice = answer.trim();
411
+ switch (choice) {
412
+ case "1":
413
+ return await autoInstallPm(pm);
414
+ case "2":
415
+ warn(`\u4F7F\u7528 npm \u4EE3\u66FF ${pm}`);
416
+ return "npm";
417
+ case "3":
418
+ default:
419
+ throw new CliError(`\u8BF7\u5148\u5B89\u88C5 ${pm}: npm install -g ${pm}`);
420
+ }
421
+ } finally {
422
+ rl.close();
423
+ }
424
+ }
425
+ async function autoInstallPm(pm) {
426
+ info(`\u6B63\u5728\u5B89\u88C5 ${pm}...`);
427
+ console.log();
428
+ try {
429
+ const result = await executeCapture(["npm", "install", "-g", pm]);
430
+ if (result.exitCode !== 0) {
431
+ error(`\u5B89\u88C5 ${pm} \u5931\u8D25`);
432
+ if (result.stderr.trim()) {
433
+ console.error(result.stderr.trim());
434
+ }
435
+ throw new CliError(`\u65E0\u6CD5\u81EA\u52A8\u5B89\u88C5 ${pm}\uFF0C\u8BF7\u624B\u52A8\u8FD0\u884C: npm install -g ${pm}`);
436
+ }
437
+ } catch (err) {
438
+ if (err instanceof CliError)
439
+ throw err;
440
+ throw new CliError(`\u5B89\u88C5 ${pm} \u65F6\u51FA\u9519\uFF0C\u8BF7\u624B\u52A8\u8FD0\u884C: npm install -g ${pm}`);
441
+ }
442
+ availabilityCache.delete(pm);
443
+ const nowAvailable = await isPmAvailable(pm);
444
+ if (!nowAvailable) {
445
+ throw new CliError(`${pm} \u5DF2\u5B89\u88C5\u4F46\u65E0\u6CD5\u6267\u884C\u3002\u8BF7\u68C0\u67E5 PATH \u6216\u91CD\u65B0\u6253\u5F00\u7EC8\u7AEF\u540E\u91CD\u8BD5\u3002`);
446
+ }
447
+ success(`${pm} \u5B89\u88C5\u5B8C\u6210`);
448
+ console.log();
449
+ return pm;
450
+ }
451
+
367
452
  // src/cli/run.ts
368
453
  async function runCommand(projectDir, options = {}) {
369
454
  const { noInstall = false, forceInstall = false, scriptType = "dev" } = options;
370
455
  log("\u6B63\u5728\u5206\u6790\u9879\u76EE...");
371
456
  const project = await analyzeProject(projectDir);
372
457
  if (project.type === "unknown") {
373
- error("\u672A\u68C0\u6D4B\u5230\u9879\u76EE\u7C7B\u578B\u3002\u8BF7\u786E\u4FDD\u5F53\u524D\u76EE\u5F55\u5305\u542B package.json");
374
- process.exit(1);
458
+ throw new CliError("\u672A\u68C0\u6D4B\u5230\u9879\u76EE\u7C7B\u578B\u3002\u8BF7\u786E\u4FDD\u5F53\u524D\u76EE\u5F55\u5305\u542B package.json");
375
459
  }
376
460
  log(`\u9879\u76EE\u7C7B\u578B: ${project.type}`);
377
461
  log(`\u5305\u7BA1\u7406\u5668: ${project.packageManager.name} (from ${project.packageManager.source})`);
378
462
  if (!project.scripts) {
379
- error("\u65E0\u6CD5\u8BFB\u53D6 package.json \u7684 scripts");
380
- process.exit(1);
463
+ throw new CliError("\u65E0\u6CD5\u8BFB\u53D6 package.json \u7684 scripts");
381
464
  }
382
465
  const scriptName = findScript(project, scriptType);
383
466
  if (!scriptName) {
384
- error(`\u672A\u627E\u5230 ${scriptType} \u76F8\u5173\u7684\u811A\u672C`);
385
467
  showAvailableScripts(project);
386
- process.exit(1);
468
+ throw new CliError(`\u672A\u627E\u5230 ${scriptType} \u76F8\u5173\u7684\u811A\u672C`);
387
469
  }
388
470
  log(`\u5C06\u6267\u884C\u811A\u672C: ${scriptName}`);
471
+ const resolvedPm = await ensurePmAvailable(project.packageManager.name);
472
+ if (resolvedPm !== project.packageManager.name) {
473
+ log(`\u4F7F\u7528 ${resolvedPm} \u4EE3\u66FF ${project.packageManager.name}`);
474
+ }
389
475
  const shouldInstall = !noInstall && (forceInstall || project.dependencies.needsInstall);
390
476
  if (shouldInstall) {
391
477
  if (forceInstall) {
@@ -394,21 +480,20 @@ async function runCommand(projectDir, options = {}) {
394
480
  log(`\u4F9D\u8D56\u72B6\u6001: ${project.dependencies.reason || "\u9700\u8981\u5B89\u88C5"}`);
395
481
  }
396
482
  newline();
397
- const installCmd = getInstallCommand(project.packageManager.name);
483
+ const installCmd = getInstallCommand(resolvedPm);
398
484
  const installExitCode = await execute(installCmd, { cwd: projectDir });
399
485
  if (installExitCode !== 0) {
400
- error("\u4F9D\u8D56\u5B89\u88C5\u5931\u8D25");
401
- process.exit(installExitCode);
486
+ throw new CliError("\u4F9D\u8D56\u5B89\u88C5\u5931\u8D25", installExitCode);
402
487
  }
403
488
  success("\u4F9D\u8D56\u5B89\u88C5\u5B8C\u6210");
404
489
  newline();
405
490
  } else if (!noInstall) {
406
491
  log("\u4F9D\u8D56\u72B6\u6001: \u5DF2\u662F\u6700\u65B0");
407
492
  }
408
- const runCmd = getRunCommand(project.packageManager.name, scriptName);
493
+ const runCmd = getRunCommand(resolvedPm, scriptName);
409
494
  const exitCode = await execute(runCmd, { cwd: projectDir });
410
495
  if (exitCode !== 0) {
411
- process.exit(exitCode);
496
+ throw new CliError("\u811A\u672C\u6267\u884C\u5931\u8D25", exitCode);
412
497
  }
413
498
  }
414
499
  function findScript(project, scriptType) {
@@ -437,7 +522,7 @@ function showAvailableScripts(project) {
437
522
  console.log(` - ${name}`);
438
523
  }
439
524
  console.log();
440
- info("\u4F7F\u7528 qy <script> \u8FD0\u884C\u4EFB\u610F\u811A\u672C");
525
+ info("\u4F7F\u7528 pr <script> \u8FD0\u884C\u4EFB\u610F\u811A\u672C");
441
526
  }
442
527
 
443
528
  // src/cli/info.ts
@@ -467,7 +552,9 @@ async function infoCommand(projectDir) {
467
552
  pmInfo += `@${pm.version}`;
468
553
  }
469
554
  pmInfo += ` ${colors.dim}(${pm.source})${colors.reset}`;
470
- console.log(`${colors.bold}\u5305\u7BA1\u7406\u5668:${colors.reset} ${pmInfo}`);
555
+ const pmAvailable = await isPmAvailable(pm.name);
556
+ const pmStatus = pmAvailable ? `${colors.green}\u5DF2\u5B89\u88C5${colors.reset}` : `${colors.red}\u672A\u5B89\u88C5${colors.reset}`;
557
+ console.log(`${colors.bold}\u5305\u7BA1\u7406\u5668:${colors.reset} ${pmInfo} [${pmStatus}]`);
471
558
  const deps = project.dependencies;
472
559
  const depsStatus = deps.needsInstall ? `${colors.yellow}\u9700\u8981\u5B89\u88C5${colors.reset} (${deps.reason})` : `${colors.green}\u5DF2\u5C31\u7EEA${colors.reset}`;
473
560
  console.log(`${colors.bold}\u4F9D\u8D56\u72B6\u6001:${colors.reset} ${depsStatus}`);
@@ -505,26 +592,23 @@ async function infoCommand(projectDir) {
505
592
  async function scriptCommand(projectDir, scriptName) {
506
593
  const project = await analyzeProject(projectDir);
507
594
  if (project.type === "unknown") {
508
- error("\u672A\u68C0\u6D4B\u5230\u9879\u76EE\u7C7B\u578B\u3002\u8BF7\u786E\u4FDD\u5F53\u524D\u76EE\u5F55\u5305\u542B package.json");
509
- process.exit(1);
595
+ throw new CliError("\u672A\u68C0\u6D4B\u5230\u9879\u76EE\u7C7B\u578B\u3002\u8BF7\u786E\u4FDD\u5F53\u524D\u76EE\u5F55\u5305\u542B package.json");
510
596
  }
511
597
  if (!project.scripts) {
512
- error("\u65E0\u6CD5\u8BFB\u53D6 package.json \u7684 scripts");
513
- process.exit(1);
598
+ throw new CliError("\u65E0\u6CD5\u8BFB\u53D6 package.json \u7684 scripts");
514
599
  }
515
600
  const scripts = project.scripts.scripts;
516
601
  if (!(scriptName in scripts)) {
517
- error(`\u811A\u672C "${scriptName}" \u4E0D\u5B58\u5728`);
518
- console.log();
519
602
  showAvailableScripts2(scripts);
520
- process.exit(1);
603
+ throw new CliError(`\u811A\u672C "${scriptName}" \u4E0D\u5B58\u5728`);
521
604
  }
522
605
  log(`\u5305\u7BA1\u7406\u5668: ${project.packageManager.name}`);
523
606
  log(`\u6267\u884C\u811A\u672C: ${scriptName}`);
524
- const runCmd = getRunCommand(project.packageManager.name, scriptName);
607
+ const resolvedPm = await ensurePmAvailable(project.packageManager.name);
608
+ const runCmd = getRunCommand(resolvedPm, scriptName);
525
609
  const exitCode = await execute(runCmd, { cwd: projectDir });
526
610
  if (exitCode !== 0) {
527
- process.exit(exitCode);
611
+ throw new CliError("\u811A\u672C\u6267\u884C\u5931\u8D25", exitCode);
528
612
  }
529
613
  }
530
614
  function showAvailableScripts2(scripts) {
@@ -540,7 +624,7 @@ function showAvailableScripts2(scripts) {
540
624
  }
541
625
 
542
626
  // src/index.ts
543
- var VERSION = "0.1.2";
627
+ var VERSION = true ? "0.2.0" : "0.0.0-dev";
544
628
  function parseArgs(args) {
545
629
  const options = {
546
630
  verbose: false,
@@ -571,6 +655,8 @@ function parseArgs(args) {
571
655
  } else {
572
656
  remainingArgs.push(arg);
573
657
  }
658
+ } else {
659
+ warn(`\u672A\u77E5\u9009\u9879: ${arg}`);
574
660
  }
575
661
  i++;
576
662
  }
@@ -643,6 +729,10 @@ async function main() {
643
729
  }
644
730
  }
645
731
  main().catch((err) => {
646
- error(err.message);
732
+ if (err instanceof CliError) {
733
+ error(err.message);
734
+ process.exit(err.exitCode);
735
+ }
736
+ error(err.message || "\u672A\u77E5\u9519\u8BEF");
647
737
  process.exit(1);
648
738
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "project-runner",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "description": "零配置智能项目运行器 - 一键运行任意 Node.js 项目",
5
5
  "author": "liangzhenqi",
6
6
  "license": "MIT",