import { describe, expect, it } from "vitest"; import { assertTeamShellCommandAllowed, assertTeamWorkspacePathAllowed, displayBotWorkspacePath, filterTeamWorkspaceEntries, resolveBotWorkspaceCwd, resolveBotWorkspacePath, teamBotWorkspaceDirectory, teamWorkspaceTargetBotId, } from "./computer-support.js"; describe("Team Computer bot folders", () => { it("uses the bot folder for relative paths and cwd", () => { expect(teamBotWorkspaceDirectory("bot-1")).toBe("bots/bot-1"); expect(resolveBotWorkspacePath("team", "bot-1", "notes/result.txt")).toBe( "bots/bot-1/notes/result.txt", ); expect(resolveBotWorkspacePath("team", "bot-1", "")).toBe("bots/bot-1"); expect(resolveBotWorkspaceCwd("team", "bot-1", undefined)).toBe("bots/bot-1"); expect(resolveBotWorkspaceCwd("team", "bot-1", undefined, "pwd")).toBe("bots/bot-1"); expect( resolveBotWorkspaceCwd( "team", "bot-1", undefined, 'grep -rn "KI" project/ --include="*.html"', ), ).toBe("."); expect(resolveBotWorkspaceCwd("team", "bot-1", ".", "ls -la project/")).toBe("."); expect(resolveBotWorkspaceCwd("team", "bot-1", undefined, "cd project && git status")).toBe( ".", ); expect(resolveBotWorkspaceCwd("team", "bot-1", undefined, "cat shared/brief.md")).toBe("."); expect(resolveBotWorkspaceCwd("team", "bot-1", "projects/site")).toBe( "bots/bot-1/projects/site", ); expect(resolveBotWorkspaceCwd("team", "bot-1", "project")).toBe("project"); expect(resolveBotWorkspaceCwd("team", "bot-1", "/project")).toBe("project"); expect(resolveBotWorkspaceCwd("team", "bot-1", "/shared/docs")).toBe("shared/docs"); expect(resolveBotWorkspaceCwd("team", "bot-1", "/")).toBe("."); expect(resolveBotWorkspaceCwd("team", "bot-1", "/Users/me/project")).toBe("/Users/me/project"); }); it("keeps shared, bot-root, and absolute paths at the Team root", () => { expect(resolveBotWorkspacePath("team", "bot-1", "shared/brief.md")).toBe("shared/brief.md"); expect(resolveBotWorkspacePath("team", "bot-1", "project/index.html")).toBe( "project/index.html", ); expect(resolveBotWorkspacePath("team", "bot-1", "bots/bot-2/result.md")).toBe( "bots/bot-2/result.md", ); expect(resolveBotWorkspacePath("team", "bot-1", "/root-note.md")).toBe("root-note.md"); expect(resolveBotWorkspacePath("team", "bot-1", "/shared/brief.md")).toBe("shared/brief.md"); }); it("presents the current bot folder as its home without hiding Team paths", () => { expect(displayBotWorkspacePath("team", "bot-1", "notes", "bots/bot-1/notes/result.txt")).toBe( "notes/result.txt", ); expect(displayBotWorkspacePath("team", "bot-1", "shared", "shared/brief.md")).toBe( "shared/brief.md", ); expect(displayBotWorkspacePath("team", "bot-1", "bots", "bots/bot-1")).toBe("bots/bot-1"); expect(displayBotWorkspacePath("team", "bot-1", "/", "bots/bot-1")).toBe("bots/bot-1"); expect( displayBotWorkspacePath("team", "bot-1", "bots/bot-1", "bots/bot-1/notes/result.txt"), ).toBe("bots/bot-1/notes/result.txt"); }); it("scopes Team bot homes to the caller's bots in shared Spaces", () => { const allowed = new Set(["bot-1", "bot-2"]); expect(teamWorkspaceTargetBotId("bots/bot-2/notes/result.txt")).toBe("bot-2"); expect(teamWorkspaceTargetBotId("shared/brief.md")).toBeNull(); expect(() => assertTeamWorkspacePathAllowed("bots/bot-2/notes/result.txt", allowed), ).not.toThrow(); expect(() => assertTeamWorkspacePathAllowed("bots/bot-3/secret.txt", allowed)).toThrow( /escapes the bot computer workspace/, ); expect(() => assertTeamShellCommandAllowed("cat bots/bot-3/secret.txt", allowed)).toThrow( /escapes the bot computer workspace/, ); expect( filterTeamWorkspaceEntries( [ { path: "bots/bot-1", name: "bot-1" }, { path: "bots/bot-3", name: "bot-3" }, { path: "shared", name: "shared" }, ], allowed, ), ).toEqual([ { path: "bots/bot-1", name: "bot-1" }, { path: "shared", name: "shared" }, ]); }); it("leaves Private Computer paths unchanged", () => { expect(resolveBotWorkspacePath("dedicated", "bot-1", "notes/result.txt")).toBe( "notes/result.txt", ); expect(resolveBotWorkspaceCwd("dedicated", "bot-1", undefined)).toBeUndefined(); expect(displayBotWorkspacePath("dedicated", "bot-1", "notes", "notes/result.txt")).toBe( "notes/result.txt", ); }); });