From cbea3f61877d4ec191798bd88d576aba88471f81 Mon Sep 17 00:00:00 2001 From: Juergen Kunz Date: Fri, 29 Aug 2025 16:52:00 +0000 Subject: [PATCH] feat(cli): Correct CLI plugin imports and add reset command/IPC to stop processes and clear persisted configs --- changelog.md | 10 +++++++ ts/00_commitinfo_data.ts | 2 +- ts/cli/commands/batch/restart-all.ts | 2 +- ts/cli/commands/batch/start-all.ts | 2 +- ts/cli/commands/batch/stop-all.ts | 2 +- ts/cli/commands/daemon/index.ts | 2 +- ts/cli/commands/default.ts | 2 +- ts/cli/commands/process/add.ts | 3 +- ts/cli/commands/process/delete.ts | 2 +- ts/cli/commands/process/describe.ts | 2 +- ts/cli/commands/process/list.ts | 2 +- ts/cli/commands/process/logs.ts | 2 +- ts/cli/commands/process/restart.ts | 2 +- ts/cli/commands/process/start.ts | 2 +- ts/cli/commands/process/stop.ts | 2 +- ts/cli/commands/reset.ts | 35 ++++++---------------- ts/cli/commands/service/disable.ts | 2 +- ts/cli/commands/service/enable.ts | 2 +- ts/cli/index.ts | 2 +- ts/cli/plugins.ts | 8 ++++++ ts/cli/registration/index.ts | 2 +- ts/daemon/processmanager.ts | 43 ++++++++++++++++++++++++++++ ts/daemon/tspm.daemon.ts | 9 ++++++ ts/shared/protocol/ipc.types.ts | 15 ++++++++++ 24 files changed, 112 insertions(+), 45 deletions(-) create mode 100644 ts/cli/plugins.ts diff --git a/changelog.md b/changelog.md index 00c151f..150c7ac 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,15 @@ # Changelog +## 2025-08-29 - 4.3.0 - feat(cli) +Correct CLI plugin imports and add reset command/IPC to stop processes and clear persisted configs + +- Fixed relative plugin imports in many CLI command modules to use the local CLI plugin wrapper (reduces startup surface and fixes import paths). +- Added a lightweight ts/cli/plugins.ts that exposes only the minimal plugin set used by the CLI. +- Implemented ProcessManager.reset(): stops running processes, collects per-id stop errors, clears in-memory maps and removes persisted configurations (with fallback to write an empty list on delete failure). +- Daemon now exposes a 'reset' IPC handler that delegates to ProcessManager.reset() so CLI can perform a single RPC to reset TSPM state. +- Updated shared IPC protocol types to include ResetRequest and ResetResponse. +- Refactored the CLI reset command to call the new 'reset' RPC (replaces previous stopAll + per-config removal logic). + ## 2025-08-29 - 4.2.0 - feat(cli) Add 'reset' CLI command to stop all processes and clear saved configurations; integrate interactive confirmation and client plugin updates diff --git a/ts/00_commitinfo_data.ts b/ts/00_commitinfo_data.ts index 723c128..e173902 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.2.0', + version: '4.3.0', description: 'a no fuzz process manager' } diff --git a/ts/cli/commands/batch/restart-all.ts b/ts/cli/commands/batch/restart-all.ts index 75134bc..4a16efa 100644 --- a/ts/cli/commands/batch/restart-all.ts +++ b/ts/cli/commands/batch/restart-all.ts @@ -1,4 +1,4 @@ -import * as plugins from '../../../plugins.js'; +import * as plugins from '../../plugins.js'; import { tspmIpcClient } from '../../../client/tspm.ipcclient.js'; import type { CliArguments } from '../../types.js'; import { registerIpcCommand } from '../../registration/index.js'; diff --git a/ts/cli/commands/batch/start-all.ts b/ts/cli/commands/batch/start-all.ts index 93ed7bf..fb22d30 100644 --- a/ts/cli/commands/batch/start-all.ts +++ b/ts/cli/commands/batch/start-all.ts @@ -1,4 +1,4 @@ -import * as plugins from '../../../plugins.js'; +import * as plugins from '../../plugins.js'; import { tspmIpcClient } from '../../../client/tspm.ipcclient.js'; import type { CliArguments } from '../../types.js'; import { registerIpcCommand } from '../../registration/index.js'; diff --git a/ts/cli/commands/batch/stop-all.ts b/ts/cli/commands/batch/stop-all.ts index 4d08018..d5f7ff9 100644 --- a/ts/cli/commands/batch/stop-all.ts +++ b/ts/cli/commands/batch/stop-all.ts @@ -1,4 +1,4 @@ -import * as plugins from '../../../plugins.js'; +import * as plugins from '../../plugins.js'; import { tspmIpcClient } from '../../../client/tspm.ipcclient.js'; import type { CliArguments } from '../../types.js'; import { registerIpcCommand } from '../../registration/index.js'; diff --git a/ts/cli/commands/daemon/index.ts b/ts/cli/commands/daemon/index.ts index 3c7ba45..4fa3bd9 100644 --- a/ts/cli/commands/daemon/index.ts +++ b/ts/cli/commands/daemon/index.ts @@ -1,4 +1,4 @@ -import * as plugins from '../../../plugins.js'; +import * as plugins from '../../plugins.js'; import * as paths from '../../../paths.js'; import { tspmIpcClient } from '../../../client/tspm.ipcclient.js'; import { Logger } from '../../../shared/common/utils.errorhandler.js'; diff --git a/ts/cli/commands/default.ts b/ts/cli/commands/default.ts index 4bd6122..26f7ec6 100644 --- a/ts/cli/commands/default.ts +++ b/ts/cli/commands/default.ts @@ -1,4 +1,4 @@ -import * as plugins from '../../plugins.js'; +import * as plugins from '../plugins.js'; import * as paths from '../../paths.js'; import { tspmIpcClient } from '../../client/tspm.ipcclient.js'; import { Logger } from '../../shared/common/utils.errorhandler.js'; diff --git a/ts/cli/commands/process/add.ts b/ts/cli/commands/process/add.ts index fc8a9fe..df5478a 100644 --- a/ts/cli/commands/process/add.ts +++ b/ts/cli/commands/process/add.ts @@ -1,4 +1,4 @@ -import * as plugins from '../../../plugins.js'; +import * as plugins from '../../plugins.js'; import { tspmIpcClient } from '../../../client/tspm.ipcclient.js'; import type { CliArguments } from '../../types.js'; import { parseMemoryString, formatMemory } from '../../helpers/memory.js'; @@ -88,4 +88,3 @@ export function registerAddCommand(smartcli: plugins.smartcli.Smartcli) { { actionLabel: 'add process config' }, ); } - diff --git a/ts/cli/commands/process/delete.ts b/ts/cli/commands/process/delete.ts index 6bfe2e1..d70ea6d 100644 --- a/ts/cli/commands/process/delete.ts +++ b/ts/cli/commands/process/delete.ts @@ -1,4 +1,4 @@ -import * as plugins from '../../../plugins.js'; +import * as plugins from '../../plugins.js'; import { tspmIpcClient } from '../../../client/tspm.ipcclient.js'; import type { CliArguments } from '../../types.js'; import { registerIpcCommand } from '../../registration/index.js'; diff --git a/ts/cli/commands/process/describe.ts b/ts/cli/commands/process/describe.ts index 8994195..6a080ba 100644 --- a/ts/cli/commands/process/describe.ts +++ b/ts/cli/commands/process/describe.ts @@ -1,4 +1,4 @@ -import * as plugins from '../../../plugins.js'; +import * as plugins from '../../plugins.js'; import { tspmIpcClient } from '../../../client/tspm.ipcclient.js'; import type { CliArguments } from '../../types.js'; import { registerIpcCommand } from '../../registration/index.js'; diff --git a/ts/cli/commands/process/list.ts b/ts/cli/commands/process/list.ts index da95671..eab488d 100644 --- a/ts/cli/commands/process/list.ts +++ b/ts/cli/commands/process/list.ts @@ -1,4 +1,4 @@ -import * as plugins from '../../../plugins.js'; +import * as plugins from '../../plugins.js'; import { tspmIpcClient } from '../../../client/tspm.ipcclient.js'; import type { CliArguments } from '../../types.js'; import { registerIpcCommand } from '../../registration/index.js'; diff --git a/ts/cli/commands/process/logs.ts b/ts/cli/commands/process/logs.ts index 2e3322b..07862c5 100644 --- a/ts/cli/commands/process/logs.ts +++ b/ts/cli/commands/process/logs.ts @@ -1,4 +1,4 @@ -import * as plugins from '../../../plugins.js'; +import * as plugins from '../../plugins.js'; import { tspmIpcClient } from '../../../client/tspm.ipcclient.js'; import type { CliArguments } from '../../types.js'; import { registerIpcCommand } from '../../registration/index.js'; diff --git a/ts/cli/commands/process/restart.ts b/ts/cli/commands/process/restart.ts index 6b1703d..097f093 100644 --- a/ts/cli/commands/process/restart.ts +++ b/ts/cli/commands/process/restart.ts @@ -1,4 +1,4 @@ -import * as plugins from '../../../plugins.js'; +import * as plugins from '../../plugins.js'; import { tspmIpcClient } from '../../../client/tspm.ipcclient.js'; import type { CliArguments } from '../../types.js'; import { registerIpcCommand } from '../../registration/index.js'; diff --git a/ts/cli/commands/process/start.ts b/ts/cli/commands/process/start.ts index d83dfe5..249f7a5 100644 --- a/ts/cli/commands/process/start.ts +++ b/ts/cli/commands/process/start.ts @@ -1,4 +1,4 @@ -import * as plugins from '../../../plugins.js'; +import * as plugins from '../../plugins.js'; import { tspmIpcClient } from '../../../client/tspm.ipcclient.js'; import type { IProcessConfig } from '../../../shared/protocol/ipc.types.js'; import type { CliArguments } from '../../types.js'; diff --git a/ts/cli/commands/process/stop.ts b/ts/cli/commands/process/stop.ts index 0ec0ef4..56e00b9 100644 --- a/ts/cli/commands/process/stop.ts +++ b/ts/cli/commands/process/stop.ts @@ -1,4 +1,4 @@ -import * as plugins from '../../../plugins.js'; +import * as plugins from '../../plugins.js'; import { tspmIpcClient } from '../../../client/tspm.ipcclient.js'; import type { CliArguments } from '../../types.js'; import { registerIpcCommand } from '../../registration/index.js'; diff --git a/ts/cli/commands/reset.ts b/ts/cli/commands/reset.ts index b0524b9..b9269ba 100644 --- a/ts/cli/commands/reset.ts +++ b/ts/cli/commands/reset.ts @@ -1,4 +1,4 @@ -import * as plugins from '../../plugins.js'; +import * as plugins from '../plugins.js'; import { registerIpcCommand } from '../registration/index.js'; import { tspmIpcClient } from '../../client/tspm.ipcclient.js'; @@ -18,33 +18,16 @@ export function registerResetCommand(smartcli: plugins.smartcli.Smartcli) { return; } - // Stop all processes first - const stopAllRes = await tspmIpcClient.request('stopAll', {}); - if (stopAllRes.failed.length) { - console.log( - `Stopped ${stopAllRes.stopped.length}, ${stopAllRes.failed.length} failed to stop. Proceeding with config reset...`, - ); - } else { - console.log(`Stopped ${stopAllRes.stopped.length} processes.`); + // Single IPC call to reset + const result = await tspmIpcClient.request('reset', {}); + const failedCount = result.failed.length; + console.log(`Stopped ${result.stopped.length} processes.`); + if (failedCount) { + console.log(`${failedCount} processes failed to stop (configs cleared anyway).`); } - - // List all processes/configs currently known - const listRes = await tspmIpcClient.request('list', {}); - - // Remove each config - for (const proc of listRes.processes) { - try { - // Prefer 'remove' which handles stop-if-running semantics as well - await tspmIpcClient.request('remove', { id: proc.id }); - console.log(`Removed config for process ${proc.id}.`); - } catch (err) { - console.error(`Failed to remove config for ${proc.id}:`, (err as Error)?.message || String(err)); - } - } - - console.log('TSPM has been reset: processes stopped and configs cleared.'); + console.log(`Cleared ${result.removed.length} saved configurations.`); + console.log('TSPM has been reset.'); }, { actionLabel: 'reset TSPM' }, ); } - diff --git a/ts/cli/commands/service/disable.ts b/ts/cli/commands/service/disable.ts index f55f66f..45c7ea7 100644 --- a/ts/cli/commands/service/disable.ts +++ b/ts/cli/commands/service/disable.ts @@ -1,4 +1,4 @@ -import * as plugins from '../../../plugins.js'; +import * as plugins from '../../plugins.js'; import { TspmServiceManager } from '../../../client/tspm.servicemanager.js'; import { Logger } from '../../../shared/common/utils.errorhandler.js'; import type { CliArguments } from '../../types.js'; diff --git a/ts/cli/commands/service/enable.ts b/ts/cli/commands/service/enable.ts index 91767b6..a373d79 100644 --- a/ts/cli/commands/service/enable.ts +++ b/ts/cli/commands/service/enable.ts @@ -1,4 +1,4 @@ -import * as plugins from '../../../plugins.js'; +import * as plugins from '../../plugins.js'; import { TspmServiceManager } from '../../../client/tspm.servicemanager.js'; import { Logger } from '../../../shared/common/utils.errorhandler.js'; import type { CliArguments } from '../../types.js'; diff --git a/ts/cli/index.ts b/ts/cli/index.ts index 894db79..b4809bf 100644 --- a/ts/cli/index.ts +++ b/ts/cli/index.ts @@ -1,4 +1,4 @@ -import * as plugins from '../plugins.js'; +import * as plugins from './plugins.js'; import * as paths from '../paths.js'; import { Logger, LogLevel } from '../shared/common/utils.errorhandler.js'; diff --git a/ts/cli/plugins.ts b/ts/cli/plugins.ts new file mode 100644 index 0000000..e646786 --- /dev/null +++ b/ts/cli/plugins.ts @@ -0,0 +1,8 @@ +// Minimal plugin set for the CLI to keep startup light +import * as path from 'node:path'; +import * as projectinfo from '@push.rocks/projectinfo'; +import * as smartcli from '@push.rocks/smartcli'; +import * as smartinteract from '@push.rocks/smartinteract'; + +export { path, projectinfo, smartcli, smartinteract }; + diff --git a/ts/cli/registration/index.ts b/ts/cli/registration/index.ts index 029b5f4..03ca4f4 100644 --- a/ts/cli/registration/index.ts +++ b/ts/cli/registration/index.ts @@ -1,4 +1,4 @@ -import * as plugins from '../../plugins.js'; +import * as plugins from '../plugins.js'; import type { CliArguments, CommandAction, diff --git a/ts/daemon/processmanager.ts b/ts/daemon/processmanager.ts index 800d18b..488feaf 100644 --- a/ts/daemon/processmanager.ts +++ b/ts/daemon/processmanager.ts @@ -470,4 +470,47 @@ export class ProcessManager extends EventEmitter { ); } } + + /** + * Reset: stop all running processes and clear all saved configurations + */ + public async reset(): Promise<{ + stopped: string[]; + removed: string[]; + failed: Array<{ id: string; error: string }>; + }> { + this.logger.info('Resetting TSPM: stopping all processes and clearing configs'); + + const removed = Array.from(this.processConfigs.keys()); + const stopped: string[] = []; + const failed: Array<{ id: string; error: string }> = []; + + // Attempt to stop all currently running processes with per-id error collection + for (const id of Array.from(this.processes.keys())) { + try { + await this.stop(id); + stopped.push(id); + } catch (error: any) { + failed.push({ id, error: error?.message || String(error) }); + } + } + + // Clear in-memory maps regardless of stop outcomes + this.processes.clear(); + this.processInfo.clear(); + this.processConfigs.clear(); + + // Remove persisted configs + try { + await this.config.deleteKey(this.configStorageKey); + this.logger.debug('Cleared persisted process configurations'); + } catch (error) { + // Fallback: write empty list if deleteKey fails for any reason + this.logger.warn('deleteKey failed, writing empty process list instead'); + await this.saveProcessConfigs().catch(() => {}); + } + + this.logger.info('TSPM reset complete'); + return { stopped, removed, failed }; + } } diff --git a/ts/daemon/tspm.daemon.ts b/ts/daemon/tspm.daemon.ts index c2be9b2..92e9307 100644 --- a/ts/daemon/tspm.daemon.ts +++ b/ts/daemon/tspm.daemon.ts @@ -293,6 +293,15 @@ export class TspmDaemon { }, ); + // Reset handler: stops all and clears configs + this.ipcServer.onMessage( + 'reset', + async (request: RequestForMethod<'reset'>) => { + const result = await this.tspmInstance.reset(); + return result; + }, + ); + // Daemon management handlers this.ipcServer.onMessage( 'daemon:status', diff --git a/ts/shared/protocol/ipc.types.ts b/ts/shared/protocol/ipc.types.ts index 6f2c5c3..9703450 100644 --- a/ts/shared/protocol/ipc.types.ts +++ b/ts/shared/protocol/ipc.types.ts @@ -165,6 +165,20 @@ export interface RestartAllResponse { }>; } +// Reset command (stop all and clear configs) +export interface ResetRequest { + // No parameters needed +} + +export interface ResetResponse { + stopped: string[]; + removed: string[]; + failed: Array<{ + id: string; + error: string; + }>; +} + // Daemon status command export interface DaemonStatusRequest { // No parameters needed @@ -235,6 +249,7 @@ export type IpcMethodMap = { startAll: { request: StartAllRequest; response: StartAllResponse }; stopAll: { request: StopAllRequest; response: StopAllResponse }; restartAll: { request: RestartAllRequest; response: RestartAllResponse }; + reset: { request: ResetRequest; response: ResetResponse }; 'daemon:status': { request: DaemonStatusRequest; response: DaemonStatusResponse;