LaunchOpts.Agent (string) and WorkspaceEntryOptions.Agent (string) are
replaced by *agent.Resolved, carrying Command, Args, and Env. The five
entry commands (new, resume, last, open, attach) each construct an
AgentSpec from the workspace metadata, apply --agent as a one-shot
agent.command override (Open Q 1 — keeps muscle memory for users
passing executable paths), call agent.Resolve, and pass the result
through. resolveEntryAgent centralises the resume/last/open/attach path.
shell.ExecAgent and shell.ExecTmuxAgent gain an args parameter; agent.env
is merged into the env map at the session.Run launch switch, AFTER
ctask's exported CTASK_* vars (per spec §5: agent.env wins on collision).
mergeAgentEnv is the centralised merge.
Lease, manifest, write lock, heartbeat, summary, and provisional
cleanup are unchanged. The Agent string fields on Lease, SessionSummary,
and SessionInfo continue to record the launched command for diagnostics.
Replace TaskMeta.Agent (string) with TaskMeta.Agent (AgentSpec) carrying
type/command/args/env. Custom UnmarshalYAML preserves the legacy scalar
form: a built-in name (claude, opencode) maps to that type; any other
scalar maps to type=custom with the scalar as command. A missing agent
field leaves Type empty so the resolver fills in default_agent at launch.
ValidateAgentSpec enforces: known type (claude|opencode|custom),
type=custom requires command, command must be an executable name or
path with no whitespace or shell metacharacters.
Launch-path wiring (Task 3) and the --agent flag rework (Task 4) are
intentionally not part of this commit; cmd/* call sites are patched to
the minimum needed for the build to compile.
Apply the v0.5.2 lookup policy to the existing commands and wire
ValidArgsFunction hooks across the workspace-accepting surface.
info: drop the --all/-a flag entirely. Direct lookup is now
archived-inclusive by default — the user typed a name, so we find
the workspace and surface its status in the output. The Status
line already distinguishes active vs archived clearly.
resume: when targeting an archived workspace, fail with a useful
hint instead of letting the resolver report "not found":
[ctask] error: workspace "X" is archived
To restore it:
ctask restore X
This is implemented by resolving archived-inclusive and rejecting
status==archived before any session-launch logic runs. Genuine
not-found and ambiguous-match behavior are unchanged.
Adds ValidArgsFunction hooks to archive (active), delete (active),
open (active), info (any), resume (active). Restore/notes/path
already have hooks from the previous commit. Shell completion now
covers the full direct-lookup surface.
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>
config.EnvVars gains a 7th launchDir argument. cmd/new, cmd/resume, and
cmd/open pass ws.Meta.LaunchDir. Child sessions can read CTASK_LAUNCH_DIR
to know which subdirectory ctask launched them into.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Every resolver, lister, and most-recent caller now passes
config.SearchRoots() so CTASK_PROJECT_ROOT is searched alongside
CTASK_ROOT. Commands use ws.Root when rendering relative paths or
session env vars so displays and CTASK_ROOT exports are correct for
workspaces living under CTASK_PROJECT_ROOT.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ctask new gains --project, which:
- records type=project on the workspace
- defaults the category to "projects"
- applies general + project seed overlays
- uses CTASK_PROJECT_ROOT when set, with no doubled "projects/"
path unless the user explicitly passes -c
- exports CTASK_TYPE=project into the child session
EnvVars now takes a taskType arg and exports CTASK_TYPE. Empty
type defaults to "task" for safety. resume/open also pass
EffectiveType so the env var is correct on resume of a v0.2
workspace.
Git init for project mode is wired in the next commit.
Refactor new/resume/open to use session.Run() which wraps child process launch with pre/post manifest capture and append-only session logging to logs/sessions.log. Bump version to 0.2.0.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Exit 2 for missing required arguments, exit 127 for agent not found. SilenceUsage on all commands to avoid dumping usage on runtime errors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Complete command implementations with all flags per spec. Shared query resolution helper.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>