Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
node_modules
coverage
.pi/readcache/
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,20 @@ pi install git:https://github.com/Gurpartap/pi-readcache

After installation, you can use pi normally. If pi is already running when you install or update, run `/reload` in that session.

### Custom Cache Storage

By default, `pi-readcache` stores its cache in `.pi/readcache` within your project root.

To override this, add a `readcacheDir` key to your `~/.pi/agent/settings.json` file:

```json
{
"readcacheDir": "/path/to/your/custom/cache"
}
```

The extension will respect this path and create the necessary subdirectories there.

## Day-to-day usage

| Action | Command | Expected result |
Expand Down
5 changes: 4 additions & 1 deletion src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ export const DEFAULT_EXCLUDED_PATH_PATTERNS = [
".netrc",
] as const;

export const READCACHE_ROOT_DIR = ".pi/readcache";
import { getReadcacheCacheDir } from "./pi-config.js";

// ...
export const READCACHE_ROOT_DIR = await getReadcacheCacheDir();
export const READCACHE_OBJECTS_DIR = `${READCACHE_ROOT_DIR}/objects`;
export const READCACHE_TMP_DIR = `${READCACHE_ROOT_DIR}/tmp`;
export const READCACHE_OBJECT_MAX_AGE_MS = 24 * 60 * 60 * 1000;
Expand Down
42 changes: 42 additions & 0 deletions src/pi-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { homedir } from "node:os";
import { join } from "node:path";
import { readFile } from "node:fs/promises";

// Configuration constants following Pi standards
const CONFIG_DIR_NAME = ".pi";
const ENV_AGENT_DIR = "PI_CODING_AGENT_DIR";

/**
* Returns the standard agent config directory (~/.pi/agent/).
*/
export function getAgentDir(): string {
const envDir = process.env[ENV_AGENT_DIR];
if (envDir) {
if (envDir === "~") return homedir();
if (envDir.startsWith("~/")) return homedir() + envDir.slice(1);
return envDir;
}
return join(homedir(), CONFIG_DIR_NAME, "agent");
}

/**
* Returns the standard path to settings.json (~/.pi/agent/settings.json).
*/
export function getSettingsPath(): string {
return join(getAgentDir(), "settings.json");
}

/**
* Reads the settings.json file and returns the 'readcacheDir' key,
* defaulting to the standard local cache path if not set.
*/
export async function getReadcacheCacheDir(): Promise<string> {
const defaultDir = ".pi/readcache";
try {
const content = await readFile(getSettingsPath(), "utf-8");
const settings = JSON.parse(content);
return settings.readcacheDir || defaultDir;
} catch {
return defaultDir;
}
}
51 changes: 51 additions & 0 deletions test/unit/pi-config.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { getReadcacheCacheDir } from "../../src/pi-config.js";
import { readFile } from "node:fs/promises";
import { homedir } from "node:os";
import { join } from "node:path";

vi.mock("node:fs/promises");

describe("getReadcacheCacheDir", () => {
const originalEnv = process.env;

beforeEach(() => {
process.env = { ...originalEnv };
vi.resetAllMocks();
});

afterEach(() => {
process.env = originalEnv;
});

it("returns default path when settings.json does not exist", async () => {
vi.mocked(readFile).mockRejectedValue(new Error("File not found"));
const dir = await getReadcacheCacheDir();
expect(dir).toBe(".pi/readcache");
});

it("returns default path when readcacheDir is missing in settings", async () => {
vi.mocked(readFile).mockResolvedValue("{}");
const dir = await getReadcacheCacheDir();
expect(dir).toBe(".pi/readcache");
});

it("returns custom path from settings.json", async () => {
vi.mocked(readFile).mockResolvedValue(JSON.stringify({ readcacheDir: "/tmp/custom-cache" }));
const dir = await getReadcacheCacheDir();
expect(dir).toBe("/tmp/custom-cache");
});

it("respects PI_CODING_AGENT_DIR override for settings location", async () => {
process.env.PI_CODING_AGENT_DIR = "/custom/agent";
vi.mocked(readFile).mockImplementation(async (path: string) => {
if (path === join("/custom/agent", "settings.json")) {
return JSON.stringify({ readcacheDir: "/env/cache" });
}
throw new Error("File not found");
});

const dir = await getReadcacheCacheDir();
expect(dir).toBe("/env/cache");
});
});