76 Commits

Author SHA1 Message Date
typebasedio d575ddd0f5 feat(v0.6): route lease-freshness callsites through IsStale
InspectLease, CleanupStaleLease, runActiveLeaseCheck, and statusAt now
use the PID-aware IsStale predicate. A dead local owner PID makes a lease
stale immediately; SessionStatus / list / info reflect this with no
display-code change.

Corrects three cmd-package session-display test fixtures that built
"active" leases with the local hostname but synthetic PIDs — now that
freshness is PID-aware, an active session must be owned by a live
process, so the fixtures use os.Getpid().
2026-05-15 14:29:50 -04:00
typebasedio f379a6d059 feat(v0.6): IsStale supplements wall-clock freshness with PID liveness 2026-05-15 14:26:15 -04:00
typebasedio 9070c4274c feat(v0.6): tri-state PID liveness probe (ProcessAlive/Dead/Unknown) 2026-05-15 14:25:31 -04:00
typebasedio 0c6ed0c0cf feat(v0.6): AGENTS.md seed + CLAUDE.md shim + handoff + context-archive scaffold
New workspaces get:
  - AGENTS.md (always): canonical agent instructions — handoff workflow,
    notes-archive convention (~300-500 line trigger), cross-workspace
    discovery, do-not-touch warnings. Project variant adds workspace-
    structure and git-conventions sections.
  - CLAUDE.md shim (claude type only per v0.6 spec §6 — opencode shim
    deferred until its instruction-file convention is verified).
  - handoff.md: minimal current-state template the agent updates per
    session.
  - context/notes-archive/.gitkeep: directory pinned for git tracking,
    ready for the agent to populate per the archive convention.

seed.ClaudeMD and seed.ClaudeMDProject removed — no callers remain.
Existing workspaces are NOT modified; this is strictly a ctask-new code
path. The seed-wins overlay rule still applies — a user seed dir's
AGENTS.md/CLAUDE.md overrides the built-in.
2026-05-15 11:15:16 -04:00
typebasedio a61f900c86 feat(v0.6): --agent flag on ctask new selects agent type
Resolver gains SetCLIFlagAgent; DefaultAgent now layers CLIFlag above
EnvVar so doctor/info attribution renders the correct precedence chain
(CLIFlag overrides EnvVar overrides ConfigFile overrides Builtin).

