Compare commits

...

5 Commits

Author SHA1 Message Date
b62e380750 fix(deps): bump smartshell ^3.3.5 (detached:true) and smartexit ^2.0.2
Some checks failed
Default (tags) / security (push) Successful in 36s
Default (tags) / test (push) Failing after 39s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2026-03-04 00:50:14 +00:00
0eef560f1d fix(deps): pin smartexit to ^2.0.1 and smartshell to ^3.3.4 for PID tracking
Some checks failed
Default (tags) / security (push) Successful in 33s
Default (tags) / test (push) Failing after 39s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2026-03-04 00:17:35 +00:00
f7f42ff36c fix(watcher): always tree-kill on stop regardless of childProcess.killed flag
Some checks failed
Default (tags) / security (push) Successful in 33s
Default (tags) / test (push) Failing after 39s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
The direct bash child may already be dead from terminal SIGINT while
grandchildren (tsrun, devserver) are still running. Removing the .killed
guard ensures tree-kill always runs to clean up the entire process tree.
2026-03-04 00:09:21 +00:00
77d2e6ee57 v3.2.2
Some checks failed
Default (tags) / security (push) Successful in 44s
Default (tags) / test (push) Failing after 4m3s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2026-03-03 23:43:39 +00:00
e8bd8da3c7 fix(lifecycle): use ProcessLifecycle for coordinated shutdown
Replace per-Watcher SIGINT handlers with a single ProcessLifecycle.install()
in TsWatch.start(). This eliminates competing signal handler races that left
orphaned child processes. Add @push.rocks/smartexit as direct dependency.
2026-03-03 23:43:26 +00:00
5 changed files with 1714 additions and 2748 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "@git.zone/tswatch",
"version": "3.2.1",
"version": "3.2.5",
"private": false,
"description": "A development tool for automatically watching and re-compiling TypeScript projects upon detecting file changes, enhancing developer workflows.",
"exports": {
@@ -31,11 +31,12 @@
"@push.rocks/npmextra": "^5.3.3",
"@push.rocks/smartcli": "^4.0.20",
"@push.rocks/smartdelay": "^3.0.5",
"@push.rocks/smartexit": "^2.0.2",
"@push.rocks/smartfs": "^1.3.1",
"@push.rocks/smartinteract": "^2.0.16",
"@push.rocks/smartlog": "^3.1.10",
"@push.rocks/smartlog-destination-local": "^9.0.2",
"@push.rocks/smartshell": "^3.3.2",
"@push.rocks/smartshell": "^3.3.5",
"@push.rocks/smartwatch": "^6.3.0",
"@push.rocks/taskbuffer": "^4.2.0"
},

4416
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -46,6 +46,14 @@ export class TsWatch {
public async start() {
logger.log('info', 'Starting tswatch with config-driven mode');
// Install global process lifecycle handlers (SIGINT, SIGTERM, etc.)
// This is the single authority for signal handling — no per-watcher handlers.
plugins.smartexit.ProcessLifecycle.install();
const exitInstance = new plugins.smartexit.SmartExit({ silent: true });
exitInstance.addCleanupFunction(async () => {
await this.stop();
});
// Start server if configured
if (this.config.server?.enabled) {
await this.startServer();

View File

@@ -181,34 +181,13 @@ export class Watcher {
}
/**
* this method sets up a clean exit strategy
* Sets up timeout-based cleanup if configured.
* Signal handling (SIGINT/SIGTERM) is managed globally by ProcessLifecycle in TsWatch.
*/
private async setupCleanup() {
// Last-resort synchronous cleanup — 'exit' event cannot await async work.
// By this point, SIGINT handler should have already called stop().
process.on('exit', () => {
if (this.currentExecution && !this.currentExecution.childProcess.killed) {
const pid = this.currentExecution.childProcess.pid;
if (pid) {
try {
process.kill(pid, 'SIGKILL');
} catch {
// Process may already be dead
}
}
}
});
process.on('SIGINT', async () => {
console.log('');
console.log('ok! got SIGINT We are exiting! Just cleaning up to exit neatly :)');
await this.stop();
process.exit(0);
});
// handle timeout
if (this.options.timeout) {
plugins.smartdelay.delayFor(this.options.timeout).then(async () => {
console.log(`timed out afer ${this.options.timeout} milliseconds! exiting!`);
console.log(`timed out after ${this.options.timeout} milliseconds! exiting!`);
await this.stop();
process.exit(0);
});
@@ -223,7 +202,9 @@ export class Watcher {
clearTimeout(this.debounceTimer);
}
await this.smartwatchInstance.stop();
if (this.currentExecution && !this.currentExecution.childProcess.killed) {
if (this.currentExecution) {
// Always tree-kill — even if the direct child is dead (.killed === true),
// grandchildren (e.g. tsrun, devserver) may still be running.
await this.currentExecution.kill();
}
}

View File

@@ -16,6 +16,7 @@ import * as lik from '@push.rocks/lik';
import * as npmextra from '@push.rocks/npmextra';
import * as smartcli from '@push.rocks/smartcli';
import * as smartdelay from '@push.rocks/smartdelay';
import * as smartexit from '@push.rocks/smartexit';
import * as smartfs from '@push.rocks/smartfs';
import * as smartinteract from '@push.rocks/smartinteract';
import * as smartlog from '@push.rocks/smartlog';
@@ -29,6 +30,7 @@ export {
npmextra,
smartcli,
smartdelay,
smartexit,
smartfs,
smartinteract,
smartlog,