@codexhost/cli-darwin-x64 0.11.0 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,6 +6,7 @@ var __export = (target, all) => {
6
6
  };
7
7
 
8
8
  // ../../harness-broker/dist/client.js
9
+ import { execFile } from "node:child_process";
9
10
  import { randomUUID } from "node:crypto";
10
11
  import { lstat, readFile } from "node:fs/promises";
11
12
  import net, {} from "node:net";
@@ -776,10 +777,10 @@ function mergeDefs(...defs) {
776
777
  function cloneDef(schema) {
777
778
  return mergeDefs(schema._zod.def);
778
779
  }
779
- function getElementAtPath(obj, path9) {
780
- if (!path9)
780
+ function getElementAtPath(obj, path10) {
781
+ if (!path10)
781
782
  return obj;
782
- return path9.reduce((acc, key) => acc?.[key], obj);
783
+ return path10.reduce((acc, key) => acc?.[key], obj);
783
784
  }
784
785
  function promiseAllObject(promisesObj) {
785
786
  const keys = Object.keys(promisesObj);
@@ -1188,11 +1189,11 @@ function explicitlyAborted(x, startIndex = 0) {
1188
1189
  }
1189
1190
  return false;
1190
1191
  }
1191
- function prefixIssues(path9, issues) {
1192
+ function prefixIssues(path10, issues) {
1192
1193
  return issues.map((iss) => {
1193
1194
  var _a3;
1194
1195
  (_a3 = iss).path ?? (_a3.path = []);
1195
- iss.path.unshift(path9);
1196
+ iss.path.unshift(path10);
1196
1197
  return iss;
1197
1198
  });
1198
1199
  }
@@ -1339,16 +1340,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
1339
1340
  }
1340
1341
  function formatError(error51, mapper = (issue2) => issue2.message) {
1341
1342
  const fieldErrors = { _errors: [] };
1342
- const processError = (error52, path9 = []) => {
1343
+ const processError = (error52, path10 = []) => {
1343
1344
  for (const issue2 of error52.issues) {
1344
1345
  if (issue2.code === "invalid_union" && issue2.errors.length) {
1345
- issue2.errors.map((issues) => processError({ issues }, [...path9, ...issue2.path]));
1346
+ issue2.errors.map((issues) => processError({ issues }, [...path10, ...issue2.path]));
1346
1347
  } else if (issue2.code === "invalid_key") {
1347
- processError({ issues: issue2.issues }, [...path9, ...issue2.path]);
1348
+ processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
1348
1349
  } else if (issue2.code === "invalid_element") {
1349
- processError({ issues: issue2.issues }, [...path9, ...issue2.path]);
1350
+ processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
1350
1351
  } else {
1351
- const fullpath = [...path9, ...issue2.path];
1352
+ const fullpath = [...path10, ...issue2.path];
1352
1353
  if (fullpath.length === 0) {
1353
1354
  fieldErrors._errors.push(mapper(issue2));
1354
1355
  } else {
@@ -1375,17 +1376,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
1375
1376
  }
1376
1377
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
1377
1378
  const result = { errors: [] };
1378
- const processError = (error52, path9 = []) => {
1379
+ const processError = (error52, path10 = []) => {
1379
1380
  var _a3, _b;
1380
1381
  for (const issue2 of error52.issues) {
1381
1382
  if (issue2.code === "invalid_union" && issue2.errors.length) {
1382
- issue2.errors.map((issues) => processError({ issues }, [...path9, ...issue2.path]));
1383
+ issue2.errors.map((issues) => processError({ issues }, [...path10, ...issue2.path]));
1383
1384
  } else if (issue2.code === "invalid_key") {
1384
- processError({ issues: issue2.issues }, [...path9, ...issue2.path]);
1385
+ processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
1385
1386
  } else if (issue2.code === "invalid_element") {
1386
- processError({ issues: issue2.issues }, [...path9, ...issue2.path]);
1387
+ processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
1387
1388
  } else {
1388
- const fullpath = [...path9, ...issue2.path];
1389
+ const fullpath = [...path10, ...issue2.path];
1389
1390
  if (fullpath.length === 0) {
1390
1391
  result.errors.push(mapper(issue2));
1391
1392
  continue;
@@ -1417,8 +1418,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
1417
1418
  }
1418
1419
  function toDotPath(_path) {
1419
1420
  const segs = [];
1420
- const path9 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1421
- for (const seg of path9) {
1421
+ const path10 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1422
+ for (const seg of path10) {
1422
1423
  if (typeof seg === "number")
1423
1424
  segs.push(`[${seg}]`);
1424
1425
  else if (typeof seg === "symbol")
@@ -14110,13 +14111,13 @@ function resolveRef(ref, ctx) {
14110
14111
  if (!ref.startsWith("#")) {
14111
14112
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
14112
14113
  }
14113
- const path9 = ref.slice(1).split("/").filter(Boolean);
14114
- if (path9.length === 0) {
14114
+ const path10 = ref.slice(1).split("/").filter(Boolean);
14115
+ if (path10.length === 0) {
14115
14116
  return ctx.rootSchema;
14116
14117
  }
14117
14118
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
14118
- if (path9[0] === defsKey) {
14119
- const key = path9[1];
14119
+ if (path10[0] === defsKey) {
14120
+ const key = path10[1];
14120
14121
  if (!key || !ctx.defs[key]) {
14121
14122
  throw new Error(`Reference not found: ${ref}`);
14122
14123
  }
@@ -14594,6 +14595,20 @@ var harnessDisplaySetSchema = external_exports.strictObject({
14594
14595
  initializeOnly: external_exports.boolean().optional()
14595
14596
  });
14596
14597
 
14598
+ // ../../shared-contracts/dist/ids.js
14599
+ var opaqueIdSchema = external_exports.string().refine((value) => value.trim().length > 0, {
14600
+ message: "Identifier must not be empty or whitespace"
14601
+ });
14602
+ var harnessIdSchema = opaqueIdSchema.brand();
14603
+ var hostThreadIdSchema = opaqueIdSchema.brand();
14604
+ var hostTurnIdSchema = opaqueIdSchema.brand();
14605
+ var hostItemIdSchema = opaqueIdSchema.brand();
14606
+ var hostInteractionIdSchema = opaqueIdSchema.brand();
14607
+
14608
+ // ../../shared-contracts/dist/thread-prewarm.js
14609
+ var threadPrewarmDiscardParamsSchema = external_exports.object({ threadId: hostThreadIdSchema });
14610
+ var threadPrewarmDiscardResultSchema = external_exports.object({ discarded: external_exports.boolean() });
14611
+
14597
14612
  // ../../shared-contracts/dist/console.js
14598
14613
  var consoleAnnouncementSchema = external_exports.strictObject({
14599
14614
  title: external_exports.string().trim().min(1).max(200),
@@ -14606,10 +14621,14 @@ var consoleOpenResultSchema = external_exports.strictObject({
14606
14621
  url: external_exports.string().max(2048).regex(/^http:\/\/(?:127\.0\.0\.1|localhost):\d{1,5}\/(?:\?.*)?$/u)
14607
14622
  });
14608
14623
  var CONSOLE_HOST_METHODS = Object.freeze([
14624
+ "codexhost/console/remote-connections",
14625
+ "codexhost/runtime/status",
14626
+ "codexhost/remote/ssh-setup",
14609
14627
  "codexhost/harness/plugins/list",
14610
14628
  "codexhost/harness/display-settings/get",
14611
14629
  "codexhost/harness/display-settings/set",
14612
14630
  "codexhost/harness/inspect",
14631
+ "codexhost/harness/installation",
14613
14632
  "codexhost/harness/launch-settings/get",
14614
14633
  "codexhost/harness/launch-settings/set",
14615
14634
  "codexhost/harness/web-ui/open",
@@ -14671,16 +14690,6 @@ var loadedSessionsSchema = external_exports.array(external_exports.strictObject(
14671
14690
  inactiveMs: external_exports.number().nonnegative()
14672
14691
  }));
14673
14692
 
14674
- // ../../shared-contracts/dist/ids.js
14675
- var opaqueIdSchema = external_exports.string().refine((value) => value.trim().length > 0, {
14676
- message: "Identifier must not be empty or whitespace"
14677
- });
14678
- var harnessIdSchema = opaqueIdSchema.brand();
14679
- var hostThreadIdSchema = opaqueIdSchema.brand();
14680
- var hostTurnIdSchema = opaqueIdSchema.brand();
14681
- var hostItemIdSchema = opaqueIdSchema.brand();
14682
- var hostInteractionIdSchema = opaqueIdSchema.brand();
14683
-
14684
14693
  // ../../shared-contracts/dist/manual-compaction.js
14685
14694
  var threadManualCompactionStartedSchema = external_exports.strictObject({
14686
14695
  threadId: hostThreadIdSchema,
@@ -15256,14 +15265,17 @@ var harnessLaunchSettingsSchema = external_exports.object({
15256
15265
  // ../../shared-contracts/dist/harness-installation.js
15257
15266
  var harnessInstallationParamsSchema = external_exports.object({
15258
15267
  harnessId: harnessIdSchema,
15259
- action: external_exports.enum(["check", "update"])
15268
+ action: external_exports.enum(["check", "update", "install"])
15260
15269
  }).strict();
15261
15270
  var harnessInstallationStateSchema = external_exports.object({
15262
15271
  currentVersion: external_exports.string().min(1).max(128),
15263
15272
  latestVersion: external_exports.string().min(1).max(128),
15264
15273
  updateAvailable: external_exports.boolean(),
15265
15274
  canUpdate: external_exports.boolean(),
15266
- message: external_exports.string().max(2048).optional()
15275
+ // Adapter-owned diagnostic text; UI uses messageCode rather than displaying it verbatim.
15276
+ message: external_exports.string().max(2048).optional(),
15277
+ messageCode: external_exports.string().min(1).max(128).optional(),
15278
+ latestVersionKind: external_exports.enum(["unknown", "tracking-branch"]).optional()
15267
15279
  }).strict();
15268
15280
 
15269
15281
  // ../../shared-contracts/dist/codex-accounts.js
@@ -15565,6 +15577,80 @@ var updateStatusResultSchema = external_exports.strictObject({
15565
15577
  status: updateStatusSchema.nullable()
15566
15578
  });
15567
15579
 
15580
+ // ../../shared-contracts/dist/remote-runtime.js
15581
+ var remoteUpdatePhaseSchema = external_exports.enum([
15582
+ "idle",
15583
+ "installing",
15584
+ "restarting",
15585
+ "succeeded",
15586
+ "failed"
15587
+ ]);
15588
+ var runtimeStatusSchema = external_exports.object({
15589
+ runningVersion: external_exports.string().nullable(),
15590
+ installedVersion: external_exports.string().nullable(),
15591
+ restartRequired: external_exports.boolean(),
15592
+ remote: external_exports.boolean(),
15593
+ updateSupported: external_exports.boolean(),
15594
+ update: external_exports.object({
15595
+ phase: remoteUpdatePhaseSchema,
15596
+ targetVersion: external_exports.string().nullable(),
15597
+ error: external_exports.string().nullable()
15598
+ })
15599
+ });
15600
+ var remoteUpdateParamsSchema = external_exports.object({
15601
+ version: external_exports.string().regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u)
15602
+ }).strict();
15603
+ var remoteSshSetupParamsSchema = external_exports.object({
15604
+ hostname: external_exports.string().min(1).max(1024).refine((value) => !value.startsWith("-") && !/\s/u.test(value)),
15605
+ port: external_exports.number().int().min(1).max(65535).nullable(),
15606
+ identity: external_exports.string().max(4096).nullable(),
15607
+ action: external_exports.enum(["inspect", "install", "update", "repair", "uninstall"]),
15608
+ uninstallPackage: external_exports.boolean().optional(),
15609
+ version: external_exports.string().regex(/^\d+\.\d+\.\d+$/u).nullable()
15610
+ }).strict();
15611
+ var remoteSshSetupResultSchema = external_exports.object({ state: external_exports.enum(["installed", "not-installed"]) }).strict();
15612
+
15613
+ // ../../shared-contracts/dist/remote-connections.js
15614
+ var hostId = external_exports.string().min(1).max(1024);
15615
+ var codexSshConnectionSchema = external_exports.object({
15616
+ hostId,
15617
+ displayName: external_exports.string().min(1).max(1024),
15618
+ source: external_exports.enum(["codex-managed", "discovered"]),
15619
+ sshAlias: external_exports.string().max(1024).nullable(),
15620
+ sshHost: external_exports.string().min(1).max(1024),
15621
+ sshPort: external_exports.number().int().min(1).max(65535).nullable(),
15622
+ identity: external_exports.string().max(4096).nullable(),
15623
+ autoConnect: external_exports.boolean(),
15624
+ connectionAnalyticsId: external_exports.string().max(1024).optional()
15625
+ });
15626
+ var codexSshDraftSchema = external_exports.strictObject({
15627
+ displayName: external_exports.string().min(1).max(1024),
15628
+ hostname: external_exports.string().min(1).max(1024),
15629
+ sshPort: external_exports.number().int().min(1).max(65535).nullable(),
15630
+ identity: external_exports.string().max(4096).nullable()
15631
+ });
15632
+ var remoteConnectionsRequestSchema = external_exports.discriminatedUnion("action", [
15633
+ external_exports.strictObject({ action: external_exports.literal("list") }),
15634
+ external_exports.strictObject({
15635
+ action: external_exports.literal("save"),
15636
+ draft: codexSshDraftSchema,
15637
+ previous: codexSshConnectionSchema.nullable()
15638
+ }),
15639
+ external_exports.strictObject({ action: external_exports.literal("remove"), previous: codexSshConnectionSchema }),
15640
+ external_exports.strictObject({ action: external_exports.literal("connect"), hostId, enabled: external_exports.boolean() }),
15641
+ external_exports.strictObject({ action: external_exports.literal("state"), hostId }),
15642
+ external_exports.strictObject({ action: external_exports.literal("runtime"), hostId }),
15643
+ external_exports.strictObject({
15644
+ action: external_exports.literal("update"),
15645
+ hostId: hostId.refine((id) => id !== "local"),
15646
+ version: remoteUpdateParamsSchema.shape.version
15647
+ })
15648
+ ]);
15649
+ var remoteConnectionsReplySchema = external_exports.union([
15650
+ external_exports.strictObject({ result: jsonValueSchema }),
15651
+ external_exports.strictObject({ error: external_exports.strictObject({ code: external_exports.number().int(), message: external_exports.string() }) })
15652
+ ]);
15653
+
15568
15654
  // ../../shared-contracts/dist/index.js
15569
15655
  var workspaceContractVersionSchema = external_exports.literal(WORKSPACE_CONTRACT_VERSION);
15570
15656
 
@@ -15858,9 +15944,12 @@ var HARNESS_BROKER_PROTOCOL_VERSION = 1;
15858
15944
  var HARNESS_BROKER_MAX_FRAME_BYTES = 8 * 1024 * 1024;
15859
15945
  var HARNESS_BROKER_MAX_PENDING_REQUESTS = 32;
15860
15946
  var HARNESS_BROKER_REQUEST_TIMEOUT_MS = 15e3;
15947
+ var HARNESS_BROKER_IDLE_TIMEOUT_MS = 60 * 60 * 1e3;
15948
+ var HARNESS_BROKER_RETIRING_ERROR_CODE = "brokerRetiring";
15861
15949
  var harnessBrokerMethodSchema = external_exports.enum([
15862
15950
  "adapter.inspect",
15863
15951
  "adapter.inspectAccount",
15952
+ "adapter.credits",
15864
15953
  "adapter.open",
15865
15954
  "adapter.subagent.readSnapshot",
15866
15955
  "session.readSnapshot",
@@ -15978,6 +16067,14 @@ function defaultHarnessBrokerDescriptorPath(environment = process.env, harnessId
15978
16067
  return path.join(defaultHarnessBrokerDirectory(environment), `${harnessId}-broker-v1.json`);
15979
16068
  return environment[HARNESS_BROKER_DESCRIPTOR_ENV] ?? path.join(defaultHarnessBrokerDirectory(environment), HARNESS_BROKER_DESCRIPTOR_FILE);
15980
16069
  }
16070
+ function harnessBrokerLaunchAgentLabel(harnessId = "claude-code") {
16071
+ harnessPluginIdSchema.parse(harnessId);
16072
+ return harnessId === "claude-code" ? "ai.bytepioneer.codexhost.native-harness-broker" : `ai.bytepioneer.codexhost.${harnessId}-broker`;
16073
+ }
16074
+ function harnessBrokerLaunchAgentPlistPath(environment = process.env, harnessId = "claude-code") {
16075
+ const home = environment.HOME || os.homedir();
16076
+ return path.join(home, "Library", "LaunchAgents", `${harnessBrokerLaunchAgentLabel(harnessId)}.plist`);
16077
+ }
15981
16078
 
15982
16079
  // ../../harness-broker/dist/validation.js
15983
16080
  var cwdSchema = external_exports.string().min(1).max(16384);
@@ -16283,10 +16380,55 @@ async function readDescriptor(descriptorPath) {
16283
16380
  try {
16284
16381
  process.kill(descriptor.ownerPid, 0);
16285
16382
  } catch {
16286
- throw new Error("Aqua Harness broker owner process is unavailable");
16383
+ throw new BrokerNotRunningError("its owner process has exited");
16287
16384
  }
16288
16385
  return descriptor;
16289
16386
  }
16387
+ var BrokerNotRunningError = class extends Error {
16388
+ };
16389
+ var BrokerRetiringError = class extends Error {
16390
+ };
16391
+ var BrokerRequestNotDeliveredError = class extends Error {
16392
+ };
16393
+ var HarnessNotInstalledError = class extends Error {
16394
+ };
16395
+ var BROKER_NOT_RUNNING_CODES = /* @__PURE__ */ new Set(["ENOENT", "ECONNREFUSED"]);
16396
+ var BROKER_START_TIMEOUT_MS = 15e3;
16397
+ var BROKER_START_POLL_MS = 250;
16398
+ function classifyConnectFailure(error51) {
16399
+ if (error51 instanceof BrokerNotRunningError)
16400
+ return error51;
16401
+ const code = error51?.code;
16402
+ if (code && BROKER_NOT_RUNNING_CODES.has(code)) {
16403
+ return new BrokerNotRunningError(code === "ENOENT" ? "its descriptor or socket is missing" : "its socket refused the connection");
16404
+ }
16405
+ return error51 instanceof Error ? error51 : new Error(String(error51));
16406
+ }
16407
+ function describeBrokerFailure(error51, harnessId) {
16408
+ if (error51 instanceof BrokerNotRunningError) {
16409
+ 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}`;
16410
+ }
16411
+ return error51 instanceof Error ? error51.message : String(error51);
16412
+ }
16413
+ function runLaunchctl(arguments_) {
16414
+ return new Promise((resolve) => {
16415
+ execFile("/bin/launchctl", arguments_, { timeout: 1e4 }, (error51) => resolve(!error51));
16416
+ });
16417
+ }
16418
+ async function startBrokerLaunchAgent(harnessId, environment) {
16419
+ const uid = process.getuid?.();
16420
+ if (uid === void 0)
16421
+ return;
16422
+ const target = `gui/${uid}/${harnessBrokerLaunchAgentLabel(harnessId)}`;
16423
+ if (await runLaunchctl(["kickstart", target]))
16424
+ return;
16425
+ await runLaunchctl([
16426
+ "bootstrap",
16427
+ `gui/${uid}`,
16428
+ harnessBrokerLaunchAgentPlistPath(environment, harnessId)
16429
+ ]);
16430
+ await runLaunchctl(["kickstart", target]);
16431
+ }
16290
16432
  var BrokerConnection = class _BrokerConnection {
16291
16433
  #onClose;
16292
16434
  onClose(callback) {
@@ -16310,21 +16452,31 @@ var BrokerConnection = class _BrokerConnection {
16310
16452
  socket.once("error", (error51) => this.#fail(error51));
16311
16453
  }
16312
16454
  static async connect(descriptorPath, harnessId) {
16313
- const descriptor = await readDescriptor(descriptorPath);
16314
- if (descriptor.harnessId !== harnessId)
16315
- throw new Error("Aqua broker belongs to another Harness");
16316
- const socket = net.createConnection(descriptor.socketPath);
16317
- await new Promise((resolve, reject) => {
16318
- const timeout = setTimeout(() => reject(new Error("Timed out connecting to Aqua Harness broker")), HARNESS_BROKER_REQUEST_TIMEOUT_MS);
16319
- socket.once("connect", () => {
16320
- clearTimeout(timeout);
16321
- resolve();
16322
- });
16323
- socket.once("error", (error51) => {
16324
- clearTimeout(timeout);
16325
- reject(error51);
16455
+ let descriptor;
16456
+ let socket;
16457
+ let connecting;
16458
+ try {
16459
+ descriptor = await readDescriptor(descriptorPath);
16460
+ if (descriptor.harnessId !== harnessId)
16461
+ throw new Error("Aqua broker belongs to another Harness");
16462
+ connecting = net.createConnection(descriptor.socketPath);
16463
+ const pending = connecting;
16464
+ await new Promise((resolve, reject) => {
16465
+ const timeout = setTimeout(() => reject(new Error("Timed out connecting to Aqua Harness broker")), HARNESS_BROKER_REQUEST_TIMEOUT_MS);
16466
+ pending.once("connect", () => {
16467
+ clearTimeout(timeout);
16468
+ resolve();
16469
+ });
16470
+ pending.once("error", (error51) => {
16471
+ clearTimeout(timeout);
16472
+ reject(error51);
16473
+ });
16326
16474
  });
16327
- });
16475
+ socket = pending;
16476
+ } catch (error51) {
16477
+ connecting?.destroy();
16478
+ throw classifyConnectFailure(error51);
16479
+ }
16328
16480
  const connection = new _BrokerConnection(descriptor, socket);
16329
16481
  const hello = connection.#waitForHello();
16330
16482
  await writeBrokerFrame(socket, {
@@ -16377,15 +16529,24 @@ var BrokerConnection = class _BrokerConnection {
16377
16529
  }, HARNESS_BROKER_REQUEST_TIMEOUT_MS);
16378
16530
  this.#pending.set(id, { resolve, reject, timeout });
16379
16531
  });
16380
- await writeBrokerFrame(this.#socket, {
16381
- version: HARNESS_BROKER_PROTOCOL_VERSION,
16382
- generation: this.#descriptor.generation,
16383
- sequence: this.#inputSequence,
16384
- kind: "request",
16385
- id,
16386
- method,
16387
- params
16388
- });
16532
+ try {
16533
+ await writeBrokerFrame(this.#socket, {
16534
+ version: HARNESS_BROKER_PROTOCOL_VERSION,
16535
+ generation: this.#descriptor.generation,
16536
+ sequence: this.#inputSequence,
16537
+ kind: "request",
16538
+ id,
16539
+ method,
16540
+ params
16541
+ });
16542
+ } catch (error51) {
16543
+ const pending = this.#pending.get(id);
16544
+ if (pending)
16545
+ clearTimeout(pending.timeout);
16546
+ this.#pending.delete(id);
16547
+ response.catch(() => void 0);
16548
+ throw new BrokerRequestNotDeliveredError(error51 instanceof Error ? error51.message : String(error51));
16549
+ }
16389
16550
  return response;
16390
16551
  }
16391
16552
  close() {
@@ -16429,6 +16590,8 @@ var BrokerConnection = class _BrokerConnection {
16429
16590
  this.#pending.delete(frame.id);
16430
16591
  if (frame.ok)
16431
16592
  pending.resolve(frame.value);
16593
+ else if (frame.error?.code === HARNESS_BROKER_RETIRING_ERROR_CODE)
16594
+ pending.reject(new BrokerRetiringError(frame.error.message));
16432
16595
  else
16433
16596
  pending.reject(new Error(frame.error?.message ?? "Broker request failed"));
16434
16597
  }
@@ -16654,17 +16817,19 @@ var BrokeredHarnessAdapter = class {
16654
16817
  harnessId;
16655
16818
  #descriptorPath;
16656
16819
  #forwardEnvironment;
16820
+ #isInstalled;
16821
+ #startBroker;
16822
+ #startTimeoutMs;
16657
16823
  #connection = null;
16658
16824
  #closed = false;
16825
+ #credits = null;
16826
+ #creditsRefresh = null;
16659
16827
  subagents = {
16660
16828
  readSnapshot: async (input) => {
16661
16829
  try {
16662
- return parseHarnessResult(await (await this.#connect()).request("adapter.subagent.readSnapshot", input));
16830
+ return parseHarnessResult(await this.#request("adapter.subagent.readSnapshot", input));
16663
16831
  } catch (error51) {
16664
- return {
16665
- ok: false,
16666
- error: unavailable(error51 instanceof Error ? error51.message : String(error51))
16667
- };
16832
+ return { ok: false, error: this.#error(error51) };
16668
16833
  }
16669
16834
  }
16670
16835
  };
@@ -16676,12 +16841,39 @@ var BrokeredHarnessAdapter = class {
16676
16841
  if (input.liveCommandCatalog)
16677
16842
  this.liveCommandCatalog = true;
16678
16843
  this.#descriptorPath = input.descriptorPath ?? defaultHarnessBrokerDescriptorPath(input.environment, this.harnessId);
16844
+ this.#isInstalled = input.isInstalled;
16845
+ const environment = input.environment ?? process.env;
16846
+ this.#startBroker = input.startBroker === false ? void 0 : input.startBroker ?? (process.platform === "darwin" && !input.descriptorPath ? () => startBrokerLaunchAgent(this.harnessId, environment) : void 0);
16847
+ this.#startTimeoutMs = input.startTimeoutMs ?? BROKER_START_TIMEOUT_MS;
16848
+ }
16849
+ credits() {
16850
+ return this.#credits;
16851
+ }
16852
+ refreshCredits() {
16853
+ if (this.#closed)
16854
+ return Promise.resolve(null);
16855
+ if (this.#creditsRefresh)
16856
+ return this.#creditsRefresh;
16857
+ this.#creditsRefresh = this.#readCredits().finally(() => {
16858
+ this.#creditsRefresh = null;
16859
+ });
16860
+ return this.#creditsRefresh;
16861
+ }
16862
+ async #readCredits() {
16863
+ try {
16864
+ const value = await this.#request("adapter.credits", {}, true);
16865
+ const credits = accountCreditsSnapshotSchema.nullable().parse(value);
16866
+ if (!this.#closed)
16867
+ this.#credits = credits;
16868
+ } catch {
16869
+ }
16870
+ return this.#credits;
16679
16871
  }
16680
16872
  async inspectAccount() {
16681
16873
  if (this.#closed)
16682
16874
  return null;
16683
16875
  try {
16684
- const value = await (await this.#connect()).request("adapter.inspectAccount", {});
16876
+ const value = await this.#request("adapter.inspectAccount", {}, true);
16685
16877
  return harnessAccountSnapshotSchema.nullable().parse(value);
16686
16878
  } catch {
16687
16879
  return null;
@@ -16691,33 +16883,46 @@ var BrokeredHarnessAdapter = class {
16691
16883
  if (this.#closed)
16692
16884
  return failedInspection("Aqua Harness broker adapter is closed");
16693
16885
  try {
16694
- return harnessInspectionSchema.parse(await (await this.#connect()).request("adapter.inspect", input));
16886
+ return harnessInspectionSchema.parse(await this.#request("adapter.inspect", input, true));
16695
16887
  } catch (error51) {
16696
16888
  this.#connection = null;
16697
- return failedInspection(error51 instanceof Error ? error51.message : String(error51));
16889
+ if (error51 instanceof HarnessNotInstalledError)
16890
+ return { status: "notInstalled", error: this.#error(error51) };
16891
+ return failedInspection(describeBrokerFailure(error51, this.harnessId));
16698
16892
  }
16699
16893
  }
16700
16894
  async open(input) {
16701
16895
  if (this.#closed)
16702
16896
  return { ok: false, error: unavailable("Aqua Harness broker adapter is closed", false) };
16897
+ const safeInput = { ...input };
16898
+ delete safeInput.environment;
16899
+ if (this.#forwardEnvironment && input.environment) {
16900
+ const allowed = [
16901
+ "CODEXHOST_CLI_PATH",
16902
+ "CODEXHOST_CLI_NODE_PATH",
16903
+ "CODEXHOST_RUNTIME_ENDPOINT",
16904
+ "CODEXHOST_RUNTIME_TOKEN",
16905
+ "CODEXHOST_THREAD_ID"
16906
+ ];
16907
+ const environment = Object.fromEntries(Object.entries(input.environment).filter(([key, value]) => allowed.includes(key) && value !== void 0));
16908
+ if (Object.keys(environment).length)
16909
+ safeInput.environment = environment;
16910
+ }
16703
16911
  let connection;
16704
16912
  try {
16705
- const safeInput = { ...input };
16706
- delete safeInput.environment;
16707
- if (this.#forwardEnvironment && input.environment) {
16708
- const allowed = [
16709
- "CODEXHOST_CLI_PATH",
16710
- "CODEXHOST_CLI_NODE_PATH",
16711
- "CODEXHOST_RUNTIME_ENDPOINT",
16712
- "CODEXHOST_RUNTIME_TOKEN",
16713
- "CODEXHOST_THREAD_ID"
16714
- ];
16715
- const environment = Object.fromEntries(Object.entries(input.environment).filter(([key, value]) => allowed.includes(key) && value !== void 0));
16716
- if (Object.keys(environment).length)
16717
- safeInput.environment = environment;
16718
- }
16719
- connection = await this.#connect();
16720
- const result = parseHarnessResult(await connection.request("adapter.open", safeInput));
16913
+ let value;
16914
+ for (let attempt = 0; ; attempt += 1) {
16915
+ connection = await this.#connect();
16916
+ try {
16917
+ value = await connection.request("adapter.open", safeInput);
16918
+ break;
16919
+ } catch (error51) {
16920
+ if (attempt > 0 || !(error51 instanceof BrokerRetiringError || error51 instanceof BrokerRequestNotDeliveredError))
16921
+ throw error51;
16922
+ this.#connection = null;
16923
+ }
16924
+ }
16925
+ const result = parseHarnessResult(value);
16721
16926
  if (!result.ok)
16722
16927
  return result;
16723
16928
  const session = new BrokeredHarnessSession(connection, parseSessionMetadata(result.value), this.harnessId, safeInput, () => this.#connect(), () => {
@@ -16728,25 +16933,51 @@ var BrokeredHarnessAdapter = class {
16728
16933
  } catch (error51) {
16729
16934
  connection?.close();
16730
16935
  this.#connection = null;
16731
- return {
16732
- ok: false,
16733
- error: unavailable(error51 instanceof Error ? error51.message : String(error51))
16734
- };
16936
+ return { ok: false, error: this.#error(error51) };
16735
16937
  }
16736
16938
  }
16737
16939
  async close() {
16738
16940
  this.#closed = true;
16941
+ this.#credits = null;
16739
16942
  await Promise.allSettled([...this.#sessions].map((session) => session.close()));
16740
16943
  this.#sessions.clear();
16741
16944
  const connection = await this.#connection?.catch(() => null);
16742
16945
  await connection?.dispose();
16743
16946
  this.#connection = null;
16744
16947
  }
16948
+ #error(error51) {
16949
+ if (error51 instanceof HarnessNotInstalledError)
16950
+ return {
16951
+ code: "notInstalled",
16952
+ message: error51.message,
16953
+ retryable: false,
16954
+ stage: "harnessBroker"
16955
+ };
16956
+ return unavailable(describeBrokerFailure(error51, this.harnessId));
16957
+ }
16958
+ /**
16959
+ * Sends one adapter-level request. A broker that retired between requests refuses it
16960
+ * unprocessed, so it is retried once on a fresh broker. Idempotent reads also retry
16961
+ * once after a plain disconnect.
16962
+ */
16963
+ async #request(method, params, idempotent = false) {
16964
+ for (let attempt = 0; ; attempt += 1) {
16965
+ const connection = await this.#connect();
16966
+ try {
16967
+ return await connection.request(method, params);
16968
+ } catch (error51) {
16969
+ const retryable = error51 instanceof BrokerRetiringError || error51 instanceof BrokerRequestNotDeliveredError || idempotent && connection.closed;
16970
+ if (attempt > 0 || !retryable)
16971
+ throw error51;
16972
+ this.#connection = null;
16973
+ }
16974
+ }
16975
+ }
16745
16976
  #connect() {
16746
16977
  if (this.#closed)
16747
16978
  return Promise.reject(new Error("Aqua Harness broker adapter is closed"));
16748
16979
  if (!this.#connection) {
16749
- const pending = BrokerConnection.connect(this.#descriptorPath, this.harnessId).then((connection) => {
16980
+ const pending = this.#establish().then((connection) => {
16750
16981
  connection.onClose(() => {
16751
16982
  if (this.#connection === pending)
16752
16983
  this.#connection = null;
@@ -16761,13 +16992,35 @@ var BrokeredHarnessAdapter = class {
16761
16992
  }
16762
16993
  return this.#connection;
16763
16994
  }
16995
+ async #establish() {
16996
+ try {
16997
+ return await BrokerConnection.connect(this.#descriptorPath, this.harnessId);
16998
+ } catch (error51) {
16999
+ if (!(error51 instanceof BrokerNotRunningError) || !this.#startBroker)
17000
+ throw error51;
17001
+ }
17002
+ if (this.#isInstalled && !this.#isInstalled()) {
17003
+ throw new HarnessNotInstalledError(`${this.harnessId} is not installed on this Mac`);
17004
+ }
17005
+ const deadline = Date.now() + this.#startTimeoutMs;
17006
+ for (; ; ) {
17007
+ await this.#startBroker();
17008
+ try {
17009
+ return await BrokerConnection.connect(this.#descriptorPath, this.harnessId);
17010
+ } catch (error51) {
17011
+ if (!(error51 instanceof BrokerNotRunningError) || Date.now() >= deadline)
17012
+ throw error51;
17013
+ }
17014
+ await new Promise((resolve) => setTimeout(resolve, BROKER_START_POLL_MS));
17015
+ }
17016
+ }
16764
17017
  };
16765
17018
 
16766
17019
  // ../codebuddy/dist/codebuddy-adapter.js
16767
- import { stat as stat2 } from "node:fs/promises";
17020
+ import { stat as stat3 } from "node:fs/promises";
16768
17021
 
16769
17022
  // ../codebuddy/dist/acp-client.js
16770
- import { execFile, spawn } from "node:child_process";
17023
+ import { execFile as execFile2, spawn } from "node:child_process";
16771
17024
  import { Readable as Readable2, Writable } from "node:stream";
16772
17025
 
16773
17026
  // ../../../node_modules/@agentclientprotocol/sdk/dist/schema/index.js
@@ -21487,7 +21740,7 @@ var CodeBuddyAcpClient = class {
21487
21740
  }
21488
21741
  const pid = this.#child.pid;
21489
21742
  if (pid && process.platform === "win32") {
21490
- await new Promise((resolve) => execFile("taskkill", ["/PID", String(pid), "/T", "/F"], { windowsHide: true, timeout: 3e3 }, () => resolve()));
21743
+ await new Promise((resolve) => execFile2("taskkill", ["/PID", String(pid), "/T", "/F"], { windowsHide: true, timeout: 3e3 }, () => resolve()));
21491
21744
  } else if (pid) {
21492
21745
  try {
21493
21746
  process.kill(-pid, "SIGKILL");
@@ -21579,7 +21832,7 @@ function confirmedConfiguration(response, id, value, profile = CODEBUDDY_RUNTIME
21579
21832
 
21580
21833
  // ../codebuddy/dist/derivation.js
21581
21834
  import { randomUUID as randomUUID2 } from "node:crypto";
21582
- import { execFile as execFile2, spawn as spawn2 } from "node:child_process";
21835
+ import { execFile as execFile3, spawn as spawn2 } from "node:child_process";
21583
21836
  import { lstat as lstat2, mkdir, readFile as readFile3, realpath as realpath4, unlink, writeFile } from "node:fs/promises";
21584
21837
  import path6 from "node:path";
21585
21838
  import { isDeepStrictEqual as isDeepStrictEqual3 } from "node:util";
@@ -21692,16 +21945,16 @@ var Diff = class {
21692
21945
  }
21693
21946
  }
21694
21947
  }
21695
- addToPath(path9, added, removed, oldPosInc, options) {
21696
- const last = path9.lastComponent;
21948
+ addToPath(path10, added, removed, oldPosInc, options) {
21949
+ const last = path10.lastComponent;
21697
21950
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
21698
21951
  return {
21699
- oldPos: path9.oldPos + oldPosInc,
21952
+ oldPos: path10.oldPos + oldPosInc,
21700
21953
  lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
21701
21954
  };
21702
21955
  } else {
21703
21956
  return {
21704
- oldPos: path9.oldPos + oldPosInc,
21957
+ oldPos: path10.oldPos + oldPosInc,
21705
21958
  lastComponent: { count: 1, added, removed, previousComponent: last }
21706
21959
  };
21707
21960
  }
@@ -23042,7 +23295,7 @@ async function copyCodeBuddySession(cwd, sourceId, targetId, environment, signal
23042
23295
  child.stderr.destroy();
23043
23296
  } else if (process.platform === "win32" && child.pid) {
23044
23297
  termination = new Promise((done) => {
23045
- execFile2("taskkill", ["/PID", String(child.pid), "/T", "/F"], { windowsHide: true, timeout: 3e3 }, () => {
23298
+ execFile3("taskkill", ["/PID", String(child.pid), "/T", "/F"], { windowsHide: true, timeout: 3e3 }, () => {
23046
23299
  child.kill();
23047
23300
  done();
23048
23301
  });
@@ -23584,6 +23837,345 @@ async function deriveCodeBuddySession(options) {
23584
23837
  }
23585
23838
  }
23586
23839
 
23840
+ // ../codebuddy/dist/session-import.js
23841
+ import { createReadStream } from "node:fs";
23842
+ import { opendir, readFile as readFile4, stat as stat2 } from "node:fs/promises";
23843
+ import path7 from "node:path";
23844
+ import { createInterface as createInterface2 } from "node:readline";
23845
+
23846
+ // ../../harness-adapter/dist/session-import.js
23847
+ import { lstat as lstat3 } from "node:fs/promises";
23848
+ var SessionImportChangedError = class extends Error {
23849
+ constructor(message = "Native Session changed during discovery; refresh and retry") {
23850
+ super(message);
23851
+ this.name = "SessionImportChangedError";
23852
+ }
23853
+ };
23854
+ function isMissingFileError(error51) {
23855
+ return typeof error51 === "object" && error51 !== null && "code" in error51 && error51.code === "ENOENT";
23856
+ }
23857
+ function sameFileFingerprint(left, right) {
23858
+ 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;
23859
+ }
23860
+ var STORAGE_ACCESS_ERRORS = /* @__PURE__ */ new Set(["EACCES", "EPERM", "EIO", "EMFILE", "ENFILE"]);
23861
+ function isStorageAccessError(error51) {
23862
+ return typeof error51 === "object" && error51 !== null && "code" in error51 && typeof error51.code === "string" && STORAGE_ACCESS_ERRORS.has(error51.code);
23863
+ }
23864
+ async function optionalLstat(file2) {
23865
+ try {
23866
+ return await lstat3(file2);
23867
+ } catch (error51) {
23868
+ if (isMissingFileError(error51))
23869
+ return null;
23870
+ throw error51;
23871
+ }
23872
+ }
23873
+ async function readStableFiles(files, read) {
23874
+ const before = await Promise.all(files.map(optionalLstat));
23875
+ const value = await read(before);
23876
+ const after = await Promise.all(files.map(optionalLstat));
23877
+ if (before.some((info, index) => !sameFileFingerprint(info, after[index] ?? null)))
23878
+ throw new SessionImportChangedError();
23879
+ return value;
23880
+ }
23881
+ function sessionImportTitle(value, maxLength = HARNESS_SESSION_IMPORT_TITLE_MAX_LENGTH) {
23882
+ if (typeof value !== "string")
23883
+ return null;
23884
+ const normalized = value.replaceAll("\0", "").replaceAll(/\s+/gu, " ").trim();
23885
+ if (!normalized)
23886
+ return null;
23887
+ if (normalized.length <= maxLength)
23888
+ return normalized;
23889
+ const characters = [...normalized];
23890
+ if (characters.length <= maxLength)
23891
+ return normalized;
23892
+ return `${characters.slice(0, maxLength - 1).join("").trimEnd()}…`;
23893
+ }
23894
+ function sessionImportCandidate(input) {
23895
+ const time3 = typeof input.updatedAt === "number" ? input.updatedAt : typeof input.updatedAt === "string" ? Date.parse(input.updatedAt) : Number.NaN;
23896
+ const parsed = harnessSessionImportCandidateSchema.safeParse({
23897
+ nativeSessionId: input.nativeSessionId,
23898
+ cwd: input.cwd,
23899
+ title: typeof input.title === "string" && input.title.trim().length > 0 ? input.title : null,
23900
+ updatedAt: Math.floor(time3),
23901
+ // Unknown must stay unknown; only an explicit boolean is a native statement.
23902
+ running: typeof input.running === "boolean" ? input.running : null
23903
+ });
23904
+ return parsed.success ? parsed.data : null;
23905
+ }
23906
+ var SessionImportScope = class {
23907
+ #abort = new AbortController();
23908
+ #options;
23909
+ #pending = /* @__PURE__ */ new Set();
23910
+ constructor(options) {
23911
+ this.#options = options;
23912
+ }
23913
+ #closed() {
23914
+ return {
23915
+ ok: false,
23916
+ error: { code: "invalidState", message: this.#options.closedMessage, retryable: false }
23917
+ };
23918
+ }
23919
+ read(operation) {
23920
+ const signal = this.#abort.signal;
23921
+ if (signal.aborted)
23922
+ return Promise.resolve(this.#closed());
23923
+ let started;
23924
+ try {
23925
+ started = operation(signal);
23926
+ } catch (error51) {
23927
+ started = Promise.reject(error51 instanceof Error ? error51 : new Error("Session read failed"));
23928
+ }
23929
+ const request = started.then((value) => signal.aborted ? this.#closed() : { ok: true, value }).catch(() => signal.aborted ? this.#closed() : {
23930
+ ok: false,
23931
+ error: {
23932
+ code: "unavailable",
23933
+ message: this.#options.unavailableMessage,
23934
+ retryable: true
23935
+ }
23936
+ }).finally(() => this.#pending.delete(request));
23937
+ this.#pending.add(request);
23938
+ return request;
23939
+ }
23940
+ /** `read` for `resolveCandidate`: a null source is the selected Session having disappeared. */
23941
+ async resolve(operation) {
23942
+ const result = await this.read(operation);
23943
+ if (!result.ok)
23944
+ return result;
23945
+ return result.value ? { ok: true, value: result.value } : {
23946
+ ok: false,
23947
+ error: {
23948
+ code: "sessionNotFound",
23949
+ message: this.#options.notFoundMessage,
23950
+ retryable: false
23951
+ }
23952
+ };
23953
+ }
23954
+ /** Idempotent. Resolves after every started read has settled. */
23955
+ async close() {
23956
+ this.#abort.abort();
23957
+ await Promise.allSettled(this.#pending);
23958
+ }
23959
+ };
23960
+
23961
+ // ../codebuddy/dist/session-import.js
23962
+ var SESSION_FILE = /^([A-Za-z0-9][A-Za-z0-9_-]{0,199})\.jsonl$/u;
23963
+ var MAX_HISTORY_BYTES = 64e6;
23964
+ var MAX_MARKER_BYTES = 64 * 1024;
23965
+ function processAlive(pid) {
23966
+ if (typeof pid !== "number" || !Number.isSafeInteger(pid) || pid <= 0)
23967
+ return false;
23968
+ try {
23969
+ process.kill(pid, 0);
23970
+ return true;
23971
+ } catch (error51) {
23972
+ return record2(error51).code === "EPERM";
23973
+ }
23974
+ }
23975
+ function userText(row) {
23976
+ if (row.type !== "message" || row.role !== "user")
23977
+ return null;
23978
+ const { content } = row;
23979
+ if (typeof content === "string")
23980
+ return content;
23981
+ if (!Array.isArray(content))
23982
+ return "";
23983
+ return content.map((part) => record2(part)).filter((part) => typeof part.text === "string").map((part) => String(part.text)).join(" ");
23984
+ }
23985
+ async function readFacts(file2, signal) {
23986
+ const stream = createReadStream(file2, { encoding: "utf8", signal });
23987
+ const lines = createInterface2({ input: stream, crlfDelay: Infinity });
23988
+ let cwd = null;
23989
+ let customTitle = null;
23990
+ let generatedTitle = null;
23991
+ let firstPrompt = null;
23992
+ let hasUser = false;
23993
+ let updatedAt = null;
23994
+ try {
23995
+ for await (const line of lines) {
23996
+ signal.throwIfAborted();
23997
+ if (!line.trim())
23998
+ continue;
23999
+ let parsed;
24000
+ try {
24001
+ parsed = JSON.parse(line);
24002
+ } catch {
24003
+ return null;
24004
+ }
24005
+ const row = record2(parsed);
24006
+ if (typeof row.cwd === "string" && path7.isAbsolute(row.cwd))
24007
+ cwd ??= row.cwd;
24008
+ if (typeof row.timestamp === "number" && Number.isFinite(row.timestamp))
24009
+ updatedAt = row.timestamp;
24010
+ if (row.type === "custom-title")
24011
+ customTitle = sessionImportTitle(row.customTitle);
24012
+ else if (row.type === "ai-title")
24013
+ generatedTitle = sessionImportTitle(row.aiTitle);
24014
+ else {
24015
+ const text2 = userText(row);
24016
+ if (text2 !== null) {
24017
+ hasUser = true;
24018
+ firstPrompt ??= sessionImportTitle(text2);
24019
+ }
24020
+ }
24021
+ }
24022
+ } finally {
24023
+ lines.close();
24024
+ stream.destroy();
24025
+ }
24026
+ if (!hasUser || !cwd)
24027
+ return null;
24028
+ return { cwd, title: customTitle ?? generatedTitle ?? firstPrompt, updatedAt };
24029
+ }
24030
+ var CodeBuddySessionImport = class {
24031
+ #environment;
24032
+ #profile;
24033
+ #scope;
24034
+ constructor(environment, profile = CODEBUDDY_RUNTIME_PROFILE) {
24035
+ this.#environment = { ...environment };
24036
+ this.#profile = profile;
24037
+ this.#scope = new SessionImportScope({
24038
+ closedMessage: `${profile.displayName} Session import is closed`,
24039
+ unavailableMessage: `${profile.displayName} sessions could not be read; close native clients, check storage access and retry`,
24040
+ notFoundMessage: `${profile.displayName} Session is no longer importable`
24041
+ });
24042
+ }
24043
+ listCandidates() {
24044
+ return this.#scope.read(async (signal) => {
24045
+ const active = await this.#activeSessions(signal);
24046
+ const candidates = [];
24047
+ for (const [nativeSessionId, files] of await this.#sessionFiles(signal)) {
24048
+ if (files.length !== 1 || !files[0])
24049
+ continue;
24050
+ try {
24051
+ const source = await this.#source(nativeSessionId, files[0], active, signal);
24052
+ if (source)
24053
+ candidates.push(source.candidate);
24054
+ } catch (error51) {
24055
+ if (!(error51 instanceof SessionImportChangedError))
24056
+ throw error51;
24057
+ }
24058
+ }
24059
+ return candidates;
24060
+ });
24061
+ }
24062
+ resolveCandidate(nativeSessionId) {
24063
+ return this.#scope.resolve(async (signal) => {
24064
+ const files = (await this.#sessionFiles(signal)).get(nativeSessionId);
24065
+ if (files?.length !== 1 || !files[0])
24066
+ return null;
24067
+ return this.#source(nativeSessionId, files[0], await this.#activeSessions(signal), signal);
24068
+ });
24069
+ }
24070
+ close() {
24071
+ return this.#scope.close();
24072
+ }
24073
+ #root() {
24074
+ return codeBuddyConfigRoot(this.#environment, this.#profile);
24075
+ }
24076
+ /** IDs a live native process registered in `<config>/sessions/<pid>.json`. */
24077
+ async #activeSessions(signal) {
24078
+ const active = /* @__PURE__ */ new Set();
24079
+ const directory = path7.join(this.#root(), "sessions");
24080
+ const markers = await opendir(directory).catch((error51) => {
24081
+ if (isMissingFileError(error51) || record2(error51).code === "ENOTDIR")
24082
+ return null;
24083
+ throw error51;
24084
+ });
24085
+ if (!markers)
24086
+ return active;
24087
+ for await (const marker of markers) {
24088
+ signal.throwIfAborted();
24089
+ if (!marker.isFile() || !marker.name.endsWith(".json"))
24090
+ continue;
24091
+ try {
24092
+ const file2 = path7.join(directory, marker.name);
24093
+ if ((await stat2(file2)).size > MAX_MARKER_BYTES)
24094
+ continue;
24095
+ const entry = record2(JSON.parse(await readFile4(file2, { encoding: "utf8", signal })));
24096
+ if (typeof entry.sessionId === "string" && processAlive(entry.pid))
24097
+ active.add(entry.sessionId);
24098
+ } catch (error51) {
24099
+ signal.throwIfAborted();
24100
+ if (isStorageAccessError(error51))
24101
+ throw error51;
24102
+ }
24103
+ }
24104
+ return active;
24105
+ }
24106
+ /** Session ID to every project file claiming it. Enumerated links are not followed. */
24107
+ async #sessionFiles(signal) {
24108
+ const root = path7.join(this.#root(), "projects");
24109
+ const found = /* @__PURE__ */ new Map();
24110
+ const info = await optionalLstat(root);
24111
+ if (!info)
24112
+ return found;
24113
+ if (!info.isDirectory())
24114
+ throw new Error(`${this.#profile.displayName} Session store is not a directory`);
24115
+ for await (const project of await opendir(root)) {
24116
+ signal.throwIfAborted();
24117
+ if (!project.isDirectory())
24118
+ continue;
24119
+ const projectDirectory = path7.join(root, project.name);
24120
+ const entries = await opendir(projectDirectory).catch((error51) => {
24121
+ if (isMissingFileError(error51))
24122
+ return null;
24123
+ throw error51;
24124
+ });
24125
+ if (!entries)
24126
+ continue;
24127
+ for await (const entry of entries) {
24128
+ signal.throwIfAborted();
24129
+ const nativeSessionId = entry.isFile() ? SESSION_FILE.exec(entry.name)?.[1] : void 0;
24130
+ if (!nativeSessionId)
24131
+ continue;
24132
+ const files = found.get(nativeSessionId) ?? [];
24133
+ files.push(path7.join(projectDirectory, entry.name));
24134
+ found.set(nativeSessionId, files);
24135
+ }
24136
+ }
24137
+ return found;
24138
+ }
24139
+ async #source(nativeSessionId, file2, active, signal) {
24140
+ signal.throwIfAborted();
24141
+ return readStableFiles([file2], async ([info]) => {
24142
+ if (!info?.isFile() || info.size === 0 || info.size > MAX_HISTORY_BYTES)
24143
+ return null;
24144
+ try {
24145
+ const facts = await readFacts(file2, signal);
24146
+ if (!facts)
24147
+ return null;
24148
+ const cwd = path7.resolve(facts.cwd);
24149
+ if (!(await stat2(cwd)).isDirectory())
24150
+ return null;
24151
+ const nativeRef = nativeSessionRefSchema.parse({
24152
+ harnessId: this.#profile.harnessId,
24153
+ nativeSessionId,
24154
+ formatVersion: 1
24155
+ });
24156
+ signal.throwIfAborted();
24157
+ const history = await codeBuddyNativeHistory(cwd, nativeRef, this.#environment, this.#profile);
24158
+ if (path7.resolve(history.file) !== path7.resolve(file2))
24159
+ return null;
24160
+ const candidate = sessionImportCandidate({
24161
+ nativeSessionId,
24162
+ cwd,
24163
+ title: facts.title,
24164
+ updatedAt: facts.updatedAt ?? info.mtimeMs,
24165
+ // A registered live process holds the Session. Absence is not proof of idleness.
24166
+ running: active.has(nativeSessionId) ? true : null
24167
+ });
24168
+ return candidate ? { candidate, nativeRef } : null;
24169
+ } catch (error51) {
24170
+ signal.throwIfAborted();
24171
+ if (isStorageAccessError(error51))
24172
+ throw error51;
24173
+ return null;
24174
+ }
24175
+ });
24176
+ }
24177
+ };
24178
+
23587
24179
  // ../codebuddy/dist/interactions.js
23588
24180
  var CodeBuddyInteractions = class {
23589
24181
  emit;
@@ -23727,7 +24319,7 @@ var CodeBuddyInteractions = class {
23727
24319
 
23728
24320
  // ../codebuddy/dist/subagent-history.js
23729
24321
  import { readdir as readdir2, realpath as realpath5 } from "node:fs/promises";
23730
- import path7 from "node:path";
24322
+ import path8 from "node:path";
23731
24323
  var equalPath2 = (a, b) => process.platform === "win32" ? a.toLowerCase() === b.toLowerCase() : a === b;
23732
24324
  var MAX_CACHED_CHILDREN = 16;
23733
24325
  var CodeBuddyChildObserver = class {
@@ -23791,8 +24383,8 @@ var CodeBuddyChildObserver = class {
23791
24383
  }
23792
24384
  async #directory() {
23793
24385
  const history = await this.#parentHistory();
23794
- const project = path7.dirname(await realpath5(history.file));
23795
- const expected = path7.join(project, this.parent.nativeSessionId, "subagents");
24386
+ const project = path8.dirname(await realpath5(history.file));
24387
+ const expected = path8.join(project, this.parent.nativeSessionId, "subagents");
23796
24388
  const actual = await realpath5(expected);
23797
24389
  this.#assertOpen();
23798
24390
  if (!equalPath2(actual, expected))
@@ -23802,7 +24394,7 @@ var CodeBuddyChildObserver = class {
23802
24394
  async #child(directory, childId) {
23803
24395
  if (!validCodeBuddyChildId(childId))
23804
24396
  throw new CodeBuddyError("invalidRequest", "Invalid native Subagent ID");
23805
- const file2 = path7.join(directory, `${childId}.jsonl`);
24397
+ const file2 = path8.join(directory, `${childId}.jsonl`);
23806
24398
  const before = await codeBuddyFileVersion(file2);
23807
24399
  if (!equalPath2(before.realFile, file2))
23808
24400
  throw new CodeBuddyError("invalidRequest", "Redirected Subagent transcript");
@@ -24514,6 +25106,7 @@ var CodeBuddyAdapter = class {
24514
25106
  harnessId;
24515
25107
  commandCatalog;
24516
25108
  liveCommandCatalog = true;
25109
+ sessionImport;
24517
25110
  subagents = {
24518
25111
  readSnapshot: async ({ parent, nativeSubagentId, cwd }) => {
24519
25112
  try {
@@ -24547,6 +25140,7 @@ var CodeBuddyAdapter = class {
24547
25140
  this.commandCatalog = commandCatalog2;
24548
25141
  }
24549
25142
  this.#environment = { ...options.environment ?? process.env };
25143
+ this.sessionImport = new CodeBuddySessionImport(this.#environment, this.#profile);
24550
25144
  this.#invocation = options.invocationFactory ?? codeBuddyInvocation;
24551
25145
  this.#factory = options.clientFactory ?? ((clientOptions) => new CodeBuddyAcpClient(clientOptions, void 0, this.#invocation));
24552
25146
  }
@@ -24566,7 +25160,7 @@ var CodeBuddyAdapter = class {
24566
25160
  try {
24567
25161
  if (this.#closed)
24568
25162
  throw new CodeBuddyError("invalidState", "Adapter is closed");
24569
- if (!(await stat2(cwd)).isDirectory())
25163
+ if (!(await stat3(cwd)).isDirectory())
24570
25164
  throw new CodeBuddyError("invalidRequest", "Working directory is not a directory");
24571
25165
  client2 = this.#factory({
24572
25166
  cwd,
@@ -24612,7 +25206,7 @@ var CodeBuddyAdapter = class {
24612
25206
  return failure("invalidRequest", "Unattended execution requires native fullAccess permissions", this.#profile);
24613
25207
  let session;
24614
25208
  try {
24615
- if (!(await stat2(input.cwd)).isDirectory())
25209
+ if (!(await stat3(input.cwd)).isDirectory())
24616
25210
  throw new CodeBuddyError("invalidRequest", "Working directory is not a directory");
24617
25211
  if (this.#closed)
24618
25212
  throw new CodeBuddyError("invalidState", "Adapter closed while opening Session");
@@ -24675,7 +25269,7 @@ var CodeBuddyAdapter = class {
24675
25269
  async close() {
24676
25270
  this.#closed = true;
24677
25271
  this.#abort.abort();
24678
- await Promise.allSettled([...this.#derivations]);
25272
+ await Promise.allSettled([this.sessionImport.close(), ...this.#derivations]);
24679
25273
  const results = await Promise.allSettled([...this.#sessions, ...this.#inspections].map((resource) => resource.close()));
24680
25274
  this.#sessions.clear();
24681
25275
  this.#inspections.clear();
@@ -24894,8 +25488,8 @@ var WORKBUDDY_RUNTIME_PROFILE = {
24894
25488
  };
24895
25489
 
24896
25490
  // dist/product-models.js
24897
- import { readFile as readFile4, stat as stat3 } from "node:fs/promises";
24898
- import path8 from "node:path";
25491
+ import { readFile as readFile5, stat as stat4 } from "node:fs/promises";
25492
+ import path9 from "node:path";
24899
25493
  var MAX_PRODUCT_SNAPSHOT_BYTES = 8 * 1024 * 1024;
24900
25494
  var PRODUCT_CONFIG_PATH_ENV = "ACC_PRODUCT_CONFIG_PATH";
24901
25495
  var PRODUCT_CONFIG_INLINE_ENVS = [
@@ -24948,16 +25542,16 @@ function parseWorkBuddyProductModels(value) {
24948
25542
  return parsed;
24949
25543
  }
24950
25544
  async function readProductJson(file2) {
24951
- const metadata = await stat3(file2);
25545
+ const metadata = await stat4(file2);
24952
25546
  if (!metadata.isFile() || metadata.size <= 0 || metadata.size > MAX_PRODUCT_SNAPSHOT_BYTES)
24953
25547
  return;
24954
- return JSON.parse(await readFile4(file2, "utf8"));
25548
+ return JSON.parse(await readFile5(file2, "utf8"));
24955
25549
  }
24956
25550
  function bundledFallbackProductPath(invocation) {
24957
25551
  const cli = invocation.arguments[0];
24958
25552
  if (!cli || cli.startsWith("-"))
24959
25553
  return;
24960
- return path8.join(path8.dirname(path8.dirname(cli)), "product.json");
25554
+ return path9.join(path9.dirname(path9.dirname(cli)), "product.json");
24961
25555
  }
24962
25556
  async function loadWorkBuddyProductModels(environment) {
24963
25557
  const invocation = workBuddyInvocation(environment, true);
@@ -25060,14 +25654,27 @@ var WorkBuddyAdapter = class extends CodeBuddyAdapter {
25060
25654
 
25061
25655
  // dist/plugin.js
25062
25656
  function createHarnessAdapter(context) {
25063
- if (context.platform === "darwin" && context.managedRemoteHost)
25657
+ if (context.platform === "darwin" && context.managedRemoteHost) {
25658
+ const environment = {
25659
+ ...context.environment,
25660
+ ...context.launchCommand ? { CODEXHOST_WORKBUDDY_COMMAND: context.launchCommand } : {}
25661
+ };
25064
25662
  return new BrokeredHarnessAdapter({
25065
25663
  harnessId: "workbuddy",
25066
25664
  commandCatalog: WORKBUDDY_COMMAND_CATALOG,
25067
25665
  forwardDelegationEnvironment: true,
25068
25666
  environment: { ...context.environment },
25667
+ isInstalled: () => {
25668
+ try {
25669
+ workBuddyInvocation(environment, true);
25670
+ return true;
25671
+ } catch (error51) {
25672
+ return !(error51 instanceof CodeBuddyError && error51.code === "notInstalled");
25673
+ }
25674
+ },
25069
25675
  ...context.brokerDescriptorPath ? { descriptorPath: context.brokerDescriptorPath } : {}
25070
25676
  });
25677
+ }
25071
25678
  return new WorkBuddyAdapter({
25072
25679
  environment: {
25073
25680
  ...context.environment,