feat(daemon): Reorganize and refactor core into client/daemon/shared modules; add IPC protocol and tests
This commit is contained in:
		
							
								
								
									
										12
									
								
								changelog.md
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								changelog.md
									
									
									
									
									
								
							@@ -1,5 +1,17 @@
 | 
			
		||||
# Changelog
 | 
			
		||||
 | 
			
		||||
## 2025-08-28 - 3.1.0 - feat(daemon)
 | 
			
		||||
Reorganize and refactor core into client/daemon/shared modules; add IPC protocol and tests
 | 
			
		||||
 | 
			
		||||
- Reorganized core code: split daemon and client logic into ts/daemon and ts/client directories
 | 
			
		||||
- Moved process management into ProcessManager, ProcessMonitor and ProcessWrapper under ts/daemon
 | 
			
		||||
- Added a dedicated IPC client and service manager under ts/client (tspm.ipcclient, tspm.servicemanager)
 | 
			
		||||
- Introduced shared protocol and error handling: ts/shared/protocol/ipc.types.ts, protocol.version.ts and ts/shared/common/utils.errorhandler.ts
 | 
			
		||||
- Updated CLI to import Logger from shared/common utils and updated related helpers
 | 
			
		||||
- Added daemon entrypoint at ts/daemon/index.ts and reorganized daemon startup/shutdown/heartbeat handling
 | 
			
		||||
- Added test assets (test/testassets/simple-test.ts, simple-script2.ts) and expanded test files under test/
 | 
			
		||||
- Removed legacy top-level class files (classes.*) in favor of the new structured layout
 | 
			
		||||
 | 
			
		||||
## 2025-08-28 - 3.0.2 - fix(daemon)
 | 
			
		||||
Ensure TSPM runtime dir exists and improve daemon startup/debug output
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,6 @@
 | 
			
		||||
 */
 | 
			
		||||
export const commitinfo = {
 | 
			
		||||
  name: '@git.zone/tspm',
 | 
			
		||||
  version: '3.0.2',
 | 
			
		||||
  version: '3.1.0',
 | 
			
		||||
  description: 'a no fuzz process manager'
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
import * as plugins from '../../../plugins.js';
 | 
			
		||||
import { tspmIpcClient } from '../../../classes.ipcclient.js';
 | 
			
		||||
import { tspmIpcClient } from '../../../client/tspm.ipcclient.js';
 | 
			
		||||
import type { CliArguments } from '../../types.js';
 | 
			
		||||
import { registerIpcCommand } from '../../registration/index.js';
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
import * as plugins from '../../../plugins.js';
 | 
			
		||||
import { tspmIpcClient } from '../../../classes.ipcclient.js';
 | 
			
		||||
import { tspmIpcClient } from '../../../client/tspm.ipcclient.js';
 | 
			
		||||
import type { CliArguments } from '../../types.js';
 | 
			
		||||
import { registerIpcCommand } from '../../registration/index.js';
 | 
			
		||||
import { pad } from '../../helpers/formatting.js';
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
import * as plugins from '../../../plugins.js';
 | 
			
		||||
import { tspmIpcClient } from '../../../classes.ipcclient.js';
 | 
			
		||||
import { tspmIpcClient } from '../../../client/tspm.ipcclient.js';
 | 
			
		||||
import type { CliArguments } from '../../types.js';
 | 
			
		||||
import { registerIpcCommand } from '../../registration/index.js';
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
import * as plugins from '../../../plugins.js';
 | 
			
		||||
import { tspmIpcClient } from '../../../classes.ipcclient.js';
 | 
			
		||||
import { tspmIpcClient } from '../../../client/tspm.ipcclient.js';
 | 
			
		||||
import type { IProcessConfig } from '../../../classes.tspm.js';
 | 
			
		||||
import type { CliArguments } from '../../types.js';
 | 
			
		||||
import { parseMemoryString, formatMemory } from '../../helpers/memory.js';
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
import * as plugins from '../../../plugins.js';
 | 
			
		||||
import { tspmIpcClient } from '../../../classes.ipcclient.js';
 | 
			
		||||
import { tspmIpcClient } from '../../../client/tspm.ipcclient.js';
 | 
			
		||||
import type { CliArguments } from '../../types.js';
 | 
			
		||||
import { registerIpcCommand } from '../../registration/index.js';
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
import * as plugins from '../plugins.js';
 | 
			
		||||
import * as paths from '../paths.js';
 | 
			
		||||
import { Logger, LogLevel } from '../utils.errorhandler.js';
 | 
			
		||||
import { Logger, LogLevel } from '../shared/common/utils.errorhandler.js';
 | 
			
		||||
 | 
			
		||||
// Import command registration functions
 | 
			
		||||
import { registerDefaultCommand } from './commands/default.js';
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										8
									
								
								ts/client/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								ts/client/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Client-side exports for TSPM
 | 
			
		||||
 * These are the only components that client applications should use
 | 
			
		||||
 * They only communicate with the daemon via IPC, never directly manage processes
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
export * from './tspm.ipcclient.js';
 | 
			
		||||
export * from './tspm.servicemanager.js';
 | 
			
		||||
@@ -1,11 +1,11 @@
 | 
			
		||||
import * as plugins from './plugins.js';
 | 
			
		||||
import * as paths from './paths.js';
 | 
			
		||||
import * as plugins from '../plugins.js';
 | 
			
		||||
import * as paths from '../paths.js';
 | 
			
		||||
 | 
			
		||||
import type {
 | 
			
		||||
  IpcMethodMap,
 | 
			
		||||
  RequestForMethod,
 | 
			
		||||
  ResponseForMethod,
 | 
			
		||||
} from './ipc.types.js';
 | 
			
		||||
} from '../shared/protocol/ipc.types.js';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * IPC client for communicating with the TSPM daemon
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
import * as plugins from './plugins.js';
 | 
			
		||||
