Skip to content
Merged
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
25 changes: 22 additions & 3 deletions cmd/entire/cli/lifecycle.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"time"

"github.com/entireio/cli/cmd/entire/cli/agent"
"github.com/entireio/cli/cmd/entire/cli/agent/types"
"github.com/entireio/cli/cmd/entire/cli/logging"
Comment thread
Soph marked this conversation as resolved.
"github.com/entireio/cli/cmd/entire/cli/paths"
"github.com/entireio/cli/cmd/entire/cli/session"
Expand Down Expand Up @@ -79,16 +80,20 @@ func handleLifecycleSessionStart(ctx context.Context, ag agent.Agent, event *age

// Build informational message — warn early if repo has no commits yet,
// since checkpoints require at least one commit to work.
message := "\n\nPowered by Entire:\n This conversation will be linked to your next commit."
message := sessionStartMessage(ag.Name(), false)
if repo, err := strategy.OpenRepository(ctx); err == nil && strategy.IsEmptyRepository(repo) {
message = "\n\nPowered by Entire:\n No commits yet — checkpoints will activate after your first commit."
message = sessionStartMessage(ag.Name(), true)
}
Comment thread
Soph marked this conversation as resolved.

// Check for concurrent sessions and append count if any
_, countSessionsSpan := perf.Start(ctx, "count_active_sessions")
strat := GetStrategy(ctx)
if count, err := strat.CountOtherActiveSessionsWithCheckpoints(ctx, event.SessionID); err == nil && count > 0 {
message += fmt.Sprintf("\n %d other active conversation(s) in this workspace will also be included.\n Use 'entire status' for more information.", count)
if ag.Name() == agent.AgentNameCodex {
message += fmt.Sprintf(" %d other active conversation(s) in this workspace will also be included. Use 'entire status' for more information.", count)
} else {
message += fmt.Sprintf("\n %d other active conversation(s) in this workspace will also be included.\n Use 'entire status' for more information.", count)
}
}
countSessionsSpan.End()

Expand Down Expand Up @@ -135,6 +140,20 @@ func handleLifecycleSessionStart(ctx context.Context, ag agent.Agent, event *age
return nil
}

func sessionStartMessage(agentName types.AgentName, emptyRepo bool) string {
if agentName == agent.AgentNameCodex {
if emptyRepo {
return "Powered by Entire: No commits yet — checkpoints will activate after your first commit."
}
return "Powered by Entire: This conversation will be linked to your next commit."
}

if emptyRepo {
return "\n\nPowered by Entire:\n No commits yet — checkpoints will activate after your first commit."
}
return "\n\nPowered by Entire:\n This conversation will be linked to your next commit."
}

// handleLifecycleModelUpdate persists the model name for the current session.
//
// If the session state file already exists (e.g., Gemini's BeforeModel fires
Expand Down
40 changes: 40 additions & 0 deletions cmd/entire/cli/lifecycle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,46 @@ func TestHandleLifecycleSessionStart_DefaultMessageWithCommits(t *testing.T) {
if strings.Contains(ag.lastMessage, "No commits yet") {
t.Errorf("did not expect empty-repo warning, got: %q", ag.lastMessage)
}
if !strings.HasPrefix(ag.lastMessage, "\n\nPowered by Entire:\n ") {
t.Errorf("expected multiline session-start banner, got %q", ag.lastMessage)
}
if strings.Contains(ag.lastMessage, "Powered by Entire: This conversation") {
t.Errorf("expected default agent banner to remain multiline, got %q", ag.lastMessage)
}
}

func TestSessionStartMessage_CodexUsesSingleLineBanner(t *testing.T) {
t.Parallel()

msg := sessionStartMessage(agent.AgentNameCodex, false)
require.Equal(t, "Powered by Entire: This conversation will be linked to your next commit.", msg)
if strings.Contains(msg, "\n") {
t.Fatalf("expected single-line Codex message, got %q", msg)
}
}

func TestSessionStartMessage_CodexUsesSingleLineBannerForEmptyRepo(t *testing.T) {
t.Parallel()

msg := sessionStartMessage(agent.AgentNameCodex, true)
require.Equal(t, "Powered by Entire: No commits yet — checkpoints will activate after your first commit.", msg)
if strings.Contains(msg, "\n") {
t.Fatalf("expected single-line Codex empty-repo message, got %q", msg)
}
}

func TestHandleLifecycleSessionStart_CodexConcurrentSessionsStaySingleLine(t *testing.T) {
t.Parallel()

msg := sessionStartMessage(agent.AgentNameCodex, false)
msg += " 1 other active conversation(s) in this workspace will also be included. Use 'entire status' for more information."

if strings.Contains(msg, "\n") {
t.Fatalf("expected Codex concurrent-session message to stay single-line, got %q", msg)
}
if strings.Contains(msg, " ") {
t.Fatalf("expected Codex concurrent-session message to avoid repeated spaces, got %q", msg)
}
}

// --- handleLifecycleTurnStart tests ---
Expand Down
Loading