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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ dispatch info 0a1b2c3d --json
dispatch info 0a1b2c3d --refs
```

The summary covers the session's repository, branch, working directory, host type, turn and file counts, timestamps, and linked ref counts. Use `--refs` to include linked commit, PR, and issue values, or `--json` for scripting. The session ID accepts the same prefix shorthand as `open`.
The summary covers the session's repository, branch, working directory, host type, saved alias, tags, note, turn and file counts, timestamps, and linked ref counts. Use `--refs` to include linked commit, PR, and issue values, or `--json` for scripting. The session ID accepts the same prefix shorthand as `open`.

### Aliases

Expand Down
29 changes: 29 additions & 0 deletions cmd/dispatch/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"io"
"strings"

"github.com/jongio/dispatch/internal/config"
"github.com/jongio/dispatch/internal/data"
)

Expand All @@ -28,6 +29,9 @@ type sessionInfo struct {
CreatedAt string `json:"created_at,omitempty"`
UpdatedAt string `json:"updated_at,omitempty"`
LastActiveAt string `json:"last_active_at,omitempty"`
Alias string `json:"alias,omitempty"`
Tags []string `json:"tags,omitempty"`
Note string `json:"note,omitempty"`
Turns int `json:"turns"`
Files int `json:"files"`
Checkpoints int `json:"checkpoints"`
Expand Down Expand Up @@ -64,6 +68,11 @@ func runInfo(w io.Writer, args []string) error {
}

info := buildSessionInfo(detail)
cfg, err := configLoadFn()
if err != nil {
return fmt.Errorf("loading config: %w", err)
}
addInfoAnnotations(&info, cfg)
if includeRefs {
addInfoRefs(&info, detail.Refs)
}
Expand Down Expand Up @@ -136,6 +145,17 @@ func buildSessionInfo(detail *data.SessionDetail) sessionInfo {
return info
}

func addInfoAnnotations(info *sessionInfo, cfg *config.Config) {
if info == nil || cfg == nil {
return
}
info.Alias = cfg.AliasFor(info.ID)
if tags := cfg.TagsFor(info.ID); len(tags) > 0 {
info.Tags = append([]string(nil), tags...)
}
info.Note = cfg.SessionNotes[info.ID]
}

func addInfoRefs(info *sessionInfo, refs []data.SessionRef) {
info.Refs = &infoRefs{
Commits: []string{},
Expand Down Expand Up @@ -180,6 +200,11 @@ func writeInfoText(w io.Writer, info sessionInfo) error {
writeField("Branch:", info.Branch)
writeField("Directory:", info.Directory)
writeField("Host:", info.HostType)
writeField("Alias:", info.Alias)
if len(info.Tags) > 0 {
writeField("Tags:", strings.Join(info.Tags, ", "))
}
writeField("Note:", oneLine(info.Note))
writeField("Created:", info.CreatedAt)
writeField("Updated:", info.UpdatedAt)
writeField("Last active:", info.LastActiveAt)
Expand Down Expand Up @@ -215,6 +240,10 @@ func pluralize(n int, singular, plural string) string {
return fmt.Sprintf("%d %s", n, plural)
}

func oneLine(value string) string {
return strings.Join(strings.Fields(value), " ")
}

func formatRefList(values []string) string {
if len(values) == 0 {
return "-"
Expand Down
49 changes: 48 additions & 1 deletion cmd/dispatch/info_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"strings"
"testing"

"github.com/jongio/dispatch/internal/config"
"github.com/jongio/dispatch/internal/data"
"github.com/jongio/dispatch/internal/update"
)
Expand All @@ -17,7 +18,12 @@ func withInfoDetail(t *testing.T, fn func(string) (*data.SessionDetail, error))
t.Helper()
prev := infoGetDetailFn
infoGetDetailFn = fn
t.Cleanup(func() { infoGetDetailFn = prev })
prevConfig := configLoadFn
configLoadFn = func() (*config.Config, error) { return &config.Config{}, nil }
t.Cleanup(func() {
infoGetDetailFn = prev
configLoadFn = prevConfig
})
}

func infoSampleDetail() *data.SessionDetail {
Expand Down Expand Up @@ -156,6 +162,47 @@ func TestRunInfo_TextWithRefs(t *testing.T) {
}
}

func TestRunInfo_IncludesAnnotations(t *testing.T) {
withInfoDetail(t, func(string) (*data.SessionDetail, error) {
return infoSampleDetail(), nil
})
prevConfig := configLoadFn
configLoadFn = func() (*config.Config, error) {
return &config.Config{
SessionAliases: map[string]string{"ses-info-1": "widget"},
SessionTags: map[string][]string{"ses-info-1": {"work", "ui"}},
SessionNotes: map[string]string{"ses-info-1": "follow up\nwith tests"},
}, nil
}
t.Cleanup(func() { configLoadFn = prevConfig })

var text bytes.Buffer
if err := runInfo(&text, []string{"info", "ses-info-1"}); err != nil {
t.Fatalf("unexpected error: %v", err)
}
for _, want := range []string{
"Alias: widget",
"Tags: work, ui",
"Note: follow up with tests",
} {
if !strings.Contains(text.String(), want) {
t.Errorf("text output missing %q, got:\n%s", want, text.String())
}
}

var jsonOut bytes.Buffer
if err := runInfo(&jsonOut, []string{"info", "ses-info-1", "--json"}); err != nil {
t.Fatalf("unexpected JSON error: %v", err)
}
var got sessionInfo
if err := json.Unmarshal(jsonOut.Bytes(), &got); err != nil {
t.Fatalf("output is not valid JSON: %v\n%s", err, jsonOut.String())
}
if got.Alias != "widget" || strings.Join(got.Tags, ",") != "work,ui" || got.Note != "follow up\nwith tests" {
t.Errorf("annotations = alias %q tags %+v note %q", got.Alias, got.Tags, got.Note)
}
}

func TestRunInfo_TextOmitsEmptyFields(t *testing.T) {
withInfoDetail(t, func(string) (*data.SessionDetail, error) {
return &data.SessionDetail{Session: data.Session{ID: "bare"}}, nil
Expand Down