UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

753 lines (752 loc) 29.7 kB
import { i as extractErrorCode } from "../../error-coercion-D_-xJ90S.js"; import { c as isRecord, t as asNonArrayRecord } from "../../record-coerce-DItp3I4t.js"; import { l as normalizePluginsConfig, u as resolveEffectiveEnableState } from "../../config-state-BkU1frVq.js"; import { n as runExec } from "../../exec-BIE-3oLG.js"; import { t as jsonResult } from "../../tool-results-BCM3fdVS.js"; import "../../error-runtime-Bz9Tw57Z.js"; import "../../string-coerce-runtime-GQa0ehRA.js"; import { c as tryReadSecretFileSync } from "../../secret-file-QljTRMYg.js"; import "../../secret-file-runtime-CGwnexKX.js"; import { t as definePluginEntry } from "../../plugin-entry-zfBGJaNO.js"; import { n as resolveLivePluginConfigObject } from "../../plugin-config-runtime-BaaMs-tR.js"; import "../../channel-secret-basic-runtime-DF6iX0Bf.js"; import "../../process-runtime-pcN9RjT8.js"; import { t as resolveTrustedOnePasswordCli } from "../../onepassword-op-path-DihGaNSB.js"; import fs from "node:fs"; import path from "node:path"; import fs$1 from "node:fs/promises"; import os from "node:os"; import { createHash, randomUUID } from "node:crypto"; //#region extensions/onepassword/src/config.ts const SLUG_PATTERN = /^[a-z0-9][a-z0-9-]{0,63}$/; const MAX_DESCRIPTION_LENGTH = 200; function requiredString(record, key) { const value = record[key]; if (typeof value !== "string" || !value.trim()) throw new Error(`1Password config ${key} must be a non-empty string`); return value.trim(); } function readOptionalOnePasswordString(record, key) { const value = record[key]; if (value === void 0) return; if (typeof value !== "string" || !value.trim()) throw new Error(`1Password config ${key} must be a non-empty string`); return value.trim(); } function readPolicy(value, label, fallback) { if (value === void 0) return fallback; if (value === "auto" || value === "approve" || value === "deny") return value; throw new Error(`1Password config ${label} must be auto, approve, or deny`); } function readOnePasswordNumber(record, key, fallback, options) { const value = record[key] ?? fallback; if (typeof value !== "number" || !Number.isFinite(value) || options.integer && !Number.isInteger(value) || (options.allowZero ? value < 0 : value <= 0)) throw new Error(`1Password config ${key} must be a valid positive number`); return value; } function parseOnePasswordConfig(value) { if (!isRecord(value) || Object.keys(value).length === 0) return; if (!Object.hasOwn(value, "vault") && !Object.hasOwn(value, "items")) return; const vault = requiredString(value, "vault"); if (vault.startsWith("-")) throw new Error("1Password config vault must not start with a hyphen"); const defaultPolicy = readPolicy(value.defaultPolicy, "defaultPolicy", "approve"); if (!isRecord(value.items) || Object.keys(value.items).length === 0) throw new Error("1Password config items must contain at least one registered slug"); if (Object.keys(value.items).length > 32) throw new Error(`1Password config items must contain at most 32 registered slugs`); const items = Object.create(null); for (const [slug, rawItem] of Object.entries(value.items)) { if (!SLUG_PATTERN.test(slug)) throw new Error(`Invalid 1Password item slug: ${slug}`); if (!isRecord(rawItem)) throw new Error(`1Password config item ${slug} must be an object`); const item = requiredString(rawItem, "item"); if (item.startsWith("-")) throw new Error(`1Password config item ${slug} item must not start with a hyphen`); const itemVault = readOptionalOnePasswordString(rawItem, "vault") ?? vault; if (itemVault.startsWith("-")) throw new Error(`1Password config item ${slug} vault must not start with a hyphen`); const description = readOptionalOnePasswordString(rawItem, "description"); if (description && description.length > MAX_DESCRIPTION_LENGTH) throw new Error(`1Password config item ${slug} description must be at most ${MAX_DESCRIPTION_LENGTH} characters`); const field = readOptionalOnePasswordString(rawItem, "field") ?? "credential"; if (field.includes(",")) throw new Error(`1Password config item ${slug} field must not contain commas`); items[slug] = { item, vault: itemVault, field, policy: readPolicy(rawItem.policy, `items.${slug}.policy`, defaultPolicy), ...description ? { description } : {} }; } const opBin = readOptionalOnePasswordString(value, "opBin"); if (opBin && !path.isAbsolute(opBin)) throw new Error("1Password config opBin must be an absolute path"); return { vault, ...opBin ? { opBin } : {}, defaultPolicy, cacheTtlSeconds: readOnePasswordNumber(value, "cacheTtlSeconds", 300, { integer: true, allowZero: true }), grantTtlHours: readOnePasswordNumber(value, "grantTtlHours", 720, { integer: false, allowZero: false }), opTimeoutMs: readOnePasswordNumber(value, "opTimeoutMs", 15e3, { integer: true, allowZero: false }), items }; } //#endregion //#region extensions/onepassword/src/errors.ts var OnePasswordError = class extends Error { constructor(code, message, options) { super(message, options); this.name = "OnePasswordError"; this.code = code; } }; //#endregion //#region extensions/onepassword/src/pending-authorization.ts const AUTHORIZATION_NONCE_PARAM = "authorizationNonce"; function consumeUniquePendingAuthorization(store, request) { let match; for (const entry of store.entries()) { const candidate = entry.value; if (candidate.agentId !== request.agentId || candidate.toolCallId !== request.toolCallId || candidate.slug !== request.slug || candidate.reason !== request.reason) continue; if (match !== void 0) return; match = entry.key; } return match === void 0 ? void 0 : store.consume(match); } //#endregion //#region extensions/onepassword/src/broker.ts const APPROVAL_TIMEOUT_MS = 6e5; const PENDING_AUTHORIZATION_TTL_MS = APPROVAL_TIMEOUT_MS; function textParam(params, key) { const value = params[key]; return typeof value === "string" ? value.trim() : void 0; } var BrokerError = class extends Error { constructor(code, message) { super(message); this.name = "BrokerError"; this.code = code; } }; function internalError(code, message) { return new BrokerError(code, message); } function fingerprintOnePasswordTarget(item) { return createHash("sha256").update(JSON.stringify([ item.vault, item.item, item.field ])).digest("hex"); } function standingGrantKey(agentId, slug) { return createHash("sha256").update(JSON.stringify([agentId, slug])).digest("hex"); } function parseToolInput(params) { if (params.action === "list") return { action: "list" }; if (params.action !== "get") throw internalError("INVALID_ACTION", "action must be list or get"); const reason = textParam(params, "reason"); if (!reason || reason.length > 300) throw internalError("INVALID_REASON", "reason is required and must be at most 300 characters"); const slug = textParam(params, "slug"); if (!slug || !SLUG_PATTERN.test(slug)) throw internalError("INVALID_SLUG", "slug must match ^[a-z0-9][a-z0-9-]{0,63}$"); return { action: "get", slug, reason }; } function errorCode(error) { if (error instanceof OnePasswordError) return error.code; if (error instanceof BrokerError) return error.code; } var OnePasswordBroker = class { constructor(options) { this.cache = /* @__PURE__ */ new Map(); this.resolveConfig = options.resolveConfig; this.opClient = options.opClient; this.stores = options.stores; this.now = options.now ?? Date.now; } observeConfigFingerprint(fingerprint) { if (this.lastConfigFingerprint !== void 0 && this.lastConfigFingerprint !== fingerprint) this.cache.clear(); this.lastConfigFingerprint = fingerprint; } currentConfig() { const config = this.resolveConfig(); if (!config) { this.observeConfigFingerprint(null); throw internalError("POLICY_CHANGED", "1Password broker is no longer configured"); } const fingerprint = createHash("sha256").update(JSON.stringify(config)).digest("hex"); this.observeConfigFingerprint(fingerprint); return { config, fingerprint }; } registerPending(nonce, authorization) { this.stores.pending.register(nonce, authorization, { ttlMs: PENDING_AUTHORIZATION_TTL_MS }); } context(event, ctx, input) { return { agentId: ctx.agentId ?? "unknown", sessionKey: ctx.sessionKey ?? "unknown", sessionId: ctx.sessionId ?? "unknown", toolCallId: event.toolCallId ?? ctx.toolCallId ?? "unknown", slug: input.slug ?? "unknown", reason: input.reason ?? "" }; } async audit(context, outcome, options = {}) { const timestampMs = this.now(); const key = `${String(timestampMs).padStart(16, "0")}:${context.toolCallId}:${randomUUID()}`; await this.stores.audit.register(key, { timestampMs, agentId: context.agentId, sessionKey: context.sessionKey, toolCallId: context.toolCallId, slug: context.slug, reason: context.reason, outcome, ...options.errorCode ? { errorCode: options.errorCode } : {} }); } async pruneStaleGrants(config) { const now = this.now(); for (const entry of await this.stores.grants.entries()) { const item = Object.hasOwn(config.items, entry.value.slug) ? config.items[entry.value.slug] : void 0; if (!item || entry.key !== standingGrantKey(entry.value.agentId, entry.value.slug) || entry.value.expiresAtMs <= now || entry.value.targetFingerprint !== fingerprintOnePasswordTarget(item)) await this.stores.grants.delete(entry.key); } } async beforeToolCall(event, ctx) { if (event.toolName !== "onepassword") return; let input; try { input = parseToolInput(event.params); } catch (error) { const context = this.context(event, ctx, { slug: textParam(event.params, "slug"), reason: textParam(event.params, "reason") }); await this.audit(context, "error", { errorCode: errorCode(error) ?? "INVALID_ACTION" }); return { block: true, blockReason: error instanceof Error ? error.message : "Invalid request" }; } if (input.action === "list") return; const context = this.context(event, ctx, input); let config; let configFingerprint; try { ({config, fingerprint: configFingerprint} = this.currentConfig()); } catch (error) { await this.audit(context, "error", { errorCode: errorCode(error) }); return { block: true, blockReason: error instanceof Error ? error.message : "1Password broker is unavailable" }; } if (!Object.hasOwn(config.items, input.slug)) { await this.audit(context, "error", { errorCode: "UNKNOWN_SLUG" }); return { block: true, blockReason: `Unknown 1Password slug: ${input.slug}` }; } const item = config.items[input.slug]; if (!item) throw new Error(`Missing 1Password config for registered slug: ${input.slug}`); if (!event.toolCallId && !ctx.toolCallId) { await this.audit(context, "error", { errorCode: "TOOL_CALL_ID_MISSING" }); return { block: true, blockReason: "1Password request is missing a tool call id" }; } if (item.policy === "deny") { await this.audit(context, "policy-denied"); return { block: true, blockReason: `1Password access denied by policy for ${input.slug}` }; } const nonce = randomUUID(); const authorizedParams = { ...event.params, [AUTHORIZATION_NONCE_PARAM]: nonce }; if (item.policy === "auto") { this.registerPending(nonce, { ...context, outcome: "auto", persistGrant: false, configFingerprint, targetFingerprint: fingerprintOnePasswordTarget(item) }); return { params: authorizedParams }; } const grantKey = context.agentId === "unknown" ? void 0 : standingGrantKey(context.agentId, input.slug); const grant = grantKey ? await this.stores.grants.lookup(grantKey) : void 0; if (grant && grant.agentId === context.agentId && grant.slug === input.slug && grant.expiresAtMs > this.now() && grant.targetFingerprint === fingerprintOnePasswordTarget(item)) { this.registerPending(nonce, { ...context, outcome: "grant", persistGrant: false, configFingerprint, targetFingerprint: fingerprintOnePasswordTarget(item) }); return { params: authorizedParams }; } if (grant && grantKey) await this.stores.grants.delete(grantKey); return { params: authorizedParams, requireApproval: { title: `1Password: ${input.slug}`, description: `Agent ${context.agentId} requests ${input.slug}. Reason: ${input.reason}`, severity: "warning", timeoutMs: APPROVAL_TIMEOUT_MS, allowedDecisions: context.agentId === "unknown" ? ["allow-once", "deny"] : [ "allow-once", "allow-always", "deny" ], onResolution: async (decision) => { if (decision === "allow-once" || decision === "allow-always") { this.registerPending(nonce, { ...context, outcome: "approved", persistGrant: decision === "allow-always" && context.agentId !== "unknown", configFingerprint, targetFingerprint: fingerprintOnePasswordTarget(item) }); return; } if (decision === "deny") { await this.audit(context, "denied"); return; } if (decision === "timeout") { await this.audit(context, "timeout"); return; } await this.audit(context, "error", { errorCode: "APPROVAL_CANCELLED" }); } } }; } async list(invocation) { const { config } = this.currentConfig(); const grants = new Map((await this.stores.grants.entries()).map((entry) => [entry.key, entry.value])); const now = this.now(); const agentId = invocation.agentId; return Object.entries(config.items).toSorted(([left], [right]) => left.localeCompare(right)).map(([slug, item]) => { const grant = agentId ? grants.get(standingGrantKey(agentId, slug)) : void 0; return { slug, description: item.description ?? "", policy: item.policy, standingGrantActive: Boolean(grant && grant.agentId === agentId && grant.slug === slug && grant.expiresAtMs > now && grant.targetFingerprint === fingerprintOnePasswordTarget(item)) }; }); } async get(toolCallId, input, invocation, nonce) { const fallbackContext = { agentId: invocation.agentId ?? "unknown", sessionKey: invocation.sessionKey ?? "unknown", sessionId: invocation.sessionId ?? "unknown", toolCallId, slug: input.slug, reason: input.reason }; const authorization = nonce !== void 0 ? this.stores.pending.consume(nonce) : consumeUniquePendingAuthorization(this.stores.pending, fallbackContext); if (!authorization || authorization.slug !== input.slug || authorization.reason !== input.reason) { await this.audit(fallbackContext, "error", { errorCode: "POLICY_NOT_EVALUATED" }); throw internalError("POLICY_NOT_EVALUATED", "1Password policy was not evaluated for this request"); } let config; let configFingerprint; try { ({config, fingerprint: configFingerprint} = this.currentConfig()); } catch (error) { await this.audit(authorization, "error", { errorCode: errorCode(error) }); throw error; } if (!Object.hasOwn(config.items, input.slug)) { await this.audit(authorization, "error", { errorCode: "UNKNOWN_SLUG" }); throw internalError("UNKNOWN_SLUG", `Unknown 1Password slug: ${input.slug}`); } const item = config.items[input.slug]; if (!item) throw new Error(`Missing 1Password config for registered slug: ${input.slug}`); if (item.policy === "deny") { await this.audit(authorization, "policy-denied"); throw internalError("POLICY_CHANGED", `1Password access denied by policy for ${input.slug}`); } if (authorization.outcome === "auto" && item.policy !== "auto" || authorization.outcome !== "auto" && item.policy !== "approve" || authorization.configFingerprint !== configFingerprint || authorization.targetFingerprint !== fingerprintOnePasswordTarget(item)) { await this.audit(authorization, "error", { errorCode: "POLICY_CHANGED" }); throw internalError("POLICY_CHANGED", "1Password policy changed before tool execution"); } if (authorization.outcome === "grant") { const grant = await this.stores.grants.lookup(standingGrantKey(authorization.agentId, input.slug)); if (!grant || grant.agentId !== authorization.agentId || grant.slug !== input.slug || grant.expiresAtMs <= this.now() || grant.targetFingerprint !== fingerprintOnePasswordTarget(item)) { await this.audit(authorization, "error", { errorCode: "GRANT_EXPIRED" }); throw internalError("GRANT_EXPIRED", "1Password standing grant expired before tool execution"); } } if (authorization.persistGrant) { const grantedAtMs = this.now(); const ttlMs = Math.round(config.grantTtlHours * 60 * 60 * 1e3); try { await this.pruneStaleGrants(config); await this.stores.grants.register(standingGrantKey(authorization.agentId, input.slug), { agentId: authorization.agentId, slug: input.slug, grantedAtMs, expiresAtMs: grantedAtMs + ttlMs, targetFingerprint: fingerprintOnePasswordTarget(item) }, { ttlMs }); } catch (error) { await this.audit(authorization, "error", { errorCode: errorCode(error) }); throw error; } } const cached = this.cache.get(input.slug); const targetFingerprint = fingerprintOnePasswordTarget(item); if (cached && cached.expiresAtMs > this.now() && cached.targetFingerprint === targetFingerprint) { await this.audit(authorization, "cache-hit"); return { slug: input.slug, value: cached.value, itemTitle: cached.itemTitle, fieldLabel: cached.fieldLabel }; } this.cache.delete(input.slug); try { const secret = await this.opClient.getItem(item); await this.audit(authorization, authorization.outcome); if (config.cacheTtlSeconds > 0) this.cache.set(input.slug, { ...secret, targetFingerprint, expiresAtMs: this.now() + config.cacheTtlSeconds * 1e3 }); return { slug: input.slug, ...secret }; } catch (error) { await this.audit(authorization, "error", { errorCode: errorCode(error) }); throw error; } } }; //#endregion //#region extensions/onepassword/src/op-client.ts const MAX_STDOUT_BYTES = 1048576; async function defaultRunner(file, args, options) { return await runExec(file, args, { baseEnv: {}, env: options.env, logOutput: false, maxBuffer: options.maxBufferBytes, timeoutMs: options.timeoutMs }); } function isExecutable(filePath) { try { fs.accessSync(filePath, fs.constants.X_OK); return true; } catch { return false; } } function resolveOpBinary(configuredPath, pathEnv) { if (configuredPath) return isExecutable(configuredPath) ? configuredPath : void 0; const executable = process.platform === "win32" ? "op.exe" : "op"; for (const directory of pathEnv.split(path.delimiter)) { if (!directory) continue; const candidate = path.resolve(directory, executable); if (isExecutable(candidate)) return candidate; } } function errorRecord(error) { return error && typeof error === "object" ? error : {}; } function classifyOpError(error) { if (error instanceof OnePasswordError) return error; const record = errorRecord(error); const normalized = (typeof record.stderr === "string" ? record.stderr : "").toLowerCase(); if (record.code === "ENOENT") return new OnePasswordError("OP_NOT_FOUND", "1Password CLI executable was not found"); if (record.killed === true || record.timedOut === true || record.code === "ETIMEDOUT" || record.signal === "SIGTERM") return new OnePasswordError("TIMEOUT", "1Password CLI request timed out"); if (/item.+(is not found|isn't found|not found|does not exist)|could not find.+item|isn't an item\b/u.test(normalized)) return new OnePasswordError("ITEM_NOT_FOUND", "1Password item was not found"); if (/isn't a field\b|field.+(?:is not found|isn't found|not found|does not exist)/u.test(normalized)) return new OnePasswordError("FIELD_NOT_FOUND", "1Password field was not found"); if (/unauthorized|authentication|not signed in|invalid service account|permission denied/u.test(normalized)) return new OnePasswordError("AUTH_FAILED", "1Password service account authentication failed"); if (/\b429\b|rate[ -]?limit|too many requests/u.test(normalized)) return new OnePasswordError("RATE_LIMITED", "1Password rate limit reached"); return new OnePasswordError("OP_ERROR", "1Password CLI request failed"); } function parseField(stdout, requestedField, itemTitle) { let field; try { const parsed = JSON.parse(stdout); if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("field response is not an object"); field = parsed; } catch (error) { throw new OnePasswordError("OP_ERROR", "1Password CLI returned invalid JSON", { cause: error }); } if (field.label !== requestedField && field.id !== requestedField || typeof field.value !== "string") throw new OnePasswordError("FIELD_NOT_FOUND", `1Password field ${requestedField} was not found`); return { value: field.value, itemTitle, fieldLabel: typeof field.label === "string" ? field.label : requestedField }; } var OpClient = class { constructor(options) { this.permissionWarningEmitted = false; this.opBin = resolveOpBinary(options.opBin, options.pathEnv ?? process.env.PATH ?? ""); this.tokenFile = options.tokenFile; this.timeoutMs = options.timeoutMs; this.runner = options.runner ?? defaultRunner; this.home = options.home ?? os.homedir(); this.warn = options.warn ?? (() => void 0); } async tokenFilePresent() { try { await fs$1.access(this.tokenFile, fs.constants.R_OK); return true; } catch { return false; } } async readToken() { let contents; try { contents = tryReadSecretFileSync(this.tokenFile, "1Password service account token", { rejectHardlinks: false }); const stat = await fs$1.stat(this.tokenFile); if (!this.permissionWarningEmitted && process.platform !== "win32" && (stat.mode & 63) !== 0) { this.permissionWarningEmitted = true; this.warn("1Password service account token file permissions are broader than 0600"); } } catch (error) { throw new OnePasswordError("TOKEN_MISSING", error instanceof Error && extractErrorCode(error) === "too-large" ? error.message : "1Password service account token file is missing", { cause: error }); } if (!contents) throw new OnePasswordError("TOKEN_MISSING", "1Password service account token file is empty"); return contents; } async getItem(params) { if (!this.opBin) throw new OnePasswordError("OP_NOT_FOUND", "1Password CLI executable was not found"); let trustedOpBin; try { const resolved = await resolveTrustedOnePasswordCli({ configuredPath: this.opBin }); if (!resolved) throw new OnePasswordError("OP_NOT_FOUND", "1Password CLI executable was not found"); trustedOpBin = resolved; } catch (error) { if (error instanceof OnePasswordError) throw error; throw new OnePasswordError("OP_NOT_FOUND", "1Password CLI executable is not trusted", { cause: error }); } const token = await this.readToken(); const args = [ "item", "get", params.item, "--vault", params.vault, "--fields", params.field, "--format", "json", "--cache=false" ]; try { return parseField((await this.runner(trustedOpBin, args, { env: { OP_SERVICE_ACCOUNT_TOKEN: token, HOME: this.home, OP_LOAD_DESKTOP_APP_SETTINGS: "false", OP_BIOMETRIC_UNLOCK_ENABLED: "false" }, timeoutMs: this.timeoutMs, maxBufferBytes: MAX_STDOUT_BYTES })).stdout, params.field, params.item); } catch (error) { throw classifyOpError(error); } } }; //#endregion //#region extensions/onepassword/src/tool.ts const OnePasswordToolSchema = { type: "object", additionalProperties: false, required: ["action"], properties: { action: { type: "string", enum: ["list", "get"], description: "List registered secret slugs or get one registered secret." }, slug: { type: "string", pattern: "^[a-z0-9][a-z0-9-]{0,63}$", description: "Registered secret slug. Required for get." }, reason: { type: "string", minLength: 1, maxLength: 300, description: "Why the agent needs this secret. Required for get." }, authorizationNonce: { type: "string", description: "Internal. Injected by the gateway policy layer; never set this manually." } } }; function errorResult(error) { const code = error instanceof OnePasswordError ? error.code : error && typeof error === "object" && "code" in error && typeof error.code === "string" ? error.code : "OP_ERROR"; const message = error instanceof Error ? error.message : "1Password request failed"; return jsonResult({ ok: false, error: { code, message } }); } function redactPersistedOnePasswordResult(event) { if (event.message.role !== "toolResult" || (event.toolName ?? event.message.toolName) !== "onepassword") return; const details = event.message.details; const contentText = event.message.content.filter((part) => part.type === "text").map((part) => part.text).join("\n"); if (!(isRecord(details) && typeof details.value === "string" || /"value"\s*:/.test(contentText))) return; const safeDetails = asNonArrayRecord(details); const persisted = { ok: true, redacted: true, ...typeof safeDetails.slug === "string" ? { slug: safeDetails.slug } : {}, ...typeof safeDetails.itemTitle === "string" ? { itemTitle: safeDetails.itemTitle } : {}, ...typeof safeDetails.fieldLabel === "string" ? { fieldLabel: safeDetails.fieldLabel } : {} }; return { message: { ...event.message, content: [{ type: "text", text: JSON.stringify(persisted, null, 2) }], details: persisted } }; } function createOnePasswordTool(broker, invocation) { return { name: "onepassword", label: "1Password", description: "List curated 1Password secret slugs or retrieve one secret under its configured access policy.", parameters: OnePasswordToolSchema, execute: async (toolCallId, rawParams) => { const params = rawParams && typeof rawParams === "object" && !Array.isArray(rawParams) ? rawParams : {}; try { const input = parseToolInput(params); if (input.action === "list") return jsonResult({ ok: true, items: await broker.list(invocation) }); const nonceValue = params[AUTHORIZATION_NONCE_PARAM]; const nonce = typeof nonceValue === "string" ? nonceValue : void 0; const secret = await broker.get(toolCallId, input, invocation, nonce); return jsonResult({ ok: true, ...secret }); } catch (error) { return errorResult(error); } } }; } //#endregion //#region extensions/onepassword/index.ts const MAX_AUDIT_ROWS = 4e4; const MAX_STANDING_GRANTS = 1024; var onepassword_default = definePluginEntry({ id: "onepassword", name: "1Password", description: "1Password SecretRef resolver and curated agent broker with approval policy and SQLite audit history.", register(api) { const startupConfig = parseOnePasswordConfig(api.pluginConfig); const resolveCurrentConfig = () => { const liveConfig = api.runtime.config?.current ? api.runtime.config.current() : void 0; if (!liveConfig) return startupConfig; const livePluginConfig = resolveLivePluginConfigObject(() => liveConfig, "onepassword", api.pluginConfig); return resolveEffectiveEnableState({ id: "onepassword", origin: "bundled", config: normalizePluginsConfig(liveConfig.plugins), rootConfig: liveConfig, enabledByDefault: livePluginConfig !== void 0 }).enabled ? parseOnePasswordConfig(livePluginConfig) : void 0; }; const grants = api.runtime.state.openKeyedStore({ namespace: "grants", maxEntries: MAX_STANDING_GRANTS, overflowPolicy: "evict-oldest" }); const audit = api.runtime.state.openKeyedStore({ namespace: "audit", maxEntries: MAX_AUDIT_ROWS, overflowPolicy: "evict-oldest" }); const pending = api.runtime.state.openSyncKeyedStore({ namespace: "pending", maxEntries: 512, overflowPolicy: "evict-oldest" }); const tokenFile = path.join(api.runtime.state.resolveStateDir(process.env), "credentials", "onepassword", "service-account-token"); let cachedOpClient; const resolveCurrentOpClient = () => { const config = resolveCurrentConfig(); const key = JSON.stringify([config?.opBin ?? null, config?.opTimeoutMs ?? 15e3]); if (cachedOpClient?.key === key) return cachedOpClient.client; const client = new OpClient({ opBin: config?.opBin, tokenFile, timeoutMs: config?.opTimeoutMs ?? 15e3, warn: (message) => api.logger.warn(message) }); cachedOpClient = { key, client }; return client; }; const broker = startupConfig ? new OnePasswordBroker({ resolveConfig: resolveCurrentConfig, opClient: { getItem: (params) => resolveCurrentOpClient().getItem(params) }, stores: { audit, grants, pending } }) : void 0; api.registerCli(async ({ program, config }) => { const { registerOnePasswordCommands } = await import("../../cli-bFwHmIQF.js"); const { registerOnePasswordSecretRefCommands } = await import("../../secret-ref-cli-D9XpLG8r.js"); registerOnePasswordCommands({ program, resolveConfig: resolveCurrentConfig, resolveOpClient: resolveCurrentOpClient, auditStore: audit, registerAdditionalCommands: (command) => registerOnePasswordSecretRefCommands({ command, config, tokenFile }) }); }, { descriptors: [{ name: "onepassword", description: "Manage the 1Password integration", hasSubcommands: true }] }); if (!broker) return; api.registerTool((context) => createOnePasswordTool(broker, context), { name: "onepassword" }); api.on("before_tool_call", (event, ctx) => broker.beforeToolCall(event, ctx)); api.on("tool_result_persist", redactPersistedOnePasswordResult); } }); //#endregion export { onepassword_default as default };