From cab7b28ed9c095346cc2f3703091b58692b24483 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Salavisa?= Date: Fri, 29 May 2026 18:18:10 +0100 Subject: [PATCH] chore: round 4 dead-code cleanup (transport helpers, detect, orphan methods) (#1156) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(agentctl): delete duplicate procattr files in adapter package setProcGroup and killProcessGroup are defined in both agentctl/server/adapter/ and agentctl/server/process/. The process/ copies are the live ones (called by process/runner.go, manager.go, vscode.go); the adapter/ copies have zero callers and are removed. Co-Authored-By: Claude Sonnet 4.6 * chore(agentctl): remove orphan helpers from transport/shared Left over from the ACP refactor. All had zero callers: - DebugEnabled(): internal debugMode var is checked directly by LogRawEvent/LogNormalizedEvent — the exported wrapper was unused. - GetBool, GetMap, GetSlice: only GetString/GetInt are called in acp/normalize.go. - NormalizeShellResult, NormalizeReadResult, NormalizeCodeSearchResult, NormalizeModifyResult: normalization moved to acp/normalize.go. - TruncateIfNeeded, MaxContentLength, MaxFileCount: only used by the four Normalize* helpers above; removed transitively. - TraceControlMessage: zero callers in the adapter transport layer. GenerateUnifiedDiff, SplitLines, DetectLanguage, Tracer, ShutdownTracing, TraceProtocolEvent, TraceProtocolRequest are alive and kept. Co-Authored-By: Claude Sonnet 4.6 * chore(agentctl): remove unused tool_payload constructors NewHttpRequest, NewCreateTask, NewSubagentTask, NewShowPlan, NewManageTodos, and NewMisc have zero callers — ACP normalization builds NormalizedPayload via struct literals and JSON unmarshaling, not these factory functions. NewReadFile, NewModifyFile, NewShellExec, NewCodeSearch, and NewGeneric are kept (live callers in acp/normalize.go). Co-Authored-By: Claude Sonnet 4.6 * chore(agents/detect): remove dead fluent options and OSPaths type WithFileExists, WithCommandOutput, WithEnvVar, expandHomePath (their transitive helper), and OSPaths (struct + Resolve + Expanded) have zero callers. Only WithCommand and WithNpxRunnable are used by agent IsInstalled implementations. Imports trimmed to context and os/exec. Co-Authored-By: Claude Sonnet 4.6 * chore(office): remove dead channel methods superseded by service/ ListComments, DeleteComment, and UpdateChannelStatus on ChannelService have zero callers — the live implementations live in internal/office/service/comments.go and service/channels.go. CreateComment is kept: it is called by HandleChannelInbound. Co-Authored-By: Claude Sonnet 4.6 * chore: remove scattered orphan helpers Remove dead single-symbol exports verified to have zero callers: - ParseCronExpression (office/shared/cron.go): NextCronTime covers all live usages; the validator wrapper was unused. - IsValidPathComponent, MustJSON (office/shared/helpers.go): zero callers; GenerateSlug is kept. - DiscoverUserSkillsAt (office/skills/userhome_discovery.go): exported wrapper over the private discoverUserSkillsAt; only the internal DiscoverUserSkills method is wired up. - Manager.Get (agent/loginpty/manager.go): zero callers; GetByID and Stop are kept (Stop is tested in manager_test.go). - DetachedWithValues (common/appctx/appctx.go): zero callers; Detached is kept. - Repository.Close no-ops (task/share, terminal/repository): both are documented no-ops with zero callers. - TaskBranchName (worktree/config.go): zero callers; the deterministic TaskBranchNameWithSuffix is kept. Note: dialect.Now was initially targeted but is tested in dialect_test.go (same-package call — missed by package-qualified grep). It remains unchanged. Co-Authored-By: Claude Sonnet 4.6 * chore(share): remove stale Close reference from provider.go comment Repository.Close() was removed as a no-op in the round-4 cleanup. The comment in provider.go still referenced it by name; updated to reflect that the repo simply doesn't own its DB connections. Co-Authored-By: Claude Sonnet 4.6 * chore(office/shared): delete helpers.go — GenerateSlug had zero callers The triage step mistakenly identified skills/service.go as a caller, but that package defines its own local GenerateSlug (different regex, adds TrimSpace and a 'skill' fallback default). shared.GenerateSlug was never called anywhere. helpers.go is now empty; delete the file. Co-Authored-By: Claude Sonnet 4.6 * chore(worktree): fix stale TaskBranchName reference in TaskBranchNameWithSuffix doc Co-Authored-By: Claude Sonnet 4.6 --------- Co-authored-by: Kandev Agent Co-authored-by: Claude Sonnet 4.6 --- apps/backend/internal/agent/agents/detect.go | 97 ------------------- .../internal/agent/loginpty/manager.go | 7 -- .../agentctl/server/adapter/procattr_linux.go | 21 ---- .../agentctl/server/adapter/procattr_unix.go | 18 ---- .../server/adapter/procattr_windows.go | 22 ----- .../server/adapter/transport/shared/debug.go | 3 - .../adapter/transport/shared/maputil.go | 24 ----- .../transport/shared/normalize_helpers.go | 96 +----------------- .../adapter/transport/shared/tracing.go | 35 ------- .../agentctl/types/streams/tool_payload.go | 67 ------------- apps/backend/internal/common/appctx/appctx.go | 23 ----- .../internal/office/channels/comments.go | 10 -- .../internal/office/channels/service.go | 10 -- apps/backend/internal/office/shared/cron.go | 11 --- .../backend/internal/office/shared/helpers.go | 36 ------- .../office/skills/userhome_discovery.go | 7 -- apps/backend/internal/task/share/provider.go | 4 +- .../backend/internal/task/share/repository.go | 3 - .../internal/terminal/repository/sqlite.go | 3 - apps/backend/internal/worktree/config.go | 11 +-- 20 files changed, 7 insertions(+), 501 deletions(-) delete mode 100644 apps/backend/internal/agentctl/server/adapter/procattr_linux.go delete mode 100644 apps/backend/internal/agentctl/server/adapter/procattr_unix.go delete mode 100644 apps/backend/internal/agentctl/server/adapter/procattr_windows.go delete mode 100644 apps/backend/internal/office/shared/helpers.go diff --git a/apps/backend/internal/agent/agents/detect.go b/apps/backend/internal/agent/agents/detect.go index d19ad79f70..21529eeb7c 100644 --- a/apps/backend/internal/agent/agents/detect.go +++ b/apps/backend/internal/agent/agents/detect.go @@ -2,33 +2,12 @@ package agents import ( "context" - "os" "os/exec" - "path/filepath" - "regexp" - "runtime" - "strings" ) // DetectOption is a detection strategy. Returns (found, matchedPath, err). type DetectOption func(ctx context.Context) (bool, string, error) -// WithFileExists checks if any of the given paths exist (supports ~ expansion). -func WithFileExists(paths ...string) DetectOption { - return func(ctx context.Context) (bool, string, error) { - for _, p := range paths { - expanded := expandHomePath(p) - if expanded == "" { - continue - } - if _, err := os.Stat(expanded); err == nil { - return true, expanded, nil - } - } - return false, "", nil - } -} - // WithCommand checks if a command is in PATH (exec.LookPath). func WithCommand(name string) DetectOption { return func(ctx context.Context) (bool, string, error) { @@ -69,36 +48,6 @@ func WithNpxRunnable(pkg string) DetectOption { } } -// WithCommandOutput runs a command and checks stdout matches regex. -func WithCommandOutput(pattern string, name string, args ...string) DetectOption { - return func(ctx context.Context) (bool, string, error) { - cmd := exec.CommandContext(ctx, name, args...) - out, err := cmd.Output() - if err != nil { - return false, "", nil - } - re, err := regexp.Compile(pattern) - if err != nil { - return false, "", err - } - if re.Match(out) { - return true, name, nil - } - return false, "", nil - } -} - -// WithEnvVar checks if an environment variable is set and non-empty. -func WithEnvVar(name string) DetectOption { - return func(ctx context.Context) (bool, string, error) { - val := os.Getenv(name) - if val != "" { - return true, name, nil - } - return false, "", nil - } -} - // Detect runs options in order, returns first match. // If none match, returns DiscoveryResult{Available: false}. func Detect(ctx context.Context, opts ...DetectOption) (*DiscoveryResult, error) { @@ -116,49 +65,3 @@ func Detect(ctx context.Context, opts ...DetectOption) (*DiscoveryResult, error) } return &DiscoveryResult{Available: false}, nil } - -// expandHomePath expands ~ to the user's home directory. -func expandHomePath(path string) string { - if path == "" { - return "" - } - if strings.HasPrefix(path, "~") { - home, err := os.UserHomeDir() - if err != nil { - return "" - } - path = filepath.Join(home, strings.TrimPrefix(path, "~")) - } - return filepath.Clean(filepath.FromSlash(path)) -} - -// OSPaths holds per-OS path lists. Use Resolve() to get the paths for the current OS. -type OSPaths struct { - Linux []string - MacOS []string - Windows []string -} - -// Resolve returns the raw paths for the current operating system. -func (p OSPaths) Resolve() []string { - switch runtime.GOOS { - case "darwin": - return p.MacOS - case "windows": - return p.Windows - default: - return p.Linux - } -} - -// Expanded returns the paths for the current OS with ~ expanded to the home directory. -func (p OSPaths) Expanded() []string { - paths := p.Resolve() - result := make([]string, 0, len(paths)) - for _, path := range paths { - if expanded := expandHomePath(path); expanded != "" { - result = append(result, expanded) - } - } - return result -} diff --git a/apps/backend/internal/agent/loginpty/manager.go b/apps/backend/internal/agent/loginpty/manager.go index 729bbc7125..c95206633b 100644 --- a/apps/backend/internal/agent/loginpty/manager.go +++ b/apps/backend/internal/agent/loginpty/manager.go @@ -110,13 +110,6 @@ func (m *Manager) Start(agentID string, cmd []string, cols, rows uint16) (*Sessi return sess, nil } -// Get returns a session by agent ID (or nil). -func (m *Manager) Get(agentID string) *Session { - m.mu.Lock() - defer m.mu.Unlock() - return m.sessions[agentID] -} - // GetByID returns a session by session ID (or nil). func (m *Manager) GetByID(sessionID string) *Session { m.mu.Lock() diff --git a/apps/backend/internal/agentctl/server/adapter/procattr_linux.go b/apps/backend/internal/agentctl/server/adapter/procattr_linux.go deleted file mode 100644 index 7b7db807b2..0000000000 --- a/apps/backend/internal/agentctl/server/adapter/procattr_linux.go +++ /dev/null @@ -1,21 +0,0 @@ -//go:build linux - -package adapter - -import ( - "os/exec" - "syscall" -) - -// setProcGroup configures the command to run in its own process group. -func setProcGroup(cmd *exec.Cmd) { - cmd.SysProcAttr = &syscall.SysProcAttr{ - Setpgid: true, - Pdeathsig: syscall.SIGTERM, - } -} - -// killProcessGroup kills the entire process group for the given PID. -func killProcessGroup(pid int) error { - return syscall.Kill(-pid, syscall.SIGKILL) -} diff --git a/apps/backend/internal/agentctl/server/adapter/procattr_unix.go b/apps/backend/internal/agentctl/server/adapter/procattr_unix.go deleted file mode 100644 index b5ee454457..0000000000 --- a/apps/backend/internal/agentctl/server/adapter/procattr_unix.go +++ /dev/null @@ -1,18 +0,0 @@ -//go:build unix && !linux - -package adapter - -import ( - "os/exec" - "syscall" -) - -// setProcGroup configures the command to run in its own process group. -func setProcGroup(cmd *exec.Cmd) { - cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} -} - -// killProcessGroup kills the entire process group for the given PID. -func killProcessGroup(pid int) error { - return syscall.Kill(-pid, syscall.SIGKILL) -} diff --git a/apps/backend/internal/agentctl/server/adapter/procattr_windows.go b/apps/backend/internal/agentctl/server/adapter/procattr_windows.go deleted file mode 100644 index 9acd5ea188..0000000000 --- a/apps/backend/internal/agentctl/server/adapter/procattr_windows.go +++ /dev/null @@ -1,22 +0,0 @@ -//go:build windows - -package adapter - -import ( - "fmt" - "os/exec" - "syscall" -) - -// setProcGroup configures the command to run in its own process group. -func setProcGroup(cmd *exec.Cmd) { - cmd.SysProcAttr = &syscall.SysProcAttr{ - CreationFlags: syscall.CREATE_NEW_PROCESS_GROUP, - } -} - -// killProcessGroup kills the entire process tree for the given PID. -func killProcessGroup(pid int) error { - kill := exec.Command("taskkill", "/F", "/T", "/PID", fmt.Sprintf("%d", pid)) - return kill.Run() -} diff --git a/apps/backend/internal/agentctl/server/adapter/transport/shared/debug.go b/apps/backend/internal/agentctl/server/adapter/transport/shared/debug.go index b9091d1675..505d910c7b 100644 --- a/apps/backend/internal/agentctl/server/adapter/transport/shared/debug.go +++ b/apps/backend/internal/agentctl/server/adapter/transport/shared/debug.go @@ -38,9 +38,6 @@ const ( ProtocolCopilot = "copilot" ) -// DebugEnabled reports whether agent message debug mode is active. -func DebugEnabled() bool { return debugMode } - func resolveDebugLogDir() string { if dir := os.Getenv("KANDEV_DEBUG_LOG_DIR"); dir != "" { return dir diff --git a/apps/backend/internal/agentctl/server/adapter/transport/shared/maputil.go b/apps/backend/internal/agentctl/server/adapter/transport/shared/maputil.go index e99dcb1e6d..d41116d47d 100644 --- a/apps/backend/internal/agentctl/server/adapter/transport/shared/maputil.go +++ b/apps/backend/internal/agentctl/server/adapter/transport/shared/maputil.go @@ -16,27 +16,3 @@ func GetInt(m map[string]any, key string) int { } return 0 } - -// GetBool extracts a bool value from a map, returning false if not found or wrong type. -func GetBool(m map[string]any, key string) bool { - if v, ok := m[key].(bool); ok { - return v - } - return false -} - -// GetMap extracts a nested map from a map, returning nil if not found or wrong type. -func GetMap(m map[string]any, key string) map[string]any { - if v, ok := m[key].(map[string]any); ok { - return v - } - return nil -} - -// GetSlice extracts a slice from a map, returning nil if not found or wrong type. -func GetSlice(m map[string]any, key string) []any { - if v, ok := m[key].([]any); ok { - return v - } - return nil -} diff --git a/apps/backend/internal/agentctl/server/adapter/transport/shared/normalize_helpers.go b/apps/backend/internal/agentctl/server/adapter/transport/shared/normalize_helpers.go index 64f4804fee..8d66027941 100644 --- a/apps/backend/internal/agentctl/server/adapter/transport/shared/normalize_helpers.go +++ b/apps/backend/internal/agentctl/server/adapter/transport/shared/normalize_helpers.go @@ -3,10 +3,11 @@ package shared import ( "fmt" "strings" - - "github.com/kandev/kandev/internal/agentctl/types/streams" ) +// langPlaintext is the fallback language identifier for files without a known extension. +const langPlaintext = "plaintext" + // GenerateUnifiedDiff creates a unified diff string from old and new content. func GenerateUnifiedDiff(oldStr, newStr, path string, startLine int) string { // If both empty or identical, no diff needed @@ -57,97 +58,6 @@ func SplitLines(s string) []string { return strings.Split(strings.ReplaceAll(s, "\r\n", "\n"), "\n") } -// NormalizeShellResult updates a ShellExecPayload with result data. -func NormalizeShellResult(payload *streams.ShellExecPayload, result any) { - if payload.Output == nil { - payload.Output = &streams.ShellExecOutput{} - } - - switch r := result.(type) { - case string: - payload.Output.Stdout = r - case map[string]any: - if stdout, ok := r["stdout"].(string); ok { - payload.Output.Stdout = stdout - } - if stderr, ok := r["stderr"].(string); ok { - payload.Output.Stderr = stderr - } - if exitCode, ok := r["exit_code"].(float64); ok { - payload.Output.ExitCode = int(exitCode) - } - } -} - -// MaxContentLength is the maximum length for tool output content before truncation. -const MaxContentLength = 50000 - -// MaxFileCount is the maximum number of files to include in code search results. -const MaxFileCount = 500 - -// langPlaintext is the fallback language identifier for files without a known extension. -const langPlaintext = "plaintext" - -// TruncateIfNeeded truncates a string if it exceeds maxLen. -func TruncateIfNeeded(s string, maxLen int) (string, bool) { - if len(s) <= maxLen { - return s, false - } - return s[:maxLen], true -} - -// NormalizeReadResult populates ReadFilePayload.Output with result content. -func NormalizeReadResult(payload *streams.ReadFilePayload, result string) { - lines := SplitLines(result) - content, truncated := TruncateIfNeeded(result, MaxContentLength) - - payload.Output = &streams.ReadFileOutput{ - Content: content, - LineCount: len(lines), - Truncated: truncated, - Language: DetectLanguage(payload.FilePath), - } -} - -// NormalizeCodeSearchResult populates CodeSearchPayload.Output with result content. -func NormalizeCodeSearchResult(payload *streams.CodeSearchPayload, result string) { - result = strings.TrimSpace(result) - if result == "" { - payload.Output = &streams.CodeSearchOutput{ - Files: []string{}, - FileCount: 0, - } - return - } - - files := strings.Split(result, "\n") - truncated := false - if len(files) > MaxFileCount { - files = files[:MaxFileCount] - truncated = true - } - - payload.Output = &streams.CodeSearchOutput{ - Files: files, - FileCount: len(files), - Truncated: truncated, - } -} - -// NormalizeModifyResult updates ModifyFilePayload with result content for Write operations. -func NormalizeModifyResult(payload *streams.ModifyFilePayload, result string) { - // For Write tool, store the written content confirmation - // The tool result confirms what was written - if len(payload.Mutations) > 0 { - mut := &payload.Mutations[0] - // If Content not already set from input args (for create), use result - if mut.Content == "" && mut.NewContent == "" && result != "" { - content, _ := TruncateIfNeeded(result, MaxContentLength) - mut.Content = content - } - } -} - // DetectLanguage maps file extension to language identifier. // Used for syntax highlighting in diffs. func DetectLanguage(path string) string { diff --git a/apps/backend/internal/agentctl/server/adapter/transport/shared/tracing.go b/apps/backend/internal/agentctl/server/adapter/transport/shared/tracing.go index 38be906d51..c88d12549f 100644 --- a/apps/backend/internal/agentctl/server/adapter/transport/shared/tracing.go +++ b/apps/backend/internal/agentctl/server/adapter/transport/shared/tracing.go @@ -100,41 +100,6 @@ func TraceProtocolRequest( return ctx, span } -// TraceControlMessage creates a span for a control-plane protocol message. -// Used for control_request, control_response, and control_cancel_request messages -// that bypass the regular sendUpdate() tracing path. -func TraceControlMessage( - ctx context.Context, - protocol, agentID string, - direction string, - eventType string, - rawData json.RawMessage, -) { - tracer := Tracer() - spanName := protocol + ".control." + eventType - - kind := trace.SpanKindInternal - if direction == "send" { - kind = trace.SpanKindClient - } - - _, span := tracer.Start(ctx, spanName, trace.WithSpanKind(kind)) - defer span.End() - - span.SetAttributes( - attribute.String("protocol", protocol), - attribute.String("agent_id", agentID), - attribute.String("direction", direction), - attribute.String("event_type", eventType), - ) - - if len(rawData) > 0 { - span.AddEvent("payload", trace.WithAttributes( - attribute.String("data", truncate(string(rawData), maxAttrValueLen)), - )) - } -} - func truncate(s string, maxLen int) string { if len(s) <= maxLen { return s diff --git a/apps/backend/internal/agentctl/types/streams/tool_payload.go b/apps/backend/internal/agentctl/types/streams/tool_payload.go index 15a994faf0..a3efd84948 100644 --- a/apps/backend/internal/agentctl/types/streams/tool_payload.go +++ b/apps/backend/internal/agentctl/types/streams/tool_payload.go @@ -334,17 +334,6 @@ func NewCodeSearch(query, pattern, path, glob string) *NormalizedPayload { } } -// NewHttpRequest creates a NormalizedPayload for HTTP request operations. -func NewHttpRequest(url, method string) *NormalizedPayload { - return &NormalizedPayload{ - kind: ToolKindHttpRequest, - httpRequest: &HttpRequestPayload{ - URL: url, - Method: method, - }, - } -} - // NewGeneric creates a NormalizedPayload for unrecognized tools. func NewGeneric(name string, input any) *NormalizedPayload { return &NormalizedPayload{ @@ -355,59 +344,3 @@ func NewGeneric(name string, input any) *NormalizedPayload { }, } } - -// NewCreateTask creates a NormalizedPayload for task creation operations. -func NewCreateTask(title, description string) *NormalizedPayload { - return &NormalizedPayload{ - kind: ToolKindCreateTask, - createTask: &CreateTaskPayload{ - Title: title, - Description: description, - }, - } -} - -// NewSubagentTask creates a NormalizedPayload for subagent task invocations. -func NewSubagentTask(description, prompt, subagentType string) *NormalizedPayload { - return &NormalizedPayload{ - kind: ToolKindSubagentTask, - subagentTask: &SubagentTaskPayload{ - Description: description, - Prompt: prompt, - SubagentType: subagentType, - }, - } -} - -// NewShowPlan creates a NormalizedPayload for plan display operations. -func NewShowPlan(summary string, steps []string) *NormalizedPayload { - return &NormalizedPayload{ - kind: ToolKindShowPlan, - showPlan: &ShowPlanPayload{ - Summary: summary, - Steps: steps, - }, - } -} - -// NewManageTodos creates a NormalizedPayload for todo management operations. -func NewManageTodos(operation string, items []TodoItem) *NormalizedPayload { - return &NormalizedPayload{ - kind: ToolKindManageTodos, - manageTodos: &ManageTodosPayload{ - Operation: operation, - Items: items, - }, - } -} - -// NewMisc creates a NormalizedPayload for miscellaneous operations. -func NewMisc(label string, details any) *NormalizedPayload { - return &NormalizedPayload{ - kind: ToolKindMisc, - misc: &MiscPayload{ - Label: label, - Details: details, - }, - } -} diff --git a/apps/backend/internal/common/appctx/appctx.go b/apps/backend/internal/common/appctx/appctx.go index 7fe67b6094..ddb0cb2c50 100644 --- a/apps/backend/internal/common/appctx/appctx.go +++ b/apps/backend/internal/common/appctx/appctx.go @@ -30,26 +30,3 @@ func Detached(parent context.Context, stopCh <-chan struct{}, timeout time.Durat return ctx, cancel } - -// DetachedWithValues creates a detached context that copies deadline-insensitive values -// from the parent context while starting fresh with no deadline. -// Use sparingly - most values should be passed explicitly. -func DetachedWithValues(parent context.Context, stopCh <-chan struct{}, timeout time.Duration) (context.Context, context.CancelFunc) { - var ctx context.Context - var cancel context.CancelFunc - if timeout > 0 { - ctx, cancel = context.WithTimeout(context.Background(), timeout) - } else { - ctx, cancel = context.WithCancel(context.Background()) - } - - go func() { - select { - case <-stopCh: - cancel() - case <-ctx.Done(): - } - }() - - return ctx, cancel -} diff --git a/apps/backend/internal/office/channels/comments.go b/apps/backend/internal/office/channels/comments.go index 43f944dcb5..cfa8fafc0d 100644 --- a/apps/backend/internal/office/channels/comments.go +++ b/apps/backend/internal/office/channels/comments.go @@ -29,16 +29,6 @@ func (s *ChannelService) CreateComment(ctx context.Context, comment *models.Task return nil } -// ListComments returns all comments for a task. -func (s *ChannelService) ListComments(ctx context.Context, taskID string) ([]*models.TaskComment, error) { - return s.repo.ListTaskComments(ctx, taskID) -} - -// DeleteComment deletes a task comment by ID. -func (s *ChannelService) DeleteComment(ctx context.Context, id string) error { - return s.repo.DeleteTaskComment(ctx, id) -} - // publishCommentCreated emits an OfficeCommentCreated event. // If no event bus is configured the call is silently skipped. func (s *ChannelService) publishCommentCreated(ctx context.Context, comment *models.TaskComment) { diff --git a/apps/backend/internal/office/channels/service.go b/apps/backend/internal/office/channels/service.go index 318e14b35a..5311fa31d6 100644 --- a/apps/backend/internal/office/channels/service.go +++ b/apps/backend/internal/office/channels/service.go @@ -144,16 +144,6 @@ func (s *ChannelService) ListChannelsByAgent(ctx context.Context, agentInstanceI return s.repo.ListChannelsByAgent(ctx, agentInstanceID) } -// UpdateChannelStatus updates a channel's status. -func (s *ChannelService) UpdateChannelStatus(ctx context.Context, id, status string) error { - channel, err := s.repo.GetChannel(ctx, id) - if err != nil { - return err - } - channel.Status = models.ChannelStatus(status) - return s.repo.UpdateChannel(ctx, channel) -} - // DeleteChannel deletes a channel by ID. func (s *ChannelService) DeleteChannel(ctx context.Context, id string) error { return s.repo.DeleteChannel(ctx, id) diff --git a/apps/backend/internal/office/shared/cron.go b/apps/backend/internal/office/shared/cron.go index d5e240efeb..712878f28e 100644 --- a/apps/backend/internal/office/shared/cron.go +++ b/apps/backend/internal/office/shared/cron.go @@ -30,17 +30,6 @@ func NextCronTime(expression, timezone string, after time.Time) (time.Time, erro return findNextMatch(spec, after.In(loc)), nil } -// ParseCronExpression validates a cron expression string and returns an error -// if it is malformed. -func ParseCronExpression(expression string) error { - fields := strings.Fields(expression) - if len(fields) != 5 { - return fmt.Errorf("expected 5 cron fields, got %d", len(fields)) - } - _, err := parseCronSpec(fields) - return err -} - type cronSpec struct { minutes []int hours []int diff --git a/apps/backend/internal/office/shared/helpers.go b/apps/backend/internal/office/shared/helpers.go deleted file mode 100644 index 8fdc51a203..0000000000 --- a/apps/backend/internal/office/shared/helpers.go +++ /dev/null @@ -1,36 +0,0 @@ -package shared - -import ( - "encoding/json" - "regexp" - "strings" -) - -var slugRe = regexp.MustCompile(`[^a-z0-9]+`) - -// IsValidPathComponent reports whether s is safe to use as a filesystem path -// component: non-empty, no slashes, no backslashes, no ".." traversal. -func IsValidPathComponent(s string) bool { - return s != "" && - !strings.Contains(s, "/") && - !strings.Contains(s, "\\") && - !strings.Contains(s, "..") -} - -// GenerateSlug converts a name to a lowercase hyphenated slug suitable for -// use as a URL or filesystem identifier. -func GenerateSlug(name string) string { - lower := strings.ToLower(name) - slug := slugRe.ReplaceAllString(lower, "-") - return strings.Trim(slug, "-") -} - -// MustJSON marshals v to a JSON string, returning "{}" on any error. -// Intended for struct fields that must always contain valid JSON. -func MustJSON(v interface{}) string { - b, err := json.Marshal(v) - if err != nil { - return "{}" - } - return string(b) -} diff --git a/apps/backend/internal/office/skills/userhome_discovery.go b/apps/backend/internal/office/skills/userhome_discovery.go index 47807c4bda..7cbdc8cb5d 100644 --- a/apps/backend/internal/office/skills/userhome_discovery.go +++ b/apps/backend/internal/office/skills/userhome_discovery.go @@ -163,13 +163,6 @@ func userHomeSourceLocator(provider, key string) string { return strings.TrimSpace(provider) + ":" + strings.Trim(strings.TrimSpace(key), "/") } -// DiscoverUserSkillsAt scans an already resolved provider user skill root. -func DiscoverUserSkillsAt( - ctx context.Context, provider, root string, -) ([]DiscoveredUserSkill, error) { - return discoverUserSkillsAt(ctx, provider, root, root) -} - func discoverUserSkillsAt( ctx context.Context, provider, root, allowedBase string, ) ([]DiscoveredUserSkill, error) { diff --git a/apps/backend/internal/task/share/provider.go b/apps/backend/internal/task/share/provider.go index 8f2e212fd0..4032b9f2a5 100644 --- a/apps/backend/internal/task/share/provider.go +++ b/apps/backend/internal/task/share/provider.go @@ -36,8 +36,6 @@ func Provide( svc := New(repo, taskReader, backend, log, cfg.KandevVersion) h := NewHTTPHandlers(svc, ghClient, log) // Cleanup is a true no-op — the repository doesn't own its database - // connection (the pool is owned by cmd/kandev), and Repository.Close() - // reflects that by returning nil. Returning an inline noop here keeps - // the contract obvious to readers without needing to chase Close. + // connection (the pool is owned by cmd/kandev). return h, func() error { return nil }, nil } diff --git a/apps/backend/internal/task/share/repository.go b/apps/backend/internal/task/share/repository.go index e980c7933d..e130ba10ad 100644 --- a/apps/backend/internal/task/share/repository.go +++ b/apps/backend/internal/task/share/repository.go @@ -56,9 +56,6 @@ func NewRepository(writer, reader *sqlx.DB, log *logger.Logger) (*Repository, er return r, nil } -// Close is a no-op; the database connections are not owned by this repo. -func (r *Repository) Close() error { return nil } - func (r *Repository) initSchema() error { mig := db.NewMigrateLogger(r.writer, r.log) mig.Apply("table.task_shares", `CREATE TABLE IF NOT EXISTS task_shares ( diff --git a/apps/backend/internal/terminal/repository/sqlite.go b/apps/backend/internal/terminal/repository/sqlite.go index adad10e752..2d53618e97 100644 --- a/apps/backend/internal/terminal/repository/sqlite.go +++ b/apps/backend/internal/terminal/repository/sqlite.go @@ -37,9 +37,6 @@ func NewWithDB(writer, reader *sqlx.DB, log *logger.Logger) (*Repository, error) return r, nil } -// Close is a no-op — the writer/reader pools are owned by the caller. -func (r *Repository) Close() error { return nil } - func (r *Repository) initSchema() error { stmts := []string{ `CREATE TABLE IF NOT EXISTS user_terminals ( diff --git a/apps/backend/internal/worktree/config.go b/apps/backend/internal/worktree/config.go index e4e74fb3ec..af75825621 100644 --- a/apps/backend/internal/worktree/config.go +++ b/apps/backend/internal/worktree/config.go @@ -149,14 +149,9 @@ func NormalizeBranchPrefix(prefix string) string { return trimmed } -// TaskBranchName returns the standard per-task branch name used by isolated -// executors. The random suffix keeps similarly titled tasks from colliding. -func TaskBranchName(taskTitle, taskID, prefix string) string { - return TaskBranchNameWithSuffix(taskTitle, taskID, prefix, SmallSuffix(3)) -} - -// TaskBranchNameWithSuffix is the deterministic form of TaskBranchName used by -// worktree naming, where the caller already generated the suffix. +// TaskBranchNameWithSuffix builds the per-task branch name from a caller-supplied suffix. +// The caller is responsible for generating the suffix (e.g. SmallSuffix(3)) so that +// naming is deterministic when the suffix is derived externally. func TaskBranchNameWithSuffix(taskTitle, taskID, prefix, suffix string) string { sanitized := SanitizeForBranch(taskTitle, 20) if sanitized == "" {