fix(extensions): created legacy auth database directory

Create the resolved agent database parent before the synchronous compatibility store opens SQLite, and cover a fresh nested agent directory.

Fixes #5879
This commit is contained in:
roboomp
2026-07-17 17:06:15 +00:00
parent 7e8c4fc01f
commit aaac0ace1d
2 changed files with 26 additions and 7 deletions
@@ -13,7 +13,7 @@
*/
import { Database } from "bun:sqlite";
import * as fs from "node:fs/promises";
import * as fs from "node:fs";
import * as path from "node:path";
import type { AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
import { type AuthCredential, SqliteAuthCredentialStore, type TSchema } from "@oh-my-pi/pi-ai";
@@ -612,16 +612,16 @@ export function createLsToolDefinition(cwd: string, options?: LsToolOptions): To
const ops = options?.operations;
const exists = ops
? await ops.exists(absolutePath)
: await fs.stat(absolutePath).then(
: await fs.promises.stat(absolutePath).then(
() => true,
() => false,
);
if (!exists) throw new Error(`Path not found: ${absolutePath}`);
const stat = ops ? await ops.stat(absolutePath) : await fs.stat(absolutePath);
const stat = ops ? await ops.stat(absolutePath) : await fs.promises.stat(absolutePath);
if (!stat.isDirectory()) {
return { content: [{ type: "text", text: rawPath }] };
}
const entries = ops ? await ops.readdir(absolutePath) : await fs.readdir(absolutePath);
const entries = ops ? await ops.readdir(absolutePath) : await fs.promises.readdir(absolutePath);
const sorted = [...entries].sort((a, b) => a.localeCompare(b));
const limited = sorted.slice(0, limit);
const output = limited.join("\n");
@@ -1106,7 +1106,7 @@ export class DefaultResourceLoader implements ResourceLoader {
: path.resolve(this.#state.cwd, resourcePath);
const files: string[] = [];
try {
const stat = await fs.stat(resolvedPath);
const stat = await fs.promises.stat(resolvedPath);
if (stat.isDirectory()) {
const glob = new Bun.Glob("**/*.md");
for await (const entry of glob.scan({ cwd: resolvedPath, absolute: false, onlyFiles: true })) {
@@ -1301,6 +1301,10 @@ export async function createAgentSession(
* call `AuthStorage.create().get()` during module initialization.
*/
export class AuthStorage {
constructor() {
fs.mkdirSync(path.dirname(getAgentDbPath()), { recursive: true, mode: 0o700 });
}
static create(): AuthStorage {
return new AuthStorage();
}
@@ -1,11 +1,17 @@
import { describe, expect, it } from "bun:test";
import * as path from "node:path";
import { loadExtensions } from "@oh-my-pi/pi-coding-agent/extensibility/extensions/loader";
import { TempDir } from "@oh-my-pi/pi-utils";
import { __resetDirsFromEnvForTests, setAgentDir, TempDir } from "@oh-my-pi/pi-utils";
describe("issue #5879: legacy provider compatibility", () => {
it("loads an extension that calls historical stream and auth exports", async () => {
it("creates a fresh agent database while loading historical auth exports", async () => {
const projectDir = TempDir.createSync("@issue-5879-");
const freshAgentDir = projectDir.join("fresh", "agent");
const originalDirEnv: Record<string, string | undefined> = {
PI_CODING_AGENT_DIR: process.env.PI_CODING_AGENT_DIR,
OMP_PROFILE: process.env.OMP_PROFILE,
PI_PROFILE: process.env.PI_PROFILE,
};
const extensionPath = path.join(projectDir.path(), "pi-provider-like-plugin", "index.ts");
await Bun.write(
extensionPath,
@@ -22,12 +28,21 @@ describe("issue #5879: legacy provider compatibility", () => {
].join("\n"),
);
setAgentDir(freshAgentDir);
try {
const result = await loadExtensions([extensionPath], projectDir.path());
expect(result.errors).toEqual([]);
expect(result.extensions).toHaveLength(1);
expect(await Bun.file(path.join(freshAgentDir, "agent.db")).exists()).toBe(true);
} finally {
for (const key in originalDirEnv) {
const value = originalDirEnv[key];
if (value === undefined) delete process.env[key];
else process.env[key] = value;
}
__resetDirsFromEnvForTests();
projectDir.removeSync();
}
});