Skip to content

share: minimal default output + info subcommand (PR1 of 2) - #1

Merged
godspede merged 16 commits into
mainfrom
claude/unruffled-heyrovsky-7fc763
Apr 22, 2026
Merged

godspede merged 16 commits into
mainfrom
claude/unruffled-heyrovsky-7fc763

Conversation

@godspede

Copy link
Copy Markdown
Owner

Summary

First of two sequential PRs for a share-UX redesign.

  • Default human output of ghosthost share is now just the URL (one line). --verbose/-v restores the previous rich block. --json unchanged (still a bare SharePayload).
  • New ghosthost info <arg> subcommand — resolves any of {full URL, URL path, bare token, bare id} to share metadata. Revoked / expired / unknown shares all surface identically as "not found" (ExitNotFound).
  • New GET /info admin endpoint — 404 on miss, 400 on parse error, Bearer-auth-gated like the rest of the admin API.

Spec: docs/superpowers/specs/2026-04-21-share-multifile-and-minimal-output-design.md
Plan: docs/superpowers/plans/2026-04-21-pr1-share-minimal-output-and-info.md

PR2 (variadic share + --anon) will land on top of this.

Breaking changes

  • ghosthost share <path> human-mode output no longer prints id/expiry. Scripts parsing stdout break; mitigation is --verbose or --json.
  • No change to --json (stays a bare object in PR1; PR2 will turn it into an array).

Test plan

  • go test ./... — 7 packages green, zero regressions
  • go vet ./... — clean
  • go build ./cmd/ghosthost — ok
  • ghosthost --help shows the new info subcommand and the --verbose flag
  • Manual end-to-end smoke against a live daemon: create a share, verify URL-only stdout, look up via ghosthost info <url> in each of the four input forms, confirm expired/revoked both surface as not-found

🤖 Generated with Claude Code

Zack Frank and others added 16 commits April 21, 2026 20:48
Design doc covering two sequential PRs: (1) reshape `share`'s default
human output to a bare URL, add `ghosthost info` for post-hoc lookup
by URL/path/token/id; (2) make `share` variadic with atomic validation,
add `--anon` for randomized display-names preserving extension, move
`--json` to an array shape.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two sequential PR plans for the share UX redesign in
docs/superpowers/specs/2026-04-21-share-multifile-and-minimal-output-design.md.

PR1 lands first: default human output becomes a bare URL, --verbose
restores the rich block, and new `ghosthost info <url-or-id>`
resolves metadata post-hoc. PR2 then makes share variadic with
atomic validation, adds --anon for randomized filename slugs with
preserved extensions, and shifts --json to always emit an array
(breaking).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- add comment explaining tokens/ids are always lowercase
- add test case locking in uppercase rejection
- correct spec regex (A-Z → a-z) and revoke lookup description (prefix → exact)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- export admin.ErrNotFound so HTTP handler can map lookup misses to 404
  and parse errors to 400
- assert Info miss paths return the sentinel via errors.Is
- add expired-but-not-yet-GC'd case using the fake clock

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…block

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…s hardcoded verbose

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- spec: "exit 3" -> "ExitNotFound (exit 5)"
- schema.go: comment on InfoPayload explaining Token is safe because
  /info is Bearer-auth-gated admin API, like /share and /list

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@godspede
godspede merged commit 48fb7e8 into main Apr 22, 2026
2 checks passed
godspede added a commit that referenced this pull request Jul 17, 2026
* docs(spec): share multi-file + minimal output design

Design doc covering two sequential PRs: (1) reshape `share`'s default
human output to a bare URL, add `ghosthost info` for post-hoc lookup
by URL/path/token/id; (2) make `share` variadic with atomic validation,
add `--anon` for randomized display-names preserving extension, move
`--json` to an array shape.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(plan): PR1 minimal-output + info, PR2 multi-file + --anon

Two sequential PR plans for the share UX redesign in
docs/superpowers/specs/2026-04-21-share-multifile-and-minimal-output-design.md.

PR1 lands first: default human output becomes a bare URL, --verbose
restores the rich block, and new `ghosthost info <url-or-id>`
resolves metadata post-hoc. PR2 then makes share variadic with
atomic validation, adds --anon for randomized filename slugs with
preserved extensions, and shifts --json to always emit an array
(breaking).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(admin): ParseInfoQuery normalizes URL/path/token/id

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* docs(admin): clarify ParseInfoQuery rejects uppercase; fix spec

- add comment explaining tokens/ids are always lowercase
- add test case locking in uppercase rejection
- correct spec regex (A-Z → a-z) and revoke lookup description (prefix → exact)

* feat(admin): add InfoPayload type

* feat(daemon): Core.Info resolves URL/path/token/id to InfoPayload

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(cli): add Info stub to stubCore to satisfy admin.Core interface

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test(daemon): cover expired case; use admin.ErrNotFound sentinel

- export admin.ErrNotFound so HTTP handler can map lookup misses to 404
  and parse errors to 400
- assert Info miss paths return the sentinel via errors.Is
- add expired-but-not-yet-GC'd case using the fake clock

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(admin): GET /info endpoint; 404 on miss, 400 on parse error

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test(admin): cover empty-q case in TestInfoEndpoint

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(cli): Client.Info

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(cli): default share output is URL only; --verbose restores rich block

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test(cli): verify --verbose is ignored in JSON mode; comment reshare's hardcoded verbose

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(cli): info subcommand

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* docs: default share output is URL only; document info subcommand

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* docs: fix stale exit-code; note Token is admin-only in InfoPayload

- spec: "exit 3" -> "ExitNotFound (exit 5)"
- schema.go: comment on InfoPayload explaining Token is safe because
  /info is Bearer-auth-gated admin API, like /share and /list

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: godspede <jehutheawesome@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@godspede
godspede deleted the claude/unruffled-heyrovsky-7fc763 branch July 17, 2026 20:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant