dsh-im-ops/bin/dsh-im.mjs
xmanrui 1ce8126edb feat(settings): move IM bot to top-level menu
Remove the legacy Plugins-tab registrations, keep the channel-logo navigation, and harden upgrade/package verification.
2026-08-25 22:42:41 +08:00

99 lines
3.5 KiB
JavaScript
Executable file
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env node
import { readFile } from 'node:fs/promises';
import { homedir, tmpdir } from 'node:os';
import { isAbsolute, join, resolve } from 'node:path';
import { spawnSync } from 'node:child_process';
const PACKAGE_NAME = '@xmanrui/dsh-im';
const DEFAULT_SOURCE = 'github:xmanrui/dsh-im';
const LEGACY_PACKAGES = [
'@xmanrui/dsh-feishu',
'@xmanrui/dsh-weixin',
'@xmanrui/dsh-dingtalk',
];
function usage() {
console.log(`Usage:
dsh-im install [--profile web] [--source <package-spec>]
dsh-im uninstall [--profile web]
Examples:
npx -y github:xmanrui/dsh-im install
dsh-im install --source .`);
}
function takeOption(args, name, fallback) {
const index = args.indexOf(name);
if (index < 0) return fallback;
const value = args[index + 1];
if (!value || value.startsWith('--')) throw new Error(`${name} requires a value`);
args.splice(index, 2);
return value;
}
function runDsh(args) {
const result = spawnSync('dsh', args, {
cwd: tmpdir(),
stdio: 'inherit',
shell: false,
});
if (result.error?.code === 'ENOENT') {
throw new Error('找不到 dsh,请先安装 DeepSeek Harness 并确保 dsh 在 PATH 中。');
}
if (result.error) throw result.error;
if (result.status !== 0) throw new Error(`dsh 退出,状态码 ${result.status ?? 1}`);
}
async function directProfilePackages(profile) {
const dshHome = process.env.DSH_HOME || join(homedir(), '.dsh');
const profilePackage = join(dshHome, 'profiles', profile, 'package.json');
try {
const manifest = JSON.parse(await readFile(profilePackage, 'utf8'));
const bundles = new Set(manifest.dsh?.profile?.bundles ?? []);
const dependencies = manifest.dependencies ?? {};
return new Set(LEGACY_PACKAGES.filter((name) => dependencies[name] || bundles.has(name)));
} catch (error) {
if (error?.code === 'ENOENT') return new Set();
throw new Error(`无法读取 Harness 配置 ${profilePackage}:${error.message}`);
}
}
const args = process.argv.slice(2);
const command = args.shift();
if (!command || command === '--help' || command === '-h') {
usage();
process.exit(0);
}
try {
const profile = takeOption(args, '--profile', 'web');
if (command === 'install') {
const requested = takeOption(args, '--source', DEFAULT_SOURCE);
const source = requested === '.' || requested === '..'
|| requested.startsWith('./') || requested.startsWith('../')
? resolve(process.cwd(), requested)
: (isAbsolute(requested) ? requested : requested);
if (args.length > 0) throw new Error(`无法识别的参数:${args.join(' ')}`);
const legacy = await directProfilePackages(profile);
runDsh(['plugin', '--profile', profile, 'add', '--save-exact', source]);
for (const packageName of legacy) {
runDsh(['plugin', '--profile', profile, 'remove', packageName]);
}
console.log('\nIM 机器人插件已安装。请重启 dsh web、刷新浏览器,然后打开「设置 → IM机器人」。');
if (legacy.size > 0) {
console.log('已用 dsh-im 替换独立飞书/微信/钉钉插件;原有凭据和扫码绑定保持不变。');
}
} else if (command === 'uninstall') {
if (args.length > 0) throw new Error(`无法识别的参数:${args.join(' ')}`);
runDsh(['plugin', '--profile', profile, 'remove', PACKAGE_NAME]);
console.log('\nIM 机器人插件已卸载。请重启 dsh web。');
} else {
throw new Error(`无法识别的命令:${command}`);
}
} catch (error) {
console.error(`dsh-im: ${error.message}`);
process.exit(1);
}