fix(omo-codex): reuse shared lsp mcp
This commit is contained in:
@@ -28,6 +28,17 @@ export async function pruneMarketplaceCache({ codexHome, marketplaceName, keepPl
|
||||
}
|
||||
}
|
||||
|
||||
export async function pruneMarketplacePluginCaches({ codexHome, marketplaceName, pluginNames }) {
|
||||
const cacheRoot = join(codexHome, "plugins", "cache", marketplaceName);
|
||||
if (!(await exists(cacheRoot))) return;
|
||||
for (const pluginName of pluginNames) {
|
||||
await rm(join(cacheRoot, pluginName), { recursive: true, force: true });
|
||||
}
|
||||
if ((await readdir(cacheRoot)).length === 0) {
|
||||
await rm(cacheRoot, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
export async function linkCachedPluginBins({ binDir, pluginRoot, platform = process.platform }) {
|
||||
const binLinks = await discoverPackageBins(pluginRoot);
|
||||
await mkdir(binDir, { recursive: true });
|
||||
|
||||
@@ -8,6 +8,7 @@ const LAZYCODEX_MARKETPLACE_SOURCE = {
|
||||
source: "https://github.com/code-yeongyu/lazycodex.git",
|
||||
ref: "main",
|
||||
};
|
||||
const SISYPHUS_LEGACY_MARKETPLACES = ["lazycodex", "code-yeongyu-codex-plugins"];
|
||||
|
||||
export async function updateCodexConfig({
|
||||
configPath,
|
||||
@@ -21,6 +22,11 @@ export async function updateCodexConfig({
|
||||
let config = "";
|
||||
if (await exists(configPath)) config = await readFile(configPath, "utf8");
|
||||
|
||||
for (const legacyMarketplaceName of legacyMarketplaceNames(marketplaceName)) {
|
||||
config = removeMarketplaceBlock(config, legacyMarketplaceName);
|
||||
config = removeStaleMarketplacePluginBlocks(config, legacyMarketplaceName, new Set());
|
||||
config = removeStaleMarketplaceHookStateBlocks(config, legacyMarketplaceName, new Set());
|
||||
}
|
||||
config = removeStaleMarketplacePluginBlocks(config, marketplaceName, new Set(pluginNames));
|
||||
config = removeStaleMarketplaceHookStateBlocks(config, marketplaceName, new Set(pluginNames));
|
||||
config = ensureFeatureEnabled(config, "plugins");
|
||||
@@ -36,6 +42,14 @@ export async function updateCodexConfig({
|
||||
await writeFile(configPath, config.trimEnd() + "\n");
|
||||
}
|
||||
|
||||
function legacyMarketplaceNames(marketplaceName) {
|
||||
return marketplaceName === "sisyphuslabs" ? SISYPHUS_LEGACY_MARKETPLACES : [];
|
||||
}
|
||||
|
||||
function removeMarketplaceBlock(config, marketplaceName) {
|
||||
return removeTomlSections(config, (header) => header === `marketplaces.${marketplaceName}`);
|
||||
}
|
||||
|
||||
function defaultMarketplaceSource(marketplaceName, repoRoot) {
|
||||
if (marketplaceName === "sisyphuslabs") return LAZYCODEX_MARKETPLACE_SOURCE;
|
||||
return {
|
||||
@@ -46,7 +60,7 @@ function defaultMarketplaceSource(marketplaceName, repoRoot) {
|
||||
|
||||
function removeStaleMarketplacePluginBlocks(config, marketplaceName, keepPluginNames) {
|
||||
return removeTomlSections(config, (header) => {
|
||||
const pluginKey = parseQuotedPluginHeader(header);
|
||||
const pluginKey = parsePluginHeaderKey(header);
|
||||
if (pluginKey === null) return false;
|
||||
const suffix = `@${marketplaceName}`;
|
||||
if (!pluginKey.endsWith(suffix)) return false;
|
||||
@@ -170,10 +184,28 @@ function parseTomlHeader(line) {
|
||||
return trimmed.slice(1, -1);
|
||||
}
|
||||
|
||||
function parseQuotedPluginHeader(header) {
|
||||
function parsePluginHeaderKey(header) {
|
||||
const prefix = "plugins.";
|
||||
if (!header.startsWith(prefix)) return null;
|
||||
return parseJsonString(header.slice(prefix.length));
|
||||
return parseLeadingJsonString(header.slice(prefix.length));
|
||||
}
|
||||
|
||||
function parseLeadingJsonString(value) {
|
||||
if (!value.startsWith('"')) return parseJsonString(value);
|
||||
let escaped = false;
|
||||
for (let index = 1; index < value.length; index += 1) {
|
||||
const char = value[index];
|
||||
if (escaped) {
|
||||
escaped = false;
|
||||
continue;
|
||||
}
|
||||
if (char === "\\") {
|
||||
escaped = true;
|
||||
continue;
|
||||
}
|
||||
if (char === '"') return parseJsonString(value.slice(0, index + 1));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function parseJsonString(value) {
|
||||
|
||||
@@ -3,10 +3,10 @@ import { join } from "node:path";
|
||||
|
||||
import { isRecord } from "./utils.mjs";
|
||||
|
||||
const MARKETPLACE_PATH = ".agents/plugins/marketplace.json";
|
||||
const DEFAULT_MARKETPLACE_PATH = "packages/omo-codex/marketplace.json";
|
||||
|
||||
export async function readMarketplace(repoRoot) {
|
||||
const marketplacePath = join(repoRoot, MARKETPLACE_PATH);
|
||||
export async function readMarketplace(repoRoot, options = {}) {
|
||||
const marketplacePath = options.marketplacePath ?? join(repoRoot, DEFAULT_MARKETPLACE_PATH);
|
||||
const raw = await readFile(marketplacePath, "utf8");
|
||||
const parsed = JSON.parse(raw);
|
||||
if (!isRecord(parsed)) throw new Error("marketplace.json must be an object");
|
||||
@@ -22,10 +22,10 @@ export async function readMarketplace(repoRoot) {
|
||||
};
|
||||
}
|
||||
|
||||
export function resolvePluginSource(repoRoot, plugin) {
|
||||
const sourcePath = localSourcePath(plugin.source);
|
||||
export function resolvePluginSource(marketplaceRoot, plugin, options = {}) {
|
||||
const sourcePath = localSourcePath(options.pathOverride ?? plugin.source);
|
||||
const relativePath = sourcePath.slice(2);
|
||||
return join(repoRoot, ...relativePath.split(/[\\/]/));
|
||||
return join(marketplaceRoot, ...relativePath.split(/[\\/]/));
|
||||
}
|
||||
|
||||
export async function readPluginManifest(pluginRoot) {
|
||||
@@ -60,10 +60,21 @@ function normalizeMarketplacePlugin(plugin, index) {
|
||||
throw new Error(`marketplace plugin ${index} name must be a non-empty string`);
|
||||
}
|
||||
validatePathSegment(plugin.name, "plugin name");
|
||||
return {
|
||||
name: plugin.name,
|
||||
source: plugin.source,
|
||||
};
|
||||
if (plugin.source === undefined || typeof plugin.source === "string") {
|
||||
if (typeof plugin.source === "string") validateLocalSourcePath(plugin.source);
|
||||
return {
|
||||
name: plugin.name,
|
||||
source: plugin.source,
|
||||
};
|
||||
}
|
||||
if (isRecord(plugin.source) && plugin.source.source === "local" && typeof plugin.source.path === "string") {
|
||||
validateLocalSourcePath(plugin.source.path);
|
||||
return {
|
||||
name: plugin.name,
|
||||
source: { source: "local", path: plugin.source.path },
|
||||
};
|
||||
}
|
||||
throw new Error("local plugin source must be a string path or { source: \"local\", path } object");
|
||||
}
|
||||
|
||||
function localSourcePath(source) {
|
||||
|
||||
Reference in New Issue
Block a user