Commit Graph

154 Commits

Author SHA1 Message Date
typebasedio 53adba638e feat(v0.5.3): centralized tmux primitives (LookupTmux, HasSession, NewSession, AttachSession, PollSessionEnd, ExecTmux*) 2026-05-08 13:50:17 -04:00
typebasedio 1ab1cda111 feat(v0.5.3): InspectLease four-state classifier 2026-05-08 13:48:37 -04:00
typebasedio 120dc54337 feat(v0.5.3): ResolveSessionMode env var resolver 2026-05-08 13:47:49 -04:00
typebasedio 32fa5d0d21 feat(v0.5.3): SessionName deterministic tmux session naming 2026-05-08 13:47:01 -04:00
typebasedio e448effd2f docs(v0.5.2): record v0.5.2 completion in notes.md
Add the v0.5.2 round summary (commits a5e508b..3b6be0d + 5910100):
restore/notes/path commands, direct-lookup archived-inclusive policy,
resume archived hint, list --names, shell completion, cross-workspace
context seed section. Windows + WSL validation passed; Linux binary
statically linked.

Add load-bearing v0.5.2 invariants to the "don't unlearn" section
(archived-inclusive lookup policy, list --names emits basenames not
slugs, completion calls ListWorkspaces directly, etc.). Replace the
"Next: v0.5.2" pointer with a "Next: v0.6 (planning)" stub covering
config/agent profile work, resume-error polish, and flag-aware
completion for open/delete --all.

Drop v0.5.2-spec.md from the untracked-files list (committed in a5e508b).
2026-05-07 20:54:29 -04:00
typebasedio 5910100d88 chore(v0.5.2): bump version to 0.5.2 2026-05-07 20:45:54 -04:00
typebasedio 3b6be0d732 feat(v0.5.2): cross-workspace context section in seed CLAUDE.md
Adds a concise "## Cross-Workspace Context" section to both the
task and project CLAUDE.md seed templates. Teaches the agent to
inspect related workspaces with the new commands before making
changes:

  ctask list --all          discover all workspaces, including archived
  ctask info <workspace>    view metadata and status of any workspace
  ctask notes <workspace>   read another workspace's notes.md
  ctask path <workspace>    get the filesystem path to inspect files

Closes the v0.5.2 design loop: ctask exposes workspace context
through CLI commands and lets agents consume it themselves. The
seed text is read-only by convention — the section explicitly
asks the agent to treat other workspaces as read-only unless the
user grants modification rights.

Applies to newly created workspaces only. Existing workspaces
keep their current CLAUDE.md (per spec: no retroactive overwrite).
Users with custom seed directories see this only if they update
their seeds.
2026-05-07 19:47:43 -04:00
typebasedio 56d2e07716 feat(v0.5.2): list --names for machine-readable enumeration
Adds a --names flag to ctask list that emits one workspace
directory basename per line, no header, no decoration. Empty
result is empty stdout with zero exit code (no "No workspaces
found." placeholder).

Used by shell completion scripts and external tooling. Candidates
are directory basenames rather than bare slugs because basenames
are unique under the resolver's exact-match step while slugs can
collide across categories or dates.

Respects existing list filters: --all, --task, --projects,
--category, --limit. So:

  ctask list --names           active workspaces only
  ctask list --names --all     active and archived
  ctask list --names --projects active project workspaces

The new TestListNamesCandidatesResolveUniquely test enforces the
spec invariant: every line emitted by list --names must resolve
to exactly one workspace via the standard resolver.
2026-05-07 19:47:33 -04:00
typebasedio b923ae8892 feat(v0.5.2): direct lookup includes archived; resume hint for archived
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.
2026-05-07 19:47:24 -04:00
typebasedio 176e788f67 feat(v0.5.2): add restore, notes, path commands with completion plumbing
Three new direct-lookup commands per v0.5.2-spec.md:

- ctask restore <ws>   un-archive a workspace (metadata-only flip,
                       mirrors archive's lease guard, refuses to
                       restore an already-active workspace)
- ctask notes <ws>     stream a workspace's notes.md to stdout (raw,
                       no framing, [ctask]-prefixed stderr on error)
                       so AI agents can read prior workspace context
                       through standard shell pipelines
- ctask path <ws>      print the absolute filesystem path of a
                       workspace, OS-native separators, one line

All three resolve archived-inclusive: the user typed a name, so we
find the workspace whether or not it's archived. Listing stays
filtered (active-only by default) per the v0.5.2 design rule
"listing is filtered, direct lookup is comprehensive".

Adds shared completion infrastructure (cmd/completion.go) used by
these commands and wired into the existing workspace-accepting
commands in a follow-up commit. Candidates are workspace directory
basenames (e.g. 2026-04-22_promptvolley) rather than bare slugs
because basenames are unique under the resolver's exact-match step
while slugs can collide across categories or dates.
2026-05-07 19:47:14 -04:00
typebasedio a5e508bcb6 docs(v0.5.1): record v0.5.1 completion; check in v0.5.2 spec
Update notes.md with the v0.5.1 Linux portability baseline (commits
7a7b249, 1033072): WSL-native validation passed, install.sh works,
ctask doctor recognizes the Linux statusline helper, the cross-built
Linux binary is statically linked, and WorkspacePath was removed from
new task.yaml metadata. Add load-bearing notes for the new invariants
(CGO_ENABLED=0, install script does not modify shell config) and a
"Next: v0.5.2" pointer.

Also check in v0.5.2-spec.md so the workspace-retrieval round has the
same on-disk durability as the prior specs.
2026-05-07 19:47:01 -04:00
typebasedio 103307218e fix(v0.5.1): force CGO_ENABLED=0 in cross-build targets
A native Linux build of build-linux defaulted to CGO_ENABLED=1 and
produced a glibc-linked binary, which would not run in minimal
containers (Alpine, distroless, scratch). The Windows cross-compile
was already pure-Go because Go disables cgo when no host C toolchain
is available; making CGO_ENABLED=0 explicit keeps both targets
statically linked regardless of build host.

Verified on WSL: file reports "statically linked", ldd reports
"not a dynamic executable".
2026-05-07 19:22:54 -04:00
typebasedio 7a7b2490c2 feat(v0.5.1): Linux portability baseline
- justfile: add build-linux, build-windows, build-all (output to dist/)
- .gitignore: cover ctask, ctask-*, dist/
- scripts/install.sh + scripts/uninstall.sh: POSIX equivalents of .ps1
- remove WorkspacePath metadata field (no production readers; legacy
  task.yaml files continue to parse silently)

Linux smoke-test on WSL/container pending.
See audit-report.md and v0.5.1-spec.md.
2026-05-07 18:22:41 -04:00
typebasedio a11d48b8cd chore(v0.5.1): bump version to 0.5.1
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 21:33:55 -04:00
typebasedio a162aec0b2 fix(v0.5.1): use local time for workspace directory prefix and info display
Workspace directory names (YYYY-MM-DD_slug) and the YYYYMMDD-HHMMSS ID
field now use local time so users see their wall-clock date rather
than UTC — the prior behavior caused evening-EST creations to appear
under tomorrow's date for several hours every day. ctask info's
Created/Updated/Archived lines also convert to local for display.

