diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 7126a1a5..33b66b61 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -8,6 +8,7 @@ ### Fixed +- Extensions defined in `settings.json` were not loaded ([#463](https://github.com/badlogic/pi-mono/pull/463) by [@melihmucuk](https://github.com/melihmucuk)) - OAuth refresh no longer logs users out when multiple pi instances are running ([#466](https://github.com/badlogic/pi-mono/pull/466) by [@Cursivez](https://github.com/Cursivez)) - Migration warnings now ignore `fd.exe` and `rg.exe` in `tools/` on Windows ([#458](https://github.com/badlogic/pi-mono/pull/458) by [@carlosgtrz](https://github.com/carlosgtrz)) - CI: add `examples/extensions/with-deps` to workspaces to fix typecheck ([#467](https://github.com/badlogic/pi-mono/pull/467) by [@aliou](https://github.com/aliou)) diff --git a/packages/coding-agent/docs/sdk.md b/packages/coding-agent/docs/sdk.md index b1c04d4e..8d62c0f4 100644 --- a/packages/coding-agent/docs/sdk.md +++ b/packages/coding-agent/docs/sdk.md @@ -468,12 +468,15 @@ Custom tools passed via `customTools` are combined with extension-registered too ### Extensions -Extensions are discovered from `~/.pi/agent/extensions/` and `.pi/extensions/`. You can also pass inline extensions or additional paths: +By default, extensions are discovered from multiple locations: +- `~/.pi/agent/extensions/` (global) +- `.pi/extensions/` (project-local) +- Paths listed in `settings.json` `"extensions"` array ```typescript import { createAgentSession, type ExtensionFactory } from "@mariozechner/pi-coding-agent"; -// Inline extension +// Inline extension factory const myExtension: ExtensionFactory = (pi) => { pi.on("tool_call", async (event, ctx) => { console.log(`Tool: ${event.toolName}`); @@ -487,15 +490,20 @@ const myExtension: ExtensionFactory = (pi) => { }); }; -// Pass inline extensions (merged with discovery) +// Pass inline extensions (skips file discovery) const { session } = await createAgentSession({ extensions: [myExtension], }); -// Or add paths to load (merged with discovery) +// Add paths to load (merged with discovery) const { session } = await createAgentSession({ additionalExtensionPaths: ["/path/to/my-extension.ts"], }); + +// Disable extension discovery entirely +const { session } = await createAgentSession({ + extensions: [], +}); ``` Extensions can register tools, subscribe to events, add commands, and more. See [extensions.md](extensions.md) for the full API. diff --git a/packages/coding-agent/src/core/sdk.ts b/packages/coding-agent/src/core/sdk.ts index b89f6e85..e84901b0 100644 --- a/packages/coding-agent/src/core/sdk.ts +++ b/packages/coding-agent/src/core/sdk.ts @@ -101,7 +101,7 @@ export interface CreateAgentSessionOptions { tools?: Tool[]; /** Custom tools to register (in addition to built-in tools). */ customTools?: ToolDefinition[]; - /** Inline extensions (merged with discovery). */ + /** Inline extensions. When provided (even if empty), skips file discovery. */ extensions?: ExtensionFactory[]; /** Additional extension paths to load (merged with discovery). */ additionalExtensionPaths?: string[]; diff --git a/packages/coding-agent/src/main.ts b/packages/coding-agent/src/main.ts index d740b7fa..eaa164cd 100644 --- a/packages/coding-agent/src/main.ts +++ b/packages/coding-agent/src/main.ts @@ -298,7 +298,10 @@ export async function main(args: string[]) { const cwd = process.cwd(); const agentDir = getAgentDir(); const eventBus = createEventBus(); - const extensionPaths = firstPass.extensions ?? []; + const settingsManager = SettingsManager.create(cwd); + time("SettingsManager.create"); + // Merge CLI --extension args with settings.json extensions + const extensionPaths = [...settingsManager.getExtensionPaths(), ...(firstPass.extensions ?? [])]; const { extensions: loadedExtensions } = await discoverAndLoadExtensions(extensionPaths, cwd, agentDir, eventBus); time("discoverExtensionFlags"); @@ -357,8 +360,6 @@ export async function main(args: string[]) { process.exit(1); } - const settingsManager = SettingsManager.create(cwd); - time("SettingsManager.create"); const { initialMessage, initialImages } = await prepareInitialMessage(parsed, settingsManager.getImageAutoResize()); time("prepareInitialMessage"); const isInteractive = !parsed.print && parsed.mode === undefined;