Files
openclaw/src/agents/pi-auth-json.ts
Peter Steinberger 538605ff44 [codex] Extract filesystem safety primitives (#77918)
* refactor: extract filesystem safety primitives

* refactor: use fs-safe for file access helpers

* refactor: reuse fs-safe for media reads

* refactor: use fs-safe for image reads

* refactor: reuse fs-safe in qqbot media opener

* refactor: reuse fs-safe for local media checks

* refactor: consume cleaner fs-safe api

* refactor: align fs-safe json option names

* fix: preserve fs-safe migration contracts

* refactor: use fs-safe primitive subpaths

* refactor: use grouped fs-safe subpaths

* refactor: align fs-safe api usage

* refactor: adapt private state store api

* chore: refresh proof gate

* refactor: follow fs-safe json api split

* refactor: follow reduced fs-safe surface

* build: default fs-safe python helper off

* fix: preserve fs-safe plugin sdk aliases

* refactor: consolidate fs-safe usage

* refactor: unify fs-safe store usage

* refactor: trim fs-safe temp workspace usage

* refactor: hide low-level fs-safe primitives

* build: use published fs-safe package

* fix: preserve outbound recovery durability after rebase

* chore: refresh pr checks
2026-05-06 02:15:17 +01:00

84 lines
2.5 KiB
TypeScript

import path from "node:path";
import { z } from "zod";
import { privateFileStore } from "../infra/private-file-store.js";
import { safeParseWithSchema } from "../utils/zod-parse.js";
import { ensureAuthProfileStore } from "./auth-profiles/store.js";
import {
piCredentialsEqual,
resolvePiCredentialMapFromStore,
type PiCredential,
} from "./pi-auth-credentials.js";
type AuthJsonShape = Record<string, unknown>;
const PiCredentialSchema: z.ZodType<PiCredential> = z.discriminatedUnion("type", [
z.object({
type: z.literal("api_key"),
key: z.string(),
}),
z.object({
type: z.literal("oauth"),
access: z.string(),
refresh: z.string(),
expires: z.number(),
}),
]);
const AuthJsonShapeSchema = z.record(z.string(), z.unknown());
async function readAuthJson(rootDir: string, filePath: string): Promise<AuthJsonShape> {
try {
const parsed = await privateFileStore(rootDir).readJsonIfExists(
path.relative(rootDir, filePath),
);
return safeParseWithSchema(AuthJsonShapeSchema, parsed) ?? {};
} catch {
return {};
}
}
/**
* pi-coding-agent's ModelRegistry/AuthStorage expects credentials in auth.json.
*
* OpenClaw stores credentials in auth-profiles.json instead. This helper
* bridges all credentials into agentDir/auth.json so pi-coding-agent can
* (a) consider providers authenticated and (b) include built-in models in its
* registry/catalog output.
*
* Syncs all credential types: api_key, token (as api_key), and oauth.
*
* @deprecated Runtime auth now comes from OpenClaw auth-profiles snapshots.
*/
export async function ensurePiAuthJsonFromAuthProfiles(agentDir: string): Promise<{
wrote: boolean;
authPath: string;
}> {
const store = ensureAuthProfileStore(agentDir, { allowKeychainPrompt: false });
const authPath = path.join(agentDir, "auth.json");
const providerCredentials = resolvePiCredentialMapFromStore(store);
if (Object.keys(providerCredentials).length === 0) {
return { wrote: false, authPath };
}
const existing = await readAuthJson(agentDir, authPath);
let changed = false;
for (const [provider, cred] of Object.entries(providerCredentials)) {
const current = safeParseWithSchema(PiCredentialSchema, existing[provider]) ?? undefined;
if (!piCredentialsEqual(current, cred)) {
existing[provider] = cred;
changed = true;
}
}
if (!changed) {
return { wrote: false, authPath };
}
await privateFileStore(agentDir).writeJson(path.basename(authPath), existing, {
trailingNewline: true,
});
return { wrote: true, authPath };
}