diff --git a/apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx b/apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx index 9fbe5a52c..4ba64bd61 100644 --- a/apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx +++ b/apps/ai-game-creator-shell/src/features/project-workspace/ResourceReferenceInput.tsx @@ -491,6 +491,7 @@ function ResourceReferenceEditor({ const skipInitialDraftChangeRef = useRef(false); const [query, setQuery] = useState(null); const [skillQuery, setSkillQuery] = useState(null); + const [clientSkills, setClientSkills] = useState([]); const [pickerOpen, setPickerOpen] = useState(false); // Enter 提交要避开候选浮层。用 ref 让命令处理器读到最新状态,不必因为 // query / pickerOpen 变化反复重注册 HIGH 优先级命令。 @@ -512,6 +513,39 @@ function ResourceReferenceEditor({ bottom: number; width: number; } | null>(null); + useEffect(() => { + const invoke = resolveTauriInvoke(); + if (!invoke) return; + let cancelled = false; + void invoke< + Array<{ + name: string; + extensionType: string; + enabled: boolean; + status: string; + }> + >('list_client_extensions') + .then((items) => { + if (cancelled) return; + setClientSkills( + items + .filter( + (item) => + item.extensionType === 'skill' && + item.enabled && + item.status === 'enabled', + ) + .map((item) => ({ type: 'skill' as const, name: item.name })), + ); + }) + .catch(() => { + if (!cancelled) setClientSkills([]); + }); + return () => { + cancelled = true; + }; + }, []); + const assetsContentSignature = assetsSignature(assets); const versionsContentSignature = iterationsSignature(versions); const assetReferences = useMemo( @@ -573,7 +607,7 @@ function ResourceReferenceEditor({ const skillOptions = useMemo(() => { if (skillQuery === null) return []; const normalized = skillQuery.trim().toLowerCase(); - const allSkills = [...BUILTIN_SKILL_REFERENCES, ...skills]; + const allSkills = [...BUILTIN_SKILL_REFERENCES, ...clientSkills, ...skills]; const seen = new Set(); return allSkills .filter((skill) => { @@ -587,7 +621,7 @@ function ResourceReferenceEditor({ }) .slice(0, 8) .map((skill) => new SkillMentionOption(skill)); - }, [skillQuery, skills]); + }, [clientSkills, skillQuery, skills]); const triggerFn = useBasicTypeaheadTriggerMatch('@', { minLength: 0,