Commit Graph

28 Commits

Author SHA1 Message Date
typebasedio e0e9cd764e feat(v0.5.4): info Session block
Add a Session block to ctask info output, surfacing the workspace
session lease state derived from SessionStatus. Inserted between Path
and any launch-dir fields so the new content is visually distinct
from both blocks.

Format: state on the header line, then indented Mode / Owner / Attach
/ Note rows aligned at column 14. The Owner line omits the hostname
when it matches the local machine. The Attach hint surfaces only for
active+persistent sessions and uses invocationName() so the suggested
command reflects the user's actual invocation. Malformed leases
render as stale with a single-line diagnostic and no Mode/Owner/Attach
rows so we never display fields parsed from a broken file.

Exposes session.CurrentHostname() so the cmd layer has a single
source of truth for the local-vs-remote hostname check.
2026-05-14 19:51:21 -04:00
typebasedio 7f2c43d599 feat(v0.5.4): SessionStatus display-only helper
Add internal/session.SessionStatus(wsDir) that derives a display-only
view of the workspace session lease. Pure read of .ctask/session.json
with no tmux invocation, no PID liveness, no lock acquisition, and no
mutation of lease state.

States: none | active | stale. Mode defaults to "direct" when a
pre-v0.5.3 lease lacks the field. Malformed leases surface as stale
with a diagnostic so the present-but-broken case stays visible
instead of being silently classified as none.

Reused for ctask info and ctask list in subsequent commits. Lifecycle
code continues to use the existing primitives (ReadLease, IsFresh,
InspectLease).
2026-05-14 19:47:24 -04:00
typebasedio c204d87b47 polish(v0.5.3): v0.4 lease-prompt hint, invocation-name in user-facing commands, smoke-checklist fixes
Three independent v0.5.3 polish items surfaced during manual WSL smoke testing,
bundled into one commit since they're all string/UX touches with no behavior change.

1. v0.4 lease-prompt tightening (`internal/session/{lease,run,run_preflight}.go`,
   `cmd/entry.go`): when ctask is about to enter direct mode on a workspace that
   already has a live tmux session, the "Continue anyway?" prompt now suggests
   `ctask attach <slug>` as the reattach path. Threaded via
   `PreflightOpts.ActiveLeaseHint` / `LaunchOpts.ActiveLeaseHint`; computed in
   `cmd/entry.go::directModeTmuxHint` (best-effort: silent when no tmux on PATH
   or no session for the workspace). Closes the footgun where a user forgot to
   `export CTASK_SESSION_MODE=persistent` in a second terminal and hit the v0.4
   coexistence prompt without realizing tmux passive-reattach was the intended
   path.

2. Invocation-name in user-facing command hints (`cmd/invocation.go` new,
   `cmd/{persistent,entry,resume,doctor}.go`): the binary name printed in
   bypass / restore / "create one with" suggestions now reflects
   `filepath.Base(os.Args[0])` instead of a hard-coded "ctask". Local-build
   PowerShell users running `.\ctask.exe` see `ctask.exe new <ws> --direct`,
   matching what they need to type. Installed contexts continue to see `ctask`.
   Test seam (`invocationNameOverride`) pins the name to "ctask" in unit tests
   so substring assertions stay stable across Go test binary names. Descriptive
   prose ("ctask persistent mode requires...") and the ssh-remote hint
   (`ssh -t <host> ctask <subcmd>`) intentionally keep the literal "ctask" —
   they refer to the program identity / remote invocation, not the local
   command form. Affected tests: `cmd/{persistent,resume}_test.go` tightened to
   check the full `"<binary> <subcmd> <workspace> --direct"` form.

3. Smoke-checklist fixes (`docs/.../2026-05-08-v0.5.3-smoke-test-checklist.md`):
   six issues caught during the run -- S2 now exports CTASK_SESSION_MODE in
   both terminals (previously only WSL-A had it, which routed WSL-B's
   secondary resume through direct mode instead of passive reattach); O3/A2
   tmux-ls expectations corrected (tmux doesn't emit a literal "(detached)"
   token); P2 expected behavior rewritten (passive reattach detach returns to
   prompt immediately -- AttachExisting calls only shell.AttachSession with
   no PollSessionEnd, the owner is responsible for finalize); A1 no longer
   asks for Ctrl-C in WSL-B; A6 path now uses a glob (was hardcoded to the
   checklist's authoring date, broke on v0.5.1 local-time directory naming);
   M1 PATH-hide rewritten to `$HOME/.local/bin` only (was `:/bin` which is a
   symlink to /usr/bin on usrmerge systems, did not hide tmux) and uses
   `command -v` instead of `which` (which is itself in /usr/bin, unreachable
   under the minimal PATH); M3/M4 reordered so the no-workspace verification
   runs after PATH is restored (was silently failing under minimal PATH);
   T1 wording made "substring match" explicit; T2 wording made N/A
   unambiguous; section 10 split into 10a-10f, each a separate input, to
   work around PSReadLine multi-line paste parsing.
2026-05-14 18:22:27 -04:00
typebasedio 08fb5bb1c3 feat(v0.5.3): AdoptExistingPersistentSession with race guard, UpdatedAt bump, attach-error propagation 2026-05-08 13:56:46 -04:00
typebasedio a1309b596e feat(v0.5.3): LaunchOpts.SessionMode/TmuxPath; shouldRunProvisional gate 2026-05-08 13:54:39 -04:00
typebasedio 8b82af1598 feat(v0.5.3): summary fields for end_reason / ownership / adoption 2026-05-08 13:53:02 -04:00
typebasedio 7697ec0507 feat(v0.5.3): AttachExisting passive reattach helper 2026-05-08 13:51:57 -04:00
typebasedio 1ab1cda111 feat(v0.5.3): InspectLease four-state classifier 2026-05-08 13:48:37 -04:00
typebasedio 32fa5d0d21 feat(v0.5.3): SessionName deterministic tmux session naming 2026-05-08 13:47:01 -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 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 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 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 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 bc5410f722 feat(v0.4): add lease freshness check and stale cleanup 2026-04-21 17:03:21 -04:00
typebasedio c29985b663 feat(v0.4): add NewLease and NewSessionID constructors 2026-04-21 17:02:48 -04:00
typebasedio 305a9d7c23 feat(v0.4): add session Lease type with JSON round-trip 2026-04-21 17:02:23 -04:00
typebasedio 75911faeeb fix: replace all non-ASCII characters with safe ASCII equivalents
Replace box-drawing characters (U+2500) in session log with ASCII dashes.
Replace em dashes (U+2014) in CLAUDE.md template with double hyphens.
Remove em dash from comment in run.go.
Add ASCII-guard tests for session log output and seed templates.
Prevents mojibake on Windows terminals that misinterpret UTF-8 as CP1252.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 10:15:02 -04:00
typebasedio 69c487cf79 feat: v0.2 tests for manifest capture, diff, ignore rules, and session log
11 new tests covering manifest capture/exclusion, roundtrip, diff logic, ignore rules (task.yaml, sessions.log, .ctask/), notes updated detection, session log formatting, append-only behavior, short session detection. Fix cross-platform ignore rule for logs/sessions.log.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 10:01:31 -04:00
typebasedio 10ab9efc80 feat: session lifecycle wrapper with manifest capture and session logging
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>
2026-04-06 09:56:21 -04:00