ds-harness-remote 0.4.10 → 0.4.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/README.md +9 -4
  2. package/dist/client-runtime.d.ts +10 -1
  3. package/dist/client-runtime.d.ts.map +1 -1
  4. package/dist/client-runtime.js +47 -22
  5. package/dist/client-runtime.js.map +1 -1
  6. package/dist/client.github.js +1 -1
  7. package/dist/client.js +1 -1
  8. package/dist/client.js.map +1 -1
  9. package/dist/codex/peer-bridge.d.ts.map +1 -1
  10. package/dist/codex/peer-bridge.js +3 -4
  11. package/dist/codex/peer-bridge.js.map +1 -1
  12. package/dist/codex/virtual-harness.d.ts +12 -3
  13. package/dist/codex/virtual-harness.d.ts.map +1 -1
  14. package/dist/codex/virtual-harness.js +155 -37
  15. package/dist/codex/virtual-harness.js.map +1 -1
  16. package/dist/control-route.d.ts +22 -0
  17. package/dist/control-route.d.ts.map +1 -1
  18. package/dist/control-route.js +120 -0
  19. package/dist/control-route.js.map +1 -1
  20. package/dist/control-runtime.d.ts +2 -1
  21. package/dist/control-runtime.d.ts.map +1 -1
  22. package/dist/control-runtime.js +3 -5
  23. package/dist/control-runtime.js.map +1 -1
  24. package/dist/harness-api-bridge.d.ts.map +1 -1
  25. package/dist/harness-api-bridge.js +3 -3
  26. package/dist/harness-api-bridge.js.map +1 -1
  27. package/dist/harness-remote-bridge.d.ts.map +1 -1
  28. package/dist/harness-remote-bridge.js +3 -4
  29. package/dist/harness-remote-bridge.js.map +1 -1
  30. package/dist/harness-version.d.ts +7 -0
  31. package/dist/harness-version.d.ts.map +1 -1
  32. package/dist/harness-version.js +16 -0
  33. package/dist/harness-version.js.map +1 -1
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +738 -219
  36. package/dist/index.js.map +4 -4
  37. package/dist/remote-api-proxy.d.ts.map +1 -1
  38. package/dist/remote-api-proxy.js +34 -1
  39. package/dist/remote-api-proxy.js.map +1 -1
  40. package/dist/remote-typert-gateway.d.ts +3 -1
  41. package/dist/remote-typert-gateway.d.ts.map +1 -1
  42. package/dist/remote-typert-gateway.js +16 -5
  43. package/dist/remote-typert-gateway.js.map +1 -1
  44. package/dist/service.d.ts +1 -0
  45. package/dist/service.d.ts.map +1 -1
  46. package/dist/service.js +8 -4
  47. package/dist/service.js.map +1 -1
  48. package/dist/session-format-compat.d.ts +3 -0
  49. package/dist/session-format-compat.d.ts.map +1 -0
  50. package/dist/session-format-compat.js +183 -0
  51. package/dist/session-format-compat.js.map +1 -0
  52. package/dist/tui-command.js +5 -3
  53. package/dist/tui-command.js.map +1 -1
  54. package/dist/version.d.ts +1 -1
  55. package/dist/version.js +1 -1
  56. package/dsh-plugin.json +1 -1
  57. package/package.json +21 -21
package/dist/index.js CHANGED
@@ -4059,6 +4059,13 @@ var MAX_DEVICE_NAME_LENGTH = 128;
4059
4059
  var MAX_DEVICE_PLATFORM_LENGTH = 64;
4060
4060
  var MAX_DEVICE_VERSION_LENGTH = 64;
4061
4061
  var MAX_AUTH_TOKEN_LENGTH = 8 * 1024;
4062
+ var HOST_REGISTRATION_CODE_TTL_MS = 10 * 6e4;
4063
+ var MAX_ACTIVE_TRANSFERS_PER_DIRECTION = 2;
4064
+ var TRANSFER_IDLE_MS = 2 * 6e4;
4065
+ var MAX_RPC_TEXT_INPUT_BYTES = 64 * 1024;
4066
+ var MAX_FILEVIEWER_RANGE_BYTES = 512 * 1024;
4067
+ var MIN_REPLAY_WINDOW_MS = 15 * 6e4;
4068
+ var MAX_ALPHA_STREAMS_PER_CONNECTION = 16;
4062
4069
  var SECURE_FRAGMENT_MAGIC = new Uint8Array([68, 83, 72, 70]);
4063
4070
  var SECURE_FRAGMENT_VERSION = 1;
4064
4071
  var SECURE_FRAGMENT_HEADER_BYTES = 17;
@@ -4116,6 +4123,52 @@ var rpcMethods = [
4116
4123
  "codex.app.transfer.read",
4117
4124
  "codex.app.transfer.close"
4118
4125
  ];
4126
+ var errorCodes = [
4127
+ // Protocol / Version
4128
+ "INVALID_MESSAGE",
4129
+ "UNSUPPORTED_VERSION",
4130
+ "CAPABILITY_NOT_SUPPORTED",
4131
+ "METHOD_NOT_FOUND",
4132
+ "METHOD_NOT_ALLOWED",
4133
+ "REQUEST_CONFLICT",
4134
+ "FRAME_TOO_LARGE",
4135
+ "RATE_LIMITED",
4136
+ // Auth / Device
4137
+ "AUTH_REQUIRED",
4138
+ "AUTH_INVALID",
4139
+ "ACCOUNT_AUTH_REQUIRED",
4140
+ "TOKEN_EXPIRED",
4141
+ "DEVICE_NOT_FOUND",
4142
+ "DEVICE_REVOKED",
4143
+ "DEVICE_OWNERSHIP_REQUIRED",
4144
+ "MEMBERSHIP_REQUIRED",
4145
+ "PEER_IDENTITY_MISMATCH",
4146
+ "HOST_REGISTRATION_CODE_NOT_FOUND",
4147
+ "HOST_REGISTRATION_CODE_EXPIRED",
4148
+ "HOST_REGISTRATION_CODE_CONSUMED",
4149
+ // Connection / Transport
4150
+ "HOST_OFFLINE",
4151
+ "CONNECTION_NOT_FOUND",
4152
+ "CONNECTION_FAILED",
4153
+ "CONNECTION_REPLACED",
4154
+ "P2P_FAILED",
4155
+ "TURN_UNAVAILABLE",
4156
+ "RELAY_UNAVAILABLE",
4157
+ "SLOW_CONSUMER",
4158
+ "SECURE_CHANNEL_FAILED",
4159
+ // Harness
4160
+ "HARNESS_UNAVAILABLE",
4161
+ "HARNESS_VERSION_INCOMPATIBLE",
4162
+ "RESPONSE_TOO_LARGE",
4163
+ "SESSION_NOT_FOUND",
4164
+ "SESSION_NOT_READY",
4165
+ "AGENT_BUSY",
4166
+ "PERMISSION_DENIED",
4167
+ "PERMISSION_NOT_PENDING",
4168
+ "RPC_TIMEOUT",
4169
+ "FULL_RESYNC_REQUIRED",
4170
+ "INTERNAL_ERROR"
4171
+ ];
4119
4172
  var selectedTransports = ["lan", "p2p", "turn", "relay"];
