Merge branch 'main' into fix/1523-checkpoint-push-batchmode-ssh · Entire

Merge branch 'main' into fix/1523-checkpoint-push-batchmode-ssh

711ae84→main·

Changes

11

"" 24 unmodified lines

func isCheckpointPolicyWarningExcludedCommand(name string) bool

switch name {
case "hooks", "__send_analytics", "curl-bash-post-install":
case "hooks", "__send_analytics", "__refresh_trail_enablement", "curl-bash-post-install":
    return true
default:
    return false
}

package execx

import (
    "context"
    "io"
    "os"
    "os/exec"
    "testing"
)

// SpawnDetached re-execs the current executable as a detached, fire-and-forget
// child running args, surviving the parent's exit (new session on Unix,
// CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS on Windows, via detachFromTTY).
// The child runs in dir (os.TempDir() when empty, so the child never holds the
// parent's working directory), inherits the parent's environment, and has its
// stdout/stderr discarded. Best-effort: every error is swallowed — callers
// treat the spawn as advisory background work.
func SpawnDetached(dir string, args ...string) {
    if testing.Testing() {
        return
    }
    executable, err := os.Executable()
    if err != nil {
        return
    }

// context.Background(): the child must outlive the parent, so it is never
    // tied to a cancellable context.
    cmd := exec.CommandContext(context.Background(), executable, args...)
    detachFromTTY(cmd)
    cmd.Dir = dir
    if cmd.Dir == "" {
        cmd.Dir = os.TempDir()
    }
    cmd.Env = os.Environ()
    cmd.Stdout = io.Discard
    cmd.Stderr = io.Discard

if err := cmd.Start(); err != nil {
        return
    }
    // Release the process so it can run independently of the parent.
    //nolint:errcheck // best effort — the child continues regardless
    _ = cmd.Process.Release()
}

// experimentalCommandMarkers are substrings that only appear in root help when
// experimental commands are visible.
var experimentalCommandMarkers = []string{
    "Experimental commands:",
    "review",
    "tokens                 Analyze token usage across sessions and checkpoints",
}

// rootHelpHasTokensCommand reports whether root help lists the experimental
// `tokens` command with its Short description, ignoring Use/Short padding.
func rootHelpHasTokensCommand(got string) bool {
    for _, line := range strings.Split(got, "\n") {
        fields := strings.Fields(line)
        if len(fields) == 0 || fields[0] != "tokens" {
            continue
        }
        if strings.Contains(line, "Analyze token usage across sessions and checkpoints") {
            return true
        }
    }
    return false
}

func TestHandleLifecycleSessionStart_NoSynchronousNetworkForTrailEnablement(t *testing.T) {
    // setupStopTestRepo,
    // runGitInDir, and other relevant context setups
    ag := newMockHookResponseAgent()
    event := &agent.Event{
        Type:      agent.SessionStart,
        SessionID: "test-no-sync-trail-dial",
        Timestamp: time.Now(),
    }

start := time.Now()
    err = handleLifecycleSessionStart(context.Background(), ag, event)
    elapsed := time.Since(start)

require.NoError(t, err)
    // Further assertions related to launch counts and elapsed time 
}

// TestRunTrailEnablementRefresh_BoundedByTimeoutAgainstUnresponsiveHost verifies...
func TestRunTrailEnablementRefresh_BoundedByTimeoutAgainstUnresponsiveHost(t *testing.T) {
    // setupStopTestRepo
    // runGitInDir
    // remainder of logic here, including setup and teardown
}