import * as paths from './paths.js';
 | 
			
		||||
import * as plugins from '../plugins.js';
 | 
			
		||||
import * as paths from '../paths.js';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Manages TSPM daemon as a systemd service via smartdaemon
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
#!/usr/bin/env node
 | 
			
		||||
 | 
			
		||||
import { startDaemon } from './classes.daemon.js';
 | 
			
		||||
import { startDaemon } from './tspm.daemon.js';
 | 
			
		||||
 | 
			
		||||
// Start the daemon
 | 
			
		||||
startDaemon().catch((error) => {
 | 
			
		||||
@@ -1,19 +1,19 @@
 | 
			
		||||
import * as plugins from './plugins.js';
 | 
			
		||||
import * as plugins from '../plugins.js';
 | 
			
		||||
import { EventEmitter } from 'events';
 | 
			
		||||
import * as paths from './paths.js';
 | 
			
		||||
import * as paths from '../paths.js';
 | 
			
		||||
import {
 | 
			
		||||
  ProcessMonitor,
 | 
			
		||||
  type IMonitorConfig,
 | 
			
		||||
} from './classes.processmonitor.js';
 | 
			
		||||
import { type IProcessLog } from './classes.processwrapper.js';
 | 
			
		||||
import { TspmConfig } from './classes.config.js';
 | 
			
		||||
} from './processmonitor.js';
 | 
			
		||||
import { type IProcessLog } from './processwrapper.js';
 | 
			
		||||
import { TspmConfig } from './tspm.config.js';
 | 
			
		||||
import {
 | 
			
		||||
  Logger,
 | 
			
		||||
  ProcessError,
 | 
			
		||||
  ConfigError,
 | 
			
		||||
  ValidationError,
 | 
			
		||||
  handleError,
 | 
			
		||||
} from './utils.errorhandler.js';
 | 
			
		||||
} from '../shared/common/utils.errorhandler.js';
 | 
			
		||||
 | 
			
		||||
export interface IProcessConfig extends IMonitorConfig {
 | 
			
		||||
  id: string; // Unique identifier for the process
 | 
			