Stored timestamps in task.yaml, session logs, the lease, the manifest,
and the session summary all continue to use UTC. Only user-facing
surfaces change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 21:33:52 -04:00
typebasedio 8130a689d4 chore(v0.5): bump version to 0.5.0
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 19:53:45 -04:00
typebasedio 82c944502d docs(v0.5): document project subdirectory, launch_dir, CTASK_LAUNCH_DIR, default discovery
Adds the workspace-layout diagram to the --project section, describes
how launch_dir is set and overridden, and documents the v0.5 rules for
fallback (missing/not-a-dir) and error (absolute/escape). Adds
CTASK_LAUNCH_DIR to the env-vars table and CTASK_PROJECT_ROOT INFO line
to the doctor example. Query Resolution note explains that both
CTASK_ROOT and the default projects/ subdirectory are searched so
default-location projects are findable from any shell.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 19:53:32 -04:00
typebasedio 0976dce8de feat(v0.5): status line helpers show effective launch path
Both .sh and .ps1 now build an effective display path by joining
CTASK_WORKSPACE with CTASK_LAUNCH_DIR when that variable is set. When
launch_dir is present and differs from the slug, the project tag also
carries ':<launch_dir>' so the display reflects user-overridden
launches. Tasks and pre-v0.5 projects are unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 19:52:43 -04:00
typebasedio cdf1c55c5f docs(v0.5): describe workspace root vs project subdir in project CLAUDE.md
Rewrites the built-in project CLAUDE.md template with a new Workspace
Structure section that explains the root-vs-subdir split. File
Placement rules refer to the subdirectory. Git section keeps the
single-repo rule and explicitly names the project subdirectory as an
example of where not to init.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 19:52:24 -04:00
typebasedio 70bd1674b3 feat(v0.5): add CTASK_PROJECT_ROOT check to ctask doctor
Three-state check matching the seed-dir pattern: INFO when unset
(points at the default discovery location), INFO with user-scope
advisory when set and present, FAIL when set but the directory
doesn't exist. Advisory wording is recommendatory, not prescriptive
(per spec amendment).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 19:51:52 -04:00
typebasedio 47430a1b1e feat(v0.5): include \$CTASK_ROOT/projects/ in SearchRoots by default
When CTASK_PROJECT_ROOT is unset, SearchRoots now appends
\$CTASK_ROOT/projects/ so that projects created under the default
category are discoverable from any shell without per-session env var
setup. Dedupe in scanAllRoots prevents double-counting workspaces that
are reachable both via the depth-2 scan under CTASK_ROOT and via the
new explicit search root. Adds a named regression test asserting no
duplicates appear in either ResolveQuery or ListWorkspaces results.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 19:51:07 -04:00
typebasedio cdff7f32eb feat(v0.5): show launch_dir fields in ctask info output
For project workspaces with launch_dir set, info prints three extra
lines after Path: Launch dir, Launch path, and Dir exists (yes/no
from a direct os.Stat of the intended path). Tasks and pre-v0.5
projects still omit these lines.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 19:50:07 -04:00
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
typebasedio 509a6d64ea feat(v0.5): export CTASK_LAUNCH_DIR into child sessions
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>
2026-04-22 19:48:23 -04:00
typebasedio 7cfafdc285 feat(v0.5): scaffold project subdirectory and set launch_dir in task.yaml
ctask new --project now creates an empty subdirectory named after the
final suffixed slug inside the workspace root, and sets meta.LaunchDir
to that slug. Task workspaces are unchanged. Seeds do not target the
subdirectory — the user populates it with their project code and their
own CLAUDE.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 19:47:33 -04:00
typebasedio dcb161022c feat(v0.5): add workspace.ResolveLaunch helper
Resolves a relative launch_dir into the absolute directory the child
process should cd into. Returns an error for absolute paths and paths
that escape the workspace via .. traversal. Returns (wsDir, warning, nil)
on os.IsNotExist or target-is-a-file so the caller prints a warning and
falls back. Non-IsNotExist stat errors (permission, invalid name, I/O)
propagate as real errors rather than being masked as warnings.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 19:46:25 -04:00
typebasedio 175fbb0075 feat(v0.5): add launch_dir field to TaskMeta
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 19:44:36 -04:00
typebasedio ba8b3a19f9 fix: only remove provisional workspace when child exits non-zero
Adds a child-exit-code guard to handleProvisional so a `ctask new`
workspace is reclaimed only when the agent was actually canceled
before real work (trust prompt rejected, Esc during startup, Ctrl+C
mid-launch — all confirmed empirically as exit code 1). A zero exit
means the user entered the agent and exited cleanly, which is a
legitimate workflow that must preserve the workspace even with an
empty manifest diff — for example when the user wants the workspace
directory established so they can populate context/ before resuming.

