Skip to content
Draft
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
63 changes: 34 additions & 29 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ ARG DOCKER_REGISTRY=ghcr.io
ARG TOOLS_UV_VERSION=latest

### STAGE 1: base image
FROM $DOCKER_REGISTRY/astral-sh/uv:${TOOLS_UV_VERSION}-bookworm-slim AS base-os
ARG TOOLS_NODE_VERSION
FROM $DOCKER_REGISTRY/astral-sh/uv:${TOOLS_UV_VERSION}-debian-slim AS base-os

#ENVIRONMENT VARIABLES
ENV DEBIAN_FRONTEND=noninteractive
Expand All @@ -22,6 +21,7 @@ RUN mkdir -p /etc/apt/keyrings \
&& ln -sf /usr/bin/python3 /usr/bin/python

FROM base-os AS base
ARG TOOLS_NODE_VERSION

# Install python
RUN uv python install 3.12
Expand All @@ -40,24 +40,20 @@ RUN mkdir -p $NVM_DIR \
&& nvm install $TOOLS_NODE_VERSION \
&& nvm use $TOOLS_NODE_VERSION \
&& which node && node --version \
&& ln -sf $NVM_DIR/versions/node/v$TOOLS_NODE_VERSION/bin/node /usr/bin/node
&& ln -sf $NVM_DIR/versions/node/v$TOOLS_NODE_VERSION/bin/node /usr/bin/node \
&& ln -sf $NVM_DIR/versions/node/v$TOOLS_NODE_VERSION/bin/npm /usr/bin/npm \
&& ln -sf $NVM_DIR/versions/node/v$TOOLS_NODE_VERSION/bin/npx /usr/bin/npx

### STAGE 2: build + tools
FROM --platform=$BUILDPLATFORM base-os AS builder
### STAGE 2: build + tools (extends base to inherit Node.js and Python)
FROM --platform=$BUILDPLATFORM base AS builder

ARG TARGETARCH
ARG TOOLS_ISTIO_VERSION
ARG TOOLS_ARGO_CD_VERSION

RUN apt-get update && apt-get install -y --no-install-recommends \
bsdmainutils \
build-essential \
ca-certificates \
conntrack \
curl \
gettext-base \
git \
gnupg \
gnupg2 \
htop \
iperf3 \
Expand All @@ -71,13 +67,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
lsof \
net-tools \
netcat-openbsd \
python3 \
python3-dev \
python3-pip \
python3-venv \
sshuttle \
tcpdump \
wget \
zsh \
&& curl -fsSL https://get.docker.com -o get-docker.sh \
&& sh get-docker.sh \
Expand All @@ -87,30 +81,35 @@ RUN apt-get update && apt-get install -y --no-install-recommends \

### STAGE 3 add golang
FROM builder AS node-python-golang
ARG TARGETARCH
ARG TOOLS_GO_VERSION
ARG TOOLS_K9S_VERSION
ARG TOOLS_KIND_VERSION
ARG TOOLS_ISTIO_VERSION
ARG TOOLS_ARGO_CD_VERSION
ARG TOOLS_KUBECTL_VERSION
ARG ARCH=${TARGETARCH:-amd64}

#ENVIRONMENT VARIABLES
ENV DEBIAN_FRONTEND=noninteractive
ENV GO111MODULE=on
ENV GOTOOLCHAIN=local
ENV GOPROXY="http://proxy.golang.org"
ENV PATH=$PATH:/usr/local/go/bin
ENV GOPATH=/root/go
ENV GOBIN=$GOPATH/bin
ENV GOPROXY="https://proxy.golang.org,direct"
ENV PATH=$PATH:/usr/local/go/bin:$GOPATH/bin

RUN --mount=type=cache,target=/cache,rw \
wget -q --show-progress -P /cache https://golang.org/dl/go${TOOLS_GO_VERSION}.linux-${ARCH}.tar.gz && \
tar -C /usr/local -xzf /cache/go${TOOLS_GO_VERSION}.linux-${ARCH}.tar.gz

