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
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ The runtime system provides a pluggable architecture for managing workspaces on

**Optional Interfaces:**
- **StorageAware**: Enables runtimes to persist data in a dedicated storage directory
- **AgentLister**: Enables runtimes to report which agents they support
- **Terminal**: Enables interactive terminal sessions with running instances

**For detailed runtime implementation guidance, use:** `/working-with-runtime-system`
Expand Down
57 changes: 57 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1854,6 +1854,63 @@ The system works without any configuration files and merges only the ones that e

## Commands

### `info` - Display Information About kortex-cli

Displays version, available agents, and supported runtimes.

#### Usage

```bash
kortex-cli info [flags]
```

#### Flags

- `--output, -o <format>` - Output format (supported: `json`)
- `--storage <path>` - Storage directory for kortex-cli data (default: `$HOME/.kortex-cli`)

#### Examples

**Show info (human-readable format):**
```bash
kortex-cli info
```
Output:
```text
Version: 0.3.0
Agents: claude
Runtimes: fake, podman
```

**Show info in JSON format:**
```bash
kortex-cli info --output json
```
Output:
```json
{
"version": "0.3.0",
"agents": [
"claude"
],
"runtimes": [
"fake",
"podman"
]
}
```

**Show info using short flag:**
```bash
kortex-cli info -o json
```

#### Notes

- Agents are discovered from runtimes that support agent configuration (e.g., the Podman runtime reports agents from its configuration files)
- Runtimes are listed based on availability in the current environment (e.g., the Podman runtime only appears if the `podman` CLI is installed)
- **JSON error handling**: When `--output json` is used, errors are written to stdout (not stderr) in JSON format, and the CLI exits with code 1. Always check the exit code to determine success/failure

### `init` - Register a New Workspace

