Skip to content
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
2 changes: 1 addition & 1 deletion .github/workflows/pr-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ jobs:
run: make build

- name: Verify binary
run: ./kortex-cli version
run: ./kdn version

- name: Generate coverage report
if: matrix.os == 'ubuntu-24.04'
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ coverage.html
go.work

# Build artifacts
/kortex-cli
/kdn
dist/

# MkDocs build output
Expand Down
4 changes: 2 additions & 2 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ before:
- go mod tidy

builds:
- main: ./cmd/kortex-cli
binary: kortex-cli
- main: ./cmd/kdn
binary: kdn
ldflags:
- -s -w
- -X github.com/kortex-hub/kortex-cli/pkg/version.Version={{.Version}}
Expand Down
12 changes: 6 additions & 6 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ This file provides guidance to AI agents when working with code in this reposito

## Project Overview

kortex-cli is a command-line interface for launching and managing AI agents (Claude Code, Goose, Cursor) with custom configurations. It provides a unified way to start different agents with specific settings including skills, MCP server connections, and LLM integrations.
kdn is a command-line interface for launching and managing AI agents (Claude Code, Goose, Cursor) with custom configurations. It provides a unified way to start different agents with specific settings including skills, MCP server connections, and LLM integrations.

## Build and Test Commands

Expand All @@ -16,14 +16,14 @@ make build
```

### Execute
After building, the `kortex-cli` binary will be created in the current directory:
After building, the `kdn` binary will be created in the current directory:

```bash
# Display help and available commands
./kortex-cli --help
./kdn --help

