mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-15 09:01:14 +00:00
fix(coding-agent): filter out commands conflict with builtins
This commit is contained in:
parent
df5b0f76c0
commit
29e2997f41
3 changed files with 57 additions and 8 deletions
|
|
@ -170,6 +170,7 @@ export class ExtensionRunner {
|
|||
private switchSessionHandler: SwitchSessionHandler = async () => ({ cancelled: false });
|
||||
private shutdownHandler: ShutdownHandler = () => {};
|
||||
private shortcutDiagnostics: ResourceDiagnostic[] = [];
|
||||
private commandDiagnostics: ResourceDiagnostic[] = [];
|
||||
|
||||
constructor(
|
||||
extensions: Extension[],
|
||||
|
|
@ -371,16 +372,31 @@ export class ExtensionRunner {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
getRegisteredCommands(): RegisteredCommand[] {
|
||||
getRegisteredCommands(reserved?: Set<string>): RegisteredCommand[] {
|
||||
this.commandDiagnostics = [];
|
||||
|
||||
const commands: RegisteredCommand[] = [];
|
||||
for (const ext of this.extensions) {
|
||||
for (const command of ext.commands.values()) {
|
||||
if (reserved?.has(command.name)) {
|
||||
const message = `Extension command '${command.name}' from ${ext.path} conflicts with built-in commands. Skipping.`;
|
||||
this.commandDiagnostics.push({ type: "warning", message, path: ext.path });
|
||||
if (!this.hasUI()) {
|
||||
console.warn(message);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
commands.push(command);
|
||||
}
|
||||
}
|
||||
return commands;
|
||||
}
|
||||
|
||||
getCommandDiagnostics(): ResourceDiagnostic[] {
|
||||
return this.commandDiagnostics;
|
||||
}
|
||||
|
||||
getRegisteredCommandsWithPaths(): Array<{ command: RegisteredCommand; extensionPath: string }> {
|
||||
const result: Array<{ command: RegisteredCommand; extensionPath: string }> = [];
|
||||
for (const ext of this.extensions) {
|
||||
|
|
|
|||
|
|
@ -347,13 +347,14 @@ export class InteractiveMode {
|
|||
}));
|
||||
|
||||
// Convert extension commands to SlashCommand format
|
||||
const extensionCommands: SlashCommand[] = (this.session.extensionRunner?.getRegisteredCommands() ?? []).map(
|
||||
(cmd) => ({
|
||||
name: cmd.name,
|
||||
description: cmd.description ?? "(extension command)",
|
||||
getArgumentCompletions: cmd.getArgumentCompletions,
|
||||
}),
|
||||
);
|
||||
const builtinCommandNames = new Set(slashCommands.map((c) => c.name));
|
||||
const extensionCommands: SlashCommand[] = (
|
||||
this.session.extensionRunner?.getRegisteredCommands(builtinCommandNames) ?? []
|
||||
).map((cmd) => ({
|
||||
name: cmd.name,
|
||||
description: cmd.description ?? "(extension command)",
|
||||
getArgumentCompletions: cmd.getArgumentCompletions,
|
||||
}));
|
||||
|
||||
// Build skill commands from session.skills (if enabled)
|
||||
this.skillCommands.clear();
|
||||
|
|
@ -959,6 +960,9 @@ export class InteractiveMode {
|
|||
}
|
||||
}
|
||||
|
||||
const commandDiagnostics = this.session.extensionRunner?.getCommandDiagnostics() ?? [];
|
||||
extensionDiagnostics.push(...commandDiagnostics);
|
||||
|
||||
const shortcutDiagnostics = this.session.extensionRunner?.getShortcutDiagnostics() ?? [];
|
||||
extensionDiagnostics.push(...shortcutDiagnostics);
|
||||
|
||||
|
|
|
|||
|
|
@ -279,6 +279,35 @@ describe("ExtensionRunner", () => {
|
|||
const missing = runner.getCommand("not-exists");
|
||||
expect(missing).toBeUndefined();
|
||||
});
|
||||
|
||||
it("filters out commands conflict with reseved", async () => {
|
||||
const cmdCode = (name: string) => `
|
||||
export default function(pi) {
|
||||
pi.registerCommand("${name}", {
|
||||
description: "Test command",
|
||||
handler: async () => {},
|
||||
});
|
||||
}
|
||||
`;
|
||||
fs.writeFileSync(path.join(extensionsDir, "cmd-a.ts"), cmdCode("cmd-a"));
|
||||
fs.writeFileSync(path.join(extensionsDir, "cmd-b.ts"), cmdCode("cmd-b"));
|
||||
|
||||
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
|
||||
|
||||
const result = await discoverAndLoadExtensions([], tempDir, tempDir);
|
||||
const runner = new ExtensionRunner(result.extensions, result.runtime, tempDir, sessionManager, modelRegistry);
|
||||
const commands = runner.getRegisteredCommands(new Set(["cmd-a"]));
|
||||
const diagnostics = runner.getCommandDiagnostics();
|
||||
|
||||
expect(commands.length).toBe(1);
|
||||
expect(commands.map((c) => c.name).sort()).toEqual(["cmd-b"]);
|
||||
|
||||
expect(diagnostics.length).toBe(1);
|
||||
expect(diagnostics[0].path).toEqual(path.join(extensionsDir, "cmd-a.ts"));
|
||||
|
||||
expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining("conflicts with built-in command"));
|
||||
warnSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
describe("error handling", () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue