From 35e48ca01808f1d21fe939b4bed964b6148286e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Krzywa=C5=BCnia?= Date: Fri, 16 Jan 2026 02:30:55 +0100 Subject: [PATCH] feat(coding-agent): extension command argument autocomplete --- packages/coding-agent/CHANGELOG.md | 1 + packages/coding-agent/docs/extensions.md | 19 +++++++++++++++++++ .../src/core/extensions/loader.ts | 2 +- .../coding-agent/src/core/extensions/types.ts | 4 +++- .../src/modes/interactive/interactive-mode.ts | 1 + 5 files changed, 25 insertions(+), 2 deletions(-) diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index ec74ca4f..2b6743ed 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -5,6 +5,7 @@ ### Added - Added bash-style argument slicing for prompt templates ([#770](https://github.com/badlogic/pi-mono/pull/770) by [@airtonix](https://github.com/airtonix)) +- Extension commands can provide argument auto-completions via `getArgumentCompletions` in `pi.registerCommand()` ([#775](https://github.com/badlogic/pi-mono/pull/775) by [@ribelo](https://github.com/ribelo)) ### Fixed diff --git a/packages/coding-agent/docs/extensions.md b/packages/coding-agent/docs/extensions.md index 248d0c98..668de64e 100644 --- a/packages/coding-agent/docs/extensions.md +++ b/packages/coding-agent/docs/extensions.md @@ -882,6 +882,25 @@ pi.registerCommand("stats", { }); ``` +Optional: add argument auto-completion for `/command ...`: + +```typescript +import type { AutocompleteItem } from "@mariozechner/pi-tui"; + +pi.registerCommand("deploy", { + description: "Deploy to an environment", + getArgumentCompletions: (prefix: string): AutocompleteItem[] | null => { + const envs = ["dev", "staging", "prod"]; + const items = envs.map((e) => ({ value: e, label: e })); + const filtered = items.filter((i) => i.value.startsWith(prefix)); + return filtered.length > 0 ? filtered : null; + }, + handler: async (args, ctx) => { + ctx.ui.notify(`Deploying: ${args}`, "info"); + }, +}); +``` + **Examples:** [custom-footer.ts](../examples/extensions/custom-footer.ts), [custom-header.ts](../examples/extensions/custom-header.ts), [handoff.ts](../examples/extensions/handoff.ts), [pirate.ts](../examples/extensions/pirate.ts), [plan-mode/index.ts](../examples/extensions/plan-mode/index.ts), [preset.ts](../examples/extensions/preset.ts), [qna.ts](../examples/extensions/qna.ts), [send-user-message.ts](../examples/extensions/send-user-message.ts), [snake.ts](../examples/extensions/snake.ts), [summarize.ts](../examples/extensions/summarize.ts), [todo.ts](../examples/extensions/todo.ts), [tools.ts](../examples/extensions/tools.ts) ### pi.registerMessageRenderer(customType, renderer) diff --git a/packages/coding-agent/src/core/extensions/loader.ts b/packages/coding-agent/src/core/extensions/loader.ts index d581b528..a6bcafda 100644 --- a/packages/coding-agent/src/core/extensions/loader.ts +++ b/packages/coding-agent/src/core/extensions/loader.ts @@ -150,7 +150,7 @@ function createExtensionAPI( }); }, - registerCommand(name: string, options: { description?: string; handler: RegisteredCommand["handler"] }): void { + registerCommand(name: string, options: Omit): void { extension.commands.set(name, { name, ...options }); }, diff --git a/packages/coding-agent/src/core/extensions/types.ts b/packages/coding-agent/src/core/extensions/types.ts index e837cf40..0c2f656c 100644 --- a/packages/coding-agent/src/core/extensions/types.ts +++ b/packages/coding-agent/src/core/extensions/types.ts @@ -16,6 +16,7 @@ import type { } from "@mariozechner/pi-agent-core"; import type { ImageContent, Model, TextContent, ToolResultMessage } from "@mariozechner/pi-ai"; import type { + AutocompleteItem, Component, EditorComponent, EditorTheme, @@ -655,6 +656,7 @@ export type MessageRenderer = ( export interface RegisteredCommand { name: string; description?: string; + getArgumentCompletions?: (argumentPrefix: string) => AutocompleteItem[] | null; handler: (args: string, ctx: ExtensionCommandContext) => Promise; } @@ -714,7 +716,7 @@ export interface ExtensionAPI { // ========================================================================= /** Register a custom command. */ - registerCommand(name: string, options: { description?: string; handler: RegisteredCommand["handler"] }): void; + registerCommand(name: string, options: Omit): void; /** Register a keyboard shortcut. */ registerShortcut( diff --git a/packages/coding-agent/src/modes/interactive/interactive-mode.ts b/packages/coding-agent/src/modes/interactive/interactive-mode.ts index 7677e116..4a4cdc5b 100644 --- a/packages/coding-agent/src/modes/interactive/interactive-mode.ts +++ b/packages/coding-agent/src/modes/interactive/interactive-mode.ts @@ -319,6 +319,7 @@ export class InteractiveMode { (cmd) => ({ name: cmd.name, description: cmd.description ?? "(extension command)", + getArgumentCompletions: cmd.getArgumentCompletions, }), );