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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/README.md +1 -1
  2. package/THIRD_PARTY_NOTICES.txt +16 -0
  3. package/app/codexhost-distribution.json +1 -1
  4. package/app/desktop-controller.mjs +184 -47
  5. package/app/host-runtime.mjs +5449 -4221
  6. package/app/plugins/antigravity/plugin.mjs +70 -61
  7. package/app/plugins/claude-code/plugin.mjs +85 -58
  8. package/app/plugins/codebuddy/plugin.mjs +102 -69
  9. package/app/plugins/cursor-cli/plugin.mjs +69 -50
  10. package/app/plugins/deepseek-harness/plugin.mjs +81 -53
  11. package/app/plugins/enabled.json +3 -1
  12. package/app/plugins/grok/plugin.mjs +94 -61
  13. package/app/plugins/hermes/plugin.mjs +308 -95
  14. package/app/plugins/kiro-cli/plugin.mjs +76 -49
  15. package/app/plugins/muse/plugin.mjs +66 -46
  16. package/app/plugins/omp/plugin.mjs +79 -52
  17. package/app/plugins/opencode/plugin.mjs +118 -92
  18. package/app/plugins/pi/plugin.mjs +79 -52
  19. package/app/plugins/qoder/assets/icon.svg +1 -0
  20. package/app/plugins/qoder/manifest.json +12 -0
  21. package/app/plugins/qoder/plugin.mjs +52290 -0
  22. package/app/plugins/qoder-cn/assets/icon.svg +1 -0
  23. package/app/plugins/qoder-cn/manifest.json +12 -0
  24. package/app/plugins/qoder-cn/plugin.mjs +52288 -0
  25. package/app/renderer-extension.js +3857 -1175
  26. package/bin/boft.exe +0 -0
  27. package/libexec/boft-node-repl.exe +0 -0
  28. package/libexec/boft-shim.exe +0 -0
  29. package/libexec/boft-updater.exe +0 -0
  30. package/licenses/Qoder-Agent-SDK-LICENSE.txt +7 -0
  31. package/licenses/QoderCN-Agent-SDK-LICENSE.txt +7 -0
  32. package/licenses/opencodex-LICENSE.txt +21 -0
  33. package/licenses/tailwindcss-LICENSE.txt +21 -0
  34. package/package.json +1 -1
@@ -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, {
@@ -14522,6 +14525,46 @@ config(en_default());
14522
14525
  // ../../shared-contracts/dist/version.js
14523
14526
  var WORKSPACE_CONTRACT_VERSION = 1;
14524
14527
 
14528
+ // ../../shared-contracts/dist/idle-release.js
14529
+ var IDLE_RELEASE_TIMEOUT_MINUTES_MIN = 5;
14530
+ var IDLE_RELEASE_TIMEOUT_MINUTES_MAX = 1440;
14531
+ var idleReleaseSettingsSchema = external_exports.strictObject({
14532
+ enabled: external_exports.boolean(),
14533
+ timeoutMinutes: external_exports.number().int().min(IDLE_RELEASE_TIMEOUT_MINUTES_MIN).max(IDLE_RELEASE_TIMEOUT_MINUTES_MAX)
14534
+ });
14535
+ var DEFAULT_IDLE_RELEASE_SETTINGS = Object.freeze({
14536
+ enabled: false,
14537
+ timeoutMinutes: 30
14538
+ });
14539
+
14540
+ // ../../shared-contracts/dist/loaded-sessions.js
14541
+ var loadedSessionStateSchema = external_exports.enum([
14542
+ "idle",
14543
+ "running",
14544
+ "busy",
14545
+ "closing",
14546
+ "failed",
14547
+ "blocked"
14548
+ ]);
14549
+ var loadedSessionReasonSchema = external_exports.enum([
14550
+ "none",
14551
+ "disabled",
14552
+ "timeout",
14553
+ "operation",
14554
+ "background",
14555
+ "identity",
14556
+ "persistence",
14557
+ "closeFailed"
14558
+ ]);
14559
+ var loadedSessionsSchema = external_exports.array(external_exports.strictObject({
14560
+ threadId: external_exports.string(),
14561
+ title: external_exports.string(),
14562
+ harnessId: external_exports.string(),
14563
+ state: loadedSessionStateSchema,
14564
+ reason: loadedSessionReasonSchema,
14565
+ inactiveMs: external_exports.number().nonnegative()
14566
+ }));
14567
+
14525
14568
  // ../../shared-contracts/dist/ids.js
14526
14569
  var opaqueIdSchema = external_exports.string().refine((value) => value.trim().length > 0, {
14527
14570
  message: "Identifier must not be empty or whitespace"
@@ -14642,12 +14685,21 @@ var harnessAccountSnapshotSchema = external_exports.object({
14642
14685
  plan: external_exports.string().trim().min(1).max(128).optional(),
14643
14686
  credits: accountCreditsSnapshotSchema
14644
14687
  }).strict();
14645
- var harnessAccountListParamsSchema = external_exports.object({}).strict();
14688
+ var harnessAccountIdentityShape = {
14689
+ harnessId: harnessIdSchema,
14690
+ harnessName: external_exports.string().trim().min(1).max(128)
14691
+ };
14692
+ var harnessAccountSourceSchema = external_exports.object(harnessAccountIdentityShape).strict();
14693
+ var harnessAccountSourceListParamsSchema = external_exports.object({}).strict();
14694
+ var harnessAccountSourceListResultSchema = external_exports.object({ sources: external_exports.array(harnessAccountSourceSchema).max(128) }).strict();
14695
+ var harnessAccountInspectParamsSchema = external_exports.object({ harnessId: harnessIdSchema, refresh: external_exports.boolean().optional() }).strict();
14696
+ var harnessAccountInspectResultSchema = external_exports.object({
14697
+ ...harnessAccountIdentityShape,
14698
+ account: harnessAccountSnapshotSchema.nullable()
14699
+ }).strict();
14700
+ var harnessAccountListParamsSchema = external_exports.object({ refresh: external_exports.boolean().optional() }).strict();
14646
14701
  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)
14702
+ accounts: external_exports.array(harnessAccountSnapshotSchema.extend(harnessAccountIdentityShape)).max(128)
14651
14703
  }).strict();
