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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## [Unreleased]

### Fixed

- Multi-line progress displays that redraw their own rows (cursor up and erase line, as concurrent downloads and container pulls do) now update in place instead of leaving a copy of every frame in the transcript ([#388](https://github.com/raiseCatError/notMyShell/issues/388)). A program can redraw only its own recent rows, at most a screen height up, never NMSh's lines or earlier commands; `/copy` copies the final rows once. Absolute cursor positioning keeps the previous behavior.
- A queued command whose command word was still being classified when the next prompt reported new shell knowledge no longer keeps the unclassified color ([#408](https://github.com/raiseCatError/notMyShell/issues/408)).

## [0.20.0] - 2026-10-18

**Terminal workflow, first-run setup, background tasks & native modules.** The first stable release since v0.18.0. A new first run lets you pick a starting point under a live aurora and review it before anything applies; queued commands read as a chronological timeline with saved summaries; completed output can be selected, copied and acted on from the keyboard; optional tools are discovered, reviewed and installed through one flow; long-running commands can run as background tasks beside the shell; and the native module catalog covers twelve more runtimes and build tools. Every new control is reached through an explicit command, key or review, and the persistent shell, the queue and program input keep their behavior.
Expand Down
21 changes: 17 additions & 4 deletions docs/development/v021-ledger.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ Automated results here are not physical-terminal validation.

| # | Slice | Issues | Branch / PR | Merged commit | State |
| --- | --- | --- | --- | --- | --- |
| 0 | Design and ledger | #410 | | | in progress |
| 1 | Reliability gates | #403, #408, #388 | | | |
| 0 | Design and ledger | #410 | `docs/v021-design` / #411 | | PR open, CI green; awaiting merge |
| 1 | Reliability gates | #403, #408, #388 | `fix/v021-reliability` (stacked on #411) | | PR open |
| 2 | `/view` | #397, #402 | | | |
| 3 | `/edit` | #402 | | | |
| 4 | Semantic Output | #386 | | | |
Expand All @@ -33,8 +33,21 @@ Automated results here are not physical-terminal validation.

## Physical QA still required

Recorded per slice when it merges.
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).

## Verification notes

- Slice 1 evidence: each new regression fails on the unfixed code and passes on the fix (Fish generator present;
superseded lookup settled `unknown` and the stored line never recolored; 9 of 10 redraw tests fail on the old parser,
the tenth being the documented unchanged absolute-positioning case). #408 tests passed 16/16 in two concurrent loops.
- Local full `npm run verify` on this 8 GB Mac: run with `NMSH_TEST_TMPDIR` at the T7 storage root
(`/Volumes/T7Tmp/ai-dev`), never a deeper directory: the runner requires test roots under 32 characters for Unix
sockets, and a longer root fails the runner self-test, tmux and session-socket tests for environmental reasons.
Live PTY tests can time out under full-suite load here and pass alone; exact-head CI is the independent gate.

## Open risks

None recorded yet.
- Merging into `dev` needs the maintainer (the agent's merge was refused by its permission policy). Slices are
stacked PRs; merge them in order, each squashed.
- #388: programs that position rows absolutely inline (rare) still append; recorded in the design.
31 changes: 31 additions & 0 deletions docs/testing/v021-physical-qa.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# v0.21 physical QA

## Status

- **Candidate, not released.** Items are added as each v0.21 slice lands ([ledger](../development/v021-ledger.md)).
Nothing below has been run yet.
- **What does not count:** headless PTY fixtures, synthetic keys, captures of a window driven that way, and green CI.
Each item needs a person at a real terminal with a real keyboard and pointer.
- **Build under test:** record the exact commit (`node dist/index.js --version`) built from a clean checkout
(`npm ci && npm run build`).
- **Isolation:** a throwaway `HOME` (or `XDG_CONFIG_HOME`) and a temporary working directory.

## Results

| Pass | Host and version | OS | Shell and version | Commit | Result | Notes |
|---|---|---|---|---|---|---|
| 1 Multi-row progress (#388) | Ghostty | macOS | zsh | | Not run | |
| 1 Multi-row progress (#388) | Terminal.app | macOS | Bash or Fish | | Not run | |

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

- [ ] 1.1 `node -e 'for (let i=0;i<=10;i++){process.stdout.write((i?"\x1b[1A\x1b[2K":"")+"Downloading "+i*10+"%\n")}'`
leaves one `Downloading 100%` line, at 80 columns and at 40 columns.
- [ ] 1.2 A two-row display (for example `docker pull` of a multi-layer image, or `brew install` of a formula with
concurrent downloads) updates its rows in place; log lines printed between frames all stay. Record the command.
- [ ] 1.3 Resize the window narrower and wider while 1.2 runs: no earlier command, prompt or NMSh notice is erased.
- [ ] 1.4 `/copy` of that block copies the final rows once, not every frame.
- [ ] 1.5 `printf '10%%\r20%%\r100%%\n'` still shows one `100%` line; `clear` still clears.
- [ ] 1.6 `vim`, `less` and `htop` still take the full screen and return to the composer.
- [ ] 1.7 Queue two quick commands (`ls` then `pwd`) with Ctrl+Q while a short command runs: both stored command
lines end with the known-command color (#408).
17 changes: 17 additions & 0 deletions scripts/test-shell-home.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import {mkdirSync} from 'node:fs';
import {join} from 'node:path';

/**
* Marks Fish's man-page completion generation as already done in a test home (#403).
*
* On a home without generated completions, an interactive Fish starts `fish_update_completions` detached
* (Fish 4 checks `$__fish_cache_dir/generated_completions`, Fish 3 `$__fish_user_data_dir/generated_completions`).
* That orphaned process keeps writing about 1,400 files into the home after the shell exits, so removing the home
* races it. Real installations keep Fish's normal behavior; only test homes are marked, in both places.
*
* @param {string} home the HOME the test's shells run with
* @param {{dataHome?: string, cacheHome?: string}} [dirs] XDG_DATA_HOME / XDG_CACHE_HOME when the test sets them
*/
export function markFishCompletionsGenerated(home, {dataHome = join(home, '.local', 'share'), cacheHome = join(home, '.cache')} = {}) {
for (const base of [dataHome, cacheHome]) mkdirSync(join(base, 'fish', 'generated_completions'), {recursive: true});
}
7 changes: 7 additions & 0 deletions scripts/test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {availableParallelism, tmpdir} from 'node:os';
import {join} from 'node:path';
import {pathToFileURL} from 'node:url';
import {discoverTestFiles, parseTestOptions, selectTestGroups, testConcurrency} from './test-selection.mjs';
import {markFishCompletionsGenerated} from './test-shell-home.mjs';

/** Short private temp roots keep Unix sockets below their path length limit. */
export async function runTestFiles(files, args = [], {cwd = process.cwd(), stdio = 'inherit', report = message => console.error(message)} = {}) {
Expand All @@ -12,11 +13,17 @@ export async function runTestFiles(files, args = [], {cwd = process.cwd(), stdio
try {
const testHome = join(root, 'home');
mkdirSync(testHome, {mode: 0o700});
markFishCompletionsGenerated(testHome);
// Existing presentation snapshots pin truecolor; baseline fixtures override this explicitly.
// Tests never see the user's real NMSh settings: configuration lives under this run's private root.
const env = {...process.env, HOME: testHome, COLORTERM: process.env.COLORTERM ?? 'truecolor', TMPDIR: root, TMP: root, TEMP: root, XDG_CONFIG_HOME: join(root, 'config'), NMSH_DISABLE_UPDATES: '1'};
// A nested runner must not impersonate its parent's test worker.
delete env.NODE_TEST_CONTEXT;
// Ambient XDG data, cache and state directories (a developer's, or a wrapper's shared cache) are not the tests':
// shells and tools fall back to the private HOME, as they do on CI where these are unset.
delete env.XDG_DATA_HOME;
delete env.XDG_CACHE_HOME;
delete env.XDG_STATE_HOME;
// PTY workers also own shell/helper processes. Bound fan-out on larger
// development hosts; explicit Node --test-concurrency options still win.
const concurrency = testConcurrency(process.env.NMSH_TEST_CONCURRENCY, availableParallelism());
Expand Down
1 change: 1 addition & 0 deletions src/app/TerminalApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10352,6 +10352,7 @@ export class TerminalApp {
this.lastPtyRows = plan.ptyRows;
this.lastPtyColumns = columns;
this.session.resize(columns, plan.ptyRows);
this.output.setScreenRows(plan.ptyRows);
}

const wrapped = this.output.wrapped(columns);
Expand Down
Loading
Loading