Registers a new workspace with kortex-cli, making it available for agent launch and configuration.
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.26.1
require (
github.com/fatih/color v1.19.0
github.com/goccy/go-yaml v1.19.2
github.com/kortex-hub/kortex-cli-api/cli/go v0.0.0-20260402113340-592f26f380bc
github.com/kortex-hub/kortex-cli-api/cli/go v0.0.0-20260403083702-361dae1613c4
github.com/kortex-hub/kortex-cli-api/workspace-configuration/go v0.0.0-20260331070743-a7c5f045c21c
github.com/rodaine/table v1.3.1
github.com/spf13/cobra v1.10.2
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/kortex-hub/kortex-cli-api/cli/go v0.0.0-20260402113340-592f26f380bc h1:7/9dbYdsvDPNduAN/Uq8dUDH9BYUbeG0yVZ2JEuhY+k=
github.com/kortex-hub/kortex-cli-api/cli/go v0.0.0-20260402113340-592f26f380bc/go.mod h1:jWKudiw26CIjuOsROQ80FOuuk2m2/5BVkuATpmD5xQQ=
github.com/kortex-hub/kortex-cli-api/cli/go v0.0.0-20260403083702-361dae1613c4 h1:pPnBONB9KiWDl6UrNBkeQYeasFddAiDvqNn8NH8RLX0=
github.com/kortex-hub/kortex-cli-api/cli/go v0.0.0-20260403083702-361dae1613c4/go.mod h1:jWKudiw26CIjuOsROQ80FOuuk2m2/5BVkuATpmD5xQQ=
github.com/kortex-hub/kortex-cli-api/workspace-configuration/go v0.0.0-20260331070743-a7c5f045c21c h1:kFz1ImgIiAJEmliiuASCJLKjiDIGFowLh6Fdd4hjFM8=
github.com/kortex-hub/kortex-cli-api/workspace-configuration/go v0.0.0-20260331070743-a7c5f045c21c/go.mod h1:N4tLoDdBbAPYJ9ALLfYbqYScydJb546JgKQ6EjHswLw=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
Expand Down
11 changes: 1 addition & 10 deletions pkg/cmd/autocomplete.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,19 +119,10 @@ func newOutputFlagCompletion(validFormats []string) func(cmd *cobra.Command, arg
}

// completeRuntimeFlag provides completion for the --runtime flag
// It lists all available runtimes, excluding the "fake" runtime (used only for testing)
func completeRuntimeFlag(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
// Get all available runtimes without requiring a manager instance
// This avoids creating storage directories during tab-completion
runtimes := runtimesetup.ListAvailable()

// Filter out "fake" runtime (used only for testing)
var filteredRuntimes []string
for _, rt := range runtimes {
if rt != "fake" {
filteredRuntimes = append(filteredRuntimes, rt)
}
}

return filteredRuntimes, cobra.ShellCompDirectiveNoFileComp
return runtimes, cobra.ShellCompDirectiveNoFileComp
}
128 changes: 128 additions & 0 deletions pkg/cmd/info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
/**********************************************************************
* Copyright (C) 2026 Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
**********************************************************************/

package cmd

import (
"encoding/json"
"fmt"
"path/filepath"
"strings"

api "github.com/kortex-hub/kortex-cli-api/cli/go"
"github.com/kortex-hub/kortex-cli/pkg/runtimesetup"
"github.com/kortex-hub/kortex-cli/pkg/version"
"github.com/spf13/cobra"
)

// infoCmd contains the configuration for the info command
type infoCmd struct {
output string
}

// preRun validates the parameters and flags
func (i *infoCmd) preRun(cmd *cobra.Command, args []string) error {
// Validate output format if specified
if i.output != "" && i.output != "json" {
return fmt.Errorf("unsupported output format: %s (supported: json)", i.output)
}

return nil
}

// run executes the info command logic
func (i *infoCmd) run(cmd *cobra.Command, args []string) error {
runtimes := runtimesetup.ListAvailable()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In pkg/cmd/autocomplete.go, the fake runtime is filtered out. I think it would be helpful to move the filter inside the runtimesetup.ListAvailable method, so we don't display it here


// Discover agents from runtimes that implement AgentLister
storageDir, err := cmd.Flags().GetString("storage")
if err != nil {
return outputErrorIfJSON(cmd, i.output, fmt.Errorf("failed to read --storage flag: %w", err))
}

absStorageDir, err := filepath.Abs(storageDir)
if err != nil {
return outputErrorIfJSON(cmd, i.output, fmt.Errorf("failed to resolve storage directory path: %w", err))
}

runtimeStorageDir := filepath.Join(absStorageDir, "runtimes")
agents, err := runtimesetup.ListAgents(runtimeStorageDir)
if err != nil {
return outputErrorIfJSON(cmd, i.output, fmt.Errorf("failed to list agents: %w", err))
}

if i.output == "json" {
return i.outputJSON(cmd, agents, runtimes)
}

// Text output
out := cmd.OutOrStdout()
fmt.Fprintf(out, "Version: %s\n", version.Version)
fmt.Fprintf(out, "Agents: %s\n", strings.Join(agents, ", "))
fmt.Fprintf(out, "Runtimes: %s\n", strings.Join(runtimes, ", "))

return nil
}

// outputJSON outputs the info response as JSON
func (i *infoCmd) outputJSON(cmd *cobra.Command, agents, runtimes []string) error {
if agents == nil {
agents = []string{}
}
if runtimes == nil {
runtimes = []string{}
}
response := api.Info{
Version: version.Version,
Agents: agents,
Runtimes: runtimes,
}

jsonData, err := json.MarshalIndent(response, "", " ")
if err != nil {
return outputErrorIfJSON(cmd, i.output, fmt.Errorf("failed to marshal info to JSON: %w", err))
}

fmt.Fprintln(cmd.OutOrStdout(), string(jsonData))
return nil
}

func NewInfoCmd() *cobra.Command {
c := &infoCmd{}

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

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

# Show info using short flag
kortex-cli info -o json`,
Args: cobra.NoArgs,
PreRunE: c.preRun,
RunE: c.run,
}

cmd.Flags().StringVarP(&c.output, "output", "o", "", "Output format (supported: json)")
cmd.RegisterFlagCompletionFunc("output", newOutputFlagCompletion([]string{"json"}))

return cmd
}
Loading
Loading