feat(daemon): Add CLI systemd service refresh on version mismatch and fix daemon memory leak; update dependencies
This commit is contained in:
		@@ -1,5 +1,14 @@
 | 
			
		||||
# Changelog
 | 
			
		||||
 | 
			
		||||
## 2025-08-30 - 5.4.0 - feat(daemon)
 | 
			
		||||
Add CLI systemd service refresh on version mismatch and fix daemon memory leak; update dependencies
 | 
			
		||||
 | 
			
		||||
- CLI: when client and daemon versions differ, prompt to refresh the systemd service and optionally disable/enable the service automatically
 | 
			
		||||
- Daemon: clear pidusage state for PIDs on process exit/stop to prevent memory leaks in long-running monitors
 | 
			
		||||
- Client: expose smartdaemon in client plugin exports and fix import path for tspm.servicemanager
 | 
			
		||||
- Package: tighten dependency ranges (set specific versions) and add @types for pidusage and ps-tree
 | 
			
		||||
- Misc: ensure IPC disconnects and PID/socket handling improvements were integrated alongside the above changes
 | 
			
		||||
 | 
			
		||||
## 2025-08-30 - 5.3.2 - fix(daemon)
 | 
			
		||||
Improve daemon log delivery and process monitor memory accounting; gate debug output and update tests to numeric ProcessId
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -40,6 +40,8 @@
 | 
			
		||||
    "@push.rocks/smartinteract": "^2.0.16",
 | 
			
		||||
    "@push.rocks/smartipc": "^2.2.2",
 | 
			
		||||
    "@push.rocks/smartpath": "^6.0.0",
 | 
			
		||||
    "@types/pidusage": "^2.0.5",
 | 
			
		||||
    "@types/ps-tree": "^1.1.6",
 | 
			
		||||
    "pidusage": "^4.0.1",
 | 
			
		||||
    "ps-tree": "^1.2.0",
 | 
			
		||||
    "tsx": "^4.20.5"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										16
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
								
							@@ -32,6 +32,12 @@ importers:
 | 
			
		||||
      '@push.rocks/smartpath':
 | 
			
		||||
        specifier: ^6.0.0
 | 
			
		||||
        version: 6.0.0
 | 
			
		||||
      '@types/pidusage':
 | 
			
		||||
        specifier: ^2.0.5
 | 
			
		||||
        version: 2.0.5
 | 
			
		||||
      '@types/ps-tree':
 | 
			
		||||
        specifier: ^1.1.6
 | 
			
		||||
        version: 1.1.6
 | 
			
		||||
      pidusage:
 | 
			
		||||
        specifier: ^4.0.1
 | 
			
		||||
        version: 4.0.1
 | 
			
		||||
@@ -1647,9 +1653,15 @@ packages:
 | 
			
		||||
  '@types/parse5@6.0.3':
 | 
			
		||||
    resolution: {integrity: sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g==}
 | 
			
		||||
 | 
			
		||||
  '@types/pidusage@2.0.5':
 | 
			
		||||
    resolution: {integrity: sha512-MIiyZI4/MK9UGUXWt0jJcCZhVw7YdhBuTOuqP/BjuLDLZ2PmmViMIQgZiWxtaMicQfAz/kMrZ5T7PKxFSkTeUA==}
 | 
			
		||||
 | 
			
		||||
  '@types/ping@0.4.4':
 | 
			
		||||
    resolution: {integrity: sha512-ifvo6w2f5eJYlXm+HiVx67iJe8WZp87sfa683nlqED5Vnt9Z93onkokNoWqOG21EaE8fMxyKPobE+mkPEyxsdw==}
 | 
			
		||||
 | 
			
		||||
  '@types/ps-tree@1.1.6':
 | 
			
		||||
    resolution: {integrity: sha512-PtrlVaOaI44/3pl3cvnlK+GxOM3re2526TJvPvh7W+keHIXdV4TE0ylpPBAcvFQCbGitaTXwL9u+RF7qtVeazQ==}
 | 
			
		||||
 | 
			
		||||
  '@types/qs@6.14.0':
 | 
			
		||||
    resolution: {integrity: sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==}
 | 
			
		||||
 | 
			
		||||
@@ -7592,8 +7604,12 @@ snapshots:
 | 
			
		||||
 | 
			
		||||
  '@types/parse5@6.0.3': {}
 | 
			
		||||
 | 
			
		||||
  '@types/pidusage@2.0.5': {}
 | 
			
		||||
 | 
			
		||||
  '@types/ping@0.4.4': {}
 | 
			
		||||
 | 
			
		||||
  '@types/ps-tree@1.1.6': {}
 | 
			
		||||
 | 
			
		||||
  '@types/qs@6.14.0': {}
 | 
			
		||||
 | 
			
		||||
  '@types/randomatic@3.1.5': {}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,6 @@
 | 
			
		||||
 */
 | 
			
		||||
