@laphilosophia/steady-watch 2.0.2 → 2.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/README.md +76 -2
- package/bin/steady-watch +1 -1
- package/dist/index.d.mts +108 -8
- package/dist/index.d.ts +108 -8
- package/dist/index.js +600 -120
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +596 -120
- package/dist/index.mjs.map +1 -1
- package/package.json +12 -9
- package/scripts/smoke-tests.mjs +277 -0
- package/steady-watch.config.json +4 -0
package/README.md
CHANGED
|
@@ -39,12 +39,19 @@ Example `steady-watch.config.json`:
|
|
|
39
39
|
{
|
|
40
40
|
"pattern": "src/**/*.ts",
|
|
41
41
|
"cmd": "npm run build",
|
|
42
|
+
"start": "node dist/server.js",
|
|
43
|
+
"restartOnSuccess": true,
|
|
44
|
+
"restartOnChange": false,
|
|
45
|
+
"initialRun": true,
|
|
42
46
|
"delay": 300,
|
|
43
47
|
"verbose": false,
|
|
44
48
|
"quiet": false,
|
|
45
49
|
"ignore": ["*.test.ts"],
|
|
46
50
|
"ext": [".ts", ".tsx"],
|
|
51
|
+
"gitChanged": false,
|
|
52
|
+
"gitBase": "HEAD",
|
|
47
53
|
"killTimeout": 10000,
|
|
54
|
+
"restartDelay": 0,
|
|
48
55
|
"retry": 3,
|
|
49
56
|
"hash": "sha256",
|
|
50
57
|
"mtimeOnly": false,
|
|
@@ -71,14 +78,22 @@ sw "src/**/*.ts" -c "npm run build"
|
|
|
71
78
|
| Option | Description | Default |
|
|
72
79
|
|--------|-------------|---------|
|
|
73
80
|
| `files` | Glob pattern to watch (e.g., `"src/**/*.ts"`) | *required* |
|
|
74
|
-
| `-c, --cmd <command>` |
|
|
81
|
+
| `-c, --cmd <command>` | Short lifecycle command to execute on change (supports `&&`) | *required unless using `--start --restart-on-change`* |
|
|
82
|
+
| `--start <command>` | Long-running process command to start or restart | *none* |
|
|
83
|
+
| `--restart-on-success` | Restart `--start` only when `--cmd` exits with code `0` | `false` |
|
|
84
|
+
| `--restart-on-change` | Restart `--start` directly on change when no `--cmd` is configured | `false` |
|
|
85
|
+
| `--initial-run` | Run the lifecycle when the watcher starts | `true` when `--start` is used |
|
|
86
|
+
| `--no-initial-run` | Wait for the first file change before running the lifecycle | `false` |
|
|
75
87
|
| `-d, --delay <ms>` | Debounce delay in milliseconds | `300` |
|
|
76
88
|
| `-v, --verbose` | Show hash calculations and file indexing | `false` |
|
|
77
89
|
| `-q, --quiet` | Minimize output | `false` |
|
|
78
90
|
| `--ignore <patterns>` | Additional ignore patterns (comma-separated) | `node_modules, .git, dist, build` |
|
|
79
91
|
| `--ext <extensions>` | Filter by file extensions (e.g., `.ts,.tsx`) | *none* |
|
|
92
|
+
| `--git-changed` | Only trigger for files changed from the git base ref | `false` |
|
|
93
|
+
| `--git-base <ref>` | Git base ref for `--git-changed` | `HEAD` |
|
|
80
94
|
| `--config <path>` | Path to config file | auto-detect |
|
|
81
|
-
| `--kill-timeout <ms>` | Force kill process after timeout
|
|
95
|
+
| `--kill-timeout <ms>` | Force kill lifecycle commands and graceful process shutdown after timeout | `5000` with `--start`, otherwise `0` |
|
|
96
|
+
| `--restart-delay <ms>` | Delay between stopping and starting `--start` | `0` |
|
|
82
97
|
| `--retry <count>` | Retry failed command (0 = disabled) | `0` |
|
|
83
98
|
| `--hash <algo>` | Hash algorithm (md5, sha1, sha256) | `md5` |
|
|
84
99
|
| `--no-hash` | Use mtime only instead of content hash (fastest) | `false` |
|
|
@@ -104,6 +119,12 @@ sw "src/**/*.ts" -c "npm run build" -q
|
|
|
104
119
|
# Filter by extensions
|
|
105
120
|
sw "src/**/*" -c "npm run build" --ext .ts,.tsx
|
|
106
121
|
|
|
122
|
+
# Only trigger for files changed from HEAD, including staged, unstaged, and untracked files
|
|
123
|
+
sw "src/**/*" -c "npm test" --git-changed
|
|
124
|
+
|
|
125
|
+
# Compare against a specific base ref
|
|
126
|
+
sw "src/**/*" -c "npm test" --git-changed --git-base main
|
|
127
|
+
|
|
107
128
|
# Custom ignore patterns
|
|
108
129
|
sw "src/**/*" -c "npm run build" --ignore "*.test.ts,tmp/*"
|
|
109
130
|
|
|
@@ -116,10 +137,21 @@ sw "src/**/*.ts" -c "npm run build" --retry 3
|
|
|
116
137
|
# Multiple commands (using &&)
|
|
117
138
|
sw "src/**/*.ts" -c "npm run build && npm run test"
|
|
118
139
|
|
|
140
|
+
# Build first, then start or restart the server only after success
|
|
141
|
+
sw "src/**/*.ts" -c "npm run build" --start "node dist/server.js" --restart-on-success
|
|
142
|
+
|
|
143
|
+
# Restart a server directly on change without a build command
|
|
144
|
+
sw "src/**/*" --start "node server.js" --restart-on-change
|
|
145
|
+
|
|
146
|
+
# Keep the old server running when build or tests fail
|
|
147
|
+
sw "src/**/*" -c "npm run build && npm test" --start "node dist/server.js" --restart-on-success --kill-timeout 10000
|
|
148
|
+
|
|
119
149
|
# Use config file
|
|
120
150
|
sw --config .steady-watchrc
|
|
121
151
|
```
|
|
122
152
|
|
|
153
|
+
When `--cmd` and `--start` are used together, `--cmd` is treated as a short lifecycle command. The running `--start` process is only replaced after a successful lifecycle command. If the lifecycle command fails, the current long-running process is preserved. File changes that arrive while a lifecycle cycle is already running are coalesced into one additional cycle.
|
|
154
|
+
|
|
123
155
|
## Programmatic API
|
|
124
156
|
|
|
125
157
|
You can also use Steady Watch as a library in your Node.js code:
|
|
@@ -131,6 +163,8 @@ import { SteadyWatcher, steadyWatch } from '@laphilosophia/steady-watch';
|
|
|
131
163
|
const watcher = steadyWatch({
|
|
132
164
|
pattern: 'src/**/*.ts',
|
|
133
165
|
cmd: 'npm run build',
|
|
166
|
+
start: 'node dist/server.js',
|
|
167
|
+
restartOnSuccess: true,
|
|
134
168
|
delay: 300
|
|
135
169
|
});
|
|
136
170
|
|
|
@@ -138,6 +172,8 @@ const watcher = steadyWatch({
|
|
|
138
172
|
const watcher = new SteadyWatcher({
|
|
139
173
|
pattern: 'src/**/*.ts',
|
|
140
174
|
cmd: 'npm run build',
|
|
175
|
+
start: 'node dist/server.js',
|
|
176
|
+
restartOnSuccess: true,
|
|
141
177
|
delay: 300
|
|
142
178
|
});
|
|
143
179
|
|
|
@@ -145,6 +181,8 @@ const watcher = new SteadyWatcher({
|
|
|
145
181
|
watcher.on('ready', () => console.log('Ready!'));
|
|
146
182
|
watcher.on('change', (file) => console.log(`Changed: ${file}`));
|
|
147
183
|
watcher.on('trigger', (cmd) => console.log(`Running: ${cmd}`));
|
|
184
|
+
watcher.on('start', (cmd, pid) => console.log(`Started: ${cmd} (${pid})`));
|
|
185
|
+
watcher.on('startExit', (code, signal, expected) => console.log({ code, signal, expected }));
|
|
148
186
|
watcher.on('done', (duration) => console.log(`Done in ${duration}s`));
|
|
149
187
|
watcher.on('fail', (code) => console.log(`Failed: ${code}`));
|
|
150
188
|
|
|
@@ -153,10 +191,45 @@ await watcher.start();
|
|
|
153
191
|
// Get tracked files
|
|
154
192
|
console.log(watcher.getTrackedFiles());
|
|
155
193
|
|
|
194
|
+
// Lifecycle command state and long-running process state are separate
|
|
195
|
+
console.log(watcher.isCurrentlyRunning());
|
|
196
|
+
console.log(watcher.isStartedProcessRunning());
|
|
197
|
+
|
|
156
198
|
// Stop watching
|
|
157
199
|
await watcher.close();
|
|
158
200
|
```
|
|
159
201
|
|
|
202
|
+
Lifecycle hooks are available through the programmatic API. They are not loaded from JSON config files or CLI flags.
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
const watcher = steadyWatch({
|
|
206
|
+
pattern: 'src/**/*.ts',
|
|
207
|
+
cmd: 'pnpm build',
|
|
208
|
+
start: 'node dist/src/app/main.js',
|
|
209
|
+
restartOnSuccess: true,
|
|
210
|
+
hooks: {
|
|
211
|
+
beforeCommand: async () => {
|
|
212
|
+
await validateWorkspace();
|
|
213
|
+
},
|
|
214
|
+
afterCommand: async ({ exitCode }) => {
|
|
215
|
+
if (exitCode !== 0) return;
|
|
216
|
+
await validateBuildArtifacts();
|
|
217
|
+
},
|
|
218
|
+
beforeStart: async () => {
|
|
219
|
+
await validateRuntimeConfig();
|
|
220
|
+
},
|
|
221
|
+
afterStart: async ({ pid }) => {
|
|
222
|
+
await warmupProcess(pid);
|
|
223
|
+
},
|
|
224
|
+
onSkip: ({ skipReason, file }) => {
|
|
225
|
+
console.log(`Skipped ${file}: ${skipReason}`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
`beforeCommand`, `afterCommand`, `beforeStop`, and `beforeStart` are lifecycle gates. If they throw, the active cycle is failed and the next phase is not run. During restart, `beforeStart` runs before `beforeStop`, so runtime validation can fail without stopping the current process. `afterStop`, `afterStart`, and `onSkip` are notification hooks; failures are reported through the `hookError` event without changing the lifecycle result.
|
|
232
|
+
|
|
160
233
|
## Themes
|
|
161
234
|
|
|
162
235
|
- `default` - Full color output
|
|
@@ -169,6 +242,7 @@ await watcher.close();
|
|
|
169
242
|
- ⏱️ **Debouncing** — Batches rapid changes into single rebuilds
|
|
170
243
|
- 🚀 **Process Management** — Won't start new build while previous is running
|
|
171
244
|
- 🚫 **Smart Ignores** — Auto-ignores `node_modules`, `.git`, `dist`, `build`
|
|
245
|
+
- 🧩 **Lifecycle Hooks** — Integrate custom checks, validation, cleanup, and warmup in code
|
|
172
246
|
- 🎨 **Pretty Output** — Color-coded, timestamped logs
|
|
173
247
|
|
|
174
248
|
## Output Example
|
package/bin/steady-watch
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -2,13 +2,28 @@ import { EventEmitter } from 'events';
|
|
|
2
2
|
|
|
3
3
|
interface SteadyWatchOptions {
|
|
4
4
|
pattern: string;
|
|
5
|
-
cmd
|
|
5
|
+
cmd?: string;
|
|
6
|
+
start?: string;
|
|
7
|
+
restartOnSuccess?: boolean;
|
|
8
|
+
restartOnChange?: boolean;
|
|
9
|
+
initialRun?: boolean;
|
|
10
|
+
hooks?: SteadyWatchHooks;
|
|
11
|
+
beforeCommand?: SteadyWatchHook;
|
|
12
|
+
afterCommand?: SteadyWatchHook;
|
|
13
|
+
beforeStop?: SteadyWatchHook;
|
|
14
|
+
afterStop?: SteadyWatchHook;
|
|
15
|
+
beforeStart?: SteadyWatchHook;
|
|
16
|
+
afterStart?: SteadyWatchHook;
|
|
17
|
+
onSkip?: SteadyWatchHook;
|
|
6
18
|
delay?: number;
|
|
7
19
|
verbose?: boolean;
|
|
8
20
|
quiet?: boolean;
|
|
9
21
|
ignore?: (string | RegExp)[];
|
|
10
22
|
ext?: string[];
|
|
23
|
+
gitChanged?: boolean;
|
|
24
|
+
gitBase?: string;
|
|
11
25
|
killTimeout?: number;
|
|
26
|
+
restartDelay?: number;
|
|
12
27
|
retry?: number;
|
|
13
28
|
hash?: HashAlgorithm;
|
|
14
29
|
mtimeOnly?: boolean;
|
|
@@ -21,6 +36,11 @@ interface SteadyWatchEvents {
|
|
|
21
36
|
ready: () => void;
|
|
22
37
|
change: (file: string) => void;
|
|
23
38
|
trigger: (cmd: string) => void;
|
|
39
|
+
start: (cmd: string, pid?: number) => void;
|
|
40
|
+
startExit: (exitCode: number | null, signal?: string, expected?: boolean) => void;
|
|
41
|
+
restart: (cmd: string) => void;
|
|
42
|
+
stop: (cmd: string, signal?: string) => void;
|
|
43
|
+
hookError: (hook: keyof SteadyWatchHooks, error: Error) => void;
|
|
24
44
|
done: (duration: number) => void;
|
|
25
45
|
fail: (exitCode: number | null, signal?: string) => void;
|
|
26
46
|
error: (error: Error) => void;
|
|
@@ -28,15 +48,48 @@ interface SteadyWatchEvents {
|
|
|
28
48
|
}
|
|
29
49
|
type HashAlgorithm = 'md5' | 'sha1' | 'sha256';
|
|
30
50
|
type ThemeName = 'default' | 'minimal' | 'none';
|
|
51
|
+
type SteadyWatchHookPhase = 'beforeCommand' | 'afterCommand' | 'beforeStop' | 'afterStop' | 'beforeStart' | 'afterStart' | 'onSkip';
|
|
52
|
+
interface SteadyWatchHookContext {
|
|
53
|
+
phase: SteadyWatchHookPhase;
|
|
54
|
+
reason?: string;
|
|
55
|
+
command?: string;
|
|
56
|
+
startCommand?: string;
|
|
57
|
+
file?: string;
|
|
58
|
+
skipReason?: string;
|
|
59
|
+
attempt?: number;
|
|
60
|
+
exitCode?: number | null;
|
|
61
|
+
signal?: string | null;
|
|
62
|
+
duration?: number;
|
|
63
|
+
pid?: number;
|
|
64
|
+
timestamp: Date;
|
|
65
|
+
}
|
|
66
|
+
type SteadyWatchHook = (context: Readonly<SteadyWatchHookContext>) => void | Promise<void>;
|
|
67
|
+
interface SteadyWatchHooks {
|
|
68
|
+
beforeCommand?: SteadyWatchHook;
|
|
69
|
+
afterCommand?: SteadyWatchHook;
|
|
70
|
+
beforeStop?: SteadyWatchHook;
|
|
71
|
+
afterStop?: SteadyWatchHook;
|
|
72
|
+
beforeStart?: SteadyWatchHook;
|
|
73
|
+
afterStart?: SteadyWatchHook;
|
|
74
|
+
onSkip?: SteadyWatchHook;
|
|
75
|
+
}
|
|
31
76
|
interface NormalizedOptions {
|
|
32
77
|
pattern: string;
|
|
33
78
|
cmd: string;
|
|
79
|
+
start: string;
|
|
80
|
+
restartOnSuccess: boolean;
|
|
81
|
+
restartOnChange: boolean;
|
|
82
|
+
initialRun: boolean;
|
|
83
|
+
hooks: SteadyWatchHooks;
|
|
34
84
|
delay: number;
|
|
35
85
|
verbose: boolean;
|
|
36
86
|
quiet: boolean;
|
|
37
87
|
ignore: (string | RegExp)[];
|
|
38
88
|
ext: string[];
|
|
89
|
+
gitChanged: boolean;
|
|
90
|
+
gitBase: string;
|
|
39
91
|
killTimeout: number;
|
|
92
|
+
restartDelay: number;
|
|
40
93
|
retry: number;
|
|
41
94
|
hash: HashAlgorithm;
|
|
42
95
|
mtimeOnly: boolean;
|
|
@@ -50,22 +103,29 @@ interface ValidationResult {
|
|
|
50
103
|
}
|
|
51
104
|
interface CliOptions {
|
|
52
105
|
cmd?: string;
|
|
106
|
+
start?: string;
|
|
107
|
+
restartOnSuccess?: boolean;
|
|
108
|
+
restartOnChange?: boolean;
|
|
109
|
+
initialRun?: boolean;
|
|
53
110
|
config?: string;
|
|
54
111
|
delay?: string;
|
|
55
112
|
verbose?: boolean;
|
|
56
113
|
quiet?: boolean;
|
|
57
114
|
ignore?: string;
|
|
58
115
|
ext?: string;
|
|
116
|
+
gitChanged?: boolean;
|
|
117
|
+
gitBase?: string;
|
|
59
118
|
killTimeout?: string;
|
|
119
|
+
restartDelay?: string;
|
|
60
120
|
retry?: string;
|
|
61
|
-
hash?: string;
|
|
121
|
+
hash?: string | boolean;
|
|
62
122
|
noHash?: boolean;
|
|
63
123
|
clear?: boolean;
|
|
64
124
|
json?: boolean;
|
|
65
125
|
theme?: string;
|
|
66
126
|
}
|
|
67
127
|
interface CliArgs {
|
|
68
|
-
pattern
|
|
128
|
+
pattern?: string;
|
|
69
129
|
}
|
|
70
130
|
|
|
71
131
|
type ChalkStyle = (s: string) => string;
|
|
@@ -85,13 +145,19 @@ declare function getTheme(name: ThemeName): Theme;
|
|
|
85
145
|
declare class SteadyWatcher extends EventEmitter {
|
|
86
146
|
private options;
|
|
87
147
|
private watcher;
|
|
148
|
+
private watcherReady;
|
|
88
149
|
private fileHashes;
|
|
150
|
+
private gitChangedFiles;
|
|
89
151
|
private timeout;
|
|
90
|
-
private
|
|
91
|
-
private
|
|
92
|
-
private
|
|
152
|
+
private cycleRunning;
|
|
153
|
+
private pendingCycle;
|
|
154
|
+
private lifecycleProcess;
|
|
155
|
+
private lifecycleKillTimer;
|
|
156
|
+
private startedProcess;
|
|
157
|
+
private stoppingStartedProcess;
|
|
93
158
|
private retryCount;
|
|
94
159
|
private disposed;
|
|
160
|
+
private closePromise;
|
|
95
161
|
private t;
|
|
96
162
|
private static readonly DEFAULT_IGNORE;
|
|
97
163
|
private static readonly VALID_HASH_ALGORITHMS;
|
|
@@ -102,21 +168,55 @@ declare class SteadyWatcher extends EventEmitter {
|
|
|
102
168
|
validate(): ValidationResult;
|
|
103
169
|
private getEffectivePattern;
|
|
104
170
|
private getHash;
|
|
171
|
+
private normalizeGitPath;
|
|
172
|
+
private runGit;
|
|
173
|
+
private refreshGitChangedFiles;
|
|
174
|
+
private isGitChangedFile;
|
|
105
175
|
private log;
|
|
106
176
|
private logVerbose;
|
|
107
177
|
private logJson;
|
|
108
178
|
private timestamp;
|
|
179
|
+
private runHook;
|
|
180
|
+
private notifyHook;
|
|
181
|
+
private sleep;
|
|
109
182
|
private parseCommand;
|
|
110
|
-
private
|
|
183
|
+
private commandNeedsShell;
|
|
184
|
+
private resolveWindowsCommand;
|
|
185
|
+
private shouldUseShell;
|
|
186
|
+
private spawnCommand;
|
|
187
|
+
private runTaskkill;
|
|
188
|
+
private forceKillProcess;
|
|
189
|
+
private terminateProcess;
|
|
190
|
+
private runSingleCommand;
|
|
191
|
+
private runCommandWithRetry;
|
|
192
|
+
private stopStartedProcess;
|
|
193
|
+
private startLongRunningProcess;
|
|
194
|
+
private restartStartedProcess;
|
|
195
|
+
private runCycle;
|
|
196
|
+
private requestCycle;
|
|
197
|
+
private skip;
|
|
198
|
+
private scheduleFileCycle;
|
|
111
199
|
private handleFileChange;
|
|
112
200
|
start(): Promise<void>;
|
|
201
|
+
private handleFileAdd;
|
|
202
|
+
private handleFileUnlink;
|
|
113
203
|
close(): Promise<void>;
|
|
204
|
+
private closeInternal;
|
|
114
205
|
getTrackedFiles(): string[];
|
|
115
206
|
isCurrentlyRunning(): boolean;
|
|
207
|
+
isStartedProcessRunning(): boolean;
|
|
116
208
|
isDisposed(): boolean;
|
|
117
209
|
}
|
|
118
210
|
declare function steadyWatch(options: SteadyWatchOptions): SteadyWatcher;
|
|
119
211
|
|
|
212
|
+
declare const CLI_VERSION = "2.1.0";
|
|
213
|
+
declare function loadConfig(configPath?: string): Record<string, unknown>;
|
|
214
|
+
declare function mergeOptions(cliArgs: CliArgs, cliOpts: CliOptions, config: Record<string, unknown>): SteadyWatchOptions;
|
|
215
|
+
declare function parseCliArgs(argv?: string[]): {
|
|
216
|
+
args: CliArgs;
|
|
217
|
+
opts: CliOptions;
|
|
218
|
+
};
|
|
219
|
+
|
|
120
220
|
declare function runCli(): void;
|
|
121
221
|
|
|
122
|
-
export { type ChalkStyle, type CliArgs, type CliOptions, type HashAlgorithm, type NormalizedOptions, type SteadyWatchEvents, type SteadyWatchOptions, SteadyWatcher, type Theme, type ThemeName, type ValidationResult, getTheme, runCli, steadyWatch, themes };
|
|
222
|
+
export { CLI_VERSION, type ChalkStyle, type CliArgs, type CliOptions, type HashAlgorithm, type NormalizedOptions, type SteadyWatchEvents, type SteadyWatchHook, type SteadyWatchHookContext, type SteadyWatchHookPhase, type SteadyWatchHooks, type SteadyWatchOptions, SteadyWatcher, type Theme, type ThemeName, type ValidationResult, getTheme, loadConfig, mergeOptions, parseCliArgs, runCli, steadyWatch, themes };
|
package/dist/index.d.ts
CHANGED
|
@@ -2,13 +2,28 @@ import { EventEmitter } from 'events';
|
|
|
2
2
|
|
|
3
3
|
interface SteadyWatchOptions {
|
|
4
4
|
pattern: string;
|
|
5
|
-
cmd
|
|
5
|
+
cmd?: string;
|
|
6
|
+
start?: string;
|
|
7
|
+
restartOnSuccess?: boolean;
|
|
8
|
+
restartOnChange?: boolean;
|
|
9
|
+
initialRun?: boolean;
|
|
10
|
+
hooks?: SteadyWatchHooks;
|
|
11
|
+
beforeCommand?: SteadyWatchHook;
|
|
12
|
+
afterCommand?: SteadyWatchHook;
|
|
13
|
+
beforeStop?: SteadyWatchHook;
|
|
14
|
+
afterStop?: SteadyWatchHook;
|
|
15
|
+
beforeStart?: SteadyWatchHook;
|
|
16
|
+
afterStart?: SteadyWatchHook;
|
|
17
|
+
onSkip?: SteadyWatchHook;
|
|
6
18
|
delay?: number;
|
|
7
19
|
verbose?: boolean;
|
|
8
20
|
quiet?: boolean;
|
|
9
21
|
ignore?: (string | RegExp)[];
|
|
10
22
|
ext?: string[];
|
|
23
|
+
gitChanged?: boolean;
|
|
24
|
+
gitBase?: string;
|
|
11
25
|
killTimeout?: number;
|
|
26
|
+
restartDelay?: number;
|
|
12
27
|
retry?: number;
|
|
13
28
|
hash?: HashAlgorithm;
|
|
14
29
|
mtimeOnly?: boolean;
|
|
@@ -21,6 +36,11 @@ interface SteadyWatchEvents {
|
|
|
21
36
|
ready: () => void;
|
|
22
37
|
change: (file: string) => void;
|
|
23
38
|
trigger: (cmd: string) => void;
|
|
39
|
+
start: (cmd: string, pid?: number) => void;
|
|
40
|
+
startExit: (exitCode: number | null, signal?: string, expected?: boolean) => void;
|
|
41
|
+
restart: (cmd: string) => void;
|
|
42
|
+
stop: (cmd: string, signal?: string) => void;
|
|
43
|
+
hookError: (hook: keyof SteadyWatchHooks, error: Error) => void;
|
|
24
44
|
done: (duration: number) => void;
|
|
25
45
|
fail: (exitCode: number | null, signal?: string) => void;
|
|
26
46
|
error: (error: Error) => void;
|
|
@@ -28,15 +48,48 @@ interface SteadyWatchEvents {
|
|
|
28
48
|
}
|
|
29
49
|
type HashAlgorithm = 'md5' | 'sha1' | 'sha256';
|
|
30
50
|
type ThemeName = 'default' | 'minimal' | 'none';
|
|
51
|
+
type SteadyWatchHookPhase = 'beforeCommand' | 'afterCommand' | 'beforeStop' | 'afterStop' | 'beforeStart' | 'afterStart' | 'onSkip';
|
|
52
|
+
interface SteadyWatchHookContext {
|
|
53
|
+
phase: SteadyWatchHookPhase;
|
|
54
|
+
reason?: string;
|
|
55
|
+
command?: string;
|
|
56
|
+
startCommand?: string;
|
|
57
|
+
file?: string;
|
|
58
|
+
skipReason?: string;
|
|
59
|
+
attempt?: number;
|
|
60
|
+
exitCode?: number | null;
|
|
61
|
+
signal?: string | null;
|
|
62
|
+
duration?: number;
|
|
63
|
+
pid?: number;
|
|
64
|
+
timestamp: Date;
|
|
65
|
+
}
|
|
66
|
+
type SteadyWatchHook = (context: Readonly<SteadyWatchHookContext>) => void | Promise<void>;
|
|
67
|
+
interface SteadyWatchHooks {
|
|
68
|
+
beforeCommand?: SteadyWatchHook;
|
|
69
|
+
afterCommand?: SteadyWatchHook;
|
|
70
|
+
beforeStop?: SteadyWatchHook;
|
|
71
|
+
afterStop?: SteadyWatchHook;
|
|
72
|
+
beforeStart?: SteadyWatchHook;
|
|
73
|
+
afterStart?: SteadyWatchHook;
|
|
74
|
+
onSkip?: SteadyWatchHook;
|
|
75
|
+
}
|
|
31
76
|
interface NormalizedOptions {
|
|
32
77
|
pattern: string;
|
|
33
78
|
cmd: string;
|
|
79
|
+
start: string;
|
|
80
|
+
restartOnSuccess: boolean;
|
|
81
|
+
restartOnChange: boolean;
|
|
82
|
+
initialRun: boolean;
|
|
83
|
+
hooks: SteadyWatchHooks;
|
|
34
84
|
delay: number;
|
|
35
85
|
verbose: boolean;
|
|
36
86
|
quiet: boolean;
|
|
37
87
|
ignore: (string | RegExp)[];
|
|
38
88
|
ext: string[];
|
|
89
|
+
gitChanged: boolean;
|
|
90
|
+
gitBase: string;
|
|
39
91
|
killTimeout: number;
|
|
92
|
+
restartDelay: number;
|
|
40
93
|
retry: number;
|
|
41
94
|
hash: HashAlgorithm;
|
|
42
95
|
mtimeOnly: boolean;
|
|
@@ -50,22 +103,29 @@ interface ValidationResult {
|
|
|
50
103
|
}
|
|
51
104
|
interface CliOptions {
|
|
52
105
|
cmd?: string;
|
|
106
|
+
start?: string;
|
|
107
|
+
restartOnSuccess?: boolean;
|
|
108
|
+
restartOnChange?: boolean;
|
|
109
|
+
initialRun?: boolean;
|
|
53
110
|
config?: string;
|
|
54
111
|
delay?: string;
|
|
55
112
|
verbose?: boolean;
|
|
56
113
|
quiet?: boolean;
|
|
57
114
|
ignore?: string;
|
|
58
115
|
ext?: string;
|
|
116
|
+
gitChanged?: boolean;
|
|
117
|
+
gitBase?: string;
|
|
59
118
|
killTimeout?: string;
|
|
119
|
+
restartDelay?: string;
|
|
60
120
|
retry?: string;
|
|
61
|
-
hash?: string;
|
|
121
|
+
hash?: string | boolean;
|
|
62
122
|
noHash?: boolean;
|
|
63
123
|
clear?: boolean;
|
|
64
124
|
json?: boolean;
|
|
65
125
|
theme?: string;
|
|
66
126
|
}
|
|
67
127
|
interface CliArgs {
|
|
68
|
-
pattern
|
|
128
|
+
pattern?: string;
|
|
69
129
|
}
|
|
70
130
|
|
|
71
131
|
type ChalkStyle = (s: string) => string;
|
|
@@ -85,13 +145,19 @@ declare function getTheme(name: ThemeName): Theme;
|
|
|
85
145
|
declare class SteadyWatcher extends EventEmitter {
|
|
86
146
|
private options;
|
|
87
147
|
private watcher;
|
|
148
|
+
private watcherReady;
|
|
88
149
|
private fileHashes;
|
|
150
|
+
private gitChangedFiles;
|
|
89
151
|
private timeout;
|
|
90
|
-
private
|
|
91
|
-
private
|
|
92
|
-
private
|
|
152
|
+
private cycleRunning;
|
|
153
|
+
private pendingCycle;
|
|
154
|
+
private lifecycleProcess;
|
|
155
|
+
private lifecycleKillTimer;
|
|
156
|
+
private startedProcess;
|
|
157
|
+
private stoppingStartedProcess;
|
|
93
158
|
private retryCount;
|
|
94
159
|
private disposed;
|
|
160
|
+
private closePromise;
|
|
95
161
|
private t;
|
|
96
162
|
private static readonly DEFAULT_IGNORE;
|
|
97
163
|
private static readonly VALID_HASH_ALGORITHMS;
|
|
@@ -102,21 +168,55 @@ declare class SteadyWatcher extends EventEmitter {
|
|
|
102
168
|
validate(): ValidationResult;
|
|
103
169
|
private getEffectivePattern;
|
|
104
170
|
private getHash;
|
|
171
|
+
private normalizeGitPath;
|
|
172
|
+
private runGit;
|
|
173
|
+
private refreshGitChangedFiles;
|
|
174
|
+
private isGitChangedFile;
|
|
105
175
|
private log;
|
|
106
176
|
private logVerbose;
|
|
107
177
|
private logJson;
|
|
108
178
|
private timestamp;
|
|
179
|
+
private runHook;
|
|
180
|
+
private notifyHook;
|
|
181
|
+
private sleep;
|
|
109
182
|
private parseCommand;
|
|
110
|
-
private
|
|
183
|
+
private commandNeedsShell;
|
|
184
|
+
private resolveWindowsCommand;
|
|
185
|
+
private shouldUseShell;
|
|
186
|
+
private spawnCommand;
|
|
187
|
+
private runTaskkill;
|
|
188
|
+
private forceKillProcess;
|
|
189
|
+
private terminateProcess;
|
|
190
|
+
private runSingleCommand;
|
|
191
|
+
private runCommandWithRetry;
|
|
192
|
+
private stopStartedProcess;
|
|
193
|
+
private startLongRunningProcess;
|
|
194
|
+
private restartStartedProcess;
|
|
195
|
+
private runCycle;
|
|
196
|
+
private requestCycle;
|
|
197
|
+
private skip;
|
|
198
|
+
private scheduleFileCycle;
|
|
111
199
|
private handleFileChange;
|
|
112
200
|
start(): Promise<void>;
|
|
201
|
+
private handleFileAdd;
|
|
202
|
+
private handleFileUnlink;
|
|
113
203
|
close(): Promise<void>;
|
|
204
|
+
private closeInternal;
|
|
114
205
|
getTrackedFiles(): string[];
|
|
115
206
|
isCurrentlyRunning(): boolean;
|
|
207
|
+
isStartedProcessRunning(): boolean;
|
|
116
208
|
isDisposed(): boolean;
|
|
117
209
|
}
|
|
118
210
|
declare function steadyWatch(options: SteadyWatchOptions): SteadyWatcher;
|
|
119
211
|
|
|
212
|
+
declare const CLI_VERSION = "2.1.0";
|
|
213
|
+
declare function loadConfig(configPath?: string): Record<string, unknown>;
|
|
214
|
+
declare function mergeOptions(cliArgs: CliArgs, cliOpts: CliOptions, config: Record<string, unknown>): SteadyWatchOptions;
|
|
215
|
+
declare function parseCliArgs(argv?: string[]): {
|
|
216
|
+
args: CliArgs;
|
|
217
|
+
opts: CliOptions;
|
|
218
|
+
};
|
|
219
|
+
|
|
120
220
|
declare function runCli(): void;
|
|
121
221
|
|
|
122
|
-
export { type ChalkStyle, type CliArgs, type CliOptions, type HashAlgorithm, type NormalizedOptions, type SteadyWatchEvents, type SteadyWatchOptions, SteadyWatcher, type Theme, type ThemeName, type ValidationResult, getTheme, runCli, steadyWatch, themes };
|
|
222
|
+
export { CLI_VERSION, type ChalkStyle, type CliArgs, type CliOptions, type HashAlgorithm, type NormalizedOptions, type SteadyWatchEvents, type SteadyWatchHook, type SteadyWatchHookContext, type SteadyWatchHookPhase, type SteadyWatchHooks, type SteadyWatchOptions, SteadyWatcher, type Theme, type ThemeName, type ValidationResult, getTheme, loadConfig, mergeOptions, parseCliArgs, runCli, steadyWatch, themes };
|