aboutsummaryrefslogtreecommitdiffstats
path: root/cli/package.json
diff options
context:
space:
mode:
authoruser <user@clank>2026-08-12 21:55:12 +0200
committeruser <user@clank>2026-08-12 21:55:12 +0200
commit72441afa75c058e4b1454108d962f2bebaee941b (patch)
treed668f1f61d8cbf19127013724db50cf680aa59c9 /cli/package.json
parentdocs: agree the sl0ppi CLI design (diff)
downloadsl0ppi-72441afa75c058e4b1454108d962f2bebaee941b.tar.gz
sl0ppi-72441afa75c058e4b1454108d962f2bebaee941b.tar.xz
sl0ppi-72441afa75c058e4b1454108d962f2bebaee941b.zip
cli: the idempotency core (discovery, tab identity, plan diff)
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.
Diffstat (limited to 'cli/package.json')
-rw-r--r--cli/package.json11
1 files changed, 11 insertions, 0 deletions
diff --git a/cli/package.json b/cli/package.json
new file mode 100644
index 0000000..2d36588
--- /dev/null
+++ b/cli/package.json
@@ -0,0 +1,11 @@
+{
+ "name": "sl0ppi-cli",
+ "version": "0.1.0",
+ "private": true,
+ "type": "module",
+ "description": "Orchestrates sl0ppij sessions: one root dir per session, one project per tab",
+ "scripts": {
+ "test": "bun test",
+ "typecheck": "bunx tsc --noEmit"
+ }
+}