### STAGE 3 add tools
### STAGE 4 add tools
FROM --platform=$BUILDPLATFORM node-python-golang AS tools-node-python-golang

ARG TARGETARCH
ARG ARCH=${TARGETARCH:-amd64}
ARG TOOLS_K9S_VERSION
ARG TOOLS_KIND_VERSION
ARG TOOLS_ISTIO_VERSION
ARG TOOLS_ARGO_CD_VERSION
ARG TOOLS_KUBECTL_VERSION

# Install kubectl argo plugin
RUN curl -o /usr/local/bin/kubectl-argo-rollouts -L https://github.com/argoproj/argo-rollouts/releases/${TOOLS_ARGO_CD_VERSION}/download/kubectl-argo-rollouts-linux-${ARCH} \
RUN curl -o /usr/local/bin/kubectl-argo-rollouts -L https://github.com/argoproj/argo-rollouts/releases/download/${TOOLS_ARGO_CD_VERSION}/kubectl-argo-rollouts-linux-${ARCH} \
&& chmod +x /usr/local/bin/kubectl-argo-rollouts

#Install Helm
Expand All @@ -125,7 +124,7 @@ RUN curl -L https://istio.io/downloadIstio | ISTIO_VERSION=${TOOLS_ISTIO_VERSION
&& rm -rf istio-*

# Install kind
RUN curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.27.0/kind-$(uname)-${ARCH} \
RUN curl -Lo ./kind https://kind.sigs.k8s.io/dl/v${TOOLS_KIND_VERSION}/kind-linux-${ARCH} \
&& chmod +x ./kind \
&& mv ./kind /usr/local/bin/

Expand All @@ -136,14 +135,20 @@ RUN curl -LO https://github.com/derailed/k9s/releases/download/v${TOOLS_K9S_VERS
&& chmod +x /usr/local/bin/k9s \
&& rm -f k9s_Linux_${ARCH}.tar.gz

# Install kubectl \
RUN curl -Lo /usr/local/bin/kubectl "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/${ARCH}/kubectl" \
# Install kubectl
RUN curl -Lo /usr/local/bin/kubectl "https://dl.k8s.io/release/v${TOOLS_KUBECTL_VERSION}/bin/linux/${ARCH}/kubectl" \
&& chmod +x /usr/local/bin/kubectl

RUN sh -c "$(wget https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh -O -)" \
sh -c "$(curl -fsSL https://starship.rs/install.sh)" -- --yes \
RUN sh -c "$(wget https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh -O -)" \
&& STARSHIP_SUFFIX=$(case ${ARCH} in amd64) echo x86_64-unknown-linux-gnu;; arm64) echo aarch64-unknown-linux-musl;; esac) \
&& curl -Lo starship.tar.gz "https://github.com/starship/starship/releases/latest/download/starship-${STARSHIP_SUFFIX}.tar.gz" \
&& tar -xzf starship.tar.gz -C /usr/local/bin/ \
&& rm starship.tar.gz \
&& mkdir -p /root/.config \
&& git config --global core.excludesfile /root/.gitignore_global \
&& echo "**/.idea/" > /root/.gitignore_global

ENTRYPOINT ["zsh"]
# Install Claude
RUN curl -fsSL https://claude.ai/install.sh | bash

