Repository navigation
feat(import): add single-skill import from configured agent sources - #6
Merged
Merged
Conversation
Adds the skill-import change: a new internal/importer package that locates a skill across globally configured agent sources, resolves the winner with the mesh rules, and copies it into ./.agents/skills/<skillID>/ transactionally. - importer.DirHash hashes the whole skill directory manifest instead of only SKILL.md, so conflict resolution sees sibling file changes. - importer.CopySkill stages into .tmp and only rotates .bak and renames on full success, leaving the destination untouched on failure. - CLI: skill-sync import <skill-name>. - TUI: import_source_view and import_skill_view wired into program.go, with a [CONFLICT] marker for unresolvable candidates. - models.SkillMetadata gains Description for the TUI listing.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
skill-sync import <skill-name>: a selective, single-skill import from the globally configured agent sources into the project-local./.agents/skills/<skillID>/. This is distinct from mesh sync — it pulls one skill into the current project instead of reconciling every target.internal/importer, a reusable primitive (FindSkill,FindAllSkills,Resolve,CopySkill,DirHash) that delegates winner selection to the existing mesh resolver.[CONFLICT]marker for candidates the resolver cannot settle.Design notes
Directory-level hashing.
DirHashhashes a sorted manifest of every regular file in the skill directory (relative path + contents,filepath.ToSlashnormalized for cross-platform determinism), not justSKILL.md. A skill whose sibling files changed is correctly seen as different.Transactional copy.
CopySkillwrites everything into a.tmpstaging directory first. On failure it removes.tmpand leaves the destination completely untouched; only on full success does it rotate the existing directory to.bakand rename.tmpinto place. This avoids the window where a naive rename-then-write leaves a half-written destination.Conflict handling. When two sources report the same
versionand the samemtimebut different hashes, the import fails withErrConflictand exit code 1 in both CLI and TUI. Interactive tie-breaking is deliberately out of scope for v1.Changes
internal/importer/manifest.goDirHash— SHA-256 over the sorted file manifest; skips symlinksinternal/importer/importer.goFindSkill,FindAllSkills(grouped by skill ID + resolved),Resolve,CopySkill,readMetadatainternal/importer/errors.goErrSkillNotFound,ErrConflictsentinelsinternal/cli/import.goNewImportCmd+runImport; uses thegetWdpackage var for test injectioninternal/cli/root.goFindSkillsForImport/RunImportcallbacksinternal/models/skill.goSkillMetadatagainsDescriptionfor the TUI listinginternal/tui/import_source_view/shared_toggle, all sources checked by defaultinternal/tui/import_skill_view/[CONFLICT]prefix, description truncated at 60 runesinternal/tui/program.gostateImportSourceandstateImportSkill, plus theimportSourcesfield soBackMsgcan recreate the source viewinternal/tui/menu/model.goopenspec/skill-importchange record (proposal, spec, design, tasks).gitignoreTest plan
All run on
feat/import_skillsatc2cba25, and confirmed green in CI on ubuntu-latest and windows-latest:go build ./...— passesgo vet ./...— passesgofmt -s -l .— clean (the first CI run caught unformatted files; fixed inc2cba25)go test ./...— passes, every package greenNew coverage, all table-driven per project convention:
internal/importer/manifest_test.go— determinism, order independence, content change, file addition, symlink skipping (Unix only,t.Skipon Windows)internal/importer/importer_test.go— find/resolve/copy paths including the transactional failure case where the destination must stay untouchedinternal/cli/import_test.go— 8 integration tests against real temp dirs: happy path, missing config, skill not found, wrong argument count (x2), conflict, idempotent re-import, and.bakbackup creationinternal/models/skill_test.go—descriptionYAML round-tripprogram.gostate transitionsNot applicable: shellcheck (no shell scripts touched).
Review size
~2,100 added lines, of which ~1,200 are tests — above the 400-line advisory budget in
openspec/config.yaml, which declareschained_pr_strategy: single-pr-default. Suggested reading order:internal/importer/first (the primitive and its invariants), theninternal/cli/import.go, then the TUI wiring.Known follow-ups
internal/tuiwritesskill-sync.yaml.bakinto the package directory instead of a temp dir. This PR only gitignores the residue; the test should be fixed to uset.TempDir().sdd-archivefor theskill-importchange (merge delta specs, move the change folder to archived) is not included here.