mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-23 05:31:11 +00:00
* refactor(browser): collapse Playwright export paths * refactor(browser): remove dead plugin exports * refactor(codex): remove dead app-server exports * refactor(codex): remove remaining dead exports * test(codex): use canonical private-type owners * test(browser): isolate proxy startup state * test(browser): remove stale chrome imports * refactor(codex): privatize remaining helpers * chore(deadcode): refresh export baseline after rebase * refactor(browser): finish canonical helper ownership * refactor: fix dead-export cleanup gates * refactor(codex): keep runtime facades LOC-neutral * chore(ci): refresh TypeScript LOC baseline * chore(deadcode): refresh ratchets after rebase * chore(ci): refresh LOC baseline after main advance * chore(deadcode): align ratchets with latest main
158 lines
5.6 KiB
TypeScript
158 lines
5.6 KiB
TypeScript
/**
|
|
* Builds stable Codex plugin/app inventory cache keys from app-server startup,
|
|
* auth, account, and version inputs without storing secret material.
|
|
*/
|
|
import { createHash } from "node:crypto";
|
|
import { createRequire } from "node:module";
|
|
import { OPENCLAW_VERSION } from "openclaw/plugin-sdk/agent-harness-runtime";
|
|
import { readPluginPackageVersion } from "openclaw/plugin-sdk/extension-shared";
|
|
import {
|
|
buildCodexAppInventoryCacheKey,
|
|
type CodexAppInventoryCacheKeyInput,
|
|
} from "./app-inventory-cache.js";
|
|
import { resolveCodexAppServerHomeDir } from "./auth-bridge.js";
|
|
import type { CodexAppServerRuntimeIdentity } from "./client.js";
|
|
import {
|
|
resolveCodexAppServerUserHomeDir,
|
|
type CodexAppServerRuntimeOptions,
|
|
type CodexAppServerStartOptions,
|
|
} from "./config.js";
|
|
|
|
const require = createRequire(import.meta.url);
|
|
const CODEX_PLUGIN_VERSION = readPluginPackageVersion({ require });
|
|
|
|
/** Inputs that identify the Codex app inventory cache scope for one runtime. */
|
|
type CodexPluginAppCacheKeyParams = Omit<
|
|
CodexAppInventoryCacheKeyInput,
|
|
"codexHome" | "endpoint"
|
|
> & {
|
|
appServer: Pick<CodexAppServerRuntimeOptions, "start">;
|
|
agentDir?: string;
|
|
runtimeIdentity?: CodexAppServerRuntimeIdentity;
|
|
};
|
|
|
|
/** Builds the full app inventory cache key for Codex plugin/app discovery. */
|
|
export function buildCodexPluginAppCacheKey(params: CodexPluginAppCacheKeyParams): string {
|
|
return buildCodexAppInventoryCacheKey(
|
|
{
|
|
codexHome:
|
|
params.runtimeIdentity?.codexHome ??
|
|
resolveCodexPluginAppCacheCodexHome(params.appServer, params.agentDir),
|
|
endpoint: resolveCodexPluginAppCacheEndpoint(params.appServer),
|
|
authProfileId: params.authProfileId,
|
|
accountId: params.accountId,
|
|
envApiKeyFingerprint: params.envApiKeyFingerprint,
|
|
appServerVersion: params.appServerVersion ?? params.runtimeIdentity?.serverVersion,
|
|
runtimeIdentity: params.runtimeIdentity,
|
|
},
|
|
OPENCLAW_VERSION,
|
|
CODEX_PLUGIN_VERSION,
|
|
);
|
|
}
|
|
|
|
/** Builds a durable thread-binding fingerprint for one initialized app-server runtime. */
|
|
export function buildCodexAppServerRuntimeFingerprint(params: {
|
|
appServer: Pick<
|
|
CodexAppServerRuntimeOptions,
|
|
"start" | "connectionClass" | "remoteWorkspaceRoot"
|
|
>;
|
|
appServerVersion?: string;
|
|
runtimeIdentity?: CodexAppServerRuntimeIdentity;
|
|
}): string {
|
|
return JSON.stringify({
|
|
endpoint: resolveCodexPluginAppCacheEndpoint(params.appServer),
|
|
connectionClass: params.appServer.connectionClass,
|
|
remoteWorkspaceRoot: params.appServer.remoteWorkspaceRoot ?? null,
|
|
appServerVersion: params.appServerVersion ?? params.runtimeIdentity?.serverVersion ?? null,
|
|
runtimeIdentity: params.runtimeIdentity ?? null,
|
|
});
|
|
}
|
|
|
|
/** Fingerprints the configured connection that owns a supervised source thread. */
|
|
export function buildCodexAppServerConnectionFingerprint(
|
|
appServer: Pick<
|
|
CodexAppServerRuntimeOptions,
|
|
"start" | "connectionClass" | "remoteWorkspaceRoot"
|
|
>,
|
|
agentDir?: string,
|
|
): string {
|
|
return JSON.stringify({
|
|
endpoint: resolveCodexPluginAppCacheEndpoint(appServer),
|
|
connectionClass: appServer.connectionClass,
|
|
remoteWorkspaceRoot: appServer.remoteWorkspaceRoot ?? null,
|
|
homeScope: appServer.start.homeScope ?? null,
|
|
codexHome: resolveCodexAppServerConnectionHome(appServer.start, agentDir),
|
|
cwd: appServer.start.cwd ?? null,
|
|
});
|
|
}
|
|
|
|
function resolveCodexAppServerConnectionHome(
|
|
start: CodexAppServerStartOptions,
|
|
agentDir?: string,
|
|
): string | null {
|
|
const configured = start.env?.CODEX_HOME?.trim();
|
|
if (configured) {
|
|
return configured;
|
|
}
|
|
if (start.transport === "unix" && (!start.url || start.url === "unix://")) {
|
|
return resolveCodexAppServerUserHomeDir(start.env ?? process.env);
|
|
}
|
|
if (start.transport !== "stdio") {
|
|
return null;
|
|
}
|
|
if (start.homeScope === "user") {
|
|
return resolveCodexAppServerUserHomeDir(process.env);
|
|
}
|
|
return agentDir ? resolveCodexAppServerHomeDir(agentDir) : null;
|
|
}
|
|
|
|
/** Serializes app-server endpoint identity, including credential fingerprints. */
|
|
function resolveCodexPluginAppCacheEndpoint(
|
|
appServer: Pick<CodexAppServerRuntimeOptions, "start">,
|
|
): string {
|
|
return JSON.stringify({
|
|
transport: appServer.start.transport,
|
|
command: appServer.start.command,
|
|
args: appServer.start.args,
|
|
url: appServer.start.url ?? null,
|
|
credentialFingerprint: fingerprintCodexPluginAppCacheCredentials(appServer.start),
|
|
});
|
|
}
|
|
|
|
/** Resolves the CODEX_HOME value that scopes local app-server inventory. */
|
|
function resolveCodexPluginAppCacheCodexHome(
|
|
appServer: Pick<CodexAppServerRuntimeOptions, "start">,
|
|
agentDir?: string,
|
|
): string | undefined {
|
|
const configuredCodexHome = appServer.start.env?.CODEX_HOME?.trim();
|
|
if (configuredCodexHome) {
|
|
return configuredCodexHome;
|
|
}
|
|
return appServer.start.transport === "stdio" && agentDir
|
|
? resolveCodexAppServerHomeDir(agentDir)
|
|
: undefined;
|
|
}
|
|
|
|
function fingerprintCodexPluginAppCacheCredentials(
|
|
startOptions: CodexAppServerStartOptions,
|
|
): string | null {
|
|
const authToken = startOptions.authToken ?? "";
|
|
const headers = Object.entries(startOptions.headers)
|
|
.map(([key, value]) => [key.toLowerCase(), value] as const)
|
|
.toSorted(([left], [right]) => left.localeCompare(right));
|
|
if (!authToken && headers.length === 0) {
|
|
return null;
|
|
}
|
|
const hash = createHash("sha256");
|
|
hash.update("openclaw:codex:plugin-app-cache-credentials:v1");
|
|
hash.update("\0");
|
|
hash.update(authToken);
|
|
for (const [key, value] of headers) {
|
|
hash.update("\0");
|
|
hash.update(key);
|
|
hash.update("\0");
|
|
hash.update(value);
|
|
}
|
|
return `sha256:${hash.digest("hex")}`;
|
|
}
|