1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
// pi's `getAgentDir()` is replicated rather than imported: a runtime import of the host package does not resolve for extensions installed via `pi install npm:...`.
import { homedir } from "node:os";
import { join } from "node:path";
const ENV_AGENT_DIR = "PI_CODING_AGENT_DIR";
// Deliberately mirrors pi's expandTildePath (never `~\…`) rather than improving on it, or the pin lands somewhere pi does not look.
const expandTildePiCompatible = (path: string): string => {
if (path === "~") return homedir();
if (path.startsWith("~/")) return homedir() + path.slice(1);
return path;
};
const expandTildeLenient = (path: string): string => {
if (path === "~") return homedir();
if (path.startsWith("~/") || path.startsWith("~\\")) return join(homedir(), path.slice(2));
return path;
};
export const agentDir = (): string => {
const fromEnv = process.env[ENV_AGENT_DIR];
if (fromEnv) return expandTildePiCompatible(fromEnv);
return join(homedir(), ".pi", "agent");
};
export const pinFilePath = (): string => join(agentDir(), "browser-harness.json");
/**
* FORK: where the chosen CDP target is persisted (see src/cdp/target-store.ts).
* A separate file from the profile pin: the two have different lifetimes, and a
* corrupt target must not cost you your profile selection or vice versa.
*/
export const targetFilePath = (): string => join(agentDir(), "browser-target.json");
const localAppData = (): string => process.env["LOCALAPPDATA"] ?? join(homedir(), "AppData", "Local");
export const userDataDirCandidates = (): ReadonlyArray<string> => {
const home = homedir();
const dirs: string[] = [];
const envOverride = process.env["CHROME_USER_DATA_DIR"];
if (envOverride) dirs.push(expandTildeLenient(envOverride));
if (process.platform === "darwin") {
const support = join(home, "Library", "Application Support");
dirs.push(
join(support, "Google/Chrome"),
join(support, "Google/Chrome Beta"),
join(support, "Google/Chrome Dev"),
join(support, "Google/Chrome Canary"),
join(support, "Chromium"),
join(support, "BraveSoftware/Brave-Browser"),
join(support, "BraveSoftware/Brave-Browser-Beta"),
join(support, "BraveSoftware/Brave-Browser-Nightly"),
join(support, "BraveSoftware/Brave-Browser-Dev"),
join(support, "Microsoft Edge"),
join(support, "Microsoft Edge Beta"),
join(support, "Microsoft Edge Dev"),
join(support, "Microsoft Edge Canary"),
);
} else if (process.platform === "win32") {
const lad = localAppData();
dirs.push(
join(lad, "Google/Chrome/User Data"),
join(lad, "Google/Chrome Beta/User Data"),
join(lad, "Google/Chrome Dev/User Data"),
join(lad, "Google/Chrome SxS/User Data"),
join(lad, "Chromium/User Data"),
join(lad, "BraveSoftware/Brave-Browser/User Data"),
join(lad, "BraveSoftware/Brave-Browser-Beta/User Data"),
join(lad, "Microsoft/Edge/User Data"),
join(lad, "Microsoft/Edge Beta/User Data"),
join(lad, "Microsoft/Edge Dev/User Data"),
join(lad, "Microsoft/Edge SxS/User Data"),
);
} else {
dirs.push(
join(home, ".config/google-chrome"),
join(home, ".config/google-chrome-beta"),
join(home, ".config/google-chrome-unstable"),
join(home, ".config/chromium"),
join(home, ".config/chromium-browser"),
join(home, ".config/BraveSoftware/Brave-Browser"),
join(home, ".config/BraveSoftware/Brave-Browser-Beta"),
join(home, ".config/BraveSoftware/Brave-Browser-Nightly"),
join(home, ".config/microsoft-edge"),
join(home, ".config/microsoft-edge-beta"),
join(home, ".config/microsoft-edge-dev"),
join(home, "snap/chromium/common/chromium"),
join(home, ".var/app/org.chromium.Chromium/config/chromium"),
join(home, ".var/app/com.google.Chrome/config/google-chrome"),
join(home, ".var/app/com.brave.Browser/config/BraveSoftware/Brave-Browser"),
join(home, ".var/app/com.microsoft.Edge/config/microsoft-edge"),
);
}
return Array.from(new Set(dirs));
};
export const browserNameForUserDataDir = (userDataDir: string): string => {
const p = userDataDir.replace(/\\/g, "/");
const has = (needle: string): boolean => p.toLowerCase().includes(needle);
if (has("brave")) return "Brave";
if (has("edge")) return "Edge";
if (has("chromium")) return "Chromium";
if (has("chrome")) return "Chrome";
const last = p.split("/").filter(Boolean).pop();
return last ?? userDataDir;
};
|