jackwener/OpenCLI · error
Unable to determine remote source for plugin at ${dir}
Error message
Unable to determine remote source for plugin at ${dir} What it means
resolveRemotePluginSource determines the remote git URL for an installed plugin from its lock entry or the plugin dir's git remote origin config. It throws a plain Error when the resolved source is missing or is of kind 'local', because a remote update (clone) cannot be performed for a locally-symlinked plugin. This guards updatePlugin's non-local branch.
Source
Thrown at src/plugin.ts:257
throw new PluginError(`Failed to clone plugin: ${getErrorMessage(err)}`, 'Check the repository URL and your network connection.');
}
return tmpCloneDir;
}
function withTempClone<T>(cloneUrl: string, work: (cloneDir: string) => T): T {
const tmpCloneDir = cloneRepoToTemp(cloneUrl);
try {
return work(tmpCloneDir);
} finally {
try { fs.rmSync(tmpCloneDir, { recursive: true, force: true }); } catch {}
}
}
function resolveRemotePluginSource(lockEntry: LockEntry | undefined, dir: string): string {
const source = resolvePluginSource(lockEntry, dir);
if (!source || source.kind === 'local') {
throw new Error(`Unable to determine remote source for plugin at ${dir}`);
}
return source.url;
}
function pathExistsSync(p: string): boolean {
try {
fs.lstatSync(p);
return true;
} catch {
return false;
}
}
function resolveRepoContainedPath(repoRoot: string, subPath: string): string {
const resolved = path.resolve(repoRoot, subPath);
if (!resolved.startsWith(repoRoot + path.sep) && resolved !== repoRoot) {
throw new PluginError(`Plugin path "${subPath}" escapes repo root.`);
}View on GitHub (pinned to 49907e53dc)
Solutions
- Check ~/.opencli/plugins.lock.json: ensure the plugin entry has a valid source (git or monorepo) with a url.
- If the plugin is local-source, do not run remote update — reinstall/update via the local path.
- Fix the git remote in the install dir (`git remote set-url origin <url>`) so getPluginSource can resolve it.
- As a last resort, uninstall and reinstall the plugin from its remote source to regenerate the lock entry.
Example fix
// before (lock entry missing source)
{ "myplugin": { "commitHash": "abc", "installedAt": "..." } }
// after
{ "myplugin": { "source": { "kind": "git", "url": "https://github.com/user/repo.git" }, "commitHash": "abc", "installedAt": "..." } } Defensive patterns
Strategy: validation
Validate before calling
import * as fs from 'node:fs';
const lock = JSON.parse(fs.readFileSync(lockPath, 'utf-8'));
const entry = lock[pluginName];
if (!entry?.source || entry.source.kind === 'local') {
// cannot remote-update; reinstall or update locally instead
} Type guard
function hasRemoteSource(entry) {
return !!entry && typeof entry === 'object'
&& entry.source != null
&& (entry.source.kind === 'git' || entry.source.kind === 'monorepo')
&& typeof entry.source.url === 'string';
} Try / catch
try {
updatePlugin(name);
} catch (err) {
if (err.message.startsWith('Unable to determine remote source')) {
// fall back to reinstalling from a known remote source
} else throw err;
} Prevention
- Don't hand-edit ~/.opencli/plugins.lock.json; use opencli commands.
- After restoring backups or dotfiles, verify lock entries still carry valid source records.
- Run `opencli plugin list` to confirm sources resolve before scripting updates.
When it happens
Trigger: updatePlugin(name) on a plugin whose lock entry in ~/.opencli/plugins.lock.json is absent/corrupt and whose directory has no git remote (e.g. installed from a local path via 'local:' or file:// source but reached this branch), or a normalized-but-local source record.
Common situations: Manually edited or hand-pruned lock file; plugin installed from a local directory symlink but the local branch was bypassed; lock file written by an older opencli version lacking a valid source field.
Related errors
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/0e7847ebfe074667.
Report an issue: GitHub.