feat(codex): support file mentions (#774)

* feat(codex): support file mentions

* fix(codex): quote file mention paths with spaces

* fix(codex): keep punctuation outside file mentions

* fix(codex): avoid parsing literal at-mentions

* fix(codex): scope file mention autocomplete
This commit is contained in:
NightWatcher314
2026-07-24 11:00:48 +08:00
committed by GitHub
parent 40c1789357
commit 5300e1ee39
4 changed files with 95 additions and 3 deletions
+43 -2
View File
@@ -7,7 +7,8 @@ import type {
SandboxMode,
SandboxPolicy,
ThreadStartParams,
TurnStartParams
TurnStartParams,
UserInput
} from '../appServerTypes';
import { resolveCodexPermissionModeConfig } from './permissionModeConfig';
@@ -127,6 +128,46 @@ function appendCollaborationInstructions(developerInstructions: string): string
return `${developerInstructions}\n\n${codexCollaborationSpawnAgentInstructions}`;
}
function mentionNameFromPath(path: string): string {
const parts = path.split(/[\\/]/).filter(Boolean);
return parts[parts.length - 1] ?? path;
}
export function buildUserInputFromMessage(message: string): UserInput[] {
const inputs: UserInput[] = [];
const mentionPattern = /(^|\s)@"((?:\\.|[^"\\])*)"/g;
let lastIndex = 0;
let match: RegExpExecArray | null;
while ((match = mentionPattern.exec(message)) !== null) {
const prefix = match[1] ?? '';
const rawPath = match[2] ?? '';
const pathText = rawPath;
const path = pathText.replace(/\\(["\\])/g, '$1');
if (!path) continue;
const atIndex = match.index + prefix.length;
const textBeforeMention = message.slice(lastIndex, atIndex);
if (textBeforeMention) {
inputs.push({ type: 'text', text: textBeforeMention });
}
inputs.push({
type: 'mention',
name: mentionNameFromPath(path),
path
});
lastIndex = mentionPattern.lastIndex - (rawPath.length - pathText.length);
}
const remainder = message.slice(lastIndex);
if (remainder || inputs.length === 0) {
inputs.push({ type: 'text', text: remainder });
}
return inputs;
}
export function buildThreadStartParams(args: {
cwd: string;
mode: EnhancedMode;
@@ -192,7 +233,7 @@ export function buildTurnStartParams(args: {
const params: TurnStartParams = {
threadId: args.threadId,
cwd: args.cwd,
input: [{ type: 'text', text: args.message }]
input: buildUserInputFromMessage(args.message)
};
const allowCliOverrides = args.mode?.permissionMode === 'default';