@liberseek/boft-cli-win32-arm64 0.6.4 → 0.6.6

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
  }
@@ -15525,6 +15525,12 @@ function parseHostUsage(value) {
15525
15525
  throw new Error(`Harness Usage contains unknown field '${key}'`);
15526
15526
  }
15527
15527
  }
15528
+ for (const field of ["totalCredits", "contextUsagePercent"]) {
15529
+ const candidate = value[field];
15530
+ if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isFinite(candidate) || candidate < 0)) {
15531
+ throw new Error(`Harness Usage '${field}' must be a finite non-negative number`);
15532
+ }
15533
+ }
15528
15534
  for (const field of tokenFields) {
15529
15535
  const candidate = value[field];
15530
15536
  if (candidate !== void 0 && (typeof candidate !== "number" || !Number.isSafeInteger(candidate) || candidate < 0)) {
@@ -16219,7 +16225,7 @@ var serializeObjectParam = ({ allowReserved, explode, name, style, value, valueO
16219
16225
 
16220
16226
  // ../../../node_modules/@opencode-ai/sdk/dist/v2/gen/core/utils.gen.js
16221
16227
  var PATH_PARAM_RE = /\{[^{}]+\}/g;
16222
- var defaultPathSerializer = ({ path: path5, url: _url2 }) => {
16228
+ var defaultPathSerializer = ({ path: path6, url: _url2 }) => {
16223
16229
  let url2 = _url2;
16224
16230
  const matches = _url2.match(PATH_PARAM_RE);
16225
16231
  if (matches) {
@@ -16238,7 +16244,7 @@ var defaultPathSerializer = ({ path: path5, url: _url2 }) => {
16238
16244
  name = name.substring(1);
16239
16245
  style = "matrix";
16240
16246
  }
16241
- const value = path5[name];
16247
+ const value = path6[name];
16242
16248
  if (value === void 0 || value === null) {
16243
16249
  continue;
16244
16250
  }
@@ -16269,11 +16275,11 @@ var defaultPathSerializer = ({ path: path5, url: _url2 }) => {
16269
16275
  }
16270
16276
  return url2;
16271
16277
  };
16272
- var getUrl = ({ baseUrl, path: path5, query, querySerializer, url: _url2 }) => {
16278
+ var getUrl = ({ baseUrl, path: path6, query, querySerializer, url: _url2 }) => {
16273
16279
  const pathUrl = _url2.startsWith("/") ? _url2 : `/${_url2}`;
16274
16280
  let url2 = (baseUrl ?? "") + pathUrl;
16275
- if (path5) {
16276
- url2 = defaultPathSerializer({ path: path5, url: url2 });
16281
+ if (path6) {
16282
+ url2 = defaultPathSerializer({ path: path6, url: url2 });
16277
16283
  }
16278
16284
  let search = query ? querySerializer(query) : "";
16279
16285
  if (search.startsWith("?")) {
@@ -22001,6 +22007,10 @@ var SdkOpenCodeTransport = class {
22001
22007
  const client2 = await this.#getClient();
22002
22008
  return responseData2(await withTimeout2(client2.session.get({ sessionID }), this.#commandTimeoutMs, "OpenCode Session read"), "Session read");
22003
22009
  }
22010
+ async getPaths() {
22011
+ const client2 = await this.#getClient();
22012
+ return responseData2(await withTimeout2(client2.path.get(), this.#commandTimeoutMs, "OpenCode Path read"), "Path read");
22013
+ }
22004
22014
  async updateSessionMetadata(sessionID, metadata) {
22005
22015
  const client2 = await this.#getClient();
22006
22016
  return responseData2(await withTimeout2(client2.session.update({ sessionID, metadata }), this.#commandTimeoutMs, "OpenCode Session metadata update"), "Session metadata update");
@@ -22143,6 +22153,65 @@ var SdkOpenCodeTransport = class {
22143
22153
  }
22144
22154
  };
22145
22155
 
22156
+ // dist/file-change-verification.js
22157
+ import fs2 from "node:fs";
22158
+ import path4 from "node:path";
22159
+ function missingPath(error51) {
22160
+ if (!error51 || typeof error51 !== "object")
22161
+ return false;
22162
+ const code = Reflect.get(error51, "code");
22163
+ return code === "ENOENT" || code === "ENOTDIR";
22164
+ }
22165
+ function hasDotPathSegment(value) {
22166
+ const segments = process.platform === "win32" ? value.split(/[\\/]+/) : value.split("/");
22167
+ return segments.some((segment) => segment === "." || segment === "..");
22168
+ }
22169
+ function canonicalDirectoryPath(value) {
22170
+ let candidate = path4.resolve(value);
22171
+ const missingSegments = [];
22172
+ for (; ; ) {
22173
+ try {
22174
+ return path4.join(fs2.realpathSync.native(candidate), ...missingSegments);
22175
+ } catch (error51) {
22176
+ if (!missingPath(error51))
22177
+ return void 0;
22178
+ const parent = path4.dirname(candidate);
22179
+ if (parent === candidate)
22180
+ return void 0;
22181
+ missingSegments.unshift(path4.basename(candidate));
22182
+ candidate = parent;
22183
+ }
22184
+ }
22185
+ }
22186
+ function canonicalFilePath(value) {
22187
+ const absolute = path4.resolve(value);
22188
+ const parent = canonicalDirectoryPath(path4.dirname(absolute));
22189
+ return parent ? path4.join(parent, path4.basename(absolute)) : void 0;
22190
+ }
22191
+ function pathIsWithin(root, candidate, allowRoot) {
22192
+ const relative = path4.relative(root, candidate);
22193
+ return allowRoot && relative === "" || relative !== "" && relative !== ".." && !relative.startsWith(`..${path4.sep}`) && !path4.isAbsolute(relative);
22194
+ }
22195
+ function verifiedOpenCodeWorktree(sessionDirectory, paths) {
22196
+ 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)) {
22197
+ return void 0;
22198
+ }
22199
+ const session = canonicalDirectoryPath(sessionDirectory);
22200
+ const directory = canonicalDirectoryPath(paths.directory);
22201
+ const worktree = canonicalDirectoryPath(paths.worktree);
22202
+ if (!session || !directory || !worktree || session !== directory || !pathIsWithin(worktree, directory, true)) {
22203
+ return void 0;
22204
+ }
22205
+ return worktree;
22206
+ }
22207
+ function openCodeFileIdentity(file2, worktree) {
22208
+ if (typeof file2 !== "string" || typeof worktree !== "string" || hasDotPathSegment(file2) || hasDotPathSegment(worktree) || !path4.isAbsolute(worktree) || !file2 || file2.includes("\0") || file2.includes("\n") || file2.includes("\r")) {
22209
+ return void 0;
22210
+ }
22211
+ const candidate = canonicalFilePath(path4.isAbsolute(file2) ? file2 : path4.resolve(worktree, file2));
22212
+ return candidate && pathIsWithin(worktree, candidate, false) ? candidate : void 0;
22213
+ }
22214
+
22146
22215
  // dist/usage.js
22147
22216
  function projectOpenCodeUsage(messages, contextWindowTokens) {
22148
22217
  if (messages.length === 0)
@@ -22181,51 +22250,9 @@ function projectOpenCodeUsage(messages, contextWindowTokens) {
22181
22250
  });
22182
22251
  }
22183
22252
 
22184
- // dist/opencode-adapter.js
22185
- var openCodeHarnessId2 = harnessIdSchema.parse("opencode");
22186
- var DEFAULT_TOOL_OUTPUT_LIMIT = 64e3;
22187
- var DEFAULT_CLOSE_TIMEOUT_MS2 = 3e3;
22188
- var DIFF_RECONCILIATION_DELAYS_MS = [25, 50, 100, 200, 400, 800];
22189
- var COMPACT_COMMAND_ID = "opencode.compact";
22253
+ // dist/history-projection.js
22190
22254
  var SELECTION_METADATA_KEY = "codexhost.selection.v1";
22191
- function invalidState(message) {
22192
- return { code: "invalidState", message, retryable: false };
22193
- }
22194
- function unsupported(message) {
22195
- return { code: "unsupported", message, retryable: false };
22196
- }
22197
- function normalizeError(error51, fallback) {
22198
- if (error51 instanceof OpenCodeTransportError) {
22199
- return {
22200
- code: error51.code,
22201
- message: error51.message,
22202
- retryable: error51.code === "unavailable" || error51.code === "processExited" || error51.code === "authenticationRequired"
22203
- };
22204
- }
22205
- const text = error51 instanceof Error ? error51.message : String(error51);
22206
- const lower = text.toLowerCase();
22207
- if (lower.includes("sessionbusy") || lower.includes("session busy")) {
22208
- return { code: "sessionBusy", message: text, retryable: true };
22209
- }
22210
- if (lower.includes("not found")) {
22211
- return { code: "sessionNotFound", message: text, retryable: false };
22212
- }
22213
- return {
22214
- code: fallback,
22215
- message: text,
22216
- retryable: fallback === "unavailable" || fallback === "nativeFailure"
22217
- };
22218
- }
22219
- function sameCwd(left, right) {
22220
- const canonical = (value) => {
22221
- try {
22222
- return fs2.realpathSync.native(value);
22223
- } catch {
22224
- return path4.resolve(value);
22225
- }
22226
- };
22227
- return canonical(left) === canonical(right);
22228
- }
22255
+ var DIFF_RECONCILIATION_DELAYS_MS = [25, 50, 100, 200, 400, 800];
22229
22256
  function storedSelection(session) {
22230
22257
  const value = session.metadata?.[SELECTION_METADATA_KEY];
22231
22258
  if (!value || typeof value !== "object" || Array.isArray(value))
@@ -22275,32 +22302,62 @@ function nativeVariantFromSession(session, messages) {
22275
22302
  }
22276
22303
  return void 0;
22277
22304
  }
22278
- function turnHasNativePatch(messages, userMessageID) {
22305
+ function turnNativePatchFiles(messages, userMessageID) {
22279
22306
  const start = messages.findIndex(({ info }) => info.id === userMessageID);
22280
22307
  if (start < 0)
22281
- return false;
22308
+ return [];
22282
22309
  let end = start + 1;
22283
22310
  while (end < messages.length && messages[end]?.info.role !== "user")
22284
22311
  end += 1;
22285
- return messages.slice(start + 1, end).some(({ parts }) => parts.some((part) => part.type === "patch" && part.files.length > 0));
22312
+ return [
22313
+ ...new Set(messages.slice(start + 1, end).flatMap(({ parts }) => parts.flatMap((part) => part.type === "patch" ? part.files : [])))
22314
+ ];
22286
22315
  }
22287
- async function readTurnDiff(transport, sessionID, userMessageID, nativePatchObserved) {
22316
+ async function readTurnDiff(transport, sessionID, userMessageID, nativePatchFiles, options = {}) {
22317
+ const strict = options.strict === true;
22288
22318
  for (let attempt = 0; ; attempt += 1) {
22289
- const diffs = await transport.getDiff(sessionID, userMessageID).catch(() => []);
22290
- if (reliableOpenCodeFileChanges(diffs).length > 0 || !nativePatchObserved || attempt >= DIFF_RECONCILIATION_DELAYS_MS.length) {
22319
+ let diffs;
22320
+ try {
22321
+ diffs = await transport.getDiff(sessionID, userMessageID);
22322
+ } catch (error51) {
22323
+ if (strict) {
22324
+ throw new OpenCodeTransportError("protocolError", "OpenCode could not verify FileChange history", { cause: error51 });
22325
+ }
22326
+ diffs = [];
22327
+ }
22328
+ const reliableChanges = reliableOpenCodeFileChanges(diffs);
22329
+ const worktree = options.worktree;
22330
+ const reliablePaths = worktree ? reliableChanges.map(({ path: file2 }) => openCodeFileIdentity(file2, worktree)) : [];
22331
+ const nativePatchPaths = worktree ? nativePatchFiles.map((file2) => openCodeFileIdentity(file2, worktree)) : [];
22332
+ const completeStrictProjection = Boolean(worktree) && reliableChanges.length === diffs.length && reliablePaths.every((file2) => file2 !== void 0) && nativePatchPaths.every((file2) => file2 !== void 0 && reliablePaths.includes(file2));
22333
+ if (strict ? completeStrictProjection : reliableChanges.length > 0 || nativePatchFiles.length === 0) {
22334
+ return diffs;
22335
+ }
22336
+ if (attempt >= DIFF_RECONCILIATION_DELAYS_MS.length) {
22337
+ if (strict) {
22338
+ throw new OpenCodeTransportError("protocolError", "OpenCode did not expose complete reliable FileChange history");
22339
+ }
22291
22340
  return diffs;
22292
22341
  }
22293
22342
  await new Promise((resolve) => setTimeout(resolve, DIFF_RECONCILIATION_DELAYS_MS[attempt]));
22294
22343
  }
22295
22344
  }
22296
- async function readProjection(transport, sessionID, providerCatalog, toolOutputLimit) {
22297
- const [session, messages] = await Promise.all([
22345
+ async function readProjection(transport, sessionID, providerCatalog, toolOutputLimit, options = {}) {
22346
+ const strictFileChanges = options.strictFileChanges === true;
22347
+ const [session, messages, paths] = await Promise.all([
22298
22348
  transport.getSession(sessionID),
22299
- transport.getMessages(sessionID)
22349
+ transport.getMessages(sessionID),
22350
+ strictFileChanges ? transport.getPaths().catch((error51) => {
22351
+ throw new OpenCodeTransportError("protocolError", "OpenCode could not verify worktree paths", { cause: error51 });
22352
+ }) : void 0
22300
22353
  ]);
22354
+ const worktree = paths ? verifiedOpenCodeWorktree(session.directory, paths) : void 0;
22355
+ if (strictFileChanges && !worktree) {
22356
+ throw new OpenCodeTransportError("protocolError", "OpenCode returned inconsistent Session and worktree paths");
22357
+ }
22301
22358
  const userMessageIds = messages.filter(({ info }) => info.role === "user").map(({ info }) => info.id);
22302
22359
  const diffEntries = await Promise.all(userMessageIds.map(async (messageID) => {
22303
- const diffs = await readTurnDiff(transport, sessionID, messageID, turnHasNativePatch(messages, messageID));
22360
+ const diffs = await readTurnDiff(transport, sessionID, messageID, turnNativePatchFiles(messages, messageID), { strict: strictFileChanges, ...worktree ? { worktree } : {} });
22304
22361
  return [messageID, diffs];
22305
22362
  }));
22306
22363
  const snapshot = projectOpenCodeHistory({
@@ -22310,7 +22367,9 @@ async function readProjection(transport, sessionID, providerCatalog, toolOutputL
22310
22367
  toolOutputLimit
22311
22368
  });
22312
22369
  const model = nativeModelFromSession(session, messages);
22313
- const variant = nativeVariantFromSession(session, messages);
22370
+ const nativeVariant = nativeVariantFromSession(session, messages);
22371
+ const nativeModel = model ? providerCatalog.all.find(({ id }) => id === model.providerID)?.models[model.modelID] : void 0;
22372
+ const variant = nativeVariant === "default" && nativeModel && !Object.hasOwn(nativeModel.variants ?? {}, "default") ? void 0 : nativeVariant;
22314
22373
  const usage = projectOpenCodeUsage(openCodeAssistantMessages(session, messages), model ? openCodeContextWindow(providerCatalog, model) : void 0);
22315
22374
  return {
22316
22375
  session,
@@ -22321,6 +22380,128 @@ async function readProjection(transport, sessionID, providerCatalog, toolOutputL
22321
22380
  ...variant ? { variant } : {}
22322
22381
  };
22323
22382
  }
22383
+
22384
+ // dist/history-derivation.js
22385
+ import { isDeepStrictEqual } from "node:util";
22386
+ function semanticHistory(snapshot) {
22387
+ return snapshot.turns.map((turn) => ({
22388
+ input: turn.input,
22389
+ items: turn.items.map(({ item, outcome }) => {
22390
+ const { itemId: _itemId, ...content } = item;
22391
+ void _itemId;
22392
+ return { item: content, outcome };
22393
+ }),
22394
+ outcome: turn.outcome,
22395
+ model: turn.model,
22396
+ checkpoint: Boolean(turn.checkpoint)
22397
+ }));
22398
+ }
22399
+ function sourceState(projection) {
22400
+ return {
22401
+ id: projection.session.id,
22402
+ directory: projection.session.directory,
22403
+ revert: projection.session.revert,
22404
+ metadata: projection.session.metadata,
22405
+ permission: projection.session.permission,
22406
+ model: projection.model,
22407
+ variant: projection.variant,
22408
+ snapshot: projection.snapshot
22409
+ };
22410
+ }
22411
+ async function deriveOpenCodeHistory(options) {
22412
+ const { transport, source, input, providers, toolOutputLimit } = options;
22413
+ const read = (id) => readProjection(transport, id, providers, toolOutputLimit, { strictFileChanges: true });
22414
+ if ((await transport.getStatus(source.id)).type !== "idle") {
22415
+ throw new Error("OpenCode source Session is busy");
22416
+ }
22417
+ const before = await read(source.id);
22418
+ const expectedSource = structuredClone(sourceState(before));
22419
+ let messageID;
22420
+ let retainedCount;
22421
+ if (input.kind === "fork") {
22422
+ const boundary = resolveOpenCodeForkBoundary(before.session, before.messages, input.checkpoint);
22423
+ if (!boundary)
22424
+ throw new OpenCodeTransportError("checkpointNotFound", "OpenCode Checkpoint is not on the source Session transcript");
22425
+ messageID = boundary.messageID;
22426
+ retainedCount = boundary.sourceTurnCount;
22427
+ } else {
22428
+ const boundary = resolveOpenCodeLastTurnBoundary(before.session, before.messages);
22429
+ if (!boundary)
22430
+ throw new OpenCodeTransportError("invalidState", "OpenCode Native Session has no Turn to roll back");
22431
+ messageID = boundary.lastUserMessageID;
22432
+ retainedCount = boundary.sourceTurnCount - 1;
22433
+ }
22434
+ const expectedHistory = structuredClone(semanticHistory(before.snapshot).slice(0, retainedCount));
22435
+ let candidate = await transport.forkSession(source.id, messageID);
22436
+ if (candidate.id === source.id) {
22437
+ throw new OpenCodeTransportError("protocolError", "OpenCode Fork did not create a distinct Native Session");
22438
+ }
22439
+ const candidateID = candidate.id;
22440
+ options.onCreated(candidate);
22441
+ if (candidate.directory !== expectedSource.directory) {
22442
+ throw new OpenCodeTransportError("protocolError", "OpenCode Fork changed working directory");
22443
+ }
22444
+ if (expectedSource.model) {
22445
+ candidate = await transport.updateSessionMetadata(candidateID, selectionMetadata(candidate, expectedSource.model, expectedSource.variant));
22446
+ }
22447
+ if (!isDeepStrictEqual(candidate.permission ?? [], expectedSource.permission ?? [])) {
22448
+ candidate = await transport.updateSessionPermission(candidateID, expectedSource.permission ?? []);
22449
+ }
22450
+ const [derived, after, candidateStatus, sourceStatus] = await Promise.all([
22451
+ read(candidateID),
22452
+ read(source.id),
22453
+ transport.getStatus(candidateID),
22454
+ transport.getStatus(source.id)
22455
+ ]);
22456
+ 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 ?? [])) {
22457
+ throw new OpenCodeTransportError("protocolError", "OpenCode derived history, source or configuration changed during Fork");
22458
+ }
22459
+ return derived.session;
22460
+ }
22461
+
22462
+ // dist/opencode-adapter.js
22463
+ var openCodeHarnessId2 = harnessIdSchema.parse("opencode");
22464
+ var DEFAULT_TOOL_OUTPUT_LIMIT = 64e3;
22465
+ var DEFAULT_CLOSE_TIMEOUT_MS2 = 3e3;
22466
+ var COMPACT_COMMAND_ID = "opencode.compact";
22467
+ function invalidState(message) {
22468
+ return { code: "invalidState", message, retryable: false };
22469
+ }
22470
+ function unsupported(message) {
22471
+ return { code: "unsupported", message, retryable: false };
22472
+ }
22473
+ function normalizeError(error51, fallback) {
22474
+ if (error51 instanceof OpenCodeTransportError) {
22475
+ return {
22476
+ code: error51.code,
22477
+ message: error51.message,
22478
+ retryable: error51.code === "unavailable" || error51.code === "processExited" || error51.code === "authenticationRequired"
22479
+ };
22480
+ }
22481
+ const text = error51 instanceof Error ? error51.message : String(error51);
22482
+ const lower = text.toLowerCase();
22483
+ if (lower.includes("sessionbusy") || lower.includes("session busy")) {
22484
+ return { code: "sessionBusy", message: text, retryable: true };
22485
+ }
22486
+ if (lower.includes("not found")) {
22487
+ return { code: "sessionNotFound", message: text, retryable: false };
22488
+ }
22489
+ return {
22490
+ code: fallback,
22491
+ message: text,
22492
+ retryable: fallback === "unavailable" || fallback === "nativeFailure"
22493
+ };
22494
+ }
22495
+ function sameCwd(left, right) {
22496
+ const canonical = (value) => {
22497
+ try {
22498
+ return fs3.realpathSync.native(value);
22499
+ } catch {
22500
+ return path5.resolve(value);
22501
+ }
22502
+ };
22503
+ return canonical(left) === canonical(right);
22504
+ }
22324
22505
  function sessionState(session, modelCatalog, model, variant, executionPolicy = "default", permissionModeId = OPENCODE_DEFAULT_PERMISSION_MODE_ID) {
22325
22506
  const effectiveModel = model ? encodeOpenCodeModelRef(model) : void 0;
22326
22507
  const modelEntry = effectiveModel ? modelCatalog.models.find(({ ref }) => ref.id === effectiveModel.id) : void 0;
@@ -22887,6 +23068,11 @@ var OpenCodeHarnessSession = class {
22887
23068
  }
22888
23069
  if (event.type === "session.error" && event.properties.sessionID === this.#session.id && active) {
22889
23070
  const error51 = event.properties.error;
23071
+ if (active.cancellationRequested || error51?.name === "MessageAbortedError") {
23072
+ active.cancellationRequested = true;
23073
+ void this.#reconcileAndFinish(active);
23074
+ return;
23075
+ }
22890
23076
  this.#completeTurn(active, {
22891
23077
  status: active.cancellationRequested ? "cancelled" : "failed",
22892
23078
  ...active.cancellationRequested ? { reason: "Cancelled by user" } : {
@@ -23140,6 +23326,19 @@ var OpenCodeHarnessSession = class {
23140
23326
  const assistants = messages.slice(userIndex + 1, end).filter((entry) => entry.info.role === "assistant");
23141
23327
  const terminal = assistants.at(-1)?.info ?? active.terminalAssistant;
23142
23328
  if (!terminal || terminal.time.completed === void 0 && !terminal.finish && !terminal.error && !active.nativeCompleted) {
23329
+ if (active.cancellationRequested) {
23330
+ for (const entry of assistants) {
23331
+ for (const part of entry.parts)
23332
+ this.#projectPart(active, part);
23333
+ }
23334
+ this.#completeTurn(active, { status: "cancelled", reason: "Cancelled by user" }, {
23335
+ harnessId: this.harnessId,
23336
+ nativeSessionId: this.#session.id,
23337
+ nativeTurnKey: active.userMessageID,
23338
+ formatVersion: 1
23339
+ });
23340
+ void this.#refreshProjection(active.turnId);
23341
+ }
23143
23342
  return;
23144
23343
  }
23145
23344
  for (const entry of assistants) {
@@ -23148,7 +23347,7 @@ var OpenCodeHarnessSession = class {
23148
23347
  }
23149
23348
  active.terminalAssistant = terminal;
23150
23349
  const userMessageID = active.userMessageID;
23151
- const changes = reliableOpenCodeFileChanges(await readTurnDiff(this.#transport, this.#session.id, userMessageID, turnHasNativePatch(messages, userMessageID)));
23350
+ const changes = reliableOpenCodeFileChanges(await readTurnDiff(this.#transport, this.#session.id, userMessageID, turnNativePatchFiles(messages, userMessageID)));
23152
23351
  if (changes.length > 0) {
23153
23352
  const id = `opencode-live-diff:${active.userMessageID}`;
23154
23353
  if (!active.items.has(id)) {
@@ -23525,7 +23724,6 @@ var OpenCodeAdapter = class {
23525
23724
  let connection;
23526
23725
  let transport;
23527
23726
  let createdForCleanup;
23528
- let revertedForCleanup;
23529
23727
  try {
23530
23728
  const sourceRef = input.kind === "create" ? void 0 : parseOpenCodeSessionRef(input.kind === "resume" ? input.nativeRef : input.sourceRef);
23531
23729
  const executionPolicy = input.kind === "create" ? input.executionPolicy ?? "default" : sourceRef?.executionPolicy ?? "default";
@@ -23604,61 +23802,17 @@ var OpenCodeAdapter = class {
23604
23802
  }
23605
23803
  if (input.kind === "resume") {
23606
23804
  session = source;
23607
- } else if (input.kind === "fork") {
23608
- const checkpoint = nativeCheckpointRefSchema.parse(input.checkpoint);
23609
- if (checkpoint.harnessId !== this.harnessId || checkpoint.nativeSessionId !== source.id) {
23610
- throw new OpenCodeTransportError("protocolError", "OpenCode Checkpoint does not belong to the source Session");
23611
- }
23612
- const sourceMessages = await transport.getMessages(source.id);
23613
- const boundary = resolveOpenCodeForkBoundary(source, sourceMessages, checkpoint);
23614
- if (!boundary) {
23615
- await transport.close().catch(() => void 0);
23616
- await connection.close().catch(() => void 0);
23617
- return {
23618
- ok: false,
23619
- error: {
23620
- code: "checkpointNotFound",
23621
- message: "OpenCode Checkpoint is not on the source Session transcript",
23622
- retryable: false
23623
- }
23624
- };
23625
- }
23626
- session = await transport.forkSession(source.id, boundary.messageID);
23627
- createdForCleanup = session;
23628
- if (session.id === source.id) {
23629
- throw new OpenCodeTransportError("protocolError", "OpenCode Fork did not create a distinct Native Session");
23630
- }
23631
- const derivedMessages = await transport.getMessages(session.id);
23632
- const derived = projectOpenCodeHistory({
23633
- session,
23634
- messages: derivedMessages,
23635
- toolOutputLimit: this.#toolOutputLimit
23636
- });
23637
- if (derived.turns.length !== boundary.sourceTurnCount) {
23638
- throw new OpenCodeTransportError("protocolError", "OpenCode Fork derived history does not match the requested Checkpoint");
23639
- }
23640
23805
  } else {
23641
- const sourceMessages = await transport.getMessages(source.id);
23642
- const boundary = resolveOpenCodeLastTurnBoundary(source, sourceMessages);
23643
- if (!boundary) {
23644
- await transport.close().catch(() => void 0);
23645
- await connection.close().catch(() => void 0);
23646
- return {
23647
- ok: false,
23648
- error: invalidState("OpenCode Native Session has no Turn to roll back")
23649
- };
23650
- }
23651
- session = await transport.revertSession(source.id, boundary.lastUserMessageID);
23652
- revertedForCleanup = source.id;
23653
- const afterMessages = await transport.getMessages(session.id);
23654
- const after = projectOpenCodeHistory({
23655
- session,
23656
- messages: afterMessages,
23657
- toolOutputLimit: this.#toolOutputLimit
23806
+ session = await deriveOpenCodeHistory({
23807
+ transport,
23808
+ source,
23809
+ input,
23810
+ providers,
23811
+ toolOutputLimit: this.#toolOutputLimit,
23812
+ onCreated: (candidate) => {
23813
+ createdForCleanup = candidate;
23814
+ }
23658
23815
  });
23659
- if (after.turns.length !== boundary.sourceTurnCount - 1) {
23660
- throw new OpenCodeTransportError("protocolError", "OpenCode rollback did not remove exactly the last Turn");
23661
- }
23662
23816
  }
23663
23817
  }
23664
23818
  const projection = await readProjection(transport, session.id, providers, this.#toolOutputLimit);
@@ -23678,12 +23832,8 @@ var OpenCodeAdapter = class {
23678
23832
  await harnessSession.start();
23679
23833
  this.#sessions.add(harnessSession);
23680
23834
  createdForCleanup = void 0;
23681
- revertedForCleanup = void 0;
23682
23835
  return { ok: true, value: harnessSession };
23683
23836
  } catch (error51) {
23684
- if (revertedForCleanup && transport) {
23685
- await transport.unrevertSession(revertedForCleanup).catch(() => void 0);
23686
- }
23687
23837
  if (createdForCleanup && transport) {
23688
23838
  await transport.deleteSession(createdForCleanup.id).catch(() => void 0);
23689
23839
  }