feat(coding-agent): add --no-extensions flag to disable extension discovery

Adds --no-extensions CLI flag that skips automatic extension discovery
while still allowing explicit -e paths. Three modes now available:

1. Default: auto-discover + any -e additions
2. --no-extensions: no extensions at all
3. --no-extensions -e foo.js: only load explicit extensions

Useful for debugging or running subagent instances without auto-discovered
extensions.

closes #524
This commit is contained in:
Mario Zechner 2026-01-08 03:22:38 +01:00
commit 7f3fa417c4
6 changed files with 71 additions and 6 deletions

View file

@ -27,6 +27,7 @@ export interface Args {
models?: string[];
tools?: ToolName[];
extensions?: string[];
noExtensions?: boolean;
print?: boolean;
export?: string;
noSkills?: boolean;
@ -116,6 +117,8 @@ export function parseArgs(args: string[], extensionFlags?: Map<string, { type: "
} else if ((arg === "--extension" || arg === "-e") && i + 1 < args.length) {
result.extensions = result.extensions ?? [];
result.extensions.push(args[++i]);
} else if (arg === "--no-extensions") {
result.noExtensions = true;
} else if (arg === "--no-skills") {
result.noSkills = true;
} else if (arg === "--skills" && i + 1 < args.length) {
@ -175,6 +178,7 @@ ${chalk.bold("Options:")}
Available: read, bash, edit, write, grep, find, ls
--thinking <level> Set thinking level: off, minimal, low, medium, high, xhigh
--extension, -e <path> Load an extension file (can be used multiple times)
--no-extensions Disable extensions discovery and loading
--no-skills Disable skills discovery and loading
--skills <patterns> Comma-separated glob patterns to filter skills (e.g., git-*,docker)
--export <file> Export session file to HTML and exit

View file

@ -16,7 +16,7 @@ import { selectSession } from "./cli/session-picker.js";
import { CONFIG_DIR_NAME, getAgentDir, getModelsPath, VERSION } from "./config.js";
import { createEventBus } from "./core/event-bus.js";
import { exportFromFile } from "./core/export-html/index.js";
import { discoverAndLoadExtensions, type LoadExtensionsResult } from "./core/extensions/index.js";
import { discoverAndLoadExtensions, type LoadExtensionsResult, loadExtensions } from "./core/extensions/index.js";
import type { ModelRegistry } from "./core/model-registry.js";
import { resolveModelScope, type ScopedModel } from "./core/model-resolver.js";
import { type CreateAgentSessionOptions, createAgentSession, discoverAuthStorage, discoverModels } from "./core/sdk.js";
@ -209,16 +209,25 @@ export async function main(args: string[]) {
const firstPass = parseArgs(args);
time("parseArgs-firstPass");
// Early load extensions to discover their CLI flags
// Early load extensions to discover their CLI flags (unless --no-extensions)
const cwd = process.cwd();
const agentDir = getAgentDir();
const eventBus = createEventBus();
const settingsManager = SettingsManager.create(cwd);
time("SettingsManager.create");
// Merge CLI --extension args with settings.json extensions
const extensionPaths = [...settingsManager.getExtensionPaths(), ...(firstPass.extensions ?? [])];
const extensionsResult = await discoverAndLoadExtensions(extensionPaths, cwd, agentDir, eventBus);
time("discoverExtensionFlags");
let extensionsResult: LoadExtensionsResult;
if (firstPass.noExtensions) {
// --no-extensions disables discovery, but explicit -e flags still work
const explicitPaths = firstPass.extensions ?? [];
extensionsResult = await loadExtensions(explicitPaths, cwd, eventBus);
time("loadExtensions");
} else {
// Merge CLI --extension args with settings.json extensions
const extensionPaths = [...settingsManager.getExtensionPaths(), ...(firstPass.extensions ?? [])];
extensionsResult = await discoverAndLoadExtensions(extensionPaths, cwd, agentDir, eventBus);
time("discoverExtensionFlags");
}
// Collect all extension flags
const extensionFlags = new Map<string, { type: "boolean" | "string" }>();