4120
4173
  function normalizeSdpMLineIndex(value) {
4121
4174
  if (value === void 0)
@@ -4140,6 +4193,7 @@ function acceptNegotiatedCapabilities(offered, negotiated) {
4140
4193
  var rpcMethodSchema = external_exports.enum(rpcMethods);
4141
4194
  var messageTypeSchema = external_exports.enum(messageTypes);
4142
4195
  var controlFrameTypeSchema = external_exports.enum(controlFrameTypes);
4196
+ var errorCodeSchema = external_exports.enum(errorCodes);
4143
4197
  var uniqueStrings = (values) => new Set(values).size === values.length;
4144
4198
  var uniqueNumbers = (values) => new Set(values).size === values.length;
4145
4199
  var utf8Length = (value) => new TextEncoder().encode(value).byteLength;
@@ -4181,6 +4235,10 @@ var hostRegistrationCodeRequestSchema = external_exports.object({
4181
4235
  code: external_exports.string().regex(/^[A-Z0-9]{4}-[A-Z0-9]{4}$/u),
4182
4236
  device: hostDeviceDescriptorSchema
4183
4237
  }).strict();
4238
+ var registerOwnedRoleRequestSchema = external_exports.object({
4239
+ v: external_exports.literal(PROTOCOL_VERSION),
4240
+ device: accountDeviceDescriptorSchema
4241
+ }).strict();
4184
4242
  var deviceRefreshRequestSchema = external_exports.object({
4185
4243
  deviceId: deviceIdSchema,
4186
4244
  refreshToken: authTokenSchema
@@ -13958,6 +14016,120 @@ async function waitForResponder(inner, noise) {
13958
14016
 
13959
14017
  // src/control-route.ts
13960
14018
  var CONTROL_RPC_PREFIX = "/ds-harness-remote";
14019
+ var ENDPOINT_SEGMENT_PATTERN = /^[A-Za-z0-9_$.-]+$/;
14020
+ var INVALID_REQUEST_RPC_ID = "invalid-request";
14021
+ function registerControlRoute(connection, handler, webServer) {
14022
+ if (webServer !== void 0 && connection.requestRejection !== void 0) {
14023
+ const dispose = webServer.register({
14024
+ kind: "prefix",
14025
+ path: CONTROL_RPC_PREFIX,
14026
+ handler: (req, res) => handleControlRequest(connection, handler, req, res)
14027
+ });
14028
+ return async () => {
14029
+ await dispose();
14030
+ };
14031
+ }
14032
+ return connection.rpc.handle(CONTROL_RPC_PREFIX, handler, {
14033
+ authority: "loopback"
14034
+ });
14035
+ }
14036
+ async function handleControlRequest(connection, handler, req, res) {
14037
+ const rejection = connection.requestRejection?.(req);
14038
+ if (rejection !== void 0) {
14039
+ res.writeHead(rejection);
14040
+ res.end(rejection === 401 ? "unauthorized" : "forbidden");
14041
+ return;
14042
+ }
14043
+ const endpoint = endpointFromPath(CONTROL_RPC_PREFIX, new URL(req.url ?? "/", "http://dsh.internal").pathname);
14044
+ if (req.method !== "POST" || endpoint === void 0) {
14045
+ writeText(res, 404, "not found");
14046
+ return;
14047
+ }
14048
+ if (contentType(req.headers) !== "application/json") {
14049
+ writeText(res, 415, "content type must be application/json");
14050
+ return;
14051
+ }
14052
+ let body;
14053
+ try {
14054
+ body = await readJsonBody(req);
14055
+ } catch {
14056
+ writeText(res, 400, "body is not JSON");
14057
+ return;
14058
+ }
14059
+ const message = clientRequest(body);
14060
+ if (message === void 0) {
14061
+ writeJson(res, 200, errorResponse(rpcId(body), {
14062
+ code: "gateway/bad-request",
14063
+ message: "invalid client-request message",
14064
+ details: { issues: [] }
14065
+ }));
14066
+ return;
14067
+ }
14068
+ if (message.method !== endpoint) {
14069
+ writeJson(res, 200, errorResponse(message.rpcId, {
14070
+ code: "gateway/bad-request",
14071
+ message: `method ${JSON.stringify(message.method)} does not match endpoint ${JSON.stringify(endpoint)}`,
14072
+ details: { issues: [] }
14073
+ }));
14074
+ return;
14075
+ }
14076
+ try {
14077
+ const result = await handler(endpoint, message.payload, requestSignal(req));
14078
+ writeJson(res, 200, fullResponse(message.rpcId, result));
14079
+ } catch (error) {
14080
+ writeText(res, 500, `handler failure: ${String(error)}`);
14081
+ }
14082
+ }
14083
+ function endpointFromPath(channel, pathname) {
14084
+ if (!pathname.startsWith(`${channel}/`)) return void 0;
14085
+ const endpoint = pathname.slice(channel.length + 1);
14086
+ if (endpoint.split("/").some((segment) => segment === "" || segment === "." || segment === ".." || !ENDPOINT_SEGMENT_PATTERN.test(segment))) {
14087
+ return void 0;
14088
+ }
14089
+ return endpoint;
14090
+ }
14091
+ function contentType(headers) {
14092
+ const raw = headers["content-type"];
14093
+ const value = Array.isArray(raw) ? raw[0] : raw;
14094
+ return value?.split(";", 1)[0]?.trim().toLowerCase();
14095
+ }
14096
+ async function readJsonBody(req) {
14097
+ const chunks = [];
14098
+ for await (const chunk of req) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
14099
+ return JSON.parse(Buffer.concat(chunks).toString("utf8"));
14100
+ }
14101
+ function requestSignal(req) {
14102
+ const abort = new AbortController();
14103
+ req.on("close", () => {
14104
+ if (!req.complete) abort.abort();
14105
+ });
14106
+ return abort.signal;
14107
+ }
14108
+ function clientRequest(value) {
14109
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return void 0;
14110
+ const record6 = value;
14111
+ if (record6.type !== "client-request" || typeof record6.rpcId !== "string" || typeof record6.method !== "string") return void 0;
14112
+ return { type: "client-request", rpcId: record6.rpcId, method: record6.method, payload: record6.payload };
14113
+ }
14114
+ function rpcId(value) {
14115
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return INVALID_REQUEST_RPC_ID;
14116
+ const record6 = value;
14117
+ return typeof record6.rpcId === "string" ? record6.rpcId : INVALID_REQUEST_RPC_ID;
14118
+ }
14119
+ function errorResponse(rpcId2, error) {
14120
+ return fullResponse(rpcId2, { ok: false, error });
14121
+ }
14122
+ function fullResponse(rpcId2, result) {
14123
+ return { type: "server-response", rpcId: rpcId2, result };
14124
+ }
14125
+ function writeJson(res, status2, body) {
14126
+ res.writeHead(status2, { "content-type": "application/json" });
14127
+ res.end(JSON.stringify(body));
14128
+ }
14129
+ function writeText(res, status2, body) {
14130
+ res.writeHead(status2);
14131
+ res.end(body);
14132
+ }
13961
14133
 
13962
14134
  // src/ids.ts
13963
14135
  import { randomBytes as randomBytes6 } from "node:crypto";
@@ -13977,8 +14149,51 @@ function uuidV7(now = Date.now()) {
13977
14149
  return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
13978
14150
  }
13979
14151
 
14152
+ // src/harness-version.ts
14153
+ import { readFile } from "node:fs/promises";
14154
+ import { dirname, isAbsolute, join } from "node:path";
14155
+ var LEGACY_PLACEHOLDER_VERSION = "0.0.1";
14156
+ function normalizeHarnessVersion(value) {
14157
+ if (typeof value !== "string") return void 0;
14158
+ const version = value.trim();
14159
+ if (version.length === 0 || version.length > 64 || /[\u0000-\u001f]/u.test(version)) return void 0;
14160
+ return version;
14161
+ }
14162
+ function selectHarnessVersion(reportedVersion, distributionVersion) {
14163
+ if (reportedVersion !== void 0 && reportedVersion !== LEGACY_PLACEHOLDER_VERSION) return reportedVersion;
14164
+ return distributionVersion;
14165
+ }
14166
+ function harnessSessionGeneration(version) {
14167
+ if (version === void 0) return "legacy";
14168
+ const match = /^(?:dsh-)?v?(\d+)\.(\d+)\.(\d+)(?:-|$)/u.exec(version.trim());
14169
+ if (match === null) return "legacy";
14170
+ const major = Number(match[1]);
14171
+ const minor = Number(match[2]);
14172
+ const patch = Number(match[3]);
14173
+ return major === 0 && minor === 1 && patch >= 5 ? "v3" : "legacy";
14174
+ }
14175
+ async function readHarnessDistributionVersion(entrypoint = process.argv[1]) {
14176
+ if (entrypoint === void 0 || !isAbsolute(entrypoint)) return void 0;
14177
+ let directory = dirname(entrypoint);
14178
+ for (let depth = 0; depth < 8; depth += 1) {
14179
+ try {
14180
+ const manifest = JSON.parse(await readFile(join(directory, "package.json"), "utf8"));
14181
+ if (manifest.name === "@deepseek-ai/dsh") return normalizeHarnessVersion(manifest.version);
14182
+ } catch {
14183
+ }
14184
+ const parent = dirname(directory);
14185
+ if (parent === directory) break;
14186
+ directory = parent;
14187
+ }
14188
+ return void 0;
14189
+ }
14190
+
13980
14191
  // src/remote-api-proxy.ts
13981
14192
  var DIRECT_API_CALL_BYTES = 2 * 1024 * 1024;
14193
+ var AGENT_PRESET_SETTINGS_NS = "agent-presets";
14194
+ var LEGACY_AGENT_PRESET_ALIASES = {
14195
+ code: "ptc"
14196
+ };
13982
14197
  var RemoteHarnessApiProxy = class {
13983
14198
  constructor(client) {
13984
14199
  this.client = client;
@@ -14067,7 +14282,7 @@ var RemoteHarnessApiProxy = class {
14067
14282
  const params = {
14068
14283
  method,
14069
14284
  rpcId: String(request.rpcId),
14070
- payload: request.payload
14285
+ payload: normalizeLegacyRequest(method, request.payload)
14071
14286
  };
14072
14287
  const encoded = new TextEncoder().encode(JSON.stringify(params));
14073
14288
  const response = method === "session.attachment" || encoded.byteLength > DIRECT_API_CALL_BYTES ? await this.callTransferred(encoded, signal) : await this.client.rpc("harness.api.call", params, signal);
@@ -14179,9 +14394,32 @@ function normalizeLegacyResponse(method, response) {
14179
14394
  }
14180
14395
  };
14181
14396
  }
14397
+ function normalizeLegacyRequest(method, payload) {
14398
+ if (!isRecord2(payload)) return payload;
14399
+ if (method === "agentPreset.read") return replaceAgentPreset(payload, "agentPreset");
14400
+ if (method === "agentPreset.select") return replaceAgentPreset(payload, "agentPreset");
14401
+ if (method === "agentPreset.copy") return replaceAgentPreset(payload, "from");
14402
+ if (method === "settings.update" || method === "settings.replace" || method === "settings.mutate") {
14403
+ return replaceAgentPresetSettings(payload);
14404
+ }
14405
+ return payload;
14406
+ }
14407
+ function replaceAgentPreset(payload, key) {
14408
+ const value = payload[key];
14409
+ const replacement = typeof value === "string" ? LEGACY_AGENT_PRESET_ALIASES[value] : void 0;
14410
+ return replacement === void 0 ? payload : { ...payload, [key]: replacement };
14411
+ }
14412
+ function replaceAgentPresetSettings(payload) {
14413
+ if (payload.ns !== AGENT_PRESET_SETTINGS_NS || !isRecord2(payload.patch)) return payload;
14414
+ const patch = replaceAgentPreset(payload.patch, "default");
14415
+ return patch === payload.patch ? payload : { ...payload, patch };
14416
+ }
14182
14417
  function isRemoteDisconnect(error) {
14183
14418
  return error instanceof RemoteClientError && (error.code === "TRANSPORT_CLOSED" || error.code === "CLIENT_CLOSED");
14184
14419
  }
14420
+ function isRecord2(value) {
14421
+ return typeof value === "object" && value !== null && !Array.isArray(value);
14422
+ }
14185
14423
  var AsyncFrameQueue = class {
14186
14424
  values = [];
14187
14425
  waiters = [];
@@ -14244,11 +14482,168 @@ function base64ToBytes2(value) {
14244
14482
  return bytes;
14245
14483
  }
14246
14484
 
14485
+ // src/session-format-compat.ts
14486
+ function normalizeLegacySessionGatewayValue(endpoint, value) {
14487
+ if (endpoint === "session/page") return normalizePage(value);
14488
+ if (endpoint === "session/follow") return normalizeFollowFrame(value);
14489
+ return value;
14490
+ }
14491
+ function normalizeFollowFrame(value) {
14492
+ if (!isRecord3(value)) return value;
14493
+ if (value.type === "snapshot") {
14494
+ return {
14495
+ ...value,
14496
+ header: normalizeHeader(value.header),
14497
+ records: normalizeRecords(value.records),
14498
+ ...value.assistantStream === void 0 ? { assistantStream: { revision: 0 } } : {}
14499
+ };
14500
+ }
14501
+ return normalizeEntry(value);
14502
+ }
14503
+ function normalizePage(value) {
14504
+ if (!isRecord3(value)) return value;
14505
+ return { ...value, records: normalizeRecords(value.records) };
14506
+ }
14507
+ function normalizeRecords(value) {
14508
+ if (!Array.isArray(value)) return value;
14509
+ const records = [];
14510
+ let previousSeq;
14511
+ for (const record6 of value) {
14512
+ if (!isEventEntry(record6)) continue;
14513
+ const seq = entrySeq(record6);
14514
+ if (previousSeq !== void 0 && seq !== void 0 && seq > previousSeq + 1) {
14515
+ for (let fillerSeq = previousSeq + 1; fillerSeq < seq; fillerSeq += 1) {
14516
+ records.push(createLegacyGapRecord(fillerSeq, record6));
14517
+ }
14518
+ }
14519
+ records.push(normalizeEntry(record6));
14520
+ if (seq !== void 0) previousSeq = seq;
14521
+ }
14522
+ return records;
14523
+ }
14524
+ function normalizeEntry(value) {
14525
+ if (!isEventEntry(value)) return value;
14526
+ return { ...value, event: normalizeEvent(value.event) };
14527
+ }
14528
+ function entrySeq(value) {
14529
+ if (!isEventEntry(value)) return void 0;
14530
+ return isEventSeq(value.event.seq) ? value.event.seq : void 0;
14531
+ }
14532
+ function createLegacyGapRecord(seq, nextRecord) {
14533
+ return {
14534
+ type: "event",
14535
+ event: {
14536
+ type: "legacy/session-gap",
14537
+ seq,
14538
+ time: eventTime(nextRecord),
14539
+ ignorable: true,
14540
+ data: {}
14541
+ }
14542
+ };
14543
+ }
14544
+ function eventTime(value) {
14545
+ if (!isEventEntry(value)) return 0;
14546
+ return typeof value.event.time === "number" && Number.isSafeInteger(value.event.time) ? value.event.time : 0;
14547
+ }
14548
+ function isEventEntry(value) {
14549
+ return isRecord3(value) && value.type === "event" && isRecord3(value.event);
14550
+ }
14551
+ function normalizeHeader(value) {
14552
+ if (!isRecord3(value)) return value;
14553
+ const next = {
14554
+ ...value,
14555
+ version: 3,
14556
+ ...value.delegationDepth === void 0 ? { delegationDepth: 0 } : {}
14557
+ };
14558
+ return next.agentPreset === "code" ? { ...next, agentPreset: "ptc" } : next;
14559
+ }
14560
+ function normalizeEvent(value) {
14561
+ if (!isRecord3(value)) return value;
14562
+ let next = value;
14563
+ const type = normalizeEventType(value.type);
14564
+ if (type !== value.type) next = { ...next, type };
14565
+ if (type === "assistant/message" && Object.hasOwn(next, "sourceEventSeqs")) {
14566
+ const { sourceEventSeqs: _sourceEventSeqs, ...rest } = next;
14567
+ next = rest;
14568
+ }
14569
+ const data = normalizeEventData(type, next.data);
14570
+ if (data !== next.data) next = { ...next, data };
14571
+ const surfaceOp = normalizeSurfaceOp(next.surfaceOp);
14572
+ if (surfaceOp !== next.surfaceOp) next = { ...next, surfaceOp };
14573
+ return next;
14574
+ }
14575
+ function normalizeEventType(value) {
14576
+ if (value === "tool/code-dispatch-start") return "tool/ptc-dispatch-start";
14577
+ if (value === "tool/code-dispatch") return "tool/ptc-dispatch";
14578
+ return value;
14579
+ }
14580
+ function normalizeEventData(type, value) {
14581
+ if (!isRecord3(value)) return value;
14582
+ if (type === "request/header") return normalizeRequestHeaderData(value);
14583
+ if (type === "agent-preset/selected" && value.agentPreset === "code") return { ...value, agentPreset: "ptc" };
14584
+ if (type === "user/message") return normalizeMessage(value);
14585
+ if (type === "agent/inbox/spliced" && Array.isArray(value.inserted)) {
14586
+ return { ...value, inserted: value.inserted.map((item) => normalizeMessage(item)) };
14587
+ }
14588
+ if (type === "session/title-llm-request" && Array.isArray(value.messages)) {
14589
+ return { ...value, messages: value.messages.map((item) => normalizeMessage(item)) };
14590
+ }
14591
+ return value;
14592
+ }
14593
+ function normalizeRequestHeaderData(value) {
14594
+ if (!isRecord3(value.header)) return value;
14595
+ const header = normalizeRequestHeader(value.header);
14596
+ return header === value.header ? value : { ...value, header };
14597
+ }
14598
+ function normalizeRequestHeader(value) {
14599
+ let changed = false;
14600
+ const next = {};
14601
+ for (const [key, field] of Object.entries(value)) {
14602
+ if (key === "system") {
14603
+ changed = true;
14604
+ continue;
14605
+ }
14606
+ if (key === "tools" && Array.isArray(field) && field.length === 0) {
14607
+ changed = true;
14608
+ continue;
14609
+ }
14610
+ if (key === "adapterDefaults" && isRecord3(field) && Object.keys(field).length === 0) {
14611
+ changed = true;
14612
+ continue;
14613
+ }
14614
+ next[key] = field;
14615
+ }
14616
+ return changed ? next : value;
14617
+ }
14618
+ function normalizeMessage(value) {
14619
+ if (!isRecord3(value) || !isRecord3(value.source)) return value;
14620
+ if (value.source.kind !== "plugin" || value.source.plugin !== "tools-code-mode") return value;
14621
+ return { ...value, source: { ...value.source, plugin: "tools-ptc" } };
14622
+ }
14623
+ function normalizeSurfaceOp(value) {
14624
+ if (!isRecord3(value) || value.op !== "replace") return value;
14625
+ const { start, end, ...rest } = value;
14626
+ if (start === void 0 && end === void 0) return value;
14627
+ return {
14628
+ ...rest,
14629
+ op: "replace",
14630
+ ...start === void 0 ? {} : { startSeq: start },
14631
+ ...end === void 0 ? {} : { endSeq: end }
14632
+ };
14633
+ }
14634
+ function isRecord3(value) {
14635
+ return typeof value === "object" && value !== null && !Array.isArray(value);
14636
+ }
14637
+ function isEventSeq(value) {
14638
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 && !Object.is(value, -0);
14639
+ }
14640
+
14247
14641
  // src/remote-typert-gateway.ts
14248
14642
  var DIRECT_REMOTE_CALL_BYTES2 = 2 * 1024 * 1024;
14249
14643
  var RemoteTypertGateway2 = class {
14250
- constructor(client) {
14644
+ constructor(client, compatibility) {
14251
14645
  this.client = client;
14646
+ this.compatibility = compatibility;
14252
14647
  }
14253
14648
  async invoke(request) {
14254
14649
  const result = await this.dispatch(
@@ -14273,7 +14668,11 @@ var RemoteTypertGateway2 = class {
14273
14668
  response = await this.callTransferred(encoded, signal);
14274
14669
  }
14275
14670
  }
14276
- return parseRpcResult(response);
14671
+ const result = parseRpcResult(response);
14672
+ if (result.ok && this.compatibility === "legacy-to-v3") {
14673
+ return { ...result, value: normalizeLegacySessionGatewayValue(endpoint, result.value) };
14674
+ }
14675
+ return result;
14277
14676
  }
14278
14677
  async open(endpoint, payload, signal) {
14279
14678
  const streamId = uuidV7();
@@ -14292,11 +14691,13 @@ var RemoteTypertGateway2 = class {
14292
14691
  unsubscribeClose();
14293
14692
  throw error;
14294
14693
  }
14295
- return this.iterate(streamId, queue, unsubscribe, unsubscribeClose, signal, onAbort);
14694
+ return this.iterate(streamId, endpoint, queue, unsubscribe, unsubscribeClose, signal, onAbort);
14296
14695
  }
14297
- async *iterate(streamId, queue, unsubscribe, unsubscribeClose, signal, onAbort) {
14696
+ async *iterate(streamId, endpoint, queue, unsubscribe, unsubscribeClose, signal, onAbort) {
14298
14697
  try {
14299
- yield* queue;
14698
+ for await (const value of queue) {
14699
+ yield this.compatibility === "legacy-to-v3" ? normalizeLegacySessionGatewayValue(endpoint, value) : value;
14700
+ }
14300
14701
  } finally {
14301
14702
  signal.removeEventListener("abort", onAbort);
14302
14703
  unsubscribe();
@@ -14416,16 +14817,16 @@ function routeStreamEvent2(event, streamId, queue) {
14416
14817
  queue.fail(remoteFailure({
14417
14818
  code: typeof failure2?.code === "string" ? failure2.code : "internal",
14418
14819
  message: typeof failure2?.message === "string" ? failure2.message : "The remote Harness stream failed.",
14419
- details: isRecord2(failure2?.details) ? failure2.details : {}
14820
+ details: isRecord4(failure2?.details) ? failure2.details : {}
14420
14821
  }));
14421
14822
  } else {
14422
14823
  queue.close();
14423
14824
  }
14424
14825
  }
14425
14826
  function parseRpcResult(value) {
14426
- if (!isRecord2(value)) throw new Error("The remote Host returned an invalid Gateway result.");
14827
+ if (!isRecord4(value)) throw new Error("The remote Host returned an invalid Gateway result.");
14427
14828
  if (value.ok === true) return Object.hasOwn(value, "value") ? { ok: true, value: value.value } : { ok: true };
14428
- if (value.ok !== false || !isRecord2(value.error) || typeof value.error.code !== "string" || typeof value.error.message !== "string" || !isRecord2(value.error.details)) {
14829
+ if (value.ok !== false || !isRecord4(value.error) || typeof value.error.code !== "string" || typeof value.error.message !== "string" || !isRecord4(value.error.details)) {
14429
14830
  throw new Error("The remote Host returned an invalid Gateway failure.");
14430
14831
  }
14431
14832
  return {
@@ -14459,7 +14860,7 @@ function base64ToBytes3(value) {
14459
14860
  if (bytesToBase643(bytes) !== value) throw new Error("The remote Host returned non-canonical Harness Remote transfer data.");
14460
14861
  return bytes;
14461
14862
  }
14462
- function isRecord2(value) {
14863
+ function isRecord4(value) {
14463
14864
  return typeof value === "object" && value !== null && !Array.isArray(value);
14464
14865
  }
14465
14866
  function hasErrorCode(error, code) {
@@ -14510,9 +14911,10 @@ async function discoverCodexVirtualWorkspaces(client, signal) {
14510
14911
  return (await loadCatalog(client, signal)).workspaces;
14511
14912
  }
14512
14913
  var CodexVirtualHarness = class _CodexVirtualHarness {
14513
- constructor(client, host) {
14914
+ constructor(client, host, sessionGeneration = "legacy") {
14514
14915
  this.client = client;
14515
14916
  this.host = host;
14917
+ this.sessionGeneration = sessionGeneration;
14516
14918
  this.api = this.createApiProxy();
14517
14919
  }
14518
14920
  api;
@@ -14536,8 +14938,8 @@ var CodexVirtualHarness = class _CodexVirtualHarness {
14536
14938
  commandSeq = 0;
14537
14939
  selectedWorkspaceId;
14538
14940
  closed = false;
14539
- static remote(core, host) {
14540
- return new _CodexVirtualHarness(new CodexRemoteClient(core), host);
14941
+ static remote(core, host, sessionGeneration = "legacy") {
14942
+ return new _CodexVirtualHarness(new CodexRemoteClient(core), host, sessionGeneration);
14541
14943
  }
14542
14944
  async workspaces(signal) {
14543
14945
  return (await this.refreshCatalog(signal)).workspaces;
@@ -14927,6 +15329,7 @@ var CodexVirtualHarness = class _CodexVirtualHarness {
14927
15329
  streamedBlocks: /* @__PURE__ */ new Map(),
14928
15330
  nextBlockIndex: 0,
14929
15331
  streamActive: false,
15332
+ assistantStreamRevision: 0,
14930
15333
  liveItems: /* @__PURE__ */ new Map(),
14931
15334
  liveToolOutput: /* @__PURE__ */ new Map(),
14932
15335
  liveToolResultSeq: /* @__PURE__ */ new Map(),
@@ -14950,7 +15353,8 @@ var CodexVirtualHarness = class _CodexVirtualHarness {
14950
15353
  permissions: codexPermissionsProjection(this.permissionSelection(sessionId)),
14951
15354
  imageLimits: codexImageLimitsProjection()
14952
15355
  }
14953
- }
15356
+ },
15357
+ ...this.sessionGeneration === "v3" ? { assistantStream: { revision: 0 } } : {}
14954
15358
  });
14955
15359
  try {
14956
15360
  const stream = await this.client.subscribe(
@@ -14988,6 +15392,7 @@ var CodexVirtualHarness = class _CodexVirtualHarness {
14988
15392
  }
14989
15393
  if (frame.method === "turn/started") {
14990
15394
  const turn = record2(params.turn);
15395
+ this.endAssistantAttempt(follow, { kind: "abandoned" });
14991
15396
  this.resetLiveTurn(follow);
14992
15397
  follow.turn += 1;
14993
15398
  follow.activeTurnId = string(turn.id);
@@ -15103,6 +15508,7 @@ var CodexVirtualHarness = class _CodexVirtualHarness {
15103
15508
  if (follow.stepOpen) {
15104
15509
  this.closeAllStreamBlocks(follow);
15105
15510
  if (follow.streamActive) this.finishStream(follow);
15511
+ this.endAssistantAttempt(follow, { kind: "abandoned" });
15106
15512
  this.pushEvent(follow, "step/end", { turn: follow.turn, step: 1 });
15107
15513
  follow.stepOpen = false;
15108
15514
  }
@@ -15141,6 +15547,7 @@ var CodexVirtualHarness = class _CodexVirtualHarness {
15141
15547
  this.closeItemStreamBlocks(follow, itemId, itemText2(item));
15142
15548
  if (type === "agentMessage" && follow.streamActive && follow.streamedBlocks.size === 0) this.finishStream(follow);
15143
15549
  const supplementalImages = type === "agentMessage" ? follow.pendingToolImages : [];
15550
+ let assistantMessageSeq;
15144
15551
  for (const event of itemEvents(
15145
15552
  item,
15146
15553
  follow.turn,
@@ -15152,7 +15559,17 @@ var CodexVirtualHarness = class _CodexVirtualHarness {
15152
15559
  )) {
15153
15560
  if (event.type === "tool/call" && follow.startedItems.has(itemId)) continue;
15154
15561
  if (event.type === "tool/result") this.pushToolResult(follow, itemId, event);
15155
- else this.pushEvent(follow, event.type, event.data, event.view);
15562
+ else {
15563
+ const seq = this.pushEvent(follow, event.type, event.data, event.view);
15564
+ if (event.type === "assistant/message") assistantMessageSeq = seq;
15565
+ }
15566
+ }
15567
+ if (type === "agentMessage" && assistantMessageSeq !== void 0) {
15568
+ this.endAssistantAttempt(follow, {
15569
+ kind: "committed",
15570
+ eventType: "assistant/message",
15571
+ seq: assistantMessageSeq
15572
+ });
15156
15573
  }
15157
15574
  if (type === "agentMessage" && supplementalImages.length > 0) follow.pendingToolImages = [];
15158
15575
  else if (type !== void 0 && isToolItemType2(type)) {
@@ -15169,18 +15586,21 @@ var CodexVirtualHarness = class _CodexVirtualHarness {
15169
15586
  type,
15170
15587
  seq,
15171
15588
  time: Date.now(),
15172
- data,
15589
+ data: adaptEventData(
15590
+ type,
15591
+ type === "assistant/message" && this.sessionGeneration === "v3" && follow.assistantAttempt !== void 0 ? { ...record2(data), stream: follow.assistantAttempt.stream } : data,
15592
+ this.sessionGeneration
15593
+ ),
15173
15594
  ...isSurfaceEvent(type) ? placement === void 0 ? { surfaceOp: "append" } : {
15174
- surfaceOp: { op: "replace", start: placement.replaceSeq, end: placement.replaceSeq },
15595
+ surfaceOp: this.sessionGeneration === "v3" ? { op: "replace", startSeq: placement.replaceSeq, endSeq: placement.replaceSeq } : { op: "replace", start: placement.replaceSeq, end: placement.replaceSeq },
15175
15596
  sourceEventSeqs: [placement.replaceSeq]
15176
15597
  } : {}
15177
15598
  };
15178
15599
  this.cacheImageBlocks(follow.sessionId, event.data);
15179
15600
  if (!follow.rcOnly) {
15180
- const alphaEvent = typeof event.surfaceOp === "object" ? { ...event, surfaceOp: "replace" } : event;
15181
15601
  follow.queue.push({
15182
15602
  type: "event",
15183
- event: alphaEvent,
15603
+ event,
15184
15604
  ...view === void 0 ? {} : { view }
15185
15605
  });
15186
15606
  }
@@ -15207,52 +15627,105 @@ var CodexVirtualHarness = class _CodexVirtualHarness {
15207
15627
  const block = { itemId, index: follow.nextBlockIndex++, kind, text: "" };
15208
15628
  follow.streamedBlocks.set(key, block);
15209
15629
  follow.streamActive = true;
15210
- this.pushEvent(follow, "assistant/chunk", {
15211
- turn: follow.turn,
15212
- step: 1,
15213
- chunk: { type: "block-start", index: block.index, blockType: kind }
15214
- });
15630
+ this.pushAssistantChunk(follow, { type: "block-start", index: block.index, blockType: kind });
15215
15631
  return block;
15216
15632
  }
15217
15633
  appendStreamDelta(follow, key, itemId, kind, delta) {
15218
15634
  const block = this.ensureStreamBlock(follow, key, itemId, kind);
15219
15635
  block.text = appendBoundedText(block.text, delta);
15220
- this.pushEvent(follow, "assistant/chunk", {
15221
- turn: follow.turn,
15222
- step: 1,
15223
- chunk: { type: kind === "reasoning" ? "reasoning-delta" : "text-delta", index: block.index, text: delta }
15636
+ this.pushAssistantChunk(follow, {
15637
+ type: kind === "reasoning" ? "reasoning-delta" : "text-delta",
15638
+ index: block.index,
15639
+ text: delta
15224
15640
  });
15225
15641
  }
15226
15642
  closeItemStreamBlocks(follow, itemId, fallback) {
15227
15643
  const matches = [...follow.streamedBlocks].filter(([, block]) => block.itemId === itemId);
15228
15644
  for (const [key, block] of matches) {
15229
15645
  const text = block.text || fallback || "";
15230
- this.pushEvent(follow, "assistant/chunk", {
15231
- turn: follow.turn,
15232
- step: 1,
15233
- chunk: { type: "block-end", index: block.index, block: { type: block.kind, text } }
15646
+ this.pushAssistantChunk(follow, {
15647
+ type: "block-end",
15648
+ index: block.index,
15649
+ block: { type: block.kind, text }
15234
15650
  });
15235
15651
  follow.streamedBlocks.delete(key);
15236
15652
  }
15237
15653
  }
15238
15654
  closeAllStreamBlocks(follow) {
15239
15655
  for (const block of follow.streamedBlocks.values()) {
15240
- this.pushEvent(follow, "assistant/chunk", {
15241
- turn: follow.turn,
15242
- step: 1,
15243
- chunk: { type: "block-end", index: block.index, block: { type: block.kind, text: block.text } }
15656
+ this.pushAssistantChunk(follow, {
15657
+ type: "block-end",
15658
+ index: block.index,
15659
+ block: { type: block.kind, text: block.text }
15244
15660
  });
15245
15661
  }
15246
15662
  follow.streamedBlocks.clear();
15247
15663
  }
15248
15664
  finishStream(follow) {
15249
- this.pushEvent(follow, "assistant/chunk", {
15250
- turn: follow.turn,
15251
- step: 1,
15252
- chunk: { type: "finish", reason: { kind: "stop" } }
15253
- });
15665
+ this.pushAssistantChunk(follow, { type: "finish", reason: { kind: "stop" } });
15254
15666
  follow.streamActive = false;
15255
15667
  }
15668
+ pushAssistantChunk(follow, chunk) {
15669
+ if (this.sessionGeneration !== "v3" || follow.rcOnly === true) {
15670
+ this.pushEvent(follow, "assistant/chunk", { turn: follow.turn, step: 1, chunk });
15671
+ return;
15672
+ }
15673
+ let attempt = follow.assistantAttempt;
15674
+ if (attempt === void 0) {
15675
+ attempt = {
15676
+ attemptId: `codex-attempt:${follow.activeTurnId ?? follow.turn}:${follow.nextSeq}`,
15677
+ startedAfterSeq: follow.nextSeq - 1,
15678
+ nextIndex: 0,
15679
+ stream: []
15680
+ };
15681
+ follow.assistantAttempt = attempt;
15682
+ follow.assistantStreamRevision += 1;
15683
+ follow.queue.push({
15684
+ type: "assistant-stream",
15685
+ frame: {
15686
+ type: "start",
15687
+ attemptId: attempt.attemptId,
15688
+ revision: follow.assistantStreamRevision,
15689
+ startedAfterSeq: attempt.startedAfterSeq,
15690
+ turn: follow.turn,
15691
+ step: 1
15692
+ }
15693
+ });
15694
+ }
15695
+ const time = Date.now();
15696
+ const index = attempt.nextIndex++;
15697
+ attempt.stream.push({ time, chunk });
15698
+ follow.assistantStreamRevision += 1;
15699
+ follow.queue.push({
15700
+ type: "assistant-stream",
15701
+ frame: {
15702
+ type: "chunk",
15703
+ attemptId: attempt.attemptId,
15704
+ revision: follow.assistantStreamRevision,
15705
+ index,
15706
+ time,
15707
+ chunk
15708
+ }
15709
+ });
15710
+ }
15711
+ endAssistantAttempt(follow, outcome) {
15712
+ const attempt = follow.assistantAttempt;
15713
+ if (attempt === void 0) return;
15714
+ follow.assistantAttempt = void 0;
15715
+ follow.assistantStreamRevision += 1;
15716
+ if (this.sessionGeneration === "v3" && follow.rcOnly !== true) {
15717
+ follow.queue.push({
15718
+ type: "assistant-stream",
15719
+ frame: {
15720
+ type: "end",
15721
+ attemptId: attempt.attemptId,
15722
+ revision: follow.assistantStreamRevision,
15723
+ index: attempt.nextIndex,
15724
+ outcome
15725
+ }
15726
+ });
15727
+ }
15728
+ }
15256
15729
  ensureToolStarted(follow, item) {
15257
15730
  const itemId = string(item.id);
15258
15731
  if (itemId === void 0) return;
@@ -15295,6 +15768,7 @@ var CodexVirtualHarness = class _CodexVirtualHarness {
15295
15768
  follow.streamedBlocks.clear();
15296
15769
  follow.nextBlockIndex = 0;
15297
15770
  follow.streamActive = false;
15771
+ follow.assistantAttempt = void 0;
15298
15772
  follow.liveItems.clear();
15299
15773
  follow.liveToolOutput.clear();
15300
15774
  follow.liveToolResultSeq.clear();
@@ -15307,7 +15781,7 @@ var CodexVirtualHarness = class _CodexVirtualHarness {
15307
15781
  this.broadcastRcHost({ type: "host/session-status", sessionId, running: args[1] });
15308
15782
  } else if (event === "api-session/removed" && sessionId !== void 0) {
15309
15783
  this.broadcastRcHost({ type: "host/session-removed", sessionId });
15310
- } else if (event === "api-session/added" && isRecord3(args[0])) {
15784
+ } else if (event === "api-session/added" && isRecord5(args[0])) {
15311
15785
  const summary = args[0];
15312
15786
  this.broadcastRcHost({
15313
15787
  type: "host/session-added",
@@ -15565,7 +16039,7 @@ var CodexVirtualHarness = class _CodexVirtualHarness {
15565
16039
  const thread = record2(result.thread);
15566
16040
  if (string(thread.id) !== threadId) throw new Error("CodeX returned an invalid Thread history.");
15567
16041
  value = paginateCodexNativeHistory(
15568
- projectCodexNativeHistory(thread, `codex:${threadId}`),
16042
+ projectCodexNativeHistory(thread, `codex:${threadId}`, this.sessionGeneration),
15569
16043
  {
15570
16044
  beforeSeq: page.beforeSeq,
15571
16045
  throughSeq: page.throughSeq,
@@ -15573,6 +16047,7 @@ var CodexVirtualHarness = class _CodexVirtualHarness {
15573
16047
  }
15574
16048
  );
15575
16049
  }
16050
+ value = adaptCodexHistoryPage(value, this.sessionGeneration);
15576
16051
  if (!isCodexNativeHistoryPage(value, `codex:${threadId}`)) {
15577
16052
  throw new Error("CodeX Remote returned an invalid paginated History.");
15578
16053
  }
@@ -15640,6 +16115,7 @@ var CodexVirtualHarness = class _CodexVirtualHarness {
15640
16115
  streamedBlocks: /* @__PURE__ */ new Map(),
15641
16116
  nextBlockIndex: 0,
15642
16117
  streamActive: false,
16118
+ assistantStreamRevision: 0,
15643
16119
  liveItems: /* @__PURE__ */ new Map(),
15644
16120
  liveToolOutput: /* @__PURE__ */ new Map(),
15645
16121
  liveToolResultSeq: /* @__PURE__ */ new Map(),
@@ -15690,7 +16166,7 @@ var CodexVirtualHarness = class _CodexVirtualHarness {
15690
16166
  }
15691
16167
  createApiProxy() {
15692
16168
  const call = (endpoint) => async (request, signal) => {
15693
- const payload = endpoint === "session.prompt" && isRecord3(request.payload) ? { ...request.payload, requestId: String(request.rpcId) } : request.payload;
16169
+ const payload = endpoint === "session.prompt" && isRecord5(request.payload) ? { ...request.payload, requestId: String(request.rpcId) } : request.payload;
15694
16170
  const result = await this.dispatch(rcEndpoint(endpoint), { args: { request: payload } }, signal ?? new AbortController().signal);
15695
16171
  return {
15696
16172
  rpcId: request.rpcId,
@@ -15774,8 +16250,8 @@ var CodexVirtualHarness = class _CodexVirtualHarness {
15774
16250
  queue.close();
15775
16251
  }
15776
16252
  }
15777
- broadcastRcMux(payload, rpcId = `codex-mux:${Date.now()}:${Math.random()}`) {
15778
- for (const queue of this.rcMuxStreams) queue.push({ rpcId, payload });
16253
+ broadcastRcMux(payload, rpcId2 = `codex-mux:${Date.now()}:${Math.random()}`) {
16254
+ for (const queue of this.rcMuxStreams) queue.push({ rpcId: rpcId2, payload });
15779
16255
  }
15780
16256
  broadcastRcHost(payload) {
15781
16257
  const frame = { rpcId: `codex-host:${Date.now()}:${Math.random()}`, payload };
@@ -15922,7 +16398,7 @@ async function loadModelDirectory(client, signal) {
15922
16398
  models
15923
16399
  };
15924
16400
  }
15925
- function projectCodexNativeHistory(thread, sessionId) {
16401
+ function projectCodexNativeHistory(thread, sessionId, sessionGeneration = "legacy") {
15926
16402
  const entries = [];
15927
16403
  let seq = 0;
15928
16404
  let turnNumber = 0;
@@ -15935,7 +16411,7 @@ function projectCodexNativeHistory(thread, sessionId) {
15935
16411
  type,
15936
16412
  seq: eventSeq,
15937
16413
  time,
15938
- data,
16414
+ data: adaptEventData(type, data, sessionGeneration),
15939
16415
  ...sourceEventSeqs === void 0 ? {} : { sourceEventSeqs },
15940
16416
  ...isSurfaceEvent(type) ? { surfaceOp: "append" } : {}
15941
16417
  },
@@ -15988,10 +16464,11 @@ function projectCodexNativeHistory(thread, sessionId) {
15988
16464
  const projected = projectCodexThread(thread);
15989
16465
  return {
15990
16466
  header: {
15991
- version: 1,
16467
+ version: sessionGeneration === "v3" ? 3 : 1,
15992
16468
  id: sessionId,
15993
16469
  createdAt: projected?.createdAt ?? Date.now(),
15994
- ...projected?.cwd === void 0 ? {} : { cwd: projected.cwd }
16470
+ ...projected?.cwd === void 0 ? {} : { cwd: projected.cwd },
16471
+ ...sessionGeneration === "v3" ? { isSeeded: false } : {}
15995
16472
  },
15996
16473
  entries,
15997
16474
  lastSeq: seq - 1,
@@ -16024,6 +16501,40 @@ function paginateCodexNativeHistory(history, request) {
16024
16501
  ...history.activeTurnId === void 0 ? {} : { activeTurnId: history.activeTurnId }
16025
16502
  };
16026
16503
  }
16504
+ function adaptEventData(type, data, sessionGeneration) {
16505
+ if (sessionGeneration !== "v3" || type !== "assistant/message") return data;
16506
+ const value = record2(data);
16507
+ return Array.isArray(value.stream) ? value : { ...value, stream: [] };
16508
+ }
16509
+ function adaptCodexHistoryPage(value, sessionGeneration) {
16510
+ if (sessionGeneration !== "v3") return value;
16511
+ const page = record2(value);
16512
+ const sourceHeader = record2(page.header);
16513
+ const { seedLength: _seedLength, ...header } = sourceHeader;
16514
+ const records = Array.isArray(page.records) ? page.records.map((raw) => {
16515
+ const entry = record2(raw);
16516
+ const sourceEvent = record2(entry.event);
16517
+ const sourceSurfaceOp = record2(sourceEvent.surfaceOp);
16518
+ const surfaceOp = sourceEvent.surfaceOp === "append" ? "append" : sourceSurfaceOp.op === "replace" && integer(sourceSurfaceOp.startSeq) !== void 0 && integer(sourceSurfaceOp.endSeq) !== void 0 ? sourceSurfaceOp : sourceSurfaceOp.op === "replace" && integer(sourceSurfaceOp.start) !== void 0 && integer(sourceSurfaceOp.end) !== void 0 ? {
16519
+ op: "replace",
16520
+ startSeq: sourceSurfaceOp.start,
16521
+ endSeq: sourceSurfaceOp.end
16522
+ } : sourceEvent.surfaceOp;
16523
+ return {
16524
+ ...entry,
16525
+ event: {
16526
+ ...sourceEvent,
16527
+ data: adaptEventData(string(sourceEvent.type) ?? "", sourceEvent.data, sessionGeneration),
16528
+ ...surfaceOp === void 0 ? {} : { surfaceOp }
16529
+ }
16530
+ };
16531
+ }) : page.records;
16532
+ return {
16533
+ ...page,
16534
+ header: { ...header, version: 3, isSeeded: sourceHeader.isSeeded === true },
16535
+ records
16536
+ };
16537
+ }
16027
16538
  function itemEvents(item, turn, step, requestId, selection = modelSelection(), sessionId = CODEX_SESSION_PREFIX, supplementalImages = []) {
16028
16539
  const type = string(item.type);
16029
16540
  const id2 = string(item.id) ?? `${turn}:${step}:${hashString(JSON.stringify(item))}`;
@@ -16180,7 +16691,7 @@ function collectImageBlocks(value, output = []) {
16180
16691
  for (const item of value) collectImageBlocks(item, output);
16181
16692
  return output;
16182
16693
  }
16183
- if (!isRecord3(value)) return output;
16694
+ if (!isRecord5(value)) return output;
16184
16695
  if (value.type === "image") output.push(value);
16185
16696
  for (const [key, child] of Object.entries(value)) {
16186
16697
  if (key === "attachment") continue;
@@ -16510,7 +17021,7 @@ function codexPromptInput(content) {
16510
17021
  if (content.length === 0 || content.length > MAX_CODEX_PROMPT_PARTS) return void 0;
16511
17022
  const input2 = [];
16512
17023
  for (const value of content) {
16513
- if (!isRecord3(value)) return void 0;
17024
+ if (!isRecord5(value)) return void 0;
16514
17025
  if (value.type === "text") {
16515
17026
  if (typeof value.text !== "string" || value.text.length === 0 || value.text.length > MAX_CODEX_PROMPT_TEXT) return void 0;
16516
17027
  input2.push({ type: "text", text: value.text });
@@ -16763,12 +17274,12 @@ function errorCode(error) {
16763
17274
  return "code" in error && typeof error.code === "string" ? error.code : void 0;
16764
17275
  }
16765
17276
  function errorDetails(error) {
16766
- return "details" in error && isRecord3(error.details) ? error.details : {};
17277
+ return "details" in error && isRecord5(error.details) ? error.details : {};
16767
17278
  }
16768
17279
  function record2(value) {
16769
- return isRecord3(value) ? value : {};
17280
+ return isRecord5(value) ? value : {};
16770
17281
  }
16771
- function isRecord3(value) {
17282
+ function isRecord5(value) {
16772
17283
  return typeof value === "object" && value !== null && !Array.isArray(value);
16773
17284
  }
16774
17285
  function array(value) {
@@ -16982,7 +17493,7 @@ function normalizeServerUrl(value) {
16982
17493
  }
16983
17494
 
16984
17495
  // src/version.ts
16985
- var PLUGIN_VERSION = "0.4.10";
17496
+ var PLUGIN_VERSION = "0.4.13";
16986
17497
 
16987
17498
  // src/server-api.ts
16988
17499
  var TERMINAL_CONTROL_CHARACTERS = /[\u0000-\u001f\u007f-\u009f]/u;
@@ -17501,7 +18012,7 @@ var TypertGatewaySwitch = class {
17501
18012
  if (normalized !== void 0) return normalized;
17502
18013
  const source = error instanceof Error ? error : new Error("The Harness Gateway rejected the request.");
17503
18014
  const code = "code" in source && typeof source.code === "string" ? source.code : "internal";
17504
- const details = "details" in source && isRecord4(source.details) ? source.details : {};
18015
+ const details = "details" in source && isRecord6(source.details) ? source.details : {};
17505
18016
  return { code, message: source.message, details };
17506
18017
  }
17507
18018
  };
@@ -17510,7 +18021,7 @@ function requestFromCarrier(endpoint, payload, signal) {
17510
18021
  if (segments.length !== 2 || segments.some((segment) => segment.length === 0)) {
17511
18022
  throw new Error("The Harness Gateway endpoint is invalid.");
17512
18023
  }
17513
- if (!isRecord4(payload) || !isRecord4(payload.args)) {
18024
+ if (!isRecord6(payload) || !isRecord6(payload.args)) {
17514
18025
  throw new Error("The Harness Gateway payload is invalid.");
17515
18026
  }
17516
18027
  return { namespace: segments[0], method: segments[1], args: payload.args, signal };
@@ -17525,7 +18036,7 @@ function isLocalOnlyEndpoint(endpoint) {
17525
18036
  function isRemoteCommandMethod(method) {
17526
18037
  return REMOTE_COMMAND_METHODS.includes(method);
17527
18038
  }
17528
- function isRecord4(value) {
18039
+ function isRecord6(value) {
17529
18040
  return typeof value === "object" && value !== null && !Array.isArray(value);
17530
18041
  }
17531
18042
 
@@ -17536,7 +18047,7 @@ import { networkInterfaces } from "node:os";
17536
18047
  // src/native-rtc-helper.ts
17537
18048
  import { spawn, spawnSync } from "node:child_process";
17538
18049
  import { existsSync, readdirSync, realpathSync, statSync } from "node:fs";
17539
- import { delimiter, dirname, join } from "node:path";
18050
+ import { delimiter, dirname as dirname2, join as join2 } from "node:path";
17540
18051
  import { fileURLToPath } from "node:url";
17541
18052
  var cachedExternalFactory;
17542
18053
  var cachedExternalFactoryResolved = false;
@@ -17587,21 +18098,21 @@ function nodeBinaryCandidates() {
17587
18098
  add3(process.env.DSH_REMOTE_NODE);
17588
18099
  add3(process.env.NODE);
17589
18100
  add3(process.execPath);
17590
- for (const part of (process.env.PATH ?? "").split(delimiter)) add3(join(part, process.platform === "win32" ? "node.exe" : "node"));
18101
+ for (const part of (process.env.PATH ?? "").split(delimiter)) add3(join2(part, process.platform === "win32" ? "node.exe" : "node"));
17591
18102
  add3("/opt/homebrew/bin/node");
17592
18103
  add3("/usr/local/bin/node");
17593
18104
  add3("/usr/bin/node");
17594
- add3(join(process.env.HOME ?? "", ".volta", "bin", process.platform === "win32" ? "node.exe" : "node"));
17595
- add3(join(process.env.HOME ?? "", ".asdf", "shims", process.platform === "win32" ? "node.exe" : "node"));
17596
- add3(join(process.env.HOME ?? "", ".local", "bin", process.platform === "win32" ? "node.exe" : "node"));
18105
+ add3(join2(process.env.HOME ?? "", ".volta", "bin", process.platform === "win32" ? "node.exe" : "node"));
18106
+ add3(join2(process.env.HOME ?? "", ".asdf", "shims", process.platform === "win32" ? "node.exe" : "node"));
18107
+ add3(join2(process.env.HOME ?? "", ".local", "bin", process.platform === "win32" ? "node.exe" : "node"));
17597
18108
  for (const nvmNode of nvmNodeCandidates()) add3(nvmNode);
17598
18109
  return candidates;
17599
18110
  }
17600
18111
  function nvmNodeCandidates() {
17601
- const root = join(process.env.HOME ?? "", ".nvm", "versions", "node");
18112
+ const root = join2(process.env.HOME ?? "", ".nvm", "versions", "node");
17602
18113
  if (root === "" || !existsSync(root)) return [];
17603
18114
  try {
17604
- return readdirSync(root).map((version) => join(root, version, "bin", process.platform === "win32" ? "node.exe" : "node")).sort((left, right) => right.localeCompare(left, "en", { numeric: true }));
18115
+ return readdirSync(root).map((version) => join2(root, version, "bin", process.platform === "win32" ? "node.exe" : "node")).sort((left, right) => right.localeCompare(left, "en", { numeric: true }));
17605
18116
  } catch {
17606
18117
  return [];
17607
18118
  }
@@ -17623,7 +18134,7 @@ function isUsableExternalNode(candidate, requireFrom) {
17623
18134
  "console.log(`node:${process.versions.node}`);"
17624
18135
  ].join("")
17625
18136
  ], {
17626
- cwd: dirname(requireFrom),
18137
+ cwd: dirname2(requireFrom),
17627
18138
  env,
17628
18139
  encoding: "utf8",
17629
18140
  timeout: 3e3
@@ -17645,7 +18156,7 @@ var ExternalNativePeerConnection = class {
17645
18156
  this.nodeBinary = nodeBinary;
17646
18157
  this.requireFrom = requireFrom;
17647
18158
  this.child = spawn(this.nodeBinary, ["--input-type=module", "--eval", HELPER_SOURCE], {
17648
- cwd: dirname(this.requireFrom),
18159
+ cwd: dirname2(this.requireFrom),
17649
18160
  env: { ...process.env, DSH_REMOTE_RTC_HELPER_REQUIRE_FROM: this.requireFrom },
17650
18161
  stdio: ["pipe", "pipe", "pipe"]
17651
18162
  });
@@ -18629,10 +19140,8 @@ var ClientModeRuntime = class {
18629
19140
  fingerprint: this.identity.fingerprint
18630
19141
  });
18631
19142
  }
18632
- registerControl(connection) {
18633
- return connection.rpc.handle(CONTROL_RPC_PREFIX, (endpoint, payload, signal) => this.handleControl(endpoint, payload, signal), {
18634
- authority: "loopback"
18635
- });
19143
+ registerControl(connection, webServer) {
19144
+ return registerControlRoute(connection, (endpoint, payload, signal) => this.handleControl(endpoint, payload, signal), webServer);
18636
19145
  }
18637
19146
  status() {
18638
19147
  const targetStatus = this.gatewaySwitch.supportsCarrier() ? this.gatewaySwitch.status() : this.proxySwitch?.status() ?? this.gatewaySwitch.status();
@@ -18813,9 +19322,9 @@ var ClientModeRuntime = class {
18813
19322
  async openRemoteWorkspace(targetDeviceId, path, signal) {
18814
19323
  if (path.trim() === "") throw new ClientModeError("INVALID_MESSAGE", "A remote working directory is required.");
18815
19324
  const remote = await this.ensureConnected(targetDeviceId, signal);
18816
- this.assertRemoteCompatible(remote);
19325
+ const transport = this.selectHarnessRemoteTransport(remote);
18817
19326
  let workspace;
18818
- if (remote.features.remoteGateway) {
19327
+ if (transport === "remoteGateway") {
18819
19328
  workspace = await new RemoteTypertGateway2(remote.client).invoke({
18820
19329
  namespace: "workspace",
18821
19330
  method: "create",
@@ -18831,7 +19340,7 @@ var ClientModeRuntime = class {
18831
19340
  workspace = unwrapNativeResult(response);
18832
19341
  }
18833
19342
  await this.closeCodexVirtual();
18834
- this.selectRemoteTarget(remote);
19343
+ this.selectRemoteTarget(remote, transport);
18835
19344
  const workspaceId = workspaceRecordId(workspace.workspace);
18836
19345
  this.pendingWorkspaceSelection = { targetDeviceId: remote.target.deviceId, workspaceId };
18837
19346
  this.logger.info("Remote workspace opened", { targetDeviceId: shortId(remote.target.deviceId) });
@@ -18851,11 +19360,11 @@ var ClientModeRuntime = class {
18851
19360
  if (!remote.features.codex) {
18852
19361
  throw new ClientModeError("FEATURE_NOT_SUPPORTED", "The selected Host does not provide CodeX workspaces.");
18853
19362
  }
18854
- this.assertRemoteCompatible(remote);
19363
+ this.assertLocalHarnessCarrierAvailable();
18855
19364
  const virtual = CodexVirtualHarness.remote(remote.client, {
18856
19365
  deviceId: remote.target.deviceId,
18857
19366
  name: remote.target.name
18858
- });
19367
+ }, harnessSessionGeneration(this.host?.localHarnessVersion?.()));
18859
19368
  let workspace;
18860
19369
  try {
18861
19370
  workspace = await virtual.selectWorkspace(workspaceId, signal);
@@ -18884,7 +19393,7 @@ var ClientModeRuntime = class {
18884
19393
  if (!remote.features.codex) {
18885
19394
  throw new ClientModeError("FEATURE_NOT_SUPPORTED", "The selected Host does not provide CodeX workspaces.");
18886
19395
  }
18887
- this.assertRemoteCompatible(remote);
19396
+ this.assertLocalHarnessCarrierAvailable();
18888
19397
  const result = record3(await new CodexRemoteClient(remote.client).request("project/create", {
18889
19398
  name: remoteWorkspaceTitle(trimmedPath),
18890
19399
  roots: [{ path: trimmedPath }],
@@ -18972,10 +19481,10 @@ var ClientModeRuntime = class {
18972
19481
  }
18973
19482
  }
18974
19483
  stream.unsubscribe = remote.client.onEvent((event) => {
18975
- if (event.event === "codex.app.frame" && isRecord5(event.data) && event.data.streamId === value.streamId) {
19484
+ if (event.event === "codex.app.frame" && isRecord7(event.data) && event.data.streamId === value.streamId) {
18976
19485
  this.appendCodexFrame(stream, event.data);
18977
19486
  }
18978
- if (event.event === "codex.app.stream.closed" && isRecord5(event.data) && event.data.streamId === value.streamId) {
19487
+ if (event.event === "codex.app.stream.closed" && isRecord7(event.data) && event.data.streamId === value.streamId) {
18979
19488
  stream.closed = typeof event.data.reason === "string" ? event.data.reason : "closed";
18980
19489
  stream.wake();
18981
19490
  }
@@ -19002,7 +19511,7 @@ var ClientModeRuntime = class {
19002
19511
  stream.wake();
19003
19512
  };
19004
19513
  appendCodexFrame(stream, data) {
19005
- if (!isRecord5(data) || !isRecord5(data.frame) || typeof data.frame.method !== "string") return;
19514
+ if (!isRecord7(data) || !isRecord7(data.frame) || typeof data.frame.method !== "string") return;
19006
19515
  if (stream.frames.length >= 256) {
19007
19516
  stream.closed = "overflow";
19008
19517
  } else {
@@ -19059,18 +19568,25 @@ var ClientModeRuntime = class {
19059
19568
  await stream.close();
19060
19569
  }));
19061
19570
  }
19062
- selectRemoteTarget(remote) {
19571
+ selectRemoteTarget(remote, transport = this.selectHarnessRemoteTransport(remote)) {
19063
19572
  const target = { deviceId: remote.target.deviceId, name: remote.target.name };
19064
- if (this.gatewaySwitch.supportsCarrier()) {
19065
- this.gatewaySwitch.selectRemote(new RemoteTypertGateway2(remote.client), void 0, target);
19573
+ if (transport === "remoteGateway") {
19574
+ this.gatewaySwitch.selectRemote(this.remoteTypertGateway(remote), void 0, target);
19066
19575
  return;
19067
19576
  }
19068
- this.proxySwitch.selectRemote(new RemoteHarnessApiProxy(remote.client).api, target);
19577
+ this.proxySwitch?.selectRemote(new RemoteHarnessApiProxy(remote.client).api, target);
19069
19578
  this.gatewaySwitch.selectRemote((request) => invokeRemoteCommand(remote.client, request), {
19070
19579
  execute: true,
19071
19580
  list: remote.features.commandList
19072
19581
  }, target);
19073
19582
  }
19583
+ remoteTypertGateway(remote) {
19584
+ const localSessionGeneration = harnessSessionGeneration(this.host?.localHarnessVersion?.());
19585
+ return new RemoteTypertGateway2(
19586
+ remote.client,
19587
+ localSessionGeneration === "v3" && remote.features.sessionFormat !== 3 ? "legacy-to-v3" : void 0
19588
+ );
19589
+ }
19074
19590
  selectCodexTarget(virtual, remote) {
19075
19591
  const target = { deviceId: remote.target.deviceId, name: remote.target.name };
19076
19592
  if (this.gatewaySwitch.supportsCarrier()) {
@@ -19086,11 +19602,29 @@ var ClientModeRuntime = class {
19086
19602
  await virtual?.close();
19087
19603
  }
19088
19604
  assertRemoteCompatible(remote) {
19605
+ this.selectHarnessRemoteTransport(remote);
19606
+ }
19607
+ selectHarnessRemoteTransport(remote) {
19089
19608
  const localRemoteGateway = this.gatewaySwitch.supportsCarrier();
19090
- if (localRemoteGateway && remote.features.remoteGateway || !localRemoteGateway && this.proxySwitch !== void 0 && remote.features.apiProxy) return;
19609
+ const localSessionGeneration = harnessSessionGeneration(this.host?.localHarnessVersion?.());
19610
+ if (localRemoteGateway && remote.features.remoteGateway) {
19611
+ if (localSessionGeneration === "v3" || remote.features.sessionFormat !== 3) return "remoteGateway";
19612
+ throw new ClientModeError(
19613
+ "HARNESS_VERSION_INCOMPATIBLE",
19614
+ "The selected Host uses Harness Session V3, but this Client uses the legacy Typert Remote session format."
19615
+ );
19616
+ }
19617
+ if (this.proxySwitch !== void 0 && remote.features.apiProxy) return "apiProxy";
19091
19618
  throw new ClientModeError(
19092
19619
  "HARNESS_VERSION_INCOMPATIBLE",
19093
- localRemoteGateway ? "The selected Host does not provide the Harness v0.1.2 Typert Remote Gateway transport." : "The selected Host does not provide the legacy Harness ApiProxy transport."
19620
+ localRemoteGateway ? "The selected Host does not provide a compatible Harness Typert Remote Gateway transport." : "The selected Host does not provide the legacy Harness ApiProxy transport."
19621
+ );
19622
+ }
19623
+ assertLocalHarnessCarrierAvailable() {
19624
+ if (this.gatewaySwitch.supportsCarrier() || this.proxySwitch !== void 0) return;
19625
+ throw new ClientModeError(
19626
+ "HARNESS_VERSION_INCOMPATIBLE",
19627
+ "This Client does not provide a compatible Harness carrier for the selected remote workspace."
19094
19628
  );
19095
19629
  }
19096
19630
  async connect(targetDeviceId, signal) {
@@ -19216,7 +19750,8 @@ var ClientModeRuntime = class {
19216
19750
  transport: connectedTransport,
19217
19751
  features,
19218
19752
  progressRunId,
19219
- ...serverDevice.clientVersion === void 0 ? {} : { clientVersion: serverDevice.clientVersion }
19753
+ ...serverDevice.clientVersion === void 0 ? {} : { clientVersion: serverDevice.clientVersion },
19754
+ ...serverDevice.harnessVersion === void 0 ? {} : { harnessVersion: serverDevice.harnessVersion }
19220
19755
  };
19221
19756
  } catch (error) {
19222
19757
  this.clearConnectionProgress(progressRunId);
@@ -19468,20 +20003,20 @@ function record3(value) {
19468
20003
  }
19469
20004
  return value;
19470
20005
  }
19471
- function isRecord5(value) {
20006
+ function isRecord7(value) {
19472
20007
  return typeof value === "object" && value !== null && !Array.isArray(value);
19473
20008
  }
19474
20009
  function ok2(value) {
19475
20010
  return { ok: true, value };
19476
20011
  }
19477
20012
  async function invokeRemoteCommand(client, request) {
19478
- const rpcId = uuidV7();
20013
+ const rpcId2 = uuidV7();
19479
20014
  const response = await client.rpc("harness.api.call", {
19480
20015
  method: `${request.namespace}.${request.method}`,
19481
- rpcId,
20016
+ rpcId: rpcId2,
19482
20017
  payload: request.args
19483
20018
  }, request.signal);
19484
- if (response.rpcId !== rpcId) {
20019
+ if (response.rpcId !== rpcId2) {
19485
20020
  throw new ClientModeError("INVALID_MESSAGE", "The remote Host returned an invalid command response.");
19486
20021
  }
19487
20022
  return unwrapNativeResult(response);
@@ -19493,11 +20028,11 @@ async function readRemoteWorkspaceBaseline(gateway, signal) {
19493
20028
  const iterator = source[Symbol.asyncIterator]();
19494
20029
  try {
19495
20030
  const first = await iterator.next();
19496
- if (first.done || !isRecord5(first.value) || first.value.type !== "baseline" || !isRecord5(first.value.value) || !Array.isArray(first.value.value.items)) {
20031
+ if (first.done || !isRecord7(first.value) || first.value.type !== "baseline" || !isRecord7(first.value.value) || !Array.isArray(first.value.value.items)) {
19497
20032
  throw new ClientModeError("INVALID_MESSAGE", "The remote Host returned an invalid Workspace baseline.");
19498
20033
  }
19499
20034
  return first.value.value.items.map((item) => {
19500
- if (!isRecord5(item) || typeof item.workspaceId !== "string" || typeof item.path !== "string" || typeof item.title !== "string") {
20035
+ if (!isRecord7(item) || typeof item.workspaceId !== "string" || typeof item.path !== "string" || typeof item.title !== "string") {
19501
20036
  throw new ClientModeError("INVALID_MESSAGE", "The remote Host returned an invalid Workspace row.");
19502
20037
  }
19503
20038
  return { workspaceId: item.workspaceId, path: item.path, title: item.title };
@@ -19562,13 +20097,20 @@ async function probeRemoteHostFeatures(client, clientVersion) {
19562
20097
  if (error instanceof Error && "code" in error && error.code === "METHOD_NOT_FOUND") return fallback;
19563
20098
  throw error;
19564
20099
  }
19565
- if (!isRecord5(value) || !Array.isArray(value.capabilities) || value.capabilities.some((capability) => typeof capability !== "string")) {
20100
+ if (!isRecord7(value) || !Array.isArray(value.capabilities) || value.capabilities.some((capability) => typeof capability !== "string")) {
19566
20101
  throw new ClientModeError("INVALID_MESSAGE", "The remote Host returned invalid transport capabilities.");
19567
20102
  }
19568
20103
  const capabilities = new Set(value.capabilities);
19569
20104
  const apiProxy = capabilities.has("harness.api.v1");
19570
- const remoteGateway = capabilities.has("harness.remote.v1");
19571
- if (!apiProxy && !remoteGateway) {
20105
+ const remoteV1 = capabilities.has("harness.remote.v1");
20106
+ const remoteV3 = capabilities.has("harness.remote.v3");
20107
+ const codex = capabilities.has("codex.appserver.v1");
20108
+ if (remoteV1 && remoteV3) {
20109
+ throw new ClientModeError("INVALID_MESSAGE", "The remote Host advertised conflicting Harness Session formats.");
20110
+ }
20111
+ const sessionFormat = remoteV3 ? 3 : void 0;
20112
+ const remoteGateway = remoteV3 || remoteV1;
20113
+ if (!apiProxy && !remoteGateway && !codex) {
19572
20114
  throw new ClientModeError("FEATURE_NOT_SUPPORTED", "The remote Host exposes no supported Harness transport.");
19573
20115
  }
19574
20116
  return {
@@ -19576,7 +20118,8 @@ async function probeRemoteHostFeatures(client, clientVersion) {
19576
20118
  fileViewer: capabilities.has("fileviewer.read.v1"),
19577
20119
  apiProxy,
19578
20120
  remoteGateway,
19579
- codex: capabilities.has("codex.appserver.v1")
20121
+ ...sessionFormat === void 0 ? {} : { sessionFormat },
20122
+ codex
19580
20123
  };
19581
20124
  }
19582
20125
  async function waitForCodexFrames(stream, signal) {
@@ -19642,9 +20185,9 @@ import { hostname as hostname2 } from "node:os";
19642
20185
 
19643
20186
  // src/identity-store.ts
19644
20187
  import { createHash } from "node:crypto";
19645
- import { chmod, mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
20188
+ import { chmod, mkdir, readFile as readFile2, rename, rm, stat, writeFile } from "node:fs/promises";
19646
20189
  import { homedir } from "node:os";
19647
- import { dirname as dirname2, join as join2 } from "node:path";
20190
+ import { dirname as dirname3, join as join3 } from "node:path";
19648
20191
  var identitySchema = external_exports.object({
19649
20192
  schemaVersion: external_exports.literal(1),
19650
20193
  deviceId: external_exports.string().uuid(),
@@ -19673,14 +20216,14 @@ var IdentityStore = class {
19673
20216
  peers = /* @__PURE__ */ new Map();
19674
20217
  constructor(options = {}) {
19675
20218
  const env = options.env ?? process.env;
19676
- const dshHome = env.DSH_HOME || join2(options.homeDirectory ?? homedir(), ".dsh");
19677
- this.directory = options.directory ?? join2(dshHome, "remote");
20219
+ const dshHome = env.DSH_HOME || join3(options.homeDirectory ?? homedir(), ".dsh");
20220
+ this.directory = options.directory ?? join3(dshHome, "remote");
19678
20221
  }
19679
20222
  async loadOrCreate(deviceName) {
19680
20223
  await mkdir(this.directory, { recursive: true, mode: 448 });
19681
20224
  await chmod(this.directory, 448);
19682
- const devicePath = join2(this.directory, "device.json");
19683
- const keyPath = join2(this.directory, "device.key");
20225
+ const devicePath = join3(this.directory, "device.json");
20226
+ const keyPath = join3(this.directory, "device.key");
19684
20227
  const [hasDevice, hasKey] = await Promise.all([exists(devicePath), exists(keyPath)]);
19685
20228
  if (hasDevice !== hasKey) {
19686
20229
  throw new IdentityInvalidError("device identity is incomplete; repair it explicitly before reconnecting");
@@ -19694,8 +20237,8 @@ var IdentityStore = class {
19694
20237
  }
19695
20238
  await assertPrivateMode(keyPath);
19696
20239
  try {
19697
- let record6 = identitySchema.parse(JSON.parse(await readFile(devicePath, "utf8")));
19698
- const privateKey = (await readFile(keyPath, "utf8")).trim();
20240
+ let record6 = identitySchema.parse(JSON.parse(await readFile2(devicePath, "utf8")));
20241
+ const privateKey = (await readFile2(keyPath, "utf8")).trim();
19699
20242
  const regenerated = generateKeyPair(fromBase64Url2(privateKey));
19700
20243
  if (regenerated.publicKey !== record6.publicKey) {
19701
20244
  throw new IdentityInvalidError("device public and private keys do not match");
@@ -19749,11 +20292,11 @@ var IdentityStore = class {
19749
20292
  return removed;
19750
20293
  }
19751
20294
  async loadPeers() {
19752
- const path = join2(this.directory, "trusted-peers.json");
20295
+ const path = join3(this.directory, "trusted-peers.json");
19753
20296
  if (!await exists(path)) {
19754
20297
  await atomicJsonWrite(path, { schemaVersion: 1, peers: [] }, 384);
19755
20298
  }
19756
- const parsed = trustedPeersSchema.parse(JSON.parse(await readFile(path, "utf8")));
20299
+ const parsed = trustedPeersSchema.parse(JSON.parse(await readFile2(path, "utf8")));
19757
20300
  const peers = /* @__PURE__ */ new Map();
19758
20301
  for (const peer of parsed.peers) {
19759
20302
  if (peer.fingerprint !== fingerprint(peer.publicKey)) {
@@ -19765,7 +20308,7 @@ var IdentityStore = class {
19765
20308
  this.peers = peers;
19766
20309
  }
19767
20310
  async savePeers() {
19768
- await atomicJsonWrite(join2(this.directory, "trusted-peers.json"), {
20311
+ await atomicJsonWrite(join3(this.directory, "trusted-peers.json"), {
19769
20312
  schemaVersion: 1,
19770
20313
  peers: [...this.peers.values()]
19771
20314
  }, 384);
@@ -19774,7 +20317,7 @@ var IdentityStore = class {
19774
20317
  function serverStorageDirectory(root, serverUrl, role) {
19775
20318
  const origin = new URL(serverUrl).origin;
19776
20319
  const scope = createHash("sha256").update(origin).digest("hex").slice(0, 24);
19777
- return join2(root, "servers", scope, role);
20320
+ return join3(root, "servers", scope, role);
19778
20321
  }
19779
20322
  function fingerprint(publicKey) {
19780
20323
  const compact = createHash("sha256").update(fromBase64Url2(publicKey)).digest("hex").slice(0, 12).toUpperCase();
@@ -19792,7 +20335,7 @@ async function atomicJsonWrite(path, value, mode) {
19792
20335
  `, mode);
19793
20336
  }
19794
20337
  async function atomicTextWrite(path, value, mode) {
19795
- await mkdir(dirname2(path), { recursive: true, mode: 448 });
20338
+ await mkdir(dirname3(path), { recursive: true, mode: 448 });
19796
20339
  const temporary = `${path}.${process.pid}.${uuidV7()}.tmp`;
19797
20340
  await writeFile(temporary, value, { encoding: "utf8", mode, flag: "wx" });
19798
20341
  await chmod(temporary, mode);
@@ -19816,8 +20359,8 @@ function safeErrorMessage(error) {
19816
20359
  }
19817
20360
 
19818
20361
  // src/server-credentials.ts
19819
- import { chmod as chmod2, mkdir as mkdir2, readFile as readFile2, rename as rename2, rm as rm2, stat as stat2, writeFile as writeFile2 } from "node:fs/promises";
19820
- import { dirname as dirname3, join as join3 } from "node:path";
20362
+ import { chmod as chmod2, mkdir as mkdir2, readFile as readFile3, rename as rename2, rm as rm2, stat as stat2, writeFile as writeFile2 } from "node:fs/promises";
20363
+ import { dirname as dirname4, join as join4 } from "node:path";
19821
20364
  var credentialSchema = external_exports.object({
19822
20365
  schemaVersion: external_exports.literal(1),
19823
20366
  serverUrl: external_exports.string().url(),
@@ -19832,14 +20375,14 @@ var credentialSchema = external_exports.object({
19832
20375
  var ServerCredentialStore = class {
19833
20376
  path;
19834
20377
  constructor(directory) {
19835
- this.path = join3(directory, "server-credentials.json");
20378
+ this.path = join4(directory, "server-credentials.json");
19836
20379
  }
19837
20380
  async load(serverUrl, deviceId) {
19838
20381
  if (!await exists2(this.path)) return void 0;
19839
20382
  await assertPrivateMode2(this.path);
19840
20383
  let parsed;
19841
20384
  try {
19842
- parsed = credentialSchema.parse(JSON.parse(await readFile2(this.path, "utf8")));
20385
+ parsed = credentialSchema.parse(JSON.parse(await readFile3(this.path, "utf8")));
19843
20386
  } catch (error) {
19844
20387
  throw new ServerCredentialsInvalidError(`server credentials are invalid: ${safeMessage(error)}`);
19845
20388
  }
@@ -19859,7 +20402,7 @@ var ServerCredentialsInvalidError = class extends Error {
19859
20402
  code = "SERVER_CREDENTIALS_INVALID";
19860
20403
  };
19861
20404
  async function atomicWrite(path, contents) {
19862
- await mkdir2(dirname3(path), { recursive: true, mode: 448 });
20405
+ await mkdir2(dirname4(path), { recursive: true, mode: 448 });
19863
20406
  const temporary = `${path}.${process.pid}.${uuidV7()}.tmp`;
19864
20407
  await writeFile2(temporary, contents, { encoding: "utf8", mode: 384, flag: "wx" });
19865
20408
  await chmod2(temporary, 384);
@@ -19893,10 +20436,8 @@ var PluginControlRuntime = class {
19893
20436
  this.client = client;
19894
20437
  this.host = host;
19895
20438
  }
19896
- register(connection) {
19897
- return connection.rpc.handle(CONTROL_RPC_PREFIX, (endpoint, payload, signal) => this.handle(endpoint, payload, signal), {
19898
- authority: "loopback"
19899
- });
20439
+ register(connection, webServer) {
20440
+ return registerControlRoute(connection, (endpoint, payload, signal) => this.handle(endpoint, payload, signal), webServer);
19900
20441
  }
19901
20442
  async handle(endpoint, payload, signal) {
19902
20443
  try {
@@ -20110,11 +20651,11 @@ function editableConfig(config) {
20110
20651
  }
20111
20652
  };
20112
20653
  }
20113
- function isRecord6(value) {
20654
+ function isRecord8(value) {
20114
20655
  return typeof value === "object" && value !== null && !Array.isArray(value);
20115
20656
  }
20116
20657
  function record4(value) {
20117
- if (!isRecord6(value)) throw new ClientModeError("INVALID_MESSAGE", "The control request payload is invalid.");
20658
+ if (!isRecord8(value)) throw new ClientModeError("INVALID_MESSAGE", "The control request payload is invalid.");
20118
20659
  return value;
20119
20660
  }
20120
20661
  function ok3(value) {
@@ -20337,36 +20878,6 @@ function shortId2(value) {
20337
20878
  return value.length <= 12 ? value : `${value.slice(0, 8)}\u2026${value.slice(-4)}`;
20338
20879
  }
20339
20880
 
20340
- // src/harness-version.ts
20341
- import { readFile as readFile3 } from "node:fs/promises";
20342
- import { dirname as dirname4, isAbsolute, join as join4 } from "node:path";
20343
- var LEGACY_PLACEHOLDER_VERSION = "0.0.1";
20344
- function normalizeHarnessVersion(value) {
20345
- if (typeof value !== "string") return void 0;
20346
- const version = value.trim();
20347
- if (version.length === 0 || version.length > 64 || /[\u0000-\u001f]/u.test(version)) return void 0;
20348
- return version;
20349
- }
20350
- function selectHarnessVersion(reportedVersion, distributionVersion) {
20351
- if (reportedVersion !== void 0 && reportedVersion !== LEGACY_PLACEHOLDER_VERSION) return reportedVersion;
20352
- return distributionVersion;
20353
- }
20354
- async function readHarnessDistributionVersion(entrypoint = process.argv[1]) {
20355
- if (entrypoint === void 0 || !isAbsolute(entrypoint)) return void 0;
20356
- let directory = dirname4(entrypoint);
20357
- for (let depth = 0; depth < 8; depth += 1) {
20358
- try {
20359
- const manifest = JSON.parse(await readFile3(join4(directory, "package.json"), "utf8"));
20360
- if (manifest.name === "@deepseek-ai/dsh") return normalizeHarnessVersion(manifest.version);
20361
- } catch {
20362
- }
20363
- const parent = dirname4(directory);
20364
- if (parent === directory) break;
20365
- directory = parent;
20366
- }
20367
- return void 0;
20368
- }
20369
-
20370
20881
  // src/safe-error.ts
20371
20882
  var RpcError = class extends Error {
20372
20883
  constructor(code, message, details, retryable = false) {
@@ -20465,7 +20976,7 @@ var RpcRouter = class {
20465
20976
  });
20466
20977
  return createRpcResponse(request.id, result);
20467
20978
  } catch (error) {
20468
- const response = errorResponse(request.id, error);
20979
+ const response = errorResponse2(request.id, error);
20469
20980
  this.logger?.warn("host rpc failed", {
20470
20981
  method: request.payload.method,
20471
20982
  durationMs: Math.round(performance.now() - startedAt),
@@ -20564,7 +21075,7 @@ var RpcRouter = class {
20564
21075
  return this.codex;
20565
21076
  }
20566
21077
  };
20567
- function errorResponse(requestId, error) {
21078
+ function errorResponse2(requestId, error) {
20568
21079
  const code = safeErrorCode(error);
20569
21080
  if (error instanceof RpcError) return createRpcError(requestId, code, error.message, error.details, error.retryable);
20570
21081
  return createRpcError(
@@ -21757,8 +22268,8 @@ var HARNESS_API_ALLOWLIST = [
21757
22268
  "credentials.unset"
21758
22269
  ];
21759
22270
  var NATIVE_CALL_TIMEOUT_MS = 3e4;
21760
- var MAX_ACTIVE_API_TRANSFERS = 2;
21761
- var API_TRANSFER_IDLE_MS = 2 * 6e4;
22271
+ var MAX_ACTIVE_API_TRANSFERS = MAX_ACTIVE_TRANSFERS_PER_DIRECTION;
22272
+ var API_TRANSFER_IDLE_MS = TRANSFER_IDLE_MS;
21762
22273
  var INLINE_TRANSFER_RESPONSE_BYTES = 2 * 1024 * 1024;
21763
22274
  var SESSION_HISTORY_PAGE_SIZES = [50, 30, 20, 12, 6, 3, 1];
21764
22275
  var HarnessApiBridge = class {
@@ -21835,9 +22346,9 @@ var HarnessApiBridge = class {
21835
22346
  const value = await listRemoteDirectory(payload.path, signal);
21836
22347
  return { rpcId: params.rpcId, result: { ok: true, value } };
21837
22348
  }
21838
- describeFallback(rpcId) {
22349
+ describeFallback(rpcId2) {
21839
22350
  return {
21840
- rpcId,
22351
+ rpcId: rpcId2,
21841
22352
  result: {
21842
22353
  ok: true,
21843
22354
  value: {
@@ -22055,8 +22566,8 @@ var HarnessApiBridge = class {
22055
22566
  }
22056
22567
  }
22057
22568
  deleteRespondable(value) {
22058
- for (const [rpcId, correlation] of this.respondable) {
22059
- if (correlation === value) this.respondable.delete(rpcId);
22569
+ for (const [rpcId2, correlation] of this.respondable) {
22570
+ if (correlation === value) this.respondable.delete(rpcId2);
22060
22571
  }
22061
22572
  }
22062
22573
  };
@@ -22243,9 +22754,9 @@ function sanitizeModelDiscoveryResponse(response, settingsNs) {
22243
22754
  if (typeof result === "object" && result !== null && "ok" in result && result.ok === true) return response;
22244
22755
  return modelDiscoveryFailure(response.rpcId, settingsNs);
22245
22756
  }
22246
- function modelDiscoveryFailure(rpcId, settingsNs) {
22757
+ function modelDiscoveryFailure(rpcId2, settingsNs) {
22247
22758
  return {
22248
- rpcId,
22759
+ rpcId: rpcId2,
22249
22760
  result: {
22250
22761
  ok: false,
22251
22762
  error: {
@@ -22305,15 +22816,15 @@ function frameSessionId(frame) {
22305
22816
  const payload = frame.payload;
22306
22817
  return typeof payload.sessionId === "string" && payload.sessionId.length > 0 ? payload.sessionId : void 0;
22307
22818
  }
22308
- function callSessionHistory(callWithTimeout, payload, rpcId) {
22819
+ function callSessionHistory(callWithTimeout, payload, rpcId2) {
22309
22820
  const fallbackPageSizes = sessionHistoryFallbackPageSizes(payloadMaxMessages(payload));
22310
- return callHistoryWithRetry(callWithTimeout, payload, rpcId, fallbackPageSizes);
22821
+ return callHistoryWithRetry(callWithTimeout, payload, rpcId2, fallbackPageSizes);
22311
22822
  }
22312
- async function callHistoryWithRetry(callWithTimeout, payload, rpcId, pageSizes) {
22823
+ async function callHistoryWithRetry(callWithTimeout, payload, rpcId2, pageSizes) {
22313
22824
  for (const maxMessages of pageSizes) {
22314
22825
  const requestPayload = historyRequestPayload(payload, maxMessages);
22315
22826
  const response = await callWithTimeout(requestPayload);
22316
- const request = createRpcResponse(rpcId, response.result);
22827
+ const request = createRpcResponse(rpcId2, response.result);
22317
22828
  if (encodeMessage(request).byteLength <= MAX_SECURE_MESSAGE_BYTES) return response;
22318
22829
  if (maxMessages === pageSizes[pageSizes.length - 1]) {
22319
22830
  throw new RpcError(
@@ -22419,9 +22930,8 @@ var transferReadSchema2 = external_exports.object({
22419
22930
  var directoryListSchema2 = external_exports.object({
22420
22931
  path: external_exports.string().min(1).max(4096).optional()
22421
22932
  }).strict();
22422
- var MAX_ACTIVE_STREAMS = 16;
22423
- var MAX_ACTIVE_TRANSFERS = 2;
22424
- var TRANSFER_IDLE_MS = 2 * 6e4;
22933
+ var MAX_ACTIVE_STREAMS = MAX_ALPHA_STREAMS_PER_CONNECTION;
22934
+ var MAX_ACTIVE_TRANSFERS = MAX_ACTIVE_TRANSFERS_PER_DIRECTION;
22425
22935
  var INLINE_TRANSFER_RESPONSE_BYTES2 = 2 * 1024 * 1024;
22426
22936
  var HARNESS_REMOTE_ALLOWLIST = [
22427
22937
  "$events",
@@ -22721,13 +23231,13 @@ function needsDirectoryFallback(result) {
22721
23231
  }
22722
23232
  function requestArgs(payload) {
22723
23233
  const root = record5(payload);
22724
- const args = isRecord7(root.args) ? root.args : root;
23234
+ const args = isRecord9(root.args) ? root.args : root;
22725
23235
  return record5(args.request ?? args._request ?? args);
22726
23236
  }
22727
23237
  function record5(value) {
22728
- return isRecord7(value) ? value : {};
23238
+ return isRecord9(value) ? value : {};
22729
23239
  }
22730
- function isRecord7(value) {
23240
+ function isRecord9(value) {
22731
23241
  return typeof value === "object" && value !== null && !Array.isArray(value);
22732
23242
  }
22733
23243
 
@@ -22921,7 +23431,7 @@ var CodexAppServerClient = class {
22921
23431
  this.handleProcessFailure("CODEX_INVALID_RESPONSE", new Error("Codex App Server emitted invalid JSON."));
22922
23432
  return;
22923
23433
  }
22924
- if (!isRecord8(value)) {
23434
+ if (!isRecord10(value)) {
22925
23435
  this.handleProcessFailure("CODEX_INVALID_RESPONSE", new Error("Codex App Server emitted an invalid message."));
22926
23436
  return;
22927
23437
  }
@@ -22966,12 +23476,12 @@ var CodexAppServerClient = class {
22966
23476
  }
22967
23477
  };
22968
23478
  function safeUpstreamError(value) {
22969
- if (!isRecord8(value) || typeof value.message !== "string") return "Codex App Server rejected the request.";
23479
+ if (!isRecord10(value) || typeof value.message !== "string") return "Codex App Server rejected the request.";
22970
23480
  const message = value.message.toLowerCase();
22971
23481
  if (message.includes("active writer")) return "Codex thread already has an active writer.";
22972
23482
  return message.includes("not initialized") ? "Codex App Server is not initialized." : "Codex App Server rejected the request.";
22973
23483
  }
22974
- function isRecord8(value) {
23484
+ function isRecord10(value) {
22975
23485
  return typeof value === "object" && value !== null && !Array.isArray(value);
22976
23486
  }
22977
23487
 
@@ -23103,9 +23613,8 @@ var transferChunkSchema3 = external_exports.object({
23103
23613
  }).strict();
23104
23614
  var transferIdSchema3 = external_exports.object({ transferId: external_exports.string().uuid() }).strict();
23105
23615
  var transferReadSchema3 = external_exports.object({ transferId: external_exports.string().uuid(), index: external_exports.number().int().nonnegative() }).strict();
23106
- var MAX_ACTIVE_STREAMS2 = 16;
23107
- var MAX_ACTIVE_TRANSFERS2 = 2;
23108
- var TRANSFER_IDLE_MS2 = 2 * 6e4;
23616
+ var MAX_ACTIVE_STREAMS2 = MAX_ALPHA_STREAMS_PER_CONNECTION;
23617
+ var MAX_ACTIVE_TRANSFERS2 = MAX_ACTIVE_TRANSFERS_PER_DIRECTION;
23109
23618
  var INLINE_TRANSFER_RESPONSE_BYTES3 = 2 * 1024 * 1024;
23110
23619
  var CodexPeerBridge = class {
23111
23620
  constructor(domain, context, publish, logger) {
@@ -23319,7 +23828,7 @@ var CodexPeerBridge = class {
23319
23828
  await this.domain.detachPeer(this.context.connectionId);
23320
23829
  }
23321
23830
  pruneTransfers() {
23322
- const staleBefore = Date.now() - TRANSFER_IDLE_MS2;
23831
+ const staleBefore = Date.now() - TRANSFER_IDLE_MS;
23323
23832
  for (const [id2, transfer] of this.incomingTransfers) {
23324
23833
  if (transfer.touchedAt < staleBefore) this.incomingTransfers.delete(id2);
23325
23834
  }
@@ -23341,15 +23850,15 @@ function decodeCanonicalBase643(value) {
23341
23850
  }
23342
23851
  return decoded;
23343
23852
  }
23344
- function isRecord9(value) {
23853
+ function isRecord11(value) {
23345
23854
  return typeof value === "object" && value !== null && !Array.isArray(value);
23346
23855
  }
23347
23856
  function safeErrorCode2(error) {
23348
- if (isRecord9(error) && typeof error.code === "string") return error.code;
23857
+ if (isRecord11(error) && typeof error.code === "string") return error.code;
23349
23858
  return "UNKNOWN";
23350
23859
  }
23351
23860
  function safeMethod(input2) {
23352
- return isRecord9(input2) && typeof input2.method === "string" ? input2.method : "invalid";
23861
+ return isRecord11(input2) && typeof input2.method === "string" ? input2.method : "invalid";
23353
23862
  }
23354
23863
  function concatChunks3(chunks, totalBytes) {
23355
23864
  const output = new Uint8Array(totalBytes);
@@ -23766,14 +24275,14 @@ var CodexRemoteDomain = class {
23766
24275
  await this.assertResultThreadAllowed(result);
23767
24276
  if (codexPermissionPresetFromResponse(result) !== params.permissionPreset) {
23768
24277
  await this.callUpstream("thread/settings/update", { threadId, ...settings });
23769
- result = { ...isRecord10(result) ? result : {}, ...settings, sandbox: settings.sandboxPolicy };
24278
+ result = { ...isRecord12(result) ? result : {}, ...settings, sandbox: settings.sandboxPolicy };
23770
24279
  }
23771
24280
  }
23772
24281
  await this.publishPermission(threadId, result);
23773
24282
  return result;
23774
24283
  }
23775
24284
  async publishPermission(threadId, value) {
23776
- const source = isRecord10(value) ? value : {};
24285
+ const source = isRecord12(value) ? value : {};
23777
24286
  const threadSettings = { approvalPolicy: source.approvalPolicy, sandboxPolicy: source.sandboxPolicy ?? source.sandbox };
23778
24287
  await this.handleInbound({ kind: "notification", method: "thread/settings/updated", params: { threadId, threadSettings } });
23779
24288
  }
@@ -23869,9 +24378,9 @@ var CodexRemoteDomain = class {
23869
24378
  itemsView,
23870
24379
  ...cursor2 === void 0 ? {} : { cursor: cursor2 }
23871
24380
  });
23872
- const pageResult = isRecord10(result) ? result : {};
24381
+ const pageResult = isRecord12(result) ? result : {};
23873
24382
  for (const rawTurn of array2(pageResult.data)) {
23874
- if (!isRecord10(rawTurn)) continue;
24383
+ if (!isRecord12(rawTurn)) continue;
23875
24384
  const turnId = typeof rawTurn.id === "string" ? rawTurn.id : void 0;
23876
24385
  const items = rawTurn.itemsView === "full" || turnId === void 0 ? array2(rawTurn.items) : await this.readThreadItems(connectionId, threadId, turnId, array2(rawTurn.items));
23877
24386
  turns.push({ ...rawTurn, items });
@@ -23893,9 +24402,9 @@ var CodexRemoteDomain = class {
23893
24402
  sortDirection: "asc",
23894
24403
  ...cursor2 === void 0 ? {} : { cursor: cursor2 }
23895
24404
  });
23896
- const pageResult = isRecord10(result) ? result : {};
24405
+ const pageResult = isRecord12(result) ? result : {};
23897
24406
  for (const entry of array2(pageResult.data)) {
23898
- if (isRecord10(entry) && entry.item !== void 0) items.push(entry.item);
24407
+ if (isRecord12(entry) && entry.item !== void 0) items.push(entry.item);
23899
24408
  }
23900
24409
  cursor2 = typeof pageResult.nextCursor === "string" && pageResult.nextCursor.length > 0 ? pageResult.nextCursor : void 0;
23901
24410
  if (cursor2 === void 0) break;
@@ -23959,7 +24468,7 @@ var CodexRemoteDomain = class {
23959
24468
  return [...this.peers.values()].some((peer) => peer.hasThreadSubscription(threadId));
23960
24469
  }
23961
24470
  resolveUpstreamApproval(params) {
23962
- if (!isRecord10(params) || typeof params.requestId !== "string" && typeof params.requestId !== "number") return;
24471
+ if (!isRecord12(params) || typeof params.requestId !== "string" && typeof params.requestId !== "number") return;
23963
24472
  for (const [handle, approval] of this.approvals) {
23964
24473
  if (approval.upstreamId === params.requestId) this.approvals.delete(handle);
23965
24474
  }
@@ -24176,24 +24685,24 @@ function codexBinaryCandidates(configured, hostPlatform = process.platform, user
24176
24685
  ])];
24177
24686
  }
24178
24687
  function parseCallEnvelope(input2) {
24179
- if (!isRecord10(input2) || typeof input2.method !== "string" || !("params" in input2) || Object.keys(input2).some((key) => key !== "method" && key !== "params")) {
24688
+ if (!isRecord12(input2) || typeof input2.method !== "string" || !("params" in input2) || Object.keys(input2).some((key) => key !== "method" && key !== "params")) {
24180
24689
  throw new RpcError("INVALID_MESSAGE", "The Codex call envelope is invalid.");
24181
24690
  }
24182
24691
  return { method: input2.method, params: input2.params };
24183
24692
  }
24184
24693
  function parseRespond(input2) {
24185
- if (!isRecord10(input2) || typeof input2.requestHandle !== "string" || !["accept", "decline", "cancel"].includes(String(input2.decision)) || Object.keys(input2).some((key) => key !== "requestHandle" && key !== "decision")) {
24694
+ if (!isRecord12(input2) || typeof input2.requestHandle !== "string" || !["accept", "decline", "cancel"].includes(String(input2.decision)) || Object.keys(input2).some((key) => key !== "requestHandle" && key !== "decision")) {
24186
24695
  throw new RpcError("INVALID_MESSAGE", "The Codex approval response is invalid.");
24187
24696
  }
24188
24697
  return input2;
24189
24698
  }
24190
24699
  function accountCanRun(result) {
24191
- if (!isRecord10(result) || typeof result.requiresOpenaiAuth !== "boolean") return false;
24192
- return result.requiresOpenaiAuth === false || isRecord10(result.account);
24700
+ if (!isRecord12(result) || typeof result.requiresOpenaiAuth !== "boolean") return false;
24701
+ return result.requiresOpenaiAuth === false || isRecord12(result.account);
24193
24702
  }
24194
24703
  function sanitizeAccount(result) {
24195
- if (!isRecord10(result)) throw new RpcError("CODEX_INVALID_RESPONSE", "Codex App Server returned invalid account state.");
24196
- const account = isRecord10(result.account) ? result.account : void 0;
24704
+ if (!isRecord12(result)) throw new RpcError("CODEX_INVALID_RESPONSE", "Codex App Server returned invalid account state.");
24705
+ const account = isRecord12(result.account) ? result.account : void 0;
24197
24706
  return {
24198
24707
  authenticated: account !== void 0 || result.requiresOpenaiAuth === false,
24199
24708
  requiresOpenaiAuth: result.requiresOpenaiAuth === true,
@@ -24206,11 +24715,11 @@ function sanitizeAccount(result) {
24206
24715
  };
24207
24716
  }
24208
24717
  function sanitizeThreadList(result) {
24209
- if (!isRecord10(result) || !Array.isArray(result.data)) {
24718
+ if (!isRecord12(result) || !Array.isArray(result.data)) {
24210
24719
  throw new RpcError("CODEX_INVALID_RESPONSE", "Codex App Server returned an invalid thread list.");
24211
24720
  }
24212
24721
  const data = result.data.flatMap((value) => {
24213
- if (!isRecord10(value) || typeof value.id !== "string") return [];
24722
+ if (!isRecord12(value) || typeof value.id !== "string") return [];
24214
24723
  return [{
24215
24724
  id: value.id,
24216
24725
  ...typeof value.sessionId === "string" ? { sessionId: value.sessionId } : {},
@@ -24222,7 +24731,7 @@ function sanitizeThreadList(result) {
24222
24731
  ...typeof value.updatedAt === "number" && Number.isFinite(value.updatedAt) ? { updatedAt: value.updatedAt } : {},
24223
24732
  ...typeof value.archived === "boolean" ? { archived: value.archived } : {},
24224
24733
  ...typeof value.isPinned === "boolean" ? { isPinned: value.isPinned } : {},
24225
- ...isRecord10(value.status) ? { status: value.status } : {}
24734
+ ...isRecord12(value.status) ? { status: value.status } : {}
24226
24735
  }];
24227
24736
  });
24228
24737
  return {
@@ -24232,18 +24741,18 @@ function sanitizeThreadList(result) {
24232
24741
  };
24233
24742
  }
24234
24743
  function filterThreadListByWorkspaceAuthority(result, authority) {
24235
- if (!isRecord10(result) || !Array.isArray(result.data)) {
24744
+ if (!isRecord12(result) || !Array.isArray(result.data)) {
24236
24745
  throw new RpcError("CODEX_INVALID_RESPONSE", "Codex App Server returned an invalid thread list.");
24237
24746
  }
24238
24747
  return {
24239
24748
  ...result,
24240
- data: result.data.map((record6) => isRecord10(record6) ? record6 : void 0).filter((thread) => thread !== void 0 && isThreadAllowedByWorkspaceAuthority(thread, authority))
24749
+ data: result.data.map((record6) => isRecord12(record6) ? record6 : void 0).filter((thread) => thread !== void 0 && isThreadAllowedByWorkspaceAuthority(thread, authority))
24241
24750
  };
24242
24751
  }
24243
24752
  function sanitizeProject(value) {
24244
- if (!isRecord10(value) || typeof value.id !== "string" || typeof value.name !== "string") return void 0;
24753
+ if (!isRecord12(value) || typeof value.id !== "string" || typeof value.name !== "string") return void 0;
24245
24754
  const roots = Array.isArray(value.roots) ? value.roots.flatMap((root) => {
24246
- const path = isRecord10(root) && typeof root.path === "string" && root.path.length > 0 ? root.path : void 0;
24755
+ const path = isRecord12(root) && typeof root.path === "string" && root.path.length > 0 ? root.path : void 0;
24247
24756
  return path === void 0 || !isAbsolute3(path) ? [] : [{ path }];
24248
24757
  }) : [];
24249
24758
  if (roots.length === 0) return void 0;
@@ -24257,7 +24766,7 @@ function sanitizeProject(value) {
24257
24766
  };
24258
24767
  }
24259
24768
  function sanitizeProjectList(result) {
24260
- if (!isRecord10(result) || !Array.isArray(result.data)) {
24769
+ if (!isRecord12(result) || !Array.isArray(result.data)) {
24261
24770
  throw new RpcError("CODEX_INVALID_RESPONSE", "Codex App Server returned an invalid project list.");
24262
24771
  }
24263
24772
  const data = result.data.flatMap((value) => sanitizeProject(value) ?? []);
@@ -24267,7 +24776,7 @@ function sanitizeProjectList(result) {
24267
24776
  };
24268
24777
  }
24269
24778
  function sanitizeProjectCreate(result) {
24270
- const project = isRecord10(result) ? sanitizeProject(result.project) : void 0;
24779
+ const project = isRecord12(result) ? sanitizeProject(result.project) : void 0;
24271
24780
  if (project === void 0) {
24272
24781
  throw new RpcError("CODEX_INVALID_RESPONSE", "Codex App Server returned an invalid created project.");
24273
24782
  }
@@ -24299,19 +24808,19 @@ function codexDirectoryCrumbs(root, path) {
24299
24808
  return crumbs2;
24300
24809
  }
24301
24810
  function extractThread(result) {
24302
- return isRecord10(result) && isRecord10(result.thread) ? result.thread : void 0;
24811
+ return isRecord12(result) && isRecord12(result.thread) ? result.thread : void 0;
24303
24812
  }
24304
24813
  function extractTurnId(result) {
24305
- if (!isRecord10(result)) return void 0;
24814
+ if (!isRecord12(result)) return void 0;
24306
24815
  if (typeof result.turnId === "string" && result.turnId.length > 0) return result.turnId;
24307
- if (isRecord10(result.turn) && typeof result.turn.id === "string" && result.turn.id.length > 0) return result.turn.id;
24816
+ if (isRecord12(result.turn) && typeof result.turn.id === "string" && result.turn.id.length > 0) return result.turn.id;
24308
24817
  return void 0;
24309
24818
  }
24310
24819
  function extractThreadId(params) {
24311
- if (!isRecord10(params)) return void 0;
24820
+ if (!isRecord12(params)) return void 0;
24312
24821
  if (typeof params.threadId === "string") return params.threadId;
24313
- if (isRecord10(params.thread) && typeof params.thread.id === "string") return params.thread.id;
24314
- if (isRecord10(params.turn) && typeof params.turn.threadId === "string") return params.turn.threadId;
24822
+ if (isRecord12(params.thread) && typeof params.thread.id === "string") return params.thread.id;
24823
+ if (isRecord12(params.turn) && typeof params.turn.threadId === "string") return params.turn.threadId;
24315
24824
  return void 0;
24316
24825
  }
24317
24826
  function optionalInteger2(value) {
@@ -24353,13 +24862,13 @@ function mapCodexImageInputs(params) {
24353
24862
  return {
24354
24863
  ...params,
24355
24864
  input: params.input.map((value) => {
24356
- if (!isRecord10(value) || value.type !== "image" || typeof value.mediaType !== "string" || typeof value.data !== "string") return value;
24865
+ if (!isRecord12(value) || value.type !== "image" || typeof value.mediaType !== "string" || typeof value.data !== "string") return value;
24357
24866
  return { type: "image", url: `data:${value.mediaType};base64,${value.data}` };
24358
24867
  })
24359
24868
  };
24360
24869
  }
24361
24870
  function sanitizeApprovalParams(params, requestHandle) {
24362
- if (!isRecord10(params)) return { requestHandle };
24871
+ if (!isRecord12(params)) return { requestHandle };
24363
24872
  const safe = { ...params };
24364
24873
  delete safe.proposedExecpolicyAmendment;
24365
24874
  delete safe.additionalPermissions;
@@ -24390,7 +24899,7 @@ function isProjectListFallbackError(error) {
24390
24899
  function canTryNextBinary(error) {
24391
24900
  return !(error instanceof RpcError) || !["CODEX_AUTH_REQUIRED", "CODEX_CLOSED"].includes(error.code);
24392
24901
  }
24393
- function isRecord10(value) {
24902
+ function isRecord12(value) {
24394
24903
  return typeof value === "object" && value !== null && !Array.isArray(value);
24395
24904
  }
24396
24905
  function array2(value) {
@@ -24498,6 +25007,9 @@ var HostPluginRuntime = class {
24498
25007
  accountRequired: error === "ACCOUNT_AUTH_REQUIRED" || error === "AUTH_INVALID" || error === "TOKEN_EXPIRED"
24499
25008
  };
24500
25009
  }
25010
+ localHarnessVersion() {
25011
+ return this.harnessVersion;
25012
+ }
24501
25013
  reconnectHost() {
24502
25014
  if (this.closed) throw new Error("remote runtime is closed");
24503
25015
  if (this.serverConnection === void 0) {
@@ -24667,9 +25179,14 @@ var HostPluginRuntime = class {
24667
25179
  }
24668
25180
  hostCapabilities() {
24669
25181
  const capabilities = [];
24670
- if (this.apiProxy !== void 0) capabilities.push("harness.api.v1", "harness.api.transfer.v1");
24671
25182
  if (this.localGateway?.supportsCarrier === true) {
24672
- capabilities.push("harness.remote.v1", "harness.remote.transfer.v1");
25183
+ capabilities.push(
25184
+ harnessSessionGeneration(this.harnessVersion) === "v3" ? "harness.remote.v3" : "harness.remote.v1",
25185
+ "harness.remote.transfer.v1"
25186
+ );
25187
+ }
25188
+ if (this.apiProxy !== void 0) {
25189
+ capabilities.push("harness.api.v1", "harness.api.transfer.v1");
24673
25190
  }
24674
25191
  if (this.fileViewerHost?.() !== void 0) capabilities.push("fileviewer.read.v1");
24675
25192
  if (this.codex.isAvailable()) capabilities.push("codex.appserver.v1", "codex.appserver.transfer.v1");
@@ -25123,7 +25640,7 @@ function remoteStatusLines(target) {
25123
25640
  `Device: ${status2.deviceId ?? "not initialized"}`,
25124
25641
  `Authorization: ${status2.authorized ? status2.account === void 0 ? "logged in" : `logged in (${status2.account})` : "logged out"}`,
25125
25642
  `Server connection: ${connection}`,
25126
- `Harness Remote API: ${capabilities.has("harness.api.v1") ? "available (ApiProxy)" : capabilities.has("harness.remote.v1") ? "available (Typert Remote)" : "unavailable"}`,
25643
+ `Harness Remote API: ${capabilities.has("harness.api.v1") ? "available (ApiProxy)" : capabilities.has("harness.remote.v3") ? "available (Typert Remote Session V3)" : capabilities.has("harness.remote.v1") ? "available (Typert Remote)" : "unavailable"}`,
25127
25644
  `Remote clients: ${diagnostics.activeConnections}`,
25128
25645
  `Codex Remote: ${codex.enabled ? codex.state : "disabled"}`,
25129
25646
  "",
@@ -25396,6 +25913,7 @@ function apply(ctx, input2 = {}) {
25396
25913
  const activateWhenCarrierReady = (runtimeContext) => {
25397
25914
  const gateway = runtimeContext.get("typertGateway");
25398
25915
  const connection = runtimeContext.get("connection");
25916
+ const webServer = runtimeContext.get("webServer");
25399
25917
  let disposePendingControl;
25400
25918
  const installPendingControl = () => {
25401
25919
  if (connection === void 0 || disposePendingControl !== void 0) return;
@@ -25407,7 +25925,7 @@ function apply(ctx, input2 = {}) {
25407
25925
  void 0,
25408
25926
  void 0
25409
25927
  );
25410
- return control.register(connection);
25928
+ return control.register(connection, webServer);
25411
25929
  }, "dsh-remote pending control");
25412
25930
  };
25413
25931
  const startActiveRuntime = async (activeContext) => {
@@ -25441,13 +25959,14 @@ async function activate(ctx, input2, tuiBinding) {
25441
25959
  reportSettingsMigration(ctx, await migration);
25442
25960
  }
25443
25961
  const connection = ctx.get("connection");
25962
+ const webServer = ctx.get("webServer");
25444
25963
  const resolvedConfig = resolveConfig(settingsScope?.get() ?? input2);
25445
25964
  const config = connection === void 0 && resolvedConfig.serverUrl === void 0 ? { ...resolvedConfig, serverUrl: DEFAULT_REMOTE_SERVER_URL } : resolvedConfig;
25446
25965
  const defaultIdentityDirectory = new IdentityStore().directory;
25447
25966
  if (!config.enabled) {
25448
25967
  if (connection !== void 0) {
25449
25968
  const controlRuntime2 = new PluginControlRuntime(config, defaultIdentityDirectory, settingsScope, void 0, void 0);
25450
- ctx.effect(() => controlRuntime2.register(connection), "dsh-remote disabled control");
25969
+ ctx.effect(() => controlRuntime2.register(connection, webServer), "dsh-remote disabled control");
25451
25970
  }
25452
25971
  return;
25453
25972
  }
@@ -25506,7 +26025,7 @@ async function activate(ctx, input2, tuiBinding) {
25506
26025
  if (tuiBinding !== void 0) tuiBinding.target = tuiTarget;
25507
26026
  await disableLegacyLoaderEntries(ctx, logger);
25508
26027
  await ctx.effect(async () => {
25509
- const disposeControl = controlRuntime?.register(connection);
26028
+ const disposeControl = controlRuntime?.register(connection, webServer);
25510
26029
  try {
25511
26030
  await runtime.start();
25512
26031
  if (clientRuntime !== void 0) {