Files
Paymahn Moghadasian d781728c6c feat: slack-cli — a no-daemon CLI over the slack-mcp-server engine (#1)
* feat: add slack-cli, a no-daemon CLI over the slack-mcp-server engine

Turn the forked slack-mcp-server into a CLI so running many agents no
longer means one resident MCP process each. Every command is a
short-lived process that reads the shared on-disk cache.

- rename module to github.com/paymog/slack-cli (go install/homebrew/ldflags)
- internal/toolcall: invoke the upstream tool handlers in-process; the only
  mcp-go coupling lives here, so pkg/handler and pkg/provider are reused
  byte-for-byte (clean upstream merges, fork-and-extend)
- internal/{cli,cmds,config,credstore,runtime,output}: cobra command tree,
  keyring-backed credential profiles, provider bootstrap, result printing
- 21 tools as subcommands (channels, conversations, users, usergroups,
  saved, reactions, attachments, cache); write tools keep their env gating
- goreleaser + homebrew release workflow; ships a skills/slack-cli skill
- unit tests for config/credstore/toolcall; MCP server still builds

The MCP server (cmd/slack-mcp-server) is kept intact.

* chore(napkin): record real-workspace verification

* docs: explain how the CLI works (in-process handler invocation, shared cache)
2026-06-26 12:45:38 -05:00

45 lines
1.3 KiB
Go

package cmds
import (
"errors"
"fmt"
"github.com/paymog/slack-cli/internal/config"
"github.com/paymog/slack-cli/internal/runtime"
"github.com/paymog/slack-cli/pkg/provider"
"github.com/spf13/cobra"
)
func newCacheCommand(cfg *config.Config) *cobra.Command {
cmd := &cobra.Command{
Use: "cache",
Short: "Manage the on-disk user/channel cache shared across invocations",
}
cmd.AddCommand(cacheRefreshCommand(cfg))
return cmd
}
func cacheRefreshCommand(cfg *config.Config) *cobra.Command {
return &cobra.Command{
Use: "refresh",
Short: "Fetch users and channels from Slack and write the cache to disk",
RunE: func(cmd *cobra.Command, _ []string) error {
p, _, err := runtime.Provider(cfg)
if err != nil {
return err
}
ctx := cmd.Context()
if err := p.ForceRefreshUsers(ctx); err != nil && !errors.Is(err, provider.ErrRefreshRateLimited) {
return fmt.Errorf("refresh users: %w", err)
}
if err := p.ForceRefreshChannels(ctx); err != nil && !errors.Is(err, provider.ErrRefreshRateLimited) {
return fmt.Errorf("refresh channels: %w", err)
}
users := p.ProvideUsersMap()
channels := p.ProvideChannelsMaps()
fmt.Fprintf(cmd.OutOrStdout(), "Cache refreshed: %d users, %d channels\n", len(users.Users), len(channels.Channels))
return nil
},
}
}