@codexhost/cli-linux-arm64 0.6.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,8 +7,8 @@ var __export = (target, all) => {
7
7
 
8
8
  // dist/opencode-adapter.js
9
9
  import { randomUUID } from "node:crypto";
10
- import fs2 from "node:fs";
11
- import path4 from "node:path";
10
+ import fs3 from "node:fs";
11
+ import path5 from "node:path";
12
12
 
13
13
  // ../../../node_modules/zod/v4/classic/external.js
14
14
  var external_exports = {};
@@ -776,10 +776,10 @@ function mergeDefs(...defs) {
776
776
  function cloneDef(schema) {
777
777
  return mergeDefs(schema._zod.def);
778
778
  }
779
- function getElementAtPath(obj, path5) {
780
- if (!path5)
779
+ function getElementAtPath(obj, path6) {
780
+ if (!path6)
781
781
  return obj;
782
- return path5.reduce((acc, key) => acc?.[key], obj);
782
+ return path6.reduce((acc, key) => acc?.[key], obj);
783
783
  }
784
784
  function promiseAllObject(promisesObj) {
785
785
  const keys = Object.keys(promisesObj);
@@ -1188,11 +1188,11 @@ function explicitlyAborted(x, startIndex = 0) {
1188
1188
  }
1189
1189
  return false;
1190
1190
  }
1191
- function prefixIssues(path5, issues) {
1191
+ function prefixIssues(path6, issues) {
1192
1192
  return issues.map((iss) => {
1193
1193
  var _a3;
1194
1194
  (_a3 = iss).path ?? (_a3.path = []);
1195
- iss.path.unshift(path5);
1195
+ iss.path.unshift(path6);
1196
1196
  return iss;
1197
1197
  });
1198
1198
  }
@@ -1339,16 +1339,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
1339
1339
  }
1340
1340
  function formatError(error51, mapper = (issue2) => issue2.message) {
1341
1341
  const fieldErrors = { _errors: [] };
1342
- const processError = (error52, path5 = []) => {
1342
+ const processError = (error52, path6 = []) => {
1343
1343
  for (const issue2 of error52.issues) {
1344
1344
  if (issue2.code === "invalid_union" && issue2.errors.length) {
1345
- issue2.errors.map((issues) => processError({ issues }, [...path5, ...issue2.path]));
1345
+ issue2.errors.map((issues) => processError({ issues }, [...path6, ...issue2.path]));
1346
1346
  } else if (issue2.code === "invalid_key") {
1347
- processError({ issues: issue2.issues }, [...path5, ...issue2.path]);
1347
+ processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
1348
1348
  } else if (issue2.code === "invalid_element") {
1349
- processError({ issues: issue2.issues }, [...path5, ...issue2.path]);
1349
+ processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
1350
1350
  } else {
1351
- const fullpath = [...path5, ...issue2.path];
1351
+ const fullpath = [...path6, ...issue2.path];
1352
1352
  if (fullpath.length === 0) {
1353
1353
  fieldErrors._errors.push(mapper(issue2));
1354
1354
  } else {
@@ -1375,17 +1375,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
1375
1375
  }
1376
1376
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
1377
1377
  const result = { errors: [] };
1378
- const processError = (error52, path5 = []) => {
1378
+ const processError = (error52, path6 = []) => {
1379
1379
  var _a3, _b;
1380
1380
  for (const issue2 of error52.issues) {
1381
1381
  if (issue2.code === "invalid_union" && issue2.errors.length) {
1382
- issue2.errors.map((issues) => processError({ issues }, [...path5, ...issue2.path]));
1382
+ issue2.errors.map((issues) => processError({ issues }, [...path6, ...issue2.path]));
1383
1383
  } else if (issue2.code === "invalid_key") {
1384
- processError({ issues: issue2.issues }, [...path5, ...issue2.path]);
1384
+ processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
1385
1385
  } else if (issue2.code === "invalid_element") {
1386
- processError({ issues: issue2.issues }, [...path5, ...issue2.path]);
1386
+ processError({ issues: issue2.issues }, [...path6, ...issue2.path]);
1387
1387
  } else {
1388
- const fullpath = [...path5, ...issue2.path];
1388
+ const fullpath = [...path6, ...issue2.path];
1389
1389
  if (fullpath.length === 0) {
1390
1390
  result.errors.push(mapper(issue2));
1391
1391
  continue;
@@ -1417,8 +1417,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
1417
1417
  }
1418
1418
  function toDotPath(_path) {
1419
1419
  const segs = [];
1420
- const path5 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1421
- for (const seg of path5) {
1420
+ const path6 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1421
+ for (const seg of path6) {
1422
1422
  if (typeof seg === "number")
1423
1423
  segs.push(`[${seg}]`);
1424
1424
  else if (typeof seg === "symbol")
@@ -14110,13 +14110,13 @@ function resolveRef(ref, ctx) {
14110
14110
  if (!ref.startsWith("#")) {
14111
14111
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
14112
14112
  }
14113
- const path5 = ref.slice(1).split("/").filter(Boolean);
14114
- if (path5.length === 0) {
14113
+ const path6 = ref.slice(1).split("/").filter(Boolean);
14114
+ if (path6.length === 0) {
14115
14115
  return ctx.rootSchema;
14116
14116
  }
14117
14117
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
14118
- if (path5[0] === defsKey) {
14119
- const key = path5[1];
14118
+ if (path6[0] === defsKey) {
14119
+ const key = path6[1];
14120
14120
  if (!key || !ctx.defs[key]) {
14121
14121
  throw new Error(`Reference not found: ${ref}`);
14122
14122
  }
@@ -14550,6 +14550,8 @@ var threadUsageSnapshotSchema = external_exports.object({
14550
14550
  reasoningOutputTokens: nonNegativeSafeIntegerSchema.optional(),
14551
14551
  totalTokens: nonNegativeSafeIntegerSchema.optional(),
14552
14552
  totalCostUsd: finiteNonNegativeNumberSchema.optional(),
14553
+ totalCredits: finiteNonNegativeNumberSchema.optional(),
14554
+ contextUsagePercent: finiteNonNegativeNumberSchema.optional(),
14553
14555
  cacheHitRatePercent: cacheHitRatePercentSchema.optional(),
14554
14556
  contextWindowTokens: nonNegativeSafeIntegerSchema.optional(),
14555
14557
  contextUsedTokens: nonNegativeSafeIntegerSchema.optional(),
@@ -15481,7 +15483,9 @@ var usageFields = /* @__PURE__ */ new Set([
15481
15483
  ...tokenFields,
15482
15484
  ...safeIntegerFields,
15483
15485
  ...percentFields,
15484
- "totalCostUsd"
15486
+ "totalCostUsd",
15487
+ "totalCredits",
15488
+ "contextUsagePercent"
15485
15489
  ]);
15486
15490
  function isRecord(value) {
15487
15491
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -15497,6 +15501,12 @@ function parseHostUsage(value) {
15497
15501
  throw new Error(`Harness Usage contains unknown field '${key}'`);
15498
15502
  }
15499
15503
  }
15504
+ for (const field of ["totalCredits", "contextUsagePercent"]) {
15505
+ const candidate = value[field];
15506
+ if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isFinite(candidate) || candidate < 0)) {
15507
+ throw new Error(`Harness Usage '${field}' must be a finite non-negative number`);
15508
+ }
15509
+ }
15500
15510
  for (const field of tokenFields) {
15501
15511
  const candidate = value[field];
15502
15512
  if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isSafeInteger(candidate) || candidate < 0)) {
@@ -16185,7 +16195,7 @@ var serializeObjectParam = ({ allowReserved, explode, name, style, value, valueO
16185
16195
 
16186
16196
  // ../../../node_modules/@opencode-ai/sdk/dist/v2/gen/core/utils.gen.js
16187
16197
  var PATH_PARAM_RE = /\{[^{}]+\}/g;
16188
- var defaultPathSerializer = ({ path: path5, url: _url2 }) => {
16198
+ var defaultPathSerializer = ({ path: path6, url: _url2 }) => {
16189
16199
  let url2 = _url2;
16190
16200
  const matches = _url2.match(PATH_PARAM_RE);
16191
16201
  if (matches) {
@@ -16204,7 +16214,7 @@ var defaultPathSerializer = ({ path: path5, url: _url2 }) => {
16204
16214
  name = name.substring(1);
16205
16215
  style = "matrix";
16206
16216
  }
16207
- const value = path5[name];
16217
+ const value = path6[name];
16208
16218
  if (value === void 0 || value === null) {
16209
16219
  continue;
16210
16220
  }
@@ -16235,11 +16245,11 @@ var defaultPathSerializer = ({ path: path5, url: _url2 }) => {
16235
16245
  }
16236
16246
  return url2;
16237
16247
  };
16238
- var getUrl = ({ baseUrl, path: path5, query, querySerializer, url: _url2 }) => {
16248
+ var getUrl = ({ baseUrl, path: path6, query, querySerializer, url: _url2 }) => {
16239
16249
  const pathUrl = _url2.startsWith("/") ? _url2 : `/${_url2}`;
16240
16250
  let url2 = (baseUrl ?? "") + pathUrl;
16241
- if (path5) {
16242
- url2 = defaultPathSerializer({ path: path5, url: url2 });
16251
+ if (path6) {
16252
+ url2 = defaultPathSerializer({ path: path6, url: url2 });
16243
16253
  }
16244
16254
  let search = query ? querySerializer(query) : "";
16245
16255
  if (search.startsWith("?")) {
@@ -21967,6 +21977,10 @@ var SdkOpenCodeTransport = class {
21967
21977
  const client2 = await this.#getClient();
21968
21978
  return responseData2(await withTimeout2(client2.session.get({ sessionID }), this.#commandTimeoutMs, "OpenCode Session read"), "Session read");
21969
21979
  }
21980
+ async getPaths() {
21981
+ const client2 = await this.#getClient();
21982
+ return responseData2(await withTimeout2(client2.path.get(), this.#commandTimeoutMs, "OpenCode Path read"), "Path read");
21983
+ }
21970
21984
  async updateSessionMetadata(sessionID, metadata) {
21971
21985
  const client2 = await this.#getClient();
21972
21986
  return responseData2(await withTimeout2(client2.session.update({ sessionID, metadata }), this.#commandTimeoutMs, "OpenCode Session metadata update"), "Session metadata update");
@@ -22109,6 +22123,65 @@ var SdkOpenCodeTransport = class {
22109
22123
  }
22110
22124
  };
22111
22125
 
22126
+ // dist/file-change-verification.js
22127
+ import fs2 from "node:fs";
22128
+ import path4 from "node:path";
22129
+ function missingPath(error51) {
22130
+ if (!error51 || typeof error51 !== "object")
22131
+ return false;
22132
+ const code = Reflect.get(error51, "code");
22133
+ return code === "ENOENT" || code === "ENOTDIR";
22134
+ }
22135
+ function hasDotPathSegment(value) {
22136
+ const segments = process.platform === "win32" ? value.split(/[\\/]+/) : value.split("/");
22137
+ return segments.some((segment) => segment === "." || segment === "..");
22138
+ }
22139
+ function canonicalDirectoryPath(value) {
22140
+ let candidate = path4.resolve(value);
22141
+ const missingSegments = [];
22142
+ for (; ; ) {
22143
+ try {
22144
+ return path4.join(fs2.realpathSync.native(candidate), ...missingSegments);
22145
+ } catch (error51) {
22146
+ if (!missingPath(error51))
22147
+ return void 0;
22148
+ const parent = path4.dirname(candidate);
22149
+ if (parent === candidate)
22150
+ return void 0;
22151
+ missingSegments.unshift(path4.basename(candidate));
22152
+ candidate = parent;
22153
+ }
22154
+ }
22155
+ }
22156
+ function canonicalFilePath(value) {
22157
+ const absolute = path4.resolve(value);
22158
+ const parent = canonicalDirectoryPath(path4.dirname(absolute));
22159
+ return parent ? path4.join(parent, path4.basename(absolute)) : void 0;
22160
+ }
22161
+ function pathIsWithin(root, candidate, allowRoot) {
22162
+ const relative = path4.relative(root, candidate);
22163
+ return allowRoot && relative === "" || relative !== "" && relative !== ".." && !relative.startsWith(`..${path4.sep}`) && !path4.isAbsolute(relative);
22164
+ }
22165
+ function verifiedOpenCodeWorktree(sessionDirectory, paths) {
22166
+ if (!paths || typeof paths !== "object" || typeof sessionDirectory !== "string" || typeof paths.directory !== "string" || typeof paths.worktree !== "string" || hasDotPathSegment(sessionDirectory) || hasDotPathSegment(paths.directory) || hasDotPathSegment(paths.worktree) || !path4.isAbsolute(sessionDirectory) || !path4.isAbsolute(paths.directory) || !path4.isAbsolute(paths.worktree)) {
22167
+ return void 0;
22168
+ }
22169
+ const session = canonicalDirectoryPath(sessionDirectory);
22170
+ const directory = canonicalDirectoryPath(paths.directory);
22171
+ const worktree = canonicalDirectoryPath(paths.worktree);
22172
+ if (!session || !directory || !worktree || session !== directory || !pathIsWithin(worktree, directory, true)) {
22173
+ return void 0;
22174
+ }
22175
+ return worktree;
22176
+ }
22177
+ function openCodeFileIdentity(file2, worktree) {
22178
+ if (typeof file2 !== "string" || typeof worktree !== "string" || hasDotPathSegment(file2) || hasDotPathSegment(worktree) || !path4.isAbsolute(worktree) || !file2 || file2.includes("\0") || file2.includes("\n") || file2.includes("\r")) {
22179
+ return void 0;
22180
+ }
22181
+ const candidate = canonicalFilePath(path4.isAbsolute(file2) ? file2 : path4.resolve(worktree, file2));
22182
+ return candidate && pathIsWithin(worktree, candidate, false) ? candidate : void 0;
22183
+ }
22184
+
22112
22185
  // dist/usage.js
22113
22186
  function projectOpenCodeUsage(messages, contextWindowTokens) {
22114
22187
  if (messages.length === 0)
@@ -22148,51 +22221,9 @@ function projectOpenCodeUsage(messages, contextWindowTokens) {
22148
22221
  });
22149
22222
  }
22150
22223
 
22151
- // dist/opencode-adapter.js
22152
- var openCodeHarnessId2 = harnessIdSchema.parse("opencode");
22153
- var DEFAULT_TOOL_OUTPUT_LIMIT = 64e3;
22154
- var DEFAULT_CLOSE_TIMEOUT_MS2 = 3e3;
22155
- var DIFF_RECONCILIATION_DELAYS_MS = [25, 50, 100, 200, 400, 800];
22156
- var COMPACT_COMMAND_ID = "opencode.compact";
22224
+ // dist/history-projection.js
22157
22225
  var SELECTION_METADATA_KEY = "codexhost.selection.v1";
22158
- function invalidState(message) {
22159
- return { code: "invalidState", message, retryable: false };
22160
- }
22161
- function unsupported(message) {
22162
- return { code: "unsupported", message, retryable: false };
22163
- }
22164
- function normalizeError(error51, fallback) {
22165
- if (error51 instanceof OpenCodeTransportError) {
22166
- return {
22167
- code: error51.code,
22168
- message: error51.message,
22169
- retryable: error51.code === "unavailable" || error51.code === "processExited" || error51.code === "authenticationRequired"
22170
- };
22171
- }
22172
- const text = error51 instanceof Error ? error51.message : String(error51);
22173
- const lower = text.toLowerCase();
22174
- if (lower.includes("sessionbusy") || lower.includes("session busy")) {
22175
- return { code: "sessionBusy", message: text, retryable: true };
22176
- }
22177
- if (lower.includes("not found")) {
22178
- return { code: "sessionNotFound", message: text, retryable: false };
22179
- }
22180
- return {
22181
- code: fallback,
22182
- message: text,
22183
- retryable: fallback === "unavailable" || fallback === "nativeFailure"
22184
- };
22185
- }
22186
- function sameCwd(left, right) {
22187
- const canonical = (value) => {
22188
- try {
22189
- return fs2.realpathSync.native(value);
22190
- } catch {
22191
- return path4.resolve(value);
22192
- }
22193
- };
22194
- return canonical(left) === canonical(right);
22195
- }
22226
+ var DIFF_RECONCILIATION_DELAYS_MS = [25, 50, 100, 200, 400, 800];
22196
22227
  function storedSelection(session) {
22197
22228
  const value = session.metadata?.[SELECTION_METADATA_KEY];
22198
22229
  if (!value || typeof value !== "object" || Array.isArray(value))
@@ -22242,32 +22273,62 @@ function nativeVariantFromSession(session, messages) {
22242
22273
  }
22243
22274
  return void 0;
22244
22275
  }
22245
- function turnHasNativePatch(messages, userMessageID) {
22276
+ function turnNativePatchFiles(messages, userMessageID) {
22246
22277
  const start = messages.findIndex(({ info }) => info.id === userMessageID);
22247
22278
  if (start < 0)
22248
- return false;
22279
+ return [];
22249
22280
  let end = start + 1;
22250
22281
  while (end < messages.length && messages[end]?.info.role !== "user")
22251
22282
  end += 1;
22252
- return messages.slice(start + 1, end).some(({ parts }) => parts.some((part) => part.type === "patch" && part.files.length > 0));
22283
+ return [
22284
+ ...new Set(messages.slice(start + 1, end).flatMap(({ parts }) => parts.flatMap((part) => part.type === "patch" ? part.files : [])))
22285
+ ];
22253
22286
  }
22254
- async function readTurnDiff(transport, sessionID, userMessageID, nativePatchObserved) {
22287
+ async function readTurnDiff(transport, sessionID, userMessageID, nativePatchFiles, options = {}) {
22288
+ const strict = options.strict === true;
22255
22289
  for (let attempt = 0; ; attempt += 1) {
22256
- const diffs = await transport.getDiff(sessionID, userMessageID).catch(() => []);
22257
- if (reliableOpenCodeFileChanges(diffs).length > 0 || !nativePatchObserved || attempt >= DIFF_RECONCILIATION_DELAYS_MS.length) {
22290
+ let diffs;
22291
+ try {
22292
+ diffs = await transport.getDiff(sessionID, userMessageID);
22293
+ } catch (error51) {
22294
+ if (strict) {
22295
+ throw new OpenCodeTransportError("protocolError", "OpenCode could not verify FileChange history", { cause: error51 });
22296
+ }
22297
+ diffs = [];
22298
+ }
22299
+ const reliableChanges = reliableOpenCodeFileChanges(diffs);
22300
+ const worktree = options.worktree;
22301
+ const reliablePaths = worktree ? reliableChanges.map(({ path: file2 }) => openCodeFileIdentity(file2, worktree)) : [];
22302
+ const nativePatchPaths = worktree ? nativePatchFiles.map((file2) => openCodeFileIdentity(file2, worktree)) : [];
22303
+ const completeStrictProjection = Boolean(worktree) && reliableChanges.length === diffs.length && reliablePaths.every((file2) => file2 !== void 0) && nativePatchPaths.every((file2) => file2 !== void 0 && reliablePaths.includes(file2));
22304
+ if (strict ? completeStrictProjection : reliableChanges.length > 0 || nativePatchFiles.length === 0) {
22305
+ return diffs;
22306
+ }
22307
+ if (attempt >= DIFF_RECONCILIATION_DELAYS_MS.length) {
22308
+ if (strict) {
22309
+ throw new OpenCodeTransportError("protocolError", "OpenCode did not expose complete reliable FileChange history");
22310
+ }
22258
22311
  return diffs;
22259
22312
  }
22260
22313
  await new Promise((resolve) => setTimeout(resolve, DIFF_RECONCILIATION_DELAYS_MS[attempt]));
22261
22314
  }
22262
22315
  }
22263
- async function readProjection(transport, sessionID, providerCatalog, toolOutputLimit) {
22264
- const [session, messages] = await Promise.all([
22316
+ async function readProjection(transport, sessionID, providerCatalog, toolOutputLimit, options = {}) {
22317
+ const strictFileChanges = options.strictFileChanges === true;
22318
+ const [session, messages, paths] = await Promise.all([
22265
22319
  transport.getSession(sessionID),
22266
- transport.getMessages(sessionID)
22320
+ transport.getMessages(sessionID),
22321
+ strictFileChanges ? transport.getPaths().catch((error51) => {
22322
+ throw new OpenCodeTransportError("protocolError", "OpenCode could not verify worktree paths", { cause: error51 });
22323
+ }) : void 0
22267
22324
  ]);
22325
+ const worktree = paths ? verifiedOpenCodeWorktree(session.directory, paths) : void 0;
22326
+ if (strictFileChanges && !worktree) {
22327
+ throw new OpenCodeTransportError("protocolError", "OpenCode returned inconsistent Session and worktree paths");
22328
+ }
22268
22329
  const userMessageIds = messages.filter(({ info }) => info.role === "user").map(({ info }) => info.id);
22269
22330
  const diffEntries = await Promise.all(userMessageIds.map(async (messageID) => {
22270
- const diffs = await readTurnDiff(transport, sessionID, messageID, turnHasNativePatch(messages, messageID));
22331
+ const diffs = await readTurnDiff(transport, sessionID, messageID, turnNativePatchFiles(messages, messageID), { strict: strictFileChanges, ...worktree ? { worktree } : {} });
22271
22332
  return [messageID, diffs];
22272
22333
  }));
22273
22334
  const snapshot = projectOpenCodeHistory({
@@ -22277,7 +22338,9 @@ async function readProjection(transport, sessionID, providerCatalog, toolOutputL
22277
22338
  toolOutputLimit
22278
22339
  });
22279
22340
  const model = nativeModelFromSession(session, messages);
22280
- const variant = nativeVariantFromSession(session, messages);
22341
+ const nativeVariant = nativeVariantFromSession(session, messages);
22342
+ const nativeModel = model ? providerCatalog.all.find(({ id }) => id === model.providerID)?.models[model.modelID] : void 0;
22343
+ const variant = nativeVariant === "default" && nativeModel && !Object.hasOwn(nativeModel.variants ?? {}, "default") ? void 0 : nativeVariant;
22281
22344
  const usage = projectOpenCodeUsage(openCodeAssistantMessages(session, messages), model ? openCodeContextWindow(providerCatalog, model) : void 0);
22282
22345
  return {
22283
22346
  session,
@@ -22288,6 +22351,128 @@ async function readProjection(transport, sessionID, providerCatalog, toolOutputL
22288
22351
  ...variant ? { variant } : {}
22289
22352
  };
22290
22353
  }
22354
+
22355
+ // dist/history-derivation.js
22356
+ import { isDeepStrictEqual } from "node:util";
22357
+ function semanticHistory(snapshot) {
22358
+ return snapshot.turns.map((turn) => ({
22359
+ input: turn.input,
22360
+ items: turn.items.map(({ item, outcome }) => {
22361
+ const { itemId: _itemId, ...content } = item;
22362
+ void _itemId;
22363
+ return { item: content, outcome };
22364
+ }),
22365
+ outcome: turn.outcome,
22366
+ model: turn.model,
22367
+ checkpoint: Boolean(turn.checkpoint)
22368
+ }));
22369
+ }
22370
+ function sourceState(projection) {
22371
+ return {
22372
+ id: projection.session.id,
22373
+ directory: projection.session.directory,
22374
+ revert: projection.session.revert,
22375
+ metadata: projection.session.metadata,
22376
+ permission: projection.session.permission,
22377
+ model: projection.model,
22378
+ variant: projection.variant,
22379
+ snapshot: projection.snapshot
22380
+ };
22381
+ }
22382
+ async function deriveOpenCodeHistory(options) {
22383
+ const { transport, source, input, providers, toolOutputLimit } = options;
22384
+ const read = (id) => readProjection(transport, id, providers, toolOutputLimit, { strictFileChanges: true });
22385
+ if ((await transport.getStatus(source.id)).type !== "idle") {
22386
+ throw new Error("OpenCode source Session is busy");
22387
+ }
22388
+ const before = await read(source.id);
22389
+ const expectedSource = structuredClone(sourceState(before));
22390
+ let messageID;
22391
+ let retainedCount;
22392
+ if (input.kind === "fork") {
22393
+ const boundary = resolveOpenCodeForkBoundary(before.session, before.messages, input.checkpoint);
22394
+ if (!boundary)
22395
+ throw new OpenCodeTransportError("checkpointNotFound", "OpenCode Checkpoint is not on the source Session transcript");
22396
+ messageID = boundary.messageID;
22397
+ retainedCount = boundary.sourceTurnCount;
22398
+ } else {
22399
+ const boundary = resolveOpenCodeLastTurnBoundary(before.session, before.messages);
22400
+ if (!boundary)
22401
+ throw new OpenCodeTransportError("invalidState", "OpenCode Native Session has no Turn to roll back");
22402
+ messageID = boundary.lastUserMessageID;
22403
+ retainedCount = boundary.sourceTurnCount - 1;
22404
+ }
22405
+ const expectedHistory = structuredClone(semanticHistory(before.snapshot).slice(0, retainedCount));
22406
+ let candidate = await transport.forkSession(source.id, messageID);
22407
+ if (candidate.id === source.id) {
22408
+ throw new OpenCodeTransportError("protocolError", "OpenCode Fork did not create a distinct Native Session");
22409
+ }
22410
+ const candidateID = candidate.id;
22411
+ options.onCreated(candidate);
22412
+ if (candidate.directory !== expectedSource.directory) {
22413
+ throw new OpenCodeTransportError("protocolError", "OpenCode Fork changed working directory");
22414
+ }
22415
+ if (expectedSource.model) {
22416
+ candidate = await transport.updateSessionMetadata(candidateID, selectionMetadata(candidate, expectedSource.model, expectedSource.variant));
22417
+ }
22418
+ if (!isDeepStrictEqual(candidate.permission ?? [], expectedSource.permission ?? [])) {
22419
+ candidate = await transport.updateSessionPermission(candidateID, expectedSource.permission ?? []);
22420
+ }
22421
+ const [derived, after, candidateStatus, sourceStatus] = await Promise.all([
22422
+ read(candidateID),
22423
+ read(source.id),
22424
+ transport.getStatus(candidateID),
22425
+ transport.getStatus(source.id)
22426
+ ]);
22427
+ if (derived.session.id !== candidateID || candidate.id !== candidateID || derived.session.directory !== before.session.directory || candidateStatus.type !== "idle" || sourceStatus.type !== "idle" || !isDeepStrictEqual(semanticHistory(derived.snapshot), expectedHistory) || !isDeepStrictEqual(sourceState(after), expectedSource) || !isDeepStrictEqual(derived.model, expectedSource.model) || derived.variant !== expectedSource.variant || !isDeepStrictEqual(derived.session.permission ?? [], expectedSource.permission ?? [])) {
22428
+ throw new OpenCodeTransportError("protocolError", "OpenCode derived history, source or configuration changed during Fork");
22429
+ }
22430
+ return derived.session;
22431
+ }
22432
+
22433
+ // dist/opencode-adapter.js
22434
+ var openCodeHarnessId2 = harnessIdSchema.parse("opencode");
22435
+ var DEFAULT_TOOL_OUTPUT_LIMIT = 64e3;
22436
+ var DEFAULT_CLOSE_TIMEOUT_MS2 = 3e3;
22437
+ var COMPACT_COMMAND_ID = "opencode.compact";
22438
+ function invalidState(message) {
22439
+ return { code: "invalidState", message, retryable: false };
22440
+ }
22441
+ function unsupported(message) {
22442
+ return { code: "unsupported", message, retryable: false };
22443
+ }
22444
+ function normalizeError(error51, fallback) {
22445
+ if (error51 instanceof OpenCodeTransportError) {
22446
+ return {
22447
+ code: error51.code,
22448
+ message: error51.message,
22449
+ retryable: error51.code === "unavailable" || error51.code === "processExited" || error51.code === "authenticationRequired"
22450
+ };
22451
+ }
22452
+ const text = error51 instanceof Error ? error51.message : String(error51);
22453
+ const lower = text.toLowerCase();
22454
+ if (lower.includes("sessionbusy") || lower.includes("session busy")) {
22455
+ return { code: "sessionBusy", message: text, retryable: true };
22456
+ }
22457
+ if (lower.includes("not found")) {
22458
+ return { code: "sessionNotFound", message: text, retryable: false };
22459
+ }
22460
+ return {
22461
+ code: fallback,
22462
+ message: text,
22463
+ retryable: fallback === "unavailable" || fallback === "nativeFailure"
22464
+ };
22465
+ }
22466
+ function sameCwd(left, right) {
22467
+ const canonical = (value) => {
22468
+ try {
22469
+ return fs3.realpathSync.native(value);
22470
+ } catch {
22471
+ return path5.resolve(value);
22472
+ }
22473
+ };
22474
+ return canonical(left) === canonical(right);
22475
+ }
22291
22476
  function sessionState(session, modelCatalog, model, variant, executionPolicy = "default", permissionModeId = OPENCODE_DEFAULT_PERMISSION_MODE_ID) {
22292
22477
  const effectiveModel = model ? encodeOpenCodeModelRef(model) : void 0;
22293
22478
  const modelEntry = effectiveModel ? modelCatalog.models.find(({ ref }) => ref.id === effectiveModel.id) : void 0;
@@ -22849,6 +23034,11 @@ var OpenCodeHarnessSession = class {
22849
23034
  }
22850
23035
  if (event.type === "session.error" && event.properties.sessionID === this.#session.id && active) {
22851
23036
  const error51 = event.properties.error;
23037
+ if (active.cancellationRequested || error51?.name === "MessageAbortedError") {
23038
+ active.cancellationRequested = true;
23039
+ void this.#reconcileAndFinish(active);
23040
+ return;
23041
+ }
22852
23042
  this.#completeTurn(active, {
22853
23043
  status: active.cancellationRequested ? "cancelled" : "failed",
22854
23044
  ...active.cancellationRequested ? { reason: "Cancelled by user" } : {
@@ -23102,6 +23292,19 @@ var OpenCodeHarnessSession = class {
23102
23292
  const assistants = messages.slice(userIndex + 1, end).filter((entry) => entry.info.role === "assistant");
23103
23293
  const terminal = assistants.at(-1)?.info ?? active.terminalAssistant;
23104
23294
  if (!terminal || terminal.time.completed === void 0 && !terminal.finish && !terminal.error && !active.nativeCompleted) {
23295
+ if (active.cancellationRequested) {
23296
+ for (const entry of assistants) {
23297
+ for (const part of entry.parts)
23298
+ this.#projectPart(active, part);
23299
+ }
23300
+ this.#completeTurn(active, { status: "cancelled", reason: "Cancelled by user" }, {
23301
+ harnessId: this.harnessId,
23302
+ nativeSessionId: this.#session.id,
23303
+ nativeTurnKey: active.userMessageID,
23304
+ formatVersion: 1
23305
+ });
23306
+ void this.#refreshProjection(active.turnId);
23307
+ }
23105
23308
  return;
23106
23309
  }
23107
23310
  for (const entry of assistants) {
@@ -23110,7 +23313,7 @@ var OpenCodeHarnessSession = class {
23110
23313
  }
23111
23314
  active.terminalAssistant = terminal;
23112
23315
  const userMessageID = active.userMessageID;
23113
- const changes = reliableOpenCodeFileChanges(await readTurnDiff(this.#transport, this.#session.id, userMessageID, turnHasNativePatch(messages, userMessageID)));
23316
+ const changes = reliableOpenCodeFileChanges(await readTurnDiff(this.#transport, this.#session.id, userMessageID, turnNativePatchFiles(messages, userMessageID)));
23114
23317
  if (changes.length > 0) {
23115
23318
  const id = `opencode-live-diff:${active.userMessageID}`;
23116
23319
  if (!active.items.has(id)) {
@@ -23487,7 +23690,6 @@ var OpenCodeAdapter = class {
23487
23690
  let connection;
23488
23691
  let transport;
23489
23692
  let createdForCleanup;
23490
- let revertedForCleanup;
23491
23693
  try {
23492
23694
  const sourceRef = input.kind === "create" ? void 0 : parseOpenCodeSessionRef(input.kind === "resume" ? input.nativeRef : input.sourceRef);
23493
23695
  const executionPolicy = input.kind === "create" ? input.executionPolicy ?? "default" : sourceRef?.executionPolicy ?? "default";
@@ -23566,61 +23768,17 @@ var OpenCodeAdapter = class {
23566
23768
  }
23567
23769
  if (input.kind === "resume") {
23568
23770
  session = source;
23569
- } else if (input.kind === "fork") {
23570
- const checkpoint = nativeCheckpointRefSchema.parse(input.checkpoint);
23571
- if (checkpoint.harnessId !== this.harnessId || checkpoint.nativeSessionId !== source.id) {
23572
- throw new OpenCodeTransportError("protocolError", "OpenCode Checkpoint does not belong to the source Session");
23573
- }
23574
- const sourceMessages = await transport.getMessages(source.id);
23575
- const boundary = resolveOpenCodeForkBoundary(source, sourceMessages, checkpoint);
23576
- if (!boundary) {
23577
- await transport.close().catch(() => void 0);
23578
- await connection.close().catch(() => void 0);
23579
- return {
23580
- ok: false,
23581
- error: {
23582
- code: "checkpointNotFound",
23583
- message: "OpenCode Checkpoint is not on the source Session transcript",
23584
- retryable: false
23585
- }
23586
- };
23587
- }
23588
- session = await transport.forkSession(source.id, boundary.messageID);
23589
- createdForCleanup = session;
23590
- if (session.id === source.id) {
23591
- throw new OpenCodeTransportError("protocolError", "OpenCode Fork did not create a distinct Native Session");
23592
- }
23593
- const derivedMessages = await transport.getMessages(session.id);
23594
- const derived = projectOpenCodeHistory({
23595
- session,
23596
- messages: derivedMessages,
23597
- toolOutputLimit: this.#toolOutputLimit
23598
- });
23599
- if (derived.turns.length !== boundary.sourceTurnCount) {
23600
- throw new OpenCodeTransportError("protocolError", "OpenCode Fork derived history does not match the requested Checkpoint");
23601
- }
23602
23771
  } else {
23603
- const sourceMessages = await transport.getMessages(source.id);
23604
- const boundary = resolveOpenCodeLastTurnBoundary(source, sourceMessages);
23605
- if (!boundary) {
23606
- await transport.close().catch(() => void 0);
23607
- await connection.close().catch(() => void 0);
23608
- return {
23609
- ok: false,
23610
- error: invalidState("OpenCode Native Session has no Turn to roll back")
23611
- };
23612
- }
23613
- session = await transport.revertSession(source.id, boundary.lastUserMessageID);
23614
- revertedForCleanup = source.id;
23615
- const afterMessages = await transport.getMessages(session.id);
23616
- const after = projectOpenCodeHistory({
23617
- session,
23618
- messages: afterMessages,
23619
- toolOutputLimit: this.#toolOutputLimit
23772
+ session = await deriveOpenCodeHistory({
23773
+ transport,
23774
+ source,
23775
+ input,
23776
+ providers,
23777
+ toolOutputLimit: this.#toolOutputLimit,
23778
+ onCreated: (candidate) => {
23779
+ createdForCleanup = candidate;
23780
+ }
23620
23781
  });
23621
- if (after.turns.length !== boundary.sourceTurnCount - 1) {
23622
- throw new OpenCodeTransportError("protocolError", "OpenCode rollback did not remove exactly the last Turn");
23623
- }
23624
23782
  }
23625
23783
  }
23626
23784
  const projection = await readProjection(transport, session.id, providers, this.#toolOutputLimit);
@@ -23640,12 +23798,8 @@ var OpenCodeAdapter = class {
23640
23798
  await harnessSession.start();
23641
23799
  this.#sessions.add(harnessSession);
23642
23800
  createdForCleanup = void 0;
23643
- revertedForCleanup = void 0;
23644
23801
  return { ok: true, value: harnessSession };
23645
23802
  } catch (error51) {
23646
- if (revertedForCleanup && transport) {
23647
- await transport.unrevertSession(revertedForCleanup).catch(() => void 0);
23648
- }
23649
23803
  if (createdForCleanup && transport) {
23650
23804
  await transport.deleteSession(createdForCleanup.id).catch(() => void 0);
23651
23805
  }