14652
14704
 
14653
14705
  // ../../shared-contracts/dist/json-value.js
@@ -14943,7 +14995,6 @@ var threadInspectionParamsSchema = external_exports.object({
14943
14995
  }).strict();
14944
14996
  var codexThreadInspectionSchema = external_exports.object({
14945
14997
  owner: external_exports.literal("codex"),
14946
- accountId: nonBlankTextSchema2.optional(),
14947
14998
  locked: external_exports.literal(true)
14948
14999
  }).strict();
14949
15000
  var externalThreadInspectionSchema = external_exports.object({
@@ -15085,53 +15136,25 @@ var codexAccountSchema = external_exports.object({
15085
15136
  label: nonBlankTextSchema3.max(256),
15086
15137
  email: external_exports.string().email().max(320).optional(),
15087
15138
  planType: codexAccountPlanTypeSchema.optional(),
15088
- codexHome: nonBlankTextSchema3.max(16384),
15089
- active: external_exports.boolean(),
15090
- isDefault: external_exports.boolean(),
15091
15139
  authKind: codexAccountAuthKindSchema.optional(),
15092
15140
  authIdentity: nonBlankTextSchema3.max(256).optional()
15093
15141
  }).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)
15106
- }).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()
15142
+ var codexAccountPhaseSchema = external_exports.enum(["ready", "unavailable"]);
15143
+ var codexAccountListResultSchema = external_exports.object({
15144
+ version: external_exports.literal(2),
15145
+ currentAccountId: accountIdSchema.nullable(),
15146
+ phase: codexAccountPhaseSchema,
15147
+ revision: external_exports.number().int().nonnegative(),
15148
+ instanceId: nonBlankTextSchema3.max(1024).optional(),
15149
+ accounts: external_exports.array(codexAccountSchema).max(1)
15114
15150
  }).strict();
15115
- var codexAccountUsageParamsSchema = external_exports.object({ accountId: accountIdSchema }).strict();
15151
+ var codexAccountUsageParamsSchema = external_exports.object({ accountId: accountIdSchema, refresh: external_exports.boolean().optional() }).strict();
15116
15152
  var codexAccountUsageResultSchema = external_exports.object({
15117
15153
  accountId: accountIdSchema,
15118
15154
  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()
15155
+ accountCredits: accountCreditsSnapshotSchema.optional(),
15156
+ freshness: external_exports.enum(["live", "cached"]),
15157
+ observedAt: external_exports.string().datetime().nullable()
15135
15158
  }).strict();
15136
15159
 
15137
15160
  // ../../shared-contracts/dist/harness-session-import.js
@@ -20061,6 +20084,19 @@ var HermesAcpTransport = class {
20061
20084
  get stderrTail() {
20062
20085
  return this.#stderrTail;
20063
20086
  }
20087
+ /**
20088
+ * Point subsequent session creation at a different working directory.
20089
+ * The spawn cwd is process-launch state and cannot change after the fact,
20090
+ * but Hermes derives all session cwd behavior from the session/new
20091
+ * parameter (agent.session_cwd, task env overrides, turn-time session
20092
+ * vars), never from the process cwd — so a warm transport spawned in one
20093
+ * directory can safely host a Session for another.
20094
+ */
20095
+ retarget(cwd) {
20096
+ if (this.#sessionId)
20097
+ throw new Error("Hermes ACP Transport cannot retarget an open Session");
20098
+ this.#options = { ...this.#options, cwd };
20099
+ }
20064
20100
  async inspect() {
20065
20101
  if (this.#sessionId)
20066
20102
  throw new Error("Hermes ACP inspection cannot reuse an open Session");
@@ -20345,6 +20381,9 @@ function decodeHermesModelRefId(modelRefId) {
20345
20381
  return null;
20346
20382
  }
20347
20383
  }
20384
+ function catalogAlignedModelLabel(name) {
20385
+ return name.replace(/\s+·\s+/g, " / ");
20386
+ }
20348
20387
  function projectHermesModelState(models) {
20349
20388
  if (!models || models.availableModels.length === 0) {
20350
20389
  return { effectiveModel: null, resolvedModelLabel: null };
@@ -20354,12 +20393,13 @@ function projectHermesModelState(models) {
20354
20393
  return { effectiveModel: null, resolvedModelLabel: null };
20355
20394
  return {
20356
20395
  effectiveModel: encodeHermesModelRef(current.modelId),
20357
- resolvedModelLabel: current.name
20396
+ resolvedModelLabel: catalogAlignedModelLabel(current.name)
20358
20397
  };
20359
20398
  }
20360
20399
 
20361
20400
  // dist/hermes-inventory.js
20362
- var VENV_PYTHON_SHIM_PATTERN = /exec\s+"([^"]+?venv\/bin\/python)"/;
20401
+ var POSIX_VENV_PYTHON_SHIM_PATTERN = /exec\s+"([^"]+?venv\/bin\/python)"/;
20402
+ var WINDOWS_VENV_HERMES_SHIM_PATTERN = /"([^"]+?[\\/]venv[\\/]Scripts[\\/]hermes\.exe)"/i;
20363
20403
  var INVENTORY_PROBE_SCRIPT = `
20364
20404
  import json
20365
20405
  from hermes_cli.inventory import build_models_payload, load_picker_context
@@ -20430,11 +20470,14 @@ print(json.dumps({"models": rows, "currentModelId": current_model_id}))
20430
20470
  `;
