Skip to content
Open
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
7 changes: 5 additions & 2 deletions cmd/pilotctl/appstore_catalogue.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,9 +316,12 @@ func cmdAppStoreCatalogue(_ []string) {
return
}
for _, e := range c.Apps {
fmt.Printf("%-40s %s\n", e.ID, e.Description)
headline := e.Description
if e.DisplayName != "" {
headline = e.DisplayName
}
fmt.Printf("%-40s %-30s view: pilotctl appstore view %s\n", e.ID, headline, e.ID)
}
fmt.Println("\nRun 'pilotctl appstore view <id>' for full details.")
}

// installSource tags how a bundle reached the install command.
Expand Down
27 changes: 15 additions & 12 deletions cmd/pilotctl/zz_appstore_cmds_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -882,10 +882,11 @@ func TestCmdAppStoreDispatcher(t *testing.T) {
}

// TestCmdAppStoreCatalogueTextOneLinePerApp asserts that text-mode output
// prints exactly one line per app in the form "<id> <description>" (PILOT-405).
// prints one line per app: "<id> <headline> view: pilotctl appstore view <id>".
// When display_name is present, it is used as headline; otherwise description.
func TestCmdAppStoreCatalogueTextOneLinePerApp(t *testing.T) {
stageCatalogue(t, `{"version":2,"updated_at":"2026-06-17","apps":[
{"id":"io.pilot.wallet","version":"1.0.0","description":"Manages x402 payment credentials","bundle_url":"https://x/a.tgz","bundle_sha256":"abc"},
{"id":"io.pilot.wallet","version":"1.0.0","display_name":"Wallet","description":"Manages x402 payment credentials","bundle_url":"https://x/a.tgz","bundle_sha256":"abc"},
{"id":"io.pilot.cosift","version":"0.2.0","description":"Web search and answer agent","bundle_url":"https://x/b.tgz","bundle_sha256":"def"}
]}`)

Expand All @@ -895,12 +896,14 @@ func TestCmdAppStoreCatalogueTextOneLinePerApp(t *testing.T) {

out := captureStdout(t, func() { cmdAppStoreCatalogue(nil) })

// Each app must appear as a single line containing both id and description.
// Each app must have id, headline (display_name or description), and view pointer.
for _, want := range []string{
"io.pilot.wallet",
"Manages x402 payment credentials",
"Wallet",
"view: pilotctl appstore view io.pilot.wallet",
"io.pilot.cosift",
"Web search and answer agent",
"view: pilotctl appstore view io.pilot.cosift",
} {
if !strings.Contains(out, want) {
t.Errorf("missing %q in catalogue output:\n%s", want, out)
Expand All @@ -918,18 +921,18 @@ func TestCmdAppStoreCatalogueTextOneLinePerApp(t *testing.T) {
if len(appLines) != 2 {
t.Errorf("expected 2 app lines, got %d:\n%s", len(appLines), out)
}
// Each app line must contain the id and the description on the same line.
if !strings.Contains(appLines[0], "io.pilot.wallet") || !strings.Contains(appLines[0], "Manages x402") {
// First app uses display_name as headline; second falls back to description.
if !strings.Contains(appLines[0], "io.pilot.wallet") || !strings.Contains(appLines[0], "Wallet") {
t.Errorf("first app line wrong: %q", appLines[0])
}
if !strings.Contains(appLines[1], "io.pilot.cosift") || !strings.Contains(appLines[1], "Web search") {
t.Errorf("second app line wrong: %q", appLines[1])
}
}

// TestCmdAppStoreCatalogueTextViewPointerHint asserts the view-pointer hint
// appears at the end of text-mode catalogue output (PILOT-405).
func TestCmdAppStoreCatalogueTextViewPointerHint(t *testing.T) {
// TestCmdAppStoreCatalogueTextViewPointer asserts the view pointer appears
// on each app line in text-mode catalogue output (PILOT-405).
func TestCmdAppStoreCatalogueTextViewPointer(t *testing.T) {
stageCatalogue(t, `{"version":1,"updated_at":"2026-06-17","apps":[
{"id":"io.pilot.wallet","version":"1.0.0","description":"Manages x402 payment credentials","bundle_url":"https://x/a.tgz","bundle_sha256":"abc"}
]}`)
Expand All @@ -940,9 +943,9 @@ func TestCmdAppStoreCatalogueTextViewPointerHint(t *testing.T) {

out := captureStdout(t, func() { cmdAppStoreCatalogue(nil) })

const hint = "Run 'pilotctl appstore view <id>' for full details."
if !strings.Contains(out, hint) {
t.Errorf("view-pointer hint missing from catalogue output:\n%s", out)
const pointer = "view: pilotctl appstore view io.pilot.wallet"
if !strings.Contains(out, pointer) {
t.Errorf("view pointer missing from catalogue output:\n%s", out)
}
}

Expand Down
Loading