@karlorz/codexhost-cli-win32-arm64 0.13.3-5 → 0.13.3-7

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.
@@ -424,10 +424,13 @@ function usageSessionTitle(value) {
424
424
  return void 0;
425
425
  if (normalized.length <= MAX_SESSION_TITLE_LENGTH)
426
426
  return normalized;
427
- const characters = [...normalized];
428
- if (characters.length <= MAX_SESSION_TITLE_LENGTH)
429
- return normalized;
430
- return `${characters.slice(0, MAX_SESSION_TITLE_LENGTH - 1).join("").trimEnd()}…`;
427
+ let title = "";
428
+ for (const character of normalized) {
429
+ if (title.length + character.length >= MAX_SESSION_TITLE_LENGTH)
430
+ break;
431
+ title += character;
432
+ }
433
+ return `${title.trimEnd()}…`;
431
434
  }
432
435
  function sessionIdOk(value) {
433
436
  return typeof value === "string" && value.length > 0 && value.length <= MAX_SESSION_ID_LENGTH;
@@ -15363,6 +15366,7 @@ var consoleOpenResultSchema = external_exports.strictObject({
15363
15366
  url: external_exports.string().max(2048).regex(/^http:\/\/(?:127\.0\.0\.1|localhost):\d{1,5}\/(?:\?.*)?$/u)
15364
15367
  });
15365
15368
  var CONSOLE_HOST_METHODS = Object.freeze([
15369
+ "codexhost/voice/gateway-status",
15366
15370
  "codexhost/console/remote-connections",
15367
15371
  "codexhost/runtime/status",
15368
15372
  "codexhost/remote/ssh-setup",
@@ -15373,6 +15377,8 @@ var CONSOLE_HOST_METHODS = Object.freeze([
15373
15377
  "codexhost/harness/installation",
15374
15378
  "codexhost/harness/launch-settings/get",
15375
15379
  "codexhost/harness/launch-settings/set",
15380
+ "codexhost/harness/grok-computer-use/get",
15381
+ "codexhost/harness/grok-computer-use/set",
15376
15382
  "codexhost/harness/web-ui/open",
15377
15383
  "codexhost/harness/accounts/sources",
15378
15384
  "codexhost/harness/accounts/list",
@@ -15901,7 +15907,9 @@ var harnessInspectionSchema = external_exports.union([
15901
15907
  var harnessInspectParamsSchema = external_exports.object({
15902
15908
  harnessId: harnessIdSchema,
15903
15909
  cwd: nonBlankTextSchema2.max(16384).optional(),
15904
- refresh: external_exports.boolean().optional()
15910
+ refresh: external_exports.boolean().optional(),
15911
+ /** `availability` asks only whether the Harness can run; see `InspectHarnessInput.purpose`. */
15912
+ purpose: external_exports.literal("availability").optional()
15905
15913
  }).strict();
15906
15914
  var harnessWebUiOpenParamsSchema = external_exports.object({
15907
15915
  harnessId: harnessIdSchema
@@ -16075,6 +16083,26 @@ var harnessLaunchSettingsSchema = external_exports.object({
16075
16083
  restartRequired: external_exports.boolean()
16076
16084
  }).strict();
16077
16085
 
16086
+ // ../../shared-contracts/dist/grok-computer-use.js
16087
+ var grokComputerUseGetSchema = external_exports.object({}).strict();
16088
+ var grokComputerUseSetSchema = external_exports.object({
16089
+ enabled: external_exports.boolean().optional(),
16090
+ browser: external_exports.boolean().optional()
16091
+ }).strict().refine((value) => value.enabled !== void 0 || value.browser !== void 0, {
16092
+ message: "Expected enabled or browser"
16093
+ });
16094
+ var grokComputerUseSettingsSchema = external_exports.object({
16095
+ enabled: external_exports.boolean(),
16096
+ available: external_exports.boolean(),
16097
+ unavailableReason: external_exports.string().min(1).max(500).optional(),
16098
+ browser: external_exports.boolean().optional(),
16099
+ browserFilesPresent: external_exports.boolean().optional(),
16100
+ browserAvailable: external_exports.boolean().optional(),
16101
+ browserUnavailableReason: external_exports.string().min(1).max(500).optional(),
16102
+ applyFailed: external_exports.boolean().optional(),
16103
+ applyError: external_exports.string().min(1).max(500).optional()
16104
+ }).strict();
16105
+
16078
16106
  // ../../shared-contracts/dist/harness-installation.js
16079
16107
  var harnessInstallationParamsSchema = external_exports.object({
16080
16108
  harnessId: harnessIdSchema,
@@ -16472,6 +16500,52 @@ var remoteConnectionsReplySchema = external_exports.union([
16472
16500
  external_exports.strictObject({ error: external_exports.strictObject({ code: external_exports.number().int(), message: external_exports.string() }) })
16473
16501
  ]);
16474
16502
 
16503
+ // ../../shared-contracts/dist/voice-settings.js
16504
+ var voiceRoutesSchema = external_exports.strictObject({
16505
+ chatExperience: external_exports.enum(["chatgpt", "codex"]),
16506
+ chatConnection: external_exports.enum(["desktop", "gateway"]),
16507
+ workConnection: external_exports.enum(["desktop", "gateway"])
16508
+ });
16509
+ var DEFAULT_VOICE_ROUTES = Object.freeze({
16510
+ chatExperience: "chatgpt",
16511
+ chatConnection: "desktop",
16512
+ workConnection: "gateway"
16513
+ });
16514
+ var voiceSettingsSchema = voiceRoutesSchema.extend({ inject: external_exports.boolean() });
16515
+ var voiceSettingsRequestSchema = external_exports.discriminatedUnion("operation", [
16516
+ external_exports.strictObject({
16517
+ operation: external_exports.literal("get"),
16518
+ runtime: external_exports.strictObject({
16519
+ id: external_exports.string().uuid(),
16520
+ revision: external_exports.string().max(64),
16521
+ activeCall: external_exports.boolean()
16522
+ }).optional()
16523
+ }),
16524
+ external_exports.strictObject({ operation: external_exports.literal("migrate"), routes: voiceRoutesSchema }),
16525
+ external_exports.strictObject({
16526
+ operation: external_exports.literal("set"),
16527
+ settings: voiceSettingsSchema,
16528
+ revision: external_exports.string().max(64)
16529
+ }),
16530
+ external_exports.strictObject({ operation: external_exports.literal("restart"), confirm: external_exports.literal(true) })
16531
+ ]);
16532
+ var voiceSettingsStateSchema = external_exports.strictObject({
16533
+ settings: voiceSettingsSchema,
16534
+ initialized: external_exports.boolean(),
16535
+ revision: external_exports.string(),
16536
+ activeInject: external_exports.boolean().nullable(),
16537
+ envOverride: external_exports.enum(["0", "1"]).nullable(),
16538
+ activeEnvOverride: external_exports.enum(["0", "1"]).nullable(),
16539
+ routesActive: external_exports.boolean().nullable(),
16540
+ activeCall: external_exports.boolean().nullable(),
16541
+ gatewayReady: external_exports.boolean().nullable(),
16542
+ restartAvailable: external_exports.boolean(),
16543
+ restart: external_exports.strictObject({
16544
+ phase: external_exports.enum(["idle", "restarting", "succeeded", "failed"]),
16545
+ error: external_exports.string().nullable()
16546
+ })
16547
+ });
16548
+
16475
16549
  // ../../shared-contracts/dist/index.js
16476
16550
  var workspaceContractVersionSchema = external_exports.literal(WORKSPACE_CONTRACT_VERSION);
16477
16551
 
@@ -17741,2256 +17815,2348 @@ function createOmpUsageStatistics(environment) {
17741
17815
  });
17742
17816
  }
17743
17817
 
17744
- // ../../../node_modules/diff/libesm/diff/base.js
17745
- var Diff = class {
17746
- diff(oldStr, newStr, options = {}) {
17747
- let callback;
17748
- if (typeof options === "function") {
17749
- callback = options;
17750
- options = {};
17751
- } else if ("callback" in options) {
17752
- callback = options.callback;
17753
- }
17754
- const oldString = this.castInput(oldStr, options);
17755
- const newString = this.castInput(newStr, options);
17756
- const oldTokens = this.removeEmpty(this.tokenize(oldString, options));
17757
- const newTokens = this.removeEmpty(this.tokenize(newString, options));
17758
- return this.diffWithOptionsObj(oldTokens, newTokens, options, callback);
17818
+ // dist/omp-model-list.js
17819
+ import { spawn as spawn2 } from "node:child_process";
17820
+
17821
+ // dist/command.js
17822
+ var ompDiscoverySpec = {
17823
+ id: "omp",
17824
+ command: "omp",
17825
+ commandEnvironmentVariable: "OMP_COMMAND",
17826
+ installRoots: {
17827
+ posix: [
17828
+ "~/.npm-global/bin",
17829
+ "~/.local/bin",
17830
+ VERSION_MANAGER_ROOTS,
17831
+ "/opt/homebrew/bin",
17832
+ "/usr/local/bin"
17833
+ ],
17834
+ windows: ["${APPDATA}/npm", "~/.local/bin", VERSION_MANAGER_ROOTS]
17759
17835
  }
17760
- diffWithOptionsObj(oldTokens, newTokens, options, callback) {
17761
- var _a3;
17762
- const done = (value) => {
17763
- value = this.postProcess(value, options);
17764
- if (callback) {
17765
- setTimeout(function() {
17766
- callback(value);
17767
- }, 0);
17768
- return void 0;
17769
- } else {
17770
- return value;
17836
+ };
17837
+ function resolveOmpExecutable(input, dependencies = {}) {
17838
+ const resolution = resolveHarnessExecutable(ompDiscoverySpec, {
17839
+ ...input.command ? { command: input.command } : {},
17840
+ environment: input.environment,
17841
+ ...dependencies.platform ? { platform: dependencies.platform } : {},
17842
+ ...dependencies.homeDirectory ? { homeDirectory: dependencies.homeDirectory } : {}
17843
+ }, { ...dependencies.isExecutable ? { isExecutable: dependencies.isExecutable } : {} });
17844
+ return resolution?.executable ?? input.command ?? input.environment.OMP_COMMAND ?? "omp";
17845
+ }
17846
+
17847
+ // dist/omp-rpc-session.js
17848
+ import { spawn, spawnSync } from "node:child_process";
17849
+ import { randomUUID } from "node:crypto";
17850
+ import path6 from "node:path";
17851
+
17852
+ // dist/omp-slash-commands.js
17853
+ var OMP_LIVE_COMMAND_ID_PREFIX = "omp.slash.";
17854
+ function isRecord6(value) {
17855
+ return typeof value === "object" && value !== null && !Array.isArray(value);
17856
+ }
17857
+ function parseOmpAvailableCommands(value) {
17858
+ if (!Array.isArray(value))
17859
+ return [];
17860
+ return value.flatMap((entry) => {
17861
+ if (!isRecord6(entry))
17862
+ return [];
17863
+ const name = typeof entry.name === "string" ? entry.name.trim().replace(/^\//u, "") : "";
17864
+ if (!name)
17865
+ return [];
17866
+ return [
17867
+ {
17868
+ name,
17869
+ description: typeof entry.description === "string" ? entry.description : "",
17870
+ source: typeof entry.source === "string" ? entry.source : null
17771
17871
  }
17772
- };
17773
- const newLen = newTokens.length, oldLen = oldTokens.length;
17774
- let editLength = 1;
17775
- let maxEditLength = newLen + oldLen;
17776
- if (options.maxEditLength != null) {
17777
- maxEditLength = Math.min(maxEditLength, options.maxEditLength);
17778
- }
17779
- const maxExecutionTime = (_a3 = options.timeout) !== null && _a3 !== void 0 ? _a3 : Infinity;
17780
- const abortAfterTimestamp = Date.now() + maxExecutionTime;
17781
- const bestPath = [{ oldPos: -1, lastComponent: void 0 }];
17782
- let newPos = this.extractCommon(bestPath[0], newTokens, oldTokens, 0, options);
17783
- if (bestPath[0].oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
17784
- return done(this.buildValues(bestPath[0].lastComponent, newTokens, oldTokens));
17785
- }
17786
- let minDiagonalToConsider = -Infinity, maxDiagonalToConsider = Infinity;
17787
- const execEditLength = () => {
17788
- for (let diagonalPath = Math.max(minDiagonalToConsider, -editLength); diagonalPath <= Math.min(maxDiagonalToConsider, editLength); diagonalPath += 2) {
17789
- let basePath;
17790
- const removePath = bestPath[diagonalPath - 1], addPath = bestPath[diagonalPath + 1];
17791
- if (removePath) {
17792
- bestPath[diagonalPath - 1] = void 0;
17793
- }
17794
- let canAdd = false;
17795
- if (addPath) {
17796
- const addPathNewPos = addPath.oldPos - diagonalPath;
17797
- canAdd = addPath && 0 <= addPathNewPos && addPathNewPos < newLen;
17798
- }
17799
- const canRemove = removePath && removePath.oldPos + 1 < oldLen;
17800
- if (!canAdd && !canRemove) {
17801
- bestPath[diagonalPath] = void 0;
17802
- continue;
17803
- }
17804
- if (!canRemove || canAdd && removePath.oldPos < addPath.oldPos) {
17805
- basePath = this.addToPath(addPath, true, false, 0, options);
17806
- } else {
17807
- basePath = this.addToPath(removePath, false, true, 1, options);
17808
- }
17809
- newPos = this.extractCommon(basePath, newTokens, oldTokens, diagonalPath, options);
17810
- if (basePath.oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
17811
- return done(this.buildValues(basePath.lastComponent, newTokens, oldTokens)) || true;
17812
- } else {
17813
- bestPath[diagonalPath] = basePath;
17814
- if (basePath.oldPos + 1 >= oldLen) {
17815
- maxDiagonalToConsider = Math.min(maxDiagonalToConsider, diagonalPath - 1);
17816
- }
17817
- if (newPos + 1 >= newLen) {
17818
- minDiagonalToConsider = Math.max(minDiagonalToConsider, diagonalPath + 1);
17819
- }
17820
- }
17872
+ ];
17873
+ });
17874
+ }
17875
+ function ompLiveCommands(native) {
17876
+ return native.filter(({ source, name }) => source !== "builtin" || name === "context").map((command) => ({
17877
+ name: command.name,
17878
+ description: command.description,
17879
+ kind: command.source === "skill" ? "skill" : "command"
17880
+ }));
17881
+ }
17882
+
17883
+ // dist/omp-session-file.js
17884
+ import { createReadStream as createReadStream3 } from "node:fs";
17885
+ import { open, realpath as realpath2 } from "node:fs/promises";
17886
+ import readline from "node:readline";
17887
+ var MAX_SESSION_HEADER_BYTES = 64 * 1024;
17888
+ var utf8Decoder = new TextDecoder("utf-8", { fatal: true });
17889
+ function isRecord7(value) {
17890
+ return typeof value === "object" && value !== null && !Array.isArray(value);
17891
+ }
17892
+ function historyEntry(value) {
17893
+ if (!isRecord7(value) || value.type === "title" || value.type === "session" || typeof value.id !== "string" || value.id.length === 0 || value.parentId !== null && typeof value.parentId !== "string" || typeof value.type !== "string") {
17894
+ return null;
17895
+ }
17896
+ return value;
17897
+ }
17898
+ async function readOmpSessionHistory(sessionFile, maxBytes) {
17899
+ const entries = [];
17900
+ let leafId = null;
17901
+ let incomplete = false;
17902
+ const lines = readline.createInterface({
17903
+ input: createReadStream3(sessionFile, {
17904
+ encoding: "utf8",
17905
+ ...maxBytes === void 0 ? {} : { end: maxBytes - 1 }
17906
+ }),
17907
+ crlfDelay: Number.POSITIVE_INFINITY
17908
+ });
17909
+ try {
17910
+ for await (const line of lines) {
17911
+ if (line.length === 0)
17912
+ continue;
17913
+ let parsed;
17914
+ try {
17915
+ parsed = JSON.parse(line);
17916
+ } catch {
17917
+ incomplete = true;
17918
+ continue;
17821
17919
  }
17822
- editLength++;
17823
- };
17824
- if (callback) {
17825
- (function exec() {
17826
- setTimeout(function() {
17827
- if (editLength > maxEditLength || Date.now() > abortAfterTimestamp) {
17828
- return callback(void 0);
17829
- }
17830
- if (!execEditLength()) {
17831
- exec();
17832
- }
17833
- }, 0);
17834
- })();
17835
- } else {
17836
- while (editLength <= maxEditLength && Date.now() <= abortAfterTimestamp) {
17837
- const ret = execEditLength();
17838
- if (ret) {
17839
- return ret;
17920
+ const entry = historyEntry(parsed);
17921
+ if (!entry) {
17922
+ if (!isRecord7(parsed) || parsed.type !== "title" && parsed.type !== "session") {
17923
+ incomplete = true;
17840
17924
  }
17925
+ continue;
17841
17926
  }
17927
+ entries.push(entry);
17928
+ leafId = entry.id;
17842
17929
  }
17930
+ } finally {
17931
+ lines.close();
17843
17932
  }
17844
- addToPath(path9, added, removed, oldPosInc, options) {
17845
- const last = path9.lastComponent;
17846
- if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
17847
- return {
17848
- oldPos: path9.oldPos + oldPosInc,
17849
- lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
17850
- };
17851
- } else {
17852
- return {
17853
- oldPos: path9.oldPos + oldPosInc,
17854
- lastComponent: { count: 1, added, removed, previousComponent: last }
17855
- };
17856
- }
17857
- }
17858
- extractCommon(basePath, newTokens, oldTokens, diagonalPath, options) {
17859
- const newLen = newTokens.length, oldLen = oldTokens.length;
17860
- let oldPos = basePath.oldPos, newPos = oldPos - diagonalPath, commonCount = 0;
17861
- while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(oldTokens[oldPos + 1], newTokens[newPos + 1], options)) {
17862
- newPos++;
17863
- oldPos++;
17864
- commonCount++;
17865
- if (options.oneChangePerToken) {
17866
- basePath.lastComponent = { count: 1, previousComponent: basePath.lastComponent, added: false, removed: false };
17867
- }
17868
- }
17869
- if (commonCount && !options.oneChangePerToken) {
17870
- basePath.lastComponent = { count: commonCount, previousComponent: basePath.lastComponent, added: false, removed: false };
17933
+ return { entries, leafId, ...incomplete ? { incomplete: true } : {} };
17934
+ }
17935
+ async function readOmpSessionHeader(sessionFile) {
17936
+ const handle = await open(sessionFile, "r");
17937
+ try {
17938
+ const buffer = Buffer.allocUnsafe(MAX_SESSION_HEADER_BYTES);
17939
+ const { bytesRead } = await handle.read(buffer, 0, buffer.length, 0);
17940
+ const contents = buffer.subarray(0, bytesRead);
17941
+ const newline = contents.indexOf(10);
17942
+ if (newline < 0 && bytesRead === buffer.length) {
17943
+ throw new Error("Omp Session header exceeds the supported size");
17871
17944
  }
17872
- basePath.oldPos = oldPos;
17873
- return newPos;
17874
- }
17875
- equals(left, right, options) {
17876
- if (options.comparator) {
17877
- return options.comparator(left, right);
17878
- } else {
17879
- return left === right || !!options.ignoreCase && left.toLowerCase() === right.toLowerCase();
17880
- }
17881
- }
17882
- removeEmpty(array2) {
17883
- const ret = [];
17884
- for (let i = 0; i < array2.length; i++) {
17885
- if (array2[i]) {
17886
- ret.push(array2[i]);
17945
+ const contentsText = utf8Decoder.decode(contents);
17946
+ for (const line of contentsText.split("\n")) {
17947
+ if (line.length === 0)
17948
+ continue;
17949
+ let parsed;
17950
+ try {
17951
+ parsed = JSON.parse(line);
17952
+ } catch {
17953
+ continue;
17887
17954
  }
17955
+ if (!isRecord7(parsed) || parsed.type !== "session")
17956
+ continue;
17957
+ if (typeof parsed.id !== "string" || parsed.id.length === 0 || typeof parsed.cwd !== "string" || parsed.cwd.length === 0) {
17958
+ throw new Error("Omp Session header is invalid");
17959
+ }
17960
+ return { type: "session", id: parsed.id, cwd: parsed.cwd };
17888
17961
  }
17889
- return ret;
17890
- }
17891
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
17892
- castInput(value, options) {
17893
- return value;
17894
- }
17895
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
17896
- tokenize(value, options) {
17897
- return Array.from(value);
17898
- }
17899
- join(chars) {
17900
- return chars.join("");
17962
+ throw new Error("Omp Session header is invalid");
17963
+ } finally {
17964
+ await handle.close();
17901
17965
  }
17902
- postProcess(changeObjects, options) {
17903
- return changeObjects;
17966
+ }
17967
+ async function verifyOmpSessionCwd(input) {
17968
+ if (!input.sessionFile)
17969
+ throw new Error("Omp Fork Session has no persisted Session file");
17970
+ const header = await readOmpSessionHeader(input.sessionFile);
17971
+ if (header.id !== input.sessionId) {
17972
+ throw new Error("Omp Fork Session header identity does not match RPC state");
17904
17973
  }
17905
- get useLongestToken() {
17906
- return false;
17974
+ const [actualCwd, expectedCwd] = await Promise.all([
17975
+ realpath2(header.cwd),
17976
+ realpath2(input.expectedCwd)
17977
+ ]);
17978
+ if (actualCwd !== expectedCwd) {
17979
+ throw new Error("Omp Fork Session did not bind the requested cwd");
17907
17980
  }
17908
- buildValues(lastComponent, newTokens, oldTokens) {
17909
- const components = [];
17910
- let nextComponent;
17911
- while (lastComponent) {
17912
- components.push(lastComponent);
17913
- nextComponent = lastComponent.previousComponent;
17914
- delete lastComponent.previousComponent;
17915
- lastComponent = nextComponent;
17981
+ }
17982
+
17983
+ // dist/omp-protocol.js
17984
+ var MAX_FRAME_BYTES = 1024 * 1024;
17985
+ var MAX_REASSEMBLED_BYTES = 64 * 1024 * 1024;
17986
+ var MAX_CHUNK_BYTES = 256 * 1024;
17987
+ function isObject2(value) {
17988
+ return typeof value === "object" && value !== null && !Array.isArray(value);
17989
+ }
17990
+ var OmpFrameDecoder = class {
17991
+ #pending = null;
17992
+ push(value) {
17993
+ if (!isObject2(value))
17994
+ throw new Error("OMP RPC frame must be a JSON object");
17995
+ if (value.type !== "rpc_chunk") {
17996
+ if (this.#pending)
17997
+ throw new Error("OMP RPC chunk sequence was interrupted");
17998
+ return value;
17916
17999
  }
17917
- components.reverse();
17918
- const componentLen = components.length;
17919
- let componentPos = 0, newPos = 0, oldPos = 0;
17920
- for (; componentPos < componentLen; componentPos++) {
17921
- const component = components[componentPos];
17922
- if (!component.removed) {
17923
- if (!component.added && this.useLongestToken) {
17924
- let value = newTokens.slice(newPos, newPos + component.count);
17925
- value = value.map(function(value2, i) {
17926
- const oldValue = oldTokens[oldPos + i];
17927
- return oldValue.length > value2.length ? oldValue : value2;
17928
- });
17929
- component.value = this.join(value);
17930
- } else {
17931
- component.value = this.join(newTokens.slice(newPos, newPos + component.count));
17932
- }
17933
- newPos += component.count;
17934
- if (!component.added) {
17935
- oldPos += component.count;
17936
- }
17937
- } else {
17938
- component.value = this.join(oldTokens.slice(oldPos, oldPos + component.count));
17939
- oldPos += component.count;
17940
- }
18000
+ const chunkId = value.chunkId;
18001
+ const index = value.index;
18002
+ const count2 = value.count;
18003
+ const byteLength = value.byteLength;
18004
+ const data = value.data;
18005
+ if (typeof chunkId !== "string" || chunkId.length === 0 || chunkId.length > 128 || !Number.isInteger(index) || !Number.isInteger(count2) || !Number.isInteger(byteLength) || index < 0 || count2 < 2 || index >= count2 || byteLength < MAX_FRAME_BYTES || byteLength > MAX_REASSEMBLED_BYTES || typeof data !== "string" || data.length === 0)
18006
+ throw new Error("Invalid OMP RPC chunk metadata");
18007
+ let bytes;
18008
+ try {
18009
+ bytes = Buffer.from(data, "base64");
18010
+ } catch {
18011
+ throw new Error("Invalid OMP RPC chunk data");
17941
18012
  }
17942
- return components;
18013
+ if (bytes.length === 0 || bytes.length > MAX_CHUNK_BYTES || bytes.toString("base64") !== data) {
18014
+ throw new Error("Invalid OMP RPC chunk data");
18015
+ }
18016
+ const chunkIndex = index;
18017
+ const chunkCount = count2;
18018
+ const declaredByteLength = byteLength;
18019
+ if (!this.#pending) {
18020
+ if (chunkIndex !== 0)
18021
+ throw new Error("OMP RPC chunk sequence must start at index 0");
18022
+ this.#pending = {
18023
+ chunkId,
18024
+ count: chunkCount,
18025
+ byteLength: declaredByteLength,
18026
+ nextIndex: 0,
18027
+ chunks: [],
18028
+ received: 0
18029
+ };
18030
+ }
18031
+ const pending = this.#pending;
18032
+ if (!pending)
18033
+ throw new Error("OMP RPC chunk state was lost");
18034
+ if (pending.chunkId !== chunkId || pending.count !== chunkCount || pending.byteLength !== declaredByteLength || pending.nextIndex !== chunkIndex) {
18035
+ throw new Error("OMP RPC chunk sequence mismatch");
18036
+ }
18037
+ pending.chunks.push(bytes);
18038
+ pending.received += bytes.length;
18039
+ pending.nextIndex += 1;
18040
+ if (pending.received > pending.byteLength)
18041
+ throw new Error("OMP RPC chunk sequence exceeds its declared length");
18042
+ if (pending.nextIndex < pending.count)
18043
+ return null;
18044
+ if (pending.received !== pending.byteLength)
18045
+ throw new Error("OMP RPC chunk sequence length mismatch");
18046
+ this.#pending = null;
18047
+ let decoded;
18048
+ try {
18049
+ decoded = JSON.parse(Buffer.concat(pending.chunks).toString("utf8"));
18050
+ } catch {
18051
+ throw new Error("Failed to decode reassembled OMP RPC frame");
18052
+ }
18053
+ if (!isObject2(decoded))
18054
+ throw new Error("Reassembled OMP RPC frame must be an object");
18055
+ return decoded;
17943
18056
  }
17944
18057
  };
17945
18058
 
17946
- // ../../../node_modules/diff/libesm/diff/line.js
17947
- var LineDiff = class extends Diff {
17948
- constructor() {
17949
- super(...arguments);
17950
- this.tokenize = tokenize;
18059
+ // dist/omp-rpc-session.js
18060
+ var OmpRpcFaultError = class extends Error {
18061
+ kind;
18062
+ diagnostic;
18063
+ constructor(kind, message3, diagnostic) {
18064
+ super(message3);
18065
+ this.kind = kind;
18066
+ this.diagnostic = diagnostic;
18067
+ this.name = "OmpRpcFaultError";
17951
18068
  }
17952
- equals(left, right, options) {
17953
- if (options.ignoreWhitespace) {
17954
- if (!options.newlineIsToken || !left.includes("\n")) {
17955
- left = left.trim();
17956
- }
17957
- if (!options.newlineIsToken || !right.includes("\n")) {
17958
- right = right.trim();
17959
- }
17960
- } else if (options.ignoreNewlineAtEof && !options.newlineIsToken) {
17961
- if (left.endsWith("\n")) {
17962
- left = left.slice(0, -1);
17963
- }
17964
- if (right.endsWith("\n")) {
17965
- right = right.slice(0, -1);
17966
- }
17967
- }
17968
- return super.equals(left, right, options);
18069
+ };
18070
+ var OmpRpcUnsupportedCommandError = class extends Error {
18071
+ command;
18072
+ constructor(command) {
18073
+ super(`Omp RPC does not support '${command}'`);
18074
+ this.command = command;
18075
+ this.name = "OmpRpcUnsupportedCommandError";
17969
18076
  }
17970
18077
  };
17971
- var lineDiff = new LineDiff();
17972
- function diffLines(oldStr, newStr, options) {
17973
- return lineDiff.diff(oldStr, newStr, options);
18078
+ var textDecoder = new TextDecoder("utf-8", { fatal: true });
18079
+ function isRecord8(value) {
18080
+ return typeof value === "object" && value !== null && !Array.isArray(value);
17974
18081
  }
17975
- function tokenize(value, options) {
17976
- if (options.stripTrailingCr) {
17977
- value = value.replace(/\r\n/g, "\n");
18082
+ function message2(value) {
18083
+ return value instanceof Error ? value.message : String(value);
18084
+ }
18085
+ function nonBlankString(value) {
18086
+ return typeof value === "string" && value.trim().length > 0;
18087
+ }
18088
+ function parseNativeModel(value, context) {
18089
+ if (value === null || value === void 0)
18090
+ return null;
18091
+ if (!isRecord8(value) || !nonBlankString(value.provider) || !nonBlankString(value.id)) {
18092
+ throw new OmpRpcFaultError("protocolError", `Omp RPC returned an invalid ${context} Model`);
17978
18093
  }
17979
- const retLines = [], linesAndNewlines = value.split(/(\n|\r\n)/);
17980
- if (!linesAndNewlines[linesAndNewlines.length - 1]) {
17981
- linesAndNewlines.pop();
18094
+ return { provider: value.provider, id: value.id };
18095
+ }
18096
+ function sessionStateData(response) {
18097
+ const data = isRecord8(response.data) ? response.data : null;
18098
+ if (!data)
18099
+ throw new OmpRpcFaultError("protocolError", "Omp RPC state response has no data");
18100
+ return data;
18101
+ }
18102
+ function parseSessionState(response) {
18103
+ const data = sessionStateData(response);
18104
+ const model2 = parseNativeModel(data.model, "state");
18105
+ if (!nonBlankString(data.sessionId)) {
18106
+ throw new OmpRpcFaultError("protocolError", "Omp RPC state has no stable Session identity");
17982
18107
  }
17983
- for (let i = 0; i < linesAndNewlines.length; i++) {
17984
- const line = linesAndNewlines[i];
17985
- if (i % 2 && !options.newlineIsToken) {
17986
- retLines[retLines.length - 1] += line;
17987
- } else {
17988
- retLines.push(line);
17989
- }
18108
+ const thinkingLevel = data.thinkingLevel === void 0 ? null : harnessThinkingOptionIdSchema.safeParse(data.thinkingLevel);
18109
+ if (thinkingLevel !== null && !thinkingLevel.success) {
18110
+ throw new OmpRpcFaultError("protocolError", "Omp RPC state has an invalid Thinking level");
17990
18111
  }
17991
- return retLines;
17992
- }
17993
-
17994
- // ../../../node_modules/diff/libesm/patch/parse.js
17995
- function parsePatch(uniDiff) {
17996
- const diffstr = uniDiff.split(/\n/), list = [];
17997
- let i = 0;
17998
- function parseIndex() {
17999
- const index = {};
18000
- list.push(index);
18001
- while (i < diffstr.length) {
18002
- const line = diffstr[i];
18003
- if (/^(---|\+\+\+|@@)\s/.test(line)) {
18004
- break;
18005
- }
18006
- const header = /^(?:Index:|diff(?: -r \w+)+)\s+(.+?)\s*$/.exec(line);
18007
- if (header) {
18008
- index.index = header[1];
18009
- }
18010
- i++;
18011
- }
18012
- parseFileHeader(index);
18013
- parseFileHeader(index);
18014
- index.hunks = [];
18015
- while (i < diffstr.length) {
18016
- const line = diffstr[i];
18017
- if (/^(Index:\s|diff\s|---\s|\+\+\+\s|===================================================================)/.test(line)) {
18018
- break;
18019
- } else if (/^@@/.test(line)) {
18020
- index.hunks.push(parseHunk());
18021
- } else if (line) {
18022
- throw new Error("Unknown line " + (i + 1) + " " + JSON.stringify(line));
18023
- } else {
18024
- i++;
18025
- }
18026
- }
18112
+ const thinking = isRecord8(data.model) && isRecord8(data.model.thinking) ? data.model.thinking : null;
18113
+ const availableThinkingLevels = thinking && Array.isArray(thinking.efforts) ? thinking.efforts.flatMap((level) => {
18114
+ const parsed = harnessThinkingOptionIdSchema.safeParse(level);
18115
+ return parsed.success ? [parsed.data] : [];
18116
+ }) : null;
18117
+ return {
18118
+ sessionId: data.sessionId,
18119
+ sessionFile: typeof data.sessionFile === "string" ? data.sessionFile : null,
18120
+ provider: model2?.provider ?? null,
18121
+ modelId: model2?.id ?? null,
18122
+ thinkingLevel: thinkingLevel?.data ?? null,
18123
+ contextUsage: optionalOmpStateContextUsage(data.contextUsage),
18124
+ availableThinkingLevels
18125
+ };
18126
+ }
18127
+ function parseSessionStreaming(response) {
18128
+ const isStreaming = sessionStateData(response).isStreaming;
18129
+ if (typeof isStreaming !== "boolean") {
18130
+ throw new OmpRpcFaultError("protocolError", "Omp RPC state has no Streaming status");
18027
18131
  }
18028
- function parseFileHeader(index) {
18029
- const fileHeader = /^(---|\+\+\+)\s+(.*)\r?$/.exec(diffstr[i]);
18030
- if (fileHeader) {
18031
- const data = fileHeader[2].split(" ", 2), header = (data[1] || "").trim();
18032
- let fileName = data[0].replace(/\\\\/g, "\\");
18033
- if (/^".*"$/.test(fileName)) {
18034
- fileName = fileName.substr(1, fileName.length - 2);
18035
- }
18036
- if (fileHeader[1] === "---") {
18037
- index.oldFileName = fileName;
18038
- index.oldHeader = header;
18039
- } else {
18040
- index.newFileName = fileName;
18041
- index.newHeader = header;
18042
- }
18043
- i++;
18044
- }
18132
+ return isStreaming;
18133
+ }
18134
+ function cancellationSettled(response, terminalEnd) {
18135
+ const data = sessionStateData(response);
18136
+ return !parseSessionStreaming(response) && (data.isSettled === true || data.isSettled === void 0 && terminalEnd) && data.isCompacting !== true && data.hasPendingAsyncWork !== true && !(typeof data.queuedMessageCount === "number" && data.queuedMessageCount > 0);
18137
+ }
18138
+ function parseAvailableModels(response) {
18139
+ const data = isRecord8(response.data) ? response.data : null;
18140
+ if (!data || !Array.isArray(data.models)) {
18141
+ throw new OmpRpcFaultError("protocolError", "Omp RPC Model catalog response has no models");
18045
18142
  }
18046
- function parseHunk() {
18047
- var _a3;
18048
- const chunkHeaderIndex = i, chunkHeaderLine = diffstr[i++], chunkHeader = chunkHeaderLine.split(/@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/);
18049
- const hunk = {
18050
- oldStart: +chunkHeader[1],
18051
- oldLines: typeof chunkHeader[2] === "undefined" ? 1 : +chunkHeader[2],
18052
- newStart: +chunkHeader[3],
18053
- newLines: typeof chunkHeader[4] === "undefined" ? 1 : +chunkHeader[4],
18054
- lines: []
18055
- };
18056
- if (hunk.oldLines === 0) {
18057
- hunk.oldStart += 1;
18058
- }
18059
- if (hunk.newLines === 0) {
18060
- hunk.newStart += 1;
18061
- }
18062
- let addCount = 0, removeCount = 0;
18063
- for (; i < diffstr.length && (removeCount < hunk.oldLines || addCount < hunk.newLines || ((_a3 = diffstr[i]) === null || _a3 === void 0 ? void 0 : _a3.startsWith("\\"))); i++) {
18064
- const operation = diffstr[i].length == 0 && i != diffstr.length - 1 ? " " : diffstr[i][0];
18065
- if (operation === "+" || operation === "-" || operation === " " || operation === "\\") {
18066
- hunk.lines.push(diffstr[i]);
18067
- if (operation === "+") {
18068
- addCount++;
18069
- } else if (operation === "-") {
18070
- removeCount++;
18071
- } else if (operation === " ") {
18072
- addCount++;
18073
- removeCount++;
18074
- }
18075
- } else {
18076
- throw new Error(`Hunk at line ${chunkHeaderIndex + 1} contained invalid line ${diffstr[i]}`);
18077
- }
18078
- }
18079
- if (!addCount && hunk.newLines === 1) {
18080
- hunk.newLines = 0;
18081
- }
18082
- if (!removeCount && hunk.oldLines === 1) {
18083
- hunk.oldLines = 0;
18084
- }
18085
- if (addCount !== hunk.newLines) {
18086
- throw new Error("Added line count did not match for hunk at line " + (chunkHeaderIndex + 1));
18087
- }
18088
- if (removeCount !== hunk.oldLines) {
18089
- throw new Error("Removed line count did not match for hunk at line " + (chunkHeaderIndex + 1));
18143
+ return data.models.map((model2) => {
18144
+ const parsed = parseNativeModel(model2, "catalog");
18145
+ if (!parsed || !isRecord8(model2) || typeof model2.reasoning !== "boolean") {
18146
+ throw new OmpRpcFaultError("protocolError", "Omp RPC catalog contains a Model without reasoning capability");
18090
18147
  }
18091
- return hunk;
18148
+ return { ...parsed, reasoning: model2.reasoning };
18149
+ });
18150
+ }
18151
+ function parseSubagentMessages(response) {
18152
+ const data = isRecord8(response.data) ? response.data : null;
18153
+ if (!data || !nonBlankString(data.sessionFile) || !Number.isSafeInteger(data.fromByte) || !Number.isSafeInteger(data.nextByte) || data.fromByte < 0 || data.nextByte < data.fromByte || typeof data.reset !== "boolean" || !Array.isArray(data.entries) || !Array.isArray(data.messages)) {
18154
+ throw new OmpRpcFaultError("protocolError", "Omp RPC Subagent transcript response is invalid");
18092
18155
  }
18093
- while (i < diffstr.length) {
18094
- parseIndex();
18156
+ const entries = data.entries.flatMap((value) => isRecord8(value) ? [value] : []);
18157
+ const messages = data.messages.flatMap((value) => isRecord8(value) ? [value] : []);
18158
+ if (entries.length !== data.entries.length || messages.length !== data.messages.length) {
18159
+ throw new OmpRpcFaultError("protocolError", "Omp RPC Subagent transcript contains invalid data");
18095
18160
  }
18096
- return list;
18161
+ return {
18162
+ sessionFile: data.sessionFile,
18163
+ fromByte: data.fromByte,
18164
+ nextByte: data.nextByte,
18165
+ reset: data.reset,
18166
+ entries,
18167
+ messages
18168
+ };
18097
18169
  }
18098
-
18099
- // ../../../node_modules/diff/libesm/patch/create.js
18100
- function structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {
18101
- let optionsObj;
18102
- if (!options) {
18103
- optionsObj = {};
18104
- } else if (typeof options === "function") {
18105
- optionsObj = { callback: options };
18106
- } else {
18107
- optionsObj = options;
18170
+ function subagentStatus(value) {
18171
+ if (value === "pending" || value === "running" || value === "completed")
18172
+ return value;
18173
+ if (value === "failed" || value === "aborted" || value === "interrupted")
18174
+ return "failed";
18175
+ throw new OmpRpcFaultError("protocolError", "Omp RPC Subagent status is invalid");
18176
+ }
18177
+ function assistantText(value) {
18178
+ if (!isRecord8(value) || value.role !== "assistant" || !Array.isArray(value.content))
18179
+ return null;
18180
+ return value.content.filter((content) => isRecord8(content) && content.type === "text" && typeof content.text === "string").map((content) => content.text).join("");
18181
+ }
18182
+ function assistantMessageId(value) {
18183
+ if (!isRecord8(value) || value.role !== "assistant")
18184
+ return null;
18185
+ return nonBlankString(value.responseId) ? value.responseId : null;
18186
+ }
18187
+ function extractReasoningText(content) {
18188
+ if (!isRecord8(content))
18189
+ return null;
18190
+ const type = String(content.type ?? "");
18191
+ if (type === "thinking" || type === "reasoning" || type === "thought") {
18192
+ const text = content.thinking ?? content.reasoning ?? content.text ?? content.delta;
18193
+ return typeof text === "string" ? text : null;
18108
18194
  }
18109
- if (typeof optionsObj.context === "undefined") {
18110
- optionsObj.context = 4;
18195
+ return null;
18196
+ }
18197
+ function assistantReasoning(value) {
18198
+ if (!isRecord8(value) || value.role !== "assistant" || !Array.isArray(value.content))
18199
+ return null;
18200
+ return value.content.map(extractReasoningText).filter((text) => typeof text === "string").join("");
18201
+ }
18202
+ function assistantFailure(value) {
18203
+ if (!isRecord8(value) || value.role !== "assistant")
18204
+ return void 0;
18205
+ if (value.stopReason !== "error" && value.stopReason !== "aborted")
18206
+ return null;
18207
+ const fallback = value.stopReason === "aborted" ? "Omp assistant message was aborted" : "Omp assistant message failed";
18208
+ return new Error(nonBlankString(value.errorMessage) ? value.errorMessage : fallback);
18209
+ }
18210
+ function signalProcessTree(child, signal) {
18211
+ if (!child.pid)
18212
+ return;
18213
+ if (process.platform === "win32") {
18214
+ spawnSync("taskkill.exe", ["/pid", String(child.pid), "/t", "/f"], {
18215
+ stdio: "ignore",
18216
+ windowsHide: true
18217
+ });
18218
+ return;
18111
18219
  }
18112
- const context = optionsObj.context;
18113
- if (optionsObj.newlineIsToken) {
18114
- throw new Error("newlineIsToken may not be used with patch-generation functions, only with diffing functions");
18220
+ try {
18221
+ process.kill(-child.pid, signal);
18222
+ } catch (error51) {
18223
+ if (!isRecord8(error51) || error51.code !== "ESRCH")
18224
+ throw error51;
18115
18225
  }
18116
- if (!optionsObj.callback) {
18117
- return diffLinesResultToPatch(diffLines(oldStr, newStr, optionsObj));
18118
- } else {
18119
- const { callback } = optionsObj;
18120
- diffLines(oldStr, newStr, Object.assign(Object.assign({}, optionsObj), { callback: (diff) => {
18121
- const patch = diffLinesResultToPatch(diff);
18122
- callback(patch);
18123
- } }));
18226
+ }
18227
+ function waitForExit(child, timeoutMs) {
18228
+ if (child.exitCode !== null || child.signalCode !== null)
18229
+ return Promise.resolve(true);
18230
+ return Promise.race([
18231
+ new Promise((resolve) => child.once("exit", () => resolve(true))),
18232
+ new Promise((resolve) => setTimeout(() => resolve(false), timeoutMs))
18233
+ ]);
18234
+ }
18235
+ function ompRpcProcessCommand(options, dependencies = {}) {
18236
+ if (options.sessionFile && options.forkSessionFile) {
18237
+ throw new Error("Omp RPC cannot combine Session resume and Fork startup");
18124
18238
  }
18125
- function diffLinesResultToPatch(diff) {
18126
- if (!diff) {
18127
- return;
18128
- }
18129
- diff.push({ value: "", lines: [] });
18130
- function contextLines(lines) {
18131
- return lines.map(function(entry) {
18132
- return " " + entry;
18133
- });
18134
- }
18135
- const hunks = [];
18136
- let oldRangeStart = 0, newRangeStart = 0, curRange = [], oldLine = 1, newLine = 1;
18137
- for (let i = 0; i < diff.length; i++) {
18138
- const current = diff[i], lines = current.lines || splitLines(current.value);
18139
- current.lines = lines;
18140
- if (current.added || current.removed) {
18141
- if (!oldRangeStart) {
18142
- const prev = diff[i - 1];
18143
- oldRangeStart = oldLine;
18144
- newRangeStart = newLine;
18145
- if (prev) {
18146
- curRange = context > 0 ? contextLines(prev.lines.slice(-context)) : [];
18147
- oldRangeStart -= curRange.length;
18148
- newRangeStart -= curRange.length;
18149
- }
18150
- }
18151
- for (const line of lines) {
18152
- curRange.push((current.added ? "+" : "-") + line);
18153
- }
18154
- if (current.added) {
18155
- newLine += lines.length;
18156
- } else {
18157
- oldLine += lines.length;
18158
- }
18159
- } else {
18160
- if (oldRangeStart) {
18161
- if (lines.length <= context * 2 && i < diff.length - 2) {
18162
- for (const line of contextLines(lines)) {
18163
- curRange.push(line);
18164
- }
18165
- } else {
18166
- const contextSize = Math.min(lines.length, context);
18167
- for (const line of contextLines(lines.slice(0, contextSize))) {
18168
- curRange.push(line);
18169
- }
18170
- const hunk = {
18171
- oldStart: oldRangeStart,
18172
- oldLines: oldLine - oldRangeStart + contextSize,
18173
- newStart: newRangeStart,
18174
- newLines: newLine - newRangeStart + contextSize,
18175
- lines: curRange
18176
- };
18177
- hunks.push(hunk);
18178
- oldRangeStart = 0;
18179
- newRangeStart = 0;
18180
- curRange = [];
18181
- }
18182
- }
18183
- oldLine += lines.length;
18184
- newLine += lines.length;
18185
- }
18239
+ if (options.model && (options.sessionFile || options.forkSessionFile)) {
18240
+ throw new Error("Omp RPC cannot combine a startup Model with Session restore or Fork");
18241
+ }
18242
+ const platform = dependencies.platform ?? process.platform;
18243
+ const command = resolveOmpExecutable({
18244
+ ...options.command ? { command: options.command } : {},
18245
+ environment: options.environment
18246
+ }, {
18247
+ platform,
18248
+ ...dependencies.homeDirectory ? { homeDirectory: dependencies.homeDirectory } : {},
18249
+ ...dependencies.isExecutable ? { isExecutable: dependencies.isExecutable } : {}
18250
+ });
18251
+ const sessionArguments = options.forkSessionFile ? ["--fork", options.forkSessionFile] : options.sessionFile ? ["--resume", options.sessionFile] : [];
18252
+ const modelArguments = options.model ? ["--provider", options.model.provider, "--model", options.model.id] : [];
18253
+ const permissionArguments = options.permissionMode ? ["--approval-mode", options.permissionMode] : [];
18254
+ const arguments_ = [
18255
+ "--mode",
18256
+ // OMP only creates ask and connects its tool UI in rpc-ui mode.
18257
+ "rpc-ui",
18258
+ ...permissionArguments,
18259
+ ...modelArguments,
18260
+ ...sessionArguments
18261
+ ];
18262
+ const extension = path6.win32.extname(command).toLowerCase();
18263
+ if (platform !== "win32" || ![".cmd", ".bat"].includes(extension)) {
18264
+ return { command, arguments: arguments_, windowsVerbatimArguments: false };
18265
+ }
18266
+ const quote = (value) => `"${value.replaceAll("%", "%%").replaceAll('"', '""')}"`;
18267
+ const commandLine = [command, ...arguments_].map(quote).join(" ");
18268
+ return {
18269
+ command: options.environment?.ComSpec ?? options.environment?.COMSPEC ?? "cmd.exe",
18270
+ arguments: ["/d", "/v:off", "/s", "/c", `"${commandLine}"`],
18271
+ windowsVerbatimArguments: true
18272
+ };
18273
+ }
18274
+ var nodeProcessAdapter = {
18275
+ spawn(options) {
18276
+ const invocation = ompRpcProcessCommand(options);
18277
+ return spawn(invocation.command, invocation.arguments, {
18278
+ cwd: options.cwd,
18279
+ env: options.environment,
18280
+ detached: process.platform !== "win32",
18281
+ stdio: ["pipe", "pipe", "pipe"],
18282
+ windowsHide: true,
18283
+ windowsVerbatimArguments: invocation.windowsVerbatimArguments
18284
+ });
18285
+ }
18286
+ };
18287
+ var OmpRpcSession = class {
18288
+ #options;
18289
+ #processAdapter;
18290
+ #activeTurn = null;
18291
+ #buffer = Buffer.alloc(0);
18292
+ #child = null;
18293
+ #closed = false;
18294
+ #closePromise = null;
18295
+ #compactionActive = false;
18296
+ #compactionTurn = null;
18297
+ #compactionTimeout = null;
18298
+ #failed = false;
18299
+ #pending = /* @__PURE__ */ new Map();
18300
+ #state = null;
18301
+ #availableCommands = null;
18302
+ #latestCacheHitRatePercent;
18303
+ #manualCompaction = null;
18304
+ #usageRequestStartedAtMs = null;
18305
+ #stderrTail = "";
18306
+ #frameDecoder = new OmpFrameDecoder();
18307
+ #startupFaultResolve = null;
18308
+ #startupFault = new Promise((resolve) => {
18309
+ this.#startupFaultResolve = resolve;
18310
+ });
18311
+ #readyResolve = null;
18312
+ #ready = new Promise((resolve) => {
18313
+ this.#readyResolve = resolve;
18314
+ });
18315
+ constructor(options, processAdapter = nodeProcessAdapter) {
18316
+ if (options.sessionFile && options.forkSessionFile) {
18317
+ throw new Error("Omp RPC cannot combine Session resume and Fork startup");
18186
18318
  }
18187
- for (const hunk of hunks) {
18188
- for (let i = 0; i < hunk.lines.length; i++) {
18189
- if (hunk.lines[i].endsWith("\n")) {
18190
- hunk.lines[i] = hunk.lines[i].slice(0, -1);
18191
- } else {
18192
- hunk.lines.splice(i + 1, 0, "\");
18193
- i++;
18194
- }
18195
- }
18319
+ if (options.model && (options.sessionFile || options.forkSessionFile)) {
18320
+ throw new Error("Omp RPC cannot combine a startup Model with Session restore or Fork");
18196
18321
  }
18197
- return {
18198
- oldFileName,
18199
- newFileName,
18200
- oldHeader,
18201
- newHeader,
18202
- hunks
18322
+ this.#options = {
18323
+ commandTimeoutMs: 3e4,
18324
+ compactionTimeoutMs: 3e5,
18325
+ // Native Abort waits for tools, persistence and deferred work to unwind.
18326
+ // Stable cancellation must outlast the Host's 20s steering wait.
18327
+ cancelTimeoutMs: 3e4,
18328
+ closeTimeoutMs: 2e3,
18329
+ ...options
18203
18330
  };
18331
+ this.#processAdapter = processAdapter;
18204
18332
  }
18205
- }
18206
- function formatPatch(patch) {
18207
- if (Array.isArray(patch)) {
18208
- return patch.map(formatPatch).join("\n");
18333
+ get state() {
18334
+ if (!this.#state)
18335
+ throw new Error("Omp RPC Session has not started");
18336
+ return this.#state;
18209
18337
  }
18210
- const ret = [];
18211
- if (patch.oldFileName == patch.newFileName) {
18212
- ret.push("Index: " + patch.oldFileName);
18338
+ get stderrTail() {
18339
+ return this.#stderrTail;
18213
18340
  }
18214
- ret.push("===================================================================");
18215
- ret.push("--- " + patch.oldFileName + (typeof patch.oldHeader === "undefined" ? "" : " " + patch.oldHeader));
18216
- ret.push("+++ " + patch.newFileName + (typeof patch.newHeader === "undefined" ? "" : " " + patch.newHeader));
18217
- for (let i = 0; i < patch.hunks.length; i++) {
18218
- const hunk = patch.hunks[i];
18219
- if (hunk.oldLines === 0) {
18220
- hunk.oldStart -= 1;
18341
+ async start() {
18342
+ if (this.#child || this.#closed)
18343
+ throw new Error("Omp RPC Session cannot be started twice");
18344
+ const child = this.#processAdapter.spawn({
18345
+ cwd: this.#options.cwd,
18346
+ ...this.#options.command ? { command: this.#options.command } : {},
18347
+ environment: withNodeRuntimeOnPath({
18348
+ ...process.env,
18349
+ ...this.#options.environment,
18350
+ OMP_SKIP_VERSION_CHECK: "1",
18351
+ OMP_TELEMETRY: "0"
18352
+ }),
18353
+ ...this.#options.sessionFile ? { sessionFile: this.#options.sessionFile } : {},
18354
+ ...this.#options.forkSessionFile ? { forkSessionFile: this.#options.forkSessionFile } : {},
18355
+ ...this.#options.model ? { model: this.#options.model } : {},
18356
+ ...this.#options.permissionMode ? { permissionMode: this.#options.permissionMode } : {}
18357
+ });
18358
+ this.#child = child;
18359
+ child.stdout.on("data", (chunk) => this.#push(chunk));
18360
+ child.stdout.on("end", () => {
18361
+ if (this.#buffer.length !== 0) {
18362
+ this.#fail(new OmpRpcFaultError("protocolError", "Omp RPC stdout ended mid-frame"));
18363
+ }
18364
+ });
18365
+ child.stderr.on("data", (chunk) => {
18366
+ this.#stderrTail = sanitizeDiagnosticTail(`${this.#stderrTail}${chunk.toString()}`);
18367
+ });
18368
+ child.once("error", (error51) => {
18369
+ const kind = isRecord8(error51) && error51.code === "ENOENT" ? "notInstalled" : "unavailable";
18370
+ this.#fail(new OmpRpcFaultError(kind, `Omp RPC failed to start: ${error51.message}`, this.stderrTail));
18371
+ });
18372
+ child.once("exit", (code, signal) => {
18373
+ if (!this.#closed) {
18374
+ this.#fail(new OmpRpcFaultError("processExited", `Omp RPC exited (code=${code}, signal=${signal})`, this.stderrTail));
18375
+ }
18376
+ });
18377
+ await Promise.race([
18378
+ new Promise((resolve, reject) => {
18379
+ child.once("spawn", resolve);
18380
+ child.once("error", reject);
18381
+ }),
18382
+ new Promise((_resolve, reject) => setTimeout(() => reject(new Error("Omp RPC start timed out")), this.#options.commandTimeoutMs))
18383
+ ]);
18384
+ let readyTimeout;
18385
+ try {
18386
+ await Promise.race([
18387
+ this.#ready,
18388
+ this.#startupFault.then((error51) => {
18389
+ throw error51;
18390
+ }),
18391
+ new Promise((_resolve, reject) => {
18392
+ readyTimeout = setTimeout(() => reject(new Error("Omp RPC ready signal timed out")), this.#options.commandTimeoutMs);
18393
+ })
18394
+ ]);
18395
+ } finally {
18396
+ clearTimeout(readyTimeout);
18221
18397
  }
18222
- if (hunk.newLines === 0) {
18223
- hunk.newStart -= 1;
18398
+ await this.#send("negotiate_protocol", { protocolVersion: 2 }).catch(() => void 0);
18399
+ if (this.#options.subscribeSubagentEvents !== false) {
18400
+ await this.#send("set_subagent_subscription", { level: "events" }).catch(() => void 0);
18224
18401
  }
18225
- ret.push("@@ -" + hunk.oldStart + "," + hunk.oldLines + " +" + hunk.newStart + "," + hunk.newLines + " @@");
18226
- for (const line of hunk.lines) {
18227
- ret.push(line);
18402
+ try {
18403
+ this.#state = parseSessionState(await this.#send("get_state", {}));
18404
+ } catch (error51) {
18405
+ const fault = error51 instanceof OmpRpcFaultError ? error51 : new OmpRpcFaultError("unavailable", `Omp RPC state unavailable: ${message2(error51)}`);
18406
+ this.#fail(fault);
18407
+ throw fault;
18228
18408
  }
18409
+ return this;
18229
18410
  }
18230
- return ret.join("\n") + "\n";
18231
- }
18232
- function createTwoFilesPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {
18233
- if (typeof options === "function") {
18234
- options = { callback: options };
18235
- }
18236
- if (!(options === null || options === void 0 ? void 0 : options.callback)) {
18237
- const patchObj = structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options);
18238
- if (!patchObj) {
18239
- return;
18240
- }
18241
- return formatPatch(patchObj);
18242
- } else {
18243
- const { callback } = options;
18244
- structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, Object.assign(Object.assign({}, options), { callback: (patchObj) => {
18245
- if (!patchObj) {
18246
- callback(void 0);
18247
- } else {
18248
- callback(formatPatch(patchObj));
18411
+ async getEntries() {
18412
+ try {
18413
+ if (this.state.sessionFile) {
18414
+ try {
18415
+ return await readOmpSessionHistory(this.state.sessionFile);
18416
+ } catch (error51) {
18417
+ if (!isRecord8(error51) || error51.code !== "ENOENT" || this.#options.sessionFile || this.#options.forkSessionFile)
18418
+ throw error51;
18419
+ const response2 = await this.#send("get_messages", {});
18420
+ const data2 = isRecord8(response2.data) ? response2.data : null;
18421
+ if (data2 && Array.isArray(data2.messages) && data2.messages.length === 0) {
18422
+ return { entries: [], leafId: null };
18423
+ }
18424
+ throw error51;
18425
+ }
18249
18426
  }
18250
- } }));
18251
- }
18252
- }
18253
- function splitLines(text) {
18254
- const hasTrailingNl = text.endsWith("\n");
18255
- const result = text.split("\n").map((line) => line + "\n");
18256
- if (hasTrailingNl) {
18257
- result.pop();
18258
- } else {
18259
- result.push(result.pop().slice(0, -1));
18260
- }
18261
- return result;
18262
- }
18263
-
18264
- // dist/omp-adapter.js
18265
- import { randomUUID as randomUUID2 } from "node:crypto";
18266
- import { realpath as realpath3, stat as stat2 } from "node:fs/promises";
18267
- import path7 from "node:path";
18268
-
18269
- // dist/omp-slash-commands.js
18270
- var OMP_LIVE_COMMAND_ID_PREFIX = "omp.slash.";
18271
- function isRecord6(value) {
18272
- return typeof value === "object" && value !== null && !Array.isArray(value);
18273
- }
18274
- function parseOmpAvailableCommands(value) {
18275
- if (!Array.isArray(value))
18276
- return [];
18277
- return value.flatMap((entry) => {
18278
- if (!isRecord6(entry))
18279
- return [];
18280
- const name = typeof entry.name === "string" ? entry.name.trim().replace(/^\//u, "") : "";
18281
- if (!name)
18282
- return [];
18283
- return [
18284
- {
18285
- name,
18286
- description: typeof entry.description === "string" ? entry.description : "",
18287
- source: typeof entry.source === "string" ? entry.source : null
18427
+ const response = await this.#send("get_messages", {});
18428
+ const data = isRecord8(response.data) ? response.data : null;
18429
+ if (!data || !Array.isArray(data.messages)) {
18430
+ throw new OmpRpcFaultError("protocolError", "Omp RPC messages response has no messages");
18288
18431
  }
18289
- ];
18290
- });
18291
- }
18292
- function ompLiveCommands(native) {
18293
- return native.filter(({ source, name }) => source !== "builtin" || name === "context").map((command) => ({
18294
- name: command.name,
18295
- description: command.description,
18296
- kind: command.source === "skill" ? "skill" : "command"
18297
- }));
18298
- }
18299
-
18300
- // dist/omp-session-file.js
18301
- import { createReadStream as createReadStream3 } from "node:fs";
18302
- import { open, realpath as realpath2 } from "node:fs/promises";
18303
- import readline from "node:readline";
18304
- var MAX_SESSION_HEADER_BYTES = 64 * 1024;
18305
- var utf8Decoder = new TextDecoder("utf-8", { fatal: true });
18306
- function isRecord7(value) {
18307
- return typeof value === "object" && value !== null && !Array.isArray(value);
18308
- }
18309
- function historyEntry(value) {
18310
- if (!isRecord7(value) || value.type === "title" || value.type === "session" || typeof value.id !== "string" || value.id.length === 0 || value.parentId !== null && typeof value.parentId !== "string" || typeof value.type !== "string") {
18311
- return null;
18312
- }
18313
- return value;
18314
- }
18315
- async function readOmpSessionHistory(sessionFile, maxBytes) {
18316
- const entries = [];
18317
- let leafId = null;
18318
- let incomplete = false;
18319
- const lines = readline.createInterface({
18320
- input: createReadStream3(sessionFile, {
18321
- encoding: "utf8",
18322
- ...maxBytes === void 0 ? {} : { end: maxBytes - 1 }
18323
- }),
18324
- crlfDelay: Number.POSITIVE_INFINITY
18325
- });
18326
- try {
18327
- for await (const line of lines) {
18328
- if (line.length === 0)
18329
- continue;
18330
- let parsed;
18432
+ let branchEntryIds = null;
18331
18433
  try {
18332
- parsed = JSON.parse(line);
18333
- } catch {
18334
- incomplete = true;
18335
- continue;
18336
- }
18337
- const entry = historyEntry(parsed);
18338
- if (!entry) {
18339
- if (!isRecord7(parsed) || parsed.type !== "title" && parsed.type !== "session") {
18340
- incomplete = true;
18434
+ const branchResponse = await this.#send("get_branch_messages", {});
18435
+ const branchData = isRecord8(branchResponse.data) ? branchResponse.data : null;
18436
+ if (branchData && Array.isArray(branchData.messages)) {
18437
+ const parsed = branchData.messages.flatMap((entry) => {
18438
+ if (!isRecord8(entry) || !nonBlankString(entry.entryId))
18439
+ return [];
18440
+ return [entry.entryId];
18441
+ });
18442
+ if (parsed.length === branchData.messages.length)
18443
+ branchEntryIds = parsed;
18341
18444
  }
18342
- continue;
18445
+ } catch (error51) {
18446
+ if (!(error51 instanceof OmpRpcUnsupportedCommandError))
18447
+ throw error51;
18343
18448
  }
18344
- entries.push(entry);
18345
- leafId = entry.id;
18449
+ let userIndex = 0;
18450
+ let parentId = null;
18451
+ const entries = data.messages.map((nativeMessage, index) => {
18452
+ const role = isRecord8(nativeMessage) ? nativeMessage.role : void 0;
18453
+ const branchId = role === "user" ? branchEntryIds?.[userIndex] : void 0;
18454
+ if (branchId)
18455
+ userIndex += 1;
18456
+ const id = branchId ?? (isRecord8(nativeMessage) && nonBlankString(nativeMessage.id) ? nativeMessage.id : `omp-message-${index}`);
18457
+ const entry = { id, parentId, type: "message", message: nativeMessage };
18458
+ parentId = id;
18459
+ return entry;
18460
+ });
18461
+ return { entries, leafId: parentId };
18462
+ } catch (error51) {
18463
+ if (error51 instanceof OmpRpcFaultError)
18464
+ this.#fail(error51);
18465
+ throw error51;
18346
18466
  }
18347
- } finally {
18348
- lines.close();
18349
18467
  }
18350
- return { entries, leafId, ...incomplete ? { incomplete: true } : {} };
18351
- }
18352
- async function readOmpSessionHeader(sessionFile) {
18353
- const handle = await open(sessionFile, "r");
18354
- try {
18355
- const buffer = Buffer.allocUnsafe(MAX_SESSION_HEADER_BYTES);
18356
- const { bytesRead } = await handle.read(buffer, 0, buffer.length, 0);
18357
- const contents = buffer.subarray(0, bytesRead);
18358
- const newline = contents.indexOf(10);
18359
- if (newline < 0 && bytesRead === buffer.length) {
18360
- throw new Error("Omp Session header exceeds the supported size");
18468
+ async getSubagentMessages(input) {
18469
+ if ((input.subagentId === void 0 || !nonBlankString(input.subagentId)) && (input.sessionFile === void 0 || !nonBlankString(input.sessionFile))) {
18470
+ throw new Error("Omp Subagent transcript requires a Subagent ID or Session file");
18361
18471
  }
18362
- const contentsText = utf8Decoder.decode(contents);
18363
- for (const line of contentsText.split("\n")) {
18364
- if (line.length === 0)
18365
- continue;
18366
- let parsed;
18367
- try {
18368
- parsed = JSON.parse(line);
18369
- } catch {
18370
- continue;
18371
- }
18372
- if (!isRecord7(parsed) || parsed.type !== "session")
18373
- continue;
18374
- if (typeof parsed.id !== "string" || parsed.id.length === 0 || typeof parsed.cwd !== "string" || parsed.cwd.length === 0) {
18375
- throw new Error("Omp Session header is invalid");
18376
- }
18377
- return { type: "session", id: parsed.id, cwd: parsed.cwd };
18472
+ if (input.fromByte !== void 0 && (!Number.isSafeInteger(input.fromByte) || input.fromByte < 0)) {
18473
+ throw new Error("Omp Subagent transcript offset is invalid");
18378
18474
  }
18379
- throw new Error("Omp Session header is invalid");
18380
- } finally {
18381
- await handle.close();
18475
+ const response = await this.#send("get_subagent_messages", {
18476
+ ...input.subagentId ? { subagentId: input.subagentId } : {},
18477
+ ...input.sessionFile ? { sessionFile: input.sessionFile } : {},
18478
+ ...input.fromByte !== void 0 ? { fromByte: input.fromByte } : {}
18479
+ });
18480
+ return parseSubagentMessages(response);
18382
18481
  }
18383
- }
18384
- async function verifyOmpSessionCwd(input) {
18385
- if (!input.sessionFile)
18386
- throw new Error("Omp Fork Session has no persisted Session file");
18387
- const header = await readOmpSessionHeader(input.sessionFile);
18388
- if (header.id !== input.sessionId) {
18389
- throw new Error("Omp Fork Session header identity does not match RPC state");
18482
+ async compact(customInstructions, onEvent) {
18483
+ if (!this.#child || !this.#state || this.#closed || this.#failed) {
18484
+ throw new Error("Omp RPC Session is unavailable");
18485
+ }
18486
+ if (this.#activeTurn || this.#manualCompaction || this.#compactionActive) {
18487
+ throw new Error("Omp RPC Session already has an active operation");
18488
+ }
18489
+ const result = new Promise((resolve, reject) => {
18490
+ this.#manualCompaction = { onEvent, resolve, reject };
18491
+ });
18492
+ try {
18493
+ await this.#send("compact", customInstructions ? { customInstructions } : {});
18494
+ } catch (error51) {
18495
+ const pending = this.#manualCompaction;
18496
+ this.#manualCompaction = null;
18497
+ pending?.reject(error51 instanceof Error ? error51 : new Error(message2(error51)));
18498
+ }
18499
+ return result;
18390
18500
  }
18391
- const [actualCwd, expectedCwd] = await Promise.all([
18392
- realpath2(header.cwd),
18393
- realpath2(input.expectedCwd)
18394
- ]);
18395
- if (actualCwd !== expectedCwd) {
18396
- throw new Error("Omp Fork Session did not bind the requested cwd");
18501
+ async getSessionUsage() {
18502
+ try {
18503
+ const usage = parseOmpSessionUsage(await this.#send("get_session_stats", {}));
18504
+ await this.#ensureLatestCacheHitRate();
18505
+ return this.#withLatestCacheHitRate(usage);
18506
+ } catch (error51) {
18507
+ if (!(error51 instanceof OmpRpcUnsupportedCommandError))
18508
+ throw error51;
18509
+ const response = await this.#send("get_state", {});
18510
+ const observedState = parseSessionState(response);
18511
+ if (!this.#state || observedState.sessionId !== this.#state.sessionId || observedState.provider !== this.#state.provider || observedState.modelId !== this.#state.modelId) {
18512
+ throw new Error("Omp RPC Usage fallback does not match the confirmed Session state");
18513
+ }
18514
+ await this.#ensureLatestCacheHitRate();
18515
+ const usage = parseOmpStateContextUsage(response);
18516
+ return usage ? this.#withLatestCacheHitRate(usage) : null;
18517
+ }
18397
18518
  }
18398
- }
18399
-
18400
- // dist/omp-last-turn-rollback.js
18401
- function modelFromState(state) {
18402
- if (state.provider === null && state.modelId === null)
18403
- return null;
18404
- if (state.provider === null || state.modelId === null) {
18405
- throw new Error("Omp state contains a partial Model identity");
18519
+ async #ensureLatestCacheHitRate() {
18520
+ if (this.#latestCacheHitRatePercent !== void 0)
18521
+ return;
18522
+ try {
18523
+ this.#latestCacheHitRatePercent = latestOmpCacheHitRatePercent(await this.getEntries());
18524
+ } catch {
18525
+ this.#latestCacheHitRatePercent = null;
18526
+ }
18406
18527
  }
18407
- return { provider: state.provider, id: state.modelId };
18408
- }
18409
- async function rollbackOmpLastTurn(transport, sourceSessionId, cwd) {
18410
- const startupState = transport.state;
18411
- const startupSessionId = startupState.sessionId;
18412
- const currentModel = modelFromState(startupState);
18413
- const currentThinking = startupState.thinkingLevel;
18414
- const copiedHistory = await transport.getEntries();
18415
- const boundary = resolveOmpLastTurnBoundary(copiedHistory);
18416
- if (!boundary)
18417
- return { ok: false, reason: "empty" };
18418
- const sourceSnapshot = mapOmpSnapshot(copiedHistory, {
18419
- sessionId: startupSessionId,
18420
- model: currentModel
18421
- });
18422
- let state = await transport.fork(boundary.lastUserEntryId);
18423
- if (state.sessionId === sourceSessionId || state.sessionId === startupSessionId) {
18424
- throw new Error("Omp last-Turn rollback did not create a distinct Native Session");
18528
+ #withLatestCacheHitRate(usage) {
18529
+ return this.#latestCacheHitRatePercent === null || this.#latestCacheHitRatePercent === void 0 ? usage : parseHostUsage({ ...usage, cacheHitRatePercent: this.#latestCacheHitRatePercent });
18425
18530
  }
18426
- if (!sameOmpModel(modelFromState(state), currentModel)) {
18427
- if (!currentModel)
18428
- throw new Error("Omp last-Turn rollback changed the current Model");
18429
- state = await transport.selectModel(currentModel);
18531
+ async fork(entryId) {
18532
+ if (!nonBlankString(entryId))
18533
+ throw new Error("Omp RPC Fork requires an Entry identity");
18534
+ try {
18535
+ const response = await this.#send("branch", { entryId });
18536
+ const data = isRecord8(response.data) ? response.data : null;
18537
+ if (!data || data.cancelled === true) {
18538
+ throw new OmpRpcFaultError("unavailable", "Omp RPC Fork was cancelled");
18539
+ }
18540
+ this.#state = parseSessionState(await this.#send("get_state", {}));
18541
+ return this.#state;
18542
+ } catch (error51) {
18543
+ if (error51 instanceof OmpRpcFaultError)
18544
+ this.#fail(error51);
18545
+ throw error51;
18546
+ }
18430
18547
  }
18431
- if (state.thinkingLevel !== currentThinking) {
18432
- if (!currentThinking)
18433
- throw new Error("Omp last-Turn rollback changed current Thinking");
18434
- state = await transport.selectThinkingOption(currentThinking);
18548
+ verifySessionCwd(expectedCwd) {
18549
+ return verifyOmpSessionCwd({
18550
+ sessionFile: this.state.sessionFile,
18551
+ sessionId: this.state.sessionId,
18552
+ expectedCwd
18553
+ });
18435
18554
  }
18436
- if (!sameOmpModel(modelFromState(state), currentModel) || state.thinkingLevel !== currentThinking) {
18437
- throw new Error("Omp last-Turn rollback could not restore current Model and Thinking");
18555
+ async getAvailableModels() {
18556
+ try {
18557
+ return parseAvailableModels(await this.#send("get_available_models", {}));
18558
+ } catch (error51) {
18559
+ if (error51 instanceof OmpRpcFaultError)
18560
+ this.#fail(error51);
18561
+ throw error51;
18562
+ }
18438
18563
  }
18439
- const snapshot = mapOmpSnapshot(await transport.getEntries(), {
18440
- sessionId: state.sessionId,
18441
- model: modelFromState(state)
18442
- });
18443
- const expectedTurnKeys = sourceSnapshot.turns.slice(0, -1).map((turn) => turn.nativeTurnRef.nativeTurnKey);
18444
- const actualTurnKeys = snapshot.turns.map((turn) => turn.nativeTurnRef.nativeTurnKey);
18445
- if (snapshot.turns.length !== boundary.sourceTurnCount - 1 || actualTurnKeys.some((key, index) => key !== expectedTurnKeys[index])) {
18446
- throw new Error("Omp last-Turn rollback did not produce the exact retained history prefix");
18564
+ async getAvailableThinkingLevels() {
18565
+ return this.state.availableThinkingLevels;
18447
18566
  }
18448
- await transport.verifySessionCwd(cwd);
18449
- return { ok: true };
18450
- }
18451
-
18452
- // dist/omp-rpc-session.js
18453
- import { spawn, spawnSync } from "node:child_process";
18454
- import { randomUUID } from "node:crypto";
18455
- import path6 from "node:path";
18456
-
18457
- // dist/command.js
18458
- var ompDiscoverySpec = {
18459
- id: "omp",
18460
- command: "omp",
18461
- commandEnvironmentVariable: "OMP_COMMAND",
18462
- installRoots: {
18463
- posix: [
18464
- "~/.npm-global/bin",
18465
- "~/.local/bin",
18466
- VERSION_MANAGER_ROOTS,
18467
- "/opt/homebrew/bin",
18468
- "/usr/local/bin"
18469
- ],
18470
- windows: ["${APPDATA}/npm", "~/.local/bin", VERSION_MANAGER_ROOTS]
18567
+ async selectModel(model2) {
18568
+ await this.#send("set_model", { provider: model2.provider, modelId: model2.id });
18569
+ return this.#refreshState("Model");
18471
18570
  }
18472
- };
18473
- function resolveOmpExecutable(input, dependencies = {}) {
18474
- const resolution = resolveHarnessExecutable(ompDiscoverySpec, {
18475
- ...input.command ? { command: input.command } : {},
18476
- environment: input.environment,
18477
- ...dependencies.platform ? { platform: dependencies.platform } : {},
18478
- ...dependencies.homeDirectory ? { homeDirectory: dependencies.homeDirectory } : {}
18479
- }, { ...dependencies.isExecutable ? { isExecutable: dependencies.isExecutable } : {} });
18480
- return resolution?.executable ?? input.command ?? input.environment.OMP_COMMAND ?? "omp";
18481
- }
18482
-
18483
- // dist/omp-protocol.js
18484
- var MAX_FRAME_BYTES = 1024 * 1024;
18485
- var MAX_REASSEMBLED_BYTES = 64 * 1024 * 1024;
18486
- var MAX_CHUNK_BYTES = 256 * 1024;
18487
- function isObject2(value) {
18488
- return typeof value === "object" && value !== null && !Array.isArray(value);
18489
- }
18490
- var OmpFrameDecoder = class {
18491
- #pending = null;
18492
- push(value) {
18493
- if (!isObject2(value))
18494
- throw new Error("OMP RPC frame must be a JSON object");
18495
- if (value.type !== "rpc_chunk") {
18496
- if (this.#pending)
18497
- throw new Error("OMP RPC chunk sequence was interrupted");
18498
- return value;
18499
- }
18500
- const chunkId = value.chunkId;
18501
- const index = value.index;
18502
- const count2 = value.count;
18503
- const byteLength = value.byteLength;
18504
- const data = value.data;
18505
- if (typeof chunkId !== "string" || chunkId.length === 0 || chunkId.length > 128 || !Number.isInteger(index) || !Number.isInteger(count2) || !Number.isInteger(byteLength) || index < 0 || count2 < 2 || index >= count2 || byteLength < MAX_FRAME_BYTES || byteLength > MAX_REASSEMBLED_BYTES || typeof data !== "string" || data.length === 0)
18506
- throw new Error("Invalid OMP RPC chunk metadata");
18507
- let bytes;
18571
+ async selectThinkingOption(thinkingOptionId) {
18572
+ const level = harnessThinkingOptionIdSchema.parse(thinkingOptionId);
18573
+ await this.#send("set_thinking_level", { level });
18574
+ return this.#refreshState("Thinking");
18575
+ }
18576
+ async #refreshState(operation) {
18508
18577
  try {
18509
- bytes = Buffer.from(data, "base64");
18510
- } catch {
18511
- throw new Error("Invalid OMP RPC chunk data");
18578
+ this.#state = parseSessionState(await this.#send("get_state", {}));
18579
+ return this.#state;
18580
+ } catch (error51) {
18581
+ const fault = error51 instanceof OmpRpcFaultError ? error51 : new OmpRpcFaultError("protocolError", `Omp RPC ${operation} state could not be confirmed: ${message2(error51)}`);
18582
+ this.#fail(fault);
18583
+ throw fault;
18512
18584
  }
18513
- if (bytes.length === 0 || bytes.length > MAX_CHUNK_BYTES || bytes.toString("base64") !== data) {
18514
- throw new Error("Invalid OMP RPC chunk data");
18585
+ }
18586
+ async runTurn(text, onEvent) {
18587
+ if (!this.#child || !this.#state || this.#closed || this.#failed) {
18588
+ throw new Error("Omp RPC Session is unavailable");
18515
18589
  }
18516
- const chunkIndex = index;
18517
- const chunkCount = count2;
18518
- const declaredByteLength = byteLength;
18519
- if (!this.#pending) {
18520
- if (chunkIndex !== 0)
18521
- throw new Error("OMP RPC chunk sequence must start at index 0");
18522
- this.#pending = {
18523
- chunkId,
18524
- count: chunkCount,
18525
- byteLength: declaredByteLength,
18526
- nextIndex: 0,
18527
- chunks: [],
18528
- received: 0
18590
+ if (this.#activeTurn)
18591
+ throw new Error("Omp RPC Session already has an active Turn");
18592
+ if (text.length === 0)
18593
+ throw new Error("Omp text Turn must not be empty");
18594
+ const promptId = `codexhost-${randomUUID()}`;
18595
+ const settled = new Promise((resolve, reject) => {
18596
+ this.#activeTurn = {
18597
+ promptId,
18598
+ localResult: null,
18599
+ text: "",
18600
+ assistantMessageId: null,
18601
+ sawStreamedMessageText: false,
18602
+ sawStreamedMessageReasoning: false,
18603
+ lastFinalizedMessageText: null,
18604
+ lastFinalizedMessageReasoning: null,
18605
+ reasoningMessageOpen: false,
18606
+ onEvent,
18607
+ resolve,
18608
+ reject,
18609
+ failure: null,
18610
+ sawTool: false,
18611
+ tools: /* @__PURE__ */ new Map(),
18612
+ interactions: /* @__PURE__ */ new Map(),
18613
+ settlement: "pending",
18614
+ terminalEnd: false,
18615
+ cancellation: "none",
18616
+ cancellationTimeout: null,
18617
+ cancellationRecheck: null,
18618
+ cancellationChecking: false,
18619
+ cancellationReloaded: false,
18620
+ abortPromise: null
18529
18621
  };
18622
+ });
18623
+ try {
18624
+ await this.#send("prompt", { message: text }, promptId);
18625
+ } catch (error51) {
18626
+ this.#rejectActiveTurn(error51 instanceof Error ? error51 : new Error(message2(error51)));
18530
18627
  }
18531
- const pending = this.#pending;
18532
- if (!pending)
18533
- throw new Error("OMP RPC chunk state was lost");
18534
- if (pending.chunkId !== chunkId || pending.count !== chunkCount || pending.byteLength !== declaredByteLength || pending.nextIndex !== chunkIndex) {
18535
- throw new Error("OMP RPC chunk sequence mismatch");
18628
+ return settled;
18629
+ }
18630
+ respondToInteraction(response) {
18631
+ return this.#resolveInteraction(response, "cancelled" in response ? "cancelled" : "responded");
18632
+ }
18633
+ async #resolveInteraction(response, reason) {
18634
+ const active = this.#activeTurn;
18635
+ const pending = active?.interactions.get(response.requestId);
18636
+ if (!active || !pending || this.#closed || this.#failed) {
18637
+ throw new Error("Omp RPC interaction is not pending");
18536
18638
  }
18537
- pending.chunks.push(bytes);
18538
- pending.received += bytes.length;
18539
- pending.nextIndex += 1;
18540
- if (pending.received > pending.byteLength)
18541
- throw new Error("OMP RPC chunk sequence exceeds its declared length");
18542
- if (pending.nextIndex < pending.count)
18543
- return null;
18544
- if (pending.received !== pending.byteLength)
18545
- throw new Error("OMP RPC chunk sequence length mismatch");
18546
- this.#pending = null;
18547
- let decoded;
18639
+ if ("value" in response && !["select", "input", "editor"].includes(pending.request.method)) {
18640
+ throw new Error("Omp RPC interaction response type does not match the request");
18641
+ }
18642
+ if ("confirmed" in response && pending.request.method !== "confirm") {
18643
+ throw new Error("Omp RPC confirmation does not match the request");
18644
+ }
18645
+ const frame = "cancelled" in response ? {
18646
+ type: "extension_ui_response",
18647
+ id: response.requestId,
18648
+ cancelled: true,
18649
+ ...reason === "expired" ? { timedOut: true } : {}
18650
+ } : "confirmed" in response ? { type: "extension_ui_response", id: response.requestId, confirmed: response.confirmed } : { type: "extension_ui_response", id: response.requestId, value: response.value };
18651
+ if (!active.interactions.delete(response.requestId)) {
18652
+ throw new Error("Omp RPC interaction is not pending");
18653
+ }
18654
+ if (pending.timeout)
18655
+ clearTimeout(pending.timeout);
18656
+ active.onEvent({ type: "interaction.closed", requestId: response.requestId, reason });
18548
18657
  try {
18549
- decoded = JSON.parse(Buffer.concat(pending.chunks).toString("utf8"));
18550
- } catch {
18551
- throw new Error("Failed to decode reassembled OMP RPC frame");
18658
+ await this.#write(frame);
18659
+ } catch (error51) {
18660
+ const fault = new OmpRpcFaultError("protocolError", `Omp RPC interaction response failed: ${message2(error51)}`);
18661
+ this.#fail(fault);
18662
+ throw fault;
18552
18663
  }
18553
- if (!isObject2(decoded))
18554
- throw new Error("Reassembled OMP RPC frame must be an object");
18555
- return decoded;
18556
18664
  }
18557
- };
18558
-
18559
- // dist/omp-rpc-session.js
18560
- var OmpRpcFaultError = class extends Error {
18561
- kind;
18562
- diagnostic;
18563
- constructor(kind, message3, diagnostic) {
18564
- super(message3);
18565
- this.kind = kind;
18566
- this.diagnostic = diagnostic;
18567
- this.name = "OmpRpcFaultError";
18568
- }
18569
- };
18570
- var OmpRpcUnsupportedCommandError = class extends Error {
18571
- command;
18572
- constructor(command) {
18573
- super(`Omp RPC does not support '${command}'`);
18574
- this.command = command;
18575
- this.name = "OmpRpcUnsupportedCommandError";
18576
- }
18577
- };
18578
- var textDecoder = new TextDecoder("utf-8", { fatal: true });
18579
- function isRecord8(value) {
18580
- return typeof value === "object" && value !== null && !Array.isArray(value);
18581
- }
18582
- function message2(value) {
18583
- return value instanceof Error ? value.message : String(value);
18584
- }
18585
- function nonBlankString(value) {
18586
- return typeof value === "string" && value.trim().length > 0;
18587
- }
18588
- function parseNativeModel(value, context) {
18589
- if (value === null || value === void 0)
18590
- return null;
18591
- if (!isRecord8(value) || !nonBlankString(value.provider) || !nonBlankString(value.id)) {
18592
- throw new OmpRpcFaultError("protocolError", `Omp RPC returned an invalid ${context} Model`);
18593
- }
18594
- return { provider: value.provider, id: value.id };
18595
- }
18596
- function sessionStateData(response) {
18597
- const data = isRecord8(response.data) ? response.data : null;
18598
- if (!data)
18599
- throw new OmpRpcFaultError("protocolError", "Omp RPC state response has no data");
18600
- return data;
18601
- }
18602
- function parseSessionState(response) {
18603
- const data = sessionStateData(response);
18604
- const model2 = parseNativeModel(data.model, "state");
18605
- if (!nonBlankString(data.sessionId)) {
18606
- throw new OmpRpcFaultError("protocolError", "Omp RPC state has no stable Session identity");
18607
- }
18608
- const thinkingLevel = data.thinkingLevel === void 0 ? null : harnessThinkingOptionIdSchema.safeParse(data.thinkingLevel);
18609
- if (thinkingLevel !== null && !thinkingLevel.success) {
18610
- throw new OmpRpcFaultError("protocolError", "Omp RPC state has an invalid Thinking level");
18611
- }
18612
- const thinking = isRecord8(data.model) && isRecord8(data.model.thinking) ? data.model.thinking : null;
18613
- const availableThinkingLevels = thinking && Array.isArray(thinking.efforts) ? thinking.efforts.flatMap((level) => {
18614
- const parsed = harnessThinkingOptionIdSchema.safeParse(level);
18615
- return parsed.success ? [parsed.data] : [];
18616
- }) : null;
18617
- return {
18618
- sessionId: data.sessionId,
18619
- sessionFile: typeof data.sessionFile === "string" ? data.sessionFile : null,
18620
- provider: model2?.provider ?? null,
18621
- modelId: model2?.id ?? null,
18622
- thinkingLevel: thinkingLevel?.data ?? null,
18623
- contextUsage: optionalOmpStateContextUsage(data.contextUsage),
18624
- availableThinkingLevels
18625
- };
18626
- }
18627
- function parseSessionStreaming(response) {
18628
- const isStreaming = sessionStateData(response).isStreaming;
18629
- if (typeof isStreaming !== "boolean") {
18630
- throw new OmpRpcFaultError("protocolError", "Omp RPC state has no Streaming status");
18665
+ abort() {
18666
+ const active = this.#activeTurn;
18667
+ if (!active || this.#closed || this.#failed) {
18668
+ return Promise.reject(new Error("Omp RPC Session has no cancellable Turn"));
18669
+ }
18670
+ if (active.abortPromise)
18671
+ return active.abortPromise;
18672
+ active.cancellation = "requesting";
18673
+ active.cancellationTimeout = setTimeout(() => {
18674
+ this.#terminateFailedCancellation(active, new OmpRpcFaultError("protocolError", "Omp Turn cancellation did not settle within its bound"));
18675
+ }, this.#options.cancelTimeoutMs);
18676
+ const aborting = this.#send("abort", {}).then(async () => {
18677
+ if (this.#activeTurn !== active)
18678
+ return;
18679
+ active.cancellation = "accepted";
18680
+ await this.#confirmCancelledTurn(active);
18681
+ }).catch((error51) => {
18682
+ if (this.#activeTurn !== active)
18683
+ throw error51;
18684
+ const fault = error51 instanceof OmpRpcFaultError ? error51 : new OmpRpcFaultError("protocolError", `Omp RPC Abort failed: ${message2(error51)}`);
18685
+ this.#terminateFailedCancellation(active, fault);
18686
+ throw fault;
18687
+ });
18688
+ active.abortPromise = aborting;
18689
+ return aborting;
18631
18690
  }
18632
- return isStreaming;
18633
- }
18634
- function cancellationSettled(response, terminalEnd) {
18635
- const data = sessionStateData(response);
18636
- return !parseSessionStreaming(response) && (data.isSettled === true || data.isSettled === void 0 && terminalEnd) && data.isCompacting !== true && data.hasPendingAsyncWork !== true && !(typeof data.queuedMessageCount === "number" && data.queuedMessageCount > 0);
18637
- }
18638
- function parseAvailableModels(response) {
18639
- const data = isRecord8(response.data) ? response.data : null;
18640
- if (!data || !Array.isArray(data.models)) {
18641
- throw new OmpRpcFaultError("protocolError", "Omp RPC Model catalog response has no models");
18691
+ #terminateFailedCancellation(active, fault) {
18692
+ if (this.#activeTurn !== active)
18693
+ return;
18694
+ if (active.cancellationTimeout)
18695
+ clearTimeout(active.cancellationTimeout);
18696
+ active.cancellationTimeout = null;
18697
+ this.#fail(fault);
18698
+ void this.close().catch(() => void 0);
18642
18699
  }
18643
- return data.models.map((model2) => {
18644
- const parsed = parseNativeModel(model2, "catalog");
18645
- if (!parsed || !isRecord8(model2) || typeof model2.reasoning !== "boolean") {
18646
- throw new OmpRpcFaultError("protocolError", "Omp RPC catalog contains a Model without reasoning capability");
18700
+ close() {
18701
+ if (!this.#closed) {
18702
+ this.#closed = true;
18703
+ this.#rejectAll(new Error("Omp RPC Session closed"));
18647
18704
  }
18648
- return { ...parsed, reasoning: model2.reasoning };
18649
- });
18650
- }
18651
- function parseSubagentMessages(response) {
18652
- const data = isRecord8(response.data) ? response.data : null;
18653
- if (!data || !nonBlankString(data.sessionFile) || !Number.isSafeInteger(data.fromByte) || !Number.isSafeInteger(data.nextByte) || data.fromByte < 0 || data.nextByte < data.fromByte || typeof data.reset !== "boolean" || !Array.isArray(data.entries) || !Array.isArray(data.messages)) {
18654
- throw new OmpRpcFaultError("protocolError", "Omp RPC Subagent transcript response is invalid");
18655
- }
18656
- const entries = data.entries.flatMap((value) => isRecord8(value) ? [value] : []);
18657
- const messages = data.messages.flatMap((value) => isRecord8(value) ? [value] : []);
18658
- if (entries.length !== data.entries.length || messages.length !== data.messages.length) {
18659
- throw new OmpRpcFaultError("protocolError", "Omp RPC Subagent transcript contains invalid data");
18705
+ this.#closePromise ??= this.#stopProcess();
18706
+ return this.#closePromise;
18660
18707
  }
18661
- return {
18662
- sessionFile: data.sessionFile,
18663
- fromByte: data.fromByte,
18664
- nextByte: data.nextByte,
18665
- reset: data.reset,
18666
- entries,
18667
- messages
18668
- };
18669
- }
18670
- function subagentStatus(value) {
18671
- if (value === "pending" || value === "running" || value === "completed")
18672
- return value;
18673
- if (value === "failed" || value === "aborted" || value === "interrupted")
18674
- return "failed";
18675
- throw new OmpRpcFaultError("protocolError", "Omp RPC Subagent status is invalid");
18676
- }
18677
- function assistantText(value) {
18678
- if (!isRecord8(value) || value.role !== "assistant" || !Array.isArray(value.content))
18679
- return null;
18680
- return value.content.filter((content) => isRecord8(content) && content.type === "text" && typeof content.text === "string").map((content) => content.text).join("");
18681
- }
18682
- function assistantMessageId(value) {
18683
- if (!isRecord8(value) || value.role !== "assistant")
18684
- return null;
18685
- return nonBlankString(value.responseId) ? value.responseId : null;
18686
- }
18687
- function extractReasoningText(content) {
18688
- if (!isRecord8(content))
18689
- return null;
18690
- const type = String(content.type ?? "");
18691
- if (type === "thinking" || type === "reasoning" || type === "thought") {
18692
- const text = content.thinking ?? content.reasoning ?? content.text ?? content.delta;
18693
- return typeof text === "string" ? text : null;
18708
+ async #stopProcess() {
18709
+ const child = this.#child;
18710
+ if (!child)
18711
+ return;
18712
+ if (child.stdin.writable)
18713
+ child.stdin.end();
18714
+ if (await waitForExit(child, this.#options.closeTimeoutMs))
18715
+ return;
18716
+ signalProcessTree(child, "SIGTERM");
18717
+ if (await waitForExit(child, this.#options.closeTimeoutMs))
18718
+ return;
18719
+ signalProcessTree(child, "SIGKILL");
18720
+ if (!await waitForExit(child, this.#options.closeTimeoutMs)) {
18721
+ throw new Error("Omp RPC process tree did not exit within cleanup bounds");
18722
+ }
18694
18723
  }
18695
- return null;
18696
- }
18697
- function assistantReasoning(value) {
18698
- if (!isRecord8(value) || value.role !== "assistant" || !Array.isArray(value.content))
18699
- return null;
18700
- return value.content.map(extractReasoningText).filter((text) => typeof text === "string").join("");
18701
- }
18702
- function assistantFailure(value) {
18703
- if (!isRecord8(value) || value.role !== "assistant")
18704
- return void 0;
18705
- if (value.stopReason !== "error" && value.stopReason !== "aborted")
18706
- return null;
18707
- const fallback = value.stopReason === "aborted" ? "Omp assistant message was aborted" : "Omp assistant message failed";
18708
- return new Error(nonBlankString(value.errorMessage) ? value.errorMessage : fallback);
18709
- }
18710
- function signalProcessTree(child, signal) {
18711
- if (!child.pid)
18712
- return;
18713
- if (process.platform === "win32") {
18714
- spawnSync("taskkill.exe", ["/pid", String(child.pid), "/t", "/f"], {
18715
- stdio: "ignore",
18716
- windowsHide: true
18717
- });
18718
- return;
18724
+ #push(chunk) {
18725
+ this.#buffer = this.#buffer.length === 0 ? chunk : Buffer.concat([this.#buffer, chunk]);
18726
+ let newline = this.#buffer.indexOf(10);
18727
+ while (newline >= 0) {
18728
+ const frame = this.#buffer.subarray(0, newline);
18729
+ this.#buffer = this.#buffer.subarray(newline + 1);
18730
+ let parsed;
18731
+ try {
18732
+ parsed = JSON.parse(textDecoder.decode(frame));
18733
+ } catch (error51) {
18734
+ this.#fail(new OmpRpcFaultError("protocolError", `Omp RPC returned invalid JSONL: ${message2(error51)}`));
18735
+ newline = this.#buffer.indexOf(10);
18736
+ continue;
18737
+ }
18738
+ try {
18739
+ const decoded = this.#frameDecoder.push(parsed);
18740
+ if (decoded === null) {
18741
+ newline = this.#buffer.indexOf(10);
18742
+ continue;
18743
+ }
18744
+ const value = decoded;
18745
+ if (!isRecord8(value) || typeof value.type !== "string") {
18746
+ throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid envelope");
18747
+ }
18748
+ this.#handle(value);
18749
+ } catch (error51) {
18750
+ this.#fail(error51 instanceof OmpRpcFaultError ? error51 : new OmpRpcFaultError("protocolError", `Omp RPC frame handling failed: ${message2(error51)}`));
18751
+ }
18752
+ newline = this.#buffer.indexOf(10);
18753
+ }
18719
18754
  }
18720
- try {
18721
- process.kill(-child.pid, signal);
18722
- } catch (error51) {
18723
- if (!isRecord8(error51) || error51.code !== "ESRCH")
18724
- throw error51;
18755
+ /** Latest `available_commands_update` of the running process, if any. */
18756
+ get availableCommands() {
18757
+ return this.#availableCommands;
18725
18758
  }
18726
- }
18727
- function waitForExit(child, timeoutMs) {
18728
- if (child.exitCode !== null || child.signalCode !== null)
18729
- return Promise.resolve(true);
18730
- return Promise.race([
18731
- new Promise((resolve) => child.once("exit", () => resolve(true))),
18732
- new Promise((resolve) => setTimeout(() => resolve(false), timeoutMs))
18733
- ]);
18734
- }
18735
- function ompRpcProcessCommand(options, dependencies = {}) {
18736
- if (options.sessionFile && options.forkSessionFile) {
18737
- throw new Error("Omp RPC cannot combine Session resume and Fork startup");
18738
- }
18739
- if (options.model && (options.sessionFile || options.forkSessionFile)) {
18740
- throw new Error("Omp RPC cannot combine a startup Model with Session restore or Fork");
18741
- }
18742
- const platform = dependencies.platform ?? process.platform;
18743
- const command = resolveOmpExecutable({
18744
- ...options.command ? { command: options.command } : {},
18745
- environment: options.environment
18746
- }, {
18747
- platform,
18748
- ...dependencies.homeDirectory ? { homeDirectory: dependencies.homeDirectory } : {},
18749
- ...dependencies.isExecutable ? { isExecutable: dependencies.isExecutable } : {}
18750
- });
18751
- const sessionArguments = options.forkSessionFile ? ["--fork", options.forkSessionFile] : options.sessionFile ? ["--resume", options.sessionFile] : [];
18752
- const modelArguments = options.model ? ["--provider", options.model.provider, "--model", options.model.id] : [];
18753
- const permissionArguments = options.permissionMode ? ["--approval-mode", options.permissionMode] : [];
18754
- const arguments_ = [
18755
- "--mode",
18756
- // OMP only creates ask and connects its tool UI in rpc-ui mode.
18757
- "rpc-ui",
18758
- ...permissionArguments,
18759
- ...modelArguments,
18760
- ...sessionArguments
18761
- ];
18762
- const extension = path6.win32.extname(command).toLowerCase();
18763
- if (platform !== "win32" || ![".cmd", ".bat"].includes(extension)) {
18764
- return { command, arguments: arguments_, windowsVerbatimArguments: false };
18765
- }
18766
- const quote = (value) => `"${value.replaceAll("%", "%%").replaceAll('"', '""')}"`;
18767
- const commandLine = [command, ...arguments_].map(quote).join(" ");
18768
- return {
18769
- command: options.environment?.ComSpec ?? options.environment?.COMSPEC ?? "cmd.exe",
18770
- arguments: ["/d", "/v:off", "/s", "/c", `"${commandLine}"`],
18771
- windowsVerbatimArguments: true
18772
- };
18773
- }
18774
- var nodeProcessAdapter = {
18775
- spawn(options) {
18776
- const invocation = ompRpcProcessCommand(options);
18777
- return spawn(invocation.command, invocation.arguments, {
18778
- cwd: options.cwd,
18779
- env: options.environment,
18780
- detached: process.platform !== "win32",
18781
- stdio: ["pipe", "pipe", "pipe"],
18782
- windowsHide: true,
18783
- windowsVerbatimArguments: invocation.windowsVerbatimArguments
18784
- });
18785
- }
18786
- };
18787
- var OmpRpcSession = class {
18788
- #options;
18789
- #processAdapter;
18790
- #activeTurn = null;
18791
- #buffer = Buffer.alloc(0);
18792
- #child = null;
18793
- #closed = false;
18794
- #closePromise = null;
18795
- #compactionActive = false;
18796
- #compactionTurn = null;
18797
- #compactionTimeout = null;
18798
- #failed = false;
18799
- #pending = /* @__PURE__ */ new Map();
18800
- #state = null;
18801
- #availableCommands = null;
18802
- #latestCacheHitRatePercent;
18803
- #manualCompaction = null;
18804
- #usageRequestStartedAtMs = null;
18805
- #stderrTail = "";
18806
- #frameDecoder = new OmpFrameDecoder();
18807
- #startupFaultResolve = null;
18808
- #startupFault = new Promise((resolve) => {
18809
- this.#startupFaultResolve = resolve;
18810
- });
18811
- #readyResolve = null;
18812
- #ready = new Promise((resolve) => {
18813
- this.#readyResolve = resolve;
18814
- });
18815
- constructor(options, processAdapter = nodeProcessAdapter) {
18816
- if (options.sessionFile && options.forkSessionFile) {
18817
- throw new Error("Omp RPC cannot combine Session resume and Fork startup");
18759
+ #handle(value) {
18760
+ if (this.#closed || this.#failed)
18761
+ return;
18762
+ if (value.type === "available_commands_update") {
18763
+ this.#availableCommands = parseOmpAvailableCommands(value.commands);
18764
+ return;
18818
18765
  }
18819
- if (options.model && (options.sessionFile || options.forkSessionFile)) {
18820
- throw new Error("Omp RPC cannot combine a startup Model with Session restore or Fork");
18766
+ if (value.type === "ready") {
18767
+ this.#readyResolve?.();
18768
+ this.#readyResolve = null;
18769
+ return;
18821
18770
  }
18822
- this.#options = {
18823
- commandTimeoutMs: 3e4,
18824
- compactionTimeoutMs: 3e5,
18825
- // Native Abort waits for tools, persistence and deferred work to unwind.
18826
- // Stable cancellation must outlast the Host's 20s steering wait.
18827
- cancelTimeoutMs: 3e4,
18828
- closeTimeoutMs: 2e3,
18829
- ...options
18830
- };
18831
- this.#processAdapter = processAdapter;
18832
- }
18833
- get state() {
18834
- if (!this.#state)
18835
- throw new Error("Omp RPC Session has not started");
18836
- return this.#state;
18837
- }
18838
- get stderrTail() {
18839
- return this.#stderrTail;
18840
- }
18841
- async start() {
18842
- if (this.#child || this.#closed)
18843
- throw new Error("Omp RPC Session cannot be started twice");
18844
- const child = this.#processAdapter.spawn({
18845
- cwd: this.#options.cwd,
18846
- ...this.#options.command ? { command: this.#options.command } : {},
18847
- environment: withNodeRuntimeOnPath({
18848
- ...process.env,
18849
- ...this.#options.environment,
18850
- OMP_SKIP_VERSION_CHECK: "1",
18851
- OMP_TELEMETRY: "0"
18852
- }),
18853
- ...this.#options.sessionFile ? { sessionFile: this.#options.sessionFile } : {},
18854
- ...this.#options.forkSessionFile ? { forkSessionFile: this.#options.forkSessionFile } : {},
18855
- ...this.#options.model ? { model: this.#options.model } : {},
18856
- ...this.#options.permissionMode ? { permissionMode: this.#options.permissionMode } : {}
18857
- });
18858
- this.#child = child;
18859
- child.stdout.on("data", (chunk) => this.#push(chunk));
18860
- child.stdout.on("end", () => {
18861
- if (this.#buffer.length !== 0) {
18862
- this.#fail(new OmpRpcFaultError("protocolError", "Omp RPC stdout ended mid-frame"));
18771
+ if (value.type === "response") {
18772
+ this.#handleResponse(value);
18773
+ return;
18774
+ }
18775
+ if (value.type === "auto_compaction_start" || value.type === "compaction_start") {
18776
+ this.#compactionActive = true;
18777
+ this.#compactionTurn = this.#activeTurn;
18778
+ this.#compactionTimeout ??= setTimeout(() => {
18779
+ this.#compactionTimeout = null;
18780
+ this.#fail(new OmpRpcFaultError("protocolError", `Omp RPC compaction timed out after ${this.#options.compactionTimeoutMs}ms`));
18781
+ }, this.#options.compactionTimeoutMs);
18782
+ const onEvent = this.#activeTurn?.onEvent ?? this.#manualCompaction?.onEvent;
18783
+ onEvent?.({ type: "compaction.started" });
18784
+ for (const pending of this.#pending.values()) {
18785
+ if (pending.command !== "prompt" && pending.command !== "compact" || !pending.timeout)
18786
+ continue;
18787
+ clearTimeout(pending.timeout);
18788
+ pending.timeout = null;
18863
18789
  }
18864
- });
18865
- child.stderr.on("data", (chunk) => {
18866
- this.#stderrTail = sanitizeDiagnosticTail(`${this.#stderrTail}${chunk.toString()}`);
18867
- });
18868
- child.once("error", (error51) => {
18869
- const kind = isRecord8(error51) && error51.code === "ENOENT" ? "notInstalled" : "unavailable";
18870
- this.#fail(new OmpRpcFaultError(kind, `Omp RPC failed to start: ${error51.message}`, this.stderrTail));
18871
- });
18872
- child.once("exit", (code, signal) => {
18873
- if (!this.#closed) {
18874
- this.#fail(new OmpRpcFaultError("processExited", `Omp RPC exited (code=${code}, signal=${signal})`, this.stderrTail));
18790
+ return;
18791
+ }
18792
+ if (value.type === "auto_compaction_end" || value.type === "compaction_end") {
18793
+ this.#compactionActive = false;
18794
+ if (this.#compactionTimeout)
18795
+ clearTimeout(this.#compactionTimeout);
18796
+ this.#compactionTimeout = null;
18797
+ const compactionTurn = this.#compactionTurn;
18798
+ this.#compactionTurn = null;
18799
+ for (const [id, pending] of this.#pending) {
18800
+ if (pending.command === "prompt" || pending.command === "compact") {
18801
+ this.#armCommandTimeout(id, pending);
18802
+ }
18875
18803
  }
18876
- });
18877
- await Promise.race([
18878
- new Promise((resolve, reject) => {
18879
- child.once("spawn", resolve);
18880
- child.once("error", reject);
18881
- }),
18882
- new Promise((_resolve, reject) => setTimeout(() => reject(new Error("Omp RPC start timed out")), this.#options.commandTimeoutMs))
18883
- ]);
18884
- let readyTimeout;
18885
- try {
18886
- await Promise.race([
18887
- this.#ready,
18888
- this.#startupFault.then((error51) => {
18889
- throw error51;
18890
- }),
18891
- new Promise((_resolve, reject) => {
18892
- readyTimeout = setTimeout(() => reject(new Error("Omp RPC ready signal timed out")), this.#options.commandTimeoutMs);
18893
- })
18894
- ]);
18895
- } finally {
18896
- clearTimeout(readyTimeout);
18804
+ const outcome = value.aborted === true ? "cancelled" : isRecord8(value.result) ? "succeeded" : "failed";
18805
+ const event = {
18806
+ type: "compaction.completed",
18807
+ outcome,
18808
+ ...nonBlankString(value.errorMessage) ? { errorMessage: value.errorMessage } : {}
18809
+ };
18810
+ compactionTurn?.onEvent(event);
18811
+ const manual = this.#manualCompaction;
18812
+ this.#manualCompaction = null;
18813
+ manual?.onEvent(event);
18814
+ manual?.resolve({
18815
+ outcome,
18816
+ ...event.errorMessage ? { errorMessage: event.errorMessage } : {}
18817
+ });
18818
+ return;
18897
18819
  }
18898
- await this.#send("negotiate_protocol", { protocolVersion: 2 }).catch(() => void 0);
18899
- if (this.#options.subscribeSubagentEvents !== false) {
18900
- await this.#send("set_subagent_subscription", { level: "events" }).catch(() => void 0);
18820
+ const active = this.#activeTurn;
18821
+ if (this.#handleSubagentFrame(active, value))
18822
+ return;
18823
+ this.#observeUsage(value);
18824
+ if (value.type === "agent_start" && active)
18825
+ active.terminalEnd = false;
18826
+ if ((value.type === "session_settled" || value.type === "agent_start") && active?.cancellation === "accepted") {
18827
+ void this.#confirmCancelledTurn(active);
18828
+ return;
18829
+ }
18830
+ if (!active) {
18831
+ if (value.type === "extension_ui_request" && this.#isBlockingInteraction(value)) {
18832
+ this.#fail(new OmpRpcFaultError("protocolError", "Omp RPC requested blocking Extension UI outside an active Turn"));
18833
+ }
18834
+ return;
18835
+ }
18836
+ if (value.type === "command_output") {
18837
+ if (active.settlement !== "pending")
18838
+ return;
18839
+ if (typeof value.text !== "string") {
18840
+ throw new OmpRpcFaultError("protocolError", "Omp RPC returned invalid command output");
18841
+ }
18842
+ active.text += value.text;
18843
+ active.onEvent({ type: "text.delta", messageId: active.promptId, delta: value.text });
18844
+ return;
18845
+ }
18846
+ if (value.type === "prompt_result") {
18847
+ if (value.id !== active.promptId || value.agentInvoked !== false)
18848
+ return;
18849
+ if (value.status === "completed" || value.status === "aborted") {
18850
+ this.#settleLocalTurn(active, { cancelled: value.status === "aborted" });
18851
+ } else if (value.status === "error" && isRecord8(value.error) && typeof value.error.message === "string") {
18852
+ this.#settleLocalTurn(active, { cancelled: false, error: value.error.message });
18853
+ } else {
18854
+ throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid local prompt result");
18855
+ }
18856
+ return;
18857
+ }
18858
+ if (value.type === "extension_ui_request") {
18859
+ this.#startInteraction(active, value);
18860
+ return;
18861
+ }
18862
+ if (value.type === "message_start" && assistantText(value.message) !== null) {
18863
+ this.#startAssistantMessage(active, value.message);
18864
+ return;
18865
+ }
18866
+ if (value.type === "message_update" && isRecord8(value.assistantMessageEvent)) {
18867
+ const event = value.assistantMessageEvent;
18868
+ const eventType = String(event.type ?? "");
18869
+ const isThinking = eventType === "thinking_delta" || eventType === "reasoning_delta" || eventType === "thought_delta" || eventType === "thinking" || eventType === "reasoning";
18870
+ const isText = eventType === "text_delta" || eventType === "text" || eventType === "content_block_delta";
18871
+ const delta = typeof event.delta === "string" ? event.delta : typeof event.thinking === "string" ? event.thinking : typeof event.reasoning === "string" ? event.reasoning : typeof event.text === "string" ? event.text : isRecord8(event.delta) && typeof event.delta.thinking === "string" ? event.delta.thinking : isRecord8(event.delta) && typeof event.delta.text === "string" ? event.delta.text : null;
18872
+ if (isThinking && delta !== null && delta.length > 0) {
18873
+ const messageId = this.#ensureAssistantMessage(active, value.message);
18874
+ active.reasoningMessageOpen = true;
18875
+ active.sawStreamedMessageReasoning = true;
18876
+ active.onEvent({ type: "reasoning.delta", messageId, delta });
18877
+ } else if (isText && delta !== null && delta.length > 0) {
18878
+ const messageId = this.#ensureAssistantMessage(active, value.message);
18879
+ active.text += delta;
18880
+ active.sawStreamedMessageText = true;
18881
+ active.onEvent({ type: "text.delta", messageId, delta });
18882
+ } else if (event.type === "error") {
18883
+ this.#ensureAssistantMessage(active, value.message);
18884
+ active.failure = assistantFailure(event.error) ?? assistantFailure(value.message) ?? new Error("Omp assistant message failed");
18885
+ }
18886
+ return;
18887
+ }
18888
+ if (value.type === "message_end") {
18889
+ this.#finalizeAssistantMessage(active, value.message);
18890
+ return;
18891
+ }
18892
+ if (value.type === "turn_end") {
18893
+ this.#finalizeAssistantMessage(active, value.message);
18894
+ return;
18895
+ }
18896
+ if (value.type === "tool_execution_start") {
18897
+ this.#startTool(active, value);
18898
+ return;
18899
+ }
18900
+ if (value.type === "tool_execution_update") {
18901
+ this.#updateTool(active, value);
18902
+ return;
18903
+ }
18904
+ if (value.type === "tool_execution_end") {
18905
+ this.#completeTool(active, value);
18906
+ return;
18907
+ }
18908
+ if (value.type === "agent_end" && Array.isArray(value.messages)) {
18909
+ for (let index = value.messages.length - 1; index >= 0; index -= 1) {
18910
+ const message3 = value.messages[index];
18911
+ if (!isRecord8(message3) || message3.role !== "assistant")
18912
+ continue;
18913
+ this.#finalizeAssistantMessage(active, message3);
18914
+ break;
18915
+ }
18916
+ }
18917
+ if (value.type === "agent_end" && value.isTerminal !== false) {
18918
+ active.terminalEnd = true;
18919
+ if (active.cancellation !== "none") {
18920
+ if (active.cancellation === "accepted")
18921
+ void this.#confirmCancelledTurn(active);
18922
+ return;
18923
+ }
18924
+ if (active.settlement !== "pending")
18925
+ return;
18926
+ active.settlement = "confirming";
18927
+ void this.#confirmSettledTurn(active);
18928
+ }
18929
+ }
18930
+ /** Every finished assistant message is one model request, with or without an active Turn. */
18931
+ #observeUsage(value) {
18932
+ if (value.type === "message_start") {
18933
+ this.#usageRequestStartedAtMs = null;
18934
+ return;
18935
+ }
18936
+ if (value.type === "message_update") {
18937
+ const event = value.assistantMessageEvent;
18938
+ if (this.#usageRequestStartedAtMs === null && isRecord8(event) && typeof event.type === "string" && /^(text|thinking|reasoning|thought|toolcall)_(start|delta)$/u.test(event.type)) {
18939
+ this.#usageRequestStartedAtMs = Date.now();
18940
+ }
18941
+ return;
18901
18942
  }
18902
- try {
18903
- this.#state = parseSessionState(await this.#send("get_state", {}));
18904
- } catch (error51) {
18905
- const fault = error51 instanceof OmpRpcFaultError ? error51 : new OmpRpcFaultError("unavailable", `Omp RPC state unavailable: ${message2(error51)}`);
18906
- this.#fail(fault);
18907
- throw fault;
18943
+ if (value.type === "message_end" && isRecord8(value.message)) {
18944
+ if (value.message.role !== "assistant")
18945
+ return;
18946
+ const startedAtMs = this.#usageRequestStartedAtMs;
18947
+ this.#usageRequestStartedAtMs = null;
18948
+ this.#options.onUsage?.({
18949
+ message: value.message,
18950
+ startedAtMs,
18951
+ completedAtMs: Date.now()
18952
+ });
18908
18953
  }
18909
- return this;
18910
18954
  }
18911
- async getEntries() {
18912
- try {
18913
- if (this.state.sessionFile) {
18914
- try {
18915
- return await readOmpSessionHistory(this.state.sessionFile);
18916
- } catch (error51) {
18917
- if (!isRecord8(error51) || error51.code !== "ENOENT" || this.#options.sessionFile || this.#options.forkSessionFile)
18918
- throw error51;
18919
- const response2 = await this.#send("get_messages", {});
18920
- const data2 = isRecord8(response2.data) ? response2.data : null;
18921
- if (data2 && Array.isArray(data2.messages) && data2.messages.length === 0) {
18922
- return { entries: [], leafId: null };
18923
- }
18924
- throw error51;
18925
- }
18926
- }
18927
- const response = await this.#send("get_messages", {});
18928
- const data = isRecord8(response.data) ? response.data : null;
18929
- if (!data || !Array.isArray(data.messages)) {
18930
- throw new OmpRpcFaultError("protocolError", "Omp RPC messages response has no messages");
18955
+ #handleSubagentFrame(active, value) {
18956
+ if (value.type !== "subagent_lifecycle" && value.type !== "subagent_progress" && value.type !== "subagent_event") {
18957
+ return false;
18958
+ }
18959
+ const payload = isRecord8(value.payload) ? value.payload : null;
18960
+ const progressPayload = value.type === "subagent_progress" && payload && isRecord8(payload.progress) ? payload.progress : null;
18961
+ const nativeIdValue = progressPayload?.id ?? payload?.id;
18962
+ if (!payload || !nonBlankString(nativeIdValue)) {
18963
+ throw new OmpRpcFaultError("protocolError", "Omp RPC Subagent frame has no stable ID");
18964
+ }
18965
+ const nativeSubagentId = nativeIdValue;
18966
+ const callId = nativeSubagentId;
18967
+ const emit = active?.onEvent ?? this.#options.onSubagentEvent;
18968
+ if (value.type === "subagent_event") {
18969
+ emit?.({ type: "subagent.transcript.changed", callId, nativeSubagentId });
18970
+ return true;
18971
+ }
18972
+ if (value.type === "subagent_lifecycle") {
18973
+ const status2 = payload.status;
18974
+ if (status2 === "started") {
18975
+ const description = nonBlankString(payload.description) ? payload.description : nonBlankString(payload.agent) ? `${payload.agent} delegation` : "Subagent delegation";
18976
+ emit?.({
18977
+ type: "subagent.started",
18978
+ callId,
18979
+ nativeSubagentId,
18980
+ description,
18981
+ ...nonBlankString(payload.agent) ? { role: payload.agent } : {},
18982
+ ...nonBlankString(payload.task) ? { prompt: payload.task } : {},
18983
+ background: payload.detached === true,
18984
+ ...typeof payload.sessionFile === "string" ? { sessionFile: payload.sessionFile } : {}
18985
+ });
18986
+ return true;
18931
18987
  }
18932
- let branchEntryIds = null;
18933
- try {
18934
- const branchResponse = await this.#send("get_branch_messages", {});
18935
- const branchData = isRecord8(branchResponse.data) ? branchResponse.data : null;
18936
- if (branchData && Array.isArray(branchData.messages)) {
18937
- const parsed = branchData.messages.flatMap((entry) => {
18938
- if (!isRecord8(entry) || !nonBlankString(entry.entryId))
18939
- return [];
18940
- return [entry.entryId];
18941
- });
18942
- if (parsed.length === branchData.messages.length)
18943
- branchEntryIds = parsed;
18944
- }
18945
- } catch (error51) {
18946
- if (!(error51 instanceof OmpRpcUnsupportedCommandError))
18947
- throw error51;
18988
+ if (status2 !== "completed" && status2 !== "failed" && status2 !== "aborted") {
18989
+ throw new OmpRpcFaultError("protocolError", "Omp RPC Subagent lifecycle status is invalid");
18948
18990
  }
18949
- let userIndex = 0;
18950
- let parentId = null;
18951
- const entries = data.messages.map((nativeMessage, index) => {
18952
- const role = isRecord8(nativeMessage) ? nativeMessage.role : void 0;
18953
- const branchId = role === "user" ? branchEntryIds?.[userIndex] : void 0;
18954
- if (branchId)
18955
- userIndex += 1;
18956
- const id = branchId ?? (isRecord8(nativeMessage) && nonBlankString(nativeMessage.id) ? nativeMessage.id : `omp-message-${index}`);
18957
- const entry = { id, parentId, type: "message", message: nativeMessage };
18958
- parentId = id;
18959
- return entry;
18991
+ emit?.({
18992
+ type: "subagent.completed",
18993
+ callId,
18994
+ nativeSubagentId,
18995
+ isError: status2 !== "completed",
18996
+ ...nonBlankString(payload.resultSummary) ? { resultSummary: payload.resultSummary } : {},
18997
+ ...typeof payload.sessionFile === "string" ? { sessionFile: payload.sessionFile } : {}
18960
18998
  });
18961
- return { entries, leafId: parentId };
18962
- } catch (error51) {
18963
- if (error51 instanceof OmpRpcFaultError)
18964
- this.#fail(error51);
18965
- throw error51;
18966
- }
18967
- }
18968
- async getSubagentMessages(input) {
18969
- if ((input.subagentId === void 0 || !nonBlankString(input.subagentId)) && (input.sessionFile === void 0 || !nonBlankString(input.sessionFile))) {
18970
- throw new Error("Omp Subagent transcript requires a Subagent ID or Session file");
18999
+ return true;
18971
19000
  }
18972
- if (input.fromByte !== void 0 && (!Number.isSafeInteger(input.fromByte) || input.fromByte < 0)) {
18973
- throw new Error("Omp Subagent transcript offset is invalid");
19001
+ const progress = progressPayload;
19002
+ if (!progress || !nonBlankString(progress.id) || progress.id !== nativeSubagentId) {
19003
+ throw new OmpRpcFaultError("protocolError", "Omp RPC Subagent progress is invalid");
18974
19004
  }
18975
- const response = await this.#send("get_subagent_messages", {
18976
- ...input.subagentId ? { subagentId: input.subagentId } : {},
18977
- ...input.sessionFile ? { sessionFile: input.sessionFile } : {},
18978
- ...input.fromByte !== void 0 ? { fromByte: input.fromByte } : {}
19005
+ const status = subagentStatus(progress.status);
19006
+ const recentOutput = Array.isArray(progress.recentOutput) ? progress.recentOutput.filter((item) => typeof item === "string") : [];
19007
+ const resultSummary = recentOutput.at(-1);
19008
+ emit?.({
19009
+ type: "subagent.updated",
19010
+ callId,
19011
+ nativeSubagentId,
19012
+ status,
19013
+ ...nonBlankString(progress.description) ? { description: progress.description } : nonBlankString(payload.task) ? { description: payload.task } : {},
19014
+ ...resultSummary !== void 0 ? { resultSummary } : {},
19015
+ ...typeof payload.sessionFile === "string" ? { sessionFile: payload.sessionFile } : {}
18979
19016
  });
18980
- return parseSubagentMessages(response);
19017
+ return true;
18981
19018
  }
18982
- async compact(customInstructions, onEvent) {
18983
- if (!this.#child || !this.#state || this.#closed || this.#failed) {
18984
- throw new Error("Omp RPC Session is unavailable");
19019
+ #isBlockingInteraction(value) {
19020
+ return ["select", "confirm", "input", "editor"].includes(String(value.method));
19021
+ }
19022
+ #startInteraction(active, value) {
19023
+ if (!this.#isBlockingInteraction(value))
19024
+ return;
19025
+ const requestId2 = value.id;
19026
+ const method = value.method;
19027
+ const title = value.title;
19028
+ const timeoutMs = value.timeout;
19029
+ if (typeof requestId2 !== "string" || requestId2.length === 0 || typeof method !== "string" || typeof title !== "string" || title.length === 0 || timeoutMs !== void 0 && (typeof timeoutMs !== "number" || !Number.isFinite(timeoutMs) || timeoutMs < 0) || active.interactions.has(requestId2)) {
19030
+ throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid Interaction request");
18985
19031
  }
18986
- if (this.#activeTurn || this.#manualCompaction || this.#compactionActive) {
18987
- throw new Error("Omp RPC Session already has an active operation");
19032
+ let request;
19033
+ if (method === "select") {
19034
+ if (!Array.isArray(value.options) || value.options.length === 0 || !value.options.every((option) => typeof option === "string" && option.length > 0)) {
19035
+ throw new OmpRpcFaultError("protocolError", "Omp RPC select request has invalid options");
19036
+ }
19037
+ let optionDetails;
19038
+ if (value.optionDetails !== void 0) {
19039
+ if (!Array.isArray(value.optionDetails) || value.optionDetails.length !== value.options.length || !value.optionDetails.every((detail) => typeof detail === "object" && detail !== null && !Array.isArray(detail) && (detail.description === void 0 || typeof detail.description === "string"))) {
19040
+ throw new OmpRpcFaultError("protocolError", "Omp RPC select option details are invalid");
19041
+ }
19042
+ optionDetails = value.optionDetails.map(({ description }) => description === void 0 ? {} : { description });
19043
+ }
19044
+ request = {
19045
+ requestId: requestId2,
19046
+ method,
19047
+ title,
19048
+ options: [...value.options],
19049
+ ...optionDetails ? { optionDetails } : {},
19050
+ ...typeof timeoutMs === "number" ? { timeoutMs } : {}
19051
+ };
19052
+ } else if (method === "confirm") {
19053
+ if (typeof value.message !== "string") {
19054
+ throw new OmpRpcFaultError("protocolError", "Omp RPC confirm request has no message");
19055
+ }
19056
+ request = {
19057
+ requestId: requestId2,
19058
+ method,
19059
+ title,
19060
+ message: value.message,
19061
+ ...typeof timeoutMs === "number" ? { timeoutMs } : {}
19062
+ };
19063
+ } else if (method === "input") {
19064
+ if (value.placeholder !== void 0 && typeof value.placeholder !== "string") {
19065
+ throw new OmpRpcFaultError("protocolError", "Omp RPC input placeholder is invalid");
19066
+ }
19067
+ request = {
19068
+ requestId: requestId2,
19069
+ method,
19070
+ title,
19071
+ ...typeof value.placeholder === "string" ? { placeholder: value.placeholder } : {},
19072
+ ...typeof timeoutMs === "number" ? { timeoutMs } : {}
19073
+ };
19074
+ } else {
19075
+ if (value.prefill !== void 0 && typeof value.prefill !== "string") {
19076
+ throw new OmpRpcFaultError("protocolError", "Omp RPC editor prefill is invalid");
19077
+ }
19078
+ request = {
19079
+ requestId: requestId2,
19080
+ method: "editor",
19081
+ title,
19082
+ ...typeof value.prefill === "string" ? { prefill: value.prefill } : {},
19083
+ ...typeof timeoutMs === "number" ? { timeoutMs } : {}
19084
+ };
18988
19085
  }
18989
- const result = new Promise((resolve, reject) => {
18990
- this.#manualCompaction = { onEvent, resolve, reject };
18991
- });
18992
- try {
18993
- await this.#send("compact", customInstructions ? { customInstructions } : {});
18994
- } catch (error51) {
18995
- const pending = this.#manualCompaction;
18996
- this.#manualCompaction = null;
18997
- pending?.reject(error51 instanceof Error ? error51 : new Error(message2(error51)));
19086
+ const pending = { request, timeout: null };
19087
+ if (request.timeoutMs !== void 0) {
19088
+ pending.timeout = setTimeout(() => {
19089
+ if (this.#activeTurn !== active || !active.interactions.has(requestId2))
19090
+ return;
19091
+ void this.#resolveInteraction({ requestId: requestId2, cancelled: true }, "expired").catch((error51) => {
19092
+ if (this.#closed || this.#failed)
19093
+ return;
19094
+ this.#fail(new OmpRpcFaultError("protocolError", `Omp RPC Interaction timeout handling failed: ${message2(error51)}`));
19095
+ });
19096
+ }, request.timeoutMs);
18998
19097
  }
18999
- return result;
19098
+ active.interactions.set(requestId2, pending);
19099
+ active.onEvent({ type: "interaction.requested", request });
19000
19100
  }
19001
- async getSessionUsage() {
19002
- try {
19003
- const usage = parseOmpSessionUsage(await this.#send("get_session_stats", {}));
19004
- await this.#ensureLatestCacheHitRate();
19005
- return this.#withLatestCacheHitRate(usage);
19006
- } catch (error51) {
19007
- if (!(error51 instanceof OmpRpcUnsupportedCommandError))
19008
- throw error51;
19009
- const response = await this.#send("get_state", {});
19010
- const observedState = parseSessionState(response);
19011
- if (!this.#state || observedState.sessionId !== this.#state.sessionId || observedState.provider !== this.#state.provider || observedState.modelId !== this.#state.modelId) {
19012
- throw new Error("Omp RPC Usage fallback does not match the confirmed Session state");
19013
- }
19014
- await this.#ensureLatestCacheHitRate();
19015
- const usage = parseOmpStateContextUsage(response);
19016
- return usage ? this.#withLatestCacheHitRate(usage) : null;
19101
+ #handleResponse(value) {
19102
+ const id = value.id;
19103
+ if (typeof id !== "string") {
19104
+ this.#fail(new OmpRpcFaultError("protocolError", "Omp RPC response has no id"));
19105
+ return;
19017
19106
  }
19018
- }
19019
- async #ensureLatestCacheHitRate() {
19020
- if (this.#latestCacheHitRatePercent !== void 0)
19107
+ const pending = this.#pending.get(id);
19108
+ const active = this.#activeTurn;
19109
+ if (!pending) {
19110
+ if (active?.promptId === id && value.command === "prompt" && value.success === false) {
19111
+ active.failure = new Error(typeof value.error === "string" ? value.error : "Omp RPC command failed");
19112
+ return;
19113
+ }
19114
+ this.#fail(new OmpRpcFaultError("protocolError", "Omp RPC response id is not pending"));
19021
19115
  return;
19022
- try {
19023
- this.#latestCacheHitRatePercent = latestOmpCacheHitRatePercent(await this.getEntries());
19024
- } catch {
19025
- this.#latestCacheHitRatePercent = null;
19026
19116
  }
19027
- }
19028
- #withLatestCacheHitRate(usage) {
19029
- return this.#latestCacheHitRatePercent === null || this.#latestCacheHitRatePercent === void 0 ? usage : parseHostUsage({ ...usage, cacheHitRatePercent: this.#latestCacheHitRatePercent });
19030
- }
19031
- async fork(entryId) {
19032
- if (!nonBlankString(entryId))
19033
- throw new Error("Omp RPC Fork requires an Entry identity");
19034
- try {
19035
- const response = await this.#send("branch", { entryId });
19036
- const data = isRecord8(response.data) ? response.data : null;
19037
- if (!data || data.cancelled === true) {
19038
- throw new OmpRpcFaultError("unavailable", "Omp RPC Fork was cancelled");
19117
+ if (pending.timeout)
19118
+ clearTimeout(pending.timeout);
19119
+ this.#pending.delete(id);
19120
+ if (value.success === true) {
19121
+ if (pending.command === "prompt" && active?.promptId === id && isRecord8(value.data) && value.data.agentInvoked === false) {
19122
+ this.#settleLocalTurn(active, { cancelled: false });
19123
+ }
19124
+ pending.resolve(value);
19125
+ } else {
19126
+ const error51 = typeof value.error === "string" ? value.error : "Omp RPC command failed";
19127
+ if (value.command === pending.command && error51 === `Unknown command: ${pending.command}`) {
19128
+ pending.reject(new OmpRpcUnsupportedCommandError(pending.command));
19129
+ } else {
19130
+ pending.reject(new Error(error51));
19039
19131
  }
19040
- this.#state = parseSessionState(await this.#send("get_state", {}));
19041
- return this.#state;
19042
- } catch (error51) {
19043
- if (error51 instanceof OmpRpcFaultError)
19044
- this.#fail(error51);
19045
- throw error51;
19046
19132
  }
19047
19133
  }
19048
- verifySessionCwd(expectedCwd) {
19049
- return verifyOmpSessionCwd({
19050
- sessionFile: this.state.sessionFile,
19051
- sessionId: this.state.sessionId,
19052
- expectedCwd
19134
+ #startTool(active, value) {
19135
+ const callId = value.toolCallId;
19136
+ const toolName = value.toolName;
19137
+ const argumentsResult = jsonValueSchema.safeParse(value.args);
19138
+ if (typeof callId !== "string" || callId.length === 0 || typeof toolName !== "string" || toolName.length === 0 || !argumentsResult.success || active.tools.has(callId)) {
19139
+ throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid Tool start");
19140
+ }
19141
+ active.sawTool = true;
19142
+ active.tools.set(callId, toolName);
19143
+ active.onEvent({
19144
+ type: "tool.started",
19145
+ callId,
19146
+ toolName,
19147
+ arguments: argumentsResult.data
19053
19148
  });
19054
19149
  }
19055
- async getAvailableModels() {
19056
- try {
19057
- return parseAvailableModels(await this.#send("get_available_models", {}));
19058
- } catch (error51) {
19059
- if (error51 instanceof OmpRpcFaultError)
19060
- this.#fail(error51);
19061
- throw error51;
19150
+ #updateTool(active, value) {
19151
+ const callId = value.toolCallId;
19152
+ if (typeof callId !== "string" || callId.length === 0) {
19153
+ throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid Tool update");
19062
19154
  }
19063
- }
19064
- async getAvailableThinkingLevels() {
19065
- return this.state.availableThinkingLevels;
19066
- }
19067
- async selectModel(model2) {
19068
- await this.#send("set_model", { provider: model2.provider, modelId: model2.id });
19069
- return this.#refreshState("Model");
19070
- }
19071
- async selectThinkingOption(thinkingOptionId) {
19072
- const level = harnessThinkingOptionIdSchema.parse(thinkingOptionId);
19073
- await this.#send("set_thinking_level", { level });
19074
- return this.#refreshState("Thinking");
19075
- }
19076
- async #refreshState(operation) {
19077
- try {
19078
- this.#state = parseSessionState(await this.#send("get_state", {}));
19079
- return this.#state;
19080
- } catch (error51) {
19081
- const fault = error51 instanceof OmpRpcFaultError ? error51 : new OmpRpcFaultError("protocolError", `Omp RPC ${operation} state could not be confirmed: ${message2(error51)}`);
19082
- this.#fail(fault);
19083
- throw fault;
19155
+ if (!active.tools.has(callId))
19156
+ return;
19157
+ const outputResult = jsonValueSchema.safeParse(value.partialResult ?? null);
19158
+ if (!outputResult.success) {
19159
+ throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid Tool update");
19084
19160
  }
19161
+ active.onEvent({ type: "tool.updated", callId, output: outputResult.data });
19085
19162
  }
19086
- async runTurn(text, onEvent) {
19087
- if (!this.#child || !this.#state || this.#closed || this.#failed) {
19088
- throw new Error("Omp RPC Session is unavailable");
19163
+ #completeTool(active, value) {
19164
+ const callId = value.toolCallId;
19165
+ const toolName = value.toolName;
19166
+ if (typeof callId !== "string" || callId.length === 0) {
19167
+ throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid Tool end");
19089
19168
  }
19090
- if (this.#activeTurn)
19091
- throw new Error("Omp RPC Session already has an active Turn");
19092
- if (text.length === 0)
19093
- throw new Error("Omp text Turn must not be empty");
19094
- const promptId = `codexhost-${randomUUID()}`;
19095
- const settled = new Promise((resolve, reject) => {
19096
- this.#activeTurn = {
19097
- promptId,
19098
- localResult: null,
19099
- text: "",
19100
- assistantMessageId: null,
19101
- sawStreamedMessageText: false,
19102
- sawStreamedMessageReasoning: false,
19103
- lastFinalizedMessageText: null,
19104
- lastFinalizedMessageReasoning: null,
19105
- reasoningMessageOpen: false,
19106
- onEvent,
19107
- resolve,
19108
- reject,
19109
- failure: null,
19110
- sawTool: false,
19111
- tools: /* @__PURE__ */ new Map(),
19112
- interactions: /* @__PURE__ */ new Map(),
19113
- settlement: "pending",
19114
- terminalEnd: false,
19115
- cancellation: "none",
19116
- cancellationTimeout: null,
19117
- cancellationRecheck: null,
19118
- cancellationChecking: false,
19119
- cancellationReloaded: false,
19120
- abortPromise: null
19121
- };
19122
- });
19123
- try {
19124
- await this.#send("prompt", { message: text }, promptId);
19125
- } catch (error51) {
19126
- this.#rejectActiveTurn(error51 instanceof Error ? error51 : new Error(message2(error51)));
19169
+ const expectedName = active.tools.get(callId);
19170
+ if (expectedName === void 0)
19171
+ return;
19172
+ const result = jsonValueSchema.safeParse(value.result);
19173
+ if (typeof toolName !== "string" || expectedName !== toolName || value.isError !== void 0 && typeof value.isError !== "boolean" || !result.success) {
19174
+ throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid Tool end");
19127
19175
  }
19128
- return settled;
19129
- }
19130
- respondToInteraction(response) {
19131
- return this.#resolveInteraction(response, "cancelled" in response ? "cancelled" : "responded");
19176
+ active.tools.delete(callId);
19177
+ active.onEvent({
19178
+ type: "tool.completed",
19179
+ callId,
19180
+ toolName,
19181
+ result: result.data,
19182
+ isError: value.isError === true
19183
+ });
19132
19184
  }
19133
- async #resolveInteraction(response, reason) {
19134
- const active = this.#activeTurn;
19135
- const pending = active?.interactions.get(response.requestId);
19136
- if (!active || !pending || this.#closed || this.#failed) {
19137
- throw new Error("Omp RPC interaction is not pending");
19138
- }
19139
- if ("value" in response && !["select", "input", "editor"].includes(pending.request.method)) {
19140
- throw new Error("Omp RPC interaction response type does not match the request");
19141
- }
19142
- if ("confirmed" in response && pending.request.method !== "confirm") {
19143
- throw new Error("Omp RPC confirmation does not match the request");
19144
- }
19145
- const frame = "cancelled" in response ? {
19146
- type: "extension_ui_response",
19147
- id: response.requestId,
19148
- cancelled: true,
19149
- ...reason === "expired" ? { timedOut: true } : {}
19150
- } : "confirmed" in response ? { type: "extension_ui_response", id: response.requestId, confirmed: response.confirmed } : { type: "extension_ui_response", id: response.requestId, value: response.value };
19151
- if (!active.interactions.delete(response.requestId)) {
19152
- throw new Error("Omp RPC interaction is not pending");
19153
- }
19154
- if (pending.timeout)
19155
- clearTimeout(pending.timeout);
19156
- active.onEvent({ type: "interaction.closed", requestId: response.requestId, reason });
19185
+ async #confirmCancelledTurn(active) {
19186
+ if (this.#activeTurn !== active || active.cancellation !== "accepted" || active.settlement === "confirming" || active.cancellationChecking)
19187
+ return;
19188
+ active.cancellationChecking = true;
19189
+ if (active.cancellationRecheck)
19190
+ clearTimeout(active.cancellationRecheck);
19191
+ active.cancellationRecheck = null;
19157
19192
  try {
19158
- await this.#write(frame);
19193
+ let response = await this.#send("get_state", {});
19194
+ if (this.#activeTurn !== active)
19195
+ return;
19196
+ if (parseSessionStreaming(response)) {
19197
+ await this.#send("abort", {});
19198
+ if (this.#activeTurn !== active)
19199
+ return;
19200
+ response = await this.#send("get_state", {});
19201
+ }
19202
+ let state = parseSessionState(response);
19203
+ if (this.#activeTurn !== active || active.cancellation !== "accepted")
19204
+ return;
19205
+ const data = sessionStateData(response);
19206
+ if (!active.cancellationReloaded && state.sessionFile && state.sessionId === this.state.sessionId && state.sessionFile === this.state.sessionFile && data.isStreaming === false && data.isCompacting === false && data.queuedMessageCount === 0 && data.hasPendingAsyncWork === true && active.tools.size === 0) {
19207
+ await this.verifySessionCwd(this.#options.cwd);
19208
+ if (this.#activeTurn !== active)
19209
+ return;
19210
+ active.cancellationReloaded = true;
19211
+ const reset = await this.#send("new_session", {});
19212
+ if (this.#activeTurn !== active)
19213
+ return;
19214
+ if (!isRecord8(reset.data) || reset.data.cancelled !== false) {
19215
+ throw new OmpRpcFaultError("unavailable", "Omp cancelled Session reset was refused");
19216
+ }
19217
+ const reloaded = await this.#send("switch_session", { sessionPath: state.sessionFile });
19218
+ if (this.#activeTurn !== active)
19219
+ return;
19220
+ if (!isRecord8(reloaded.data) || reloaded.data.cancelled !== false) {
19221
+ throw new OmpRpcFaultError("unavailable", "Omp cancelled Session reload was refused");
19222
+ }
19223
+ const previous = state;
19224
+ response = await this.#send("get_state", {});
19225
+ state = parseSessionState(response);
19226
+ if (state.sessionId !== previous.sessionId || state.sessionFile !== previous.sessionFile) {
19227
+ throw new OmpRpcFaultError("protocolError", "Omp cancelled Session reload changed its identity");
19228
+ }
19229
+ if (state.provider !== previous.provider || state.modelId !== previous.modelId) {
19230
+ if (!previous.provider || !previous.modelId) {
19231
+ throw new OmpRpcFaultError("protocolError", "Omp cancelled Session has no restorable Model");
19232
+ }
19233
+ await this.#send("set_model", { provider: previous.provider, modelId: previous.modelId });
19234
+ }
19235
+ if (previous.thinkingLevel && state.thinkingLevel !== previous.thinkingLevel) {
19236
+ await this.#send("set_thinking_level", { level: previous.thinkingLevel });
19237
+ }
19238
+ response = await this.#send("get_state", {});
19239
+ state = parseSessionState(response);
19240
+ if (state.sessionId !== previous.sessionId || state.sessionFile !== previous.sessionFile || state.provider !== previous.provider || state.modelId !== previous.modelId || previous.thinkingLevel !== null && state.thinkingLevel !== previous.thinkingLevel) {
19241
+ throw new OmpRpcFaultError("protocolError", "Omp cancelled Session reload changed its identity or configuration");
19242
+ }
19243
+ }
19244
+ if (!cancellationSettled(response, active.terminalEnd)) {
19245
+ active.settlement = "pending";
19246
+ active.cancellationRecheck = setTimeout(() => {
19247
+ active.cancellationRecheck = null;
19248
+ void this.#confirmCancelledTurn(active);
19249
+ }, 250);
19250
+ return;
19251
+ }
19252
+ this.#state = state;
19253
+ active.settlement = "confirmed";
19254
+ this.#finishSettledTurn(active);
19159
19255
  } catch (error51) {
19160
- const fault = new OmpRpcFaultError("protocolError", `Omp RPC interaction response failed: ${message2(error51)}`);
19161
- this.#fail(fault);
19162
- throw fault;
19256
+ if (this.#activeTurn !== active)
19257
+ return;
19258
+ const fault = error51 instanceof OmpRpcFaultError ? error51 : new OmpRpcFaultError("protocolError", `Omp RPC cancelled Turn state could not be confirmed: ${message2(error51)}`);
19259
+ this.#terminateFailedCancellation(active, fault);
19260
+ } finally {
19261
+ active.cancellationChecking = false;
19163
19262
  }
19164
19263
  }
19165
- abort() {
19166
- const active = this.#activeTurn;
19167
- if (!active || this.#closed || this.#failed) {
19168
- return Promise.reject(new Error("Omp RPC Session has no cancellable Turn"));
19169
- }
19170
- if (active.abortPromise)
19171
- return active.abortPromise;
19172
- active.cancellation = "requesting";
19173
- active.cancellationTimeout = setTimeout(() => {
19174
- this.#terminateFailedCancellation(active, new OmpRpcFaultError("protocolError", "Omp Turn cancellation did not settle within its bound"));
19175
- }, this.#options.cancelTimeoutMs);
19176
- const aborting = this.#send("abort", {}).then(async () => {
19264
+ #settleLocalTurn(active, result) {
19265
+ if (this.#activeTurn !== active || active.settlement !== "pending")
19266
+ return;
19267
+ active.localResult = result;
19268
+ active.settlement = "confirming";
19269
+ void this.#confirmSettledTurn(active);
19270
+ }
19271
+ async #confirmSettledTurn(active) {
19272
+ try {
19273
+ const response = await this.#send("get_state", {});
19274
+ const state = parseSessionState(response);
19177
19275
  if (this.#activeTurn !== active)
19178
19276
  return;
19179
- active.cancellation = "accepted";
19180
- await this.#confirmCancelledTurn(active);
19181
- }).catch((error51) => {
19277
+ if (active.cancellation !== "none") {
19278
+ active.settlement = "pending";
19279
+ if (active.cancellation === "accepted")
19280
+ void this.#confirmCancelledTurn(active);
19281
+ return;
19282
+ }
19283
+ if (parseSessionStreaming(response)) {
19284
+ throw new OmpRpcFaultError("protocolError", "Omp RPC completed Turn state is still Streaming");
19285
+ }
19286
+ this.#state = state;
19287
+ active.settlement = "confirmed";
19288
+ this.#finishSettledTurn(active);
19289
+ } catch (error51) {
19182
19290
  if (this.#activeTurn !== active)
19183
- throw error51;
19184
- const fault = error51 instanceof OmpRpcFaultError ? error51 : new OmpRpcFaultError("protocolError", `Omp RPC Abort failed: ${message2(error51)}`);
19185
- this.#terminateFailedCancellation(active, fault);
19186
- throw fault;
19187
- });
19188
- active.abortPromise = aborting;
19189
- return aborting;
19291
+ return;
19292
+ const fault = error51 instanceof OmpRpcFaultError ? error51 : new OmpRpcFaultError("protocolError", `Omp RPC stable Turn state could not be confirmed: ${message2(error51)}`);
19293
+ this.#fail(fault);
19294
+ }
19190
19295
  }
19191
- #terminateFailedCancellation(active, fault) {
19192
- if (this.#activeTurn !== active)
19296
+ #finishSettledTurn(active) {
19297
+ if (this.#activeTurn !== active || active.settlement !== "confirmed" || active.cancellation === "requesting") {
19193
19298
  return;
19299
+ }
19194
19300
  if (active.cancellationTimeout)
19195
19301
  clearTimeout(active.cancellationTimeout);
19196
19302
  active.cancellationTimeout = null;
19197
- this.#fail(fault);
19198
- void this.close().catch(() => void 0);
19199
- }
19200
- close() {
19201
- if (!this.#closed) {
19202
- this.#closed = true;
19203
- this.#rejectAll(new Error("Omp RPC Session closed"));
19204
- }
19205
- this.#closePromise ??= this.#stopProcess();
19206
- return this.#closePromise;
19207
- }
19208
- async #stopProcess() {
19209
- const child = this.#child;
19210
- if (!child)
19211
- return;
19212
- if (child.stdin.writable)
19213
- child.stdin.end();
19214
- if (await waitForExit(child, this.#options.closeTimeoutMs))
19215
- return;
19216
- signalProcessTree(child, "SIGTERM");
19217
- if (await waitForExit(child, this.#options.closeTimeoutMs))
19303
+ if (active.cancellationRecheck)
19304
+ clearTimeout(active.cancellationRecheck);
19305
+ active.cancellationRecheck = null;
19306
+ this.#closeInteractions(active, active.cancellation === "accepted" ? "cancelled" : "superseded");
19307
+ if (active.tools.size > 0) {
19308
+ this.#fail(new OmpRpcFaultError("protocolError", "Omp RPC settled with active Tool executions"));
19218
19309
  return;
19219
- signalProcessTree(child, "SIGKILL");
19220
- if (!await waitForExit(child, this.#options.closeTimeoutMs)) {
19221
- throw new Error("Omp RPC process tree did not exit within cleanup bounds");
19310
+ }
19311
+ this.#activeTurn = null;
19312
+ if (active.localResult) {
19313
+ active.resolve({
19314
+ text: active.text,
19315
+ agentInvoked: false,
19316
+ ...active.localResult,
19317
+ cancelled: active.localResult.cancelled || active.cancellation === "accepted"
19318
+ });
19319
+ } else if (active.cancellation === "accepted") {
19320
+ active.resolve({ text: active.text, cancelled: true, agentInvoked: true });
19321
+ } else if (active.failure) {
19322
+ active.reject(active.failure);
19323
+ } else if (active.text.trim().length === 0 && !active.sawTool) {
19324
+ active.reject(new Error("Omp RPC settled without displayable output"));
19325
+ } else {
19326
+ active.resolve({ text: active.text, cancelled: false, agentInvoked: true });
19222
19327
  }
19223
19328
  }
19224
- #push(chunk) {
19225
- this.#buffer = this.#buffer.length === 0 ? chunk : Buffer.concat([this.#buffer, chunk]);
19226
- let newline = this.#buffer.indexOf(10);
19227
- while (newline >= 0) {
19228
- const frame = this.#buffer.subarray(0, newline);
19229
- this.#buffer = this.#buffer.subarray(newline + 1);
19230
- let parsed;
19231
- try {
19232
- parsed = JSON.parse(textDecoder.decode(frame));
19233
- } catch (error51) {
19234
- this.#fail(new OmpRpcFaultError("protocolError", `Omp RPC returned invalid JSONL: ${message2(error51)}`));
19235
- newline = this.#buffer.indexOf(10);
19236
- continue;
19237
- }
19238
- try {
19239
- const decoded = this.#frameDecoder.push(parsed);
19240
- if (decoded === null) {
19241
- newline = this.#buffer.indexOf(10);
19242
- continue;
19243
- }
19244
- const value = decoded;
19245
- if (!isRecord8(value) || typeof value.type !== "string") {
19246
- throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid envelope");
19247
- }
19248
- this.#handle(value);
19249
- } catch (error51) {
19250
- this.#fail(error51 instanceof OmpRpcFaultError ? error51 : new OmpRpcFaultError("protocolError", `Omp RPC frame handling failed: ${message2(error51)}`));
19251
- }
19252
- newline = this.#buffer.indexOf(10);
19329
+ #startAssistantMessage(active, value) {
19330
+ if (active.assistantMessageId !== null && active.reasoningMessageOpen) {
19331
+ active.onEvent({ type: "reasoning.completed", messageId: active.assistantMessageId });
19253
19332
  }
19333
+ const messageId = assistantMessageId(value) ?? randomUUID();
19334
+ active.assistantMessageId = messageId;
19335
+ active.sawStreamedMessageText = false;
19336
+ active.sawStreamedMessageReasoning = false;
19337
+ active.reasoningMessageOpen = false;
19338
+ return messageId;
19254
19339
  }
19255
- /** Latest `available_commands_update` of the running process, if any. */
19256
- get availableCommands() {
19257
- return this.#availableCommands;
19340
+ #ensureAssistantMessage(active, value) {
19341
+ return active.assistantMessageId ?? this.#startAssistantMessage(active, value);
19258
19342
  }
19259
- #handle(value) {
19260
- if (this.#closed || this.#failed)
19343
+ #finalizeAssistantMessage(active, value) {
19344
+ const finalText = assistantText(value);
19345
+ const finalReasoning = assistantReasoning(value);
19346
+ const failure = assistantFailure(value);
19347
+ const cacheHitRatePercent = optionalOmpCacheHitRatePercent(value);
19348
+ if (finalText === null || finalReasoning === null || failure === void 0)
19261
19349
  return;
19262
- if (value.type === "available_commands_update") {
19263
- this.#availableCommands = parseOmpAvailableCommands(value.commands);
19350
+ if (active.assistantMessageId === null && finalText === active.lastFinalizedMessageText && finalReasoning === active.lastFinalizedMessageReasoning && !active.sawStreamedMessageText && !active.sawStreamedMessageReasoning) {
19264
19351
  return;
19265
19352
  }
19266
- if (value.type === "ready") {
19267
- this.#readyResolve?.();
19268
- this.#readyResolve = null;
19269
- return;
19353
+ active.failure = failure;
19354
+ this.#latestCacheHitRatePercent = cacheHitRatePercent;
19355
+ const messageId = this.#ensureAssistantMessage(active, value);
19356
+ if (!active.sawStreamedMessageReasoning && finalReasoning.length > 0) {
19357
+ active.reasoningMessageOpen = true;
19358
+ active.onEvent({ type: "reasoning.delta", messageId, delta: finalReasoning });
19270
19359
  }
19271
- if (value.type === "response") {
19272
- this.#handleResponse(value);
19273
- return;
19360
+ if (active.reasoningMessageOpen && active.failure === null) {
19361
+ active.onEvent({ type: "reasoning.completed", messageId });
19274
19362
  }
19275
- if (value.type === "auto_compaction_start" || value.type === "compaction_start") {
19276
- this.#compactionActive = true;
19277
- this.#compactionTurn = this.#activeTurn;
19278
- this.#compactionTimeout ??= setTimeout(() => {
19279
- this.#compactionTimeout = null;
19280
- this.#fail(new OmpRpcFaultError("protocolError", `Omp RPC compaction timed out after ${this.#options.compactionTimeoutMs}ms`));
19281
- }, this.#options.compactionTimeoutMs);
19282
- const onEvent = this.#activeTurn?.onEvent ?? this.#manualCompaction?.onEvent;
19283
- onEvent?.({ type: "compaction.started" });
19284
- for (const pending of this.#pending.values()) {
19285
- if (pending.command !== "prompt" && pending.command !== "compact" || !pending.timeout)
19286
- continue;
19287
- clearTimeout(pending.timeout);
19288
- pending.timeout = null;
19289
- }
19290
- return;
19363
+ if (!active.sawStreamedMessageText && finalText.length > 0) {
19364
+ active.text += finalText;
19365
+ active.onEvent({ type: "text.delta", messageId, delta: finalText });
19291
19366
  }
19292
- if (value.type === "auto_compaction_end" || value.type === "compaction_end") {
19293
- this.#compactionActive = false;
19294
- if (this.#compactionTimeout)
19295
- clearTimeout(this.#compactionTimeout);
19296
- this.#compactionTimeout = null;
19297
- const compactionTurn = this.#compactionTurn;
19298
- this.#compactionTurn = null;
19299
- for (const [id, pending] of this.#pending) {
19300
- if (pending.command === "prompt" || pending.command === "compact") {
19301
- this.#armCommandTimeout(id, pending);
19302
- }
19303
- }
19304
- const outcome = value.aborted === true ? "cancelled" : isRecord8(value.result) ? "succeeded" : "failed";
19305
- const event = {
19306
- type: "compaction.completed",
19307
- outcome,
19308
- ...nonBlankString(value.errorMessage) ? { errorMessage: value.errorMessage } : {}
19309
- };
19310
- compactionTurn?.onEvent(event);
19311
- const manual = this.#manualCompaction;
19312
- this.#manualCompaction = null;
19313
- manual?.onEvent(event);
19314
- manual?.resolve({
19315
- outcome,
19316
- ...event.errorMessage ? { errorMessage: event.errorMessage } : {}
19317
- });
19318
- return;
19367
+ active.assistantMessageId = null;
19368
+ active.sawStreamedMessageText = false;
19369
+ active.sawStreamedMessageReasoning = false;
19370
+ active.reasoningMessageOpen = false;
19371
+ active.lastFinalizedMessageText = finalText;
19372
+ active.lastFinalizedMessageReasoning = finalReasoning;
19373
+ active.onEvent({ type: "message.completed", messageId });
19374
+ }
19375
+ #write(value) {
19376
+ const child = this.#child;
19377
+ if (!child?.stdin.writable || this.#closed || this.#failed) {
19378
+ return Promise.reject(new Error("Omp RPC stdin is unavailable"));
19319
19379
  }
19320
- const active = this.#activeTurn;
19321
- if (this.#handleSubagentFrame(active, value))
19322
- return;
19323
- this.#observeUsage(value);
19324
- if (value.type === "agent_start" && active)
19325
- active.terminalEnd = false;
19326
- if ((value.type === "session_settled" || value.type === "agent_start") && active?.cancellation === "accepted") {
19327
- void this.#confirmCancelledTurn(active);
19328
- return;
19380
+ return new Promise((resolve, reject) => {
19381
+ const frame = Buffer.from(`${JSON.stringify(value)}
19382
+ `, "utf8");
19383
+ child.stdin.write(frame, (error51) => error51 ? reject(error51) : resolve());
19384
+ });
19385
+ }
19386
+ #send(type, payload, id = `codexhost-${randomUUID()}`) {
19387
+ const child = this.#child;
19388
+ if (!child?.stdin.writable || this.#closed || this.#failed) {
19389
+ return Promise.reject(new Error("Omp RPC stdin is unavailable"));
19329
19390
  }
19330
- if (!active) {
19331
- if (value.type === "extension_ui_request" && this.#isBlockingInteraction(value)) {
19332
- this.#fail(new OmpRpcFaultError("protocolError", "Omp RPC requested blocking Extension UI outside an active Turn"));
19333
- }
19391
+ return new Promise((resolve, reject) => {
19392
+ const pending = {
19393
+ command: type,
19394
+ resolve,
19395
+ reject,
19396
+ timeout: null
19397
+ };
19398
+ this.#pending.set(id, pending);
19399
+ this.#armCommandTimeout(id, pending);
19400
+ const frame = Buffer.from(`${JSON.stringify({ id, type, ...payload })}
19401
+ `, "utf8");
19402
+ child.stdin.write(frame, (error51) => {
19403
+ if (error51) {
19404
+ if (pending.timeout)
19405
+ clearTimeout(pending.timeout);
19406
+ this.#pending.delete(id);
19407
+ reject(error51);
19408
+ }
19409
+ });
19410
+ });
19411
+ }
19412
+ #armCommandTimeout(id, pending) {
19413
+ if (pending.timeout || this.#pending.get(id) !== pending || (pending.command === "prompt" || pending.command === "compact") && this.#compactionActive) {
19334
19414
  return;
19335
19415
  }
19336
- if (value.type === "command_output") {
19337
- if (active.settlement !== "pending")
19416
+ pending.timeout = setTimeout(() => {
19417
+ if (this.#pending.get(id) !== pending)
19338
19418
  return;
19339
- if (typeof value.text !== "string") {
19340
- throw new OmpRpcFaultError("protocolError", "Omp RPC returned invalid command output");
19341
- }
19342
- active.text += value.text;
19343
- active.onEvent({ type: "text.delta", messageId: active.promptId, delta: value.text });
19344
- return;
19345
- }
19346
- if (value.type === "prompt_result") {
19347
- if (value.id !== active.promptId || value.agentInvoked !== false)
19419
+ pending.timeout = null;
19420
+ const error51 = new Error(`Omp RPC '${pending.command}' command timed out`);
19421
+ if (pending.command !== "prompt") {
19422
+ this.#pending.delete(id);
19423
+ pending.reject(error51);
19348
19424
  return;
19349
- if (value.status === "completed" || value.status === "aborted") {
19350
- this.#settleLocalTurn(active, { cancelled: value.status === "aborted" });
19351
- } else if (value.status === "error" && isRecord8(value.error) && typeof value.error.message === "string") {
19352
- this.#settleLocalTurn(active, { cancelled: false, error: value.error.message });
19353
- } else {
19354
- throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid local prompt result");
19355
19425
  }
19426
+ const fault = new OmpRpcFaultError("protocolError", error51.message);
19427
+ void this.#terminateTimedOutPrompt(fault);
19428
+ }, this.#options.commandTimeoutMs);
19429
+ }
19430
+ async #terminateTimedOutPrompt(fault) {
19431
+ if (this.#closed || this.#failed)
19356
19432
  return;
19433
+ this.#failed = true;
19434
+ this.#closed = true;
19435
+ for (const pending of this.#pending.values()) {
19436
+ if (pending.timeout)
19437
+ clearTimeout(pending.timeout);
19438
+ pending.timeout = null;
19357
19439
  }
19358
- if (value.type === "extension_ui_request") {
19359
- this.#startInteraction(active, value);
19360
- return;
19361
- }
19362
- if (value.type === "message_start" && assistantText(value.message) !== null) {
19363
- this.#startAssistantMessage(active, value.message);
19364
- return;
19440
+ let finalFault = fault;
19441
+ try {
19442
+ await this.close();
19443
+ } catch (error51) {
19444
+ finalFault = new OmpRpcFaultError("processExited", `Omp RPC timed-out Prompt cleanup failed: ${message2(error51)}`);
19365
19445
  }
19366
- if (value.type === "message_update" && isRecord8(value.assistantMessageEvent)) {
19367
- const event = value.assistantMessageEvent;
19368
- const eventType = String(event.type ?? "");
19369
- const isThinking = eventType === "thinking_delta" || eventType === "reasoning_delta" || eventType === "thought_delta" || eventType === "thinking" || eventType === "reasoning";
19370
- const isText = eventType === "text_delta" || eventType === "text" || eventType === "content_block_delta";
19371
- const delta = typeof event.delta === "string" ? event.delta : typeof event.thinking === "string" ? event.thinking : typeof event.reasoning === "string" ? event.reasoning : typeof event.text === "string" ? event.text : isRecord8(event.delta) && typeof event.delta.thinking === "string" ? event.delta.thinking : isRecord8(event.delta) && typeof event.delta.text === "string" ? event.delta.text : null;
19372
- if (isThinking && delta !== null && delta.length > 0) {
19373
- const messageId = this.#ensureAssistantMessage(active, value.message);
19374
- active.reasoningMessageOpen = true;
19375
- active.sawStreamedMessageReasoning = true;
19376
- active.onEvent({ type: "reasoning.delta", messageId, delta });
19377
- } else if (isText && delta !== null && delta.length > 0) {
19378
- const messageId = this.#ensureAssistantMessage(active, value.message);
19379
- active.text += delta;
19380
- active.sawStreamedMessageText = true;
19381
- active.onEvent({ type: "text.delta", messageId, delta });
19382
- } else if (event.type === "error") {
19383
- this.#ensureAssistantMessage(active, value.message);
19384
- active.failure = assistantFailure(event.error) ?? assistantFailure(value.message) ?? new Error("Omp assistant message failed");
19385
- }
19386
- return;
19446
+ this.#rejectAll(finalFault);
19447
+ this.#options.onFault?.(finalFault);
19448
+ }
19449
+ #closeInteractions(active, reason) {
19450
+ for (const [requestId2, pending] of active.interactions) {
19451
+ active.interactions.delete(requestId2);
19452
+ if (pending.timeout)
19453
+ clearTimeout(pending.timeout);
19454
+ active.onEvent({ type: "interaction.closed", requestId: requestId2, reason });
19387
19455
  }
19388
- if (value.type === "message_end") {
19389
- this.#finalizeAssistantMessage(active, value.message);
19456
+ }
19457
+ #rejectActiveTurn(error51) {
19458
+ const active = this.#activeTurn;
19459
+ if (!active)
19390
19460
  return;
19461
+ if (active.cancellationTimeout)
19462
+ clearTimeout(active.cancellationTimeout);
19463
+ if (active.cancellationRecheck)
19464
+ clearTimeout(active.cancellationRecheck);
19465
+ this.#closeInteractions(active, "cancelled");
19466
+ this.#activeTurn = null;
19467
+ active.reject(error51);
19468
+ }
19469
+ #rejectAll(error51) {
19470
+ if (this.#compactionTimeout)
19471
+ clearTimeout(this.#compactionTimeout);
19472
+ this.#compactionTimeout = null;
19473
+ for (const pending of this.#pending.values()) {
19474
+ if (pending.timeout)
19475
+ clearTimeout(pending.timeout);
19476
+ pending.reject(error51);
19391
19477
  }
19392
- if (value.type === "turn_end") {
19393
- this.#finalizeAssistantMessage(active, value.message);
19478
+ this.#pending.clear();
19479
+ const manual = this.#manualCompaction;
19480
+ this.#manualCompaction = null;
19481
+ manual?.reject(error51);
19482
+ this.#rejectActiveTurn(error51);
19483
+ }
19484
+ #fail(error51) {
19485
+ if (this.#closed || this.#failed)
19394
19486
  return;
19487
+ this.#failed = true;
19488
+ this.#startupFaultResolve?.(error51);
19489
+ this.#startupFaultResolve = null;
19490
+ this.#rejectAll(error51);
19491
+ this.#options.onFault?.(error51);
19492
+ }
19493
+ };
19494
+
19495
+ // dist/omp-model-list.js
19496
+ var OMP_MODEL_LIST_TIMEOUT_MS = 15e3;
19497
+ var OMP_MODEL_LIST_OUTPUT_LIMIT = 4 * 1024 * 1024;
19498
+ function listOmpModels(input) {
19499
+ const environment = withNodeRuntimeOnPath({
19500
+ ...process.env,
19501
+ ...input.environment,
19502
+ OMP_SKIP_VERSION_CHECK: "1",
19503
+ OMP_TELEMETRY: "0"
19504
+ });
19505
+ const executable = resolveOmpExecutable({
19506
+ ...input.command ? { command: input.command } : {},
19507
+ environment
19508
+ });
19509
+ const invocation = commandInvocation(executable, ["models", "--json"], environment);
19510
+ return new Promise((resolve) => {
19511
+ if (input.signal?.aborted)
19512
+ return resolve({ kind: "unanswered" });
19513
+ const child = spawn2(invocation.command, invocation.arguments, {
19514
+ cwd: input.cwd,
19515
+ env: environment,
19516
+ // A process group lets a stop reach OMP and its descendants, not only a launcher shim.
19517
+ detached: process.platform !== "win32",
19518
+ stdio: ["ignore", "pipe", "ignore"],
19519
+ windowsHide: true,
19520
+ windowsVerbatimArguments: invocation.windowsVerbatimArguments
19521
+ });
19522
+ let settled = false;
19523
+ let stdout = "";
19524
+ const finish = (result, stop = false) => {
19525
+ if (settled)
19526
+ return;
19527
+ settled = true;
19528
+ clearTimeout(timer);
19529
+ input.signal?.removeEventListener("abort", onAbort);
19530
+ child.stdout.removeAllListeners("data");
19531
+ if (stop) {
19532
+ child.stdout.destroy();
19533
+ try {
19534
+ signalProcessTree(child, "SIGKILL");
19535
+ } catch {
19536
+ }
19537
+ }
19538
+ resolve(result);
19539
+ };
19540
+ const onAbort = () => finish({ kind: "unanswered" }, true);
19541
+ input.signal?.addEventListener("abort", onAbort, { once: true });
19542
+ const timer = setTimeout(() => finish({ kind: "timedOut" }, true), input.timeoutMs ?? OMP_MODEL_LIST_TIMEOUT_MS);
19543
+ child.stdout.setEncoding("utf8").on("data", (chunk) => {
19544
+ stdout += chunk;
19545
+ if (stdout.length > OMP_MODEL_LIST_OUTPUT_LIMIT)
19546
+ finish({ kind: "unanswered" }, true);
19547
+ });
19548
+ child.once("error", (error51) => {
19549
+ finish(error51.code === "ENOENT" ? { kind: "notInstalled", message: "Oh My Pi (omp) is not installed" } : { kind: "unanswered" });
19550
+ });
19551
+ child.once("close", (code) => {
19552
+ if (code !== 0)
19553
+ return finish({ kind: "unanswered" });
19554
+ const models = parseOmpModelList(stdout);
19555
+ finish(models ? { kind: "models", models } : { kind: "unanswered" });
19556
+ });
19557
+ });
19558
+ }
19559
+ function parseOmpModelList(output) {
19560
+ let parsed;
19561
+ try {
19562
+ parsed = JSON.parse(output);
19563
+ } catch {
19564
+ return null;
19565
+ }
19566
+ if (!isRecord9(parsed) || !Array.isArray(parsed.models))
19567
+ return null;
19568
+ const models = [];
19569
+ for (const model2 of parsed.models) {
19570
+ if (!isRecord9(model2) || !nonBlankString2(model2.provider) || !nonBlankString2(model2.id) || typeof model2.reasoning !== "boolean") {
19571
+ return null;
19395
19572
  }
19396
- if (value.type === "tool_execution_start") {
19397
- this.#startTool(active, value);
19398
- return;
19573
+ models.push({ provider: model2.provider, id: model2.id, reasoning: model2.reasoning });
19574
+ }
19575
+ return models;
19576
+ }
19577
+ function isRecord9(value) {
19578
+ return typeof value === "object" && value !== null && !Array.isArray(value);
19579
+ }
19580
+ function nonBlankString2(value) {
19581
+ return typeof value === "string" && value.trim().length > 0;
19582
+ }
19583
+
19584
+ // ../../../node_modules/diff/libesm/diff/base.js
19585
+ var Diff = class {
19586
+ diff(oldStr, newStr, options = {}) {
19587
+ let callback;
19588
+ if (typeof options === "function") {
19589
+ callback = options;
19590
+ options = {};
19591
+ } else if ("callback" in options) {
19592
+ callback = options.callback;
19399
19593
  }
19400
- if (value.type === "tool_execution_update") {
19401
- this.#updateTool(active, value);
19402
- return;
19594
+ const oldString = this.castInput(oldStr, options);
19595
+ const newString = this.castInput(newStr, options);
19596
+ const oldTokens = this.removeEmpty(this.tokenize(oldString, options));
19597
+ const newTokens = this.removeEmpty(this.tokenize(newString, options));
19598
+ return this.diffWithOptionsObj(oldTokens, newTokens, options, callback);
19599
+ }
19600
+ diffWithOptionsObj(oldTokens, newTokens, options, callback) {
19601
+ var _a3;
19602
+ const done = (value) => {
19603
+ value = this.postProcess(value, options);
19604
+ if (callback) {
19605
+ setTimeout(function() {
19606
+ callback(value);
19607
+ }, 0);
19608
+ return void 0;
19609
+ } else {
19610
+ return value;
19611
+ }
19612
+ };
19613
+ const newLen = newTokens.length, oldLen = oldTokens.length;
19614
+ let editLength = 1;
19615
+ let maxEditLength = newLen + oldLen;
19616
+ if (options.maxEditLength != null) {
19617
+ maxEditLength = Math.min(maxEditLength, options.maxEditLength);
19403
19618
  }
19404
- if (value.type === "tool_execution_end") {
19405
- this.#completeTool(active, value);
19406
- return;
19619
+ const maxExecutionTime = (_a3 = options.timeout) !== null && _a3 !== void 0 ? _a3 : Infinity;
19620
+ const abortAfterTimestamp = Date.now() + maxExecutionTime;
19621
+ const bestPath = [{ oldPos: -1, lastComponent: void 0 }];
19622
+ let newPos = this.extractCommon(bestPath[0], newTokens, oldTokens, 0, options);
19623
+ if (bestPath[0].oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
19624
+ return done(this.buildValues(bestPath[0].lastComponent, newTokens, oldTokens));
19407
19625
  }
19408
- if (value.type === "agent_end" && Array.isArray(value.messages)) {
19409
- for (let index = value.messages.length - 1; index >= 0; index -= 1) {
19410
- const message3 = value.messages[index];
19411
- if (!isRecord8(message3) || message3.role !== "assistant")
19626
+ let minDiagonalToConsider = -Infinity, maxDiagonalToConsider = Infinity;
19627
+ const execEditLength = () => {
19628
+ for (let diagonalPath = Math.max(minDiagonalToConsider, -editLength); diagonalPath <= Math.min(maxDiagonalToConsider, editLength); diagonalPath += 2) {
19629
+ let basePath;
19630
+ const removePath = bestPath[diagonalPath - 1], addPath = bestPath[diagonalPath + 1];
19631
+ if (removePath) {
19632
+ bestPath[diagonalPath - 1] = void 0;
19633
+ }
19634
+ let canAdd = false;
19635
+ if (addPath) {
19636
+ const addPathNewPos = addPath.oldPos - diagonalPath;
19637
+ canAdd = addPath && 0 <= addPathNewPos && addPathNewPos < newLen;
19638
+ }
19639
+ const canRemove = removePath && removePath.oldPos + 1 < oldLen;
19640
+ if (!canAdd && !canRemove) {
19641
+ bestPath[diagonalPath] = void 0;
19412
19642
  continue;
19413
- this.#finalizeAssistantMessage(active, message3);
19414
- break;
19643
+ }
19644
+ if (!canRemove || canAdd && removePath.oldPos < addPath.oldPos) {
19645
+ basePath = this.addToPath(addPath, true, false, 0, options);
19646
+ } else {
19647
+ basePath = this.addToPath(removePath, false, true, 1, options);
19648
+ }
19649
+ newPos = this.extractCommon(basePath, newTokens, oldTokens, diagonalPath, options);
19650
+ if (basePath.oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
19651
+ return done(this.buildValues(basePath.lastComponent, newTokens, oldTokens)) || true;
19652
+ } else {
19653
+ bestPath[diagonalPath] = basePath;
19654
+ if (basePath.oldPos + 1 >= oldLen) {
19655
+ maxDiagonalToConsider = Math.min(maxDiagonalToConsider, diagonalPath - 1);
19656
+ }
19657
+ if (newPos + 1 >= newLen) {
19658
+ minDiagonalToConsider = Math.max(minDiagonalToConsider, diagonalPath + 1);
19659
+ }
19660
+ }
19415
19661
  }
19416
- }
19417
- if (value.type === "agent_end" && value.isTerminal !== false) {
19418
- active.terminalEnd = true;
19419
- if (active.cancellation !== "none") {
19420
- if (active.cancellation === "accepted")
19421
- void this.#confirmCancelledTurn(active);
19422
- return;
19662
+ editLength++;
19663
+ };
19664
+ if (callback) {
19665
+ (function exec() {
19666
+ setTimeout(function() {
19667
+ if (editLength > maxEditLength || Date.now() > abortAfterTimestamp) {
19668
+ return callback(void 0);
19669
+ }
19670
+ if (!execEditLength()) {
19671
+ exec();
19672
+ }
19673
+ }, 0);
19674
+ })();
19675
+ } else {
19676
+ while (editLength <= maxEditLength && Date.now() <= abortAfterTimestamp) {
19677
+ const ret = execEditLength();
19678
+ if (ret) {
19679
+ return ret;
19680
+ }
19423
19681
  }
19424
- if (active.settlement !== "pending")
19425
- return;
19426
- active.settlement = "confirming";
19427
- void this.#confirmSettledTurn(active);
19428
19682
  }
19429
19683
  }
19430
- /** Every finished assistant message is one model request, with or without an active Turn. */
19431
- #observeUsage(value) {
19432
- if (value.type === "message_start") {
19433
- this.#usageRequestStartedAtMs = null;
19434
- return;
19684
+ addToPath(path9, added, removed, oldPosInc, options) {
19685
+ const last = path9.lastComponent;
19686
+ if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
19687
+ return {
19688
+ oldPos: path9.oldPos + oldPosInc,
19689
+ lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
19690
+ };
19691
+ } else {
19692
+ return {
19693
+ oldPos: path9.oldPos + oldPosInc,
19694
+ lastComponent: { count: 1, added, removed, previousComponent: last }
19695
+ };
19435
19696
  }
19436
- if (value.type === "message_update") {
19437
- const event = value.assistantMessageEvent;
19438
- if (this.#usageRequestStartedAtMs === null && isRecord8(event) && typeof event.type === "string" && /^(text|thinking|reasoning|thought|toolcall)_(start|delta)$/u.test(event.type)) {
19439
- this.#usageRequestStartedAtMs = Date.now();
19697
+ }
19698
+ extractCommon(basePath, newTokens, oldTokens, diagonalPath, options) {
19699
+ const newLen = newTokens.length, oldLen = oldTokens.length;
19700
+ let oldPos = basePath.oldPos, newPos = oldPos - diagonalPath, commonCount = 0;
19701
+ while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(oldTokens[oldPos + 1], newTokens[newPos + 1], options)) {
19702
+ newPos++;
19703
+ oldPos++;
19704
+ commonCount++;
19705
+ if (options.oneChangePerToken) {
19706
+ basePath.lastComponent = { count: 1, previousComponent: basePath.lastComponent, added: false, removed: false };
19440
19707
  }
19441
- return;
19442
19708
  }
19443
- if (value.type === "message_end" && isRecord8(value.message)) {
19444
- if (value.message.role !== "assistant")
19445
- return;
19446
- const startedAtMs = this.#usageRequestStartedAtMs;
19447
- this.#usageRequestStartedAtMs = null;
19448
- this.#options.onUsage?.({
19449
- message: value.message,
19450
- startedAtMs,
19451
- completedAtMs: Date.now()
19452
- });
19709
+ if (commonCount && !options.oneChangePerToken) {
19710
+ basePath.lastComponent = { count: commonCount, previousComponent: basePath.lastComponent, added: false, removed: false };
19453
19711
  }
19712
+ basePath.oldPos = oldPos;
19713
+ return newPos;
19454
19714
  }
19455
- #handleSubagentFrame(active, value) {
19456
- if (value.type !== "subagent_lifecycle" && value.type !== "subagent_progress" && value.type !== "subagent_event") {
19457
- return false;
19458
- }
19459
- const payload = isRecord8(value.payload) ? value.payload : null;
19460
- const progressPayload = value.type === "subagent_progress" && payload && isRecord8(payload.progress) ? payload.progress : null;
19461
- const nativeIdValue = progressPayload?.id ?? payload?.id;
19462
- if (!payload || !nonBlankString(nativeIdValue)) {
19463
- throw new OmpRpcFaultError("protocolError", "Omp RPC Subagent frame has no stable ID");
19464
- }
19465
- const nativeSubagentId = nativeIdValue;
19466
- const callId = nativeSubagentId;
19467
- const emit = active?.onEvent ?? this.#options.onSubagentEvent;
19468
- if (value.type === "subagent_event") {
19469
- emit?.({ type: "subagent.transcript.changed", callId, nativeSubagentId });
19470
- return true;
19715
+ equals(left, right, options) {
19716
+ if (options.comparator) {
19717
+ return options.comparator(left, right);
19718
+ } else {
19719
+ return left === right || !!options.ignoreCase && left.toLowerCase() === right.toLowerCase();
19471
19720
  }
19472
- if (value.type === "subagent_lifecycle") {
19473
- const status2 = payload.status;
19474
- if (status2 === "started") {
19475
- const description = nonBlankString(payload.description) ? payload.description : nonBlankString(payload.agent) ? `${payload.agent} delegation` : "Subagent delegation";
19476
- emit?.({
19477
- type: "subagent.started",
19478
- callId,
19479
- nativeSubagentId,
19480
- description,
19481
- ...nonBlankString(payload.agent) ? { role: payload.agent } : {},
19482
- ...nonBlankString(payload.task) ? { prompt: payload.task } : {},
19483
- background: payload.detached === true,
19484
- ...typeof payload.sessionFile === "string" ? { sessionFile: payload.sessionFile } : {}
19485
- });
19486
- return true;
19487
- }
19488
- if (status2 !== "completed" && status2 !== "failed" && status2 !== "aborted") {
19489
- throw new OmpRpcFaultError("protocolError", "Omp RPC Subagent lifecycle status is invalid");
19721
+ }
19722
+ removeEmpty(array2) {
19723
+ const ret = [];
19724
+ for (let i = 0; i < array2.length; i++) {
19725
+ if (array2[i]) {
19726
+ ret.push(array2[i]);
19490
19727
  }
19491
- emit?.({
19492
- type: "subagent.completed",
19493
- callId,
19494
- nativeSubagentId,
19495
- isError: status2 !== "completed",
19496
- ...nonBlankString(payload.resultSummary) ? { resultSummary: payload.resultSummary } : {},
19497
- ...typeof payload.sessionFile === "string" ? { sessionFile: payload.sessionFile } : {}
19498
- });
19499
- return true;
19500
19728
  }
19501
- const progress = progressPayload;
19502
- if (!progress || !nonBlankString(progress.id) || progress.id !== nativeSubagentId) {
19503
- throw new OmpRpcFaultError("protocolError", "Omp RPC Subagent progress is invalid");
19504
- }
19505
- const status = subagentStatus(progress.status);
19506
- const recentOutput = Array.isArray(progress.recentOutput) ? progress.recentOutput.filter((item) => typeof item === "string") : [];
19507
- const resultSummary = recentOutput.at(-1);
19508
- emit?.({
19509
- type: "subagent.updated",
19510
- callId,
19511
- nativeSubagentId,
19512
- status,
19513
- ...nonBlankString(progress.description) ? { description: progress.description } : nonBlankString(payload.task) ? { description: payload.task } : {},
19514
- ...resultSummary !== void 0 ? { resultSummary } : {},
19515
- ...typeof payload.sessionFile === "string" ? { sessionFile: payload.sessionFile } : {}
19516
- });
19517
- return true;
19729
+ return ret;
19518
19730
  }
19519
- #isBlockingInteraction(value) {
19520
- return ["select", "confirm", "input", "editor"].includes(String(value.method));
19731
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
19732
+ castInput(value, options) {
19733
+ return value;
19521
19734
  }
19522
- #startInteraction(active, value) {
19523
- if (!this.#isBlockingInteraction(value))
19524
- return;
19525
- const requestId2 = value.id;
19526
- const method = value.method;
19527
- const title = value.title;
19528
- const timeoutMs = value.timeout;
19529
- if (typeof requestId2 !== "string" || requestId2.length === 0 || typeof method !== "string" || typeof title !== "string" || title.length === 0 || timeoutMs !== void 0 && (typeof timeoutMs !== "number" || !Number.isFinite(timeoutMs) || timeoutMs < 0) || active.interactions.has(requestId2)) {
19530
- throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid Interaction request");
19735
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
19736
+ tokenize(value, options) {
19737
+ return Array.from(value);
19738
+ }
19739
+ join(chars) {
19740
+ return chars.join("");
19741
+ }
19742
+ postProcess(changeObjects, options) {
19743
+ return changeObjects;
19744
+ }
19745
+ get useLongestToken() {
19746
+ return false;
19747
+ }
19748
+ buildValues(lastComponent, newTokens, oldTokens) {
19749
+ const components = [];
19750
+ let nextComponent;
19751
+ while (lastComponent) {
19752
+ components.push(lastComponent);
19753
+ nextComponent = lastComponent.previousComponent;
19754
+ delete lastComponent.previousComponent;
19755
+ lastComponent = nextComponent;
19531
19756
  }
19532
- let request;
19533
- if (method === "select") {
19534
- if (!Array.isArray(value.options) || value.options.length === 0 || !value.options.every((option) => typeof option === "string" && option.length > 0)) {
19535
- throw new OmpRpcFaultError("protocolError", "Omp RPC select request has invalid options");
19536
- }
19537
- let optionDetails;
19538
- if (value.optionDetails !== void 0) {
19539
- if (!Array.isArray(value.optionDetails) || value.optionDetails.length !== value.options.length || !value.optionDetails.every((detail) => typeof detail === "object" && detail !== null && !Array.isArray(detail) && (detail.description === void 0 || typeof detail.description === "string"))) {
19540
- throw new OmpRpcFaultError("protocolError", "Omp RPC select option details are invalid");
19757
+ components.reverse();
19758
+ const componentLen = components.length;
19759
+ let componentPos = 0, newPos = 0, oldPos = 0;
19760
+ for (; componentPos < componentLen; componentPos++) {
19761
+ const component = components[componentPos];
19762
+ if (!component.removed) {
19763
+ if (!component.added && this.useLongestToken) {
19764
+ let value = newTokens.slice(newPos, newPos + component.count);
19765
+ value = value.map(function(value2, i) {
19766
+ const oldValue = oldTokens[oldPos + i];
19767
+ return oldValue.length > value2.length ? oldValue : value2;
19768
+ });
19769
+ component.value = this.join(value);
19770
+ } else {
19771
+ component.value = this.join(newTokens.slice(newPos, newPos + component.count));
19541
19772
  }
19542
- optionDetails = value.optionDetails.map(({ description }) => description === void 0 ? {} : { description });
19543
- }
19544
- request = {
19545
- requestId: requestId2,
19546
- method,
19547
- title,
19548
- options: [...value.options],
19549
- ...optionDetails ? { optionDetails } : {},
19550
- ...typeof timeoutMs === "number" ? { timeoutMs } : {}
19551
- };
19552
- } else if (method === "confirm") {
19553
- if (typeof value.message !== "string") {
19554
- throw new OmpRpcFaultError("protocolError", "Omp RPC confirm request has no message");
19555
- }
19556
- request = {
19557
- requestId: requestId2,
19558
- method,
19559
- title,
19560
- message: value.message,
19561
- ...typeof timeoutMs === "number" ? { timeoutMs } : {}
19562
- };
19563
- } else if (method === "input") {
19564
- if (value.placeholder !== void 0 && typeof value.placeholder !== "string") {
19565
- throw new OmpRpcFaultError("protocolError", "Omp RPC input placeholder is invalid");
19566
- }
19567
- request = {
19568
- requestId: requestId2,
19569
- method,
19570
- title,
19571
- ...typeof value.placeholder === "string" ? { placeholder: value.placeholder } : {},
19572
- ...typeof timeoutMs === "number" ? { timeoutMs } : {}
19573
- };
19574
- } else {
19575
- if (value.prefill !== void 0 && typeof value.prefill !== "string") {
19576
- throw new OmpRpcFaultError("protocolError", "Omp RPC editor prefill is invalid");
19773
+ newPos += component.count;
19774
+ if (!component.added) {
19775
+ oldPos += component.count;
19776
+ }
19777
+ } else {
19778
+ component.value = this.join(oldTokens.slice(oldPos, oldPos + component.count));
19779
+ oldPos += component.count;
19577
19780
  }
19578
- request = {
19579
- requestId: requestId2,
19580
- method: "editor",
19581
- title,
19582
- ...typeof value.prefill === "string" ? { prefill: value.prefill } : {},
19583
- ...typeof timeoutMs === "number" ? { timeoutMs } : {}
19584
- };
19585
- }
19586
- const pending = { request, timeout: null };
19587
- if (request.timeoutMs !== void 0) {
19588
- pending.timeout = setTimeout(() => {
19589
- if (this.#activeTurn !== active || !active.interactions.has(requestId2))
19590
- return;
19591
- void this.#resolveInteraction({ requestId: requestId2, cancelled: true }, "expired").catch((error51) => {
19592
- if (this.#closed || this.#failed)
19593
- return;
19594
- this.#fail(new OmpRpcFaultError("protocolError", `Omp RPC Interaction timeout handling failed: ${message2(error51)}`));
19595
- });
19596
- }, request.timeoutMs);
19597
19781
  }
19598
- active.interactions.set(requestId2, pending);
19599
- active.onEvent({ type: "interaction.requested", request });
19782
+ return components;
19600
19783
  }
19601
- #handleResponse(value) {
19602
- const id = value.id;
19603
- if (typeof id !== "string") {
19604
- this.#fail(new OmpRpcFaultError("protocolError", "Omp RPC response has no id"));
19605
- return;
19606
- }
19607
- const pending = this.#pending.get(id);
19608
- const active = this.#activeTurn;
19609
- if (!pending) {
19610
- if (active?.promptId === id && value.command === "prompt" && value.success === false) {
19611
- active.failure = new Error(typeof value.error === "string" ? value.error : "Omp RPC command failed");
19612
- return;
19784
+ };
19785
+
19786
+ // ../../../node_modules/diff/libesm/diff/line.js
19787
+ var LineDiff = class extends Diff {
19788
+ constructor() {
19789
+ super(...arguments);
19790
+ this.tokenize = tokenize;
19791
+ }
19792
+ equals(left, right, options) {
19793
+ if (options.ignoreWhitespace) {
19794
+ if (!options.newlineIsToken || !left.includes("\n")) {
19795
+ left = left.trim();
19613
19796
  }
19614
- this.#fail(new OmpRpcFaultError("protocolError", "Omp RPC response id is not pending"));
19615
- return;
19616
- }
19617
- if (pending.timeout)
19618
- clearTimeout(pending.timeout);
19619
- this.#pending.delete(id);
19620
- if (value.success === true) {
19621
- if (pending.command === "prompt" && active?.promptId === id && isRecord8(value.data) && value.data.agentInvoked === false) {
19622
- this.#settleLocalTurn(active, { cancelled: false });
19797
+ if (!options.newlineIsToken || !right.includes("\n")) {
19798
+ right = right.trim();
19623
19799
  }
19624
- pending.resolve(value);
19625
- } else {
19626
- const error51 = typeof value.error === "string" ? value.error : "Omp RPC command failed";
19627
- if (value.command === pending.command && error51 === `Unknown command: ${pending.command}`) {
19628
- pending.reject(new OmpRpcUnsupportedCommandError(pending.command));
19629
- } else {
19630
- pending.reject(new Error(error51));
19800
+ } else if (options.ignoreNewlineAtEof && !options.newlineIsToken) {
19801
+ if (left.endsWith("\n")) {
19802
+ left = left.slice(0, -1);
19803
+ }
19804
+ if (right.endsWith("\n")) {
19805
+ right = right.slice(0, -1);
19631
19806
  }
19632
19807
  }
19808
+ return super.equals(left, right, options);
19633
19809
  }
19634
- #startTool(active, value) {
19635
- const callId = value.toolCallId;
19636
- const toolName = value.toolName;
19637
- const argumentsResult = jsonValueSchema.safeParse(value.args);
19638
- if (typeof callId !== "string" || callId.length === 0 || typeof toolName !== "string" || toolName.length === 0 || !argumentsResult.success || active.tools.has(callId)) {
19639
- throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid Tool start");
19640
- }
19641
- active.sawTool = true;
19642
- active.tools.set(callId, toolName);
19643
- active.onEvent({
19644
- type: "tool.started",
19645
- callId,
19646
- toolName,
19647
- arguments: argumentsResult.data
19648
- });
19810
+ };
19811
+ var lineDiff = new LineDiff();
19812
+ function diffLines(oldStr, newStr, options) {
19813
+ return lineDiff.diff(oldStr, newStr, options);
19814
+ }
19815
+ function tokenize(value, options) {
19816
+ if (options.stripTrailingCr) {
19817
+ value = value.replace(/\r\n/g, "\n");
19649
19818
  }
19650
- #updateTool(active, value) {
19651
- const callId = value.toolCallId;
19652
- if (typeof callId !== "string" || callId.length === 0) {
19653
- throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid Tool update");
19654
- }
19655
- if (!active.tools.has(callId))
19656
- return;
19657
- const outputResult = jsonValueSchema.safeParse(value.partialResult ?? null);
19658
- if (!outputResult.success) {
19659
- throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid Tool update");
19660
- }
19661
- active.onEvent({ type: "tool.updated", callId, output: outputResult.data });
19819
+ const retLines = [], linesAndNewlines = value.split(/(\n|\r\n)/);
19820
+ if (!linesAndNewlines[linesAndNewlines.length - 1]) {
19821
+ linesAndNewlines.pop();
19662
19822
  }
19663
- #completeTool(active, value) {
19664
- const callId = value.toolCallId;
19665
- const toolName = value.toolName;
19666
- if (typeof callId !== "string" || callId.length === 0) {
19667
- throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid Tool end");
19668
- }
19669
- const expectedName = active.tools.get(callId);
19670
- if (expectedName === void 0)
19671
- return;
19672
- const result = jsonValueSchema.safeParse(value.result);
19673
- if (typeof toolName !== "string" || expectedName !== toolName || value.isError !== void 0 && typeof value.isError !== "boolean" || !result.success) {
19674
- throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid Tool end");
19823
+ for (let i = 0; i < linesAndNewlines.length; i++) {
19824
+ const line = linesAndNewlines[i];
19825
+ if (i % 2 && !options.newlineIsToken) {
19826
+ retLines[retLines.length - 1] += line;
19827
+ } else {
19828
+ retLines.push(line);
19675
19829
  }
19676
- active.tools.delete(callId);
19677
- active.onEvent({
19678
- type: "tool.completed",
19679
- callId,
19680
- toolName,
19681
- result: result.data,
19682
- isError: value.isError === true
19683
- });
19684
19830
  }
19685
- async #confirmCancelledTurn(active) {
19686
- if (this.#activeTurn !== active || active.cancellation !== "accepted" || active.settlement === "confirming" || active.cancellationChecking)
19687
- return;
19688
- active.cancellationChecking = true;
19689
- if (active.cancellationRecheck)
19690
- clearTimeout(active.cancellationRecheck);
19691
- active.cancellationRecheck = null;
19692
- try {
19693
- let response = await this.#send("get_state", {});
19694
- if (this.#activeTurn !== active)
19695
- return;
19696
- if (parseSessionStreaming(response)) {
19697
- await this.#send("abort", {});
19698
- if (this.#activeTurn !== active)
19699
- return;
19700
- response = await this.#send("get_state", {});
19701
- }
19702
- let state = parseSessionState(response);
19703
- if (this.#activeTurn !== active || active.cancellation !== "accepted")
19704
- return;
19705
- const data = sessionStateData(response);
19706
- if (!active.cancellationReloaded && state.sessionFile && state.sessionId === this.state.sessionId && state.sessionFile === this.state.sessionFile && data.isStreaming === false && data.isCompacting === false && data.queuedMessageCount === 0 && data.hasPendingAsyncWork === true && active.tools.size === 0) {
19707
- await this.verifySessionCwd(this.#options.cwd);
19708
- if (this.#activeTurn !== active)
19709
- return;
19710
- active.cancellationReloaded = true;
19711
- const reset = await this.#send("new_session", {});
19712
- if (this.#activeTurn !== active)
19713
- return;
19714
- if (!isRecord8(reset.data) || reset.data.cancelled !== false) {
19715
- throw new OmpRpcFaultError("unavailable", "Omp cancelled Session reset was refused");
19716
- }
19717
- const reloaded = await this.#send("switch_session", { sessionPath: state.sessionFile });
19718
- if (this.#activeTurn !== active)
19719
- return;
19720
- if (!isRecord8(reloaded.data) || reloaded.data.cancelled !== false) {
19721
- throw new OmpRpcFaultError("unavailable", "Omp cancelled Session reload was refused");
19722
- }
19723
- const previous = state;
19724
- response = await this.#send("get_state", {});
19725
- state = parseSessionState(response);
19726
- if (state.sessionId !== previous.sessionId || state.sessionFile !== previous.sessionFile) {
19727
- throw new OmpRpcFaultError("protocolError", "Omp cancelled Session reload changed its identity");
19728
- }
19729
- if (state.provider !== previous.provider || state.modelId !== previous.modelId) {
19730
- if (!previous.provider || !previous.modelId) {
19731
- throw new OmpRpcFaultError("protocolError", "Omp cancelled Session has no restorable Model");
19732
- }
19733
- await this.#send("set_model", { provider: previous.provider, modelId: previous.modelId });
19734
- }
19735
- if (previous.thinkingLevel && state.thinkingLevel !== previous.thinkingLevel) {
19736
- await this.#send("set_thinking_level", { level: previous.thinkingLevel });
19737
- }
19738
- response = await this.#send("get_state", {});
19739
- state = parseSessionState(response);
19740
- if (state.sessionId !== previous.sessionId || state.sessionFile !== previous.sessionFile || state.provider !== previous.provider || state.modelId !== previous.modelId || previous.thinkingLevel !== null && state.thinkingLevel !== previous.thinkingLevel) {
19741
- throw new OmpRpcFaultError("protocolError", "Omp cancelled Session reload changed its identity or configuration");
19742
- }
19831
+ return retLines;
19832
+ }
19833
+
19834
+ // ../../../node_modules/diff/libesm/patch/parse.js
19835
+ function parsePatch(uniDiff) {
19836
+ const diffstr = uniDiff.split(/\n/), list = [];
19837
+ let i = 0;
19838
+ function parseIndex() {
19839
+ const index = {};
19840
+ list.push(index);
19841
+ while (i < diffstr.length) {
19842
+ const line = diffstr[i];
19843
+ if (/^(---|\+\+\+|@@)\s/.test(line)) {
19844
+ break;
19743
19845
  }
19744
- if (!cancellationSettled(response, active.terminalEnd)) {
19745
- active.settlement = "pending";
19746
- active.cancellationRecheck = setTimeout(() => {
19747
- active.cancellationRecheck = null;
19748
- void this.#confirmCancelledTurn(active);
19749
- }, 250);
19750
- return;
19846
+ const header = /^(?:Index:|diff(?: -r \w+)+)\s+(.+?)\s*$/.exec(line);
19847
+ if (header) {
19848
+ index.index = header[1];
19849
+ }
19850
+ i++;
19851
+ }
19852
+ parseFileHeader(index);
19853
+ parseFileHeader(index);
19854
+ index.hunks = [];
19855
+ while (i < diffstr.length) {
19856
+ const line = diffstr[i];
19857
+ if (/^(Index:\s|diff\s|---\s|\+\+\+\s|===================================================================)/.test(line)) {
19858
+ break;
19859
+ } else if (/^@@/.test(line)) {
19860
+ index.hunks.push(parseHunk());
19861
+ } else if (line) {
19862
+ throw new Error("Unknown line " + (i + 1) + " " + JSON.stringify(line));
19863
+ } else {
19864
+ i++;
19751
19865
  }
19752
- this.#state = state;
19753
- active.settlement = "confirmed";
19754
- this.#finishSettledTurn(active);
19755
- } catch (error51) {
19756
- if (this.#activeTurn !== active)
19757
- return;
19758
- const fault = error51 instanceof OmpRpcFaultError ? error51 : new OmpRpcFaultError("protocolError", `Omp RPC cancelled Turn state could not be confirmed: ${message2(error51)}`);
19759
- this.#terminateFailedCancellation(active, fault);
19760
- } finally {
19761
- active.cancellationChecking = false;
19762
19866
  }
19763
19867
  }
19764
- #settleLocalTurn(active, result) {
19765
- if (this.#activeTurn !== active || active.settlement !== "pending")
19766
- return;
19767
- active.localResult = result;
19768
- active.settlement = "confirming";
19769
- void this.#confirmSettledTurn(active);
19770
- }
19771
- async #confirmSettledTurn(active) {
19772
- try {
19773
- const response = await this.#send("get_state", {});
19774
- const state = parseSessionState(response);
19775
- if (this.#activeTurn !== active)
19776
- return;
19777
- if (active.cancellation !== "none") {
19778
- active.settlement = "pending";
19779
- if (active.cancellation === "accepted")
19780
- void this.#confirmCancelledTurn(active);
19781
- return;
19868
+ function parseFileHeader(index) {
19869
+ const fileHeader = /^(---|\+\+\+)\s+(.*)\r?$/.exec(diffstr[i]);
19870
+ if (fileHeader) {
19871
+ const data = fileHeader[2].split(" ", 2), header = (data[1] || "").trim();
19872
+ let fileName = data[0].replace(/\\\\/g, "\\");
19873
+ if (/^".*"$/.test(fileName)) {
19874
+ fileName = fileName.substr(1, fileName.length - 2);
19782
19875
  }
19783
- if (parseSessionStreaming(response)) {
19784
- throw new OmpRpcFaultError("protocolError", "Omp RPC completed Turn state is still Streaming");
19876
+ if (fileHeader[1] === "---") {
19877
+ index.oldFileName = fileName;
19878
+ index.oldHeader = header;
19879
+ } else {
19880
+ index.newFileName = fileName;
19881
+ index.newHeader = header;
19785
19882
  }
19786
- this.#state = state;
19787
- active.settlement = "confirmed";
19788
- this.#finishSettledTurn(active);
19789
- } catch (error51) {
19790
- if (this.#activeTurn !== active)
19791
- return;
19792
- const fault = error51 instanceof OmpRpcFaultError ? error51 : new OmpRpcFaultError("protocolError", `Omp RPC stable Turn state could not be confirmed: ${message2(error51)}`);
19793
- this.#fail(fault);
19883
+ i++;
19794
19884
  }
19795
19885
  }
19796
- #finishSettledTurn(active) {
19797
- if (this.#activeTurn !== active || active.settlement !== "confirmed" || active.cancellation === "requesting") {
19798
- return;
19886
+ function parseHunk() {
19887
+ var _a3;
19888
+ const chunkHeaderIndex = i, chunkHeaderLine = diffstr[i++], chunkHeader = chunkHeaderLine.split(/@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/);
19889
+ const hunk = {
19890
+ oldStart: +chunkHeader[1],
19891
+ oldLines: typeof chunkHeader[2] === "undefined" ? 1 : +chunkHeader[2],
19892
+ newStart: +chunkHeader[3],
19893
+ newLines: typeof chunkHeader[4] === "undefined" ? 1 : +chunkHeader[4],
19894
+ lines: []
19895
+ };
19896
+ if (hunk.oldLines === 0) {
19897
+ hunk.oldStart += 1;
19799
19898
  }
19800
- if (active.cancellationTimeout)
19801
- clearTimeout(active.cancellationTimeout);
19802
- active.cancellationTimeout = null;
19803
- if (active.cancellationRecheck)
19804
- clearTimeout(active.cancellationRecheck);
19805
- active.cancellationRecheck = null;
19806
- this.#closeInteractions(active, active.cancellation === "accepted" ? "cancelled" : "superseded");
19807
- if (active.tools.size > 0) {
19808
- this.#fail(new OmpRpcFaultError("protocolError", "Omp RPC settled with active Tool executions"));
19809
- return;
19899
+ if (hunk.newLines === 0) {
19900
+ hunk.newStart += 1;
19810
19901
  }
19811
- this.#activeTurn = null;
19812
- if (active.localResult) {
19813
- active.resolve({
19814
- text: active.text,
19815
- agentInvoked: false,
19816
- ...active.localResult,
19817
- cancelled: active.localResult.cancelled || active.cancellation === "accepted"
19818
- });
19819
- } else if (active.cancellation === "accepted") {
19820
- active.resolve({ text: active.text, cancelled: true, agentInvoked: true });
19821
- } else if (active.failure) {
19822
- active.reject(active.failure);
19823
- } else if (active.text.trim().length === 0 && !active.sawTool) {
19824
- active.reject(new Error("Omp RPC settled without displayable output"));
19825
- } else {
19826
- active.resolve({ text: active.text, cancelled: false, agentInvoked: true });
19902
+ let addCount = 0, removeCount = 0;
19903
+ for (; i < diffstr.length && (removeCount < hunk.oldLines || addCount < hunk.newLines || ((_a3 = diffstr[i]) === null || _a3 === void 0 ? void 0 : _a3.startsWith("\\"))); i++) {
19904
+ const operation = diffstr[i].length == 0 && i != diffstr.length - 1 ? " " : diffstr[i][0];
19905
+ if (operation === "+" || operation === "-" || operation === " " || operation === "\\") {
19906
+ hunk.lines.push(diffstr[i]);
19907
+ if (operation === "+") {
19908
+ addCount++;
19909
+ } else if (operation === "-") {
19910
+ removeCount++;
19911
+ } else if (operation === " ") {
19912
+ addCount++;
19913
+ removeCount++;
19914
+ }
19915
+ } else {
19916
+ throw new Error(`Hunk at line ${chunkHeaderIndex + 1} contained invalid line ${diffstr[i]}`);
19917
+ }
19827
19918
  }
19828
- }
19829
- #startAssistantMessage(active, value) {
19830
- if (active.assistantMessageId !== null && active.reasoningMessageOpen) {
19831
- active.onEvent({ type: "reasoning.completed", messageId: active.assistantMessageId });
19919
+ if (!addCount && hunk.newLines === 1) {
19920
+ hunk.newLines = 0;
19832
19921
  }
19833
- const messageId = assistantMessageId(value) ?? randomUUID();
19834
- active.assistantMessageId = messageId;
19835
- active.sawStreamedMessageText = false;
19836
- active.sawStreamedMessageReasoning = false;
19837
- active.reasoningMessageOpen = false;
19838
- return messageId;
19922
+ if (!removeCount && hunk.oldLines === 1) {
19923
+ hunk.oldLines = 0;
19924
+ }
19925
+ if (addCount !== hunk.newLines) {
19926
+ throw new Error("Added line count did not match for hunk at line " + (chunkHeaderIndex + 1));
19927
+ }
19928
+ if (removeCount !== hunk.oldLines) {
19929
+ throw new Error("Removed line count did not match for hunk at line " + (chunkHeaderIndex + 1));
19930
+ }
19931
+ return hunk;
19839
19932
  }
19840
- #ensureAssistantMessage(active, value) {
19841
- return active.assistantMessageId ?? this.#startAssistantMessage(active, value);
19933
+ while (i < diffstr.length) {
19934
+ parseIndex();
19842
19935
  }
19843
- #finalizeAssistantMessage(active, value) {
19844
- const finalText = assistantText(value);
19845
- const finalReasoning = assistantReasoning(value);
19846
- const failure = assistantFailure(value);
19847
- const cacheHitRatePercent = optionalOmpCacheHitRatePercent(value);
19848
- if (finalText === null || finalReasoning === null || failure === void 0)
19849
- return;
19850
- if (active.assistantMessageId === null && finalText === active.lastFinalizedMessageText && finalReasoning === active.lastFinalizedMessageReasoning && !active.sawStreamedMessageText && !active.sawStreamedMessageReasoning) {
19936
+ return list;
19937
+ }
19938
+
19939
+ // ../../../node_modules/diff/libesm/patch/create.js
19940
+ function structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {
19941
+ let optionsObj;
19942
+ if (!options) {
19943
+ optionsObj = {};
19944
+ } else if (typeof options === "function") {
19945
+ optionsObj = { callback: options };
19946
+ } else {
19947
+ optionsObj = options;
19948
+ }
19949
+ if (typeof optionsObj.context === "undefined") {
19950
+ optionsObj.context = 4;
19951
+ }
19952
+ const context = optionsObj.context;
19953
+ if (optionsObj.newlineIsToken) {
19954
+ throw new Error("newlineIsToken may not be used with patch-generation functions, only with diffing functions");
19955
+ }
19956
+ if (!optionsObj.callback) {
19957
+ return diffLinesResultToPatch(diffLines(oldStr, newStr, optionsObj));
19958
+ } else {
19959
+ const { callback } = optionsObj;
19960
+ diffLines(oldStr, newStr, Object.assign(Object.assign({}, optionsObj), { callback: (diff) => {
19961
+ const patch = diffLinesResultToPatch(diff);
19962
+ callback(patch);
19963
+ } }));
19964
+ }
19965
+ function diffLinesResultToPatch(diff) {
19966
+ if (!diff) {
19851
19967
  return;
19852
19968
  }
19853
- active.failure = failure;
19854
- this.#latestCacheHitRatePercent = cacheHitRatePercent;
19855
- const messageId = this.#ensureAssistantMessage(active, value);
19856
- if (!active.sawStreamedMessageReasoning && finalReasoning.length > 0) {
19857
- active.reasoningMessageOpen = true;
19858
- active.onEvent({ type: "reasoning.delta", messageId, delta: finalReasoning });
19969
+ diff.push({ value: "", lines: [] });
19970
+ function contextLines(lines) {
19971
+ return lines.map(function(entry) {
19972
+ return " " + entry;
19973
+ });
19859
19974
  }
19860
- if (active.reasoningMessageOpen && active.failure === null) {
19861
- active.onEvent({ type: "reasoning.completed", messageId });
19975
+ const hunks = [];
19976
+ let oldRangeStart = 0, newRangeStart = 0, curRange = [], oldLine = 1, newLine = 1;
19977
+ for (let i = 0; i < diff.length; i++) {
19978
+ const current = diff[i], lines = current.lines || splitLines(current.value);
19979
+ current.lines = lines;
19980
+ if (current.added || current.removed) {
19981
+ if (!oldRangeStart) {
19982
+ const prev = diff[i - 1];
19983
+ oldRangeStart = oldLine;
19984
+ newRangeStart = newLine;
19985
+ if (prev) {
19986
+ curRange = context > 0 ? contextLines(prev.lines.slice(-context)) : [];
19987
+ oldRangeStart -= curRange.length;
19988
+ newRangeStart -= curRange.length;
19989
+ }
19990
+ }
19991
+ for (const line of lines) {
19992
+ curRange.push((current.added ? "+" : "-") + line);
19993
+ }
19994
+ if (current.added) {
19995
+ newLine += lines.length;
19996
+ } else {
19997
+ oldLine += lines.length;
19998
+ }
19999
+ } else {
20000
+ if (oldRangeStart) {
20001
+ if (lines.length <= context * 2 && i < diff.length - 2) {
20002
+ for (const line of contextLines(lines)) {
20003
+ curRange.push(line);
20004
+ }
20005
+ } else {
20006
+ const contextSize = Math.min(lines.length, context);
20007
+ for (const line of contextLines(lines.slice(0, contextSize))) {
20008
+ curRange.push(line);
20009
+ }
20010
+ const hunk = {
20011
+ oldStart: oldRangeStart,
20012
+ oldLines: oldLine - oldRangeStart + contextSize,
20013
+ newStart: newRangeStart,
20014
+ newLines: newLine - newRangeStart + contextSize,
20015
+ lines: curRange
20016
+ };
20017
+ hunks.push(hunk);
20018
+ oldRangeStart = 0;
20019
+ newRangeStart = 0;
20020
+ curRange = [];
20021
+ }
20022
+ }
20023
+ oldLine += lines.length;
20024
+ newLine += lines.length;
20025
+ }
20026
+ }
20027
+ for (const hunk of hunks) {
20028
+ for (let i = 0; i < hunk.lines.length; i++) {
20029
+ if (hunk.lines[i].endsWith("\n")) {
20030
+ hunk.lines[i] = hunk.lines[i].slice(0, -1);
20031
+ } else {
20032
+ hunk.lines.splice(i + 1, 0, "\");
20033
+ i++;
20034
+ }
20035
+ }
20036
+ }
20037
+ return {
20038
+ oldFileName,
20039
+ newFileName,
20040
+ oldHeader,
20041
+ newHeader,
20042
+ hunks
20043
+ };
20044
+ }
20045
+ }
20046
+ function formatPatch(patch) {
20047
+ if (Array.isArray(patch)) {
20048
+ return patch.map(formatPatch).join("\n");
20049
+ }
20050
+ const ret = [];
20051
+ if (patch.oldFileName == patch.newFileName) {
20052
+ ret.push("Index: " + patch.oldFileName);
20053
+ }
20054
+ ret.push("===================================================================");
20055
+ ret.push("--- " + patch.oldFileName + (typeof patch.oldHeader === "undefined" ? "" : " " + patch.oldHeader));
20056
+ ret.push("+++ " + patch.newFileName + (typeof patch.newHeader === "undefined" ? "" : " " + patch.newHeader));
20057
+ for (let i = 0; i < patch.hunks.length; i++) {
20058
+ const hunk = patch.hunks[i];
20059
+ if (hunk.oldLines === 0) {
20060
+ hunk.oldStart -= 1;
19862
20061
  }
19863
- if (!active.sawStreamedMessageText && finalText.length > 0) {
19864
- active.text += finalText;
19865
- active.onEvent({ type: "text.delta", messageId, delta: finalText });
20062
+ if (hunk.newLines === 0) {
20063
+ hunk.newStart -= 1;
19866
20064
  }
19867
- active.assistantMessageId = null;
19868
- active.sawStreamedMessageText = false;
19869
- active.sawStreamedMessageReasoning = false;
19870
- active.reasoningMessageOpen = false;
19871
- active.lastFinalizedMessageText = finalText;
19872
- active.lastFinalizedMessageReasoning = finalReasoning;
19873
- active.onEvent({ type: "message.completed", messageId });
19874
- }
19875
- #write(value) {
19876
- const child = this.#child;
19877
- if (!child?.stdin.writable || this.#closed || this.#failed) {
19878
- return Promise.reject(new Error("Omp RPC stdin is unavailable"));
20065
+ ret.push("@@ -" + hunk.oldStart + "," + hunk.oldLines + " +" + hunk.newStart + "," + hunk.newLines + " @@");
20066
+ for (const line of hunk.lines) {
20067
+ ret.push(line);
19879
20068
  }
19880
- return new Promise((resolve, reject) => {
19881
- const frame = Buffer.from(`${JSON.stringify(value)}
19882
- `, "utf8");
19883
- child.stdin.write(frame, (error51) => error51 ? reject(error51) : resolve());
19884
- });
19885
20069
  }
19886
- #send(type, payload, id = `codexhost-${randomUUID()}`) {
19887
- const child = this.#child;
19888
- if (!child?.stdin.writable || this.#closed || this.#failed) {
19889
- return Promise.reject(new Error("Omp RPC stdin is unavailable"));
19890
- }
19891
- return new Promise((resolve, reject) => {
19892
- const pending = {
19893
- command: type,
19894
- resolve,
19895
- reject,
19896
- timeout: null
19897
- };
19898
- this.#pending.set(id, pending);
19899
- this.#armCommandTimeout(id, pending);
19900
- const frame = Buffer.from(`${JSON.stringify({ id, type, ...payload })}
19901
- `, "utf8");
19902
- child.stdin.write(frame, (error51) => {
19903
- if (error51) {
19904
- if (pending.timeout)
19905
- clearTimeout(pending.timeout);
19906
- this.#pending.delete(id);
19907
- reject(error51);
19908
- }
19909
- });
19910
- });
20070
+ return ret.join("\n") + "\n";
20071
+ }
20072
+ function createTwoFilesPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {
20073
+ if (typeof options === "function") {
20074
+ options = { callback: options };
19911
20075
  }
19912
- #armCommandTimeout(id, pending) {
19913
- if (pending.timeout || this.#pending.get(id) !== pending || (pending.command === "prompt" || pending.command === "compact") && this.#compactionActive) {
20076
+ if (!(options === null || options === void 0 ? void 0 : options.callback)) {
20077
+ const patchObj = structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options);
20078
+ if (!patchObj) {
19914
20079
  return;
19915
20080
  }
19916
- pending.timeout = setTimeout(() => {
19917
- if (this.#pending.get(id) !== pending)
19918
- return;
19919
- pending.timeout = null;
19920
- const error51 = new Error(`Omp RPC '${pending.command}' command timed out`);
19921
- if (pending.command !== "prompt") {
19922
- this.#pending.delete(id);
19923
- pending.reject(error51);
19924
- return;
20081
+ return formatPatch(patchObj);
20082
+ } else {
20083
+ const { callback } = options;
20084
+ structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, Object.assign(Object.assign({}, options), { callback: (patchObj) => {
20085
+ if (!patchObj) {
20086
+ callback(void 0);
20087
+ } else {
20088
+ callback(formatPatch(patchObj));
19925
20089
  }
19926
- const fault = new OmpRpcFaultError("protocolError", error51.message);
19927
- void this.#terminateTimedOutPrompt(fault);
19928
- }, this.#options.commandTimeoutMs);
20090
+ } }));
19929
20091
  }
19930
- async #terminateTimedOutPrompt(fault) {
19931
- if (this.#closed || this.#failed)
19932
- return;
19933
- this.#failed = true;
19934
- this.#closed = true;
19935
- for (const pending of this.#pending.values()) {
19936
- if (pending.timeout)
19937
- clearTimeout(pending.timeout);
19938
- pending.timeout = null;
19939
- }
19940
- let finalFault = fault;
19941
- try {
19942
- await this.close();
19943
- } catch (error51) {
19944
- finalFault = new OmpRpcFaultError("processExited", `Omp RPC timed-out Prompt cleanup failed: ${message2(error51)}`);
19945
- }
19946
- this.#rejectAll(finalFault);
19947
- this.#options.onFault?.(finalFault);
20092
+ }
20093
+ function splitLines(text) {
20094
+ const hasTrailingNl = text.endsWith("\n");
20095
+ const result = text.split("\n").map((line) => line + "\n");
20096
+ if (hasTrailingNl) {
20097
+ result.pop();
20098
+ } else {
20099
+ result.push(result.pop().slice(0, -1));
19948
20100
  }
19949
- #closeInteractions(active, reason) {
19950
- for (const [requestId2, pending] of active.interactions) {
19951
- active.interactions.delete(requestId2);
19952
- if (pending.timeout)
19953
- clearTimeout(pending.timeout);
19954
- active.onEvent({ type: "interaction.closed", requestId: requestId2, reason });
19955
- }
20101
+ return result;
20102
+ }
20103
+
20104
+ // dist/omp-adapter.js
20105
+ import { randomUUID as randomUUID2 } from "node:crypto";
20106
+ import { realpath as realpath3, stat as stat2 } from "node:fs/promises";
20107
+ import path7 from "node:path";
20108
+
20109
+ // dist/omp-last-turn-rollback.js
20110
+ function modelFromState(state) {
20111
+ if (state.provider === null && state.modelId === null)
20112
+ return null;
20113
+ if (state.provider === null || state.modelId === null) {
20114
+ throw new Error("Omp state contains a partial Model identity");
19956
20115
  }
19957
- #rejectActiveTurn(error51) {
19958
- const active = this.#activeTurn;
19959
- if (!active)
19960
- return;
19961
- if (active.cancellationTimeout)
19962
- clearTimeout(active.cancellationTimeout);
19963
- if (active.cancellationRecheck)
19964
- clearTimeout(active.cancellationRecheck);
19965
- this.#closeInteractions(active, "cancelled");
19966
- this.#activeTurn = null;
19967
- active.reject(error51);
20116
+ return { provider: state.provider, id: state.modelId };
20117
+ }
20118
+ async function rollbackOmpLastTurn(transport, sourceSessionId, cwd) {
20119
+ const startupState = transport.state;
20120
+ const startupSessionId = startupState.sessionId;
20121
+ const currentModel = modelFromState(startupState);
20122
+ const currentThinking = startupState.thinkingLevel;
20123
+ const copiedHistory = await transport.getEntries();
20124
+ const boundary = resolveOmpLastTurnBoundary(copiedHistory);
20125
+ if (!boundary)
20126
+ return { ok: false, reason: "empty" };
20127
+ const sourceSnapshot = mapOmpSnapshot(copiedHistory, {
20128
+ sessionId: startupSessionId,
20129
+ model: currentModel
20130
+ });
20131
+ let state = await transport.fork(boundary.lastUserEntryId);
20132
+ if (state.sessionId === sourceSessionId || state.sessionId === startupSessionId) {
20133
+ throw new Error("Omp last-Turn rollback did not create a distinct Native Session");
19968
20134
  }
19969
- #rejectAll(error51) {
19970
- if (this.#compactionTimeout)
19971
- clearTimeout(this.#compactionTimeout);
19972
- this.#compactionTimeout = null;
19973
- for (const pending of this.#pending.values()) {
19974
- if (pending.timeout)
19975
- clearTimeout(pending.timeout);
19976
- pending.reject(error51);
19977
- }
19978
- this.#pending.clear();
19979
- const manual = this.#manualCompaction;
19980
- this.#manualCompaction = null;
19981
- manual?.reject(error51);
19982
- this.#rejectActiveTurn(error51);
20135
+ if (!sameOmpModel(modelFromState(state), currentModel)) {
20136
+ if (!currentModel)
20137
+ throw new Error("Omp last-Turn rollback changed the current Model");
20138
+ state = await transport.selectModel(currentModel);
19983
20139
  }
19984
- #fail(error51) {
19985
- if (this.#closed || this.#failed)
19986
- return;
19987
- this.#failed = true;
19988
- this.#startupFaultResolve?.(error51);
19989
- this.#startupFaultResolve = null;
19990
- this.#rejectAll(error51);
19991
- this.#options.onFault?.(error51);
20140
+ if (state.thinkingLevel !== currentThinking) {
20141
+ if (!currentThinking)
20142
+ throw new Error("Omp last-Turn rollback changed current Thinking");
20143
+ state = await transport.selectThinkingOption(currentThinking);
19992
20144
  }
19993
- };
20145
+ if (!sameOmpModel(modelFromState(state), currentModel) || state.thinkingLevel !== currentThinking) {
20146
+ throw new Error("Omp last-Turn rollback could not restore current Model and Thinking");
20147
+ }
20148
+ const snapshot = mapOmpSnapshot(await transport.getEntries(), {
20149
+ sessionId: state.sessionId,
20150
+ model: modelFromState(state)
20151
+ });
20152
+ const expectedTurnKeys = sourceSnapshot.turns.slice(0, -1).map((turn) => turn.nativeTurnRef.nativeTurnKey);
20153
+ const actualTurnKeys = snapshot.turns.map((turn) => turn.nativeTurnRef.nativeTurnKey);
20154
+ if (snapshot.turns.length !== boundary.sourceTurnCount - 1 || actualTurnKeys.some((key, index) => key !== expectedTurnKeys[index])) {
20155
+ throw new Error("Omp last-Turn rollback did not produce the exact retained history prefix");
20156
+ }
20157
+ await transport.verifySessionCwd(cwd);
20158
+ return { ok: true };
20159
+ }
19994
20160
 
19995
20161
  // dist/omp-permission-modes.js
19996
20162
  var nativePermissionModes = /* @__PURE__ */ new Set(["always-ask", "write", "yolo"]);
@@ -20143,6 +20309,24 @@ var OmpSubagentLifecycle = class {
20143
20309
  };
20144
20310
 
20145
20311
  // dist/omp-adapter.js
20312
+ function closedInspection() {
20313
+ return {
20314
+ status: "unavailable",
20315
+ error: { code: "invalidState", message: "Omp Adapter is closed", retryable: false }
20316
+ };
20317
+ }
20318
+ function ompInspectionCapabilities(selectThinkingOption) {
20319
+ return {
20320
+ configuration: {
20321
+ selectModel: true,
20322
+ selectThinkingOption,
20323
+ selectPermissionMode: true,
20324
+ permissionModeScope: "live"
20325
+ },
20326
+ history: { fork: true, forkAcrossCwd: true, rollbackLastTurn: true },
20327
+ subagents: { observe: true, readTranscript: true }
20328
+ };
20329
+ }
20146
20330
  var ompHarnessId2 = harnessIdSchema.parse("omp");
20147
20331
  var ompCommandCatalog = harnessCommandCatalogSchema.parse({
20148
20332
  commands: [
@@ -20157,7 +20341,7 @@ var ompCommandCatalog = harnessCommandCatalogSchema.parse({
20157
20341
  ]
20158
20342
  });
20159
20343
  var DEFAULT_TOOL_OUTPUT_LIMIT = 64e3;
20160
- function isRecord9(value) {
20344
+ function isRecord10(value) {
20161
20345
  return typeof value === "object" && value !== null && !Array.isArray(value);
20162
20346
  }
20163
20347
  function errorMessage(error51) {
@@ -20172,7 +20356,7 @@ var OmpAdapterFaultError = class extends Error {
20172
20356
  }
20173
20357
  };
20174
20358
  function normalizedError(error51, fallbackCode) {
20175
- if (isRecord9(error51) && error51.code === "ENOENT") {
20359
+ if (isRecord10(error51) && error51.code === "ENOENT") {
20176
20360
  return { code: "notInstalled", message: errorMessage(error51), retryable: false };
20177
20361
  }
20178
20362
  if (error51 instanceof OmpAdapterFaultError)
@@ -20249,7 +20433,7 @@ function nativeModelForHistory(state) {
20249
20433
  return nativeModelFromState(state);
20250
20434
  }
20251
20435
  function sessionFileFromRef(ref) {
20252
- if (ref.harnessId !== ompHarnessId2 || !isRecord9(ref.locator) || typeof ref.locator.sessionFile !== "string" || ref.locator.sessionFile.length === 0) {
20436
+ if (ref.harnessId !== ompHarnessId2 || !isRecord10(ref.locator) || typeof ref.locator.sessionFile !== "string" || ref.locator.sessionFile.length === 0) {
20253
20437
  throw new Error("Omp Native Session Ref has no resumable Session file");
20254
20438
  }
20255
20439
  return ref.locator.sessionFile;
@@ -20304,9 +20488,9 @@ function toolFailure(toolName) {
20304
20488
  function nativeText(value) {
20305
20489
  if (typeof value === "string")
20306
20490
  return value;
20307
- if (!isRecord9(value) || !Array.isArray(value.content))
20491
+ if (!isRecord10(value) || !Array.isArray(value.content))
20308
20492
  return "";
20309
- return value.content.filter((content) => isRecord9(content) && content.type === "text" && typeof content.text === "string").map(({ text }) => text).join("");
20493
+ return value.content.filter((content) => isRecord10(content) && content.type === "text" && typeof content.text === "string").map(({ text }) => text).join("");
20310
20494
  }
20311
20495
  function boundedOutput(value, limit) {
20312
20496
  const text = nativeText(value);
@@ -20322,17 +20506,17 @@ function outputText(output) {
20322
20506
  return output?.content.filter((content) => content.type === "text").map(({ text }) => text).join("") ?? "";
20323
20507
  }
20324
20508
  function stringField2(value, key) {
20325
- if (!isRecord9(value))
20509
+ if (!isRecord10(value))
20326
20510
  return void 0;
20327
20511
  const field = value[key];
20328
20512
  if (typeof field === "string" && field.length > 0)
20329
20513
  return field;
20330
- if (isRecord9(value.input)) {
20514
+ if (isRecord10(value.input)) {
20331
20515
  const nested = value.input[key];
20332
20516
  if (typeof nested === "string" && nested.length > 0)
20333
20517
  return nested;
20334
20518
  }
20335
- if (isRecord9(value.arguments)) {
20519
+ if (isRecord10(value.arguments)) {
20336
20520
  const nested = value.arguments[key];
20337
20521
  if (typeof nested === "string" && nested.length > 0)
20338
20522
  return nested;
@@ -20340,7 +20524,7 @@ function stringField2(value, key) {
20340
20524
  return void 0;
20341
20525
  }
20342
20526
  function numberField(value, key) {
20343
- if (!isRecord9(value))
20527
+ if (!isRecord10(value))
20344
20528
  return void 0;
20345
20529
  const field = value[key];
20346
20530
  return typeof field === "number" || field === null ? field : void 0;
@@ -20379,7 +20563,7 @@ function fileMutatingKind(toolName) {
20379
20563
  return null;
20380
20564
  }
20381
20565
  function nestedToolString(value, keys) {
20382
- if (!isRecord9(value))
20566
+ if (!isRecord10(value))
20383
20567
  return void 0;
20384
20568
  for (const key of keys) {
20385
20569
  const field = value[key];
@@ -20394,14 +20578,14 @@ function nestedToolString(value, keys) {
20394
20578
  return void 0;
20395
20579
  }
20396
20580
  function patchFromResult(result) {
20397
- if (!isRecord9(result))
20581
+ if (!isRecord10(result))
20398
20582
  return void 0;
20399
20583
  for (const key of ["patch", "diff", "unifiedDiff"]) {
20400
20584
  const field = result[key];
20401
20585
  if (typeof field === "string" && field.length > 0)
20402
20586
  return field;
20403
20587
  }
20404
- if (isRecord9(result.details)) {
20588
+ if (isRecord10(result.details)) {
20405
20589
  for (const key of ["patch", "diff", "unifiedDiff"]) {
20406
20590
  const field = result.details[key];
20407
20591
  if (typeof field === "string" && field.length > 0)
@@ -21976,6 +22160,9 @@ var OmpAdapter = class {
21976
22160
  #inspectionCache = /* @__PURE__ */ new Map();
21977
22161
  #inspectionInFlight = /* @__PURE__ */ new Map();
21978
22162
  #inspections = /* @__PURE__ */ new Set();
22163
+ #availabilityInFlight = /* @__PURE__ */ new Map();
22164
+ #availabilityListings = /* @__PURE__ */ new Set();
22165
+ #listModels;
21979
22166
  #sessions = /* @__PURE__ */ new Set();
21980
22167
  #toolOutputLimit;
21981
22168
  #closePromise = null;
@@ -21984,22 +22171,21 @@ var OmpAdapter = class {
21984
22171
  createTransport: (sessionOptions) => new OmpRpcSession({ ...options, ...sessionOptions })
21985
22172
  }) {
21986
22173
  this.#createTransport = dependencies.createTransport;
22174
+ const listModels = dependencies.listModels ?? listOmpModels;
22175
+ this.#listModels = ({ cwd, signal }) => listModels({
22176
+ cwd,
22177
+ signal,
22178
+ ...options.command ? { command: options.command } : {},
22179
+ ...options.environment ? { environment: options.environment } : {}
22180
+ });
21987
22181
  this.sessionImport = new OmpSessionImport({ ...process.env, ...options.environment });
21988
22182
  this.usageStatistics = createOmpUsageStatistics({ ...process.env, ...options.environment });
21989
22183
  this.#closeTimeoutMs = options.closeTimeoutMs ?? 2e3;
21990
22184
  this.#toolOutputLimit = options.toolOutputLimit ?? DEFAULT_TOOL_OUTPUT_LIMIT;
21991
22185
  }
21992
22186
  async inspect(input = {}) {
21993
- if (this.#closePromise) {
21994
- return {
21995
- status: "unavailable",
21996
- error: {
21997
- code: "invalidState",
21998
- message: "Omp Adapter is closed",
21999
- retryable: false
22000
- }
22001
- };
22002
- }
22187
+ if (this.#closePromise)
22188
+ return closedInspection();
22003
22189
  const cwd = input.cwd ?? process.cwd();
22004
22190
  const inFlight = this.#inspectionInFlight.get(cwd);
22005
22191
  if (inFlight)
@@ -22009,6 +22195,37 @@ var OmpAdapter = class {
22009
22195
  if (cached2)
22010
22196
  return cached2;
22011
22197
  }
22198
+ if (input.purpose === "availability")
22199
+ return this.#inspectAvailability(cwd, input.refresh);
22200
+ return this.#startFullInspection(cwd);
22201
+ }
22202
+ /**
22203
+ * Availability without a Session: a Session startup runs OMP's own startup work, including
22204
+ * Provider connection prewarm, for a Harness the user may never select. The listed result
22205
+ * carries no native default Model or Thinking option, so it is neither cached nor used to
22206
+ * update `#thinkingSelectionSupported`. When the list cannot answer, a full inspection answers
22207
+ * instead, reusing one that is in flight or finished meanwhile.
22208
+ */
22209
+ async #inspectAvailability(cwd, refresh = false) {
22210
+ if (refresh)
22211
+ this.#inspectionCache.delete(cwd);
22212
+ let pending = this.#availabilityInFlight.get(cwd);
22213
+ if (!pending) {
22214
+ const listing = this.#listAvailability(cwd);
22215
+ pending = listing.finally(() => {
22216
+ if (this.#availabilityInFlight.get(cwd) === pending)
22217
+ this.#availabilityInFlight.delete(cwd);
22218
+ });
22219
+ this.#availabilityInFlight.set(cwd, pending);
22220
+ }
22221
+ const listed = await pending;
22222
+ if (listed)
22223
+ return listed;
22224
+ if (this.#closePromise)
22225
+ return closedInspection();
22226
+ return this.#inspectionInFlight.get(cwd) ?? this.#inspectionCache.get(cwd) ?? this.#startFullInspection(cwd);
22227
+ }
22228
+ #startFullInspection(cwd) {
22012
22229
  const inspection = this.#inspectCwd(cwd).then((result) => {
22013
22230
  if (result.status === "ready")
22014
22231
  this.#inspectionCache.set(cwd, result);
@@ -22021,6 +22238,59 @@ var OmpAdapter = class {
22021
22238
  }
22022
22239
  });
22023
22240
  }
22241
+ /** Returns null when a Session must answer: this OMP cannot list Models, or lists none. */
22242
+ async #listAvailability(cwd) {
22243
+ const startedAt = Date.now();
22244
+ const stage = "model-list";
22245
+ const controller = new AbortController();
22246
+ this.#availabilityListings.add(controller);
22247
+ let listed;
22248
+ try {
22249
+ listed = await this.#listModels({ cwd, signal: controller.signal });
22250
+ } finally {
22251
+ this.#availabilityListings.delete(controller);
22252
+ }
22253
+ if (listed.kind === "unanswered")
22254
+ return null;
22255
+ if (listed.kind === "notInstalled") {
22256
+ return {
22257
+ status: "notInstalled",
22258
+ error: {
22259
+ code: "notInstalled",
22260
+ message: listed.message,
22261
+ retryable: false,
22262
+ stage,
22263
+ durationMs: Date.now() - startedAt
22264
+ }
22265
+ };
22266
+ }
22267
+ if (listed.kind === "timedOut") {
22268
+ return {
22269
+ status: "error",
22270
+ error: {
22271
+ code: "unavailable",
22272
+ message: "Oh My Pi did not list its models in time",
22273
+ retryable: true,
22274
+ stage,
22275
+ durationMs: Date.now() - startedAt
22276
+ }
22277
+ };
22278
+ }
22279
+ if (listed.models.length === 0)
22280
+ return null;
22281
+ let catalog;
22282
+ try {
22283
+ catalog = normalizeOmpModelCatalog(listed.models, null, null, null);
22284
+ } catch {
22285
+ return null;
22286
+ }
22287
+ return {
22288
+ status: "ready",
22289
+ catalog,
22290
+ permissionModes: OMP_PERMISSION_MODE_CATALOG,
22291
+ capabilities: ompInspectionCapabilities(false)
22292
+ };
22293
+ }
22024
22294
  async #inspectCwd(cwd) {
22025
22295
  const startedAt = Date.now();
22026
22296
  let stage = "spawn";
@@ -22044,16 +22314,7 @@ var OmpAdapter = class {
22044
22314
  status: "ready",
22045
22315
  catalog,
22046
22316
  permissionModes: OMP_PERMISSION_MODE_CATALOG,
22047
- capabilities: {
22048
- configuration: {
22049
- selectModel: true,
22050
- selectThinkingOption: thinkingLevels !== null,
22051
- selectPermissionMode: true,
22052
- permissionModeScope: "live"
22053
- },
22054
- history: { fork: true, forkAcrossCwd: true, rollbackLastTurn: true },
22055
- subagents: { observe: true, readTranscript: true }
22056
- }
22317
+ capabilities: ompInspectionCapabilities(thinkingLevels !== null)
22057
22318
  };
22058
22319
  } catch (error51) {
22059
22320
  await transport.close().catch(() => void 0);
@@ -22264,6 +22525,8 @@ var OmpAdapter = class {
22264
22525
  }
22265
22526
  close() {
22266
22527
  if (!this.#closePromise) {
22528
+ for (const listing of this.#availabilityListings)
22529
+ listing.abort();
22267
22530
  this.#closePromise = Promise.all([
22268
22531
  this.sessionImport.close(),
22269
22532
  ...[...this.#inspections].map((transport) => transport.close()),