Skip to content

Commit a07aa55

Browse files
authored
Merge branch 'main' into simonfaltum/auth-profile-host-conflict
2 parents 0d2236d + 113448b commit a07aa55

22 files changed

+3132
-184
lines changed

experimental/aitools/cmd/aitools.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ Provides commands to:
1818
}
1919

2020
cmd.AddCommand(newInstallCmd())
21+
cmd.AddCommand(newUpdateCmd())
22+
cmd.AddCommand(newUninstallCmd())
23+
cmd.AddCommand(newListCmd())
24+
cmd.AddCommand(newVersionCmd())
2125
cmd.AddCommand(newSkillsCmd())
2226
cmd.AddCommand(newToolsCmd())
2327

experimental/aitools/cmd/flags.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package aitools
2+
3+
import "strings"
4+
5+
// splitAndTrim splits a comma-separated string, trims whitespace from each
6+
// element, and drops empty entries.
7+
func splitAndTrim(s string) []string {
8+
if s == "" {
9+
return nil
10+
}
11+
parts := strings.Split(s, ",")
12+
var result []string
13+
for _, p := range parts {
14+
p = strings.TrimSpace(p)
15+
if p != "" {
16+
result = append(result, p)
17+
}
18+
}
19+
if len(result) == 0 {
20+
return nil
21+
}
22+
return result
23+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package aitools
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestSplitAndTrim(t *testing.T) {
10+
tests := []struct {
11+
name string
12+
input string
13+
expected []string
14+
}{
15+
{"simple", "a,b", []string{"a", "b"}},
16+
{"whitespace", "a, b , c", []string{"a", "b", "c"}},
17+
{"empty input", "", nil},
18+
{"trailing comma", "a,b,", []string{"a", "b"}},
19+
{"only commas", ",,", nil},
20+
{"single value", "a", []string{"a"}},
21+
}
22+
for _, tt := range tests {
23+
t.Run(tt.name, func(t *testing.T) {
24+
assert.Equal(t, tt.expected, splitAndTrim(tt.input))
25+
})
26+
}
27+
}
Lines changed: 108 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,120 @@
11
package aitools
22

33
import (
4+
"context"
5+
"errors"
6+
"fmt"
7+
"strings"
8+
9+
"github.com/databricks/cli/experimental/aitools/lib/agents"
10+
"github.com/databricks/cli/experimental/aitools/lib/installer"
11+
"github.com/databricks/cli/libs/cmdio"
12+
"github.com/fatih/color"
413
"github.com/spf13/cobra"
514
)
615

716
func newInstallCmd() *cobra.Command {
8-
return &cobra.Command{
9-
Use: "install [skill-name]",
10-
Short: "Alias for skills install",
11-
Long: `Alias for "databricks experimental aitools skills install".
17+
var skillsFlag, agentsFlag string
18+
var includeExperimental bool
19+
20+
cmd := &cobra.Command{
21+
Use: "install",
22+
Short: "Install AI skills for coding agents",
23+
Long: `Install Databricks AI skills for detected coding agents.
24+
25+
Skills are installed globally to each agent's skills directory.
26+
When multiple agents are detected, skills are stored in a canonical location
27+
and symlinked to each agent to avoid duplication.
1228
13-
Installs Databricks skills for detected coding agents.`,
29+
Supported agents: Claude Code, Cursor, Codex CLI, OpenCode, GitHub Copilot, Antigravity`,
30+
Args: cobra.NoArgs,
1431
RunE: func(cmd *cobra.Command, args []string) error {
15-
return runSkillsInstall(cmd.Context(), args)
32+
ctx := cmd.Context()
33+
34+
// Resolve target agents.
35+
var targetAgents []*agents.Agent
36+
if agentsFlag != "" {
37+
var err error
38+
targetAgents, err = resolveAgentNames(ctx, agentsFlag)
39+
if err != nil {
40+
return err
41+
}
42+
} else {
43+
detected := agents.DetectInstalled(ctx)
44+
if len(detected) == 0 {
45+
printNoAgentsMessage(ctx)
46+
return nil
47+
}
48+
49+
switch {
50+
case len(detected) == 1:
51+
targetAgents = detected
52+
case cmdio.IsPromptSupported(ctx):
53+
var err error
54+
targetAgents, err = promptAgentSelection(ctx, detected)
55+
if err != nil {
56+
return err
57+
}
58+
default:
59+
targetAgents = detected
60+
}
61+
}
62+
63+
// Build install options.
64+
opts := installer.InstallOptions{
65+
IncludeExperimental: includeExperimental,
66+
}
67+
opts.SpecificSkills = splitAndTrim(skillsFlag)
68+
69+
installer.PrintInstallingFor(ctx, targetAgents)
70+
71+
src := &installer.GitHubManifestSource{}
72+
return installSkillsForAgentsFn(ctx, src, targetAgents, opts)
1673
},
1774
}
75+
76+
cmd.Flags().StringVar(&skillsFlag, "skills", "", "Specific skills to install (comma-separated)")
77+
cmd.Flags().StringVar(&agentsFlag, "agents", "", "Agents to install for (comma-separated, e.g. claude-code,cursor)")
78+
cmd.Flags().BoolVar(&includeExperimental, "experimental", false, "Include experimental skills")
79+
return cmd
80+
}
81+
82+
// resolveAgentNames parses a comma-separated list of agent names and validates
83+
// them against the registry. Returns an error for unrecognized names.
84+
func resolveAgentNames(ctx context.Context, names string) ([]*agents.Agent, error) {
85+
available := make(map[string]*agents.Agent, len(agents.Registry))
86+
var availableNames []string
87+
for i := range agents.Registry {
88+
a := &agents.Registry[i]
89+
available[a.Name] = a
90+
availableNames = append(availableNames, a.Name)
91+
}
92+
93+
var result []*agents.Agent
94+
seen := make(map[string]bool)
95+
for _, name := range strings.Split(names, ",") {
96+
name = strings.TrimSpace(name)
97+
if name == "" || seen[name] {
98+
continue
99+
}
100+
seen[name] = true
101+
agent, ok := available[name]
102+
if !ok {
103+
return nil, fmt.Errorf("unknown agent %q. Available agents: %s", name, strings.Join(availableNames, ", "))
104+
}
105+
result = append(result, agent)
106+
}
107+
108+
if len(result) == 0 {
109+
return nil, errors.New("no agents specified")
110+
}
111+
return result, nil
112+
}
113+
114+
// printNoAgentsMessage prints the "no agents detected" message.
115+
func printNoAgentsMessage(ctx context.Context) {
116+
cmdio.LogString(ctx, color.YellowString("No supported coding agents detected."))
117+
cmdio.LogString(ctx, "")
118+
cmdio.LogString(ctx, "Supported agents: Claude Code, Cursor, Codex CLI, OpenCode, GitHub Copilot, Antigravity")
119+
cmdio.LogString(ctx, "Please install at least one coding agent first.")
18120
}

0 commit comments

Comments
 (0)