@codexhost/cli-darwin-x64 0.11.0 → 0.12.1

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.
@@ -5,6 +5,409 @@ var __export = (target, all) => {
5
5
  __defProp(target, name, { get: all[name], enumerable: true });
6
6
  };
7
7
 
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
71
+ import path3 from "node:path";
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
+
8
411
  // ../../../node_modules/diff/libesm/diff/base.js
9
412
  var Diff = class {
10
413
  diff(oldStr, newStr, options = {}) {
@@ -105,16 +508,16 @@ var Diff = class {
105
508
  }
106
509
  }
107
510
  }
108
- addToPath(path7, added, removed, oldPosInc, options) {
109
- const last = path7.lastComponent;
511
+ addToPath(path8, added, removed, oldPosInc, options) {
512
+ const last = path8.lastComponent;
110
513
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
111
514
  return {
112
- oldPos: path7.oldPos + oldPosInc,
515
+ oldPos: path8.oldPos + oldPosInc,
113
516
  lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
114
517
  };
115
518
  } else {
116
519
  return {
117
- oldPos: path7.oldPos + oldPosInc,
520
+ oldPos: path8.oldPos + oldPosInc,
118
521
  lastComponent: { count: 1, added, removed, previousComponent: last }
119
522
  };
120
523
  }
@@ -527,8 +930,8 @@ function splitLines(text) {
527
930
 
528
931
  // dist/omp-adapter.js
529
932
  import { randomUUID as randomUUID2 } from "node:crypto";
530
- import { realpath as realpath2, stat } from "node:fs/promises";
531
- import path5 from "node:path";
933
+ import { realpath as realpath3, stat as stat2 } from "node:fs/promises";
934
+ import path6 from "node:path";
532
935
 
533
936
  // ../../../node_modules/zod/v4/classic/external.js
534
937
  var external_exports = {};
@@ -1296,10 +1699,10 @@ function mergeDefs(...defs) {
1296
1699
  function cloneDef(schema) {
1297
1700
  return mergeDefs(schema._zod.def);
1298
1701
  }
1299
- function getElementAtPath(obj, path7) {
1300
- if (!path7)
1702
+ function getElementAtPath(obj, path8) {
1703
+ if (!path8)
1301
1704
  return obj;
1302
- return path7.reduce((acc, key) => acc?.[key], obj);
1705
+ return path8.reduce((acc, key) => acc?.[key], obj);
1303
1706
  }
1304
1707
  function promiseAllObject(promisesObj) {
1305
1708
  const keys = Object.keys(promisesObj);
@@ -1708,11 +2111,11 @@ function explicitlyAborted(x, startIndex = 0) {
1708
2111
  }
1709
2112
  return false;
1710
2113
  }
1711
- function prefixIssues(path7, issues) {
2114
+ function prefixIssues(path8, issues) {
1712
2115
  return issues.map((iss) => {
1713
2116
  var _a3;
1714
2117
  (_a3 = iss).path ?? (_a3.path = []);
1715
- iss.path.unshift(path7);
2118
+ iss.path.unshift(path8);
1716
2119
  return iss;
1717
2120
  });
1718
2121
  }
@@ -1859,16 +2262,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
1859
2262
  }
1860
2263
  function formatError(error51, mapper = (issue2) => issue2.message) {
1861
2264
  const fieldErrors = { _errors: [] };
1862
- const processError = (error52, path7 = []) => {
2265
+ const processError = (error52, path8 = []) => {
1863
2266
  for (const issue2 of error52.issues) {
1864
2267
  if (issue2.code === "invalid_union" && issue2.errors.length) {
1865
- issue2.errors.map((issues) => processError({ issues }, [...path7, ...issue2.path]));
2268
+ issue2.errors.map((issues) => processError({ issues }, [...path8, ...issue2.path]));
1866
2269
  } else if (issue2.code === "invalid_key") {
1867
- processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
2270
+ processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
1868
2271
  } else if (issue2.code === "invalid_element") {
1869
- processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
2272
+ processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
1870
2273
  } else {
1871
- const fullpath = [...path7, ...issue2.path];
2274
+ const fullpath = [...path8, ...issue2.path];
1872
2275
  if (fullpath.length === 0) {
1873
2276
  fieldErrors._errors.push(mapper(issue2));
1874
2277
  } else {
@@ -1895,17 +2298,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
1895
2298
  }
1896
2299
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
1897
2300
  const result = { errors: [] };
1898
- const processError = (error52, path7 = []) => {
2301
+ const processError = (error52, path8 = []) => {
1899
2302
  var _a3, _b;
1900
2303
  for (const issue2 of error52.issues) {
1901
2304
  if (issue2.code === "invalid_union" && issue2.errors.length) {
1902
- issue2.errors.map((issues) => processError({ issues }, [...path7, ...issue2.path]));
2305
+ issue2.errors.map((issues) => processError({ issues }, [...path8, ...issue2.path]));
1903
2306
  } else if (issue2.code === "invalid_key") {
1904
- processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
2307
+ processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
1905
2308
  } else if (issue2.code === "invalid_element") {
1906
- processError({ issues: issue2.issues }, [...path7, ...issue2.path]);
2309
+ processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
1907
2310
  } else {
1908
- const fullpath = [...path7, ...issue2.path];
2311
+ const fullpath = [...path8, ...issue2.path];
1909
2312
  if (fullpath.length === 0) {
1910
2313
  result.errors.push(mapper(issue2));
1911
2314
  continue;
@@ -1937,8 +2340,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
1937
2340
  }
1938
2341
  function toDotPath(_path) {
1939
2342
  const segs = [];
1940
- const path7 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1941
- for (const seg of path7) {
2343
+ const path8 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
2344
+ for (const seg of path8) {
1942
2345
  if (typeof seg === "number")
1943
2346
  segs.push(`[${seg}]`);
1944
2347
  else if (typeof seg === "symbol")
@@ -14630,13 +15033,13 @@ function resolveRef(ref, ctx) {
14630
15033
  if (!ref.startsWith("#")) {
14631
15034
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
14632
15035
  }
14633
- const path7 = ref.slice(1).split("/").filter(Boolean);
14634
- if (path7.length === 0) {
15036
+ const path8 = ref.slice(1).split("/").filter(Boolean);
15037
+ if (path8.length === 0) {
14635
15038
  return ctx.rootSchema;
14636
15039
  }
14637
15040
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
14638
- if (path7[0] === defsKey) {
14639
- const key = path7[1];
15041
+ if (path8[0] === defsKey) {
15042
+ const key = path8[1];
14640
15043
  if (!key || !ctx.defs[key]) {
14641
15044
  throw new Error(`Reference not found: ${ref}`);
14642
15045
  }
@@ -15114,6 +15517,20 @@ var harnessDisplaySetSchema = external_exports.strictObject({
15114
15517
  initializeOnly: external_exports.boolean().optional()
15115
15518
  });
15116
15519
 
15520
+ // ../../shared-contracts/dist/ids.js
15521
+ var opaqueIdSchema = external_exports.string().refine((value) => value.trim().length > 0, {
15522
+ message: "Identifier must not be empty or whitespace"
15523
+ });
15524
+ var harnessIdSchema = opaqueIdSchema.brand();
15525
+ var hostThreadIdSchema = opaqueIdSchema.brand();
15526
+ var hostTurnIdSchema = opaqueIdSchema.brand();
15527
+ var hostItemIdSchema = opaqueIdSchema.brand();
15528
+ var hostInteractionIdSchema = opaqueIdSchema.brand();
15529
+
15530
+ // ../../shared-contracts/dist/thread-prewarm.js
15531
+ var threadPrewarmDiscardParamsSchema = external_exports.object({ threadId: hostThreadIdSchema });
15532
+ var threadPrewarmDiscardResultSchema = external_exports.object({ discarded: external_exports.boolean() });
15533
+
15117
15534
  // ../../shared-contracts/dist/console.js
15118
15535
  var consoleAnnouncementSchema = external_exports.strictObject({
15119
15536
  title: external_exports.string().trim().min(1).max(200),
@@ -15126,10 +15543,14 @@ var consoleOpenResultSchema = external_exports.strictObject({
15126
15543
  url: external_exports.string().max(2048).regex(/^http:\/\/(?:127\.0\.0\.1|localhost):\d{1,5}\/(?:\?.*)?$/u)
15127
15544
  });
15128
15545
  var CONSOLE_HOST_METHODS = Object.freeze([
15546
+ "codexhost/console/remote-connections",
15547
+ "codexhost/runtime/status",
15548
+ "codexhost/remote/ssh-setup",
15129
15549
  "codexhost/harness/plugins/list",
15130
15550
  "codexhost/harness/display-settings/get",
15131
15551
  "codexhost/harness/display-settings/set",
15132
15552
  "codexhost/harness/inspect",
15553
+ "codexhost/harness/installation",
15133
15554
  "codexhost/harness/launch-settings/get",
15134
15555
  "codexhost/harness/launch-settings/set",
15135
15556
  "codexhost/harness/web-ui/open",
@@ -15191,16 +15612,6 @@ var loadedSessionsSchema = external_exports.array(external_exports.strictObject(
15191
15612
  inactiveMs: external_exports.number().nonnegative()
15192
15613
  }));
15193
15614
 
15194
- // ../../shared-contracts/dist/ids.js
15195
- var opaqueIdSchema = external_exports.string().refine((value) => value.trim().length > 0, {
15196
- message: "Identifier must not be empty or whitespace"
15197
- });
15198
- var harnessIdSchema = opaqueIdSchema.brand();
15199
- var hostThreadIdSchema = opaqueIdSchema.brand();
15200
- var hostTurnIdSchema = opaqueIdSchema.brand();
15201
- var hostItemIdSchema = opaqueIdSchema.brand();
15202
- var hostInteractionIdSchema = opaqueIdSchema.brand();
15203
-
15204
15615
  // ../../shared-contracts/dist/manual-compaction.js
15205
15616
  var threadManualCompactionStartedSchema = external_exports.strictObject({
15206
15617
  threadId: hostThreadIdSchema,
@@ -15776,14 +16187,17 @@ var harnessLaunchSettingsSchema = external_exports.object({
15776
16187
  // ../../shared-contracts/dist/harness-installation.js
15777
16188
  var harnessInstallationParamsSchema = external_exports.object({
15778
16189
  harnessId: harnessIdSchema,
15779
- action: external_exports.enum(["check", "update"])
16190
+ action: external_exports.enum(["check", "update", "install"])
15780
16191
  }).strict();
15781
16192
  var harnessInstallationStateSchema = external_exports.object({
15782
16193
  currentVersion: external_exports.string().min(1).max(128),
15783
16194
  latestVersion: external_exports.string().min(1).max(128),
15784
16195
  updateAvailable: external_exports.boolean(),
15785
16196
  canUpdate: external_exports.boolean(),
15786
- message: external_exports.string().max(2048).optional()
16197
+ // Adapter-owned diagnostic text; UI uses messageCode rather than displaying it verbatim.
16198
+ message: external_exports.string().max(2048).optional(),
16199
+ messageCode: external_exports.string().min(1).max(128).optional(),
16200
+ latestVersionKind: external_exports.enum(["unknown", "tracking-branch"]).optional()
15787
16201
  }).strict();
15788
16202
 
15789
16203
  // ../../shared-contracts/dist/codex-accounts.js
@@ -16085,6 +16499,80 @@ var updateStatusResultSchema = external_exports.strictObject({
16085
16499
  status: updateStatusSchema.nullable()
16086
16500
  });
16087
16501
 
16502
+ // ../../shared-contracts/dist/remote-runtime.js
16503
+ var remoteUpdatePhaseSchema = external_exports.enum([
16504
+ "idle",
16505
+ "installing",
16506
+ "restarting",
16507
+ "succeeded",
16508
+ "failed"
16509
+ ]);
16510
+ var runtimeStatusSchema = external_exports.object({
16511
+ runningVersion: external_exports.string().nullable(),
16512
+ installedVersion: external_exports.string().nullable(),
16513
+ restartRequired: external_exports.boolean(),
16514
+ remote: external_exports.boolean(),
16515
+ updateSupported: external_exports.boolean(),
16516
+ update: external_exports.object({
16517
+ phase: remoteUpdatePhaseSchema,
16518
+ targetVersion: external_exports.string().nullable(),
16519
+ error: external_exports.string().nullable()
16520
+ })
16521
+ });
16522
+ var remoteUpdateParamsSchema = external_exports.object({
16523
+ version: external_exports.string().regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u)
16524
+ }).strict();
16525
+ var remoteSshSetupParamsSchema = external_exports.object({
16526
+ hostname: external_exports.string().min(1).max(1024).refine((value) => !value.startsWith("-") && !/\s/u.test(value)),
16527
+ port: external_exports.number().int().min(1).max(65535).nullable(),
16528
+ identity: external_exports.string().max(4096).nullable(),
16529
+ action: external_exports.enum(["inspect", "install", "update", "repair", "uninstall"]),
16530
+ uninstallPackage: external_exports.boolean().optional(),
16531
+ version: external_exports.string().regex(/^\d+\.\d+\.\d+$/u).nullable()
16532
+ }).strict();
16533
+ var remoteSshSetupResultSchema = external_exports.object({ state: external_exports.enum(["installed", "not-installed"]) }).strict();
16534
+
16535
+ // ../../shared-contracts/dist/remote-connections.js
16536
+ var hostId = external_exports.string().min(1).max(1024);
16537
+ var codexSshConnectionSchema = external_exports.object({
16538
+ hostId,
16539
+ displayName: external_exports.string().min(1).max(1024),
16540
+ source: external_exports.enum(["codex-managed", "discovered"]),
16541
+ sshAlias: external_exports.string().max(1024).nullable(),
16542
+ sshHost: external_exports.string().min(1).max(1024),
16543
+ sshPort: external_exports.number().int().min(1).max(65535).nullable(),
16544
+ identity: external_exports.string().max(4096).nullable(),
16545
+ autoConnect: external_exports.boolean(),
16546
+ connectionAnalyticsId: external_exports.string().max(1024).optional()
16547
+ });
16548
+ var codexSshDraftSchema = external_exports.strictObject({
16549
+ displayName: external_exports.string().min(1).max(1024),
16550
+ hostname: external_exports.string().min(1).max(1024),
16551
+ sshPort: external_exports.number().int().min(1).max(65535).nullable(),
16552
+ identity: external_exports.string().max(4096).nullable()
16553
+ });
16554
+ var remoteConnectionsRequestSchema = external_exports.discriminatedUnion("action", [
16555
+ external_exports.strictObject({ action: external_exports.literal("list") }),
16556
+ external_exports.strictObject({
16557
+ action: external_exports.literal("save"),
16558
+ draft: codexSshDraftSchema,
16559
+ previous: codexSshConnectionSchema.nullable()
16560
+ }),
16561
+ external_exports.strictObject({ action: external_exports.literal("remove"), previous: codexSshConnectionSchema }),
16562
+ external_exports.strictObject({ action: external_exports.literal("connect"), hostId, enabled: external_exports.boolean() }),
16563
+ external_exports.strictObject({ action: external_exports.literal("state"), hostId }),
16564
+ external_exports.strictObject({ action: external_exports.literal("runtime"), hostId }),
16565
+ external_exports.strictObject({
16566
+ action: external_exports.literal("update"),
16567
+ hostId: hostId.refine((id) => id !== "local"),
16568
+ version: remoteUpdateParamsSchema.shape.version
16569
+ })
16570
+ ]);
16571
+ var remoteConnectionsReplySchema = external_exports.union([
16572
+ external_exports.strictObject({ result: jsonValueSchema }),
16573
+ external_exports.strictObject({ error: external_exports.strictObject({ code: external_exports.number().int(), message: external_exports.string() }) })
16574
+ ]);
16575
+
16088
16576
  // ../../shared-contracts/dist/index.js
16089
16577
  var workspaceContractVersionSchema = external_exports.literal(WORKSPACE_CONTRACT_VERSION);
16090
16578
 
@@ -16792,512 +17280,502 @@ function mapOmpSnapshot(history, state) {
16792
17280
  const changed = modelChange(entry);
16793
17281
  if (changed)
16794
17282
  effectiveModel = changed;
16795
- }
16796
- index = end;
16797
- }
16798
- return { turns };
16799
- }
16800
- function resolveOmpLastTurnBoundary(history) {
16801
- const users = activeOmpEntries(history).filter((entry) => messageRole(entry) === "user");
16802
- const last = users.at(-1);
16803
- return last ? { lastUserEntryId: last.id, sourceTurnCount: users.length } : null;
16804
- }
16805
- function resolveOmpForkBoundary(history, checkpointId) {
16806
- const active = activeOmpEntries(history);
16807
- const users = active.filter((entry) => messageRole(entry) === "user");
16808
- const targetTurnIndex = users.findIndex((entry) => entry.id === checkpointId);
16809
- if (targetTurnIndex < 0)
16810
- throw new Error("Omp Checkpoint is not on the active branch");
16811
- return {
16812
- targetTurnIndex,
16813
- nextUserEntryId: users[targetTurnIndex + 1]?.id ?? null
16814
- };
16815
- }
16816
-
16817
- // dist/omp-session-file.js
16818
- import { createReadStream } from "node:fs";
16819
- import { open, realpath } from "node:fs/promises";
16820
- import readline from "node:readline";
16821
- var MAX_SESSION_HEADER_BYTES = 64 * 1024;
16822
- var utf8Decoder = new TextDecoder("utf-8", { fatal: true });
16823
- function isRecord5(value) {
16824
- return typeof value === "object" && value !== null && !Array.isArray(value);
16825
- }
16826
- function historyEntry(value) {
16827
- if (!isRecord5(value) || value.type === "title" || value.type === "session" || typeof value.id !== "string" || value.id.length === 0 || value.parentId !== null && typeof value.parentId !== "string" || typeof value.type !== "string") {
16828
- return null;
16829
- }
16830
- return value;
16831
- }
16832
- async function readOmpSessionHistory(sessionFile, maxBytes) {
16833
- const entries = [];
16834
- let leafId = null;
16835
- const lines = readline.createInterface({
16836
- input: createReadStream(sessionFile, {
16837
- encoding: "utf8",
16838
- ...maxBytes === void 0 ? {} : { end: maxBytes - 1 }
16839
- }),
16840
- crlfDelay: Number.POSITIVE_INFINITY
16841
- });
16842
- try {
16843
- for await (const line of lines) {
16844
- if (line.length === 0)
16845
- continue;
16846
- let parsed;
16847
- try {
16848
- parsed = JSON.parse(line);
16849
- } catch {
16850
- continue;
16851
- }
16852
- const entry = historyEntry(parsed);
16853
- if (!entry)
16854
- continue;
16855
- entries.push(entry);
16856
- leafId = entry.id;
16857
- }
16858
- } finally {
16859
- lines.close();
16860
- }
16861
- return { entries, leafId };
16862
- }
16863
- async function readOmpSessionHeader(sessionFile) {
16864
- const handle = await open(sessionFile, "r");
16865
- try {
16866
- const buffer = Buffer.allocUnsafe(MAX_SESSION_HEADER_BYTES);
16867
- const { bytesRead } = await handle.read(buffer, 0, buffer.length, 0);
16868
- const contents = buffer.subarray(0, bytesRead);
16869
- const newline = contents.indexOf(10);
16870
- if (newline < 0 && bytesRead === buffer.length) {
16871
- throw new Error("Omp Session header exceeds the supported size");
16872
- }
16873
- const contentsText = utf8Decoder.decode(contents);
16874
- for (const line of contentsText.split("\n")) {
16875
- if (line.length === 0)
16876
- continue;
16877
- let parsed;
16878
- try {
16879
- parsed = JSON.parse(line);
16880
- } catch {
16881
- continue;
16882
- }
16883
- if (!isRecord5(parsed) || parsed.type !== "session")
16884
- continue;
16885
- if (typeof parsed.id !== "string" || parsed.id.length === 0 || typeof parsed.cwd !== "string" || parsed.cwd.length === 0) {
16886
- throw new Error("Omp Session header is invalid");
16887
- }
16888
- return { type: "session", id: parsed.id, cwd: parsed.cwd };
16889
- }
16890
- throw new Error("Omp Session header is invalid");
16891
- } finally {
16892
- await handle.close();
16893
- }
16894
- }
16895
- async function verifyOmpSessionCwd(input) {
16896
- if (!input.sessionFile)
16897
- throw new Error("Omp Fork Session has no persisted Session file");
16898
- const header = await readOmpSessionHeader(input.sessionFile);
16899
- if (header.id !== input.sessionId) {
16900
- throw new Error("Omp Fork Session header identity does not match RPC state");
16901
- }
16902
- const [actualCwd, expectedCwd] = await Promise.all([
16903
- realpath(header.cwd),
16904
- realpath(input.expectedCwd)
16905
- ]);
16906
- if (actualCwd !== expectedCwd) {
16907
- throw new Error("Omp Fork Session did not bind the requested cwd");
16908
- }
16909
- }
16910
-
16911
- // dist/omp-last-turn-rollback.js
16912
- function modelFromState(state) {
16913
- if (state.provider === null && state.modelId === null)
16914
- return null;
16915
- if (state.provider === null || state.modelId === null) {
16916
- throw new Error("Omp state contains a partial Model identity");
16917
- }
16918
- return { provider: state.provider, id: state.modelId };
16919
- }
16920
- async function rollbackOmpLastTurn(transport, sourceSessionId, cwd) {
16921
- const startupState = transport.state;
16922
- const startupSessionId = startupState.sessionId;
16923
- const currentModel = modelFromState(startupState);
16924
- const currentThinking = startupState.thinkingLevel;
16925
- const copiedHistory = await transport.getEntries();
16926
- const boundary = resolveOmpLastTurnBoundary(copiedHistory);
16927
- if (!boundary)
16928
- return { ok: false, reason: "empty" };
16929
- const sourceSnapshot = mapOmpSnapshot(copiedHistory, {
16930
- sessionId: startupSessionId,
16931
- model: currentModel
16932
- });
16933
- let state = await transport.fork(boundary.lastUserEntryId);
16934
- if (state.sessionId === sourceSessionId || state.sessionId === startupSessionId) {
16935
- throw new Error("Omp last-Turn rollback did not create a distinct Native Session");
16936
- }
16937
- if (!sameOmpModel(modelFromState(state), currentModel)) {
16938
- if (!currentModel)
16939
- throw new Error("Omp last-Turn rollback changed the current Model");
16940
- state = await transport.selectModel(currentModel);
16941
- }
16942
- if (state.thinkingLevel !== currentThinking) {
16943
- if (!currentThinking)
16944
- throw new Error("Omp last-Turn rollback changed current Thinking");
16945
- state = await transport.selectThinkingOption(currentThinking);
16946
- }
16947
- if (!sameOmpModel(modelFromState(state), currentModel) || state.thinkingLevel !== currentThinking) {
16948
- throw new Error("Omp last-Turn rollback could not restore current Model and Thinking");
16949
- }
16950
- const snapshot = mapOmpSnapshot(await transport.getEntries(), {
16951
- sessionId: state.sessionId,
16952
- model: modelFromState(state)
16953
- });
16954
- const expectedTurnKeys = sourceSnapshot.turns.slice(0, -1).map((turn) => turn.nativeTurnRef.nativeTurnKey);
16955
- const actualTurnKeys = snapshot.turns.map((turn) => turn.nativeTurnRef.nativeTurnKey);
16956
- if (snapshot.turns.length !== boundary.sourceTurnCount - 1 || actualTurnKeys.some((key, index) => key !== expectedTurnKeys[index])) {
16957
- throw new Error("Omp last-Turn rollback did not produce the exact retained history prefix");
16958
- }
16959
- await transport.verifySessionCwd(cwd);
16960
- return { ok: true };
16961
- }
16962
-
16963
- // dist/omp-rpc-session.js
16964
- import { spawn, spawnSync } from "node:child_process";
16965
- import { randomUUID } from "node:crypto";
16966
- import path4 from "node:path";
16967
-
16968
- // ../../harness-discovery/dist/environment.js
16969
- import fs from "node:fs";
16970
- import path from "node:path";
16971
- function targetPath(platform) {
16972
- return platform === "win32" ? path.win32 : path.posix;
16973
- }
16974
- function environmentValue(environment, name) {
16975
- const lowered = name.toLowerCase();
16976
- for (const [key, value] of Object.entries(environment)) {
16977
- if (key.toLowerCase() === lowered)
16978
- return value;
16979
- }
16980
- return void 0;
16981
- }
16982
- function pathDelimiter(platform) {
16983
- return platform === "win32" ? ";" : ":";
16984
- }
16985
- function pathDirectories(environment, platform) {
16986
- return (environmentValue(environment, "PATH") ?? "").split(pathDelimiter(platform)).map((directory) => directory.trim().replace(/^"|"$/gu, "")).filter(Boolean);
16987
- }
16988
- function executableExtensions(command, platform, environment) {
16989
- if (platform !== "win32")
16990
- return [""];
16991
- if (targetPath(platform).extname(command) !== "")
16992
- return [""];
16993
- return (environmentValue(environment, "PATHEXT") ?? ".COM;.EXE;.BAT;.CMD").split(";").map((extension) => extension.trim()).filter(Boolean);
16994
- }
16995
- function isExecutableFile(filePath, platform) {
16996
- try {
16997
- fs.accessSync(filePath, platform === "win32" ? fs.constants.F_OK : fs.constants.X_OK);
16998
- return fs.statSync(filePath).isFile();
16999
- } catch {
17000
- return false;
17001
- }
17002
- }
17003
- function subdirectoryNames(directory) {
17004
- try {
17005
- return fs.readdirSync(directory, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
17006
- } catch {
17007
- return [];
17283
+ }
17284
+ index = end;
17008
17285
  }
17286
+ return { turns };
17009
17287
  }
17010
- function newestFirst(names) {
17011
- return [...names].sort((left, right) => right.localeCompare(left, void 0, { numeric: true }));
17288
+ function resolveOmpLastTurnBoundary(history) {
17289
+ const users = activeOmpEntries(history).filter((entry) => messageRole(entry) === "user");
17290
+ const last = users.at(-1);
17291
+ return last ? { lastUserEntryId: last.id, sourceTurnCount: users.length } : null;
17012
17292
  }
17013
-
17014
- // ../../harness-discovery/dist/invocation.js
17015
- import path2 from "node:path";
17016
- function commandInvocation(command, arguments_, environment, platform = process.platform) {
17017
- const extension = path2.win32.extname(command).toLowerCase();
17018
- if (platform !== "win32" || ![".cmd", ".bat"].includes(extension)) {
17019
- return { command, arguments: [...arguments_], windowsVerbatimArguments: false };
17020
- }
17021
- const quote = (value) => `"${value.replaceAll("%", "%%").replaceAll('"', '""')}"`;
17022
- const commandLine = [command, ...arguments_].map(quote).join(" ");
17293
+ function resolveOmpForkBoundary(history, checkpointId) {
17294
+ const active = activeOmpEntries(history);
17295
+ const users = active.filter((entry) => messageRole(entry) === "user");
17296
+ const targetTurnIndex = users.findIndex((entry) => entry.id === checkpointId);
17297
+ if (targetTurnIndex < 0)
17298
+ throw new Error("Omp Checkpoint is not on the active branch");
17023
17299
  return {
17024
- command: environmentValue(environment, "ComSpec") ?? "cmd.exe",
17025
- arguments: ["/d", "/v:off", "/s", "/c", `"${commandLine}"`],
17026
- windowsVerbatimArguments: true
17300
+ targetTurnIndex,
17301
+ nextUserEntryId: users[targetTurnIndex + 1]?.id ?? null
17027
17302
  };
17028
17303
  }
17029
17304
 
17030
- // ../../harness-discovery/dist/node-runtime.js
17031
- import path3 from "node:path";
17032
- function withNodeRuntimeOnPath(environment, runtimeExecutable = process.execPath, platform = process.platform) {
17033
- const pathKey = Object.keys(environment).find((name) => name.toLowerCase() === "path") ?? "PATH";
17034
- const delimiter = platform === "win32" ? ";" : ":";
17035
- const runtimeDirectory = path3.dirname(runtimeExecutable);
17036
- const directories = (environment[pathKey] ?? "").split(delimiter).filter(Boolean);
17037
- const equal = platform === "win32" ? (value) => value.toLowerCase() : (value) => value;
17038
- if (!directories.some((directory) => equal(directory) === equal(runtimeDirectory))) {
17039
- directories.push(runtimeDirectory);
17305
+ // dist/omp-session-file.js
17306
+ import { createReadStream } from "node:fs";
17307
+ import { open, realpath } from "node:fs/promises";
17308
+ import readline from "node:readline";
17309
+ var MAX_SESSION_HEADER_BYTES = 64 * 1024;
17310
+ var utf8Decoder = new TextDecoder("utf-8", { fatal: true });
17311
+ function isRecord5(value) {
17312
+ return typeof value === "object" && value !== null && !Array.isArray(value);
17313
+ }
17314
+ function historyEntry(value) {
17315
+ if (!isRecord5(value) || value.type === "title" || value.type === "session" || typeof value.id !== "string" || value.id.length === 0 || value.parentId !== null && typeof value.parentId !== "string" || typeof value.type !== "string") {
17316
+ return null;
17040
17317
  }
17041
- return { ...environment, [pathKey]: directories.join(delimiter) };
17318
+ return value;
17042
17319
  }
17043
-
17044
- // ../../harness-discovery/dist/resolve.js
17045
- import os from "node:os";
17046
-
17047
- // ../../harness-discovery/dist/version-managers.js
17048
- function versionManagerBinaryDirectories(context) {
17049
- const { platform, environment, home } = context;
17050
- const list = context.subdirectories ?? subdirectoryNames;
17051
- const pathFlavor = targetPath(platform);
17052
- const value = (name) => environmentValue(environment, name);
17053
- const directories = [];
17054
- const versioned = (root, ...tail) => {
17055
- for (const version2 of newestFirst(list(root))) {
17056
- directories.push(pathFlavor.join(root, version2, ...tail));
17320
+ async function readOmpSessionHistory(sessionFile, maxBytes) {
17321
+ const entries = [];
17322
+ let leafId = null;
17323
+ const lines = readline.createInterface({
17324
+ input: createReadStream(sessionFile, {
17325
+ encoding: "utf8",
17326
+ ...maxBytes === void 0 ? {} : { end: maxBytes - 1 }
17327
+ }),
17328
+ crlfDelay: Number.POSITIVE_INFINITY
17329
+ });
17330
+ try {
17331
+ for await (const line of lines) {
17332
+ if (line.length === 0)
17333
+ continue;
17334
+ let parsed;
17335
+ try {
17336
+ parsed = JSON.parse(line);
17337
+ } catch {
17338
+ continue;
17339
+ }
17340
+ const entry = historyEntry(parsed);
17341
+ if (!entry)
17342
+ continue;
17343
+ entries.push(entry);
17344
+ leafId = entry.id;
17057
17345
  }
17058
- };
17059
- if (platform === "win32") {
17060
- const appData = value("APPDATA") ?? pathFlavor.join(home, "AppData", "Roaming");
17061
- const localAppData = value("LOCALAPPDATA") ?? pathFlavor.join(home, "AppData", "Local");
17062
- versioned(pathFlavor.join(appData, "nvm"));
17063
- versioned(value("FNM_DIR") ?? pathFlavor.join(appData, "fnm", "node-versions"), "installation");
17064
- directories.push(pathFlavor.join(localAppData, "Volta", "bin"));
17065
- directories.push(pathFlavor.join(home, ".bun", "bin"));
17066
- const pnpmHome2 = value("PNPM_HOME");
17067
- if (pnpmHome2)
17068
- directories.push(pnpmHome2);
17069
- directories.push(pathFlavor.join(localAppData, "pnpm"));
17070
- return directories;
17071
- }
17072
- versioned(pathFlavor.join(value("NVM_DIR") ?? pathFlavor.join(home, ".nvm"), "versions", "node"), "bin");
17073
- const fnmRoots = [
17074
- value("FNM_DIR"),
17075
- pathFlavor.join(home, ".local", "share", "fnm"),
17076
- pathFlavor.join(home, "Library", "Application Support", "fnm")
17077
- ].filter((root) => root !== void 0);
17078
- for (const root of fnmRoots) {
17079
- versioned(pathFlavor.join(root, "node-versions"), "installation", "bin");
17346
+ } finally {
17347
+ lines.close();
17080
17348
  }
17081
- const voltaHome = value("VOLTA_HOME") ?? pathFlavor.join(home, ".volta");
17082
- versioned(pathFlavor.join(voltaHome, "tools", "image", "node"), "bin");
17083
- directories.push(pathFlavor.join(voltaHome, "bin"));
17084
- const asdfHome = value("ASDF_DATA_DIR") ?? pathFlavor.join(home, ".asdf");
17085
- versioned(pathFlavor.join(asdfHome, "installs", "nodejs"), "bin");
17086
- directories.push(pathFlavor.join(asdfHome, "shims"));
17087
- const nodenvHome = value("NODENV_ROOT") ?? pathFlavor.join(home, ".nodenv");
17088
- versioned(pathFlavor.join(nodenvHome, "versions"), "bin");
17089
- directories.push(pathFlavor.join(nodenvHome, "shims"));
17090
- versioned(pathFlavor.join(value("N_PREFIX") ?? "/usr/local", "n", "versions", "node"), "bin");
17091
- directories.push(pathFlavor.join(home, ".bun", "bin"));
17092
- const pnpmHome = value("PNPM_HOME");
17093
- if (pnpmHome)
17094
- directories.push(pnpmHome);
17095
- directories.push(pathFlavor.join(home, "Library", "pnpm"));
17096
- directories.push(pathFlavor.join(home, ".local", "share", "pnpm"));
17097
- for (const prefix of ["/opt/homebrew/opt", "/usr/local/opt"]) {
17098
- for (const formula of newestFirst(list(prefix).filter((name) => name.startsWith("node@")))) {
17099
- directories.push(pathFlavor.join(prefix, formula, "bin"));
17349
+ return { entries, leafId };
17350
+ }
17351
+ async function readOmpSessionHeader(sessionFile) {
17352
+ const handle = await open(sessionFile, "r");
17353
+ try {
17354
+ const buffer = Buffer.allocUnsafe(MAX_SESSION_HEADER_BYTES);
17355
+ const { bytesRead } = await handle.read(buffer, 0, buffer.length, 0);
17356
+ const contents = buffer.subarray(0, bytesRead);
17357
+ const newline = contents.indexOf(10);
17358
+ if (newline < 0 && bytesRead === buffer.length) {
17359
+ throw new Error("Omp Session header exceeds the supported size");
17360
+ }
17361
+ const contentsText = utf8Decoder.decode(contents);
17362
+ for (const line of contentsText.split("\n")) {
17363
+ if (line.length === 0)
17364
+ continue;
17365
+ let parsed;
17366
+ try {
17367
+ parsed = JSON.parse(line);
17368
+ } catch {
17369
+ continue;
17370
+ }
17371
+ if (!isRecord5(parsed) || parsed.type !== "session")
17372
+ continue;
17373
+ if (typeof parsed.id !== "string" || parsed.id.length === 0 || typeof parsed.cwd !== "string" || parsed.cwd.length === 0) {
17374
+ throw new Error("Omp Session header is invalid");
17375
+ }
17376
+ return { type: "session", id: parsed.id, cwd: parsed.cwd };
17100
17377
  }
17378
+ throw new Error("Omp Session header is invalid");
17379
+ } finally {
17380
+ await handle.close();
17101
17381
  }
17102
- return directories;
17103
17382
  }
17104
-
17105
- // ../../harness-discovery/dist/resolve.js
17106
- var VERSION_MANAGER_ROOTS = "<version-managers>";
17107
- function installRootExtensions(platform) {
17108
- return platform === "win32" ? [".exe", ".cmd"] : [""];
17109
- }
17110
- function resolveHomeDirectory(input) {
17111
- return input.homeDirectory ?? environmentValue(input.environment, "HOME") ?? environmentValue(input.environment, "USERPROFILE") ?? os.homedir();
17383
+ async function verifyOmpSessionCwd(input) {
17384
+ if (!input.sessionFile)
17385
+ throw new Error("Omp Fork Session has no persisted Session file");
17386
+ const header = await readOmpSessionHeader(input.sessionFile);
17387
+ if (header.id !== input.sessionId) {
17388
+ throw new Error("Omp Fork Session header identity does not match RPC state");
17389
+ }
17390
+ const [actualCwd, expectedCwd] = await Promise.all([
17391
+ realpath(header.cwd),
17392
+ realpath(input.expectedCwd)
17393
+ ]);
17394
+ if (actualCwd !== expectedCwd) {
17395
+ throw new Error("Omp Fork Session did not bind the requested cwd");
17396
+ }
17112
17397
  }
17113
- function templateVariables(environment, platform, home) {
17114
- const pathFlavor = targetPath(platform);
17115
- return {
17116
- HOME: home,
17117
- USERPROFILE: home,
17118
- APPDATA: environmentValue(environment, "APPDATA") ?? pathFlavor.join(home, "AppData", "Roaming"),
17119
- LOCALAPPDATA: environmentValue(environment, "LOCALAPPDATA") ?? pathFlavor.join(home, "AppData", "Local")
17120
- };
17398
+
17399
+ // dist/session-import.js
17400
+ import { createReadStream as createReadStream2 } from "node:fs";
17401
+ import { opendir, realpath as realpath2, stat } from "node:fs/promises";
17402
+ import os2 from "node:os";
17403
+ import path4 from "node:path";
17404
+ import { createInterface } from "node:readline";
17405
+
17406
+ // ../../harness-adapter/dist/session-import.js
17407
+ import { lstat } from "node:fs/promises";
17408
+ var SessionImportChangedError = class extends Error {
17409
+ constructor(message3 = "Native Session changed during discovery; refresh and retry") {
17410
+ super(message3);
17411
+ this.name = "SessionImportChangedError";
17412
+ }
17413
+ };
17414
+ function isMissingFileError(error51) {
17415
+ return typeof error51 === "object" && error51 !== null && "code" in error51 && error51.code === "ENOENT";
17121
17416
  }
17122
- function joinTemplate(platform, value) {
17123
- const pathFlavor = targetPath(platform);
17124
- const segments = value.split("/");
17125
- const head = segments[0] ?? "";
17126
- const tail = segments.slice(1);
17127
- if (head === "")
17128
- return pathFlavor.join(pathFlavor.sep, ...tail);
17129
- return tail.length === 0 ? head : pathFlavor.join(head, ...tail);
17417
+ function sameFileFingerprint(left, right) {
17418
+ 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;
17130
17419
  }
17131
- function expandInstallRoot(template, environment, platform, home) {
17132
- const variables = templateVariables(environment, platform, home);
17133
- let unresolved = false;
17134
- const substituted = template.replace(/^~(?=\/|$)/u, home).replace(/\$\{(\w+)\}/gu, (_match, name) => {
17135
- const value = variables[name] ?? environmentValue(environment, name);
17136
- if (value === void 0 || value === "") {
17137
- unresolved = true;
17138
- return "";
17139
- }
17140
- return value;
17141
- });
17142
- return unresolved ? void 0 : joinTemplate(platform, substituted);
17420
+ var STORAGE_ACCESS_ERRORS = /* @__PURE__ */ new Set(["EACCES", "EPERM", "EIO", "EMFILE", "ENFILE"]);
17421
+ function isStorageAccessError(error51) {
17422
+ return typeof error51 === "object" && error51 !== null && "code" in error51 && typeof error51.code === "string" && STORAGE_ACCESS_ERRORS.has(error51.code);
17143
17423
  }
17144
- function installRootDirectories(spec, input, dependencies, platform, home) {
17145
- const templates = (platform === "win32" ? spec.installRoots?.windows : spec.installRoots?.posix) ?? [];
17146
- const directories = [];
17147
- for (const template of templates) {
17148
- if (template === VERSION_MANAGER_ROOTS) {
17149
- directories.push(...versionManagerBinaryDirectories({
17150
- platform,
17151
- environment: input.environment,
17152
- home,
17153
- ...dependencies.subdirectories ? { subdirectories: dependencies.subdirectories } : {}
17154
- }));
17155
- continue;
17156
- }
17157
- const directory = expandInstallRoot(template, input.environment, platform, home);
17158
- if (directory !== void 0)
17159
- directories.push(directory);
17424
+ async function optionalLstat(file2) {
17425
+ try {
17426
+ return await lstat(file2);
17427
+ } catch (error51) {
17428
+ if (isMissingFileError(error51))
17429
+ return null;
17430
+ throw error51;
17160
17431
  }
17161
- return directories;
17162
17432
  }
17163
- function harnessCandidates(spec, input, dependencies = {}) {
17164
- const platform = input.platform ?? process.platform;
17165
- const pathFlavor = targetPath(platform);
17166
- const configured = input.command ?? (spec.commandEnvironmentVariable ? environmentValue(input.environment, spec.commandEnvironmentVariable) : void 0);
17167
- const command = configured ?? spec.command;
17168
- if (pathFlavor.isAbsolute(command) || command.includes("/") || command.includes("\\")) {
17169
- return [{ candidate: command, source: "configured" }];
17433
+ async function readStableFiles(files, read) {
17434
+ const before = await Promise.all(files.map(optionalLstat));
17435
+ const value = await read(before);
17436
+ const after = await Promise.all(files.map(optionalLstat));
17437
+ if (before.some((info, index) => !sameFileFingerprint(info, after[index] ?? null)))
17438
+ throw new SessionImportChangedError();
17439
+ return value;
17440
+ }
17441
+ function sessionImportTitle(value, maxLength = HARNESS_SESSION_IMPORT_TITLE_MAX_LENGTH) {
17442
+ if (typeof value !== "string")
17443
+ return null;
17444
+ const normalized = value.replaceAll("\0", "").replaceAll(/\s+/gu, " ").trim();
17445
+ if (!normalized)
17446
+ return null;
17447
+ if (normalized.length <= maxLength)
17448
+ return normalized;
17449
+ const characters = [...normalized];
17450
+ if (characters.length <= maxLength)
17451
+ return normalized;
17452
+ return `${characters.slice(0, maxLength - 1).join("").trimEnd()}…`;
17453
+ }
17454
+ function sessionImportCandidate(input) {
17455
+ const time3 = typeof input.updatedAt === "number" ? input.updatedAt : typeof input.updatedAt === "string" ? Date.parse(input.updatedAt) : Number.NaN;
17456
+ const parsed = harnessSessionImportCandidateSchema.safeParse({
17457
+ nativeSessionId: input.nativeSessionId,
17458
+ cwd: input.cwd,
17459
+ title: typeof input.title === "string" && input.title.trim().length > 0 ? input.title : null,
17460
+ updatedAt: Math.floor(time3),
17461
+ // Unknown must stay unknown; only an explicit boolean is a native statement.
17462
+ running: typeof input.running === "boolean" ? input.running : null
17463
+ });
17464
+ return parsed.success ? parsed.data : null;
17465
+ }
17466
+ var SessionImportScope = class {
17467
+ #abort = new AbortController();
17468
+ #options;
17469
+ #pending = /* @__PURE__ */ new Set();
17470
+ constructor(options) {
17471
+ this.#options = options;
17170
17472
  }
17171
- const candidates = [];
17172
- const extensions = executableExtensions(command, platform, input.environment);
17173
- for (const directory of pathDirectories(input.environment, platform)) {
17174
- for (const extension of extensions) {
17175
- candidates.push({
17176
- candidate: pathFlavor.join(directory, command + extension),
17177
- source: "path"
17178
- });
17179
- }
17473
+ #closed() {
17474
+ return {
17475
+ ok: false,
17476
+ error: { code: "invalidState", message: this.#options.closedMessage, retryable: false }
17477
+ };
17180
17478
  }
17181
- if (configured !== void 0)
17182
- return candidates;
17183
- const home = resolveHomeDirectory(input);
17184
- for (const directory of installRootDirectories(spec, input, dependencies, platform, home)) {
17185
- for (const extension of installRootExtensions(platform)) {
17186
- candidates.push({
17187
- candidate: pathFlavor.join(directory, spec.command + extension),
17188
- source: "install-root"
17189
- });
17479
+ read(operation) {
17480
+ const signal = this.#abort.signal;
17481
+ if (signal.aborted)
17482
+ return Promise.resolve(this.#closed());
17483
+ let started;
17484
+ try {
17485
+ started = operation(signal);
17486
+ } catch (error51) {
17487
+ started = Promise.reject(error51 instanceof Error ? error51 : new Error("Session read failed"));
17190
17488
  }
17489
+ const request = started.then((value) => signal.aborted ? this.#closed() : { ok: true, value }).catch(() => signal.aborted ? this.#closed() : {
17490
+ ok: false,
17491
+ error: {
17492
+ code: "unavailable",
17493
+ message: this.#options.unavailableMessage,
17494
+ retryable: true
17495
+ }
17496
+ }).finally(() => this.#pending.delete(request));
17497
+ this.#pending.add(request);
17498
+ return request;
17191
17499
  }
17192
- return candidates;
17193
- }
17194
- function resolveHarnessExecutable(spec, input, dependencies = {}) {
17195
- const platform = input.platform ?? process.platform;
17196
- const isExecutable = dependencies.isExecutable ?? ((candidate) => isExecutableFile(candidate, platform));
17197
- const runnable = spec.runnableCandidate ?? ((candidate) => candidate);
17198
- const context = { platform, isExecutable };
17199
- for (const { candidate, source } of harnessCandidates(spec, input, dependencies)) {
17200
- const executable = runnable(candidate, context);
17201
- if (executable !== void 0 && isExecutable(executable))
17202
- return { executable, source };
17500
+ /** `read` for `resolveCandidate`: a null source is the selected Session having disappeared. */
17501
+ async resolve(operation) {
17502
+ const result = await this.read(operation);
17503
+ if (!result.ok)
17504
+ return result;
17505
+ return result.value ? { ok: true, value: result.value } : {
17506
+ ok: false,
17507
+ error: {
17508
+ code: "sessionNotFound",
17509
+ message: this.#options.notFoundMessage,
17510
+ retryable: false
17511
+ }
17512
+ };
17203
17513
  }
17204
- return void 0;
17205
- }
17514
+ /** Idempotent. Resolves after every started read has settled. */
17515
+ async close() {
17516
+ this.#abort.abort();
17517
+ await Promise.allSettled(this.#pending);
17518
+ }
17519
+ };
17206
17520
 
17207
- // ../../harness-discovery/dist/installation.js
17208
- import { execFile } from "node:child_process";
17209
- import { homedir } from "node:os";
17210
- function runInstallationCommand(command, args, environment, timeout = 3e4) {
17211
- const env = withNodeRuntimeOnPath(environment);
17212
- const invocation = /\.[cm]?js$/i.test(command) ? commandInvocation(process.execPath, [command, ...args], env) : commandInvocation(command, args, env);
17213
- return new Promise((resolve, reject) => {
17214
- const child = execFile(invocation.command, invocation.arguments, {
17215
- env,
17216
- cwd: env.HOME ?? env.USERPROFILE ?? homedir(),
17217
- encoding: "utf8",
17218
- timeout,
17219
- killSignal: "SIGKILL",
17220
- maxBuffer: 1024 * 1024,
17221
- windowsHide: true,
17222
- windowsVerbatimArguments: invocation.windowsVerbatimArguments
17223
- }, (error51, stdout, stderr) => {
17224
- if (error51)
17225
- reject(new Error(error51.killed ? "Harness command timed out" : "Harness command failed; check the native installation and retry"));
17226
- else
17227
- resolve((stdout || stderr).trim());
17228
- });
17229
- child.stdin?.end();
17230
- });
17521
+ // dist/session-import.js
17522
+ function isRecord6(value) {
17523
+ return typeof value === "object" && value !== null && !Array.isArray(value);
17231
17524
  }
17232
- function installationVersion(value) {
17233
- if (typeof value !== "string" || !/^v?\d+(?:\.\d+){1,3}(?:-[\w.-]+)?(?:\+[\w.-]+)?$/.test(value.trim()))
17234
- throw new Error("Harness returned an invalid version");
17235
- return value.trim().replace(/^v/, "");
17525
+ function expandDirectory(value, home) {
17526
+ return path4.resolve(value === "~" ? home : value.startsWith(`~${path4.sep}`) || value.startsWith("~/") ? path4.join(home, value.slice(2)) : value);
17236
17527
  }
17237
- function versionFromOutput(output) {
17238
- return installationVersion(output.match(/\b\d+(?:\.\d+){1,3}(?:-[\w.-]+)?(?:\+[\w.-]+)?\b/)?.[0]);
17528
+ function ompSessionImportDirectory(environment) {
17529
+ const home = (process.platform === "win32" ? environment.USERPROFILE : environment.HOME) || os2.homedir();
17530
+ const custom2 = environment.PI_CODING_AGENT_SESSION_DIR;
17531
+ if (custom2)
17532
+ return { directory: expandDirectory(custom2, home), flat: true };
17533
+ const agent = environment.PI_CODING_AGENT_DIR;
17534
+ return {
17535
+ directory: path4.join(agent ? expandDirectory(agent, home) : path4.join(home, ".omp", "agent"), "sessions"),
17536
+ flat: false
17537
+ };
17239
17538
  }
17240
- function newerInstallationVersion(current, latest) {
17241
- const a = installationVersion(current).replace(/\+.*/, "");
17242
- const b = installationVersion(latest).replace(/\+.*/, "");
17243
- const coreA = a.replace(/-.*/, "").split(".").map(BigInt);
17244
- const coreB = b.replace(/-.*/, "").split(".").map(BigInt);
17245
- for (let i = 0; i < Math.max(coreA.length, coreB.length); i++) {
17246
- if ((coreA[i] ?? 0n) !== (coreB[i] ?? 0n))
17247
- return (coreB[i] ?? 0n) > (coreA[i] ?? 0n);
17248
- }
17249
- const preA = a.includes("-") ? a.slice(a.indexOf("-") + 1).split(".") : [];
17250
- const preB = b.includes("-") ? b.slice(b.indexOf("-") + 1).split(".") : [];
17251
- if (!preA.length || !preB.length)
17252
- return !!preA.length && !preB.length;
17253
- for (let i = 0; i < Math.max(preA.length, preB.length); i++) {
17254
- const x = preA[i];
17255
- const y = preB[i];
17256
- if (x === y)
17257
- continue;
17258
- if (x === void 0 || y === void 0)
17259
- return x === void 0;
17260
- const numericX = /^\d+$/.test(x);
17261
- const numericY = /^\d+$/.test(y);
17262
- if (numericX && numericY) {
17263
- if (BigInt(x) === BigInt(y))
17539
+ function messageText(content) {
17540
+ if (typeof content === "string")
17541
+ return content;
17542
+ if (!Array.isArray(content))
17543
+ return "";
17544
+ return content.filter((part) => isRecord6(part) && part.type === "text" && typeof part.text === "string").map((part) => String(part.text)).join(" ");
17545
+ }
17546
+ async function readFacts(file2, signal) {
17547
+ const stream = createReadStream2(file2, { encoding: "utf8", signal });
17548
+ const lines = createInterface({ input: stream, crlfDelay: Infinity });
17549
+ let header = null;
17550
+ let nativeTitle = null;
17551
+ let firstPrompt = null;
17552
+ let updatedAt = null;
17553
+ let leafHasUser = false;
17554
+ const hasUserAncestry = /* @__PURE__ */ new Map();
17555
+ try {
17556
+ for await (const line of lines) {
17557
+ signal.throwIfAborted();
17558
+ if (!line.trim())
17264
17559
  continue;
17265
- return BigInt(y) > BigInt(x);
17560
+ let entry;
17561
+ try {
17562
+ entry = JSON.parse(line);
17563
+ } catch {
17564
+ continue;
17565
+ }
17566
+ if (!isRecord6(entry))
17567
+ continue;
17568
+ if (entry.type === "title") {
17569
+ nativeTitle = sessionImportTitle(entry.title);
17570
+ continue;
17571
+ }
17572
+ if (entry.type === "session") {
17573
+ if (header)
17574
+ return null;
17575
+ if (typeof entry.id !== "string" || entry.id.length === 0 || typeof entry.cwd !== "string" || !path4.isAbsolute(entry.cwd))
17576
+ return null;
17577
+ header = { id: entry.id, cwd: entry.cwd };
17578
+ continue;
17579
+ }
17580
+ if (typeof entry.id !== "string" || entry.id.length === 0)
17581
+ continue;
17582
+ const message3 = isRecord6(entry.message) ? entry.message : null;
17583
+ const isUser = entry.type === "message" && message3?.role === "user";
17584
+ if (isUser)
17585
+ firstPrompt ??= sessionImportTitle(messageText(message3?.content));
17586
+ leafHasUser = isUser || typeof entry.parentId === "string" && hasUserAncestry.get(entry.parentId) === true;
17587
+ hasUserAncestry.set(entry.id, leafHasUser);
17588
+ if (entry.type === "message" && (message3?.role === "user" || message3?.role === "assistant")) {
17589
+ const time3 = typeof message3.timestamp === "number" ? message3.timestamp : typeof entry.timestamp === "string" ? Date.parse(entry.timestamp) : Number.NaN;
17590
+ if (Number.isFinite(time3) && time3 >= 0)
17591
+ updatedAt = time3;
17592
+ }
17266
17593
  }
17267
- if (numericX !== numericY)
17268
- return numericX;
17269
- return y > x;
17594
+ } finally {
17595
+ lines.close();
17596
+ stream.destroy();
17270
17597
  }
17271
- return false;
17272
- }
17273
- function createInstallationManager(options) {
17274
- let checking;
17275
- let updating;
17276
- const check2 = () => checking ??= options.check().finally(() => {
17277
- checking = void 0;
17598
+ if (!header || !leafHasUser)
17599
+ return null;
17600
+ return {
17601
+ nativeSessionId: header.id,
17602
+ cwd: header.cwd,
17603
+ title: nativeTitle ?? firstPrompt,
17604
+ updatedAt
17605
+ };
17606
+ }
17607
+ var OmpSessionImport = class {
17608
+ #location;
17609
+ #scope = new SessionImportScope({
17610
+ closedMessage: "Omp Session import is closed",
17611
+ unavailableMessage: "Omp sessions could not be read; close native clients, check storage access and retry",
17612
+ notFoundMessage: "Omp Session is no longer importable"
17278
17613
  });
17279
- return (action) => {
17280
- if (updating)
17281
- return updating;
17282
- if (action === "check")
17283
- return check2();
17284
- updating = (async () => {
17285
- const before = await check2();
17286
- if (!before.updateAvailable)
17287
- return before;
17288
- if (!before.canUpdate)
17289
- throw new Error(before.message ?? "This installation cannot be updated automatically");
17290
- await options.update(before);
17291
- const after = await check2();
17292
- if (after.currentVersion === before.currentVersion)
17293
- throw new Error("The Harness version did not change; check the native updater and retry");
17294
- return after;
17295
- })().finally(() => {
17296
- updating = void 0;
17614
+ constructor(environment) {
17615
+ this.#location = ompSessionImportDirectory(environment);
17616
+ }
17617
+ listCandidates() {
17618
+ return this.#scope.read(async (signal) => [...(await this.#sources(signal)).values()].flatMap((sources) => (
17619
+ // One identity in two files cannot be resumed unambiguously.
17620
+ sources.length === 1 && sources[0] ? [sources[0].candidate] : []
17621
+ )));
17622
+ }
17623
+ resolveCandidate(nativeSessionId) {
17624
+ return this.#scope.resolve(async (signal) => {
17625
+ const sources = (await this.#sources(signal)).get(nativeSessionId);
17626
+ if (sources?.length !== 1 || !sources[0])
17627
+ return null;
17628
+ const source = await this.#source(sources[0].file, signal);
17629
+ return source?.nativeRef.nativeSessionId === nativeSessionId ? { candidate: source.candidate, nativeRef: source.nativeRef } : null;
17297
17630
  });
17298
- return updating;
17299
- };
17631
+ }
17632
+ close() {
17633
+ return this.#scope.close();
17634
+ }
17635
+ async #sessionFiles(signal) {
17636
+ const { directory, flat } = this.#location;
17637
+ const info = await optionalLstat(directory);
17638
+ if (!info)
17639
+ return [];
17640
+ if (!info.isDirectory())
17641
+ throw new Error("Omp Session store is not a directory");
17642
+ const files = [];
17643
+ const visit = async (current, projectLevel) => {
17644
+ const entries = await opendir(current).catch((error51) => {
17645
+ if (isMissingFileError(error51))
17646
+ return null;
17647
+ throw error51;
17648
+ });
17649
+ if (!entries)
17650
+ return;
17651
+ for await (const entry of entries) {
17652
+ signal.throwIfAborted();
17653
+ if (projectLevel && entry.isDirectory())
17654
+ await visit(path4.join(current, entry.name), false);
17655
+ else if (!projectLevel && entry.isFile() && entry.name.endsWith(".jsonl"))
17656
+ files.push(path4.join(current, entry.name));
17657
+ }
17658
+ };
17659
+ await visit(directory, !flat);
17660
+ return files;
17661
+ }
17662
+ /** Session ID to every readable file claiming it. Files changing under the read are skipped. */
17663
+ async #sources(signal) {
17664
+ const found = /* @__PURE__ */ new Map();
17665
+ for (const file2 of await this.#sessionFiles(signal)) {
17666
+ signal.throwIfAborted();
17667
+ try {
17668
+ const source = await this.#source(file2, signal);
17669
+ if (!source)
17670
+ continue;
17671
+ const sources = found.get(source.nativeRef.nativeSessionId) ?? [];
17672
+ sources.push(source);
17673
+ found.set(source.nativeRef.nativeSessionId, sources);
17674
+ } catch (error51) {
17675
+ if (!(error51 instanceof SessionImportChangedError))
17676
+ throw error51;
17677
+ }
17678
+ }
17679
+ return found;
17680
+ }
17681
+ async #source(file2, signal) {
17682
+ signal.throwIfAborted();
17683
+ return readStableFiles([file2], async ([info]) => {
17684
+ if (!info?.isFile() || info.size === 0)
17685
+ return null;
17686
+ try {
17687
+ const facts = await readFacts(file2, signal);
17688
+ if (!facts)
17689
+ return null;
17690
+ const cwd = await realpath2(facts.cwd);
17691
+ if (!(await stat(cwd)).isDirectory())
17692
+ return null;
17693
+ const candidate = sessionImportCandidate({
17694
+ nativeSessionId: facts.nativeSessionId,
17695
+ cwd,
17696
+ title: facts.title,
17697
+ updatedAt: facts.updatedAt ?? info.mtimeMs
17698
+ // OMP has no cross-process activity marker: idleness cannot be established.
17699
+ });
17700
+ if (!candidate)
17701
+ return null;
17702
+ return {
17703
+ file: file2,
17704
+ candidate,
17705
+ // Resume needs the file itself: OMP is started with `--session <file>`.
17706
+ nativeRef: nativeSessionRefSchema.parse({
17707
+ harnessId: "omp",
17708
+ nativeSessionId: facts.nativeSessionId,
17709
+ locator: { sessionFile: await realpath2(file2) },
17710
+ formatVersion: 1
17711
+ })
17712
+ };
17713
+ } catch (error51) {
17714
+ signal.throwIfAborted();
17715
+ if (isStorageAccessError(error51))
17716
+ throw error51;
17717
+ return null;
17718
+ }
17719
+ });
17720
+ }
17721
+ };
17722
+
17723
+ // dist/omp-last-turn-rollback.js
17724
+ function modelFromState(state) {
17725
+ if (state.provider === null && state.modelId === null)
17726
+ return null;
17727
+ if (state.provider === null || state.modelId === null) {
17728
+ throw new Error("Omp state contains a partial Model identity");
17729
+ }
17730
+ return { provider: state.provider, id: state.modelId };
17300
17731
  }
17732
+ async function rollbackOmpLastTurn(transport, sourceSessionId, cwd) {
17733
+ const startupState = transport.state;
17734
+ const startupSessionId = startupState.sessionId;
17735
+ const currentModel = modelFromState(startupState);
17736
+ const currentThinking = startupState.thinkingLevel;
17737
+ const copiedHistory = await transport.getEntries();
17738
+ const boundary = resolveOmpLastTurnBoundary(copiedHistory);
17739
+ if (!boundary)
17740
+ return { ok: false, reason: "empty" };
17741
+ const sourceSnapshot = mapOmpSnapshot(copiedHistory, {
17742
+ sessionId: startupSessionId,
17743
+ model: currentModel
17744
+ });
17745
+ let state = await transport.fork(boundary.lastUserEntryId);
17746
+ if (state.sessionId === sourceSessionId || state.sessionId === startupSessionId) {
17747
+ throw new Error("Omp last-Turn rollback did not create a distinct Native Session");
17748
+ }
17749
+ if (!sameOmpModel(modelFromState(state), currentModel)) {
17750
+ if (!currentModel)
17751
+ throw new Error("Omp last-Turn rollback changed the current Model");
17752
+ state = await transport.selectModel(currentModel);
17753
+ }
17754
+ if (state.thinkingLevel !== currentThinking) {
17755
+ if (!currentThinking)
17756
+ throw new Error("Omp last-Turn rollback changed current Thinking");
17757
+ state = await transport.selectThinkingOption(currentThinking);
17758
+ }
17759
+ if (!sameOmpModel(modelFromState(state), currentModel) || state.thinkingLevel !== currentThinking) {
17760
+ throw new Error("Omp last-Turn rollback could not restore current Model and Thinking");
17761
+ }
17762
+ const snapshot = mapOmpSnapshot(await transport.getEntries(), {
17763
+ sessionId: state.sessionId,
17764
+ model: modelFromState(state)
17765
+ });
17766
+ const expectedTurnKeys = sourceSnapshot.turns.slice(0, -1).map((turn) => turn.nativeTurnRef.nativeTurnKey);
17767
+ const actualTurnKeys = snapshot.turns.map((turn) => turn.nativeTurnRef.nativeTurnKey);
17768
+ if (snapshot.turns.length !== boundary.sourceTurnCount - 1 || actualTurnKeys.some((key, index) => key !== expectedTurnKeys[index])) {
17769
+ throw new Error("Omp last-Turn rollback did not produce the exact retained history prefix");
17770
+ }
17771
+ await transport.verifySessionCwd(cwd);
17772
+ return { ok: true };
17773
+ }
17774
+
17775
+ // dist/omp-rpc-session.js
17776
+ import { spawn, spawnSync } from "node:child_process";
17777
+ import { randomUUID } from "node:crypto";
17778
+ import path5 from "node:path";
17301
17779
 
17302
17780
  // dist/command.js
17303
17781
  var ompDiscoverySpec = {
@@ -17326,14 +17804,14 @@ function resolveOmpExecutable(input, dependencies = {}) {
17326
17804
  }
17327
17805
 
17328
17806
  // dist/omp-usage.js
17329
- function isRecord6(value) {
17807
+ function isRecord7(value) {
17330
17808
  return typeof value === "object" && value !== null && !Array.isArray(value);
17331
17809
  }
17332
17810
  function nonNegativeSafeInteger(value) {
17333
17811
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : null;
17334
17812
  }
17335
17813
  function optionalOmpCacheHitRatePercent(value) {
17336
- if (!isRecord6(value) || value.role !== "assistant" || !isRecord6(value.usage))
17814
+ if (!isRecord7(value) || value.role !== "assistant" || !isRecord7(value.usage))
17337
17815
  return null;
17338
17816
  const input = nonNegativeSafeInteger(value.usage.input);
17339
17817
  const cacheRead = nonNegativeSafeInteger(value.usage.cacheRead);
@@ -17346,20 +17824,20 @@ function optionalOmpCacheHitRatePercent(value) {
17346
17824
  function latestOmpCacheHitRatePercent(history) {
17347
17825
  let latest = null;
17348
17826
  for (const entry of activeOmpEntries(history)) {
17349
- if (entry.type === "message" && isRecord6(entry.message) && entry.message.role === "assistant") {
17827
+ if (entry.type === "message" && isRecord7(entry.message) && entry.message.role === "assistant") {
17350
17828
  latest = optionalOmpCacheHitRatePercent(entry.message);
17351
17829
  }
17352
17830
  }
17353
17831
  return latest;
17354
17832
  }
17355
17833
  function responseData(response, operation) {
17356
- if (!isRecord6(response.data)) {
17834
+ if (!isRecord7(response.data)) {
17357
17835
  throw new Error(`Omp RPC ${operation} response has no data`);
17358
17836
  }
17359
17837
  return response.data;
17360
17838
  }
17361
17839
  function contextUsage(value) {
17362
- if (!isRecord6(value))
17840
+ if (!isRecord7(value))
17363
17841
  throw new Error("Omp RPC context Usage is invalid");
17364
17842
  return parseHostUsage({
17365
17843
  contextUsedTokens: value.tokens,
@@ -17369,15 +17847,15 @@ function contextUsage(value) {
17369
17847
  function parseOmpSessionUsage(response) {
17370
17848
  const data = responseData(response, "Session stats");
17371
17849
  const tokens = data.tokens;
17372
- if (tokens !== void 0 && !isRecord6(tokens)) {
17850
+ if (tokens !== void 0 && !isRecord7(tokens)) {
17373
17851
  throw new Error("Omp RPC Session stats tokens are invalid");
17374
17852
  }
17375
17853
  return parseHostUsage({
17376
- ...isRecord6(tokens) && tokens.input !== void 0 ? { inputTokens: tokens.input } : {},
17377
- ...isRecord6(tokens) && tokens.cacheRead !== void 0 ? { cachedInputTokens: tokens.cacheRead } : {},
17378
- ...isRecord6(tokens) && tokens.cacheWrite !== void 0 ? { cacheWriteInputTokens: tokens.cacheWrite } : {},
17379
- ...isRecord6(tokens) && tokens.output !== void 0 ? { outputTokens: tokens.output } : {},
17380
- ...isRecord6(tokens) && tokens.total !== void 0 ? { totalTokens: tokens.total } : {},
17854
+ ...isRecord7(tokens) && tokens.input !== void 0 ? { inputTokens: tokens.input } : {},
17855
+ ...isRecord7(tokens) && tokens.cacheRead !== void 0 ? { cachedInputTokens: tokens.cacheRead } : {},
17856
+ ...isRecord7(tokens) && tokens.cacheWrite !== void 0 ? { cacheWriteInputTokens: tokens.cacheWrite } : {},
17857
+ ...isRecord7(tokens) && tokens.output !== void 0 ? { outputTokens: tokens.output } : {},
17858
+ ...isRecord7(tokens) && tokens.total !== void 0 ? { totalTokens: tokens.total } : {},
17381
17859
  ...data.cost !== void 0 ? { totalCostUsd: data.cost } : {},
17382
17860
  ...data.contextUsage !== void 0 ? contextUsage(data.contextUsage) : {}
17383
17861
  });
@@ -17492,7 +17970,7 @@ var OmpRpcUnsupportedCommandError = class extends Error {
17492
17970
  }
17493
17971
  };
17494
17972
  var textDecoder = new TextDecoder("utf-8", { fatal: true });
17495
- function isRecord7(value) {
17973
+ function isRecord8(value) {
17496
17974
  return typeof value === "object" && value !== null && !Array.isArray(value);
17497
17975
  }
17498
17976
  function message2(value) {
@@ -17504,13 +17982,13 @@ function nonBlankString(value) {
17504
17982
  function parseNativeModel(value, context) {
17505
17983
  if (value === null || value === void 0)
17506
17984
  return null;
17507
- if (!isRecord7(value) || !nonBlankString(value.provider) || !nonBlankString(value.id)) {
17985
+ if (!isRecord8(value) || !nonBlankString(value.provider) || !nonBlankString(value.id)) {
17508
17986
  throw new OmpRpcFaultError("protocolError", `Omp RPC returned an invalid ${context} Model`);
17509
17987
  }
17510
17988
  return { provider: value.provider, id: value.id };
17511
17989
  }
17512
17990
  function sessionStateData(response) {
17513
- const data = isRecord7(response.data) ? response.data : null;
17991
+ const data = isRecord8(response.data) ? response.data : null;
17514
17992
  if (!data)
17515
17993
  throw new OmpRpcFaultError("protocolError", "Omp RPC state response has no data");
17516
17994
  return data;
@@ -17525,7 +18003,7 @@ function parseSessionState(response) {
17525
18003
  if (thinkingLevel !== null && !thinkingLevel.success) {
17526
18004
  throw new OmpRpcFaultError("protocolError", "Omp RPC state has an invalid Thinking level");
17527
18005
  }
17528
- const thinking = isRecord7(data.model) && isRecord7(data.model.thinking) ? data.model.thinking : null;
18006
+ const thinking = isRecord8(data.model) && isRecord8(data.model.thinking) ? data.model.thinking : null;
17529
18007
  const availableThinkingLevels = thinking && Array.isArray(thinking.efforts) ? thinking.efforts.flatMap((level) => {
17530
18008
  const parsed = harnessThinkingOptionIdSchema.safeParse(level);
17531
18009
  return parsed.success ? [parsed.data] : [];
@@ -17548,25 +18026,25 @@ function parseSessionStreaming(response) {
17548
18026
  return isStreaming;
17549
18027
  }
17550
18028
  function parseAvailableModels(response) {
17551
- const data = isRecord7(response.data) ? response.data : null;
18029
+ const data = isRecord8(response.data) ? response.data : null;
17552
18030
  if (!data || !Array.isArray(data.models)) {
17553
18031
  throw new OmpRpcFaultError("protocolError", "Omp RPC Model catalog response has no models");
17554
18032
  }
17555
18033
  return data.models.map((model) => {
17556
18034
  const parsed = parseNativeModel(model, "catalog");
17557
- if (!parsed || !isRecord7(model) || typeof model.reasoning !== "boolean") {
18035
+ if (!parsed || !isRecord8(model) || typeof model.reasoning !== "boolean") {
17558
18036
  throw new OmpRpcFaultError("protocolError", "Omp RPC catalog contains a Model without reasoning capability");
17559
18037
  }
17560
18038
  return { ...parsed, reasoning: model.reasoning };
17561
18039
  });
17562
18040
  }
17563
18041
  function parseSubagentMessages(response) {
17564
- const data = isRecord7(response.data) ? response.data : null;
18042
+ const data = isRecord8(response.data) ? response.data : null;
17565
18043
  if (!data || !nonBlankString(data.sessionFile) || !Number.isSafeInteger(data.fromByte) || !Number.isSafeInteger(data.nextByte) || data.fromByte < 0 || data.nextByte < data.fromByte || typeof data.reset !== "boolean" || !Array.isArray(data.entries) || !Array.isArray(data.messages)) {
17566
18044
  throw new OmpRpcFaultError("protocolError", "Omp RPC Subagent transcript response is invalid");
17567
18045
  }
17568
- const entries = data.entries.flatMap((value) => isRecord7(value) ? [value] : []);
17569
- const messages = data.messages.flatMap((value) => isRecord7(value) ? [value] : []);
18046
+ const entries = data.entries.flatMap((value) => isRecord8(value) ? [value] : []);
18047
+ const messages = data.messages.flatMap((value) => isRecord8(value) ? [value] : []);
17570
18048
  if (entries.length !== data.entries.length || messages.length !== data.messages.length) {
17571
18049
  throw new OmpRpcFaultError("protocolError", "Omp RPC Subagent transcript contains invalid data");
17572
18050
  }
@@ -17587,17 +18065,17 @@ function subagentStatus(value) {
17587
18065
  throw new OmpRpcFaultError("protocolError", "Omp RPC Subagent status is invalid");
17588
18066
  }
17589
18067
  function assistantText(value) {
17590
- if (!isRecord7(value) || value.role !== "assistant" || !Array.isArray(value.content))
18068
+ if (!isRecord8(value) || value.role !== "assistant" || !Array.isArray(value.content))
17591
18069
  return null;
17592
- return value.content.filter((content) => isRecord7(content) && content.type === "text" && typeof content.text === "string").map((content) => content.text).join("");
18070
+ return value.content.filter((content) => isRecord8(content) && content.type === "text" && typeof content.text === "string").map((content) => content.text).join("");
17593
18071
  }
17594
18072
  function assistantMessageId(value) {
17595
- if (!isRecord7(value) || value.role !== "assistant")
18073
+ if (!isRecord8(value) || value.role !== "assistant")
17596
18074
  return null;
17597
18075
  return nonBlankString(value.responseId) ? value.responseId : null;
17598
18076
  }
17599
18077
  function extractReasoningText(content) {
17600
- if (!isRecord7(content))
18078
+ if (!isRecord8(content))
17601
18079
  return null;
17602
18080
  const type = String(content.type ?? "");
17603
18081
  if (type === "thinking" || type === "reasoning" || type === "thought") {
@@ -17607,12 +18085,12 @@ function extractReasoningText(content) {
17607
18085
  return null;
17608
18086
  }
17609
18087
  function assistantReasoning(value) {
17610
- if (!isRecord7(value) || value.role !== "assistant" || !Array.isArray(value.content))
18088
+ if (!isRecord8(value) || value.role !== "assistant" || !Array.isArray(value.content))
17611
18089
  return null;
17612
18090
  return value.content.map(extractReasoningText).filter((text) => typeof text === "string").join("");
17613
18091
  }
17614
18092
  function assistantFailure(value) {
17615
- if (!isRecord7(value) || value.role !== "assistant")
18093
+ if (!isRecord8(value) || value.role !== "assistant")
17616
18094
  return void 0;
17617
18095
  if (value.stopReason !== "error" && value.stopReason !== "aborted")
17618
18096
  return null;
@@ -17632,7 +18110,7 @@ function signalProcessTree(child, signal) {
17632
18110
  try {
17633
18111
  process.kill(-child.pid, signal);
17634
18112
  } catch (error51) {
17635
- if (!isRecord7(error51) || error51.code !== "ESRCH")
18113
+ if (!isRecord8(error51) || error51.code !== "ESRCH")
17636
18114
  throw error51;
17637
18115
  }
17638
18116
  }
@@ -17671,7 +18149,7 @@ function ompRpcProcessCommand(options, dependencies = {}) {
17671
18149
  ...modelArguments,
17672
18150
  ...sessionArguments
17673
18151
  ];
17674
- const extension = path4.win32.extname(command).toLowerCase();
18152
+ const extension = path5.win32.extname(command).toLowerCase();
17675
18153
  if (platform !== "win32" || ![".cmd", ".bat"].includes(extension)) {
17676
18154
  return { command, arguments: arguments_, windowsVerbatimArguments: false };
17677
18155
  }
@@ -17714,6 +18192,10 @@ var OmpRpcSession = class {
17714
18192
  #manualCompaction = null;
17715
18193
  #stderrTail = "";
17716
18194
  #frameDecoder = new OmpFrameDecoder();
18195
+ #startupFaultResolve = null;
18196
+ #startupFault = new Promise((resolve) => {
18197
+ this.#startupFaultResolve = resolve;
18198
+ });
17717
18199
  #readyResolve = null;
17718
18200
  #ready = new Promise((resolve) => {
17719
18201
  this.#readyResolve = resolve;
@@ -17770,7 +18252,7 @@ var OmpRpcSession = class {
17770
18252
  this.#stderrTail = sanitizeDiagnosticTail(`${this.#stderrTail}${chunk.toString()}`);
17771
18253
  });
17772
18254
  child.once("error", (error51) => {
17773
- const kind = isRecord7(error51) && error51.code === "ENOENT" ? "notInstalled" : "unavailable";
18255
+ const kind = isRecord8(error51) && error51.code === "ENOENT" ? "notInstalled" : "unavailable";
17774
18256
  this.#fail(new OmpRpcFaultError(kind, `Omp RPC failed to start: ${error51.message}`, this.stderrTail));
17775
18257
  });
17776
18258
  child.once("exit", (code, signal) => {
@@ -17785,10 +18267,20 @@ var OmpRpcSession = class {
17785
18267
  }),
17786
18268
  new Promise((_resolve, reject) => setTimeout(() => reject(new Error("Omp RPC start timed out")), this.#options.commandTimeoutMs))
17787
18269
  ]);
17788
- await Promise.race([
17789
- this.#ready,
17790
- new Promise((_resolve, reject) => setTimeout(() => reject(new Error("Omp RPC ready signal timed out")), this.#options.commandTimeoutMs))
17791
- ]);
18270
+ let readyTimeout;
18271
+ try {
18272
+ await Promise.race([
18273
+ this.#ready,
18274
+ this.#startupFault.then((error51) => {
18275
+ throw error51;
18276
+ }),
18277
+ new Promise((_resolve, reject) => {
18278
+ readyTimeout = setTimeout(() => reject(new Error("Omp RPC ready signal timed out")), this.#options.commandTimeoutMs);
18279
+ })
18280
+ ]);
18281
+ } finally {
18282
+ clearTimeout(readyTimeout);
18283
+ }
17792
18284
  await this.#send("negotiate_protocol", { protocolVersion: 2 }).catch(() => void 0);
17793
18285
  if (this.#options.subscribeSubagentEvents !== false) {
17794
18286
  await this.#send("set_subagent_subscription", { level: "events" }).catch(() => void 0);
@@ -17808,17 +18300,17 @@ var OmpRpcSession = class {
17808
18300
  return await readOmpSessionHistory(this.state.sessionFile);
17809
18301
  }
17810
18302
  const response = await this.#send("get_messages", {});
17811
- const data = isRecord7(response.data) ? response.data : null;
18303
+ const data = isRecord8(response.data) ? response.data : null;
17812
18304
  if (!data || !Array.isArray(data.messages)) {
17813
18305
  throw new OmpRpcFaultError("protocolError", "Omp RPC messages response has no messages");
17814
18306
  }
17815
18307
  let branchEntryIds = null;
17816
18308
  try {
17817
18309
  const branchResponse = await this.#send("get_branch_messages", {});
17818
- const branchData = isRecord7(branchResponse.data) ? branchResponse.data : null;
18310
+ const branchData = isRecord8(branchResponse.data) ? branchResponse.data : null;
17819
18311
  if (branchData && Array.isArray(branchData.messages)) {
17820
18312
  const parsed = branchData.messages.flatMap((entry) => {
17821
- if (!isRecord7(entry) || !nonBlankString(entry.entryId))
18313
+ if (!isRecord8(entry) || !nonBlankString(entry.entryId))
17822
18314
  return [];
17823
18315
  return [entry.entryId];
17824
18316
  });
@@ -17832,11 +18324,11 @@ var OmpRpcSession = class {
17832
18324
  let userIndex = 0;
17833
18325
  let parentId = null;
17834
18326
  const entries = data.messages.map((nativeMessage, index) => {
17835
- const role = isRecord7(nativeMessage) ? nativeMessage.role : void 0;
18327
+ const role = isRecord8(nativeMessage) ? nativeMessage.role : void 0;
17836
18328
  const branchId = role === "user" ? branchEntryIds?.[userIndex] : void 0;
17837
18329
  if (branchId)
17838
18330
  userIndex += 1;
17839
- const id = branchId ?? (isRecord7(nativeMessage) && nonBlankString(nativeMessage.id) ? nativeMessage.id : `omp-message-${index}`);
18331
+ const id = branchId ?? (isRecord8(nativeMessage) && nonBlankString(nativeMessage.id) ? nativeMessage.id : `omp-message-${index}`);
17840
18332
  const entry = { id, parentId, type: "message", message: nativeMessage };
17841
18333
  parentId = id;
17842
18334
  return entry;
@@ -17916,7 +18408,7 @@ var OmpRpcSession = class {
17916
18408
  throw new Error("Omp RPC Fork requires an Entry identity");
17917
18409
  try {
17918
18410
  const response = await this.#send("branch", { entryId });
17919
- const data = isRecord7(response.data) ? response.data : null;
18411
+ const data = isRecord8(response.data) ? response.data : null;
17920
18412
  if (!data || data.cancelled === true) {
17921
18413
  throw new OmpRpcFaultError("unavailable", "Omp RPC Fork was cancelled");
17922
18414
  }
@@ -18109,7 +18601,7 @@ var OmpRpcSession = class {
18109
18601
  continue;
18110
18602
  }
18111
18603
  const value = decoded;
18112
- if (!isRecord7(value) || typeof value.type !== "string") {
18604
+ if (!isRecord8(value) || typeof value.type !== "string") {
18113
18605
  throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid envelope");
18114
18606
  }
18115
18607
  this.#handle(value);
@@ -18168,7 +18660,7 @@ var OmpRpcSession = class {
18168
18660
  this.#armCommandTimeout(id, pending);
18169
18661
  }
18170
18662
  }
18171
- const outcome = value.aborted === true ? "cancelled" : isRecord7(value.result) ? "succeeded" : "failed";
18663
+ const outcome = value.aborted === true ? "cancelled" : isRecord8(value.result) ? "succeeded" : "failed";
18172
18664
  const event = {
18173
18665
  type: "compaction.completed",
18174
18666
  outcome,
@@ -18201,12 +18693,12 @@ var OmpRpcSession = class {
18201
18693
  this.#startAssistantMessage(active, value.message);
18202
18694
  return;
18203
18695
  }
18204
- if (value.type === "message_update" && isRecord7(value.assistantMessageEvent)) {
18696
+ if (value.type === "message_update" && isRecord8(value.assistantMessageEvent)) {
18205
18697
  const event = value.assistantMessageEvent;
18206
18698
  const eventType = String(event.type ?? "");
18207
18699
  const isThinking = eventType === "thinking_delta" || eventType === "reasoning_delta" || eventType === "thought_delta" || eventType === "thinking" || eventType === "reasoning";
18208
18700
  const isText = eventType === "text_delta" || eventType === "text" || eventType === "content_block_delta";
18209
- const delta = typeof event.delta === "string" ? event.delta : typeof event.thinking === "string" ? event.thinking : typeof event.reasoning === "string" ? event.reasoning : typeof event.text === "string" ? event.text : isRecord7(event.delta) && typeof event.delta.thinking === "string" ? event.delta.thinking : isRecord7(event.delta) && typeof event.delta.text === "string" ? event.delta.text : null;
18701
+ const delta = typeof event.delta === "string" ? event.delta : typeof event.thinking === "string" ? event.thinking : typeof event.reasoning === "string" ? event.reasoning : typeof event.text === "string" ? event.text : isRecord8(event.delta) && typeof event.delta.thinking === "string" ? event.delta.thinking : isRecord8(event.delta) && typeof event.delta.text === "string" ? event.delta.text : null;
18210
18702
  if (isThinking && delta !== null && delta.length > 0) {
18211
18703
  const messageId = this.#ensureAssistantMessage(active, value.message);
18212
18704
  active.reasoningMessageOpen = true;
@@ -18246,7 +18738,7 @@ var OmpRpcSession = class {
18246
18738
  if (value.type === "agent_end" && Array.isArray(value.messages)) {
18247
18739
  for (let index = value.messages.length - 1; index >= 0; index -= 1) {
18248
18740
  const message3 = value.messages[index];
18249
- if (!isRecord7(message3) || message3.role !== "assistant")
18741
+ if (!isRecord8(message3) || message3.role !== "assistant")
18250
18742
  continue;
18251
18743
  this.#finalizeAssistantMessage(active, message3);
18252
18744
  break;
@@ -18263,8 +18755,8 @@ var OmpRpcSession = class {
18263
18755
  if (value.type !== "subagent_lifecycle" && value.type !== "subagent_progress" && value.type !== "subagent_event") {
18264
18756
  return false;
18265
18757
  }
18266
- const payload = isRecord7(value.payload) ? value.payload : null;
18267
- const progressPayload = value.type === "subagent_progress" && payload && isRecord7(payload.progress) ? payload.progress : null;
18758
+ const payload = isRecord8(value.payload) ? value.payload : null;
18759
+ const progressPayload = value.type === "subagent_progress" && payload && isRecord8(payload.progress) ? payload.progress : null;
18268
18760
  const nativeIdValue = progressPayload?.id ?? payload?.id;
18269
18761
  if (!payload || !nonBlankString(nativeIdValue)) {
18270
18762
  throw new OmpRpcFaultError("protocolError", "Omp RPC Subagent frame has no stable ID");
@@ -18681,6 +19173,8 @@ var OmpRpcSession = class {
18681
19173
  if (this.#closed || this.#failed)
18682
19174
  return;
18683
19175
  this.#failed = true;
19176
+ this.#startupFaultResolve?.(error51);
19177
+ this.#startupFaultResolve = null;
18684
19178
  this.#rejectAll(error51);
18685
19179
  this.#options.onFault?.(error51);
18686
19180
  }
@@ -18841,7 +19335,7 @@ var ompCommandCatalog = harnessCommandCatalogSchema.parse({
18841
19335
  ]
18842
19336
  });
18843
19337
  var DEFAULT_TOOL_OUTPUT_LIMIT = 64e3;
18844
- function isRecord8(value) {
19338
+ function isRecord9(value) {
18845
19339
  return typeof value === "object" && value !== null && !Array.isArray(value);
18846
19340
  }
18847
19341
  function errorMessage(error51) {
@@ -18856,7 +19350,7 @@ var OmpAdapterFaultError = class extends Error {
18856
19350
  }
18857
19351
  };
18858
19352
  function normalizedError(error51, fallbackCode) {
18859
- if (isRecord8(error51) && error51.code === "ENOENT") {
19353
+ if (isRecord9(error51) && error51.code === "ENOENT") {
18860
19354
  return { code: "notInstalled", message: errorMessage(error51), retryable: false };
18861
19355
  }
18862
19356
  if (error51 instanceof OmpAdapterFaultError)
@@ -18933,7 +19427,7 @@ function nativeModelForHistory(state) {
18933
19427
  return nativeModelFromState(state);
18934
19428
  }
18935
19429
  function sessionFileFromRef(ref) {
18936
- if (ref.harnessId !== ompHarnessId2 || !isRecord8(ref.locator) || typeof ref.locator.sessionFile !== "string" || ref.locator.sessionFile.length === 0) {
19430
+ if (ref.harnessId !== ompHarnessId2 || !isRecord9(ref.locator) || typeof ref.locator.sessionFile !== "string" || ref.locator.sessionFile.length === 0) {
18937
19431
  throw new Error("Omp Native Session Ref has no resumable Session file");
18938
19432
  }
18939
19433
  return ref.locator.sessionFile;
@@ -18943,7 +19437,7 @@ function subagentTranscriptPath(parentSessionFile, nativeSubagentId) {
18943
19437
  if (nativeSubagentId.includes("/") || nativeSubagentId.includes("\\") || nativeSubagentId.includes("\0") || nativeSubagentId === "." || nativeSubagentId === "..") {
18944
19438
  throw new Error("Omp Subagent ID is not a plain transcript file name");
18945
19439
  }
18946
- if (!parentSessionFile.endsWith(".jsonl") || !path5.isAbsolute(parentSessionFile)) {
19440
+ if (!parentSessionFile.endsWith(".jsonl") || !path6.isAbsolute(parentSessionFile)) {
18947
19441
  return null;
18948
19442
  }
18949
19443
  return `${parentSessionFile.slice(0, -".jsonl".length)}/${nativeSubagentId}.jsonl`;
@@ -18952,10 +19446,10 @@ async function readSubagentTranscriptFile(parentSessionFile, nativeSubagentId) {
18952
19446
  const transcriptFile = subagentTranscriptPath(parentSessionFile, nativeSubagentId);
18953
19447
  if (transcriptFile === null)
18954
19448
  return { status: "missing" };
18955
- const parentDirectory = path5.dirname(transcriptFile);
19449
+ const parentDirectory = path6.dirname(transcriptFile);
18956
19450
  let metadata;
18957
19451
  try {
18958
- metadata = await stat(transcriptFile);
19452
+ metadata = await stat2(transcriptFile);
18959
19453
  } catch (error51) {
18960
19454
  if (error51.code === "ENOENT")
18961
19455
  return { status: "missing" };
@@ -18967,10 +19461,10 @@ async function readSubagentTranscriptFile(parentSessionFile, nativeSubagentId) {
18967
19461
  throw new Error("Omp Subagent transcript exceeds the supported size");
18968
19462
  }
18969
19463
  const [resolvedTranscript, resolvedParentDirectory] = await Promise.all([
18970
- realpath2(transcriptFile),
18971
- realpath2(parentDirectory)
19464
+ realpath3(transcriptFile),
19465
+ realpath3(parentDirectory)
18972
19466
  ]);
18973
- if (path5.dirname(resolvedTranscript) !== resolvedParentDirectory) {
19467
+ if (path6.dirname(resolvedTranscript) !== resolvedParentDirectory) {
18974
19468
  throw new Error("Omp Subagent transcript resolves outside its parent Session directory");
18975
19469
  }
18976
19470
  return {
@@ -18988,9 +19482,9 @@ function toolFailure(toolName) {
18988
19482
  function nativeText(value) {
18989
19483
  if (typeof value === "string")
18990
19484
  return value;
18991
- if (!isRecord8(value) || !Array.isArray(value.content))
19485
+ if (!isRecord9(value) || !Array.isArray(value.content))
18992
19486
  return "";
18993
- return value.content.filter((content) => isRecord8(content) && content.type === "text" && typeof content.text === "string").map(({ text }) => text).join("");
19487
+ return value.content.filter((content) => isRecord9(content) && content.type === "text" && typeof content.text === "string").map(({ text }) => text).join("");
18994
19488
  }
18995
19489
  function boundedOutput(value, limit) {
18996
19490
  const text = nativeText(value);
@@ -19006,17 +19500,17 @@ function outputText(output) {
19006
19500
  return output?.content.filter((content) => content.type === "text").map(({ text }) => text).join("") ?? "";
19007
19501
  }
19008
19502
  function stringField2(value, key) {
19009
- if (!isRecord8(value))
19503
+ if (!isRecord9(value))
19010
19504
  return void 0;
19011
19505
  const field = value[key];
19012
19506
  if (typeof field === "string" && field.length > 0)
19013
19507
  return field;
19014
- if (isRecord8(value.input)) {
19508
+ if (isRecord9(value.input)) {
19015
19509
  const nested = value.input[key];
19016
19510
  if (typeof nested === "string" && nested.length > 0)
19017
19511
  return nested;
19018
19512
  }
19019
- if (isRecord8(value.arguments)) {
19513
+ if (isRecord9(value.arguments)) {
19020
19514
  const nested = value.arguments[key];
19021
19515
  if (typeof nested === "string" && nested.length > 0)
19022
19516
  return nested;
@@ -19024,7 +19518,7 @@ function stringField2(value, key) {
19024
19518
  return void 0;
19025
19519
  }
19026
19520
  function numberField(value, key) {
19027
- if (!isRecord8(value))
19521
+ if (!isRecord9(value))
19028
19522
  return void 0;
19029
19523
  const field = value[key];
19030
19524
  return typeof field === "number" || field === null ? field : void 0;
@@ -19035,10 +19529,10 @@ function stripDiffPrefix(pathString) {
19035
19529
  return pathString.startsWith("a/") || pathString.startsWith("b/") ? pathString.slice(2) : pathString;
19036
19530
  }
19037
19531
  function displayPath(nativePath, cwd) {
19038
- const resolvedCwd = path5.resolve(cwd);
19039
- const resolvedPath = path5.isAbsolute(nativePath) ? path5.resolve(nativePath) : path5.resolve(cwd, nativePath);
19040
- const relative = path5.relative(resolvedCwd, resolvedPath);
19041
- const inside = relative.length > 0 && relative !== ".." && !relative.startsWith(`..${path5.sep}`);
19532
+ const resolvedCwd = path6.resolve(cwd);
19533
+ const resolvedPath = path6.isAbsolute(nativePath) ? path6.resolve(nativePath) : path6.resolve(cwd, nativePath);
19534
+ const relative = path6.relative(resolvedCwd, resolvedPath);
19535
+ const inside = relative.length > 0 && relative !== ".." && !relative.startsWith(`..${path6.sep}`);
19042
19536
  const selected = inside ? relative : resolvedPath;
19043
19537
  const normalized = selected.replaceAll("\\", "/");
19044
19538
  if (normalized.length === 0 || normalized === ".")
@@ -19063,7 +19557,7 @@ function fileMutatingKind(toolName) {
19063
19557
  return null;
19064
19558
  }
19065
19559
  function nestedToolString(value, keys) {
19066
- if (!isRecord8(value))
19560
+ if (!isRecord9(value))
19067
19561
  return void 0;
19068
19562
  for (const key of keys) {
19069
19563
  const field = value[key];
@@ -19078,14 +19572,14 @@ function nestedToolString(value, keys) {
19078
19572
  return void 0;
19079
19573
  }
19080
19574
  function patchFromResult(result) {
19081
- if (!isRecord8(result))
19575
+ if (!isRecord9(result))
19082
19576
  return void 0;
19083
19577
  for (const key of ["patch", "diff", "unifiedDiff"]) {
19084
19578
  const field = result[key];
19085
19579
  if (typeof field === "string" && field.length > 0)
19086
19580
  return field;
19087
19581
  }
19088
- if (isRecord8(result.details)) {
19582
+ if (isRecord9(result.details)) {
19089
19583
  for (const key of ["patch", "diff", "unifiedDiff"]) {
19090
19584
  const field = result.details[key];
19091
19585
  if (typeof field === "string" && field.length > 0)
@@ -20567,6 +21061,7 @@ var OmpAdapter = class {
20567
21061
  commandCatalog = ompCommandCatalog;
20568
21062
  liveCommandCatalog = true;
20569
21063
  harnessId = ompHarnessId2;
21064
+ sessionImport;
20570
21065
  subagents = {
20571
21066
  readSnapshot: async (input) => {
20572
21067
  if (input.parent.harnessId !== this.harnessId || input.nativeSubagentId.trim().length === 0 || input.cwd.length === 0) {
@@ -20626,6 +21121,7 @@ var OmpAdapter = class {
20626
21121
  createTransport: (sessionOptions) => new OmpRpcSession({ ...options, ...sessionOptions })
20627
21122
  }) {
20628
21123
  this.#createTransport = dependencies.createTransport;
21124
+ this.sessionImport = new OmpSessionImport({ ...process.env, ...options.environment });
20629
21125
  this.#closeTimeoutMs = options.closeTimeoutMs ?? 2e3;
20630
21126
  this.#toolOutputLimit = options.toolOutputLimit ?? DEFAULT_TOOL_OUTPUT_LIMIT;
20631
21127
  }
@@ -20697,7 +21193,11 @@ var OmpAdapter = class {
20697
21193
  };
20698
21194
  } catch (error51) {
20699
21195
  await transport.close().catch(() => void 0);
20700
- const normalized = normalizedError(error51, "unavailable");
21196
+ const normalized = stage === "startup" && /No models available\.\s*Use \/login or set an API key environment variable\./i.test(transport.stderrTail ?? "") ? {
21197
+ code: "configurationRequired",
21198
+ message: "No models are configured for use in Oh My Pi. Configure a Provider and its API key or models.yml, then run `omp` and use `/model` to select a model. For Providers that support it, `/login` configures Provider authentication, not an Oh My Pi account.",
21199
+ retryable: false
21200
+ } : normalizedError(error51, "unavailable");
20701
21201
  return {
20702
21202
  status: normalized.code === "notInstalled" ? "notInstalled" : "error",
20703
21203
  error: {
@@ -20887,6 +21387,7 @@ var OmpAdapter = class {
20887
21387
  close() {
20888
21388
  if (!this.#closePromise) {
20889
21389
  this.#closePromise = Promise.all([
21390
+ this.sessionImport.close(),
20890
21391
  ...[...this.#inspections].map((transport) => transport.close()),
20891
21392
  ...[...this.#sessions].map((session) => session.close())
20892
21393
  ]).then(() => void 0);
@@ -20896,22 +21397,22 @@ var OmpAdapter = class {
20896
21397
  };
20897
21398
 
20898
21399
  // dist/installation.js
20899
- import { realpath as realpath3 } from "node:fs/promises";
20900
- import path6 from "node:path";
21400
+ import { realpath as realpath4 } from "node:fs/promises";
21401
+ import path7 from "node:path";
20901
21402
  function createOmpInstallation(environment, command) {
20902
21403
  let executable;
20903
21404
  let env;
20904
21405
  return createInstallationManager({
20905
21406
  async check() {
20906
21407
  executable = resolveOmpExecutable({ environment, ...command ? { command } : {} });
20907
- const selected = await realpath3(executable);
21408
+ const selected = await realpath4(executable);
20908
21409
  const pathKey = Object.keys(environment).find((key) => key.toLowerCase() === "path") ?? "PATH";
20909
21410
  env = {
20910
21411
  ...environment,
20911
- [pathKey]: `${path6.dirname(executable)}${path6.delimiter}${environment[pathKey] ?? ""}`
21412
+ [pathKey]: `${path7.dirname(executable)}${path7.delimiter}${environment[pathKey] ?? ""}`
20912
21413
  };
20913
21414
  const target = resolveHarnessExecutable({ id: "omp", command: "omp", installRoots: { posix: [], windows: [] } }, { environment: env });
20914
- const canUpdate = !selected.includes("/nix/store/") && !!target && await realpath3(target.executable) === selected;
21415
+ const canUpdate = !selected.includes("/nix/store/") && !!target && await realpath4(target.executable) === selected;
20915
21416
  const output = await runInstallationCommand(executable, ["update", "--check"], env);
20916
21417
  const currentVersion = versionFromOutput(output);
20917
21418
  const available = output.match(/New version available:\s*(\S+)/i);
@@ -20923,7 +21424,10 @@ function createOmpInstallation(environment, command) {
20923
21424
  latestVersion,
20924
21425
  updateAvailable: newerInstallationVersion(currentVersion, latestVersion),
20925
21426
  canUpdate,
20926
- ...!canUpdate ? { message: "Update this installation with its original package manager or launcher." } : {}
21427
+ ...!canUpdate ? {
21428
+ messageCode: "original-installer",
21429
+ message: "Update this installation with its original package manager or launcher."
21430
+ } : {}
20927
21431
  };
20928
21432
  },
20929
21433
  async update() {
@@ -20939,7 +21443,14 @@ function createHarnessAdapter(context) {
20939
21443
  return Object.assign(new OmpAdapter({
20940
21444
  ...environment[OMP_COMMAND_ENV] ? { command: environment[OMP_COMMAND_ENV] } : {},
20941
21445
  environment
20942
- }), { installation: createOmpInstallation(environment, environment[OMP_COMMAND_ENV]) });
21446
+ }), {
21447
+ installation: createOmpInstallation(environment, environment[OMP_COMMAND_ENV]),
21448
+ install: createHarnessInstaller(environment, {
21449
+ posix: "https://omp.sh/install",
21450
+ windows: "https://omp.sh/install.ps1",
21451
+ shell: "sh"
21452
+ })
21453
+ });
20943
21454
  }
20944
21455
  export {
20945
21456
  OMP_COMMAND_ENV,