UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

154 lines (153 loc) 8.43 kB
import { a as writeRuntimeJson, o as writeRuntimeStdout, r as defaultRuntime } from "./runtime-CF2WjnNZ.js"; import { t as formatErrorMessage } from "./errors-Db3Ymjlb.js"; import { h as clearNodeSqliteKyselyCacheForDatabase, t as openNodeSqliteDatabase, u as runSqliteImmediateTransactionSync } from "./node-sqlite-BpQX3W0e.js"; import { a as getNodeSqliteKysely, r as executeSqliteQuerySync } from "./kysely-sync-COmh4HWh.js"; import { g as resolveDatabasePath, l as assertOpenClawStateDatabaseForMaintenance } from "./openclaw-state-db-cache-C7ljO0xP.js"; import { a as OPENCLAW_DATABASE_SCHEMA_DOCS_URL, o as OPENCLAW_SQLITE_BUSY_TIMEOUT_MS } from "./openclaw-state-db-contract-DYCYxE4w.js"; import { t as assertSqliteIntegrity } from "./sqlite-integrity-NpEtFIdK.js"; import { d as OpenClawStateOwnershipMetadataError, f as STATE_SUPERVISION_KEY, g as inspectOpenClawStateOwnershipFromDatabase, h as inspectOpenClawStateOwnershipAtPath, i as openOpenClawStateDatabase, s as runOpenClawStateWriteTransaction, v as normalizeOpenClawStateManagerId, y as runWithOpenClawStateOwnershipCoordinator } from "./openclaw-state-db-BRTnL-D8.js"; import { r as configureSqliteWalMaintenance } from "./sqlite-wal-B4waQq_w.js"; import { o as isGatewayExternallySupervised } from "./gateway-supervision-D7p37rG2.js"; import { t as applyParentDefaultHelpAction } from "./parent-default-help-DQUF3qKA.js"; import { i as preflightOpenClawStateDatabasePath } from "./openclaw-database-preflight-DmhpNBQv.js"; //#region src/state/openclaw-state-ownership-operations.ts function requireOwnershipCheckpoint(walMaintenance, databasePath) { if (!walMaintenance.checkpoint()) throw new Error(`External ownership was committed for ${databasePath}, but its WAL checkpoint failed. Retry the same ownership claim before activating the supervisor.`); } function claimOwnershipRow(database, databasePath, managerId, repairMalformed) { let current = null; try { current = inspectOpenClawStateOwnershipFromDatabase(database, databasePath); } catch (error) { if (!repairMalformed || !(error instanceof OpenClawStateOwnershipMetadataError)) throw error; } if (current) { if (current.managerId !== managerId) throw new Error(`OpenClaw shared state is already claimed by external manager ${current.managerId}; manager ${managerId} cannot replace that durable ownership.`); return current; } const ownership = { version: 1, mode: "external", managerId, claimedAt: Date.now() }; const valueJson = JSON.stringify(ownership); const stateDb = getNodeSqliteKysely(database); executeSqliteQuerySync(database, stateDb.insertInto("config_machine_state").values({ state_key: STATE_SUPERVISION_KEY, value_json: valueJson, updated_at_ms: ownership.claimedAt }).onConflict((conflict) => conflict.column("state_key").doUpdateSet({ value_json: valueJson, updated_at_ms: ownership.claimedAt }))); return ownership; } function repairMalformedOwnershipClaim(databasePath, managerId) { return runWithOpenClawStateOwnershipCoordinator(databasePath, "malformed state ownership repair/checkpoint", () => { const database = openNodeSqliteDatabase(databasePath); let walMaintenance; try { database.exec(`PRAGMA busy_timeout = ${OPENCLAW_SQLITE_BUSY_TIMEOUT_MS};`); assertSqliteIntegrity(database, databasePath); assertOpenClawStateDatabaseForMaintenance(database, { pathname: databasePath }); walMaintenance = configureSqliteWalMaintenance(database, { busyTimeoutMs: OPENCLAW_SQLITE_BUSY_TIMEOUT_MS, checkpointIntervalMs: 0, checkpointMode: "TRUNCATE", databaseLabel: "OpenClaw shared state ownership", databasePath }); const ownership = runSqliteImmediateTransactionSync(database, () => { assertOpenClawStateDatabaseForMaintenance(database, { pathname: databasePath }); return claimOwnershipRow(database, databasePath, managerId, true); }, { busyTimeoutMs: OPENCLAW_SQLITE_BUSY_TIMEOUT_MS, databaseLabel: databasePath, operationLabel: "state.ownership.repair" }); requireOwnershipCheckpoint(walMaintenance, databasePath); return ownership; } finally { walMaintenance?.close({ checkpointMode: "PASSIVE" }); clearNodeSqliteKyselyCacheForDatabase(database); database.close(); } }); } /** Claim durable shared-state write ownership for the active external supervisor. */ function claimOpenClawStateOwnership(managerId, options = {}) { const env = options.env ?? process.env; if (!isGatewayExternallySupervised(env)) throw new Error("Claiming external shared-state ownership requires OPENCLAW_SUPERVISOR_MODE=external."); const normalizedManagerId = normalizeOpenClawStateManagerId(managerId); try { const database = openOpenClawStateDatabase(options); return runWithOpenClawStateOwnershipCoordinator(database.path, "state ownership claim/checkpoint", () => { const ownership = runOpenClawStateWriteTransaction(({ db, path: databasePath }) => claimOwnershipRow(db, databasePath, normalizedManagerId, false), { ...options, database }, { operationLabel: "state.ownership.claim" }); requireOwnershipCheckpoint(database.walMaintenance, database.path); return ownership; }); } catch (error) { if (!(error instanceof OpenClawStateOwnershipMetadataError)) throw error; const ownership = repairMalformedOwnershipClaim(resolveDatabasePath(options), normalizedManagerId); openOpenClawStateDatabase(options); return ownership; } } //#endregion //#region src/cli/program/register.database.ts function writeDatabaseError(error, json) { const message = formatErrorMessage(error); if (json) writeRuntimeJson(defaultRuntime, { error: message }); else defaultRuntime.error(message); defaultRuntime.exit(1); } async function runDatabasePreflight(databasePath, options) { const result = await preflightOpenClawStateDatabasePath(databasePath); if (options.json) writeRuntimeJson(defaultRuntime, result); else { const detail = result.reason ?? result.issues[0]?.message; writeRuntimeStdout(defaultRuntime, `Database preflight: ${result.status} (found ${result.foundVersion ?? "unknown"}, target ${result.targetVersion}).${detail ? `\n${detail}` : ""}\nSee ${OPENCLAW_DATABASE_SCHEMA_DOCS_URL}.\n`); } if (result.status === "incompatible" || result.status === "indeterminate") defaultRuntime.exit(1); } function runDatabaseOwnership(options) { try { const databasePath = resolveDatabasePath({ env: process.env }); const ownership = options.manager !== void 0 ? claimOpenClawStateOwnership(options.manager, { path: databasePath, env: process.env }) : inspectOpenClawStateOwnershipAtPath(databasePath); const status = ownership ? { status: "external", ownership } : { status: "unowned" }; if (options.json) { writeRuntimeJson(defaultRuntime, { databasePath, ...status }); return; } const message = status.status === "external" ? `Shared state is externally owned by ${status.ownership.managerId}.` : "Shared state is not externally owned."; writeRuntimeStdout(defaultRuntime, `${message}\nSee ${OPENCLAW_DATABASE_SCHEMA_DOCS_URL}.\n`); } catch (error) { writeDatabaseError(error, options.json === true); } } function registerDatabaseCommand(program) { const database = program.command("database").description("Inspect shared-state schema compatibility and write ownership").addHelpText("after", `\nDocs: ${OPENCLAW_DATABASE_SCHEMA_DOCS_URL}\n`); database.command("preflight").description("Compare one copied SQLite file with this release's state schema").argument("<path>", "explicit copied SQLite database path").option("--json", "emit machine-readable JSON", false).action(async (databasePath, options) => { await runDatabasePreflight(databasePath, options); }); const ownership = database.command("ownership").description("Inspect or claim write ownership"); ownership.command("status").description("Show durable shared-state write ownership").option("--json", "emit machine-readable JSON", false).action((options) => runDatabaseOwnership(options)); ownership.command("claim").description("Claim shared-state writes for the active external supervisor").requiredOption("--manager <id>", "stable external manager identifier").option("--json", "emit machine-readable JSON", false).action((options) => runDatabaseOwnership(options)); applyParentDefaultHelpAction(ownership); applyParentDefaultHelpAction(database); } //#endregion export { registerDatabaseCommand };