Skip to content
This repository was archived by the owner on Jan 23, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions cmd/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,8 +369,8 @@ func getAgentList(logger logger.Logger, apiUrl string, apikey string, project pr
return remoteAgents, err
}

func normalAgentName(name string) string {
return util.SafeFilename(strings.ToLower(name))
func normalAgentName(name string, isPython bool) string {
return util.SafeProjectFilename(strings.ToLower(name), isPython)
}

func reconcileAgentList(logger logger.Logger, cmd *cobra.Command, apiUrl string, apikey string, theproject project.ProjectContext) ([]string, map[string]agentListState) {
Expand All @@ -395,7 +395,8 @@ func reconcileAgentList(logger logger.Logger, cmd *cobra.Command, apiUrl string,
fileAgents := make(map[string]project.AgentConfig)
fileAgentsByID := make(map[string]project.AgentConfig)
for _, agent := range theproject.Project.Agents {
fileAgents[normalAgentName(agent.Name)] = agent
key := normalAgentName(agent.Name, theproject.Project.IsPython())
fileAgents[key] = agent
fileAgentsByID[agent.ID] = agent
}

Expand All @@ -405,10 +406,11 @@ func reconcileAgentList(logger logger.Logger, cmd *cobra.Command, apiUrl string,
// perform the reconcilation
state := make(map[string]agentListState)
for _, agent := range remoteAgents {
state[normalAgentName(agent.Name)] = agentListState{
key := normalAgentName(agent.Name, theproject.Project.IsPython())
state[key] = agentListState{
Agent: &agent,
Filename: filepath.Join(agentSrcDir, util.SafeFilename(agent.Name), agentFilename),
FoundLocal: util.Exists(filepath.Join(agentSrcDir, util.SafeFilename(agent.Name), agentFilename)),
Filename: filepath.Join(agentSrcDir, key, agentFilename),
FoundLocal: util.Exists(filepath.Join(agentSrcDir, key, agentFilename)),
FoundRemote: true,
}
}
Expand All @@ -418,7 +420,7 @@ func reconcileAgentList(logger logger.Logger, cmd *cobra.Command, apiUrl string,
}
for _, filename := range localAgents {
agentName := filepath.Base(filepath.Dir(filename))
key := normalAgentName(agentName)
key := normalAgentName(agentName, theproject.Project.IsPython())
// var found bool
// for _, agent := range remoteAgents {
// if localAgent, ok := fileAgentsByID[agent.ID]; ok {
Expand Down
2 changes: 1 addition & 1 deletion cmd/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ Examples:
}
return nil
})
fp := filepath.Join(filepath.Dir(cfgFile), util.SafeFilename(name)+".yaml")
fp := filepath.Join(filepath.Dir(cfgFile), util.SafeProjectFilename(name, false)+".yaml")
os.WriteFile(fp, []byte(fmt.Sprintf(`name: "%s"`, name)+"\n"), 0644)
},
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,7 @@ Examples:
provider = resp.Provider
}
}
projectDir := filepath.Join(cwd, util.SafeFilename(name))
projectDir := filepath.Join(cwd, util.SafeProjectFilename(name, provider.Language == "python"))
dir, _ := cmd.Flags().GetString("dir")
if dir != "" {
absDir, err := filepath.Abs(dir)
Expand Down
6 changes: 1 addition & 5 deletions internal/bundler/bundler.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,11 +336,7 @@ func getAgents(theproject *project.Project, filename string) []AgentConfig {
var agents []AgentConfig
for _, agent := range theproject.Agents {
var agentfilename string
if theproject.Bundler.Language == "python" {
agentfilename = util.SafePythonFilename(agent.Name)
} else {
agentfilename = util.SafeFilename(agent.Name)
}
agentfilename = util.SafeProjectFilename(agent.Name, theproject.IsPython())
agents = append(agents, AgentConfig{
ID: agent.ID,
Name: agent.Name,
Expand Down
8 changes: 8 additions & 0 deletions internal/project/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,14 @@ type Project struct {
Agents []AgentConfig `json:"agents" yaml:"agents" hc:"The agents that are part of this project"`
}

func (p *Project) SafeFilename() string {
return util.SafeProjectFilename(p.Name, p.IsPython())
}

func (p *Project) IsPython() bool {
return p.Bundler.Language == "python" || p.Bundler.Language == "py"
}

// Load will load the project from a file in the given directory.
func (p *Project) Load(dir string) error {
fn := getFilename(dir)
Expand Down
2 changes: 1 addition & 1 deletion internal/templates/steps.go
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,7 @@ func resolveStep(ctx TemplateContext, step any) (Step, bool) {
}
var name string
if val, ok := kv["name"].(string); ok {
name = util.SafeFilename(ctx.Interpolate(val).(string))
name = util.SafeProjectFilename(ctx.Interpolate(val).(string), ctx.Template.Language == "python")
}
var version string
if val, ok := kv["version"].(string); ok {
Expand Down
5 changes: 1 addition & 4 deletions internal/templates/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,7 @@ type TemplateContext struct {
func funcTemplates(t *template.Template, isPython bool) *template.Template {
return t.Funcs(template.FuncMap{
"safe_filename": func(s string) string {
if isPython {
return util.SafePythonFilename(s)
}
return util.SafeFilename(s)
return util.SafeProjectFilename(s, isPython)
},
})
}
Expand Down
29 changes: 14 additions & 15 deletions internal/util/strings.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,21 @@ var beginsWithNumber = regexp.MustCompile(`^[0-9]+`)
var removeStartingDashes = regexp.MustCompile(`^[-]+`)
var removeEndingDashes = regexp.MustCompile(`[-]+$`)

func SafeFilename(name string) string {
return safeNameTransformer.ReplaceAllString(name, "-")
}

func SafePythonFilename(name string) string {
if beginsWithNumber.MatchString(name) {
name = beginsWithNumber.ReplaceAllString(name, "")
func SafeProjectFilename(name string, python bool) string {
if python {
if beginsWithNumber.MatchString(name) {
name = beginsWithNumber.ReplaceAllString(name, "")
}
name = safePythonNameTransformer.ReplaceAllString(name, "_")
if removeStartingDashes.MatchString(name) {
name = removeStartingDashes.ReplaceAllString(name, "")
}
if removeEndingDashes.MatchString(name) {
name = removeEndingDashes.ReplaceAllString(name, "")
}
return name
}
name = safePythonNameTransformer.ReplaceAllString(name, "_")
if removeStartingDashes.MatchString(name) {
name = removeStartingDashes.ReplaceAllString(name, "")
}
if removeEndingDashes.MatchString(name) {
name = removeEndingDashes.ReplaceAllString(name, "")
}
return name
return safeNameTransformer.ReplaceAllString(name, "-")
}

func Pluralize(count int, singular string, plural string) string {
Expand Down
50 changes: 25 additions & 25 deletions internal/util/strings_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,6 @@ import (
"github.com/stretchr/testify/assert"
)

func TestSafeFilename(t *testing.T) {
tests := []struct {
name string
input string
expected string
}{
{"empty string", "", ""},
{"no special characters", "filename", "filename"},
{"with spaces", "file name", "file-name"},
{"with special characters", "file@#$%^&*()name", "file---------name"},
{"mixed case", "FileName", "FileName"},
{"with numbers", "file123name", "file123name"},
{"with underscores", "file_name", "file_name"},
{"with hyphens", "file-name", "file-name"},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
result := SafeFilename(test.input)
assert.Equal(t, test.expected, result)
})
}
}

func TestPluralize(t *testing.T) {
tests := []struct {
name string
Expand Down Expand Up @@ -99,7 +75,31 @@ func TestSafePythonFilename(t *testing.T) {

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
result := SafePythonFilename(test.input)
result := SafeProjectFilename(test.input, true)
assert.Equal(t, test.expected, result)
})
}
}

func TestSafeFilename(t *testing.T) {
tests := []struct {
name string
input string
expected string
}{
{"empty string", "", ""},
{"no special characters", "filename", "filename"},
{"with spaces", "file name", "file-name"},
{"with special characters", "file@#$%^&*()name", "file---------name"},
{"mixed case", "FileName", "FileName"},
{"with numbers", "file123name", "file123name"},
{"with underscores", "file_name", "file_name"},
{"with hyphens", "file-name", "file-name"},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
result := SafeProjectFilename(test.input, false)
assert.Equal(t, test.expected, result)
})
}
Expand Down
Loading