Skip to content

Commit 8a30d3d

Browse files
authored
Merge pull request #20 from EvanDbg/feat/projects-menu-folder-and-path
feat(projects): show folder name and full path in /projects menu
2 parents eda4893 + 2fc0732 commit 8a30d3d

2 files changed

Lines changed: 55 additions & 3 deletions

File tree

src/bot/commands/projects.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,22 @@ function formatProjectButtonLabel(label: string, isActive: boolean): string {
3030
return `${prefix}${label.slice(0, Math.max(0, availableLength - 3))}...`;
3131
}
3232

33+
export function getProjectFolderName(worktree: string): string {
34+
const normalized = worktree.replace(/[\\/]+$/g, "");
35+
36+
if (!normalized) {
37+
return worktree;
38+
}
39+
40+
const segments = normalized.split(/[\\/]/).filter(Boolean);
41+
return segments.at(-1) ?? normalized;
42+
}
43+
44+
export function buildProjectButtonLabel(index: number, worktree: string): string {
45+
const folderName = getProjectFolderName(worktree);
46+
return `${index + 1}. [${folderName}][${worktree}]`;
47+
}
48+
3349
export async function projectsCommand(ctx: CommandContext<Context>) {
3450
try {
3551
await syncSessionDirectoryCache();
@@ -48,9 +64,7 @@ export async function projectsCommand(ctx: CommandContext<Context>) {
4864
const isActive =
4965
currentProject &&
5066
(project.id === currentProject.id || project.worktree === currentProject.worktree);
51-
const label = project.name
52-
? `${index + 1}. ${project.name}`
53-
: `${index + 1}. ${project.worktree}`;
67+
const label = buildProjectButtonLabel(index, project.worktree);
5468
const labelWithCheck = formatProjectButtonLabel(label, Boolean(isActive));
5569
keyboard.text(labelWithCheck, `project:${project.id}`).row();
5670
});
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { describe, expect, it } from "vitest";
2+
import {
3+
buildProjectButtonLabel,
4+
getProjectFolderName,
5+
} from "../../../src/bot/commands/projects.js";
6+
7+
describe("bot/commands/projects", () => {
8+
describe("getProjectFolderName", () => {
9+
it("extracts folder name from unix path", () => {
10+
expect(getProjectFolderName("/Users/evan/work/opencode-telegram-bot")).toBe(
11+
"opencode-telegram-bot",
12+
);
13+
});
14+
15+
it("extracts folder name from windows path", () => {
16+
expect(getProjectFolderName("C:\\work\\my-project")).toBe("my-project");
17+
});
18+
19+
it("handles trailing separators", () => {
20+
expect(getProjectFolderName("/var/www/project/")).toBe("project");
21+
expect(getProjectFolderName("C:\\repo\\project\\")).toBe("project");
22+
});
23+
});
24+
25+
describe("buildProjectButtonLabel", () => {
26+
it("formats label as index + folder + full path", () => {
27+
expect(buildProjectButtonLabel(0, "/Users/evan/work/opencode-telegram-bot")).toBe(
28+
"1. [opencode-telegram-bot][/Users/evan/work/opencode-telegram-bot]",
29+
);
30+
});
31+
32+
it("formats windows path label", () => {
33+
expect(buildProjectButtonLabel(3, "D:\\repo\\awesome")).toBe(
34+
"4. [awesome][D:\\repo\\awesome]",
35+
);
36+
});
37+
});
38+
});

0 commit comments

Comments
 (0)