From dfe0677cab7f3920e1c99cdb7979c880eaacf522 Mon Sep 17 00:00:00 2001 From: Juergen Kunz Date: Fri, 29 Aug 2025 21:10:01 +0000 Subject: [PATCH] fix(cli): Use server-side start-by-id flow for starting processes --- changelog.md | 7 +++++++ ts/00_commitinfo_data.ts | 2 +- ts/cli/commands/process/start.ts | 10 ++-------- ts/cli/index.ts | 17 +++++++++++++++++ ts/daemon/tspm.daemon.ts | 32 ++++++++++++++++++++++++++++++++ ts/shared/protocol/ipc.types.ts | 13 +++++++++++++ 6 files changed, 72 insertions(+), 9 deletions(-) diff --git a/changelog.md b/changelog.md index 2475ebb..3bbc9fb 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,12 @@ # Changelog +## 2025-08-29 - 4.4.1 - fix(cli) +Use server-side start-by-id flow for starting processes + +- CLI: 'tspm start ' now calls a new 'startById' IPC method instead of fetching the full config via 'describe' and submitting it back to 'start'. +- Daemon: Added server-side handler for 'startById' which resolves the stored process config and starts the process on the daemon. +- Protocol: Added StartByIdRequest/StartByIdResponse types and registered 'startById' in the IPC method map. + ## 2025-08-29 - 4.4.0 - feat(daemon) Persist desired process states and add daemon restart command diff --git a/ts/00_commitinfo_data.ts b/ts/00_commitinfo_data.ts index 363d4e3..d7eaac4 100644 --- a/ts/00_commitinfo_data.ts +++ b/ts/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@git.zone/tspm', - version: '4.4.0', + version: '4.4.1', description: 'a no fuzz process manager' } diff --git a/ts/cli/commands/process/start.ts b/ts/cli/commands/process/start.ts index 249f7a5..d8d0432 100644 --- a/ts/cli/commands/process/start.ts +++ b/ts/cli/commands/process/start.ts @@ -17,14 +17,8 @@ export function registerStartCommand(smartcli: plugins.smartcli.Smartcli) { return; } - const desc = await tspmIpcClient.request('describe', { id }).catch(() => null); - if (!desc) { - console.error(`Process with id '${id}' not found. Use 'tspm add' first.`); - return; - } - - console.log(`Starting process id ${id} (${desc.config.name || id})...`); - const response = await tspmIpcClient.request('start', { config: desc.config }); + console.log(`Starting process id ${id}...`); + const response = await tspmIpcClient.request('startById', { id }); console.log('✓ Process started'); console.log(` ID: ${response.processId}`); console.log(` PID: ${response.pid || 'N/A'}`); diff --git a/ts/cli/index.ts b/ts/cli/index.ts index b4809bf..2cedf86 100644 --- a/ts/cli/index.ts +++ b/ts/cli/index.ts @@ -1,4 +1,5 @@ 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'; @@ -38,6 +39,22 @@ export const run = async (): Promise => { } const smartcliInstance = new plugins.smartcli.Smartcli(); + // Intercept -v/--version to show CLI and daemon versions + const args = process.argv.slice(2); + if (args.includes('-v') || args.includes('--version')) { + const cliVersion = tspmProjectinfo.npm.version; + console.log(`tspm CLI: ${cliVersion}`); + const status = await tspmIpcClient.getDaemonStatus(); + if (status) { + console.log( + `Daemon: running v${status.version || 'unknown'} (pid ${status.pid})`, + ); + } else { + console.log('Daemon: not running'); + } + return; // do not start parser + } + // Keep Smartcli version info for help output but not used for -v now smartcliInstance.addVersion(tspmProjectinfo.npm.version); // Register all commands diff --git a/ts/daemon/tspm.daemon.ts b/ts/daemon/tspm.daemon.ts index ea3b34d..3faedc7 100644 --- a/ts/daemon/tspm.daemon.ts +++ b/ts/daemon/tspm.daemon.ts @@ -20,12 +20,20 @@ export class TspmDaemon { private socketPath: string; private heartbeatInterval: NodeJS.Timeout | null = null; private daemonPidFile: string; + private version: string; constructor() { 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(); + // Determine daemon version from package metadata + try { + const proj = new plugins.projectinfo.ProjectInfo(paths.packageDir); + this.version = proj.npm.version || 'unknown'; + } catch { + this.version = 'unknown'; + } } /** @@ -128,6 +136,29 @@ export class TspmDaemon { }, ); + // Start by id (resolve config on server) + this.ipcServer.onMessage( + 'startById', + async (request: RequestForMethod<'startById'>) => { + try { + const config = this.tspmInstance.processConfigs.get(request.id); + if (!config) { + throw new Error(`Process ${request.id} not found`); + } + await this.tspmInstance.setDesiredState(request.id, 'online'); + await this.tspmInstance.start(config); + const processInfo = this.tspmInstance.processInfo.get(request.id); + return { + processId: request.id, + pid: processInfo?.pid, + status: processInfo?.status || 'stopped', + }; + } catch (error) { + throw new Error(`Failed to start process: ${error.message}`); + } + }, + ); + this.ipcServer.onMessage( 'stop', async (request: RequestForMethod<'stop'>) => { @@ -321,6 +352,7 @@ export class TspmDaemon { processCount: this.tspmInstance.processes.size, memoryUsage: memUsage.heapUsed, cpuUsage: process.cpuUsage().user / 1000000, // Convert to seconds + version: this.version, }; }, ); diff --git a/ts/shared/protocol/ipc.types.ts b/ts/shared/protocol/ipc.types.ts index 9703450..82af1ff 100644 --- a/ts/shared/protocol/ipc.types.ts +++ b/ts/shared/protocol/ipc.types.ts @@ -66,6 +66,17 @@ export interface StartResponse { status: 'online' | 'stopped' | 'errored'; } +// Start by id (server resolves config) +export interface StartByIdRequest { + id: string; +} + +export interface StartByIdResponse { + processId: string; + pid?: number; + status: 'online' | 'stopped' | 'errored'; +} + // Stop command export interface StopRequest { id: string; @@ -191,6 +202,7 @@ export interface DaemonStatusResponse { processCount: number; memoryUsage?: number; cpuUsage?: number; + version?: string; } // Daemon shutdown command @@ -238,6 +250,7 @@ export interface RemoveResponse { // Type mappings for methods export type IpcMethodMap = { start: { request: StartRequest; response: StartResponse }; + startById: { request: StartByIdRequest; response: StartByIdResponse }; stop: { request: StopRequest; response: StopResponse }; restart: { request: RestartRequest; response: RestartResponse }; delete: { request: DeleteRequest; response: DeleteResponse };