UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

122 lines (121 loc) • 6.38 kB
import { a as getNodeSqliteKysely, i as executeSqliteQueryTakeFirstSync, r as executeSqliteQuerySync } from "./kysely-sync-K7ftY-g4.mjs"; import { l as runOpenClawStateWriteTransaction } from "./openclaw-state-db-D1jWDzK3.mjs"; import { t as createOpenClawStateSchemaEnsurer } from "./openclaw-state-feature-schema-gpylD4Gq.mjs"; import { n as assertOpenClawStateLeaseWorkerOwnedInTransaction } from "./openclaw-state-lease-worker-Bfyut3YB.mjs"; import { t as slugifyWorktreeTitle } from "./name-CNrUfUUC.mjs"; //#region src/projects/project-registry.kernel.ts const PROJECT_ID_MAX_LENGTH = 64; const ensureProjectRegistrySchema = createOpenClawStateSchemaEnsurer({ table: "projects", operationLabel: "projects.registry.schema.ensure" }); function rowToProject(row) { return { id: row.id, displayName: row.display_name, repoRoot: row.repo_root, ...row.origin_url ? { originUrl: row.origin_url } : {}, source: row.source }; } function insertProjectRegistryInDatabase(database, input) { const db = getNodeSqliteKysely(database); const sameRoot = executeSqliteQueryTakeFirstSync(database, db.selectFrom("projects").selectAll().where("repo_root", "=", input.repoRoot)); if (sameRoot) return rowToProject(sameRoot); if (input.source === "cloned" && input.originUrl) { const duplicate = executeSqliteQueryTakeFirstSync(database, db.selectFrom("projects").selectAll().where("origin_url", "=", input.originUrl)); if (duplicate) return rowToProject(duplicate); } const existing = new Set(executeSqliteQuerySync(database, db.selectFrom("projects").select("id")).rows.map((row) => row.id)); const baseId = slugifyWorktreeTitle(input.displayName) ?? "project"; let id = baseId; for (let suffixNumber = 2; existing.has(id); suffixNumber++) { const suffix = `-${suffixNumber}`; id = `${baseId.slice(0, PROJECT_ID_MAX_LENGTH - suffix.length).replace(/-+$/u, "")}${suffix}`; } const now = Date.now(); const row = { id, display_name: input.displayName, repo_root: input.repoRoot, origin_url: input.originUrl ?? null, source: input.source, created_at_ms: now, updated_at_ms: now }; executeSqliteQuerySync(database, db.insertInto("projects").values(row)); return rowToProject(row); } function listProjectRegistryInDatabase(database) { const db = getNodeSqliteKysely(database); return executeSqliteQuerySync(database, db.selectFrom("projects").selectAll()).rows.map(rowToProject); } function resolveProjectRegistryInDatabase(database, id) { const db = getNodeSqliteKysely(database); const row = executeSqliteQueryTakeFirstSync(database, db.selectFrom("projects").selectAll().where("id", "=", id)); return row ? rowToProject(row) : void 0; } function resolveRecordedProjectRootInDatabase(database, repoRoot) { const db = getNodeSqliteKysely(database); return executeSqliteQueryTakeFirstSync(database, db.selectFrom("projects").select("repo_root").where("repo_root", "=", repoRoot))?.repo_root; } function readMatchingProjectRow(database, project) { const db = getNodeSqliteKysely(database); const row = executeSqliteQueryTakeFirstSync(database, db.selectFrom("projects").selectAll().where("id", "=", project.id)); return row && row.id === project.id && row.repo_root === project.repoRoot && row.source === project.source && (row.origin_url ?? void 0) === project.originUrl ? row : void 0; } function resolveProjectCloneRefreshOwnerInDatabase(database, project) { const current = readMatchingProjectRow(database, project); return current?.source === "cloned" ? rowToProject(current) : void 0; } function removeProjectRegistryInDatabase(database, project) { if (!readMatchingProjectRow(database, project)) return false; const db = getNodeSqliteKysely(database); return executeSqliteQuerySync(database, db.deleteFrom("projects").where("id", "=", project.id)).numAffectedRows === 1n; } function removeProjectCheckoutReferenceInDatabase(database, project) { const db = getNodeSqliteKysely(database); const current = executeSqliteQueryTakeFirstSync(database, db.selectFrom("projects").selectAll().where("id", "=", project.id)); if (!current) return "missing"; if (current.source !== "cloned" || current.repo_root !== project.repoRoot) return "changed"; executeSqliteQuerySync(database, db.deleteFrom("projects").where("id", "=", project.id)); const sibling = executeSqliteQueryTakeFirstSync(database, db.selectFrom("projects").selectAll().where("repo_root", "=", project.repoRoot).orderBy("id", "asc")); if (!sibling) return "final"; if (sibling.source === "registered") executeSqliteQuerySync(database, db.updateTable("projects").set({ source: "cloned", origin_url: sibling.origin_url ?? current.origin_url, updated_at_ms: Date.now() }).where("id", "=", sibling.id)); return "remaining"; } //#endregion //#region src/projects/project-registry.worker.ts function checkoutTransaction(operationLabel, operation) { return ({ project, lease }, { open, stateOptions }) => runOpenClawStateWriteTransaction(({ db }) => { if (lease.scope !== "projects.checkout" || lease.key !== project.repoRoot) throw new Error("Project registry write requires its checkout lifecycle lease"); assertOpenClawStateLeaseWorkerOwnedInTransaction(db, lease); return operation(db, project); }, { database: open(), ...stateOptions() }, { operationLabel }); } function registryDatabase({ open, stateOptions }) { const database = open(); ensureProjectRegistrySchema({ database, ...stateOptions() }); return database.db; } const projectRegistryOperations = { "projects.findRoot": (input, context) => resolveRecordedProjectRootInDatabase(registryDatabase(context), input.repoRoot), "projects.list": (_input, context) => listProjectRegistryInDatabase(registryDatabase(context)), "projects.resolve": (input, context) => resolveProjectRegistryInDatabase(registryDatabase(context), input.id), "projects.insert": checkoutTransaction("projects.registry.insert", insertProjectRegistryInDatabase), "projects.remove": checkoutTransaction("projects.registry.remove", removeProjectRegistryInDatabase), "projects.resolveRefreshOwner": checkoutTransaction("projects.registry.refresh-owner.resolve", resolveProjectCloneRefreshOwnerInDatabase), "projects.removeCheckoutReference": checkoutTransaction("projects.registry.checkout-reference.remove", removeProjectCheckoutReferenceInDatabase) }; //#endregion export { projectRegistryOperations };