@codexhost/cli-linux-arm64 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,488 @@ 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/npm-installation.js
358
+ import { readFile, realpath } from "node:fs/promises";
359
+ import path4 from "node:path";
360
+ function referencesNpmBin(shim, name, bin) {
361
+ if (bin.includes(".."))
362
+ return false;
363
+ const target = `node_modules/${name}/${bin.replace(/^\.\//, "")}`.toLowerCase();
364
+ const text2 = shim.replaceAll("\\", "/").toLowerCase();
365
+ return text2.includes(`%dp0%/${target}"`) || text2.includes(`%~dp0/${target}"`);
366
+ }
367
+ async function npmInstallation(command, packages, environment) {
368
+ let selected = await realpath(command);
369
+ if (process.platform === "win32" && /\.(cmd|bat)$/i.test(selected)) {
370
+ const shim = (await readFile(selected, "utf8")).replaceAll("\\", "/");
371
+ const root = path4.dirname(selected);
372
+ for (const name of packages) {
373
+ const directory2 = path4.join(root, "node_modules", ...name.split("/"));
374
+ const metadata = await readFile(path4.join(directory2, "package.json"), "utf8").then((text2) => JSON.parse(text2)).catch(() => null);
375
+ const bins = typeof metadata?.bin === "string" ? [metadata.bin] : Object.values(metadata?.bin ?? {});
376
+ const bin = bins.find((entry) => referencesNpmBin(shim, name, entry));
377
+ if (bin) {
378
+ selected = await realpath(path4.join(directory2, bin));
379
+ break;
380
+ }
381
+ }
382
+ }
383
+ let directory = path4.dirname(selected);
384
+ for (let depth = 0; depth < 8; depth++) {
385
+ const metadata = await readFile(path4.join(directory, "package.json"), "utf8").then((text2) => JSON.parse(text2)).catch(() => null);
386
+ if (metadata?.name && packages.includes(metadata.name)) {
387
+ const name = metadata.name;
388
+ const currentVersion = installationVersion(metadata.version);
389
+ const segments = name.split("/");
390
+ let modules = directory;
391
+ for (let index = 0; index < segments.length; index++)
392
+ modules = path4.dirname(modules);
393
+ const prefix = process.platform === "win32" ? path4.dirname(modules) : path4.dirname(path4.dirname(modules));
394
+ const globalRoot = process.platform === "win32" ? path4.join(prefix, "node_modules") : path4.join(prefix, "lib", "node_modules");
395
+ const env = withNodeRuntimeOnPath(environment);
396
+ const npm = resolveHarnessExecutable({ id: "npm", command: "npm", installRoots: { posix: [], windows: [] } }, { environment: env });
397
+ let globalInstall = modules === globalRoot;
398
+ if (process.platform === "win32") {
399
+ const project = (await Promise.all(["package.json", "package-lock.json", "npm-shrinkwrap.json"].map((file2) => readFile(path4.join(prefix, file2), "utf8").then(() => true, (error51) => error51.code !== "ENOENT")))).some(Boolean);
400
+ const bins = typeof metadata.bin === "string" ? { [name.split("/").at(-1) ?? name]: metadata.bin } : metadata.bin ?? {};
401
+ const launchers = await Promise.all(Object.entries(bins).map(async ([bin, entry]) => {
402
+ if (path4.basename(bin) !== bin || entry.includes(".."))
403
+ return false;
404
+ const target = await realpath(path4.join(directory, entry)).catch(() => "");
405
+ if (target.toLowerCase() !== selected.toLowerCase())
406
+ return false;
407
+ const shim = await readFile(path4.join(prefix, `${bin}.cmd`), "utf8").catch(() => "");
408
+ return referencesNpmBin(shim, name, entry);
409
+ }));
410
+ globalInstall = globalInstall && !project && launchers.some(Boolean);
411
+ }
412
+ const canUpdate = globalInstall && !!npm;
413
+ return {
414
+ prefix,
415
+ currentVersion,
416
+ canUpdate,
417
+ latest: async () => {
418
+ const data = JSON.parse(await fetchInstallationText(`https://registry.npmjs.org/${encodeURIComponent(name)}/latest`));
419
+ return installationVersion(data.version);
420
+ },
421
+ update: async (version2) => {
422
+ if (!canUpdate || !npm)
423
+ throw new Error("Use the original package manager to update this installation");
424
+ await runInstallationCommand(npm.executable, ["install", "--global", "--prefix", prefix, `${name}@${installationVersion(version2)}`], env, 3e5);
425
+ }
426
+ };
427
+ }
428
+ const parent = path4.dirname(directory);
429
+ if (parent === directory)
430
+ break;
431
+ directory = parent;
432
+ }
433
+ return null;
434
+ }
435
+
436
+ // ../../harness-discovery/dist/installer.js
437
+ import { mkdtemp, rm, writeFile } from "node:fs/promises";
438
+ import { tmpdir } from "node:os";
439
+ import { join } from "node:path";
440
+ function createHarnessInstaller(environment, source) {
441
+ return async () => {
442
+ if (!["darwin", "linux", "win32"].includes(process.platform))
443
+ throw new Error("Unsupported installation platform");
444
+ const env = withNodeRuntimeOnPath(environment);
445
+ if ("npm" in source) {
446
+ const npm = resolveHarnessExecutable({
447
+ id: "npm",
448
+ command: "npm",
449
+ installRoots: {
450
+ posix: [
451
+ "~/.npm-global/bin",
452
+ "~/.local/bin",
453
+ VERSION_MANAGER_ROOTS,
454
+ "/opt/homebrew/bin",
455
+ "/usr/local/bin",
456
+ "/usr/bin"
457
+ ],
458
+ windows: [
459
+ "${APPDATA}/npm",
460
+ VERSION_MANAGER_ROOTS,
461
+ "${ProgramFiles}/nodejs",
462
+ "${LOCALAPPDATA}/Programs/nodejs"
463
+ ]
464
+ }
465
+ }, { environment: env });
466
+ if (!npm)
467
+ throw new Error("Install Node.js and npm first");
468
+ await runInstallationCommand(npm.executable, ["install", "--global", source.npm], {
469
+ ...env,
470
+ ...source.allowScripts ? { npm_config_allow_scripts: source.allowScripts } : {}
471
+ }, 6e5);
472
+ return;
473
+ }
474
+ const windows = process.platform === "win32";
475
+ const url2 = windows ? source.windows : source.posix;
476
+ if (new URL(url2).protocol !== "https:")
477
+ throw new Error("Installer requires HTTPS");
478
+ const script = await fetchInstallationText(url2);
479
+ const directory = await mkdtemp(join(tmpdir(), "codexhost-installer-"));
480
+ try {
481
+ const file2 = join(directory, windows ? "install.ps1" : "install.sh");
482
+ await writeFile(file2, script, { mode: 384 });
483
+ await runInstallationCommand(windows ? "powershell.exe" : source.shell ?? "bash", windows ? ["-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-File", file2] : [file2], env, 6e5);
484
+ } finally {
485
+ await rm(directory, { recursive: true, force: true });
486
+ }
487
+ };
488
+ }
489
+
8
490
  // ../../../node_modules/zod/v4/classic/external.js
9
491
  var external_exports = {};
