feat(v0.5.3): ResolveSessionMode env var resolver

This commit is contained in:
2026-05-08 13:47:49 -04:00
parent 32fa5d0d21
commit 120dc54337
2 changed files with 80 additions and 0 deletions
+20
View File
@@ -1,6 +1,7 @@
package config
import (
"fmt"
"os"
"path/filepath"
"runtime"
@@ -148,6 +149,25 @@ func defaultSeedDir(leaf string) string {
return filepath.Join(home, ".config", "ctask", leaf)
}
// ResolveSessionMode returns "direct" or "persistent" based on CTASK_SESSION_MODE.
// Default (unset/empty) is "direct". Any other value falls back to "direct"
// after printing a stderr warning. Used by entry commands (new, resume, last,
// open) to dispatch between the standard session.Run path and the tmux-backed
// persistent path.
func ResolveSessionMode() string {
v := os.Getenv("CTASK_SESSION_MODE")
switch v {
case "", "direct":
return "direct"
case "persistent":
return "persistent"
default:
fmt.Fprintf(os.Stderr,
"[ctask] warning: CTASK_SESSION_MODE=%q is not recognized; using direct mode\n", v)
return "direct"
}
}
// expandPath expands a leading ~/ and resolves to an absolute path when possible.
func expandPath(p string) string {
if strings.HasPrefix(p, "~/") || p == "~" {
+60
View File
@@ -1,9 +1,11 @@
package config
import (
"io"
"os"
"path/filepath"
"runtime"
"strings"
"testing"
)
@@ -191,3 +193,61 @@ func TestEnvVarsLaunchDirEmpty(t *testing.T) {
t.Errorf("CTASK_LAUNCH_DIR: got %q, want empty", got)
}
}
func TestResolveSessionModeDefault(t *testing.T) {
os.Unsetenv("CTASK_SESSION_MODE")
if got := ResolveSessionMode(); got != "direct" {
t.Errorf("default: got %q, want %q", got, "direct")
}
}
func TestResolveSessionModeEmpty(t *testing.T) {
os.Setenv("CTASK_SESSION_MODE", "")
defer os.Unsetenv("CTASK_SESSION_MODE")
if got := ResolveSessionMode(); got != "direct" {
t.Errorf("empty: got %q, want %q", got, "direct")
}
}
func TestResolveSessionModeDirect(t *testing.T) {
os.Setenv("CTASK_SESSION_MODE", "direct")
defer os.Unsetenv("CTASK_SESSION_MODE")
if got := ResolveSessionMode(); got != "direct" {
t.Errorf("direct: got %q, want %q", got, "direct")
}
}
func TestResolveSessionModePersistent(t *testing.T) {
os.Setenv("CTASK_SESSION_MODE", "persistent")
defer os.Unsetenv("CTASK_SESSION_MODE")
if got := ResolveSessionMode(); got != "persistent" {
t.Errorf("persistent: got %q, want %q", got, "persistent")
}
}
func TestResolveSessionModeUnknownFallsBackWithWarning(t *testing.T) {
os.Setenv("CTASK_SESSION_MODE", "garbage")
defer os.Unsetenv("CTASK_SESSION_MODE")
r, w, err := os.Pipe()
if err != nil {
t.Fatalf("pipe: %v", err)
}
origStderr := os.Stderr
os.Stderr = w
defer func() { os.Stderr = origStderr }()
got := ResolveSessionMode()
w.Close()
out, _ := io.ReadAll(r)
if got != "direct" {
t.Errorf("unknown: got %q, want %q (fallback)", got, "direct")
}
if !strings.Contains(string(out), "garbage") {
t.Errorf("warning should echo bad value: %q", out)
}
if !strings.Contains(string(out), "not recognized") {
t.Errorf("warning should say 'not recognized': %q", out)
}
}