The exit code reaches handleProvisional via a new childExitCode
helper that unwraps *exec.ExitError from cmd.Run's return. Non-exit
errors (agent not found, OS-level failure) map to -1 so the
workspace is still cleaned up — the child never actually ran.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 19:03:17 -04:00
typebasedio 35d3b24e09 chore(v0.4.1): bump version to 0.4.1
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 18:03:43 -04:00
typebasedio 4fdd153bc4 feat(v0.4.1): warn when archiving workspace with active session
Archive now inspects .ctask/session.json before mutating task.yaml. A
fresh lease (heartbeat within 60s) triggers a warning. Interactive
stdin gets a y/N prompt (default N). Non-interactive stdin refuses
with a non-zero exit, which is safer than silently hiding an actively
writing workspace. Stale or missing leases pass through unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 17:57:31 -04:00
typebasedio 57c6c909d3 feat(v0.4.1): add seed directory checks to ctask doctor
Replaces the always-informational seed-dir block with three-state checks:
INFO when the env var is unset (defaults will be used), PASS when set and
the path exists, FAIL when set but the directory is missing. Only the
configured-but-missing state counts as a failed check and raises the
doctor exit code.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 17:56:27 -04:00
typebasedio b4f35231d4 docs(v0.4.1): add nested git guidance for project mode
Project CLAUDE.md template now includes a Git section stating that the
workspace uses a single git repo at the root and subdirectory git init
is not permitted. docs/commands.md picks up the same guidance under the
--project flag section.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 17:55:29 -04:00
typebasedio 0c1f03ba3a fix(v0.4.1): route all workspace commands through SearchRoots
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>
2026-04-22 17:54:58 -04:00
typebasedio 075000497f fix(v0.4.1): scan both CTASK_ROOT and CTASK_PROJECT_ROOT in workspace queries
Rewrites scanWorkspaces to handle both category layout
(root/<category>/<workspace>/task.yaml) and flat layout
(root/<workspace>/task.yaml used under CTASK_PROJECT_ROOT).

Adds scanAllRoots to walk multiple roots with absolute-path dedupe.
ResolveQuery, ListWorkspaces, and MostRecentActive now accept []string.
QueryResult gains a Root field so callers can render display paths and
session env vars relative to the originating root.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 17:53:58 -04:00
typebasedio 42efcc261a feat(v0.4.1): add config.SearchRoots for multi-root workspace lookup
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 17:51:37 -04:00
typebasedio 02dcdcc215 fix: remove provisional workspace when launch is canceled with no changes
When `ctask new` launched the agent or shell and the child exited without
touching any files (e.g. the user canceled at Claude Code's trust prompt),
the workspace was left behind as empty clutter. Now, if the invocation
just created the workspace and the manifest diff is empty (zero added,
modified, deleted), the workspace directory is removed and finalize is
skipped. resume/open/last are unaffected (NewlyCreated defaults to false),
and --no-launch is unaffected (session.Run is never called).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 12:01:34 -04:00
typebasedio f129d59596 feat(v0.4): bump version to 0.4.0 2026-04-21 17:17:07 -04:00
typebasedio 46c7ef2c5c docs(v0.4): document --force, session lease, stale-workspace detection, and coexisting-session limitation 2026-04-21 17:16:54 -04:00
typebasedio 0e7d4a5717 test(v0.4): cover session finalize end-to-end 2026-04-21 17:10:58 -04:00
typebasedio c8e06a5324 feat(v0.4): sequence session.Run through Layers 1-4 2026-04-21 17:10:37 -04:00
typebasedio a050b116fa feat(v0.4): add Preflight checks for Layer 1 and Layer 3 2026-04-21 17:09:41 -04:00
typebasedio 77513aa5f8 feat(v0.4): add DetectExternalChanges and stale-workspace warning 2026-04-21 17:08:46 -04:00
typebasedio aabb7c6464 test(v0.4): cover SummarizeFromDiff and FormatLaunchContext 2026-04-21 17:08:09 -04:00
typebasedio 68a4f7e4cc feat(v0.4): add SessionSummary type with round-trip and launch-context formatter 2026-04-21 17:07:47 -04:00
typebasedio 67138584d4 feat(v0.4): add --force flag on resume, last, and open 2026-04-21 17:07:04 -04:00
typebasedio 25b2b46171 feat(v0.4): add Force to LaunchOpts (no-op until Phase 9) 2026-04-21 17:06:32 -04:00
typebasedio 8d7d4cbff9 feat(v0.4): add FormatActiveWarning and FormatStaleCleanupNotice 2026-04-21 17:06:14 -04:00
typebasedio cc7a8535a3 feat(v0.4): add ConfirmYN prompt helper 2026-04-21 17:05:36 -04:00
typebasedio 42fce73824 feat(v0.4): add heartbeat goroutine that updates lease timestamp 2026-04-21 17:05:15 -04:00
typebasedio ab89a167a5 refactor(v0.4): route session-lifecycle and archive task.yaml writes through write lock 2026-04-21 17:04:23 -04:00