@codexhost/cli-linux-arm64 0.10.2 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/README.md +1 -1
  2. package/THIRD_PARTY_NOTICES.txt +4 -0
  3. package/app/codexhost-distribution.json +1 -1
  4. package/app/console-server.mjs +18001 -0
  5. package/app/console-web.js +27674 -0
  6. package/app/desktop-controller.mjs +452 -110
  7. package/app/host-runtime.mjs +6670 -1272
  8. package/app/plugins/antigravity/plugin.mjs +686 -305
  9. package/app/plugins/claude-code/plugin.mjs +2283 -1450
  10. package/app/plugins/codebuddy/plugin.mjs +1272 -506
  11. package/app/plugins/cursor-cli/manifest.json +1 -1
  12. package/app/plugins/cursor-cli/plugin.mjs +1295 -497
  13. package/app/plugins/deepseek-harness/plugin.mjs +4718 -4925
  14. package/app/plugins/enabled.json +2 -1
  15. package/app/plugins/grok/plugin.mjs +1012 -369
  16. package/app/plugins/hermes/plugin.mjs +18587 -22714
  17. package/app/plugins/kimi-code/plugin.mjs +1283 -355
  18. package/app/plugins/kiro-cli/plugin.mjs +840 -299
  19. package/app/plugins/omp/plugin.mjs +1045 -328
  20. package/app/plugins/opencode/plugin.mjs +5341 -1686
  21. package/app/plugins/pi/plugin.mjs +1343 -534
  22. package/app/plugins/qoder/plugin.mjs +913 -258
  23. package/app/plugins/qoder-cn/plugin.mjs +712 -49
  24. package/app/plugins/workbuddy/plugin.mjs +531 -44
  25. package/app/plugins/zcode/assets/icon.svg +8 -0
  26. package/app/plugins/zcode/manifest.json +14 -0
  27. package/app/plugins/zcode/plugin.mjs +19202 -0
  28. package/app/renderer-extension.js +5011 -1899
  29. package/bin/codexhost +0 -0
  30. package/libexec/codexhost-shim +0 -0
  31. package/libexec/codexhost-updater +0 -0
  32. package/licenses/OpenCode-v2-Client-LICENSE.txt +21 -0
  33. package/package.json +1 -1
@@ -5,15 +5,413 @@ var __export = (target, all) => {
5
5
  __defProp(target, name, { get: all[name], enumerable: true });
6
6
  };
7
7
 
