@codexhost/cli-darwin-x64 0.13.3 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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;
@@ -15202,10 +15205,19 @@ var model = external_exports.string().min(1).max(512);
15202
15205
  var project = external_exports.string().min(1).max(4096);
15203
15206
  var usageStatisticsParamsSchema = external_exports.strictObject({
15204
15207
  range: external_exports.enum(USAGE_STATISTICS_RANGES),
15208
+ /** Display timezone for ranges, dates and hourly buckets; omitted means the Host's local zone. */
15209
+ timeZone: external_exports.string().min(1).max(128).refine((value) => {
15210
+ try {
15211
+ new Intl.DateTimeFormat("en", { timeZone: value });
15212
+ return true;
15213
+ } catch {
15214
+ return false;
15215
+ }
15216
+ }, "Unsupported usage statistics timezone").optional(),
15205
15217
  harness: harness.optional(),
15206
15218
  model: model.nullable().optional(),
15207
15219
  project: project.nullable().optional(),
15208
- /** One local date inside the range. */
15220
+ /** One date in the query timezone inside the range. */
15209
15221
  date: localDate.optional()
15210
15222
  });
15211
15223
  var usageStatisticsTotalsSchema = external_exports.strictObject({
@@ -15241,7 +15253,7 @@ var usageStatisticsSessionSchema = external_exports.strictObject({
15241
15253
  });
15242
15254
  var usageStatisticsResultSchema = external_exports.strictObject({
15243
15255
  range: external_exports.enum(USAGE_STATISTICS_RANGES),
15244
- /** First local date of the range; null for all time. */
15256
+ /** First date in the query timezone (Host local when omitted); null for all time. */
15245
15257
  from: localDate.nullable(),
15246
15258
  to: localDate,
15247
15259
  /** The filters these figures apply, echoed so a late answer to older filters is recognised. */
@@ -15281,7 +15293,7 @@ var usageStatisticsResultSchema = external_exports.strictObject({
15281
15293
  totals: usageStatisticsTotalsSchema,
15282
15294
  /** Each date and Harness of the range: every filter except the day. */
15283
15295
  daily: external_exports.array(external_exports.strictObject({ date: localDate, harness, ...totals })).max(2e5),
15284
- /** Local weekday (0 = Sunday) and hour, all filters applied. */
15296
+ /** Weekday (0 = Sunday) and hour in the query timezone, all filters applied. */
15285
15297
  hourly: external_exports.array(external_exports.strictObject({
15286
15298
  weekday: external_exports.number().int().min(0).max(6),
15287
15299
  hour: external_exports.number().int().min(0).max(23),
@@ -15341,6 +15353,8 @@ var CONSOLE_HOST_METHODS = Object.freeze([
15341
15353
  "codexhost/harness/display-settings/set",
15342
15354
  "codexhost/harness/inspect",
15343
15355
  "codexhost/harness/installation",
15356
+ "codexhost/harness/installation/start",
15357
+ "codexhost/harness/installation/status",
15344
15358
  "codexhost/harness/launch-settings/get",
15345
15359
  "codexhost/harness/launch-settings/set",
15346
15360
  "codexhost/harness/web-ui/open",
@@ -15416,7 +15430,18 @@ var threadManualCompactionStartedSchema = external_exports.strictObject({
15416
15430
  var nonNegativeSafeIntegerSchema = external_exports.number().int().safe().nonnegative();
15417
15431
  var finiteNonNegativeNumberSchema = external_exports.number().finite().nonnegative();
15418
15432
  var cacheHitRatePercentSchema = external_exports.number().finite().min(0).max(100);
15433
+ var indicatorTextSchema = (maximum) => harnessLocalizedTextSchema.refine((entries) => Object.values(entries).every((text) => text.length <= maximum));
15434
+ var composerIndicatorsSchema = external_exports.array(external_exports.object({
15435
+ kind: external_exports.literal("countdown"),
15436
+ id: external_exports.string().min(1).max(64),
15437
+ expiresAtUnix: nonNegativeSafeIntegerSchema,
15438
+ label: indicatorTextSchema(256).optional(),
15439
+ tooltip: indicatorTextSchema(1024).optional()
15440
+ }).strict()).max(2).refine((entries) => new Set(entries.map(({ id }) => id)).size === entries.length, {
15441
+ message: "Composer indicator IDs must be unique"
15442
+ });
15419
15443
  var threadUsageSnapshotSchema = external_exports.object({
15444
+ composerIndicators: composerIndicatorsSchema.optional(),
15420
15445
  inputTokens: nonNegativeSafeIntegerSchema.optional(),
15421
15446
  cachedInputTokens: nonNegativeSafeIntegerSchema.optional(),
15422
15447
  cacheWriteInputTokens: nonNegativeSafeIntegerSchema.optional(),
@@ -15824,7 +15849,9 @@ var harnessSessionCapabilitiesSchema = external_exports.object({
15824
15849
  }).strict().optional(),
15825
15850
  autonomousTurns: external_exports.object({
15826
15851
  observe: external_exports.boolean()
15827
- }).strict().optional()
15852
+ }).strict().optional(),
15853
+ /** True only when `turn.steer` delivers input into the active Turn through a native primitive. */
15854
+ steer: external_exports.boolean().optional()
15828
15855
  }).strict();
15829
15856
  var harnessConfigurationStateSchema = external_exports.object({
15830
15857
  effectiveModel: harnessModelRefSchema.optional(),
@@ -15871,7 +15898,9 @@ var harnessInspectionSchema = external_exports.union([
15871
15898
  var harnessInspectParamsSchema = external_exports.object({
15872
15899
  harnessId: harnessIdSchema,
15873
15900
  cwd: nonBlankTextSchema2.max(16384).optional(),
15874
- refresh: external_exports.boolean().optional()
15901
+ refresh: external_exports.boolean().optional(),
15902
+ /** `availability` asks only whether the Harness can run; see `InspectHarnessInput.purpose`. */
15903
+ purpose: external_exports.literal("availability").optional()
15875
15904
  }).strict();
15876
15905
  var harnessWebUiOpenParamsSchema = external_exports.object({
15877
15906
  harnessId: harnessIdSchema
@@ -15954,6 +15983,15 @@ var threadOwnershipListResultSchema = external_exports.object({
15954
15983
  seen.add(thread.threadId);
15955
15984
  }
15956
15985
  });
15986
+ var threadSteeringInspectParamsSchema = external_exports.object({
15987
+ threadId: hostThreadIdSchema,
15988
+ /** The text about to be steered; a Harness command always stops and restarts. */
15989
+ text: external_exports.string().optional()
15990
+ }).strict();
15991
+ var threadSteerDeliverySchema = external_exports.enum(["activeTurn", "newTurn"]);
15992
+ var threadSteeringInspectResultSchema = external_exports.object({
15993
+ delivery: external_exports.enum(["official", "activeTurn", "newTurn"])
15994
+ }).strict();
15957
15995
 
15958
15996
  // ../../shared-contracts/dist/harness-plugins.js
15959
15997
  var HARNESS_PLUGIN_MANIFEST_MAX_BYTES = 32 * 1024;
@@ -16055,6 +16093,10 @@ var harnessInstallationStateSchema = external_exports.object({
16055
16093
  latestVersion: external_exports.string().min(1).max(128),
16056
16094
  updateAvailable: external_exports.boolean(),
16057
16095
  canUpdate: external_exports.boolean(),
16096
+ /** Defaults to CLI; some Harnesses ship only inside a desktop application. */
16097
+ versionKind: external_exports.enum(["cli", "application"]).optional(),
16098
+ /** Official download opened by the user; does not imply an automatic installation. */
16099
+ manualUpdateUrl: external_exports.url().max(2048).refine((value) => /^https:\/\/[^/?#@]+(?:[/?#]|$)/iu.test(value), "Manual updates require a credential-free HTTPS URL").optional(),
16058
16100
  // Adapter-owned diagnostic text; UI uses messageCode rather than displaying it verbatim.
16059
16101
  message: external_exports.string().max(2048).optional(),
16060
16102
  messageCode: external_exports.string().min(1).max(128).optional(),
@@ -16062,6 +16104,20 @@ var harnessInstallationStateSchema = external_exports.object({
16062
16104
  notice: harnessLocalizedTextSchema.optional(),
16063
16105
  latestVersionKind: external_exports.enum(["unknown", "tracking-branch"]).optional()
16064
16106
  }).strict();
16107
+ var harnessInstallationTaskParamsSchema = external_exports.object({ taskId: external_exports.string().uuid() }).strict();
16108
+ var harnessInstallationTaskSchema = external_exports.discriminatedUnion("status", [
16109
+ external_exports.object({ taskId: external_exports.string().uuid(), status: external_exports.literal("running") }).strict(),
16110
+ external_exports.object({
16111
+ taskId: external_exports.string().uuid(),
16112
+ status: external_exports.literal("succeeded"),
16113
+ result: harnessInstallationStateSchema
16114
+ }).strict(),
16115
+ external_exports.object({
16116
+ taskId: external_exports.string().uuid(),
16117
+ status: external_exports.literal("failed"),
16118
+ error: external_exports.object({ code: external_exports.number().int(), message: external_exports.string().min(1).max(2048) }).strict()
16119
+ }).strict()
16120
+ ]);
16065
16121
 
16066
16122
  // ../../shared-contracts/dist/codex-accounts.js
16067
16123
  var accountIdSchema = external_exports.string().min(1).max(256).regex(/^[A-Za-z0-9._~-]+$/u);
@@ -16863,6 +16919,18 @@ function sanitizeDiagnosticTail(value) {
16863
16919
  return redacted.length <= DIAGNOSTIC_TAIL_MAX_LENGTH ? redacted : redacted.slice(-DIAGNOSTIC_TAIL_MAX_LENGTH);
16864
16920
  }
16865
16921
 
16922
+ // ../../harness-adapter/dist/steer.js
16923
+ function unsupportedSteer(harnessLabel) {
16924
+ return {
16925
+ ok: false,
16926
+ error: {
16927
+ code: "unsupported",
16928
+ message: `${harnessLabel} cannot steer an active Turn natively`,
16929
+ retryable: false
16930
+ }
16931
+ };
16932
+ }
16933
+
16866
16934
  // ../../harness-adapter/dist/usage.js
16867
16935
  var tokenFields = [
16868
16936
  "inputTokens",
@@ -16890,6 +16958,7 @@ var usageFields = /* @__PURE__ */ new Set([
16890
16958
  ...safeIntegerFields,
16891
16959
  ...percentFields,
16892
16960
  "sessionCacheUsage",
16961
+ "composerIndicators",
16893
16962
  "totalCostUsd",
16894
16963
  "totalCredits",
16895
16964
  "contextUsagePercent",
@@ -16912,6 +16981,7 @@ function parseHostUsage(value) {
16912
16981
  throw new Error(`Harness Usage contains unknown field '${key}'`);
16913
16982
  }
16914
16983
  }
16984
+ const indicators = value.composerIndicators === void 0 ? {} : { composerIndicators: composerIndicatorsSchema.parse(value.composerIndicators) };
16915
16985
  for (const field of [
16916
16986
  "totalCredits",
16917
16987
  "contextUsagePercent",
@@ -16982,9 +17052,9 @@ function parseHostUsage(value) {
16982
17052
  if (value.costSource !== "publicPrice") {
16983
17053
  throw new Error("Harness Usage 'unpricedModels' must be provided with a 'publicPrice' cost");
16984
17054
  }
16985
- return { ...value, unpricedModels: [...models] };
17055
+ return { ...value, ...indicators, unpricedModels: [...models] };
16986
17056
  }
16987
- return { ...value };
17057
+ return { ...value, ...indicators };
16988
17058
  }
16989
17059
  var requestTokenFields = [
16990
17060
  "inputTokens",
@@ -17711,857 +17781,283 @@ function createOmpUsageStatistics(environment) {
17711
17781
  });
17712
17782
  }
17713
17783
 
17714
- // ../../../node_modules/diff/libesm/diff/base.js
17715
- var Diff = class {
17716
- diff(oldStr, newStr, options = {}) {
17717
- let callback;
17718
- if (typeof options === "function") {
17719
- callback = options;
17720
- options = {};
17721
- } else if ("callback" in options) {
17722
- callback = options.callback;
17723
- }
17724
- const oldString = this.castInput(oldStr, options);
17725
- const newString = this.castInput(newStr, options);
17726
- const oldTokens = this.removeEmpty(this.tokenize(oldString, options));
17727
- const newTokens = this.removeEmpty(this.tokenize(newString, options));
17728
- return this.diffWithOptionsObj(oldTokens, newTokens, options, callback);
17784
+ // dist/omp-model-list.js
17785
+ import { spawn as spawn2 } from "node:child_process";
17786
+
17787
+ // dist/command.js
17788
+ var ompDiscoverySpec = {
17789
+ id: "omp",
17790
+ command: "omp",
17791
+ commandEnvironmentVariable: "OMP_COMMAND",
17792
+ installRoots: {
17793
+ posix: [
17794
+ "~/.npm-global/bin",
17795
+ "~/.local/bin",
17796
+ VERSION_MANAGER_ROOTS,
17797
+ "/opt/homebrew/bin",
17798
+ "/usr/local/bin"
17799
+ ],
17800
+ windows: ["${APPDATA}/npm", "~/.local/bin", VERSION_MANAGER_ROOTS]
17729
17801
  }
17730
- diffWithOptionsObj(oldTokens, newTokens, options, callback) {
17731
- var _a3;
17732
- const done = (value) => {
17733
- value = this.postProcess(value, options);
17734
- if (callback) {
17735
- setTimeout(function() {
17736
- callback(value);
17737
- }, 0);
17738
- return void 0;
17739
- } else {
17740
- return value;
17802
+ };
17803
+ function resolveOmpExecutable(input, dependencies = {}) {
17804
+ const resolution = resolveHarnessExecutable(ompDiscoverySpec, {
17805
+ ...input.command ? { command: input.command } : {},
17806
+ environment: input.environment,
17807
+ ...dependencies.platform ? { platform: dependencies.platform } : {},
17808
+ ...dependencies.homeDirectory ? { homeDirectory: dependencies.homeDirectory } : {}
17809
+ }, { ...dependencies.isExecutable ? { isExecutable: dependencies.isExecutable } : {} });
17810
+ return resolution?.executable ?? input.command ?? input.environment.OMP_COMMAND ?? "omp";
17811
+ }
17812
+
17813
+ // dist/omp-rpc-session.js
17814
+ import { spawn, spawnSync } from "node:child_process";
17815
+ import { randomUUID } from "node:crypto";
17816
+ import path6 from "node:path";
17817
+
17818
+ // dist/omp-slash-commands.js
17819
+ var OMP_LIVE_COMMAND_ID_PREFIX = "omp.slash.";
17820
+ function isRecord6(value) {
17821
+ return typeof value === "object" && value !== null && !Array.isArray(value);
17822
+ }
17823
+ function parseOmpAvailableCommands(value) {
17824
+ if (!Array.isArray(value))
17825
+ return [];
17826
+ return value.flatMap((entry) => {
17827
+ if (!isRecord6(entry))
17828
+ return [];
17829
+ const name = typeof entry.name === "string" ? entry.name.trim().replace(/^\//u, "") : "";
17830
+ if (!name)
17831
+ return [];
17832
+ return [
17833
+ {
17834
+ name,
17835
+ description: typeof entry.description === "string" ? entry.description : "",
17836
+ source: typeof entry.source === "string" ? entry.source : null
17741
17837
  }
17742
- };
17743
- const newLen = newTokens.length, oldLen = oldTokens.length;
17744
- let editLength = 1;
17745
- let maxEditLength = newLen + oldLen;
17746
- if (options.maxEditLength != null) {
17747
- maxEditLength = Math.min(maxEditLength, options.maxEditLength);
17748
- }
17749
- const maxExecutionTime = (_a3 = options.timeout) !== null && _a3 !== void 0 ? _a3 : Infinity;
17750
- const abortAfterTimestamp = Date.now() + maxExecutionTime;
17751
- const bestPath = [{ oldPos: -1, lastComponent: void 0 }];
17752
- let newPos = this.extractCommon(bestPath[0], newTokens, oldTokens, 0, options);
17753
- if (bestPath[0].oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
17754
- return done(this.buildValues(bestPath[0].lastComponent, newTokens, oldTokens));
17755
- }
17756
- let minDiagonalToConsider = -Infinity, maxDiagonalToConsider = Infinity;
17757
- const execEditLength = () => {
17758
- for (let diagonalPath = Math.max(minDiagonalToConsider, -editLength); diagonalPath <= Math.min(maxDiagonalToConsider, editLength); diagonalPath += 2) {
17759
- let basePath;
17760
- const removePath = bestPath[diagonalPath - 1], addPath = bestPath[diagonalPath + 1];
17761
- if (removePath) {
17762
- bestPath[diagonalPath - 1] = void 0;
17763
- }
17764
- let canAdd = false;
17765
- if (addPath) {
17766
- const addPathNewPos = addPath.oldPos - diagonalPath;
17767
- canAdd = addPath && 0 <= addPathNewPos && addPathNewPos < newLen;
17768
- }
17769
- const canRemove = removePath && removePath.oldPos + 1 < oldLen;
17770
- if (!canAdd && !canRemove) {
17771
- bestPath[diagonalPath] = void 0;
17772
- continue;
17773
- }
17774
- if (!canRemove || canAdd && removePath.oldPos < addPath.oldPos) {
17775
- basePath = this.addToPath(addPath, true, false, 0, options);
17776
- } else {
17777
- basePath = this.addToPath(removePath, false, true, 1, options);
17778
- }
17779
- newPos = this.extractCommon(basePath, newTokens, oldTokens, diagonalPath, options);
17780
- if (basePath.oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
17781
- return done(this.buildValues(basePath.lastComponent, newTokens, oldTokens)) || true;
17782
- } else {
17783
- bestPath[diagonalPath] = basePath;
17784
- if (basePath.oldPos + 1 >= oldLen) {
17785
- maxDiagonalToConsider = Math.min(maxDiagonalToConsider, diagonalPath - 1);
17786
- }
17787
- if (newPos + 1 >= newLen) {
17788
- minDiagonalToConsider = Math.max(minDiagonalToConsider, diagonalPath + 1);
17789
- }
17790
- }
17838
+ ];
17839
+ });
17840
+ }
17841
+ function ompLiveCommands(native) {
17842
+ return native.filter(({ source, name }) => source !== "builtin" || name === "context").map((command) => ({
17843
+ name: command.name,
17844
+ description: command.description,
17845
+ kind: command.source === "skill" ? "skill" : "command"
17846
+ }));
17847
+ }
17848
+
17849
+ // dist/omp-session-file.js
17850
+ import { createReadStream as createReadStream3 } from "node:fs";
17851
+ import { open, realpath as realpath2 } from "node:fs/promises";
17852
+ import readline from "node:readline";
17853
+ var MAX_SESSION_HEADER_BYTES = 64 * 1024;
17854
+ var utf8Decoder = new TextDecoder("utf-8", { fatal: true });
17855
+ function isRecord7(value) {
17856
+ return typeof value === "object" && value !== null && !Array.isArray(value);
17857
+ }
17858
+ function historyEntry(value) {
17859
+ 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") {
17860
+ return null;
17861
+ }
17862
+ return value;
17863
+ }
17864
+ async function readOmpSessionHistory(sessionFile, maxBytes) {
17865
+ const entries = [];
17866
+ let leafId = null;
17867
+ let incomplete = false;
17868
+ const lines = readline.createInterface({
17869
+ input: createReadStream3(sessionFile, {
17870
+ encoding: "utf8",
17871
+ ...maxBytes === void 0 ? {} : { end: maxBytes - 1 }
17872
+ }),
17873
+ crlfDelay: Number.POSITIVE_INFINITY
17874
+ });
17875
+ try {
17876
+ for await (const line of lines) {
17877
+ if (line.length === 0)
17878
+ continue;
17879
+ let parsed;
17880
+ try {
17881
+ parsed = JSON.parse(line);
17882
+ } catch {
17883
+ incomplete = true;
17884
+ continue;
17791
17885
  }
17792
- editLength++;
17793
- };
17794
- if (callback) {
17795
- (function exec() {
17796
- setTimeout(function() {
17797
- if (editLength > maxEditLength || Date.now() > abortAfterTimestamp) {
17798
- return callback(void 0);
17799
- }
17800
- if (!execEditLength()) {
17801
- exec();
17802
- }
17803
- }, 0);
17804
- })();
17805
- } else {
17806
- while (editLength <= maxEditLength && Date.now() <= abortAfterTimestamp) {
17807
- const ret = execEditLength();
17808
- if (ret) {
17809
- return ret;
17886
+ const entry = historyEntry(parsed);
17887
+ if (!entry) {
17888
+ if (!isRecord7(parsed) || parsed.type !== "title" && parsed.type !== "session") {
17889
+ incomplete = true;
17810
17890
  }
17891
+ continue;
17811
17892
  }
17893
+ entries.push(entry);
17894
+ leafId = entry.id;
17812
17895
  }
17896
+ } finally {
17897
+ lines.close();
17813
17898
  }
17814
- addToPath(path9, added, removed, oldPosInc, options) {
17815
- const last = path9.lastComponent;
17816
- if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
17817
- return {
17818
- oldPos: path9.oldPos + oldPosInc,
17819
- lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
17820
- };
17821
- } else {
17822
- return {
17823
- oldPos: path9.oldPos + oldPosInc,
17824
- lastComponent: { count: 1, added, removed, previousComponent: last }
17825
- };
17899
+ return { entries, leafId, ...incomplete ? { incomplete: true } : {} };
17900
+ }
17901
+ async function readOmpSessionHeader(sessionFile) {
17902
+ const handle = await open(sessionFile, "r");
17903
+ try {
17904
+ const buffer = Buffer.allocUnsafe(MAX_SESSION_HEADER_BYTES);
17905
+ const { bytesRead } = await handle.read(buffer, 0, buffer.length, 0);
17906
+ const contents = buffer.subarray(0, bytesRead);
17907
+ const newline = contents.indexOf(10);
17908
+ if (newline < 0 && bytesRead === buffer.length) {
17909
+ throw new Error("Omp Session header exceeds the supported size");
17826
17910
  }
17827
- }
17828
- extractCommon(basePath, newTokens, oldTokens, diagonalPath, options) {
17829
- const newLen = newTokens.length, oldLen = oldTokens.length;
17830
- let oldPos = basePath.oldPos, newPos = oldPos - diagonalPath, commonCount = 0;
17831
- while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(oldTokens[oldPos + 1], newTokens[newPos + 1], options)) {
17832
- newPos++;
17833
- oldPos++;
17834
- commonCount++;
17835
- if (options.oneChangePerToken) {
17836
- basePath.lastComponent = { count: 1, previousComponent: basePath.lastComponent, added: false, removed: false };
17911
+ const contentsText = utf8Decoder.decode(contents);
17912
+ for (const line of contentsText.split("\n")) {
17913
+ if (line.length === 0)
17914
+ continue;
17915
+ let parsed;
17916
+ try {
17917
+ parsed = JSON.parse(line);
17918
+ } catch {
17919
+ continue;
17837
17920
  }
17838
- }
17839
- if (commonCount && !options.oneChangePerToken) {
17840
- basePath.lastComponent = { count: commonCount, previousComponent: basePath.lastComponent, added: false, removed: false };
17841
- }
17842
- basePath.oldPos = oldPos;
17843
- return newPos;
17844
- }
17845
- equals(left, right, options) {
17846
- if (options.comparator) {
17847
- return options.comparator(left, right);
17848
- } else {
17849
- return left === right || !!options.ignoreCase && left.toLowerCase() === right.toLowerCase();
17850
- }
17851
- }
17852
- removeEmpty(array2) {
17853
- const ret = [];
17854
- for (let i = 0; i < array2.length; i++) {
17855
- if (array2[i]) {
17856
- ret.push(array2[i]);
17921
+ if (!isRecord7(parsed) || parsed.type !== "session")
17922
+ continue;
17923
+ if (typeof parsed.id !== "string" || parsed.id.length === 0 || typeof parsed.cwd !== "string" || parsed.cwd.length === 0) {
17924
+ throw new Error("Omp Session header is invalid");
17857
17925
  }
17926
+ return { type: "session", id: parsed.id, cwd: parsed.cwd };
17858
17927
  }
17859
- return ret;
17860
- }
17861
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
17862
- castInput(value, options) {
17863
- return value;
17864
- }
17865
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
17866
- tokenize(value, options) {
17867
- return Array.from(value);
17868
- }
17869
- join(chars) {
17870
- return chars.join("");
17928
+ throw new Error("Omp Session header is invalid");
17929
+ } finally {
17930
+ await handle.close();
17871
17931
  }
17872
- postProcess(changeObjects, options) {
17873
- return changeObjects;
17932
+ }
17933
+ async function verifyOmpSessionCwd(input) {
17934
+ if (!input.sessionFile)
17935
+ throw new Error("Omp Fork Session has no persisted Session file");
17936
+ const header = await readOmpSessionHeader(input.sessionFile);
17937
+ if (header.id !== input.sessionId) {
17938
+ throw new Error("Omp Fork Session header identity does not match RPC state");
17874
17939
  }
17875
- get useLongestToken() {
17876
- return false;
17940
+ const [actualCwd, expectedCwd] = await Promise.all([
17941
+ realpath2(header.cwd),
17942
+ realpath2(input.expectedCwd)
17943
+ ]);
17944
+ if (actualCwd !== expectedCwd) {
17945
+ throw new Error("Omp Fork Session did not bind the requested cwd");
17877
17946
  }
17878
- buildValues(lastComponent, newTokens, oldTokens) {
17879
- const components = [];
17880
- let nextComponent;
17881
- while (lastComponent) {
17882
- components.push(lastComponent);
17883
- nextComponent = lastComponent.previousComponent;
17884
- delete lastComponent.previousComponent;
17885
- lastComponent = nextComponent;
17947
+ }
17948
+
17949
+ // dist/omp-protocol.js
17950
+ var MAX_FRAME_BYTES = 1024 * 1024;
17951
+ var MAX_REASSEMBLED_BYTES = 64 * 1024 * 1024;
17952
+ var MAX_CHUNK_BYTES = 256 * 1024;
17953
+ function isObject2(value) {
17954
+ return typeof value === "object" && value !== null && !Array.isArray(value);
17955
+ }
17956
+ var OmpFrameDecoder = class {
17957
+ #pending = null;
17958
+ push(value) {
17959
+ if (!isObject2(value))
17960
+ throw new Error("OMP RPC frame must be a JSON object");
17961
+ if (value.type !== "rpc_chunk") {
17962
+ if (this.#pending)
17963
+ throw new Error("OMP RPC chunk sequence was interrupted");
17964
+ return value;
17886
17965
  }
17887
- components.reverse();
17888
- const componentLen = components.length;
17889
- let componentPos = 0, newPos = 0, oldPos = 0;
17890
- for (; componentPos < componentLen; componentPos++) {
17891
- const component = components[componentPos];
17892
- if (!component.removed) {
17893
- if (!component.added && this.useLongestToken) {
17894
- let value = newTokens.slice(newPos, newPos + component.count);
17895
- value = value.map(function(value2, i) {
17896
- const oldValue = oldTokens[oldPos + i];
17897
- return oldValue.length > value2.length ? oldValue : value2;
17898
- });
17899
- component.value = this.join(value);
17900
- } else {
17901
- component.value = this.join(newTokens.slice(newPos, newPos + component.count));
17902
- }
17903
- newPos += component.count;
17904
- if (!component.added) {
17905
- oldPos += component.count;
17906
- }
17907
- } else {
17908
- component.value = this.join(oldTokens.slice(oldPos, oldPos + component.count));
17909
- oldPos += component.count;
17910
- }
17966
+ const chunkId = value.chunkId;
17967
+ const index = value.index;
17968
+ const count2 = value.count;
17969
+ const byteLength = value.byteLength;
17970
+ const data = value.data;
17971
+ 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)
17972
+ throw new Error("Invalid OMP RPC chunk metadata");
17973
+ let bytes;
17974
+ try {
17975
+ bytes = Buffer.from(data, "base64");
17976
+ } catch {
17977
+ throw new Error("Invalid OMP RPC chunk data");
17911
17978
  }
17912
- return components;
17979
+ if (bytes.length === 0 || bytes.length > MAX_CHUNK_BYTES || bytes.toString("base64") !== data) {
17980
+ throw new Error("Invalid OMP RPC chunk data");
17981
+ }
17982
+ const chunkIndex = index;
17983
+ const chunkCount = count2;
17984
+ const declaredByteLength = byteLength;
17985
+ if (!this.#pending) {
17986
+ if (chunkIndex !== 0)
17987
+ throw new Error("OMP RPC chunk sequence must start at index 0");
17988
+ this.#pending = {
17989
+ chunkId,
17990
+ count: chunkCount,
17991
+ byteLength: declaredByteLength,
17992
+ nextIndex: 0,
17993
+ chunks: [],
17994
+ received: 0
17995
+ };
17996
+ }
17997
+ const pending = this.#pending;
17998
+ if (!pending)
17999
+ throw new Error("OMP RPC chunk state was lost");
18000
+ if (pending.chunkId !== chunkId || pending.count !== chunkCount || pending.byteLength !== declaredByteLength || pending.nextIndex !== chunkIndex) {
18001
+ throw new Error("OMP RPC chunk sequence mismatch");
18002
+ }
18003
+ pending.chunks.push(bytes);
18004
+ pending.received += bytes.length;
18005
+ pending.nextIndex += 1;
18006
+ if (pending.received > pending.byteLength)
18007
+ throw new Error("OMP RPC chunk sequence exceeds its declared length");
18008
+ if (pending.nextIndex < pending.count)
18009
+ return null;
18010
+ if (pending.received !== pending.byteLength)
18011
+ throw new Error("OMP RPC chunk sequence length mismatch");
18012
+ this.#pending = null;
18013
+ let decoded;
18014
+ try {
18015
+ decoded = JSON.parse(Buffer.concat(pending.chunks).toString("utf8"));
18016
+ } catch {
18017
+ throw new Error("Failed to decode reassembled OMP RPC frame");
18018
+ }
18019
+ if (!isObject2(decoded))
18020
+ throw new Error("Reassembled OMP RPC frame must be an object");
18021
+ return decoded;
17913
18022
  }
17914
18023
  };
17915
18024
 
17916
- // ../../../node_modules/diff/libesm/diff/line.js
17917
- var LineDiff = class extends Diff {
17918
- constructor() {
17919
- super(...arguments);
17920
- this.tokenize = tokenize;
18025
+ // dist/omp-rpc-session.js
18026
+ var OmpRpcFaultError = class extends Error {
18027
+ kind;
18028
+ diagnostic;
18029
+ constructor(kind, message3, diagnostic) {
18030
+ super(message3);
18031
+ this.kind = kind;
18032
+ this.diagnostic = diagnostic;
18033
+ this.name = "OmpRpcFaultError";
17921
18034
  }
17922
- equals(left, right, options) {
17923
- if (options.ignoreWhitespace) {
17924
- if (!options.newlineIsToken || !left.includes("\n")) {
17925
- left = left.trim();
17926
- }
17927
- if (!options.newlineIsToken || !right.includes("\n")) {
17928
- right = right.trim();
17929
- }
17930
- } else if (options.ignoreNewlineAtEof && !options.newlineIsToken) {
17931
- if (left.endsWith("\n")) {
17932
- left = left.slice(0, -1);
17933
- }
17934
- if (right.endsWith("\n")) {
17935
- right = right.slice(0, -1);
17936
- }
17937
- }
17938
- return super.equals(left, right, options);
18035
+ };
18036
+ var OmpRpcUnsupportedCommandError = class extends Error {
18037
+ command;
18038
+ constructor(command) {
18039
+ super(`Omp RPC does not support '${command}'`);
18040
+ this.command = command;
18041
+ this.name = "OmpRpcUnsupportedCommandError";
17939
18042
  }
17940
18043
  };
17941
- var lineDiff = new LineDiff();
17942
- function diffLines(oldStr, newStr, options) {
17943
- return lineDiff.diff(oldStr, newStr, options);
18044
+ var textDecoder = new TextDecoder("utf-8", { fatal: true });
18045
+ function isRecord8(value) {
18046
+ return typeof value === "object" && value !== null && !Array.isArray(value);
17944
18047
  }
17945
- function tokenize(value, options) {
17946
- if (options.stripTrailingCr) {
17947
- value = value.replace(/\r\n/g, "\n");
17948
- }
17949
- const retLines = [], linesAndNewlines = value.split(/(\n|\r\n)/);
17950
- if (!linesAndNewlines[linesAndNewlines.length - 1]) {
17951
- linesAndNewlines.pop();
17952
- }
17953
- for (let i = 0; i < linesAndNewlines.length; i++) {
17954
- const line = linesAndNewlines[i];
17955
- if (i % 2 && !options.newlineIsToken) {
17956
- retLines[retLines.length - 1] += line;
17957
- } else {
17958
- retLines.push(line);
17959
- }
18048
+ function message2(value) {
18049
+ return value instanceof Error ? value.message : String(value);
18050
+ }
18051
+ function nonBlankString(value) {
18052
+ return typeof value === "string" && value.trim().length > 0;
18053
+ }
18054
+ function parseNativeModel(value, context) {
18055
+ if (value === null || value === void 0)
18056
+ return null;
18057
+ if (!isRecord8(value) || !nonBlankString(value.provider) || !nonBlankString(value.id)) {
18058
+ throw new OmpRpcFaultError("protocolError", `Omp RPC returned an invalid ${context} Model`);
17960
18059
  }
17961
- return retLines;
17962
- }
17963
-
17964
- // ../../../node_modules/diff/libesm/patch/parse.js
17965
- function parsePatch(uniDiff) {
17966
- const diffstr = uniDiff.split(/\n/), list = [];
17967
- let i = 0;
17968
- function parseIndex() {
17969
- const index = {};
17970
- list.push(index);
17971
- while (i < diffstr.length) {
17972
- const line = diffstr[i];
17973
- if (/^(---|\+\+\+|@@)\s/.test(line)) {
17974
- break;
17975
- }
17976
- const header = /^(?:Index:|diff(?: -r \w+)+)\s+(.+?)\s*$/.exec(line);
17977
- if (header) {
17978
- index.index = header[1];
17979
- }
17980
- i++;
17981
- }
17982
- parseFileHeader(index);
17983
- parseFileHeader(index);
17984
- index.hunks = [];
17985
- while (i < diffstr.length) {
17986
- const line = diffstr[i];
17987
- if (/^(Index:\s|diff\s|---\s|\+\+\+\s|===================================================================)/.test(line)) {
17988
- break;
17989
- } else if (/^@@/.test(line)) {
17990
- index.hunks.push(parseHunk());
17991
- } else if (line) {
17992
- throw new Error("Unknown line " + (i + 1) + " " + JSON.stringify(line));
17993
- } else {
17994
- i++;
17995
- }
17996
- }
17997
- }
17998
- function parseFileHeader(index) {
17999
- const fileHeader = /^(---|\+\+\+)\s+(.*)\r?$/.exec(diffstr[i]);
18000
- if (fileHeader) {
18001
- const data = fileHeader[2].split(" ", 2), header = (data[1] || "").trim();
18002
- let fileName = data[0].replace(/\\\\/g, "\\");
18003
- if (/^".*"$/.test(fileName)) {
18004
- fileName = fileName.substr(1, fileName.length - 2);
18005
- }
18006
- if (fileHeader[1] === "---") {
18007
- index.oldFileName = fileName;
18008
- index.oldHeader = header;
18009
- } else {
18010
- index.newFileName = fileName;
18011
- index.newHeader = header;
18012
- }
18013
- i++;
18014
- }
18015
- }
18016
- function parseHunk() {
18017
- var _a3;
18018
- const chunkHeaderIndex = i, chunkHeaderLine = diffstr[i++], chunkHeader = chunkHeaderLine.split(/@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/);
18019
- const hunk = {
18020
- oldStart: +chunkHeader[1],
18021
- oldLines: typeof chunkHeader[2] === "undefined" ? 1 : +chunkHeader[2],
18022
- newStart: +chunkHeader[3],
18023
- newLines: typeof chunkHeader[4] === "undefined" ? 1 : +chunkHeader[4],
18024
- lines: []
18025
- };
18026
- if (hunk.oldLines === 0) {
18027
- hunk.oldStart += 1;
18028
- }
18029
- if (hunk.newLines === 0) {
18030
- hunk.newStart += 1;
18031
- }
18032
- let addCount = 0, removeCount = 0;
18033
- for (; i < diffstr.length && (removeCount < hunk.oldLines || addCount < hunk.newLines || ((_a3 = diffstr[i]) === null || _a3 === void 0 ? void 0 : _a3.startsWith("\\"))); i++) {
18034
- const operation = diffstr[i].length == 0 && i != diffstr.length - 1 ? " " : diffstr[i][0];
18035
- if (operation === "+" || operation === "-" || operation === " " || operation === "\\") {
18036
- hunk.lines.push(diffstr[i]);
18037
- if (operation === "+") {
18038
- addCount++;
18039
- } else if (operation === "-") {
18040
- removeCount++;
18041
- } else if (operation === " ") {
18042
- addCount++;
18043
- removeCount++;
18044
- }
18045
- } else {
18046
- throw new Error(`Hunk at line ${chunkHeaderIndex + 1} contained invalid line ${diffstr[i]}`);
18047
- }
18048
- }
18049
- if (!addCount && hunk.newLines === 1) {
18050
- hunk.newLines = 0;
18051
- }
18052
- if (!removeCount && hunk.oldLines === 1) {
18053
- hunk.oldLines = 0;
18054
- }
18055
- if (addCount !== hunk.newLines) {
18056
- throw new Error("Added line count did not match for hunk at line " + (chunkHeaderIndex + 1));
18057
- }
18058
- if (removeCount !== hunk.oldLines) {
18059
- throw new Error("Removed line count did not match for hunk at line " + (chunkHeaderIndex + 1));
18060
- }
18061
- return hunk;
18062
- }
18063
- while (i < diffstr.length) {
18064
- parseIndex();
18065
- }
18066
- return list;
18067
- }
18068
-
18069
- // ../../../node_modules/diff/libesm/patch/create.js
18070
- function structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {
18071
- let optionsObj;
18072
- if (!options) {
18073
- optionsObj = {};
18074
- } else if (typeof options === "function") {
18075
- optionsObj = { callback: options };
18076
- } else {
18077
- optionsObj = options;
18078
- }
18079
- if (typeof optionsObj.context === "undefined") {
18080
- optionsObj.context = 4;
18081
- }
18082
- const context = optionsObj.context;
18083
- if (optionsObj.newlineIsToken) {
18084
- throw new Error("newlineIsToken may not be used with patch-generation functions, only with diffing functions");
18085
- }
18086
- if (!optionsObj.callback) {
18087
- return diffLinesResultToPatch(diffLines(oldStr, newStr, optionsObj));
18088
- } else {
18089
- const { callback } = optionsObj;
18090
- diffLines(oldStr, newStr, Object.assign(Object.assign({}, optionsObj), { callback: (diff) => {
18091
- const patch = diffLinesResultToPatch(diff);
18092
- callback(patch);
18093
- } }));
18094
- }
18095
- function diffLinesResultToPatch(diff) {
18096
- if (!diff) {
18097
- return;
18098
- }
18099
- diff.push({ value: "", lines: [] });
18100
- function contextLines(lines) {
18101
- return lines.map(function(entry) {
18102
- return " " + entry;
18103
- });
18104
- }
18105
- const hunks = [];
18106
- let oldRangeStart = 0, newRangeStart = 0, curRange = [], oldLine = 1, newLine = 1;
18107
- for (let i = 0; i < diff.length; i++) {
18108
- const current = diff[i], lines = current.lines || splitLines(current.value);
18109
- current.lines = lines;
18110
- if (current.added || current.removed) {
18111
- if (!oldRangeStart) {
18112
- const prev = diff[i - 1];
18113
- oldRangeStart = oldLine;
18114
- newRangeStart = newLine;
18115
- if (prev) {
18116
- curRange = context > 0 ? contextLines(prev.lines.slice(-context)) : [];
18117
- oldRangeStart -= curRange.length;
18118
- newRangeStart -= curRange.length;
18119
- }
18120
- }
18121
- for (const line of lines) {
18122
- curRange.push((current.added ? "+" : "-") + line);
18123
- }
18124
- if (current.added) {
18125
- newLine += lines.length;
18126
- } else {
18127
- oldLine += lines.length;
18128
- }
18129
- } else {
18130
- if (oldRangeStart) {
18131
- if (lines.length <= context * 2 && i < diff.length - 2) {
18132
- for (const line of contextLines(lines)) {
18133
- curRange.push(line);
18134
- }
18135
- } else {
18136
- const contextSize = Math.min(lines.length, context);
18137
- for (const line of contextLines(lines.slice(0, contextSize))) {
18138
- curRange.push(line);
18139
- }
18140
- const hunk = {
18141
- oldStart: oldRangeStart,
18142
- oldLines: oldLine - oldRangeStart + contextSize,
18143
- newStart: newRangeStart,
18144
- newLines: newLine - newRangeStart + contextSize,
18145
- lines: curRange
18146
- };
18147
- hunks.push(hunk);
18148
- oldRangeStart = 0;
18149
- newRangeStart = 0;
18150
- curRange = [];
18151
- }
18152
- }
18153
- oldLine += lines.length;
18154
- newLine += lines.length;
18155
- }
18156
- }
18157
- for (const hunk of hunks) {
18158
- for (let i = 0; i < hunk.lines.length; i++) {
18159
- if (hunk.lines[i].endsWith("\n")) {
18160
- hunk.lines[i] = hunk.lines[i].slice(0, -1);
18161
- } else {
18162
- hunk.lines.splice(i + 1, 0, "\");
18163
- i++;
18164
- }
18165
- }
18166
- }
18167
- return {
18168
- oldFileName,
18169
- newFileName,
18170
- oldHeader,
18171
- newHeader,
18172
- hunks
18173
- };
18174
- }
18175
- }
18176
- function formatPatch(patch) {
18177
- if (Array.isArray(patch)) {
18178
- return patch.map(formatPatch).join("\n");
18179
- }
18180
- const ret = [];
18181
- if (patch.oldFileName == patch.newFileName) {
18182
- ret.push("Index: " + patch.oldFileName);
18183
- }
18184
- ret.push("===================================================================");
18185
- ret.push("--- " + patch.oldFileName + (typeof patch.oldHeader === "undefined" ? "" : " " + patch.oldHeader));
18186
- ret.push("+++ " + patch.newFileName + (typeof patch.newHeader === "undefined" ? "" : " " + patch.newHeader));
18187
- for (let i = 0; i < patch.hunks.length; i++) {
18188
- const hunk = patch.hunks[i];
18189
- if (hunk.oldLines === 0) {
18190
- hunk.oldStart -= 1;
18191
- }
18192
- if (hunk.newLines === 0) {
18193
- hunk.newStart -= 1;
18194
- }
18195
- ret.push("@@ -" + hunk.oldStart + "," + hunk.oldLines + " +" + hunk.newStart + "," + hunk.newLines + " @@");
18196
- for (const line of hunk.lines) {
18197
- ret.push(line);
18198
- }
18199
- }
18200
- return ret.join("\n") + "\n";
18201
- }
18202
- function createTwoFilesPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {
18203
- if (typeof options === "function") {
18204
- options = { callback: options };
18205
- }
18206
- if (!(options === null || options === void 0 ? void 0 : options.callback)) {
18207
- const patchObj = structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options);
18208
- if (!patchObj) {
18209
- return;
18210
- }
18211
- return formatPatch(patchObj);
18212
- } else {
18213
- const { callback } = options;
18214
- structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, Object.assign(Object.assign({}, options), { callback: (patchObj) => {
18215
- if (!patchObj) {
18216
- callback(void 0);
18217
- } else {
18218
- callback(formatPatch(patchObj));
18219
- }
18220
- } }));
18221
- }
18222
- }
18223
- function splitLines(text) {
18224
- const hasTrailingNl = text.endsWith("\n");
18225
- const result = text.split("\n").map((line) => line + "\n");
18226
- if (hasTrailingNl) {
18227
- result.pop();
18228
- } else {
18229
- result.push(result.pop().slice(0, -1));
18230
- }
18231
- return result;
18232
- }
18233
-
18234
- // dist/omp-adapter.js
18235
- import { randomUUID as randomUUID2 } from "node:crypto";
18236
- import { realpath as realpath3, stat as stat2 } from "node:fs/promises";
18237
- import path7 from "node:path";
18238
-
18239
- // dist/omp-slash-commands.js
18240
- var OMP_LIVE_COMMAND_ID_PREFIX = "omp.slash.";
18241
- function isRecord6(value) {
18242
- return typeof value === "object" && value !== null && !Array.isArray(value);
18243
- }
18244
- function parseOmpAvailableCommands(value) {
18245
- if (!Array.isArray(value))
18246
- return [];
18247
- return value.flatMap((entry) => {
18248
- if (!isRecord6(entry))
18249
- return [];
18250
- const name = typeof entry.name === "string" ? entry.name.trim().replace(/^\//u, "") : "";
18251
- if (!name)
18252
- return [];
18253
- return [
18254
- {
18255
- name,
18256
- description: typeof entry.description === "string" ? entry.description : "",
18257
- source: typeof entry.source === "string" ? entry.source : null
18258
- }
18259
- ];
18260
- });
18261
- }
18262
- function ompLiveCommands(native) {
18263
- return native.filter(({ source, name }) => source !== "builtin" || name === "context").map((command) => ({
18264
- name: command.name,
18265
- description: command.description,
18266
- kind: command.source === "skill" ? "skill" : "command"
18267
- }));
18268
- }
18269
-
18270
- // dist/omp-session-file.js
18271
- import { createReadStream as createReadStream3 } from "node:fs";
18272
- import { open, realpath as realpath2 } from "node:fs/promises";
18273
- import readline from "node:readline";
18274
- var MAX_SESSION_HEADER_BYTES = 64 * 1024;
18275
- var utf8Decoder = new TextDecoder("utf-8", { fatal: true });
18276
- function isRecord7(value) {
18277
- return typeof value === "object" && value !== null && !Array.isArray(value);
18278
- }
18279
- function historyEntry(value) {
18280
- 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") {
18281
- return null;
18282
- }
18283
- return value;
18284
- }
18285
- async function readOmpSessionHistory(sessionFile, maxBytes) {
18286
- const entries = [];
18287
- let leafId = null;
18288
- let incomplete = false;
18289
- const lines = readline.createInterface({
18290
- input: createReadStream3(sessionFile, {
18291
- encoding: "utf8",
18292
- ...maxBytes === void 0 ? {} : { end: maxBytes - 1 }
18293
- }),
18294
- crlfDelay: Number.POSITIVE_INFINITY
18295
- });
18296
- try {
18297
- for await (const line of lines) {
18298
- if (line.length === 0)
18299
- continue;
18300
- let parsed;
18301
- try {
18302
- parsed = JSON.parse(line);
18303
- } catch {
18304
- incomplete = true;
18305
- continue;
18306
- }
18307
- const entry = historyEntry(parsed);
18308
- if (!entry) {
18309
- if (!isRecord7(parsed) || parsed.type !== "title" && parsed.type !== "session") {
18310
- incomplete = true;
18311
- }
18312
- continue;
18313
- }
18314
- entries.push(entry);
18315
- leafId = entry.id;
18316
- }
18317
- } finally {
18318
- lines.close();
18319
- }
18320
- return { entries, leafId, ...incomplete ? { incomplete: true } : {} };
18321
- }
18322
- async function readOmpSessionHeader(sessionFile) {
18323
- const handle = await open(sessionFile, "r");
18324
- try {
18325
- const buffer = Buffer.allocUnsafe(MAX_SESSION_HEADER_BYTES);
18326
- const { bytesRead } = await handle.read(buffer, 0, buffer.length, 0);
18327
- const contents = buffer.subarray(0, bytesRead);
18328
- const newline = contents.indexOf(10);
18329
- if (newline < 0 && bytesRead === buffer.length) {
18330
- throw new Error("Omp Session header exceeds the supported size");
18331
- }
18332
- const contentsText = utf8Decoder.decode(contents);
18333
- for (const line of contentsText.split("\n")) {
18334
- if (line.length === 0)
18335
- continue;
18336
- let parsed;
18337
- try {
18338
- parsed = JSON.parse(line);
18339
- } catch {
18340
- continue;
18341
- }
18342
- if (!isRecord7(parsed) || parsed.type !== "session")
18343
- continue;
18344
- if (typeof parsed.id !== "string" || parsed.id.length === 0 || typeof parsed.cwd !== "string" || parsed.cwd.length === 0) {
18345
- throw new Error("Omp Session header is invalid");
18346
- }
18347
- return { type: "session", id: parsed.id, cwd: parsed.cwd };
18348
- }
18349
- throw new Error("Omp Session header is invalid");
18350
- } finally {
18351
- await handle.close();
18352
- }
18353
- }
18354
- async function verifyOmpSessionCwd(input) {
18355
- if (!input.sessionFile)
18356
- throw new Error("Omp Fork Session has no persisted Session file");
18357
- const header = await readOmpSessionHeader(input.sessionFile);
18358
- if (header.id !== input.sessionId) {
18359
- throw new Error("Omp Fork Session header identity does not match RPC state");
18360
- }
18361
- const [actualCwd, expectedCwd] = await Promise.all([
18362
- realpath2(header.cwd),
18363
- realpath2(input.expectedCwd)
18364
- ]);
18365
- if (actualCwd !== expectedCwd) {
18366
- throw new Error("Omp Fork Session did not bind the requested cwd");
18367
- }
18368
- }
18369
-
18370
- // dist/omp-last-turn-rollback.js
18371
- function modelFromState(state) {
18372
- if (state.provider === null && state.modelId === null)
18373
- return null;
18374
- if (state.provider === null || state.modelId === null) {
18375
- throw new Error("Omp state contains a partial Model identity");
18376
- }
18377
- return { provider: state.provider, id: state.modelId };
18378
- }
18379
- async function rollbackOmpLastTurn(transport, sourceSessionId, cwd) {
18380
- const startupState = transport.state;
18381
- const startupSessionId = startupState.sessionId;
18382
- const currentModel = modelFromState(startupState);
18383
- const currentThinking = startupState.thinkingLevel;
18384
- const copiedHistory = await transport.getEntries();
18385
- const boundary = resolveOmpLastTurnBoundary(copiedHistory);
18386
- if (!boundary)
18387
- return { ok: false, reason: "empty" };
18388
- const sourceSnapshot = mapOmpSnapshot(copiedHistory, {
18389
- sessionId: startupSessionId,
18390
- model: currentModel
18391
- });
18392
- let state = await transport.fork(boundary.lastUserEntryId);
18393
- if (state.sessionId === sourceSessionId || state.sessionId === startupSessionId) {
18394
- throw new Error("Omp last-Turn rollback did not create a distinct Native Session");
18395
- }
18396
- if (!sameOmpModel(modelFromState(state), currentModel)) {
18397
- if (!currentModel)
18398
- throw new Error("Omp last-Turn rollback changed the current Model");
18399
- state = await transport.selectModel(currentModel);
18400
- }
18401
- if (state.thinkingLevel !== currentThinking) {
18402
- if (!currentThinking)
18403
- throw new Error("Omp last-Turn rollback changed current Thinking");
18404
- state = await transport.selectThinkingOption(currentThinking);
18405
- }
18406
- if (!sameOmpModel(modelFromState(state), currentModel) || state.thinkingLevel !== currentThinking) {
18407
- throw new Error("Omp last-Turn rollback could not restore current Model and Thinking");
18408
- }
18409
- const snapshot = mapOmpSnapshot(await transport.getEntries(), {
18410
- sessionId: state.sessionId,
18411
- model: modelFromState(state)
18412
- });
18413
- const expectedTurnKeys = sourceSnapshot.turns.slice(0, -1).map((turn) => turn.nativeTurnRef.nativeTurnKey);
18414
- const actualTurnKeys = snapshot.turns.map((turn) => turn.nativeTurnRef.nativeTurnKey);
18415
- if (snapshot.turns.length !== boundary.sourceTurnCount - 1 || actualTurnKeys.some((key, index) => key !== expectedTurnKeys[index])) {
18416
- throw new Error("Omp last-Turn rollback did not produce the exact retained history prefix");
18417
- }
18418
- await transport.verifySessionCwd(cwd);
18419
- return { ok: true };
18420
- }
18421
-
18422
- // dist/omp-rpc-session.js
18423
- import { spawn, spawnSync } from "node:child_process";
18424
- import { randomUUID } from "node:crypto";
18425
- import path6 from "node:path";
18426
-
18427
- // dist/command.js
18428
- var ompDiscoverySpec = {
18429
- id: "omp",
18430
- command: "omp",
18431
- commandEnvironmentVariable: "OMP_COMMAND",
18432
- installRoots: {
18433
- posix: [
18434
- "~/.npm-global/bin",
18435
- "~/.local/bin",
18436
- VERSION_MANAGER_ROOTS,
18437
- "/opt/homebrew/bin",
18438
- "/usr/local/bin"
18439
- ],
18440
- windows: ["${APPDATA}/npm", "~/.local/bin", VERSION_MANAGER_ROOTS]
18441
- }
18442
- };
18443
- function resolveOmpExecutable(input, dependencies = {}) {
18444
- const resolution = resolveHarnessExecutable(ompDiscoverySpec, {
18445
- ...input.command ? { command: input.command } : {},
18446
- environment: input.environment,
18447
- ...dependencies.platform ? { platform: dependencies.platform } : {},
18448
- ...dependencies.homeDirectory ? { homeDirectory: dependencies.homeDirectory } : {}
18449
- }, { ...dependencies.isExecutable ? { isExecutable: dependencies.isExecutable } : {} });
18450
- return resolution?.executable ?? input.command ?? input.environment.OMP_COMMAND ?? "omp";
18451
- }
18452
-
18453
- // dist/omp-protocol.js
18454
- var MAX_FRAME_BYTES = 1024 * 1024;
18455
- var MAX_REASSEMBLED_BYTES = 64 * 1024 * 1024;
18456
- var MAX_CHUNK_BYTES = 256 * 1024;
18457
- function isObject2(value) {
18458
- return typeof value === "object" && value !== null && !Array.isArray(value);
18459
- }
18460
- var OmpFrameDecoder = class {
18461
- #pending = null;
18462
- push(value) {
18463
- if (!isObject2(value))
18464
- throw new Error("OMP RPC frame must be a JSON object");
18465
- if (value.type !== "rpc_chunk") {
18466
- if (this.#pending)
18467
- throw new Error("OMP RPC chunk sequence was interrupted");
18468
- return value;
18469
- }
18470
- const chunkId = value.chunkId;
18471
- const index = value.index;
18472
- const count2 = value.count;
18473
- const byteLength = value.byteLength;
18474
- const data = value.data;
18475
- 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)
18476
- throw new Error("Invalid OMP RPC chunk metadata");
18477
- let bytes;
18478
- try {
18479
- bytes = Buffer.from(data, "base64");
18480
- } catch {
18481
- throw new Error("Invalid OMP RPC chunk data");
18482
- }
18483
- if (bytes.length === 0 || bytes.length > MAX_CHUNK_BYTES || bytes.toString("base64") !== data) {
18484
- throw new Error("Invalid OMP RPC chunk data");
18485
- }
18486
- const chunkIndex = index;
18487
- const chunkCount = count2;
18488
- const declaredByteLength = byteLength;
18489
- if (!this.#pending) {
18490
- if (chunkIndex !== 0)
18491
- throw new Error("OMP RPC chunk sequence must start at index 0");
18492
- this.#pending = {
18493
- chunkId,
18494
- count: chunkCount,
18495
- byteLength: declaredByteLength,
18496
- nextIndex: 0,
18497
- chunks: [],
18498
- received: 0
18499
- };
18500
- }
18501
- const pending = this.#pending;
18502
- if (!pending)
18503
- throw new Error("OMP RPC chunk state was lost");
18504
- if (pending.chunkId !== chunkId || pending.count !== chunkCount || pending.byteLength !== declaredByteLength || pending.nextIndex !== chunkIndex) {
18505
- throw new Error("OMP RPC chunk sequence mismatch");
18506
- }
18507
- pending.chunks.push(bytes);
18508
- pending.received += bytes.length;
18509
- pending.nextIndex += 1;
18510
- if (pending.received > pending.byteLength)
18511
- throw new Error("OMP RPC chunk sequence exceeds its declared length");
18512
- if (pending.nextIndex < pending.count)
18513
- return null;
18514
- if (pending.received !== pending.byteLength)
18515
- throw new Error("OMP RPC chunk sequence length mismatch");
18516
- this.#pending = null;
18517
- let decoded;
18518
- try {
18519
- decoded = JSON.parse(Buffer.concat(pending.chunks).toString("utf8"));
18520
- } catch {
18521
- throw new Error("Failed to decode reassembled OMP RPC frame");
18522
- }
18523
- if (!isObject2(decoded))
18524
- throw new Error("Reassembled OMP RPC frame must be an object");
18525
- return decoded;
18526
- }
18527
- };
18528
-
18529
- // dist/omp-rpc-session.js
18530
- var OmpRpcFaultError = class extends Error {
18531
- kind;
18532
- diagnostic;
18533
- constructor(kind, message3, diagnostic) {
18534
- super(message3);
18535
- this.kind = kind;
18536
- this.diagnostic = diagnostic;
18537
- this.name = "OmpRpcFaultError";
18538
- }
18539
- };
18540
- var OmpRpcUnsupportedCommandError = class extends Error {
18541
- command;
18542
- constructor(command) {
18543
- super(`Omp RPC does not support '${command}'`);
18544
- this.command = command;
18545
- this.name = "OmpRpcUnsupportedCommandError";
18546
- }
18547
- };
18548
- var textDecoder = new TextDecoder("utf-8", { fatal: true });
18549
- function isRecord8(value) {
18550
- return typeof value === "object" && value !== null && !Array.isArray(value);
18551
- }
18552
- function message2(value) {
18553
- return value instanceof Error ? value.message : String(value);
18554
- }
18555
- function nonBlankString(value) {
18556
- return typeof value === "string" && value.trim().length > 0;
18557
- }
18558
- function parseNativeModel(value, context) {
18559
- if (value === null || value === void 0)
18560
- return null;
18561
- if (!isRecord8(value) || !nonBlankString(value.provider) || !nonBlankString(value.id)) {
18562
- throw new OmpRpcFaultError("protocolError", `Omp RPC returned an invalid ${context} Model`);
18563
- }
18564
- return { provider: value.provider, id: value.id };
18060
+ return { provider: value.provider, id: value.id };
18565
18061
  }
18566
18062
  function sessionStateData(response) {
18567
18063
  const data = isRecord8(response.data) ? response.data : null;
@@ -18789,1178 +18285,1844 @@ var OmpRpcSession = class {
18789
18285
  if (options.model && (options.sessionFile || options.forkSessionFile)) {
18790
18286
  throw new Error("Omp RPC cannot combine a startup Model with Session restore or Fork");
18791
18287
  }
18792
- this.#options = {
18793
- commandTimeoutMs: 3e4,
18794
- compactionTimeoutMs: 3e5,
18795
- // Native Abort waits for tools, persistence and deferred work to unwind.
18796
- // Stable cancellation must outlast the Host's 20s steering wait.
18797
- cancelTimeoutMs: 3e4,
18798
- closeTimeoutMs: 2e3,
18799
- ...options
18800
- };
18801
- this.#processAdapter = processAdapter;
18288
+ this.#options = {
18289
+ commandTimeoutMs: 3e4,
18290
+ compactionTimeoutMs: 3e5,
18291
+ // Native Abort waits for tools, persistence and deferred work to unwind.
18292
+ // Stable cancellation must outlast the Host's 20s steering wait.
18293
+ cancelTimeoutMs: 3e4,
18294
+ closeTimeoutMs: 2e3,
18295
+ ...options
18296
+ };
18297
+ this.#processAdapter = processAdapter;
18298
+ }
18299
+ get state() {
18300
+ if (!this.#state)
18301
+ throw new Error("Omp RPC Session has not started");
18302
+ return this.#state;
18303
+ }
18304
+ get stderrTail() {
18305
+ return this.#stderrTail;
18306
+ }
18307
+ async start() {
18308
+ if (this.#child || this.#closed)
18309
+ throw new Error("Omp RPC Session cannot be started twice");
18310
+ const child = this.#processAdapter.spawn({
18311
+ cwd: this.#options.cwd,
18312
+ ...this.#options.command ? { command: this.#options.command } : {},
18313
+ environment: withNodeRuntimeOnPath({
18314
+ ...process.env,
18315
+ ...this.#options.environment,
18316
+ OMP_SKIP_VERSION_CHECK: "1",
18317
+ OMP_TELEMETRY: "0"
18318
+ }),
18319
+ ...this.#options.sessionFile ? { sessionFile: this.#options.sessionFile } : {},
18320
+ ...this.#options.forkSessionFile ? { forkSessionFile: this.#options.forkSessionFile } : {},
18321
+ ...this.#options.model ? { model: this.#options.model } : {},
18322
+ ...this.#options.permissionMode ? { permissionMode: this.#options.permissionMode } : {}
18323
+ });
18324
+ this.#child = child;
18325
+ child.stdout.on("data", (chunk) => this.#push(chunk));
18326
+ child.stdout.on("end", () => {
18327
+ if (this.#buffer.length !== 0) {
18328
+ this.#fail(new OmpRpcFaultError("protocolError", "Omp RPC stdout ended mid-frame"));
18329
+ }
18330
+ });
18331
+ child.stderr.on("data", (chunk) => {
18332
+ this.#stderrTail = sanitizeDiagnosticTail(`${this.#stderrTail}${chunk.toString()}`);
18333
+ });
18334
+ child.once("error", (error51) => {
18335
+ const kind = isRecord8(error51) && error51.code === "ENOENT" ? "notInstalled" : "unavailable";
18336
+ this.#fail(new OmpRpcFaultError(kind, `Omp RPC failed to start: ${error51.message}`, this.stderrTail));
18337
+ });
18338
+ child.once("exit", (code, signal) => {
18339
+ if (!this.#closed) {
18340
+ this.#fail(new OmpRpcFaultError("processExited", `Omp RPC exited (code=${code}, signal=${signal})`, this.stderrTail));
18341
+ }
18342
+ });
18343
+ await Promise.race([
18344
+ new Promise((resolve, reject) => {
18345
+ child.once("spawn", resolve);
18346
+ child.once("error", reject);
18347
+ }),
18348
+ new Promise((_resolve, reject) => setTimeout(() => reject(new Error("Omp RPC start timed out")), this.#options.commandTimeoutMs))
18349
+ ]);
18350
+ let readyTimeout;
18351
+ try {
18352
+ await Promise.race([
18353
+ this.#ready,
18354
+ this.#startupFault.then((error51) => {
18355
+ throw error51;
18356
+ }),
18357
+ new Promise((_resolve, reject) => {
18358
+ readyTimeout = setTimeout(() => reject(new Error("Omp RPC ready signal timed out")), this.#options.commandTimeoutMs);
18359
+ })
18360
+ ]);
18361
+ } finally {
18362
+ clearTimeout(readyTimeout);
18363
+ }
18364
+ await this.#send("negotiate_protocol", { protocolVersion: 2 }).catch(() => void 0);
18365
+ if (this.#options.subscribeSubagentEvents !== false) {
18366
+ await this.#send("set_subagent_subscription", { level: "events" }).catch(() => void 0);
18367
+ }
18368
+ try {
18369
+ this.#state = parseSessionState(await this.#send("get_state", {}));
18370
+ } catch (error51) {
18371
+ const fault = error51 instanceof OmpRpcFaultError ? error51 : new OmpRpcFaultError("unavailable", `Omp RPC state unavailable: ${message2(error51)}`);
18372
+ this.#fail(fault);
18373
+ throw fault;
18374
+ }
18375
+ return this;
18376
+ }
18377
+ async getEntries() {
18378
+ try {
18379
+ if (this.state.sessionFile) {
18380
+ try {
18381
+ return await readOmpSessionHistory(this.state.sessionFile);
18382
+ } catch (error51) {
18383
+ if (!isRecord8(error51) || error51.code !== "ENOENT" || this.#options.sessionFile || this.#options.forkSessionFile)
18384
+ throw error51;
18385
+ const response2 = await this.#send("get_messages", {});
18386
+ const data2 = isRecord8(response2.data) ? response2.data : null;
18387
+ if (data2 && Array.isArray(data2.messages) && data2.messages.length === 0) {
18388
+ return { entries: [], leafId: null };
18389
+ }
18390
+ throw error51;
18391
+ }
18392
+ }
18393
+ const response = await this.#send("get_messages", {});
18394
+ const data = isRecord8(response.data) ? response.data : null;
18395
+ if (!data || !Array.isArray(data.messages)) {
18396
+ throw new OmpRpcFaultError("protocolError", "Omp RPC messages response has no messages");
18397
+ }
18398
+ let branchEntryIds = null;
18399
+ try {
18400
+ const branchResponse = await this.#send("get_branch_messages", {});
18401
+ const branchData = isRecord8(branchResponse.data) ? branchResponse.data : null;
18402
+ if (branchData && Array.isArray(branchData.messages)) {
18403
+ const parsed = branchData.messages.flatMap((entry) => {
18404
+ if (!isRecord8(entry) || !nonBlankString(entry.entryId))
18405
+ return [];
18406
+ return [entry.entryId];
18407
+ });
18408
+ if (parsed.length === branchData.messages.length)
18409
+ branchEntryIds = parsed;
18410
+ }
18411
+ } catch (error51) {
18412
+ if (!(error51 instanceof OmpRpcUnsupportedCommandError))
18413
+ throw error51;
18414
+ }
18415
+ let userIndex = 0;
18416
+ let parentId = null;
18417
+ const entries = data.messages.map((nativeMessage, index) => {
18418
+ const role = isRecord8(nativeMessage) ? nativeMessage.role : void 0;
18419
+ const branchId = role === "user" ? branchEntryIds?.[userIndex] : void 0;
18420
+ if (branchId)
18421
+ userIndex += 1;
18422
+ const id = branchId ?? (isRecord8(nativeMessage) && nonBlankString(nativeMessage.id) ? nativeMessage.id : `omp-message-${index}`);
18423
+ const entry = { id, parentId, type: "message", message: nativeMessage };
18424
+ parentId = id;
18425
+ return entry;
18426
+ });
18427
+ return { entries, leafId: parentId };
18428
+ } catch (error51) {
18429
+ if (error51 instanceof OmpRpcFaultError)
18430
+ this.#fail(error51);
18431
+ throw error51;
18432
+ }
18433
+ }
18434
+ async getSubagentMessages(input) {
18435
+ if ((input.subagentId === void 0 || !nonBlankString(input.subagentId)) && (input.sessionFile === void 0 || !nonBlankString(input.sessionFile))) {
18436
+ throw new Error("Omp Subagent transcript requires a Subagent ID or Session file");
18437
+ }
18438
+ if (input.fromByte !== void 0 && (!Number.isSafeInteger(input.fromByte) || input.fromByte < 0)) {
18439
+ throw new Error("Omp Subagent transcript offset is invalid");
18440
+ }
18441
+ const response = await this.#send("get_subagent_messages", {
18442
+ ...input.subagentId ? { subagentId: input.subagentId } : {},
18443
+ ...input.sessionFile ? { sessionFile: input.sessionFile } : {},
18444
+ ...input.fromByte !== void 0 ? { fromByte: input.fromByte } : {}
18445
+ });
18446
+ return parseSubagentMessages(response);
18447
+ }
18448
+ async compact(customInstructions, onEvent) {
18449
+ if (!this.#child || !this.#state || this.#closed || this.#failed) {
18450
+ throw new Error("Omp RPC Session is unavailable");
18451
+ }
18452
+ if (this.#activeTurn || this.#manualCompaction || this.#compactionActive) {
18453
+ throw new Error("Omp RPC Session already has an active operation");
18454
+ }
18455
+ const result = new Promise((resolve, reject) => {
18456
+ this.#manualCompaction = { onEvent, resolve, reject };
18457
+ });
18458
+ try {
18459
+ await this.#send("compact", customInstructions ? { customInstructions } : {});
18460
+ } catch (error51) {
18461
+ const pending = this.#manualCompaction;
18462
+ this.#manualCompaction = null;
18463
+ pending?.reject(error51 instanceof Error ? error51 : new Error(message2(error51)));
18464
+ }
18465
+ return result;
18466
+ }
18467
+ async getSessionUsage() {
18468
+ try {
18469
+ const usage = parseOmpSessionUsage(await this.#send("get_session_stats", {}));
18470
+ await this.#ensureLatestCacheHitRate();
18471
+ return this.#withLatestCacheHitRate(usage);
18472
+ } catch (error51) {
18473
+ if (!(error51 instanceof OmpRpcUnsupportedCommandError))
18474
+ throw error51;
18475
+ const response = await this.#send("get_state", {});
18476
+ const observedState = parseSessionState(response);
18477
+ if (!this.#state || observedState.sessionId !== this.#state.sessionId || observedState.provider !== this.#state.provider || observedState.modelId !== this.#state.modelId) {
18478
+ throw new Error("Omp RPC Usage fallback does not match the confirmed Session state");
18479
+ }
18480
+ await this.#ensureLatestCacheHitRate();
18481
+ const usage = parseOmpStateContextUsage(response);
18482
+ return usage ? this.#withLatestCacheHitRate(usage) : null;
18483
+ }
18802
18484
  }
18803
- get state() {
18804
- if (!this.#state)
18805
- throw new Error("Omp RPC Session has not started");
18806
- return this.#state;
18485
+ async #ensureLatestCacheHitRate() {
18486
+ if (this.#latestCacheHitRatePercent !== void 0)
18487
+ return;
18488
+ try {
18489
+ this.#latestCacheHitRatePercent = latestOmpCacheHitRatePercent(await this.getEntries());
18490
+ } catch {
18491
+ this.#latestCacheHitRatePercent = null;
18492
+ }
18807
18493
  }
18808
- get stderrTail() {
18809
- return this.#stderrTail;
18494
+ #withLatestCacheHitRate(usage) {
18495
+ return this.#latestCacheHitRatePercent === null || this.#latestCacheHitRatePercent === void 0 ? usage : parseHostUsage({ ...usage, cacheHitRatePercent: this.#latestCacheHitRatePercent });
18810
18496
  }
18811
- async start() {
18812
- if (this.#child || this.#closed)
18813
- throw new Error("Omp RPC Session cannot be started twice");
18814
- const child = this.#processAdapter.spawn({
18815
- cwd: this.#options.cwd,
18816
- ...this.#options.command ? { command: this.#options.command } : {},
18817
- environment: withNodeRuntimeOnPath({
18818
- ...process.env,
18819
- ...this.#options.environment,
18820
- OMP_SKIP_VERSION_CHECK: "1",
18821
- OMP_TELEMETRY: "0"
18822
- }),
18823
- ...this.#options.sessionFile ? { sessionFile: this.#options.sessionFile } : {},
18824
- ...this.#options.forkSessionFile ? { forkSessionFile: this.#options.forkSessionFile } : {},
18825
- ...this.#options.model ? { model: this.#options.model } : {},
18826
- ...this.#options.permissionMode ? { permissionMode: this.#options.permissionMode } : {}
18827
- });
18828
- this.#child = child;
18829
- child.stdout.on("data", (chunk) => this.#push(chunk));
18830
- child.stdout.on("end", () => {
18831
- if (this.#buffer.length !== 0) {
18832
- this.#fail(new OmpRpcFaultError("protocolError", "Omp RPC stdout ended mid-frame"));
18497
+ async fork(entryId) {
18498
+ if (!nonBlankString(entryId))
18499
+ throw new Error("Omp RPC Fork requires an Entry identity");
18500
+ try {
18501
+ const response = await this.#send("branch", { entryId });
18502
+ const data = isRecord8(response.data) ? response.data : null;
18503
+ if (!data || data.cancelled === true) {
18504
+ throw new OmpRpcFaultError("unavailable", "Omp RPC Fork was cancelled");
18833
18505
  }
18506
+ this.#state = parseSessionState(await this.#send("get_state", {}));
18507
+ return this.#state;
18508
+ } catch (error51) {
18509
+ if (error51 instanceof OmpRpcFaultError)
18510
+ this.#fail(error51);
18511
+ throw error51;
18512
+ }
18513
+ }
18514
+ verifySessionCwd(expectedCwd) {
18515
+ return verifyOmpSessionCwd({
18516
+ sessionFile: this.state.sessionFile,
18517
+ sessionId: this.state.sessionId,
18518
+ expectedCwd
18834
18519
  });
18835
- child.stderr.on("data", (chunk) => {
18836
- this.#stderrTail = sanitizeDiagnosticTail(`${this.#stderrTail}${chunk.toString()}`);
18837
- });
18838
- child.once("error", (error51) => {
18839
- const kind = isRecord8(error51) && error51.code === "ENOENT" ? "notInstalled" : "unavailable";
18840
- this.#fail(new OmpRpcFaultError(kind, `Omp RPC failed to start: ${error51.message}`, this.stderrTail));
18841
- });
18842
- child.once("exit", (code, signal) => {
18843
- if (!this.#closed) {
18844
- this.#fail(new OmpRpcFaultError("processExited", `Omp RPC exited (code=${code}, signal=${signal})`, this.stderrTail));
18845
- }
18520
+ }
18521
+ async getAvailableModels() {
18522
+ try {
18523
+ return parseAvailableModels(await this.#send("get_available_models", {}));
18524
+ } catch (error51) {
18525
+ if (error51 instanceof OmpRpcFaultError)
18526
+ this.#fail(error51);
18527
+ throw error51;
18528
+ }
18529
+ }
18530
+ async getAvailableThinkingLevels() {
18531
+ return this.state.availableThinkingLevels;
18532
+ }
18533
+ async selectModel(model2) {
18534
+ await this.#send("set_model", { provider: model2.provider, modelId: model2.id });
18535
+ return this.#refreshState("Model");
18536
+ }
18537
+ async selectThinkingOption(thinkingOptionId) {
18538
+ const level = harnessThinkingOptionIdSchema.parse(thinkingOptionId);
18539
+ await this.#send("set_thinking_level", { level });
18540
+ return this.#refreshState("Thinking");
18541
+ }
18542
+ async #refreshState(operation) {
18543
+ try {
18544
+ this.#state = parseSessionState(await this.#send("get_state", {}));
18545
+ return this.#state;
18546
+ } catch (error51) {
18547
+ const fault = error51 instanceof OmpRpcFaultError ? error51 : new OmpRpcFaultError("protocolError", `Omp RPC ${operation} state could not be confirmed: ${message2(error51)}`);
18548
+ this.#fail(fault);
18549
+ throw fault;
18550
+ }
18551
+ }
18552
+ async runTurn(text, onEvent) {
18553
+ if (!this.#child || !this.#state || this.#closed || this.#failed) {
18554
+ throw new Error("Omp RPC Session is unavailable");
18555
+ }
18556
+ if (this.#activeTurn)
18557
+ throw new Error("Omp RPC Session already has an active Turn");
18558
+ if (text.length === 0)
18559
+ throw new Error("Omp text Turn must not be empty");
18560
+ const promptId = `codexhost-${randomUUID()}`;
18561
+ const settled = new Promise((resolve, reject) => {
18562
+ this.#activeTurn = {
18563
+ promptId,
18564
+ localResult: null,
18565
+ text: "",
18566
+ assistantMessageId: null,
18567
+ sawStreamedMessageText: false,
18568
+ sawStreamedMessageReasoning: false,
18569
+ lastFinalizedMessageText: null,
18570
+ lastFinalizedMessageReasoning: null,
18571
+ reasoningMessageOpen: false,
18572
+ onEvent,
18573
+ resolve,
18574
+ reject,
18575
+ failure: null,
18576
+ sawTool: false,
18577
+ tools: /* @__PURE__ */ new Map(),
18578
+ interactions: /* @__PURE__ */ new Map(),
18579
+ settlement: "pending",
18580
+ terminalEnd: false,
18581
+ cancellation: "none",
18582
+ cancellationTimeout: null,
18583
+ cancellationRecheck: null,
18584
+ cancellationChecking: false,
18585
+ cancellationReloaded: false,
18586
+ abortPromise: null
18587
+ };
18846
18588
  });
18847
- await Promise.race([
18848
- new Promise((resolve, reject) => {
18849
- child.once("spawn", resolve);
18850
- child.once("error", reject);
18851
- }),
18852
- new Promise((_resolve, reject) => setTimeout(() => reject(new Error("Omp RPC start timed out")), this.#options.commandTimeoutMs))
18853
- ]);
18854
- let readyTimeout;
18855
18589
  try {
18856
- await Promise.race([
18857
- this.#ready,
18858
- this.#startupFault.then((error51) => {
18859
- throw error51;
18860
- }),
18861
- new Promise((_resolve, reject) => {
18862
- readyTimeout = setTimeout(() => reject(new Error("Omp RPC ready signal timed out")), this.#options.commandTimeoutMs);
18863
- })
18864
- ]);
18865
- } finally {
18866
- clearTimeout(readyTimeout);
18590
+ await this.#send("prompt", { message: text }, promptId);
18591
+ } catch (error51) {
18592
+ this.#rejectActiveTurn(error51 instanceof Error ? error51 : new Error(message2(error51)));
18867
18593
  }
18868
- await this.#send("negotiate_protocol", { protocolVersion: 2 }).catch(() => void 0);
18869
- if (this.#options.subscribeSubagentEvents !== false) {
18870
- await this.#send("set_subagent_subscription", { level: "events" }).catch(() => void 0);
18594
+ return settled;
18595
+ }
18596
+ respondToInteraction(response) {
18597
+ return this.#resolveInteraction(response, "cancelled" in response ? "cancelled" : "responded");
18598
+ }
18599
+ async #resolveInteraction(response, reason) {
18600
+ const active = this.#activeTurn;
18601
+ const pending = active?.interactions.get(response.requestId);
18602
+ if (!active || !pending || this.#closed || this.#failed) {
18603
+ throw new Error("Omp RPC interaction is not pending");
18604
+ }
18605
+ if ("value" in response && !["select", "input", "editor"].includes(pending.request.method)) {
18606
+ throw new Error("Omp RPC interaction response type does not match the request");
18607
+ }
18608
+ if ("confirmed" in response && pending.request.method !== "confirm") {
18609
+ throw new Error("Omp RPC confirmation does not match the request");
18610
+ }
18611
+ const frame = "cancelled" in response ? {
18612
+ type: "extension_ui_response",
18613
+ id: response.requestId,
18614
+ cancelled: true,
18615
+ ...reason === "expired" ? { timedOut: true } : {}
18616
+ } : "confirmed" in response ? { type: "extension_ui_response", id: response.requestId, confirmed: response.confirmed } : { type: "extension_ui_response", id: response.requestId, value: response.value };
18617
+ if (!active.interactions.delete(response.requestId)) {
18618
+ throw new Error("Omp RPC interaction is not pending");
18871
18619
  }
18620
+ if (pending.timeout)
18621
+ clearTimeout(pending.timeout);
18622
+ active.onEvent({ type: "interaction.closed", requestId: response.requestId, reason });
18872
18623
  try {
18873
- this.#state = parseSessionState(await this.#send("get_state", {}));
18624
+ await this.#write(frame);
18874
18625
  } catch (error51) {
18875
- const fault = error51 instanceof OmpRpcFaultError ? error51 : new OmpRpcFaultError("unavailable", `Omp RPC state unavailable: ${message2(error51)}`);
18626
+ const fault = new OmpRpcFaultError("protocolError", `Omp RPC interaction response failed: ${message2(error51)}`);
18876
18627
  this.#fail(fault);
18877
18628
  throw fault;
18878
18629
  }
18879
- return this;
18880
18630
  }
18881
- async getEntries() {
18882
- try {
18883
- if (this.state.sessionFile) {
18884
- try {
18885
- return await readOmpSessionHistory(this.state.sessionFile);
18886
- } catch (error51) {
18887
- if (!isRecord8(error51) || error51.code !== "ENOENT" || this.#options.sessionFile || this.#options.forkSessionFile)
18888
- throw error51;
18889
- const response2 = await this.#send("get_messages", {});
18890
- const data2 = isRecord8(response2.data) ? response2.data : null;
18891
- if (data2 && Array.isArray(data2.messages) && data2.messages.length === 0) {
18892
- return { entries: [], leafId: null };
18893
- }
18894
- throw error51;
18895
- }
18896
- }
18897
- const response = await this.#send("get_messages", {});
18898
- const data = isRecord8(response.data) ? response.data : null;
18899
- if (!data || !Array.isArray(data.messages)) {
18900
- throw new OmpRpcFaultError("protocolError", "Omp RPC messages response has no messages");
18631
+ abort() {
18632
+ const active = this.#activeTurn;
18633
+ if (!active || this.#closed || this.#failed) {
18634
+ return Promise.reject(new Error("Omp RPC Session has no cancellable Turn"));
18635
+ }
18636
+ if (active.abortPromise)
18637
+ return active.abortPromise;
18638
+ active.cancellation = "requesting";
18639
+ active.cancellationTimeout = setTimeout(() => {
18640
+ this.#terminateFailedCancellation(active, new OmpRpcFaultError("protocolError", "Omp Turn cancellation did not settle within its bound"));
18641
+ }, this.#options.cancelTimeoutMs);
18642
+ const aborting = this.#send("abort", {}).then(async () => {
18643
+ if (this.#activeTurn !== active)
18644
+ return;
18645
+ active.cancellation = "accepted";
18646
+ await this.#confirmCancelledTurn(active);
18647
+ }).catch((error51) => {
18648
+ if (this.#activeTurn !== active)
18649
+ throw error51;
18650
+ const fault = error51 instanceof OmpRpcFaultError ? error51 : new OmpRpcFaultError("protocolError", `Omp RPC Abort failed: ${message2(error51)}`);
18651
+ this.#terminateFailedCancellation(active, fault);
18652
+ throw fault;
18653
+ });
18654
+ active.abortPromise = aborting;
18655
+ return aborting;
18656
+ }
18657
+ #terminateFailedCancellation(active, fault) {
18658
+ if (this.#activeTurn !== active)
18659
+ return;
18660
+ if (active.cancellationTimeout)
18661
+ clearTimeout(active.cancellationTimeout);
18662
+ active.cancellationTimeout = null;
18663
+ this.#fail(fault);
18664
+ void this.close().catch(() => void 0);
18665
+ }
18666
+ close() {
18667
+ if (!this.#closed) {
18668
+ this.#closed = true;
18669
+ this.#rejectAll(new Error("Omp RPC Session closed"));
18670
+ }
18671
+ this.#closePromise ??= this.#stopProcess();
18672
+ return this.#closePromise;
18673
+ }
18674
+ async #stopProcess() {
18675
+ const child = this.#child;
18676
+ if (!child)
18677
+ return;
18678
+ if (child.stdin.writable)
18679
+ child.stdin.end();
18680
+ if (await waitForExit(child, this.#options.closeTimeoutMs))
18681
+ return;
18682
+ signalProcessTree(child, "SIGTERM");
18683
+ if (await waitForExit(child, this.#options.closeTimeoutMs))
18684
+ return;
18685
+ signalProcessTree(child, "SIGKILL");
18686
+ if (!await waitForExit(child, this.#options.closeTimeoutMs)) {
18687
+ throw new Error("Omp RPC process tree did not exit within cleanup bounds");
18688
+ }
18689
+ }
18690
+ #push(chunk) {
18691
+ this.#buffer = this.#buffer.length === 0 ? chunk : Buffer.concat([this.#buffer, chunk]);
18692
+ let newline = this.#buffer.indexOf(10);
18693
+ while (newline >= 0) {
18694
+ const frame = this.#buffer.subarray(0, newline);
18695
+ this.#buffer = this.#buffer.subarray(newline + 1);
18696
+ let parsed;
18697
+ try {
18698
+ parsed = JSON.parse(textDecoder.decode(frame));
18699
+ } catch (error51) {
18700
+ this.#fail(new OmpRpcFaultError("protocolError", `Omp RPC returned invalid JSONL: ${message2(error51)}`));
18701
+ newline = this.#buffer.indexOf(10);
18702
+ continue;
18901
18703
  }
18902
- let branchEntryIds = null;
18903
18704
  try {
18904
- const branchResponse = await this.#send("get_branch_messages", {});
18905
- const branchData = isRecord8(branchResponse.data) ? branchResponse.data : null;
18906
- if (branchData && Array.isArray(branchData.messages)) {
18907
- const parsed = branchData.messages.flatMap((entry) => {
18908
- if (!isRecord8(entry) || !nonBlankString(entry.entryId))
18909
- return [];
18910
- return [entry.entryId];
18911
- });
18912
- if (parsed.length === branchData.messages.length)
18913
- branchEntryIds = parsed;
18705
+ const decoded = this.#frameDecoder.push(parsed);
18706
+ if (decoded === null) {
18707
+ newline = this.#buffer.indexOf(10);
18708
+ continue;
18709
+ }
18710
+ const value = decoded;
18711
+ if (!isRecord8(value) || typeof value.type !== "string") {
18712
+ throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid envelope");
18914
18713
  }
18714
+ this.#handle(value);
18915
18715
  } catch (error51) {
18916
- if (!(error51 instanceof OmpRpcUnsupportedCommandError))
18917
- throw error51;
18716
+ this.#fail(error51 instanceof OmpRpcFaultError ? error51 : new OmpRpcFaultError("protocolError", `Omp RPC frame handling failed: ${message2(error51)}`));
18918
18717
  }
18919
- let userIndex = 0;
18920
- let parentId = null;
18921
- const entries = data.messages.map((nativeMessage, index) => {
18922
- const role = isRecord8(nativeMessage) ? nativeMessage.role : void 0;
18923
- const branchId = role === "user" ? branchEntryIds?.[userIndex] : void 0;
18924
- if (branchId)
18925
- userIndex += 1;
18926
- const id = branchId ?? (isRecord8(nativeMessage) && nonBlankString(nativeMessage.id) ? nativeMessage.id : `omp-message-${index}`);
18927
- const entry = { id, parentId, type: "message", message: nativeMessage };
18928
- parentId = id;
18929
- return entry;
18930
- });
18931
- return { entries, leafId: parentId };
18932
- } catch (error51) {
18933
- if (error51 instanceof OmpRpcFaultError)
18934
- this.#fail(error51);
18935
- throw error51;
18718
+ newline = this.#buffer.indexOf(10);
18936
18719
  }
18937
18720
  }
18938
- async getSubagentMessages(input) {
18939
- if ((input.subagentId === void 0 || !nonBlankString(input.subagentId)) && (input.sessionFile === void 0 || !nonBlankString(input.sessionFile))) {
18940
- throw new Error("Omp Subagent transcript requires a Subagent ID or Session file");
18721
+ /** Latest `available_commands_update` of the running process, if any. */
18722
+ get availableCommands() {
18723
+ return this.#availableCommands;
18724
+ }
18725
+ #handle(value) {
18726
+ if (this.#closed || this.#failed)
18727
+ return;
18728
+ if (value.type === "available_commands_update") {
18729
+ this.#availableCommands = parseOmpAvailableCommands(value.commands);
18730
+ return;
18941
18731
  }
18942
- if (input.fromByte !== void 0 && (!Number.isSafeInteger(input.fromByte) || input.fromByte < 0)) {
18943
- throw new Error("Omp Subagent transcript offset is invalid");
18732
+ if (value.type === "ready") {
18733
+ this.#readyResolve?.();
18734
+ this.#readyResolve = null;
18735
+ return;
18736
+ }
18737
+ if (value.type === "response") {
18738
+ this.#handleResponse(value);
18739
+ return;
18740
+ }
18741
+ if (value.type === "auto_compaction_start" || value.type === "compaction_start") {
18742
+ this.#compactionActive = true;
18743
+ this.#compactionTurn = this.#activeTurn;
18744
+ this.#compactionTimeout ??= setTimeout(() => {
18745
+ this.#compactionTimeout = null;
18746
+ this.#fail(new OmpRpcFaultError("protocolError", `Omp RPC compaction timed out after ${this.#options.compactionTimeoutMs}ms`));
18747
+ }, this.#options.compactionTimeoutMs);
18748
+ const onEvent = this.#activeTurn?.onEvent ?? this.#manualCompaction?.onEvent;
18749
+ onEvent?.({ type: "compaction.started" });
18750
+ for (const pending of this.#pending.values()) {
18751
+ if (pending.command !== "prompt" && pending.command !== "compact" || !pending.timeout)
18752
+ continue;
18753
+ clearTimeout(pending.timeout);
18754
+ pending.timeout = null;
18755
+ }
18756
+ return;
18757
+ }
18758
+ if (value.type === "auto_compaction_end" || value.type === "compaction_end") {
18759
+ this.#compactionActive = false;
18760
+ if (this.#compactionTimeout)
18761
+ clearTimeout(this.#compactionTimeout);
18762
+ this.#compactionTimeout = null;
18763
+ const compactionTurn = this.#compactionTurn;
18764
+ this.#compactionTurn = null;
18765
+ for (const [id, pending] of this.#pending) {
18766
+ if (pending.command === "prompt" || pending.command === "compact") {
18767
+ this.#armCommandTimeout(id, pending);
18768
+ }
18769
+ }
18770
+ const outcome = value.aborted === true ? "cancelled" : isRecord8(value.result) ? "succeeded" : "failed";
18771
+ const event = {
18772
+ type: "compaction.completed",
18773
+ outcome,
18774
+ ...nonBlankString(value.errorMessage) ? { errorMessage: value.errorMessage } : {}
18775
+ };
18776
+ compactionTurn?.onEvent(event);
18777
+ const manual = this.#manualCompaction;
18778
+ this.#manualCompaction = null;
18779
+ manual?.onEvent(event);
18780
+ manual?.resolve({
18781
+ outcome,
18782
+ ...event.errorMessage ? { errorMessage: event.errorMessage } : {}
18783
+ });
18784
+ return;
18785
+ }
18786
+ const active = this.#activeTurn;
18787
+ if (this.#handleSubagentFrame(active, value))
18788
+ return;
18789
+ this.#observeUsage(value);
18790
+ if (value.type === "agent_start" && active)
18791
+ active.terminalEnd = false;
18792
+ if ((value.type === "session_settled" || value.type === "agent_start") && active?.cancellation === "accepted") {
18793
+ void this.#confirmCancelledTurn(active);
18794
+ return;
18795
+ }
18796
+ if (!active) {
18797
+ if (value.type === "extension_ui_request" && this.#isBlockingInteraction(value)) {
18798
+ this.#fail(new OmpRpcFaultError("protocolError", "Omp RPC requested blocking Extension UI outside an active Turn"));
18799
+ }
18800
+ return;
18801
+ }
18802
+ if (value.type === "command_output") {
18803
+ if (active.settlement !== "pending")
18804
+ return;
18805
+ if (typeof value.text !== "string") {
18806
+ throw new OmpRpcFaultError("protocolError", "Omp RPC returned invalid command output");
18807
+ }
18808
+ active.text += value.text;
18809
+ active.onEvent({ type: "text.delta", messageId: active.promptId, delta: value.text });
18810
+ return;
18811
+ }
18812
+ if (value.type === "prompt_result") {
18813
+ if (value.id !== active.promptId || value.agentInvoked !== false)
18814
+ return;
18815
+ if (value.status === "completed" || value.status === "aborted") {
18816
+ this.#settleLocalTurn(active, { cancelled: value.status === "aborted" });
18817
+ } else if (value.status === "error" && isRecord8(value.error) && typeof value.error.message === "string") {
18818
+ this.#settleLocalTurn(active, { cancelled: false, error: value.error.message });
18819
+ } else {
18820
+ throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid local prompt result");
18821
+ }
18822
+ return;
18823
+ }
18824
+ if (value.type === "extension_ui_request") {
18825
+ this.#startInteraction(active, value);
18826
+ return;
18827
+ }
18828
+ if (value.type === "message_start" && assistantText(value.message) !== null) {
18829
+ this.#startAssistantMessage(active, value.message);
18830
+ return;
18831
+ }
18832
+ if (value.type === "message_update" && isRecord8(value.assistantMessageEvent)) {
18833
+ const event = value.assistantMessageEvent;
18834
+ const eventType = String(event.type ?? "");
18835
+ const isThinking = eventType === "thinking_delta" || eventType === "reasoning_delta" || eventType === "thought_delta" || eventType === "thinking" || eventType === "reasoning";
18836
+ const isText = eventType === "text_delta" || eventType === "text" || eventType === "content_block_delta";
18837
+ 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;
18838
+ if (isThinking && delta !== null && delta.length > 0) {
18839
+ const messageId = this.#ensureAssistantMessage(active, value.message);
18840
+ active.reasoningMessageOpen = true;
18841
+ active.sawStreamedMessageReasoning = true;
18842
+ active.onEvent({ type: "reasoning.delta", messageId, delta });
18843
+ } else if (isText && delta !== null && delta.length > 0) {
18844
+ const messageId = this.#ensureAssistantMessage(active, value.message);
18845
+ active.text += delta;
18846
+ active.sawStreamedMessageText = true;
18847
+ active.onEvent({ type: "text.delta", messageId, delta });
18848
+ } else if (event.type === "error") {
18849
+ this.#ensureAssistantMessage(active, value.message);
18850
+ active.failure = assistantFailure(event.error) ?? assistantFailure(value.message) ?? new Error("Omp assistant message failed");
18851
+ }
18852
+ return;
18853
+ }
18854
+ if (value.type === "message_end") {
18855
+ this.#finalizeAssistantMessage(active, value.message);
18856
+ return;
18857
+ }
18858
+ if (value.type === "turn_end") {
18859
+ this.#finalizeAssistantMessage(active, value.message);
18860
+ return;
18861
+ }
18862
+ if (value.type === "tool_execution_start") {
18863
+ this.#startTool(active, value);
18864
+ return;
18865
+ }
18866
+ if (value.type === "tool_execution_update") {
18867
+ this.#updateTool(active, value);
18868
+ return;
18869
+ }
18870
+ if (value.type === "tool_execution_end") {
18871
+ this.#completeTool(active, value);
18872
+ return;
18873
+ }
18874
+ if (value.type === "agent_end" && Array.isArray(value.messages)) {
18875
+ for (let index = value.messages.length - 1; index >= 0; index -= 1) {
18876
+ const message3 = value.messages[index];
18877
+ if (!isRecord8(message3) || message3.role !== "assistant")
18878
+ continue;
18879
+ this.#finalizeAssistantMessage(active, message3);
18880
+ break;
18881
+ }
18882
+ }
18883
+ if (value.type === "agent_end" && value.isTerminal !== false) {
18884
+ active.terminalEnd = true;
18885
+ if (active.cancellation !== "none") {
18886
+ if (active.cancellation === "accepted")
18887
+ void this.#confirmCancelledTurn(active);
18888
+ return;
18889
+ }
18890
+ if (active.settlement !== "pending")
18891
+ return;
18892
+ active.settlement = "confirming";
18893
+ void this.#confirmSettledTurn(active);
18944
18894
  }
18945
- const response = await this.#send("get_subagent_messages", {
18946
- ...input.subagentId ? { subagentId: input.subagentId } : {},
18947
- ...input.sessionFile ? { sessionFile: input.sessionFile } : {},
18948
- ...input.fromByte !== void 0 ? { fromByte: input.fromByte } : {}
18949
- });
18950
- return parseSubagentMessages(response);
18951
18895
  }
18952
- async compact(customInstructions, onEvent) {
18953
- if (!this.#child || !this.#state || this.#closed || this.#failed) {
18954
- throw new Error("Omp RPC Session is unavailable");
18896
+ /** Every finished assistant message is one model request, with or without an active Turn. */
18897
+ #observeUsage(value) {
18898
+ if (value.type === "message_start") {
18899
+ this.#usageRequestStartedAtMs = null;
18900
+ return;
18955
18901
  }
18956
- if (this.#activeTurn || this.#manualCompaction || this.#compactionActive) {
18957
- throw new Error("Omp RPC Session already has an active operation");
18902
+ if (value.type === "message_update") {
18903
+ const event = value.assistantMessageEvent;
18904
+ if (this.#usageRequestStartedAtMs === null && isRecord8(event) && typeof event.type === "string" && /^(text|thinking|reasoning|thought|toolcall)_(start|delta)$/u.test(event.type)) {
18905
+ this.#usageRequestStartedAtMs = Date.now();
18906
+ }
18907
+ return;
18958
18908
  }
18959
- const result = new Promise((resolve, reject) => {
18960
- this.#manualCompaction = { onEvent, resolve, reject };
18961
- });
18962
- try {
18963
- await this.#send("compact", customInstructions ? { customInstructions } : {});
18964
- } catch (error51) {
18965
- const pending = this.#manualCompaction;
18966
- this.#manualCompaction = null;
18967
- pending?.reject(error51 instanceof Error ? error51 : new Error(message2(error51)));
18909
+ if (value.type === "message_end" && isRecord8(value.message)) {
18910
+ if (value.message.role !== "assistant")
18911
+ return;
18912
+ const startedAtMs = this.#usageRequestStartedAtMs;
18913
+ this.#usageRequestStartedAtMs = null;
18914
+ this.#options.onUsage?.({
18915
+ message: value.message,
18916
+ startedAtMs,
18917
+ completedAtMs: Date.now()
18918
+ });
18968
18919
  }
18969
- return result;
18970
18920
  }
18971
- async getSessionUsage() {
18972
- try {
18973
- const usage = parseOmpSessionUsage(await this.#send("get_session_stats", {}));
18974
- await this.#ensureLatestCacheHitRate();
18975
- return this.#withLatestCacheHitRate(usage);
18976
- } catch (error51) {
18977
- if (!(error51 instanceof OmpRpcUnsupportedCommandError))
18978
- throw error51;
18979
- const response = await this.#send("get_state", {});
18980
- const observedState = parseSessionState(response);
18981
- if (!this.#state || observedState.sessionId !== this.#state.sessionId || observedState.provider !== this.#state.provider || observedState.modelId !== this.#state.modelId) {
18982
- throw new Error("Omp RPC Usage fallback does not match the confirmed Session state");
18983
- }
18984
- await this.#ensureLatestCacheHitRate();
18985
- const usage = parseOmpStateContextUsage(response);
18986
- return usage ? this.#withLatestCacheHitRate(usage) : null;
18921
+ #handleSubagentFrame(active, value) {
18922
+ if (value.type !== "subagent_lifecycle" && value.type !== "subagent_progress" && value.type !== "subagent_event") {
18923
+ return false;
18987
18924
  }
18988
- }
18989
- async #ensureLatestCacheHitRate() {
18990
- if (this.#latestCacheHitRatePercent !== void 0)
18991
- return;
18992
- try {
18993
- this.#latestCacheHitRatePercent = latestOmpCacheHitRatePercent(await this.getEntries());
18994
- } catch {
18995
- this.#latestCacheHitRatePercent = null;
18925
+ const payload = isRecord8(value.payload) ? value.payload : null;
18926
+ const progressPayload = value.type === "subagent_progress" && payload && isRecord8(payload.progress) ? payload.progress : null;
18927
+ const nativeIdValue = progressPayload?.id ?? payload?.id;
18928
+ if (!payload || !nonBlankString(nativeIdValue)) {
18929
+ throw new OmpRpcFaultError("protocolError", "Omp RPC Subagent frame has no stable ID");
18996
18930
  }
18997
- }
18998
- #withLatestCacheHitRate(usage) {
18999
- return this.#latestCacheHitRatePercent === null || this.#latestCacheHitRatePercent === void 0 ? usage : parseHostUsage({ ...usage, cacheHitRatePercent: this.#latestCacheHitRatePercent });
19000
- }
19001
- async fork(entryId) {
19002
- if (!nonBlankString(entryId))
19003
- throw new Error("Omp RPC Fork requires an Entry identity");
19004
- try {
19005
- const response = await this.#send("branch", { entryId });
19006
- const data = isRecord8(response.data) ? response.data : null;
19007
- if (!data || data.cancelled === true) {
19008
- throw new OmpRpcFaultError("unavailable", "Omp RPC Fork was cancelled");
18931
+ const nativeSubagentId = nativeIdValue;
18932
+ const callId = nativeSubagentId;
18933
+ const emit = active?.onEvent ?? this.#options.onSubagentEvent;
18934
+ if (value.type === "subagent_event") {
18935
+ emit?.({ type: "subagent.transcript.changed", callId, nativeSubagentId });
18936
+ return true;
18937
+ }
18938
+ if (value.type === "subagent_lifecycle") {
18939
+ const status2 = payload.status;
18940
+ if (status2 === "started") {
18941
+ const description = nonBlankString(payload.description) ? payload.description : nonBlankString(payload.agent) ? `${payload.agent} delegation` : "Subagent delegation";
18942
+ emit?.({
18943
+ type: "subagent.started",
18944
+ callId,
18945
+ nativeSubagentId,
18946
+ description,
18947
+ ...nonBlankString(payload.agent) ? { role: payload.agent } : {},
18948
+ ...nonBlankString(payload.task) ? { prompt: payload.task } : {},
18949
+ background: payload.detached === true,
18950
+ ...typeof payload.sessionFile === "string" ? { sessionFile: payload.sessionFile } : {}
18951
+ });
18952
+ return true;
19009
18953
  }
19010
- this.#state = parseSessionState(await this.#send("get_state", {}));
19011
- return this.#state;
19012
- } catch (error51) {
19013
- if (error51 instanceof OmpRpcFaultError)
19014
- this.#fail(error51);
19015
- throw error51;
18954
+ if (status2 !== "completed" && status2 !== "failed" && status2 !== "aborted") {
18955
+ throw new OmpRpcFaultError("protocolError", "Omp RPC Subagent lifecycle status is invalid");
18956
+ }
18957
+ emit?.({
18958
+ type: "subagent.completed",
18959
+ callId,
18960
+ nativeSubagentId,
18961
+ isError: status2 !== "completed",
18962
+ ...nonBlankString(payload.resultSummary) ? { resultSummary: payload.resultSummary } : {},
18963
+ ...typeof payload.sessionFile === "string" ? { sessionFile: payload.sessionFile } : {}
18964
+ });
18965
+ return true;
19016
18966
  }
19017
- }
19018
- verifySessionCwd(expectedCwd) {
19019
- return verifyOmpSessionCwd({
19020
- sessionFile: this.state.sessionFile,
19021
- sessionId: this.state.sessionId,
19022
- expectedCwd
19023
- });
19024
- }
19025
- async getAvailableModels() {
19026
- try {
19027
- return parseAvailableModels(await this.#send("get_available_models", {}));
19028
- } catch (error51) {
19029
- if (error51 instanceof OmpRpcFaultError)
19030
- this.#fail(error51);
19031
- throw error51;
18967
+ const progress = progressPayload;
18968
+ if (!progress || !nonBlankString(progress.id) || progress.id !== nativeSubagentId) {
18969
+ throw new OmpRpcFaultError("protocolError", "Omp RPC Subagent progress is invalid");
19032
18970
  }
18971
+ const status = subagentStatus(progress.status);
18972
+ const recentOutput = Array.isArray(progress.recentOutput) ? progress.recentOutput.filter((item) => typeof item === "string") : [];
18973
+ const resultSummary = recentOutput.at(-1);
18974
+ emit?.({
18975
+ type: "subagent.updated",
18976
+ callId,
18977
+ nativeSubagentId,
18978
+ status,
18979
+ ...nonBlankString(progress.description) ? { description: progress.description } : nonBlankString(payload.task) ? { description: payload.task } : {},
18980
+ ...resultSummary !== void 0 ? { resultSummary } : {},
18981
+ ...typeof payload.sessionFile === "string" ? { sessionFile: payload.sessionFile } : {}
18982
+ });
18983
+ return true;
19033
18984
  }
19034
- async getAvailableThinkingLevels() {
19035
- return this.state.availableThinkingLevels;
19036
- }
19037
- async selectModel(model2) {
19038
- await this.#send("set_model", { provider: model2.provider, modelId: model2.id });
19039
- return this.#refreshState("Model");
19040
- }
19041
- async selectThinkingOption(thinkingOptionId) {
19042
- const level = harnessThinkingOptionIdSchema.parse(thinkingOptionId);
19043
- await this.#send("set_thinking_level", { level });
19044
- return this.#refreshState("Thinking");
19045
- }
19046
- async #refreshState(operation) {
19047
- try {
19048
- this.#state = parseSessionState(await this.#send("get_state", {}));
19049
- return this.#state;
19050
- } catch (error51) {
19051
- const fault = error51 instanceof OmpRpcFaultError ? error51 : new OmpRpcFaultError("protocolError", `Omp RPC ${operation} state could not be confirmed: ${message2(error51)}`);
19052
- this.#fail(fault);
19053
- throw fault;
19054
- }
18985
+ #isBlockingInteraction(value) {
18986
+ return ["select", "confirm", "input", "editor"].includes(String(value.method));
19055
18987
  }
19056
- async runTurn(text, onEvent) {
19057
- if (!this.#child || !this.#state || this.#closed || this.#failed) {
19058
- throw new Error("Omp RPC Session is unavailable");
18988
+ #startInteraction(active, value) {
18989
+ if (!this.#isBlockingInteraction(value))
18990
+ return;
18991
+ const requestId = value.id;
18992
+ const method = value.method;
18993
+ const title = value.title;
18994
+ const timeoutMs = value.timeout;
18995
+ if (typeof requestId !== "string" || requestId.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(requestId)) {
18996
+ throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid Interaction request");
19059
18997
  }
19060
- if (this.#activeTurn)
19061
- throw new Error("Omp RPC Session already has an active Turn");
19062
- if (text.length === 0)
19063
- throw new Error("Omp text Turn must not be empty");
19064
- const promptId = `codexhost-${randomUUID()}`;
19065
- const settled = new Promise((resolve, reject) => {
19066
- this.#activeTurn = {
19067
- promptId,
19068
- localResult: null,
19069
- text: "",
19070
- assistantMessageId: null,
19071
- sawStreamedMessageText: false,
19072
- sawStreamedMessageReasoning: false,
19073
- lastFinalizedMessageText: null,
19074
- lastFinalizedMessageReasoning: null,
19075
- reasoningMessageOpen: false,
19076
- onEvent,
19077
- resolve,
19078
- reject,
19079
- failure: null,
19080
- sawTool: false,
19081
- tools: /* @__PURE__ */ new Map(),
19082
- interactions: /* @__PURE__ */ new Map(),
19083
- settlement: "pending",
19084
- terminalEnd: false,
19085
- cancellation: "none",
19086
- cancellationTimeout: null,
19087
- cancellationRecheck: null,
19088
- cancellationChecking: false,
19089
- cancellationReloaded: false,
19090
- abortPromise: null
18998
+ let request;
18999
+ if (method === "select") {
19000
+ if (!Array.isArray(value.options) || value.options.length === 0 || !value.options.every((option) => typeof option === "string" && option.length > 0)) {
19001
+ throw new OmpRpcFaultError("protocolError", "Omp RPC select request has invalid options");
19002
+ }
19003
+ let optionDetails;
19004
+ if (value.optionDetails !== void 0) {
19005
+ 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"))) {
19006
+ throw new OmpRpcFaultError("protocolError", "Omp RPC select option details are invalid");
19007
+ }
19008
+ optionDetails = value.optionDetails.map(({ description }) => description === void 0 ? {} : { description });
19009
+ }
19010
+ request = {
19011
+ requestId,
19012
+ method,
19013
+ title,
19014
+ options: [...value.options],
19015
+ ...optionDetails ? { optionDetails } : {},
19016
+ ...typeof timeoutMs === "number" ? { timeoutMs } : {}
19017
+ };
19018
+ } else if (method === "confirm") {
19019
+ if (typeof value.message !== "string") {
19020
+ throw new OmpRpcFaultError("protocolError", "Omp RPC confirm request has no message");
19021
+ }
19022
+ request = {
19023
+ requestId,
19024
+ method,
19025
+ title,
19026
+ message: value.message,
19027
+ ...typeof timeoutMs === "number" ? { timeoutMs } : {}
19028
+ };
19029
+ } else if (method === "input") {
19030
+ if (value.placeholder !== void 0 && typeof value.placeholder !== "string") {
19031
+ throw new OmpRpcFaultError("protocolError", "Omp RPC input placeholder is invalid");
19032
+ }
19033
+ request = {
19034
+ requestId,
19035
+ method,
19036
+ title,
19037
+ ...typeof value.placeholder === "string" ? { placeholder: value.placeholder } : {},
19038
+ ...typeof timeoutMs === "number" ? { timeoutMs } : {}
19039
+ };
19040
+ } else {
19041
+ if (value.prefill !== void 0 && typeof value.prefill !== "string") {
19042
+ throw new OmpRpcFaultError("protocolError", "Omp RPC editor prefill is invalid");
19043
+ }
19044
+ request = {
19045
+ requestId,
19046
+ method: "editor",
19047
+ title,
19048
+ ...typeof value.prefill === "string" ? { prefill: value.prefill } : {},
19049
+ ...typeof timeoutMs === "number" ? { timeoutMs } : {}
19091
19050
  };
19092
- });
19093
- try {
19094
- await this.#send("prompt", { message: text }, promptId);
19095
- } catch (error51) {
19096
- this.#rejectActiveTurn(error51 instanceof Error ? error51 : new Error(message2(error51)));
19097
- }
19098
- return settled;
19099
- }
19100
- respondToInteraction(response) {
19101
- return this.#resolveInteraction(response, "cancelled" in response ? "cancelled" : "responded");
19102
- }
19103
- async #resolveInteraction(response, reason) {
19104
- const active = this.#activeTurn;
19105
- const pending = active?.interactions.get(response.requestId);
19106
- if (!active || !pending || this.#closed || this.#failed) {
19107
- throw new Error("Omp RPC interaction is not pending");
19108
19051
  }
19109
- if ("value" in response && !["select", "input", "editor"].includes(pending.request.method)) {
19110
- throw new Error("Omp RPC interaction response type does not match the request");
19052
+ const pending = { request, timeout: null };
19053
+ if (request.timeoutMs !== void 0) {
19054
+ pending.timeout = setTimeout(() => {
19055
+ if (this.#activeTurn !== active || !active.interactions.has(requestId))
19056
+ return;
19057
+ void this.#resolveInteraction({ requestId, cancelled: true }, "expired").catch((error51) => {
19058
+ if (this.#closed || this.#failed)
19059
+ return;
19060
+ this.#fail(new OmpRpcFaultError("protocolError", `Omp RPC Interaction timeout handling failed: ${message2(error51)}`));
19061
+ });
19062
+ }, request.timeoutMs);
19111
19063
  }
19112
- if ("confirmed" in response && pending.request.method !== "confirm") {
19113
- throw new Error("Omp RPC confirmation does not match the request");
19064
+ active.interactions.set(requestId, pending);
19065
+ active.onEvent({ type: "interaction.requested", request });
19066
+ }
19067
+ #handleResponse(value) {
19068
+ const id = value.id;
19069
+ if (typeof id !== "string") {
19070
+ this.#fail(new OmpRpcFaultError("protocolError", "Omp RPC response has no id"));
19071
+ return;
19114
19072
  }
19115
- const frame = "cancelled" in response ? {
19116
- type: "extension_ui_response",
19117
- id: response.requestId,
19118
- cancelled: true,
19119
- ...reason === "expired" ? { timedOut: true } : {}
19120
- } : "confirmed" in response ? { type: "extension_ui_response", id: response.requestId, confirmed: response.confirmed } : { type: "extension_ui_response", id: response.requestId, value: response.value };
19121
- if (!active.interactions.delete(response.requestId)) {
19122
- throw new Error("Omp RPC interaction is not pending");
19073
+ const pending = this.#pending.get(id);
19074
+ const active = this.#activeTurn;
19075
+ if (!pending) {
19076
+ if (active?.promptId === id && value.command === "prompt" && value.success === false) {
19077
+ active.failure = new Error(typeof value.error === "string" ? value.error : "Omp RPC command failed");
19078
+ return;
19079
+ }
19080
+ this.#fail(new OmpRpcFaultError("protocolError", "Omp RPC response id is not pending"));
19081
+ return;
19123
19082
  }
19124
19083
  if (pending.timeout)
19125
19084
  clearTimeout(pending.timeout);
19126
- active.onEvent({ type: "interaction.closed", requestId: response.requestId, reason });
19127
- try {
19128
- await this.#write(frame);
19129
- } catch (error51) {
19130
- const fault = new OmpRpcFaultError("protocolError", `Omp RPC interaction response failed: ${message2(error51)}`);
19131
- this.#fail(fault);
19132
- throw fault;
19085
+ this.#pending.delete(id);
19086
+ if (value.success === true) {
19087
+ if (pending.command === "prompt" && active?.promptId === id && isRecord8(value.data) && value.data.agentInvoked === false) {
19088
+ this.#settleLocalTurn(active, { cancelled: false });
19089
+ }
19090
+ pending.resolve(value);
19091
+ } else {
19092
+ const error51 = typeof value.error === "string" ? value.error : "Omp RPC command failed";
19093
+ if (value.command === pending.command && error51 === `Unknown command: ${pending.command}`) {
19094
+ pending.reject(new OmpRpcUnsupportedCommandError(pending.command));
19095
+ } else {
19096
+ pending.reject(new Error(error51));
19097
+ }
19133
19098
  }
19134
19099
  }
19135
- abort() {
19136
- const active = this.#activeTurn;
19137
- if (!active || this.#closed || this.#failed) {
19138
- return Promise.reject(new Error("Omp RPC Session has no cancellable Turn"));
19100
+ #startTool(active, value) {
19101
+ const callId = value.toolCallId;
19102
+ const toolName = value.toolName;
19103
+ const argumentsResult = jsonValueSchema.safeParse(value.args);
19104
+ if (typeof callId !== "string" || callId.length === 0 || typeof toolName !== "string" || toolName.length === 0 || !argumentsResult.success || active.tools.has(callId)) {
19105
+ throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid Tool start");
19139
19106
  }
19140
- if (active.abortPromise)
19141
- return active.abortPromise;
19142
- active.cancellation = "requesting";
19143
- active.cancellationTimeout = setTimeout(() => {
19144
- this.#terminateFailedCancellation(active, new OmpRpcFaultError("protocolError", "Omp Turn cancellation did not settle within its bound"));
19145
- }, this.#options.cancelTimeoutMs);
19146
- const aborting = this.#send("abort", {}).then(async () => {
19147
- if (this.#activeTurn !== active)
19148
- return;
19149
- active.cancellation = "accepted";
19150
- await this.#confirmCancelledTurn(active);
19151
- }).catch((error51) => {
19152
- if (this.#activeTurn !== active)
19153
- throw error51;
19154
- const fault = error51 instanceof OmpRpcFaultError ? error51 : new OmpRpcFaultError("protocolError", `Omp RPC Abort failed: ${message2(error51)}`);
19155
- this.#terminateFailedCancellation(active, fault);
19156
- throw fault;
19107
+ active.sawTool = true;
19108
+ active.tools.set(callId, toolName);
19109
+ active.onEvent({
19110
+ type: "tool.started",
19111
+ callId,
19112
+ toolName,
19113
+ arguments: argumentsResult.data
19157
19114
  });
19158
- active.abortPromise = aborting;
19159
- return aborting;
19160
19115
  }
19161
- #terminateFailedCancellation(active, fault) {
19162
- if (this.#activeTurn !== active)
19116
+ #updateTool(active, value) {
19117
+ const callId = value.toolCallId;
19118
+ if (typeof callId !== "string" || callId.length === 0) {
19119
+ throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid Tool update");
19120
+ }
19121
+ if (!active.tools.has(callId))
19163
19122
  return;
19164
- if (active.cancellationTimeout)
19165
- clearTimeout(active.cancellationTimeout);
19166
- active.cancellationTimeout = null;
19167
- this.#fail(fault);
19168
- void this.close().catch(() => void 0);
19169
- }
19170
- close() {
19171
- if (!this.#closed) {
19172
- this.#closed = true;
19173
- this.#rejectAll(new Error("Omp RPC Session closed"));
19123
+ const outputResult = jsonValueSchema.safeParse(value.partialResult ?? null);
19124
+ if (!outputResult.success) {
19125
+ throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid Tool update");
19174
19126
  }
19175
- this.#closePromise ??= this.#stopProcess();
19176
- return this.#closePromise;
19127
+ active.onEvent({ type: "tool.updated", callId, output: outputResult.data });
19177
19128
  }
19178
- async #stopProcess() {
19179
- const child = this.#child;
19180
- if (!child)
19181
- return;
19182
- if (child.stdin.writable)
19183
- child.stdin.end();
19184
- if (await waitForExit(child, this.#options.closeTimeoutMs))
19185
- return;
19186
- signalProcessTree(child, "SIGTERM");
19187
- if (await waitForExit(child, this.#options.closeTimeoutMs))
19129
+ #completeTool(active, value) {
19130
+ const callId = value.toolCallId;
19131
+ const toolName = value.toolName;
19132
+ if (typeof callId !== "string" || callId.length === 0) {
19133
+ throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid Tool end");
19134
+ }
19135
+ const expectedName = active.tools.get(callId);
19136
+ if (expectedName === void 0)
19188
19137
  return;
19189
- signalProcessTree(child, "SIGKILL");
19190
- if (!await waitForExit(child, this.#options.closeTimeoutMs)) {
19191
- throw new Error("Omp RPC process tree did not exit within cleanup bounds");
19138
+ const result = jsonValueSchema.safeParse(value.result);
19139
+ if (typeof toolName !== "string" || expectedName !== toolName || value.isError !== void 0 && typeof value.isError !== "boolean" || !result.success) {
19140
+ throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid Tool end");
19192
19141
  }
19142
+ active.tools.delete(callId);
19143
+ active.onEvent({
19144
+ type: "tool.completed",
19145
+ callId,
19146
+ toolName,
19147
+ result: result.data,
19148
+ isError: value.isError === true
19149
+ });
19193
19150
  }
19194
- #push(chunk) {
19195
- this.#buffer = this.#buffer.length === 0 ? chunk : Buffer.concat([this.#buffer, chunk]);
19196
- let newline = this.#buffer.indexOf(10);
19197
- while (newline >= 0) {
19198
- const frame = this.#buffer.subarray(0, newline);
19199
- this.#buffer = this.#buffer.subarray(newline + 1);
19200
- let parsed;
19201
- try {
19202
- parsed = JSON.parse(textDecoder.decode(frame));
19203
- } catch (error51) {
19204
- this.#fail(new OmpRpcFaultError("protocolError", `Omp RPC returned invalid JSONL: ${message2(error51)}`));
19205
- newline = this.#buffer.indexOf(10);
19206
- continue;
19151
+ async #confirmCancelledTurn(active) {
19152
+ if (this.#activeTurn !== active || active.cancellation !== "accepted" || active.settlement === "confirming" || active.cancellationChecking)
19153
+ return;
19154
+ active.cancellationChecking = true;
19155
+ if (active.cancellationRecheck)
19156
+ clearTimeout(active.cancellationRecheck);
19157
+ active.cancellationRecheck = null;
19158
+ try {
19159
+ let response = await this.#send("get_state", {});
19160
+ if (this.#activeTurn !== active)
19161
+ return;
19162
+ if (parseSessionStreaming(response)) {
19163
+ await this.#send("abort", {});
19164
+ if (this.#activeTurn !== active)
19165
+ return;
19166
+ response = await this.#send("get_state", {});
19207
19167
  }
19208
- try {
19209
- const decoded = this.#frameDecoder.push(parsed);
19210
- if (decoded === null) {
19211
- newline = this.#buffer.indexOf(10);
19212
- continue;
19168
+ let state = parseSessionState(response);
19169
+ if (this.#activeTurn !== active || active.cancellation !== "accepted")
19170
+ return;
19171
+ const data = sessionStateData(response);
19172
+ 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) {
19173
+ await this.verifySessionCwd(this.#options.cwd);
19174
+ if (this.#activeTurn !== active)
19175
+ return;
19176
+ active.cancellationReloaded = true;
19177
+ const reset = await this.#send("new_session", {});
19178
+ if (this.#activeTurn !== active)
19179
+ return;
19180
+ if (!isRecord8(reset.data) || reset.data.cancelled !== false) {
19181
+ throw new OmpRpcFaultError("unavailable", "Omp cancelled Session reset was refused");
19182
+ }
19183
+ const reloaded = await this.#send("switch_session", { sessionPath: state.sessionFile });
19184
+ if (this.#activeTurn !== active)
19185
+ return;
19186
+ if (!isRecord8(reloaded.data) || reloaded.data.cancelled !== false) {
19187
+ throw new OmpRpcFaultError("unavailable", "Omp cancelled Session reload was refused");
19188
+ }
19189
+ const previous = state;
19190
+ response = await this.#send("get_state", {});
19191
+ state = parseSessionState(response);
19192
+ if (state.sessionId !== previous.sessionId || state.sessionFile !== previous.sessionFile) {
19193
+ throw new OmpRpcFaultError("protocolError", "Omp cancelled Session reload changed its identity");
19194
+ }
19195
+ if (state.provider !== previous.provider || state.modelId !== previous.modelId) {
19196
+ if (!previous.provider || !previous.modelId) {
19197
+ throw new OmpRpcFaultError("protocolError", "Omp cancelled Session has no restorable Model");
19198
+ }
19199
+ await this.#send("set_model", { provider: previous.provider, modelId: previous.modelId });
19213
19200
  }
19214
- const value = decoded;
19215
- if (!isRecord8(value) || typeof value.type !== "string") {
19216
- throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid envelope");
19201
+ if (previous.thinkingLevel && state.thinkingLevel !== previous.thinkingLevel) {
19202
+ await this.#send("set_thinking_level", { level: previous.thinkingLevel });
19203
+ }
19204
+ response = await this.#send("get_state", {});
19205
+ state = parseSessionState(response);
19206
+ if (state.sessionId !== previous.sessionId || state.sessionFile !== previous.sessionFile || state.provider !== previous.provider || state.modelId !== previous.modelId || previous.thinkingLevel !== null && state.thinkingLevel !== previous.thinkingLevel) {
19207
+ throw new OmpRpcFaultError("protocolError", "Omp cancelled Session reload changed its identity or configuration");
19217
19208
  }
19218
- this.#handle(value);
19219
- } catch (error51) {
19220
- this.#fail(error51 instanceof OmpRpcFaultError ? error51 : new OmpRpcFaultError("protocolError", `Omp RPC frame handling failed: ${message2(error51)}`));
19221
19209
  }
19222
- newline = this.#buffer.indexOf(10);
19210
+ if (!cancellationSettled(response, active.terminalEnd)) {
19211
+ active.settlement = "pending";
19212
+ active.cancellationRecheck = setTimeout(() => {
19213
+ active.cancellationRecheck = null;
19214
+ void this.#confirmCancelledTurn(active);
19215
+ }, 250);
19216
+ return;
19217
+ }
19218
+ this.#state = state;
19219
+ active.settlement = "confirmed";
19220
+ this.#finishSettledTurn(active);
19221
+ } catch (error51) {
19222
+ if (this.#activeTurn !== active)
19223
+ return;
19224
+ const fault = error51 instanceof OmpRpcFaultError ? error51 : new OmpRpcFaultError("protocolError", `Omp RPC cancelled Turn state could not be confirmed: ${message2(error51)}`);
19225
+ this.#terminateFailedCancellation(active, fault);
19226
+ } finally {
19227
+ active.cancellationChecking = false;
19223
19228
  }
19224
19229
  }
19225
- /** Latest `available_commands_update` of the running process, if any. */
19226
- get availableCommands() {
19227
- return this.#availableCommands;
19228
- }
19229
- #handle(value) {
19230
- if (this.#closed || this.#failed)
19231
- return;
19232
- if (value.type === "available_commands_update") {
19233
- this.#availableCommands = parseOmpAvailableCommands(value.commands);
19234
- return;
19235
- }
19236
- if (value.type === "ready") {
19237
- this.#readyResolve?.();
19238
- this.#readyResolve = null;
19239
- return;
19240
- }
19241
- if (value.type === "response") {
19242
- this.#handleResponse(value);
19243
- return;
19244
- }
19245
- if (value.type === "auto_compaction_start" || value.type === "compaction_start") {
19246
- this.#compactionActive = true;
19247
- this.#compactionTurn = this.#activeTurn;
19248
- this.#compactionTimeout ??= setTimeout(() => {
19249
- this.#compactionTimeout = null;
19250
- this.#fail(new OmpRpcFaultError("protocolError", `Omp RPC compaction timed out after ${this.#options.compactionTimeoutMs}ms`));
19251
- }, this.#options.compactionTimeoutMs);
19252
- const onEvent = this.#activeTurn?.onEvent ?? this.#manualCompaction?.onEvent;
19253
- onEvent?.({ type: "compaction.started" });
19254
- for (const pending of this.#pending.values()) {
19255
- if (pending.command !== "prompt" && pending.command !== "compact" || !pending.timeout)
19256
- continue;
19257
- clearTimeout(pending.timeout);
19258
- pending.timeout = null;
19259
- }
19230
+ #settleLocalTurn(active, result) {
19231
+ if (this.#activeTurn !== active || active.settlement !== "pending")
19260
19232
  return;
19261
- }
19262
- if (value.type === "auto_compaction_end" || value.type === "compaction_end") {
19263
- this.#compactionActive = false;
19264
- if (this.#compactionTimeout)
19265
- clearTimeout(this.#compactionTimeout);
19266
- this.#compactionTimeout = null;
19267
- const compactionTurn = this.#compactionTurn;
19268
- this.#compactionTurn = null;
19269
- for (const [id, pending] of this.#pending) {
19270
- if (pending.command === "prompt" || pending.command === "compact") {
19271
- this.#armCommandTimeout(id, pending);
19272
- }
19233
+ active.localResult = result;
19234
+ active.settlement = "confirming";
19235
+ void this.#confirmSettledTurn(active);
19236
+ }
19237
+ async #confirmSettledTurn(active) {
19238
+ try {
19239
+ const response = await this.#send("get_state", {});
19240
+ const state = parseSessionState(response);
19241
+ if (this.#activeTurn !== active)
19242
+ return;
19243
+ if (active.cancellation !== "none") {
19244
+ active.settlement = "pending";
19245
+ if (active.cancellation === "accepted")
19246
+ void this.#confirmCancelledTurn(active);
19247
+ return;
19273
19248
  }
19274
- const outcome = value.aborted === true ? "cancelled" : isRecord8(value.result) ? "succeeded" : "failed";
19275
- const event = {
19276
- type: "compaction.completed",
19277
- outcome,
19278
- ...nonBlankString(value.errorMessage) ? { errorMessage: value.errorMessage } : {}
19279
- };
19280
- compactionTurn?.onEvent(event);
19281
- const manual = this.#manualCompaction;
19282
- this.#manualCompaction = null;
19283
- manual?.onEvent(event);
19284
- manual?.resolve({
19285
- outcome,
19286
- ...event.errorMessage ? { errorMessage: event.errorMessage } : {}
19287
- });
19288
- return;
19289
- }
19290
- const active = this.#activeTurn;
19291
- if (this.#handleSubagentFrame(active, value))
19292
- return;
19293
- this.#observeUsage(value);
19294
- if (value.type === "agent_start" && active)
19295
- active.terminalEnd = false;
19296
- if ((value.type === "session_settled" || value.type === "agent_start") && active?.cancellation === "accepted") {
19297
- void this.#confirmCancelledTurn(active);
19298
- return;
19299
- }
19300
- if (!active) {
19301
- if (value.type === "extension_ui_request" && this.#isBlockingInteraction(value)) {
19302
- this.#fail(new OmpRpcFaultError("protocolError", "Omp RPC requested blocking Extension UI outside an active Turn"));
19249
+ if (parseSessionStreaming(response)) {
19250
+ throw new OmpRpcFaultError("protocolError", "Omp RPC completed Turn state is still Streaming");
19303
19251
  }
19304
- return;
19305
- }
19306
- if (value.type === "command_output") {
19307
- if (active.settlement !== "pending")
19252
+ this.#state = state;
19253
+ active.settlement = "confirmed";
19254
+ this.#finishSettledTurn(active);
19255
+ } catch (error51) {
19256
+ if (this.#activeTurn !== active)
19308
19257
  return;
19309
- if (typeof value.text !== "string") {
19310
- throw new OmpRpcFaultError("protocolError", "Omp RPC returned invalid command output");
19311
- }
19312
- active.text += value.text;
19313
- active.onEvent({ type: "text.delta", messageId: active.promptId, delta: value.text });
19314
- return;
19258
+ const fault = error51 instanceof OmpRpcFaultError ? error51 : new OmpRpcFaultError("protocolError", `Omp RPC stable Turn state could not be confirmed: ${message2(error51)}`);
19259
+ this.#fail(fault);
19315
19260
  }
19316
- if (value.type === "prompt_result") {
19317
- if (value.id !== active.promptId || value.agentInvoked !== false)
19318
- return;
19319
- if (value.status === "completed" || value.status === "aborted") {
19320
- this.#settleLocalTurn(active, { cancelled: value.status === "aborted" });
19321
- } else if (value.status === "error" && isRecord8(value.error) && typeof value.error.message === "string") {
19322
- this.#settleLocalTurn(active, { cancelled: false, error: value.error.message });
19323
- } else {
19324
- throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid local prompt result");
19325
- }
19261
+ }
19262
+ #finishSettledTurn(active) {
19263
+ if (this.#activeTurn !== active || active.settlement !== "confirmed" || active.cancellation === "requesting") {
19326
19264
  return;
19327
19265
  }
19328
- if (value.type === "extension_ui_request") {
19329
- this.#startInteraction(active, value);
19266
+ if (active.cancellationTimeout)
19267
+ clearTimeout(active.cancellationTimeout);
19268
+ active.cancellationTimeout = null;
19269
+ if (active.cancellationRecheck)
19270
+ clearTimeout(active.cancellationRecheck);
19271
+ active.cancellationRecheck = null;
19272
+ this.#closeInteractions(active, active.cancellation === "accepted" ? "cancelled" : "superseded");
19273
+ if (active.tools.size > 0) {
19274
+ this.#fail(new OmpRpcFaultError("protocolError", "Omp RPC settled with active Tool executions"));
19330
19275
  return;
19331
19276
  }
19332
- if (value.type === "message_start" && assistantText(value.message) !== null) {
19333
- this.#startAssistantMessage(active, value.message);
19334
- return;
19277
+ this.#activeTurn = null;
19278
+ if (active.localResult) {
19279
+ active.resolve({
19280
+ text: active.text,
19281
+ agentInvoked: false,
19282
+ ...active.localResult,
19283
+ cancelled: active.localResult.cancelled || active.cancellation === "accepted"
19284
+ });
19285
+ } else if (active.cancellation === "accepted") {
19286
+ active.resolve({ text: active.text, cancelled: true, agentInvoked: true });
19287
+ } else if (active.failure) {
19288
+ active.reject(active.failure);
19289
+ } else if (active.text.trim().length === 0 && !active.sawTool) {
19290
+ active.reject(new Error("Omp RPC settled without displayable output"));
19291
+ } else {
19292
+ active.resolve({ text: active.text, cancelled: false, agentInvoked: true });
19335
19293
  }
19336
- if (value.type === "message_update" && isRecord8(value.assistantMessageEvent)) {
19337
- const event = value.assistantMessageEvent;
19338
- const eventType = String(event.type ?? "");
19339
- const isThinking = eventType === "thinking_delta" || eventType === "reasoning_delta" || eventType === "thought_delta" || eventType === "thinking" || eventType === "reasoning";
19340
- const isText = eventType === "text_delta" || eventType === "text" || eventType === "content_block_delta";
19341
- 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;
19342
- if (isThinking && delta !== null && delta.length > 0) {
19343
- const messageId = this.#ensureAssistantMessage(active, value.message);
19344
- active.reasoningMessageOpen = true;
19345
- active.sawStreamedMessageReasoning = true;
19346
- active.onEvent({ type: "reasoning.delta", messageId, delta });
19347
- } else if (isText && delta !== null && delta.length > 0) {
19348
- const messageId = this.#ensureAssistantMessage(active, value.message);
19349
- active.text += delta;
19350
- active.sawStreamedMessageText = true;
19351
- active.onEvent({ type: "text.delta", messageId, delta });
19352
- } else if (event.type === "error") {
19353
- this.#ensureAssistantMessage(active, value.message);
19354
- active.failure = assistantFailure(event.error) ?? assistantFailure(value.message) ?? new Error("Omp assistant message failed");
19355
- }
19356
- return;
19294
+ }
19295
+ #startAssistantMessage(active, value) {
19296
+ if (active.assistantMessageId !== null && active.reasoningMessageOpen) {
19297
+ active.onEvent({ type: "reasoning.completed", messageId: active.assistantMessageId });
19357
19298
  }
19358
- if (value.type === "message_end") {
19359
- this.#finalizeAssistantMessage(active, value.message);
19299
+ const messageId = assistantMessageId(value) ?? randomUUID();
19300
+ active.assistantMessageId = messageId;
19301
+ active.sawStreamedMessageText = false;
19302
+ active.sawStreamedMessageReasoning = false;
19303
+ active.reasoningMessageOpen = false;
19304
+ return messageId;
19305
+ }
19306
+ #ensureAssistantMessage(active, value) {
19307
+ return active.assistantMessageId ?? this.#startAssistantMessage(active, value);
19308
+ }
19309
+ #finalizeAssistantMessage(active, value) {
19310
+ const finalText = assistantText(value);
19311
+ const finalReasoning = assistantReasoning(value);
19312
+ const failure = assistantFailure(value);
19313
+ const cacheHitRatePercent = optionalOmpCacheHitRatePercent(value);
19314
+ if (finalText === null || finalReasoning === null || failure === void 0)
19360
19315
  return;
19361
- }
19362
- if (value.type === "turn_end") {
19363
- this.#finalizeAssistantMessage(active, value.message);
19316
+ if (active.assistantMessageId === null && finalText === active.lastFinalizedMessageText && finalReasoning === active.lastFinalizedMessageReasoning && !active.sawStreamedMessageText && !active.sawStreamedMessageReasoning) {
19364
19317
  return;
19365
19318
  }
19366
- if (value.type === "tool_execution_start") {
19367
- this.#startTool(active, value);
19368
- return;
19319
+ active.failure = failure;
19320
+ this.#latestCacheHitRatePercent = cacheHitRatePercent;
19321
+ const messageId = this.#ensureAssistantMessage(active, value);
19322
+ if (!active.sawStreamedMessageReasoning && finalReasoning.length > 0) {
19323
+ active.reasoningMessageOpen = true;
19324
+ active.onEvent({ type: "reasoning.delta", messageId, delta: finalReasoning });
19369
19325
  }
19370
- if (value.type === "tool_execution_update") {
19371
- this.#updateTool(active, value);
19372
- return;
19326
+ if (active.reasoningMessageOpen && active.failure === null) {
19327
+ active.onEvent({ type: "reasoning.completed", messageId });
19373
19328
  }
19374
- if (value.type === "tool_execution_end") {
19375
- this.#completeTool(active, value);
19376
- return;
19329
+ if (!active.sawStreamedMessageText && finalText.length > 0) {
19330
+ active.text += finalText;
19331
+ active.onEvent({ type: "text.delta", messageId, delta: finalText });
19377
19332
  }
19378
- if (value.type === "agent_end" && Array.isArray(value.messages)) {
19379
- for (let index = value.messages.length - 1; index >= 0; index -= 1) {
19380
- const message3 = value.messages[index];
19381
- if (!isRecord8(message3) || message3.role !== "assistant")
19382
- continue;
19383
- this.#finalizeAssistantMessage(active, message3);
19384
- break;
19385
- }
19333
+ active.assistantMessageId = null;
19334
+ active.sawStreamedMessageText = false;
19335
+ active.sawStreamedMessageReasoning = false;
19336
+ active.reasoningMessageOpen = false;
19337
+ active.lastFinalizedMessageText = finalText;
19338
+ active.lastFinalizedMessageReasoning = finalReasoning;
19339
+ active.onEvent({ type: "message.completed", messageId });
19340
+ }
19341
+ #write(value) {
19342
+ const child = this.#child;
19343
+ if (!child?.stdin.writable || this.#closed || this.#failed) {
19344
+ return Promise.reject(new Error("Omp RPC stdin is unavailable"));
19386
19345
  }
19387
- if (value.type === "agent_end" && value.isTerminal !== false) {
19388
- active.terminalEnd = true;
19389
- if (active.cancellation !== "none") {
19390
- if (active.cancellation === "accepted")
19391
- void this.#confirmCancelledTurn(active);
19392
- return;
19393
- }
19394
- if (active.settlement !== "pending")
19395
- return;
19396
- active.settlement = "confirming";
19397
- void this.#confirmSettledTurn(active);
19346
+ return new Promise((resolve, reject) => {
19347
+ const frame = Buffer.from(`${JSON.stringify(value)}
19348
+ `, "utf8");
19349
+ child.stdin.write(frame, (error51) => error51 ? reject(error51) : resolve());
19350
+ });
19351
+ }
19352
+ #send(type, payload, id = `codexhost-${randomUUID()}`) {
19353
+ const child = this.#child;
19354
+ if (!child?.stdin.writable || this.#closed || this.#failed) {
19355
+ return Promise.reject(new Error("Omp RPC stdin is unavailable"));
19398
19356
  }
19357
+ return new Promise((resolve, reject) => {
19358
+ const pending = {
19359
+ command: type,
19360
+ resolve,
19361
+ reject,
19362
+ timeout: null
19363
+ };
19364
+ this.#pending.set(id, pending);
19365
+ this.#armCommandTimeout(id, pending);
19366
+ const frame = Buffer.from(`${JSON.stringify({ id, type, ...payload })}
19367
+ `, "utf8");
19368
+ child.stdin.write(frame, (error51) => {
19369
+ if (error51) {
19370
+ if (pending.timeout)
19371
+ clearTimeout(pending.timeout);
19372
+ this.#pending.delete(id);
19373
+ reject(error51);
19374
+ }
19375
+ });
19376
+ });
19399
19377
  }
19400
- /** Every finished assistant message is one model request, with or without an active Turn. */
19401
- #observeUsage(value) {
19402
- if (value.type === "message_start") {
19403
- this.#usageRequestStartedAtMs = null;
19378
+ #armCommandTimeout(id, pending) {
19379
+ if (pending.timeout || this.#pending.get(id) !== pending || (pending.command === "prompt" || pending.command === "compact") && this.#compactionActive) {
19404
19380
  return;
19405
19381
  }
19406
- if (value.type === "message_update") {
19407
- const event = value.assistantMessageEvent;
19408
- if (this.#usageRequestStartedAtMs === null && isRecord8(event) && typeof event.type === "string" && /^(text|thinking|reasoning|thought|toolcall)_(start|delta)$/u.test(event.type)) {
19409
- this.#usageRequestStartedAtMs = Date.now();
19382
+ pending.timeout = setTimeout(() => {
19383
+ if (this.#pending.get(id) !== pending)
19384
+ return;
19385
+ pending.timeout = null;
19386
+ const error51 = new Error(`Omp RPC '${pending.command}' command timed out`);
19387
+ if (pending.command !== "prompt") {
19388
+ this.#pending.delete(id);
19389
+ pending.reject(error51);
19390
+ return;
19410
19391
  }
19392
+ const fault = new OmpRpcFaultError("protocolError", error51.message);
19393
+ void this.#terminateTimedOutPrompt(fault);
19394
+ }, this.#options.commandTimeoutMs);
19395
+ }
19396
+ async #terminateTimedOutPrompt(fault) {
19397
+ if (this.#closed || this.#failed)
19411
19398
  return;
19399
+ this.#failed = true;
19400
+ this.#closed = true;
19401
+ for (const pending of this.#pending.values()) {
19402
+ if (pending.timeout)
19403
+ clearTimeout(pending.timeout);
19404
+ pending.timeout = null;
19412
19405
  }
19413
- if (value.type === "message_end" && isRecord8(value.message)) {
19414
- if (value.message.role !== "assistant")
19415
- return;
19416
- const startedAtMs = this.#usageRequestStartedAtMs;
19417
- this.#usageRequestStartedAtMs = null;
19418
- this.#options.onUsage?.({
19419
- message: value.message,
19420
- startedAtMs,
19421
- completedAtMs: Date.now()
19422
- });
19406
+ let finalFault = fault;
19407
+ try {
19408
+ await this.close();
19409
+ } catch (error51) {
19410
+ finalFault = new OmpRpcFaultError("processExited", `Omp RPC timed-out Prompt cleanup failed: ${message2(error51)}`);
19423
19411
  }
19412
+ this.#rejectAll(finalFault);
19413
+ this.#options.onFault?.(finalFault);
19424
19414
  }
19425
- #handleSubagentFrame(active, value) {
19426
- if (value.type !== "subagent_lifecycle" && value.type !== "subagent_progress" && value.type !== "subagent_event") {
19427
- return false;
19428
- }
19429
- const payload = isRecord8(value.payload) ? value.payload : null;
19430
- const progressPayload = value.type === "subagent_progress" && payload && isRecord8(payload.progress) ? payload.progress : null;
19431
- const nativeIdValue = progressPayload?.id ?? payload?.id;
19432
- if (!payload || !nonBlankString(nativeIdValue)) {
19433
- throw new OmpRpcFaultError("protocolError", "Omp RPC Subagent frame has no stable ID");
19415
+ #closeInteractions(active, reason) {
19416
+ for (const [requestId, pending] of active.interactions) {
19417
+ active.interactions.delete(requestId);
19418
+ if (pending.timeout)
19419
+ clearTimeout(pending.timeout);
19420
+ active.onEvent({ type: "interaction.closed", requestId, reason });
19434
19421
  }
19435
- const nativeSubagentId = nativeIdValue;
19436
- const callId = nativeSubagentId;
19437
- const emit = active?.onEvent ?? this.#options.onSubagentEvent;
19438
- if (value.type === "subagent_event") {
19439
- emit?.({ type: "subagent.transcript.changed", callId, nativeSubagentId });
19440
- return true;
19422
+ }
19423
+ #rejectActiveTurn(error51) {
19424
+ const active = this.#activeTurn;
19425
+ if (!active)
19426
+ return;
19427
+ if (active.cancellationTimeout)
19428
+ clearTimeout(active.cancellationTimeout);
19429
+ if (active.cancellationRecheck)
19430
+ clearTimeout(active.cancellationRecheck);
19431
+ this.#closeInteractions(active, "cancelled");
19432
+ this.#activeTurn = null;
19433
+ active.reject(error51);
19434
+ }
19435
+ #rejectAll(error51) {
19436
+ if (this.#compactionTimeout)
19437
+ clearTimeout(this.#compactionTimeout);
19438
+ this.#compactionTimeout = null;
19439
+ for (const pending of this.#pending.values()) {
19440
+ if (pending.timeout)
19441
+ clearTimeout(pending.timeout);
19442
+ pending.reject(error51);
19441
19443
  }
19442
- if (value.type === "subagent_lifecycle") {
19443
- const status2 = payload.status;
19444
- if (status2 === "started") {
19445
- const description = nonBlankString(payload.description) ? payload.description : nonBlankString(payload.agent) ? `${payload.agent} delegation` : "Subagent delegation";
19446
- emit?.({
19447
- type: "subagent.started",
19448
- callId,
19449
- nativeSubagentId,
19450
- description,
19451
- ...nonBlankString(payload.agent) ? { role: payload.agent } : {},
19452
- ...nonBlankString(payload.task) ? { prompt: payload.task } : {},
19453
- background: payload.detached === true,
19454
- ...typeof payload.sessionFile === "string" ? { sessionFile: payload.sessionFile } : {}
19455
- });
19456
- return true;
19457
- }
19458
- if (status2 !== "completed" && status2 !== "failed" && status2 !== "aborted") {
19459
- throw new OmpRpcFaultError("protocolError", "Omp RPC Subagent lifecycle status is invalid");
19444
+ this.#pending.clear();
19445
+ const manual = this.#manualCompaction;
19446
+ this.#manualCompaction = null;
19447
+ manual?.reject(error51);
19448
+ this.#rejectActiveTurn(error51);
19449
+ }
19450
+ #fail(error51) {
19451
+ if (this.#closed || this.#failed)
19452
+ return;
19453
+ this.#failed = true;
19454
+ this.#startupFaultResolve?.(error51);
19455
+ this.#startupFaultResolve = null;
19456
+ this.#rejectAll(error51);
19457
+ this.#options.onFault?.(error51);
19458
+ }
19459
+ };
19460
+
19461
+ // dist/omp-model-list.js
19462
+ var OMP_MODEL_LIST_TIMEOUT_MS = 15e3;
19463
+ var OMP_MODEL_LIST_OUTPUT_LIMIT = 4 * 1024 * 1024;
19464
+ function listOmpModels(input) {
19465
+ const environment = withNodeRuntimeOnPath({
19466
+ ...process.env,
19467
+ ...input.environment,
19468
+ OMP_SKIP_VERSION_CHECK: "1",
19469
+ OMP_TELEMETRY: "0"
19470
+ });
19471
+ const executable = resolveOmpExecutable({
19472
+ ...input.command ? { command: input.command } : {},
19473
+ environment
19474
+ });
19475
+ const invocation = commandInvocation(executable, ["models", "--json"], environment);
19476
+ return new Promise((resolve) => {
19477
+ if (input.signal?.aborted)
19478
+ return resolve({ kind: "unanswered" });
19479
+ const child = spawn2(invocation.command, invocation.arguments, {
19480
+ cwd: input.cwd,
19481
+ env: environment,
19482
+ // A process group lets a stop reach OMP and its descendants, not only a launcher shim.
19483
+ detached: process.platform !== "win32",
19484
+ stdio: ["ignore", "pipe", "ignore"],
19485
+ windowsHide: true,
19486
+ windowsVerbatimArguments: invocation.windowsVerbatimArguments
19487
+ });
19488
+ let settled = false;
19489
+ let stdout = "";
19490
+ const finish = (result, stop = false) => {
19491
+ if (settled)
19492
+ return;
19493
+ settled = true;
19494
+ clearTimeout(timer);
19495
+ input.signal?.removeEventListener("abort", onAbort);
19496
+ child.stdout.removeAllListeners("data");
19497
+ if (stop) {
19498
+ child.stdout.destroy();
19499
+ try {
19500
+ signalProcessTree(child, "SIGKILL");
19501
+ } catch {
19502
+ }
19460
19503
  }
19461
- emit?.({
19462
- type: "subagent.completed",
19463
- callId,
19464
- nativeSubagentId,
19465
- isError: status2 !== "completed",
19466
- ...nonBlankString(payload.resultSummary) ? { resultSummary: payload.resultSummary } : {},
19467
- ...typeof payload.sessionFile === "string" ? { sessionFile: payload.sessionFile } : {}
19468
- });
19469
- return true;
19470
- }
19471
- const progress = progressPayload;
19472
- if (!progress || !nonBlankString(progress.id) || progress.id !== nativeSubagentId) {
19473
- throw new OmpRpcFaultError("protocolError", "Omp RPC Subagent progress is invalid");
19474
- }
19475
- const status = subagentStatus(progress.status);
19476
- const recentOutput = Array.isArray(progress.recentOutput) ? progress.recentOutput.filter((item) => typeof item === "string") : [];
19477
- const resultSummary = recentOutput.at(-1);
19478
- emit?.({
19479
- type: "subagent.updated",
19480
- callId,
19481
- nativeSubagentId,
19482
- status,
19483
- ...nonBlankString(progress.description) ? { description: progress.description } : nonBlankString(payload.task) ? { description: payload.task } : {},
19484
- ...resultSummary !== void 0 ? { resultSummary } : {},
19485
- ...typeof payload.sessionFile === "string" ? { sessionFile: payload.sessionFile } : {}
19504
+ resolve(result);
19505
+ };
19506
+ const onAbort = () => finish({ kind: "unanswered" }, true);
19507
+ input.signal?.addEventListener("abort", onAbort, { once: true });
19508
+ const timer = setTimeout(() => finish({ kind: "timedOut" }, true), input.timeoutMs ?? OMP_MODEL_LIST_TIMEOUT_MS);
19509
+ child.stdout.setEncoding("utf8").on("data", (chunk) => {
19510
+ stdout += chunk;
19511
+ if (stdout.length > OMP_MODEL_LIST_OUTPUT_LIMIT)
19512
+ finish({ kind: "unanswered" }, true);
19486
19513
  });
19487
- return true;
19514
+ child.once("error", (error51) => {
19515
+ finish(error51.code === "ENOENT" ? { kind: "notInstalled", message: "Oh My Pi (omp) is not installed" } : { kind: "unanswered" });
19516
+ });
19517
+ child.once("close", (code) => {
19518
+ if (code !== 0)
19519
+ return finish({ kind: "unanswered" });
19520
+ const models = parseOmpModelList(stdout);
19521
+ finish(models ? { kind: "models", models } : { kind: "unanswered" });
19522
+ });
19523
+ });
19524
+ }
19525
+ function parseOmpModelList(output) {
19526
+ let parsed;
19527
+ try {
19528
+ parsed = JSON.parse(output);
19529
+ } catch {
19530
+ return null;
19488
19531
  }
19489
- #isBlockingInteraction(value) {
19490
- return ["select", "confirm", "input", "editor"].includes(String(value.method));
19532
+ if (!isRecord9(parsed) || !Array.isArray(parsed.models))
19533
+ return null;
19534
+ const models = [];
19535
+ for (const model2 of parsed.models) {
19536
+ if (!isRecord9(model2) || !nonBlankString2(model2.provider) || !nonBlankString2(model2.id) || typeof model2.reasoning !== "boolean") {
19537
+ return null;
19538
+ }
19539
+ models.push({ provider: model2.provider, id: model2.id, reasoning: model2.reasoning });
19491
19540
  }
19492
- #startInteraction(active, value) {
19493
- if (!this.#isBlockingInteraction(value))
19494
- return;
19495
- const requestId = value.id;
19496
- const method = value.method;
19497
- const title = value.title;
19498
- const timeoutMs = value.timeout;
19499
- if (typeof requestId !== "string" || requestId.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(requestId)) {
19500
- throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid Interaction request");
19541
+ return models;
19542
+ }
19543
+ function isRecord9(value) {
19544
+ return typeof value === "object" && value !== null && !Array.isArray(value);
19545
+ }
19546
+ function nonBlankString2(value) {
19547
+ return typeof value === "string" && value.trim().length > 0;
19548
+ }
19549
+
19550
+ // ../../../node_modules/diff/libesm/diff/base.js
19551
+ var Diff = class {
19552
+ diff(oldStr, newStr, options = {}) {
19553
+ let callback;
19554
+ if (typeof options === "function") {
19555
+ callback = options;
19556
+ options = {};
19557
+ } else if ("callback" in options) {
19558
+ callback = options.callback;
19501
19559
  }
19502
- let request;
19503
- if (method === "select") {
19504
- if (!Array.isArray(value.options) || value.options.length === 0 || !value.options.every((option) => typeof option === "string" && option.length > 0)) {
19505
- throw new OmpRpcFaultError("protocolError", "Omp RPC select request has invalid options");
19560
+ const oldString = this.castInput(oldStr, options);
19561
+ const newString = this.castInput(newStr, options);
19562
+ const oldTokens = this.removeEmpty(this.tokenize(oldString, options));
19563
+ const newTokens = this.removeEmpty(this.tokenize(newString, options));
19564
+ return this.diffWithOptionsObj(oldTokens, newTokens, options, callback);
19565
+ }
19566
+ diffWithOptionsObj(oldTokens, newTokens, options, callback) {
19567
+ var _a3;
19568
+ const done = (value) => {
19569
+ value = this.postProcess(value, options);
19570
+ if (callback) {
19571
+ setTimeout(function() {
19572
+ callback(value);
19573
+ }, 0);
19574
+ return void 0;
19575
+ } else {
19576
+ return value;
19506
19577
  }
19507
- let optionDetails;
19508
- if (value.optionDetails !== void 0) {
19509
- 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"))) {
19510
- throw new OmpRpcFaultError("protocolError", "Omp RPC select option details are invalid");
19578
+ };
19579
+ const newLen = newTokens.length, oldLen = oldTokens.length;
19580
+ let editLength = 1;
19581
+ let maxEditLength = newLen + oldLen;
19582
+ if (options.maxEditLength != null) {
19583
+ maxEditLength = Math.min(maxEditLength, options.maxEditLength);
19584
+ }
19585
+ const maxExecutionTime = (_a3 = options.timeout) !== null && _a3 !== void 0 ? _a3 : Infinity;
19586
+ const abortAfterTimestamp = Date.now() + maxExecutionTime;
19587
+ const bestPath = [{ oldPos: -1, lastComponent: void 0 }];
19588
+ let newPos = this.extractCommon(bestPath[0], newTokens, oldTokens, 0, options);
19589
+ if (bestPath[0].oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
19590
+ return done(this.buildValues(bestPath[0].lastComponent, newTokens, oldTokens));
19591
+ }
19592
+ let minDiagonalToConsider = -Infinity, maxDiagonalToConsider = Infinity;
19593
+ const execEditLength = () => {
19594
+ for (let diagonalPath = Math.max(minDiagonalToConsider, -editLength); diagonalPath <= Math.min(maxDiagonalToConsider, editLength); diagonalPath += 2) {
19595
+ let basePath;
19596
+ const removePath = bestPath[diagonalPath - 1], addPath = bestPath[diagonalPath + 1];
19597
+ if (removePath) {
19598
+ bestPath[diagonalPath - 1] = void 0;
19599
+ }
19600
+ let canAdd = false;
19601
+ if (addPath) {
19602
+ const addPathNewPos = addPath.oldPos - diagonalPath;
19603
+ canAdd = addPath && 0 <= addPathNewPos && addPathNewPos < newLen;
19604
+ }
19605
+ const canRemove = removePath && removePath.oldPos + 1 < oldLen;
19606
+ if (!canAdd && !canRemove) {
19607
+ bestPath[diagonalPath] = void 0;
19608
+ continue;
19609
+ }
19610
+ if (!canRemove || canAdd && removePath.oldPos < addPath.oldPos) {
19611
+ basePath = this.addToPath(addPath, true, false, 0, options);
19612
+ } else {
19613
+ basePath = this.addToPath(removePath, false, true, 1, options);
19614
+ }
19615
+ newPos = this.extractCommon(basePath, newTokens, oldTokens, diagonalPath, options);
19616
+ if (basePath.oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
19617
+ return done(this.buildValues(basePath.lastComponent, newTokens, oldTokens)) || true;
19618
+ } else {
19619
+ bestPath[diagonalPath] = basePath;
19620
+ if (basePath.oldPos + 1 >= oldLen) {
19621
+ maxDiagonalToConsider = Math.min(maxDiagonalToConsider, diagonalPath - 1);
19622
+ }
19623
+ if (newPos + 1 >= newLen) {
19624
+ minDiagonalToConsider = Math.max(minDiagonalToConsider, diagonalPath + 1);
19625
+ }
19511
19626
  }
19512
- optionDetails = value.optionDetails.map(({ description }) => description === void 0 ? {} : { description });
19513
- }
19514
- request = {
19515
- requestId,
19516
- method,
19517
- title,
19518
- options: [...value.options],
19519
- ...optionDetails ? { optionDetails } : {},
19520
- ...typeof timeoutMs === "number" ? { timeoutMs } : {}
19521
- };
19522
- } else if (method === "confirm") {
19523
- if (typeof value.message !== "string") {
19524
- throw new OmpRpcFaultError("protocolError", "Omp RPC confirm request has no message");
19525
19627
  }
19526
- request = {
19527
- requestId,
19528
- method,
19529
- title,
19530
- message: value.message,
19531
- ...typeof timeoutMs === "number" ? { timeoutMs } : {}
19532
- };
19533
- } else if (method === "input") {
19534
- if (value.placeholder !== void 0 && typeof value.placeholder !== "string") {
19535
- throw new OmpRpcFaultError("protocolError", "Omp RPC input placeholder is invalid");
19628
+ editLength++;
19629
+ };
19630
+ if (callback) {
19631
+ (function exec() {
19632
+ setTimeout(function() {
19633
+ if (editLength > maxEditLength || Date.now() > abortAfterTimestamp) {
19634
+ return callback(void 0);
19635
+ }
19636
+ if (!execEditLength()) {
19637
+ exec();
19638
+ }
19639
+ }, 0);
19640
+ })();
19641
+ } else {
19642
+ while (editLength <= maxEditLength && Date.now() <= abortAfterTimestamp) {
19643
+ const ret = execEditLength();
19644
+ if (ret) {
19645
+ return ret;
19646
+ }
19536
19647
  }
19537
- request = {
19538
- requestId,
19539
- method,
19540
- title,
19541
- ...typeof value.placeholder === "string" ? { placeholder: value.placeholder } : {},
19542
- ...typeof timeoutMs === "number" ? { timeoutMs } : {}
19648
+ }
19649
+ }
19650
+ addToPath(path9, added, removed, oldPosInc, options) {
19651
+ const last = path9.lastComponent;
19652
+ if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
19653
+ return {
19654
+ oldPos: path9.oldPos + oldPosInc,
19655
+ lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
19543
19656
  };
19544
19657
  } else {
19545
- if (value.prefill !== void 0 && typeof value.prefill !== "string") {
19546
- throw new OmpRpcFaultError("protocolError", "Omp RPC editor prefill is invalid");
19547
- }
19548
- request = {
19549
- requestId,
19550
- method: "editor",
19551
- title,
19552
- ...typeof value.prefill === "string" ? { prefill: value.prefill } : {},
19553
- ...typeof timeoutMs === "number" ? { timeoutMs } : {}
19658
+ return {
19659
+ oldPos: path9.oldPos + oldPosInc,
19660
+ lastComponent: { count: 1, added, removed, previousComponent: last }
19554
19661
  };
19555
19662
  }
19556
- const pending = { request, timeout: null };
19557
- if (request.timeoutMs !== void 0) {
19558
- pending.timeout = setTimeout(() => {
19559
- if (this.#activeTurn !== active || !active.interactions.has(requestId))
19560
- return;
19561
- void this.#resolveInteraction({ requestId, cancelled: true }, "expired").catch((error51) => {
19562
- if (this.#closed || this.#failed)
19563
- return;
19564
- this.#fail(new OmpRpcFaultError("protocolError", `Omp RPC Interaction timeout handling failed: ${message2(error51)}`));
19565
- });
19566
- }, request.timeoutMs);
19663
+ }
19664
+ extractCommon(basePath, newTokens, oldTokens, diagonalPath, options) {
19665
+ const newLen = newTokens.length, oldLen = oldTokens.length;
19666
+ let oldPos = basePath.oldPos, newPos = oldPos - diagonalPath, commonCount = 0;
19667
+ while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(oldTokens[oldPos + 1], newTokens[newPos + 1], options)) {
19668
+ newPos++;
19669
+ oldPos++;
19670
+ commonCount++;
19671
+ if (options.oneChangePerToken) {
19672
+ basePath.lastComponent = { count: 1, previousComponent: basePath.lastComponent, added: false, removed: false };
19673
+ }
19567
19674
  }
19568
- active.interactions.set(requestId, pending);
19569
- active.onEvent({ type: "interaction.requested", request });
19675
+ if (commonCount && !options.oneChangePerToken) {
19676
+ basePath.lastComponent = { count: commonCount, previousComponent: basePath.lastComponent, added: false, removed: false };
19677
+ }
19678
+ basePath.oldPos = oldPos;
19679
+ return newPos;
19570
19680
  }
19571
- #handleResponse(value) {
19572
- const id = value.id;
19573
- if (typeof id !== "string") {
19574
- this.#fail(new OmpRpcFaultError("protocolError", "Omp RPC response has no id"));
19575
- return;
19681
+ equals(left, right, options) {
19682
+ if (options.comparator) {
19683
+ return options.comparator(left, right);
19684
+ } else {
19685
+ return left === right || !!options.ignoreCase && left.toLowerCase() === right.toLowerCase();
19576
19686
  }
19577
- const pending = this.#pending.get(id);
19578
- const active = this.#activeTurn;
19579
- if (!pending) {
19580
- if (active?.promptId === id && value.command === "prompt" && value.success === false) {
19581
- active.failure = new Error(typeof value.error === "string" ? value.error : "Omp RPC command failed");
19582
- return;
19687
+ }
19688
+ removeEmpty(array2) {
19689
+ const ret = [];
19690
+ for (let i = 0; i < array2.length; i++) {
19691
+ if (array2[i]) {
19692
+ ret.push(array2[i]);
19583
19693
  }
19584
- this.#fail(new OmpRpcFaultError("protocolError", "Omp RPC response id is not pending"));
19585
- return;
19586
19694
  }
19587
- if (pending.timeout)
19588
- clearTimeout(pending.timeout);
19589
- this.#pending.delete(id);
19590
- if (value.success === true) {
19591
- if (pending.command === "prompt" && active?.promptId === id && isRecord8(value.data) && value.data.agentInvoked === false) {
19592
- this.#settleLocalTurn(active, { cancelled: false });
19593
- }
19594
- pending.resolve(value);
19595
- } else {
19596
- const error51 = typeof value.error === "string" ? value.error : "Omp RPC command failed";
19597
- if (value.command === pending.command && error51 === `Unknown command: ${pending.command}`) {
19598
- pending.reject(new OmpRpcUnsupportedCommandError(pending.command));
19695
+ return ret;
19696
+ }
19697
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
19698
+ castInput(value, options) {
19699
+ return value;
19700
+ }
19701
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
19702
+ tokenize(value, options) {
19703
+ return Array.from(value);
19704
+ }
19705
+ join(chars) {
19706
+ return chars.join("");
19707
+ }
19708
+ postProcess(changeObjects, options) {
19709
+ return changeObjects;
19710
+ }
19711
+ get useLongestToken() {
19712
+ return false;
19713
+ }
19714
+ buildValues(lastComponent, newTokens, oldTokens) {
19715
+ const components = [];
19716
+ let nextComponent;
19717
+ while (lastComponent) {
19718
+ components.push(lastComponent);
19719
+ nextComponent = lastComponent.previousComponent;
19720
+ delete lastComponent.previousComponent;
19721
+ lastComponent = nextComponent;
19722
+ }
19723
+ components.reverse();
19724
+ const componentLen = components.length;
19725
+ let componentPos = 0, newPos = 0, oldPos = 0;
19726
+ for (; componentPos < componentLen; componentPos++) {
19727
+ const component = components[componentPos];
19728
+ if (!component.removed) {
19729
+ if (!component.added && this.useLongestToken) {
19730
+ let value = newTokens.slice(newPos, newPos + component.count);
19731
+ value = value.map(function(value2, i) {
19732
+ const oldValue = oldTokens[oldPos + i];
19733
+ return oldValue.length > value2.length ? oldValue : value2;
19734
+ });
19735
+ component.value = this.join(value);
19736
+ } else {
19737
+ component.value = this.join(newTokens.slice(newPos, newPos + component.count));
19738
+ }
19739
+ newPos += component.count;
19740
+ if (!component.added) {
19741
+ oldPos += component.count;
19742
+ }
19599
19743
  } else {
19600
- pending.reject(new Error(error51));
19744
+ component.value = this.join(oldTokens.slice(oldPos, oldPos + component.count));
19745
+ oldPos += component.count;
19601
19746
  }
19602
19747
  }
19748
+ return components;
19603
19749
  }
19604
- #startTool(active, value) {
19605
- const callId = value.toolCallId;
19606
- const toolName = value.toolName;
19607
- const argumentsResult = jsonValueSchema.safeParse(value.args);
19608
- if (typeof callId !== "string" || callId.length === 0 || typeof toolName !== "string" || toolName.length === 0 || !argumentsResult.success || active.tools.has(callId)) {
19609
- throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid Tool start");
19610
- }
19611
- active.sawTool = true;
19612
- active.tools.set(callId, toolName);
19613
- active.onEvent({
19614
- type: "tool.started",
19615
- callId,
19616
- toolName,
19617
- arguments: argumentsResult.data
19618
- });
19750
+ };
19751
+
19752
+ // ../../../node_modules/diff/libesm/diff/line.js
19753
+ var LineDiff = class extends Diff {
19754
+ constructor() {
19755
+ super(...arguments);
19756
+ this.tokenize = tokenize;
19619
19757
  }
19620
- #updateTool(active, value) {
19621
- const callId = value.toolCallId;
19622
- if (typeof callId !== "string" || callId.length === 0) {
19623
- throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid Tool update");
19624
- }
19625
- if (!active.tools.has(callId))
19626
- return;
19627
- const outputResult = jsonValueSchema.safeParse(value.partialResult ?? null);
19628
- if (!outputResult.success) {
19629
- throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid Tool update");
19758
+ equals(left, right, options) {
19759
+ if (options.ignoreWhitespace) {
19760
+ if (!options.newlineIsToken || !left.includes("\n")) {
19761
+ left = left.trim();
19762
+ }
19763
+ if (!options.newlineIsToken || !right.includes("\n")) {
19764
+ right = right.trim();
19765
+ }
19766
+ } else if (options.ignoreNewlineAtEof && !options.newlineIsToken) {
19767
+ if (left.endsWith("\n")) {
19768
+ left = left.slice(0, -1);
19769
+ }
19770
+ if (right.endsWith("\n")) {
19771
+ right = right.slice(0, -1);
19772
+ }
19630
19773
  }
19631
- active.onEvent({ type: "tool.updated", callId, output: outputResult.data });
19774
+ return super.equals(left, right, options);
19632
19775
  }
19633
- #completeTool(active, value) {
19634
- const callId = value.toolCallId;
19635
- const toolName = value.toolName;
19636
- if (typeof callId !== "string" || callId.length === 0) {
19637
- throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid Tool end");
19638
- }
19639
- const expectedName = active.tools.get(callId);
19640
- if (expectedName === void 0)
19641
- return;
19642
- const result = jsonValueSchema.safeParse(value.result);
19643
- if (typeof toolName !== "string" || expectedName !== toolName || value.isError !== void 0 && typeof value.isError !== "boolean" || !result.success) {
19644
- throw new OmpRpcFaultError("protocolError", "Omp RPC returned an invalid Tool end");
19776
+ };
19777
+ var lineDiff = new LineDiff();
19778
+ function diffLines(oldStr, newStr, options) {
19779
+ return lineDiff.diff(oldStr, newStr, options);
19780
+ }
19781
+ function tokenize(value, options) {
19782
+ if (options.stripTrailingCr) {
19783
+ value = value.replace(/\r\n/g, "\n");
19784
+ }
19785
+ const retLines = [], linesAndNewlines = value.split(/(\n|\r\n)/);
19786
+ if (!linesAndNewlines[linesAndNewlines.length - 1]) {
19787
+ linesAndNewlines.pop();
19788
+ }
19789
+ for (let i = 0; i < linesAndNewlines.length; i++) {
19790
+ const line = linesAndNewlines[i];
19791
+ if (i % 2 && !options.newlineIsToken) {
19792
+ retLines[retLines.length - 1] += line;
19793
+ } else {
19794
+ retLines.push(line);
19645
19795
  }
19646
- active.tools.delete(callId);
19647
- active.onEvent({
19648
- type: "tool.completed",
19649
- callId,
19650
- toolName,
19651
- result: result.data,
19652
- isError: value.isError === true
19653
- });
19654
19796
  }
19655
- async #confirmCancelledTurn(active) {
19656
- if (this.#activeTurn !== active || active.cancellation !== "accepted" || active.settlement === "confirming" || active.cancellationChecking)
19657
- return;
19658
- active.cancellationChecking = true;
19659
- if (active.cancellationRecheck)
19660
- clearTimeout(active.cancellationRecheck);
19661
- active.cancellationRecheck = null;
19662
- try {
19663
- let response = await this.#send("get_state", {});
19664
- if (this.#activeTurn !== active)
19665
- return;
19666
- if (parseSessionStreaming(response)) {
19667
- await this.#send("abort", {});
19668
- if (this.#activeTurn !== active)
19669
- return;
19670
- response = await this.#send("get_state", {});
19797
+ return retLines;
19798
+ }
19799
+
19800
+ // ../../../node_modules/diff/libesm/patch/parse.js
19801
+ function parsePatch(uniDiff) {
19802
+ const diffstr = uniDiff.split(/\n/), list = [];
19803
+ let i = 0;
19804
+ function parseIndex() {
19805
+ const index = {};
19806
+ list.push(index);
19807
+ while (i < diffstr.length) {
19808
+ const line = diffstr[i];
19809
+ if (/^(---|\+\+\+|@@)\s/.test(line)) {
19810
+ break;
19671
19811
  }
19672
- let state = parseSessionState(response);
19673
- if (this.#activeTurn !== active || active.cancellation !== "accepted")
19674
- return;
19675
- const data = sessionStateData(response);
19676
- 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) {
19677
- await this.verifySessionCwd(this.#options.cwd);
19678
- if (this.#activeTurn !== active)
19679
- return;
19680
- active.cancellationReloaded = true;
19681
- const reset = await this.#send("new_session", {});
19682
- if (this.#activeTurn !== active)
19683
- return;
19684
- if (!isRecord8(reset.data) || reset.data.cancelled !== false) {
19685
- throw new OmpRpcFaultError("unavailable", "Omp cancelled Session reset was refused");
19686
- }
19687
- const reloaded = await this.#send("switch_session", { sessionPath: state.sessionFile });
19688
- if (this.#activeTurn !== active)
19689
- return;
19690
- if (!isRecord8(reloaded.data) || reloaded.data.cancelled !== false) {
19691
- throw new OmpRpcFaultError("unavailable", "Omp cancelled Session reload was refused");
19692
- }
19693
- const previous = state;
19694
- response = await this.#send("get_state", {});
19695
- state = parseSessionState(response);
19696
- if (state.sessionId !== previous.sessionId || state.sessionFile !== previous.sessionFile) {
19697
- throw new OmpRpcFaultError("protocolError", "Omp cancelled Session reload changed its identity");
19698
- }
19699
- if (state.provider !== previous.provider || state.modelId !== previous.modelId) {
19700
- if (!previous.provider || !previous.modelId) {
19701
- throw new OmpRpcFaultError("protocolError", "Omp cancelled Session has no restorable Model");
19702
- }
19703
- await this.#send("set_model", { provider: previous.provider, modelId: previous.modelId });
19704
- }
19705
- if (previous.thinkingLevel && state.thinkingLevel !== previous.thinkingLevel) {
19706
- await this.#send("set_thinking_level", { level: previous.thinkingLevel });
19707
- }
19708
- response = await this.#send("get_state", {});
19709
- state = parseSessionState(response);
19710
- if (state.sessionId !== previous.sessionId || state.sessionFile !== previous.sessionFile || state.provider !== previous.provider || state.modelId !== previous.modelId || previous.thinkingLevel !== null && state.thinkingLevel !== previous.thinkingLevel) {
19711
- throw new OmpRpcFaultError("protocolError", "Omp cancelled Session reload changed its identity or configuration");
19712
- }
19812
+ const header = /^(?:Index:|diff(?: -r \w+)+)\s+(.+?)\s*$/.exec(line);
19813
+ if (header) {
19814
+ index.index = header[1];
19713
19815
  }
19714
- if (!cancellationSettled(response, active.terminalEnd)) {
19715
- active.settlement = "pending";
19716
- active.cancellationRecheck = setTimeout(() => {
19717
- active.cancellationRecheck = null;
19718
- void this.#confirmCancelledTurn(active);
19719
- }, 250);
19720
- return;
19816
+ i++;
19817
+ }
19818
+ parseFileHeader(index);
19819
+ parseFileHeader(index);
19820
+ index.hunks = [];
19821
+ while (i < diffstr.length) {
19822
+ const line = diffstr[i];
19823
+ if (/^(Index:\s|diff\s|---\s|\+\+\+\s|===================================================================)/.test(line)) {
19824
+ break;
19825
+ } else if (/^@@/.test(line)) {
19826
+ index.hunks.push(parseHunk());
19827
+ } else if (line) {
19828
+ throw new Error("Unknown line " + (i + 1) + " " + JSON.stringify(line));
19829
+ } else {
19830
+ i++;
19721
19831
  }
19722
- this.#state = state;
19723
- active.settlement = "confirmed";
19724
- this.#finishSettledTurn(active);
19725
- } catch (error51) {
19726
- if (this.#activeTurn !== active)
19727
- return;
19728
- const fault = error51 instanceof OmpRpcFaultError ? error51 : new OmpRpcFaultError("protocolError", `Omp RPC cancelled Turn state could not be confirmed: ${message2(error51)}`);
19729
- this.#terminateFailedCancellation(active, fault);
19730
- } finally {
19731
- active.cancellationChecking = false;
19732
19832
  }
19733
19833
  }
19734
- #settleLocalTurn(active, result) {
19735
- if (this.#activeTurn !== active || active.settlement !== "pending")
19736
- return;
19737
- active.localResult = result;
19738
- active.settlement = "confirming";
19739
- void this.#confirmSettledTurn(active);
19740
- }
19741
- async #confirmSettledTurn(active) {
19742
- try {
19743
- const response = await this.#send("get_state", {});
19744
- const state = parseSessionState(response);
19745
- if (this.#activeTurn !== active)
19746
- return;
19747
- if (active.cancellation !== "none") {
19748
- active.settlement = "pending";
19749
- if (active.cancellation === "accepted")
19750
- void this.#confirmCancelledTurn(active);
19751
- return;
19834
+ function parseFileHeader(index) {
19835
+ const fileHeader = /^(---|\+\+\+)\s+(.*)\r?$/.exec(diffstr[i]);
19836
+ if (fileHeader) {
19837
+ const data = fileHeader[2].split(" ", 2), header = (data[1] || "").trim();
19838
+ let fileName = data[0].replace(/\\\\/g, "\\");
19839
+ if (/^".*"$/.test(fileName)) {
19840
+ fileName = fileName.substr(1, fileName.length - 2);
19752
19841
  }
19753
- if (parseSessionStreaming(response)) {
19754
- throw new OmpRpcFaultError("protocolError", "Omp RPC completed Turn state is still Streaming");
19842
+ if (fileHeader[1] === "---") {
19843
+ index.oldFileName = fileName;
19844
+ index.oldHeader = header;
19845
+ } else {
19846
+ index.newFileName = fileName;
19847
+ index.newHeader = header;
19848
+ }
19849
+ i++;
19850
+ }
19851
+ }
19852
+ function parseHunk() {
19853
+ var _a3;
19854
+ const chunkHeaderIndex = i, chunkHeaderLine = diffstr[i++], chunkHeader = chunkHeaderLine.split(/@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/);
19855
+ const hunk = {
19856
+ oldStart: +chunkHeader[1],
19857
+ oldLines: typeof chunkHeader[2] === "undefined" ? 1 : +chunkHeader[2],
19858
+ newStart: +chunkHeader[3],
19859
+ newLines: typeof chunkHeader[4] === "undefined" ? 1 : +chunkHeader[4],
19860
+ lines: []
19861
+ };
19862
+ if (hunk.oldLines === 0) {
19863
+ hunk.oldStart += 1;
19864
+ }
19865
+ if (hunk.newLines === 0) {
19866
+ hunk.newStart += 1;
19867
+ }
19868
+ let addCount = 0, removeCount = 0;
19869
+ for (; i < diffstr.length && (removeCount < hunk.oldLines || addCount < hunk.newLines || ((_a3 = diffstr[i]) === null || _a3 === void 0 ? void 0 : _a3.startsWith("\\"))); i++) {
19870
+ const operation = diffstr[i].length == 0 && i != diffstr.length - 1 ? " " : diffstr[i][0];
19871
+ if (operation === "+" || operation === "-" || operation === " " || operation === "\\") {
19872
+ hunk.lines.push(diffstr[i]);
19873
+ if (operation === "+") {
19874
+ addCount++;
19875
+ } else if (operation === "-") {
19876
+ removeCount++;
19877
+ } else if (operation === " ") {
19878
+ addCount++;
19879
+ removeCount++;
19880
+ }
19881
+ } else {
19882
+ throw new Error(`Hunk at line ${chunkHeaderIndex + 1} contained invalid line ${diffstr[i]}`);
19755
19883
  }
19756
- this.#state = state;
19757
- active.settlement = "confirmed";
19758
- this.#finishSettledTurn(active);
19759
- } catch (error51) {
19760
- if (this.#activeTurn !== active)
19761
- return;
19762
- const fault = error51 instanceof OmpRpcFaultError ? error51 : new OmpRpcFaultError("protocolError", `Omp RPC stable Turn state could not be confirmed: ${message2(error51)}`);
19763
- this.#fail(fault);
19764
19884
  }
19765
- }
19766
- #finishSettledTurn(active) {
19767
- if (this.#activeTurn !== active || active.settlement !== "confirmed" || active.cancellation === "requesting") {
19768
- return;
19885
+ if (!addCount && hunk.newLines === 1) {
19886
+ hunk.newLines = 0;
19769
19887
  }
19770
- if (active.cancellationTimeout)
19771
- clearTimeout(active.cancellationTimeout);
19772
- active.cancellationTimeout = null;
19773
- if (active.cancellationRecheck)
19774
- clearTimeout(active.cancellationRecheck);
19775
- active.cancellationRecheck = null;
19776
- this.#closeInteractions(active, active.cancellation === "accepted" ? "cancelled" : "superseded");
19777
- if (active.tools.size > 0) {
19778
- this.#fail(new OmpRpcFaultError("protocolError", "Omp RPC settled with active Tool executions"));
19779
- return;
19888
+ if (!removeCount && hunk.oldLines === 1) {
19889
+ hunk.oldLines = 0;
19780
19890
  }
19781
- this.#activeTurn = null;
19782
- if (active.localResult) {
19783
- active.resolve({
19784
- text: active.text,
19785
- agentInvoked: false,
19786
- ...active.localResult,
19787
- cancelled: active.localResult.cancelled || active.cancellation === "accepted"
19788
- });
19789
- } else if (active.cancellation === "accepted") {
19790
- active.resolve({ text: active.text, cancelled: true, agentInvoked: true });
19791
- } else if (active.failure) {
19792
- active.reject(active.failure);
19793
- } else if (active.text.trim().length === 0 && !active.sawTool) {
19794
- active.reject(new Error("Omp RPC settled without displayable output"));
19795
- } else {
19796
- active.resolve({ text: active.text, cancelled: false, agentInvoked: true });
19891
+ if (addCount !== hunk.newLines) {
19892
+ throw new Error("Added line count did not match for hunk at line " + (chunkHeaderIndex + 1));
19797
19893
  }
19798
- }
19799
- #startAssistantMessage(active, value) {
19800
- if (active.assistantMessageId !== null && active.reasoningMessageOpen) {
19801
- active.onEvent({ type: "reasoning.completed", messageId: active.assistantMessageId });
19894
+ if (removeCount !== hunk.oldLines) {
19895
+ throw new Error("Removed line count did not match for hunk at line " + (chunkHeaderIndex + 1));
19802
19896
  }
19803
- const messageId = assistantMessageId(value) ?? randomUUID();
19804
- active.assistantMessageId = messageId;
19805
- active.sawStreamedMessageText = false;
19806
- active.sawStreamedMessageReasoning = false;
19807
- active.reasoningMessageOpen = false;
19808
- return messageId;
19897
+ return hunk;
19809
19898
  }
19810
- #ensureAssistantMessage(active, value) {
19811
- return active.assistantMessageId ?? this.#startAssistantMessage(active, value);
19899
+ while (i < diffstr.length) {
19900
+ parseIndex();
19812
19901
  }
19813
- #finalizeAssistantMessage(active, value) {
19814
- const finalText = assistantText(value);
19815
- const finalReasoning = assistantReasoning(value);
19816
- const failure = assistantFailure(value);
19817
- const cacheHitRatePercent = optionalOmpCacheHitRatePercent(value);
19818
- if (finalText === null || finalReasoning === null || failure === void 0)
19819
- return;
19820
- if (active.assistantMessageId === null && finalText === active.lastFinalizedMessageText && finalReasoning === active.lastFinalizedMessageReasoning && !active.sawStreamedMessageText && !active.sawStreamedMessageReasoning) {
19902
+ return list;
19903
+ }
19904
+
19905
+ // ../../../node_modules/diff/libesm/patch/create.js
19906
+ function structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {
19907
+ let optionsObj;
19908
+ if (!options) {
19909
+ optionsObj = {};
19910
+ } else if (typeof options === "function") {
19911
+ optionsObj = { callback: options };
19912
+ } else {
19913
+ optionsObj = options;
19914
+ }
19915
+ if (typeof optionsObj.context === "undefined") {
19916
+ optionsObj.context = 4;
19917
+ }
19918
+ const context = optionsObj.context;
19919
+ if (optionsObj.newlineIsToken) {
19920
+ throw new Error("newlineIsToken may not be used with patch-generation functions, only with diffing functions");
19921
+ }
19922
+ if (!optionsObj.callback) {
19923
+ return diffLinesResultToPatch(diffLines(oldStr, newStr, optionsObj));
19924
+ } else {
19925
+ const { callback } = optionsObj;
19926
+ diffLines(oldStr, newStr, Object.assign(Object.assign({}, optionsObj), { callback: (diff) => {
19927
+ const patch = diffLinesResultToPatch(diff);
19928
+ callback(patch);
19929
+ } }));
19930
+ }
19931
+ function diffLinesResultToPatch(diff) {
19932
+ if (!diff) {
19821
19933
  return;
19822
19934
  }
19823
- active.failure = failure;
19824
- this.#latestCacheHitRatePercent = cacheHitRatePercent;
19825
- const messageId = this.#ensureAssistantMessage(active, value);
19826
- if (!active.sawStreamedMessageReasoning && finalReasoning.length > 0) {
19827
- active.reasoningMessageOpen = true;
19828
- active.onEvent({ type: "reasoning.delta", messageId, delta: finalReasoning });
19935
+ diff.push({ value: "", lines: [] });
19936
+ function contextLines(lines) {
19937
+ return lines.map(function(entry) {
19938
+ return " " + entry;
19939
+ });
19829
19940
  }
19830
- if (active.reasoningMessageOpen && active.failure === null) {
19831
- active.onEvent({ type: "reasoning.completed", messageId });
19941
+ const hunks = [];
19942
+ let oldRangeStart = 0, newRangeStart = 0, curRange = [], oldLine = 1, newLine = 1;
19943
+ for (let i = 0; i < diff.length; i++) {
19944
+ const current = diff[i], lines = current.lines || splitLines(current.value);
19945
+ current.lines = lines;
19946
+ if (current.added || current.removed) {
19947
+ if (!oldRangeStart) {
19948
+ const prev = diff[i - 1];
19949
+ oldRangeStart = oldLine;
19950
+ newRangeStart = newLine;
19951
+ if (prev) {
19952
+ curRange = context > 0 ? contextLines(prev.lines.slice(-context)) : [];
19953
+ oldRangeStart -= curRange.length;
19954
+ newRangeStart -= curRange.length;
19955
+ }
19956
+ }
19957
+ for (const line of lines) {
19958
+ curRange.push((current.added ? "+" : "-") + line);
19959
+ }
19960
+ if (current.added) {
19961
+ newLine += lines.length;
19962
+ } else {
19963
+ oldLine += lines.length;
19964
+ }
19965
+ } else {
19966
+ if (oldRangeStart) {
19967
+ if (lines.length <= context * 2 && i < diff.length - 2) {
19968
+ for (const line of contextLines(lines)) {
19969
+ curRange.push(line);
19970
+ }
19971
+ } else {
19972
+ const contextSize = Math.min(lines.length, context);
19973
+ for (const line of contextLines(lines.slice(0, contextSize))) {
19974
+ curRange.push(line);
19975
+ }
19976
+ const hunk = {
19977
+ oldStart: oldRangeStart,
19978
+ oldLines: oldLine - oldRangeStart + contextSize,
19979
+ newStart: newRangeStart,
19980
+ newLines: newLine - newRangeStart + contextSize,
19981
+ lines: curRange
19982
+ };
19983
+ hunks.push(hunk);
19984
+ oldRangeStart = 0;
19985
+ newRangeStart = 0;
19986
+ curRange = [];
19987
+ }
19988
+ }
19989
+ oldLine += lines.length;
19990
+ newLine += lines.length;
19991
+ }
19832
19992
  }
19833
- if (!active.sawStreamedMessageText && finalText.length > 0) {
19834
- active.text += finalText;
19835
- active.onEvent({ type: "text.delta", messageId, delta: finalText });
19993
+ for (const hunk of hunks) {
19994
+ for (let i = 0; i < hunk.lines.length; i++) {
19995
+ if (hunk.lines[i].endsWith("\n")) {
19996
+ hunk.lines[i] = hunk.lines[i].slice(0, -1);
19997
+ } else {
19998
+ hunk.lines.splice(i + 1, 0, "\");
19999
+ i++;
20000
+ }
20001
+ }
19836
20002
  }
19837
- active.assistantMessageId = null;
19838
- active.sawStreamedMessageText = false;
19839
- active.sawStreamedMessageReasoning = false;
19840
- active.reasoningMessageOpen = false;
19841
- active.lastFinalizedMessageText = finalText;
19842
- active.lastFinalizedMessageReasoning = finalReasoning;
19843
- active.onEvent({ type: "message.completed", messageId });
20003
+ return {
20004
+ oldFileName,
20005
+ newFileName,
20006
+ oldHeader,
20007
+ newHeader,
20008
+ hunks
20009
+ };
19844
20010
  }
19845
- #write(value) {
19846
- const child = this.#child;
19847
- if (!child?.stdin.writable || this.#closed || this.#failed) {
19848
- return Promise.reject(new Error("Omp RPC stdin is unavailable"));
19849
- }
19850
- return new Promise((resolve, reject) => {
19851
- const frame = Buffer.from(`${JSON.stringify(value)}
19852
- `, "utf8");
19853
- child.stdin.write(frame, (error51) => error51 ? reject(error51) : resolve());
19854
- });
20011
+ }
20012
+ function formatPatch(patch) {
20013
+ if (Array.isArray(patch)) {
20014
+ return patch.map(formatPatch).join("\n");
19855
20015
  }
19856
- #send(type, payload, id = `codexhost-${randomUUID()}`) {
19857
- const child = this.#child;
19858
- if (!child?.stdin.writable || this.#closed || this.#failed) {
19859
- return Promise.reject(new Error("Omp RPC stdin is unavailable"));
19860
- }
19861
- return new Promise((resolve, reject) => {
19862
- const pending = {
19863
- command: type,
19864
- resolve,
19865
- reject,
19866
- timeout: null
19867
- };
19868
- this.#pending.set(id, pending);
19869
- this.#armCommandTimeout(id, pending);
19870
- const frame = Buffer.from(`${JSON.stringify({ id, type, ...payload })}
19871
- `, "utf8");
19872
- child.stdin.write(frame, (error51) => {
19873
- if (error51) {
19874
- if (pending.timeout)
19875
- clearTimeout(pending.timeout);
19876
- this.#pending.delete(id);
19877
- reject(error51);
19878
- }
19879
- });
19880
- });
20016
+ const ret = [];
20017
+ if (patch.oldFileName == patch.newFileName) {
20018
+ ret.push("Index: " + patch.oldFileName);
20019
+ }
20020
+ ret.push("===================================================================");
20021
+ ret.push("--- " + patch.oldFileName + (typeof patch.oldHeader === "undefined" ? "" : " " + patch.oldHeader));
20022
+ ret.push("+++ " + patch.newFileName + (typeof patch.newHeader === "undefined" ? "" : " " + patch.newHeader));
20023
+ for (let i = 0; i < patch.hunks.length; i++) {
20024
+ const hunk = patch.hunks[i];
20025
+ if (hunk.oldLines === 0) {
20026
+ hunk.oldStart -= 1;
20027
+ }
20028
+ if (hunk.newLines === 0) {
20029
+ hunk.newStart -= 1;
20030
+ }
20031
+ ret.push("@@ -" + hunk.oldStart + "," + hunk.oldLines + " +" + hunk.newStart + "," + hunk.newLines + " @@");
20032
+ for (const line of hunk.lines) {
20033
+ ret.push(line);
20034
+ }
19881
20035
  }
19882
- #armCommandTimeout(id, pending) {
19883
- if (pending.timeout || this.#pending.get(id) !== pending || (pending.command === "prompt" || pending.command === "compact") && this.#compactionActive) {
20036
+ return ret.join("\n") + "\n";
20037
+ }
20038
+ function createTwoFilesPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {
20039
+ if (typeof options === "function") {
20040
+ options = { callback: options };
20041
+ }
20042
+ if (!(options === null || options === void 0 ? void 0 : options.callback)) {
20043
+ const patchObj = structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options);
20044
+ if (!patchObj) {
19884
20045
  return;
19885
20046
  }
19886
- pending.timeout = setTimeout(() => {
19887
- if (this.#pending.get(id) !== pending)
19888
- return;
19889
- pending.timeout = null;
19890
- const error51 = new Error(`Omp RPC '${pending.command}' command timed out`);
19891
- if (pending.command !== "prompt") {
19892
- this.#pending.delete(id);
19893
- pending.reject(error51);
19894
- return;
20047
+ return formatPatch(patchObj);
20048
+ } else {
20049
+ const { callback } = options;
20050
+ structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, Object.assign(Object.assign({}, options), { callback: (patchObj) => {
20051
+ if (!patchObj) {
20052
+ callback(void 0);
20053
+ } else {
20054
+ callback(formatPatch(patchObj));
19895
20055
  }
19896
- const fault = new OmpRpcFaultError("protocolError", error51.message);
19897
- void this.#terminateTimedOutPrompt(fault);
19898
- }, this.#options.commandTimeoutMs);
20056
+ } }));
19899
20057
  }
19900
- async #terminateTimedOutPrompt(fault) {
19901
- if (this.#closed || this.#failed)
19902
- return;
19903
- this.#failed = true;
19904
- this.#closed = true;
19905
- for (const pending of this.#pending.values()) {
19906
- if (pending.timeout)
19907
- clearTimeout(pending.timeout);
19908
- pending.timeout = null;
19909
- }
19910
- let finalFault = fault;
19911
- try {
19912
- await this.close();
19913
- } catch (error51) {
19914
- finalFault = new OmpRpcFaultError("processExited", `Omp RPC timed-out Prompt cleanup failed: ${message2(error51)}`);
19915
- }
19916
- this.#rejectAll(finalFault);
19917
- this.#options.onFault?.(finalFault);
20058
+ }
20059
+ function splitLines(text) {
20060
+ const hasTrailingNl = text.endsWith("\n");
20061
+ const result = text.split("\n").map((line) => line + "\n");
20062
+ if (hasTrailingNl) {
20063
+ result.pop();
20064
+ } else {
20065
+ result.push(result.pop().slice(0, -1));
19918
20066
  }
19919
- #closeInteractions(active, reason) {
19920
- for (const [requestId, pending] of active.interactions) {
19921
- active.interactions.delete(requestId);
19922
- if (pending.timeout)
19923
- clearTimeout(pending.timeout);
19924
- active.onEvent({ type: "interaction.closed", requestId, reason });
19925
- }
20067
+ return result;
20068
+ }
20069
+
20070
+ // dist/omp-adapter.js
20071
+ import { randomUUID as randomUUID2 } from "node:crypto";
20072
+ import { realpath as realpath3, stat as stat2 } from "node:fs/promises";
20073
+ import path7 from "node:path";
20074
+
20075
+ // dist/omp-last-turn-rollback.js
20076
+ function modelFromState(state) {
20077
+ if (state.provider === null && state.modelId === null)
20078
+ return null;
20079
+ if (state.provider === null || state.modelId === null) {
20080
+ throw new Error("Omp state contains a partial Model identity");
19926
20081
  }
19927
- #rejectActiveTurn(error51) {
19928
- const active = this.#activeTurn;
19929
- if (!active)
19930
- return;
19931
- if (active.cancellationTimeout)
19932
- clearTimeout(active.cancellationTimeout);
19933
- if (active.cancellationRecheck)
19934
- clearTimeout(active.cancellationRecheck);
19935
- this.#closeInteractions(active, "cancelled");
19936
- this.#activeTurn = null;
19937
- active.reject(error51);
20082
+ return { provider: state.provider, id: state.modelId };
20083
+ }
20084
+ async function rollbackOmpLastTurn(transport, sourceSessionId, cwd) {
20085
+ const startupState = transport.state;
20086
+ const startupSessionId = startupState.sessionId;
20087
+ const currentModel = modelFromState(startupState);
20088
+ const currentThinking = startupState.thinkingLevel;
20089
+ const copiedHistory = await transport.getEntries();
20090
+ const boundary = resolveOmpLastTurnBoundary(copiedHistory);
20091
+ if (!boundary)
20092
+ return { ok: false, reason: "empty" };
20093
+ const sourceSnapshot = mapOmpSnapshot(copiedHistory, {
20094
+ sessionId: startupSessionId,
20095
+ model: currentModel
20096
+ });
20097
+ let state = await transport.fork(boundary.lastUserEntryId);
20098
+ if (state.sessionId === sourceSessionId || state.sessionId === startupSessionId) {
20099
+ throw new Error("Omp last-Turn rollback did not create a distinct Native Session");
19938
20100
  }
19939
- #rejectAll(error51) {
19940
- if (this.#compactionTimeout)
19941
- clearTimeout(this.#compactionTimeout);
19942
- this.#compactionTimeout = null;
19943
- for (const pending of this.#pending.values()) {
19944
- if (pending.timeout)
19945
- clearTimeout(pending.timeout);
19946
- pending.reject(error51);
19947
- }
19948
- this.#pending.clear();
19949
- const manual = this.#manualCompaction;
19950
- this.#manualCompaction = null;
19951
- manual?.reject(error51);
19952
- this.#rejectActiveTurn(error51);
20101
+ if (!sameOmpModel(modelFromState(state), currentModel)) {
20102
+ if (!currentModel)
20103
+ throw new Error("Omp last-Turn rollback changed the current Model");
20104
+ state = await transport.selectModel(currentModel);
19953
20105
  }
19954
- #fail(error51) {
19955
- if (this.#closed || this.#failed)
19956
- return;
19957
- this.#failed = true;
19958
- this.#startupFaultResolve?.(error51);
19959
- this.#startupFaultResolve = null;
19960
- this.#rejectAll(error51);
19961
- this.#options.onFault?.(error51);
20106
+ if (state.thinkingLevel !== currentThinking) {
20107
+ if (!currentThinking)
20108
+ throw new Error("Omp last-Turn rollback changed current Thinking");
20109
+ state = await transport.selectThinkingOption(currentThinking);
19962
20110
  }
19963
- };
20111
+ if (!sameOmpModel(modelFromState(state), currentModel) || state.thinkingLevel !== currentThinking) {
20112
+ throw new Error("Omp last-Turn rollback could not restore current Model and Thinking");
20113
+ }
20114
+ const snapshot = mapOmpSnapshot(await transport.getEntries(), {
20115
+ sessionId: state.sessionId,
20116
+ model: modelFromState(state)
20117
+ });
20118
+ const expectedTurnKeys = sourceSnapshot.turns.slice(0, -1).map((turn) => turn.nativeTurnRef.nativeTurnKey);
20119
+ const actualTurnKeys = snapshot.turns.map((turn) => turn.nativeTurnRef.nativeTurnKey);
20120
+ if (snapshot.turns.length !== boundary.sourceTurnCount - 1 || actualTurnKeys.some((key, index) => key !== expectedTurnKeys[index])) {
20121
+ throw new Error("Omp last-Turn rollback did not produce the exact retained history prefix");
20122
+ }
20123
+ await transport.verifySessionCwd(cwd);
20124
+ return { ok: true };
20125
+ }
19964
20126
 
19965
20127
  // dist/omp-permission-modes.js
19966
20128
  var nativePermissionModes = /* @__PURE__ */ new Set(["always-ask", "write", "yolo"]);
@@ -20113,6 +20275,24 @@ var OmpSubagentLifecycle = class {
20113
20275
  };
20114
20276
 
20115
20277
  // dist/omp-adapter.js
20278
+ function closedInspection() {
20279
+ return {
20280
+ status: "unavailable",
20281
+ error: { code: "invalidState", message: "Omp Adapter is closed", retryable: false }
20282
+ };
20283
+ }
20284
+ function ompInspectionCapabilities(selectThinkingOption) {
20285
+ return {
20286
+ configuration: {
20287
+ selectModel: true,
20288
+ selectThinkingOption,
20289
+ selectPermissionMode: true,
20290
+ permissionModeScope: "live"
20291
+ },
20292
+ history: { fork: true, forkAcrossCwd: true, rollbackLastTurn: true },
20293
+ subagents: { observe: true, readTranscript: true }
20294
+ };
20295
+ }
20116
20296
  var ompHarnessId2 = harnessIdSchema.parse("omp");
20117
20297
  var ompCommandCatalog = harnessCommandCatalogSchema.parse({
20118
20298
  commands: [
@@ -20127,7 +20307,7 @@ var ompCommandCatalog = harnessCommandCatalogSchema.parse({
20127
20307
  ]
20128
20308
  });
20129
20309
  var DEFAULT_TOOL_OUTPUT_LIMIT = 64e3;
20130
- function isRecord9(value) {
20310
+ function isRecord10(value) {
20131
20311
  return typeof value === "object" && value !== null && !Array.isArray(value);
20132
20312
  }
20133
20313
  function errorMessage(error51) {
@@ -20142,7 +20322,7 @@ var OmpAdapterFaultError = class extends Error {
20142
20322
  }
20143
20323
  };
20144
20324
  function normalizedError(error51, fallbackCode) {
20145
- if (isRecord9(error51) && error51.code === "ENOENT") {
20325
+ if (isRecord10(error51) && error51.code === "ENOENT") {
20146
20326
  return { code: "notInstalled", message: errorMessage(error51), retryable: false };
20147
20327
  }
20148
20328
  if (error51 instanceof OmpAdapterFaultError)
@@ -20219,7 +20399,7 @@ function nativeModelForHistory(state) {
20219
20399
  return nativeModelFromState(state);
20220
20400
  }
20221
20401
  function sessionFileFromRef(ref) {
20222
- if (ref.harnessId !== ompHarnessId2 || !isRecord9(ref.locator) || typeof ref.locator.sessionFile !== "string" || ref.locator.sessionFile.length === 0) {
20402
+ if (ref.harnessId !== ompHarnessId2 || !isRecord10(ref.locator) || typeof ref.locator.sessionFile !== "string" || ref.locator.sessionFile.length === 0) {
20223
20403
  throw new Error("Omp Native Session Ref has no resumable Session file");
20224
20404
  }
20225
20405
  return ref.locator.sessionFile;
@@ -20274,9 +20454,9 @@ function toolFailure(toolName) {
20274
20454
  function nativeText(value) {
20275
20455
  if (typeof value === "string")
20276
20456
  return value;
20277
- if (!isRecord9(value) || !Array.isArray(value.content))
20457
+ if (!isRecord10(value) || !Array.isArray(value.content))
20278
20458
  return "";
20279
- return value.content.filter((content) => isRecord9(content) && content.type === "text" && typeof content.text === "string").map(({ text }) => text).join("");
20459
+ return value.content.filter((content) => isRecord10(content) && content.type === "text" && typeof content.text === "string").map(({ text }) => text).join("");
20280
20460
  }
20281
20461
  function boundedOutput(value, limit) {
20282
20462
  const text = nativeText(value);
@@ -20292,17 +20472,17 @@ function outputText(output) {
20292
20472
  return output?.content.filter((content) => content.type === "text").map(({ text }) => text).join("") ?? "";
20293
20473
  }
20294
20474
  function stringField2(value, key) {
20295
- if (!isRecord9(value))
20475
+ if (!isRecord10(value))
20296
20476
  return void 0;
20297
20477
  const field = value[key];
20298
20478
  if (typeof field === "string" && field.length > 0)
20299
20479
  return field;
20300
- if (isRecord9(value.input)) {
20480
+ if (isRecord10(value.input)) {
20301
20481
  const nested = value.input[key];
20302
20482
  if (typeof nested === "string" && nested.length > 0)
20303
20483
  return nested;
20304
20484
  }
20305
- if (isRecord9(value.arguments)) {
20485
+ if (isRecord10(value.arguments)) {
20306
20486
  const nested = value.arguments[key];
20307
20487
  if (typeof nested === "string" && nested.length > 0)
20308
20488
  return nested;
@@ -20310,7 +20490,7 @@ function stringField2(value, key) {
20310
20490
  return void 0;
20311
20491
  }
20312
20492
  function numberField(value, key) {
20313
- if (!isRecord9(value))
20493
+ if (!isRecord10(value))
20314
20494
  return void 0;
20315
20495
  const field = value[key];
20316
20496
  return typeof field === "number" || field === null ? field : void 0;
@@ -20349,7 +20529,7 @@ function fileMutatingKind(toolName) {
20349
20529
  return null;
20350
20530
  }
20351
20531
  function nestedToolString(value, keys) {
20352
- if (!isRecord9(value))
20532
+ if (!isRecord10(value))
20353
20533
  return void 0;
20354
20534
  for (const key of keys) {
20355
20535
  const field = value[key];
@@ -20364,14 +20544,14 @@ function nestedToolString(value, keys) {
20364
20544
  return void 0;
20365
20545
  }
20366
20546
  function patchFromResult(result) {
20367
- if (!isRecord9(result))
20547
+ if (!isRecord10(result))
20368
20548
  return void 0;
20369
20549
  for (const key of ["patch", "diff", "unifiedDiff"]) {
20370
20550
  const field = result[key];
20371
20551
  if (typeof field === "string" && field.length > 0)
20372
20552
  return field;
20373
20553
  }
20374
- if (isRecord9(result.details)) {
20554
+ if (isRecord10(result.details)) {
20375
20555
  for (const key of ["patch", "diff", "unifiedDiff"]) {
20376
20556
  const field = result.details[key];
20377
20557
  if (typeof field === "string" && field.length > 0)
@@ -20498,9 +20678,6 @@ var OmpHarnessSession = class {
20498
20678
  #usage;
20499
20679
  #usageGeneration = 0;
20500
20680
  #usageRefreshSequence = 0;
20501
- #backgroundTurnId = null;
20502
- #backgroundSubagents = /* @__PURE__ */ new Map();
20503
- #backgroundTurnFailed = false;
20504
20681
  constructor(cwd, createTransport, onClosed, options) {
20505
20682
  this.#cwd = cwd;
20506
20683
  this.#createTransport = createTransport;
@@ -20558,44 +20735,6 @@ var OmpHarnessSession = class {
20558
20735
  #backgroundStatus(status) {
20559
20736
  return status === "pending" || status === "running" ? "running" : status === "interrupted" ? "interrupted" : status;
20560
20737
  }
20561
- #ensureBackgroundTurn() {
20562
- if (this.#backgroundTurnId)
20563
- return this.#backgroundTurnId;
20564
- const turnId = hostTurnIdSchema.parse(randomUUID2());
20565
- this.#backgroundTurnId = turnId;
20566
- this.#backgroundTurnFailed = false;
20567
- this.#event({
20568
- type: "turn.autonomous.started",
20569
- turnId,
20570
- input: []
20571
- });
20572
- return turnId;
20573
- }
20574
- #backgroundDelegationStart(event) {
20575
- const turnId = this.#ensureBackgroundTurn();
20576
- const description = event.type === "subagent.started" ? event.description : event.type === "subagent.updated" ? event.description ?? "Background subagent" : "Background subagent";
20577
- const role = event.type === "subagent.started" ? event.role : void 0;
20578
- const background = event.type === "subagent.started" ? event.background : true;
20579
- const state = {
20580
- subagentId: event.nativeSubagentId,
20581
- nativeSubagentId: event.nativeSubagentId,
20582
- description,
20583
- ...role ? { role } : {},
20584
- background,
20585
- status: "running"
20586
- };
20587
- const item = {
20588
- type: "subagentDelegation",
20589
- itemId: this.#newItemId(),
20590
- operation: "spawn",
20591
- ...event.type === "subagent.started" && event.prompt ? { prompt: event.prompt } : {},
20592
- subagents: [state]
20593
- };
20594
- const delegation = { item, turnId };
20595
- this.#backgroundSubagents.set(event.callId, delegation);
20596
- this.#event({ type: "item.started", turnId, item });
20597
- return delegation;
20598
- }
20599
20738
  #handleBackgroundSubagentEvent(event) {
20600
20739
  if (event.type === "subagent.transcript.changed") {
20601
20740
  this.#event({
@@ -20607,12 +20746,6 @@ var OmpHarnessSession = class {
20607
20746
  if (event.type !== "subagent.started" && event.type !== "subagent.updated" && event.type !== "subagent.completed") {
20608
20747
  return;
20609
20748
  }
20610
- let delegation = this.#backgroundSubagents.get(event.callId);
20611
- if (!delegation)
20612
- delegation = this.#backgroundDelegationStart(event);
20613
- const current = delegation.item.subagents[0];
20614
- if (!current)
20615
- throw new Error("Omp background delegation has no Agent state");
20616
20749
  if (event.type === "subagent.started") {
20617
20750
  this.#event({
20618
20751
  type: "subagent.state.changed",
@@ -20623,19 +20756,6 @@ var OmpHarnessSession = class {
20623
20756
  }
20624
20757
  if (event.type === "subagent.updated") {
20625
20758
  const status2 = this.#backgroundStatus(event.status);
20626
- const subagent2 = {
20627
- ...current,
20628
- status: status2,
20629
- ...event.description ? { description: event.description } : {},
20630
- ...event.resultSummary ? { resultSummary: event.resultSummary } : {}
20631
- };
20632
- delegation.item = { ...delegation.item, subagents: [subagent2] };
20633
- this.#event({
20634
- type: "item.updated",
20635
- turnId: delegation.turnId,
20636
- itemId: delegation.item.itemId,
20637
- update: { type: "subagents.replace", subagents: delegation.item.subagents }
20638
- });
20639
20759
  this.#event({
20640
20760
  type: "subagent.state.changed",
20641
20761
  nativeSubagentId: event.nativeSubagentId,
@@ -20645,58 +20765,12 @@ var OmpHarnessSession = class {
20645
20765
  return;
20646
20766
  }
20647
20767
  const status = event.isError ? "failed" : "completed";
20648
- const subagent = {
20649
- ...current,
20650
- status,
20651
- ...event.resultSummary ? { resultSummary: event.resultSummary } : {}
20652
- };
20653
- delegation.item = { ...delegation.item, subagents: [subagent] };
20654
- this.#event({
20655
- type: "item.updated",
20656
- turnId: delegation.turnId,
20657
- itemId: delegation.item.itemId,
20658
- update: { type: "subagents.replace", subagents: delegation.item.subagents }
20659
- });
20660
- this.#event({
20661
- type: "item.completed",
20662
- turnId: delegation.turnId,
20663
- snapshot: {
20664
- item: delegation.item,
20665
- outcome: event.isError ? {
20666
- status: "failed",
20667
- error: {
20668
- code: "nativeFailure",
20669
- message: "Omp background Subagent failed",
20670
- retryable: false
20671
- }
20672
- } : { status: "succeeded" }
20673
- }
20674
- });
20675
20768
  this.#event({
20676
20769
  type: "subagent.state.changed",
20677
20770
  nativeSubagentId: event.nativeSubagentId,
20678
20771
  status,
20679
20772
  ...event.resultSummary ? { resultSummary: event.resultSummary } : {}
20680
20773
  });
20681
- this.#backgroundTurnFailed ||= event.isError;
20682
- this.#backgroundSubagents.delete(event.callId);
20683
- if (this.#backgroundSubagents.size === 0 && this.#backgroundTurnId === delegation.turnId) {
20684
- const turnId = this.#backgroundTurnId;
20685
- this.#backgroundTurnId = null;
20686
- this.#event({
20687
- type: "turn.completed",
20688
- turnId,
20689
- outcome: this.#backgroundTurnFailed ? {
20690
- status: "failed",
20691
- error: {
20692
- code: "nativeFailure",
20693
- message: "Omp background Subagent failed",
20694
- retryable: false
20695
- }
20696
- } : { status: "succeeded" }
20697
- });
20698
- this.#backgroundTurnFailed = false;
20699
- }
20700
20774
  }
20701
20775
  async readSnapshot() {
20702
20776
  if (this.#phase !== "open" && this.#phase !== "faulted") {
@@ -20751,6 +20825,8 @@ var OmpHarnessSession = class {
20751
20825
  }
20752
20826
  if (command.type === "turn.cancel")
20753
20827
  return this.#cancel(command);
20828
+ if (command.type === "turn.steer")
20829
+ return unsupportedSteer("OMP");
20754
20830
  if (command.type === "interaction.respond")
20755
20831
  return this.#respond(command);
20756
20832
  if (command.type === "model.select")
@@ -21946,6 +22022,9 @@ var OmpAdapter = class {
21946
22022
  #inspectionCache = /* @__PURE__ */ new Map();
21947
22023
  #inspectionInFlight = /* @__PURE__ */ new Map();
21948
22024
  #inspections = /* @__PURE__ */ new Set();
22025
+ #availabilityInFlight = /* @__PURE__ */ new Map();
22026
+ #availabilityListings = /* @__PURE__ */ new Set();
22027
+ #listModels;
21949
22028
  #sessions = /* @__PURE__ */ new Set();
21950
22029
  #toolOutputLimit;
21951
22030
  #closePromise = null;
@@ -21954,22 +22033,21 @@ var OmpAdapter = class {
21954
22033
  createTransport: (sessionOptions) => new OmpRpcSession({ ...options, ...sessionOptions })
21955
22034
  }) {
21956
22035
  this.#createTransport = dependencies.createTransport;
22036
+ const listModels = dependencies.listModels ?? listOmpModels;
22037
+ this.#listModels = ({ cwd, signal }) => listModels({
22038
+ cwd,
22039
+ signal,
22040
+ ...options.command ? { command: options.command } : {},
22041
+ ...options.environment ? { environment: options.environment } : {}
22042
+ });
21957
22043
  this.sessionImport = new OmpSessionImport({ ...process.env, ...options.environment });
21958
22044
  this.usageStatistics = createOmpUsageStatistics({ ...process.env, ...options.environment });
21959
22045
  this.#closeTimeoutMs = options.closeTimeoutMs ?? 2e3;
21960
22046
  this.#toolOutputLimit = options.toolOutputLimit ?? DEFAULT_TOOL_OUTPUT_LIMIT;
21961
22047
  }
21962
22048
  async inspect(input = {}) {
21963
- if (this.#closePromise) {
21964
- return {
21965
- status: "unavailable",
21966
- error: {
21967
- code: "invalidState",
21968
- message: "Omp Adapter is closed",
21969
- retryable: false
21970
- }
21971
- };
21972
- }
22049
+ if (this.#closePromise)
22050
+ return closedInspection();
21973
22051
  const cwd = input.cwd ?? process.cwd();
21974
22052
  const inFlight = this.#inspectionInFlight.get(cwd);
21975
22053
  if (inFlight)
@@ -21979,6 +22057,37 @@ var OmpAdapter = class {
21979
22057
  if (cached2)
21980
22058
  return cached2;
21981
22059
  }
22060
+ if (input.purpose === "availability")
22061
+ return this.#inspectAvailability(cwd, input.refresh);
22062
+ return this.#startFullInspection(cwd);
22063
+ }
22064
+ /**
22065
+ * Availability without a Session: a Session startup runs OMP's own startup work, including
22066
+ * Provider connection prewarm, for a Harness the user may never select. The listed result
22067
+ * carries no native default Model or Thinking option, so it is neither cached nor used to
22068
+ * update `#thinkingSelectionSupported`. When the list cannot answer, a full inspection answers
22069
+ * instead, reusing one that is in flight or finished meanwhile.
22070
+ */
22071
+ async #inspectAvailability(cwd, refresh = false) {
22072
+ if (refresh)
22073
+ this.#inspectionCache.delete(cwd);
22074
+ let pending = this.#availabilityInFlight.get(cwd);
22075
+ if (!pending) {
22076
+ const listing = this.#listAvailability(cwd);
22077
+ pending = listing.finally(() => {
22078
+ if (this.#availabilityInFlight.get(cwd) === pending)
22079
+ this.#availabilityInFlight.delete(cwd);
22080
+ });
22081
+ this.#availabilityInFlight.set(cwd, pending);
22082
+ }
22083
+ const listed = await pending;
22084
+ if (listed)
22085
+ return listed;
22086
+ if (this.#closePromise)
22087
+ return closedInspection();
22088
+ return this.#inspectionInFlight.get(cwd) ?? this.#inspectionCache.get(cwd) ?? this.#startFullInspection(cwd);
22089
+ }
22090
+ #startFullInspection(cwd) {
21982
22091
  const inspection = this.#inspectCwd(cwd).then((result) => {
21983
22092
  if (result.status === "ready")
21984
22093
  this.#inspectionCache.set(cwd, result);
@@ -21991,6 +22100,59 @@ var OmpAdapter = class {
21991
22100
  }
21992
22101
  });
21993
22102
  }
22103
+ /** Returns null when a Session must answer: this OMP cannot list Models, or lists none. */
22104
+ async #listAvailability(cwd) {
22105
+ const startedAt = Date.now();
22106
+ const stage = "model-list";
22107
+ const controller = new AbortController();
22108
+ this.#availabilityListings.add(controller);
22109
+ let listed;
22110
+ try {
22111
+ listed = await this.#listModels({ cwd, signal: controller.signal });
22112
+ } finally {
22113
+ this.#availabilityListings.delete(controller);
22114
+ }
22115
+ if (listed.kind === "unanswered")
22116
+ return null;
22117
+ if (listed.kind === "notInstalled") {
22118
+ return {
22119
+ status: "notInstalled",
22120
+ error: {
22121
+ code: "notInstalled",
22122
+ message: listed.message,
22123
+ retryable: false,
22124
+ stage,
22125
+ durationMs: Date.now() - startedAt
22126
+ }
22127
+ };
22128
+ }
22129
+ if (listed.kind === "timedOut") {
22130
+ return {
22131
+ status: "error",
22132
+ error: {
22133
+ code: "unavailable",
22134
+ message: "Oh My Pi did not list its models in time",
22135
+ retryable: true,
22136
+ stage,
22137
+ durationMs: Date.now() - startedAt
22138
+ }
22139
+ };
22140
+ }
22141
+ if (listed.models.length === 0)
22142
+ return null;
22143
+ let catalog;
22144
+ try {
22145
+ catalog = normalizeOmpModelCatalog(listed.models, null, null, null);
22146
+ } catch {
22147
+ return null;
22148
+ }
22149
+ return {
22150
+ status: "ready",
22151
+ catalog,
22152
+ permissionModes: OMP_PERMISSION_MODE_CATALOG,
22153
+ capabilities: ompInspectionCapabilities(false)
22154
+ };
22155
+ }
21994
22156
  async #inspectCwd(cwd) {
21995
22157
  const startedAt = Date.now();
21996
22158
  let stage = "spawn";
@@ -22014,16 +22176,7 @@ var OmpAdapter = class {
22014
22176
  status: "ready",
22015
22177
  catalog,
22016
22178
  permissionModes: OMP_PERMISSION_MODE_CATALOG,
22017
- capabilities: {
22018
- configuration: {
22019
- selectModel: true,
22020
- selectThinkingOption: thinkingLevels !== null,
22021
- selectPermissionMode: true,
22022
- permissionModeScope: "live"
22023
- },
22024
- history: { fork: true, forkAcrossCwd: true, rollbackLastTurn: true },
22025
- subagents: { observe: true, readTranscript: true }
22026
- }
22179
+ capabilities: ompInspectionCapabilities(thinkingLevels !== null)
22027
22180
  };
22028
22181
  } catch (error51) {
22029
22182
  await transport.close().catch(() => void 0);
@@ -22234,6 +22387,8 @@ var OmpAdapter = class {
22234
22387
  }
22235
22388
  close() {
22236
22389
  if (!this.#closePromise) {
22390
+ for (const listing of this.#availabilityListings)
22391
+ listing.abort();
22237
22392
  this.#closePromise = Promise.all([
22238
22393
  this.sessionImport.close(),
22239
22394
  ...[...this.#inspections].map((transport) => transport.close()),