feat(cli): Add interactive edit command and update support for process configurations
This commit is contained in:
@@ -76,6 +76,9 @@ export function registerAddCommand(smartcli: plugins.smartcli.Smartcli) {
|
||||
args: cmdArgs,
|
||||
projectDir,
|
||||
memoryLimitBytes: memoryLimit,
|
||||
// Persist the PATH from the current CLI environment so managed
|
||||
// processes see the same PATH they had when added.
|
||||
env: { PATH: process.env.PATH || '' },
|
||||
autorestart,
|
||||
watch,
|
||||
watchPaths,
|
||||
|
117
ts/cli/commands/process/edit.ts
Normal file
117
ts/cli/commands/process/edit.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
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';
|
||||
import { formatMemory, parseMemoryString } from '../../helpers/memory.js';
|
||||
|
||||
export function registerEditCommand(smartcli: plugins.smartcli.Smartcli) {
|
||||
registerIpcCommand(
|
||||
smartcli,
|
||||
'edit',
|
||||
async (argvArg: CliArguments) => {
|
||||
const idRaw = argvArg._[1];
|
||||
if (!idRaw) {
|
||||
console.error('Error: Please provide a process ID to edit');
|
||||
console.log('Usage: tspm edit <id>');
|
||||
return;
|
||||
}
|
||||
|
||||
const id = idRaw;
|
||||
|
||||
// Load current config
|
||||
const { config } = await tspmIpcClient.request('describe', { id });
|
||||
|
||||
const si = plugins.smartinteract;
|
||||
|
||||
const answers: any = {};
|
||||
answers.name = await si.question.text(
|
||||
`Name [${config.name || ''}]`,
|
||||
config.name || '',
|
||||
);
|
||||
answers.command = await si.question.text(
|
||||
`Command [${config.command}]`,
|
||||
config.command,
|
||||
);
|
||||
const currentArgs = (config.args || []).join(' ');
|
||||
const argsStr = await si.question.text(
|
||||
`Args (space separated) [${currentArgs}]`,
|
||||
currentArgs,
|
||||
);
|
||||
answers.args = argsStr.trim() ? argsStr.split(/\s+/) : [];
|
||||
answers.projectDir = await si.question.text(
|
||||
`Working directory [${config.projectDir}]`,
|
||||
config.projectDir,
|
||||
);
|
||||
const memStrDefault = formatMemory(config.memoryLimitBytes);
|
||||
const memStr = await si.question.text(
|
||||
`Memory limit [${memStrDefault}]`,
|
||||
memStrDefault,
|
||||
);
|
||||
answers.memoryLimitBytes = parseMemoryString(memStr || memStrDefault);
|
||||
answers.autorestart = await si.question.confirm(
|
||||
`Autorestart? [${config.autorestart ? 'Y' : 'N'}]`,
|
||||
!!config.autorestart,
|
||||
);
|
||||
const watchEnabled = await si.question.confirm(
|
||||
`Watch for changes? [${config.watch ? 'Y' : 'N'}]`,
|
||||
!!config.watch,
|
||||
);
|
||||
answers.watch = watchEnabled;
|
||||
if (watchEnabled) {
|
||||
const existingWatch = (config.watchPaths || []).join(',');
|
||||
const watchStr = await si.question.text(
|
||||
`Watch paths (comma separated) [${existingWatch}]`,
|
||||
existingWatch,
|
||||
);
|
||||
answers.watchPaths = watchStr
|
||||
.split(',')
|
||||
.map((s) => s.trim())
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
const replacePath = await si.question.confirm(
|
||||
'Replace stored PATH with current PATH?',
|
||||
false,
|
||||
);
|
||||
|
||||
const updates: any = {};
|
||||
if (answers.name !== config.name) updates.name = answers.name;
|
||||
if (answers.command !== config.command) updates.command = answers.command;
|
||||
if (JSON.stringify(answers.args) !== JSON.stringify(config.args || []))
|
||||
updates.args = answers.args.length ? answers.args : undefined;
|
||||
if (answers.projectDir !== config.projectDir)
|
||||
updates.projectDir = answers.projectDir;
|
||||
if (answers.memoryLimitBytes !== config.memoryLimitBytes)
|
||||
updates.memoryLimitBytes = answers.memoryLimitBytes;
|
||||
if (answers.autorestart !== config.autorestart)
|
||||
updates.autorestart = answers.autorestart;
|
||||
if (answers.watch !== config.watch) updates.watch = answers.watch;
|
||||
if (answers.watch && JSON.stringify(answers.watchPaths || []) !== JSON.stringify(config.watchPaths || []))
|
||||
updates.watchPaths = answers.watchPaths;
|
||||
|
||||
if (replacePath) {
|
||||
updates.env = { ...(config.env || {}), PATH: process.env.PATH || '' };
|
||||
}
|
||||
|
||||
if (Object.keys(updates).length === 0) {
|
||||
console.log('No changes. Nothing to update.');
|
||||
return;
|
||||
}
|
||||
|
||||
const { config: newConfig } = await tspmIpcClient.request('update', {
|
||||
id,
|
||||
updates,
|
||||
} as any);
|
||||
|
||||
console.log('✓ Updated process configuration');
|
||||
console.log(` ID: ${newConfig.id}`);
|
||||
console.log(` Command: ${newConfig.command}`);
|
||||
console.log(` CWD: ${newConfig.projectDir}`);
|
||||
if (newConfig.env?.PATH) {
|
||||
console.log(' PATH: [stored]');
|
||||
}
|
||||
},
|
||||
{ actionLabel: 'edit process config' },
|
||||
);
|
||||
}
|
||||
|
@@ -13,6 +13,7 @@ import { registerDeleteCommand } from './commands/process/delete.js';
|
||||
import { registerListCommand } from './commands/process/list.js';
|
||||
import { registerDescribeCommand } from './commands/process/describe.js';
|
||||
import { registerLogsCommand } from './commands/process/logs.js';
|
||||
import { registerEditCommand } from './commands/process/edit.js';
|
||||
import { registerStartAllCommand } from './commands/batch/start-all.js';
|
||||
import { registerStopAllCommand } from './commands/batch/stop-all.js';
|
||||
import { registerRestartAllCommand } from './commands/batch/restart-all.js';
|
||||
@@ -72,6 +73,7 @@ export const run = async (): Promise<void> => {
|
||||
registerListCommand(smartcliInstance);
|
||||
registerDescribeCommand(smartcliInstance);
|
||||
registerLogsCommand(smartcliInstance);
|
||||
registerEditCommand(smartcliInstance);
|
||||
|
||||
// Batch commands
|
||||
registerStartAllCommand(smartcliInstance);
|
||||
|
Reference in New Issue
Block a user