8
- // dist/pi-credential-imports.js
9
- import { randomUUID } from "node:crypto";
10
- import { execFile } from "node:child_process";
11
- import { promisify } from "node:util";
12
- import { existsSync, readFileSync, writeFileSync, mkdirSync, rmSync, readdirSync, lstatSync, renameSync, rmdirSync } from "node:fs";
13
- import { realpath } from "node:fs/promises";
14
- import os2 from "node:os";
8
+ // ../../harness-discovery/dist/environment.js
9
+ import fs from "node:fs";
10
+ import path from "node:path";
11
+ function targetPath(platform) {
12
+ return platform === "win32" ? path.win32 : path.posix;
13
+ }
14
+ function environmentValue(environment, name) {
15
+ const lowered = name.toLowerCase();
16
+ for (const [key, value] of Object.entries(environment)) {
17
+ if (key.toLowerCase() === lowered)
18
+ return value;
19
+ }
20
+ return void 0;
21
+ }
22
+ function pathDelimiter(platform) {
23
+ return platform === "win32" ? ";" : ":";
24
+ }
25
+ function pathDirectories(environment, platform) {
26
+ return (environmentValue(environment, "PATH") ?? "").split(pathDelimiter(platform)).map((directory) => directory.trim().replace(/^"|"$/gu, "")).filter(Boolean);
27
+ }
28
+ function executableExtensions(command, platform, environment) {
29
+ if (platform !== "win32")
30
+ return [""];
31
+ if (targetPath(platform).extname(command) !== "")
32
+ return [""];
33
+ return (environmentValue(environment, "PATHEXT") ?? ".COM;.EXE;.BAT;.CMD").split(";").map((extension) => extension.trim()).filter(Boolean);
34
+ }
35
+ function isExecutableFile(filePath, platform) {
36
+ try {
37
+ fs.accessSync(filePath, platform === "win32" ? fs.constants.F_OK : fs.constants.X_OK);
38
+ return fs.statSync(filePath).isFile();
39
+ } catch {
40
+ return false;
41
+ }
42
+ }
43
+ function subdirectoryNames(directory) {
44
+ try {
45
+ return fs.readdirSync(directory, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
46
+ } catch {
47
+ return [];
48
+ }
49
+ }
50
+ function newestFirst(names) {
51
+ return [...names].sort((left, right) => right.localeCompare(left, void 0, { numeric: true }));
52
+ }
53
+
54
+ // ../../harness-discovery/dist/invocation.js
55
+ import path2 from "node:path";
56
+ function commandInvocation(command, arguments_, environment, platform = process.platform) {
57
+ const extension = path2.win32.extname(command).toLowerCase();
58
+ if (platform !== "win32" || ![".cmd", ".bat"].includes(extension)) {
59
+ return { command, arguments: [...arguments_], windowsVerbatimArguments: false };
60
+ }
61
+ const quote = (value) => `"${value.replaceAll("%", "%%").replaceAll('"', '""')}"`;
62
+ const commandLine = [command, ...arguments_].map(quote).join(" ");
63
+ return {
64
+ command: environmentValue(environment, "ComSpec") ?? "cmd.exe",
65
+ arguments: ["/d", "/v:off", "/s", "/c", `"${commandLine}"`],
66
+ windowsVerbatimArguments: true
67
+ };
68
+ }
69
+
70
+ // ../../harness-discovery/dist/node-runtime.js
15
71
  import path3 from "node:path";
16
- import { pathToFileURL } from "node:url";
72
+ function withNodeRuntimeOnPath(environment, runtimeExecutable = process.execPath, platform = process.platform) {
73
+ const pathKey = Object.keys(environment).find((name) => name.toLowerCase() === "path") ?? "PATH";
74
+ const delimiter = platform === "win32" ? ";" : ":";
75
+ const runtimeDirectory = path3.dirname(runtimeExecutable);
76
+ const directories = (environment[pathKey] ?? "").split(delimiter).filter(Boolean);
77
+ const equal = platform === "win32" ? (value) => value.toLowerCase() : (value) => value;
78
+ if (!directories.some((directory) => equal(directory) === equal(runtimeDirectory))) {
79
+ directories.push(runtimeDirectory);
80
+ }
81
+ return { ...environment, [pathKey]: directories.join(delimiter) };
82
+ }
83
+
84
+ // ../../harness-discovery/dist/resolve.js
85
+ import os from "node:os";
86
+
87
+ // ../../harness-discovery/dist/version-managers.js
88
+ function versionManagerBinaryDirectories(context) {
89
+ const { platform, environment, home } = context;
90
+ const list = context.subdirectories ?? subdirectoryNames;
91
+ const pathFlavor = targetPath(platform);
92
+ const value = (name) => environmentValue(environment, name);
93
+ const directories = [];
94
+ const versioned = (root, ...tail) => {
95
+ for (const version2 of newestFirst(list(root))) {
96
+ directories.push(pathFlavor.join(root, version2, ...tail));
97
+ }
98
+ };
99
+ if (platform === "win32") {
100
+ const appData = value("APPDATA") ?? pathFlavor.join(home, "AppData", "Roaming");
101
+ const localAppData = value("LOCALAPPDATA") ?? pathFlavor.join(home, "AppData", "Local");
102
+ versioned(pathFlavor.join(appData, "nvm"));
103
+ versioned(value("FNM_DIR") ?? pathFlavor.join(appData, "fnm", "node-versions"), "installation");
104
+ directories.push(pathFlavor.join(localAppData, "Volta", "bin"));
105
+ directories.push(pathFlavor.join(home, ".bun", "bin"));
106
+ const pnpmHome2 = value("PNPM_HOME");
107
+ if (pnpmHome2)
108
+ directories.push(pnpmHome2);
109
+ directories.push(pathFlavor.join(localAppData, "pnpm"));
110
+ return directories;
111
+ }
112
+ versioned(pathFlavor.join(value("NVM_DIR") ?? pathFlavor.join(home, ".nvm"), "versions", "node"), "bin");
113
+ const fnmRoots = [
114
+ value("FNM_DIR"),
115
+ pathFlavor.join(home, ".local", "share", "fnm"),
116
+ pathFlavor.join(home, "Library", "Application Support", "fnm")
117
+ ].filter((root) => root !== void 0);
118
+ for (const root of fnmRoots) {
119
+ versioned(pathFlavor.join(root, "node-versions"), "installation", "bin");
120
+ }
121
+ const voltaHome = value("VOLTA_HOME") ?? pathFlavor.join(home, ".volta");
122
+ versioned(pathFlavor.join(voltaHome, "tools", "image", "node"), "bin");
123
+ directories.push(pathFlavor.join(voltaHome, "bin"));
124
+ const asdfHome = value("ASDF_DATA_DIR") ?? pathFlavor.join(home, ".asdf");
125
+ versioned(pathFlavor.join(asdfHome, "installs", "nodejs"), "bin");
126
+ directories.push(pathFlavor.join(asdfHome, "shims"));
127
+ const nodenvHome = value("NODENV_ROOT") ?? pathFlavor.join(home, ".nodenv");
128
+ versioned(pathFlavor.join(nodenvHome, "versions"), "bin");
129
+ directories.push(pathFlavor.join(nodenvHome, "shims"));
130
+ versioned(pathFlavor.join(value("N_PREFIX") ?? "/usr/local", "n", "versions", "node"), "bin");
131
+ directories.push(pathFlavor.join(home, ".bun", "bin"));
132
+ const pnpmHome = value("PNPM_HOME");
133
+ if (pnpmHome)
134
+ directories.push(pnpmHome);
135
+ directories.push(pathFlavor.join(home, "Library", "pnpm"));
136
+ directories.push(pathFlavor.join(home, ".local", "share", "pnpm"));
137
+ for (const prefix of ["/opt/homebrew/opt", "/usr/local/opt"]) {
138
+ for (const formula of newestFirst(list(prefix).filter((name) => name.startsWith("node@")))) {
139
+ directories.push(pathFlavor.join(prefix, formula, "bin"));
140
+ }
141
+ }
142
+ return directories;
143
+ }
144
+
145
+ // ../../harness-discovery/dist/resolve.js
146
+ var VERSION_MANAGER_ROOTS = "<version-managers>";
147
+ function installRootExtensions(platform) {
148
+ return platform === "win32" ? [".exe", ".cmd"] : [""];
149
+ }
150
+ function resolveHomeDirectory(input) {
151
+ return input.homeDirectory ?? environmentValue(input.environment, "HOME") ?? environmentValue(input.environment, "USERPROFILE") ?? os.homedir();
152
+ }
153
+ function templateVariables(environment, platform, home) {
154
+ const pathFlavor = targetPath(platform);
155
+ return {
156
+ HOME: home,
157
+ USERPROFILE: home,
158
+ APPDATA: environmentValue(environment, "APPDATA") ?? pathFlavor.join(home, "AppData", "Roaming"),
159
+ LOCALAPPDATA: environmentValue(environment, "LOCALAPPDATA") ?? pathFlavor.join(home, "AppData", "Local")
160
+ };
161
+ }
162
+ function joinTemplate(platform, value) {
163
+ const pathFlavor = targetPath(platform);
164
+ const segments = value.split("/");
165
+ const head = segments[0] ?? "";
166
+ const tail = segments.slice(1);
167
+ if (head === "")
168
+ return pathFlavor.join(pathFlavor.sep, ...tail);
169
+ return tail.length === 0 ? head : pathFlavor.join(head, ...tail);
170
+ }
171
+ function expandInstallRoot(template, environment, platform, home) {
172
+ const variables = templateVariables(environment, platform, home);
173
+ let unresolved = false;
174
+ const substituted = template.replace(/^~(?=\/|$)/u, home).replace(/\$\{(\w+)\}/gu, (_match, name) => {
175
+ const value = variables[name] ?? environmentValue(environment, name);
176
+ if (value === void 0 || value === "") {
177
+ unresolved = true;
178
+ return "";
179
+ }
180
+ return value;
181
+ });
182
+ return unresolved ? void 0 : joinTemplate(platform, substituted);
183
+ }
184
+ function installRootDirectories(spec, input, dependencies, platform, home) {
185
+ const templates = (platform === "win32" ? spec.installRoots?.windows : spec.installRoots?.posix) ?? [];
186
+ const directories = [];
187
+ for (const template of templates) {
188
+ if (template === VERSION_MANAGER_ROOTS) {
189
+ directories.push(...versionManagerBinaryDirectories({
190
+ platform,
191
+ environment: input.environment,
192
+ home,
193
+ ...dependencies.subdirectories ? { subdirectories: dependencies.subdirectories } : {}
194
+ }));
195
+ continue;
196
+ }
197
+ const directory = expandInstallRoot(template, input.environment, platform, home);
198
+ if (directory !== void 0)
199
+ directories.push(directory);
200
+ }
201
+ return directories;
202
+ }
203
+ function harnessCandidates(spec, input, dependencies = {}) {
204
+ const platform = input.platform ?? process.platform;
205
+ const pathFlavor = targetPath(platform);
206
+ const configured = input.command ?? (spec.commandEnvironmentVariable ? environmentValue(input.environment, spec.commandEnvironmentVariable) : void 0);
207
+ const command = configured ?? spec.command;
208
+ if (pathFlavor.isAbsolute(command) || command.includes("/") || command.includes("\\")) {
209
+ return [{ candidate: command, source: "configured" }];
210
+ }
211
+ const candidates = [];
212
+ const extensions = executableExtensions(command, platform, input.environment);
213
+ for (const directory of pathDirectories(input.environment, platform)) {
214
+ for (const extension of extensions) {
215
+ candidates.push({
216
+ candidate: pathFlavor.join(directory, command + extension),
217
+ source: "path"
218
+ });
219
+ }
220
+ }
221
+ if (configured !== void 0)
222
+ return candidates;
223
+ const home = resolveHomeDirectory(input);
224
+ for (const directory of installRootDirectories(spec, input, dependencies, platform, home)) {
225
+ for (const extension of installRootExtensions(platform)) {
226
+ candidates.push({
227
+ candidate: pathFlavor.join(directory, spec.command + extension),
228
+ source: "install-root"
229
+ });
230
+ }
231
+ }
232
+ return candidates;
233
+ }
234
+ function resolveHarnessExecutable(spec, input, dependencies = {}) {
235
+ const platform = input.platform ?? process.platform;
236
+ const isExecutable = dependencies.isExecutable ?? ((candidate) => isExecutableFile(candidate, platform));
237
+ const runnable = spec.runnableCandidate ?? ((candidate) => candidate);
238
+ const context = { platform, isExecutable };
239
+ for (const { candidate, source } of harnessCandidates(spec, input, dependencies)) {
240
+ const executable = runnable(candidate, context);
241
+ if (executable !== void 0 && isExecutable(executable))
242
+ return { executable, source };
243
+ }
244
+ return void 0;
245
+ }
246
+
247
+ // ../../harness-discovery/dist/installation.js
248
+ import { execFile } from "node:child_process";
249
+ import { homedir } from "node:os";
250
+ function runInstallationCommand(command, args, environment, timeout = 3e4) {
251
+ const env = withNodeRuntimeOnPath(environment);
252
+ const invocation = /\.[cm]?js$/i.test(command) ? commandInvocation(process.execPath, [command, ...args], env) : commandInvocation(command, args, env);
253
+ return new Promise((resolve, reject) => {
254
+ const child = execFile(invocation.command, invocation.arguments, {
255
+ env,
256
+ cwd: env.HOME ?? env.USERPROFILE ?? homedir(),
257
+ encoding: "utf8",
258
+ timeout,
259
+ killSignal: "SIGKILL",
260
+ maxBuffer: 1024 * 1024,
261
+ windowsHide: true,
262
+ windowsVerbatimArguments: invocation.windowsVerbatimArguments
263
+ }, (error51, stdout, stderr) => {
264
+ if (error51)
265
+ reject(new Error(error51.killed ? "Harness command timed out" : "Harness command failed; check the native installation and retry"));
266
+ else
267
+ resolve((stdout || stderr).trim());
268
+ });
269
+ child.stdin?.end();
270
+ });
271
+ }
272
+ function installationVersion(value) {
273
+ if (typeof value !== "string" || !/^v?\d+(?:\.\d+){1,3}(?:-[\w.-]+)?(?:\+[\w.-]+)?$/.test(value.trim()))
274
+ throw new Error("Harness returned an invalid version");
275
+ return value.trim().replace(/^v/, "");
276
+ }
277
+ function versionFromOutput(output) {
278
+ return installationVersion(output.match(/\b\d+(?:\.\d+){1,3}(?:-[\w.-]+)?(?:\+[\w.-]+)?\b/)?.[0]);
279
+ }
280
+ function newerInstallationVersion(current, latest) {
281
+ const a = installationVersion(current).replace(/\+.*/, "");
282
+ const b = installationVersion(latest).replace(/\+.*/, "");
283
+ const coreA = a.replace(/-.*/, "").split(".").map(BigInt);
284
+ const coreB = b.replace(/-.*/, "").split(".").map(BigInt);
285
+ for (let i = 0; i < Math.max(coreA.length, coreB.length); i++) {
286
+ if ((coreA[i] ?? 0n) !== (coreB[i] ?? 0n))
287
+ return (coreB[i] ?? 0n) > (coreA[i] ?? 0n);
288
+ }
289
+ const preA = a.includes("-") ? a.slice(a.indexOf("-") + 1).split(".") : [];
290
+ const preB = b.includes("-") ? b.slice(b.indexOf("-") + 1).split(".") : [];
291
+ if (!preA.length || !preB.length)
292
+ return !!preA.length && !preB.length;
293
+ for (let i = 0; i < Math.max(preA.length, preB.length); i++) {
294
+ const x = preA[i];
295
+ const y = preB[i];
296
+ if (x === y)
297
+ continue;
298
+ if (x === void 0 || y === void 0)
299
+ return x === void 0;
300
+ const numericX = /^\d+$/.test(x);
301
+ const numericY = /^\d+$/.test(y);
302
+ if (numericX && numericY) {
303
+ if (BigInt(x) === BigInt(y))
304
+ continue;
305
+ return BigInt(y) > BigInt(x);
306
+ }
307
+ if (numericX !== numericY)
308
+ return numericX;
309
+ return y > x;
310
+ }
311
+ return false;
312
+ }
313
+ function createInstallationManager(options) {
314
+ let checking;
315
+ let updating;
316
+ const check2 = () => checking ??= options.check().finally(() => {
317
+ checking = void 0;
318
+ });
319
+ return (action) => {
320
+ if (updating)
321
+ return updating;
322
+ if (action === "check")
323
+ return check2();
324
+ updating = (async () => {
325
+ const before = await check2();
326
+ if (!before.updateAvailable)
327
+ return before;
328
+ if (!before.canUpdate)
329
+ throw new Error(before.message ?? "This installation cannot be updated automatically");
330
+ await options.update(before);
331
+ const after = await check2();
332
+ if (after.currentVersion === before.currentVersion)
333
+ throw new Error("The Harness version did not change; check the native updater and retry");
334
+ return after;
335
+ })().finally(() => {
336
+ updating = void 0;
337
+ });
338
+ return updating;
339
+ };
340
+ }
341
+ async function fetchInstallationText(url2) {
342
+ const request = async () => {
343
+ const response = await fetch(url2, { signal: AbortSignal.timeout(15e3) });
344
+ if (!response.ok)
345
+ throw new Error("Could not check the latest Harness version");
346
+ return response.text();
347
+ };
348
+ try {
349
+ return await request();
350
+ } catch (error51) {
351
+ if (error51 instanceof DOMException && (error51.name === "AbortError" || error51.name === "TimeoutError"))
352
+ throw error51;
353
+ return request();
354
+ }
355
+ }
356
+
357
+ // ../../harness-discovery/dist/installer.js
358
+ import { mkdtemp, rm, writeFile } from "node:fs/promises";
359
+ import { tmpdir } from "node:os";
360
+ import { join } from "node:path";
361
+ function createHarnessInstaller(environment, source) {
362
+ return async () => {
363
+ if (!["darwin", "linux", "win32"].includes(process.platform))
364
+ throw new Error("Unsupported installation platform");
365
+ const env = withNodeRuntimeOnPath(environment);
366
+ if ("npm" in source) {
367
+ const npm = resolveHarnessExecutable({
368
+ id: "npm",
369
+ command: "npm",
370
+ installRoots: {
371
+ posix: [
372
+ "~/.npm-global/bin",
373
+ "~/.local/bin",
374
+ VERSION_MANAGER_ROOTS,
375
+ "/opt/homebrew/bin",
376
+ "/usr/local/bin",
377
+ "/usr/bin"
378
+ ],
379
+ windows: [
380
+ "${APPDATA}/npm",
381
+ VERSION_MANAGER_ROOTS,
382
+ "${ProgramFiles}/nodejs",
383
+ "${LOCALAPPDATA}/Programs/nodejs"
384
+ ]
385
+ }
386
+ }, { environment: env });
387
+ if (!npm)
388
+ throw new Error("Install Node.js and npm first");
389
+ await runInstallationCommand(npm.executable, ["install", "--global", source.npm], {
390
+ ...env,
391
+ ...source.allowScripts ? { npm_config_allow_scripts: source.allowScripts } : {}
392
+ }, 6e5);
393
+ return;
394
+ }
395
+ const windows = process.platform === "win32";
396
+ const url2 = windows ? source.windows : source.posix;
397
+ if (new URL(url2).protocol !== "https:")
398
+ throw new Error("Installer requires HTTPS");
399
+ const script = await fetchInstallationText(url2);
400
+ const directory = await mkdtemp(join(tmpdir(), "codexhost-installer-"));
401
+ try {
402
+ const file2 = join(directory, windows ? "install.ps1" : "install.sh");
403
+ await writeFile(file2, script, { mode: 384 });
404
+ await runInstallationCommand(windows ? "powershell.exe" : source.shell ?? "bash", windows ? ["-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-File", file2] : [file2], env, 6e5);
405
+ } finally {
406
+ await rm(directory, { recursive: true, force: true });
407
+ }
408
+ };
409
+ }
410
+
411
+ // dist/account-balance.js
412
+ import { readFile } from "node:fs/promises";
413
+ import { homedir as homedir2 } from "node:os";
414
+ import path4 from "node:path";
17
415
 
18
416
  // ../../../node_modules/zod/v4/classic/external.js
19
417
  var external_exports = {};
@@ -781,10 +1179,10 @@ function mergeDefs(...defs) {
781
1179
  function cloneDef(schema) {
782
1180
  return mergeDefs(schema._zod.def);
783
1181
  }
784
- function getElementAtPath(obj, path10) {
785
- if (!path10)
1182
+ function getElementAtPath(obj, path14) {
1183
+ if (!path14)
786
1184
  return obj;
787
- return path10.reduce((acc, key) => acc?.[key], obj);
1185
+ return path14.reduce((acc, key) => acc?.[key], obj);
788
1186
  }
789
1187
  function promiseAllObject(promisesObj) {
790
1188
  const keys = Object.keys(promisesObj);
@@ -1193,11 +1591,11 @@ function explicitlyAborted(x, startIndex = 0) {
1193
1591
  }
1194
1592
  return false;
1195
1593
  }
1196
- function prefixIssues(path10, issues) {
1594
+ function prefixIssues(path14, issues) {
1197
1595
  return issues.map((iss) => {
1198
1596
  var _a3;
1199
1597
  (_a3 = iss).path ?? (_a3.path = []);
1200
- iss.path.unshift(path10);
1598
+ iss.path.unshift(path14);
1201
1599
  return iss;
1202
1600
  });
1203
1601
  }
@@ -1344,16 +1742,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
1344
1742
  }
1345
1743
  function formatError(error51, mapper = (issue2) => issue2.message) {
1346
1744
  const fieldErrors = { _errors: [] };
1347
- const processError = (error52, path10 = []) => {
1745
+ const processError = (error52, path14 = []) => {
1348
1746
  for (const issue2 of error52.issues) {
1349
1747
  if (issue2.code === "invalid_union" && issue2.errors.length) {
1350
- issue2.errors.map((issues) => processError({ issues }, [...path10, ...issue2.path]));
1748
+ issue2.errors.map((issues) => processError({ issues }, [...path14, ...issue2.path]));
1351
1749
  } else if (issue2.code === "invalid_key") {
1352
- processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
1750
+ processError({ issues: issue2.issues }, [...path14, ...issue2.path]);
1353
1751
  } else if (issue2.code === "invalid_element") {
1354
- processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
1752
+ processError({ issues: issue2.issues }, [...path14, ...issue2.path]);
1355
1753
  } else {
1356
- const fullpath = [...path10, ...issue2.path];
1754
+ const fullpath = [...path14, ...issue2.path];
1357
1755
  if (fullpath.length === 0) {
1358
1756
  fieldErrors._errors.push(mapper(issue2));
1359
1757
  } else {
@@ -1380,17 +1778,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
1380
1778
  }
1381
1779
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
1382
1780
  const result = { errors: [] };
1383
- const processError = (error52, path10 = []) => {
1781
+ const processError = (error52, path14 = []) => {
1384
1782
  var _a3, _b;
1385
1783
  for (const issue2 of error52.issues) {
1386
1784
  if (issue2.code === "invalid_union" && issue2.errors.length) {
1387
- issue2.errors.map((issues) => processError({ issues }, [...path10, ...issue2.path]));
1785
+ issue2.errors.map((issues) => processError({ issues }, [...path14, ...issue2.path]));
1388
1786
  } else if (issue2.code === "invalid_key") {
1389
- processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
1787
+ processError({ issues: issue2.issues }, [...path14, ...issue2.path]);
1390
1788
  } else if (issue2.code === "invalid_element") {
1391
- processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
1789
+ processError({ issues: issue2.issues }, [...path14, ...issue2.path]);
1392
1790
  } else {
1393
- const fullpath = [...path10, ...issue2.path];
1791
+ const fullpath = [...path14, ...issue2.path];
1394
1792
  if (fullpath.length === 0) {
1395
1793
  result.errors.push(mapper(issue2));
1396
1794
  continue;
@@ -1422,8 +1820,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
1422
1820
  }
1423
1821
  function toDotPath(_path) {
1424
1822
  const segs = [];
1425
- const path10 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1426
- for (const seg of path10) {
1823
+ const path14 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1824
+ for (const seg of path14) {
1427
1825
  if (typeof seg === "number")
1428
1826
  segs.push(`[${seg}]`);
1429
1827
  else if (typeof seg === "symbol")
@@ -14115,13 +14513,13 @@ function resolveRef(ref, ctx) {
14115
14513
  if (!ref.startsWith("#")) {
14116
14514
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
14117
14515
  }
14118
- const path10 = ref.slice(1).split("/").filter(Boolean);
14119
- if (path10.length === 0) {
14516
+ const path14 = ref.slice(1).split("/").filter(Boolean);
14517
+ if (path14.length === 0) {
14120
14518
  return ctx.rootSchema;
14121
14519
  }
14122
14520
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
14123
- if (path10[0] === defsKey) {
14124
- const key = path10[1];
14521
+ if (path14[0] === defsKey) {
14522
+ const key = path14[1];
14125
14523
  if (!key || !ctx.defs[key]) {
14126
14524
  throw new Error(`Reference not found: ${ref}`);
14127
14525
  }
@@ -14584,6 +14982,56 @@ var credentialImportsParamsSchema = external_exports.object({
14584
14982
  request: credentialImportsRequestSchema
14585
14983
  }).strict();
14586
14984
 
14985
+ // ../../shared-contracts/dist/harness-display-settings.js
14986
+ var harnessDisplayEntriesSchema = external_exports.array(external_exports.strictObject({
14987
+ agent: external_exports.string().min(1).max(128),
14988
+ section: external_exports.enum(["main", "more", "auto"])
14989
+ })).max(256).refine((entries) => new Set(entries.map((entry) => entry.agent)).size === entries.length, "Duplicate Harness IDs");
14990
+ var harnessDisplaySettingsSchema = external_exports.strictObject({
14991
+ entries: harnessDisplayEntriesSchema.nullable()
14992
+ });
14993
+ var harnessDisplayGetSchema = external_exports.strictObject({});
14994
+ var harnessDisplaySetSchema = external_exports.strictObject({
14995
+ entries: harnessDisplayEntriesSchema,
14996
+ /** Import legacy Desktop preferences only if no shared settings exist yet. */
14997
+ initializeOnly: external_exports.boolean().optional()
14998
+ });
14999
+
15000
+ // ../../shared-contracts/dist/console.js
15001
+ var consoleAnnouncementSchema = external_exports.strictObject({
15002
+ title: external_exports.string().trim().min(1).max(200),
15003
+ type: external_exports.enum(["info", "warning", "danger"]),
15004
+ body: external_exports.string().trim().min(1).max(16 * 1024)
15005
+ });
15006
+ var consoleOpenParamsSchema = external_exports.strictObject({});
15007
+ var consoleOpenResultSchema = external_exports.strictObject({
15008
+ /** The console address. */
15009
+ url: external_exports.string().max(2048).regex(/^http:\/\/(?:127\.0\.0\.1|localhost):\d{1,5}\/(?:\?.*)?$/u)
15010
+ });
15011
+ var CONSOLE_HOST_METHODS = Object.freeze([
15012
+ "codexhost/harness/plugins/list",
15013
+ "codexhost/harness/display-settings/get",
15014
+ "codexhost/harness/display-settings/set",
15015
+ "codexhost/harness/inspect",
15016
+ "codexhost/harness/installation",
15017
+ "codexhost/harness/launch-settings/get",
15018
+ "codexhost/harness/launch-settings/set",
15019
+ "codexhost/harness/web-ui/open",
15020
+ "codexhost/harness/accounts/sources",
15021
+ "codexhost/harness/accounts/list",
15022
+ "codexhost/harness/accounts/inspect",
15023
+ "codexhost/harness/credential-imports",
15024
+ "codexhost/harness/session-import/sources",
15025
+ "codexhost/harness/session-import/list",
15026
+ "codexhost/harness/session-import/import",
15027
+ "codexhost/account/list",
15028
+ "codexhost/account/refresh",
15029
+ "codexhost/account/usage/inspect",
15030
+ "codexhost/update/check",
15031
+ "codexhost/update/start",
15032
+ "codexhost/update/status"
15033
+ ]);
15034
+
14587
15035
  // ../../shared-contracts/dist/version.js
14588
15036
  var WORKSPACE_CONTRACT_VERSION = 1;
14589
15037
 
@@ -14637,6 +15085,12 @@ var hostTurnIdSchema = opaqueIdSchema.brand();
14637
15085
  var hostItemIdSchema = opaqueIdSchema.brand();
14638
15086
  var hostInteractionIdSchema = opaqueIdSchema.brand();
14639
15087
 
15088
+ // ../../shared-contracts/dist/manual-compaction.js
15089
+ var threadManualCompactionStartedSchema = external_exports.strictObject({
15090
+ threadId: hostThreadIdSchema,
15091
+ turnId: hostTurnIdSchema
15092
+ });
15093
+
14640
15094
  // ../../shared-contracts/dist/thread-usage.js
14641
15095
  var nonNegativeSafeIntegerSchema = external_exports.number().int().safe().nonnegative();
14642
15096
  var finiteNonNegativeNumberSchema = external_exports.number().finite().nonnegative();
@@ -14697,6 +15151,10 @@ var threadUsageSnapshotSchema = external_exports.object({
14697
15151
  var usagePercentSchema = external_exports.number().finite().min(0).max(100);
14698
15152
  var accountCreditsProductUsageSchema = external_exports.object({
14699
15153
  product: external_exports.string().min(1),
15154
+ used: external_exports.number().finite().nonnegative().optional(),
15155
+ // Zero is a real empty cap, not an absent field.
15156
+ limit: external_exports.number().finite().nonnegative().optional(),
15157
+ unit: external_exports.string().min(1).max(32).optional(),
14700
15158
  usagePercent: usagePercentSchema,
14701
15159
  resetsAt: external_exports.string().min(1).optional()
14702
15160
  }).strict();
@@ -14706,6 +15164,10 @@ var accountResetCreditsSchema = external_exports.object({
14706
15164
  expiresAt: external_exports.array(external_exports.string().min(1)).min(1).max(32).optional()
14707
15165
  }).strict();
14708
15166
  var accountCreditsSnapshotSchema = external_exports.object({
15167
+ used: external_exports.number().finite().nonnegative().optional(),
15168
+ // Zero is a real empty cap, not an absent field.
15169
+ limit: external_exports.number().finite().nonnegative().optional(),
15170
+ unit: external_exports.string().min(1).max(32).optional(),
14709
15171
  /** Native label when the primary limit is scoped to a model or product group. */
14710
15172
  label: external_exports.string().min(1).optional(),
14711
15173
  usedPercent: usagePercentSchema,
@@ -14725,12 +15187,27 @@ var threadUsageInspectionSchema = external_exports.object({
14725
15187
  }).strict();
14726
15188
 
14727
15189
  // ../../shared-contracts/dist/harness-accounts.js
14728
- var harnessAccountSnapshotSchema = external_exports.object({
15190
+ var accountBalanceSnapshotSchema = external_exports.object({
15191
+ amount: external_exports.number().finite().nonnegative(),
15192
+ /** ISO 4217 code as reported by the Provider, for example `CNY`. */
15193
+ currency: external_exports.string().trim().min(1).max(8),
15194
+ /** Native label when the Harness exposes several Billing Sources. */
15195
+ label: external_exports.string().trim().min(1).max(128).optional()
15196
+ }).strict();
15197
+ var harnessAccountSnapshotObject = external_exports.object({
14729
15198
  email: external_exports.string().trim().min(1).max(320).optional(),
14730
15199
  label: external_exports.string().trim().min(1).max(256).optional(),
14731
15200
  plan: external_exports.string().trim().min(1).max(128).optional(),
14732
- credits: accountCreditsSnapshotSchema
15201
+ credits: accountCreditsSnapshotSchema.optional(),
15202
+ balance: accountBalanceSnapshotSchema.optional()
14733
15203
  }).strict();
15204
+ function requireReportedQuota(schema) {
15205
+ return schema.refine((value) => {
15206
+ const reported = value;
15207
+ return reported.credits !== void 0 || reported.balance !== void 0;
15208
+ }, { message: "Account must report either credits or a balance" });
15209
+ }
15210
+ var harnessAccountSnapshotSchema = requireReportedQuota(harnessAccountSnapshotObject);
14734
15211
  var harnessAccountIdentityShape = {
14735
15212
  harnessId: harnessIdSchema,
14736
15213
  harnessName: external_exports.string().trim().min(1).max(128)
@@ -14741,11 +15218,13 @@ var harnessAccountSourceListResultSchema = external_exports.object({ sources: ex
14741
15218
  var harnessAccountInspectParamsSchema = external_exports.object({ harnessId: harnessIdSchema, refresh: external_exports.boolean().optional() }).strict();
14742
15219
  var harnessAccountInspectResultSchema = external_exports.object({
14743
15220
  ...harnessAccountIdentityShape,
14744
- account: harnessAccountSnapshotSchema.nullable()
15221
+ account: harnessAccountSnapshotSchema.nullable(),
15222
+ /** Every Billing Source from one Harness; `account` remains the first for older clients. */
15223
+ accounts: external_exports.array(harnessAccountSnapshotSchema).max(8).optional()
14745
15224
  }).strict();
14746
15225
  var harnessAccountListParamsSchema = external_exports.object({ refresh: external_exports.boolean().optional() }).strict();
14747
15226
  var harnessAccountListResultSchema = external_exports.object({
14748
- accounts: external_exports.array(harnessAccountSnapshotSchema.extend(harnessAccountIdentityShape)).max(128)
15227
+ accounts: external_exports.array(requireReportedQuota(harnessAccountSnapshotObject.extend(harnessAccountIdentityShape))).max(128)
14749
15228
  }).strict();
14750
15229
 
14751
15230
  // ../../shared-contracts/dist/json-value.js
@@ -14883,6 +15362,8 @@ var harnessModelSchema = external_exports.object({
14883
15362
  ref: harnessModelRefSchema,
14884
15363
  label: nonBlankTextSchema2.max(HARNESS_MODEL_LABEL_MAX_LENGTH),
14885
15364
  resolvedModelLabel: harnessResolvedModelLabelSchema.optional(),
15365
+ /** Optional opaque selection for this same Model with priority processing enabled. */
15366
+ fastModel: harnessModelRefSchema.optional(),
14886
15367
  supportedThinkingOptionIds: external_exports.array(harnessThinkingOptionIdSchema).optional()
14887
15368
  }).strict();
14888
15369
  var harnessThinkingOptionsSchema = external_exports.array(harnessThinkingOptionSchema).superRefine((options, context) => {
@@ -14915,6 +15396,16 @@ var harnessModelCatalogSchema = external_exports.object({
14915
15396
  });
14916
15397
  }
14917
15398
  refs.add(model.ref.id);
15399
+ if (model.fastModel) {
15400
+ if (refs.has(model.fastModel.id) || catalog.models.some((entry) => entry.ref.id === model.fastModel?.id)) {
15401
+ context.addIssue({
15402
+ code: "custom",
15403
+ message: "Fast Model refs must be distinct and unique",
15404
+ path: ["models", index, "fastModel"]
15405
+ });
15406
+ }
15407
+ refs.add(model.fastModel.id);
15408
+ }
14918
15409
  const supportedThinkingIds = /* @__PURE__ */ new Set();
14919
15410
  for (const [optionIndex, optionId] of (model.supportedThinkingOptionIds ?? []).entries()) {
14920
15411
  if (supportedThinkingIds.has(optionId)) {
@@ -15034,11 +15525,13 @@ var threadThinkingSelectParamsSchema = external_exports.object({
15034
15525
  thinkingOptionId: harnessThinkingOptionIdSchema
15035
15526
  }).strict();
15036
15527
  var threadInspectionParamsSchema = external_exports.object({
15037
- threadId: hostThreadIdSchema
15528
+ threadId: hostThreadIdSchema,
15529
+ includeReferenceCapability: external_exports.boolean().optional()
15038
15530
  }).strict();
15039
15531
  var codexThreadInspectionSchema = external_exports.object({
15040
15532
  owner: external_exports.literal("codex"),
15041
- locked: external_exports.literal(true)
15533
+ locked: external_exports.literal(true),
15534
+ supportsThreadReferences: external_exports.literal(true).optional()
15042
15535
  }).strict();
15043
15536
  var externalThreadInspectionSchema = external_exports.object({
15044
15537
  owner: external_exports.literal("external"),
@@ -15164,6 +15657,22 @@ var harnessLaunchSettingsSchema = external_exports.object({
15164
15657
  restartRequired: external_exports.boolean()
15165
15658
  }).strict();
15166
15659
 
15660
+ // ../../shared-contracts/dist/harness-installation.js
15661
+ var harnessInstallationParamsSchema = external_exports.object({
15662
+ harnessId: harnessIdSchema,
15663
+ action: external_exports.enum(["check", "update", "install"])
15664
+ }).strict();
15665
+ var harnessInstallationStateSchema = external_exports.object({
15666
+ currentVersion: external_exports.string().min(1).max(128),
15667
+ latestVersion: external_exports.string().min(1).max(128),
15668
+ updateAvailable: external_exports.boolean(),
15669
+ canUpdate: external_exports.boolean(),
15670
+ // Adapter-owned diagnostic text; UI uses messageCode rather than displaying it verbatim.
15671
+ message: external_exports.string().max(2048).optional(),
15672
+ messageCode: external_exports.string().min(1).max(128).optional(),
15673
+ latestVersionKind: external_exports.enum(["unknown", "tracking-branch"]).optional()
15674
+ }).strict();
15675
+
15167
15676
  // ../../shared-contracts/dist/codex-accounts.js
15168
15677
  var accountIdSchema = external_exports.string().min(1).max(256).regex(/^[A-Za-z0-9._~-]+$/u);
15169
15678
  var nonBlankTextSchema3 = external_exports.string().trim().min(1);
@@ -15463,233 +15972,198 @@ var updateStatusResultSchema = external_exports.strictObject({
15463
15972
  status: updateStatusSchema.nullable()
15464
15973
  });
15465
15974
 
15975
+ // ../../shared-contracts/dist/remote-runtime.js
15976
+ var remoteUpdatePhaseSchema = external_exports.enum([
15977
+ "idle",
15978
+ "installing",
15979
+ "restarting",
15980
+ "succeeded",
15981
+ "failed"
15982
+ ]);
15983
+ var runtimeStatusSchema = external_exports.object({
15984
+ runningVersion: external_exports.string().nullable(),
15985
+ installedVersion: external_exports.string().nullable(),
15986
+ restartRequired: external_exports.boolean(),
15987
+ remote: external_exports.boolean(),
15988
+ updateSupported: external_exports.boolean(),
15989
+ update: external_exports.object({
15990
+ phase: remoteUpdatePhaseSchema,
15991
+ targetVersion: external_exports.string().nullable(),
15992
+ error: external_exports.string().nullable()
15993
+ })
15994
+ });
15995
+ var remoteUpdateParamsSchema = external_exports.object({
15996
+ version: external_exports.string().regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u)
15997
+ }).strict();
15998
+ var remoteSshSetupParamsSchema = external_exports.object({
15999
+ hostname: external_exports.string().min(1).max(1024).refine((value) => !value.startsWith("-") && !/\s/u.test(value)),
16000
+ port: external_exports.number().int().min(1).max(65535).nullable(),
16001
+ identity: external_exports.string().max(4096).nullable(),
16002
+ action: external_exports.enum(["inspect", "install", "update", "repair"]),
16003
+ version: external_exports.string().regex(/^\d+\.\d+\.\d+$/u).nullable()
16004
+ }).strict();
16005
+ var remoteSshSetupResultSchema = external_exports.object({ state: external_exports.enum(["installed", "not-installed"]) }).strict();
16006
+
15466
16007
  // ../../shared-contracts/dist/index.js
15467
16008
  var workspaceContractVersionSchema = external_exports.literal(WORKSPACE_CONTRACT_VERSION);
15468
16009
 
15469
- // ../../harness-discovery/dist/environment.js
15470
- import fs from "node:fs";
15471
- import path from "node:path";
15472
- function targetPath(platform) {
15473
- return platform === "win32" ? path.win32 : path.posix;
15474
- }
15475
- function environmentValue(environment, name) {
15476
- const lowered = name.toLowerCase();
15477
- for (const [key, value] of Object.entries(environment)) {
15478
- if (key.toLowerCase() === lowered)
15479
- return value;
15480
- }
15481
- return void 0;
15482
- }
15483
- function pathDelimiter(platform) {
15484
- return platform === "win32" ? ";" : ":";
15485
- }
15486
- function pathDirectories(environment, platform) {
15487
- return (environmentValue(environment, "PATH") ?? "").split(pathDelimiter(platform)).map((directory) => directory.trim().replace(/^"|"$/gu, "")).filter(Boolean);
15488
- }
15489
- function executableExtensions(command, platform, environment) {
15490
- if (platform !== "win32")
15491
- return [""];
15492
- if (targetPath(platform).extname(command) !== "")
15493
- return [""];
15494
- return (environmentValue(environment, "PATHEXT") ?? ".COM;.EXE;.BAT;.CMD").split(";").map((extension) => extension.trim()).filter(Boolean);
15495
- }
15496
- function isExecutableFile(filePath, platform) {
15497
- try {
15498
- fs.accessSync(filePath, platform === "win32" ? fs.constants.F_OK : fs.constants.X_OK);
15499
- return fs.statSync(filePath).isFile();
15500
- } catch {
15501
- return false;
15502
- }
15503
- }
15504
- function subdirectoryNames(directory) {
15505
- try {
15506
- return fs.readdirSync(directory, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
15507
- } catch {
15508
- return [];
15509
- }
15510
- }
15511
- function newestFirst(names) {
15512
- return [...names].sort((left, right) => right.localeCompare(left, void 0, { numeric: true }));
15513
- }
15514
-
15515
- // ../../harness-discovery/dist/node-runtime.js
15516
- import path2 from "node:path";
15517
- function withNodeRuntimeOnPath(environment, runtimeExecutable = process.execPath, platform = process.platform) {
15518
- const pathKey = Object.keys(environment).find((name) => name.toLowerCase() === "path") ?? "PATH";
15519
- const delimiter = platform === "win32" ? ";" : ":";
15520
- const runtimeDirectory = path2.dirname(runtimeExecutable);
15521
- const directories = (environment[pathKey] ?? "").split(delimiter).filter(Boolean);
15522
- const equal = platform === "win32" ? (value) => value.toLowerCase() : (value) => value;
15523
- if (!directories.some((directory) => equal(directory) === equal(runtimeDirectory))) {
15524
- directories.push(runtimeDirectory);
15525
- }
15526
- return { ...environment, [pathKey]: directories.join(delimiter) };
15527
- }
15528
-
15529
- // ../../harness-discovery/dist/resolve.js
15530
- import os from "node:os";
15531
-
15532
- // ../../harness-discovery/dist/version-managers.js
15533
- function versionManagerBinaryDirectories(context) {
15534
- const { platform, environment, home } = context;
15535
- const list = context.subdirectories ?? subdirectoryNames;
15536
- const pathFlavor = targetPath(platform);
15537
- const value = (name) => environmentValue(environment, name);
15538
- const directories = [];
15539
- const versioned = (root, ...tail) => {
15540
- for (const version2 of newestFirst(list(root))) {
15541
- directories.push(pathFlavor.join(root, version2, ...tail));
15542
- }
15543
- };
15544
- if (platform === "win32") {
15545
- const appData = value("APPDATA") ?? pathFlavor.join(home, "AppData", "Roaming");
15546
- const localAppData = value("LOCALAPPDATA") ?? pathFlavor.join(home, "AppData", "Local");
15547
- versioned(pathFlavor.join(appData, "nvm"));
15548
- versioned(value("FNM_DIR") ?? pathFlavor.join(appData, "fnm", "node-versions"), "installation");
15549
- directories.push(pathFlavor.join(localAppData, "Volta", "bin"));
15550
- directories.push(pathFlavor.join(home, ".bun", "bin"));
15551
- const pnpmHome2 = value("PNPM_HOME");
15552
- if (pnpmHome2)
15553
- directories.push(pnpmHome2);
15554
- directories.push(pathFlavor.join(localAppData, "pnpm"));
15555
- return directories;
15556
- }
15557
- versioned(pathFlavor.join(value("NVM_DIR") ?? pathFlavor.join(home, ".nvm"), "versions", "node"), "bin");
15558
- const fnmRoots = [
15559
- value("FNM_DIR"),
15560
- pathFlavor.join(home, ".local", "share", "fnm"),
15561
- pathFlavor.join(home, "Library", "Application Support", "fnm")
15562
- ].filter((root) => root !== void 0);
15563
- for (const root of fnmRoots) {
15564
- versioned(pathFlavor.join(root, "node-versions"), "installation", "bin");
15565
- }
15566
- const voltaHome = value("VOLTA_HOME") ?? pathFlavor.join(home, ".volta");
15567
- versioned(pathFlavor.join(voltaHome, "tools", "image", "node"), "bin");
15568
- directories.push(pathFlavor.join(voltaHome, "bin"));
15569
- const asdfHome = value("ASDF_DATA_DIR") ?? pathFlavor.join(home, ".asdf");
15570
- versioned(pathFlavor.join(asdfHome, "installs", "nodejs"), "bin");
15571
- directories.push(pathFlavor.join(asdfHome, "shims"));
15572
- const nodenvHome = value("NODENV_ROOT") ?? pathFlavor.join(home, ".nodenv");
15573
- versioned(pathFlavor.join(nodenvHome, "versions"), "bin");
15574
- directories.push(pathFlavor.join(nodenvHome, "shims"));
15575
- versioned(pathFlavor.join(value("N_PREFIX") ?? "/usr/local", "n", "versions", "node"), "bin");
15576
- directories.push(pathFlavor.join(home, ".bun", "bin"));
15577
- const pnpmHome = value("PNPM_HOME");
15578
- if (pnpmHome)
15579
- directories.push(pnpmHome);
15580
- directories.push(pathFlavor.join(home, "Library", "pnpm"));
15581
- directories.push(pathFlavor.join(home, ".local", "share", "pnpm"));
15582
- for (const prefix of ["/opt/homebrew/opt", "/usr/local/opt"]) {
15583
- for (const formula of newestFirst(list(prefix).filter((name) => name.startsWith("node@")))) {
15584
- directories.push(pathFlavor.join(prefix, formula, "bin"));
15585
- }
15586
- }
15587
- return directories;
15588
- }
15589
-
15590
- // ../../harness-discovery/dist/resolve.js
15591
- var VERSION_MANAGER_ROOTS = "<version-managers>";
15592
- function installRootExtensions(platform) {
15593
- return platform === "win32" ? [".exe", ".cmd"] : [""];
15594
- }
15595
- function resolveHomeDirectory(input) {
15596
- return input.homeDirectory ?? environmentValue(input.environment, "HOME") ?? environmentValue(input.environment, "USERPROFILE") ?? os.homedir();
16010
+ // dist/account-balance.js
16011
+ var DEEPSEEK_BALANCE_ENDPOINT = "https://api.deepseek.com/user/balance";
16012
+ var SUB2API_USAGE_PATH = "/v1/usage";
16013
+ var REQUEST_TIMEOUT_MS = 1e4;
16014
+ var MAX_PI_ACCOUNTS = 8;
16015
+ function agentDirectory(environment) {
16016
+ const configured = environment.PI_CODING_AGENT_DIR?.trim();
16017
+ if (configured)
16018
+ return configured;
16019
+ return path4.join(environment.HOME ?? environment.USERPROFILE ?? homedir2(), ".pi", "agent");
16020
+ }
16021
+ var record2 = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
16022
+ async function deepSeekApiKey(environment) {
16023
+ const auth = record2(JSON.parse(await readFile(path4.join(agentDirectory(environment), "auth.json"), "utf8")));
16024
+ const deepseek = record2(auth.deepseek);
16025
+ if (deepseek.type !== "api_key")
16026
+ return void 0;
16027
+ return typeof deepseek.key === "string" && deepseek.key.trim() ? deepseek.key : void 0;
15597
16028
  }
15598
- function templateVariables(environment, platform, home) {
15599
- const pathFlavor = targetPath(platform);
15600
- return {
15601
- HOME: home,
15602
- USERPROFILE: home,
15603
- APPDATA: environmentValue(environment, "APPDATA") ?? pathFlavor.join(home, "AppData", "Roaming"),
15604
- LOCALAPPDATA: environmentValue(environment, "LOCALAPPDATA") ?? pathFlavor.join(home, "AppData", "Local")
15605
- };
16029
+ function projectSub2ApiUsage(payload, providerId) {
16030
+ const data = record2(payload);
16031
+ if (data.isValid === false)
16032
+ return null;
16033
+ if (data.mode !== "unrestricted" && data.mode !== "quota_limited")
16034
+ return null;
16035
+ const currency = typeof data.unit === "string" ? data.unit.trim() : "";
16036
+ if (!/^[A-Z]{3}$/u.test(currency))
16037
+ return null;
16038
+ const wallet = finiteAmount(data.balance);
16039
+ const remaining = finiteAmount(data.remaining);
16040
+ const quotaRemaining = finiteAmount(record2(data.quota).remaining);
16041
+ const amount = wallet ?? remaining ?? quotaRemaining;
16042
+ if (amount === null)
16043
+ return null;
16044
+ const planName = typeof data.planName === "string" ? data.planName.trim() : "";
16045
+ const label = providerId.trim();
16046
+ if (!label || label.length > 128)
16047
+ return null;
16048
+ const parsed = harnessAccountSnapshotSchema.safeParse({
16049
+ label,
16050
+ ...planName ? { plan: planName.slice(0, 128) } : {},
16051
+ balance: { amount, currency, label: planName || label }
16052
+ });
16053
+ return parsed.success ? parsed.data : null;
15606
16054
  }
15607
- function joinTemplate(platform, value) {
15608
- const pathFlavor = targetPath(platform);
15609
- const segments = value.split("/");
15610
- const head = segments[0] ?? "";
15611
- const tail = segments.slice(1);
15612
- if (head === "")
15613
- return pathFlavor.join(pathFlavor.sep, ...tail);
15614
- return tail.length === 0 ? head : pathFlavor.join(head, ...tail);
16055
+ function finiteAmount(value) {
16056
+ const amount = typeof value === "number" ? value : typeof value === "string" && value.trim() ? Number(value) : Number.NaN;
16057
+ return Number.isFinite(amount) && amount >= 0 ? amount : null;
15615
16058
  }
15616
- function expandInstallRoot(template, environment, platform, home) {
15617
- const variables = templateVariables(environment, platform, home);
15618
- let unresolved = false;
15619
- const substituted = template.replace(/^~(?=\/|$)/u, home).replace(/\$\{(\w+)\}/gu, (_match, name) => {
15620
- const value = variables[name] ?? environmentValue(environment, name);
15621
- if (value === void 0 || value === "") {
15622
- unresolved = true;
15623
- return "";
15624
- }
15625
- return value;
16059
+ function projectDeepSeekBalance(payload) {
16060
+ const data = record2(payload);
16061
+ if (!Array.isArray(data.balance_infos))
16062
+ return null;
16063
+ const first = record2(data.balance_infos[0]);
16064
+ const amount = finiteAmount(first.total_balance);
16065
+ const currency = typeof first.currency === "string" ? first.currency.trim() : "";
16066
+ if (amount === null || !currency)
16067
+ return null;
16068
+ const parsed = harnessAccountSnapshotSchema.safeParse({
16069
+ label: "DeepSeek",
16070
+ balance: { amount, currency, label: "DeepSeek API" }
15626
16071
  });
15627
- return unresolved ? void 0 : joinTemplate(platform, substituted);
15628
- }
15629
- function installRootDirectories(spec, input, dependencies, platform, home) {
15630
- const templates = (platform === "win32" ? spec.installRoots?.windows : spec.installRoots?.posix) ?? [];
15631
- const directories = [];
15632
- for (const template of templates) {
15633
- if (template === VERSION_MANAGER_ROOTS) {
15634
- directories.push(...versionManagerBinaryDirectories({
15635
- platform,
15636
- environment: input.environment,
15637
- home,
15638
- ...dependencies.subdirectories ? { subdirectories: dependencies.subdirectories } : {}
15639
- }));
15640
- continue;
15641
- }
15642
- const directory = expandInstallRoot(template, input.environment, platform, home);
15643
- if (directory !== void 0)
15644
- directories.push(directory);
15645
- }
15646
- return directories;
16072
+ return parsed.success ? parsed.data : null;
15647
16073
  }
15648
- function harnessCandidates(spec, input, dependencies = {}) {
15649
- const platform = input.platform ?? process.platform;
15650
- const pathFlavor = targetPath(platform);
15651
- const configured = input.command ?? (spec.commandEnvironmentVariable ? environmentValue(input.environment, spec.commandEnvironmentVariable) : void 0);
15652
- const command = configured ?? spec.command;
15653
- if (pathFlavor.isAbsolute(command) || command.includes("/") || command.includes("\\")) {
15654
- return [{ candidate: command, source: "configured" }];
16074
+ function usageEndpoint(baseUrl) {
16075
+ let url2;
16076
+ try {
16077
+ url2 = new URL(baseUrl);
16078
+ } catch {
16079
+ return null;
15655
16080
  }
15656
- const candidates = [];
15657
- const extensions = executableExtensions(command, platform, input.environment);
15658
- for (const directory of pathDirectories(input.environment, platform)) {
15659
- for (const extension of extensions) {
15660
- candidates.push({
15661
- candidate: pathFlavor.join(directory, command + extension),
15662
- source: "path"
15663
- });
16081
+ if (url2.protocol !== "https:" && url2.protocol !== "http:" || !url2.hostname)
16082
+ return null;
16083
+ url2.username = "";
16084
+ url2.password = "";
16085
+ url2.pathname = SUB2API_USAGE_PATH;
16086
+ url2.search = "";
16087
+ url2.hash = "";
16088
+ return url2.toString();
16089
+ }
16090
+ async function configuredSub2ApiProviders(environment) {
16091
+ try {
16092
+ const models = record2(JSON.parse(await readFile(path4.join(agentDirectory(environment), "models.json"), "utf8")));
16093
+ const providers = record2(models.providers);
16094
+ const found = [];
16095
+ for (const [id, definition] of Object.entries(providers)) {
16096
+ const provider = record2(definition);
16097
+ const apiKey = typeof provider.apiKey === "string" ? provider.apiKey.trim() : "";
16098
+ const baseUrl = typeof provider.baseUrl === "string" ? provider.baseUrl.trim() : "";
16099
+ if (!id.trim() || id.length > 128 || !apiKey || !usageEndpoint(baseUrl))
16100
+ continue;
16101
+ found.push({ id, apiKey, baseUrl });
15664
16102
  }
16103
+ return found.sort((left, right) => left.id.localeCompare(right.id));
16104
+ } catch {
16105
+ return [];
15665
16106
  }
15666
- if (configured !== void 0)
15667
- return candidates;
15668
- const home = resolveHomeDirectory(input);
15669
- for (const directory of installRootDirectories(spec, input, dependencies, platform, home)) {
15670
- for (const extension of installRootExtensions(platform)) {
15671
- candidates.push({
15672
- candidate: pathFlavor.join(directory, spec.command + extension),
15673
- source: "install-root"
15674
- });
15675
- }
16107
+ }
16108
+ async function fetchSub2ApiBalance(provider, fetchImpl, signal) {
16109
+ const endpoint = usageEndpoint(provider.baseUrl);
16110
+ if (!endpoint)
16111
+ return null;
16112
+ const response = await fetchImpl(endpoint, {
16113
+ headers: { Authorization: `Bearer ${provider.apiKey}`, Accept: "application/json" },
16114
+ redirect: "error",
16115
+ signal
16116
+ });
16117
+ if (!response.ok)
16118
+ return null;
16119
+ return projectSub2ApiUsage(await response.json(), provider.id);
16120
+ }
16121
+ async function fetchPiAccounts(input = {}) {
16122
+ try {
16123
+ const environment = input.environment ?? process.env;
16124
+ const fetchImpl = input.fetch ?? fetch;
16125
+ const signal = input.signal ? AbortSignal.any([input.signal, AbortSignal.timeout(REQUEST_TIMEOUT_MS)]) : AbortSignal.timeout(REQUEST_TIMEOUT_MS);
16126
+ const [providers, deepseek] = await Promise.all([
16127
+ input.readProviders ? input.readProviders() : configuredSub2ApiProviders(environment),
16128
+ fetchPiAccountBalance({ ...input, environment, fetch: fetchImpl, signal })
16129
+ ]);
16130
+ const wallets = await Promise.all(providers.filter((provider) => provider.apiKey.trim() && usageEndpoint(provider.baseUrl)).map((provider) => fetchSub2ApiBalance(provider, fetchImpl, signal).catch(() => null)));
16131
+ return [...wallets, deepseek].filter((account) => account !== null).slice(0, MAX_PI_ACCOUNTS);
16132
+ } catch {
16133
+ return [];
15676
16134
  }
15677
- return candidates;
15678
16135
  }
15679
- function resolveHarnessExecutable(spec, input, dependencies = {}) {
15680
- const platform = input.platform ?? process.platform;
15681
- const isExecutable = dependencies.isExecutable ?? ((candidate) => isExecutableFile(candidate, platform));
15682
- const runnable = spec.runnableCandidate ?? ((candidate) => candidate);
15683
- const context = { platform, isExecutable };
15684
- for (const { candidate, source } of harnessCandidates(spec, input, dependencies)) {
15685
- const executable = runnable(candidate, context);
15686
- if (executable !== void 0 && isExecutable(executable))
15687
- return { executable, source };
16136
+ async function fetchPiAccountBalance(input) {
16137
+ try {
16138
+ const key = await (input.readApiKey ? input.readApiKey() : deepSeekApiKey(input.environment));
16139
+ if (!key)
16140
+ return null;
16141
+ const response = await input.fetch(DEEPSEEK_BALANCE_ENDPOINT, {
16142
+ headers: { Authorization: `Bearer ${key}`, Accept: "application/json" },
16143
+ signal: input.signal
16144
+ });
16145
+ if (!response.ok)
16146
+ return null;
16147
+ return projectDeepSeekBalance(await response.json());
16148
+ } catch {
16149
+ return null;
15688
16150
  }
15689
- return void 0;
15690
16151
  }
15691
16152
 
16153
+ // dist/pi-credential-imports.js
16154
+ import { randomUUID } from "node:crypto";
16155
+ import { execFile as execFile2 } from "node:child_process";
16156
+ import { promisify } from "node:util";
16157
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, rmSync, readdirSync, lstatSync, renameSync, rmdirSync } from "node:fs";
16158
+ import { realpath } from "node:fs/promises";
16159
+ import os2 from "node:os";
16160
+ import path6 from "node:path";
16161
+ import { pathToFileURL } from "node:url";
16162
+
15692
16163
  // dist/command.js
16164
+ import fs2 from "node:fs";
16165
+ import { homedir as homedir3, tmpdir as tmpdir2 } from "node:os";
16166
+ import path5 from "node:path";
15693
16167
  var piDiscoverySpec = {
15694
16168
  id: "pi",
15695
16169
  command: "pi",
@@ -15714,6 +16188,34 @@ function resolvePiExecutable(input, dependencies = {}) {
15714
16188
  }, { ...dependencies.isExecutable ? { isExecutable: dependencies.isExecutable } : {} });
15715
16189
  return resolution?.executable ?? input.command ?? input.environment.PI_COMMAND ?? "pi";
15716
16190
  }
16191
+ function isFilesystemRoot(cwd) {
16192
+ const resolved = path5.resolve(cwd);
16193
+ return resolved === path5.parse(resolved).root;
16194
+ }
16195
+ function writableDirectory(candidate) {
16196
+ if (!candidate || !path5.isAbsolute(candidate) || isFilesystemRoot(candidate))
16197
+ return void 0;
16198
+ try {
16199
+ if (!fs2.statSync(candidate).isDirectory())
16200
+ return void 0;
16201
+ fs2.accessSync(candidate, fs2.constants.R_OK | fs2.constants.W_OK);
16202
+ return candidate;
16203
+ } catch {
16204
+ return void 0;
16205
+ }
16206
+ }
16207
+ function resolvePiInspectCwd(inputCwd, environment = process.env) {
16208
+ if (typeof inputCwd === "string" && inputCwd.length > 0 && !isFilesystemRoot(inputCwd)) {
16209
+ return path5.resolve(inputCwd);
16210
+ }
16211
+ const candidates = [environment.USERPROFILE, environment.HOME, homedir3(), tmpdir2()];
16212
+ for (const candidate of candidates) {
16213
+ const usable = writableDirectory(candidate);
16214
+ if (usable)
16215
+ return usable;
16216
+ }
16217
+ return inputCwd && inputCwd.length > 0 ? path5.resolve(inputCwd) : process.cwd();
16218
+ }
15717
16219
 
15718
16220
  // dist/pi-credential-imports.js
15719
16221
  var PREFIX = "codexhost-account-";
@@ -15756,6 +16258,15 @@ function describeOauth(credential) {
15756
16258
  ...match ? { vendor: match.vendor } : {}
15757
16259
  };
15758
16260
  }
16261
+ function readPiCodexProviderNames(environment) {
16262
+ const agentDir = environment.PI_CODING_AGENT_DIR ?? path6.join(environment.HOME ?? environment.USERPROFILE ?? os2.homedir(), ".pi/agent");
16263
+ try {
16264
+ const auth = parseAuth(readFileSync(path6.join(agentDir, "auth.json"), "utf8"));
16265
+ return Object.entries(auth).filter(([, credential]) => describeOauth(credential).vendor === "openai-codex").map(([provider]) => provider);
16266
+ } catch {
16267
+ return [];
16268
+ }
16269
+ }
15759
16270
  function writeAuth(filename, content) {
15760
16271
  const temporary = `${filename}.${randomUUID()}.tmp`;
15761
16272
  try {
@@ -15766,8 +16277,8 @@ function writeAuth(filename, content) {
15766
16277
  }
15767
16278
  }
15768
16279
  function removeOwnedFiles(dir) {
15769
- rmSync(path3.join(dir, "index.ts"), { force: true });
15770
- rmSync(path3.join(dir, "import.json"), { force: true });
16280
+ rmSync(path6.join(dir, "index.ts"), { force: true });
16281
+ rmSync(path6.join(dir, "import.json"), { force: true });
15771
16282
  try {
15772
16283
  rmdirSync(dir);
15773
16284
  } catch {
@@ -15775,26 +16286,26 @@ function removeOwnedFiles(dir) {
15775
16286
  }
15776
16287
  async function installation(command, environment, authPath) {
15777
16288
  const executable = await realpath(resolvePiExecutable({ ...command ? { command } : {}, environment }));
15778
- let directory = path3.dirname(executable);
16289
+ let directory = path6.dirname(executable);
15779
16290
  while (true) {
15780
- const manifest = path3.join(directory, "package.json");
16291
+ const manifest = path6.join(directory, "package.json");
15781
16292
  if (existsSync(manifest)) {
15782
16293
  const pkg = JSON.parse(readFileSync(manifest, "utf8"));
15783
16294
  if (pkg.name === "@earendil-works/pi-coding-agent")
15784
16295
  break;
15785
16296
  }
15786
- const parent = path3.dirname(directory);
16297
+ const parent = path6.dirname(directory);
15787
16298
  if (parent === directory)
15788
16299
  throw new Error("Pi credential import requires a supported npm Pi installation");
15789
16300
  directory = parent;
15790
16301
  }
15791
- const storage = await import(pathToFileURL(path3.join(directory, "dist/core/auth-storage.js")).href);
15792
- const ai = path3.join(directory, "node_modules/@earendil-works/pi-ai/dist");
15793
- const all = await import(pathToFileURL(path3.join(ai, "providers/all.js")).href);
16302
+ const storage = await import(pathToFileURL(path6.join(directory, "dist/core/auth-storage.js")).href);
16303
+ const ai = path6.join(directory, "node_modules/@earendil-works/pi-ai/dist");
16304
+ const all = await import(pathToFileURL(path6.join(ai, "providers/all.js")).href);
15794
16305
  const providers = all.getBuiltinProviders();
15795
16306
  const providerModules = {
15796
- "openai-codex": pathToFileURL(path3.join(ai, "providers/openai-codex.js")).href,
15797
- xai: pathToFileURL(path3.join(ai, "providers/xai.js")).href
16307
+ "openai-codex": pathToFileURL(path6.join(ai, "providers/openai-codex.js")).href,
16308
+ xai: pathToFileURL(path6.join(ai, "providers/xai.js")).href
15798
16309
  };
15799
16310
  for (const [id, url2] of Object.entries(providerModules)) {
15800
16311
  const module = await import(url2);
@@ -15807,9 +16318,9 @@ async function installation(command, environment, authPath) {
15807
16318
  providerModules,
15808
16319
  reservedNames: providers.map((p) => typeof p === "string" ? p : p.id),
15809
16320
  async configuredProviderNames() {
15810
- const { stdout } = await promisify(execFile)(process.execPath, [executable, "--offline", "--no-approve", "--list-models"], {
15811
- cwd: existsSync(path3.dirname(authPath)) ? path3.dirname(authPath) : os2.homedir(),
15812
- env: { ...environment, PI_CODING_AGENT_DIR: path3.dirname(authPath), PI_OFFLINE: "1" },
16321
+ const { stdout } = await promisify(execFile2)(process.execPath, [executable, "--offline", "--no-approve", "--list-models"], {
16322
+ cwd: existsSync(path6.dirname(authPath)) ? path6.dirname(authPath) : os2.homedir(),
16323
+ env: { ...environment, PI_CODING_AGENT_DIR: path6.dirname(authPath), PI_OFFLINE: "1" },
15813
16324
  timeout: 15e3,
15814
16325
  maxBuffer: 4 * 1024 * 1024
15815
16326
  });
@@ -15839,26 +16350,26 @@ export default async function (pi) {
15839
16350
  }
15840
16351
  function createPiCredentialImports(options = {}) {
15841
16352
  const env = { ...process.env, ...options.environment };
15842
- const agentDir = env.PI_CODING_AGENT_DIR ?? path3.join(env.HOME ?? os2.homedir(), ".pi/agent");
15843
- const authPath = path3.join(agentDir, "auth.json");
15844
- const extensionsDir = path3.join(agentDir, "extensions");
16353
+ const agentDir = env.PI_CODING_AGENT_DIR ?? path6.join(env.HOME ?? os2.homedir(), ".pi/agent");
16354
+ const authPath = path6.join(agentDir, "auth.json");
16355
+ const extensionsDir = path6.join(agentDir, "extensions");
15845
16356
  const saveAuth = (auth) => (options.writeAuth ?? writeAuth)(authPath, JSON.stringify(auth, null, 2) + "\n");
15846
16357
  const resolve = () => options.resolveInstallation?.(authPath) ?? installation(options.command, env, authPath);
15847
- const location = (name) => path3.join(extensionsDir, `${PREFIX}${credentialImportNameSchema.parse(name)}`);
16358
+ const location = (name) => path6.join(extensionsDir, `${PREFIX}${credentialImportNameSchema.parse(name)}`);
15848
16359
  const readRecord = (name) => {
15849
16360
  const dir = location(name);
15850
16361
  if (lstatSync(dir).isSymbolicLink())
15851
16362
  throw new Error("Imported configuration was changed; manage it in Pi");
15852
- const value = JSON.parse(readFileSync(path3.join(dir, "import.json"), "utf8"));
16363
+ const value = JSON.parse(readFileSync(path6.join(dir, "import.json"), "utf8"));
15853
16364
  if (value.version !== 1 || typeof value.owner !== "string" || typeof value.extension !== "string")
15854
16365
  throw new Error("Invalid import metadata");
15855
- const record6 = value.record;
15856
- if (!object2(record6))
16366
+ const record7 = value.record;
16367
+ if (!object2(record7))
15857
16368
  throw new Error("Invalid import metadata");
15858
16369
  value.record = credentialImportRecordSchema.parse({
15859
- name: record6.name,
15860
- source: record6.source,
15861
- importedAt: record6.importedAt
16370
+ name: record7.name,
16371
+ source: record7.source,
16372
+ importedAt: record7.importedAt
15862
16373
  });
15863
16374
  if (value.record.name !== name)
15864
16375
  throw new Error("Import identity mismatch");
@@ -15866,7 +16377,7 @@ function createPiCredentialImports(options = {}) {
15866
16377
  };
15867
16378
  const owned = (meta3, auth) => {
15868
16379
  const credential = auth[meta3.record.name];
15869
- const file2 = path3.join(location(meta3.record.name), "index.ts");
16380
+ const file2 = path6.join(location(meta3.record.name), "index.ts");
15870
16381
  return existsSync(file2) && !lstatSync(file2).isSymbolicLink() && readFileSync(file2, "utf8") === meta3.extension && object2(credential) && credential.type === "oauth" && credential.codexhostImportId === meta3.owner;
15871
16382
  };
15872
16383
  const readAuth = () => existsSync(authPath) ? parseAuth(readFileSync(authPath, "utf8")) : {};
@@ -15880,7 +16391,7 @@ function createPiCredentialImports(options = {}) {
15880
16391
  const name = entry.slice(PREFIX.length);
15881
16392
  if (!credentialImportNameSchema.safeParse(name).success)
15882
16393
  continue;
15883
- if (!existsSync(path3.join(location(name), "import.json")))
16394
+ if (!existsSync(path6.join(location(name), "import.json")))
15884
16395
  continue;
15885
16396
  try {
15886
16397
  const meta3 = readRecord(name);
@@ -15901,7 +16412,7 @@ function createPiCredentialImports(options = {}) {
15901
16412
  },
15902
16413
  async listOthers() {
15903
16414
  const auth = readAuth();
15904
- const ours = new Set(ownedRecords(auth).map((record6) => record6.name));
16415
+ const ours = new Set(ownedRecords(auth).map((record7) => record7.name));
15905
16416
  const result = /* @__PURE__ */ new Map();
15906
16417
  const usable = (provider) => Boolean(provider) && provider.length <= 128 && !ours.has(provider) && !result.has(provider);
15907
16418
  for (const [provider, credential] of Object.entries(auth)) {
@@ -15914,7 +16425,7 @@ function createPiCredentialImports(options = {}) {
15914
16425
  ...describeOauth(credential)
15915
16426
  });
15916
16427
  }
15917
- const modelsPath = path3.join(agentDir, "models.json");
16428
+ const modelsPath = path6.join(agentDir, "models.json");
15918
16429
  if (existsSync(modelsPath)) {
15919
16430
  const models = JSON.parse(readFileSync(modelsPath, "utf8"));
15920
16431
  const providers = object2(models) && object2(models.providers) ? models.providers : {};
@@ -15936,7 +16447,7 @@ function createPiCredentialImports(options = {}) {
15936
16447
  if (sdk.reservedNames.includes(name) || (await sdk.configuredProviderNames?.())?.includes(name))
15937
16448
  throw new Error("Provider name already exists; choose another name");
15938
16449
  const owner = randomUUID();
15939
- const record6 = credentialImportRecordSchema.parse({
16450
+ const record7 = credentialImportRecordSchema.parse({
15940
16451
  name,
15941
16452
  source: transfer.source,
15942
16453
  importedAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -15948,15 +16459,15 @@ function createPiCredentialImports(options = {}) {
15948
16459
  try {
15949
16460
  sdk.backend.withLock((current) => {
15950
16461
  const auth = parseAuth(current);
15951
- const modelsPath = path3.join(agentDir, "models.json");
16462
+ const modelsPath = path6.join(agentDir, "models.json");
15952
16463
  const models = existsSync(modelsPath) ? JSON.parse(readFileSync(modelsPath, "utf8")) : {};
15953
- if (Object.hasOwn(auth, name) || Object.hasOwn(models.providers ?? {}, name) || existsSync(dir) || existsSync(path3.join(extensionsDir, `${name}-provider.ts`)))
16464
+ if (Object.hasOwn(auth, name) || Object.hasOwn(models.providers ?? {}, name) || existsSync(dir) || existsSync(path6.join(extensionsDir, `${name}-provider.ts`)))
15954
16465
  throw new Error("Provider name already exists; choose another name");
15955
16466
  mkdirSync(extensionsDir, { recursive: true, mode: 448 });
15956
16467
  mkdirSync(dir, { mode: 448 });
15957
16468
  created = true;
15958
- writeFileSync(path3.join(dir, "import.json"), JSON.stringify({ version: 1, owner, record: record6, extension }), { flag: "wx", mode: 384 });
15959
- writeFileSync(path3.join(dir, "index.ts"), extension, { flag: "wx", mode: 384 });
16469
+ writeFileSync(path6.join(dir, "import.json"), JSON.stringify({ version: 1, owner, record: record7, extension }), { flag: "wx", mode: 384 });
16470
+ writeFileSync(path6.join(dir, "index.ts"), extension, { flag: "wx", mode: 384 });
15960
16471
  auth[name] = { type: "oauth", ...transfer.oauth, codexhostImportId: owner };
15961
16472
  saveAuth(auth);
15962
16473
  committed = true;
@@ -15975,7 +16486,7 @@ function createPiCredentialImports(options = {}) {
15975
16486
  const auth = parseAuth(current);
15976
16487
  if (!owned(meta3, auth) || meta3.record.source.id !== transfer.source.id || meta3.record.source.provider !== transfer.source.provider)
15977
16488
  throw new Error("Import ownership or source account changed; refusing replacement");
15978
- const metadataPath = path3.join(location(name), "import.json");
16489
+ const metadataPath = path6.join(location(name), "import.json");
15979
16490
  const previous = readFileSync(metadataPath, "utf8");
15980
16491
  const updated = {
15981
16492
  ...meta3,
@@ -16009,15 +16520,229 @@ function createPiCredentialImports(options = {}) {
16009
16520
  };
16010
16521
  }
16011
16522
 
16523
+ // dist/pi-fast-mode.js
16524
+ import { createHash, randomUUID as randomUUID2 } from "node:crypto";
16525
+ import { mkdir, readFile as readFile2, rename, rm as rm2, writeFile as writeFile2 } from "node:fs/promises";
16526
+ import { homedir as homedir4 } from "node:os";
16527
+ import path7 from "node:path";
16528
+
16529
+ // dist/pi-model-catalog.js
16530
+ var PI_MODEL_REF_PREFIX = "pi-model-v1.";
16531
+ var PI_DRAFT_THINKING_OPTION_IDS = [
16532
+ "off",
16533
+ "minimal",
16534
+ "low",
16535
+ "medium",
16536
+ "high",
16537
+ "xhigh",
16538
+ "max"
16539
+ ].map((id) => harnessThinkingOptionIdSchema.parse(id));
16540
+ var PI_THINKING_LABELS = {
16541
+ off: "Off",
16542
+ minimal: "Minimal",
16543
+ low: "Low",
16544
+ medium: "Medium",
16545
+ high: "High",
16546
+ xhigh: "Extra High",
16547
+ max: "Max"
16548
+ };
16549
+ function compareText(left, right) {
16550
+ return left < right ? -1 : left > right ? 1 : 0;
16551
+ }
16552
+ function assertNativePart(value, name) {
16553
+ if (value.trim().length === 0)
16554
+ throw new Error(`Pi ${name} must not be empty`);
16555
+ }
16556
+ function encodePiModelRef(model) {
16557
+ assertNativePart(model.provider, "Model provider");
16558
+ assertNativePart(model.id, "Model id");
16559
+ const encoded = Buffer.from(JSON.stringify(model.fast ? [model.provider, model.id, true] : [model.provider, model.id]), "utf8").toString("base64url");
16560
+ return harnessModelRefSchema.parse({ id: `${PI_MODEL_REF_PREFIX}${encoded}` });
16561
+ }
16562
+ function decodePiModelRef(ref) {
16563
+ const parsedRef = harnessModelRefSchema.parse(ref);
16564
+ if (!parsedRef.id.startsWith(PI_MODEL_REF_PREFIX)) {
16565
+ throw new Error("Model Ref does not belong to PiAdapter");
16566
+ }
16567
+ const encoded = parsedRef.id.slice(PI_MODEL_REF_PREFIX.length);
16568
+ let decoded;
16569
+ try {
16570
+ decoded = JSON.parse(Buffer.from(encoded, "base64url").toString("utf8"));
16571
+ } catch {
16572
+ throw new Error("Pi Model Ref is malformed");
16573
+ }
16574
+ if (!Array.isArray(decoded) || decoded.length !== 2 && !(decoded.length === 3 && decoded[2] === true) || typeof decoded[0] !== "string" || typeof decoded[1] !== "string") {
16575
+ throw new Error("Pi Model Ref has an invalid native identity");
16576
+ }
16577
+ const native = {
16578
+ provider: decoded[0],
16579
+ id: decoded[1],
16580
+ ...decoded[2] === true ? { fast: true } : {}
16581
+ };
16582
+ assertNativePart(native.provider, "Model provider");
16583
+ assertNativePart(native.id, "Model id");
16584
+ if (encodePiModelRef(native).id !== parsedRef.id) {
16585
+ throw new Error("Pi Model Ref is not canonical");
16586
+ }
16587
+ return native;
16588
+ }
16589
+ function samePiModel(left, right) {
16590
+ return left === null ? right === null : right !== null && left.provider === right.provider && left.id === right.id;
16591
+ }
16592
+ function fallbackThinkingLabel(id) {
16593
+ const label = id.split(/[._~-]+/u).filter((part) => part.length > 0).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
16594
+ return label || id;
16595
+ }
16596
+ function normalizePiThinkingOptions(levels) {
16597
+ return levels.map((id) => harnessThinkingOptionSchema.parse({
16598
+ id,
16599
+ label: PI_THINKING_LABELS[id] ?? fallbackThinkingLabel(id)
16600
+ }));
16601
+ }
16602
+ function normalizePiModelCatalog(nativeModels, effectiveModel, thinkingLevels, effectiveThinkingOptionId) {
16603
+ const byRef = /* @__PURE__ */ new Map();
16604
+ for (const native of nativeModels) {
16605
+ const ref = encodePiModelRef(native);
16606
+ const existing = byRef.get(ref.id);
16607
+ if (existing) {
16608
+ if (existing.reasoning !== native.reasoning) {
16609
+ throw new Error("Pi duplicate Model entries disagree on reasoning capability");
16610
+ }
16611
+ continue;
16612
+ }
16613
+ byRef.set(ref.id, {
16614
+ model: {
16615
+ ref,
16616
+ label: `${native.provider} / ${native.id}`
16617
+ },
16618
+ reasoning: native.reasoning
16619
+ });
16620
+ }
16621
+ const defaultModel = effectiveModel ? encodePiModelRef(effectiveModel) : void 0;
16622
+ if (defaultModel && !byRef.has(defaultModel.id)) {
16623
+ throw new Error("Pi effective Model is absent from the available Model catalog");
16624
+ }
16625
+ if (thinkingLevels && effectiveThinkingOptionId && !thinkingLevels.includes(effectiveThinkingOptionId)) {
16626
+ throw new Error("Pi effective Thinking option is absent from the available option catalog");
16627
+ }
16628
+ if (thinkingLevels && !effectiveThinkingOptionId) {
16629
+ throw new Error("Pi did not report an effective Thinking option");
16630
+ }
16631
+ const thinkingOptions = thinkingLevels ? normalizePiThinkingOptions(PI_DRAFT_THINKING_OPTION_IDS) : [];
16632
+ const allThinkingOptionIds = thinkingOptions.map(({ id }) => id);
16633
+ const offThinkingOptionId = thinkingOptions.find(({ id }) => id === "off")?.id;
16634
+ const models = [...byRef.values()].map(({ model, reasoning }) => ({
16635
+ ...model,
16636
+ supportedThinkingOptionIds: reasoning ? allThinkingOptionIds : offThinkingOptionId ? [offThinkingOptionId] : []
16637
+ })).sort((left, right) => compareText(left.label, right.label) || compareText(left.ref.id, right.ref.id));
16638
+ const defaultThinkingOptionId = thinkingOptions.find(({ id }) => id === effectiveThinkingOptionId)?.id;
16639
+ return harnessModelCatalogSchema.parse({
16640
+ models,
16641
+ ...defaultModel ? { defaultModel } : {},
16642
+ thinkingOptions,
16643
+ ...defaultThinkingOptionId ? { defaultThinkingOptionId } : {}
16644
+ });
16645
+ }
16646
+
16647
+ // dist/pi-fast-mode.js
16648
+ var PI_FAST_COMMAND = "codexhost-fast-mode";
16649
+ var PI_FAST_ACK = "codexhost-fast-mode:";
16650
+ var PI_FAST_EXTENSION = `export default function(pi) {
16651
+ let target;
16652
+ const wrapped = new Set();
16653
+ pi.on("model_select", (_event, ctx) => {
16654
+ if (target && (target.provider !== ctx.model?.provider || target.id !== ctx.model?.id || ctx.model?.api !== "openai-codex-responses")) target = undefined;
16655
+ });
16656
+ pi.on("session_start", (_event, ctx) => {
16657
+ if (typeof ctx.modelRegistry.getProvider !== "function") return;
16658
+ pi.registerCommand("${PI_FAST_COMMAND}", {
16659
+ description: "Codex Host Fast mode",
16660
+ handler: async (args, ctx) => {
16661
+ const [mode, nonce] = args.split(" ");
16662
+ if (!nonce || (mode !== "on" && mode !== "off")) throw new Error("Invalid Fast selection");
16663
+ if (mode === "on") {
16664
+ const model = ctx.model;
16665
+ if (!model || model.api !== "openai-codex-responses") throw new Error("Fast requires the Codex API");
16666
+ const original = ctx.modelRegistry.getProvider(model.provider);
16667
+ if (!original) throw new Error("Codex Provider is unavailable");
16668
+ if (!wrapped.has(model.provider)) {
16669
+ const options = (model, value) => target && model.api === "openai-codex-responses" && target.provider === model.provider && target.id === model.id
16670
+ ? {
16671
+ ...value,
16672
+ serviceTier: "priority",
16673
+ // Pi streamSimple drops serviceTier but preserves onPayload.
16674
+ onPayload: async (payload, requestModel) => {
16675
+ const request = { ...payload, service_tier: "priority" };
16676
+ const replacement = await value?.onPayload?.(request, requestModel);
16677
+ return { ...(replacement === undefined ? request : replacement), service_tier: "priority" };
16678
+ },
16679
+ } : value;
16680
+ pi.registerProvider({
16681
+ ...original,
16682
+ stream: (model, context, value) => original.stream(model, context, options(model, value)),
16683
+ streamSimple: (model, context, value) => original.streamSimple(model, context, options(model, value)),
16684
+ });
16685
+ wrapped.add(model.provider);
16686
+ }
16687
+ target = { provider: model.provider, id: model.id };
16688
+ } else target = undefined;
16689
+ ctx.ui.notify("${PI_FAST_ACK}" + nonce + ":" + mode, "info");
16690
+ },
16691
+ });
16692
+ });
16693
+ }
16694
+ `;
16695
+ async function ensurePiFastExtension(environment) {
16696
+ const digest = createHash("sha256").update(PI_FAST_EXTENSION).digest("hex").slice(0, 16);
16697
+ const dataDirectory = environment.CODEXHOST_DATA_DIR ?? path7.join(environment.HOME ?? environment.USERPROFILE ?? homedir4(), ".codexhost");
16698
+ const directory = path7.resolve(dataDirectory, "extensions", "pi-codex-fast");
16699
+ const file2 = path7.join(directory, `${digest}.mjs`);
16700
+ if (await readFile2(file2, "utf8").catch(() => "") === PI_FAST_EXTENSION)
16701
+ return file2;
16702
+ await mkdir(directory, { recursive: true });
16703
+ const temporary = `${file2}.${randomUUID2()}.tmp`;
16704
+ try {
16705
+ await writeFile2(temporary, PI_FAST_EXTENSION, { mode: 384 });
16706
+ try {
16707
+ await rename(temporary, file2);
16708
+ } catch (error51) {
16709
+ if (await readFile2(file2, "utf8").catch(() => "") !== PI_FAST_EXTENSION)
16710
+ throw error51;
16711
+ }
16712
+ } finally {
16713
+ await rm2(temporary, { force: true });
16714
+ }
16715
+ return file2;
16716
+ }
16717
+ async function piFastModelKeys(models, environment) {
16718
+ try {
16719
+ const codexHome = environment.CODEX_HOME ?? path7.join(environment.HOME ?? environment.USERPROFILE ?? homedir4(), ".codex");
16720
+ const cache = JSON.parse(await readFile2(path7.join(codexHome, "models_cache.json"), "utf8"));
16721
+ if (!cache || typeof cache !== "object" || !("models" in cache) || !Array.isArray(cache.models))
16722
+ return /* @__PURE__ */ new Set();
16723
+ const priority = new Set(cache.models.filter((model) => typeof model?.slug === "string" && Array.isArray(model.service_tiers) && model.service_tiers.some((tier) => tier?.id === "priority")).map((model) => model.slug));
16724
+ const codexProviders = new Set(readPiCodexProviderNames(environment));
16725
+ return new Set(models.filter((model) => model.api === "openai-codex-responses" && codexProviders.has(model.provider) && priority.has(model.id)).map((model) => encodePiModelRef(model).id));
16726
+ } catch {
16727
+ return /* @__PURE__ */ new Set();
16728
+ }
16729
+ }
16730
+ function withPiFast(catalog, supported) {
16731
+ return {
16732
+ ...catalog,
16733
+ models: catalog.models.map((model) => supported.has(model.ref.id) ? { ...model, fastModel: encodePiModelRef({ ...decodePiModelRef(model.ref), fast: true }) } : model)
16734
+ };
16735
+ }
16736
+
16012
16737
  // dist/pi-empty-session.js
16013
16738
  import { createReadStream } from "node:fs";
16014
16739
  import { createInterface } from "node:readline";
16015
- import { randomUUID as randomUUID2 } from "node:crypto";
16016
- import { link, open as open2, rm } from "node:fs/promises";
16017
- import path4 from "node:path";
16740
+ import { randomUUID as randomUUID3 } from "node:crypto";
16741
+ import { link, open as open2, rm as rm3 } from "node:fs/promises";
16742
+ import path8 from "node:path";
16018
16743
 
16019
16744
  // dist/pi-subagents.js
16020
- import { createHash } from "node:crypto";
16745
+ import { createHash as createHash2 } from "node:crypto";
16021
16746
 
16022
16747
  // dist/pi-subagent-workflow.js
16023
16748
  var PREFIX2 = "pi-subagents-workflow-v1:";
@@ -16031,23 +16756,23 @@ var STATES = {
16031
16756
  rejected: "failed",
16032
16757
  detached: "running"
16033
16758
  };
16034
- function record2(value) {
16759
+ function record3(value) {
16035
16760
  return typeof value === "object" && value !== null && !Array.isArray(value);
16036
16761
  }
16037
16762
  function text(value, limit = 256) {
16038
16763
  return typeof value === "string" && value.length > 0 && value.length <= limit;
16039
16764
  }
16040
16765
  function piWorkflowSummary(result) {
16041
- if (!record2(result) || !record2(result.details) || result.details.mode !== "workflow" || result.details.asyncId !== void 0)
16766
+ if (!record3(result) || !record3(result.details) || result.details.mode !== "workflow" || result.details.asyncId !== void 0)
16042
16767
  return null;
16043
16768
  const details = result.details;
16044
16769
  const summary = details.workflowChildren;
16045
- if (!record2(summary) || summary.version !== 1 || !text(summary.workflowRunId) || summary.workflowRunId !== details.runId || !text(summary.parentToolCallId) || typeof summary.inventoryComplete !== "boolean" || !Array.isArray(summary.children) || summary.children.length > 256)
16770
+ if (!record3(summary) || summary.version !== 1 || !text(summary.workflowRunId) || summary.workflowRunId !== details.runId || !text(summary.parentToolCallId) || typeof summary.inventoryComplete !== "boolean" || !Array.isArray(summary.children) || summary.children.length > 256)
16046
16771
  return null;
16047
16772
  const children = [];
16048
16773
  const seen = /* @__PURE__ */ new Set();
16049
16774
  for (const child of summary.children) {
16050
- if (!record2(child) || !text(child.childId) || seen.has(child.childId) || typeof child.state !== "string" || !Object.hasOwn(STATES, child.state))
16775
+ if (!record3(child) || !text(child.childId) || seen.has(child.childId) || typeof child.state !== "string" || !Object.hasOwn(STATES, child.state))
16051
16776
  return null;
16052
16777
  for (const key of ["agent", "sessionName", "model", "thinking"]) {
16053
16778
  if (child[key] !== void 0 && !text(child[key], 2048))
@@ -16120,7 +16845,7 @@ var STATUS_PREFIX = "PI_SUBAGENT_ASYNC_JSON:";
16120
16845
  var INSPECT_PREFIX = "PI_SUBAGENT_INSPECT_JSON:";
16121
16846
  var ID_PREFIX = "pi-subagents-v1:";
16122
16847
  var MAX_BYTES = 64 * 1024;
16123
- function record3(value) {
16848
+ function record4(value) {
16124
16849
  return typeof value === "object" && value !== null && !Array.isArray(value);
16125
16850
  }
16126
16851
  function token(value) {
@@ -16137,7 +16862,7 @@ var statuses = {
16137
16862
  rejected: "failed"
16138
16863
  };
16139
16864
  function node(value, depth, budget) {
16140
- if (!record3(value) || depth > 8 || ++budget.count > 256 || !token(value.id) || !["subagent", "workflow", "step", "host-step"].includes(String(value.kind)) || typeof value.label !== "string" || value.label.length > 2048 || typeof value.state !== "string" || !Object.hasOwn(statuses, value.state))
16865
+ if (!record4(value) || depth > 8 || ++budget.count > 256 || !token(value.id) || !["subagent", "workflow", "step", "host-step"].includes(String(value.kind)) || typeof value.label !== "string" || value.label.length > 2048 || typeof value.state !== "string" || !Object.hasOwn(statuses, value.state))
16141
16866
  return null;
16142
16867
  const children = [];
16143
16868
  if (value.children !== void 0) {
@@ -16159,14 +16884,14 @@ function node(value, depth, budget) {
16159
16884
  };
16160
16885
  }
16161
16886
  function widget(value, key, prefix) {
16162
- if (!record3(value) || value.type !== "extension_ui_request" || value.method !== "setWidget" || value.widgetKey !== key || !Array.isArray(value.widgetLines))
16887
+ if (!record4(value) || value.type !== "extension_ui_request" || value.method !== "setWidget" || value.widgetKey !== key || !Array.isArray(value.widgetLines))
16163
16888
  return null;
16164
16889
  const line = value.widgetLines.find((part) => typeof part === "string" && part.startsWith(prefix));
16165
16890
  if (!line || Buffer.byteLength(line) > MAX_BYTES + prefix.length)
16166
16891
  return null;
16167
16892
  try {
16168
16893
  const parsed = JSON.parse(line.slice(prefix.length));
16169
- return record3(parsed) && parsed.version === 1 ? parsed : null;
16894
+ return record4(parsed) && parsed.version === 1 ? parsed : null;
16170
16895
  } catch {
16171
16896
  return null;
16172
16897
  }
@@ -16230,7 +16955,7 @@ function states(run) {
16230
16955
  return result;
16231
16956
  }
16232
16957
  function asyncRunId(toolName, result) {
16233
- if (toolName !== "subagent" || !record3(result) || !record3(result.details))
16958
+ if (toolName !== "subagent" || !record4(result) || !record4(result.details))
16234
16959
  return null;
16235
16960
  const details = result.details;
16236
16961
  return ["single", "parallel", "chain", "workflow"].includes(String(details.mode)) && token(details.asyncId) && typeof details.asyncDir === "string" ? details.asyncId : null;
@@ -16370,15 +17095,15 @@ function parsePiSubagentInspection(value) {
16370
17095
  const parsed = widget(value, "subagent-inspect", INSPECT_PREFIX);
16371
17096
  if (!parsed || parsed.kind !== "pi-subagents.inspect-reply" || !token(parsed.requestId))
16372
17097
  return null;
16373
- if (parsed.error !== void 0 && (!record3(parsed.error) || typeof parsed.error.code !== "string" || typeof parsed.error.message !== "string"))
17098
+ if (parsed.error !== void 0 && (!record4(parsed.error) || typeof parsed.error.code !== "string" || typeof parsed.error.message !== "string"))
16374
17099
  return null;
16375
17100
  for (const field of ["asyncId", "childId", "status", "task", "finalOutput"]) {
16376
17101
  if (parsed[field] !== void 0 && typeof parsed[field] !== "string")
16377
17102
  return null;
16378
17103
  }
16379
- if (parsed.messages !== void 0 && (!Array.isArray(parsed.messages) || parsed.messages.length > 200 || parsed.messages.some((entry) => !record3(entry) || typeof entry.role !== "string" || typeof entry.text !== "string" || !["text", "toolCall", "toolResult"].includes(String(entry.kind)) || entry.name !== void 0 && typeof entry.name !== "string")))
17104
+ if (parsed.messages !== void 0 && (!Array.isArray(parsed.messages) || parsed.messages.length > 200 || parsed.messages.some((entry) => !record4(entry) || typeof entry.role !== "string" || typeof entry.text !== "string" || !["text", "toolCall", "toolResult"].includes(String(entry.kind)) || entry.name !== void 0 && typeof entry.name !== "string")))
16380
17105
  return null;
16381
- if (parsed.truncated !== void 0 && (!record3(parsed.truncated) || typeof parsed.truncated.task !== "boolean" || typeof parsed.truncated.finalOutput !== "boolean" || !Number.isSafeInteger(parsed.truncated.messages) || Number(parsed.truncated.messages) < 0))
17106
+ if (parsed.truncated !== void 0 && (!record4(parsed.truncated) || typeof parsed.truncated.task !== "boolean" || typeof parsed.truncated.finalOutput !== "boolean" || !Number.isSafeInteger(parsed.truncated.messages) || Number(parsed.truncated.messages) < 0))
16382
17107
  return null;
16383
17108
  return parsed;
16384
17109
  }
@@ -16397,7 +17122,7 @@ ${entry.text}`);
16397
17122
  nativeTurnRef: nativeTurnRefSchema.parse({
16398
17123
  harnessId: "pi",
16399
17124
  nativeSessionId: parentSessionId,
16400
- nativeTurnKey: `pi-subagent-${createHash("sha256").update(id).digest("hex")}`,
17125
+ nativeTurnKey: `pi-subagent-${createHash2("sha256").update(id).digest("hex")}`,
16401
17126
  formatVersion: 1
16402
17127
  }),
16403
17128
  input: reply.task ? [{ type: "text", text: reply.task }] : [],
@@ -16405,7 +17130,7 @@ ${entry.text}`);
16405
17130
  item: {
16406
17131
  type: "agentMessage",
16407
17132
  text: text2,
16408
- itemId: hostItemIdSchema.parse(`pi-subagent-${createHash("sha256").update(`${id}:${index}:${text2}`).digest("hex")}`)
17133
+ itemId: hostItemIdSchema.parse(`pi-subagent-${createHash2("sha256").update(`${id}:${index}:${text2}`).digest("hex")}`)
16409
17134
  },
16410
17135
  outcome: { status: "succeeded" }
16411
17136
  })),
@@ -16425,120 +17150,6 @@ ${entry.text}`);
16425
17150
  };
16426
17151
  }
16427
17152
 
16428
- // dist/pi-model-catalog.js
16429
- var PI_MODEL_REF_PREFIX = "pi-model-v1.";
16430
- var PI_DRAFT_THINKING_OPTION_IDS = [
16431
- "off",
16432
- "minimal",
16433
- "low",
16434
- "medium",
16435
- "high",
16436
- "xhigh",
16437
- "max"
16438
- ].map((id) => harnessThinkingOptionIdSchema.parse(id));
16439
- var PI_THINKING_LABELS = {
16440
- off: "Off",
16441
- minimal: "Minimal",
16442
- low: "Low",
16443
- medium: "Medium",
16444
- high: "High",
16445
- xhigh: "Extra High",
16446
- max: "Max"
16447
- };
16448
- function compareText(left, right) {
16449
- return left < right ? -1 : left > right ? 1 : 0;
16450
- }
16451
- function assertNativePart(value, name) {
16452
- if (value.trim().length === 0)
16453
- throw new Error(`Pi ${name} must not be empty`);
16454
- }
16455
- function encodePiModelRef(model) {
16456
- assertNativePart(model.provider, "Model provider");
16457
- assertNativePart(model.id, "Model id");
16458
- const encoded = Buffer.from(JSON.stringify([model.provider, model.id]), "utf8").toString("base64url");
16459
- return harnessModelRefSchema.parse({ id: `${PI_MODEL_REF_PREFIX}${encoded}` });
16460
- }
16461
- function decodePiModelRef(ref) {
16462
- const parsedRef = harnessModelRefSchema.parse(ref);
16463
- if (!parsedRef.id.startsWith(PI_MODEL_REF_PREFIX)) {
16464
- throw new Error("Model Ref does not belong to PiAdapter");
16465
- }
16466
- const encoded = parsedRef.id.slice(PI_MODEL_REF_PREFIX.length);
16467
- let decoded;
16468
- try {
16469
- decoded = JSON.parse(Buffer.from(encoded, "base64url").toString("utf8"));
16470
- } catch {
16471
- throw new Error("Pi Model Ref is malformed");
16472
- }
16473
- if (!Array.isArray(decoded) || decoded.length !== 2 || typeof decoded[0] !== "string" || typeof decoded[1] !== "string") {
16474
- throw new Error("Pi Model Ref has an invalid native identity");
16475
- }
16476
- const native = { provider: decoded[0], id: decoded[1] };
16477
- assertNativePart(native.provider, "Model provider");
16478
- assertNativePart(native.id, "Model id");
16479
- if (encodePiModelRef(native).id !== parsedRef.id) {
16480
- throw new Error("Pi Model Ref is not canonical");
16481
- }
16482
- return native;
16483
- }
16484
- function samePiModel(left, right) {
16485
- return left === null ? right === null : right !== null && left.provider === right.provider && left.id === right.id;
16486
- }
16487
- function fallbackThinkingLabel(id) {
16488
- const label = id.split(/[._~-]+/u).filter((part) => part.length > 0).map((part) => `${part[0]?.toUpperCase() ?? ""}${part.slice(1)}`).join(" ");
16489
- return label || id;
16490
- }
16491
- function normalizePiThinkingOptions(levels) {
16492
- return levels.map((id) => harnessThinkingOptionSchema.parse({
16493
- id,
16494
- label: PI_THINKING_LABELS[id] ?? fallbackThinkingLabel(id)
16495
- }));
16496
- }
16497
- function normalizePiModelCatalog(nativeModels, effectiveModel, thinkingLevels, effectiveThinkingOptionId) {
16498
- const byRef = /* @__PURE__ */ new Map();
16499
- for (const native of nativeModels) {
16500
- const ref = encodePiModelRef(native);
16501
- const existing = byRef.get(ref.id);
16502
- if (existing) {
16503
- if (existing.reasoning !== native.reasoning) {
16504
- throw new Error("Pi duplicate Model entries disagree on reasoning capability");
16505
- }
16506
- continue;
16507
- }
16508
- byRef.set(ref.id, {
16509
- model: {
16510
- ref,
16511
- label: `${native.provider} / ${native.id}`
16512
- },
16513
- reasoning: native.reasoning
16514
- });
16515
- }
16516
- const defaultModel = effectiveModel ? encodePiModelRef(effectiveModel) : void 0;
16517
- if (defaultModel && !byRef.has(defaultModel.id)) {
16518
- throw new Error("Pi effective Model is absent from the available Model catalog");
16519
- }
16520
- if (thinkingLevels && effectiveThinkingOptionId && !thinkingLevels.includes(effectiveThinkingOptionId)) {
16521
- throw new Error("Pi effective Thinking option is absent from the available option catalog");
16522
- }
16523
- if (thinkingLevels && !effectiveThinkingOptionId) {
16524
- throw new Error("Pi did not report an effective Thinking option");
16525
- }
16526
- const thinkingOptions = thinkingLevels ? normalizePiThinkingOptions(PI_DRAFT_THINKING_OPTION_IDS) : [];
16527
- const allThinkingOptionIds = thinkingOptions.map(({ id }) => id);
16528
- const offThinkingOptionId = thinkingOptions.find(({ id }) => id === "off")?.id;
16529
- const models = [...byRef.values()].map(({ model, reasoning }) => ({
16530
- ...model,
16531
- supportedThinkingOptionIds: reasoning ? allThinkingOptionIds : offThinkingOptionId ? [offThinkingOptionId] : []
16532
- })).sort((left, right) => compareText(left.label, right.label) || compareText(left.ref.id, right.ref.id));
16533
- const defaultThinkingOptionId = thinkingOptions.find(({ id }) => id === effectiveThinkingOptionId)?.id;
16534
- return harnessModelCatalogSchema.parse({
16535
- models,
16536
- ...defaultModel ? { defaultModel } : {},
16537
- thinkingOptions,
16538
- ...defaultThinkingOptionId ? { defaultThinkingOptionId } : {}
16539
- });
16540
- }
16541
-
16542
17153
  // dist/pi-history.js
16543
17154
  var piHarnessId = harnessIdSchema.parse("pi");
16544
17155
  function isRecord(value) {
@@ -16844,7 +17455,7 @@ async function verifyPiSessionCwd(input) {
16844
17455
  async function persistEmptyPiSession(input) {
16845
17456
  const { state: state2, history, sourceSessionFile, sourceSessionId, cwd } = input;
16846
17457
  const destination = state2.sessionFile;
16847
- if (!destination || !path4.isAbsolute(destination) || path4.resolve(destination) === path4.resolve(sourceSessionFile) || state2.sessionId === sourceSessionId || mapPiSnapshot(history, { sessionId: state2.sessionId, model: null }).turns.length !== 0)
17458
+ if (!destination || !path8.isAbsolute(destination) || path8.resolve(destination) === path8.resolve(sourceSessionFile) || state2.sessionId === sourceSessionId || mapPiSnapshot(history, { sessionId: state2.sessionId, model: null }).turns.length !== 0)
16848
17459
  throw new Error("Pi empty Session is not an independent empty native fork");
16849
17460
  await verifyPiSessionCwd({
16850
17461
  sessionFile: sourceSessionFile,
@@ -16868,7 +17479,7 @@ async function persistEmptyPiSession(input) {
16868
17479
  cwd,
16869
17480
  parentSession: sourceSessionFile
16870
17481
  };
16871
- const temporary = path4.join(path4.dirname(destination), `.codexhost-${randomUUID2()}.tmp`);
17482
+ const temporary = path8.join(path8.dirname(destination), `.codexhost-${randomUUID3()}.tmp`);
16872
17483
  try {
16873
17484
  const file2 = await open2(temporary, "wx", 384);
16874
17485
  try {
@@ -16879,7 +17490,7 @@ async function persistEmptyPiSession(input) {
16879
17490
  }
16880
17491
  await link(temporary, destination);
16881
17492
  if (process.platform !== "win32") {
16882
- const directory = await open2(path4.dirname(destination), "r");
17493
+ const directory = await open2(path8.dirname(destination), "r");
16883
17494
  try {
16884
17495
  await directory.sync();
16885
17496
  } finally {
@@ -16887,7 +17498,7 @@ async function persistEmptyPiSession(input) {
16887
17498
  }
16888
17499
  }
16889
17500
  } finally {
16890
- await rm(temporary, { force: true });
17501
+ await rm3(temporary, { force: true });
16891
17502
  }
16892
17503
  }
16893
17504
  async function readPiEmptySessionConfiguration(sessionFile) {
@@ -17042,16 +17653,16 @@ var Diff = class {
17042
17653
  }
17043
17654
  }
17044
17655
  }
17045
- addToPath(path10, added, removed, oldPosInc, options) {
17046
- const last = path10.lastComponent;
17656
+ addToPath(path14, added, removed, oldPosInc, options) {
17657
+ const last = path14.lastComponent;
17047
17658
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
17048
17659
  return {
17049
- oldPos: path10.oldPos + oldPosInc,
17660
+ oldPos: path14.oldPos + oldPosInc,
17050
17661
  lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
17051
17662
  };
17052
17663
  } else {
17053
17664
  return {
17054
- oldPos: path10.oldPos + oldPosInc,
17665
+ oldPos: path14.oldPos + oldPosInc,
17055
17666
  lastComponent: { count: 1, added, removed, previousComponent: last }
17056
17667
  };
17057
17668
  }
@@ -17463,8 +18074,8 @@ function splitLines(text2) {
17463
18074
  }
17464
18075
 
17465
18076
  // dist/pi-adapter.js
17466
- import { randomUUID as randomUUID5 } from "node:crypto";
17467
- import path9 from "node:path";
18077
+ import { randomUUID as randomUUID6 } from "node:crypto";
18078
+ import path13 from "node:path";
17468
18079
 
17469
18080
  // ../../harness-adapter/dist/question.js
17470
18081
  function invalidRequest(message3) {
@@ -17769,16 +18380,16 @@ function mergeLiveHarnessCommands(builtIns, idPrefix, live, exclusions = {}) {
17769
18380
  }
17770
18381
 
17771
18382
  // dist/pi-workflow-child-history.js
17772
- import { createHash as createHash2 } from "node:crypto";
18383
+ import { createHash as createHash3 } from "node:crypto";
17773
18384
  import { constants } from "node:fs";
17774
18385
  import { open as open3 } from "node:fs/promises";
17775
- import path5 from "node:path";
17776
- function record4(value) {
18386
+ import path9 from "node:path";
18387
+ function record5(value) {
17777
18388
  return typeof value === "object" && value !== null && !Array.isArray(value);
17778
18389
  }
17779
18390
  var MAX_SESSION_BYTES = 8 * 1024 * 1024;
17780
18391
  async function childHistory(file2, parentSessionId, identity) {
17781
- if (!path5.isAbsolute(file2))
18392
+ if (!path9.isAbsolute(file2))
17782
18393
  throw new Error("Pi child Session path is not absolute");
17783
18394
  const handle = await open3(file2, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0) | (constants.O_NONBLOCK ?? 0));
17784
18395
  try {
@@ -17791,18 +18402,18 @@ async function childHistory(file2, parentSessionId, identity) {
17791
18402
  throw new Error("Pi child Session exceeds read bounds");
17792
18403
  const values = buffer.subarray(0, bytesRead).toString("utf8").split("\n").filter((line) => line.trim()).map((line) => JSON.parse(line));
17793
18404
  const header = values[0];
17794
- if (!record4(header) || header.type !== "session" || typeof header.id !== "string" || header.version !== 3)
18405
+ if (!record5(header) || header.type !== "session" || typeof header.id !== "string" || header.version !== 3)
17795
18406
  throw new Error("Unsupported Pi child Session header");
17796
18407
  const entries = [];
17797
18408
  for (const entry of values.slice(1)) {
17798
18409
  const parsed = jsonValueSchema.safeParse(entry);
17799
- if (!parsed.success || !record4(parsed.data) || typeof parsed.data.id !== "string")
18410
+ if (!parsed.success || !record5(parsed.data) || typeof parsed.data.id !== "string")
17800
18411
  throw new Error("Malformed Pi child Session entry");
17801
18412
  entries.push(parsed.data);
17802
18413
  }
17803
18414
  const history = { entries, leafId: String(entries.at(-1)?.id ?? "") || null };
17804
18415
  const snapshot = mapPiSnapshot(history, { sessionId: parentSessionId, model: null });
17805
- const prefix = createHash2("sha256").update(identity).digest("hex");
18416
+ const prefix = createHash3("sha256").update(identity).digest("hex");
17806
18417
  return {
17807
18418
  turns: snapshot.turns.map((turn) => {
17808
18419
  const readonlyTurn = {
@@ -17823,7 +18434,7 @@ async function childHistory(file2, parentSessionId, identity) {
17823
18434
  async function readPiWorkflowChild(history, parentSessionId, address) {
17824
18435
  for (const entry of activePiEntries(history).reverse()) {
17825
18436
  const message3 = entry.message;
17826
- if (!record4(message3) || message3.role !== "toolResult" || message3.toolName !== "subagent")
18437
+ if (!record5(message3) || message3.role !== "toolResult" || message3.toolName !== "subagent")
17827
18438
  continue;
17828
18439
  const summary = piWorkflowSummary(message3);
17829
18440
  if (!summary || summary.workflowRunId !== address.workflowRunId || summary.parentToolCallId !== message3.toolCallId)
@@ -17832,10 +18443,10 @@ async function readPiWorkflowChild(history, parentSessionId, address) {
17832
18443
  if (!child)
17833
18444
  break;
17834
18445
  const details = message3.details;
17835
- if (!record4(details) || !Array.isArray(details.results))
18446
+ if (!record5(details) || !Array.isArray(details.results))
17836
18447
  break;
17837
- const result = details.results.findLast((candidate) => record4(candidate) && candidate.workflowKey === address.childId);
17838
- if (!record4(result))
18448
+ const result = details.results.findLast((candidate) => record5(candidate) && candidate.workflowKey === address.childId);
18449
+ if (!record5(result))
17839
18450
  break;
17840
18451
  const id = piWorkflowSubagentId(address);
17841
18452
  if (typeof result.sessionFile === "string") {
@@ -17881,22 +18492,22 @@ ${output}`,
17881
18492
  // dist/pi-subagent-history.js
17882
18493
  import { constants as constants2 } from "node:fs";
17883
18494
  import { open as open4 } from "node:fs/promises";
17884
- import path6 from "node:path";
17885
- function record5(value) {
18495
+ import path10 from "node:path";
18496
+ function record6(value) {
17886
18497
  return typeof value === "object" && value !== null && !Array.isArray(value);
17887
18498
  }
17888
18499
  function state(value) {
17889
18500
  return value === "pending" ? "queued" : value === "completed" ? "complete" : value;
17890
18501
  }
17891
18502
  function piSubagentArtifact(value, runId, parentSessionId) {
17892
- if (!record5(value) || value.lifecycleArtifactVersion !== 3 || value.runId !== runId || value.sessionId !== parentSessionId || !["single", "parallel", "chain", "workflow"].includes(String(value.mode)))
18503
+ if (!record6(value) || value.lifecycleArtifactVersion !== 3 || value.runId !== runId || value.sessionId !== parentSessionId || !["single", "parallel", "chain", "workflow"].includes(String(value.mode)))
17893
18504
  return null;
17894
18505
  if (value.steps !== void 0 && (!Array.isArray(value.steps) || value.steps.length > 128))
17895
18506
  return null;
17896
18507
  const steps = Array.isArray(value.steps) ? value.steps : [];
17897
18508
  const children = [];
17898
18509
  for (const [index, step] of steps.entries()) {
17899
- if (!record5(step) || typeof step.agent !== "string")
18510
+ if (!record6(step) || typeof step.agent !== "string")
17900
18511
  return null;
17901
18512
  children.push({
17902
18513
  id: step.workflowKey ?? step.runId ?? `step:${index}`,
@@ -17929,17 +18540,17 @@ function piSubagentArtifact(value, runId, parentSessionId) {
17929
18540
  async function restorePiSubagents(history, parentSessionId, observer) {
17930
18541
  const receipts = /* @__PURE__ */ new Map();
17931
18542
  for (const entry of activePiEntries(history)) {
17932
- if (!record5(entry.message) || entry.message.role !== "toolResult" || entry.message.toolName !== "subagent" || entry.message.isError !== false || !record5(entry.message.details))
18543
+ if (!record6(entry.message) || entry.message.role !== "toolResult" || entry.message.toolName !== "subagent" || entry.message.isError !== false || !record6(entry.message.details))
17933
18544
  continue;
17934
18545
  const details = entry.message.details;
17935
- if (!["single", "parallel", "chain", "workflow"].includes(String(details.mode)) || typeof details.asyncId !== "string" || typeof details.asyncDir !== "string" || !path6.isAbsolute(details.asyncDir) || path6.basename(details.asyncDir) !== details.asyncId)
18546
+ if (!["single", "parallel", "chain", "workflow"].includes(String(details.mode)) || typeof details.asyncId !== "string" || typeof details.asyncDir !== "string" || !path10.isAbsolute(details.asyncDir) || path10.basename(details.asyncDir) !== details.asyncId)
17936
18547
  continue;
17937
18548
  receipts.set(details.asyncId, details.asyncDir);
17938
18549
  }
17939
18550
  for (const [id, directory] of [...receipts].slice(-128)) {
17940
18551
  let file2;
17941
18552
  try {
17942
- file2 = await open4(path6.join(directory, "status.json"), constants2.O_RDONLY | (constants2.O_NOFOLLOW ?? 0));
18553
+ file2 = await open4(path10.join(directory, "status.json"), constants2.O_RDONLY | (constants2.O_NOFOLLOW ?? 0));
17943
18554
  const stat2 = await file2.stat();
17944
18555
  if (!stat2.isFile() || stat2.size > 1024 * 1024)
17945
18556
  continue;
@@ -18021,24 +18632,109 @@ async function rollbackPiLastTurn(transport, sourceSessionId, cwd) {
18021
18632
  import { createReadStream as createReadStream2 } from "node:fs";
18022
18633
  import { opendir, realpath as realpath3, stat } from "node:fs/promises";
18023
18634
  import os3 from "node:os";
18024
- import path7 from "node:path";
18635
+ import path11 from "node:path";
18025
18636
  import { createInterface as createInterface2 } from "node:readline";
18026
- var PiSessionChangedError = class extends Error {
18027
- constructor() {
18028
- super("Pi Session changed during discovery; refresh and retry");
18637
+
18638
+ // ../../harness-adapter/dist/session-import.js
18639
+ var SessionImportChangedError = class extends Error {
18640
+ constructor(message3 = "Native Session changed during discovery; refresh and retry") {
18641
+ super(message3);
18642
+ this.name = "SessionImportChangedError";
18029
18643
  }
18030
18644
  };
18031
- function sameFile(left, right) {
18032
- return left.size === right.size && left.mtimeMs === right.mtimeMs && left.ctimeMs === right.ctimeMs && left.ino === right.ino && left.dev === right.dev;
18645
+ function isMissingFileError(error51) {
18646
+ return typeof error51 === "object" && error51 !== null && "code" in error51 && error51.code === "ENOENT";
18647
+ }
18648
+ function sameFileFingerprint(left, right) {
18649
+ return left === null || right === null ? left === right : left.dev === right.dev && left.ino === right.ino && left.size === right.size && left.mtimeMs === right.mtimeMs && left.ctimeMs === right.ctimeMs;
18650
+ }
18651
+ function sessionImportTitle(value, maxLength = HARNESS_SESSION_IMPORT_TITLE_MAX_LENGTH) {
18652
+ if (typeof value !== "string")
18653
+ return null;
18654
+ const normalized = value.replaceAll("\0", "").replaceAll(/\s+/gu, " ").trim();
18655
+ if (!normalized)
18656
+ return null;
18657
+ if (normalized.length <= maxLength)
18658
+ return normalized;
18659
+ const characters = [...normalized];
18660
+ if (characters.length <= maxLength)
18661
+ return normalized;
18662
+ return `${characters.slice(0, maxLength - 1).join("").trimEnd()}…`;
18663
+ }
18664
+ function sessionImportCandidate(input) {
18665
+ const time3 = typeof input.updatedAt === "number" ? input.updatedAt : typeof input.updatedAt === "string" ? Date.parse(input.updatedAt) : Number.NaN;
18666
+ const parsed = harnessSessionImportCandidateSchema.safeParse({
18667
+ nativeSessionId: input.nativeSessionId,
18668
+ cwd: input.cwd,
18669
+ title: typeof input.title === "string" && input.title.trim().length > 0 ? input.title : null,
18670
+ updatedAt: Math.floor(time3),
18671
+ // Unknown must stay unknown; only an explicit boolean is a native statement.
18672
+ running: typeof input.running === "boolean" ? input.running : null
18673
+ });
18674
+ return parsed.success ? parsed.data : null;
18033
18675
  }
18676
+ var SessionImportScope = class {
18677
+ #abort = new AbortController();
18678
+ #options;
18679
+ #pending = /* @__PURE__ */ new Set();
18680
+ constructor(options) {
18681
+ this.#options = options;
18682
+ }
18683
+ #closed() {
18684
+ return {
18685
+ ok: false,
18686
+ error: { code: "invalidState", message: this.#options.closedMessage, retryable: false }
18687
+ };
18688
+ }
18689
+ read(operation) {
18690
+ const signal = this.#abort.signal;
18691
+ if (signal.aborted)
18692
+ return Promise.resolve(this.#closed());
18693
+ let started;
18694
+ try {
18695
+ started = operation(signal);
18696
+ } catch (error51) {
18697
+ started = Promise.reject(error51 instanceof Error ? error51 : new Error("Session read failed"));
18698
+ }
18699
+ const request = started.then((value) => signal.aborted ? this.#closed() : { ok: true, value }).catch(() => signal.aborted ? this.#closed() : {
18700
+ ok: false,
18701
+ error: {
18702
+ code: "unavailable",
18703
+ message: this.#options.unavailableMessage,
18704
+ retryable: true
18705
+ }
18706
+ }).finally(() => this.#pending.delete(request));
18707
+ this.#pending.add(request);
18708
+ return request;
18709
+ }
18710
+ /** `read` for `resolveCandidate`: a null source is the selected Session having disappeared. */
18711
+ async resolve(operation) {
18712
+ const result = await this.read(operation);
18713
+ if (!result.ok)
18714
+ return result;
18715
+ return result.value ? { ok: true, value: result.value } : {
18716
+ ok: false,
18717
+ error: {
18718
+ code: "sessionNotFound",
18719
+ message: this.#options.notFoundMessage,
18720
+ retryable: false
18721
+ }
18722
+ };
18723
+ }
18724
+ /** Idempotent. Resolves after every started read has settled. */
18725
+ async close() {
18726
+ this.#abort.abort();
18727
+ await Promise.allSettled(this.#pending);
18728
+ }
18729
+ };
18730
+
18731
+ // dist/pi-session-import.js
18732
+ var PI_SESSION_CHANGED = "Pi Session changed during discovery; refresh and retry";
18034
18733
  function isRecord4(value) {
18035
18734
  return typeof value === "object" && value !== null && !Array.isArray(value);
18036
18735
  }
18037
- function missing(error51) {
18038
- return isRecord4(error51) && error51.code === "ENOENT";
18039
- }
18040
18736
  function expandDirectory(value, home) {
18041
- return path7.resolve(value === "~" ? home : value.startsWith(`~${path7.sep}`) || value.startsWith("~/") ? path7.join(home, value.slice(2)) : value);
18737
+ return path11.resolve(value === "~" ? home : value.startsWith(`~${path11.sep}`) || value.startsWith("~/") ? path11.join(home, value.slice(2)) : value);
18042
18738
  }
18043
18739
  function piSessionImportDirectory(environment) {
18044
18740
  const home = (process.platform === "win32" ? environment.USERPROFILE : environment.HOME) || os3.homedir();
@@ -18047,7 +18743,7 @@ function piSessionImportDirectory(environment) {
18047
18743
  return { directory: expandDirectory(custom2, home), flat: true };
18048
18744
  const agent = environment.PI_CODING_AGENT_DIR;
18049
18745
  return {
18050
- directory: path7.join(agent ? expandDirectory(agent, home) : path7.join(home, ".pi", "agent"), "sessions"),
18746
+ directory: path11.join(agent ? expandDirectory(agent, home) : path11.join(home, ".pi", "agent"), "sessions"),
18051
18747
  flat: false
18052
18748
  };
18053
18749
  }
@@ -18056,7 +18752,7 @@ async function sessionFiles(directory, flat, signal) {
18056
18752
  const visit = async (dir, projectLevel) => {
18057
18753
  signal.throwIfAborted();
18058
18754
  const entries = await opendir(dir).catch((error51) => {
18059
- if (missing(error51))
18755
+ if (isMissingFileError(error51))
18060
18756
  return null;
18061
18757
  throw error51;
18062
18758
  });
@@ -18065,9 +18761,9 @@ async function sessionFiles(directory, flat, signal) {
18065
18761
  for await (const entry of entries) {
18066
18762
  signal.throwIfAborted();
18067
18763
  if (projectLevel && entry.isDirectory())
18068
- await visit(path7.join(dir, entry.name), false);
18764
+ await visit(path11.join(dir, entry.name), false);
18069
18765
  else if (!projectLevel && entry.isFile() && entry.name.endsWith(".jsonl")) {
18070
- files.push(path7.join(dir, entry.name));
18766
+ files.push(path11.join(dir, entry.name));
18071
18767
  }
18072
18768
  }
18073
18769
  };
@@ -18100,7 +18796,7 @@ async function readCandidate(file2, signal) {
18100
18796
  if (!isRecord4(entry))
18101
18797
  return null;
18102
18798
  if (!header) {
18103
- if (entry.type !== "session" || entry.version !== 3 || typeof entry.id !== "string" || typeof entry.cwd !== "string" || !path7.isAbsolute(entry.cwd))
18799
+ if (entry.type !== "session" || entry.version !== 3 || typeof entry.id !== "string" || typeof entry.cwd !== "string" || !path11.isAbsolute(entry.cwd))
18104
18800
  return null;
18105
18801
  header = entry;
18106
18802
  continue;
@@ -18111,12 +18807,12 @@ async function readCandidate(file2, signal) {
18111
18807
  if (!firstMessage && entry.type === "message" && message3?.role === "user") {
18112
18808
  const content = message3.content;
18113
18809
  const text2 = typeof content === "string" ? content : Array.isArray(content) ? content.filter((block) => isRecord4(block) && block.type === "text" && typeof block.text === "string").map((block) => block.text).join(" ") : "";
18114
- firstMessage = text2.replaceAll("\0", "").trim().slice(0, HARNESS_SESSION_IMPORT_TITLE_MAX_LENGTH) || null;
18810
+ firstMessage = sessionImportTitle(text2);
18115
18811
  }
18116
18812
  hasUser = entry.type === "message" && message3?.role === "user" || typeof entry.parentId === "string" && entries.get(entry.parentId) === true;
18117
18813
  entries.set(entry.id, hasUser);
18118
18814
  if (entry.type === "session_info")
18119
- name = typeof entry.name === "string" ? entry.name.trim() || null : null;
18815
+ name = sessionImportTitle(entry.name);
18120
18816
  if (entry.type === "message" && (message3?.role === "user" || message3?.role === "assistant")) {
18121
18817
  const time3 = typeof message3.timestamp === "number" ? message3.timestamp : typeof entry.timestamp === "string" ? Date.parse(entry.timestamp) : NaN;
18122
18818
  if (Number.isFinite(time3))
@@ -18132,8 +18828,8 @@ async function readCandidate(file2, signal) {
18132
18828
  if (!hasUser)
18133
18829
  return null;
18134
18830
  const after = await stat(file2);
18135
- if (!sameFile(before, after))
18136
- throw new PiSessionChangedError();
18831
+ if (!sameFileFingerprint(before, after))
18832
+ throw new SessionImportChangedError(PI_SESSION_CHANGED);
18137
18833
  const cwd = await realpath3(String(header.cwd));
18138
18834
  if (!(await stat(cwd)).isDirectory())
18139
18835
  return null;
@@ -18143,14 +18839,13 @@ async function readCandidate(file2, signal) {
18143
18839
  locator: { sessionFile: await realpath3(file2) },
18144
18840
  formatVersion: 1
18145
18841
  });
18146
- const candidate = harnessSessionImportCandidateSchema.safeParse({
18842
+ const candidate = sessionImportCandidate({
18147
18843
  nativeSessionId: header.id,
18148
18844
  cwd,
18149
18845
  title: name ?? firstMessage,
18150
- updatedAt: Math.floor(updatedAt),
18151
- running: null
18846
+ updatedAt
18152
18847
  });
18153
- return candidate.success && nativeRef.success ? { candidate: candidate.data, nativeRef: nativeRef.data } : null;
18848
+ return candidate && nativeRef.success ? { candidate, nativeRef: nativeRef.data } : null;
18154
18849
  }
18155
18850
  async function readIdentity(file2, signal) {
18156
18851
  const stream = createReadStream2(file2, { encoding: "utf8", signal });
@@ -18198,7 +18893,7 @@ var PiSessionImportIndex = class {
18198
18893
  try {
18199
18894
  const fingerprint = await stat(file2);
18200
18895
  const cached2 = this.#cache.get(file2);
18201
- const source = cached2 && sameFile(cached2.fingerprint, fingerprint) ? cached2.source : await readCandidate(file2, signal);
18896
+ const source = cached2 && sameFileFingerprint(cached2.fingerprint, fingerprint) ? cached2.source : await readCandidate(file2, signal);
18202
18897
  if (!source)
18203
18898
  continue;
18204
18899
  if (!(await stat(source.candidate.cwd)).isDirectory())
@@ -18209,7 +18904,7 @@ var PiSessionImportIndex = class {
18209
18904
  next.set(file2, { fingerprint, source });
18210
18905
  sources.push(source);
18211
18906
  } catch (error51) {
18212
- if (!missing(error51) && !(error51 instanceof PiSessionChangedError))
18907
+ if (!isMissingFileError(error51) && !(error51 instanceof SessionImportChangedError))
18213
18908
  throw error51;
18214
18909
  }
18215
18910
  }
@@ -18224,14 +18919,14 @@ var PiSessionImportIndex = class {
18224
18919
  try {
18225
18920
  const fingerprint = await stat(file2);
18226
18921
  const cached2 = this.#cache.get(file2);
18227
- const id = cached2 && sameFile(cached2.fingerprint, fingerprint) ? cached2.source.nativeRef.nativeSessionId : await readIdentity(file2, signal);
18922
+ const id = cached2 && sameFileFingerprint(cached2.fingerprint, fingerprint) ? cached2.source.nativeRef.nativeSessionId : await readIdentity(file2, signal);
18228
18923
  if (id !== nativeSessionId)
18229
18924
  continue;
18230
18925
  if (selected)
18231
18926
  throw new Error("Pi Session identity is ambiguous across files");
18232
18927
  selected = file2;
18233
18928
  } catch (error51) {
18234
- if (!missing(error51))
18929
+ if (!isMissingFileError(error51))
18235
18930
  throw error51;
18236
18931
  }
18237
18932
  }
@@ -18241,7 +18936,7 @@ var PiSessionImportIndex = class {
18241
18936
  const source = await readCandidate(selected, signal);
18242
18937
  return source?.nativeRef.nativeSessionId === nativeSessionId ? source : null;
18243
18938
  } catch (error51) {
18244
- if (missing(error51))
18939
+ if (isMissingFileError(error51))
18245
18940
  return null;
18246
18941
  throw error51;
18247
18942
  }
@@ -18250,8 +18945,8 @@ var PiSessionImportIndex = class {
18250
18945
 
18251
18946
  // dist/pi-rpc-session.js
18252
18947
  import { spawn, spawnSync } from "node:child_process";
18253
- import { randomUUID as randomUUID4 } from "node:crypto";
18254
- import path8 from "node:path";
18948
+ import { randomUUID as randomUUID5 } from "node:crypto";
18949
+ import path12 from "node:path";
18255
18950
 
18256
18951
  // dist/pi-slash-commands.js
18257
18952
  var DYNAMIC_ID_PREFIX = "pi.slash.";
@@ -18273,15 +18968,15 @@ function parsePiNativeCommands(response) {
18273
18968
  return data.commands.flatMap((entry) => {
18274
18969
  if (typeof entry !== "object" || entry === null)
18275
18970
  return [];
18276
- const record6 = entry;
18277
- const name = typeof record6.name === "string" ? record6.name.trim().replace(/^\//u, "") : "";
18971
+ const record7 = entry;
18972
+ const name = typeof record7.name === "string" ? record7.name.trim().replace(/^\//u, "") : "";
18278
18973
  if (!name)
18279
18974
  return [];
18280
18975
  return [
18281
18976
  {
18282
18977
  name,
18283
- ...typeof record6.description === "string" ? { description: record6.description } : {},
18284
- ...typeof record6.source === "string" ? { source: record6.source } : {}
18978
+ ...typeof record7.description === "string" ? { description: record7.description } : {},
18979
+ ...typeof record7.source === "string" ? { source: record7.source } : {}
18285
18980
  }
18286
18981
  ];
18287
18982
  });
@@ -18369,7 +19064,7 @@ function optionalPiStateContextUsage(value) {
18369
19064
  }
18370
19065
 
18371
19066
  // dist/pi-subagent-rpc.js
18372
- import { randomUUID as randomUUID3 } from "node:crypto";
19067
+ import { randomUUID as randomUUID4 } from "node:crypto";
18373
19068
  var PiSubagentRpc = class {
18374
19069
  send;
18375
19070
  timeoutMs;
@@ -18411,7 +19106,7 @@ var PiSubagentRpc = class {
18411
19106
  if (!Array.isArray(data?.commands) || !data.commands.some((command) => command?.name === "subagents-inspect-rpc" && command.source === "extension")) {
18412
19107
  throw new Error("Installed Pi has no pi-subagents Host inspection command");
18413
19108
  }
18414
- const requestId = randomUUID3();
19109
+ const requestId = randomUUID4();
18415
19110
  const reply = new Promise((resolve, reject) => {
18416
19111
  const timer = setTimeout(() => {
18417
19112
  this.#pending.delete(requestId);
@@ -18557,7 +19252,11 @@ function parseAvailableModels(response) {
18557
19252
  if (!parsed || !isRecord6(model) || typeof model.reasoning !== "boolean") {
18558
19253
  throw new PiRpcFaultError("protocolError", "Pi RPC catalog contains a Model without reasoning capability");
18559
19254
  }
18560
- return { ...parsed, reasoning: model.reasoning };
19255
+ return {
19256
+ ...parsed,
19257
+ reasoning: model.reasoning,
19258
+ ...typeof model.api === "string" ? { api: model.api } : {}
19259
+ };
18561
19260
  });
18562
19261
  }
18563
19262
  function assistantText(value) {
@@ -18642,13 +19341,14 @@ function piRpcProcessCommand(options, dependencies = {}) {
18642
19341
  const modelArguments = startupModel ? ["--provider", startupModel.provider, "--model", startupModel.id] : [];
18643
19342
  const thinkingArguments = options.emptySessionConfiguration ? ["--thinking", options.emptySessionConfiguration.thinkingLevel] : [];
18644
19343
  const arguments_ = [
19344
+ ...options.fastExtension ? ["--extension", options.fastExtension] : [],
18645
19345
  "--mode",
18646
19346
  "rpc",
18647
19347
  ...modelArguments,
18648
19348
  ...thinkingArguments,
18649
19349
  ...sessionArguments
18650
19350
  ];
18651
- const extension = path8.win32.extname(command).toLowerCase();
19351
+ const extension = path12.win32.extname(command).toLowerCase();
18652
19352
  if (platform !== "win32" || ![".cmd", ".bat"].includes(extension)) {
18653
19353
  return { command, arguments: arguments_, windowsVerbatimArguments: false };
18654
19354
  }
@@ -18687,6 +19387,8 @@ var PiRpcSession = class {
18687
19387
  #failed = false;
18688
19388
  #pending = /* @__PURE__ */ new Map();
18689
19389
  #state = null;
19390
+ #fast = null;
19391
+ #fastAcknowledgement = null;
18690
19392
  #latestCacheHitRatePercent;
18691
19393
  #manualCompaction = null;
18692
19394
  #stderrTail = "";
@@ -18713,7 +19415,9 @@ var PiRpcSession = class {
18713
19415
  get state() {
18714
19416
  if (!this.#state)
18715
19417
  throw new Error("Pi RPC Session has not started");
18716
- return this.#state;
19418
+ if (this.#fast && (this.#fast.provider !== this.#state.provider || this.#fast.id !== this.#state.modelId))
19419
+ this.#fast = null;
19420
+ return this.#fast ? { ...this.#state, fast: true } : this.#state;
18717
19421
  }
18718
19422
  get stderrTail() {
18719
19423
  return this.#stderrTail;
@@ -18730,8 +19434,10 @@ var PiRpcSession = class {
18730
19434
  async start() {
18731
19435
  if (this.#child || this.#closed)
18732
19436
  throw new Error("Pi RPC Session cannot be started twice");
19437
+ const fastExtension = this.#processAdapter === nodeProcessAdapter ? await ensurePiFastExtension({ ...process.env, ...this.#options.environment }) : void 0;
18733
19438
  const child = this.#processAdapter.spawn({
18734
19439
  cwd: this.#options.cwd,
19440
+ ...fastExtension ? { fastExtension } : {},
18735
19441
  ...this.#options.command ? { command: this.#options.command } : {},
18736
19442
  environment: withNodeRuntimeOnPath({
18737
19443
  ...process.env,
@@ -18878,7 +19584,36 @@ var PiRpcSession = class {
18878
19584
  throw error51;
18879
19585
  }
18880
19586
  }
19587
+ async supportsFastMode() {
19588
+ return (await this.getCommands()).some((command) => command.name === PI_FAST_COMMAND && command.source === "extension");
19589
+ }
19590
+ async selectFastMode(enabled) {
19591
+ if (!enabled && !this.#fast)
19592
+ return this.state;
19593
+ if (!await this.supportsFastMode())
19594
+ throw new Error("Installed Pi does not support the Host Fast extension");
19595
+ const nonce = randomUUID5();
19596
+ const mode = enabled ? "on" : "off";
19597
+ const acknowledgement = { message: `${PI_FAST_ACK}${nonce}:${mode}`, received: false };
19598
+ this.#fastAcknowledgement = acknowledgement;
19599
+ try {
19600
+ await this.#send("prompt", { message: `/${PI_FAST_COMMAND} ${mode} ${nonce}` });
19601
+ if (!acknowledgement.received)
19602
+ throw new Error("Pi did not confirm the Fast selection");
19603
+ this.#fast = enabled ? { provider: this.state.provider ?? "", id: this.state.modelId ?? "" } : null;
19604
+ return this.state;
19605
+ } catch (error51) {
19606
+ const fault = error51 instanceof PiRpcFaultError ? error51 : new PiRpcFaultError("protocolError", `Pi Fast selection could not be confirmed: ${message2(error51)}`);
19607
+ this.#fail(fault);
19608
+ await this.close().catch(() => void 0);
19609
+ throw fault;
19610
+ } finally {
19611
+ this.#fastAcknowledgement = null;
19612
+ }
19613
+ }
18881
19614
  async selectModel(model) {
19615
+ if (this.#fast)
19616
+ await this.selectFastMode(false);
18882
19617
  await this.#send("set_model", { provider: model.provider, modelId: model.id });
18883
19618
  return this.#refreshState("Model");
18884
19619
  }
@@ -18890,7 +19625,7 @@ var PiRpcSession = class {
18890
19625
  async #refreshState(operation) {
18891
19626
  try {
18892
19627
  this.#state = parseSessionState(await this.#send("get_state", {}));
18893
- return this.#state;
19628
+ return this.state;
18894
19629
  } catch (error51) {
18895
19630
  const fault = error51 instanceof PiRpcFaultError ? error51 : new PiRpcFaultError("protocolError", `Pi RPC ${operation} state could not be confirmed: ${message2(error51)}`);
18896
19631
  this.#fail(fault);
@@ -19046,6 +19781,11 @@ var PiRpcSession = class {
19046
19781
  }
19047
19782
  }
19048
19783
  #handle(value) {
19784
+ if (value.type === "extension_ui_request" && value.method === "notify" && typeof value.message === "string" && value.message.startsWith(PI_FAST_ACK)) {
19785
+ if (this.#fastAcknowledgement?.message === value.message)
19786
+ this.#fastAcknowledgement.received = true;
19787
+ return;
19788
+ }
19049
19789
  if (this.#closed || this.#failed)
19050
19790
  return;
19051
19791
  if (value.type === "response") {
@@ -19168,7 +19908,7 @@ var PiRpcSession = class {
19168
19908
  const active = {
19169
19909
  origin: "autonomous",
19170
19910
  autonomousEvents: events,
19171
- nativeTurnKey: assistantMessageId(value) ?? randomUUID4(),
19911
+ nativeTurnKey: assistantMessageId(value) ?? randomUUID5(),
19172
19912
  nativeCancellationObserved: false,
19173
19913
  text: "",
19174
19914
  assistantMessageId: null,
@@ -19411,7 +20151,7 @@ var PiRpcSession = class {
19411
20151
  if (active.assistantMessageId !== null && active.reasoningMessageOpen) {
19412
20152
  active.onEvent({ type: "reasoning.completed", messageId: active.assistantMessageId });
19413
20153
  }
19414
- const messageId = assistantMessageId(value) ?? randomUUID4();
20154
+ const messageId = assistantMessageId(value) ?? randomUUID5();
19415
20155
  active.assistantMessageId = messageId;
19416
20156
  active.sawStreamedMessageText = false;
19417
20157
  active.sawStreamedMessageReasoning = false;
@@ -19472,7 +20212,7 @@ var PiRpcSession = class {
19472
20212
  if (!child?.stdin.writable || this.#closed || this.#failed) {
19473
20213
  return Promise.reject(new Error("Pi RPC stdin is unavailable"));
19474
20214
  }
19475
- const id = `codexhost-${randomUUID4()}`;
20215
+ const id = `codexhost-${randomUUID5()}`;
19476
20216
  return new Promise((resolve, reject) => {
19477
20217
  const pending = {
19478
20218
  command: type,
@@ -19647,7 +20387,7 @@ function nativeModelFromState(state2) {
19647
20387
  }
19648
20388
  function effectiveModelFromState(state2) {
19649
20389
  const model = nativeModelFromState(state2);
19650
- return model ? encodePiModelRef(model) : void 0;
20390
+ return model ? encodePiModelRef({ ...model, ...state2.fast ? { fast: true } : {} }) : void 0;
19651
20391
  }
19652
20392
  function harnessStateFromPi(state2, thinkingLevels) {
19653
20393
  const effectiveModel = effectiveModelFromState(state2);
@@ -19733,10 +20473,10 @@ function stripDiffPrefix(pathString) {
19733
20473
  return pathString.startsWith("a/") || pathString.startsWith("b/") ? pathString.slice(2) : pathString;
19734
20474
  }
19735
20475
  function displayPath(nativePath, cwd) {
19736
- const resolvedCwd = path9.resolve(cwd);
19737
- const resolvedPath = path9.isAbsolute(nativePath) ? path9.resolve(nativePath) : path9.resolve(cwd, nativePath);
19738
- const relative = path9.relative(resolvedCwd, resolvedPath);
19739
- const inside = relative.length > 0 && relative !== ".." && !relative.startsWith(`..${path9.sep}`);
20476
+ const resolvedCwd = path13.resolve(cwd);
20477
+ const resolvedPath = path13.isAbsolute(nativePath) ? path13.resolve(nativePath) : path13.resolve(cwd, nativePath);
20478
+ const relative = path13.relative(resolvedCwd, resolvedPath);
20479
+ const inside = relative.length > 0 && relative !== ".." && !relative.startsWith(`..${path13.sep}`);
19740
20480
  const selected = inside ? relative : resolvedPath;
19741
20481
  const normalized = selected.replaceAll("\\", "/");
19742
20482
  if (normalized.length === 0 || normalized === ".")
@@ -19935,6 +20675,7 @@ var PiHarnessSession = class {
19935
20675
  #requestedModel;
19936
20676
  #requestedThinkingOptionId;
19937
20677
  #toolOutputLimit;
20678
+ #isFastSupported;
19938
20679
  #acceptingTurn = false;
19939
20680
  #active = null;
19940
20681
  #closePromise = null;
@@ -19956,6 +20697,7 @@ var PiHarnessSession = class {
19956
20697
  this.#requestedModel = options.model;
19957
20698
  this.#requestedThinkingOptionId = options.thinkingOptionId;
19958
20699
  this.#toolOutputLimit = options.toolOutputLimit;
20700
+ this.#isFastSupported = options.isFastSupported;
19959
20701
  this.capabilities = {
19960
20702
  configuration: {
19961
20703
  selectModel: true,
@@ -19984,13 +20726,13 @@ var PiHarnessSession = class {
19984
20726
  return this.#transport?.state.sessionId === id;
19985
20727
  }
19986
20728
  async readSubagentHistory(cwd) {
19987
- if (this.#phase !== "open" || path9.resolve(cwd) !== path9.resolve(this.#cwd)) {
20729
+ if (this.#phase !== "open" || path13.resolve(cwd) !== path13.resolve(this.#cwd)) {
19988
20730
  throw new Error("Pi Subagent parent workspace or Session is unavailable");
19989
20731
  }
19990
20732
  return (await this.#ensureTransport()).getEntries();
19991
20733
  }
19992
20734
  async inspectSubagent(id, cwd) {
19993
- if (this.#phase !== "open" || path9.resolve(cwd) !== path9.resolve(this.#cwd)) {
20735
+ if (this.#phase !== "open" || path13.resolve(cwd) !== path13.resolve(this.#cwd)) {
19994
20736
  throw new Error("Pi Subagent parent workspace or Session is unavailable");
19995
20737
  }
19996
20738
  const transport = await this.#ensureTransport();
@@ -20233,20 +20975,27 @@ var PiHarnessSession = class {
20233
20975
  error: invalidState("Pi Model selection requires a started Native Session")
20234
20976
  };
20235
20977
  }
20236
- let requested;
20237
- try {
20238
- requested = decodePiModelRef(command.model);
20239
- } catch (error51) {
20240
- return { ok: false, error: normalizedError(error51, "invalidRequest") };
20241
- }
20242
20978
  const previousModel = this.#state.effectiveModel;
20243
20979
  this.#configuring = true;
20244
20980
  try {
20981
+ let requested;
20982
+ try {
20983
+ requested = decodePiModelRef(command.model);
20984
+ if (requested.fast && !await this.#isFastSupported(command.model, transport))
20985
+ throw new Error("Fast is unavailable for this Pi Model");
20986
+ } catch (error51) {
20987
+ return { ok: false, error: normalizedError(error51, "invalidRequest") };
20988
+ }
20245
20989
  let state2;
20246
20990
  let thinkingLevels;
20247
20991
  try {
20248
- state2 = await transport.selectModel(requested);
20992
+ state2 = samePiModel(nativeModelFromState(transport.state), requested) ? transport.state : await transport.selectModel(requested);
20249
20993
  thinkingLevels = await transport.getAvailableThinkingLevels();
20994
+ if (requested.fast || state2.fast) {
20995
+ if (!transport.selectFastMode)
20996
+ throw new Error("Pi Fast extension is unavailable");
20997
+ state2 = await transport.selectFastMode(requested.fast === true);
20998
+ }
20250
20999
  this.#publishTransportState(state2, thinkingLevels);
20251
21000
  } catch (error51) {
20252
21001
  if (error51 instanceof PiRpcFaultError)
@@ -20383,7 +21132,7 @@ var PiHarnessSession = class {
20383
21132
  const transport = this.#transport;
20384
21133
  if (this.#phase === "open" && transport?.getCommands) {
20385
21134
  try {
20386
- this.#liveCommands = piLiveCommandCatalog(piCommandCatalog, await transport.getCommands());
21135
+ this.#liveCommands = piLiveCommandCatalog(piCommandCatalog, (await transport.getCommands()).filter((command) => command.name !== PI_FAST_COMMAND));
20387
21136
  } catch {
20388
21137
  }
20389
21138
  }
@@ -20530,6 +21279,11 @@ var PiHarnessSession = class {
20530
21279
  this.#publishTransportState(state2, thinkingLevels);
20531
21280
  throw new Error("Pi did not activate the requested create Model");
20532
21281
  }
21282
+ if (requested.fast) {
21283
+ if (!await this.#isFastSupported(this.#requestedModel, transport) || !transport.selectFastMode)
21284
+ throw new Error("Fast is unavailable for this Pi Model");
21285
+ state2 = await transport.selectFastMode(true);
21286
+ }
20533
21287
  }
20534
21288
  if (this.#requestedThinkingOptionId) {
20535
21289
  if (!thinkingLevels) {
@@ -20610,7 +21364,7 @@ var PiHarnessSession = class {
20610
21364
  }));
20611
21365
  return;
20612
21366
  }
20613
- const turnId = hostTurnIdSchema.parse(randomUUID5());
21367
+ const turnId = hostTurnIdSchema.parse(randomUUID6());
20614
21368
  let resolveCompletion = () => void 0;
20615
21369
  const completion = new Promise((resolve) => {
20616
21370
  resolveCompletion = resolve;
@@ -20772,7 +21526,7 @@ var PiHarnessSession = class {
20772
21526
  if (active.interactionByNativeId.has(request.requestId)) {
20773
21527
  throw new Error("Pi Interaction started more than once");
20774
21528
  }
20775
- const interactionId = hostInteractionIdSchema.parse(randomUUID5());
21529
+ const interactionId = hostInteractionIdSchema.parse(randomUUID6());
20776
21530
  const question = request.method === "select" ? {
20777
21531
  id: "answer",
20778
21532
  type: "choice",
@@ -21119,7 +21873,7 @@ var PiHarnessSession = class {
21119
21873
  this.#channel.emit({ kind: "event", event });
21120
21874
  }
21121
21875
  #newItemId() {
21122
- return hostItemIdSchema.parse(randomUUID5());
21876
+ return hostItemIdSchema.parse(randomUUID6());
21123
21877
  }
21124
21878
  };
21125
21879
  var PiAdapter = class {
@@ -21182,27 +21936,17 @@ var PiAdapter = class {
21182
21936
  };
21183
21937
  sessionImport = Object.freeze({
21184
21938
  listCandidates: async () => {
21185
- const result = await this.#readImport((signal) => this.#importIndex.list(signal));
21939
+ const result = await this.#importScope.read((signal) => this.#importIndex.list(signal));
21186
21940
  return result.ok ? { ok: true, value: result.value.map(({ candidate }) => candidate) } : result;
21187
21941
  },
21188
- resolveCandidate: async (nativeSessionId) => {
21189
- const result = await this.#readImport((signal) => this.#importIndex.resolve(nativeSessionId, signal));
21190
- if (!result.ok)
21191
- return result;
21192
- const source = result.value;
21193
- return source ? { ok: true, value: source } : {
21194
- ok: false,
21195
- error: {
21196
- code: "sessionNotFound",
21197
- message: "Pi Session is no longer importable",
21198
- retryable: false
21199
- }
21200
- };
21201
- }
21942
+ resolveCandidate: (nativeSessionId) => this.#importScope.resolve((signal) => this.#importIndex.resolve(nativeSessionId, signal))
21202
21943
  });
21203
21944
  #importIndex;
21204
- #importAbort = new AbortController();
21205
- #importRequests = /* @__PURE__ */ new Set();
21945
+ #importScope = new SessionImportScope({
21946
+ closedMessage: "Pi Adapter is closed",
21947
+ unavailableMessage: "Pi Session discovery failed; check storage access and duplicate Session identities, then retry after closing native clients",
21948
+ notFoundMessage: "Pi Session is no longer importable"
21949
+ });
21206
21950
  #closeTimeoutMs;
21207
21951
  #createTransport;
21208
21952
  #inspectionCache = /* @__PURE__ */ new Map();
@@ -21210,6 +21954,7 @@ var PiAdapter = class {
21210
21954
  #inspections = /* @__PURE__ */ new Set();
21211
21955
  #sessions = /* @__PURE__ */ new Set();
21212
21956
  #toolOutputLimit;
21957
+ #environment;
21213
21958
  #closePromise = null;
21214
21959
  #thinkingSelectionSupported = null;
21215
21960
  constructor(options = {}, dependencies = {
@@ -21229,23 +21974,20 @@ var PiAdapter = class {
21229
21974
  remove: (name) => updateCatalog(imports.remove(name))
21230
21975
  };
21231
21976
  this.#createTransport = dependencies.createTransport;
21977
+ this.#environment = options.environment ?? process.env;
21232
21978
  this.#importIndex = new PiSessionImportIndex({ ...process.env, ...options.environment });
21233
21979
  this.#closeTimeoutMs = options.closeTimeoutMs ?? 2e3;
21234
21980
  this.#toolOutputLimit = options.toolOutputLimit ?? DEFAULT_TOOL_OUTPUT_LIMIT;
21235
21981
  }
21236
- #readImport(operation) {
21237
- if (this.#importAbort.signal.aborted)
21238
- return Promise.resolve({ ok: false, error: invalidState("Pi Adapter is closed") });
21239
- const request = operation(this.#importAbort.signal).then((value) => ({ ok: true, value })).catch(() => ({
21240
- ok: false,
21241
- error: {
21242
- code: "unavailable",
21243
- message: "Pi Session discovery failed; check storage access and duplicate Session identities, then retry after closing native clients",
21244
- retryable: true
21245
- }
21246
- })).finally(() => this.#importRequests.delete(request));
21247
- this.#importRequests.add(request);
21248
- return request;
21982
+ /** Pi itself holds no Account; this reports configured Provider balances. */
21983
+ async inspectAccounts() {
21984
+ if (this.#closePromise)
21985
+ return [];
21986
+ return fetchPiAccounts({ environment: this.#environment });
21987
+ }
21988
+ async inspectAccount() {
21989
+ const accounts = await this.inspectAccounts();
21990
+ return accounts[0] ?? null;
21249
21991
  }
21250
21992
  async inspect(input = {}) {
21251
21993
  if (this.#closePromise) {
@@ -21258,7 +22000,7 @@ var PiAdapter = class {
21258
22000
  }
21259
22001
  };
21260
22002
  }
21261
- const cwd = input.cwd ?? process.cwd();
22003
+ const cwd = resolvePiInspectCwd(input.cwd);
21262
22004
  const inFlight = this.#inspectionInFlight.get(cwd);
21263
22005
  if (inFlight)
21264
22006
  return inFlight;
@@ -21292,7 +22034,9 @@ var PiAdapter = class {
21292
22034
  stage = "capabilities";
21293
22035
  const thinkingLevels = await transport.getAvailableThinkingLevels();
21294
22036
  this.#thinkingSelectionSupported = thinkingLevels !== null;
21295
- const catalog = normalizePiModelCatalog(models, nativeModelFromState(transport.state), thinkingLevels, transport.state.thinkingLevel);
22037
+ const normalized = normalizePiModelCatalog(models, nativeModelFromState(transport.state), thinkingLevels, transport.state.thinkingLevel);
22038
+ const fastModels = await transport.supportsFastMode?.() ? await piFastModelKeys(models, this.#environment) : /* @__PURE__ */ new Set();
22039
+ const catalog = withPiFast(normalized, fastModels);
21296
22040
  await transport.close();
21297
22041
  return {
21298
22042
  status: "ready",
@@ -21329,6 +22073,27 @@ var PiAdapter = class {
21329
22073
  if (this.#closePromise) {
21330
22074
  return { ok: false, error: invalidState("Pi Adapter is closed") };
21331
22075
  }
22076
+ if ("model" in input && input.model) {
22077
+ let model;
22078
+ try {
22079
+ model = decodePiModelRef(input.model);
22080
+ } catch (error51) {
22081
+ return { ok: false, error: normalizedError(error51, "invalidRequest") };
22082
+ }
22083
+ if (model.fast) {
22084
+ if (!this.#isFastSupported(input.model, input.cwd))
22085
+ await this.inspect({ cwd: input.cwd });
22086
+ if (!this.#isFastSupported(input.model, input.cwd) && input.kind !== "resume")
22087
+ return {
22088
+ ok: false,
22089
+ error: {
22090
+ code: "unsupported",
22091
+ message: "Fast is unavailable for this Pi Model",
22092
+ retryable: false
22093
+ }
22094
+ };
22095
+ }
22096
+ }
21332
22097
  if (input.cwd.length === 0) {
21333
22098
  return {
21334
22099
  ok: false,
@@ -21499,6 +22264,11 @@ var PiAdapter = class {
21499
22264
  await transport.verifySessionCwd(input.cwd);
21500
22265
  }
21501
22266
  }
22267
+ if (input.kind === "resume" && input.model && this.#isFastSupported(input.model, input.cwd) && decodePiModelRef(input.model).fast && samePiModel(nativeModelFromState(transport.state), decodePiModelRef(input.model))) {
22268
+ if (!transport.selectFastMode)
22269
+ throw new Error("Pi Fast extension is unavailable");
22270
+ await transport.selectFastMode(true);
22271
+ }
21502
22272
  const startedThinkingLevels = await transport.getAvailableThinkingLevels();
21503
22273
  this.#thinkingSelectionSupported = startedThinkingLevels !== null;
21504
22274
  const initialUsage = await transport.getSessionUsage().catch(() => null);
@@ -21515,6 +22285,9 @@ var PiAdapter = class {
21515
22285
  return { ok: false, error: normalizedError(error51, "nativeFailure") };
21516
22286
  }
21517
22287
  }
22288
+ #isFastSupported(ref, cwd) {
22289
+ return this.#inspectionCache.get(cwd)?.catalog.models.some((model) => model.fastModel?.id === ref.id) ?? false;
22290
+ }
21518
22291
  #trackSession(cwd, options) {
21519
22292
  const environment = options.environment;
21520
22293
  const createTransport = environment ? (input) => this.#createTransport({ ...input, environment }) : this.#createTransport;
@@ -21526,6 +22299,14 @@ var PiAdapter = class {
21526
22299
  ...options.thinkingOptionId ? { thinkingOptionId: options.thinkingOptionId } : {},
21527
22300
  toolOutputLimit: this.#toolOutputLimit,
21528
22301
  supportsThinkingSelection: options.supportsThinkingSelection,
22302
+ isFastSupported: async (ref, transport) => {
22303
+ if (this.#inspectionCache.has(cwd))
22304
+ return this.#isFastSupported(ref, cwd);
22305
+ if (!await transport.supportsFastMode?.())
22306
+ return false;
22307
+ const fastModels = await piFastModelKeys(await transport.getAvailableModels(), environment ?? this.#environment);
22308
+ return fastModels.has(encodePiModelRef({ ...decodePiModelRef(ref), fast: false }).id);
22309
+ },
21529
22310
  ...options.startedTransport ? { startedTransport: options.startedTransport } : {},
21530
22311
  ...options.startedThinkingLevels !== void 0 ? { startedThinkingLevels: options.startedThinkingLevels } : {},
21531
22312
  ...options.initialUsage !== void 0 ? { initialUsage: options.initialUsage } : {}
@@ -21535,9 +22316,8 @@ var PiAdapter = class {
21535
22316
  }
21536
22317
  close() {
21537
22318
  if (!this.#closePromise) {
21538
- this.#importAbort.abort();
21539
22319
  this.#closePromise = Promise.all([
21540
- ...this.#importRequests,
22320
+ this.#importScope.close(),
21541
22321
  ...[...this.#inspections].map((transport) => transport.close()),
21542
22322
  ...[...this.#sessions].map((session) => session.close())
21543
22323
  ]).then(() => void 0);
@@ -21546,13 +22326,42 @@ var PiAdapter = class {
21546
22326
  }
21547
22327
  };
21548
22328
 
22329
+ // dist/installation.js
22330
+ var PI_LATEST_VERSION_URL = "https://pi.dev/api/latest-version";
22331
+ function createPiInstallation(environment, command) {
22332
+ const run = (args, timeout) => runInstallationCommand(resolvePiExecutable({ environment, ...command ? { command } : {} }), args, environment, timeout);
22333
+ return createInstallationManager({
22334
+ async check() {
22335
+ const currentVersion = versionFromOutput(await run(["--version"]));
22336
+ const payload = JSON.parse(await fetchInstallationText(PI_LATEST_VERSION_URL));
22337
+ const latestVersion = installationVersion(payload.version);
22338
+ return {
22339
+ currentVersion,
22340
+ latestVersion,
22341
+ updateAvailable: newerInstallationVersion(currentVersion, latestVersion),
22342
+ canUpdate: true
22343
+ };
22344
+ },
22345
+ async update() {
22346
+ await run(["update"], 3e5);
22347
+ }
22348
+ });
22349
+ }
22350
+
21549
22351
  // dist/plugin.js
21550
22352
  var PI_COMMAND_ENV = "CODEXHOST_PI_COMMAND";
21551
22353
  function createHarnessAdapter(context) {
21552
22354
  const environment = { ...context.environment };
21553
- return new PiAdapter({
22355
+ return Object.assign(new PiAdapter({
21554
22356
  ...environment[PI_COMMAND_ENV] ? { command: environment[PI_COMMAND_ENV] } : {},
21555
22357
  environment
22358
+ }), {
22359
+ installation: createPiInstallation(environment, environment[PI_COMMAND_ENV]),
22360
+ install: createHarnessInstaller(environment, {
22361
+ posix: "https://pi.dev/install.sh",
22362
+ windows: "https://pi.dev/install.ps1",
22363
+ shell: "sh"
22364
+ })
21556
22365
  });
21557
22366
  }
21558
22367
  export {