@liberseek/boft-cli-win32-arm64 0.6.8 → 0.6.9

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,9 @@ var __export = (target, all) => {
5
5
  __defProp(target, name, { get: all[name], enumerable: true });
6
6
  };
7
7
 
8
+ // dist/hermes-adapter.js
9
+ import { createHash } from "node:crypto";
10
+
8
11
  // ../../../node_modules/zod/v4/classic/external.js
9
12
  var external_exports = {};
10
13
  __export(external_exports, {
@@ -14642,12 +14645,21 @@ var harnessAccountSnapshotSchema = external_exports.object({
14642
14645
  plan: external_exports.string().trim().min(1).max(128).optional(),
14643
14646
  credits: accountCreditsSnapshotSchema
14644
14647
  }).strict();
14645
- var harnessAccountListParamsSchema = external_exports.object({}).strict();
14648
+ var harnessAccountIdentityShape = {
14649
+ harnessId: harnessIdSchema,
14650
+ harnessName: external_exports.string().trim().min(1).max(128)
14651
+ };
14652
+ var harnessAccountSourceSchema = external_exports.object(harnessAccountIdentityShape).strict();
14653
+ var harnessAccountSourceListParamsSchema = external_exports.object({}).strict();
14654
+ var harnessAccountSourceListResultSchema = external_exports.object({ sources: external_exports.array(harnessAccountSourceSchema).max(128) }).strict();
14655
+ var harnessAccountInspectParamsSchema = external_exports.object({ harnessId: harnessIdSchema, refresh: external_exports.boolean().optional() }).strict();
14656
+ var harnessAccountInspectResultSchema = external_exports.object({
14657
+ ...harnessAccountIdentityShape,
14658
+ account: harnessAccountSnapshotSchema.nullable()
14659
+ }).strict();
14660
+ var harnessAccountListParamsSchema = external_exports.object({ refresh: external_exports.boolean().optional() }).strict();
14646
14661
  var harnessAccountListResultSchema = external_exports.object({
14647
- accounts: external_exports.array(harnessAccountSnapshotSchema.extend({
14648
- harnessId: harnessIdSchema,
14649
- harnessName: external_exports.string().min(1)
14650
- })).max(128)
14662
+ accounts: external_exports.array(harnessAccountSnapshotSchema.extend(harnessAccountIdentityShape)).max(128)
14651
14663
  }).strict();
14652
14664
 
14653
14665
  // ../../shared-contracts/dist/json-value.js
@@ -14943,7 +14955,6 @@ var threadInspectionParamsSchema = external_exports.object({
14943
14955
  }).strict();
14944
14956
  var codexThreadInspectionSchema = external_exports.object({
14945
14957
  owner: external_exports.literal("codex"),
14946
- accountId: nonBlankTextSchema2.optional(),
14947
14958
  locked: external_exports.literal(true)
14948
14959
  }).strict();
14949
14960
  var externalThreadInspectionSchema = external_exports.object({
@@ -15085,53 +15096,25 @@ var codexAccountSchema = external_exports.object({
15085
15096
  label: nonBlankTextSchema3.max(256),
15086
15097
  email: external_exports.string().email().max(320).optional(),
15087
15098
  planType: codexAccountPlanTypeSchema.optional(),
15088
- codexHome: nonBlankTextSchema3.max(16384),
15089
- active: external_exports.boolean(),
15090
- isDefault: external_exports.boolean(),
15091
15099
  authKind: codexAccountAuthKindSchema.optional(),
15092
15100
  authIdentity: nonBlankTextSchema3.max(256).optional()
15093
15101
  }).strict();
15094
- var codexAccountListResultSchema = external_exports.object({ accounts: external_exports.array(codexAccountSchema).max(128) }).strict();
15095
- var codexAccountCreateParamsSchema = external_exports.object({ label: nonBlankTextSchema3.max(256).optional() }).strict();
15096
- var codexAccountActivateParamsSchema = external_exports.object({ accountId: accountIdSchema }).strict();
15097
- var codexAccountDeleteParamsSchema = external_exports.object({ accountId: accountIdSchema }).strict();
15098
- var codexAccountDeleteResultSchema = external_exports.object({ deletedAccountId: accountIdSchema }).strict();
15099
- var codexAccountMutationResultSchema = external_exports.object({ account: codexAccountSchema }).strict();
15100
- var codexAccountLoginStartParamsSchema = external_exports.object({ accountId: accountIdSchema }).strict();
15101
- var codexAccountLoginStartResultSchema = external_exports.object({
15102
- accountId: accountIdSchema,
15103
- loginId: nonBlankTextSchema3.max(1024),
15104
- verificationUrl: external_exports.string().url().max(16384),
15105
- userCode: nonBlankTextSchema3.max(1024)
15102
+ var codexAccountPhaseSchema = external_exports.enum(["ready", "unavailable"]);
15103
+ var codexAccountListResultSchema = external_exports.object({
15104
+ version: external_exports.literal(2),
15105
+ currentAccountId: accountIdSchema.nullable(),
15106
+ phase: codexAccountPhaseSchema,
15107
+ revision: external_exports.number().int().nonnegative(),
15108
+ instanceId: nonBlankTextSchema3.max(1024).optional(),
15109
+ accounts: external_exports.array(codexAccountSchema).max(1)
15106
15110
  }).strict();
15107
- var codexAccountLoginCancelParamsSchema = external_exports.object({ accountId: accountIdSchema.optional(), loginId: nonBlankTextSchema3.max(1024) }).strict();
15108
- var codexAccountLoginCancelResultSchema = external_exports.object({ cancelled: external_exports.boolean() }).strict();
15109
- var codexAccountLoginCompletedSchema = external_exports.object({
15110
- accountId: accountIdSchema,
15111
- loginId: nonBlankTextSchema3.max(1024),
15112
- success: external_exports.boolean(),
15113
- error: external_exports.string().max(4096).nullable()
15114
- }).strict();
15115
- var codexAccountUsageParamsSchema = external_exports.object({ accountId: accountIdSchema }).strict();
15111
+ var codexAccountUsageParamsSchema = external_exports.object({ accountId: accountIdSchema, refresh: external_exports.boolean().optional() }).strict();
15116
15112
  var codexAccountUsageResultSchema = external_exports.object({
15117
15113
  accountId: accountIdSchema,
15118
15114
  usage: threadUsageSnapshotSchema.nullable(),
15119
- accountCredits: accountCreditsSnapshotSchema.optional()
15120
- }).strict();
15121
- var codexAccountResetCreditConsumeParamsSchema = external_exports.object({
15122
- accountId: accountIdSchema,
15123
- idempotencyKey: external_exports.string().uuid().optional()
15124
- }).strict();
15125
- var codexAccountResetCreditConsumeOutcomeSchema = external_exports.enum([
15126
- "reset",
15127
- "nothingToReset",
15128
- "noCredit",
15129
- "alreadyRedeemed"
15130
- ]);
15131
- var codexAccountResetCreditConsumeResultSchema = external_exports.object({
15132
- accountId: accountIdSchema,
15133
- outcome: codexAccountResetCreditConsumeOutcomeSchema,
15134
- accountCredits: accountCreditsSnapshotSchema.optional()
15115
+ accountCredits: accountCreditsSnapshotSchema.optional(),
15116
+ freshness: external_exports.enum(["live", "cached"]),
15117
+ observedAt: external_exports.string().datetime().nullable()
15135
15118
  }).strict();
15136
15119
 
15137
15120
  // ../../shared-contracts/dist/harness-session-import.js
@@ -20061,6 +20044,19 @@ var HermesAcpTransport = class {
20061
20044
  get stderrTail() {
20062
20045
  return this.#stderrTail;
20063
20046
  }
20047
+ /**
20048
+ * Point subsequent session creation at a different working directory.
20049
+ * The spawn cwd is process-launch state and cannot change after the fact,
20050
+ * but Hermes derives all session cwd behavior from the session/new
20051
+ * parameter (agent.session_cwd, task env overrides, turn-time session
20052
+ * vars), never from the process cwd — so a warm transport spawned in one
20053
+ * directory can safely host a Session for another.
20054
+ */
20055
+ retarget(cwd) {
20056
+ if (this.#sessionId)
20057
+ throw new Error("Hermes ACP Transport cannot retarget an open Session");
20058
+ this.#options = { ...this.#options, cwd };
20059
+ }
20064
20060
  async inspect() {
20065
20061
  if (this.#sessionId)
20066
20062
  throw new Error("Hermes ACP inspection cannot reuse an open Session");
@@ -20345,6 +20341,9 @@ function decodeHermesModelRefId(modelRefId) {
20345
20341
  return null;
20346
20342
  }
20347
20343
  }
20344
+ function catalogAlignedModelLabel(name) {
20345
+ return name.replace(/\s+·\s+/g, " / ");
20346
+ }
20348
20347
  function projectHermesModelState(models) {
20349
20348
  if (!models || models.availableModels.length === 0) {
20350
20349
  return { effectiveModel: null, resolvedModelLabel: null };
@@ -20354,12 +20353,13 @@ function projectHermesModelState(models) {
20354
20353
  return { effectiveModel: null, resolvedModelLabel: null };
20355
20354
  return {
20356
20355
  effectiveModel: encodeHermesModelRef(current.modelId),
20357
- resolvedModelLabel: current.name
20356
+ resolvedModelLabel: catalogAlignedModelLabel(current.name)
20358
20357
  };
20359
20358
  }
20360
20359
 
20361
20360
  // dist/hermes-inventory.js
20362
- var VENV_PYTHON_SHIM_PATTERN = /exec\s+"([^"]+?venv\/bin\/python)"/;
20361
+ var POSIX_VENV_PYTHON_SHIM_PATTERN = /exec\s+"([^"]+?venv\/bin\/python)"/;
20362
+ var WINDOWS_VENV_HERMES_SHIM_PATTERN = /"([^"]+?[\\/]venv[\\/]Scripts[\\/]hermes\.exe)"/i;
20363
20363
  var INVENTORY_PROBE_SCRIPT = `
20364
20364
  import json
20365
20365
  from hermes_cli.inventory import build_models_payload, load_picker_context
@@ -20430,11 +20430,14 @@ print(json.dumps({"models": rows, "currentModelId": current_model_id}))
20430
20430
  `;
20431
20431
  var HermesInventoryError = class extends Error {
20432
20432
  };
20433
- async function venvPythonFromShim(hermesExecutable) {
20433
+ async function venvPythonFromShim(hermesExecutable, platform = process.platform) {
20434
20434
  try {
20435
20435
  const shim = await readFile(hermesExecutable, "utf8");
20436
- const match = VENV_PYTHON_SHIM_PATTERN.exec(shim);
20437
- return match?.[1] ?? null;
20436
+ if (platform === "win32") {
20437
+ const target = WINDOWS_VENV_HERMES_SHIM_PATTERN.exec(shim)?.[1];
20438
+ return target ? path4.win32.join(path4.win32.dirname(target), "python.exe") : null;
20439
+ }
20440
+ return POSIX_VENV_PYTHON_SHIM_PATTERN.exec(shim)?.[1] ?? null;
20438
20441
  } catch {
20439
20442
  return null;
20440
20443
  }
@@ -20447,15 +20450,17 @@ function inventoryPythonCandidates(hermesExecutable, platform = process.platform
20447
20450
  if (environmentDirectory === "scripts") {
20448
20451
  candidates.push(pathApi.join(executableDirectory, "python.exe"));
20449
20452
  } else if (environmentDirectory === "bin") {
20450
- candidates.push(pathApi.join(executableDirectory, "python"));
20453
+ candidates.push(pathApi.join(executableDirectory, platform === "win32" ? "python.exe" : "python"));
20451
20454
  }
20452
- const agentDir = pathApi.resolve(executableDirectory, "../../.hermes/hermes-agent");
20453
- candidates.push(pathApi.join(agentDir, platform === "win32" ? "venv/Scripts/python.exe" : "venv/bin/python"));
20455
+ const relativePython = platform === "win32" ? "venv/Scripts/python.exe" : "venv/bin/python";
20456
+ candidates.push(pathApi.resolve(executableDirectory, "../hermes-agent", relativePython));
20457
+ candidates.push(pathApi.resolve(executableDirectory, "../../.hermes/hermes-agent", relativePython));
20454
20458
  return [...new Set(candidates)];
20455
20459
  }
20456
20460
  function runProbe(pythonExecutable, timeoutMs, environment) {
20457
20461
  return new Promise((resolve, reject) => {
20458
- const child = spawn2(pythonExecutable, ["-c", INVENTORY_PROBE_SCRIPT], {
20462
+ const child = spawn2(pythonExecutable, ["-I", "-c", INVENTORY_PROBE_SCRIPT], {
20463
+ cwd: path4.dirname(pythonExecutable),
20459
20464
  env: { ...process.env, ...environment },
20460
20465
  stdio: ["ignore", "pipe", "pipe"]
20461
20466
  });
@@ -20495,11 +20500,12 @@ function runProbe(pythonExecutable, timeoutMs, environment) {
20495
20500
  });
20496
20501
  }
20497
20502
  async function readHermesModelInventory(hermesExecutable, timeoutMs = 2e4, options = {}) {
20503
+ const platform = options.platform ?? process.platform;
20498
20504
  const candidates = [
20499
- ...options.platform === "win32" ? [] : [await venvPythonFromShim(hermesExecutable) ?? ""],
20500
- ...inventoryPythonCandidates(hermesExecutable, options.platform)
20505
+ await venvPythonFromShim(hermesExecutable, platform) ?? "",
20506
+ ...inventoryPythonCandidates(hermesExecutable, platform)
20501
20507
  ].filter((candidate, index, all) => candidate.length > 0 && all.indexOf(candidate) === index);
20502
- let pythonExecutable = candidates[0];
20508
+ let pythonExecutable = null;
20503
20509
  for (const candidate of candidates) {
20504
20510
  try {
20505
20511
  await access(candidate);
@@ -20508,8 +20514,9 @@ async function readHermesModelInventory(hermesExecutable, timeoutMs = 2e4, optio
20508
20514
  } catch {
20509
20515
  }
20510
20516
  }
20511
- if (!pythonExecutable)
20512
- throw new HermesInventoryError("Hermes inventory interpreter not found");
20517
+ if (!pythonExecutable) {
20518
+ throw new HermesInventoryError(`Hermes inventory interpreter not found (searched: ${candidates.join(", ")})`);
20519
+ }
20513
20520
  return runProbe(pythonExecutable, timeoutMs, options.environment);
20514
20521
  }
20515
20522
  function catalogModelsFromInventory(inventory) {
@@ -20659,6 +20666,7 @@ var ActiveTurn = class {
20659
20666
  #currentText = null;
20660
20667
  #toolItems = /* @__PURE__ */ new Map();
20661
20668
  #finishedItems = [];
20669
+ #emittedTerminalItemIds = /* @__PURE__ */ new Set();
20662
20670
  constructor(turnId, turnKey, input) {
20663
20671
  this.turnId = hostTurnIdSchema.parse(turnId);
20664
20672
  this.turnKey = turnKey;
@@ -20681,23 +20689,42 @@ var ActiveTurn = class {
20681
20689
  this.#currentText = { kind, item: appended };
20682
20690
  return { startedItem: item, item: appended };
20683
20691
  }
20692
+ completeCurrentText() {
20693
+ if (!this.#currentText)
20694
+ return null;
20695
+ const snapshot = {
20696
+ item: this.#currentText.item,
20697
+ outcome: { status: "succeeded" }
20698
+ };
20699
+ this.#currentText = null;
20700
+ this.#finishedItems.push(snapshot);
20701
+ this.#emittedTerminalItemIds.add(snapshot.item.itemId);
20702
+ return snapshot;
20703
+ }
20684
20704
  addToolItem(toolCallId, entry) {
20685
20705
  this.#toolItems.set(toolCallId, entry);
20686
20706
  }
20687
20707
  getToolItem(toolCallId) {
20688
20708
  return this.#toolItems.get(toolCallId);
20689
20709
  }
20710
+ updateToolOutput(toolCallId, output) {
20711
+ const entry = this.#toolItems.get(toolCallId);
20712
+ if (entry)
20713
+ entry.output = output;
20714
+ }
20690
20715
  completeToolItem(toolCallId, output, failed) {
20691
20716
  const entry = this.#toolItems.get(toolCallId);
20692
20717
  if (!entry)
20693
20718
  return null;
20694
20719
  this.#toolItems.delete(toolCallId);
20695
20720
  const outcome = failed ? { status: "failed", error: harnessError("nativeFailure", "Tool execution failed") } : { status: "succeeded" };
20721
+ const finalOutput = output ?? entry.output;
20696
20722
  const snapshot = {
20697
- item: { ...entry.item, ...output ? { output } : {} },
20723
+ item: { ...entry.item, ...finalOutput ? { output: finalOutput } : {} },
20698
20724
  outcome
20699
20725
  };
20700
20726
  this.#finishedItems.push(snapshot);
20727
+ this.#emittedTerminalItemIds.add(snapshot.item.itemId);
20701
20728
  return snapshot;
20702
20729
  }
20703
20730
  finish() {
@@ -20710,14 +20737,17 @@ var ActiveTurn = class {
20710
20737
  }
20711
20738
  for (const [, entry] of this.#toolItems) {
20712
20739
  this.#finishedItems.push({
20713
- item: entry.item,
20740
+ item: { ...entry.item, ...entry.output ? { output: entry.output } : {} },
20714
20741
  outcome: { status: "cancelled", reason: "Turn ended" }
20715
20742
  });
20716
20743
  }
20717
20744
  this.#toolItems.clear();
20718
20745
  }
20719
20746
  drainPendingItems() {
20720
- return this.#finishedItems.splice(0);
20747
+ const pending = this.#finishedItems.filter((snapshot) => !this.#emittedTerminalItemIds.has(snapshot.item.itemId));
20748
+ this.#finishedItems = [];
20749
+ this.#emittedTerminalItemIds.clear();
20750
+ return pending;
20721
20751
  }
20722
20752
  toSnapshot(nativeTurnRef, outcome, includeItems) {
20723
20753
  return {
@@ -20749,6 +20779,7 @@ function toolOutputFromUpdate(update) {
20749
20779
  function historyTurnsFromReplay(replay, nativeRef, knownTurnRefs = []) {
20750
20780
  const turns = [];
20751
20781
  let current = null;
20782
+ let toolItemIndexes = /* @__PURE__ */ new Map();
20752
20783
  const closeTurn = () => {
20753
20784
  if (!current || current.items.length === 0) {
20754
20785
  current = null;
@@ -20765,9 +20796,13 @@ function historyTurnsFromReplay(replay, nativeRef, knownTurnRefs = []) {
20765
20796
  nativeTurnRef,
20766
20797
  input: [{ type: "text", text: current.inputText }],
20767
20798
  items: current.items,
20768
- outcome: { status: "succeeded" }
20799
+ outcome: {
20800
+ status: "unknown",
20801
+ reason: "Hermes replay does not include terminal Turn outcome metadata"
20802
+ }
20769
20803
  });
20770
20804
  current = null;
20805
+ toolItemIndexes = /* @__PURE__ */ new Map();
20771
20806
  };
20772
20807
  const pushText = (kind, text) => {
20773
20808
  if (!current)
@@ -20789,8 +20824,12 @@ function historyTurnsFromReplay(replay, nativeRef, knownTurnRefs = []) {
20789
20824
  for (const event of replay) {
20790
20825
  switch (event.type) {
20791
20826
  case "user.text": {
20792
- closeTurn();
20793
- current = { inputText: event.text, items: [], turnKey: `history-${turns.length + 1}` };
20827
+ if (current && current.items.length === 0) {
20828
+ current.inputText += event.text;
20829
+ } else {
20830
+ closeTurn();
20831
+ current = { inputText: event.text, items: [], turnKey: `history-${turns.length + 1}` };
20832
+ }
20794
20833
  break;
20795
20834
  }
20796
20835
  case "agent.thought":
@@ -20803,16 +20842,42 @@ function historyTurnsFromReplay(replay, nativeRef, knownTurnRefs = []) {
20803
20842
  if (!current)
20804
20843
  current = { inputText: "(resumed)", items: [], turnKey: `history-${turns.length + 1}` };
20805
20844
  const update = event.update;
20845
+ const output = toolOutputFromUpdate(update);
20806
20846
  const toolName = typeof update.title === "string" && update.title.trim() || typeof update.name === "string" && update.name.trim() || event.toolCallId;
20807
20847
  current.items.push({
20808
20848
  item: {
20809
20849
  type: "toolExecution",
20810
20850
  itemId: hostItemIdSchema.parse(randomUUID()),
20811
20851
  toolName,
20812
- arguments: isPlainObjectOrArray(update.rawInput) ? update.rawInput : null
20852
+ arguments: isPlainObjectOrArray(update.rawInput) ? update.rawInput : null,
20853
+ ...output ? { output } : {}
20813
20854
  },
20814
- outcome: { status: "succeeded" }
20855
+ outcome: update.status === "completed" ? { status: "succeeded" } : update.status === "failed" ? {
20856
+ status: "failed",
20857
+ error: harnessError("nativeFailure", "Tool execution failed")
20858
+ } : { status: "cancelled", reason: "Turn ended before terminal tool update" }
20815
20859
  });
20860
+ toolItemIndexes.set(event.toolCallId, current.items.length - 1);
20861
+ break;
20862
+ }
20863
+ case "tool.update": {
20864
+ if (!current)
20865
+ break;
20866
+ const itemIndex = toolItemIndexes.get(event.toolCallId);
20867
+ if (itemIndex === void 0)
20868
+ break;
20869
+ const prior = current.items[itemIndex];
20870
+ if (!prior || prior.item.type !== "toolExecution")
20871
+ break;
20872
+ const update = event.update;
20873
+ const output = toolOutputFromUpdate(update);
20874
+ current.items[itemIndex] = {
20875
+ item: { ...prior.item, ...output ? { output } : {} },
20876
+ outcome: update.status === "completed" ? { status: "succeeded" } : update.status === "failed" ? {
20877
+ status: "failed",
20878
+ error: harnessError("nativeFailure", "Tool execution failed")
20879
+ } : prior.outcome
20880
+ };
20816
20881
  break;
20817
20882
  }
20818
20883
  default:
@@ -20858,10 +20923,12 @@ var HermesSession = class {
20858
20923
  #state;
20859
20924
  #faulted = null;
20860
20925
  #closed = false;
20926
+ #availableModels = [];
20861
20927
  #activeTurn = null;
20862
20928
  #activeTurnId = null;
20863
20929
  #completedTurns = [];
20864
20930
  #historyTurns;
20931
+ #latestUsage;
20865
20932
  #approvalWaiters = /* @__PURE__ */ new Map();
20866
20933
  constructor(options) {
20867
20934
  this.#transport = options.transport;
@@ -20869,6 +20936,7 @@ var HermesSession = class {
20869
20936
  this.#onSettle = options.onSettle;
20870
20937
  const projected = projectHermesModelState(options.open.session.models);
20871
20938
  const modes = options.open.session.modes;
20939
+ this.#availableModels = options.open.session.models?.availableModels ?? [];
20872
20940
  this.#state = {
20873
20941
  nativeRef: this.#nativeRef,
20874
20942
  ...projected.effectiveModel ? { effectiveModel: projected.effectiveModel } : {},
@@ -20878,6 +20946,7 @@ var HermesSession = class {
20878
20946
  this.initialState = { ...this.#state };
20879
20947
  this.#historyTurns = historyTurnsFromReplay(options.open.replay, this.#nativeRef, options.knownTurnRefs);
20880
20948
  this.initialUsage = lastUsageFromReplay(options.open.replay);
20949
+ this.#latestUsage = this.initialUsage;
20881
20950
  this.outputs = this.#channel.outputs;
20882
20951
  this.#transport.onFault = (error51) => this.#fault(transportErrorToHarness(error51));
20883
20952
  }
@@ -20924,8 +20993,14 @@ var HermesSession = class {
20924
20993
  this.#onSettle(this);
20925
20994
  }
20926
20995
  #cancelApprovalWaiters() {
20927
- for (const waiter of this.#approvalWaiters.values()) {
20996
+ for (const [interactionId, waiter] of this.#approvalWaiters) {
20928
20997
  waiter.resolve({ outcome: { outcome: "cancelled" } });
20998
+ this.#emit({
20999
+ type: "interaction.closed",
21000
+ interactionId,
21001
+ turnId: waiter.turnId,
21002
+ reason: "cancelled"
21003
+ });
20929
21004
  }
20930
21005
  this.#approvalWaiters.clear();
20931
21006
  }
@@ -20934,8 +21009,9 @@ var HermesSession = class {
20934
21009
  return;
20935
21010
  this.#faulted = error51;
20936
21011
  this.#cancelApprovalWaiters();
20937
- this.#activeTurn = null;
20938
- this.#activeTurnId = null;
21012
+ if (this.#activeTurn) {
21013
+ this.#completeActiveTurn(this.#activeTurn, { status: "failed", error: error51 });
21014
+ }
20939
21015
  this.#emit({ type: "session.faulted", error: error51 });
20940
21016
  this.#channel.end();
20941
21017
  this.#onSettle(this);
@@ -20950,8 +21026,8 @@ var HermesSession = class {
20950
21026
  if (this.#activeTurn) {
20951
21027
  return err("sessionBusy", "Hermes Session already has an active Turn", true);
20952
21028
  }
20953
- const text = command.input.filter((chunk) => chunk.type === "text").map((chunk) => chunk.text).join("\n").trim();
20954
- if (text.length === 0) {
21029
+ const text = command.input.flatMap((chunk) => chunk.type === "text" ? [chunk.text] : []).join("\n");
21030
+ if (text.trim().length === 0) {
20955
21031
  return err("invalidRequest", "turn.start requires non-empty text input");
20956
21032
  }
20957
21033
  const turnKey = randomUUID();
@@ -20973,9 +21049,6 @@ var HermesSession = class {
20973
21049
  if (this.#activeTurn !== active) {
20974
21050
  return;
20975
21051
  }
20976
- this.#activeTurn = null;
20977
- this.#activeTurnId = null;
20978
- active.finish();
20979
21052
  let outcome;
20980
21053
  if (failure2) {
20981
21054
  outcome = { status: "failed", error: failure2 };
@@ -20989,6 +21062,16 @@ var HermesSession = class {
20989
21062
  } else {
20990
21063
  outcome = { status: "succeeded" };
20991
21064
  }
21065
+ const terminalUsage = promptResponse ? usageFromPromptResponse(promptResponse.usage) : null;
21066
+ const usage = terminalUsage ? this.#mergeUsage(terminalUsage) : null;
21067
+ this.#completeActiveTurn(active, outcome, usage);
21068
+ }
21069
+ #completeActiveTurn(active, outcome, usage = null) {
21070
+ if (this.#activeTurn !== active)
21071
+ return;
21072
+ this.#activeTurn = null;
21073
+ this.#activeTurnId = null;
21074
+ active.finish();
20992
21075
  const nativeTurnRef = nativeTurnRefSchema.parse({
20993
21076
  harnessId: this.#nativeRef.harnessId,
20994
21077
  nativeSessionId: this.#nativeRef.nativeSessionId,
@@ -20999,7 +21082,6 @@ var HermesSession = class {
20999
21082
  for (const pending of active.drainPendingItems()) {
21000
21083
  this.#emit({ type: "item.completed", turnId: active.turnId, snapshot: pending });
21001
21084
  }
21002
- const usage = promptResponse ? usageFromPromptResponse(promptResponse.usage) : null;
21003
21085
  if (usage) {
21004
21086
  this.#emit({ type: "session.usage.changed", usage, observedForTurnId: active.turnId });
21005
21087
  }
@@ -21012,9 +21094,10 @@ var HermesSession = class {
21012
21094
  const usage = usageFromContext(event.used, event.size);
21013
21095
  if (!usage)
21014
21096
  return;
21097
+ const mergedUsage = this.#mergeUsage(usage);
21015
21098
  this.#emit({
21016
21099
  type: "session.usage.changed",
21017
- usage,
21100
+ usage: mergedUsage,
21018
21101
  observedForTurnId: active.turnId
21019
21102
  });
21020
21103
  return;
@@ -21028,6 +21111,7 @@ var HermesSession = class {
21028
21111
  case "tool.call": {
21029
21112
  const update = event.update;
21030
21113
  this.#startToolItem(active, event.toolCallId, typeof update.title === "string" ? update.title : null, typeof update.name === "string" ? update.name : null, update.rawInput);
21114
+ this.#updateToolItem(active, update);
21031
21115
  return;
21032
21116
  }
21033
21117
  case "tool.update":
@@ -21052,6 +21136,10 @@ var HermesSession = class {
21052
21136
  });
21053
21137
  }
21054
21138
  #startToolItem(active, toolCallId, title, name, rawInput) {
21139
+ const completedText = active.completeCurrentText();
21140
+ if (completedText) {
21141
+ this.#emit({ type: "item.completed", turnId: active.turnId, snapshot: completedText });
21142
+ }
21055
21143
  const item = {
21056
21144
  type: "toolExecution",
21057
21145
  itemId: hostItemIdSchema.parse(randomUUID()),
@@ -21061,12 +21149,18 @@ var HermesSession = class {
21061
21149
  active.addToolItem(toolCallId, { item, startedAt: Date.now() });
21062
21150
  this.#emit({ type: "item.started", turnId: active.turnId, item });
21063
21151
  }
21152
+ #mergeUsage(usage) {
21153
+ const merged = { ...this.#latestUsage ?? {}, ...usage };
21154
+ this.#latestUsage = merged;
21155
+ return merged;
21156
+ }
21064
21157
  #updateToolItem(active, update) {
21065
21158
  const entry = active.getToolItem(update.toolCallId);
21066
21159
  if (!entry)
21067
21160
  return;
21068
21161
  const output = toolOutputFromUpdate(update);
21069
21162
  if (output && output.content.length > 0) {
21163
+ active.updateToolOutput(update.toolCallId, output);
21070
21164
  this.#emit({
21071
21165
  type: "item.updated",
21072
21166
  turnId: active.turnId,
@@ -21178,10 +21272,14 @@ var HermesSession = class {
21178
21272
  }
21179
21273
  return err("nativeFailure", error51 instanceof Error ? error51.message : "Hermes rejected Model selection");
21180
21274
  }
21275
+ const projectedAfterSelect = projectHermesModelState({
21276
+ availableModels: this.#availableModels,
21277
+ currentModelId: native
21278
+ });
21181
21279
  this.#state = {
21182
21280
  ...this.#state,
21183
21281
  effectiveModel: command.model,
21184
- resolvedModelLabel: native
21282
+ resolvedModelLabel: projectedAfterSelect.resolvedModelLabel ?? catalogAlignedModelLabel(native)
21185
21283
  };
21186
21284
  this.#emit({ type: "session.state.changed", state: { ...this.#state } });
21187
21285
  return ok({ completed: true });
@@ -21213,6 +21311,7 @@ var HermesSession = class {
21213
21311
  // dist/hermes-adapter.js
21214
21312
  var hermesHarnessId = harnessIdSchema.parse("hermes");
21215
21313
  var IMPORT_TIMEOUT_MS = 2e4;
21314
+ var HERMES_THREAD_ID_ENV = "CODEXHOST_THREAD_ID";
21216
21315
  var HermesAdapter = class {
21217
21316
  harnessId = hermesHarnessId;
21218
21317
  sessionImport = {
@@ -21223,6 +21322,7 @@ var HermesAdapter = class {
21223
21322
  #inspectionCache = null;
21224
21323
  #inspectionCacheScope = null;
21225
21324
  #sessions = /* @__PURE__ */ new Set();
21325
+ #warmTransports = /* @__PURE__ */ new Map();
21226
21326
  #transports = /* @__PURE__ */ new Set();
21227
21327
  #closed = false;
21228
21328
  constructor(options = {}) {
@@ -21233,7 +21333,9 @@ var HermesAdapter = class {
21233
21333
  if (!input.refresh && this.#inspectionCache && this.#inspectionCacheScope === cwd) {
21234
21334
  return this.#inspectionCache;
21235
21335
  }
21236
- const transport = this.#createTransport(cwd);
21336
+ const environment = this.#effectiveEnvironment();
21337
+ const transport = await this.#takeTransport(cwd, environment);
21338
+ let retainedForOpen = false;
21237
21339
  try {
21238
21340
  await transport.inspect();
21239
21341
  const inventory = await this.#readInventory();
@@ -21265,11 +21367,14 @@ var HermesAdapter = class {
21265
21367
  };
21266
21368
  this.#inspectionCache = inspection;
21267
21369
  this.#inspectionCacheScope = cwd;
21370
+ this.#keepWarmTransport(cwd, environment, transport);
21371
+ retainedForOpen = true;
21268
21372
  return inspection;
21269
21373
  } catch (error51) {
21270
21374
  return inspectionFromTransportError(error51);
21271
21375
  } finally {
21272
- await this.#releaseTransport(transport);
21376
+ if (!retainedForOpen)
21377
+ await this.#releaseTransport(transport);
21273
21378
  }
21274
21379
  }
21275
21380
  async #readInventory() {
@@ -21290,9 +21395,18 @@ var HermesAdapter = class {
21290
21395
  return failure("invalidRequest", "open requires a cwd");
21291
21396
  }
21292
21397
  let transportOpen;
21398
+ let permissionModeId;
21293
21399
  if (input.kind === "create") {
21294
21400
  transportOpen = { kind: "create" };
21401
+ permissionModeId = input.permissionModeId;
21402
+ if (input.executionPolicy === "unattended-full-access") {
21403
+ if (permissionModeId && permissionModeId !== HERMES_MODE_DONT_ASK) {
21404
+ return failure("invalidRequest", "unattended-full-access requires the Hermes dont_ask Permission Mode");
21405
+ }
21406
+ permissionModeId = harnessPermissionModeIdSchema.parse(HERMES_MODE_DONT_ASK);
21407
+ }
21295
21408
  } else if (input.kind === "resume") {
21409
+ permissionModeId = input.permissionModeId;
21296
21410
  if (!input.nativeRef || input.nativeRef.harnessId !== this.harnessId) {
21297
21411
  return failure("invalidRequest", "Native Ref does not belong to Hermes");
21298
21412
  }
@@ -21300,7 +21414,11 @@ var HermesAdapter = class {
21300
21414
  } else {
21301
21415
  return failure("unsupported", `Hermes does not support ${input.kind}`);
21302
21416
  }
21303
- const transport = this.#createTransport(cwd);
21417
+ if (permissionModeId && !isHermesModeId(permissionModeId)) {
21418
+ return failure("invalidRequest", "Permission Mode does not belong to Hermes");
21419
+ }
21420
+ const environment = this.#effectiveEnvironment(input.environment);
21421
+ const transport = await this.#takeTransport(cwd, environment);
21304
21422
  if (this.#closed) {
21305
21423
  await this.#releaseTransport(transport);
21306
21424
  return failure("invalidState", "Hermes Adapter is closed");
@@ -21330,16 +21448,12 @@ var HermesAdapter = class {
21330
21448
  currentModelId: nativeModelId
21331
21449
  };
21332
21450
  }
21333
- if (input.permissionModeId) {
21334
- if (!isHermesModeId(input.permissionModeId)) {
21335
- await this.#releaseTransport(transport);
21336
- return failure("invalidRequest", "Permission Mode does not belong to Hermes");
21337
- }
21338
- if (open.session.modes?.currentModeId !== input.permissionModeId) {
21339
- await transport.setPermissionMode(input.permissionModeId);
21451
+ if (permissionModeId) {
21452
+ if (open.session.modes?.currentModeId !== permissionModeId) {
21453
+ await transport.setPermissionMode(permissionModeId);
21340
21454
  }
21341
21455
  open.session.modes = {
21342
- currentModeId: input.permissionModeId,
21456
+ currentModeId: permissionModeId,
21343
21457
  availableModes: open.session.modes?.availableModes ?? []
21344
21458
  };
21345
21459
  }
@@ -21358,6 +21472,10 @@ var HermesAdapter = class {
21358
21472
  }
21359
21473
  });
21360
21474
  this.#sessions.add(session);
21475
+ const threadSpecificKeys = Object.keys(input.environment ?? {}).filter((key) => key !== HERMES_THREAD_ID_ENV);
21476
+ if (threadSpecificKeys.length === 0) {
21477
+ this.#primeTransport(cwd, environment);
21478
+ }
21361
21479
  return { ok: true, value: session };
21362
21480
  } catch (error51) {
21363
21481
  await this.#releaseTransport(transport);
@@ -21382,11 +21500,69 @@ var HermesAdapter = class {
21382
21500
  this.#inspectionCache = null;
21383
21501
  const sessions = [...this.#sessions];
21384
21502
  this.#sessions.clear();
21503
+ this.#warmTransports.clear();
21385
21504
  await Promise.all(sessions.map((session) => session.close().catch(() => void 0)));
21386
21505
  await Promise.all([...this.#transports].map((transport) => this.#releaseTransport(transport)));
21387
21506
  }
21388
- #createTransport(cwd) {
21389
- const { command, environment, commandTimeoutMs, closeTimeoutMs } = this.#options;
21507
+ #effectiveEnvironment(environment) {
21508
+ const merged = { ...this.#options.environment ?? process.env, ...environment ?? {} };
21509
+ return Object.fromEntries(Object.entries(merged).filter(([key]) => key !== HERMES_THREAD_ID_ENV));
21510
+ }
21511
+ #transportScope(_cwd, environment) {
21512
+ const serialized = JSON.stringify(Object.entries(environment).sort(([left], [right]) => left.localeCompare(right)));
21513
+ return createHash("sha256").update(serialized).digest("hex");
21514
+ }
21515
+ async #takeTransport(cwd, environment) {
21516
+ const scope = this.#transportScope(cwd, environment);
21517
+ const pending = this.#warmTransports.get(scope);
21518
+ if (!pending)
21519
+ return this.#createTransport(cwd, environment);
21520
+ this.#warmTransports.delete(scope);
21521
+ const warmed = await pending;
21522
+ if (!warmed)
21523
+ return this.#createTransport(cwd, environment);
21524
+ warmed.retarget(cwd);
21525
+ return warmed;
21526
+ }
21527
+ #keepWarmTransport(cwd, environment, transport) {
21528
+ if (this.#closed) {
21529
+ void this.#releaseTransport(transport);
21530
+ return;
21531
+ }
21532
+ const scope = this.#transportScope(cwd, environment);
21533
+ const previous = this.#warmTransports.get(scope);
21534
+ const entry = Promise.resolve(transport);
21535
+ this.#watchWarmTransport(scope, entry, transport);
21536
+ this.#warmTransports.set(scope, entry);
21537
+ if (previous) {
21538
+ void previous.then((losing) => {
21539
+ if (losing && losing !== transport)
21540
+ return this.#releaseTransport(losing);
21541
+ });
21542
+ }
21543
+ }
21544
+ #primeTransport(cwd, environment) {
21545
+ const scope = this.#transportScope(cwd, environment);
21546
+ if (this.#closed || this.#warmTransports.has(scope))
21547
+ return;
21548
+ const transport = this.#createTransport(cwd, environment);
21549
+ const pending = transport.inspect().then(() => transport).catch(async () => {
21550
+ await this.#releaseTransport(transport);
21551
+ return null;
21552
+ });
21553
+ this.#watchWarmTransport(scope, pending, transport);
21554
+ this.#warmTransports.set(scope, pending);
21555
+ }
21556
+ #watchWarmTransport(scope, entry, transport) {
21557
+ transport.onFault = () => {
21558
+ if (this.#warmTransports.get(scope) !== entry)
21559
+ return;
21560
+ this.#warmTransports.delete(scope);
21561
+ void this.#releaseTransport(transport);
21562
+ };
21563
+ }
21564
+ #createTransport(cwd, environment = this.#effectiveEnvironment()) {
21565
+ const { command, commandTimeoutMs, closeTimeoutMs } = this.#options;
21390
21566
  const transport = new HermesAcpTransport({
21391
21567
  cwd,
21392
21568
  ...command !== void 0 && command.length > 0 ? { command } : {},