		||||
@@ -32,7 +32,7 @@ export interface IProcessInfo {
 | 
			
		||||
  restarts: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class Tspm extends EventEmitter {
 | 
			
		||||
export class ProcessManager extends EventEmitter {
 | 
			
		||||
  public processes: Map<string, ProcessMonitor> = new Map();
 | 
			
		||||
  public processConfigs: Map<string, IProcessConfig> = new Map();
 | 
			
		||||
  public processInfo: Map<string, IProcessInfo> = new Map();
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
import * as plugins from './plugins.js';
 | 
			
		||||
import * as plugins from '../plugins.js';
 | 
			
		||||
import { EventEmitter } from 'events';
 | 
			
		||||
import { ProcessWrapper, type IProcessLog } from './classes.processwrapper.js';
 | 
			
		||||
import { Logger, ProcessError, handleError } from './utils.errorhandler.js';
 | 
			
		||||
import { ProcessWrapper, type IProcessLog } from './processwrapper.js';
 | 
			
		||||
import { Logger, ProcessError, handleError } from '../shared/common/utils.errorhandler.js';
 | 
			
		||||
 | 
			
		||||
export interface IMonitorConfig {
 | 
			
		||||
  name?: string; // Optional name to identify the instance
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
import * as plugins from './plugins.js';
 | 
			
		||||
import * as plugins from '../plugins.js';
 | 
			
		||||
import { EventEmitter } from 'events';
 | 
			
		||||
import { Logger, ProcessError, handleError } from './utils.errorhandler.js';
 | 
			
		||||
import { Logger, ProcessError, handleError } from '../shared/common/utils.errorhandler.js';
 | 
			
		||||
 | 
			
		||||
export interface IProcessWrapperOptions {
 | 
			
		||||
  command: string;
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
import * as plugins from './plugins.js';
 | 
			
		||||
import * as plugins from '../plugins.js';
 | 
			
		||||
 | 
			
		||||
export class TspmConfig {
 | 
			
		||||
  public npmextraInstance = new plugins.npmextra.KeyValueStore({
 | 
			
		||||
@@ -1,19 +1,19 @@
 | 
			
		||||
import * as plugins from './plugins.js';
 | 
			
		||||
import * as paths from './paths.js';
 | 
			
		||||
import { Tspm } from './classes.tspm.js';
 | 
			
		||||
import * as plugins from '../plugins.js';
 | 
			
		||||
import * as paths from '../paths.js';
 | 
			
		||||
import { ProcessManager } from './processmanager.js';
 | 
			
		||||
import type {
 | 
			
		||||
  IpcMethodMap,
 | 
			
		||||
  RequestForMethod,
 | 
			
		||||
  ResponseForMethod,
 | 
			
		||||
  DaemonStatusResponse,
 | 
			
		||||
  HeartbeatResponse,
 | 
			
		||||
} from './ipc.types.js';
 | 
			
		||||
} from '../shared/protocol/ipc.types.js';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Central daemon server that manages all TSPM processes
 | 
			
		||||
 */
 | 
			
		||||
export class TspmDaemon {
 | 
			
		||||
  private tspmInstance: Tspm;
 | 
			
		||||
  private tspmInstance: ProcessManager;
 | 
			
		||||
  private ipcServer: plugins.smartipc.IpcServer;
 | 
			
		||||
  private startTime: number;
 | 
			
		||||
  private isShuttingDown: boolean = false;
 | 
			
		||||
@@ -22,7 +22,7 @@ export class TspmDaemon {
 | 
			
		||||
  private daemonPidFile: string;
 | 
			
		||||
 | 
			
		||||
  constructor() {
 | 
			
		||||
    this.tspmInstance = new Tspm();
 | 
			
		||||
    this.tspmInstance = new ProcessManager();
 | 
			
		||||
    this.socketPath = plugins.path.join(paths.tspmDir, 'tspm.sock');
 | 
			
		||||
    this.daemonPidFile = plugins.path.join(paths.tspmDir, 'daemon.pid');
 | 
			
		||||
    this.startTime = Date.now();
 | 
			
		||||
							
								
								
									
										26
									
								
								ts/shared/protocol/error.codes.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								ts/shared/protocol/error.codes.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Standardized error codes for IPC communication
 | 
			
		||||
 * These are used instead of string messages for better error handling
 | 
			
		||||
 */
 | 
			
		||||
export enum ErrorCode {
 | 
			
		||||
  // General errors
 | 
			
		||||
  UNKNOWN_ERROR = 'UNKNOWN_ERROR',
 | 
			
		||||
  INVALID_REQUEST = 'INVALID_REQUEST',
 | 
			
		||||
  
 | 
			
		||||
  // Process errors
 | 
			
		||||
  PROCESS_NOT_FOUND = 'PROCESS_NOT_FOUND',
 | 
			
		||||
  PROCESS_ALREADY_EXISTS = 'PROCESS_ALREADY_EXISTS',
 | 
			
		||||
  PROCESS_START_FAILED = 'PROCESS_START_FAILED',
 | 
			
		||||
  PROCESS_STOP_FAILED = 'PROCESS_STOP_FAILED',
 | 
			
		||||
  
 | 
			
		||||
  // Daemon errors
 | 
			
		||||
  DAEMON_NOT_RUNNING = 'DAEMON_NOT_RUNNING',
 | 
			
		||||
  DAEMON_ALREADY_RUNNING = 'DAEMON_ALREADY_RUNNING',
 | 
			
		||||
  
 | 
			
		||||
  // Memory errors
 | 
			
		||||
  MEMORY_LIMIT_EXCEEDED = 'MEMORY_LIMIT_EXCEEDED',
 | 
			
		||||
  
 | 
			
		||||
  // Config errors
 | 
			
		||||
  CONFIG_INVALID = 'CONFIG_INVALID',
 | 
			
		||||
  CONFIG_SAVE_FAILED = 'CONFIG_SAVE_FAILED',
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										5
									
								
								ts/shared/protocol/protocol.version.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								ts/shared/protocol/protocol.version.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Protocol version for client-daemon communication
 | 
			
		||||
 * This allows for version compatibility checks between client and daemon
 | 
			
		||||
 */
 | 
			
		||||
export const PROTOCOL_VERSION = '1.0.0';
 | 
			
		||||
		Reference in New Issue
	
	Block a user