mirror of
https://github.com/lukaszraczylo/harness-sync.git
synced 2026-10-17 01:17:35 +00:00
fix: pre-select all in init prompt, preserve agent paths with slashes, fix rollback off-by-one
This commit is contained in:
+37
-4
@@ -49,7 +49,11 @@ func NewInit(reg *adapter.Registry) *cobra.Command {
|
|||||||
var picked []string
|
var picked []string
|
||||||
switch {
|
switch {
|
||||||
case len(from) > 0:
|
case len(from) > 0:
|
||||||
picked = from
|
for _, f := range from {
|
||||||
|
if f != "" {
|
||||||
|
picked = append(picked, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
case noPrompt:
|
case noPrompt:
|
||||||
picked = candidates
|
picked = candidates
|
||||||
default:
|
default:
|
||||||
@@ -58,6 +62,14 @@ func NewInit(reg *adapter.Registry) *cobra.Command {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if len(picked) == 0 {
|
||||||
|
return fmt.Errorf("no harnesses selected; rerun with --no-prompt or --from <name,name>")
|
||||||
|
}
|
||||||
|
for _, name := range picked {
|
||||||
|
if _, ok := reg.Get(name); !ok {
|
||||||
|
return fmt.Errorf("unknown adapter %q (try `harness-sync adapter list`)", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
return runImport(cmd, reg, r, home, picked)
|
return runImport(cmd, reg, r, home, picked)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -134,7 +146,10 @@ func runImport(cmd *cobra.Command, reg *adapter.Registry, root, home string, pic
|
|||||||
if err := repo.Commit(fmt.Sprintf("import from %s", strings.Join(picked, ", "))); err != nil {
|
if err := repo.Commit(fmt.Sprintf("import from %s", strings.Join(picked, ", "))); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "imported from %v into %s\n", picked, root)
|
_, _ = fmt.Fprintf(cmd.OutOrStdout(),
|
||||||
|
"imported from %v into %s\n skills: %d\n agents: %d\n mcp servers: %d\n instructions: %d source(s)\n",
|
||||||
|
picked, root, len(bundle.Skills), len(bundle.Agents), len(bundle.MCP.Servers), len(instructions),
|
||||||
|
)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,7 +198,11 @@ func writeCanonical(root string, b *canonical.Bundle, picked []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, s := range b.Skills {
|
for _, s := range b.Skills {
|
||||||
path := filepath.Join(root, "skills", s.Name, "SKILL.md")
|
rel := s.Path
|
||||||
|
if rel == "" {
|
||||||
|
rel = filepath.Join(safeFilename(s.Name), "SKILL.md")
|
||||||
|
}
|
||||||
|
path := filepath.Join(root, "skills", rel)
|
||||||
if err := os.MkdirAll(filepath.Dir(path), 0o750); err != nil {
|
if err := os.MkdirAll(filepath.Dir(path), 0o750); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -192,7 +211,14 @@ func writeCanonical(root string, b *canonical.Bundle, picked []string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, a := range b.Agents {
|
for _, a := range b.Agents {
|
||||||
path := filepath.Join(root, "agents", a.Name+".md")
|
rel := a.Path
|
||||||
|
if rel == "" {
|
||||||
|
rel = safeFilename(a.Name) + ".md"
|
||||||
|
}
|
||||||
|
path := filepath.Join(root, "agents", rel)
|
||||||
|
if err := os.MkdirAll(filepath.Dir(path), 0o750); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if err := os.WriteFile(path, []byte(a.Body), 0o600); err != nil {
|
if err := os.WriteFile(path, []byte(a.Body), 0o600); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -205,3 +231,10 @@ func writeCanonical(root string, b *canonical.Bundle, picked []string) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// safeFilename strips path separators and other characters that would break
|
||||||
|
// when used as a basename.
|
||||||
|
func safeFilename(s string) string {
|
||||||
|
r := strings.NewReplacer("/", "-", "\\", "-", ":", "-", "\x00", "")
|
||||||
|
return r.Replace(s)
|
||||||
|
}
|
||||||
|
|||||||
@@ -68,7 +68,12 @@ func (r *Repo) IsRepo() bool {
|
|||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Revert undoes the last N commits with `git revert --no-edit HEAD~N..HEAD`.
|
||||||
|
// n must be >= 1.
|
||||||
func (r *Repo) Revert(n int) error {
|
func (r *Repo) Revert(n int) error {
|
||||||
_, err := r.run("revert", "--no-edit", fmt.Sprintf("HEAD~%d..HEAD", n-1))
|
if n < 1 {
|
||||||
|
return fmt.Errorf("revert: n must be >= 1, got %d", n)
|
||||||
|
}
|
||||||
|
_, err := r.run("revert", "--no-edit", fmt.Sprintf("HEAD~%d..HEAD", n))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-2
@@ -44,19 +44,28 @@ func MultiSelect(title string, choices []string, opts ...Option) ([]string, erro
|
|||||||
}
|
}
|
||||||
return o.nonInteractive, nil
|
return o.nonInteractive, nil
|
||||||
}
|
}
|
||||||
var picked []string
|
// Pre-select every choice. Users deselect what they don't want; hitting
|
||||||
|
// enter without toggling thus accepts all (the common case) instead of
|
||||||
|
// silently producing an empty result.
|
||||||
|
picked := make([]string, len(choices))
|
||||||
|
copy(picked, choices)
|
||||||
|
|
||||||
opts2 := make([]huh.Option[string], 0, len(choices))
|
opts2 := make([]huh.Option[string], 0, len(choices))
|
||||||
for _, c := range choices {
|
for _, c := range choices {
|
||||||
opts2 = append(opts2, huh.NewOption(c, c))
|
opts2 = append(opts2, huh.NewOption(c, c).Selected(true))
|
||||||
}
|
}
|
||||||
form := huh.NewForm(huh.NewGroup(
|
form := huh.NewForm(huh.NewGroup(
|
||||||
huh.NewMultiSelect[string]().
|
huh.NewMultiSelect[string]().
|
||||||
Title(title).
|
Title(title).
|
||||||
|
Description("space to toggle · enter to confirm · all pre-selected").
|
||||||
Options(opts2...).
|
Options(opts2...).
|
||||||
Value(&picked),
|
Value(&picked),
|
||||||
))
|
))
|
||||||
if err := form.Run(); err != nil {
|
if err := form.Run(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if len(picked) == 0 {
|
||||||
|
return nil, fmt.Errorf("no items selected")
|
||||||
|
}
|
||||||
return picked, nil
|
return picked, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user