# Execute a specific command
./kortex-cli <command> [flags]
./kdn <command> [flags]
```

### Run Tests
Expand Down Expand Up @@ -73,7 +73,7 @@ make install
## Architecture

### Command Structure (Cobra-based)
- Entry point: `cmd/kortex-cli/main.go` → calls `cmd.NewRootCmd().Execute()` and handles errors with `os.Exit(1)`
- Entry point: `cmd/kdn/main.go` → calls `cmd.NewRootCmd().Execute()` and handles errors with `os.Exit(1)`
- Root command: `pkg/cmd/root.go` exports `NewRootCmd()` which creates and configures the root command
- Subcommands: Each command is in `pkg/cmd/<command>.go` with a `New<Command>Cmd()` factory function
- Commands use a factory pattern: each command exports a `New<Command>Cmd()` function that returns `*cobra.Command`
Expand All @@ -84,7 +84,7 @@ make install
Global flags are defined as persistent flags in `pkg/cmd/root.go` and are available to all commands.

#### Accessing the --storage Flag
The `--storage` flag specifies the directory where kortex-cli stores all its files. The default path is computed at runtime using `os.UserHomeDir()` and `filepath.Join()` to ensure cross-platform compatibility (Linux, macOS, Windows). The default is `$HOME/.kortex-cli` with a fallback to `.kortex-cli` in the current directory if the home directory cannot be determined.
The `--storage` flag specifies the directory where kdn stores all its files. The default path is computed at runtime using `os.UserHomeDir()` and `filepath.Join()` to ensure cross-platform compatibility (Linux, macOS, Windows). The default is `$HOME/.kortex-cli` with a fallback to `.kortex-cli` in the current directory if the home directory cannot be determined.

**Environment Variable**: The `KORTEX_CLI_STORAGE` environment variable can be used to set the storage directory path. The flag `--storage` will override the environment variable if both are specified.

Expand Down
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
.PHONY: help build test test-coverage fmt vet clean install check-fmt check-vet ci-checks all

# Binary name
BINARY_NAME=kortex-cli
BINARY_NAME=kdn
# Build output directory
BUILD_DIR=.
# Go command
Expand All @@ -31,14 +31,14 @@ all: build
help: ## Display this help message
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {sub("\\\\n",sprintf("\n%22c"," "), $$2);printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)

build: ## Build the kortex-cli binary
build: ## Build the kdn binary
build:
@echo "Building $(BINARY_NAME)..."
$(GO) build -o $(BUILD_DIR)/$(BINARY_NAME) ./cmd/kortex-cli
$(GO) build -o $(BUILD_DIR)/$(BINARY_NAME) ./cmd/kdn

install: ## Install the binary to GOPATH/bin
@echo "Installing $(BINARY_NAME)..."
$(GO) install ./cmd/kortex-cli
$(GO) install ./cmd/kdn

test: ## Run all tests
@echo "Running tests..."
Expand Down
392 changes: 196 additions & 196 deletions README.md

Large diffs are not rendered by default.

File renamed without changes.
2 changes: 1 addition & 1 deletion cmd/kortex-cli/main_test.go → cmd/kdn/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func TestMain_VersionSubcommand(t *testing.T) {
defer func() { os.Args = oldArgs }()

// Set os.Args to call the version subcommand
os.Args = []string{"kortex-cli", "version"}
os.Args = []string{"kdn", "version"}

// Call main() - test passes if it doesn't panic
main()
Expand Down
12 changes: 6 additions & 6 deletions pkg/cmd/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,26 @@ import "strings"
// Example:
//
// original := `# List all workspaces
// kortex-cli workspace list
// kdn workspace list
//
// # List in JSON format
// kortex-cli workspace list --output json`
// kdn workspace list --output json`
//
// adapted := AdaptExampleForAlias(original, "workspace list", "list")
// // Result:
// // `# List all workspaces
// // kortex-cli list
// // kdn list
// //
// // # List in JSON format
// // kortex-cli list --output json`
// // kdn list --output json`
func AdaptExampleForAlias(example, originalCmd, aliasCmd string) string {
lines := strings.Split(example, "\n")
var result []string

for _, line := range lines {
trimmed := strings.TrimSpace(line)
// Only replace in command lines (starting with kortex-cli), not in comments
if strings.HasPrefix(trimmed, "kortex-cli ") {
// Only replace in command lines (starting with kdn), not in comments
if strings.HasPrefix(trimmed, "kdn ") {
line = strings.Replace(line, originalCmd, aliasCmd, 1)
}
result = append(result, line)
Expand Down
36 changes: 18 additions & 18 deletions pkg/cmd/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,59 +29,59 @@ func TestAdaptExampleForAlias(t *testing.T) {
{
name: "replaces command in simple example",
example: `# List all workspaces
kortex-cli workspace list`,
kdn workspace list`,
originalCmd: "workspace list",
aliasCmd: "list",
want: `# List all workspaces
kortex-cli list`,
kdn list`,
},
{
name: "replaces command with flags",
example: `# List workspaces in JSON format
kortex-cli workspace list --output json`,
kdn workspace list --output json`,
originalCmd: "workspace list",
aliasCmd: "list",
want: `# List workspaces in JSON format
kortex-cli list --output json`,
kdn list --output json`,
},
{
name: "replaces multiple occurrences",
example: `# List all workspaces
kortex-cli workspace list
kdn workspace list

# List in JSON format
kortex-cli workspace list --output json
kdn workspace list --output json

# List using short flag
kortex-cli workspace list -o json`,
kdn workspace list -o json`,
originalCmd: "workspace list",
aliasCmd: "list",
want: `# List all workspaces
kortex-cli list
kdn list

# List in JSON format
kortex-cli list --output json
kdn list --output json

# List using short flag
kortex-cli list -o json`,
kdn list -o json`,
},
{
name: "does not replace in comments",
example: `# Use workspace list to see all workspaces
kortex-cli workspace list`,
kdn workspace list`,
originalCmd: "workspace list",
aliasCmd: "list",
want: `# Use workspace list to see all workspaces
kortex-cli list`,
kdn list`,
},
{
name: "replaces remove command",
example: `# Remove workspace by ID
kortex-cli workspace remove abc123`,
kdn workspace remove abc123`,
originalCmd: "workspace remove",
aliasCmd: "remove",
want: `# Remove workspace by ID
kortex-cli remove abc123`,
kdn remove abc123`,
},
{
name: "handles empty example",
Expand All @@ -93,17 +93,17 @@ kortex-cli remove abc123`,
{
name: "preserves indentation",
example: `# List all workspaces
kortex-cli workspace list
kdn workspace list

# Another example
kortex-cli workspace list --output json`,
kdn workspace list --output json`,
originalCmd: "workspace list",
aliasCmd: "list",
want: `# List all workspaces
kortex-cli list
kdn list

# Another example
kortex-cli list --output json`,
kdn list --output json`,
},
}

Expand Down
8 changes: 4 additions & 4 deletions pkg/cmd/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,15 @@ func NewInfoCmd() *cobra.Command {

cmd := &cobra.Command{
Use: "info",
Short: "Display information about kortex-cli",
Short: "Display information about kdn",
Example: `# Show info
kortex-cli info
kdn info

# Show info in JSON format
kortex-cli info --output json
kdn info --output json

# Show info using short flag
kortex-cli info -o json`,
kdn info -o json`,
Args: cobra.NoArgs,
PreRunE: c.preRun,
RunE: c.run,
Expand Down
16 changes: 8 additions & 8 deletions pkg/cmd/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,28 +301,28 @@ func NewInitCmd() *cobra.Command {
The sources directory defaults to the current directory (.) if not specified.
The workspace configuration directory defaults to .kaiden/ inside the sources directory if not specified.`,
Example: `# Register current directory as workspace
kortex-cli init --runtime podman --agent claude
kdn init --runtime podman --agent claude

# Register specific directory as workspace
kortex-cli init --runtime podman --agent claude /path/to/project
kdn init --runtime podman --agent claude /path/to/project

# Register with custom workspace name
kortex-cli init --runtime podman --agent claude --name my-project
kdn init --runtime podman --agent claude --name my-project

# Register with custom project identifier
kortex-cli init --runtime podman --agent goose --project my-custom-project
kdn init --runtime podman --agent goose --project my-custom-project

# Register with a specific model
kortex-cli init --runtime podman --agent claude --model claude-sonnet-4-20250514
kdn init --runtime podman --agent claude --model claude-sonnet-4-20250514

# Register and start workspace
kortex-cli init --runtime podman --agent claude --start
kdn init --runtime podman --agent claude --start

# Show detailed output
kortex-cli init --runtime podman --agent claude --verbose
kdn init --runtime podman --agent claude --verbose

# Show runtime command output
kortex-cli init --runtime podman --agent claude --show-logs`,
kdn init --runtime podman --agent claude --show-logs`,
Args: cobra.MaximumNArgs(1),
PreRunE: c.preRun,
RunE: c.run,
Expand Down
4 changes: 2 additions & 2 deletions pkg/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func NewRootCmd() *cobra.Command {
}

rootCmd := &cobra.Command{
Use: "kortex-cli",
Use: "kdn",
Short: "Launch and manage AI agent workspaces with custom configurations",
Args: cobra.NoArgs,
SilenceUsage: true,
Expand Down Expand Up @@ -89,7 +89,7 @@ func NewRootCmd() *cobra.Command {
rootCmd.AddCommand(NewInfoCmd())

// Global flags
rootCmd.PersistentFlags().String("storage", defaultStoragePath, "Directory where kortex-cli will store all its files")
rootCmd.PersistentFlags().String("storage", defaultStoragePath, "Directory where kdn will store all its files")

return rootCmd
}
4 changes: 2 additions & 2 deletions pkg/cmd/root_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ func TestRootCmd_Initialization(t *testing.T) {
t.Parallel()

rootCmd := NewRootCmd()
if rootCmd.Use != "kortex-cli" {
t.Errorf("Expected Use to be 'kortex-cli', got '%s'", rootCmd.Use)
if rootCmd.Use != "kdn" {
t.Errorf("Expected Use to be 'kdn', got '%s'", rootCmd.Use)
}

if rootCmd.Short == "" {
Expand Down
8 changes: 4 additions & 4 deletions pkg/cmd/terminal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,12 @@ func TestTerminalCmd_ExamplesAdapted(t *testing.T) {
terminalCmd := NewTerminalCmd()

// Verify examples are adapted
if !strings.Contains(terminalCmd.Example, "kortex-cli terminal") {
t.Error("Expected examples to contain 'kortex-cli terminal'")
if !strings.Contains(terminalCmd.Example, "kdn terminal") {
t.Error("Expected examples to contain 'kdn terminal'")
}

if strings.Contains(terminalCmd.Example, "kortex-cli workspace terminal") {
t.Error("Examples should not contain 'kortex-cli workspace terminal'")
if strings.Contains(terminalCmd.Example, "kdn workspace terminal") {
t.Error("Examples should not contain 'kdn workspace terminal'")
}
}

Expand Down
12 changes: 6 additions & 6 deletions pkg/cmd/testutil/example_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,16 @@ import (
// ExampleCommand represents a parsed command from an Example string
type ExampleCommand struct {
Raw string // Original command line
Binary string // Binary name (should be "kortex-cli")
Binary string // Binary name (should be "kdn")
Args []string // Subcommands and positional arguments
FlagPresent map[string]bool // Flags that were present in the command
FlagValues map[string]string // Values for flags (empty string if no value provided)
Flags map[string]string // Deprecated: use FlagPresent and FlagValues instead
}

// ParseExampleCommands extracts kortex-cli commands from Example string
// ParseExampleCommands extracts kdn commands from Example string
// - Ignores empty lines and comment lines (starting with #)
// - Returns error if non-comment, non-kortex-cli lines exist
// - Returns error if non-comment, non-kdn lines exist
func ParseExampleCommands(example string) ([]ExampleCommand, error) {
var commands []ExampleCommand
lines := strings.Split(example, "\n")
Expand Down Expand Up @@ -72,9 +72,9 @@ func parseCommandLine(line string) (ExampleCommand, error) {
return ExampleCommand{}, fmt.Errorf("empty command line")
}

// First part should be kortex-cli
if parts[0] != "kortex-cli" {
return ExampleCommand{}, fmt.Errorf("command must start with 'kortex-cli', got '%s'", parts[0])
// First part should be kdn
if parts[0] != "kdn" {
return ExampleCommand{}, fmt.Errorf("command must start with 'kdn', got '%s'", parts[0])
}

cmd := ExampleCommand{
Expand Down
Loading
Loading