import { describe, expect, test } from "bun:test"; import { parseArgs, passthroughArgs } from "../src/index.ts"; import { agentStateOf } from "../src/commands/workspace.ts"; import { withoutSessionEnv } from "../src/core/sl0ppij.ts"; describe("parseArgs", () => { test("defaults to up", () => { expect(parseArgs([]).command).toBe("up"); expect(parseArgs(["--root", "/x"]).command).toBe("up"); }); test("recognises the verbs", () => { for (const verb of ["up", "ls", "open", "close", "help"]) { expect(parseArgs([verb]).command).toBe(verb); } }); test("keeps the project name as an argument", () => { const args = parseArgs(["open", "myproj", "--root", "/x"]); expect(args.command).toBe("open"); expect(args.rest).toEqual(["myproj"]); expect(args.rootFlag).toBe("/x"); }); test("accepts both flag spellings", () => { expect(parseArgs(["--root=/x"]).rootFlag).toBe("/x"); expect(parseArgs(["--depth=3"]).depth).toBe(3); expect(parseArgs(["--depth", "2"]).depth).toBe(2); expect(parseArgs(["-n"]).dryRun).toBe(true); }); test("a bad depth falls back to 1 rather than NaN", () => { expect(parseArgs(["--depth", "banana"]).depth).toBe(1); }); }); // Falling open is only useful if what we hand over is something sl0ppij // understands. Passing `up` through just yields "unrecognized subcommand" and // still leaves the user without a terminal. describe("passthroughArgs", () => { test("strips our verbs and flags", () => { expect(passthroughArgs(["up", "--root", "/x"])).toEqual([]); expect(passthroughArgs(["ls", "--depth=2"])).toEqual([]); expect(passthroughArgs(["open", "proj", "-n"])).toEqual(["proj"]); }); test("keeps arguments sl0ppij would understand", () => { expect(passthroughArgs(["attach", "mysession"])).toEqual(["attach", "mysession"]); expect(passthroughArgs(["--root", "/x", "list-sessions"])).toEqual(["list-sessions"]); }); test("only the leading verb is dropped", () => { // `sl0ppij action ... close` style words further along must survive expect(passthroughArgs(["action", "close-tab"])).toEqual(["action", "close-tab"]); }); }); describe("agentStateOf", () => { // A start_suspended pane reports is_held, not exited: the command is staged // but has never run. Conflating the two made `ls` claim twelve agents were // running when none were. test("held means suspended", () => { expect(agentStateOf({ is_held: true })).toBe("suspended"); }); test("exited means exited", () => { expect(agentStateOf({ exited: true })).toBe("exited"); }); test("neither means running", () => { expect(agentStateOf({})).toBe("running"); }); test("absent means none", () => { expect(agentStateOf(undefined)).toBe("none"); }); }); describe("withoutSessionEnv", () => { // `attach --create-background` fails with "There is no active session!" when // the caller is inside a session, and sl0ppi is nearly always run from one. test("drops both spellings of the session markers", () => { const cleaned = withoutSessionEnv({ ZELLIJ: "0", ZELLIJ_SESSION_NAME: "inventive-drum", SL0PPIJ: "0", SL0PPIJ_SESSION_NAME: "dev", SL0PPIJ_PANE_ID: "3", PATH: "/usr/bin", }); expect(cleaned.ZELLIJ).toBeUndefined(); expect(cleaned.ZELLIJ_SESSION_NAME).toBeUndefined(); expect(cleaned.SL0PPIJ).toBeUndefined(); expect(cleaned.SL0PPIJ_SESSION_NAME).toBeUndefined(); expect(cleaned.SL0PPIJ_PANE_ID).toBeUndefined(); expect(cleaned.PATH).toBe("/usr/bin"); }); });