Files
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

150 lines
3.5 KiB
TypeScript

import type { AgentSessionCommand } from "../../../shared/agentSessionTypes";
import {
draftForSlashCommandTrigger,
getPromptStartSlashCommandQuery
} from "./agentComposerTriggerQueries";
export interface SlashCommandSearchItem {
aliases?: readonly string[];
description?: string;
name: string;
}
interface SlashCommandQueryMatch {
query: string;
prefix: string;
}
export interface SlashCommandInvocation {
args: string;
commandName: string;
leadingWhitespace: string;
normalizedPrompt: string;
}
export function getSlashCommandQueryMatch(
draft: string
): SlashCommandQueryMatch | null {
const query = getPromptStartSlashCommandQuery(draft);
if (query === null) {
return null;
}
return {
query,
prefix: /^(\s*)/.exec(draft)?.[1] ?? ""
};
}
export function getSlashCommandQuery(draft: string): string | null {
return getSlashCommandQueryMatch(draft)?.query ?? null;
}
export function filterSlashCommands<T extends SlashCommandSearchItem>(
commands: readonly T[],
query: string
): T[] {
const normalizedQuery = query.trim().toLowerCase();
if (!normalizedQuery) {
return [...commands];
}
return commands.filter((command) => {
const name = command.name.trim().toLowerCase();
const description = command.description?.trim().toLowerCase() ?? "";
const aliases = command.aliases ?? [];
return (
name.startsWith(normalizedQuery) ||
aliases.some((alias) =>
alias.trim().toLowerCase().startsWith(normalizedQuery)
) ||
description.includes(normalizedQuery)
);
});
}
export function mergeSlashCommands(
primaryCommands: readonly AgentSessionCommand[],
fallbackCommands: readonly AgentSessionCommand[]
): AgentSessionCommand[] {
const merged: AgentSessionCommand[] = [];
const seen = new Set<string>();
const append = (command: AgentSessionCommand): void => {
const name = command.name.trim();
if (!name) {
return;
}
const key = name.toLowerCase();
if (seen.has(key)) {
return;
}
seen.add(key);
merged.push({ ...command, name });
};
for (const command of primaryCommands) {
append(command);
}
for (const command of fallbackCommands) {
append(command);
}
return merged;
}
export function parseSlashCommandInvocation(
draft: string
): SlashCommandInvocation | null {
const match = /^(\s*)\/([^\s]+)(?:\s+([\s\S]*))?$/.exec(draft);
if (!match) {
return null;
}
const commandName = (match[2] ?? "").trim();
if (!commandName) {
return null;
}
const args = match[3] ?? "";
const normalizedPrompt = args ? `/${commandName} ${args}` : `/${commandName}`;
return {
args,
commandName,
leadingWhitespace: match[1] ?? "",
normalizedPrompt
};
}
export function moveSlashCommandHighlight(
currentIndex: number,
itemCount: number,
delta: number
): number {
if (itemCount <= 0) {
return 0;
}
return (currentIndex + delta + itemCount) % itemCount;
}
export function clampSlashCommandHighlight(
currentIndex: number,
itemCount: number
): number {
if (itemCount <= 0) {
return 0;
}
return Math.min(Math.max(currentIndex, 0), itemCount - 1);
}
export function draftForSlashCommand(
command: AgentSessionCommand,
currentDraft = ""
): string {
return draftForSlashCommandTrigger({
commandName: command.name,
currentDraft
});
}
export function promptForSlashCommand(command: AgentSessionCommand): string {
return `/${command.name.trim()}`;
}
export function labelForSlashCommand(command: AgentSessionCommand): string {
return command.name.trim();
}