ENTRYPOINT ["zsh"]
10 changes: 5 additions & 5 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@
"build": {
"dockerfile": "Dockerfile",
"args": {
"TOOLS_GO_VERSION": "1.25.5",
"TOOLS_GO_VERSION": "1.26.1",
"TOOLS_NODE_VERSION": "24.13.0",
"TOOLS_UV_VERSION": "0.7.2",
"TOOLS_UV_VERSION": "0.10.4",
"TOOLS_K9S_VERSION": "0.50.4",
"TOOLS_KIND_VERSION": "0.27.0",
"TOOLS_ISTIO_VERSION": "1.26.0",
"TOOLS_ARGO_CD_VERSION": "v1.8.4",
"TOOLS_KUBECTL_VERSION": "1.33.4"
}
},
"features": {
"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {},
"ghcr.io/devcontainers/features/docker-outside-of-docker:1": { "moby": false },
"ghcr.io/mpriscella/features/kind:1": {}
},
"customizations": {
Expand All @@ -35,8 +36,7 @@
"ms-vscode.vscode-typescript-next",
"ms-azuretools.vscode-containers",
"ms-windows-ai-studio.windows-ai-studio",
"GitHub.copilot",
"GitHub.copilot-chat",
"anthropic.claude-code",
"Catppuccin.catppuccin-vsc",
"Catppuccin.catppuccin-vsc-icons"
]
Expand Down
5 changes: 2 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -433,9 +433,8 @@ kagent-addon-install: use-kind-cluster

.PHONY: open-dev-container
open-dev-container:
@echo "Opening dev container..."
devcontainer build .
@devcontainer open .
@echo "Building and starting dev container..."
devcontainer up --workspace-folder .

.PHONY: otel-local
otel-local:
Expand Down
19 changes: 18 additions & 1 deletion go/core/cli/cmd/kagent/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,24 @@ Examples:
runCmd.Flags().StringVar(&runCfg.ProjectDir, "project-dir", "", "Project directory (default: current directory)")
runCmd.Flags().BoolVar(&runCfg.Build, "build", false, "Rebuild the Docker image before running")

rootCmd.AddCommand(installCmd, uninstallCmd, invokeCmd, bugReportCmd, versionCmd, dashboardCmd, getCmd, initCmd, buildCmd, deployCmd, addMcpCmd, runCmd, mcp.NewMCPCmd(), envdoc.NewEnvCmd())
experimentalTuiCmd := &cobra.Command{
Use: "experimental-tui",
Short: "Run the experimental TUI (for development/testing)",
Long: `Run the experimental TUI (for development/testing)`,
Run: func(cmd *cobra.Command, args []string) {
if err := cli.RunExperimentalTUI(cmd.Context(), runCfg); err != nil {
fmt.Fprintf(os.Stderr, "Error running experimental TUI: %v\n", err)
os.Exit(1)
}
},
}

commands := []*cobra.Command{installCmd, uninstallCmd, invokeCmd, bugReportCmd, versionCmd, dashboardCmd, getCmd, initCmd, buildCmd, deployCmd, addMcpCmd, runCmd, mcp.NewMCPCmd(), envdoc.NewEnvCmd()}
if os.Getenv("ENVIRONMENT") == "local" {
commands = append(commands, experimentalTuiCmd)
}
Comment on lines +430 to +445
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

The PR description says this command is a "hidden experimental-tui command", but the implementation conditionally registers it only when ENVIRONMENT == local. If the intent is "hidden but available", prefer always registering the command and marking it hidden via Cobra (e.g., Hidden: true) rather than gating it behind an environment variable.

Copilot uses AI. Check for mistakes.

rootCmd.AddCommand(commands...)

// Initialize config
if err := config.Init(); err != nil {
Expand Down
6 changes: 6 additions & 0 deletions go/core/cli/internal/cli/agent/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

commonexec "github.com/kagent-dev/kagent/go/core/cli/internal/common/exec"
"github.com/kagent-dev/kagent/go/core/cli/internal/config"
experimentaltui "github.com/kagent-dev/kagent/go/core/cli/internal/experimental_tui"
"github.com/kagent-dev/kagent/go/core/cli/internal/tui"
a2aclient "trpc.group/trpc-go/trpc-a2a-go/client"
"trpc.group/trpc-go/trpc-a2a-go/protocol"
Expand Down Expand Up @@ -186,3 +187,8 @@ func waitForAgent(ctx context.Context, agentURL string, timeout time.Duration) e
}
}
}

