File size: 2,254 Bytes
3f76ff4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
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);
}