20431
20471
  var HermesInventoryError = class extends Error {
20432
20472
  };
20433
- async function venvPythonFromShim(hermesExecutable) {
20473
+ async function venvPythonFromShim(hermesExecutable, platform = process.platform) {
20434
20474
  try {
20435
20475
  const shim = await readFile(hermesExecutable, "utf8");
20436
- const match = VENV_PYTHON_SHIM_PATTERN.exec(shim);
20437
- return match?.[1] ?? null;
20476
+ if (platform === "win32") {
20477
+ const target = WINDOWS_VENV_HERMES_SHIM_PATTERN.exec(shim)?.[1];
20478
+ return target ? path4.win32.join(path4.win32.dirname(target), "python.exe") : null;
20479
+ }
20480
+ return POSIX_VENV_PYTHON_SHIM_PATTERN.exec(shim)?.[1] ?? null;
20438
20481
  } catch {
20439
20482
  return null;
20440
20483
  }
@@ -20447,15 +20490,17 @@ function inventoryPythonCandidates(hermesExecutable, platform = process.platform
20447
20490
  if (environmentDirectory === "scripts") {
20448
20491
  candidates.push(pathApi.join(executableDirectory, "python.exe"));
20449
20492
  } else if (environmentDirectory === "bin") {
20450
- candidates.push(pathApi.join(executableDirectory, "python"));
20493
+ candidates.push(pathApi.join(executableDirectory, platform === "win32" ? "python.exe" : "python"));
20451
20494
  }
20452
- const agentDir = pathApi.resolve(executableDirectory, "../../.hermes/hermes-agent");
20453
- candidates.push(pathApi.join(agentDir, platform === "win32" ? "venv/Scripts/python.exe" : "venv/bin/python"));
20495
+ const relativePython = platform === "win32" ? "venv/Scripts/python.exe" : "venv/bin/python";
20496
+ candidates.push(pathApi.resolve(executableDirectory, "../hermes-agent", relativePython));
20497
+ candidates.push(pathApi.resolve(executableDirectory, "../../.hermes/hermes-agent", relativePython));
20454
20498
  return [...new Set(candidates)];
20455
20499
  }
20456
20500
  function runProbe(pythonExecutable, timeoutMs, environment) {
20457
20501
  return new Promise((resolve, reject) => {
20458
- const child = spawn2(pythonExecutable, ["-c", INVENTORY_PROBE_SCRIPT], {
20502
+ const child = spawn2(pythonExecutable, ["-I", "-c", INVENTORY_PROBE_SCRIPT], {
20503
+ cwd: path4.dirname(pythonExecutable),
20459
20504
  env: { ...process.env, ...environment },
20460
20505
  stdio: ["ignore", "pipe", "pipe"]
20461
20506
  });
@@ -20495,11 +20540,12 @@ function runProbe(pythonExecutable, timeoutMs, environment) {
20495
20540
  });
20496
20541
  }
20497
20542
  async function readHermesModelInventory(hermesExecutable, timeoutMs = 2e4, options = {}) {
20543
+ const platform = options.platform ?? process.platform;
20498
20544
  const candidates = [
20499
- ...options.platform === "win32" ? [] : [await venvPythonFromShim(hermesExecutable) ?? ""],
20500
- ...inventoryPythonCandidates(hermesExecutable, options.platform)
20545
+ await venvPythonFromShim(hermesExecutable, platform) ?? "",
20546
+ ...inventoryPythonCandidates(hermesExecutable, platform)
20501
20547
  ].filter((candidate, index, all) => candidate.length > 0 && all.indexOf(candidate) === index);
20502
- let pythonExecutable = candidates[0];
20548
+ let pythonExecutable = null;
20503
20549
  for (const candidate of candidates) {
20504
20550
  try {
20505
20551
  await access(candidate);
@@ -20508,8 +20554,9 @@ async function readHermesModelInventory(hermesExecutable, timeoutMs = 2e4, optio
20508
20554
  } catch {
20509
20555
  }
20510
20556
  }
20511
- if (!pythonExecutable)
20512
- throw new HermesInventoryError("Hermes inventory interpreter not found");
20557
+ if (!pythonExecutable) {
20558
+ throw new HermesInventoryError(`Hermes inventory interpreter not found (searched: ${candidates.join(", ")})`);
20559
+ }
20513
20560
  return runProbe(pythonExecutable, timeoutMs, options.environment);
20514
20561
  }
20515
20562
  function catalogModelsFromInventory(inventory) {
@@ -20659,6 +20706,7 @@ var ActiveTurn = class {
20659
20706
  #currentText = null;
20660
20707
  #toolItems = /* @__PURE__ */ new Map();
20661
20708
  #finishedItems = [];
20709
+ #emittedTerminalItemIds = /* @__PURE__ */ new Set();
20662
20710
  constructor(turnId, turnKey, input) {
20663
20711
  this.turnId = hostTurnIdSchema.parse(turnId);
20664
20712
  this.turnKey = turnKey;
@@ -20681,23 +20729,42 @@ var ActiveTurn = class {
20681
20729
  this.#currentText = { kind, item: appended };
20682
20730
  return { startedItem: item, item: appended };
20683
20731
  }
20732
+ completeCurrentText() {
20733
+ if (!this.#currentText)
20734
+ return null;
20735
+ const snapshot = {
20736
+ item: this.#currentText.item,
20737
+ outcome: { status: "succeeded" }
20738
+ };
20739
+ this.#currentText = null;
20740
+ this.#finishedItems.push(snapshot);
20741
+ this.#emittedTerminalItemIds.add(snapshot.item.itemId);
20742
+ return snapshot;
20743
+ }
20684
20744
  addToolItem(toolCallId, entry) {
20685
20745
  this.#toolItems.set(toolCallId, entry);
20686
20746
  }
20687
20747
  getToolItem(toolCallId) {
20688
20748
  return this.#toolItems.get(toolCallId);
20689
20749
  }
20750
+ updateToolOutput(toolCallId, output) {
20751
+ const entry = this.#toolItems.get(toolCallId);
20752
+ if (entry)
20753
+ entry.output = output;
20754
+ }
20690
20755
  completeToolItem(toolCallId, output, failed) {
20691
20756
  const entry = this.#toolItems.get(toolCallId);
20692
20757
  if (!entry)
20693
20758
  return null;
20694
20759
  this.#toolItems.delete(toolCallId);
20695
20760
  const outcome = failed ? { status: "failed", error: harnessError("nativeFailure", "Tool execution failed") } : { status: "succeeded" };
20761
+ const finalOutput = output ?? entry.output;
20696
20762
  const snapshot = {
20697
- item: { ...entry.item, ...output ? { output } : {} },
20763
+ item: { ...entry.item, ...finalOutput ? { output: finalOutput } : {} },
20698
20764
  outcome
20699
20765
  };
20700
20766
  this.#finishedItems.push(snapshot);
20767
+ this.#emittedTerminalItemIds.add(snapshot.item.itemId);
20701
20768
  return snapshot;
20702
20769
  }
20703
20770
  finish() {
@@ -20710,14 +20777,17 @@ var ActiveTurn = class {
20710
20777
  }
20711
20778
  for (const [, entry] of this.#toolItems) {
20712
20779
  this.#finishedItems.push({
20713
- item: entry.item,
20780
+ item: { ...entry.item, ...entry.output ? { output: entry.output } : {} },
20714
20781
  outcome: { status: "cancelled", reason: "Turn ended" }
20715
20782
  });
20716
20783
  }
20717
20784
  this.#toolItems.clear();
20718
20785
  }
20719
20786
  drainPendingItems() {
20720
- return this.#finishedItems.splice(0);
20787
+ const pending = this.#finishedItems.filter((snapshot) => !this.#emittedTerminalItemIds.has(snapshot.item.itemId));
20788
+ this.#finishedItems = [];
20789
+ this.#emittedTerminalItemIds.clear();
20790
+ return pending;
20721
20791
  }
20722
20792
  toSnapshot(nativeTurnRef, outcome, includeItems) {
20723
20793
  return {
@@ -20749,6 +20819,7 @@ function toolOutputFromUpdate(update) {
20749
20819
  function historyTurnsFromReplay(replay, nativeRef, knownTurnRefs = []) {
20750
20820
  const turns = [];
20751
20821
  let current = null;
20822
+ let toolItemIndexes = /* @__PURE__ */ new Map();
20752
20823
  const closeTurn = () => {
20753
20824
  if (!current || current.items.length === 0) {
20754
20825
  current = null;
@@ -20765,9 +20836,13 @@ function historyTurnsFromReplay(replay, nativeRef, knownTurnRefs = []) {
20765
20836
  nativeTurnRef,
20766
20837
  input: [{ type: "text", text: current.inputText }],
20767
20838
  items: current.items,
20768
- outcome: { status: "succeeded" }
20839
+ outcome: {
20840
+ status: "unknown",
20841
+ reason: "Hermes replay does not include terminal Turn outcome metadata"
20842
+ }
20769
20843
  });
20770
20844
  current = null;
20845
+ toolItemIndexes = /* @__PURE__ */ new Map();
20771
20846
  };
20772
20847
  const pushText = (kind, text) => {
20773
20848
  if (!current)
@@ -20789,8 +20864,12 @@ function historyTurnsFromReplay(replay, nativeRef, knownTurnRefs = []) {
20789
20864
  for (const event of replay) {
20790
20865
  switch (event.type) {
20791
20866
  case "user.text": {
20792
- closeTurn();
20793
- current = { inputText: event.text, items: [], turnKey: `history-${turns.length + 1}` };
20867
+ if (current && current.items.length === 0) {
20868
+ current.inputText += event.text;
20869
+ } else {
20870
+ closeTurn();
20871
+ current = { inputText: event.text, items: [], turnKey: `history-${turns.length + 1}` };
20872
+ }
20794
20873
  break;
20795
20874
  }
20796
20875
  case "agent.thought":
@@ -20803,16 +20882,42 @@ function historyTurnsFromReplay(replay, nativeRef, knownTurnRefs = []) {
20803
20882
  if (!current)
20804
20883
  current = { inputText: "(resumed)", items: [], turnKey: `history-${turns.length + 1}` };
20805
20884
  const update = event.update;
20885
+ const output = toolOutputFromUpdate(update);
20806
20886
  const toolName = typeof update.title === "string" && update.title.trim() || typeof update.name === "string" && update.name.trim() || event.toolCallId;
20807
20887
  current.items.push({
20808
20888
  item: {
20809
20889
  type: "toolExecution",
20810
20890
  itemId: hostItemIdSchema.parse(randomUUID()),
20811
20891
  toolName,
20812
- arguments: isPlainObjectOrArray(update.rawInput) ? update.rawInput : null
20892
+ arguments: isPlainObjectOrArray(update.rawInput) ? update.rawInput : null,
20893
+ ...output ? { output } : {}
20813
20894
  },
20814
- outcome: { status: "succeeded" }
20895
+ outcome: update.status === "completed" ? { status: "succeeded" } : update.status === "failed" ? {
20896
+ status: "failed",
20897
+ error: harnessError("nativeFailure", "Tool execution failed")
20898
+ } : { status: "cancelled", reason: "Turn ended before terminal tool update" }
20815
20899
  });
20900
+ toolItemIndexes.set(event.toolCallId, current.items.length - 1);
20901
+ break;
20902
+ }
20903
+ case "tool.update": {
20904
+ if (!current)
20905
+ break;
20906
+ const itemIndex = toolItemIndexes.get(event.toolCallId);
20907
+ if (itemIndex === void 0)
20908
+ break;
20909
+ const prior = current.items[itemIndex];
20910
+ if (!prior || prior.item.type !== "toolExecution")
20911
+ break;
20912
+ const update = event.update;
20913
+ const output = toolOutputFromUpdate(update);
20914
+ current.items[itemIndex] = {
20915
+ item: { ...prior.item, ...output ? { output } : {} },
20916
+ outcome: update.status === "completed" ? { status: "succeeded" } : update.status === "failed" ? {
20917
+ status: "failed",
20918
+ error: harnessError("nativeFailure", "Tool execution failed")
20919
+ } : prior.outcome
20920
+ };
20816
20921
  break;
20817
20922
  }
20818
20923
  default:
@@ -20858,10 +20963,12 @@ var HermesSession = class {
20858
20963
  #state;
20859
20964
  #faulted = null;
20860
20965
  #closed = false;
20966
+ #availableModels = [];
20861
20967
  #activeTurn = null;
20862
20968
  #activeTurnId = null;
20863
20969
  #completedTurns = [];
20864
20970
  #historyTurns;
20971
+ #latestUsage;
20865
20972
  #approvalWaiters = /* @__PURE__ */ new Map();
20866
20973
  constructor(options) {
20867
20974
  this.#transport = options.transport;
@@ -20869,6 +20976,7 @@ var HermesSession = class {
20869
20976
  this.#onSettle = options.onSettle;
20870
20977
  const projected = projectHermesModelState(options.open.session.models);
20871
20978
  const modes = options.open.session.modes;
20979
+ this.#availableModels = options.open.session.models?.availableModels ?? [];
20872
20980
  this.#state = {
20873
20981
  nativeRef: this.#nativeRef,
20874
20982
  ...projected.effectiveModel ? { effectiveModel: projected.effectiveModel } : {},
@@ -20878,6 +20986,7 @@ var HermesSession = class {
20878
20986
  this.initialState = { ...this.#state };
20879
20987
  this.#historyTurns = historyTurnsFromReplay(options.open.replay, this.#nativeRef, options.knownTurnRefs);
20880
20988
  this.initialUsage = lastUsageFromReplay(options.open.replay);
20989
+ this.#latestUsage = this.initialUsage;
20881
20990
  this.outputs = this.#channel.outputs;
20882
20991
  this.#transport.onFault = (error51) => this.#fault(transportErrorToHarness(error51));
20883
20992
  }
@@ -20924,8 +21033,14 @@ var HermesSession = class {
20924
21033
  this.#onSettle(this);
20925
21034
  }
20926
21035
  #cancelApprovalWaiters() {
20927
- for (const waiter of this.#approvalWaiters.values()) {
21036
+ for (const [interactionId, waiter] of this.#approvalWaiters) {
20928
21037
  waiter.resolve({ outcome: { outcome: "cancelled" } });
21038
+ this.#emit({
21039
+ type: "interaction.closed",
21040
+ interactionId,
21041
+ turnId: waiter.turnId,
21042
+ reason: "cancelled"
21043
+ });
20929
21044
  }
20930
21045
  this.#approvalWaiters.clear();
20931
21046
  }
@@ -20934,8 +21049,9 @@ var HermesSession = class {
20934
21049
  return;
20935
21050
  this.#faulted = error51;
20936
21051
  this.#cancelApprovalWaiters();
20937
- this.#activeTurn = null;
20938
- this.#activeTurnId = null;
21052
+ if (this.#activeTurn) {
21053
+ this.#completeActiveTurn(this.#activeTurn, { status: "failed", error: error51 });
21054
+ }
20939
21055
  this.#emit({ type: "session.faulted", error: error51 });
20940
21056
  this.#channel.end();
20941
21057
  this.#onSettle(this);
@@ -20950,8 +21066,8 @@ var HermesSession = class {
20950
21066
  if (this.#activeTurn) {
20951
21067
  return err("sessionBusy", "Hermes Session already has an active Turn", true);
20952
21068
  }
20953
- const text = command.input.filter((chunk) => chunk.type === "text").map((chunk) => chunk.text).join("\n").trim();
20954
- if (text.length === 0) {
21069
+ const text = command.input.flatMap((chunk) => chunk.type === "text" ? [chunk.text] : []).join("\n");
21070
+ if (text.trim().length === 0) {
20955
21071
  return err("invalidRequest", "turn.start requires non-empty text input");
20956
21072
  }
20957
21073
  const turnKey = randomUUID();
@@ -20973,9 +21089,6 @@ var HermesSession = class {
20973
21089
  if (this.#activeTurn !== active) {
20974
21090
  return;
20975
21091
  }
20976
- this.#activeTurn = null;
20977
- this.#activeTurnId = null;
20978
- active.finish();
20979
21092
  let outcome;
20980
21093
  if (failure2) {
20981
21094
  outcome = { status: "failed", error: failure2 };
@@ -20989,6 +21102,16 @@ var HermesSession = class {
20989
21102
  } else {
20990
21103
  outcome = { status: "succeeded" };
20991
21104
  }
21105
+ const terminalUsage = promptResponse ? usageFromPromptResponse(promptResponse.usage) : null;
21106
+ const usage = terminalUsage ? this.#mergeUsage(terminalUsage) : null;
21107
+ this.#completeActiveTurn(active, outcome, usage);
21108
+ }
21109
+ #completeActiveTurn(active, outcome, usage = null) {
21110
+ if (this.#activeTurn !== active)
21111
+ return;
21112
+ this.#activeTurn = null;
21113
+ this.#activeTurnId = null;
21114
+ active.finish();
20992
21115
  const nativeTurnRef = nativeTurnRefSchema.parse({
20993
21116
  harnessId: this.#nativeRef.harnessId,
20994
21117
  nativeSessionId: this.#nativeRef.nativeSessionId,
@@ -20999,7 +21122,6 @@ var HermesSession = class {
20999
21122
  for (const pending of active.drainPendingItems()) {
21000
21123
  this.#emit({ type: "item.completed", turnId: active.turnId, snapshot: pending });
21001
21124
  }
21002
- const usage = promptResponse ? usageFromPromptResponse(promptResponse.usage) : null;
21003
21125
  if (usage) {
21004
21126
  this.#emit({ type: "session.usage.changed", usage, observedForTurnId: active.turnId });
21005
21127
  }
@@ -21012,9 +21134,10 @@ var HermesSession = class {
21012
21134
  const usage = usageFromContext(event.used, event.size);
21013
21135
  if (!usage)
21014
21136
  return;
21137
+ const mergedUsage = this.#mergeUsage(usage);
21015
21138
  this.#emit({
21016
21139
  type: "session.usage.changed",
21017
- usage,
21140
+ usage: mergedUsage,
21018
21141
  observedForTurnId: active.turnId
21019
21142
  });
21020
21143
  return;
@@ -21028,6 +21151,7 @@ var HermesSession = class {
21028
21151
  case "tool.call": {
21029
21152
  const update = event.update;
21030
21153
  this.#startToolItem(active, event.toolCallId, typeof update.title === "string" ? update.title : null, typeof update.name === "string" ? update.name : null, update.rawInput);
21154
+ this.#updateToolItem(active, update);
21031
21155
  return;
21032
21156
  }
21033
21157
  case "tool.update":
@@ -21052,6 +21176,10 @@ var HermesSession = class {
21052
21176
  });
21053
21177
  }
21054
21178
  #startToolItem(active, toolCallId, title, name, rawInput) {
21179
+ const completedText = active.completeCurrentText();
21180
+ if (completedText) {
21181
+ this.#emit({ type: "item.completed", turnId: active.turnId, snapshot: completedText });
21182
+ }
21055
21183
  const item = {
21056
21184
  type: "toolExecution",
21057
21185
  itemId: hostItemIdSchema.parse(randomUUID()),
@@ -21061,12 +21189,18 @@ var HermesSession = class {
21061
21189
  active.addToolItem(toolCallId, { item, startedAt: Date.now() });
21062
21190
  this.#emit({ type: "item.started", turnId: active.turnId, item });
21063
21191
  }
21192
+ #mergeUsage(usage) {
21193
+ const merged = { ...this.#latestUsage ?? {}, ...usage };
21194
+ this.#latestUsage = merged;
21195
+ return merged;
21196
+ }
21064
21197
  #updateToolItem(active, update) {
21065
21198
  const entry = active.getToolItem(update.toolCallId);
21066
21199
  if (!entry)
21067
21200
  return;
21068
21201
  const output = toolOutputFromUpdate(update);
21069
21202
  if (output && output.content.length > 0) {
21203
+ active.updateToolOutput(update.toolCallId, output);
21070
21204
  this.#emit({
21071
21205
  type: "item.updated",
21072
21206
  turnId: active.turnId,
@@ -21163,9 +21297,6 @@ var HermesSession = class {
21163
21297
  }
21164
21298
  }
21165
21299
  async #selectModel(command) {
21166
- if (this.#activeTurn) {
21167
- return err("sessionBusy", "Model selection conflicts with an active Turn", true);
21168
- }
21169
21300
  const native = decodeHermesModelRefId(command.model.id);
21170
21301
  if (!native) {
21171
21302
  return err("invalidRequest", "Model Ref does not belong to Hermes");
@@ -21178,10 +21309,14 @@ var HermesSession = class {
21178
21309
  }
21179
21310
  return err("nativeFailure", error51 instanceof Error ? error51.message : "Hermes rejected Model selection");
21180
21311
  }
21312
+ const projectedAfterSelect = projectHermesModelState({
21313
+ availableModels: this.#availableModels,
21314
+ currentModelId: native
21315
+ });
21181
21316
  this.#state = {
21182
21317
  ...this.#state,
21183
21318
  effectiveModel: command.model,
21184
- resolvedModelLabel: native
21319
+ resolvedModelLabel: projectedAfterSelect.resolvedModelLabel ?? catalogAlignedModelLabel(native)
21185
21320
  };
21186
21321
  this.#emit({ type: "session.state.changed", state: { ...this.#state } });
21187
21322
  return ok({ completed: true });
@@ -21213,6 +21348,7 @@ var HermesSession = class {
21213
21348
  // dist/hermes-adapter.js
21214
21349
  var hermesHarnessId = harnessIdSchema.parse("hermes");
21215
21350
  var IMPORT_TIMEOUT_MS = 2e4;
21351
+ var HERMES_THREAD_ID_ENV = "CODEXHOST_THREAD_ID";
21216
21352
  var HermesAdapter = class {
21217
21353
  harnessId = hermesHarnessId;
21218
21354
  sessionImport = {
@@ -21223,6 +21359,7 @@ var HermesAdapter = class {
21223
21359
  #inspectionCache = null;
21224
21360
  #inspectionCacheScope = null;
21225
21361
  #sessions = /* @__PURE__ */ new Set();
21362
+ #warmTransports = /* @__PURE__ */ new Map();
21226
21363
  #transports = /* @__PURE__ */ new Set();
21227
21364
  #closed = false;
21228
21365
  constructor(options = {}) {
@@ -21233,7 +21370,9 @@ var HermesAdapter = class {
21233
21370
  if (!input.refresh && this.#inspectionCache && this.#inspectionCacheScope === cwd) {
21234
21371
  return this.#inspectionCache;
21235
21372
  }
21236
- const transport = this.#createTransport(cwd);
21373
+ const environment = this.#effectiveEnvironment();
21374
+ const transport = await this.#takeTransport(cwd, environment);
21375
+ let retainedForOpen = false;
21237
21376
  try {
21238
21377
  await transport.inspect();
21239
21378
  const inventory = await this.#readInventory();
@@ -21265,11 +21404,14 @@ var HermesAdapter = class {
21265
21404
  };
21266
21405
  this.#inspectionCache = inspection;
21267
21406
  this.#inspectionCacheScope = cwd;
21407
+ this.#keepWarmTransport(cwd, environment, transport);
21408
+ retainedForOpen = true;
21268
21409
  return inspection;
21269
21410
  } catch (error51) {
21270
21411
  return inspectionFromTransportError(error51);
21271
21412
  } finally {
21272
- await this.#releaseTransport(transport);
21413
+ if (!retainedForOpen)
21414
+ await this.#releaseTransport(transport);
21273
21415
  }
21274
21416
  }
21275
21417
  async #readInventory() {
@@ -21290,9 +21432,18 @@ var HermesAdapter = class {
21290
21432
  return failure("invalidRequest", "open requires a cwd");
21291
21433
  }
21292
21434
  let transportOpen;
21435
+ let permissionModeId;
21293
21436
  if (input.kind === "create") {
21294
21437
  transportOpen = { kind: "create" };
21438
+ permissionModeId = input.permissionModeId;
21439
+ if (input.executionPolicy === "unattended-full-access") {
21440
+ if (permissionModeId && permissionModeId !== HERMES_MODE_DONT_ASK) {
21441
+ return failure("invalidRequest", "unattended-full-access requires the Hermes dont_ask Permission Mode");
21442
+ }
21443
+ permissionModeId = harnessPermissionModeIdSchema.parse(HERMES_MODE_DONT_ASK);
21444
+ }
21295
21445
  } else if (input.kind === "resume") {
21446
+ permissionModeId = input.permissionModeId;
21296
21447
  if (!input.nativeRef || input.nativeRef.harnessId !== this.harnessId) {
21297
21448
  return failure("invalidRequest", "Native Ref does not belong to Hermes");
21298
21449
  }
@@ -21300,7 +21451,11 @@ var HermesAdapter = class {
21300
21451
  } else {
21301
21452
  return failure("unsupported", `Hermes does not support ${input.kind}`);
21302
21453
  }
21303
- const transport = this.#createTransport(cwd);
21454
+ if (permissionModeId && !isHermesModeId(permissionModeId)) {
21455
+ return failure("invalidRequest", "Permission Mode does not belong to Hermes");
21456
+ }
21457
+ const environment = this.#effectiveEnvironment(input.environment);
21458
+ const transport = await this.#takeTransport(cwd, environment);
21304
21459
  if (this.#closed) {
21305
21460
  await this.#releaseTransport(transport);
21306
21461
  return failure("invalidState", "Hermes Adapter is closed");
@@ -21330,16 +21485,12 @@ var HermesAdapter = class {
21330
21485
  currentModelId: nativeModelId
21331
21486
  };
21332
21487
  }
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);
21488
+ if (permissionModeId) {
21489
+ if (open.session.modes?.currentModeId !== permissionModeId) {
21490
+ await transport.setPermissionMode(permissionModeId);
21340
21491
  }
21341
21492
  open.session.modes = {
21342
- currentModeId: input.permissionModeId,
21493
+ currentModeId: permissionModeId,
21343
21494
  availableModes: open.session.modes?.availableModes ?? []
21344
21495
  };
21345
21496
  }
@@ -21358,6 +21509,10 @@ var HermesAdapter = class {
21358
21509
  }
21359
21510
  });
21360
21511
  this.#sessions.add(session);
21512
+ const threadSpecificKeys = Object.keys(input.environment ?? {}).filter((key) => key !== HERMES_THREAD_ID_ENV);
21513
+ if (threadSpecificKeys.length === 0) {
21514
+ this.#primeTransport(cwd, environment);
21515
+ }
21361
21516
  return { ok: true, value: session };
21362
21517
  } catch (error51) {
21363
21518
  await this.#releaseTransport(transport);
@@ -21382,11 +21537,69 @@ var HermesAdapter = class {
21382
21537
  this.#inspectionCache = null;
21383
21538
  const sessions = [...this.#sessions];
21384
21539
  this.#sessions.clear();
21540
+ this.#warmTransports.clear();
21385
21541
  await Promise.all(sessions.map((session) => session.close().catch(() => void 0)));
21386
21542
  await Promise.all([...this.#transports].map((transport) => this.#releaseTransport(transport)));
21387
21543
  }
21388
- #createTransport(cwd) {
21389
- const { command, environment, commandTimeoutMs, closeTimeoutMs } = this.#options;
21544
+ #effectiveEnvironment(environment) {
21545
+ const merged = { ...this.#options.environment ?? process.env, ...environment ?? {} };
21546
+ return Object.fromEntries(Object.entries(merged).filter(([key]) => key !== HERMES_THREAD_ID_ENV));
21547
+ }
21548
+ #transportScope(_cwd, environment) {
21549
+ const serialized = JSON.stringify(Object.entries(environment).sort(([left], [right]) => left.localeCompare(right)));
21550
+ return createHash("sha256").update(serialized).digest("hex");
21551
+ }
21552
+ async #takeTransport(cwd, environment) {
21553
+ const scope = this.#transportScope(cwd, environment);
21554
+ const pending = this.#warmTransports.get(scope);
21555
+ if (!pending)
21556
+ return this.#createTransport(cwd, environment);
21557
+ this.#warmTransports.delete(scope);
21558
+ const warmed = await pending;
21559
+ if (!warmed)
21560
+ return this.#createTransport(cwd, environment);
21561
+ warmed.retarget(cwd);
21562
+ return warmed;
21563
+ }
21564
+ #keepWarmTransport(cwd, environment, transport) {
21565
+ if (this.#closed) {
21566
+ void this.#releaseTransport(transport);
21567
+ return;
21568
+ }
21569
+ const scope = this.#transportScope(cwd, environment);
21570
+ const previous = this.#warmTransports.get(scope);
21571
+ const entry = Promise.resolve(transport);
21572
+ this.#watchWarmTransport(scope, entry, transport);
21573
+ this.#warmTransports.set(scope, entry);
21574
+ if (previous) {
21575
+ void previous.then((losing) => {
21576
+ if (losing && losing !== transport)
21577
+ return this.#releaseTransport(losing);
21578
+ });
21579
+ }
21580
+ }
21581
+ #primeTransport(cwd, environment) {
21582
+ const scope = this.#transportScope(cwd, environment);
21583
+ if (this.#closed || this.#warmTransports.has(scope))
21584
+ return;
21585
+ const transport = this.#createTransport(cwd, environment);
21586
+ const pending = transport.inspect().then(() => transport).catch(async () => {
21587
+ await this.#releaseTransport(transport);
21588
+ return null;
21589
+ });
21590
+ this.#watchWarmTransport(scope, pending, transport);
21591
+ this.#warmTransports.set(scope, pending);
21592
+ }
21593
+ #watchWarmTransport(scope, entry, transport) {
21594
+ transport.onFault = () => {
21595
+ if (this.#warmTransports.get(scope) !== entry)
21596
+ return;
21597
+ this.#warmTransports.delete(scope);
21598
+ void this.#releaseTransport(transport);
21599
+ };
21600
+ }
21601
+ #createTransport(cwd, environment = this.#effectiveEnvironment()) {
21602
+ const { command, commandTimeoutMs, closeTimeoutMs } = this.#options;
21390
21603
  const transport = new HermesAcpTransport({
21391
21604
  cwd,
21392
21605
  ...command !== void 0 && command.length > 0 ? { command } : {},