func RunExperimentalTUI(ctx context.Context, cfg *RunCfg) error {
experimentaltui.Run()
return nil
}
Comment on lines +192 to +194
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

RunExperimentalTUI ignores the error returned by experimentaltui.Run() and always returns nil. This will hide failures from the CLI command and makes the error handling in main.go ineffective; return the error from experimentaltui.Run() instead.

Suggested change
experimentaltui.Run()
return nil
}
return experimentaltui.Run()
}

Copilot uses AI. Check for mistakes.
29 changes: 29 additions & 0 deletions go/core/cli/internal/experimental_tui/app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package experimentaltui

import (
"fmt"
"os"

tea "github.com/charmbracelet/bubbletea"
"github.com/kagent-dev/kagent/go/core/cli/internal/experimental_tui/domain"
"github.com/kagent-dev/kagent/go/core/cli/internal/experimental_tui/screen"
)

var demoAgents = []domain.Agent{
{ID: "1", Name: "Agent Alpha hogehogehogehogehogehogehogehogehogehoge", Status: domain.AgentStatusRunning, Provider: NewDemoProvider()},
{ID: "2", Name: "Agent Beta", Status: domain.AgentStatusError, Provider: NewDemoProvider()},
{ID: "3", Name: "Agent Gamma", Status: domain.AgentStatusFinished, Provider: NewDemoProvider()},
{ID: "4", Name: "Agent Delta", Status: domain.AgentStatusStopped, Provider: NewDemoProvider()},
}

func Run() error {
m := screen.NewRootModel(screen.NewAgentListModel(demoAgents))

p := tea.NewProgram(m)
if _, err := p.Run(); err != nil {
fmt.Printf("Error running program: %v", err)
os.Exit(1)
}
Comment on lines +19 to +26
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

Run() returns an error but currently prints the error and calls os.Exit(1), which makes it hard for callers (and tests) to handle failures and also makes the return value misleading. Consider returning the p.Run() error instead of exiting, and let the Cobra command decide whether to os.Exit. Also consider using tea.WithAltScreen() (as the existing TUI does) to avoid leaving the UI rendered in the user’s terminal buffer.

Copilot uses AI. Check for mistakes.

return nil
}
27 changes: 27 additions & 0 deletions go/core/cli/internal/experimental_tui/component/guage.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package component

import (
Comment on lines +1 to +3
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

File name appears to be misspelled (guage vs gauge). Renaming it to gauge.go will improve discoverability/searchability and avoid propagating the typo in future references.

Copilot uses AI. Check for mistakes.
"fmt"
"strings"

"github.com/charmbracelet/lipgloss"
"github.com/kagent-dev/kagent/go/core/cli/internal/tui/theme"
)

func RenderUsageGauge(rate float64, width int) string {
if rate < 0 {
rate = 0
} else if rate > 1 {
rate = 1
}

filledWidth := int(rate * float64(width))
emptyWidth := width - filledWidth

barColor := theme.ColorPrimary

filled := lipgloss.NewStyle().Foreground(barColor).Render(strings.Repeat("■", filledWidth))
empty := lipgloss.NewStyle().Foreground(theme.ColorBorder).Render(strings.Repeat("■", emptyWidth))

return fmt.Sprintf("[%s%s] %3.0f%%", filled, empty, rate*100)
}
18 changes: 18 additions & 0 deletions go/core/cli/internal/experimental_tui/component/status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package component

import (
"strings"

"github.com/charmbracelet/lipgloss"
"github.com/kagent-dev/kagent/go/core/cli/internal/experimental_tui/domain"
)

var baseStatusStyle = lipgloss.NewStyle().
Bold(true).
Padding(0, 1)

func RenderStatusBadge(status domain.AgentStatus) string {
text := strings.ToUpper(string(status))

return text
}
Loading
Loading