diff --git a/commands/query.go b/commands/query.go index 8953963..ec27c44 100644 --- a/commands/query.go +++ b/commands/query.go @@ -60,7 +60,7 @@ func commandQuery(c *cli.Context) error { } // Get system context - systemContext, err := getSystemContext(query) + systemContext, err := getSystemContext(query, cfg.AI) if err != nil { slog.Warn("Failed to get system context", slog.Any("err", err)) } @@ -225,7 +225,7 @@ func sanitizeSuggestedCommand(raw string) string { return s } -func getSystemContext(query string) (model.CommandSuggestVariables, error) { +func getSystemContext(query string, ai *model.AIConfig) (model.CommandSuggestVariables, error) { // Get shell information shell := os.Getenv("SHELL") if shell == "" { @@ -240,9 +240,25 @@ func getSystemContext(query string) (model.CommandSuggestVariables, error) { // Get OS information osInfo := runtime.GOOS - return model.CommandSuggestVariables{ + vars := model.CommandSuggestVariables{ Shell: shell, Os: osInfo, Query: query, - }, nil + } + + // Skip context fields when the user has opted out via config: + // [ai] + // shareContext = false + if ai != nil && ai.ShareContext != nil && !*ai.ShareContext { + return vars, nil + } + + if pwd, err := os.Getwd(); err == nil { + vars.Pwd = pwd + } + if host, err := os.Hostname(); err == nil { + vars.Hostname = host + } + + return vars, nil } diff --git a/commands/query_test.go b/commands/query_test.go index 09974b6..52bef78 100644 --- a/commands/query_test.go +++ b/commands/query_test.go @@ -326,7 +326,7 @@ func (s *queryTestSuite) TestGetSystemContext() { os.Setenv("SHELL", "/bin/bash") defer os.Setenv("SHELL", originalShell) - context, err := getSystemContext(query) + context, err := getSystemContext(query, nil) assert.Nil(s.T(), err) assert.Equal(s.T(), "bash", context.Shell) assert.Equal(s.T(), runtime.GOOS, context.Os) @@ -334,7 +334,7 @@ func (s *queryTestSuite) TestGetSystemContext() { // Test with no SHELL environment variable os.Unsetenv("SHELL") - context, err = getSystemContext(query) + context, err = getSystemContext(query, nil) assert.Nil(s.T(), err) assert.Equal(s.T(), "unknown", context.Shell) assert.Equal(s.T(), runtime.GOOS, context.Os) @@ -342,9 +342,16 @@ func (s *queryTestSuite) TestGetSystemContext() { // Test with full path shell os.Setenv("SHELL", "/usr/local/bin/zsh") - context, err = getSystemContext(query) + context, err = getSystemContext(query, nil) assert.Nil(s.T(), err) assert.Equal(s.T(), "zsh", context.Shell) + + // Opt-out: when ShareContext is explicitly false, pwd/hostname are omitted. + disabled := false + context, err = getSystemContext(query, &model.AIConfig{ShareContext: &disabled}) + assert.Nil(s.T(), err) + assert.Empty(s.T(), context.Pwd) + assert.Empty(s.T(), context.Hostname) } func (s *queryTestSuite) TestQueryCommandWithAlias() { diff --git a/model/ai_service.go b/model/ai_service.go index 75f859a..a916bf9 100644 --- a/model/ai_service.go +++ b/model/ai_service.go @@ -17,9 +17,11 @@ type AIService interface { } type CommandSuggestVariables struct { - Shell string `json:"shell"` - Os string `json:"os"` - Query string `json:"query"` + Shell string `json:"shell"` + Os string `json:"os"` + Query string `json:"query"` + Pwd string `json:"pwd,omitempty"` + Hostname string `json:"hostname,omitempty"` } type sseAIService struct{} diff --git a/model/types.go b/model/types.go index 1940bf6..dc8e208 100644 --- a/model/types.go +++ b/model/types.go @@ -19,6 +19,9 @@ type AIAgentConfig struct { type AIConfig struct { Agent AIAgentConfig `toml:"agent,omitempty" yaml:"agent,omitempty" json:"agent,omitempty"` ShowTips *bool `toml:"showTips" yaml:"showTips" json:"showTips"` + // ShareContext controls whether `shelltime q` sends the working directory + // and hostname alongside the prompt. Defaults to true if unset. + ShareContext *bool `toml:"shareContext,omitempty" yaml:"shareContext,omitempty" json:"shareContext,omitempty"` } type CCUsage struct {