feat: add argument parsing and module resolution for assistant app

- Implemented argument parsing in args.ts to handle root, home, and help options.
- Added parseHomeArg and parseHelpArg functions for command line argument handling.
- Created ModuleResolver class in assistant-app-resolve.ts to resolve module paths, including scoped packages and relative paths.
- Introduced caching mechanism for package.json reads to improve performance.
- Added utility functions for checking file existence and clearing the cache.
This commit is contained in:
2026-01-31 17:42:53 +08:00
parent 51822506d7
commit a80a3ede46
11 changed files with 517 additions and 337 deletions

View File

@@ -1,6 +1,7 @@
import { program, Command } from '@/program.ts';
import { spawnSync } from 'node:child_process';
import { parseHomeArg, HomeConfigDir } from '@/module/assistant/config/args.ts';
import './reload.ts'
const command = new Command('server')
.description('启动服务')
.option('-d, --daemon', '是否以守护进程方式运行')
@@ -28,17 +29,22 @@ const command = new Command('server')
shellCommands.push(`-e ${options.interpreter}`);
}
const basename = _interpreter.split('/').pop();
const m = parseHomeArg(HomeConfigDir);
const cwd = m.isDev ? process.cwd() : m.configDir;
console.log('当前工作目录:', cwd);
if (basename.includes('bun')) {
console.log(`Assistant server shell command: bun src/run-server.ts server ${shellCommands.join(' ')}`);
const child = spawnSync(_interpreter, ['src/run-server.ts', ...shellCommands], {
stdio: 'inherit',
shell: true,
cwd: cwd,
});
} else {
console.log(`Assistant server shell command: asst-server ${shellCommands.join(' ')}`);
const child = spawnSync('asst-server', shellCommands, {
stdio: 'inherit',
shell: true,
cwd: cwd,
});
}
});

View File

@@ -0,0 +1,17 @@
import { program, Command } from '@/program.ts';
import { spawnSync } from 'node:child_process';
const reload = new Command('reload')
.description('重载正在运行的 Assistant Server 服务')
.action(() => {
console.log('正在重载 Assistant Server 服务...');
const cwd = 'pm2 restart assistant-server';
const child = spawnSync('pm2', ['restart', 'assistant-server'], {
stdio: 'inherit',
shell: true,
cwd: cwd,
});
console.log('Assistant Server 服务重载完成。');
});
program.addCommand(reload);

View File

@@ -0,0 +1,79 @@
import { program, Command, assistantConfig } from '@/program.ts';
import { spawnSync } from 'node:child_process';
import { parseHomeArg, HomeConfigDir } from '@/module/assistant/config/args.ts';
import { execCommand } from '@/module/npm-install.ts';
/**
* 解析包名,分离出安装包名和配置名称
* 例如: @kevisual/cnb/routes -> pkgName: @kevisual/cnb, configName: routes
* 例如: react -> pkgName: react, configName: react
*/
function parsePluginName(name: string): { pkgName: string; configName: string } {
if (name.startsWith('@') && name.includes('/')) {
const parts = name.split('/');
if (parts.length >= 3) {
// @scope/package/submodule -> pkgName: @scope/package, configName: @scope/package/submodule
return {
pkgName: parts.slice(0, 2).join('/'),
configName: name,
};
}
}
return { pkgName: name, configName: name };
}
const pluginCommand = new Command('plugin');
const installCommand = new Command('install')
.alias('i')
.argument('<plugin-name>')
.description('安装Routes插件').action(async (name, options) => {
const { pkgName, configName } = parsePluginName(name);
const m = parseHomeArg(HomeConfigDir);
const cwd = m.isDev ? process.cwd() : m.configDir;
const shellCommand = `pnpm i ${pkgName} -w`;
const result = execCommand(shellCommand, { cwd });
if (result.status === 0) {
const mount = assistantConfig.checkMounted();
const config = assistantConfig.getConfig();
const routes = config.routes || [];
if (!routes.includes(configName)) {
routes.push(configName);
config.routes = routes;
assistantConfig.setConfig(config);
console.log(`插件 ${configName} 安装成功并已添加到配置中。`);
} else {
console.log(`插件 ${configName} 已存在于配置中。`);
}
}
});
const uninstallCommand = new Command('remove')
.alias('r')
.argument('<plugin-name>')
.description('卸载Routes插件').action(async (name, options) => {
const { pkgName, configName } = parsePluginName(name);
const m = parseHomeArg(HomeConfigDir);
const cwd = m.isDev ? process.cwd() : m.configDir;
const shellCommand = `pnpm remove ${pkgName} -w`;
const result = execCommand(shellCommand, { cwd });
assistantConfig.checkMounted();
const config = assistantConfig.getConfig();
let routes = config.routes || [];
// 从配置中移除时,查找匹配的配置名称
const index = routes.findIndex(r => r === configName);
if (index !== -1) {
routes.splice(index, 1);
config.routes = routes;
assistantConfig.setConfig(config);
console.log(`插件 ${configName} 卸载成功并已从配置中移除。`);
} else {
console.log(`插件 ${configName} 不存在于配置中。`);
}
});
pluginCommand.addCommand(uninstallCommand);
pluginCommand.addCommand(installCommand);
program.addCommand(pluginCommand);