@@ -207,7 +207,8 @@ type flagData struct {
207207
208208type argData struct {
209209 Name string // original arg name used in string literals
210- GoName string // sanitized Go identifier
210+ GoName string // sanitized Go identifier (camelCase, lowercase first)
211+ GoNameCap string // GoName with first letter uppercased (PascalCase)
211212 GoType string
212213 Required bool
213214 Description string
@@ -224,10 +225,11 @@ type toolGoData struct {
224225 AuthType string
225226 TokenEnv string
226227 TokenFlag string
227- HasNonStringArgs bool // true if any arg needs strconv parsing
228- HasNonStringArrayFlags bool // true if any flag is a non-string array type needing strconv
229- HasObjectFlags bool // true if any flag is type "object" or "object[]"
230- IsBinaryOutput bool // true if tool output format is "binary"
228+ HasNonStringArgs bool // true if any arg needs strconv parsing
229+ HasNonStringArrayFlags bool // true if any flag is a non-string array type needing strconv
230+ HasObjectFlags bool // true if any flag is type "object" or "object[]"
231+ IsBinaryOutput bool // true if tool output format is "binary"
232+ Entrypoint string // executable path from manifest tool.Entrypoint
231233}
232234
233235type goModData struct {
@@ -317,9 +319,15 @@ func toolSummaries(m manifest.Toolkit) []toolSummary {
317319func buildToolData (m manifest.Toolkit , tool manifest.Tool , auth manifest.Auth ) toolGoData {
318320 args := make ([]argData , len (tool .Args ))
319321 for i , a := range tool .Args {
322+ gn := goIdentifier (a .Name )
323+ gnCap := gn
324+ if len (gn ) > 0 {
325+ gnCap = strings .ToUpper (gn [:1 ]) + gn [1 :]
326+ }
320327 args [i ] = argData {
321328 Name : a .Name ,
322- GoName : goIdentifier (a .Name ),
329+ GoName : gn ,
330+ GoNameCap : gnCap ,
323331 GoType : goType (a .Type ),
324332 Required : a .Required ,
325333 Description : a .Description ,
@@ -413,6 +421,7 @@ func buildToolData(m manifest.Toolkit, tool manifest.Tool, auth manifest.Auth) t
413421 HasNonStringArrayFlags : hasNonStringArrayFlags ,
414422 HasObjectFlags : hasObjectFlags ,
415423 IsBinaryOutput : tool .Output .Format == "binary" ,
424+ Entrypoint : tool .Entrypoint ,
416425 }
417426}
418427
@@ -694,6 +703,7 @@ import (
694703{{- $authType := .AuthType}}
695704{{- $tokenEnv := .TokenEnv}}
696705{{- $tokenFlag := .TokenFlag}}
706+ {{- $entrypoint := .Entrypoint}}
697707var (
698708{{- range .Flags}}
699709{{- if .IsArray}}
@@ -740,114 +750,158 @@ var {{.GoName}}Cmd = &cobra.Command{
740750 RunE: func(cmd *cobra.Command, args []string) error {
741751{{- range $i, $a := .Args}}
742752{{- if eq $a.GoType "string"}}
743- arg{{$a.GoName }} := args[{{$i}}] // {{$a.GoType}}
753+ arg{{$a.GoNameCap }} := args[{{$i}}] // {{$a.GoType}}
744754{{- else if eq $a.GoType "int"}}
745- arg{{$a.GoName }}, err := strconv.Atoi(args[{{$i}}]) // {{$a.GoType}}
755+ arg{{$a.GoNameCap }}, err := strconv.Atoi(args[{{$i}}]) // {{$a.GoType}}
746756 if err != nil {
747757 return fmt.Errorf("invalid value %q for argument {{$a.Name}}: %w", args[{{$i}}], err)
748758 }
749759{{- else if eq $a.GoType "float64"}}
750- arg{{$a.GoName }}, err := strconv.ParseFloat(args[{{$i}}], 64) // {{$a.GoType}}
760+ arg{{$a.GoNameCap }}, err := strconv.ParseFloat(args[{{$i}}], 64) // {{$a.GoType}}
751761 if err != nil {
752762 return fmt.Errorf("invalid value %q for argument {{$a.Name}}: %w", args[{{$i}}], err)
753763 }
754764{{- else if eq $a.GoType "bool"}}
755- arg{{$a.GoName }}, err := strconv.ParseBool(args[{{$i}}]) // {{$a.GoType}}
765+ arg{{$a.GoNameCap }}, err := strconv.ParseBool(args[{{$i}}]) // {{$a.GoType}}
756766 if err != nil {
757767 return fmt.Errorf("invalid value %q for argument {{$a.Name}}: %w", args[{{$i}}], err)
758768 }
759769{{- end}}
760- _ = arg{{$a.GoName}}
770+ {{- end}}
771+ {{- if $hasAuth}}
772+ // Resolve auth token: prefer flag, fall back to env var.
773+ token := {{$goName}}Token
774+ if token == "" {
775+ token = os.Getenv("{{$tokenEnv | esc}}")
776+ }
777+ if token == "" {
778+ return fmt.Errorf("auth required: set {{$tokenEnv | esc}} or pass --{{$tokenFlag | esc}}")
779+ }
780+ {{- end}}
781+ entrypoint := "{{$entrypoint | esc}}"
782+ if entrypoint == "" {
783+ return fmt.Errorf("{{$toolName}}: entrypoint not configured")
784+ }
785+ var cliArgs []string
786+ {{- range $i, $a := .Args}}
787+ {{- if eq $a.GoType "string"}}
788+ cliArgs = append(cliArgs, arg{{$a.GoNameCap}})
789+ {{- else if eq $a.GoType "int"}}
790+ cliArgs = append(cliArgs, fmt.Sprintf("%d", arg{{$a.GoNameCap}}))
791+ {{- else if eq $a.GoType "float64"}}
792+ cliArgs = append(cliArgs, fmt.Sprintf("%g", arg{{$a.GoNameCap}}))
793+ {{- else if eq $a.GoType "bool"}}
794+ cliArgs = append(cliArgs, strconv.FormatBool(arg{{$a.GoNameCap}}))
795+ {{- end}}
761796{{- end}}
762797{{- range .Flags}}
763798{{- if .IsArray}}
764- {{- if eq .ArrayBase "int"}}
765- parsed{{.GoName}} := make([]int, len({{$goName}}Flag{{.GoName}}))
766- for i, s := range {{$goName}}Flag{{.GoName}} {
767- v, err := strconv.Atoi(s)
768- if err != nil {
769- return fmt.Errorf("invalid value %q for element of --{{.Name}}: not a valid int", s)
799+ {{- if eq .ArrayBase "string"}}
800+ for _, v := range {{$goName}}Flag{{.GoName}} {
801+ cliArgs = append(cliArgs, "--{{.Name}}", v)
802+ }
803+ {{- else if eq .ArrayBase "int"}}
804+ {
805+ parsed{{.GoName}} := make([]int, len({{$goName}}Flag{{.GoName}}))
806+ for i, s := range {{$goName}}Flag{{.GoName}} {
807+ v, err := strconv.Atoi(s)
808+ if err != nil {
809+ return fmt.Errorf("invalid value %q for element of --{{.Name}}: not a valid int", s)
810+ }
811+ parsed{{.GoName}}[i] = v
812+ }
813+ for _, v := range parsed{{.GoName}} {
814+ cliArgs = append(cliArgs, "--{{.Name}}", strconv.Itoa(v))
770815 }
771- parsed{{.GoName}}[i] = v
772816 }
773- _ = parsed{{.GoName}}
774817{{- else if eq .ArrayBase "float"}}
775- parsed{{.GoName}} := make([]float64, len({{$goName}}Flag{{.GoName}}))
776- for i, s := range {{$goName}}Flag{{.GoName}} {
777- v, err := strconv.ParseFloat(s, 64)
778- if err != nil {
779- return fmt.Errorf("invalid value %q for element of --{{.Name}}: not a valid float", s)
818+ {
819+ parsed{{.GoName}} := make([]float64, len({{$goName}}Flag{{.GoName}}))
820+ for i, s := range {{$goName}}Flag{{.GoName}} {
821+ v, err := strconv.ParseFloat(s, 64)
822+ if err != nil {
823+ return fmt.Errorf("invalid value %q for element of --{{.Name}}: not a valid float", s)
824+ }
825+ parsed{{.GoName}}[i] = v
826+ }
827+ for _, v := range parsed{{.GoName}} {
828+ cliArgs = append(cliArgs, "--{{.Name}}", fmt.Sprintf("%g", v))
780829 }
781- parsed{{.GoName}}[i] = v
782830 }
783- _ = parsed{{.GoName}}
784831{{- else if eq .ArrayBase "bool"}}
785- parsed{{.GoName}} := make([]bool, len({{$goName}}Flag{{.GoName}}))
786- for i, s := range {{$goName}}Flag{{.GoName}} {
787- v, err := strconv.ParseBool(s)
788- if err != nil {
789- return fmt.Errorf("invalid value %q for element of --{{.Name}}: not a valid bool", s)
832+ {
833+ parsed{{.GoName}} := make([]bool, len({{$goName}}Flag{{.GoName}}))
834+ for i, s := range {{$goName}}Flag{{.GoName}} {
835+ v, err := strconv.ParseBool(s)
836+ if err != nil {
837+ return fmt.Errorf("invalid value %q for element of --{{.Name}}: not a valid bool", s)
838+ }
839+ parsed{{.GoName}}[i] = v
840+ }
841+ for _, v := range parsed{{.GoName}} {
842+ cliArgs = append(cliArgs, "--{{.Name}}", strconv.FormatBool(v))
790843 }
791- parsed{{.GoName}}[i] = v
792844 }
793- _ = parsed{{.GoName}}
794- {{- end}}
795845{{- end}}
796- {{- end}}
797- {{- range .Flags}}
798- {{- if .IsObject}}
846+ {{- else if .IsObject}}
847+ if {{$goName}}Flag{{.GoName}} != "" {
799848{{- if .IsObjectArray}}
800- var parsed{{.GoName}} []map[string]any
801- if err := json.Unmarshal([]byte({{$goName}}Flag{{.GoName}}), &parsed{{.GoName}}); err != nil {
802- return fmt.Errorf("invalid JSON for --{{.Name}}: %w", err)
803- }
849+ var parsed{{.GoName}} []map[string]any
850+ if err := json.Unmarshal([]byte({{$goName}}Flag{{.GoName}}), &parsed{{.GoName}}); err != nil {
851+ return fmt.Errorf("invalid JSON for --{{.Name}}: %w", err)
852+ }
804853{{- if .HasItemSchema}}
805- for _idx, _elem := range parsed{{.GoName}} {
806- for _, _field := range []string{ {{joinQuoted .ItemSchemaProperties}} } {
807- if _, ok := _elem[_field]; !ok {
808- return fmt.Errorf("--{{.Name}}[%d]: required field %q missing from JSON object", _idx, _field)
854+ for _idx, _elem := range parsed{{.GoName}} {
855+ for _, _field := range []string{ {{joinQuoted .ItemSchemaProperties}} } {
856+ if _, ok := _elem[_field]; !ok {
857+ return fmt.Errorf("--{{.Name}}[%d]: required field %q missing from JSON object", _idx, _field)
858+ }
809859 }
810860 }
811- }
812861{{- end}}
813862{{- else}}
814- var parsed{{.GoName}} map[string]any
815- if err := json.Unmarshal([]byte({{$goName}}Flag{{.GoName}}), &parsed{{.GoName}}); err != nil {
816- return fmt.Errorf("invalid JSON for --{{.Name}}: %w", err)
817- }
863+ var parsed{{.GoName}} map[string]any
864+ if err := json.Unmarshal([]byte({{$goName}}Flag{{.GoName}}), &parsed{{.GoName}}); err != nil {
865+ return fmt.Errorf("invalid JSON for --{{.Name}}: %w", err)
866+ }
818867{{- if .HasItemSchema}}
819- for _, _field := range []string{ {{joinQuoted .ItemSchemaProperties}} } {
820- if _, ok := parsed{{.GoName}}[_field]; !ok {
821- return fmt.Errorf("--{{.Name}}: required field %q missing from JSON object", _field)
868+ for _, _field := range []string{ {{joinQuoted .ItemSchemaProperties}} } {
869+ if _, ok := parsed{{.GoName}}[_field]; !ok {
870+ return fmt.Errorf("--{{.Name}}: required field %q missing from JSON object", _field)
871+ }
822872 }
823- }
824873{{- end}}
825874{{- end}}
826- _ = parsed{{.GoName}}
875+ cliArgs = append(cliArgs, "--{{.Name}}", {{$goName}}Flag{{.GoName}})
876+ }
877+ {{- else if eq .GoType "bool"}}
878+ if {{$goName}}Flag{{.GoName}} {
879+ cliArgs = append(cliArgs, "--{{.Name}}")
880+ }
881+ {{- else if eq .GoType "string"}}
882+ if {{$goName}}Flag{{.GoName}} != "" {
883+ cliArgs = append(cliArgs, "--{{.Name}}", {{$goName}}Flag{{.GoName}})
884+ }
885+ {{- else if eq .GoType "int"}}
886+ cliArgs = append(cliArgs, "--{{.Name}}", fmt.Sprintf("%d", {{$goName}}Flag{{.GoName}}))
887+ {{- else if eq .GoType "float64"}}
888+ cliArgs = append(cliArgs, "--{{.Name}}", fmt.Sprintf("%g", {{$goName}}Flag{{.GoName}}))
827889{{- end}}
828890{{- end}}
829891{{- if $hasAuth}}
830- // Resolve auth token: prefer flag, fall back to env var.
831- token := {{$goName}}Token
832- if token == "" {
833- token = os.Getenv("{{$tokenEnv | esc}}")
834- }
835- if token == "" {
836- return fmt.Errorf("auth required: set {{$tokenEnv | esc}} or pass --{{$tokenFlag | esc}}")
837- }
838- _ = token // passed to the entrypoint via environment
892+ cliArgs = append(cliArgs, "--{{$tokenFlag | esc}}", token)
839893{{- end}}
894+ ctx := cmd.Context()
840895{{- if .IsBinaryOutput}}
841- // Binary output: detect TTY and handle appropriately.
896+ // Binary output handling
842897 fi, statErr := os.Stdout.Stat()
843898 isTTY := statErr == nil && (fi.Mode()&os.ModeCharDevice) != 0
844899 if isTTY && {{$goName}}FlagOutput == "" {
845900 return fmt.Errorf("binary output requires --output <file> or pipe")
846901 }
847- c := exec.CommandContext(cmd.Context(), "echo", "running", "{{$toolName}}" )
902+ c := exec.CommandContext(ctx, entrypoint, cliArgs... )
848903 c.Stderr = os.Stderr
849904 if {{$goName}}FlagOutput != "" {
850- // --output provided: capture stdout and write to file.
851905 out, err := c.Output()
852906 if err != nil {
853907 return fmt.Errorf("{{$toolName}} failed: %w", err)
@@ -856,15 +910,14 @@ var {{.GoName}}Cmd = &cobra.Command{
856910 return fmt.Errorf("writing output file: %w", err)
857911 }
858912 } else {
859- // No --output: stream directly to stdout (pipe mode).
860913 c.Stdout = os.Stdout
861914 if err := c.Run(); err != nil {
862915 return fmt.Errorf("{{$toolName}} failed: %w", err)
863916 }
864917 }
865918{{- else}}
866919 // Execute the tool entrypoint.
867- c := exec.CommandContext(cmd.Context(), "echo", "running", "{{$toolName}}" )
920+ c := exec.CommandContext(ctx, entrypoint, cliArgs... )
868921 c.Stdout = os.Stdout
869922 c.Stderr = os.Stderr
870923 if err := c.Run(); err != nil {
0 commit comments