jackwener/OpenCLI · error

Updated source is now a monorepo: ${cloneUrl}

Error message

Updated source is now a monorepo: ${cloneUrl}

What it means

During updatePlugin() of a standalone (non-monorepo) plugin, the library re-clones the source and checks the manifest. If the updated source has become a monorepo (manifest exists and isMonorepo is true), the standalone update path cannot handle it, so it throws. This detects upstream conversions from standalone plugin to monorepo layout.

Source

Thrown at src/plugin.ts:1167

      publishMonorepoPlugins(
        monoDir,
        PLUGINS_DIR,
        updatedPlugins.map((plugin) => ({ name: plugin.name, subPath: plugin.manifestEntry.path })),
        { stagingDir: tmpCloneDir, parentDir: path.dirname(monoDir) },
        (commitHash) => {
          updateMonorepoLockEntries(lock, updatedPlugins, cloneUrl, monoName, commitHash);
          writeLockFile(lock);
        },
      );
    });
    return;
  }

  const cloneUrl = resolveRemotePluginSource(lockEntry, targetDir);
  withTempClone(cloneUrl, (tmpCloneDir) => {
    const manifest = readPluginManifest(tmpCloneDir);
    if (manifest && isMonorepo(manifest)) {
      throw new Error(`Updated source is now a monorepo: ${cloneUrl}`);
    }

    if (manifest?.opencli && !checkCompatibility(manifest.opencli)) {
      throw new Error(
        `Plugin requires opencli ${manifest.opencli}, but current version is incompatible.`
      );
    }

    ensureStandalonePluginReady(tmpCloneDir);
    publishStandalonePlugin(tmpCloneDir, targetDir, (commitHash) => {
      updateStandaloneLockEntry(lock, name, cloneUrl, lock[name], commitHash);
      if (commitHash) {
        writeLockFile(lock);
      }
    });
  });
}

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Uninstall the standalone plugin and reinstall it as a monorepo sub-plugin from the new source (monorepo install flow).
  2. Point the lock entry at a commit/tag/branch where the repo is still standalone if you must stay on the old layout.
  3. Ask upstream for the new sub-plugin name(s) and install those instead.
  4. Verify the manifest at cloneUrl to confirm the conversion before migrating.
Defensive patterns

Strategy: try-catch

Validate before calling

// Peek at the upstream manifest before updating a standalone plugin:
// withTempClone(lockEntry.url, (tmp) => {
//   const m = readPluginManifest(tmp);
//   if (m && isMonorepo(m)) migrateToMonorepoInstall();
//   else updatePlugin(name);
// });

Try / catch

try {
  updatePlugin(name);
} catch (e) {
  if (e instanceof Error && e.message.startsWith("Updated source is now a monorepo:")) {
    // uninstall standalone plugin; install corresponding sub-plugin from the monorepo
  } else throw e;
}

Prevention

When it happens

Trigger: updatePlugin on a plugin whose lock entry resolves to a standalone git source, where the freshly cloned repo at cloneUrl now has a monorepo manifest (isMonorepo(manifest) true) — e.g. upstream converted the repo into a multi-plugin monorepo.

Common situations: Upstream merged the standalone plugin into a monorepo with sub-plugins; user's lock entry still points at the old standalone repo URL; branch/tag drift where default branch changed structure.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/7802e201acbdb129. Report an issue: GitHub.