合并远程主分支客户端收口
This commit is contained in:
115
electron/opencode/course-skills.ts
Normal file
115
electron/opencode/course-skills.ts
Normal file
@@ -0,0 +1,115 @@
|
||||
import {
|
||||
cpSync,
|
||||
existsSync,
|
||||
lstatSync,
|
||||
mkdirSync,
|
||||
rmSync,
|
||||
unlinkSync,
|
||||
} from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
|
||||
export interface BundledSkillsPathInput {
|
||||
isPackaged: boolean;
|
||||
resourcesPath: string;
|
||||
appPath: string;
|
||||
}
|
||||
|
||||
export interface EnsureBundledCourseSkillsOptions {
|
||||
managedConfigDir: string;
|
||||
sourceDir?: string;
|
||||
}
|
||||
|
||||
export const BUNDLED_COURSE_SKILL_IDS = [
|
||||
'agent-browser',
|
||||
'designer-design-spec',
|
||||
'dev-build-test',
|
||||
'game-assets',
|
||||
'marketing-launch-story',
|
||||
'nianxxgame-skill',
|
||||
'partner-agent-showcase',
|
||||
'pm-project-plan',
|
||||
'product-demo-prototype',
|
||||
'ui-ux-course-quality',
|
||||
'youth-plain-language',
|
||||
'youth-ai-product-course',
|
||||
] as const;
|
||||
const RETIRED_COURSE_SKILL_IDS = [
|
||||
'course-stage-review',
|
||||
'deploy-publish-check',
|
||||
'student-growth-logger',
|
||||
] as const;
|
||||
const LEGACY_SUPERPOWERS_ARTIFACTS = [
|
||||
'plugins/superpowers-niancode.js',
|
||||
'plugins/superpowers.js',
|
||||
'superpowers-active.json',
|
||||
'superpowers-bundles',
|
||||
] as const;
|
||||
|
||||
export function resolveBundledCourseSkillsDir(input: BundledSkillsPathInput): string {
|
||||
return input.isPackaged
|
||||
? join(input.resourcesPath, 'course-skills')
|
||||
: join(input.appPath, '.opencode', 'skills');
|
||||
}
|
||||
|
||||
export function resolveBundledAgentBrowserPluginPath(input: BundledSkillsPathInput): string {
|
||||
return join(
|
||||
resolveBundledCourseSkillsDir(input),
|
||||
'agent-browser',
|
||||
'.opencode',
|
||||
'plugins',
|
||||
'niancode-agent-browser.js',
|
||||
);
|
||||
}
|
||||
|
||||
export function getManagedOpencodeConfigDir(userDataDir: string): string {
|
||||
return join(userDataDir, 'opencode', 'niancode-config');
|
||||
}
|
||||
|
||||
function copyDirectorySync(sourceDir: string, targetDir: string): void {
|
||||
cpSync(sourceDir, targetDir, {
|
||||
recursive: true,
|
||||
force: true,
|
||||
filter: (sourcePath, targetPath) => {
|
||||
// Node 24.14's Windows override path can corrupt non-ASCII destinations
|
||||
// when replacing a file. Public unlink keeps force-overwrite semantics.
|
||||
if (lstatSync(sourcePath).isFile() && existsSync(targetPath)) {
|
||||
unlinkSync(targetPath);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function removeLegacySuperpowersArtifacts(managedConfigDir: string): void {
|
||||
for (const artifact of LEGACY_SUPERPOWERS_ARTIFACTS) {
|
||||
rmSync(join(managedConfigDir, artifact), { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
export function ensureBundledCourseSkills(options: EnsureBundledCourseSkillsOptions): boolean {
|
||||
const sourceDir = options.sourceDir?.trim();
|
||||
if (!sourceDir || !existsSync(sourceDir)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const targetSkillsDir = join(options.managedConfigDir, 'skills');
|
||||
mkdirSync(targetSkillsDir, { recursive: true });
|
||||
for (const skillId of RETIRED_COURSE_SKILL_IDS) {
|
||||
rmSync(join(targetSkillsDir, skillId), { recursive: true, force: true });
|
||||
}
|
||||
copyDirectorySync(sourceDir, targetSkillsDir);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function ensureBundledAgentBrowserPlugin(options: {
|
||||
managedConfigDir: string;
|
||||
sourcePath?: string;
|
||||
}): boolean {
|
||||
const sourcePath = options.sourcePath?.trim();
|
||||
if (!sourcePath || !existsSync(sourcePath)) return false;
|
||||
const targetPluginsDir = join(options.managedConfigDir, 'plugins');
|
||||
mkdirSync(targetPluginsDir, { recursive: true });
|
||||
cpSync(sourcePath, join(targetPluginsDir, 'niancode-agent-browser.js'), { force: true });
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user