aboutsummaryrefslogtreecommitdiffstats
path: root/cli/test/purpose.test.ts (follow)
Commit message (Collapse)AuthorAge
* cli: the idempotency core (discovery, tab identity, plan diff)user2026-08-12
Slice 1 of docs/cli-design.md: the only part with logic worth testing hard. Pure functions, no subprocesses, so the tests hit them directly. purpose.ts tab identity as a zellij tab purpose carrying the project's root-relative path discover.ts depth-1 scan for .sl0ppi/ markers plan.ts discovered projects vs list-tabs -> {create, close, keep, foreign} Identity carries the *path* because `list-panes --json` exposes no cwd (checked against a live session, not assumed), so there is otherwise no way back from a tab to a directory on disk. Slashes survive the fork's sanitiser, so nested paths encode fine. Two safety properties, both fuzzed over 5000 random names: - a purpose never exceeds 64 chars and always survives re-sanitising, so what we generate is what the terminal stores - projectRelPath() reconstructs the original path exactly or returns null -- never a different path. Wrong answers close the wrong tab; refusing only leaves a stale one. The fuzz caught a real bug in the second property. The first implementation detected lossy encodings by re-encoding and comparing, which silently failed: `project:<47 a's>.<hash8>` is itself 64 legal characters, so it re-encodes to itself, the check passed, and a bogus path was "reconstructed" -- which would have closed a live tab. Lossy purposes now carry a structural marker (a leading dot, which no discovered path can have) instead of relying on a comparison. Plus the mount guard from the design: when the ROOT itself is missing, close nothing. An unmounted filesystem is indistinguishable from mass deletion, and one of those two readings eats your whole session. 31 unit tests + 2 fuzz properties, 10178 assertions, green.