feat: implement PI-090 product tools
This commit is contained in:
100
electron/coding-projects/skill-registry.ts
Normal file
100
electron/coding-projects/skill-registry.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import {
|
||||
BUNDLED_CODING_SKILL_IDS,
|
||||
type BundledCodingSkillId,
|
||||
} from '../../shared/coding-skills';
|
||||
|
||||
export interface ProductCodingSkill {
|
||||
id: BundledCodingSkillId;
|
||||
name: string;
|
||||
description: string;
|
||||
selected: boolean;
|
||||
}
|
||||
|
||||
export interface ProductCodingCommand {
|
||||
name: string;
|
||||
title: string;
|
||||
description: string;
|
||||
source: 'makelore' | 'pi' | 'skill';
|
||||
skillId?: BundledCodingSkillId;
|
||||
}
|
||||
|
||||
const MAKELORE_COMMANDS: readonly ProductCodingCommand[] = [
|
||||
{ name: 'models', title: '切换模型', description: '切换当前会话后续轮次使用的模型', source: 'makelore' },
|
||||
{ name: 'thinking', title: '思考强度', description: '设置当前会话的思考强度', source: 'makelore' },
|
||||
{ name: 'compact', title: '压缩会话', description: '使用当前模型总结会话上下文', source: 'makelore' },
|
||||
{ name: 'fork', title: '分叉会话', description: '从当前用户消息创建新的产品会话', source: 'makelore' },
|
||||
{ name: 'recover', title: '恢复会话', description: '重新创建当前会话 worker 并恢复状态', source: 'makelore' },
|
||||
] as const;
|
||||
|
||||
function frontmatterScalar(content: string, key: string): string | undefined {
|
||||
const block = content.match(/^---\s*\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/)?.[1];
|
||||
if (!block) return undefined;
|
||||
const line = block.split(/\r?\n/).find((candidate) => candidate.startsWith(`${key}:`));
|
||||
if (!line) return undefined;
|
||||
const value = line.slice(key.length + 1).trim();
|
||||
if ((value.startsWith('"') && value.endsWith('"'))
|
||||
|| (value.startsWith("'") && value.endsWith("'"))) {
|
||||
return value.slice(1, -1).trim() || undefined;
|
||||
}
|
||||
return value || undefined;
|
||||
}
|
||||
|
||||
function selectedSkillIds(value: readonly string[]): Set<BundledCodingSkillId> {
|
||||
const allowed = new Set<string>(BUNDLED_CODING_SKILL_IDS);
|
||||
const selected = new Set<BundledCodingSkillId>();
|
||||
for (const raw of value) {
|
||||
const id = raw.trim();
|
||||
if (!allowed.has(id)) throw new Error(`Unknown bundled coding skill: ${id}`);
|
||||
selected.add(id as BundledCodingSkillId);
|
||||
}
|
||||
return selected;
|
||||
}
|
||||
|
||||
export async function listProductCodingSkills(
|
||||
bundledSkillsDir: string,
|
||||
selectedIds: readonly string[] = [],
|
||||
): Promise<ProductCodingSkill[]> {
|
||||
const selected = selectedSkillIds(selectedIds);
|
||||
return await Promise.all(BUNDLED_CODING_SKILL_IDS.map(async (id) => {
|
||||
const content = await readFile(path.join(bundledSkillsDir, id, 'SKILL.md'), 'utf8');
|
||||
return {
|
||||
id,
|
||||
name: frontmatterScalar(content, 'name') ?? id,
|
||||
description: frontmatterScalar(content, 'description') ?? '',
|
||||
selected: selected.has(id),
|
||||
};
|
||||
}));
|
||||
}
|
||||
|
||||
export function buildProductCodingCommandCatalog(
|
||||
skills: readonly ProductCodingSkill[],
|
||||
piCommands: readonly { name: string; description?: string }[] = [],
|
||||
): ProductCodingCommand[] {
|
||||
const commands = [...MAKELORE_COMMANDS];
|
||||
const used = new Set(commands.map((command) => command.name));
|
||||
for (const command of piCommands) {
|
||||
const name = command.name.trim();
|
||||
if (!name || /\s/u.test(name) || used.has(name)) continue;
|
||||
used.add(name);
|
||||
commands.push({
|
||||
name,
|
||||
title: name,
|
||||
description: command.description?.trim() || 'Pi 命令',
|
||||
source: 'pi',
|
||||
});
|
||||
}
|
||||
for (const skill of skills) {
|
||||
if (!skill.selected || used.has(skill.id)) continue;
|
||||
used.add(skill.id);
|
||||
commands.push({
|
||||
name: skill.id,
|
||||
title: skill.name,
|
||||
description: skill.description || '项目技能',
|
||||
source: 'skill',
|
||||
skillId: skill.id,
|
||||
});
|
||||
}
|
||||
return commands;
|
||||
}
|
||||
Reference in New Issue
Block a user