can1357/oh-my-pi · error · Error
project-scoped install requires running inside a project dir
Error message
project-scoped install requires running inside a project directory
What it means
MarketplaceManager.#registryPath() returns the file path of the installed-plugins registry for a scope. For the "project" scope it relies on the projectInstalledRegistryPath option, which is only provided when the manager was constructed inside a recognizable project directory. When that option is absent, any project-scoped operation throws this error.
Source
Thrown at packages/coding-agent/src/extensibility/plugins/marketplace/manager.ts:870
const config = await this.#loadRuntimeConfig(scope);
delete config.plugins[packageName];
delete config.settings[packageName];
await this.#writeRuntimeConfig(scope, config);
}
async #setRuntimePluginEnabled(scope: "user" | "project", packageName: string, enabled: boolean): Promise<void> {
const config = await this.#loadRuntimeConfig(scope);
const previous = config.plugins[packageName];
if (!previous) return;
config.plugins[packageName] = { ...previous, enabled };
await this.#writeRuntimeConfig(scope, config);
}
#registryPath(scope: "user" | "project"): string {
if (scope === "project") {
if (!this.#opts.projectInstalledRegistryPath) {
throw new Error("project-scoped install requires running inside a project directory");
}
return this.#opts.projectInstalledRegistryPath;
}
return this.#opts.installedRegistryPath;
}
async #findInBothRegistries(pluginId: string): Promise<{
userEntries: InstalledPluginEntry[] | undefined;
projectEntries: InstalledPluginEntry[] | undefined;
userReg: InstalledPluginsRegistry;
projectReg: InstalledPluginsRegistry;
}> {
const [userReg, projectReg] = await Promise.all([
readInstalledPluginsRegistry(this.#opts.installedRegistryPath),
this.#opts.projectInstalledRegistryPath
? readInstalledPluginsRegistry(this.#opts.projectInstalledRegistryPath)
: Promise.resolve({ version: 2 as const, plugins: {} as Record<string, InstalledPluginEntry[]> }),
]);View on GitHub (pinned to 9690622007)
Solutions
- cd into a project directory (one that yields a project registry path) and retry
- Use user scope instead: {scope: "user"}
- If embedding the manager, pass projectInstalledRegistryPath in the constructor options
Example fix
// before
await manager.installPlugin("myplugin", "community", { scope: "project" }); // run in ~/
// after
cd ~/my-project # or:
await manager.installPlugin("myplugin", "community", { scope: "user" }); Defensive patterns
Strategy: fallback
Validate before calling
// ensure a project registry path is available before project-scope ops const inProject = Boolean(projectRoot && projectInstalledRegistryPath); const scope = inProject ? 'project' : 'user';
Type guard
null
Try / catch
try {
await manager.installPlugin(name, marketplace, { scope: 'project' });
} catch (err) {
if (err.message.includes('requires running inside a project directory')) {
await manager.installPlugin(name, marketplace, { scope: 'user' });
} else throw err;
} Prevention
- cd into the project root before project-scoped installs
- Pass projectInstalledRegistryPath when constructing the manager in embedded/SDK contexts
- Default scripts to user scope when project context is uncertain
- Detect project root (git root / config file) before choosing scope
When it happens
Trigger: Calling installPlugin(name, marketplace, {scope:"project"}), uninstall with project scope, or any code path that resolves the project registry while the manager was constructed without a project directory (e.g. in a home directory, tmp, or SDK embedding without projectInstalledRegistryPath).
Common situations: Running a project-scoped install from outside a git/project root; CI jobs executing in a bare workspace without project detection; embedding the MarketplaceManager programmatically without passing projectInstalledRegistryPath.
Related errors
- Path "${filePath}" uses internal scheme "local://" and must
- No model configured
- Azure OpenAI base URL is required. Set AZURE_OPENAI_BASE_URL
- Cannot register custom API "${api}": built-in API names are
- Unable to read OMP_AUTH_BROKER_ACCOUNT_POOL_FILE at ${filePa
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/f3841fe1b6d08979.
Report an issue: GitHub.