CoDEVX / agentic_pm_demo_codex_plans /lib /command-parser.ts
Tiger's Macbook Air
Build agentic PM demo app
3f76ff4
import type { CommandMode, ParsedCommand, WorkPackage } from "./work-package-types";
const commandModes: CommandMode[] = ["ask", "plan", "change", "execute"];
export function parseWorkPackageCommand(
input: string,
workPackages: WorkPackage[],
): ParsedCommand | null {
const trimmedInput = input.trim();
if (!trimmedInput.startsWith("@")) {
return null;
}
const mentionBody = trimmedInput.slice(1);
const candidates = workPackages
.flatMap((workPackage) => [
{ name: workPackage.title, workPackage },
{ name: workPackage.shortName, workPackage },
])
.sort((left, right) => right.name.length - left.name.length);
for (const candidate of candidates) {
const packageName = candidate.name.toLowerCase();
const inputName = mentionBody.toLowerCase();
if (!inputName.startsWith(packageName)) {
continue;
}
const boundaryCharacter = mentionBody[candidate.name.length];
const isBoundary =
boundaryCharacter === undefined ||
boundaryCharacter === " " ||
boundaryCharacter === "#" ||
boundaryCharacter === ":";
if (!isBoundary) {
continue;
}
const remainingText = mentionBody.slice(candidate.name.length).trim();
const [maybeMode, ...instructionParts] = remainingText.split(/\s+/);
const mode = commandModes.includes(maybeMode as CommandMode)
? (maybeMode as CommandMode)
: "ask";
return {
referencedPackageName: candidate.name,
workPackageId: candidate.workPackage.id,
mode,
instruction:
mode === maybeMode
? instructionParts.join(" ").trim()
: remainingText.replace(/^#\S+\s*/, "").trim(),
};
}
return {
mode: "ask",
instruction: trimmedInput,
};
}
export function getPackageSuggestions(input: string, workPackages: WorkPackage[]) {
const match = input.match(/@([A-Za-z\s-]*)$/);
if (!match) {
return [];
}
const query = match[1].toLowerCase().trim();
return workPackages
.filter((workPackage) => {
if (!query) {
return true;
}
return (
workPackage.title.toLowerCase().includes(query) ||
workPackage.shortName.toLowerCase().includes(query)
);
})
.slice(0, 6);
}