10
492
  __export(external_exports, {
@@ -771,10 +1253,10 @@ function mergeDefs(...defs) {
771
1253
  function cloneDef(schema) {
772
1254
  return mergeDefs(schema._zod.def);
773
1255
  }
774
- function getElementAtPath(obj, path9) {
775
- if (!path9)
1256
+ function getElementAtPath(obj, path10) {
1257
+ if (!path10)
776
1258
  return obj;
777
- return path9.reduce((acc, key) => acc?.[key], obj);
1259
+ return path10.reduce((acc, key) => acc?.[key], obj);
778
1260
  }
779
1261
  function promiseAllObject(promisesObj) {
780
1262
  const keys = Object.keys(promisesObj);
@@ -1183,11 +1665,11 @@ function explicitlyAborted(x, startIndex = 0) {
1183
1665
  }
1184
1666
  return false;
1185
1667
  }
1186
- function prefixIssues(path9, issues) {
1668
+ function prefixIssues(path10, issues) {
1187
1669
  return issues.map((iss) => {
1188
1670
  var _a3;
1189
1671
  (_a3 = iss).path ?? (_a3.path = []);
1190
- iss.path.unshift(path9);
1672
+ iss.path.unshift(path10);
1191
1673
  return iss;
1192
1674
  });
1193
1675
  }
@@ -1334,16 +1816,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
1334
1816
  }
1335
1817
  function formatError(error51, mapper = (issue2) => issue2.message) {
1336
1818
  const fieldErrors = { _errors: [] };
1337
- const processError = (error52, path9 = []) => {
1819
+ const processError = (error52, path10 = []) => {
1338
1820
  for (const issue2 of error52.issues) {
1339
1821
  if (issue2.code === "invalid_union" && issue2.errors.length) {
1340
- issue2.errors.map((issues) => processError({ issues }, [...path9, ...issue2.path]));
1822
+ issue2.errors.map((issues) => processError({ issues }, [...path10, ...issue2.path]));
1341
1823
  } else if (issue2.code === "invalid_key") {
1342
- processError({ issues: issue2.issues }, [...path9, ...issue2.path]);
1824
+ processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
1343
1825
  } else if (issue2.code === "invalid_element") {
1344
- processError({ issues: issue2.issues }, [...path9, ...issue2.path]);
1826
+ processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
1345
1827
  } else {
1346
- const fullpath = [...path9, ...issue2.path];
1828
+ const fullpath = [...path10, ...issue2.path];
1347
1829
  if (fullpath.length === 0) {
1348
1830
  fieldErrors._errors.push(mapper(issue2));
1349
1831
  } else {
@@ -1370,17 +1852,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
1370
1852
  }
1371
1853
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
1372
1854
  const result = { errors: [] };
1373
- const processError = (error52, path9 = []) => {
1855
+ const processError = (error52, path10 = []) => {
1374
1856
  var _a3, _b;
1375
1857
  for (const issue2 of error52.issues) {
1376
1858
  if (issue2.code === "invalid_union" && issue2.errors.length) {
1377
- issue2.errors.map((issues) => processError({ issues }, [...path9, ...issue2.path]));
1859
+ issue2.errors.map((issues) => processError({ issues }, [...path10, ...issue2.path]));
1378
1860
  } else if (issue2.code === "invalid_key") {
1379
- processError({ issues: issue2.issues }, [...path9, ...issue2.path]);
1861
+ processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
1380
1862
  } else if (issue2.code === "invalid_element") {
1381
- processError({ issues: issue2.issues }, [...path9, ...issue2.path]);
1863
+ processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
1382
1864
  } else {
1383
- const fullpath = [...path9, ...issue2.path];
1865
+ const fullpath = [...path10, ...issue2.path];
1384
1866
  if (fullpath.length === 0) {
1385
1867
  result.errors.push(mapper(issue2));
1386
1868
  continue;
@@ -1412,8 +1894,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
1412
1894
  }
1413
1895
  function toDotPath(_path) {
1414
1896
  const segs = [];
1415
- const path9 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1416
- for (const seg of path9) {
1897
+ const path10 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1898
+ for (const seg of path10) {
1417
1899
  if (typeof seg === "number")
1418
1900
  segs.push(`[${seg}]`);
1419
1901
  else if (typeof seg === "symbol")
@@ -14105,13 +14587,13 @@ function resolveRef(ref, ctx) {
14105
14587
  if (!ref.startsWith("#")) {
14106
14588
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
14107
14589
  }
14108
- const path9 = ref.slice(1).split("/").filter(Boolean);
14109
- if (path9.length === 0) {
14590
+ const path10 = ref.slice(1).split("/").filter(Boolean);
14591
+ if (path10.length === 0) {
14110
14592
  return ctx.rootSchema;
14111
14593
  }
14112
14594
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
14113
- if (path9[0] === defsKey) {
14114
- const key = path9[1];
14595
+ if (path10[0] === defsKey) {
14596
+ const key = path10[1];
14115
14597
  if (!key || !ctx.defs[key]) {
14116
14598
  throw new Error(`Reference not found: ${ref}`);
14117
14599
  }
@@ -14589,6 +15071,20 @@ var harnessDisplaySetSchema = external_exports.strictObject({
14589
15071
  initializeOnly: external_exports.boolean().optional()
14590
15072
  });
14591
15073
 
15074
+ // ../../shared-contracts/dist/ids.js
15075
+ var opaqueIdSchema = external_exports.string().refine((value) => value.trim().length > 0, {
15076
+ message: "Identifier must not be empty or whitespace"
15077
+ });
15078
+ var harnessIdSchema = opaqueIdSchema.brand();
15079
+ var hostThreadIdSchema = opaqueIdSchema.brand();
15080
+ var hostTurnIdSchema = opaqueIdSchema.brand();
15081
+ var hostItemIdSchema = opaqueIdSchema.brand();
15082
+ var hostInteractionIdSchema = opaqueIdSchema.brand();
15083
+
15084
+ // ../../shared-contracts/dist/thread-prewarm.js
15085
+ var threadPrewarmDiscardParamsSchema = external_exports.object({ threadId: hostThreadIdSchema });
15086
+ var threadPrewarmDiscardResultSchema = external_exports.object({ discarded: external_exports.boolean() });
15087
+
14592
15088
  // ../../shared-contracts/dist/console.js
14593
15089
  var consoleAnnouncementSchema = external_exports.strictObject({
14594
15090
  title: external_exports.string().trim().min(1).max(200),
@@ -14601,10 +15097,14 @@ var consoleOpenResultSchema = external_exports.strictObject({
14601
15097
  url: external_exports.string().max(2048).regex(/^http:\/\/(?:127\.0\.0\.1|localhost):\d{1,5}\/(?:\?.*)?$/u)
14602
15098
  });
14603
15099
  var CONSOLE_HOST_METHODS = Object.freeze([
15100
+ "codexhost/console/remote-connections",
15101
+ "codexhost/runtime/status",
15102
+ "codexhost/remote/ssh-setup",
14604
15103
  "codexhost/harness/plugins/list",
14605
15104
  "codexhost/harness/display-settings/get",
14606
15105
  "codexhost/harness/display-settings/set",
14607
15106
  "codexhost/harness/inspect",
15107
+ "codexhost/harness/installation",
14608
15108
  "codexhost/harness/launch-settings/get",
14609
15109
  "codexhost/harness/launch-settings/set",
14610
15110
  "codexhost/harness/web-ui/open",
@@ -14659,22 +15159,12 @@ var loadedSessionReasonSchema = external_exports.enum([
14659
15159
  ]);
14660
15160
  var loadedSessionsSchema = external_exports.array(external_exports.strictObject({
14661
15161
  threadId: external_exports.string(),
14662
- title: external_exports.string(),
14663
- harnessId: external_exports.string(),
14664
- state: loadedSessionStateSchema,
14665
- reason: loadedSessionReasonSchema,
14666
- inactiveMs: external_exports.number().nonnegative()
14667
- }));
14668
-
14669
- // ../../shared-contracts/dist/ids.js
14670
- var opaqueIdSchema = external_exports.string().refine((value) => value.trim().length > 0, {
14671
- message: "Identifier must not be empty or whitespace"
14672
- });
14673
- var harnessIdSchema = opaqueIdSchema.brand();
14674
- var hostThreadIdSchema = opaqueIdSchema.brand();
14675
- var hostTurnIdSchema = opaqueIdSchema.brand();
14676
- var hostItemIdSchema = opaqueIdSchema.brand();
14677
- var hostInteractionIdSchema = opaqueIdSchema.brand();
15162
+ title: external_exports.string(),
15163
+ harnessId: external_exports.string(),
15164
+ state: loadedSessionStateSchema,
15165
+ reason: loadedSessionReasonSchema,
15166
+ inactiveMs: external_exports.number().nonnegative()
15167
+ }));
14678
15168
 
14679
15169
  // ../../shared-contracts/dist/manual-compaction.js
14680
15170
  var threadManualCompactionStartedSchema = external_exports.strictObject({
@@ -15251,14 +15741,17 @@ var harnessLaunchSettingsSchema = external_exports.object({
15251
15741
  // ../../shared-contracts/dist/harness-installation.js
15252
15742
  var harnessInstallationParamsSchema = external_exports.object({
15253
15743
  harnessId: harnessIdSchema,
15254
- action: external_exports.enum(["check", "update"])
15744
+ action: external_exports.enum(["check", "update", "install"])
15255
15745
  }).strict();
15256
15746
  var harnessInstallationStateSchema = external_exports.object({
15257
15747
  currentVersion: external_exports.string().min(1).max(128),
15258
15748
  latestVersion: external_exports.string().min(1).max(128),
15259
15749
  updateAvailable: external_exports.boolean(),
15260
15750
  canUpdate: external_exports.boolean(),
15261
- message: external_exports.string().max(2048).optional()
15751
+ // Adapter-owned diagnostic text; UI uses messageCode rather than displaying it verbatim.
15752
+ message: external_exports.string().max(2048).optional(),
15753
+ messageCode: external_exports.string().min(1).max(128).optional(),
15754
+ latestVersionKind: external_exports.enum(["unknown", "tracking-branch"]).optional()
15262
15755
  }).strict();
15263
15756
 
15264
15757
  // ../../shared-contracts/dist/codex-accounts.js
@@ -15560,6 +16053,80 @@ var updateStatusResultSchema = external_exports.strictObject({
15560
16053
  status: updateStatusSchema.nullable()
15561
16054
  });
15562
16055
 
16056
+ // ../../shared-contracts/dist/remote-runtime.js
16057
+ var remoteUpdatePhaseSchema = external_exports.enum([
16058
+ "idle",
16059
+ "installing",
16060
+ "restarting",
16061
+ "succeeded",
16062
+ "failed"
16063
+ ]);
16064
+ var runtimeStatusSchema = external_exports.object({
16065
+ runningVersion: external_exports.string().nullable(),
16066
+ installedVersion: external_exports.string().nullable(),
16067
+ restartRequired: external_exports.boolean(),
16068
+ remote: external_exports.boolean(),
16069
+ updateSupported: external_exports.boolean(),
16070
+ update: external_exports.object({
16071
+ phase: remoteUpdatePhaseSchema,
16072
+ targetVersion: external_exports.string().nullable(),
16073
+ error: external_exports.string().nullable()
16074
+ })
16075
+ });
16076
+ var remoteUpdateParamsSchema = external_exports.object({
16077
+ version: external_exports.string().regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u)
16078
+ }).strict();
16079
+ var remoteSshSetupParamsSchema = external_exports.object({
16080
+ hostname: external_exports.string().min(1).max(1024).refine((value) => !value.startsWith("-") && !/\s/u.test(value)),
16081
+ port: external_exports.number().int().min(1).max(65535).nullable(),
16082
+ identity: external_exports.string().max(4096).nullable(),
16083
+ action: external_exports.enum(["inspect", "install", "update", "repair", "uninstall"]),
16084
+ uninstallPackage: external_exports.boolean().optional(),
16085
+ version: external_exports.string().regex(/^\d+\.\d+\.\d+$/u).nullable()
16086
+ }).strict();
16087
+ var remoteSshSetupResultSchema = external_exports.object({ state: external_exports.enum(["installed", "not-installed"]) }).strict();
16088
+
16089
+ // ../../shared-contracts/dist/remote-connections.js
16090
+ var hostId = external_exports.string().min(1).max(1024);
16091
+ var codexSshConnectionSchema = external_exports.object({
16092
+ hostId,
16093
+ displayName: external_exports.string().min(1).max(1024),
16094
+ source: external_exports.enum(["codex-managed", "discovered"]),
16095
+ sshAlias: external_exports.string().max(1024).nullable(),
16096
+ sshHost: external_exports.string().min(1).max(1024),
16097
+ sshPort: external_exports.number().int().min(1).max(65535).nullable(),
16098
+ identity: external_exports.string().max(4096).nullable(),
16099
+ autoConnect: external_exports.boolean(),
16100
+ connectionAnalyticsId: external_exports.string().max(1024).optional()
16101
+ });
16102
+ var codexSshDraftSchema = external_exports.strictObject({
16103
+ displayName: external_exports.string().min(1).max(1024),
16104
+ hostname: external_exports.string().min(1).max(1024),
16105
+ sshPort: external_exports.number().int().min(1).max(65535).nullable(),
16106
+ identity: external_exports.string().max(4096).nullable()
16107
+ });
16108
+ var remoteConnectionsRequestSchema = external_exports.discriminatedUnion("action", [
16109
+ external_exports.strictObject({ action: external_exports.literal("list") }),
16110
+ external_exports.strictObject({
16111
+ action: external_exports.literal("save"),
16112
+ draft: codexSshDraftSchema,
16113
+ previous: codexSshConnectionSchema.nullable()
16114
+ }),
16115
+ external_exports.strictObject({ action: external_exports.literal("remove"), previous: codexSshConnectionSchema }),
16116
+ external_exports.strictObject({ action: external_exports.literal("connect"), hostId, enabled: external_exports.boolean() }),
16117
+ external_exports.strictObject({ action: external_exports.literal("state"), hostId }),
16118
+ external_exports.strictObject({ action: external_exports.literal("runtime"), hostId }),
16119
+ external_exports.strictObject({
16120
+ action: external_exports.literal("update"),
16121
+ hostId: hostId.refine((id) => id !== "local"),
16122
+ version: remoteUpdateParamsSchema.shape.version
16123
+ })
16124
+ ]);
16125
+ var remoteConnectionsReplySchema = external_exports.union([
16126
+ external_exports.strictObject({ result: jsonValueSchema }),
16127
+ external_exports.strictObject({ error: external_exports.strictObject({ code: external_exports.number().int(), message: external_exports.string() }) })
16128
+ ]);
16129
+
15563
16130
  // ../../shared-contracts/dist/index.js
15564
16131
  var workspaceContractVersionSchema = external_exports.literal(WORKSPACE_CONTRACT_VERSION);
15565
16132
 
@@ -15902,6 +16469,44 @@ async function bounded(operation, milliseconds, label, onTimeout) {
15902
16469
  }
15903
16470
  }
15904
16471
 
16472
+ // dist/command.js
16473
+ var codeBuddyDiscoverySpec = {
16474
+ id: "codebuddy",
16475
+ command: "codebuddy",
16476
+ commandEnvironmentVariable: "CODEXHOST_CODEBUDDY_COMMAND",
16477
+ installRoots: {
16478
+ windows: ["${APPDATA}/npm", "~/.local/bin", VERSION_MANAGER_ROOTS],
16479
+ posix: [
16480
+ "~/.local/bin",
16481
+ "~/.npm-global/bin",
16482
+ VERSION_MANAGER_ROOTS,
16483
+ "/opt/homebrew/bin",
16484
+ "/usr/local/bin"
16485
+ ]
16486
+ }
16487
+ };
16488
+ function codeBuddyInvocation(environment, ephemeral, argumentsOverride) {
16489
+ const resolved = resolveHarnessExecutable(codeBuddyDiscoverySpec, { environment });
16490
+ if (!resolved)
16491
+ throw new CodeBuddyError("notInstalled", "CLI is not installed; run codebuddy and sign in first");
16492
+ const env = withNodeRuntimeOnPath(environment);
16493
+ return {
16494
+ ...commandInvocation(resolved.executable, argumentsOverride ?? [
16495
+ "--acp",
16496
+ ...ephemeral ? ["--no-session-persistence"] : [],
16497
+ ...!ephemeral && [
16498
+ "CODEXHOST_CLI_PATH",
16499
+ "CODEXHOST_RUNTIME_ENDPOINT",
16500
+ "CODEXHOST_RUNTIME_TOKEN",
16501
+ "CODEXHOST_THREAD_ID"
16502
+ ].every((key) => environment[key]) ? ["--append-system-prompt", CODEBUDDY_DELEGATION_INSTRUCTIONS] : []
16503
+ ], env),
16504
+ environment: env
16505
+ };
16506
+ }
16507
+ var CODEBUDDY_DELEGATION_INSTRUCTIONS = `This Session runs inside codexhost.
16508
+ When the user requests cross-Harness agent delegation, use the executable at the CODEXHOST_CLI_PATH environment variable through your native shell tool. Start with its --help and harness list commands, then use delegate start and thread send/read/wait/cancel as documented by the CLI. Pass --format compact when reporting results. Keep the inherited CODEXHOST_RUNTIME_ENDPOINT, CODEXHOST_RUNTIME_TOKEN and CODEXHOST_THREAD_ID environment variables for all such calls; they identify this Runtime and parent Thread. Do not print or expose their values, replace the configured executable, or start delegation unless the user's request authorizes it. Native CodeBuddy Agent subagents remain available for CodeBuddy-only work.`;
16509
+
15905
16510
  // dist/slash-commands.js
15906
16511
  var excluded = /* @__PURE__ */ new Set([
15907
16512
  "background",
@@ -15980,7 +16585,7 @@ function commandPrompt(command, catalog, profile = CODEBUDDY_RUNTIME_PROFILE) {
15980
16585
  }
15981
16586
 
15982
16587
  // dist/codebuddy-adapter.js
15983
- import { stat as stat2 } from "node:fs/promises";
16588
+ import { stat as stat3 } from "node:fs/promises";
15984
16589
 
15985
16590
  // dist/acp-client.js
15986
16591
  import { execFile as execFile2, spawn } from "node:child_process";
@@ -19887,793 +20492,327 @@ var ClientSideConnection = class {
19887
20492
  * After successful authentication, the client can proceed to create sessions with
19888
20493
  * `newSession` without receiving an `auth_required` error.
19889
20494
  *
19890
- * See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
19891
- */
19892
- authenticate(params) {
19893
- return this.connection.sendRequest(AGENT_METHODS.authenticate, params, emptyObjectResponse);
19894
- }
19895
- /**
19896
- * **UNSTABLE**
19897
- *
19898
- * This capability is not part of the spec yet, and may be removed or changed at any point.
19899
- *
19900
- * Lists providers that can be configured by the client.
19901
- *
19902
- * This method is only available if the agent advertises the `providers` capability.
19903
- *
19904
- * @experimental
19905
- */
19906
- unstable_listProviders(params) {
19907
- return this.connection.sendRequest(AGENT_METHODS.providers_list, params);
19908
- }
19909
- /**
19910
- * **UNSTABLE**
19911
- *
19912
- * This capability is not part of the spec yet, and may be removed or changed at any point.
19913
- *
19914
- * Replaces the configuration for a provider.
19915
- *
19916
- * This method is only available if the agent advertises the `providers` capability.
19917
- *
19918
- * @experimental
19919
- */
19920
- unstable_setProvider(params) {
19921
- return this.connection.sendRequest(AGENT_METHODS.providers_set, params, emptyObjectResponse);
19922
- }
19923
- /**
19924
- * **UNSTABLE**
19925
- *
19926
- * This capability is not part of the spec yet, and may be removed or changed at any point.
19927
- *
19928
- * Disables a provider.
19929
- *
19930
- * This method is only available if the agent advertises the `providers` capability.
19931
- *
19932
- * @experimental
19933
- */
19934
- unstable_disableProvider(params) {
19935
- return this.connection.sendRequest(AGENT_METHODS.providers_disable, params, emptyObjectResponse);
19936
- }
19937
- /**
19938
- * Logout of the current authentication method.
19939
- */
19940
- logout(params) {
19941
- return this.connection.sendRequest(AGENT_METHODS.logout, params, emptyObjectResponse);
19942
- }
19943
- /**
19944
- * Processes a user prompt within a session.
19945
- *
19946
- * This method handles the whole lifecycle of a prompt:
19947
- * - Receives user messages with optional context (files, images, etc.)
19948
- * - Processes the prompt using language models
19949
- * - Reports language model content and tool calls to the Clients
19950
- * - Requests permission to run tools
19951
- * - Executes any requested tool calls
19952
- * - Returns when the turn is complete with a stop reason
19953
- *
19954
- * See protocol docs: [Prompt Turn](https://agentclientprotocol.com/protocol/prompt-turn)
19955
- */
19956
- prompt(params) {
19957
- return this.connection.sendRequest(AGENT_METHODS.session_prompt, params);
19958
- }
19959
- /**
19960
- * Cancels ongoing operations for a session.
19961
- *
19962
- * This is a notification sent by the client to cancel an ongoing prompt turn.
19963
- *
19964
- * Upon receiving this notification, the Agent SHOULD:
19965
- * - Stop all language model requests as soon as possible
19966
- * - Abort all tool call invocations in progress
19967
- * - Send any pending `session/update` notifications
19968
- * - Respond to the original `session/prompt` request with `StopReason::Cancelled`
19969
- *
19970
- * See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)
19971
- */
19972
- cancel(params) {
19973
- return this.connection.sendNotification(AGENT_METHODS.session_cancel, params);
19974
- }
19975
- /**
19976
- * **UNSTABLE**: This capability is not part of the spec yet, and may be removed or changed at any point.
19977
- *
19978
- * Starts a NES (Next Edit Suggestions) session.
19979
- *
19980
- * @experimental
19981
- */
19982
- unstable_startNes(params) {
19983
- return this.connection.sendRequest(AGENT_METHODS.nes_start, params);
19984
- }
19985
- /**
19986
- * **UNSTABLE**: This capability is not part of the spec yet, and may be removed or changed at any point.
19987
- *
19988
- * Sends a NES suggestion request.
19989
- *
19990
- * @experimental
19991
- */
19992
- unstable_suggestNes(params) {
19993
- return this.connection.sendRequest(AGENT_METHODS.nes_suggest, params);
19994
- }
19995
- /**
19996
- * **UNSTABLE**: This capability is not part of the spec yet, and may be removed or changed at any point.
19997
- *
19998
- * Closes a NES session.
19999
- *
20000
- * @experimental
20001
- */
20002
- unstable_closeNes(params) {
20003
- return this.connection.sendRequest(AGENT_METHODS.nes_close, params, emptyObjectResponse);
20004
- }
20005
- /**
20006
- * **UNSTABLE**: This capability is not part of the spec yet, and may be removed or changed at any point.
20007
- *
20008
- * Notifies the agent that a document was opened.
20009
- *
20010
- * @experimental
20011
- */
20012
- unstable_didOpenDocument(params) {
20013
- return this.connection.sendNotification(AGENT_METHODS.document_did_open, params);
20014
- }
20015
- /**
20016
- * **UNSTABLE**: This capability is not part of the spec yet, and may be removed or changed at any point.
20017
- *
20018
- * Notifies the agent that a document was changed.
20019
- *
20020
- * @experimental
20021
- */
20022
- unstable_didChangeDocument(params) {
20023
- return this.connection.sendNotification(AGENT_METHODS.document_did_change, params);
20024
- }
20025
- /**
20026
- * **UNSTABLE**: This capability is not part of the spec yet, and may be removed or changed at any point.
20027
- *
20028
- * Notifies the agent that a document was closed.
20029
- *
20030
- * @experimental
20031
- */
20032
- unstable_didCloseDocument(params) {
20033
- return this.connection.sendNotification(AGENT_METHODS.document_did_close, params);
20034
- }
20035
- /**
20036
- * **UNSTABLE**: This capability is not part of the spec yet, and may be removed or changed at any point.
20037
- *
20038
- * Notifies the agent that a document was saved.
20039
- *
20040
- * @experimental
20041
- */
20042
- unstable_didSaveDocument(params) {
20043
- return this.connection.sendNotification(AGENT_METHODS.document_did_save, params);
20044
- }
20045
- /**
20046
- * **UNSTABLE**: This capability is not part of the spec yet, and may be removed or changed at any point.
20047
- *
20048
- * Notifies the agent that a document received focus.
20049
- *
20050
- * @experimental
20051
- */
20052
- unstable_didFocusDocument(params) {
20053
- return this.connection.sendNotification(AGENT_METHODS.document_did_focus, params);
20054
- }
20055
- /**
20056
- * **UNSTABLE**: This capability is not part of the spec yet, and may be removed or changed at any point.
20057
- *
20058
- * Notifies the agent that a NES suggestion was accepted.
20059
- *
20060
- * @experimental
20061
- */
20062
- unstable_acceptNes(params) {
20063
- return this.connection.sendNotification(AGENT_METHODS.nes_accept, params);
20064
- }
20065
- /**
20066
- * **UNSTABLE**: This capability is not part of the spec yet, and may be removed or changed at any point.
20067
- *
20068
- * Notifies the agent that a NES suggestion was rejected.
20069
- *
20070
- * @experimental
20071
- */
20072
- unstable_rejectNes(params) {
20073
- return this.connection.sendNotification(AGENT_METHODS.nes_reject, params);
20074
- }
20075
- request(method, params, options) {
20076
- const spec = agentRequestSpecsByMethod[method];
20077
- return this.connection.sendRequest(method, params, spec?.mapResponse, options);
20078
- }
20079
- notify(method, params) {
20080
- return this.connection.sendNotification(method, params);
20081
- }
20082
- /**
20083
- * Extension method.
20084
- *
20085
- * @deprecated Use {@link request}.
20495
+ * See protocol docs: [Initialization](https://agentclientprotocol.com/protocol/initialization)
20086
20496
  */
20087
- extMethod(method, params) {
20088
- return this.request(method, params);
20497
+ authenticate(params) {
20498
+ return this.connection.sendRequest(AGENT_METHODS.authenticate, params, emptyObjectResponse);
20089
20499
  }
20090
20500
  /**
20091
- * Extension notification.
20501
+ * **UNSTABLE**
20092
20502
  *
20093
- * @deprecated Use {@link notify}.
20503
+ * This capability is not part of the spec yet, and may be removed or changed at any point.
20504
+ *
20505
+ * Lists providers that can be configured by the client.
20506
+ *
20507
+ * This method is only available if the agent advertises the `providers` capability.
20508
+ *
20509
+ * @experimental
20094
20510
  */
20095
- extNotification(method, params) {
20096
- return this.notify(method, params);
20511
+ unstable_listProviders(params) {
20512
+ return this.connection.sendRequest(AGENT_METHODS.providers_list, params);
20097
20513
  }
20098
20514
  /**
20099
- * AbortSignal that aborts when the connection closes.
20100
- *
20101
- * This signal can be used to:
20102
- * - Listen for connection closure: `connection.signal.addEventListener('abort', () => {...})`
20103
- * - Check connection status synchronously: `if (connection.signal.aborted) {...}`
20104
- * - Pass to other APIs (fetch, setTimeout) for automatic cancellation
20105
- *
20106
- * The connection closes when the underlying stream ends, either normally or due to an error.
20515
+ * **UNSTABLE**
20107
20516
  *
20108
- * @example
20109
- * ```typescript
20110
- * const connection = new ClientSideConnection(client, stream);
20517
+ * This capability is not part of the spec yet, and may be removed or changed at any point.
20111
20518
  *
20112
- * // Listen for closure
20113
- * connection.signal.addEventListener('abort', () => {
20114
- * console.log('Connection closed - performing cleanup');
20115
- * });
20519
+ * Replaces the configuration for a provider.
20116
20520
  *
20117
- * // Check status
20118
- * if (connection.signal.aborted) {
20119
- * console.log('Connection is already closed');
20120
- * }
20521
+ * This method is only available if the agent advertises the `providers` capability.
20121
20522
  *
20122
- * // Pass to other APIs
20123
- * fetch(url, { signal: connection.signal });
20124
- * ```
20523
+ * @experimental
20125
20524
  */
20126
- get signal() {
20127
- return this.connection.signal;
20525
+ unstable_setProvider(params) {
20526
+ return this.connection.sendRequest(AGENT_METHODS.providers_set, params, emptyObjectResponse);
20128
20527
  }
20129
20528
  /**
20130
- * Promise that resolves when the connection closes.
20529
+ * **UNSTABLE**
20131
20530
  *
20132
- * The connection closes when the underlying stream ends, either normally or due to an error.
20133
- * Once closed, the connection cannot send or receive any more messages.
20531
+ * This capability is not part of the spec yet, and may be removed or changed at any point.
20134
20532
  *
20135
- * This is useful for async/await style cleanup:
20533
+ * Disables a provider.
20136
20534
  *
20137
- * @example
20138
- * ```typescript
20139
- * const connection = new ClientSideConnection(client, stream);
20140
- * await connection.closed;
20141
- * console.log('Connection closed - performing cleanup');
20142
- * ```
20535
+ * This method is only available if the agent advertises the `providers` capability.
20536
+ *
20537
+ * @experimental
20143
20538
  */
20144
- get closed() {
20145
- return this.connection.closed;
20146
- }
20147
- };
20148
-
20149
- // dist/copy-cleanup.js
20150
- import { randomBytes } from "node:crypto";
20151
- import { createInterface } from "node:readline";
20152
- import { stripVTControlCharacters } from "node:util";
20153
- import { Readable } from "node:stream";
20154
- var CodeBuddyCopyCleanup = class {
20155
- copyId;
20156
- cwd;
20157
- password = randomBytes(32).toString("base64url");
20158
- arguments = [
20159
- "--acp",
20160
- "--serve",
20161
- "--host",
20162
- "127.0.0.1",
20163
- "--port",
20164
- "0",
20165
- "--auth",
20166
- "password"
20167
- ];
20168
- #endpoint;
20169
- constructor(copyId, cwd) {
20170
- this.copyId = copyId;
20171
- this.cwd = cwd;
20172
- }
20173
- environment(environment) {
20174
- return {
20175
- ...environment,
20176
- CODEBUDDY_GATEWAY_AUTH: "password",
20177
- CODEBUDDY_GATEWAY_PASSWORD: this.password,
20178
- CODEBUDDY_GATEWAY_BASE_PATH: ""
20179
- };
20180
- }
20181
- /** Native --serve banners include its password; never pass them to the ACP parser/logs. */
20182
- protocolOutput(stdout) {
20183
- return Readable.from(this.#protocolLines(stdout));
20184
- }
20185
- async *#protocolLines(stdout) {
20186
- for await (const line of createInterface({ input: stdout })) {
20187
- const endpoint = /^\s*Endpoint\s+(http:\/\/127\.0\.0\.1:\d+)\s*$/u.exec(stripVTControlCharacters(line));
20188
- if (endpoint)
20189
- this.#endpoint = endpoint[1];
20190
- if (line.trimStart().startsWith("{"))
20191
- yield Buffer.from(`${line}
20192
- `);
20193
- }
20194
- }
20195
- async remove() {
20196
- if (!this.#endpoint)
20197
- throw new CodeBuddyError("nativeFailure", `Native cleanup endpoint was not reported; temporary Session ${this.copyId} remains`);
20198
- const response = await fetch(`${this.#endpoint}/api/v1/sessions/${encodeURIComponent(this.copyId)}?cwd=${encodeURIComponent(this.cwd)}`, {
20199
- method: "DELETE",
20200
- headers: { Authorization: `Bearer ${this.password}`, "x-codebuddy-request": "true" },
20201
- signal: AbortSignal.timeout(5e3),
20202
- redirect: "error"
20203
- }).catch(() => {
20204
- throw new CodeBuddyError("nativeFailure", `Native cleanup request failed; temporary Session ${this.copyId} remains`);
20205
- });
20206
- await response.body?.cancel();
20207
- if (response.status !== 204)
20208
- throw new CodeBuddyError("nativeFailure", `Native cleanup failed (${response.status}); temporary Session ${this.copyId} remains`);
20209
- }
20210
- };
20211
-
20212
- // ../../harness-discovery/dist/environment.js
20213
- import fs from "node:fs";
20214
- import path from "node:path";
20215
- function targetPath(platform) {
20216
- return platform === "win32" ? path.win32 : path.posix;
20217
- }
20218
- function environmentValue(environment, name) {
20219
- const lowered = name.toLowerCase();
20220
- for (const [key, value] of Object.entries(environment)) {
20221
- if (key.toLowerCase() === lowered)
20222
- return value;
20223
- }
20224
- return void 0;
20225
- }
20226
- function pathDelimiter(platform) {
20227
- return platform === "win32" ? ";" : ":";
20228
- }
20229
- function pathDirectories(environment, platform) {
20230
- return (environmentValue(environment, "PATH") ?? "").split(pathDelimiter(platform)).map((directory) => directory.trim().replace(/^"|"$/gu, "")).filter(Boolean);
20231
- }
20232
- function executableExtensions(command, platform, environment) {
20233
- if (platform !== "win32")
20234
- return [""];
20235
- if (targetPath(platform).extname(command) !== "")
20236
- return [""];
20237
- return (environmentValue(environment, "PATHEXT") ?? ".COM;.EXE;.BAT;.CMD").split(";").map((extension) => extension.trim()).filter(Boolean);
20238
- }
20239
- function isExecutableFile(filePath, platform) {
20240
- try {
20241
- fs.accessSync(filePath, platform === "win32" ? fs.constants.F_OK : fs.constants.X_OK);
20242
- return fs.statSync(filePath).isFile();
20243
- } catch {
20244
- return false;
20245
- }
20246
- }
20247
- function subdirectoryNames(directory) {
20248
- try {
20249
- return fs.readdirSync(directory, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
20250
- } catch {
20251
- return [];
20252
- }
20253
- }
20254
- function newestFirst(names) {
20255
- return [...names].sort((left, right) => right.localeCompare(left, void 0, { numeric: true }));
20256
- }
20257
-
20258
- // ../../harness-discovery/dist/invocation.js
20259
- import path2 from "node:path";
20260
- function commandInvocation(command, arguments_, environment, platform = process.platform) {
20261
- const extension = path2.win32.extname(command).toLowerCase();
20262
- if (platform !== "win32" || ![".cmd", ".bat"].includes(extension)) {
20263
- return { command, arguments: [...arguments_], windowsVerbatimArguments: false };
20539
+ unstable_disableProvider(params) {
20540
+ return this.connection.sendRequest(AGENT_METHODS.providers_disable, params, emptyObjectResponse);
20264
20541
  }
20265
- const quote = (value) => `"${value.replaceAll("%", "%%").replaceAll('"', '""')}"`;
20266
- const commandLine = [command, ...arguments_].map(quote).join(" ");
20267
- return {
20268
- command: environmentValue(environment, "ComSpec") ?? "cmd.exe",
20269
- arguments: ["/d", "/v:off", "/s", "/c", `"${commandLine}"`],
20270
- windowsVerbatimArguments: true
20271
- };
20272
- }
20273
-
20274
- // ../../harness-discovery/dist/node-runtime.js
20275
- import path3 from "node:path";
20276
- function withNodeRuntimeOnPath(environment, runtimeExecutable = process.execPath, platform = process.platform) {
20277
- const pathKey = Object.keys(environment).find((name) => name.toLowerCase() === "path") ?? "PATH";
20278
- const delimiter = platform === "win32" ? ";" : ":";
20279
- const runtimeDirectory = path3.dirname(runtimeExecutable);
20280
- const directories = (environment[pathKey] ?? "").split(delimiter).filter(Boolean);
20281
- const equal = platform === "win32" ? (value) => value.toLowerCase() : (value) => value;
20282
- if (!directories.some((directory) => equal(directory) === equal(runtimeDirectory))) {
20283
- directories.push(runtimeDirectory);
20542
+ /**
20543
+ * Logout of the current authentication method.
20544
+ */
20545
+ logout(params) {
20546
+ return this.connection.sendRequest(AGENT_METHODS.logout, params, emptyObjectResponse);
20284
20547
  }
20285
- return { ...environment, [pathKey]: directories.join(delimiter) };
20286
- }
20287
-
20288
- // ../../harness-discovery/dist/resolve.js
20289
- import os from "node:os";
20290
-
20291
- // ../../harness-discovery/dist/version-managers.js
20292
- function versionManagerBinaryDirectories(context) {
20293
- const { platform, environment, home } = context;
20294
- const list = context.subdirectories ?? subdirectoryNames;
20295
- const pathFlavor = targetPath(platform);
20296
- const value = (name) => environmentValue(environment, name);
20297
- const directories = [];
20298
- const versioned = (root, ...tail) => {
20299
- for (const version2 of newestFirst(list(root))) {
20300
- directories.push(pathFlavor.join(root, version2, ...tail));
20301
- }
20302
- };
20303
- if (platform === "win32") {
20304
- const appData = value("APPDATA") ?? pathFlavor.join(home, "AppData", "Roaming");
20305
- const localAppData = value("LOCALAPPDATA") ?? pathFlavor.join(home, "AppData", "Local");
20306
- versioned(pathFlavor.join(appData, "nvm"));
20307
- versioned(value("FNM_DIR") ?? pathFlavor.join(appData, "fnm", "node-versions"), "installation");
20308
- directories.push(pathFlavor.join(localAppData, "Volta", "bin"));
20309
- directories.push(pathFlavor.join(home, ".bun", "bin"));
20310
- const pnpmHome2 = value("PNPM_HOME");
20311
- if (pnpmHome2)
20312
- directories.push(pnpmHome2);
20313
- directories.push(pathFlavor.join(localAppData, "pnpm"));
20314
- return directories;
20548
+ /**
20549
+ * Processes a user prompt within a session.
20550
+ *
20551
+ * This method handles the whole lifecycle of a prompt:
20552
+ * - Receives user messages with optional context (files, images, etc.)
20553
+ * - Processes the prompt using language models
20554
+ * - Reports language model content and tool calls to the Clients
20555
+ * - Requests permission to run tools
20556
+ * - Executes any requested tool calls
20557
+ * - Returns when the turn is complete with a stop reason
20558
+ *
20559
+ * See protocol docs: [Prompt Turn](https://agentclientprotocol.com/protocol/prompt-turn)
20560
+ */
20561
+ prompt(params) {
20562
+ return this.connection.sendRequest(AGENT_METHODS.session_prompt, params);
20315
20563
  }
20316
- versioned(pathFlavor.join(value("NVM_DIR") ?? pathFlavor.join(home, ".nvm"), "versions", "node"), "bin");
20317
- const fnmRoots = [
20318
- value("FNM_DIR"),
20319
- pathFlavor.join(home, ".local", "share", "fnm"),
20320
- pathFlavor.join(home, "Library", "Application Support", "fnm")
20321
- ].filter((root) => root !== void 0);
20322
- for (const root of fnmRoots) {
20323
- versioned(pathFlavor.join(root, "node-versions"), "installation", "bin");
20564
+ /**
20565
+ * Cancels ongoing operations for a session.
20566
+ *
20567
+ * This is a notification sent by the client to cancel an ongoing prompt turn.
20568
+ *
20569
+ * Upon receiving this notification, the Agent SHOULD:
20570
+ * - Stop all language model requests as soon as possible
20571
+ * - Abort all tool call invocations in progress
20572
+ * - Send any pending `session/update` notifications
20573
+ * - Respond to the original `session/prompt` request with `StopReason::Cancelled`
20574
+ *
20575
+ * See protocol docs: [Cancellation](https://agentclientprotocol.com/protocol/prompt-turn#cancellation)
20576
+ */
20577
+ cancel(params) {
20578
+ return this.connection.sendNotification(AGENT_METHODS.session_cancel, params);
20324
20579
  }
20325
- const voltaHome = value("VOLTA_HOME") ?? pathFlavor.join(home, ".volta");
20326
- versioned(pathFlavor.join(voltaHome, "tools", "image", "node"), "bin");
20327
- directories.push(pathFlavor.join(voltaHome, "bin"));
20328
- const asdfHome = value("ASDF_DATA_DIR") ?? pathFlavor.join(home, ".asdf");
20329
- versioned(pathFlavor.join(asdfHome, "installs", "nodejs"), "bin");
20330
- directories.push(pathFlavor.join(asdfHome, "shims"));
20331
- const nodenvHome = value("NODENV_ROOT") ?? pathFlavor.join(home, ".nodenv");
20332
- versioned(pathFlavor.join(nodenvHome, "versions"), "bin");
20333
- directories.push(pathFlavor.join(nodenvHome, "shims"));
20334
- versioned(pathFlavor.join(value("N_PREFIX") ?? "/usr/local", "n", "versions", "node"), "bin");
20335
- directories.push(pathFlavor.join(home, ".bun", "bin"));
20336
- const pnpmHome = value("PNPM_HOME");
20337
- if (pnpmHome)
20338
- directories.push(pnpmHome);
20339
- directories.push(pathFlavor.join(home, "Library", "pnpm"));
20340
- directories.push(pathFlavor.join(home, ".local", "share", "pnpm"));
20341
- for (const prefix of ["/opt/homebrew/opt", "/usr/local/opt"]) {
20342
- for (const formula of newestFirst(list(prefix).filter((name) => name.startsWith("node@")))) {
20343
- directories.push(pathFlavor.join(prefix, formula, "bin"));
20344
- }
20580
+ /**
20581
+ * **UNSTABLE**: This capability is not part of the spec yet, and may be removed or changed at any point.
20582
+ *
20583
+ * Starts a NES (Next Edit Suggestions) session.
20584
+ *
20585
+ * @experimental
20586
+ */
20587
+ unstable_startNes(params) {
20588
+ return this.connection.sendRequest(AGENT_METHODS.nes_start, params);
20345
20589
  }
20346
- return directories;
20347
- }
20348
-
20349
- // ../../harness-discovery/dist/resolve.js
20350
- var VERSION_MANAGER_ROOTS = "<version-managers>";
20351
- function installRootExtensions(platform) {
20352
- return platform === "win32" ? [".exe", ".cmd"] : [""];
20353
- }
20354
- function resolveHomeDirectory(input) {
20355
- return input.homeDirectory ?? environmentValue(input.environment, "HOME") ?? environmentValue(input.environment, "USERPROFILE") ?? os.homedir();
20356
- }
20357
- function templateVariables(environment, platform, home) {
20358
- const pathFlavor = targetPath(platform);
20359
- return {
20360
- HOME: home,
20361
- USERPROFILE: home,
20362
- APPDATA: environmentValue(environment, "APPDATA") ?? pathFlavor.join(home, "AppData", "Roaming"),
20363
- LOCALAPPDATA: environmentValue(environment, "LOCALAPPDATA") ?? pathFlavor.join(home, "AppData", "Local")
20364
- };
20365
- }
20366
- function joinTemplate(platform, value) {
20367
- const pathFlavor = targetPath(platform);
20368
- const segments = value.split("/");
20369
- const head = segments[0] ?? "";
20370
- const tail = segments.slice(1);
20371
- if (head === "")
20372
- return pathFlavor.join(pathFlavor.sep, ...tail);
20373
- return tail.length === 0 ? head : pathFlavor.join(head, ...tail);
20374
- }
20375
- function expandInstallRoot(template, environment, platform, home) {
20376
- const variables = templateVariables(environment, platform, home);
20377
- let unresolved = false;
20378
- const substituted = template.replace(/^~(?=\/|$)/u, home).replace(/\$\{(\w+)\}/gu, (_match, name) => {
20379
- const value = variables[name] ?? environmentValue(environment, name);
20380
- if (value === void 0 || value === "") {
20381
- unresolved = true;
20382
- return "";
20383
- }
20384
- return value;
20385
- });
20386
- return unresolved ? void 0 : joinTemplate(platform, substituted);
20387
- }
20388
- function installRootDirectories(spec, input, dependencies, platform, home) {
20389
- const templates = (platform === "win32" ? spec.installRoots?.windows : spec.installRoots?.posix) ?? [];
20390
- const directories = [];
20391
- for (const template of templates) {
20392
- if (template === VERSION_MANAGER_ROOTS) {
20393
- directories.push(...versionManagerBinaryDirectories({
20394
- platform,
20395
- environment: input.environment,
20396
- home,
20397
- ...dependencies.subdirectories ? { subdirectories: dependencies.subdirectories } : {}
20398
- }));
20399
- continue;
20400
- }
20401
- const directory = expandInstallRoot(template, input.environment, platform, home);
20402
- if (directory !== void 0)
20403
- directories.push(directory);
20590
+ /**
20591
+ * **UNSTABLE**: This capability is not part of the spec yet, and may be removed or changed at any point.
20592
+ *
20593
+ * Sends a NES suggestion request.
20594
+ *
20595
+ * @experimental
20596
+ */
20597
+ unstable_suggestNes(params) {
20598
+ return this.connection.sendRequest(AGENT_METHODS.nes_suggest, params);
20404
20599
  }
20405
- return directories;
20406
- }
20407
- function harnessCandidates(spec, input, dependencies = {}) {
20408
- const platform = input.platform ?? process.platform;
20409
- const pathFlavor = targetPath(platform);
20410
- const configured = input.command ?? (spec.commandEnvironmentVariable ? environmentValue(input.environment, spec.commandEnvironmentVariable) : void 0);
20411
- const command = configured ?? spec.command;
20412
- if (pathFlavor.isAbsolute(command) || command.includes("/") || command.includes("\\")) {
20413
- return [{ candidate: command, source: "configured" }];
20600
+ /**
20601
+ * **UNSTABLE**: This capability is not part of the spec yet, and may be removed or changed at any point.
20602
+ *
20603
+ * Closes a NES session.
20604
+ *
20605
+ * @experimental
20606
+ */
20607
+ unstable_closeNes(params) {
20608
+ return this.connection.sendRequest(AGENT_METHODS.nes_close, params, emptyObjectResponse);
20414
20609
  }
20415
- const candidates = [];
20416
- const extensions = executableExtensions(command, platform, input.environment);
20417
- for (const directory of pathDirectories(input.environment, platform)) {
20418
- for (const extension of extensions) {
20419
- candidates.push({
20420
- candidate: pathFlavor.join(directory, command + extension),
20421
- source: "path"
20422
- });
20423
- }
20610
+ /**
20611
+ * **UNSTABLE**: This capability is not part of the spec yet, and may be removed or changed at any point.
20612
+ *
20613
+ * Notifies the agent that a document was opened.
20614
+ *
20615
+ * @experimental
20616
+ */
20617
+ unstable_didOpenDocument(params) {
20618
+ return this.connection.sendNotification(AGENT_METHODS.document_did_open, params);
20424
20619
  }
20425
- if (configured !== void 0)
20426
- return candidates;
20427
- const home = resolveHomeDirectory(input);
20428
- for (const directory of installRootDirectories(spec, input, dependencies, platform, home)) {
20429
- for (const extension of installRootExtensions(platform)) {
20430
- candidates.push({
20431
- candidate: pathFlavor.join(directory, spec.command + extension),
20432
- source: "install-root"
20433
- });
20434
- }
20620
+ /**
20621
+ * **UNSTABLE**: This capability is not part of the spec yet, and may be removed or changed at any point.
20622
+ *
20623
+ * Notifies the agent that a document was changed.
20624
+ *
20625
+ * @experimental
20626
+ */
20627
+ unstable_didChangeDocument(params) {
20628
+ return this.connection.sendNotification(AGENT_METHODS.document_did_change, params);
20435
20629
  }
20436
- return candidates;
20437
- }
20438
- function resolveHarnessExecutable(spec, input, dependencies = {}) {
20439
- const platform = input.platform ?? process.platform;
20440
- const isExecutable = dependencies.isExecutable ?? ((candidate) => isExecutableFile(candidate, platform));
20441
- const runnable = spec.runnableCandidate ?? ((candidate) => candidate);
20442
- const context = { platform, isExecutable };
20443
- for (const { candidate, source } of harnessCandidates(spec, input, dependencies)) {
20444
- const executable = runnable(candidate, context);
20445
- if (executable !== void 0 && isExecutable(executable))
20446
- return { executable, source };
20630
+ /**
20631
+ * **UNSTABLE**: This capability is not part of the spec yet, and may be removed or changed at any point.
20632
+ *
20633
+ * Notifies the agent that a document was closed.
20634
+ *
20635
+ * @experimental
20636
+ */
20637
+ unstable_didCloseDocument(params) {
20638
+ return this.connection.sendNotification(AGENT_METHODS.document_did_close, params);
20447
20639
  }
20448
- return void 0;
20449
- }
20450
-
20451
- // ../../harness-discovery/dist/installation.js
20452
- import { execFile } from "node:child_process";
20453
- import { homedir } from "node:os";
20454
- function runInstallationCommand(command, args, environment, timeout = 3e4) {
20455
- const env = withNodeRuntimeOnPath(environment);
20456
- const invocation = /\.[cm]?js$/i.test(command) ? commandInvocation(process.execPath, [command, ...args], env) : commandInvocation(command, args, env);
20457
- return new Promise((resolve, reject) => {
20458
- const child = execFile(invocation.command, invocation.arguments, {
20459
- env,
20460
- cwd: env.HOME ?? env.USERPROFILE ?? homedir(),
20461
- encoding: "utf8",
20462
- timeout,
20463
- killSignal: "SIGKILL",
20464
- maxBuffer: 1024 * 1024,
20465
- windowsHide: true,
20466
- windowsVerbatimArguments: invocation.windowsVerbatimArguments
20467
- }, (error51, stdout, stderr) => {
20468
- if (error51)
20469
- reject(new Error(error51.killed ? "Harness command timed out" : "Harness command failed; check the native installation and retry"));
20470
- else
20471
- resolve((stdout || stderr).trim());
20472
- });
20473
- child.stdin?.end();
20474
- });
20475
- }
20476
- function installationVersion(value) {
20477
- if (typeof value !== "string" || !/^v?\d+(?:\.\d+){1,3}(?:-[\w.-]+)?(?:\+[\w.-]+)?$/.test(value.trim()))
20478
- throw new Error("Harness returned an invalid version");
20479
- return value.trim().replace(/^v/, "");
20480
- }
20481
- function versionFromOutput(output) {
20482
- return installationVersion(output.match(/\b\d+(?:\.\d+){1,3}(?:-[\w.-]+)?(?:\+[\w.-]+)?\b/)?.[0]);
20483
- }
20484
- function newerInstallationVersion(current, latest) {
20485
- const a = installationVersion(current).replace(/\+.*/, "");
20486
- const b = installationVersion(latest).replace(/\+.*/, "");
20487
- const coreA = a.replace(/-.*/, "").split(".").map(BigInt);
20488
- const coreB = b.replace(/-.*/, "").split(".").map(BigInt);
20489
- for (let i = 0; i < Math.max(coreA.length, coreB.length); i++) {
20490
- if ((coreA[i] ?? 0n) !== (coreB[i] ?? 0n))
20491
- return (coreB[i] ?? 0n) > (coreA[i] ?? 0n);
20640
+ /**
20641
+ * **UNSTABLE**: This capability is not part of the spec yet, and may be removed or changed at any point.
20642
+ *
20643
+ * Notifies the agent that a document was saved.
20644
+ *
20645
+ * @experimental
20646
+ */
20647
+ unstable_didSaveDocument(params) {
20648
+ return this.connection.sendNotification(AGENT_METHODS.document_did_save, params);
20649
+ }
20650
+ /**
20651
+ * **UNSTABLE**: This capability is not part of the spec yet, and may be removed or changed at any point.
20652
+ *
20653
+ * Notifies the agent that a document received focus.
20654
+ *
20655
+ * @experimental
20656
+ */
20657
+ unstable_didFocusDocument(params) {
20658
+ return this.connection.sendNotification(AGENT_METHODS.document_did_focus, params);
20492
20659
  }
20493
- const preA = a.includes("-") ? a.slice(a.indexOf("-") + 1).split(".") : [];
20494
- const preB = b.includes("-") ? b.slice(b.indexOf("-") + 1).split(".") : [];
20495
- if (!preA.length || !preB.length)
20496
- return !!preA.length && !preB.length;
20497
- for (let i = 0; i < Math.max(preA.length, preB.length); i++) {
20498
- const x = preA[i];
20499
- const y = preB[i];
20500
- if (x === y)
20501
- continue;
20502
- if (x === void 0 || y === void 0)
20503
- return x === void 0;
20504
- const numericX = /^\d+$/.test(x);
20505
- const numericY = /^\d+$/.test(y);
20506
- if (numericX && numericY) {
20507
- if (BigInt(x) === BigInt(y))
20508
- continue;
20509
- return BigInt(y) > BigInt(x);
20510
- }
20511
- if (numericX !== numericY)
20512
- return numericX;
20513
- return y > x;
20660
+ /**
20661
+ * **UNSTABLE**: This capability is not part of the spec yet, and may be removed or changed at any point.
20662
+ *
20663
+ * Notifies the agent that a NES suggestion was accepted.
20664
+ *
20665
+ * @experimental
20666
+ */
20667
+ unstable_acceptNes(params) {
20668
+ return this.connection.sendNotification(AGENT_METHODS.nes_accept, params);
20514
20669
  }
20515
- return false;
20516
- }
20517
- function createInstallationManager(options) {
20518
- let checking;
20519
- let updating;
20520
- const check2 = () => checking ??= options.check().finally(() => {
20521
- checking = void 0;
20522
- });
20523
- return (action) => {
20524
- if (updating)
20525
- return updating;
20526
- if (action === "check")
20527
- return check2();
20528
- updating = (async () => {
20529
- const before = await check2();
20530
- if (!before.updateAvailable)
20531
- return before;
20532
- if (!before.canUpdate)
20533
- throw new Error(before.message ?? "This installation cannot be updated automatically");
20534
- await options.update(before);
20535
- const after = await check2();
20536
- if (after.currentVersion === before.currentVersion)
20537
- throw new Error("The Harness version did not change; check the native updater and retry");
20538
- return after;
20539
- })().finally(() => {
20540
- updating = void 0;
20541
- });
20542
- return updating;
20543
- };
20544
- }
20545
- async function fetchInstallationText(url2) {
20546
- const request = async () => {
20547
- const response = await fetch(url2, { signal: AbortSignal.timeout(15e3) });
20548
- if (!response.ok)
20549
- throw new Error("Could not check the latest Harness version");
20550
- return response.text();
20551
- };
20552
- try {
20553
- return await request();
20554
- } catch (error51) {
20555
- if (error51 instanceof DOMException && (error51.name === "AbortError" || error51.name === "TimeoutError"))
20556
- throw error51;
20557
- return request();
20670
+ /**
20671
+ * **UNSTABLE**: This capability is not part of the spec yet, and may be removed or changed at any point.
20672
+ *
20673
+ * Notifies the agent that a NES suggestion was rejected.
20674
+ *
20675
+ * @experimental
20676
+ */
20677
+ unstable_rejectNes(params) {
20678
+ return this.connection.sendNotification(AGENT_METHODS.nes_reject, params);
20558
20679
  }
20559
- }
20680
+ request(method, params, options) {
20681
+ const spec = agentRequestSpecsByMethod[method];
20682
+ return this.connection.sendRequest(method, params, spec?.mapResponse, options);
20683
+ }
20684
+ notify(method, params) {
20685
+ return this.connection.sendNotification(method, params);
20686
+ }
20687
+ /**
20688
+ * Extension method.
20689
+ *
20690
+ * @deprecated Use {@link request}.
20691
+ */
20692
+ extMethod(method, params) {
20693
+ return this.request(method, params);
20694
+ }
20695
+ /**
20696
+ * Extension notification.
20697
+ *
20698
+ * @deprecated Use {@link notify}.
20699
+ */
20700
+ extNotification(method, params) {
20701
+ return this.notify(method, params);
20702
+ }
20703
+ /**
20704
+ * AbortSignal that aborts when the connection closes.
20705
+ *
20706
+ * This signal can be used to:
20707
+ * - Listen for connection closure: `connection.signal.addEventListener('abort', () => {...})`
20708
+ * - Check connection status synchronously: `if (connection.signal.aborted) {...}`
20709
+ * - Pass to other APIs (fetch, setTimeout) for automatic cancellation
20710
+ *
20711
+ * The connection closes when the underlying stream ends, either normally or due to an error.
20712
+ *
20713
+ * @example
20714
+ * ```typescript
20715
+ * const connection = new ClientSideConnection(client, stream);
20716
+ *
20717
+ * // Listen for closure
20718
+ * connection.signal.addEventListener('abort', () => {
20719
+ * console.log('Connection closed - performing cleanup');
20720
+ * });
20721
+ *
20722
+ * // Check status
20723
+ * if (connection.signal.aborted) {
20724
+ * console.log('Connection is already closed');
20725
+ * }
20726
+ *
20727
+ * // Pass to other APIs
20728
+ * fetch(url, { signal: connection.signal });
20729
+ * ```
20730
+ */
20731
+ get signal() {
20732
+ return this.connection.signal;
20733
+ }
20734
+ /**
20735
+ * Promise that resolves when the connection closes.
20736
+ *
20737
+ * The connection closes when the underlying stream ends, either normally or due to an error.
20738
+ * Once closed, the connection cannot send or receive any more messages.
20739
+ *
20740
+ * This is useful for async/await style cleanup:
20741
+ *
20742
+ * @example
20743
+ * ```typescript
20744
+ * const connection = new ClientSideConnection(client, stream);
20745
+ * await connection.closed;
20746
+ * console.log('Connection closed - performing cleanup');
20747
+ * ```
20748
+ */
20749
+ get closed() {
20750
+ return this.connection.closed;
20751
+ }
20752
+ };
20560
20753
 
20561
- // ../../harness-discovery/dist/npm-installation.js
20562
- import { readFile, realpath } from "node:fs/promises";
20563
- import path4 from "node:path";
20564
- function referencesNpmBin(shim, name, bin) {
20565
- if (bin.includes(".."))
20566
- return false;
20567
- const target = `node_modules/${name}/${bin.replace(/^\.\//, "")}`.toLowerCase();
20568
- const text2 = shim.replaceAll("\\", "/").toLowerCase();
20569
- return text2.includes(`%dp0%/${target}"`) || text2.includes(`%~dp0/${target}"`);
20570
- }
20571
- async function npmInstallation(command, packages, environment) {
20572
- let selected = await realpath(command);
20573
- if (process.platform === "win32" && /\.(cmd|bat)$/i.test(selected)) {
20574
- const shim = (await readFile(selected, "utf8")).replaceAll("\\", "/");
20575
- const root = path4.dirname(selected);
20576
- for (const name of packages) {
20577
- const directory2 = path4.join(root, "node_modules", ...name.split("/"));
20578
- const metadata = await readFile(path4.join(directory2, "package.json"), "utf8").then((text2) => JSON.parse(text2)).catch(() => null);
20579
- const bins = typeof metadata?.bin === "string" ? [metadata.bin] : Object.values(metadata?.bin ?? {});
20580
- const bin = bins.find((entry) => referencesNpmBin(shim, name, entry));
20581
- if (bin) {
20582
- selected = await realpath(path4.join(directory2, bin));
20583
- break;
20584
- }
20585
- }
20754
+ // dist/copy-cleanup.js
20755
+ import { randomBytes } from "node:crypto";
20756
+ import { createInterface } from "node:readline";
20757
+ import { stripVTControlCharacters } from "node:util";
20758
+ import { Readable } from "node:stream";
20759
+ var CodeBuddyCopyCleanup = class {
20760
+ copyId;
20761
+ cwd;
20762
+ password = randomBytes(32).toString("base64url");
20763
+ arguments = [
20764
+ "--acp",
20765
+ "--serve",
20766
+ "--host",
20767
+ "127.0.0.1",
20768
+ "--port",
20769
+ "0",
20770
+ "--auth",
20771
+ "password"
20772
+ ];
20773
+ #endpoint;
20774
+ constructor(copyId, cwd) {
20775
+ this.copyId = copyId;
20776
+ this.cwd = cwd;
20586
20777
  }
20587
- let directory = path4.dirname(selected);
20588
- for (let depth = 0; depth < 8; depth++) {
20589
- const metadata = await readFile(path4.join(directory, "package.json"), "utf8").then((text2) => JSON.parse(text2)).catch(() => null);
20590
- if (metadata?.name && packages.includes(metadata.name)) {
20591
- const name = metadata.name;
20592
- const currentVersion = installationVersion(metadata.version);
20593
- const segments = name.split("/");
20594
- let modules = directory;
20595
- for (let index = 0; index < segments.length; index++)
20596
- modules = path4.dirname(modules);
20597
- const prefix = process.platform === "win32" ? path4.dirname(modules) : path4.dirname(path4.dirname(modules));
20598
- const globalRoot = process.platform === "win32" ? path4.join(prefix, "node_modules") : path4.join(prefix, "lib", "node_modules");
20599
- const env = withNodeRuntimeOnPath(environment);
20600
- const npm = resolveHarnessExecutable({ id: "npm", command: "npm", installRoots: { posix: [], windows: [] } }, { environment: env });
20601
- let globalInstall = modules === globalRoot;
20602
- if (process.platform === "win32") {
20603
- const project = (await Promise.all(["package.json", "package-lock.json", "npm-shrinkwrap.json"].map((file2) => readFile(path4.join(prefix, file2), "utf8").then(() => true, (error51) => error51.code !== "ENOENT")))).some(Boolean);
20604
- const bins = typeof metadata.bin === "string" ? { [name.split("/").at(-1) ?? name]: metadata.bin } : metadata.bin ?? {};
20605
- const launchers = await Promise.all(Object.entries(bins).map(async ([bin, entry]) => {
20606
- if (path4.basename(bin) !== bin || entry.includes(".."))
20607
- return false;
20608
- const target = await realpath(path4.join(directory, entry)).catch(() => "");
20609
- if (target.toLowerCase() !== selected.toLowerCase())
20610
- return false;
20611
- const shim = await readFile(path4.join(prefix, `${bin}.cmd`), "utf8").catch(() => "");
20612
- return referencesNpmBin(shim, name, entry);
20613
- }));
20614
- globalInstall = globalInstall && !project && launchers.some(Boolean);
20615
- }
20616
- const canUpdate = globalInstall && !!npm;
20617
- return {
20618
- prefix,
20619
- currentVersion,
20620
- canUpdate,
20621
- latest: async () => {
20622
- const data = JSON.parse(await fetchInstallationText(`https://registry.npmjs.org/${encodeURIComponent(name)}/latest`));
20623
- return installationVersion(data.version);
20624
- },
20625
- update: async (version2) => {
20626
- if (!canUpdate || !npm)
20627
- throw new Error("Use the original package manager to update this installation");
20628
- await runInstallationCommand(npm.executable, ["install", "--global", "--prefix", prefix, `${name}@${installationVersion(version2)}`], env, 3e5);
20629
- }
20630
- };
20778
+ environment(environment) {
20779
+ return {
20780
+ ...environment,
20781
+ CODEBUDDY_GATEWAY_AUTH: "password",
20782
+ CODEBUDDY_GATEWAY_PASSWORD: this.password,
20783
+ CODEBUDDY_GATEWAY_BASE_PATH: ""
20784
+ };
20785
+ }
20786
+ /** Native --serve banners include its password; never pass them to the ACP parser/logs. */
20787
+ protocolOutput(stdout) {
20788
+ return Readable.from(this.#protocolLines(stdout));
20789
+ }
20790
+ async *#protocolLines(stdout) {
20791
+ for await (const line of createInterface({ input: stdout })) {
20792
+ const endpoint = /^\s*Endpoint\s+(http:\/\/127\.0\.0\.1:\d+)\s*$/u.exec(stripVTControlCharacters(line));
20793
+ if (endpoint)
20794
+ this.#endpoint = endpoint[1];
20795
+ if (line.trimStart().startsWith("{"))
20796
+ yield Buffer.from(`${line}
20797
+ `);
20631
20798
  }
20632
- const parent = path4.dirname(directory);
20633
- if (parent === directory)
20634
- break;
20635
- directory = parent;
20636
20799
  }
20637
- return null;
20638
- }
20639
-
20640
- // dist/command.js
20641
- var codeBuddyDiscoverySpec = {
20642
- id: "codebuddy",
20643
- command: "codebuddy",
20644
- commandEnvironmentVariable: "CODEXHOST_CODEBUDDY_COMMAND",
20645
- installRoots: {
20646
- windows: ["${APPDATA}/npm", "~/.local/bin", VERSION_MANAGER_ROOTS],
20647
- posix: [
20648
- "~/.local/bin",
20649
- "~/.npm-global/bin",
20650
- VERSION_MANAGER_ROOTS,
20651
- "/opt/homebrew/bin",
20652
- "/usr/local/bin"
20653
- ]
20800
+ async remove() {
20801
+ if (!this.#endpoint)
20802
+ throw new CodeBuddyError("nativeFailure", `Native cleanup endpoint was not reported; temporary Session ${this.copyId} remains`);
20803
+ const response = await fetch(`${this.#endpoint}/api/v1/sessions/${encodeURIComponent(this.copyId)}?cwd=${encodeURIComponent(this.cwd)}`, {
20804
+ method: "DELETE",
20805
+ headers: { Authorization: `Bearer ${this.password}`, "x-codebuddy-request": "true" },
20806
+ signal: AbortSignal.timeout(5e3),
20807
+ redirect: "error"
20808
+ }).catch(() => {
20809
+ throw new CodeBuddyError("nativeFailure", `Native cleanup request failed; temporary Session ${this.copyId} remains`);
20810
+ });
20811
+ await response.body?.cancel();
20812
+ if (response.status !== 204)
20813
+ throw new CodeBuddyError("nativeFailure", `Native cleanup failed (${response.status}); temporary Session ${this.copyId} remains`);
20654
20814
  }
20655
20815
  };
20656
- function codeBuddyInvocation(environment, ephemeral, argumentsOverride) {
20657
- const resolved = resolveHarnessExecutable(codeBuddyDiscoverySpec, { environment });
20658
- if (!resolved)
20659
- throw new CodeBuddyError("notInstalled", "CLI is not installed; run codebuddy and sign in first");
20660
- const env = withNodeRuntimeOnPath(environment);
20661
- return {
20662
- ...commandInvocation(resolved.executable, argumentsOverride ?? [
20663
- "--acp",
20664
- ...ephemeral ? ["--no-session-persistence"] : [],
20665
- ...!ephemeral && [
20666
- "CODEXHOST_CLI_PATH",
20667
- "CODEXHOST_RUNTIME_ENDPOINT",
20668
- "CODEXHOST_RUNTIME_TOKEN",
20669
- "CODEXHOST_THREAD_ID"
20670
- ].every((key) => environment[key]) ? ["--append-system-prompt", CODEBUDDY_DELEGATION_INSTRUCTIONS] : []
20671
- ], env),
20672
- environment: env
20673
- };
20674
- }
20675
- var CODEBUDDY_DELEGATION_INSTRUCTIONS = `This Session runs inside codexhost.
20676
- When the user requests cross-Harness agent delegation, use the executable at the CODEXHOST_CLI_PATH environment variable through your native shell tool. Start with its --help and harness list commands, then use delegate start and thread send/read/wait/cancel as documented by the CLI. Pass --format compact when reporting results. Keep the inherited CODEXHOST_RUNTIME_ENDPOINT, CODEXHOST_RUNTIME_TOKEN and CODEXHOST_THREAD_ID environment variables for all such calls; they identify this Runtime and parent Thread. Do not print or expose their values, replace the configured executable, or start delegation unless the user's request authorizes it. Native CodeBuddy Agent subagents remain available for CodeBuddy-only work.`;
20677
20816
 
20678
20817
  // dist/acp-client.js
20679
20818
  var CodeBuddyAcpClient = class {
@@ -20922,7 +21061,7 @@ function confirmedConfiguration(response, id, value, profile = CODEBUDDY_RUNTIME
20922
21061
  // dist/derivation.js
20923
21062
  import { randomUUID } from "node:crypto";
20924
21063
  import { execFile as execFile3, spawn as spawn2 } from "node:child_process";
20925
- import { lstat, mkdir, readFile as readFile3, realpath as realpath5, unlink, writeFile } from "node:fs/promises";
21064
+ import { lstat, mkdir, readFile as readFile3, realpath as realpath5, unlink, writeFile as writeFile2 } from "node:fs/promises";
20926
21065
  import path6 from "node:path";
20927
21066
  import { isDeepStrictEqual as isDeepStrictEqual3 } from "node:util";
20928
21067
 
@@ -21034,16 +21173,16 @@ var Diff = class {
21034
21173
  }
21035
21174
  }
21036
21175
  }
21037
- addToPath(path9, added, removed, oldPosInc, options) {
21038
- const last = path9.lastComponent;
21176
+ addToPath(path10, added, removed, oldPosInc, options) {
21177
+ const last = path10.lastComponent;
21039
21178
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
21040
21179
  return {
21041
- oldPos: path9.oldPos + oldPosInc,
21180
+ oldPos: path10.oldPos + oldPosInc,
21042
21181
  lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
21043
21182
  };
21044
21183
  } else {
21045
21184
  return {
21046
- oldPos: path9.oldPos + oldPosInc,
21185
+ oldPos: path10.oldPos + oldPosInc,
21047
21186
  lastComponent: { count: 1, added, removed, previousComponent: last }
21048
21187
  };
21049
21188
  }
@@ -22424,7 +22563,7 @@ async function bridgeCopyToTarget(sourceCwd, targetCwd, ref, contents, environme
22424
22563
  if (!sameResolvedPath(realTargetDirectory, path6.join(realProjects, codeBuddyProjectSlug(targetCwd, profile))))
22425
22564
  throw new CodeBuddyError("invalidRequest", "Cross-directory history bridge target escaped the native projects root");
22426
22565
  const expected = Buffer.from(contents, "utf8");
22427
- await writeFile(targetFile, expected, { flag: "wx", mode: 384 });
22566
+ await writeFile2(targetFile, expected, { flag: "wx", mode: 384 });
22428
22567
  const bridge = { file: targetFile, expected };
22429
22568
  try {
22430
22569
  const persisted = await readFile3(targetFile);
@@ -22554,7 +22693,7 @@ async function verifiedChildFile(file2, expected) {
22554
22693
  }
22555
22694
  async function persistChildCopy(file2, expected) {
22556
22695
  try {
22557
- await writeFile(file2, expected, { flag: "wx", mode: 384 });
22696
+ await writeFile2(file2, expected, { flag: "wx", mode: 384 });
22558
22697
  } catch (error51) {
22559
22698
  if (record2(error51).code !== "EEXIST")
22560
22699
  throw error51;
@@ -22849,6 +22988,345 @@ async function deriveCodeBuddySession(options) {
22849
22988
  }
22850
22989
  }
22851
22990
 
22991
+ // dist/session-import.js
22992
+ import { createReadStream } from "node:fs";
22993
+ import { opendir, readFile as readFile4, stat as stat2 } from "node:fs/promises";
22994
+ import path7 from "node:path";
22995
+ import { createInterface as createInterface2 } from "node:readline";
22996
+
22997
+ // ../../harness-adapter/dist/session-import.js
22998
+ import { lstat as lstat2 } from "node:fs/promises";
22999
+ var SessionImportChangedError = class extends Error {
23000
+ constructor(message = "Native Session changed during discovery; refresh and retry") {
23001
+ super(message);
23002
+ this.name = "SessionImportChangedError";
23003
+ }
23004
+ };
23005
+ function isMissingFileError(error51) {
23006
+ return typeof error51 === "object" && error51 !== null && "code" in error51 && error51.code === "ENOENT";
23007
+ }
23008
+ function sameFileFingerprint(left, right) {
23009
+ 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;
23010
+ }
23011
+ var STORAGE_ACCESS_ERRORS = /* @__PURE__ */ new Set(["EACCES", "EPERM", "EIO", "EMFILE", "ENFILE"]);
23012
+ function isStorageAccessError(error51) {
23013
+ return typeof error51 === "object" && error51 !== null && "code" in error51 && typeof error51.code === "string" && STORAGE_ACCESS_ERRORS.has(error51.code);
23014
+ }
23015
+ async function optionalLstat(file2) {
23016
+ try {
23017
+ return await lstat2(file2);
23018
+ } catch (error51) {
23019
+ if (isMissingFileError(error51))
23020
+ return null;
23021
+ throw error51;
23022
+ }
23023
+ }
23024
+ async function readStableFiles(files, read) {
23025
+ const before = await Promise.all(files.map(optionalLstat));
23026
+ const value = await read(before);
23027
+ const after = await Promise.all(files.map(optionalLstat));
23028
+ if (before.some((info, index) => !sameFileFingerprint(info, after[index] ?? null)))
23029
+ throw new SessionImportChangedError();
23030
+ return value;
23031
+ }
23032
+ function sessionImportTitle(value, maxLength = HARNESS_SESSION_IMPORT_TITLE_MAX_LENGTH) {
23033
+ if (typeof value !== "string")
23034
+ return null;
23035
+ const normalized = value.replaceAll("\0", "").replaceAll(/\s+/gu, " ").trim();
23036
+ if (!normalized)
23037
+ return null;
23038
+ if (normalized.length <= maxLength)
23039
+ return normalized;
23040
+ const characters = [...normalized];
23041
+ if (characters.length <= maxLength)
23042
+ return normalized;
23043
+ return `${characters.slice(0, maxLength - 1).join("").trimEnd()}…`;
23044
+ }
23045
+ function sessionImportCandidate(input) {
23046
+ const time3 = typeof input.updatedAt === "number" ? input.updatedAt : typeof input.updatedAt === "string" ? Date.parse(input.updatedAt) : Number.NaN;
23047
+ const parsed = harnessSessionImportCandidateSchema.safeParse({
23048
+ nativeSessionId: input.nativeSessionId,
23049
+ cwd: input.cwd,
23050
+ title: typeof input.title === "string" && input.title.trim().length > 0 ? input.title : null,
23051
+ updatedAt: Math.floor(time3),
23052
+ // Unknown must stay unknown; only an explicit boolean is a native statement.
23053
+ running: typeof input.running === "boolean" ? input.running : null
23054
+ });
23055
+ return parsed.success ? parsed.data : null;
23056
+ }
23057
+ var SessionImportScope = class {
23058
+ #abort = new AbortController();
23059
+ #options;
23060
+ #pending = /* @__PURE__ */ new Set();
23061
+ constructor(options) {
23062
+ this.#options = options;
23063
+ }
23064
+ #closed() {
23065
+ return {
23066
+ ok: false,
23067
+ error: { code: "invalidState", message: this.#options.closedMessage, retryable: false }
23068
+ };
23069
+ }
23070
+ read(operation) {
23071
+ const signal = this.#abort.signal;
23072
+ if (signal.aborted)
23073
+ return Promise.resolve(this.#closed());
23074
+ let started;
23075
+ try {
23076
+ started = operation(signal);
23077
+ } catch (error51) {
23078
+ started = Promise.reject(error51 instanceof Error ? error51 : new Error("Session read failed"));
23079
+ }
23080
+ const request = started.then((value) => signal.aborted ? this.#closed() : { ok: true, value }).catch(() => signal.aborted ? this.#closed() : {
23081
+ ok: false,
23082
+ error: {
23083
+ code: "unavailable",
23084
+ message: this.#options.unavailableMessage,
23085
+ retryable: true
23086
+ }
23087
+ }).finally(() => this.#pending.delete(request));
23088
+ this.#pending.add(request);
23089
+ return request;
23090
+ }
23091
+ /** `read` for `resolveCandidate`: a null source is the selected Session having disappeared. */
23092
+ async resolve(operation) {
23093
+ const result = await this.read(operation);
23094
+ if (!result.ok)
23095
+ return result;
23096
+ return result.value ? { ok: true, value: result.value } : {
23097
+ ok: false,
23098
+ error: {
23099
+ code: "sessionNotFound",
23100
+ message: this.#options.notFoundMessage,
23101
+ retryable: false
23102
+ }
23103
+ };
23104
+ }
23105
+ /** Idempotent. Resolves after every started read has settled. */
23106
+ async close() {
23107
+ this.#abort.abort();
23108
+ await Promise.allSettled(this.#pending);
23109
+ }
23110
+ };
23111
+
23112
+ // dist/session-import.js
23113
+ var SESSION_FILE = /^([A-Za-z0-9][A-Za-z0-9_-]{0,199})\.jsonl$/u;
23114
+ var MAX_HISTORY_BYTES = 64e6;
23115
+ var MAX_MARKER_BYTES = 64 * 1024;
23116
+ function processAlive(pid) {
23117
+ if (typeof pid !== "number" || !Number.isSafeInteger(pid) || pid <= 0)
23118
+ return false;
23119
+ try {
23120
+ process.kill(pid, 0);
23121
+ return true;
23122
+ } catch (error51) {
23123
+ return record2(error51).code === "EPERM";
23124
+ }
23125
+ }
23126
+ function userText(row) {
23127
+ if (row.type !== "message" || row.role !== "user")
23128
+ return null;
23129
+ const { content } = row;
23130
+ if (typeof content === "string")
23131
+ return content;
23132
+ if (!Array.isArray(content))
23133
+ return "";
23134
+ return content.map((part) => record2(part)).filter((part) => typeof part.text === "string").map((part) => String(part.text)).join(" ");
23135
+ }
23136
+ async function readFacts(file2, signal) {
23137
+ const stream = createReadStream(file2, { encoding: "utf8", signal });
23138
+ const lines = createInterface2({ input: stream, crlfDelay: Infinity });
23139
+ let cwd = null;
23140
+ let customTitle = null;
23141
+ let generatedTitle = null;
23142
+ let firstPrompt = null;
23143
+ let hasUser = false;
23144
+ let updatedAt = null;
23145
+ try {
23146
+ for await (const line of lines) {
23147
+ signal.throwIfAborted();
23148
+ if (!line.trim())
23149
+ continue;
23150
+ let parsed;
23151
+ try {
23152
+ parsed = JSON.parse(line);
23153
+ } catch {
23154
+ return null;
23155
+ }
23156
+ const row = record2(parsed);
23157
+ if (typeof row.cwd === "string" && path7.isAbsolute(row.cwd))
23158
+ cwd ??= row.cwd;
23159
+ if (typeof row.timestamp === "number" && Number.isFinite(row.timestamp))
23160
+ updatedAt = row.timestamp;
23161
+ if (row.type === "custom-title")
23162
+ customTitle = sessionImportTitle(row.customTitle);
23163
+ else if (row.type === "ai-title")
23164
+ generatedTitle = sessionImportTitle(row.aiTitle);
23165
+ else {
23166
+ const text2 = userText(row);
23167
+ if (text2 !== null) {
23168
+ hasUser = true;
23169
+ firstPrompt ??= sessionImportTitle(text2);
23170
+ }
23171
+ }
23172
+ }
23173
+ } finally {
23174
+ lines.close();
23175
+ stream.destroy();
23176
+ }
23177
+ if (!hasUser || !cwd)
23178
+ return null;
23179
+ return { cwd, title: customTitle ?? generatedTitle ?? firstPrompt, updatedAt };
23180
+ }
23181
+ var CodeBuddySessionImport = class {
23182
+ #environment;
23183
+ #profile;
23184
+ #scope;
23185
+ constructor(environment, profile = CODEBUDDY_RUNTIME_PROFILE) {
23186
+ this.#environment = { ...environment };
23187
+ this.#profile = profile;
23188
+ this.#scope = new SessionImportScope({
23189
+ closedMessage: `${profile.displayName} Session import is closed`,
23190
+ unavailableMessage: `${profile.displayName} sessions could not be read; close native clients, check storage access and retry`,
23191
+ notFoundMessage: `${profile.displayName} Session is no longer importable`
23192
+ });
23193
+ }
23194
+ listCandidates() {
23195
+ return this.#scope.read(async (signal) => {
23196
+ const active = await this.#activeSessions(signal);
23197
+ const candidates = [];
23198
+ for (const [nativeSessionId, files] of await this.#sessionFiles(signal)) {
23199
+ if (files.length !== 1 || !files[0])
23200
+ continue;
23201
+ try {
23202
+ const source = await this.#source(nativeSessionId, files[0], active, signal);
23203
+ if (source)
23204
+ candidates.push(source.candidate);
23205
+ } catch (error51) {
23206
+ if (!(error51 instanceof SessionImportChangedError))
23207
+ throw error51;
23208
+ }
23209
+ }
23210
+ return candidates;
23211
+ });
23212
+ }
23213
+ resolveCandidate(nativeSessionId) {
23214
+ return this.#scope.resolve(async (signal) => {
23215
+ const files = (await this.#sessionFiles(signal)).get(nativeSessionId);
23216
+ if (files?.length !== 1 || !files[0])
23217
+ return null;
23218
+ return this.#source(nativeSessionId, files[0], await this.#activeSessions(signal), signal);
23219
+ });
23220
+ }
23221
+ close() {
23222
+ return this.#scope.close();
23223
+ }
23224
+ #root() {
23225
+ return codeBuddyConfigRoot(this.#environment, this.#profile);
23226
+ }
23227
+ /** IDs a live native process registered in `<config>/sessions/<pid>.json`. */
23228
+ async #activeSessions(signal) {
23229
+ const active = /* @__PURE__ */ new Set();
23230
+ const directory = path7.join(this.#root(), "sessions");
23231
+ const markers = await opendir(directory).catch((error51) => {
23232
+ if (isMissingFileError(error51) || record2(error51).code === "ENOTDIR")
23233
+ return null;
23234
+ throw error51;
23235
+ });
23236
+ if (!markers)
23237
+ return active;
23238
+ for await (const marker of markers) {
23239
+ signal.throwIfAborted();
23240
+ if (!marker.isFile() || !marker.name.endsWith(".json"))
23241
+ continue;
23242
+ try {
23243
+ const file2 = path7.join(directory, marker.name);
23244
+ if ((await stat2(file2)).size > MAX_MARKER_BYTES)
23245
+ continue;
23246
+ const entry = record2(JSON.parse(await readFile4(file2, { encoding: "utf8", signal })));
23247
+ if (typeof entry.sessionId === "string" && processAlive(entry.pid))
23248
+ active.add(entry.sessionId);
23249
+ } catch (error51) {
23250
+ signal.throwIfAborted();
23251
+ if (isStorageAccessError(error51))
23252
+ throw error51;
23253
+ }
23254
+ }
23255
+ return active;
23256
+ }
23257
+ /** Session ID to every project file claiming it. Enumerated links are not followed. */
23258
+ async #sessionFiles(signal) {
23259
+ const root = path7.join(this.#root(), "projects");
23260
+ const found = /* @__PURE__ */ new Map();
23261
+ const info = await optionalLstat(root);
23262
+ if (!info)
23263
+ return found;
23264
+ if (!info.isDirectory())
23265
+ throw new Error(`${this.#profile.displayName} Session store is not a directory`);
23266
+ for await (const project of await opendir(root)) {
23267
+ signal.throwIfAborted();
23268
+ if (!project.isDirectory())
23269
+ continue;
23270
+ const projectDirectory = path7.join(root, project.name);
23271
+ const entries = await opendir(projectDirectory).catch((error51) => {
23272
+ if (isMissingFileError(error51))
23273
+ return null;
23274
+ throw error51;
23275
+ });
23276
+ if (!entries)
23277
+ continue;
23278
+ for await (const entry of entries) {
23279
+ signal.throwIfAborted();
23280
+ const nativeSessionId = entry.isFile() ? SESSION_FILE.exec(entry.name)?.[1] : void 0;
23281
+ if (!nativeSessionId)
23282
+ continue;
23283
+ const files = found.get(nativeSessionId) ?? [];
23284
+ files.push(path7.join(projectDirectory, entry.name));
23285
+ found.set(nativeSessionId, files);
23286
+ }
23287
+ }
23288
+ return found;
23289
+ }
23290
+ async #source(nativeSessionId, file2, active, signal) {
23291
+ signal.throwIfAborted();
23292
+ return readStableFiles([file2], async ([info]) => {
23293
+ if (!info?.isFile() || info.size === 0 || info.size > MAX_HISTORY_BYTES)
23294
+ return null;
23295
+ try {
23296
+ const facts = await readFacts(file2, signal);
23297
+ if (!facts)
23298
+ return null;
23299
+ const cwd = path7.resolve(facts.cwd);
23300
+ if (!(await stat2(cwd)).isDirectory())
23301
+ return null;
23302
+ const nativeRef = nativeSessionRefSchema.parse({
23303
+ harnessId: this.#profile.harnessId,
23304
+ nativeSessionId,
23305
+ formatVersion: 1
23306
+ });
23307
+ signal.throwIfAborted();
23308
+ const history = await codeBuddyNativeHistory(cwd, nativeRef, this.#environment, this.#profile);
23309
+ if (path7.resolve(history.file) !== path7.resolve(file2))
23310
+ return null;
23311
+ const candidate = sessionImportCandidate({
23312
+ nativeSessionId,
23313
+ cwd,
23314
+ title: facts.title,
23315
+ updatedAt: facts.updatedAt ?? info.mtimeMs,
23316
+ // A registered live process holds the Session. Absence is not proof of idleness.
23317
+ running: active.has(nativeSessionId) ? true : null
23318
+ });
23319
+ return candidate ? { candidate, nativeRef } : null;
23320
+ } catch (error51) {
23321
+ signal.throwIfAborted();
23322
+ if (isStorageAccessError(error51))
23323
+ throw error51;
23324
+ return null;
23325
+ }
23326
+ });
23327
+ }
23328
+ };
23329
+
22852
23330
  // dist/interactions.js
22853
23331
  var CodeBuddyInteractions = class {
22854
23332
  emit;
@@ -22992,7 +23470,7 @@ var CodeBuddyInteractions = class {
22992
23470
 
22993
23471
  // dist/subagent-history.js
22994
23472
  import { readdir as readdir2, realpath as realpath6 } from "node:fs/promises";
22995
- import path7 from "node:path";
23473
+ import path8 from "node:path";
22996
23474
  var equalPath2 = (a, b) => process.platform === "win32" ? a.toLowerCase() === b.toLowerCase() : a === b;
22997
23475
  var MAX_CACHED_CHILDREN = 16;
22998
23476
  var CodeBuddyChildObserver = class {
@@ -23056,8 +23534,8 @@ var CodeBuddyChildObserver = class {
23056
23534
  }
23057
23535
  async #directory() {
23058
23536
  const history = await this.#parentHistory();
23059
- const project = path7.dirname(await realpath6(history.file));
23060
- const expected = path7.join(project, this.parent.nativeSessionId, "subagents");
23537
+ const project = path8.dirname(await realpath6(history.file));
23538
+ const expected = path8.join(project, this.parent.nativeSessionId, "subagents");
23061
23539
  const actual = await realpath6(expected);
23062
23540
  this.#assertOpen();
23063
23541
  if (!equalPath2(actual, expected))
@@ -23067,7 +23545,7 @@ var CodeBuddyChildObserver = class {
23067
23545
  async #child(directory, childId) {
23068
23546
  if (!validCodeBuddyChildId(childId))
23069
23547
  throw new CodeBuddyError("invalidRequest", "Invalid native Subagent ID");
23070
- const file2 = path7.join(directory, `${childId}.jsonl`);
23548
+ const file2 = path8.join(directory, `${childId}.jsonl`);
23071
23549
  const before = await codeBuddyFileVersion(file2);
23072
23550
  if (!equalPath2(before.realFile, file2))
23073
23551
  throw new CodeBuddyError("invalidRequest", "Redirected Subagent transcript");
@@ -23779,6 +24257,7 @@ var CodeBuddyAdapter = class {
23779
24257
  harnessId;
23780
24258
  commandCatalog;
23781
24259
  liveCommandCatalog = true;
24260
+ sessionImport;
23782
24261
  subagents = {
23783
24262
  readSnapshot: async ({ parent, nativeSubagentId, cwd }) => {
23784
24263
  try {
@@ -23812,6 +24291,7 @@ var CodeBuddyAdapter = class {
23812
24291
  this.commandCatalog = commandCatalog2;
23813
24292
  }
23814
24293
  this.#environment = { ...options.environment ?? process.env };
24294
+ this.sessionImport = new CodeBuddySessionImport(this.#environment, this.#profile);
23815
24295
  this.#invocation = options.invocationFactory ?? codeBuddyInvocation;
23816
24296
  this.#factory = options.clientFactory ?? ((clientOptions) => new CodeBuddyAcpClient(clientOptions, void 0, this.#invocation));
23817
24297
  }
@@ -23831,7 +24311,7 @@ var CodeBuddyAdapter = class {
23831
24311
  try {
23832
24312
  if (this.#closed)
23833
24313
  throw new CodeBuddyError("invalidState", "Adapter is closed");
23834
- if (!(await stat2(cwd)).isDirectory())
24314
+ if (!(await stat3(cwd)).isDirectory())
23835
24315
  throw new CodeBuddyError("invalidRequest", "Working directory is not a directory");
23836
24316
  client2 = this.#factory({
23837
24317
  cwd,
@@ -23877,7 +24357,7 @@ var CodeBuddyAdapter = class {
23877
24357
  return failure("invalidRequest", "Unattended execution requires native fullAccess permissions", this.#profile);
23878
24358
  let session;
23879
24359
  try {
23880
- if (!(await stat2(input.cwd)).isDirectory())
24360
+ if (!(await stat3(input.cwd)).isDirectory())
23881
24361
  throw new CodeBuddyError("invalidRequest", "Working directory is not a directory");
23882
24362
  if (this.#closed)
23883
24363
  throw new CodeBuddyError("invalidState", "Adapter closed while opening Session");
@@ -23940,7 +24420,7 @@ var CodeBuddyAdapter = class {
23940
24420
  async close() {
23941
24421
  this.#closed = true;
23942
24422
  this.#abort.abort();
23943
- await Promise.allSettled([...this.#derivations]);
24423
+ await Promise.allSettled([this.sessionImport.close(), ...this.#derivations]);
23944
24424
  const results = await Promise.allSettled([...this.#sessions, ...this.#inspections].map((resource) => resource.close()));
23945
24425
  this.#sessions.clear();
23946
24426
  this.#inspections.clear();
@@ -23970,6 +24450,7 @@ function createCodeBuddyInstallation(environment) {
23970
24450
  updateAvailable: !!npm && newerInstallationVersion(currentVersion, latestVersion),
23971
24451
  canUpdate,
23972
24452
  ...!canUpdate ? {
24453
+ messageCode: "codebuddy-npm-required",
23973
24454
  message: "Use CodeBuddy's native updater or original package manager for this installation. Latest-version checks here require an identified npm installation."
23974
24455
  } : {}
23975
24456
  };
@@ -23983,8 +24464,9 @@ function createCodeBuddyInstallation(environment) {
23983
24464
  }
23984
24465
 
23985
24466
  // ../../harness-broker/dist/client.js
24467
+ import { execFile as execFile4 } from "node:child_process";
23986
24468
  import { randomUUID as randomUUID2 } from "node:crypto";
23987
- import { lstat as lstat2, readFile as readFile4 } from "node:fs/promises";
24469
+ import { lstat as lstat3, readFile as readFile5 } from "node:fs/promises";
23988
24470
  import net, {} from "node:net";
23989
24471
 
23990
24472
  // ../../harness-broker/dist/protocol.js
@@ -23992,9 +24474,12 @@ var HARNESS_BROKER_PROTOCOL_VERSION = 1;
23992
24474
  var HARNESS_BROKER_MAX_FRAME_BYTES = 8 * 1024 * 1024;
23993
24475
  var HARNESS_BROKER_MAX_PENDING_REQUESTS = 32;
23994
24476
  var HARNESS_BROKER_REQUEST_TIMEOUT_MS = 15e3;
24477
+ var HARNESS_BROKER_IDLE_TIMEOUT_MS = 60 * 60 * 1e3;
24478
+ var HARNESS_BROKER_RETIRING_ERROR_CODE = "brokerRetiring";
23995
24479
  var harnessBrokerMethodSchema = external_exports.enum([
23996
24480
  "adapter.inspect",
23997
24481
  "adapter.inspectAccount",
24482
+ "adapter.credits",
23998
24483
  "adapter.open",
23999
24484
  "adapter.subagent.readSnapshot",
24000
24485
  "session.readSnapshot",
@@ -24099,18 +24584,26 @@ function consumeBrokerFrames(socket, onFrame, onError) {
24099
24584
 
24100
24585
  // ../../harness-broker/dist/paths.js
24101
24586
  import os2 from "node:os";
24102
- import path8 from "node:path";
24587
+ import path9 from "node:path";
24103
24588
  var HARNESS_BROKER_DESCRIPTOR_ENV = "CODEXHOST_CLAUDE_BROKER_DESCRIPTOR";
24104
24589
  var HARNESS_BROKER_DESCRIPTOR_FILE = "claude-code-broker-v1.json";
24105
24590
  function defaultHarnessBrokerDirectory(environment = process.env) {
24106
24591
  const home = environment.HOME || os2.homedir();
24107
- return path8.join(home, ".codexhost", "harness-broker");
24592
+ return path9.join(home, ".codexhost", "harness-broker");
24108
24593
  }
24109
24594
  function defaultHarnessBrokerDescriptorPath(environment = process.env, harnessId = "claude-code") {
24110
24595
  harnessPluginIdSchema.parse(harnessId);
24111
24596
  if (harnessId !== "claude-code")
24112
- return path8.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.json`);
24113
- return environment[HARNESS_BROKER_DESCRIPTOR_ENV] ?? path8.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_DESCRIPTOR_FILE);
24597
+ return path9.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.json`);
24598
+ return environment[HARNESS_BROKER_DESCRIPTOR_ENV] ?? path9.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_DESCRIPTOR_FILE);
24599
+ }
24600
+ function harnessBrokerLaunchAgentLabel(harnessId = "claude-code") {
24601
+ harnessPluginIdSchema.parse(harnessId);
24602
+ return harnessId === "claude-code" ? "ai.bytepioneer.codexhost.native-harness-broker" : `ai.bytepioneer.codexhost.${harnessId}-broker`;
24603
+ }
24604
+ function harnessBrokerLaunchAgentPlistPath(environment = process.env, harnessId = "claude-code") {
24605
+ const home = environment.HOME || os2.homedir();
24606
+ return path9.join(home, "Library", "LaunchAgents", `${harnessBrokerLaunchAgentLabel(harnessId)}.plist`);
24114
24607
  }
24115
24608
 
24116
24609
  // ../../harness-broker/dist/validation.js
@@ -24389,7 +24882,7 @@ function parseSessionMetadata(value) {
24389
24882
  };
24390
24883
  }
24391
24884
  async function readDescriptor(descriptorPath) {
24392
- const metadata = await lstat2(descriptorPath);
24885
+ const metadata = await lstat3(descriptorPath);
24393
24886
  if (metadata.isSymbolicLink())
24394
24887
  throw new Error("Aqua Harness broker descriptor must not be a symlink");
24395
24888
  if (!metadata.isFile())
@@ -24401,12 +24894,12 @@ async function readDescriptor(descriptorPath) {
24401
24894
  throw new Error("Aqua Harness broker descriptor belongs to another user");
24402
24895
  }
24403
24896
  }
24404
- const descriptor = harnessBrokerDescriptorSchema.parse(JSON.parse(await readFile4(descriptorPath, "utf8")));
24897
+ const descriptor = harnessBrokerDescriptorSchema.parse(JSON.parse(await readFile5(descriptorPath, "utf8")));
24405
24898
  if (process.platform === "darwin" && Buffer.byteLength(descriptor.socketPath) > 103) {
24406
24899
  throw new Error("Aqua Harness broker socket path is too long for macOS");
24407
24900
  }
24408
24901
  if (process.platform !== "win32") {
24409
- const socket = await lstat2(descriptor.socketPath);
24902
+ const socket = await lstat3(descriptor.socketPath);
24410
24903
  if (socket.isSymbolicLink() || !socket.isSocket()) {
24411
24904
  throw new Error("Aqua Harness broker endpoint is not a Unix socket");
24412
24905
  }
@@ -24417,10 +24910,55 @@ async function readDescriptor(descriptorPath) {
24417
24910
  try {
24418
24911
  process.kill(descriptor.ownerPid, 0);
24419
24912
  } catch {
24420
- throw new Error("Aqua Harness broker owner process is unavailable");
24913
+ throw new BrokerNotRunningError("its owner process has exited");
24421
24914
  }
24422
24915
  return descriptor;
24423
24916
  }
24917
+ var BrokerNotRunningError = class extends Error {
24918
+ };
24919
+ var BrokerRetiringError = class extends Error {
24920
+ };
24921
+ var BrokerRequestNotDeliveredError = class extends Error {
24922
+ };
24923
+ var HarnessNotInstalledError = class extends Error {
24924
+ };
24925
+ var BROKER_NOT_RUNNING_CODES = /* @__PURE__ */ new Set(["ENOENT", "ECONNREFUSED"]);
24926
+ var BROKER_START_TIMEOUT_MS = 15e3;
24927
+ var BROKER_START_POLL_MS = 250;
24928
+ function classifyConnectFailure(error51) {
24929
+ if (error51 instanceof BrokerNotRunningError)
24930
+ return error51;
24931
+ const code = error51?.code;
24932
+ if (code && BROKER_NOT_RUNNING_CODES.has(code)) {
24933
+ return new BrokerNotRunningError(code === "ENOENT" ? "its descriptor or socket is missing" : "its socket refused the connection");
24934
+ }
24935
+ return error51 instanceof Error ? error51 : new Error(String(error51));
24936
+ }
24937
+ function describeBrokerFailure(error51, harnessId) {
24938
+ if (error51 instanceof BrokerNotRunningError) {
24939
+ return `The ${harnessId} Aqua Harness broker on this Mac could not be started (${error51.message}). Keep the desktop user logged in, then repair the remote service or run on this Mac: codexhost broker install --harness ${harnessId}`;
24940
+ }
24941
+ return error51 instanceof Error ? error51.message : String(error51);
24942
+ }
24943
+ function runLaunchctl(arguments_) {
24944
+ return new Promise((resolve) => {
24945
+ execFile4("/bin/launchctl", arguments_, { timeout: 1e4 }, (error51) => resolve(!error51));
24946
+ });
24947
+ }
24948
+ async function startBrokerLaunchAgent(harnessId, environment) {
24949
+ const uid = process.getuid?.();
24950
+ if (uid === void 0)
24951
+ return;
24952
+ const target = `gui/${uid}/${harnessBrokerLaunchAgentLabel(harnessId)}`;
24953
+ if (await runLaunchctl(["kickstart", target]))
24954
+ return;
24955
+ await runLaunchctl([
24956
+ "bootstrap",
24957
+ `gui/${uid}`,
24958
+ harnessBrokerLaunchAgentPlistPath(environment, harnessId)
24959
+ ]);
24960
+ await runLaunchctl(["kickstart", target]);
24961
+ }
24424
24962
  var BrokerConnection = class _BrokerConnection {
24425
24963
  #onClose;
24426
24964
  onClose(callback) {
@@ -24444,21 +24982,31 @@ var BrokerConnection = class _BrokerConnection {
24444
24982
  socket.once("error", (error51) => this.#fail(error51));
24445
24983
  }
24446
24984
  static async connect(descriptorPath, harnessId) {
24447
- const descriptor = await readDescriptor(descriptorPath);
24448
- if (descriptor.harnessId !== harnessId)
24449
- throw new Error("Aqua broker belongs to another Harness");
24450
- const socket = net.createConnection(descriptor.socketPath);
24451
- await new Promise((resolve, reject) => {
24452
- const timeout = setTimeout(() => reject(new Error("Timed out connecting to Aqua Harness broker")), HARNESS_BROKER_REQUEST_TIMEOUT_MS);
24453
- socket.once("connect", () => {
24454
- clearTimeout(timeout);
24455
- resolve();
24456
- });
24457
- socket.once("error", (error51) => {
24458
- clearTimeout(timeout);
24459
- reject(error51);
24985
+ let descriptor;
24986
+ let socket;
24987
+ let connecting;
24988
+ try {
24989
+ descriptor = await readDescriptor(descriptorPath);
24990
+ if (descriptor.harnessId !== harnessId)
24991
+ throw new Error("Aqua broker belongs to another Harness");
24992
+ connecting = net.createConnection(descriptor.socketPath);
24993
+ const pending = connecting;
24994
+ await new Promise((resolve, reject) => {
24995
+ const timeout = setTimeout(() => reject(new Error("Timed out connecting to Aqua Harness broker")), HARNESS_BROKER_REQUEST_TIMEOUT_MS);
24996
+ pending.once("connect", () => {
24997
+ clearTimeout(timeout);
24998
+ resolve();
24999
+ });
25000
+ pending.once("error", (error51) => {
25001
+ clearTimeout(timeout);
25002
+ reject(error51);
25003
+ });
24460
25004
  });
24461
- });
25005
+ socket = pending;
25006
+ } catch (error51) {
25007
+ connecting?.destroy();
25008
+ throw classifyConnectFailure(error51);
25009
+ }
24462
25010
  const connection = new _BrokerConnection(descriptor, socket);
24463
25011
  const hello = connection.#waitForHello();
24464
25012
  await writeBrokerFrame(socket, {
@@ -24511,15 +25059,24 @@ var BrokerConnection = class _BrokerConnection {
24511
25059
  }, HARNESS_BROKER_REQUEST_TIMEOUT_MS);
24512
25060
  this.#pending.set(id, { resolve, reject, timeout });
24513
25061
  });
24514
- await writeBrokerFrame(this.#socket, {
24515
- version: HARNESS_BROKER_PROTOCOL_VERSION,
24516
- generation: this.#descriptor.generation,
24517
- sequence: this.#inputSequence,
24518
- kind: "request",
24519
- id,
24520
- method,
24521
- params
24522
- });
25062
+ try {
25063
+ await writeBrokerFrame(this.#socket, {
25064
+ version: HARNESS_BROKER_PROTOCOL_VERSION,
25065
+ generation: this.#descriptor.generation,
25066
+ sequence: this.#inputSequence,
25067
+ kind: "request",
25068
+ id,
25069
+ method,
25070
+ params
25071
+ });
25072
+ } catch (error51) {
25073
+ const pending = this.#pending.get(id);
25074
+ if (pending)
25075
+ clearTimeout(pending.timeout);
25076
+ this.#pending.delete(id);
25077
+ response.catch(() => void 0);
25078
+ throw new BrokerRequestNotDeliveredError(error51 instanceof Error ? error51.message : String(error51));
25079
+ }
24523
25080
  return response;
24524
25081
  }
24525
25082
  close() {
@@ -24563,6 +25120,8 @@ var BrokerConnection = class _BrokerConnection {
24563
25120
  this.#pending.delete(frame.id);
24564
25121
  if (frame.ok)
24565
25122
  pending.resolve(frame.value);
25123
+ else if (frame.error?.code === HARNESS_BROKER_RETIRING_ERROR_CODE)
25124
+ pending.reject(new BrokerRetiringError(frame.error.message));
24566
25125
  else
24567
25126
  pending.reject(new Error(frame.error?.message ?? "Broker request failed"));
24568
25127
  }
@@ -24788,17 +25347,19 @@ var BrokeredHarnessAdapter = class {
24788
25347
  harnessId;
24789
25348
  #descriptorPath;
24790
25349
  #forwardEnvironment;
25350
+ #isInstalled;
25351
+ #startBroker;
25352
+ #startTimeoutMs;
24791
25353
  #connection = null;
24792
25354
  #closed = false;
25355
+ #credits = null;
25356
+ #creditsRefresh = null;
24793
25357
  subagents = {
24794
25358
  readSnapshot: async (input) => {
24795
25359
  try {
24796
- return parseHarnessResult(await (await this.#connect()).request("adapter.subagent.readSnapshot", input));
25360
+ return parseHarnessResult(await this.#request("adapter.subagent.readSnapshot", input));
24797
25361
  } catch (error51) {
24798
- return {
24799
- ok: false,
24800
- error: unavailable(error51 instanceof Error ? error51.message : String(error51))
24801
- };
25362
+ return { ok: false, error: this.#error(error51) };
24802
25363
  }
24803
25364
  }
24804
25365
  };
@@ -24810,12 +25371,39 @@ var BrokeredHarnessAdapter = class {
24810
25371
  if (input.liveCommandCatalog)
24811
25372
  this.liveCommandCatalog = true;
24812
25373
  this.#descriptorPath = input.descriptorPath ?? defaultHarnessBrokerDescriptorPath(input.environment, this.harnessId);
25374
+ this.#isInstalled = input.isInstalled;
25375
+ const environment = input.environment ?? process.env;
25376
+ this.#startBroker = input.startBroker === false ? void 0 : input.startBroker ?? (process.platform === "darwin" && !input.descriptorPath ? () => startBrokerLaunchAgent(this.harnessId, environment) : void 0);
25377
+ this.#startTimeoutMs = input.startTimeoutMs ?? BROKER_START_TIMEOUT_MS;
25378
+ }
25379
+ credits() {
25380
+ return this.#credits;
25381
+ }
25382
+ refreshCredits() {
25383
+ if (this.#closed)
25384
+ return Promise.resolve(null);
25385
+ if (this.#creditsRefresh)
25386
+ return this.#creditsRefresh;
25387
+ this.#creditsRefresh = this.#readCredits().finally(() => {
25388
+ this.#creditsRefresh = null;
25389
+ });
25390
+ return this.#creditsRefresh;
25391
+ }
25392
+ async #readCredits() {
25393
+ try {
25394
+ const value = await this.#request("adapter.credits", {}, true);
25395
+ const credits = accountCreditsSnapshotSchema.nullable().parse(value);
25396
+ if (!this.#closed)
25397
+ this.#credits = credits;
25398
+ } catch {
25399
+ }
25400
+ return this.#credits;
24813
25401
  }
24814
25402
  async inspectAccount() {
24815
25403
  if (this.#closed)
24816
25404
  return null;
24817
25405
  try {
24818
- const value = await (await this.#connect()).request("adapter.inspectAccount", {});
25406
+ const value = await this.#request("adapter.inspectAccount", {}, true);
24819
25407
  return harnessAccountSnapshotSchema.nullable().parse(value);
24820
25408
  } catch {
24821
25409
  return null;
@@ -24825,33 +25413,46 @@ var BrokeredHarnessAdapter = class {
24825
25413
  if (this.#closed)
24826
25414
  return failedInspection("Aqua Harness broker adapter is closed");
24827
25415
  try {
24828
- return harnessInspectionSchema.parse(await (await this.#connect()).request("adapter.inspect", input));
25416
+ return harnessInspectionSchema.parse(await this.#request("adapter.inspect", input, true));
24829
25417
  } catch (error51) {
24830
25418
  this.#connection = null;
24831
- return failedInspection(error51 instanceof Error ? error51.message : String(error51));
25419
+ if (error51 instanceof HarnessNotInstalledError)
25420
+ return { status: "notInstalled", error: this.#error(error51) };
25421
+ return failedInspection(describeBrokerFailure(error51, this.harnessId));
24832
25422
  }
24833
25423
  }
24834
25424
  async open(input) {
24835
25425
  if (this.#closed)
24836
25426
  return { ok: false, error: unavailable("Aqua Harness broker adapter is closed", false) };
25427
+ const safeInput = { ...input };
25428
+ delete safeInput.environment;
25429
+ if (this.#forwardEnvironment && input.environment) {
25430
+ const allowed = [
25431
+ "CODEXHOST_CLI_PATH",
25432
+ "CODEXHOST_CLI_NODE_PATH",
25433
+ "CODEXHOST_RUNTIME_ENDPOINT",
25434
+ "CODEXHOST_RUNTIME_TOKEN",
25435
+ "CODEXHOST_THREAD_ID"
25436
+ ];
25437
+ const environment = Object.fromEntries(Object.entries(input.environment).filter(([key, value]) => allowed.includes(key) && value !== void 0));
25438
+ if (Object.keys(environment).length)
25439
+ safeInput.environment = environment;
25440
+ }
24837
25441
  let connection;
24838
25442
  try {
24839
- const safeInput = { ...input };
24840
- delete safeInput.environment;
24841
- if (this.#forwardEnvironment && input.environment) {
24842
- const allowed = [
24843
- "CODEXHOST_CLI_PATH",
24844
- "CODEXHOST_CLI_NODE_PATH",
24845
- "CODEXHOST_RUNTIME_ENDPOINT",
24846
- "CODEXHOST_RUNTIME_TOKEN",
24847
- "CODEXHOST_THREAD_ID"
24848
- ];
24849
- const environment = Object.fromEntries(Object.entries(input.environment).filter(([key, value]) => allowed.includes(key) && value !== void 0));
24850
- if (Object.keys(environment).length)
24851
- safeInput.environment = environment;
24852
- }
24853
- connection = await this.#connect();
24854
- const result = parseHarnessResult(await connection.request("adapter.open", safeInput));
25443
+ let value;
25444
+ for (let attempt = 0; ; attempt += 1) {
25445
+ connection = await this.#connect();
25446
+ try {
25447
+ value = await connection.request("adapter.open", safeInput);
25448
+ break;
25449
+ } catch (error51) {
25450
+ if (attempt > 0 || !(error51 instanceof BrokerRetiringError || error51 instanceof BrokerRequestNotDeliveredError))
25451
+ throw error51;
25452
+ this.#connection = null;
25453
+ }
25454
+ }
25455
+ const result = parseHarnessResult(value);
24855
25456
  if (!result.ok)
24856
25457
  return result;
24857
25458
  const session = new BrokeredHarnessSession(connection, parseSessionMetadata(result.value), this.harnessId, safeInput, () => this.#connect(), () => {
@@ -24862,25 +25463,51 @@ var BrokeredHarnessAdapter = class {
24862
25463
  } catch (error51) {
24863
25464
  connection?.close();
24864
25465
  this.#connection = null;
24865
- return {
24866
- ok: false,
24867
- error: unavailable(error51 instanceof Error ? error51.message : String(error51))
24868
- };
25466
+ return { ok: false, error: this.#error(error51) };
24869
25467
  }
24870
25468
  }
24871
25469
  async close() {
24872
25470
  this.#closed = true;
25471
+ this.#credits = null;
24873
25472
  await Promise.allSettled([...this.#sessions].map((session) => session.close()));
24874
25473
  this.#sessions.clear();
24875
25474
  const connection = await this.#connection?.catch(() => null);
24876
25475
  await connection?.dispose();
24877
25476
  this.#connection = null;
24878
25477
  }
25478
+ #error(error51) {
25479
+ if (error51 instanceof HarnessNotInstalledError)
25480
+ return {
25481
+ code: "notInstalled",
25482
+ message: error51.message,
25483
+ retryable: false,
25484
+ stage: "harnessBroker"
25485
+ };
25486
+ return unavailable(describeBrokerFailure(error51, this.harnessId));
25487
+ }
25488
+ /**
25489
+ * Sends one adapter-level request. A broker that retired between requests refuses it
25490
+ * unprocessed, so it is retried once on a fresh broker. Idempotent reads also retry
25491
+ * once after a plain disconnect.
25492
+ */
25493
+ async #request(method, params, idempotent = false) {
25494
+ for (let attempt = 0; ; attempt += 1) {
25495
+ const connection = await this.#connect();
25496
+ try {
25497
+ return await connection.request(method, params);
25498
+ } catch (error51) {
25499
+ const retryable = error51 instanceof BrokerRetiringError || error51 instanceof BrokerRequestNotDeliveredError || idempotent && connection.closed;
25500
+ if (attempt > 0 || !retryable)
25501
+ throw error51;
25502
+ this.#connection = null;
25503
+ }
25504
+ }
25505
+ }
24879
25506
  #connect() {
24880
25507
  if (this.#closed)
24881
25508
  return Promise.reject(new Error("Aqua Harness broker adapter is closed"));
24882
25509
  if (!this.#connection) {
24883
- const pending = BrokerConnection.connect(this.#descriptorPath, this.harnessId).then((connection) => {
25510
+ const pending = this.#establish().then((connection) => {
24884
25511
  connection.onClose(() => {
24885
25512
  if (this.#connection === pending)
24886
25513
  this.#connection = null;
@@ -24895,21 +25522,47 @@ var BrokeredHarnessAdapter = class {
24895
25522
  }
24896
25523
  return this.#connection;
24897
25524
  }
25525
+ async #establish() {
25526
+ try {
25527
+ return await BrokerConnection.connect(this.#descriptorPath, this.harnessId);
25528
+ } catch (error51) {
25529
+ if (!(error51 instanceof BrokerNotRunningError) || !this.#startBroker)
25530
+ throw error51;
25531
+ }
25532
+ if (this.#isInstalled && !this.#isInstalled()) {
25533
+ throw new HarnessNotInstalledError(`${this.harnessId} is not installed on this Mac`);
25534
+ }
25535
+ const deadline = Date.now() + this.#startTimeoutMs;
25536
+ for (; ; ) {
25537
+ await this.#startBroker();
25538
+ try {
25539
+ return await BrokerConnection.connect(this.#descriptorPath, this.harnessId);
25540
+ } catch (error51) {
25541
+ if (!(error51 instanceof BrokerNotRunningError) || Date.now() >= deadline)
25542
+ throw error51;
25543
+ }
25544
+ await new Promise((resolve) => setTimeout(resolve, BROKER_START_POLL_MS));
25545
+ }
25546
+ }
24898
25547
  };
24899
25548
 
24900
25549
  // dist/plugin.js
24901
25550
  function createHarnessAdapter(context) {
24902
- if (context.platform === "darwin" && context.managedRemoteHost)
25551
+ if (context.platform === "darwin" && context.managedRemoteHost) {
25552
+ const environment2 = { ...context.environment };
24903
25553
  return new BrokeredHarnessAdapter({
24904
25554
  harnessId: "codebuddy",
24905
25555
  forwardDelegationEnvironment: true,
24906
25556
  commandCatalog: CODEBUDDY_COMMAND_CATALOG,
24907
25557
  liveCommandCatalog: true,
24908
- environment: { ...context.environment }
25558
+ environment: environment2,
25559
+ isInstalled: () => resolveHarnessExecutable(codeBuddyDiscoverySpec, { environment: environment2 }) !== void 0
24909
25560
  });
25561
+ }
24910
25562
  const environment = { ...context.environment };
24911
25563
  return Object.assign(new CodeBuddyAdapter({ environment }), {
24912
- installation: createCodeBuddyInstallation(environment)
25564
+ installation: createCodeBuddyInstallation(environment),
25565
+ install: createHarnessInstaller(environment, { npm: "@tencent-ai/codebuddy-code" })
24913
25566
  });
24914
25567
  }
24915
25568
  export {