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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
- `messages thread` and `messages history` now surface file attachments in text output as `[file] <name> (<type>, <size>) — slck files download <id>` hints, giving readers a valid download command inline (#141)
- `messages thread` and `messages history` now render Slack rich-text blocks (previously dropped), so messages pasted as tables, lists, or formatted content are visible in the default text output (#141)

### Changed
- Renamed the `whoami` command to `me` for consistency with sibling CLIs; `whoami` has been removed with no backwards-compatible alias (#159)

### Fixed
- `messages thread` text output no longer truncates at 80 characters (#134)
- `messages thread` / `messages history` no longer silently drop file attachments or rich-text block content (#141)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -746,7 +746,7 @@ slck canvas delete F12345ABC

```bash
# Show authenticated identity (bot, user, workspace)
slck whoami
slck me
```

### Config
Expand Down
6 changes: 3 additions & 3 deletions integration-tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -573,12 +573,12 @@ These are read-only tests with no side effects.

No additional scopes required (uses `auth.test` which works with any valid token).

### 9.1 Whoami
### 9.1 Me

| Step | Command | Expected |
|------|---------|----------|
| 1 | `slck whoami` | Shows Bot name/ID, Workspace name |
| 2 | `slck whoami -o json` | JSON with bot, workspace fields |
| 1 | `slck me` | Shows Bot name/ID, Workspace name |
| 2 | `slck me -o json` | JSON with bot, workspace fields |

---

Expand Down
20 changes: 10 additions & 10 deletions internal/cmd/whoami/whoami.go → internal/cmd/me/me.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package whoami
package me

import (
"github.com/spf13/cobra"
Expand All @@ -7,10 +7,10 @@ import (
"github.com/open-cli-collective/slack-chat-api/internal/output"
)

type whoamiOptions struct{}
type meOptions struct{}

// WhoamiResult represents the authenticated identity info
type WhoamiResult struct {
// MeResult represents the authenticated identity info
type MeResult struct {
Bot *BotInfo `json:"bot,omitempty"`
User *UserInfo `json:"user,omitempty"`
Workspace *WorkspaceInfo `json:"workspace"`
Expand All @@ -34,25 +34,25 @@ type WorkspaceInfo struct {
ID string `json:"id"`
}

// NewCmd creates the whoami command
// NewCmd creates the me command
func NewCmd() *cobra.Command {
opts := &whoamiOptions{}
opts := &meOptions{}

return &cobra.Command{
Use: "whoami",
Use: "me",
Short: "Show the authenticated identity",
Long: `Show the identity associated with the configured API tokens.

This is a quick way to verify which bot or user account will be used
for operations, and which workspace the tokens are associated with.`,
RunE: func(cmd *cobra.Command, args []string) error {
return runWhoami(opts, nil, nil)
return runMe(opts, nil, nil)
},
}
}

func runWhoami(opts *whoamiOptions, botClient *client.Client, userClient *client.Client) error {
result := &WhoamiResult{}
func runMe(opts *meOptions, botClient *client.Client, userClient *client.Client) error {
result := &MeResult{}
var workspace *WorkspaceInfo

// Test bot token
Expand Down
38 changes: 19 additions & 19 deletions internal/cmd/whoami/whoami_test.go → internal/cmd/me/me_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package whoami
package me

import (
"encoding/json"
Expand All @@ -13,7 +13,7 @@ import (
"github.com/open-cli-collective/slack-chat-api/internal/testutil"
)

func TestRunWhoami_BotTokenOnly(t *testing.T) {
func TestRunMe_BotTokenOnly(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, "/auth.test", r.URL.Path)
w.Header().Set("Content-Type", "application/json")
Expand All @@ -29,14 +29,14 @@ func TestRunWhoami_BotTokenOnly(t *testing.T) {
defer server.Close()

botClient := client.NewWithConfig(server.URL, "xoxb-test", nil)
opts := &whoamiOptions{}
opts := &meOptions{}

// Pass bot client, nil for user client
err := runWhoami(opts, botClient, nil)
err := runMe(opts, botClient, nil)
require.NoError(t, err)
}

func TestRunWhoami_UserTokenOnly(t *testing.T) {
func TestRunMe_UserTokenOnly(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, "/auth.test", r.URL.Path)
w.Header().Set("Content-Type", "application/json")
Expand All @@ -51,14 +51,14 @@ func TestRunWhoami_UserTokenOnly(t *testing.T) {
defer server.Close()

userClient := client.NewWithConfig(server.URL, "xoxp-test", nil)
opts := &whoamiOptions{}
opts := &meOptions{}

// Pass nil for bot client, user client provided
err := runWhoami(opts, nil, userClient)
err := runMe(opts, nil, userClient)
require.NoError(t, err)
}

func TestRunWhoami_BothTokens(t *testing.T) {
func TestRunMe_BothTokens(t *testing.T) {
botServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(map[string]interface{}{
Expand Down Expand Up @@ -86,24 +86,24 @@ func TestRunWhoami_BothTokens(t *testing.T) {

botClient := client.NewWithConfig(botServer.URL, "xoxb-test", nil)
userClient := client.NewWithConfig(userServer.URL, "xoxp-test", nil)
opts := &whoamiOptions{}
opts := &meOptions{}

err := runWhoami(opts, botClient, userClient)
err := runMe(opts, botClient, userClient)
require.NoError(t, err)
}

func TestRunWhoami_NoTokens(t *testing.T) {
func TestRunMe_NoTokens(t *testing.T) {
// Hermetic empty keyring (file backend, temp HOME) — no real keychain.
testutil.Setup(t)

opts := &whoamiOptions{}
opts := &meOptions{}

// Pass nil clients to trigger token lookup
err := runWhoami(opts, nil, nil)
err := runMe(opts, nil, nil)
require.NoError(t, err)
}

func TestRunWhoami_AuthFailed(t *testing.T) {
func TestRunMe_AuthFailed(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(map[string]interface{}{
Expand All @@ -114,14 +114,14 @@ func TestRunWhoami_AuthFailed(t *testing.T) {
defer server.Close()

botClient := client.NewWithConfig(server.URL, "bad-token", nil)
opts := &whoamiOptions{}
opts := &meOptions{}

// Auth fails, but function should handle gracefully
err := runWhoami(opts, botClient, nil)
err := runMe(opts, botClient, nil)
require.NoError(t, err)
}

func TestRunWhoami_BotWithoutBotID(t *testing.T) {
func TestRunMe_BotWithoutBotID(t *testing.T) {
// Some tokens may not have a bot_id
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
Expand All @@ -136,8 +136,8 @@ func TestRunWhoami_BotWithoutBotID(t *testing.T) {
defer server.Close()

botClient := client.NewWithConfig(server.URL, "xoxb-test", nil)
opts := &whoamiOptions{}
opts := &meOptions{}

err := runWhoami(opts, botClient, nil)
err := runMe(opts, botClient, nil)
require.NoError(t, err)
}
4 changes: 2 additions & 2 deletions internal/cmd/root/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ import (
"github.com/open-cli-collective/slack-chat-api/internal/cmd/emoji"
"github.com/open-cli-collective/slack-chat-api/internal/cmd/files"
"github.com/open-cli-collective/slack-chat-api/internal/cmd/initcmd"
"github.com/open-cli-collective/slack-chat-api/internal/cmd/me"
"github.com/open-cli-collective/slack-chat-api/internal/cmd/messages"
"github.com/open-cli-collective/slack-chat-api/internal/cmd/search"
"github.com/open-cli-collective/slack-chat-api/internal/cmd/setcred"
"github.com/open-cli-collective/slack-chat-api/internal/cmd/users"
"github.com/open-cli-collective/slack-chat-api/internal/cmd/whoami"
"github.com/open-cli-collective/slack-chat-api/internal/cmd/workspace"
"github.com/open-cli-collective/slack-chat-api/internal/output"
"github.com/open-cli-collective/slack-chat-api/internal/version"
Expand Down Expand Up @@ -96,7 +96,7 @@ func init() {
rootCmd.AddCommand(messages.NewCmd())
rootCmd.AddCommand(search.NewCmd())
rootCmd.AddCommand(workspace.NewCmd())
rootCmd.AddCommand(whoami.NewCmd())
rootCmd.AddCommand(me.NewCmd())
rootCmd.AddCommand(config.NewCmd())
rootCmd.AddCommand(emoji.NewCmd())
rootCmd.AddCommand(files.NewCmd())
Expand Down
23 changes: 23 additions & 0 deletions internal/cmd/root/root_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,26 @@ func TestNoFlagsDefaultsBotMode(t *testing.T) {
t.Errorf("default should resolve the bot token; got %q", msg)
}
}

// TestRootRegistersMeNotWhoami locks the issue #159 contract: the identity
// command is registered as `me` (matching sibling CLIs) and `whoami` is gone
// with no alias fallback (no backwards compatibility).
func TestRootRegistersMeNotWhoami(t *testing.T) {
var meCount int
for _, c := range rootCmd.Commands() {
if c.Name() == "whoami" {
t.Errorf("whoami command must not be registered (issue #159)")
}
if c.Name() == "me" {
meCount++
}
for _, a := range c.Aliases {
if a == "whoami" {
t.Errorf("command %q must not alias whoami (no backwards compatibility)", c.Name())
}
}
}
if meCount != 1 {
t.Errorf("expected exactly one `me` command, found %d", meCount)
}
}
10 changes: 5 additions & 5 deletions internal/noleak/noleak_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ import (
"github.com/open-cli-collective/slack-chat-api/internal/cmd/channels"
cfgcmd "github.com/open-cli-collective/slack-chat-api/internal/cmd/config"
initcmd "github.com/open-cli-collective/slack-chat-api/internal/cmd/initcmd"
"github.com/open-cli-collective/slack-chat-api/internal/cmd/me"
"github.com/open-cli-collective/slack-chat-api/internal/cmd/messages"
"github.com/open-cli-collective/slack-chat-api/internal/cmd/setcred"
"github.com/open-cli-collective/slack-chat-api/internal/cmd/whoami"
"github.com/open-cli-collective/slack-chat-api/internal/keychain"
"github.com/open-cli-collective/slack-chat-api/internal/output"
"github.com/open-cli-collective/slack-chat-api/internal/testutil"
Expand Down Expand Up @@ -133,14 +133,14 @@ func TestNoLeak_InitFromEnv(t *testing.T) {
assertNoLeak(t, "init --bot-token-from-env", out)
}

func TestNoLeak_Whoami(t *testing.T) {
func TestNoLeak_Me(t *testing.T) {
testutil.Setup(t)
seed(t)
c := whoami.NewCmd()
c := me.NewCmd()
c.SetArgs([]string{})
// whoami will fail to reach Slack (hermetic env); we only care that no
// me will fail to reach Slack (hermetic env); we only care that no
// output channel echoes the seeded token.
assertNoLeak(t, "whoami", captureAll(t, "", func() { _ = c.Execute() }))
assertNoLeak(t, "me", captureAll(t, "", func() { _ = c.Execute() }))
}

func TestNoLeak_ConfigTest(t *testing.T) {
Expand Down
Loading