Files
ctask/cmd/resume.go
T
typebasedio 103f2cd33e feat(v0.5): launch agent inside project subdirectory via launch_dir
LaunchOpts gains LaunchDir. session.Run resolves it via
workspace.ResolveLaunch, prints any fallback warning, and passes the
absolute path as the child process's working directory. Security
violations (absolute paths, .. escape) abort the session. The banner
gains a 'project dir: <name>/' line when launch_dir is set.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 19:49:29 -04:00

78 lines
2.2 KiB
Go

package cmd
import (
"fmt"
"path/filepath"
"time"
"github.com/spf13/cobra"
"github.com/warrenronsiek/ctask/internal/config"
"github.com/warrenronsiek/ctask/internal/session"
"github.com/warrenronsiek/ctask/internal/shell"
"github.com/warrenronsiek/ctask/internal/workspace"
)
var resumeCmd = &cobra.Command{
Use: "resume <query>",
Short: "Reopen an existing workspace and launch the agent",
Args: cobra.ExactArgs(1),
SilenceUsage: true,
RunE: runResume,
}
var (
resumeContainer bool
resumeShell bool
resumeAgent string
resumeForce bool
)
func init() {
resumeCmd.Flags().BoolVar(&resumeContainer, "container", false, "Resume in container mode (deferred)")
resumeCmd.Flags().BoolVar(&resumeShell, "shell", false, "Open shell instead of agent")
resumeCmd.Flags().StringVarP(&resumeAgent, "agent", "a", "", "Override agent command")
resumeCmd.Flags().BoolVar(&resumeForce, "force", false, "Skip active-session and stale-workspace warnings")
rootCmd.AddCommand(resumeCmd)
}
func runResume(cmd *cobra.Command, args []string) error {
return doResume(args[0], resumeContainer, resumeShell, resumeForce, resumeAgent)
}
// doResume is the shared resume logic used by both resume and last commands.
func doResume(query string, container, useShell, force bool, agentOverride string) error {
if container {
fmt.Println(shell.ContainerNotice())
return nil
}
roots := config.SearchRoots()
ws := resolveOne(roots, query, false)
// Update updated_at
now := time.Now().UTC().Truncate(time.Second)
ws.Meta.UpdatedAt = now
metaPath := filepath.Join(ws.Path, "task.yaml")
if err := workspace.WriteMetaLocked(metaPath, ws.Meta); err != nil {
return fmt.Errorf("updating metadata: %w", err)
}
agent := agentOverride
if agent == "" {
agent = ws.Meta.Agent
}
envVars := config.EnvVars(ws.Meta.Slug, ws.Meta.Mode, ws.Root, ws.Path, ws.Meta.Category, workspace.EffectiveType(ws.Meta), ws.Meta.LaunchDir)
return session.Run(session.LaunchOpts{
WsDir: ws.Path,
EnvVars: envVars,
Agent: agent,
Mode: ws.Meta.Mode,
Slug: ws.Meta.Slug,
Shell: useShell,
LaunchDir: ws.Meta.LaunchDir,
Force: force,
})
}