mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-05 13:29:44 +02:00
* fix(skills): unify Add Skill UX + surface every local skill with real file count Iterating on the local-skill import flow that just landed. Three fixes shipped together because they all surfaced while testing the same code path on the Skills page. UX — fold runtime import into the existing "+ Add Skill" dialog - Drop the standalone HardDrive icon button + the empty-state "Import From Runtime" buttons. Adding a skill is now a single entry point: the "+" header button (or empty-state button) opens one dialog with three tabs: Create / Import URL / From Runtime. - Extract the runtime-import body into RuntimeLocalSkillImportPanel so it can mount inline as a tab. The standalone Dialog wrapper stays for the per-runtime "Import this skill" flow on the agent skills tab, which preselects runtime + skill and benefits from its own modal. - Cap the dialog at max-h-[85vh] with a scrollable tabs body so the From-Runtime tab (runtime selector + skill list + name/description form) no longer overflows the screen on shorter displays. - Filter the runtime selector to runtimes the caller owns. Other users' runtimes were listed but the import endpoint rejects them anyway, matching the Runtimes page's "Mine" default. - The selected-runtime label in the trigger now shows the runtime name (`Claude (MacBook-Air.local) (claude)`) instead of the raw UUID — the shadcn SelectValue needs explicit children when items don't render the bare value as their label. - Drop the placeholder Sparkles icon to the left of the skill name / description inputs in the detail header — it was decorative noise. Daemon — surface every installed local skill and report the right count - listRuntimeLocalSkills used filepath.WalkDir, which silently dropped every symlinked skill via the os.ModeSymlink early return. Skill installers like lark-cli ship every skill at ~/.agents/skills/<name> and symlink each one into ~/.claude/skills/, so users with dozens of skills only saw the few they had cloned in place. Switch to ReadDir + os.Stat (which follows symlinks) on the runtime root. - collectLocalSkillFiles also failed for symlinked skill dirs because filepath.WalkDir does not descend into a symlinked root, so every such skill reported 0 files. Resolve the skill dir via EvalSymlinks before walking. - Bundle file count purposely excludes SKILL.md (it travels in the bundle's `Content` field to avoid duplication on import). The summary now adds 1 back so the user-facing count matches the real file total — every skill has SKILL.md, we just required it to be parseable. Tests - New TestListRuntimeLocalSkills_FollowsSymlinkedSkillDirs seeds a shared installer dir, symlinks one skill into the runtime root, and asserts both regular and symlinked skills come back with the right source path (~/.claude/...) and metadata. - TestListRuntimeLocalSkills_Claude updated to expect file_count = 2 (one supporting file + SKILL.md) and a comment explains the +1 split. * test(skills): drive new Add Skill dialog flow in skills-page test Old test asserted the standalone "Import From Runtime" button. The PR folded that into the unified "+ Add skill" dialog as the third tab, so the test now opens the dialog, switches to the "From Runtime" tab, and asserts the same end state. Also stub useAuthStore so the runtime panel's "Mine"-only filter sees the seeded runtime owner (user-1). * fix(daemon): list nested skills, not just depth-1 entries Per #1480 review (MUL-1246): switching listRuntimeLocalSkills from filepath.WalkDir to flat ReadDir lost coverage for nested skill layouts. opencode stores skills as e.g. `release/reporter/SKILL.md`, and loadRuntimeLocalSkillBundle accepts that slash-delimited key, so the import dialog could no longer surface skills the load endpoint was perfectly happy to fetch. Replace the flat ReadDir with a recursive enumerator that: - Follows symlinks at every level (so installer-style symlinked skill trees still work — that was the original reason for moving off WalkDir). - Short-circuits at every SKILL.md: a directory that qualifies as a skill is registered, and its children are NOT scanned for further skills. Stale nested SKILL.md files inside a parent skill's bundle stay part of that bundle. - Caps recursion at maxLocalSkillDirDepth=4 (covers opencode's depth=2 with headroom) and tracks visited resolved paths so a cyclic symlink can't loop forever. New regression test seeds both a top-level skill (with a decoy SKILL.md inside its templates dir) and a depth-2 nested skill, and asserts the walker registers exactly two keys — "top" and "release/reporter" — with the inner templates SKILL.md correctly ignored.