diff options
| author | user <user@clank> | 2026-08-12 23:49:19 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-08-12 23:49:19 +0200 |
| commit | acf61609ee7b99138251cea879d593d5f1689392 (patch) | |
| tree | 06f880e8c2e312e1a600c4ee0a63943c29eb902f /cli/src/core/errors.ts | |
| parent | release: publish sl0ppi.sl0p.foo, and a script to keep it current (diff) | |
| download | sl0ppi-acf61609ee7b99138251cea879d593d5f1689392.tar.gz sl0ppi-acf61609ee7b99138251cea879d593d5f1689392.tar.xz sl0ppi-acf61609ee7b99138251cea879d593d5f1689392.zip | |
cli: survive a dead session, and a flaky terminal
Three bugs found on a fresh Debian box, all of which made sl0ppi look broken
when the terminal underneath it was the problem.
1. JSON crash on startup. `action list-panes --json` against a session that has
died exits 0 with EMPTY stdout, and JSON.parse("") threw "JSON Parse error:
Unexpected EOF" at the user. Empty output is now "nothing", and genuinely
malformed output is reported with the command name and the offending text.
2. `up` silently resurrected. A dead-but-resurrectable session is not an empty
slot: `attach --create-background NAME` restores it from the serialised copy
and IGNORES --layout. The result was a root full of projects coming back as
plain shells with no agents and no purposes -- and the resurrected background
session then exited again within seconds. sl0ppi now refuses to guess and
explains the two real options (`up --fresh` to rebuild, `sl0ppij attach` to
restore it properly in a terminal). Verified on a clean slate that a fresh
`up` produces exactly the right panes: purpose='agent:main' held=true cmd='pi'.
3. The terminal's CLI actions are racy. Measured against a LIVE session on a
2-vCPU box: list-tabs and list-panes each fail ~60% of the time while the
session is detached, ~25% with a client attached, either with empty output or
"There is no active session!" (the action client consults
get_active_session() before it looks at -s). That is a defect in sl0ppij --
filed as a known issue -- but these are idempotent reads, so sl0ppi retries
them with backoff and distinguishes "the session is gone" from "the terminal
would not answer". `sl0ppi ls` went from failing most runs to 8/8.
Also:
- session creation returns before the server is registered, so `up` now waits
for readiness instead of racing its own next command
- UserError: actionable answers ("no project foo", "that session is a saved
dead copy") print and exit 1 instead of falling through to sl0ppij, which
buried the explanation and started a session nobody asked for
- `sl0ppi print <project>` implemented; it was referenced by the init template
and the design doc but did not exist
Diffstat (limited to 'cli/src/core/errors.ts')
| -rw-r--r-- | cli/src/core/errors.ts | 14 |
1 files changed, 14 insertions, 0 deletions
diff --git a/cli/src/core/errors.ts b/cli/src/core/errors.ts new file mode 100644 index 0000000..0bab4bd --- /dev/null +++ b/cli/src/core/errors.ts @@ -0,0 +1,14 @@ +/** + * An error the user can act on, as opposed to a bug. + * + * These are printed and the process exits non-zero. They deliberately do NOT + * trigger the fail-open handover to sl0ppij: "no project called foo" or "that + * session is a saved dead copy" are answers, and replacing them with a raw + * multiplexer would hide the answer and start a session nobody asked for. + */ +export class UserError extends Error { + constructor(message: string) { + super(message); + this.name = "UserError"; + } +} |