export const commitinfo = {
 | 
			
		||||
  name: '@git.zone/tspm',
 | 
			
		||||
  version: '5.3.2',
 | 
			
		||||
  version: '5.4.0',
 | 
			
		||||
  description: 'a no fuzz process manager'
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@ import * as plugins from './plugins.js';
 | 
			
		||||
import { tspmIpcClient } from '../client/tspm.ipcclient.js';
 | 
			
		||||
import * as paths from '../paths.js';
 | 
			
		||||
import { Logger, LogLevel } from '../shared/common/utils.errorhandler.js';
 | 
			
		||||
import { TspmServiceManager } from '../client/tspm.servicemanager.js';
 | 
			
		||||
 | 
			
		||||
// Import command registration functions
 | 
			
		||||
import { registerDefaultCommand } from './commands/default.js';
 | 
			
		||||
@@ -51,6 +52,38 @@ export const run = async (): Promise<void> => {
 | 
			
		||||
      console.log(
 | 
			
		||||
        `Daemon: running v${status.version || 'unknown'} (pid ${status.pid})`,
 | 
			
		||||
      );
 | 
			
		||||
      // If versions mismatch, offer to refresh the systemd service
 | 
			
		||||
      if (status.version && status.version !== cliVersion) {
 | 
			
		||||
        console.log('\nVersion mismatch detected:');
 | 
			
		||||
        console.log(`  CLI:    v${cliVersion}`);
 | 
			
		||||
        console.log(`  Daemon: v${status.version}`);
 | 
			
		||||
        console.log(
 | 
			
		||||
          '\nThis can happen after upgrading tspm. The systemd service may still point to an older version.\n' +
 | 
			
		||||
            'You can refresh the service (equivalent to "tspm disable" then "tspm enable").',
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        // Ask the user for confirmation
 | 
			
		||||
        const confirm = await plugins.smartinteract.SmartInteract.getCliConfirmation(
 | 
			
		||||
          'Refresh the systemd service now?',
 | 
			
		||||
          true,
 | 
			
		||||
        );
 | 
			
		||||
        if (confirm) {
 | 
			
		||||
          try {
 | 
			
		||||
            const sm = new TspmServiceManager();
 | 
			
		||||
            console.log('Refreshing TSPM system service...');
 | 
			
		||||
            await sm.disableService();
 | 
			
		||||
            await sm.enableService();
 | 
			
		||||
            console.log('✓ Service refreshed. Daemon restarted via systemd.');
 | 
			
		||||
          } catch (err: any) {
 | 
			
		||||
            console.error(
 | 
			
		||||
              'Failed to refresh service automatically. You can try manually:\n  tspm disable && tspm enable',
 | 
			
		||||
            );
 | 
			
		||||
            console.error(err?.message || String(err));
 | 
			
		||||
          }
 | 
			
		||||
        } else {
 | 
			
		||||
          console.log('Skipped service refresh.');
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      console.log('Daemon: not running');
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
// Minimal plugin set for lightweight client startup
 | 
			
		||||
import * as path from 'node:path';
 | 
			
		||||
import * as smartdaemon from '@push.rocks/smartdaemon';
 | 
			
		||||
import * as smartipc from '@push.rocks/smartipc';
 | 
			
		||||
 | 
			
		||||
export { path, smartipc };
 | 
			
		||||
export { path, smartdaemon, smartipc };
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
import * as plugins from '../plugins.js';
 | 
			
		||||
import * as plugins from './plugins.js';
 | 
			
		||||
import * as paths from '../paths.js';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
@@ -139,6 +139,14 @@ export class ProcessMonitor extends EventEmitter {
 | 
			
		||||
        this.logger.info(exitMsg);
 | 
			
		||||
        this.log(exitMsg);
 | 
			
		||||
        
 | 
			
		||||
        // Clear pidusage internal state for this PID to prevent memory leaks
 | 
			
		||||
        try {
 | 
			
		||||
          const pidToClear = this.processWrapper?.getPid();
 | 
			
		||||
          if (pidToClear) {
 | 
			
		||||
            (plugins.pidusage as any)?.clear?.(pidToClear);
 | 
			
		||||
          }
 | 
			
		||||
        } catch {}
 | 
			
		||||
        
 | 
			
		||||
        // Flush logs to disk on exit
 | 
			
		||||
        if (this.processId && this.logs.length > 0) {
 | 
			
		||||
          try {
 | 
			
		||||
@@ -385,6 +393,13 @@ export class ProcessMonitor extends EventEmitter {
 | 
			
		||||
      clearInterval(this.intervalId);
 | 
			
		||||
    }
 | 
			
		||||
    if (this.processWrapper) {
 | 
			
		||||
      // Clear pidusage state for current PID before stopping to avoid leaks
 | 
			
		||||
      try {
 | 
			
		||||
        const pidToClear = this.processWrapper.getPid();
 | 
			
		||||
        if (pidToClear) {
 | 
			
		||||
          (plugins.pidusage as any)?.clear?.(pidToClear);
 | 
			
		||||
        }
 | 
			
		||||
      } catch {}
 | 
			
		||||
      this.processWrapper.stop();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user