feat(cli): add cobra-based CLI with subcommands

Replace simple argument parsing with cobra to provide better CLI experience:

- Add 'execute' subcommand for running TypeScript files
- Add 'types' subcommand for printing TypeScript type declarations
- Add help text and error handling
- Update documentation with new usage examples

Add dependencies: github.com/spf13/cobra, github.com/spf13/pflag
This commit is contained in:
2026-01-29 20:07:35 -05:00
parent ccbe9cd7bf
commit 23730868b8
5 changed files with 73 additions and 25 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
.opencode

View File

@@ -48,6 +48,12 @@ The project is cleanly separated into three packages:
go build ./cmd/poiesis
```
## CLI Options
- `[file]` - Path to TypeScript file to execute (optional)
- `--print-types` - Print TypeScript type declarations for all registered functions
- `--help` - Show help information
## Testing
```bash
@@ -58,8 +64,9 @@ golangci-lint run
## Usage
```bash
poiesis <typescript-file>
poiesis -print-types
poiesis execute [file] # Run TypeScript file
poiesis types # Print TypeScript type declarations
poiesis --help # Show help
```
## Function System

View File

@@ -5,36 +5,64 @@ import (
"fmt"
"os"
"github.com/spf13/cobra"
"reichard.io/poiesis/internal/runtime"
)
func main() {
// Validate Arguments
if len(os.Args) < 2 {
fmt.Fprintln(os.Stderr, "Usage: poiesis <typescript-file>")
fmt.Fprintln(os.Stderr, " poiesis -print-types")
os.Exit(1)
}
// Print Types
if os.Args[1] == "-print-types" {
rt, err := runtime.New(context.Background())
var runCmd = &cobra.Command{
Use: "execute [file]",
Short: "Transpile and execute TypeScript code",
Long: `Poiesis transpiles TypeScript to JavaScript using esbuild and executes it with QuickJS.
It also provides a builtin system for exposing Go functions to TypeScript.`,
Args: cobra.MaximumNArgs(1),
Run: func(cmd *cobra.Command, args []string) {
ctx := context.Background()
rt, err := runtime.New(ctx)
if err != nil {
panic(err)
fmt.Fprintf(os.Stderr, "Failed to create runtime: %v\n", err)
os.Exit(1)
}
if len(args) == 0 {
fmt.Fprintln(os.Stderr, "Usage: poiesis execute [file]")
cmd.Help()
os.Exit(1)
}
if err := rt.RunFile(args[0]); err != nil {
fmt.Fprintf(os.Stderr, "Failed to run file: %v\n", err)
os.Exit(1)
}
},
}
var typesCmd = &cobra.Command{
Use: "types",
Short: "Print TypeScript type declarations",
Run: func(cmd *cobra.Command, args []string) {
ctx := context.Background()
rt, err := runtime.New(ctx)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to create runtime: %v\n", err)
os.Exit(1)
}
fmt.Println(rt.GetTypeDeclarations())
return
}
},
}
// Create Runtime
rt, err := runtime.New(context.Background())
if err != nil {
panic(err)
}
var rootCmd = &cobra.Command{
Use: "poiesis",
Short: "TypeScript transpiler and executor",
}
// Run File
filePath := os.Args[1]
if err := rt.RunFile(filePath); err != nil {
panic(err)
func init() {
rootCmd.AddCommand(runCmd)
rootCmd.AddCommand(typesCmd)
}
func main() {
if err := rootCmd.Execute(); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
}

3
go.mod
View File

@@ -10,7 +10,10 @@ require (
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/spf13/cobra v1.10.2 // indirect
github.com/spf13/pflag v1.0.9 // indirect
github.com/tetratelabs/wazero v1.9.0 // indirect
golang.org/x/sys v0.37.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect

9
go.sum
View File

@@ -1,15 +1,24 @@
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/evanw/esbuild v0.27.2 h1:3xBEws9y/JosfewXMM2qIyHAi+xRo8hVx475hVkJfNg=
github.com/evanw/esbuild v0.27.2/go.mod h1:D2vIQZqV/vIf/VRHtViaUtViZmG7o+kKmlBfVQuRi48=
github.com/fastschema/qjs v0.0.6 h1:C45KMmQMd21UwsUAmQHxUxiWOfzwTg1GJW0DA0AbFEE=
github.com/fastschema/qjs v0.0.6/go.mod h1:bbg36wxXnx8g0FdKIe5+nCubrQvHa7XEVWqUptjHt/A=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I=
github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=