git-watchtower 1.10.18 → 1.10.20

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.
@@ -368,6 +368,14 @@ const cliArgs = parseCliArgs(process.argv.slice(2), {
368
368
  onHelp: (v) => { console.log(getHelpText(v)); process.exit(0); },
369
369
  });
370
370
 
371
+ if (cliArgs.errors.length > 0) {
372
+ for (const err of cliArgs.errors) {
373
+ console.error(`Error: ${err}`);
374
+ }
375
+ console.error('\nRun git-watchtower --help for usage information.');
376
+ process.exit(1);
377
+ }
378
+
371
379
  // Configuration - these will be set after config is loaded
372
380
  let SERVER_MODE = 'static'; // 'static' | 'command' | 'none'
373
381
  let NO_SERVER = false; // Derived from SERVER_MODE === 'none'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "git-watchtower",
3
- "version": "1.10.18",
3
+ "version": "1.10.20",
4
4
  "description": "Terminal-based Git branch monitor with activity sparklines and optional dev server with live reload",
5
5
  "main": "bin/git-watchtower.js",
6
6
  "bin": {
package/src/cli/args.js CHANGED
@@ -22,6 +22,7 @@ const { version: PACKAGE_VERSION } = require('../../package.json');
22
22
  * @property {boolean} casino - Enable casino mode
23
23
  * @property {boolean} web - Enable web dashboard mode
24
24
  * @property {number|null} webPort - Web dashboard port override
25
+ * @property {string[]} errors - Validation errors encountered during parsing
25
26
  */
26
27
 
27
28
  /**
@@ -55,6 +56,8 @@ function parseArgs(argv, options = {}) {
55
56
  // Actions
56
57
  init: false,
57
58
  casino: false,
59
+ // Parsing errors
60
+ errors: [],
58
61
  };
59
62
 
60
63
  for (let i = 0; i < args.length; i++) {
@@ -63,21 +66,33 @@ function parseArgs(argv, options = {}) {
63
66
  const mode = args[i + 1];
64
67
  if (['static', 'command', 'none'].includes(mode)) {
65
68
  result.mode = mode;
69
+ } else {
70
+ result.errors.push(`Invalid value for ${args[i]}: "${mode || ''}" (expected: static, command, none)`);
66
71
  }
67
72
  i++;
68
73
  } else if (args[i] === '--port' || args[i] === '-p') {
69
74
  const portValue = parseInt(args[i + 1], 10);
70
75
  if (!isNaN(portValue) && portValue > 0 && portValue < 65536) {
71
76
  result.port = portValue;
77
+ } else {
78
+ result.errors.push(`Invalid value for ${args[i]}: "${args[i + 1] || ''}" (expected: port number 1-65535)`);
72
79
  }
73
80
  i++;
74
81
  } else if (args[i] === '--no-server' || args[i] === '-n') {
75
82
  result.noServer = true;
76
83
  } else if (args[i] === '--static-dir') {
77
- result.staticDir = args[i + 1];
84
+ if (args[i + 1] && !args[i + 1].startsWith('-')) {
85
+ result.staticDir = args[i + 1];
86
+ } else {
87
+ result.errors.push(`Missing value for ${args[i]}`);
88
+ }
78
89
  i++;
79
90
  } else if (args[i] === '--command' || args[i] === '-c') {
80
- result.command = args[i + 1];
91
+ if (args[i + 1] !== undefined) {
92
+ result.command = args[i + 1];
93
+ } else {
94
+ result.errors.push(`Missing value for ${args[i]}`);
95
+ }
81
96
  i++;
82
97
  } else if (args[i] === '--restart-on-switch') {
83
98
  result.restartOnSwitch = true;
@@ -86,7 +101,11 @@ function parseArgs(argv, options = {}) {
86
101
  }
87
102
  // Git settings
88
103
  else if (args[i] === '--remote' || args[i] === '-r') {
89
- result.remote = args[i + 1];
104
+ if (args[i + 1] && !args[i + 1].startsWith('-')) {
105
+ result.remote = args[i + 1];
106
+ } else {
107
+ result.errors.push(`Missing value for ${args[i]}`);
108
+ }
90
109
  i++;
91
110
  } else if (args[i] === '--auto-pull') {
92
111
  result.autoPull = true;
@@ -96,6 +115,8 @@ function parseArgs(argv, options = {}) {
96
115
  const interval = parseInt(args[i + 1], 10);
97
116
  if (!isNaN(interval) && interval > 0) {
98
117
  result.pollInterval = interval;
118
+ } else {
119
+ result.errors.push(`Invalid value for ${args[i]}: "${args[i + 1] || ''}" (expected: positive integer in ms)`);
99
120
  }
100
121
  i++;
101
122
  }
@@ -108,6 +129,8 @@ function parseArgs(argv, options = {}) {
108
129
  const count = parseInt(args[i + 1], 10);
109
130
  if (!isNaN(count) && count > 0) {
110
131
  result.visibleBranches = count;
132
+ } else {
133
+ result.errors.push(`Invalid value for ${args[i]}: "${args[i + 1] || ''}" (expected: positive integer)`);
111
134
  }
112
135
  i++;
113
136
  } else if (args[i] === '--casino') {
@@ -120,6 +143,8 @@ function parseArgs(argv, options = {}) {
120
143
  const webPortValue = parseInt(args[i + 1], 10);
121
144
  if (!isNaN(webPortValue) && webPortValue > 0 && webPortValue < 65536) {
122
145
  result.webPort = webPortValue;
146
+ } else {
147
+ result.errors.push(`Invalid value for ${args[i]}: "${args[i + 1] || ''}" (expected: port number 1-65535)`);
123
148
  }
124
149
  i++;
125
150
  }
@@ -135,6 +160,10 @@ function parseArgs(argv, options = {}) {
135
160
  options.onHelp(PACKAGE_VERSION);
136
161
  }
137
162
  }
163
+ // Unknown flag
164
+ else if (args[i].startsWith('-')) {
165
+ result.errors.push(`Unknown option: ${args[i]}`);
166
+ }
138
167
  }
139
168
  return result;
140
169
  }
@@ -5,6 +5,7 @@
5
5
 
6
6
  const { spawn } = require('child_process');
7
7
  const { ServerError } = require('../utils/errors');
8
+ const { Mutex } = require('../utils/async');
8
9
 
9
10
  /**
10
11
  * @typedef {Object} ServerProcessState
@@ -90,6 +91,7 @@ class ProcessManager {
90
91
  this.crashed = false;
91
92
  this.logs = [];
92
93
  this.command = '';
94
+ this._restartMutex = new Mutex();
93
95
  }
94
96
 
95
97
  /**
@@ -283,13 +285,15 @@ class ProcessManager {
283
285
  * @returns {Promise<{success: boolean, error?: Error, pid?: number}>}
284
286
  */
285
287
  async restart() {
286
- const command = this.command;
287
- this.stop();
288
+ return this._restartMutex.withLock(async () => {
289
+ const command = this.command;
290
+ this.stop();
288
291
 
289
- // Wait before restarting
290
- await new Promise((resolve) => setTimeout(resolve, RESTART_DELAY));
292
+ // Wait before restarting
293
+ await new Promise((resolve) => setTimeout(resolve, RESTART_DELAY));
291
294
 
292
- return this.start(command);
295
+ return this.start(command);
296
+ });
293
297
  }
294
298
 
295
299
  /**