chore: remove old unused helpers

This commit is contained in:
Peter Steinberger
2026-05-30 23:13:34 +01:00
parent 2442e9c178
commit 4739f0cfe2
7 changed files with 5 additions and 403 deletions

View File

@@ -1,8 +1,7 @@
import { accessSync, constants, existsSync, readFileSync, realpathSync } from "node:fs";
import { existsSync, readFileSync } from "node:fs";
import { homedir } from "node:os";
import { basename, dirname, join, resolve, sep, win32 } from "node:path";
import { dirname, join, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { spawnProcessSync } from "./utils/child-process.ts";
// =============================================================================
// Package Detection
@@ -20,321 +19,6 @@ export const isBunBinary =
import.meta.url.includes("~BUN") ||
import.meta.url.includes("%7EBUN");
/** Detect if Bun is the runtime (compiled binary or bun run) */
export const isBunRuntime = !!process.versions.bun;
// =============================================================================
// Install Method Detection
// =============================================================================
export type InstallMethod = "bun-binary" | "npm" | "pnpm" | "yarn" | "bun" | "unknown";
interface SelfUpdateCommandStep {
command: string;
args: string[];
display: string;
}
export interface SelfUpdateCommand extends SelfUpdateCommandStep {
steps?: SelfUpdateCommandStep[];
}
function makeSelfUpdateCommand(
installStep: SelfUpdateCommandStep,
uninstallStep?: SelfUpdateCommandStep,
): SelfUpdateCommand {
if (!uninstallStep) {
return installStep;
}
return {
...installStep,
display: `${uninstallStep.display} && ${installStep.display}`,
steps: [uninstallStep, installStep],
};
}
function makeSelfUpdateCommandStep(command: string, args: string[]): SelfUpdateCommandStep {
return {
command,
args,
display: [command, ...args].map((arg) => (/\s/.test(arg) ? `"${arg}"` : arg)).join(" "),
};
}
export function detectInstallMethod(): InstallMethod {
if (isBunBinary) {
return "bun-binary";
}
const resolvedPath = `${currentDir}\0${process.execPath || ""}`.toLowerCase().replace(/\\/g, "/");
if (resolvedPath.includes("/pnpm/") || resolvedPath.includes("/.pnpm/")) {
return "pnpm";
}
if (resolvedPath.includes("/yarn/") || resolvedPath.includes("/.yarn/")) {
return "yarn";
}
if (isBunRuntime || resolvedPath.includes("/install/global/node_modules/")) {
return "bun";
}
if (resolvedPath.includes("/npm/") || resolvedPath.includes("/node_modules/")) {
return "npm";
}
return "unknown";
}
function getInferredNpmInstall(): { root: string; prefix: string } | undefined {
const packageDir = getPackageDir();
const path =
process.platform === "win32" || packageDir.includes("\\") ? win32 : { basename, dirname };
const parent = path.dirname(packageDir);
let root: string | undefined;
if (
path.basename(parent).startsWith("@") &&
path.basename(path.dirname(parent)) === "node_modules"
) {
root = path.dirname(parent);
} else if (path.basename(parent) === "node_modules") {
root = parent;
}
if (!root) {
return undefined;
}
const rootParent = path.dirname(root);
if (path.basename(rootParent) === "lib") {
return { root, prefix: path.dirname(rootParent) };
}
// Windows global npm prefixes use `<prefix>\\node_modules`, which is
// indistinguishable from local project installs by path shape alone. Do not
// infer unsupported Windows custom prefixes without `npm root -g` evidence.
return undefined;
}
function getSelfUpdateCommandForMethod(
method: InstallMethod,
installedPackageName: string,
updatePackageName = installedPackageName,
npmCommand?: string[],
): SelfUpdateCommand | undefined {
switch (method) {
case "bun-binary":
return undefined;
case "pnpm":
return makeSelfUpdateCommand(
makeSelfUpdateCommandStep("pnpm", ["install", "-g", "--ignore-scripts", updatePackageName]),
updatePackageName === installedPackageName
? undefined
: makeSelfUpdateCommandStep("pnpm", ["remove", "-g", installedPackageName]),
);
case "yarn":
return makeSelfUpdateCommand(
makeSelfUpdateCommandStep("yarn", ["global", "add", "--ignore-scripts", updatePackageName]),
updatePackageName === installedPackageName
? undefined
: makeSelfUpdateCommandStep("yarn", ["global", "remove", installedPackageName]),
);
case "bun":
return makeSelfUpdateCommand(
makeSelfUpdateCommandStep("bun", ["install", "-g", "--ignore-scripts", updatePackageName]),
updatePackageName === installedPackageName
? undefined
: makeSelfUpdateCommandStep("bun", ["uninstall", "-g", installedPackageName]),
);
case "npm": {
const [command = "npm", ...npmArgs] = npmCommand ?? [];
const inferred = npmCommand?.length ? undefined : getInferredNpmInstall();
const prefixArgs = [...npmArgs, ...(inferred ? ["--prefix", inferred.prefix] : [])];
const installStep = makeSelfUpdateCommandStep(command, [
...prefixArgs,
"install",
"-g",
"--ignore-scripts",
updatePackageName,
]);
const uninstallStep =
updatePackageName === installedPackageName
? undefined
: makeSelfUpdateCommandStep(command, [
...prefixArgs,
"uninstall",
"-g",
installedPackageName,
]);
return makeSelfUpdateCommand(installStep, uninstallStep);
}
case "unknown":
return undefined;
}
return undefined;
}
function readCommandOutput(
command: string,
args: string[],
options: { requireSuccess?: boolean } = {},
): string | undefined {
const result = spawnProcessSync(command, args, {
encoding: "utf-8",
stdio: ["ignore", "pipe", "pipe"],
});
if (result.status === 0) {
return result.stdout.trim() || undefined;
}
if (options.requireSuccess) {
const reason =
result.error?.message || result.stderr.trim() || `exit code ${result.status ?? "unknown"}`;
throw new Error(`Failed to run ${[command, ...args].join(" ")}: ${reason}`);
}
return undefined;
}
function getGlobalPackageRoots(
method: InstallMethod,
_packageName: string,
npmCommand?: string[],
): string[] {
switch (method) {
case "npm": {
const configured = !!npmCommand?.length;
const [command = "npm", ...npmArgs] = npmCommand ?? [];
if (configured && command === "bun") {
const bunBin = readCommandOutput(command, [...npmArgs, "pm", "bin", "-g"], {
requireSuccess: true,
});
const roots = [join(homedir(), ".bun", "install", "global", "node_modules")];
if (bunBin) {
roots.push(join(dirname(bunBin), "install", "global", "node_modules"));
}
return roots;
}
const root = readCommandOutput(command, [...npmArgs, "root", "-g"], {
requireSuccess: configured,
});
const inferred = configured ? undefined : getInferredNpmInstall();
return [root, inferred?.root].filter((x): x is string => !!x);
}
case "pnpm": {
const root = readCommandOutput("pnpm", ["root", "-g"]);
return root ? [root, dirname(root)] : [];
}
case "yarn": {
const dir = readCommandOutput("yarn", ["global", "dir"]);
return dir ? [dir, join(dir, "node_modules")] : [];
}
case "bun": {
const bunBin = readCommandOutput("bun", ["pm", "bin", "-g"]);
const roots = [join(homedir(), ".bun", "install", "global", "node_modules")];
if (bunBin) {
roots.push(join(dirname(bunBin), "install", "global", "node_modules"));
}
return roots;
}
case "bun-binary":
case "unknown":
return [];
}
return [];
}
function normalizeExistingPathForComparison(
path: string,
resolveSymlinks: boolean,
): string | undefined {
const resolvedPath = resolve(path);
if (!existsSync(resolvedPath)) {
return undefined;
}
let normalizedPath = resolvedPath;
if (resolveSymlinks) {
try {
normalizedPath = realpathSync(resolvedPath);
} catch {
return undefined;
}
}
if (process.platform === "win32") {
normalizedPath = normalizedPath.toLowerCase();
}
return normalizedPath;
}
function getPathComparisonCandidates(path: string): string[] {
return Array.from(
new Set(
[
normalizeExistingPathForComparison(path, false),
normalizeExistingPathForComparison(path, true),
].filter((candidate): candidate is string => !!candidate),
),
);
}
function getEntrypointPackageDir(): string | undefined {
const entrypoint = process.argv[1];
if (!entrypoint) {
return undefined;
}
let dir = dirname(entrypoint);
while (dir !== dirname(dir)) {
if (existsSync(join(dir, "package.json"))) {
return dir;
}
dir = dirname(dir);
}
return undefined;
}
function isSelfUpdatePathWritable(): boolean {
const packageDir = getPackageDir();
try {
accessSync(packageDir, constants.W_OK);
accessSync(dirname(packageDir), constants.W_OK);
return true;
} catch {
return false;
}
}
function isManagedByGlobalPackageManager(
method: InstallMethod,
packageName: string,
npmCommand?: string[],
): boolean {
const packageDirs = [getPackageDir(), getEntrypointPackageDir()].filter(
(dir): dir is string => !!dir,
);
const packageDirCandidates = packageDirs.flatMap((dir) => getPathComparisonCandidates(dir));
return getGlobalPackageRoots(method, packageName, npmCommand).some((root) => {
return getPathComparisonCandidates(root).some((normalizedRoot) => {
const rootPrefix = normalizedRoot.endsWith(sep) ? normalizedRoot : `${normalizedRoot}${sep}`;
return packageDirCandidates.some((packageDir) => packageDir.startsWith(rootPrefix));
});
});
}
export function getSelfUpdateUnavailableInstruction(
packageName: string,
npmCommand?: string[],
updatePackageName = packageName,
): string {
const method = detectInstallMethod();
if (method === "bun-binary") {
return `Download from: https://github.com/openclaw/openclaw/releases/latest`;
}
const command = getSelfUpdateCommandForMethod(method, packageName, updatePackageName, npmCommand);
if (command) {
if (
isManagedByGlobalPackageManager(method, packageName, npmCommand) &&
!isSelfUpdatePathWritable()
) {
return `This installation is managed by a global ${method} install, but the install path is not writable. Update it yourself with: ${command.display}`;
}
return `This installation is not managed by a global ${method} install. Update it with the package manager, wrapper, or source checkout that provides it.`;
}
return `Update ${updatePackageName} using the package manager, wrapper, or source checkout that provides this installation.`;
}
// =============================================================================
// Package Asset Paths (shipped with executable)
// =============================================================================

View File

@@ -1,14 +1,4 @@
export {
bashExecutionToText,
BRANCH_SUMMARY_PREFIX,
BRANCH_SUMMARY_SUFFIX,
COMPACTION_SUMMARY_PREFIX,
COMPACTION_SUMMARY_SUFFIX,
convertToLlm,
createBranchSummaryMessage,
createCompactionSummaryMessage,
createCustomMessage,
} from "../../../packages/agent-core/src/harness/messages.js";
export { convertToLlm } from "../../../packages/agent-core/src/harness/messages.js";
export type {
BashExecutionMessage,

View File

@@ -114,25 +114,6 @@ export function resolveConfigValueOrThrow(config: string, description: string):
throw new Error(`Failed to resolve ${description}`);
}
/**
* Resolve all header values using the same resolution logic as API keys.
*/
export function resolveHeaders(
headers: Record<string, string> | undefined,
): Record<string, string> | undefined {
if (!headers) {
return undefined;
}
const resolved: Record<string, string> = {};
for (const [key, value] of Object.entries(headers)) {
const resolvedValue = resolveConfigValue(value);
if (resolvedValue) {
resolved[key] = resolvedValue;
}
}
return Object.keys(resolved).length > 0 ? resolved : undefined;
}
export function resolveHeadersOrThrow(
headers: Record<string, string> | undefined,
description: string,

View File

@@ -22,7 +22,6 @@ import { DefaultResourceLoader } from "./resource-loader.js";
import { getDefaultSessionDir, SessionManager } from "./session-manager.js";
import { SettingsManager } from "./settings-manager.js";
import { isInstallTelemetryEnabled } from "./telemetry.js";
import { time } from "./timings.js";
import {
createBashTool,
createCodingTools,
@@ -218,7 +217,6 @@ export async function createAgentSession(
if (!resourceLoader) {
resourceLoader = new DefaultResourceLoader({ cwd, agentDir, settingsManager });
await resourceLoader.reload();
time("resourceLoader.reload");
}
// Check if session has existing data to restore

View File

@@ -1,37 +0,0 @@
/**
* Central timing instrumentation for startup profiling.
* Enable with OPENCLAW_TIMING=1 environment variable.
*/
const ENABLED = process.env.OPENCLAW_TIMING === "1";
const timings: Array<{ label: string; ms: number }> = [];
let lastTime = Date.now();
export function resetTimings(): void {
if (!ENABLED) {
return;
}
timings.length = 0;
lastTime = Date.now();
}
export function time(label: string): void {
if (!ENABLED) {
return;
}
const now = Date.now();
timings.push({ label, ms: now - lastTime });
lastTime = now;
}
export function printTimings(): void {
if (!ENABLED || timings.length === 0) {
return;
}
console.error("\n--- Startup Timings ---");
for (const t of timings) {
console.error(` ${t.label}: ${t.ms}ms`);
}
console.error(` TOTAL: ${timings.reduce((a, b) => a + b.ms, 0)}ms`);
console.error("------------------------\n");
}

View File

@@ -2,11 +2,8 @@ import {
type ChildProcess,
type ChildProcessByStdio,
spawn as nodeSpawn,
spawnSync as nodeSpawnSync,
type SpawnOptions,
type SpawnOptionsWithStdioTuple,
type SpawnSyncOptionsWithStringEncoding,
type SpawnSyncReturns,
type StdioNull,
type StdioPipe,
} from "node:child_process";
@@ -27,16 +24,6 @@ export function spawnProcess(command: string, args: string[], options: SpawnOpti
: nodeSpawn(command, args, options);
}
export function spawnProcessSync(
command: string,
args: string[],
options: SpawnSyncOptionsWithStringEncoding,
): SpawnSyncReturns<string> {
return process.platform === "win32"
? crossSpawn.sync(command, args, options)
: nodeSpawnSync(command, args, options);
}
/**
* Wait for a child process to terminate without hanging on inherited stdio handles.
*

View File

@@ -1,10 +1,9 @@
import "./fs-safe-defaults.js";
import fs from "node:fs";
import path from "node:path";
import { tryReadJsonSync, tryReadJson, writeJsonSync } from "@openclaw/fs-safe/json";
import { tryReadJsonSync, writeJsonSync } from "@openclaw/fs-safe/json";
export { tryReadJson, tryReadJsonSync, writeJsonSync };
export const readJsonFile = tryReadJson;
export { tryReadJsonSync, writeJsonSync };
function resolveJsonSymlinkTarget(pathname: string): string | undefined {
let stat: fs.Stats;