openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
1,349 lines • 55 kB
JavaScript
import { r as isMissingPathError, t as hasErrnoCode } from "./errno-jiy5vtf-.mjs";
import { E as asOptionalObjectRecord, T as asNullableRecord, _ as normalizeLowercaseStringOrEmpty, b as normalizeOptionalString, w as resolveGlobalSingleton } from "./number-coercion-PJEgwXYS.mjs";
import { o as normalizeWindowsPathPreservingCase } from "./utils-Bv29YgC5.mjs";
import { $ as pruneMapToMaxSize } from "./redact-DO6ydQMZ.mjs";
import "./errors-Qhjprk1B.mjs";
import { t as LruCache } from "./lru-cache-C3Xgvc4Q.mjs";
import "./detached-async-context-DFi5_D5X.mjs";
import { t as createDeferredCore } from "./deferred-D0La5CRk.mjs";
import { n as registerListener } from "./listeners-BogSNJ-R.mjs";
import { createRequire } from "node:module";
import fsSync, { realpathSync, statSync, default as openClawRootFsSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { readFileDescriptorBoundedSync, readFileWindowFullySync } from "@openclaw/fs-safe/advanced";
import { AsyncLocalStorage } from "node:async_hooks";
import "@openclaw/fs-safe/path";
import { isUtf8 } from "node:buffer";
import { realpath, stat } from "node:fs/promises";
//#region src/infra/sqlite-error-diagnostics.ts
const inspectionOperations = resolveGlobalSingleton(Symbol.for("openclaw.sqliteInspectionOperations"), () => /* @__PURE__ */ new WeakMap());
const nativeOpenFailures = resolveGlobalSingleton(Symbol.for("openclaw.sqliteNativeOpenFailures"), () => /* @__PURE__ */ new WeakSet());
function markSqliteNativeOpenFailure(error) {
if (error !== null && typeof error === "object") nativeOpenFailures.add(error);
}
/** Record the native effect without changing its error or tagging surrounding authority checks. */
function withSqliteNativeOpen(open) {
try {
return open();
} catch (error) {
markSqliteNativeOpenFailure(error);
throw error;
}
}
function isSqliteNativeOpenFailure(error) {
return error !== null && typeof error === "object" && nativeOpenFailures.has(error);
}
function markSqliteInspectionOperation(error, operation) {
if (error !== null && typeof error === "object" && !inspectionOperations.has(error)) inspectionOperations.set(error, operation);
return error;
}
const SQLITE_LOCK_ERROR_CODES = /* @__PURE__ */ new Set(["SQLITE_BUSY", "SQLITE_LOCKED"]);
const SQLITE_BUSY_RESULT_CODE = 5;
const SQLITE_LOCKED_RESULT_CODE = 6;
const SQLITE_CORRUPT_RESULT_CODE = 11;
const SQLITE_NOTADB_RESULT_CODE = 26;
const SQLITE_PRIMARY_RESULT_CODE_MASK = 255;
function sqliteErrorCode(error) {
const code = asOptionalObjectRecord(error)?.code;
return typeof code === "string" ? code : void 0;
}
function sqliteExtendedResultCode(error) {
const errcode = asOptionalObjectRecord(error)?.errcode;
return typeof errcode === "number" && Number.isInteger(errcode) ? errcode : void 0;
}
function sqlitePrimaryResultCode(error) {
const errcode = sqliteExtendedResultCode(error);
return errcode === void 0 ? void 0 : errcode & SQLITE_PRIMARY_RESULT_CODE_MASK;
}
function isSqliteLockError(error) {
const code = sqliteErrorCode(error);
if (code !== void 0 && SQLITE_LOCK_ERROR_CODES.has(code)) return true;
const primaryCode = sqlitePrimaryResultCode(error);
return primaryCode === SQLITE_BUSY_RESULT_CODE || primaryCode === SQLITE_LOCKED_RESULT_CODE;
}
/** Report proven file damage (corrupt page or non-database header), not transient failure. */
function isSqliteCorruptionError(error) {
const primaryCode = sqlitePrimaryResultCode(error);
return primaryCode === SQLITE_CORRUPT_RESULT_CODE || primaryCode === SQLITE_NOTADB_RESULT_CODE;
}
//#endregion
//#region src/state/openclaw-state-db-contract.ts
const DOCTOR_OWNED_STATE_TABLES = ["agent_deletion_journal"];
const FIRST_USE_STATE_TABLES = [
"user_profile_identities",
"local_workspace_projections",
"update_runs",
"session_repository_workspaces",
"github_repository_publication_requests",
"github_publication_session_lifecycles",
"skill_library_entries",
"skill_library_revisions",
"skill_library_events",
"skill_library_uploads",
"github_personal_publication_requests",
"cron_job_runtime_authorities",
"cron_run_trigger_state_retirements",
"execution_identity_contexts",
"mcp_oauth_pending_authorizations",
"node_worker_launch_containers",
"node_worker_launch_boots",
"node_worker_launch_cleanup",
"node_worker_launch_process_scopes",
"node_worker_launches",
"node_worker_prepared_workspaces",
"node_worker_turns",
"operator_approval_execution_identities",
"operator_approval_standing_grants",
"operator_approval_standing_grant_generations",
"web_push_approval_deliveries",
"execution_decision_facts",
"execution_owner_lifecycle_bindings",
"outbound_message_execution_bindings",
"outbound_message_progress"
];
const FIRST_USE_STATE_INDEXES = [
"idx_user_profile_identities_profile_id",
"idx_user_profile_identities_authorization",
"idx_update_runs_created",
"idx_update_runs_active",
"idx_github_repository_publication_shared_request",
"idx_github_repository_publication_personal_request",
"idx_github_personal_publication_owner_session",
"idx_github_personal_publication_pending",
"idx_node_worker_launches_terminal_completed",
"idx_node_worker_turns_terminal_completed",
"idx_node_worker_turns_active_owner",
"idx_operator_approval_standing_grants_binding",
"idx_web_push_approval_deliveries_subscription",
"execution_identity_contexts_run_created_idx",
"execution_decision_facts_context_occurred_idx",
"execution_decision_facts_run_occurred_idx",
"outbound_message_execution_bindings_execution_event_idx",
"outbound_message_progress_occurred_idx",
"outbound_message_progress_run_occurred_idx"
];
const LAZY_ADDITIVE_STATE_TABLES = [
...FIRST_USE_STATE_TABLES,
"agent_provenance",
"cron_run_receipts",
"config_revision_keys",
"secret_store_entries",
"projects",
"worktree_templates",
"user_preferences",
"device_pair_setup_completions",
"github_publication_requests",
"device_pairing_join_codes",
"skill_workshop_changes",
"worker_environment_ssh_fallback_ports",
"worker_session_placement_moves"
];
const LAZY_ADDITIVE_STATE_INDEXES = [
...FIRST_USE_STATE_INDEXES,
"idx_cron_run_receipts_active_job",
"idx_cron_run_receipts_job_history",
"idx_github_publication_requests_pending",
"secret_store_entries_live_idx",
"idx_skill_workshop_changes_agent_time"
];
/** Maximum time one synchronous SQLite call may wait for a lock. */
const OPENCLAW_SQLITE_BUSY_TIMEOUT_MS = 5e3;
/** User-facing guide for schema refusals; lives here so error sites avoid import cycles. */
const OPENCLAW_DATABASE_SCHEMA_DOCS_URL = "https://docs.openclaw.ai/reference/database-schemas";
//#endregion
//#region src/infra/git-root.ts
function walkUpFrom(startDir, opts, resolveAtDir) {
let current = path.resolve(startDir);
for (let i = 0; opts.maxDepth === void 0 || i < opts.maxDepth; i += 1) {
const resolved = resolveAtDir(current);
if (resolved !== null && resolved !== void 0) return resolved;
const parent = path.dirname(current);
if (parent === current) break;
current = parent;
}
return null;
}
function readGitMetadataFile(filePath, limit = 1048576) {
const fd = fsSync.openSync(filePath, fsSync.constants.O_RDONLY | (fsSync.constants.O_NONBLOCK ?? 0));
try {
const stat = fsSync.fstatSync(fd);
if (!stat.isFile() || stat.size > limit) throw new Error("Git metadata is not a bounded regular file");
const bytes = readFileDescriptorBoundedSync(fd, Math.min(stat.size, limit));
if (bytes.length !== stat.size) throw new Error("Git metadata changed during its read");
return bytes;
} finally {
fsSync.closeSync(fd);
}
}
function readGitDirectoryPointerTarget(filePath, prefix = "") {
const bytes = readGitMetadataFile(filePath);
const raw = bytes.toString("utf8").replace(/[\r\n]+$/u, "");
if (!isUtf8(bytes) || !raw.startsWith(prefix) || raw.length === prefix.length || raw.includes("\0")) throw new Error("Git directory pointer is incomplete or malformed");
const target = raw.slice(prefix.length);
return path.isAbsolute(target) ? target : `${path.dirname(filePath)}${path.sep}${target}`;
}
function readGitDirectoryPointer(filePath, prefix = "") {
return fsSync.realpathSync.native(readGitDirectoryPointerTarget(filePath, prefix));
}
function resolveGitDirFromMarker(repoRoot) {
const gitPath = path.join(repoRoot, ".git");
try {
const stat = fsSync.statSync(gitPath);
if (stat.isDirectory()) return gitPath;
if (!stat.isFile()) return null;
return readGitDirectoryPointer(gitPath, "gitdir: ");
} catch {
return null;
}
}
function resolveGitHeadPath(startDir, opts = {}) {
return walkUpFrom(startDir, opts, (repoRoot) => {
const gitDir = resolveGitDirFromMarker(repoRoot);
return gitDir ? path.join(gitDir, "HEAD") : null;
});
}
/** Read at most `limit` bytes from Git or build metadata. */
function readGitMetadataPrefix(filePath, limit = 256) {
const fd = fsSync.openSync(filePath, fsSync.constants.O_RDONLY | (fsSync.constants.O_NONBLOCK ?? 0));
try {
if (!fsSync.fstatSync(fd).isFile()) throw new Error("Git metadata is not a regular file");
const buf = Buffer.alloc(limit);
const bytesRead = readFileWindowFullySync(fd, buf, 0);
return buf.subarray(0, bytesRead).toString("utf-8");
} finally {
fsSync.closeSync(fd);
}
}
function readGitHead(startDir, opts = {}) {
const headPath = resolveGitHeadPath(startDir, opts);
if (!headPath) return;
const head = readGitMetadataFile(headPath).toString("utf8").trim();
if (!head.startsWith("ref:")) return {
headPath,
ref: null,
value: head || null
};
const ref = head.replace(/^ref:\s*/i, "").trim();
const refsBase = resolveGitRefsBase(headPath);
return {
headPath,
ref,
value: readGitRefs(refsBase, [ref]).get(ref) ?? null,
refsBase
};
}
function resolveGitRefsBase(headPath) {
const gitDir = path.dirname(headPath);
const marker = path.join(gitDir, "commondir");
try {
return readGitDirectoryPointer(marker);
} catch (error) {
if (!isMissingPathError(error) || fsSync.lstatSync(marker, { throwIfNoEntry: false })) throw error;
}
return gitDir;
}
/** Raw ref contents, sharing one packed inventory across the requested names. */
function readGitRefs(refsBase, refs) {
const values = new Map(refs.map((ref) => [ref, null]));
const missing = /* @__PURE__ */ new Set();
for (const ref of refs) {
const refPath = resolveRefPath(refsBase, ref);
if (!refPath) continue;
try {
values.set(ref, readGitMetadataPrefix(refPath).trim());
} catch (error) {
if (!isMissingPathError(error)) throw error;
missing.add(ref);
}
}
if (missing.size === 0) return values;
try {
const packedRefs = readGitMetadataFile(path.join(refsBase, "packed-refs"), Number.MAX_SAFE_INTEGER).toString("utf8");
for (const line of packedRefs.split("\n")) {
if (!line || line.startsWith("#") || line.startsWith("^")) continue;
const [value, packedRef] = line.trim().split(/\s+/, 2);
if (packedRef && missing.delete(packedRef)) values.set(packedRef, value ?? null);
}
} catch (error) {
if (!isMissingPathError(error)) throw error;
}
return values;
}
/** Safely resolve a Git ref path, rejecting traversal from a crafted HEAD file. */
function resolveRefPath(refsBase, ref) {
if (!ref.startsWith("refs/")) return null;
if (ref.split(/[/]/).includes("..")) return null;
const resolved = path.resolve(refsBase, ref);
const rel = path.relative(refsBase, resolved);
if (!rel || rel.startsWith("..") || path.isAbsolute(rel)) return null;
return resolved;
}
//#endregion
//#region src/infra/error-graph-internal.ts
/** Retained errors must not keep callers alive through V8's lazy stack frames. */
function materializeErrorStack(failure) {
let error = failure;
const seen = /* @__PURE__ */ new Set();
while (error instanceof Error && !seen.has(error)) {
seen.add(error);
try {
error.stack = String(error.stack);
} catch {
error.stack = "Stack trace unavailable: custom formatter failed";
}
error = error.cause;
}
}
//#endregion
//#region src/shared/async-work-scope.ts
const currentWorkScope = resolveGlobalSingleton(Symbol.for("openclaw.asyncWorkScope"), () => new AsyncLocalStorage());
const currentWorkScopeAncestry = resolveGlobalSingleton(Symbol.for("openclaw.asyncWorkScopeAncestry"), () => new AsyncLocalStorage());
/** Joins cooperating descendants even when their caller returns a cached value first. */
var AsyncWorkScope = class AsyncWorkScope {
constructor(failures) {
this.failures = failures;
this.pending = /* @__PURE__ */ new Set();
this.controller = new AbortController();
this.phase = "open";
}
get signal() {
return this.controller.signal;
}
get hasPendingWork() {
return this.pending.size > 0;
}
get isClosing() {
return this.phase !== "open";
}
enter(run) {
const owner = currentWorkScope.getStore();
const ancestry = currentWorkScopeAncestry.getStore();
const parent = owner ? ancestry?.scope === owner ? ancestry : { scope: owner } : void 0;
return currentWorkScopeAncestry.run({
scope: this,
parent
}, () => currentWorkScope.run(this, run));
}
/** Enters synchronous work without inspecting or assimilating its return value. */
run(run) {
if (this.phase === "closed") throw new Error("Async work scope is closed");
const operation = createDeferredCore();
this.pending.add(operation.promise);
try {
return this.enter(run);
} finally {
operation.resolve();
this.pending.delete(operation.promise);
}
}
track(run) {
if (this.phase === "closed") return Promise.reject(/* @__PURE__ */ new Error("Async work scope is closed"));
const operation = createDeferredCore();
this.pending.add(operation.promise);
operation.promise.then(() => this.pending.delete(operation.promise), (error) => {
this.pending.delete(operation.promise);
this.failures?.add(error);
});
try {
operation.resolve(this.enter(run));
} catch (error) {
operation.reject(error);
}
return operation.promise;
}
beginClose(reason) {
if (this.phase !== "open") return;
this.phase = "closing";
this.controller.abort(reason);
}
/** Starts the next phase in the same continuation that observes settled pending work. */
runWhenIdle(run) {
return AsyncWorkScope.runWhenAllIdle(() => [this], () => this.track(run));
}
/** Reselects owners so work admitted into a later phase is not mistaken for earlier work. */
static async runWhenAllIdle(selectScopes, run) {
let scopes = selectScopes();
while (scopes.some((scope) => scope.pending.size > 0)) {
await Promise.allSettled(scopes.flatMap((scope) => Array.from(scope.pending)));
scopes = selectScopes();
}
return run();
}
async drain() {
this.beginClose();
while (this.pending.size > 0) await Promise.allSettled(this.pending);
this.phase = "closed";
}
};
/** Outside a managed scope, the returned promise remains the caller's responsibility. */
async function trackAsyncWork(run) {
const scope = currentWorkScope.getStore();
return await (scope ? scope.track(run) : run());
}
/** Starts work its caller does not own, so the caller's scope neither waits for it nor closes under it. */
function runOutsideAsyncWorkScope(run) {
return currentWorkScope.exit(() => currentWorkScopeAncestry.exit(run));
}
//#endregion
//#region src/plugins/host-hook-cleanup-result.ts
/** Merge raw instance outcomes without duplicating their existing host or instance report. */
function appendPluginInstanceCleanupFailures(failures, pluginId, result) {
for (const error of result.errors) {
if (failures.some((failure) => failure.pluginId === pluginId && failure.error === error && (failure.hookId === "instance" || result.hostCleanupErrors?.includes(error)))) continue;
failures.push({
pluginId,
hookId: "instance",
error
});
}
}
//#endregion
//#region src/plugins/plugin-cache-sdk.ts
/** Derived SDK facts share the plugin cache lifetime; none owns a separate expiry. */
function createPluginCacheSdk() {
return {
hosts: /* @__PURE__ */ new Map(),
contexts: /* @__PURE__ */ new Map(),
packageNames: /* @__PURE__ */ new Map(),
packageSearches: /* @__PURE__ */ new Map(),
argvDirectories: /* @__PURE__ */ new Map(),
devSourceRoots: /* @__PURE__ */ new Map(),
runtimeModules: /* @__PURE__ */ new Map(),
usableDistArtifacts: /* @__PURE__ */ new Map(),
normalizedJitiAliases: /* @__PURE__ */ new Map(),
aliasFacts: /* @__PURE__ */ new WeakMap(),
native: {
sdkProviders: /* @__PURE__ */ new Map(),
nextSdkProviderOrder: 0,
parents: /* @__PURE__ */ new Map(),
aliases: /* @__PURE__ */ new Map(),
registeredHosts: /* @__PURE__ */ new Set(),
hostRoots: /* @__PURE__ */ new Map(),
nearestPackageRoots: /* @__PURE__ */ new Map(),
loaderPackageRoots: /* @__PURE__ */ new Map(),
allowedParentRoots: /* @__PURE__ */ new Map()
}
};
}
resolveGlobalSingleton(Symbol.for("openclaw.pluginSourceRecoveryUnavailableError"), () => class SourceRecoveryUnavailableError extends Error {
constructor(cause) {
super("Captured plugin source is missing; its previous code cannot be recovered.", { cause });
this.name = "PluginSourceRecoveryUnavailableError";
}
});
const PluginInstanceDrainTimeoutError = resolveGlobalSingleton(Symbol.for("openclaw.pluginInstanceDrainTimeoutError"), () => class DrainTimeoutError extends Error {
constructor(message, settled, options, forcedRetirement) {
super(message, options);
this.settled = settled;
this.forcedRetirement = forcedRetirement;
this.name = "PluginInstanceDrainTimeoutError";
}
});
//#endregion
//#region src/plugins/plugin-instance-invocation.ts
var InvocationFrame = class InvocationFrame {
constructor(scopes, invocation = scopes.invocation) {
this.invocation = invocation;
this.metadataScope = scopes.metadataScope;
this.cacheScope = scopes.cacheScope;
this.sourceCaptureStorage = scopes.sourceCaptureStorage;
}
withScopes(scopes) {
return new InvocationFrame(scopes);
}
};
/** Copy core scopes through the current owner so runtime-only fields survive. */
function createPluginExecutionFrame(scopes, current) {
return current ? current.withScopes(scopes) : new InvocationFrame(scopes);
}
const pluginExecutionContext = resolveGlobalSingleton(Symbol.for("openclaw.pluginInstanceInvocation"), () => {
const frames = new AsyncLocalStorage();
return {
invocation: {
getStore() {
return frames.getStore()?.invocation;
},
run(invocation, run) {
const current = frames.getStore();
return frames.run(current?.invocation === invocation ? current : createPluginExecutionFrame({
...current,
invocation
}, current), run);
},
exit(run) {
const current = frames.getStore();
return current?.invocation ? frames.run(current.withScopes({
...current,
invocation: void 0
}), run) : run();
}
},
getFrame() {
return frames.getStore();
},
runFrame(frame, run) {
return frames.run(frame, run);
}
};
});
pluginExecutionContext.invocation;
const getPluginExecutionFrame = pluginExecutionContext.getFrame;
pluginExecutionContext.runFrame;
//#endregion
//#region src/plugins/plugin-cache.ts
const PLUGIN_CACHE_FACT_INVALIDATED = "PLUGIN_CACHE_FACT_INVALIDATED";
/** Explicit fact invalidation cancels its preparation. */
var PluginCacheFactInvalidatedError = class extends Error {
constructor(..._args) {
super(..._args);
this.code = PLUGIN_CACHE_FACT_INVALIDATED;
}
};
const state = resolveGlobalSingleton(Symbol.for("openclaw.pluginCache"), () => ({
snapshotOwners: /* @__PURE__ */ new WeakMap(),
retirements: []
}));
const cacheRetainers = resolveGlobalSingleton(Symbol.for("openclaw.pluginCacheRetainers"), () => /* @__PURE__ */ new WeakMap());
const instanceCacheOwners = resolveGlobalSingleton(Symbol.for("openclaw.pluginInstanceCacheOwners"), () => /* @__PURE__ */ new WeakMap());
/** A retiring inventory releases its own custody; terminal disposal releases every birth cache. */
function releasePluginCacheInstance(instance, cache) {
const owners = instanceCacheOwners.get(instance);
if (cache) {
cache.instances.delete(instance);
owners?.delete(cache);
} else {
for (const owner of owners ?? []) owner.instances.delete(instance);
owners?.clear();
}
if (owners?.size === 0) instanceCacheOwners.delete(instance);
}
function getPluginCacheRetainers(cache) {
let retained = cacheRetainers.get(cache);
if (!retained) {
retained = {
references: /* @__PURE__ */ new Set(),
controller: new AbortController(),
settled: createDeferredCore()
};
cacheRetainers.set(cache, retained);
}
return retained;
}
/** Cache retirement revokes cached publications before waiting for admitted borrowers. */
function getPluginCacheRetirementSignal(cache) {
return getPluginCacheRetainers(cache).controller.signal;
}
function createPluginMetadataCache() {
return {
current: {
snapshot: void 0,
owner: "operation",
configFingerprint: void 0,
agentWorkspaceFingerprint: void 0,
envFingerprint: void 0,
defaultDiscoveryCompatible: false,
compatiblePolicyHashes: void 0,
compatibleConfigFingerprints: void 0,
revision: Symbol("plugin-metadata-snapshot"),
configIdentities: /* @__PURE__ */ new WeakSet()
},
snapshots: /* @__PURE__ */ new Map(),
discovery: /* @__PURE__ */ new Map(),
sharedDiscovery: /* @__PURE__ */ new Map(),
projections: /* @__PURE__ */ new WeakMap(),
projectionSources: /* @__PURE__ */ new WeakMap(),
completions: /* @__PURE__ */ new WeakMap(),
indexFacts: /* @__PURE__ */ new WeakMap(),
providerPolicyOwners: /* @__PURE__ */ new WeakMap(),
channelAdapters: /* @__PURE__ */ new WeakMap(),
bundledChannelCatalogs: /* @__PURE__ */ new Map(),
bundledProviderPolicySurfaces: /* @__PURE__ */ new WeakMap(),
staticCatalogStates: /* @__PURE__ */ new WeakMap(),
modelSuppressionResolvers: /* @__PURE__ */ new WeakMap(),
mcpAuthDeclarations: /* @__PURE__ */ new WeakMap()
};
}
/** Invalidate discovery facts without retiring callbacks owned by this operation. */
function invalidatePluginCacheMetadata(cache) {
cache.inspectionNativeEsmPolicy = void 0;
cache.sourceAdmissions?.invalidate();
cache.metadata = createPluginMetadataCache();
cache.sdk.native.parents.clear();
for (const root of cache.roots.values()) {
root.files.clear();
root.checkedEntries.clear();
root.paths.clear();
root.directory = void 0;
root.artifacts.clear();
root.runtimeArtifacts.clear();
root.entryBoundaries.clear();
root.entryPaths.clear();
}
cache.rootAliases.clear();
cache.installRecords.clear();
cache.persistedInstalledIndex.clear();
cache.preparedBundledDiscoveryModes.clear();
cache.dependencyStatus = /* @__PURE__ */ new WeakMap();
}
/** Each inventory owns its acquired facts and reusable load results; publication owns activation. */
function createPluginCache(options = {}) {
return {
async [Symbol.asyncDispose]() {
await retirePluginCache(this);
},
kind: options.kind ?? "operation",
roots: /* @__PURE__ */ new Map(),
rootAliases: /* @__PURE__ */ new Map(),
sdk: createPluginCacheSdk(),
setupModules: /* @__PURE__ */ new Map(),
instances: /* @__PURE__ */ new Set(),
metadata: createPluginMetadataCache(),
installRecords: /* @__PURE__ */ new Map(),
persistedInstalledIndex: /* @__PURE__ */ new Map(),
preparedBundledDiscoveryModes: /* @__PURE__ */ new Map(),
dependencyStatus: /* @__PURE__ */ new WeakMap(),
moduleLoaders: /* @__PURE__ */ new Map(),
sources: /* @__PURE__ */ new Map(),
sourceAliases: /* @__PURE__ */ new Map(),
runtimeRecordRoots: /* @__PURE__ */ new WeakMap()
};
}
function getProcessPluginCache() {
return state.current ??= createPluginCache({ kind: "process" });
}
function getScopedPluginCache() {
return getPluginExecutionFrame()?.cacheScope?.cache;
}
/** Installation refreshes every enclosing operation, including callers outside metadata phases. */
function getScopedPluginCaches() {
const caches = [];
for (let scope = getPluginExecutionFrame()?.cacheScope; scope; scope = scope.parent) caches.push(scope.cache);
return caches;
}
function getPluginCache() {
return getScopedPluginCache() ?? getProcessPluginCache();
}
/** Stop new setup calls immediately; the owner awaits in-flight calls and graph cleanup. */
function retirePluginCache(cache, beforeRetire, options) {
const retained = getPluginCacheRetainers(cache);
if (retained.retirement) return retained.retirement;
const completion = createDeferredCore();
retained.retirement = completion.promise;
const trackRetirement = async (run) => {
const work = new AsyncWorkScope();
try {
return await work.track(run);
} finally {
await work.run(() => work.drain());
}
};
retained.beginRetirement = (track = trackAsyncWork) => {
let admitted = false;
track(() => {
admitted = true;
retained.beginRetirement = void 0;
return beginPluginCacheRetirement(cache, beforeRetire, options);
}).then(completion.resolve, (error) => {
if (admitted) completion.reject(error);
else retained.beginRetirement?.(trackRetirement);
});
};
retained.controller.abort();
materializeErrorStack(retained.controller.signal.reason);
if (retained.references.size === 0) retained.beginRetirement?.();
else retained.settled.promise.then(() => {
retained.beginRetirement?.(trackRetirement);
});
return completion.promise;
}
function beginPluginCacheRetirement(cache, beforeRetire, options) {
if (cache.retirement) return cache.retirement;
const retirement = createDeferredCore();
cache.retirement = retirement.promise;
const cleanup = async () => {
beforeRetire?.();
const registries = cache.retireRegistryLoads?.();
const resources = /* @__PURE__ */ new Set([...cache.setupModules.values(), ...cache.instances]);
for (const resource of resources) resource.quiesce();
const [registry] = await Promise.allSettled([registries]);
const outcomes = await Promise.allSettled([...resources].map(async (resource) => ({
resource,
result: await resource.dispose(void 0, options)
})));
const nativeAdmissions = cache.sourceAdmissions;
if (nativeAdmissions) {
const pending = outcomes.flatMap((outcome) => outcome.status === "fulfilled" ? outcome.value.result.errors.flatMap((error) => error instanceof PluginInstanceDrainTimeoutError ? [error.settled] : []) : []);
if (pending.length > 0) Promise.allSettled(pending).then(() => nativeAdmissions.dispose()).catch((error) => process.emitWarning(`Plugin native capture cleanup failed: ${String(error)}`));
else await nativeAdmissions.dispose();
}
cache.setupModules.clear();
for (const instance of cache.instances) releasePluginCacheInstance(instance, cache);
const unexpected = [...registry.status === "rejected" ? [registry.reason] : [], ...outcomes.flatMap((result) => result.status === "rejected" ? [result.reason] : [])];
if (unexpected.length) throw new AggregateError(unexpected, "Plugin cache resources failed to retire");
const host = registry.status === "fulfilled" ? registry.value : void 0;
const failures = [...host?.failures ?? []];
for (const outcome of outcomes) {
if (outcome.status !== "fulfilled") continue;
const { resource, result } = outcome.value;
appendPluginInstanceCleanupFailures(failures, resource.pluginId, result);
}
return {
cleanupCount: host?.cleanupCount ?? 0,
failures
};
};
cleanup().then(retirement.resolve, retirement.reject);
return retirement.promise;
}
function getPluginCacheRoot(rootDir) {
const cache = getPluginCache();
const cached = cache.roots.get(cache.rootAliases.get(rootDir) ?? rootDir);
if (cached) return cached;
const lexical = path.resolve(rootDir);
const key = cache.rootAliases.get(lexical) ?? lexical;
let root = cache.roots.get(key);
if (!root) {
root = {
rootDir: key,
files: /* @__PURE__ */ new Map(),
checkedEntries: /* @__PURE__ */ new Map(),
paths: /* @__PURE__ */ new Map(),
artifactLoadsInProgress: /* @__PURE__ */ new Set(),
artifacts: /* @__PURE__ */ new Map(),
runtimeArtifacts: /* @__PURE__ */ new Map(),
entryBoundaries: /* @__PURE__ */ new Map(),
entryPaths: /* @__PURE__ */ new Map()
};
cache.roots.set(key, root);
}
return root;
}
function mergeRootFacts(target, source) {
for (const [key, value] of source) if (!target.has(key)) target.set(key, value);
}
/** Bind aliases only after a checked file establishes their shared package boundary. */
function bindPluginCacheRoot(rootDir, canonicalRoot) {
const cache = getPluginCache();
const lexical = path.resolve(rootDir);
const canonical = path.resolve(canonicalRoot);
const root = getPluginCacheRoot(lexical);
root.rootDir = canonical;
const existing = cache.roots.get(canonical);
if (existing && existing !== root) {
mergeRootFacts(root.files, existing.files);
mergeRootFacts(root.checkedEntries, existing.checkedEntries);
mergeRootFacts(root.paths, existing.paths);
mergeRootFacts(root.artifacts, existing.artifacts);
mergeRootFacts(root.runtimeArtifacts, existing.runtimeArtifacts);
mergeRootFacts(root.entryBoundaries, existing.entryBoundaries);
mergeRootFacts(root.entryPaths, existing.entryPaths);
root.directory ??= existing.directory;
root.publicSurfaceBoundary ??= existing.publicSurfaceBoundary;
for (const artifact of existing.artifactLoadsInProgress) root.artifactLoadsInProgress.add(artifact);
Object.assign(existing, root);
}
cache.roots.set(canonical, root);
cache.rootAliases.set(lexical, canonical);
return root;
}
//#endregion
//#region src/infra/openclaw-root.ts
function parsePackageName(raw) {
const parsed = JSON.parse(raw);
return typeof parsed.name === "string" ? parsed.name : null;
}
function readPackageNameSync(dir) {
const packageNameCache = getPluginCache().sdk.packageNames;
const packageJsonPath = path.join(path.resolve(dir), "package.json");
if (packageNameCache.has(packageJsonPath)) return packageNameCache.get(packageJsonPath) ?? null;
try {
const name = parsePackageName(openClawRootFsSync.readFileSync(packageJsonPath, "utf-8"));
packageNameCache.set(packageJsonPath, name);
return name;
} catch {
packageNameCache.set(packageJsonPath, null);
return null;
}
}
function findPackageRootSync(startDir, maxDepth = 12) {
for (const current of iterAncestorDirs(startDir, maxDepth)) if (readPackageNameSync(current) === "openclaw") return current;
return null;
}
function* iterAncestorDirs(startDir, maxDepth) {
let current = path.resolve(startDir);
for (let i = 0; i < maxDepth; i += 1) {
yield current;
if (path.basename(current) === "node_modules") break;
const parent = path.dirname(current);
if (parent === current) break;
current = parent;
}
}
function candidateDirsFromArgv1(argv1) {
const argv1CandidateCache = getPluginCache().sdk.argvDirectories;
const cacheKey = path.resolve(argv1);
const cached = argv1CandidateCache.get(cacheKey);
if (cached) return [...cached];
const normalized = cacheKey;
const candidates = [];
try {
const resolved = openClawRootFsSync.realpathSync(normalized);
if (resolved !== normalized) candidates.push(path.dirname(resolved));
} catch {}
candidates.push(path.dirname(normalized));
const parts = normalized.split(path.sep);
const binIndex = parts.lastIndexOf(".bin");
if (binIndex > 0 && parts[binIndex - 1] === "node_modules") {
const binName = path.basename(normalized);
const nodeModulesDir = parts.slice(0, binIndex).join(path.sep);
candidates.push(path.join(nodeModulesDir, binName));
}
const deduped = dedupeCandidates(candidates);
argv1CandidateCache.set(cacheKey, deduped);
return [...deduped];
}
function preparePackageRootSearch(opts, preserveInventory) {
const candidates = buildCandidates(opts);
const cacheKey = candidates.join("\0");
const searches = getPluginCache().sdk.packageSearches;
const cached = searches.get(cacheKey);
return {
candidates,
first: cached?.all ? cached.all[0] ?? null : cached?.first,
complete(first) {
searches.set(cacheKey, preserveInventory ? {
...searches.get(cacheKey),
first
} : { first });
return first;
}
};
}
function resolveOpenClawPackageRootSync(opts) {
const search = preparePackageRootSearch(opts, false);
if (search.first !== void 0) return search.first;
for (const candidate of search.candidates) {
const found = findPackageRootSync(candidate);
if (found) return search.complete(found);
}
return search.complete(null);
}
function buildCandidates(opts) {
const candidates = [];
if (opts.moduleUrl) try {
candidates.push(path.dirname(fileURLToPath(opts.moduleUrl)));
} catch {}
if (opts.argv1) candidates.push(...candidateDirsFromArgv1(opts.argv1));
if (opts.cwd) candidates.push(opts.cwd);
return dedupeCandidates(candidates);
}
function dedupeCandidates(candidates) {
return [...new Set(candidates.map((candidate) => path.resolve(candidate)))];
}
//#endregion
//#region src/infra/git-commit.ts
const formatCommit = (value) => {
const match = value?.match(/[0-9a-fA-F]{7,40}/);
return match ? normalizeLowercaseStringOrEmpty(match[0].slice(0, 7)) : null;
};
const cachedGitCommitBySearchDir = new LruCache(256);
const resolveCommitSearchDir = (options) => {
if (options.cwd) return path.resolve(options.cwd);
if (options.moduleUrl) try {
return path.dirname(fileURLToPath(options.moduleUrl));
} catch {}
return process.cwd();
};
const cacheGitCommit = (searchDir, commit) => {
cachedGitCommitBySearchDir.set(searchDir, commit);
return commit;
};
const resolveGitLookupDepth = (searchDir, packageRoot) => {
if (!packageRoot) return;
const relative = path.relative(packageRoot, searchDir);
if (relative.startsWith("..") || path.isAbsolute(relative)) return;
return (relative ? relative.split(path.sep).filter(Boolean).length : 0) + 1;
};
const readCommitFromGit = (searchDir, packageRoot) => {
const head = readGitHead(searchDir, { maxDepth: resolveGitLookupDepth(searchDir, packageRoot) });
return head === void 0 ? void 0 : formatCommit(head.value);
};
const readCommitFromPackageJson = () => {
try {
const pkg = createRequire(import.meta.url)("../../package.json");
return formatCommit(pkg.gitHead ?? pkg.githead ?? null);
} catch {
return null;
}
};
const readCommitProbe = (moduleUrl, candidates, field) => {
try {
for (const candidate of candidates) {
const filePath = fileURLToPath(new URL(candidate, moduleUrl));
let raw;
try {
raw = readGitMetadataPrefix(filePath, 1024);
} catch (error) {
if (isMissingPathError(error)) continue;
return null;
}
try {
const value = asNullableRecord(JSON.parse(raw))?.[field];
return typeof value === "string" ? formatCommit(value) : null;
} catch {
return null;
}
}
} catch {}
};
const readCommitFromBuildInfo = (moduleUrl = import.meta.url) => {
return readCommitProbe(moduleUrl, ["../build-info.json", "./build-info.json"], "commit") ?? null;
};
const readLoadedCommit = (moduleUrl) => {
const buildStamp = readCommitProbe(moduleUrl, ["../.buildstamp", "./.buildstamp"], "head");
const runtimeStamp = readCommitProbe(moduleUrl, ["../.runtime-postbuildstamp", "./.runtime-postbuildstamp"], "head");
if (buildStamp !== void 0 || runtimeStamp !== void 0) {
if (buildStamp || runtimeStamp) return buildStamp && buildStamp === runtimeStamp ? buildStamp : null;
return readCommitFromBuildInfo(moduleUrl);
}
return readCommitProbe(moduleUrl, ["../build-info.json", "./build-info.json"], "commit");
};
const resolveCommitHash = (options = {}) => {
const env = options.env ?? process.env;
const readers = options.readers ?? {};
const readGitCommit = readers.readGitCommit ?? readCommitFromGit;
const envCommit = env.GIT_COMMIT?.trim() || env.GIT_SHA?.trim();
const normalized = formatCommit(envCommit);
if (normalized) return normalized;
const searchDir = resolveCommitSearchDir(options);
const cached = cachedGitCommitBySearchDir.get(searchDir);
if (cached !== void 0) return cached;
const packageRoot = resolveOpenClawPackageRootSync({
cwd: options.cwd,
moduleUrl: options.moduleUrl
});
try {
const gitCommit = readGitCommit(searchDir, packageRoot);
if (gitCommit !== void 0) return cacheGitCommit(searchDir, gitCommit);
} catch {}
const buildInfoCommit = readers.readBuildInfoCommit?.() ?? readCommitFromBuildInfo();
if (buildInfoCommit) return cacheGitCommit(searchDir, buildInfoCommit);
const pkgCommit = readers.readPackageJsonCommit?.() ?? readCommitFromPackageJson();
if (pkgCommit) return cacheGitCommit(searchDir, pkgCommit);
try {
return cacheGitCommit(searchDir, readGitCommit(searchDir, packageRoot) ?? null);
} catch {
return cacheGitCommit(searchDir, null);
}
};
/** Resolve the commit that produced the loaded artifact, not the checkout's current revision. */
function resolveLoadedCommitHash(options = {}) {
const moduleUrl = options.moduleUrl ?? import.meta.url;
const loaded = readLoadedCommit(moduleUrl);
return loaded === void 0 ? resolveCommitHash({
moduleUrl,
...options.env ? { env: options.env } : {}
}) : loaded;
}
//#endregion
//#region src/version.ts
const CORE_PACKAGE_NAME = "openclaw";
const PACKAGE_JSON_CANDIDATES = [
"../package.json",
"../../package.json",
"../../../package.json",
"./package.json"
];
const BUILD_INFO_CANDIDATES = [
"../build-info.json",
"../../build-info.json",
"./build-info.json"
];
function readVersionFromJsonCandidates(moduleUrl, candidates, opts = {}) {
try {
const require = createRequire(moduleUrl);
for (const candidate of candidates) try {
const parsed = require(candidate);
const version = normalizeOptionalString(parsed.version);
if (!version) continue;
if (opts.requirePackageName && parsed.name !== CORE_PACKAGE_NAME) continue;
return version;
} catch {}
return null;
} catch {
return null;
}
}
function readBuildIdFromJsonCandidates(moduleUrl) {
try {
const require = createRequire(moduleUrl);
for (const candidate of BUILD_INFO_CANDIDATES) try {
const parsed = require(candidate);
const buildId = normalizeOptionalString(parsed.buildId);
if (buildId && buildId.length <= 96) return buildId;
} catch {}
return null;
} catch {
return null;
}
}
function firstNonEmpty(...values) {
for (const value of values) {
const trimmed = normalizeOptionalString(value);
if (trimmed && trimmed.toLowerCase() !== "undefined" && trimmed.toLowerCase() !== "null") return trimmed;
}
}
function readVersionFromPackageJsonForModuleUrl(moduleUrl) {
return readVersionFromJsonCandidates(moduleUrl, PACKAGE_JSON_CANDIDATES, { requirePackageName: true });
}
function readVersionFromBuildInfoForModuleUrl(moduleUrl) {
return readVersionFromJsonCandidates(moduleUrl, BUILD_INFO_CANDIDATES);
}
function readBuildIdFromBuildInfoForModuleUrl(moduleUrl) {
return readBuildIdFromJsonCandidates(moduleUrl);
}
function resolveVersionFromModuleUrl(moduleUrl) {
return readVersionFromBuildInfoForModuleUrl(moduleUrl) || readVersionFromPackageJsonForModuleUrl(moduleUrl);
}
function resolveBinaryVersion(params) {
return resolveVersionFromModuleUrl(params.moduleUrl) || firstNonEmpty(params.bundledVersion) || params.fallback || "0.0.0";
}
const RUNTIME_SERVICE_VERSION_FALLBACK = "unknown";
function resolveUsableRuntimeVersion(version) {
const trimmed = normalizeOptionalString(version);
if (!trimmed || trimmed === "0.0.0") return;
return trimmed;
}
function resolveVersionFromRuntimeSources(params) {
return firstNonEmpty(...params.preference === "env-first" ? [params.env["OPENCLAW_VERSION"], params.runtimeVersion] : [params.runtimeVersion, params.env["OPENCLAW_VERSION"]], params.env["npm_package_version"]) ?? params.fallback;
}
readBuildIdFromBuildInfoForModuleUrl(import.meta.url);
const RUNTIME_SERVICE_COMMIT = resolveLoadedCommitHash({ moduleUrl: import.meta.url });
function resolveRuntimeServiceCommit() {
return RUNTIME_SERVICE_COMMIT;
}
function resolveCompatibilityHostVersion(env = process.env, fallback = RUNTIME_SERVICE_VERSION_FALLBACK) {
const explicitCompatibilityVersion = firstNonEmpty(env.OPENCLAW_COMPATIBILITY_HOST_VERSION);
if (explicitCompatibilityVersion) return explicitCompatibilityVersion;
return resolveVersionFromRuntimeSources({
env,
runtimeVersion: resolveUsableRuntimeVersion(VERSION),
fallback,
preference: env === process.env ? "runtime-first" : "env-first"
});
}
const VERSION = resolveBinaryVersion({
moduleUrl: import.meta.url,
bundledVersion: process.env.OPENCLAW_BUNDLED_VERSION
});
//#endregion
//#region src/infra/kysely-sync-cache-state.ts
const { kyselyByDatabase, queryErrorHandlerByDatabase } = resolveGlobalSingleton(Symbol.for("openclaw.sqliteKyselyCacheState"), () => ({
kyselyByDatabase: /* @__PURE__ */ new WeakMap(),
queryErrorHandlerByDatabase: /* @__PURE__ */ new WeakMap()
}));
const statementCacheSymbol = Symbol.for("openclaw.kyselySyncStatementCache");
const statementInvalidationSymbol = Symbol.for("openclaw.kyselySyncStatementInvalidation");
const statementCacheEnabledSymbol = Symbol.for("openclaw.kyselySyncStatementCacheEnabled");
const authorizerActiveSymbol = Symbol.for("openclaw.kyselySyncAuthorizerActive");
const disposeCallbacksSymbol = Symbol.for("openclaw.sqliteDisposeCallbacks");
const statementCacheCapacity = 64;
const statementCacheEntryBytes = 65536;
/** Retire dependent native resources before this connection closes or is replaced. */
function registerNodeSqliteDisposeCallback(db, callback) {
const owner = db;
installStatementInvalidation(owner);
return registerListener(owner[disposeCallbacksSymbol] ??= /* @__PURE__ */ new Set(), callback);
}
function disposeNodeSqliteDependents(owner, reason = "close") {
for (const callback of owner[disposeCallbacksSymbol] ?? []) callback(reason);
}
/** Register the lifecycle owner's handler for synchronous Kysely query failures. */
function registerNodeSqliteKyselyQueryErrorHandler(db, handler) {
queryErrorHandlerByDatabase.set(db, handler);
}
/** Drop cached Kysely state for a DatabaseSync. */
function clearNodeSqliteKyselyCacheForDatabase(db) {
delete db[statementCacheSymbol];
kyselyByDatabase.delete(db);
queryErrorHandlerByDatabase.delete(db);
}
function installStatementInvalidation(owner) {
if (owner[statementInvalidationSymbol]) return;
if (typeof owner.setAuthorizer === "function") {
const setAuthorizer = owner.setAuthorizer.bind(owner);
Object.defineProperty(owner, "setAuthorizer", {
configurable: true,
writable: true,
value(callback) {
setAuthorizer(callback);
this[authorizerActiveSymbol] = callback !== null;
delete this[statementCacheSymbol];
}
});
}
if (typeof owner.deserialize === "function") {
const deserialize = owner.deserialize.bind(owner);
Object.defineProperty(owner, "deserialize", {
configurable: true,
writable: true,
value(...args) {
disposeNodeSqliteDependents(this, "replace");
try {
deserialize(...args);
} finally {
delete this[statementCacheSymbol];
}
}
});
}
for (const method of ["close", Symbol.dispose]) if (typeof owner[method] === "function") {
const dispose = owner[method].bind(owner);
Object.defineProperty(owner, method, {
configurable: true,
writable: true,
value() {
disposeNodeSqliteDependents(this);
clearNodeSqliteKyselyCacheForDatabase(this);
return dispose();
}
});
}
Object.defineProperty(owner, statementInvalidationSymbol, {
configurable: true,
value: true
});
}
/**
* Enable bounded statement caching for a lifecycle-owned database that has not
* installed an authorizer before this call.
*/
function enableNodeSqliteKyselyStatementCache(db) {
const owner = db;
installStatementInvalidation(owner);
owner[statementCacheEnabledSymbol] = true;
}
function queryFitsStatementCache(sql, parameters) {
let bytes = Buffer.byteLength(sql);
if (bytes > statementCacheEntryBytes) return false;
for (const parameter of parameters) {
if (typeof parameter === "string") {
if (parameter.length > statementCacheEntryBytes - bytes) return false;
bytes += Buffer.byteLength(parameter);
} else if (ArrayBuffer.isView(parameter)) bytes += parameter.byteLength;
if (bytes > statementCacheEntryBytes) return false;
}
return true;
}
function executeWithCachedStatement(db, sql, parameters, execute) {
const owner = db;
if (!owner[statementCacheEnabledSymbol] || owner[authorizerActiveSymbol] || !queryFitsStatementCache(sql, parameters)) return execute(db.prepare(sql));
let cache = owner[statementCacheSymbol];
if (!cache) {
cache = {
statements: /* @__PURE__ */ new Map(),
candidates: /* @__PURE__ */ new Set(),
active: /* @__PURE__ */ new WeakSet()
};
Object.defineProperty(owner, statementCacheSymbol, {
configurable: true,
value: cache
});
}
const cached = cache.statements.get(sql);
let statement;
if (cached && !cache.active.has(cached)) {
cache.statements.delete(sql);
cache.statements.set(sql, cached);
statement = cached;
} else {
statement = db.prepare(sql);
if (!cached && cache.candidates.delete(sql)) {
cache.statements.set(sql, statement);
pruneMapToMaxSize(cache.statements, statementCacheCapacity);
} else if (!cached) {
cache.candidates.add(sql);
if (cache.candidates.size > statementCacheCapacity) {
const oldestCandidate = cache.candidates.values().next().value;
if (oldestCandidate !== void 0) cache.candidates.delete(oldestCandidate);
}
}
}
cache.active.add(statement);
try {
return execute(statement);
} finally {
cache.active.delete(statement);
}
}
//#endregion
//#region src/infra/startup-maintenance-required.ts
const GATEWAY_STARTUP_MAINTENANCE_REQUIRED_REASON = "gateway.maintenance_required";
const maintenanceReasons = {
"state-migrations": "state migration",
"newer-schema": "a newer OpenClaw build",
"agent-media": "offline media migration",
"audit-events-v2": "state database schema migration",
"legacy-workshop-review-index": "state database schema migration",
"legacy-cron-run-logs": "cron run history migration",
"legacy-workspace": "workspace setup state migration",
"legacy-session-store": "session store migration"
};
function isStartupMaintenanceKind(value) {
return typeof value === "string" && Object.hasOwn(maintenanceReasons, value);
}
var StartupMaintenanceRequiredError = class extends Error {
constructor(kind, message, options) {
super(message, options);
this.kind = kind;
this.code = GATEWAY_STARTUP_MAINTENANCE_REQUIRED_REASON;
this.name = "StartupMaintenanceRequiredError";
}
get reason() {
return maintenanceReasons[this.kind];
}
};
//#endregion
//#region src/infra/sqlite-user-version.ts
const SQLITE_SCHEMA_VERSION_ERROR_NAME = "SqliteSchemaVersionError";
var SqliteSchemaVersionError = class extends StartupMaintenanceRequiredError {
constructor(message) {
super("newer-schema", message);
this.name = SQLITE_SCHEMA_VERSION_ERROR_NAME;
}
};
function isSqliteSchemaVersionError(error) {
return error instanceof SqliteSchemaVersionError || error instanceof Error && error.name === SQLITE_SCHEMA_VERSION_ERROR_NAME;
}
function readSqliteUserVersion(db) {
const row = executeWithCachedStatement(db, "PRAGMA user_version", [], (statement) => statement.get());
return Number(row?.user_version ?? 0);
}
/**
* Name the refusing build from immutable loaded metadata, plus its install root.
* The path remains actionable when multiple installs share a version or build.
*/
function describeRunningOpenClawBuild() {
const commit = resolveRuntimeServiceCommit();
const root = resolveOpenClawPackageRootSync({ moduleUrl: import.meta.url });
const identity = commit ? `OpenClaw ${VERSION} (${commit})` : `OpenClaw ${VERSION}`;
return root ? `${identity} installed at ${root}` : identity;
}
function createNewerSqliteSchemaVersionError(databaseLabel, pathname, schemaVersion, supportedVersion) {
return new SqliteSchemaVersionError(`This OpenClaw build cannot open your existing data.
${databaseLabel} ${pathname} uses newer schema version ${schemaVersion}; this build supports ${supportedVersion}.\nRefused by ${describeRunningOpenClawBuild()}.\nUse a build that supports schema ${schemaVersion} or newer with this state directory. To use an older build, restore your pre-update backup created with openclaw backup create.\nSee ${OPENCLAW_DATABASE_SCHEMA_DOCS_URL}.`);
}
//#endregion
//#region src/infra/sqlite-worker-identity.ts
const useDatabaseBirthtime = process.platform !== "linux" && process.platform !== "android";
function databaseFileIdentityKey(file) {
return `${file.dev}:${file.ino}`;
}
function readDatabaseIdentityBirthtime(file) {
return useDatabaseBirthtime ? file.birthtimeNs.toString() : "0";
}
/** Native SQLite namespaces are filesystem locators, not distinct database owners. */
function normalizeDatabasePath(location) {
const normalized = process.platform === "win32" ? normalizeWindowsPathPreservingCase(location) : location;
return process.platform === "win32" && !/^(?:[a-z]:[\\/]|[\\/]{2})/iu.test(normalized) ? location : normalized;
}
function readDatabaseFileIdentity(value) {
if (!value || typeof value !== "object" || Array.isArray(value) || !("key" in value) || typeof value.key !== "string" || !/^file:(?:0|[1-9]\d{0,19}):(?:0|[1-9]\d{0,19})$/.test(value.key) || "birthtime" in value && value.birthtime !== void 0 && (typeof value.birthtime !== "string" || !/^-?(?:0|[1-9]\d{0,29})$/.test(value.birthtime))) throw new Error("SQLite snapshot requires a captured physical file identity");
return {
key: value.key,
..."birthtime" in value && typeof value.birthtime === "string" ? { birthtime: value.birthtime } : {}
};
}
function assertDatabaseFileIdentity(file, expected) {
if (!file.isFile() || `file:${databaseFileIdentityKey(file)}` !== expected.key || expected.birthtime !== void 0 && readDatabaseIdentityBirthtime(file) !== expected.birthtime) throw new Error("SQLite database file identity changed before existing-only open");
}
function existingIdentity(file, canonicalFile, canonicalPath) {
if (!file.isFile()) throw new Error("SQLite worker database path must identify a regular file");
if (file.dev !== canonicalFile.dev || file.ino !== canonicalFile.ino || readDatabaseIdentityBirthtime(file) !== readDatabaseIdentityBirthtime(canonicalFile)) throw new Error("SQLite database pathname changed during admission");
return {
key: `file:${databaseFileIdentityKey(file)}`,
canonicalPath: normalizeDatabasePath(canonicalPath),
birthtime: readDatabaseIdentityBirthtime(file)
};
}
function missingAncestorParent(ancestor, missing, error) {
if (!hasErrnoCode(error, "ENOENT")) throw error;
missing.unshift(path.basename(ancestor));
const parent = path.dirname(ancestor);
if (parent === ancestor) throw error;
return parent;
}
/** In-process owner key only; never rewrite a configured or persisted database locator. */
function resolveDatabasePathKey(databasePath) {
let ancestor = path.resolve(databasePath);
const missing = [];
while (true) try {
return normalizeDatabasePath(path.join(realpathSync.native(ancestor), ...missing));
} catch (error) {
ancestor = missingAncestorParent(ancestor, missing, error);
}
}
/** Inspect a native-owner path without replacing its diagnostic for a non-file target. */
function inspectDatabasePathIdentitySync(databasePath) {
const resolvedPath = path.resolve(databasePath);
let file;
try {
file = statSync(resolvedPath, { bigint: true });
} catch (error) {
if (!hasErrnoCode(error, "ENOENT")) throw error;
}
if (file) {
if (!file.isFile()) return;
const canonicalPath = resolveDatabasePathKey(resolvedPath);
return existingIdentity(file, statSync(canonicalPath, { bigint: true }), canonicalPath);
}
const canonicalPath = resolveDatabasePathKey(resolvedPath);
return {
key: `path:${canonicalPath}`,
canonicalPath
};
}
/** Capture identity before yielding; worker admission requires a regular file or absent path. */
function readDatabasePathIdentitySync(databasePath) {
const identity = inspectDatabasePathIdentitySync(databasePath);
if (!identity) throw new Error("SQLite worker database path must identify a regular file");
return identity;
}
/** Inspect retained aliases only while binding a newly observed database path. */
function findChangedDatabasePaths(paths, observed) {
return [...paths].filter((pathname) => inspectDatabasePathIdentitySync(pathname)?.key !== observed.key);
}
async function readDatabasePathIdentity(databasePath) {
const file = await stat(databasePath, { bigint: true }).catch((error) => {
if (hasErrnoCode(error, "ENOENT")) return;
throw error;
});
if (file) try {
const canonicalPath = await realpath(databasePath);
return existingIdentity(file, await stat(canonicalPath, { bigint: true }), canonicalPath);
} catch (error) {
if (hasErrnoCode(error, "ENOENT")) throw new Error("SQLite database pathname changed during admission", { cause: error });
throw error;
}
const missing = [];
let ancestor = databasePath;
while (true) try {
const canonicalPath = normalizeDatabasePath(path.join(await realpath(ancestor), ...missing));
return {
key: `path:${canonicalPath}`,
canonicalPath
};
} catch (error) {
ancestor = missingAncestorParent(ancestor, missing, error);
}
}
function assertExistingDatabaseIdentity(databasePath, expected, expectedBirthtime) {
assertDatabaseFileIdentity(statSync(databasePath, { bigint: true }), {
key: expected,
birthtime: expectedBirthtime
});
}
//#endregion
export { sqliteErrorCode as $, getPluginCacheRetirementSignal as A, materializeErrorStack as B, registerNodeSqliteKyselyQueryErrorHandler as C, PluginCacheFactInvalidatedError as D, resolveOpenClawPackageRootSync as E, invalidatePluginCacheMetadata as F, LAZY_ADDITIVE_STATE_TABLES as G, FIRST_USE_STATE_INDEXES as H, InvocationFrame as I, isSqliteCorruptionError as J, OPENCLAW_DATABASE_SCHEMA_DOCS_URL as K, getPluginExecutionFrame as L, getProcessPluginCache as M, getScopedPluginCache as N, bindPluginCacheRoot as O, getScopedPluginCaches as P, markSqliteNativeOpenFailure as Q, AsyncWorkScope as R, registerNodeSqliteDisposeCallback as S, resolveCompatibilityHostVersion as T, FIRST_USE_STATE_TABLES as U, DOCTOR_OWNED_STATE_TABLES as V, LAZY_ADDITIVE_STATE_INDEXES as W, isSqliteNativeOpenFailure as X, isSqliteLockError as Y, markSqliteInspectionOperation as Z, enableNodeSqliteKyselyStatementCache as _, readDatabaseFileIdentity as a, kyselyByDatabase as b, readDatabasePathIdentitySync as c, createNewerSqliteSchemaVersionError as d, sqliteExtendedResultCode as et, isSqliteSchemaVersionError as f, clearNodeSqliteKyselyCacheForDatabase as g, isStartupMaintenanceKind as h, normalizeDatabasePath as i, getPluginCacheRoot as j, getPluginCache as k, resolveDatabasePathKey as l, StartupMaintenanceRequiredError as m, findChangedDatabasePaths as n, withSqliteNativeOpen as nt, readDatabaseIdentityBirthtime as o, readSqliteUserVersion as p, OPENCLAW_SQLITE_BUSY_TIMEOUT_MS as q, inspectDatabasePathIdentitySync as r, readDatabasePathIdentity as s, assertExistingDatabaseIdentity as t, sqlitePrimaryResultCode as tt, SqliteSchemaVersionError as u, executeWithCachedStatement as v, VERSION as w, queryErrorHandlerByDatabase as x, installStatementInvalidation as y, runOutsideAsyncWorkScope as z };