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
5 changes: 5 additions & 0 deletions .golangci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ linters:
- whitespace
- wrapcheck
settings:
gosec:
excludes:
- G204 # subprocess with variables is expected for git/opencode CLI wrappers
- G702 # command injection via taint - controlled CLI inputs
- G705 # XSS not applicable to CLI stderr output
dupl:
# Token threshold for duplication detection
# Lower = more sensitive (catches smaller duplicates)
Expand Down
4 changes: 2 additions & 2 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ builds:
- arm64
ldflags:
- -s -w
- -X github.com/entireio/cli/cmd/entire/cli/buildinfo.Version={{.Version}}
- -X github.com/entireio/cli/cmd/entire/cli/buildinfo.Commit={{.ShortCommit}}
- -X github.com/entireio/cli/cmd/entire/cli/versioninfo.Version={{.Version}}
- -X github.com/entireio/cli/cmd/entire/cli/versioninfo.Commit={{.ShortCommit}}
- -X github.com/entireio/cli/cmd/entire/cli/telemetry.PostHogAPIKey={{.Env.POSTHOG_API_KEY}}
- -X github.com/entireio/cli/cmd/entire/cli/telemetry.PostHogEndpoint={{.Env.POSTHOG_ENDPOINT}}

Expand Down
12 changes: 6 additions & 6 deletions cmd/entire/cli/checkpoint/checkpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ import (
"time"

"github.com/entireio/cli/cmd/entire/cli/agent"
"github.com/entireio/cli/cmd/entire/cli/buildinfo"
"github.com/entireio/cli/cmd/entire/cli/checkpoint/id"
"github.com/entireio/cli/cmd/entire/cli/paths"
"github.com/entireio/cli/cmd/entire/cli/trailers"
"github.com/entireio/cli/cmd/entire/cli/versioninfo"

"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/config"
Expand Down Expand Up @@ -2857,7 +2857,7 @@ func TestCopyMetadataDir_RedactsSecrets(t *testing.T) {
}
}

// TestWriteCommitted_CLIVersionField verifies that buildinfo.Version is written
// TestWriteCommitted_CLIVersionField verifies that versioninfo.Version is written
// to both the root CheckpointSummary and session-level CommittedMetadata.
func TestWriteCommitted_CLIVersionField(t *testing.T) {
t.Parallel()
Expand Down Expand Up @@ -2942,8 +2942,8 @@ func TestWriteCommitted_CLIVersionField(t *testing.T) {
t.Fatalf("failed to parse root metadata.json: %v", err)
}

if summary.CLIVersion != buildinfo.Version {
t.Errorf("CheckpointSummary.CLIVersion = %q, want %q", summary.CLIVersion, buildinfo.Version)
if summary.CLIVersion != versioninfo.Version {
t.Errorf("CheckpointSummary.CLIVersion = %q, want %q", summary.CLIVersion, versioninfo.Version)
}

// Verify session-level metadata.json (CommittedMetadata) has CLIVersion
Expand All @@ -2967,8 +2967,8 @@ func TestWriteCommitted_CLIVersionField(t *testing.T) {
t.Fatalf("failed to parse session metadata.json: %v", err)
}

if sessionMetadata.CLIVersion != buildinfo.Version {
t.Errorf("CommittedMetadata.CLIVersion = %q, want %q", sessionMetadata.CLIVersion, buildinfo.Version)
if sessionMetadata.CLIVersion != versioninfo.Version {
t.Errorf("CommittedMetadata.CLIVersion = %q, want %q", sessionMetadata.CLIVersion, versioninfo.Version)
}
}

Expand Down
18 changes: 9 additions & 9 deletions cmd/entire/cli/checkpoint/committed.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ import (
"time"

"github.com/entireio/cli/cmd/entire/cli/agent"
"github.com/entireio/cli/cmd/entire/cli/buildinfo"
"github.com/entireio/cli/cmd/entire/cli/checkpoint/id"
"github.com/entireio/cli/cmd/entire/cli/jsonutil"
"github.com/entireio/cli/cmd/entire/cli/logging"
"github.com/entireio/cli/cmd/entire/cli/paths"
"github.com/entireio/cli/cmd/entire/cli/trailers"
"github.com/entireio/cli/cmd/entire/cli/validation"
"github.com/entireio/cli/cmd/entire/cli/versioninfo"
"github.com/entireio/cli/redact"

"github.com/go-git/go-git/v5"
Expand Down Expand Up @@ -358,7 +358,7 @@ func (s *GitStore) writeSessionToSubdirectory(opts WriteCommittedOptions, sessio
TokenUsage: opts.TokenUsage,
InitialAttribution: opts.InitialAttribution,
Summary: redactSummary(opts.Summary),
CLIVersion: buildinfo.Version,
CLIVersion: versioninfo.Version,
}

metadataJSON, err := jsonutil.MarshalIndentWithNewline(sessionMetadata, "", " ")
Expand Down Expand Up @@ -403,7 +403,7 @@ func (s *GitStore) writeCheckpointSummary(opts WriteCommittedOptions, basePath s

summary := CheckpointSummary{
CheckpointID: opts.CheckpointID,
CLIVersion: buildinfo.Version,
CLIVersion: versioninfo.Version,
Strategy: opts.Strategy,
Branch: opts.Branch,
CheckpointsCount: checkpointsCount,
Expand Down Expand Up @@ -669,22 +669,22 @@ func (s *GitStore) buildCommitMessage(opts WriteCommittedOptions, taskMetadataPa
var commitMsg strings.Builder

// Subject line is always the checkpoint ID for consistent formatting
commitMsg.WriteString(fmt.Sprintf("Checkpoint: %s\n\n", opts.CheckpointID))
fmt.Fprintf(&commitMsg, "Checkpoint: %s\n\n", opts.CheckpointID)

// Include custom description in body if provided (e.g., task checkpoint details)
if opts.CommitSubject != "" {
commitMsg.WriteString(opts.CommitSubject + "\n\n")
}
commitMsg.WriteString(fmt.Sprintf("%s: %s\n", trailers.SessionTrailerKey, opts.SessionID))
commitMsg.WriteString(fmt.Sprintf("%s: %s\n", trailers.StrategyTrailerKey, opts.Strategy))
fmt.Fprintf(&commitMsg, "%s: %s\n", trailers.SessionTrailerKey, opts.SessionID)
fmt.Fprintf(&commitMsg, "%s: %s\n", trailers.StrategyTrailerKey, opts.Strategy)
if opts.Agent != "" {
commitMsg.WriteString(fmt.Sprintf("%s: %s\n", trailers.AgentTrailerKey, opts.Agent))
fmt.Fprintf(&commitMsg, "%s: %s\n", trailers.AgentTrailerKey, opts.Agent)
}
if opts.EphemeralBranch != "" {
commitMsg.WriteString(fmt.Sprintf("%s: %s\n", trailers.EphemeralBranchTrailerKey, opts.EphemeralBranch))
fmt.Fprintf(&commitMsg, "%s: %s\n", trailers.EphemeralBranchTrailerKey, opts.EphemeralBranch)
}
if taskMetadataPath != "" {
commitMsg.WriteString(fmt.Sprintf("%s: %s\n", trailers.MetadataTaskTrailerKey, taskMetadataPath))
fmt.Fprintf(&commitMsg, "%s: %s\n", trailers.MetadataTaskTrailerKey, taskMetadataPath)
}

return commitMsg.String()
Expand Down
2 changes: 1 addition & 1 deletion cmd/entire/cli/checkpoint/temporary.go
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,7 @@ func (s *GitStore) ShadowBranchExists(baseCommit, worktreeID string) bool {
// persist deletions with packed refs or worktrees.
func (s *GitStore) DeleteShadowBranch(baseCommit, worktreeID string) error {
shadowBranchName := ShadowBranchNameForCommit(baseCommit, worktreeID)
cmd := exec.CommandContext(context.Background(), "git", "branch", "-D", "--", shadowBranchName) //nolint:gosec // shadowBranchName is constructed from commit hash, not user input
cmd := exec.CommandContext(context.Background(), "git", "branch", "-D", "--", shadowBranchName)
if output, err := cmd.CombinedOutput(); err != nil {
return fmt.Errorf("failed to delete shadow branch %s: %s: %w", shadowBranchName, strings.TrimSpace(string(output)), err)
}
Expand Down
5 changes: 3 additions & 2 deletions cmd/entire/cli/explain.go
Original file line number Diff line number Diff line change
Expand Up @@ -1268,9 +1268,10 @@ func formatSessionInfo(session *strategy.Session, sourceRef string, checkpoints
// outputWithPager outputs content through a pager if stdout is a terminal and content is long.
func outputWithPager(w io.Writer, content string) {
// Check if we're writing to stdout and it's a terminal
//nolint:gosec // G115: uintptr->int is safe for fd on 64-bit platforms
if f, ok := w.(*os.File); ok && f == os.Stdout && term.IsTerminal(int(f.Fd())) {
// Get terminal height
_, height, err := term.GetSize(int(f.Fd()))
_, height, err := term.GetSize(int(f.Fd())) //nolint:gosec // G115: same as above
if err != nil {
height = 24 // Default fallback
}
Expand All @@ -1285,7 +1286,7 @@ func outputWithPager(w io.Writer, content string) {
pager = "less"
}

cmd := exec.CommandContext(context.Background(), pager) //nolint:gosec // pager from env is expected
cmd := exec.CommandContext(context.Background(), pager)
cmd.Stdin = strings.NewReader(content)
cmd.Stdout = f
cmd.Stderr = os.Stderr
Expand Down
4 changes: 2 additions & 2 deletions cmd/entire/cli/git_operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ func FetchAndCheckoutRemoteBranch(branchName string) error {
defer cancel()

refSpec := fmt.Sprintf("+refs/heads/%s:refs/remotes/origin/%s", branchName, branchName)
//nolint:gosec // G204: branchName validated above via git check-ref-format

fetchCmd := exec.CommandContext(ctx, "git", "fetch", "origin", refSpec)
if output, err := fetchCmd.CombinedOutput(); err != nil {
if ctx.Err() == context.DeadlineExceeded {
Expand Down Expand Up @@ -367,7 +367,7 @@ func FetchMetadataBranch() error {
defer cancel()

refSpec := fmt.Sprintf("+refs/heads/%s:refs/remotes/origin/%s", branchName, branchName)
//nolint:gosec // G204: branchName is a constant from paths package

fetchCmd := exec.CommandContext(ctx, "git", "fetch", "origin", refSpec)
if output, err := fetchCmd.CombinedOutput(); err != nil {
if ctx.Err() == context.DeadlineExceeded {
Expand Down
8 changes: 4 additions & 4 deletions cmd/entire/cli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import (
"fmt"
"runtime"

"github.com/entireio/cli/cmd/entire/cli/buildinfo"
"github.com/entireio/cli/cmd/entire/cli/telemetry"
"github.com/entireio/cli/cmd/entire/cli/versioncheck"
"github.com/entireio/cli/cmd/entire/cli/versioninfo"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -58,12 +58,12 @@ func NewRootCmd() *cobra.Command {
// Use detached tracking (non-blocking)
installedAgents := GetAgentsWithHooksInstalled()
agentStr := JoinAgentNames(installedAgents)
telemetry.TrackCommandDetached(cmd, settings.Strategy, agentStr, settings.Enabled, buildinfo.Version)
telemetry.TrackCommandDetached(cmd, settings.Strategy, agentStr, settings.Enabled, versioninfo.Version)
}

// Version check and notification (synchronous with 2s timeout)
// Runs AFTER command completes to avoid interfering with interactive modes
versioncheck.CheckAndNotify(cmd.OutOrStdout(), buildinfo.Version)
versioncheck.CheckAndNotify(cmd.OutOrStdout(), versioninfo.Version)
},
RunE: func(cmd *cobra.Command, _ []string) error {
return cmd.Help()
Expand Down Expand Up @@ -97,7 +97,7 @@ func newVersionCmd() *cobra.Command {
Use: "version",
Short: "Show build information",
Run: func(_ *cobra.Command, _ []string) {
fmt.Printf("Entire CLI %s (%s)\n", buildinfo.Version, buildinfo.Commit)
fmt.Printf("Entire CLI %s (%s)\n", versioninfo.Version, versioninfo.Commit)
fmt.Printf("Go version: %s\n", runtime.Version())
fmt.Printf("OS/Arch: %s/%s\n", runtime.GOOS, runtime.GOARCH)
},
Expand Down
4 changes: 2 additions & 2 deletions cmd/entire/cli/strategy/auto_commit.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ import (
"time"

"github.com/entireio/cli/cmd/entire/cli/agent"
"github.com/entireio/cli/cmd/entire/cli/buildinfo"
"github.com/entireio/cli/cmd/entire/cli/checkpoint"
"github.com/entireio/cli/cmd/entire/cli/checkpoint/id"
"github.com/entireio/cli/cmd/entire/cli/logging"
"github.com/entireio/cli/cmd/entire/cli/paths"
"github.com/entireio/cli/cmd/entire/cli/trailers"
"github.com/entireio/cli/cmd/entire/cli/versioninfo"

"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
Expand Down Expand Up @@ -970,7 +970,7 @@ func (s *AutoCommitStrategy) InitializeSession(sessionID string, agentType agent
now := time.Now()
state := &SessionState{
SessionID: sessionID,
CLIVersion: buildinfo.Version,
CLIVersion: versioninfo.Version,
BaseCommit: baseCommit,
StartedAt: now,
LastInteractionTime: &now,
Expand Down
18 changes: 9 additions & 9 deletions cmd/entire/cli/strategy/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -773,13 +773,13 @@ func checkCanRewind() (bool, string, error) {
var msg strings.Builder
msg.WriteString("You have uncommitted changes:\n")
for _, f := range modified {
msg.WriteString(fmt.Sprintf(" modified: %s\n", f))
fmt.Fprintf(&msg, " modified: %s\n", f)
}
for _, f := range added {
msg.WriteString(fmt.Sprintf(" added: %s\n", f))
fmt.Fprintf(&msg, " added: %s\n", f)
}
for _, f := range deleted {
msg.WriteString(fmt.Sprintf(" deleted: %s\n", f))
fmt.Fprintf(&msg, " deleted: %s\n", f)
}
msg.WriteString("\nPlease commit or stash your changes before rewinding.")

Expand Down Expand Up @@ -920,15 +920,15 @@ func checkCanRewindWithWarning() (bool, string, error) {
stats = fmt.Sprintf("-%d", c.removed)
}

msg.WriteString(fmt.Sprintf(" %-10s %s", c.status+":", c.filename))
fmt.Fprintf(&msg, " %-10s %s", c.status+":", c.filename)
if stats != "" {
msg.WriteString(fmt.Sprintf(" (%s)", stats))
fmt.Fprintf(&msg, " (%s)", stats)
}
msg.WriteString("\n")
}

if totalAdded > 0 || totalRemoved > 0 {
msg.WriteString(fmt.Sprintf("\nTotal: +%d/-%d lines\n", totalAdded, totalRemoved))
fmt.Fprintf(&msg, "\nTotal: +%d/-%d lines\n", totalAdded, totalRemoved)
}

return true, msg.String(), nil
Expand Down Expand Up @@ -1178,7 +1178,7 @@ func DeleteBranchCLI(branchName string) error {
// git show-ref exits 1 for "not found" and 128+ for fatal errors (corrupt
// repo, permissions, not a git directory). Only map exit code 1 to
// ErrBranchNotFound; propagate other failures as-is.
check := exec.CommandContext(ctx, "git", "show-ref", "--verify", "--quiet", "refs/heads/"+branchName) //nolint:gosec // branchName comes from internal shadow branch naming
check := exec.CommandContext(ctx, "git", "show-ref", "--verify", "--quiet", "refs/heads/"+branchName)
if err := check.Run(); err != nil {
var exitErr *exec.ExitError
if errors.As(err, &exitErr) && exitErr.ExitCode() == 1 {
Expand All @@ -1198,7 +1198,7 @@ func DeleteBranchCLI(branchName string) error {
// Returns nil if the branch exists, or an error if it does not.
func branchExistsCLI(branchName string) error {
ctx := context.Background()
cmd := exec.CommandContext(ctx, "git", "show-ref", "--verify", "--quiet", "refs/heads/"+branchName) //nolint:gosec // branchName comes from internal shadow branch naming
cmd := exec.CommandContext(ctx, "git", "show-ref", "--verify", "--quiet", "refs/heads/"+branchName)
if err := cmd.Run(); err != nil {
return fmt.Errorf("branch %s not found: %w", branchName, err)
}
Expand All @@ -1212,7 +1212,7 @@ func branchExistsCLI(branchName string) error {
func HardResetWithProtection(commitHash plumbing.Hash) (shortID string, err error) {
ctx := context.Background()
hashStr := commitHash.String()
cmd := exec.CommandContext(ctx, "git", "reset", "--hard", hashStr) //nolint:gosec // hashStr is a plumbing.Hash, not user input
cmd := exec.CommandContext(ctx, "git", "reset", "--hard", hashStr)
if output, err := cmd.CombinedOutput(); err != nil {
return "", fmt.Errorf("reset failed: %s: %w", strings.TrimSpace(string(output)), err)
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/entire/cli/strategy/manual_commit_condensation.go
Original file line number Diff line number Diff line change
Expand Up @@ -684,7 +684,7 @@ func generateContextFromPrompts(prompts []string) []byte {
if len(displayPrompt) > 500 {
displayPrompt = displayPrompt[:500] + "..."
}
buf.WriteString(fmt.Sprintf("### Prompt %d\n\n", i+1))
fmt.Fprintf(&buf, "### Prompt %d\n\n", i+1)
buf.WriteString(displayPrompt)
buf.WriteString("\n\n")
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/entire/cli/strategy/manual_commit_session.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import (
"time"

"github.com/entireio/cli/cmd/entire/cli/agent"
"github.com/entireio/cli/cmd/entire/cli/buildinfo"
"github.com/entireio/cli/cmd/entire/cli/checkpoint"
"github.com/entireio/cli/cmd/entire/cli/checkpoint/id"
"github.com/entireio/cli/cmd/entire/cli/paths"
"github.com/entireio/cli/cmd/entire/cli/versioninfo"

"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
Expand Down Expand Up @@ -226,7 +226,7 @@ func (s *ManualCommitStrategy) initializeSession(repo *git.Repository, sessionID
headHash := head.Hash().String()
state := &SessionState{
SessionID: sessionID,
CLIVersion: buildinfo.Version,
CLIVersion: versioninfo.Version,
BaseCommit: headHash,
AttributionBaseCommit: headHash,
WorktreePath: worktreePath,
Expand Down
8 changes: 4 additions & 4 deletions cmd/entire/cli/strategy/phase_wiring_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import (
"testing"
"time"

"github.com/entireio/cli/cmd/entire/cli/buildinfo"
"github.com/entireio/cli/cmd/entire/cli/session"
"github.com/entireio/cli/cmd/entire/cli/versioninfo"

"github.com/go-git/go-git/v5"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -203,7 +203,7 @@ func setupGitRepo(t *testing.T) string {
}

// TestInitializeSession_SetsCLIVersion verifies that InitializeSession
// persists buildinfo.Version in the session state.
// persists versioninfo.Version in the session state.
func TestInitializeSession_SetsCLIVersion(t *testing.T) {
dir := setupGitRepo(t)
t.Chdir(dir)
Expand All @@ -217,8 +217,8 @@ func TestInitializeSession_SetsCLIVersion(t *testing.T) {
require.NoError(t, err)
require.NotNil(t, state)

assert.Equal(t, buildinfo.Version, state.CLIVersion,
"InitializeSession should set CLIVersion to buildinfo.Version")
assert.Equal(t, versioninfo.Version, state.CLIVersion,
"InitializeSession should set CLIVersion to versioninfo.Version")
}

// writeTestFile is a helper to create a test file with given content.
Expand Down
1 change: 0 additions & 1 deletion cmd/entire/cli/telemetry/detached_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ func spawnDetachedAnalytics(payloadJSON string) {
return
}

//nolint:gosec // G204: payloadJSON is controlled internally, not user input
cmd := exec.CommandContext(context.Background(), executable, "__send_analytics", payloadJSON)

// Detach from parent process group so subprocess survives parent exit
Expand Down
12 changes: 6 additions & 6 deletions cmd/entire/cli/trailers/trailers.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,9 +203,9 @@ func FormatShadowCommit(message, metadataDir, sessionID string) string {
var sb strings.Builder
sb.WriteString(message)
sb.WriteString("\n\n")
sb.WriteString(fmt.Sprintf("%s: %s\n", MetadataTrailerKey, metadataDir))
sb.WriteString(fmt.Sprintf("%s: %s\n", SessionTrailerKey, sessionID))
sb.WriteString(fmt.Sprintf("%s: %s\n", StrategyTrailerKey, "manual-commit"))
fmt.Fprintf(&sb, "%s: %s\n", MetadataTrailerKey, metadataDir)
fmt.Fprintf(&sb, "%s: %s\n", SessionTrailerKey, sessionID)
fmt.Fprintf(&sb, "%s: %s\n", StrategyTrailerKey, "manual-commit")
return sb.String()
}

Expand All @@ -215,9 +215,9 @@ func FormatShadowTaskCommit(message, taskMetadataDir, sessionID string) string {
var sb strings.Builder
sb.WriteString(message)
sb.WriteString("\n\n")
sb.WriteString(fmt.Sprintf("%s: %s\n", MetadataTaskTrailerKey, taskMetadataDir))
sb.WriteString(fmt.Sprintf("%s: %s\n", SessionTrailerKey, sessionID))
sb.WriteString(fmt.Sprintf("%s: %s\n", StrategyTrailerKey, "manual-commit"))
fmt.Fprintf(&sb, "%s: %s\n", MetadataTaskTrailerKey, taskMetadataDir)
fmt.Fprintf(&sb, "%s: %s\n", SessionTrailerKey, sessionID)
fmt.Fprintf(&sb, "%s: %s\n", StrategyTrailerKey, "manual-commit")
return sb.String()
}

Expand Down
Loading
Loading