Skip to content

Add entire search command#679

Open
evisdren wants to merge 19 commits intomainfrom
cli_search
Open

Add entire search command#679
evisdren wants to merge 19 commits intomainfrom
cli_search

Conversation

@evisdren
Copy link
Contributor

@evisdren evisdren commented Mar 10, 2026

Summary

  • New entire search <query> command for hybrid semantic + keyword checkpoint search
  • Calls the Entire search service (thin HTTP client, no direct Turbopuffer/OpenAI keys needed)
  • Auth exclusively via GitHub device flow token (entire login) — PAT fallbacks (GITHUB_TOKEN env var, gh auth token) removed
  • Supports --branch filtering and --limit; JSON output only for agent/script consumption
  • Updated README with search command docs and auth requirements

Files

  • cmd/entire/cli/search/ — search client package (github.go for remote parsing, search.go for service client)
  • cmd/entire/cli/search_cmd.go — Cobra command
  • cmd/entire/cli/auth/resolve.go — simplified to device flow token only
  • cmd/entire/cli/auth_cmd.go — updated auth-status to use new signature
  • cmd/entire/cli/root.go — command registration
  • README.md — docs for search command, flags, and auth

Companion PR

  • Search service: entirehq/entire.io#981

Test plan

  • go build ./cmd/entire/ compiles cleanly
  • go test ./... — all tests pass
  • entire login completes device flow and stores token
  • entire search "test query" with stored token returns results
  • entire search without a stored token shows: not authenticated. Run 'entire login'
  • GITHUB_TOKEN env var is no longer accepted as auth
  • entire auth-status shows correct status with/without stored token
  • mise run lint passes

🤖 Generated with Claude Code

@evisdren evisdren requested a review from a team as a code owner March 10, 2026 19:55
Copilot AI review requested due to automatic review settings March 10, 2026 19:55
@cursor
Copy link

cursor bot commented Mar 10, 2026

PR Summary

Medium Risk
Adds a new networked command that sends a GitHub token to an external service and depends on remote URL parsing; failures or misconfiguration primarily impact this new command’s UX rather than existing flows.

Overview
Adds a new entire search <query> CLI command that queries the Entire hosted search service to find checkpoints using hybrid semantic+keyword ranking, with optional --branch, --limit, and --json output modes.

The command resolves repo identity from the origin GitHub remote, requires a GitHub token (GITHUB_TOKEN or gh auth token) for authenticated requests, and introduces a small HTTP client (cmd/entire/cli/search) plus README documentation for usage and environment variables (including ENTIRE_SEARCH_URL).

Written by Cursor Bugbot for commit bf3e776. Configure here.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Byte-based truncation duplicates existing UTF-8-safe utility
    • Replaced byte-slicing truncation in truncateStr with stringutil.TruncateRunes to ensure UTF-8-safe truncation and reuse the existing utility.
  • ✅ Fixed: Display count uses server total, not actual results
    • Updated the header to report len(resp.Results) so the displayed count matches the number of rows shown to users.

Create PR

Or push these changes by commenting:

@cursor push 43625e2af1
Preview (43625e2af1)
diff --git a/cmd/entire/cli/search_cmd.go b/cmd/entire/cli/search_cmd.go
--- a/cmd/entire/cli/search_cmd.go
+++ b/cmd/entire/cli/search_cmd.go
@@ -10,6 +10,7 @@
 	"github.com/entireio/cli/cmd/entire/cli/jsonutil"
 	"github.com/entireio/cli/cmd/entire/cli/search"
 	"github.com/entireio/cli/cmd/entire/cli/strategy"
+	"github.com/entireio/cli/cmd/entire/cli/stringutil"
 	"github.com/spf13/cobra"
 )
 
@@ -113,7 +114,7 @@
 			}
 
 			// Pretty print
-			fmt.Fprintf(cmd.OutOrStdout(), "\nFound %d results for %s:\n\n", resp.Total, resp.Repo)
+			fmt.Fprintf(cmd.OutOrStdout(), "\nFound %d results for %s:\n\n", len(resp.Results), resp.Repo)
 			w := tabwriter.NewWriter(cmd.OutOrStdout(), 0, 0, 2, ' ', 0)
 			fmt.Fprintln(w, "RANK\tCHECKPOINT\tSCORE\tMATCH\tBRANCH\tAUTHOR\tPROMPT")
 			for i, r := range resp.Results {
@@ -147,8 +148,5 @@
 }
 
 func truncateStr(s string, maxLen int) string {
-	if len(s) <= maxLen {
-		return s
-	}
-	return s[:maxLen-3] + "..."
+	return stringutil.TruncateRunes(s, maxLen, "...")
 }

This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.

Comment @cursor review or bugbot run to trigger another review on this PR

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new entire search <query> CLI command that queries the Entire hosted search service to find checkpoints in the current Git repository, supporting both human-readable and --json output for automation.

Changes:

  • Introduces entire search Cobra command with --json, --branch, and --limit flags and origin-remote parsing.
  • Adds a thin HTTP client (cmd/entire/cli/search) plus unit tests for GitHub remote parsing.
  • Registers the command and documents usage/auth requirements in the README.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
cmd/entire/cli/search_cmd.go Implements the entire search command, token resolution, repo remote parsing, and output formatting.
cmd/entire/cli/search/search.go Adds HTTP client to call the Entire search service and parse responses.
cmd/entire/cli/search/github.go Adds GitHub remote URL parsing helper.
cmd/entire/cli/search/search_test.go Unit tests for ParseGitHubRemote variants.
cmd/entire/cli/root.go Registers the new search command on the root CLI.
README.md Documents entire search, flags, and token requirements.

var path string

// SSH format: git@github.com:owner/repo.git
if strings.HasPrefix(remoteURL, "git@") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed in person: I'd be interested to see if url.Parse() would work on a SSH URL as well, but I'm assuming that there's a reason for this conditional to be there. 👍

Copy link
Collaborator

@Soph Soph left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to say that using gh auth token in any way is not something we will do.

evisdren and others added 16 commits March 11, 2026 13:10
New command that calls the Entire search service to perform hybrid
semantic + keyword search over checkpoints. Auth via GitHub token
(GITHUB_TOKEN env var or `gh auth token`). Supports --json for
agent consumption, --branch filtering, and --limit.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Extract repeated test string to constant (goconst)
- Suppress gosec G704 SSRF warning on trusted URL (gosec)
- Handle tabwriter Flush error (gosec G104)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The search service now returns full checkpoint data (commit info, token
usage, file stats, etc.) instead of just IDs and scores. Updated Result
struct and display to use the new nested searchMeta and camelCase fields.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove TUI, tabwriter, and --json flag. Output is always JSON,
making the command straightforward for agent and script consumption.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- TrimSpace on GITHUB_TOKEN env var to handle trailing newlines
- Reject non-github.com remotes in ParseGitHubRemote with clear error
- Add httptest-based tests for Search(): URL/query construction, auth
  header, branch/limit omission, JSON error handling, raw body error,
  and successful result parsing
- truncateStr was already removed with the TUI deletion

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- entire login: GitHub OAuth device flow, stores token in .entire/auth.json
- entire logout: removes stored credentials
- entire auth-status: shows token source (file, env, or gh CLI)
- Token resolution: .entire/auth.json → GITHUB_TOKEN → gh auth token
- Search command uses new resolver instead of inline token logic

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Removes GITHUB_TOKEN env var and gh CLI token fallbacks from
ResolveGitHubToken so the CLI exclusively uses the token stored by
'entire login' (GitHub device flow). If no token is found, the user
is directed to run 'entire login'.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Entire-Checkpoint: c175a1a3a7c5
- gosec: nolint OAuth endpoint URL (G101) and token field (G117) false positives
- errcheck: explicit type assertion for error_description; handle readAuth errors in Set* funcs
- nilnil: replace (nil, nil) with errNoAuth sentinel in readAuth
- forbidigo: nolint os.Getwd() in authFilePath (walks up dirs, handles subdirectories)
- perfsprint: errors.New for static strings, strconv.Itoa for int formatting

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The file manages a JSON file in .entire/auth.json, not a system keyring.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- auth_cmd.go: guard against panic on short tokens in auth-status masking
- auth_cmd.go: use SetStoredAuth for atomic token+username write on login
- auth_cmd.go: pass raw interval to WaitForAuthorization (floor moved to auth logic)
- auth_cmd.go: call GetStoredToken directly, remove ResolveGitHubToken indirection
- github_device.go: unexport pollForToken (internal implementation detail)
- github_device.go: enforce 5s minimum polling interval inside WaitForAuthorization
- resolve.go: remove ResolveGitHubToken wrapper, keep only SourceEntireDir constant
- search_cmd.go: call GetStoredToken directly
- search.go: use http.DefaultClient consistently (matches auth package)
- store.go: replace deprecated os.IsNotExist with errors.Is(err, fs.ErrNotExist)
- store.go: add SetStoredAuth for atomic single-write of token+username
- store_test.go: add 5 tests covering walk-up, round-trip, no-file, atomic write, preservation
- README.md: document device flow auth, remove GITHUB_TOKEN/--json references

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- store.go: unexport setStoredToken/setStoredUsername (dead external API)
- store.go: move SourceEntireDir constant here, delete resolve.go
- github_device.go: add io.LimitReader(1MB) to all three auth HTTP reads
- README.md: add login/logout/auth-status to commands table and Authentication section

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- revive: rename 'real' variable to 'resolved' (shadows builtin)
- usetesting: replace os.Chdir with t.Chdir (handles restore automatically)

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

@Soph Soph left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use github.com/zalando/go-keyring to securely store the tokens?

Default to OS keyring (macOS Keychain, Linux Secret Service, Windows
Credential Manager) via go-keyring. Fall back to .entire/auth.json
when ENTIRE_TOKEN_STORE=file, matching the entiredb tokenstore pattern.

- store.go: introduce tokenStore interface with keyringTokenStore and
  fileTokenStore implementations; sync.Once backend resolution
- auth_cmd.go: use TokenSource() instead of hardcoded SourceEntireDir
- store_test.go: TestMain forces file backend; resetBackend() between
  tests; add TestTokenSourceFileBackend

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@evisdren
Copy link
Contributor Author

Can we use github.com/zalando/go-keyring to securely store the tokens?

updated

evisdren and others added 2 commits March 11, 2026 13:56
- wrapcheck: nolint thin public wrappers over tokenStore interface
- nolintlint: remove unused errcheck from TestMain nolint directive

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@evisdren evisdren requested a review from Soph March 11, 2026 21:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

4 participants