Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
- Safe saving: the new text is written beside the file and renamed over it, keeping its mode, group, line endings, BOM and final newline; a symlink stays a symlink. If the file changed, was replaced or was deleted since you opened it, nothing is written until you choose Keep editing, Overwrite or Reload. A new file never replaces one that appeared meanwhile.
- Limits: your own regular UTF-8 text files up to 1 MiB with one hard link, writable, with one kind of line ending. Others are refused with the reason and stay readable in `/view`. Extended attributes and ACLs are not carried over by a save. Unsaved text is lost if the NMSh window itself is closed.
- **Semantic Output** for test runs and builds ([#386](https://github.com/raiseCatError/notMyShell/issues/386), first phase). A completed block whose output NMSh recognizes gets one overview row with the counts the tool printed (`✔ node --test · 1,772 passed · 0 failed · 25 skipped`, `✘ TypeScript · 3 errors in 2 files`) and, when it listed failures or diagnostics, a details row that opens them, taken verbatim from the output. Recognized: Node's test runner (spec and TAP), Jest, Vitest, pytest, `cargo test`, `go test`, TypeScript, Rust and GCC/Clang diagnostics; anything else stays raw only, and short passing output gets nothing. Details start open when the raw output is folded; click the details row or use Actions → Show or hide details. The output itself, its folding, search, selection and plain `/copy` are unchanged. `/copy --semantic` copies the reading (raw for an output without one, as the note says) and `/copy --both` the raw output and the reading under labelled NMSh separators. Settings → Transcript → Semantic Output turns it off.
- **`/track`** keeps one live result of a finite command in the transcript, refreshed in place ([#393](https://github.com/raiseCatError/notMyShell/issues/393)). `/track df -h` or `/track --every 5s -- docker system df` writes the command once, then shows a status row (`live · every 5s · updated 13:49:25 · exit 0`, a failing exit, a timeout, paused, stale, refreshing) and the latest result under it, with a stable height. The shell stays free; nothing accumulates per refresh, and find, selection and `/copy` never include the live rows. `/track copy` copies the latest result, `/track refresh`, `pause`, `resume` and `stop` control it, and stopping leaves the last result in the transcript once. Samples run `sh -c` from the starting directory with your shell's PATH (not its aliases or functions), never overlap, and are bounded (200 kB, a timeout, at most 8 trackers); destructive and unknown commands are refused or need a Yes, as for `/watch`. Trackers stop with the window that started them. `/watch` keeps its manager and its behavior; both share one scheduler, which gains stricter interval parsing, refusals for substitutions, background jobs and heredocs, UTF-8-safe bounded capture, visible timeouts and a stop grace period (from draft #394).

### Fixed

Expand Down
57 changes: 57 additions & 0 deletions docs/development/track-live-command-refresh.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Live command tracking (`/track`)

`/track` (#393) keeps **one live result** of a finite command in the transcript, refreshed in place, while the shell
stays free for other commands. It runs on the existing `/watch` scheduler (`src/tasks/WatchTasks.ts`), whose hardening
was first written in draft PR #394 and carried into v0.21; `/watch` keeps its own behavior (its manager panel and
what-changed view) and both names manage the same trackers.

## Usage

```sh
/track df -h /Volumes/T7Projects
/track --every 5s -- docker system df
/track # the manager (same as /watch)
/track refresh [N] # one refresh now (never a second, overlapping one)
/track pause [N] · /track resume [N]
/track copy [N] # copy the latest completed result, as plain text
/track stop [N] · /track stop all
```

`N` is the tracker's position in the manager (the newest when omitted). The `--` after the cadence is optional but
keeps a command's own flags from reading as NMSh's.

## What the transcript shows

- The command line and one note, stored once like any NMSh block: what is tracked, where, and how it runs.
- Under them, drawn live and **never stored**: a status row and the latest completed result. The status says only what
is known: first run pending, `live · every 5s · updated 13:49:25 · exit 0 · 12 runs`, a failing exit code, a timeout,
a spawn error, `paused`, `no new result for 1m 20s` (stale), `refreshing…` while a sample runs.
- The result keeps a stable height (the largest seen, at most 12 rows) so a shorter refresh never moves what is below;
a longer one says how many lines are not shown. `/track copy` copies all of it.
- Live rows are presentation: find, selection and `/copy` never include them, and nothing accumulates per refresh.
- Stopping a tracker (`/track stop`, or S in the manager) writes its **last result once** into the transcript, so
history keeps it. A tracker whose window closes leaves only its stored lines.

## Execution and safety

- Every sample is `sh -c <command>` in its own process group, from the directory the tracker started in, with NMSh's
environment and the live shell's PATH. It does not see the shell's aliases, functions, unexported variables or
options, and it does not follow later `cd`s; the note in the block says so.
- Default interval 5 s; at least 2 s locally and 15 s for remote network targets; at most 60 minutes. Invalid
intervals fail before anything runs. At most 8 active trackers. A sample never overlaps another of the same tracker;
a refresh while one runs is refused with the reason.
- Repeated commands can repeat side effects. Read-only commands (and the exact `docker system df`) start at once;
unknown ones need an explicit Yes; installing, modifying, destroying, privileged, downloaded-code, `cd`, substitution,
background (`&`) and heredoc commands are refused.
- Each sample keeps at most 200 kB of stdout and stderr (decoded as UTF-8 across chunk boundaries), says when it was
cut, and has its terminal control sequences removed. A sample is stopped after the lesser of 60 s or three
intervals and shown as timed out. Stopping signals the owned process group (TERM, then KILL after a grace period);
processes that deliberately leave the group are not followed.

## Ownership and limits

Trackers belong to the window that started them, as `/watch` always has: detaching or closing the window stops them
and their processes. They are not restarted on reattach; the stored lines remain. Service-owned tracking that survives
detach would reuse the session's background-task supervisor (#382) and is not part of v0.21.

Physical terminal checks are listed in `docs/testing/v021-physical-qa.md`.
8 changes: 6 additions & 2 deletions docs/development/v021-ledger.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Automated results here are not physical-terminal validation.
| 2 | `/view` | #397, #402 | `feature/v021-view` (stacked on slice 1) | | PR open |
| 3 | `/edit` | #402 | `feature/v021-edit` (stacked on slice 2) | | PR open |
| 4 | Semantic Output | #386 | `feature/v021-semantic` (stacked on slice 3) | | PR open |
| 5 | `/track` | #393 (#394) | | | |
| 5 | `/track` | #393 (#394) | `feature/v021-track` (stacked on slice 4) | | PR open |
| 6 | Modules and diagnostics | #364, #365 | | | |
| 7 | Themes and controls | #401, #336 | | | |

Expand All @@ -30,13 +30,17 @@ Automated results here are not physical-terminal validation.
- #408 is a production race in `SemanticService` (superseded lookups resolved `unknown`), plus a test that raced the
real shell's startup knowledge.
- `/track` stays window-owned like `/watch` in v0.21; service-owned scheduling is deferred and documented.
- PR #394's `WatchTasks.ts`/`WatchPanel.ts` were adopted as written (neither file changed on `dev` since its base) and
its tests kept; its other edits were re-applied by hand. #394 itself is superseded by the slice 5 PR and was not merged.
- `/track` samples run `sh -c` (as `/watch` always has) with the live shell's PATH, not the session shell, so `/watch`
semantics stay the same for Fish users.

## Physical QA still required

Checklist: [v0.21 physical QA](../testing/v021-physical-qa.md). Slice 1: section 1 (multi-row progress in Ghostty
and Terminal.app, queued highlight colors). Slice 2: section 2 (`/view` keys, rendering, refusals, hostile text,
NO_COLOR). Slice 3: section 3 (`/edit` editing keys, saving, conflicts, refusals). Slice 4: section 4 (overview rows, details
toggle, copy flags, Off).
toggle, copy flags, Off). Slice 5: section 5 (`/track` block, refresh, copy, stop, cleanup).

## Verification notes

Expand Down
18 changes: 18 additions & 0 deletions docs/testing/v021-physical-qa.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
| 3 `/edit` | Ghostty | macOS | zsh | | Not run | |
| 3 `/edit` | Terminal.app | macOS | Bash or Fish | | Not run | |
| 4 Semantic Output | Ghostty | macOS | zsh | | Not run | |
| 5 `/track` | Ghostty | macOS | zsh | | Not run | |
| 5 `/track` | Terminal.app | macOS | Fish | | Not run | |

## 1. Multi-row progress redraws (#388)

Expand Down Expand Up @@ -85,3 +87,19 @@
output only; find (Ctrl+F) never matches the overview text.
- [ ] 4.6 Settings → Transcript → Semantic Output Off: the rows disappear from every block; On brings them back.
- [ ] 4.7 `NO_COLOR=1` and Safe glyphs: the overview reads `+`/`x` and stays readable at 40 columns.

## 5. `/track`

- [ ] 5.1 `/track df -h` and (where Docker runs) `/track --every 5s -- docker system df`: one block, a status row and the
result; it updates in place every interval while you run other commands; scrolling up and selecting text in other
blocks is never disturbed.
- [ ] 5.2 Make the result shorter and longer (`/track --every 2s -- cat f.txt` while editing `f.txt`): shorter results
do not move what is below; longer ones say how many lines are not shown.
- [ ] 5.3 `/track refresh` twice quickly: the second is refused, never overlapped. `/track pause`, `/track resume`.
- [ ] 5.4 A failing command (`/track --every 2s -- ls missing`): the status shows the exit code, never a healthy result.
- [ ] 5.5 `/track copy` copies only the latest result; find (Ctrl+F) never matches the live rows.
- [ ] 5.6 `/track stop`: the last result appears once in the transcript; `/resume` of the saved session shows it
without any per-refresh copies.
- [ ] 5.7 An unknown command asks for Yes first; `rm`, `sudo`, `cd`, `$(...)`, `&` and heredocs are refused.
- [ ] 5.8 Close the window with a tracker running: no `sh` or command processes are left (`ps`). `/watch git status`
still opens its manager.
Loading
Loading