mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-17 06:04:51 +00:00
Merge pull request #1196 from haoqixu/fix-commands-conflict
fix(coding-agent): filter out commands conflict with builtins
This commit is contained in:
commit
7a9c668357
3 changed files with 57 additions and 8 deletions
|
|
@ -172,6 +172,7 @@ export class ExtensionRunner {
|
||||||
private switchSessionHandler: SwitchSessionHandler = async () => ({ cancelled: false });
|
private switchSessionHandler: SwitchSessionHandler = async () => ({ cancelled: false });
|
||||||
private shutdownHandler: ShutdownHandler = () => {};
|
private shutdownHandler: ShutdownHandler = () => {};
|
||||||
private shortcutDiagnostics: ResourceDiagnostic[] = [];
|
private shortcutDiagnostics: ResourceDiagnostic[] = [];
|
||||||
|
private commandDiagnostics: ResourceDiagnostic[] = [];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
extensions: Extension[],
|
extensions: Extension[],
|
||||||
|
|
@ -373,16 +374,31 @@ export class ExtensionRunner {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
getRegisteredCommands(): RegisteredCommand[] {
|
getRegisteredCommands(reserved?: Set<string>): RegisteredCommand[] {
|
||||||
|
this.commandDiagnostics = [];
|
||||||
|
|
||||||
const commands: RegisteredCommand[] = [];
|
const commands: RegisteredCommand[] = [];
|
||||||
for (const ext of this.extensions) {
|
for (const ext of this.extensions) {
|
||||||
for (const command of ext.commands.values()) {
|
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);
|
commands.push(command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return commands;
|
return commands;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getCommandDiagnostics(): ResourceDiagnostic[] {
|
||||||
|
return this.commandDiagnostics;
|
||||||
|
}
|
||||||
|
|
||||||
getRegisteredCommandsWithPaths(): Array<{ command: RegisteredCommand; extensionPath: string }> {
|
getRegisteredCommandsWithPaths(): Array<{ command: RegisteredCommand; extensionPath: string }> {
|
||||||
const result: Array<{ command: RegisteredCommand; extensionPath: string }> = [];
|
const result: Array<{ command: RegisteredCommand; extensionPath: string }> = [];
|
||||||
for (const ext of this.extensions) {
|
for (const ext of this.extensions) {
|
||||||
|
|
|
||||||
|
|
@ -347,13 +347,14 @@ export class InteractiveMode {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Convert extension commands to SlashCommand format
|
// Convert extension commands to SlashCommand format
|
||||||
const extensionCommands: SlashCommand[] = (this.session.extensionRunner?.getRegisteredCommands() ?? []).map(
|
const builtinCommandNames = new Set(slashCommands.map((c) => c.name));
|
||||||
(cmd) => ({
|
const extensionCommands: SlashCommand[] = (
|
||||||
name: cmd.name,
|
this.session.extensionRunner?.getRegisteredCommands(builtinCommandNames) ?? []
|
||||||
description: cmd.description ?? "(extension command)",
|
).map((cmd) => ({
|
||||||
getArgumentCompletions: cmd.getArgumentCompletions,
|
name: cmd.name,
|
||||||
}),
|
description: cmd.description ?? "(extension command)",
|
||||||
);
|
getArgumentCompletions: cmd.getArgumentCompletions,
|
||||||
|
}));
|
||||||
|
|
||||||
// Build skill commands from session.skills (if enabled)
|
// Build skill commands from session.skills (if enabled)
|
||||||
this.skillCommands.clear();
|
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() ?? [];
|
const shortcutDiagnostics = this.session.extensionRunner?.getShortcutDiagnostics() ?? [];
|
||||||
extensionDiagnostics.push(...shortcutDiagnostics);
|
extensionDiagnostics.push(...shortcutDiagnostics);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -279,6 +279,35 @@ describe("ExtensionRunner", () => {
|
||||||
const missing = runner.getCommand("not-exists");
|
const missing = runner.getCommand("not-exists");
|
||||||
expect(missing).toBeUndefined();
|
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", () => {
|
describe("error handling", () => {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue