diff --git a/docs/README.md b/docs/README.md index b86fd45..eace472 100644 --- a/docs/README.md +++ b/docs/README.md @@ -8,7 +8,7 @@ - [How it works](how-it-works.md): the PTY emulation, input routing, and activity grouping - [Sessions](sessions.md): the task recipe format and where it lives - [Agent session resume](agent-resume.md): how `fleetcom` captures and resumes supported `claude`, `codex`, and `grok` sessions -- [Storage paths](#storage-paths): the socket, the lock, and the session paths +- [Storage paths](#storage-paths): runtime and session paths - [First-run walkthrough](#first-run-walkthrough): a first run, start to finish - [Security](#security): the trust boundary, on-disk state, and what is not protected - [Operational constraints](#operational-constraints): process and protocol boundaries @@ -25,11 +25,11 @@ From a repository clone: ## Storage paths -Runtime state contains the daemon socket and lock. Configuration contains durable session recipes. The paths resolve independently. +Runtime state contains the daemon socket, lock, and log. Configuration contains durable session recipes. The paths resolve independently. -### Runtime directory (socket + lock) +### Runtime directory (socket + lock + log) -The runtime directory holds `default.sock`, the mode-`0600` client↔daemon socket, and `daemon.lock`, the single-instance `flock`. The daemon records its PID in the lock file; `--kill` uses that PID rather than waiting for the socket. `fleetcom` creates the directory with mode `0700`. An existing path must be a real directory owned by the current user, so symlinks and directories owned by another user are rejected. +The runtime directory holds `default.sock`, the client↔daemon socket; `daemon.lock`, the single-instance `flock`; and `daemon.log`, the stderr of an autostarted daemon. The daemon records its PID in the lock file; `--kill` uses that PID rather than waiting for the socket. [Security](#security) documents the permissions and the ownership checks this directory must satisfy. Resolved in this order: @@ -51,7 +51,7 @@ Holds saved sessions under a `sessions/` subdirectory: one sanitized-name `.json | 2 | Linux | `${XDG_CONFIG_HOME:-~/.config}/fleetcom/sessions` | | 2 | macOS | `~/Library/Application Support/fleetcom/sessions` | -The platform default is [`dirs::config_dir()`](https://docs.rs/dirs/latest/dirs/fn.config_dir.html) joined with `fleetcom`. The first save creates missing session directories with mode `0700`; recipe files use mode `0600`. +The platform default is [`dirs::config_dir()`](https://docs.rs/dirs/latest/dirs/fn.config_dir.html) joined with `fleetcom`. The first save creates any missing session directories. ## First-run walkthrough @@ -62,7 +62,7 @@ Run `fleetcom`. The first invocation starts the daemon and opens an empty dashbo ```text fleetcom 0 running · 0 idle · 0 done by state · dir · custom - ❯ n run · @ dir · s sort · w save · o load + ❯ n run · @ dir · / find · s sort · w save · o load ↑↓ select · enter attach · space peek · m tag · g group · R rename · r rerun · X kill · q detach · Q quit ``` @@ -75,7 +75,7 @@ Press `n`, enter a command, and press `Enter`. The command runs in its own PTY a ✻ cargo watch -x test test result: ok. 42 passed 9s ✻ npm run dev VITE v5.0 ready in 312 ms 4s - ❯ n run · @ dir · s sort · w save · o load + ❯ n run · @ dir · / find · s sort · w save · o load ↑↓ select · enter attach · space peek · m tag · g group · R rename · r rerun · X kill · q detach · Q quit ``` @@ -107,7 +107,7 @@ Each row is `glyph · tag · command · latest output · age`. The age counts fr ✻ npm run dev VITE v5.0 ready in 312 ms 1m ``` -`s` cycles through state, directory, and custom grouping. The header renders the active mode in bold. In custom mode, `g` assigns the selected task to a named group. Named sections sort alphabetically; Unassigned appears last when at least one task has no group: +`s` cycles through state, directory, and custom grouping. The header renders the active mode in bold. In custom mode, `g` assigns the selected task to a named group. Named sections sort without regard to case, so `API` and `api` are adjacent. They remain separate because group identity is case-sensitive. Unassigned appears last when at least one task has no group: ```text fleetcom 2 running · 0 idle · 0 done by state · dir · custom @@ -145,7 +145,7 @@ The attached status bar shows both: `[attached] api tests · cargo watch -x test | Path | Mode | Contents | | -- | -- | -- | -| [runtime directory](#runtime-directory-socket--lock) | `0700` | the socket, lock, daemon log, and any capture roots resolved beneath it | +| [runtime directory](#runtime-directory-socket--lock--log) | `0700` | the socket, lock, daemon log, and any capture roots resolved beneath it | | `/default.sock` | `0600` | the client↔daemon socket | | `/daemon.lock` | `0666 & ~umask` when new; otherwise unchanged | the owning daemon's PID, trustworthy only while its `flock` is held | | `/daemon.log` | `0666 & ~umask` when new; otherwise unchanged | stderr from the autostarted daemon | @@ -187,7 +187,7 @@ Because the daemon holds each PTY master, daemon termination closes the terminal ### Environment and directory -Each launch uses the launching client's environment and working directory, sent once per connection during the hello handshake. Connect from a venv terminal and your spawns, reruns, and session loads all see that venv, whichever client originally autostarted the daemon. Environment is never written to disk; session files store only directories, commands, group assignments, and display names. +Each client sends its environment and working directory once during the connection handshake. Spawns, reruns, and session loads initiated by that client use the same launch context. [Security](#security) covers what persists. ### Scrollback depth is fixed per supervisor diff --git a/docs/commands.md b/docs/commands.md index 58e1ac2..29df21e 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -26,6 +26,7 @@ | `Space` | Peek at the selected task | | `n` | New command in the invocation directory | | `@` | New command in a directory you pick | +| `/` | Jump the selection to a task by name, command, or group (opens the [find palette](#the--find-palette)) | | `s` | Cycle grouping: by state / by directory / by custom group | | `m` | Tag the selected task "in use" (toggles) | | `g` | Assign the selected task to a group (opens the group picker) | @@ -118,12 +119,14 @@ A `TERM`-ignoring member can also survive when its leader exits during shutdown. `s` cycles three grouping modes: state, dir, custom. The header shows the strip `by state · dir · custom` with the active mode bold and the rest dim. - By state: In use / Running / Idle / Completed. A running task files under Idle after 10 s without output; Completed stays one section (`✓`/`✗` show exit status). -- By dir: one section per working directory; the invocation directory first, the rest alphabetical. -- By custom group: one section per group name, sorted by name, with Unassigned last. Fresh spawns remain unassigned unless they inherit a group, and the Unassigned section exists only while it has a member. +- By dir: one section per working directory; the invocation directory first, then the remaining labels sorted without regard to case. +- By custom group: one section per group name, sorted without regard to case, with Unassigned last. Fresh spawns remain unassigned unless they inherit a group, and the Unassigned section exists only while it has a member. + +Dashboard section labels and within-section directory tiebreaks use the same case-insensitive order. Names that differ only by case sort next to each other in a deterministic order. Group identity remains case-sensitive, so `API` and `api` stay separate sections. Groups belong to task state: an assignment survives client detach and rerun (`r`), and switching grouping modes does not modify it. `g` reassigns the selected task through the [group picker](#the-g-group-picker). -`m` toggles the "in use" tag and marks the task with `◆`. In state mode, tagged tasks form the In use section at the top. In custom mode, a tag moves the task to the top of its existing group rather than creating a global section. Within each group, the order is tagged, running, idle, completed; each bucket then sorts by directory and spawn order. +`m` toggles the "in use" tag and marks the task with `◆`. In state mode, tagged tasks form the In use section at the top. In custom mode, a tag moves the task to the top of its existing group rather than creating a global section. Within a dir or custom section, tasks sort as tagged, live, then completed; each class then sorts by directory and spawn order. Idle state does not affect row order in these modes, so a quiet task keeps its position and shows `∙`. State mode instead moves quiet tasks from Running to Idle. In custom mode only, a new command inherits the selected task's group, through both `n` and the `@` picker. The spawn prompt shows the destination as `❯ dir ▸ group ▸ command`, each segment present only when it applies: the dir segment for a non-default directory, the group segment when a group will be inherited. State- and dir-mode spawns start unassigned. @@ -145,9 +148,19 @@ The daemon removes control characters, trims surrounding whitespace, and limits Typing filters the rows; `Backspace` deletes one character and the matches re-filter; `↑`/`↓` move the highlight; `Esc` cancels. Completion updates on each input, permitting navigation and launch without leaving the dashboard. `←`/`→` move the caret within the typed path (`→` descends only when the caret is at the end), and `Ctrl-A`/`Ctrl-E` (or `Home`/`End`) jump to either end; the same caret keys work in every `fleetcom` text field. +## The `/` find palette + +`/` opens a bottom panel listing tasks that match the query. Each row reads `