cli: show owner/repo, not the repo_id ULID, in recap's scope line · Entire
cli: show owner/repo, not the repo_id ULID, in recap's scope line
24b5d4b→main·
Soph·1w ago·4 files·+71 added/-26 removed
/me/recap identifies the scoped repo by its repo_id ULID and echoes it back in repo, so recap rendered "repo 01KSFAN..." once routed to a cell. Thread the human owner/repo name (which the CLI already knows for the current repo) through RenderOptions/recapTUIOptions and prefer it in the scope label. Only set when actually scoped, so an unscoped recap isn't mislabelled.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
Sessions
0a8172314e8aView transcript
[?
Route CLI Commands to entire-apiClaude Code·2 steps](/content/gh/entireio/cli/session/473b5e55-d61f-4bc6-bcae-ab078e0d3cdd#timeline-0a8172314e8a/index.html)
Changes
4
cmd/entire/cli
Mrecap.go+20/-10
recap
Mrender_static.go+17/-7
Mstatic_server_test.go+19
Mrecap_tui.go+15/-9
137 unmodified lines
138
139
140
141
142
143
144
145
146
147
148
149
150
143
144
145
146
147
151
152
153
154
155
156
157
158
159
2 unmodified lines
162
163
164
156
157
158
159
160
165
166
167
168
169
170
171
172
173
137 unmodified lines
return err
}
rangeKey := f.rangeKey()
// The ?repo= value is a repo_id ULID when routed to a cell, which the recap
// response echoes back; show the human owner/repo name instead. Only when
// actually scoped (a repo query was sent), so an unscoped recap isn't
// mislabelled as scoped to the current repo.
repoName := ""
if repoSlug != "" {
repoName = currentRepoSlug(ctx)
}
if f.useTUI(interactive.IsTerminalWriter(w), interactive.CanPromptInteractively(), IsAccessibleMode()) {
return runRecapTUI(ctx, client, recapTUIOptions{
Range: rangeKey,
View: mode,
Agent: f.agentName(),
Repo: repoSlug,
Color: color,
Range: rangeKey,
View: mode,
Agent: f.agentName(),
Repo: repoSlug,
RepoName: repoName,
Color: color,
})
}
start, end := rangeKey.Bounds(time.Now())
2 unmodified lines
return handleRecapFetchError(errW, err)
}
fmt.Fprint(w, recap.RenderStaticRecap(resp, recap.RenderOptions{
Range: rangeKey,
View: mode,
Agent: f.agentName(),
Width: terminalWidth(w),
Color: color,
Range: rangeKey,
View: mode,
Agent: f.agentName(),
Width: terminalWidth(w),
Color: color,
RepoName: repoName,
}))
fmt.Fprintln(w)
return nil
Mcmd/entire/cli/recap.go+20/-10
22 unmodified lines
23
24
25
26
27
28
29
30
26
27
28
29
30
31
32
33
34
35
36
37
38
126 unmodified lines
165
166
167
163
168
169
170
171
142 unmodified lines
314
315
316
312
317
318
319
320
321
322
323
324
325
22 unmodified lines
)
type RenderOptions struct {
Range RangeKey
View ViewMode
Agent string
Width int
Color bool
Range Key
View ViewMode
Agent string
Width int
Color bool
// RepoName is the human owner/repo name of the repo the recap is scoped to,
// when the caller knows it. It is preferred over the response's repo field
// for display: /me/recap identifies the scoped repo by its repo_id ULID
// (echoed back verbatim), which is meaningless to show a user.
RepoName string
Location *time.Location
}
126 unmodified lines
lines = append(lines, "", styles.muted.Render("top")+" "+strings.Join(top, styles.muted.Render(" · ")))
}
context := []string{plural(len(filteredAgents(resp, opts)), "agent")}
if repoScope := repoScopeText(resp); repoScope != "" {
if repoScope := repoScopeText(resp, opts.RepoName); repoScope != "" {
context = append(context, repoScope)
}
if !agentFiltered {
142 unmodified lines
return t.Format("Jan 2, 2006 15:04 MST")
}
func repoScopeText(resp *MeRecapResponse) string {
func repoScopeText(resp *MeRecapResponse, repoName string) string {
// The caller-supplied human name wins when the recap is scoped to one repo:
// the response echoes the queried repo_id ULID, not an owner/repo slug.
if name := strings.TrimSpace(repoName); name != "" {
return "repo " + name
}
repos := recapRepoNames(resp)
switch {
case len(repos) == 1:
Mcmd/entire/cli/recap/render_static.go+17/-7
6 unmodified lines
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
6 unmodified lines
"time"
)
func TestRenderStaticRecap_RepoNameOverridesEchoedID(t *testing.T) {
t.Parallel()
// /me/recap echoes the queried repo_id ULID in Repo; the caller-supplied
// human name must be shown instead.
resp := &MeRecapResponse{
Repo: ptr("01KSFAN13YPQ0EWBV5KRE7F5HV"),
Since: "2026-05-02T04:00:00Z",
Until: "2026-05-09T04:00:00Z",
Summary: Summary{Me: SummaryTotals{Checkpoints: 1}, RepoCount: 1, ActiveDays: 1},
}
out := RenderStaticRecap(resp, RenderOptions{Range: RangeDay, View: ViewYou, Width: 80, RepoName: "entireio/cli"})
if !strings.Contains(out, "repo entireio/cli") {
t.Errorf("expected human repo name in output, got:\n%s", out)
}
if strings.Contains(out, "01KSFAN13YPQ0EWBV5KRE7F5HV") {
t.Errorf("expected the repo_id ULID to be hidden, got:\n%s", out)
}
}
func TestRenderStaticRecap_ServerBackedBoth90(t *testing.T) {
t.Parallel()
resp := &MeRecapResponse{
Mcmd/entire/cli/recap/static_server_test.go+19
20 unmodified lines
21
22
23
24
24
25
26
27
28
29
30
7 unmodified lines
38
39
40
38
39
40
41
42
43
44
45
46
47
33 unmodified lines
81
82
83
84
85
86
87
161 unmodified lines
249
250
251
247
248
249
250
251
252
253
254
255
256
257
258
259
260
20 unmodified lines
View recap.ViewMode
Agent string
Repo string
Color bool
// RepoName is the human owner/repo display name for the scoped repo; Repo is
// the ?repo= query value (a repo_id ULID when routed to a cell).
RepoName string
Color bool
}
type recapDataMsg struct {
7 unmodified lines
}
type recapTUIModel struct {
ctx context.Context
client *api.Client
repo string
ctx context.Context
client *api.Client
repo string
repoName string
rangeKey recap.RangeKey
view recap.ViewMode
33 unmodified lines
ctx: ctx,
client: client,
repo: opts.Repo,
repoName: opts.RepoName,
rangeKey: opts.Range,
view: opts.View,
agent: opts.Agent,
161 unmodified lines
}
if m.resp != nil {
m.viewport.SetContent(recap.RenderStaticRecap(m.resp, recap.RenderOptions{
Range: m.rangeKey,
View: m.view,
Agent: m.agent,
Width: m.width,
Color: m.color,
Range: m.rangeKey,
View: m.view,
Agent: m.agent,
Width: m.width,
Color: m.color,
RepoName: m.repoName,
}))
}
return m