ctask new --agent <type> writes agent.type into the new workspace's
task.yaml. Resolution and validation run before workspace.Create, so
--agent custom without a companion command refuses ("type custom
requires command") with no half-created workspace left on disk. The
deferred Phase 1 test TestCLIFlagOverridesEnvVar lands here.

--agent on resume/last/attach is unchanged (one-shot agent.command
override on the AgentSpec — Open Q 1).
2026-05-15 11:11:16 -04:00
typebasedio b75b82e676 feat(v0.6): launch path carries ResolvedAgent (command + args + env)
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.
2026-05-15 11:08:03 -04:00
typebasedio 24f213449e feat(v0.6): internal/agent package — Resolve + BuiltinProfiles
Pure resolution logic combining a workspace's AgentSpec with the
user-level default_agent into a Resolved value carrying Command, Args,
and Env. No I/O — PATH lookup stays in shell.ExecAgent and ctask agents
check, so Resolve is trivially testable and reusable.

BuiltinProfiles enumerates claude and opencode; "custom" is the escape
hatch and requires command. Keep BuiltinProfiles in sync with
workspace.knownAgentTypes and workspace.IsBuiltinAgentType (Task 1).
2026-05-15 10:58:55 -04:00
typebasedio 8120c399df feat(v0.6): AgentSpec field on TaskMeta with backward-compat unmarshal
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.
2026-05-15 10:58:06 -04:00
typebasedio 0b21b8d3da feat(v0.6): schema_version and workspace.mode in task.yaml
Adds the two new metadata fields specified for Phase 1 of v0.6 plus
the validation and defaulting helpers around them.

internal/workspace/metadata.go:

- CurrentMetaSchemaVersion = 1 constant.
- WorkspaceSection struct {Mode string} with omitempty.
- SchemaVersion int and Workspace WorkspaceSection fields added to
  TaskMeta at the top of the struct. Both are omitempty so legacy
  task.yaml files (no schema_version, no workspace block) round-trip
  without acquiring these keys when an unrelated field is updated.
- EffectiveSchemaVersion(meta) — returns 1 for stored-value-0 legacy
  workspaces; non-zero stored values are returned verbatim.
- ValidateSchemaVersion(slug, meta) — rejects stored values higher
  than CurrentMetaSchemaVersion with the spec-mandated upgrade
  message. Accepts 0 (legacy missing).
- ValidateWorkspaceMode(slug, meta) — rejects modes other than ""
  and "native". "adopted" is reserved for v0.7.
- ReadMeta now runs both validators after unmarshal. The validation
  error includes the workspace slug (derived from task.yaml's slug
  field, falling back to the directory basename when the file itself
  is corrupt).

internal/workspace/create.go:

- workspace.Create stamps every new meta with
  SchemaVersion: CurrentMetaSchemaVersion and Workspace.Mode: "native".
  This is the ONLY write site for these fields in v0.6; resume,
  archive, restore, and any other path that rewrites task.yaml MUST
  NOT backfill them (the "no opportunistic schema writes" invariant).

internal/workspace/schema_test.go:

- 10 tests:
  * new meta written by Create contains schema_version: 1 +
    workspace.mode: native (both serialization and round-trip)
  * legacy meta without these fields loads with stored value 0 / ""
    and EffectiveSchemaVersion returns 1
  * task.yaml with schema_version: 2 is rejected with upgrade message
  * task.yaml with workspace.mode: adopted is rejected
  * the no-opportunistic-writes invariant is pinned for both WriteMeta
    and WriteMetaLocked: a legacy file rewritten with an updated
    UpdatedAt does NOT acquire schema_version or workspace: keys
  * ValidateSchemaVersion accepts {0, 1}; ValidateWorkspaceMode
    accepts {"", "native"}
2026-05-14 21:50:02 -04:00
typebasedio 6f80c8bf5c feat(v0.6): config file parser + resolver + source attribution
Phase 1 foundation. Adds:

- internal/config/configfile.go — strict-key YAML parser for the
  global config file. Unknown top-level keys invalidate the entire
  file (no partial apply); future schema versions are rejected with
  an upgrade message. Platform-appropriate path (XDG_CONFIG_HOME or
  ~/.config on Unix, %APPDATA% on native Windows).

- internal/config/resolver.go — Resolver / ResolvedSetting /
  SettingSource (Builtin, ConfigFileSrc, EnvVar, CLIFlag,
  PlatformOverride). Each setting carries provenance plus an
  Override chain so callers can render "env var (overrides config
  file: X)" lines. session_mode applies the native-Windows
  platform override at the resolver layer with the configured
  value chained as Override. Exports SetConfigPathForTest and
  SetIsNativeWindowsForTest so cross-package tests can isolate
  themselves from host config or simulate the override.

- internal/config/config.go — legacy ResolveRoot / ResolveAgent /
  ResolveSeedDir / ResolveProjectRoot / ResolveSessionMode now
  delegate to LoadResolver so config-file values take effect for
  entry commands. ResolveProjectRoot preserves the "" sentinel for
  built-in source so SearchRoots and doctor checkProjectRoot keep
  their existing fallback semantics. ResolveSessionMode preserves
  the v0.5.3 unknown-value stderr warning, distinguishing env-var
  and config-file sources in the message.

- Tests: 6 LoadConfigFile cases (missing, basic, partial, unknown
  key, future schema, malformed YAML), 3 ConfigFilePath cases
  (XDG / ~/.config / %APPDATA%), 11 resolver cases including
  layering, override chains, path expansion, platform override,
  and SettingSource string rendering.

- Test isolation: vulnerable tests in config_test.go and
  config_roots_test.go that asserted Builtin-source defaults now
  call SetConfigPathForTest to point at a nonexistent path,
  insulating them from developer-host config files. Three cmd
  tests that asserted persistent session_mode behavior now call
  SetIsNativeWindowsForTest to disable the platform override
  (Phase 1 introduces the override; the layering-only behavior
  these tests cover is tested separately in resolver_test.go).

No new dependencies (gopkg.in/yaml.v3 was already in go.mod).
No version bump (lands at the end of Phase 3 per the v0.6 spec).
2026-05-14 21:47:25 -04:00
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 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 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 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 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 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 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 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 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 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 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 d1bcd1a1ba feat(v0.4): add WriteMetaLocked wrapper backed by workspace write lock 2026-04-21 17:04:01 -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