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 cmd/cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ func main() {
commands.DotfilesCommand,
commands.DoctorCommand,
commands.QueryCommand,
commands.CCCommand,
}
err = app.Run(os.Args)
if err != nil {
Expand Down
44 changes: 21 additions & 23 deletions cmd/daemon/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ package main

import (
"context"
"fmt"
"log/slog"
"os"
"os/signal"
"path/filepath"
"syscall"

"github.com/ThreeDotsLabs/watermill"
Expand All @@ -25,36 +25,22 @@ var (
ppToken = ""
)

func getConfigPath() string {
homeDir, err := os.UserHomeDir()
if err != nil {
slog.Error("Failed to get user home directory", slog.Any("err", err))
return ""
}
return filepath.Join(homeDir, ".shelltime", "config.toml")
}

func main() {
l := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
AddSource: true,
Level: slog.LevelDebug,
}))
slog.SetDefault(l)

daemonConfigService := daemon.NewConfigService(daemon.DefaultConfigPath)
daemonConfig, err := daemonConfigService.GetConfig()
ctx := context.Background()
configFile := os.ExpandEnv(fmt.Sprintf("%s/%s/%s", "$HOME", model.COMMAND_BASE_STORAGE_FOLDER, "config.toml"))
daemonConfigService := model.NewConfigService(configFile)
cfg, err := daemonConfigService.ReadConfigFile(ctx)
if err != nil {
slog.Error("Failed to get daemon config", slog.Any("err", err))
return
}

cs, err := daemonConfigService.GetUserConfig()
if err != nil {
slog.Error("Failed to get user config", slog.Any("err", err))
return
}

ctx := context.Background()
uptraceOptions := []uptrace.Option{
uptrace.WithDSN(uptraceDsn),
uptrace.WithServiceName("cli-daemon"),
Expand All @@ -66,7 +52,6 @@ func main() {
uptraceOptions = append(uptraceOptions, uptrace.WithResourceAttributes(attribute.String("hostname", hs)))
}

cfg, err := cs.ReadConfigFile(ctx)
if err != nil ||
cfg.EnableMetrics == nil ||
*cfg.EnableMetrics == false ||
Expand All @@ -82,7 +67,7 @@ func main() {
defer uptrace.Shutdown(ctx)
defer uptrace.ForceFlush(ctx)

daemon.Init(cs, version)
daemon.Init(daemonConfigService, version)
model.InjectVar(version)
cmdService := model.NewCommandService()

Expand All @@ -96,7 +81,7 @@ func main() {

go daemon.SocketTopicProccessor(msg)

// Start CCUsage service if enabled
// Start CCUsage service if enabled (v1 - ccusage CLI based)
if cfg.CCUsage != nil && cfg.CCUsage.Enabled != nil && *cfg.CCUsage.Enabled {
ccUsageService := model.NewCCUsageService(cfg, cmdService)
if err := ccUsageService.Start(ctx); err != nil {
Expand All @@ -107,8 +92,21 @@ func main() {
}
}

// Start CCOtel service if enabled (v2 - OTEL gRPC passthrough)
var ccOtelServer *daemon.CCOtelServer
if cfg.CCOtel != nil && cfg.CCOtel.Enabled != nil && *cfg.CCOtel.Enabled {
ccOtelProcessor := daemon.NewCCOtelProcessor(cfg)
ccOtelServer = daemon.NewCCOtelServer(cfg.CCOtel.GRPCPort, ccOtelProcessor)
if err := ccOtelServer.Start(); err != nil {
slog.Error("Failed to start CCOtel gRPC server", slog.Any("err", err))
} else {
slog.Info("CCOtel gRPC server started", slog.Int("port", cfg.CCOtel.GRPCPort))
defer ccOtelServer.Stop()
}
}

// Create processor instance
processor := daemon.NewSocketHandler(daemonConfig, pubsub)
processor := daemon.NewSocketHandler(&cfg, pubsub)

// Start processor
if err := processor.Start(); err != nil {
Expand Down
83 changes: 83 additions & 0 deletions commands/cc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package commands

import (
"github.com/gookit/color"
"github.com/malamtime/cli/model"
"github.com/urfave/cli/v2"
)

var CCCommand = &cli.Command{
Name: "cc",
Usage: "Claude Code integration commands",
Subcommands: []*cli.Command{
CCInstallCommand,
CCUninstallCommand,
},
}

var CCInstallCommand = &cli.Command{
Name: "install",
Aliases: []string{"i"},
Usage: "Install Claude Code OTEL environment configuration to shell config files",
Action: commandCCInstall,
}

var CCUninstallCommand = &cli.Command{
Name: "uninstall",
Aliases: []string{"u"},
Usage: "Remove Claude Code OTEL environment configuration from shell config files",
Action: commandCCUninstall,
}

func commandCCInstall(c *cli.Context) error {
color.Yellow.Println("Installing Claude Code OTEL configuration...")

// Create shell services
zshService := model.NewZshCCOtelEnvService()
fishService := model.NewFishCCOtelEnvService()
bashService := model.NewBashCCOtelEnvService()

// Install for all shells (non-blocking failures)
if err := zshService.Install(); err != nil {
color.Red.Printf("Failed to install for zsh: %v\n", err)
}

if err := fishService.Install(); err != nil {
color.Red.Printf("Failed to install for fish: %v\n", err)
}

if err := bashService.Install(); err != nil {
color.Red.Printf("Failed to install for bash: %v\n", err)
}

color.Green.Println("Claude Code OTEL configuration has been installed!")
color.Yellow.Println("Please restart your shell or source your config file to apply changes.")

return nil
}

func commandCCUninstall(c *cli.Context) error {
color.Yellow.Println("Removing Claude Code OTEL configuration...")

// Create shell services
zshService := model.NewZshCCOtelEnvService()
fishService := model.NewFishCCOtelEnvService()
bashService := model.NewBashCCOtelEnvService()

// Uninstall from all shells
if err := zshService.Uninstall(); err != nil {
color.Red.Printf("Failed to uninstall from zsh: %v\n", err)
}

if err := fishService.Uninstall(); err != nil {
color.Red.Printf("Failed to uninstall from fish: %v\n", err)
}

if err := bashService.Uninstall(); err != nil {
color.Red.Printf("Failed to uninstall from bash: %v\n", err)
}

color.Green.Println("Claude Code OTEL configuration has been removed!")

return nil
}
2 changes: 1 addition & 1 deletion commands/track.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ func DoSyncData(
trackingData []model.TrackingData,
meta model.TrackingMetaData,
) error {
socketPath := daemon.DefaultSocketPath
socketPath := config.SocketPath
isSocketReady := daemon.IsSocketReady(ctx, socketPath)

logrus.Traceln("is socket ready: ", isSocketReady)
Expand Down
Loading
Loading