@codexhost/cli-darwin-x64 0.12.2 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +1 -1
  2. package/THIRD_PARTY_NOTICES.txt +8 -0
  3. package/app/codexhost-distribution.json +1 -1
  4. package/app/console-server.mjs +232 -21
  5. package/app/console-web.js +4924 -935
  6. package/app/desktop-controller.mjs +252 -41
  7. package/app/host-runtime.mjs +5312 -1442
  8. package/app/plugins/antigravity/manifest.json +18 -1
  9. package/app/plugins/antigravity/plugin.mjs +275 -41
  10. package/app/plugins/claude-code/manifest.json +28 -0
  11. package/app/plugins/claude-code/plugin.mjs +1045 -355
  12. package/app/plugins/codebuddy/manifest.json +17 -0
  13. package/app/plugins/codebuddy/plugin.mjs +5930 -5357
  14. package/app/plugins/codex-usage/manifest.json +9 -0
  15. package/app/plugins/codex-usage/plugin.mjs +16703 -0
  16. package/app/plugins/cursor-cli/manifest.json +17 -0
  17. package/app/plugins/cursor-cli/plugin.mjs +350 -76
  18. package/app/plugins/deepseek-harness/assets/icon.svg +1 -0
  19. package/app/plugins/deepseek-harness/manifest.json +35 -2
  20. package/app/plugins/deepseek-harness/plugin.mjs +797 -241
  21. package/app/plugins/enabled.json +2 -1
  22. package/app/plugins/grok/manifest.json +21 -1
  23. package/app/plugins/grok/plugin.mjs +883 -258
  24. package/app/plugins/hermes/assets/icon.png +0 -0
  25. package/app/plugins/hermes/manifest.json +30 -2
  26. package/app/plugins/hermes/plugin.mjs +277 -32
  27. package/app/plugins/kimi-code/assets/icon.svg +5 -0
  28. package/app/plugins/kimi-code/manifest.json +25 -2
  29. package/app/plugins/kimi-code/plugin.mjs +554 -35
  30. package/app/plugins/kiro-cli/assets/kiro-agent.svg +11 -0
  31. package/app/plugins/kiro-cli/manifest.json +18 -1
  32. package/app/plugins/kiro-cli/plugin.mjs +283 -21
  33. package/app/plugins/omp/manifest.json +21 -1
  34. package/app/plugins/omp/plugin.mjs +2737 -1956
  35. package/app/plugins/opencode/manifest.json +18 -1
  36. package/app/plugins/opencode/plugin.mjs +693 -146
  37. package/app/plugins/pi/manifest.json +32 -0
  38. package/app/plugins/pi/plugin.mjs +2809 -2254
  39. package/app/plugins/qoder/manifest.json +18 -1
  40. package/app/plugins/qoder/plugin.mjs +584 -80
  41. package/app/plugins/qoder-cn/manifest.json +18 -1
  42. package/app/plugins/qoder-cn/plugin.mjs +584 -80
  43. package/app/plugins/workbuddy/manifest.json +18 -0
  44. package/app/plugins/workbuddy/plugin.mjs +6316 -5745
  45. package/app/plugins/zcode/manifest.json +19 -1
  46. package/app/plugins/zcode/plugin.mjs +1065 -259
  47. package/app/renderer-extension.js +1485 -1570
  48. package/bin/codexhost +0 -0
  49. package/libexec/codexhost-shim +0 -0
  50. package/libexec/codexhost-updater +0 -0
  51. package/licenses/Cordis-LICENSE.txt +21 -0
  52. package/licenses/Cosmokit-LICENSE.txt +21 -0
  53. package/package.json +1 -1
  54. package/app/plugins/kiro-cli/assets/icon.svg +0 -5
@@ -396,7 +396,7 @@ async function npmInstallation(command, packages, environment) {
396
396
  const npm = resolveHarnessExecutable({ id: "npm", command: "npm", installRoots: { posix: [], windows: [] } }, { environment: env });
397
397
  let globalInstall = modules === globalRoot;
398
398
  if (process.platform === "win32") {
399
- const project = (await Promise.all(["package.json", "package-lock.json", "npm-shrinkwrap.json"].map((file2) => readFile(path4.join(prefix, file2), "utf8").then(() => true, (error51) => error51.code !== "ENOENT")))).some(Boolean);
399
+ const project2 = (await Promise.all(["package.json", "package-lock.json", "npm-shrinkwrap.json"].map((file2) => readFile(path4.join(prefix, file2), "utf8").then(() => true, (error51) => error51.code !== "ENOENT")))).some(Boolean);
400
400
  const bins = typeof metadata.bin === "string" ? { [name.split("/").at(-1) ?? name]: metadata.bin } : metadata.bin ?? {};
401
401
  const launchers = await Promise.all(Object.entries(bins).map(async ([bin, entry]) => {
402
402
  if (path4.basename(bin) !== bin || entry.includes(".."))
@@ -407,7 +407,7 @@ async function npmInstallation(command, packages, environment) {
407
407
  const shim = await readFile(path4.join(prefix, `${bin}.cmd`), "utf8").catch(() => "");
408
408
  return referencesNpmBin(shim, name, entry);
409
409
  }));
410
- globalInstall = globalInstall && !project && launchers.some(Boolean);
410
+ globalInstall = globalInstall && !project2 && launchers.some(Boolean);
411
411
  }
412
412
  const canUpdate = globalInstall && !!npm;
413
413
  return {
@@ -487,10 +487,50 @@ function createHarnessInstaller(environment, source) {
487
487
  };
488
488
  }
489
489
 
490
- // dist/opencode-adapter.js
491
- import { randomUUID } from "node:crypto";
492
- import fs4 from "node:fs";
493
- import path8 from "node:path";
490
+ // dist/usage-statistics.js
491
+ import os2 from "node:os";
492
+ import path5 from "node:path";
493
+ import { lstat } from "node:fs/promises";
494
+
495
+ // ../../harness-adapter/dist/usage-statistics.js
496
+ var MAX_SESSION_ID_LENGTH = 512;
497
+ var MAX_CWD_LENGTH = 4096;
498
+ function sessionIdOk(value) {
499
+ return typeof value === "string" && value.length > 0 && value.length <= MAX_SESSION_ID_LENGTH;
500
+ }
501
+ function cwdOk(value) {
502
+ return typeof value === "string" && value.length > 0 && value.length <= MAX_CWD_LENGTH && !value.includes("\0") && (value.startsWith("/") || /^[A-Za-z]:[\\/]/u.test(value) || value.startsWith("\\\\"));
503
+ }
504
+ function withUsageSession(entry, session) {
505
+ const sessionId = sessionIdOk(session.sessionId) ? session.sessionId : void 0;
506
+ const cwd = cwdOk(session.cwd) ? session.cwd : void 0;
507
+ if (sessionId === void 0 && cwd === void 0)
508
+ return entry;
509
+ return {
510
+ ...entry,
511
+ ...sessionId !== void 0 ? { sessionId } : {},
512
+ ...cwd !== void 0 ? { cwd } : {}
513
+ };
514
+ }
515
+ function usageEntryFromRequest(request, occurredAtMs) {
516
+ if (!Number.isSafeInteger(occurredAtMs) || occurredAtMs <= 0)
517
+ return null;
518
+ return {
519
+ id: request.requestId,
520
+ occurredAtMs,
521
+ ...request.model !== void 0 ? { model: request.model } : {},
522
+ inputTokens: request.inputTokens,
523
+ ...request.cachedInputTokens !== void 0 ? { cachedInputTokens: request.cachedInputTokens } : {},
524
+ ...request.cacheWriteInputTokens !== void 0 ? { cacheWriteInputTokens: request.cacheWriteInputTokens } : {},
525
+ ...request.cacheWrite1hInputTokens !== void 0 ? { cacheWrite1hInputTokens: request.cacheWrite1hInputTokens } : {},
526
+ outputTokens: request.outputTokens,
527
+ ...request.reasoningOutputTokens !== void 0 ? { reasoningOutputTokens: request.reasoningOutputTokens } : {}
528
+ };
529
+ }
530
+ function nativeTimeMs(value) {
531
+ const time3 = typeof value === "number" ? value : typeof value === "string" ? Date.parse(value) : Number.NaN;
532
+ return Number.isFinite(time3) && time3 > 0 ? Math.floor(time3) : null;
533
+ }
494
534
 
495
535
  // ../../../node_modules/zod/v4/classic/external.js
496
536
  var external_exports = {};
@@ -1258,10 +1298,10 @@ function mergeDefs(...defs) {
1258
1298
  function cloneDef(schema) {
1259
1299
  return mergeDefs(schema._zod.def);
1260
1300
  }
1261
- function getElementAtPath(obj, path13) {
1262
- if (!path13)
1301
+ function getElementAtPath(obj, path14) {
1302
+ if (!path14)
1263
1303
  return obj;
1264
- return path13.reduce((acc, key) => acc?.[key], obj);
1304
+ return path14.reduce((acc, key) => acc?.[key], obj);
1265
1305
  }
1266
1306
  function promiseAllObject(promisesObj) {
1267
1307
  const keys = Object.keys(promisesObj);
@@ -1670,11 +1710,11 @@ function explicitlyAborted(x, startIndex = 0) {
1670
1710
  }
1671
1711
  return false;
1672
1712
  }
1673
- function prefixIssues(path13, issues) {
1713
+ function prefixIssues(path14, issues) {
1674
1714
  return issues.map((iss) => {
1675
1715
  var _a3;
1676
1716
  (_a3 = iss).path ?? (_a3.path = []);
1677
- iss.path.unshift(path13);
1717
+ iss.path.unshift(path14);
1678
1718
  return iss;
1679
1719
  });
1680
1720
  }
@@ -1821,16 +1861,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
1821
1861
  }
1822
1862
  function formatError(error51, mapper = (issue2) => issue2.message) {
1823
1863
  const fieldErrors = { _errors: [] };
1824
- const processError = (error52, path13 = []) => {
1864
+ const processError = (error52, path14 = []) => {
1825
1865
  for (const issue2 of error52.issues) {
1826
1866
  if (issue2.code === "invalid_union" && issue2.errors.length) {
1827
- issue2.errors.map((issues) => processError({ issues }, [...path13, ...issue2.path]));
1867
+ issue2.errors.map((issues) => processError({ issues }, [...path14, ...issue2.path]));
1828
1868
  } else if (issue2.code === "invalid_key") {
1829
- processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
1869
+ processError({ issues: issue2.issues }, [...path14, ...issue2.path]);
1830
1870
  } else if (issue2.code === "invalid_element") {
1831
- processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
1871
+ processError({ issues: issue2.issues }, [...path14, ...issue2.path]);
1832
1872
  } else {
1833
- const fullpath = [...path13, ...issue2.path];
1873
+ const fullpath = [...path14, ...issue2.path];
1834
1874
  if (fullpath.length === 0) {
1835
1875
  fieldErrors._errors.push(mapper(issue2));
1836
1876
  } else {
@@ -1857,17 +1897,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
1857
1897
  }
1858
1898
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
1859
1899
  const result = { errors: [] };
1860
- const processError = (error52, path13 = []) => {
1900
+ const processError = (error52, path14 = []) => {
1861
1901
  var _a3, _b;
1862
1902
  for (const issue2 of error52.issues) {
1863
1903
  if (issue2.code === "invalid_union" && issue2.errors.length) {
1864
- issue2.errors.map((issues) => processError({ issues }, [...path13, ...issue2.path]));
1904
+ issue2.errors.map((issues) => processError({ issues }, [...path14, ...issue2.path]));
1865
1905
  } else if (issue2.code === "invalid_key") {
1866
- processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
1906
+ processError({ issues: issue2.issues }, [...path14, ...issue2.path]);
1867
1907
  } else if (issue2.code === "invalid_element") {
1868
- processError({ issues: issue2.issues }, [...path13, ...issue2.path]);
1908
+ processError({ issues: issue2.issues }, [...path14, ...issue2.path]);
1869
1909
  } else {
1870
- const fullpath = [...path13, ...issue2.path];
1910
+ const fullpath = [...path14, ...issue2.path];
1871
1911
  if (fullpath.length === 0) {
1872
1912
  result.errors.push(mapper(issue2));
1873
1913
  continue;
@@ -1899,8 +1939,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
1899
1939
  }
1900
1940
  function toDotPath(_path) {
1901
1941
  const segs = [];
1902
- const path13 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1903
- for (const seg of path13) {
1942
+ const path14 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1943
+ for (const seg of path14) {
1904
1944
  if (typeof seg === "number")
1905
1945
  segs.push(`[${seg}]`);
1906
1946
  else if (typeof seg === "symbol")
@@ -5128,8 +5168,8 @@ function az_default() {
5128
5168
  }
5129
5169
 
5130
5170
  // ../../../node_modules/zod/v4/locales/be.js
5131
- function getBelarusianPlural(count, one, few, many) {
5132
- const absCount = Math.abs(count);
5171
+ function getBelarusianPlural(count2, one, few, many) {
5172
+ const absCount = Math.abs(count2);
5133
5173
  const lastDigit = absCount % 10;
5134
5174
  const lastTwoDigits = absCount % 100;
5135
5175
  if (lastTwoDigits >= 11 && lastTwoDigits <= 19) {
@@ -7207,8 +7247,8 @@ function hu_default() {
7207
7247
  }
7208
7248
 
7209
7249
  // ../../../node_modules/zod/v4/locales/hy.js
7210
- function getArmenianPlural(count, one, many) {
7211
- return Math.abs(count) === 1 ? one : many;
7250
+ function getArmenianPlural(count2, one, many) {
7251
+ return Math.abs(count2) === 1 ? one : many;
7212
7252
  }
7213
7253
  function withDefiniteArticle(word) {
7214
7254
  if (!word)
@@ -9336,8 +9376,8 @@ function ro_default() {
9336
9376
  }
9337
9377
 
9338
9378
  // ../../../node_modules/zod/v4/locales/ru.js
9339
- function getRussianPlural(count, one, few, many) {
9340
- const absCount = Math.abs(count);
9379
+ function getRussianPlural(count2, one, few, many) {
9380
+ const absCount = Math.abs(count2);
9341
9381
  const lastDigit = absCount % 10;
9342
9382
  const lastTwoDigits = absCount % 100;
9343
9383
  if (lastTwoDigits >= 11 && lastTwoDigits <= 19) {
@@ -14592,13 +14632,13 @@ function resolveRef(ref, ctx) {
14592
14632
  if (!ref.startsWith("#")) {
14593
14633
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
14594
14634
  }
14595
- const path13 = ref.slice(1).split("/").filter(Boolean);
14596
- if (path13.length === 0) {
14635
+ const path14 = ref.slice(1).split("/").filter(Boolean);
14636
+ if (path14.length === 0) {
14597
14637
  return ctx.rootSchema;
14598
14638
  }
14599
14639
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
14600
- if (path13[0] === defsKey) {
14601
- const key = path13[1];
14640
+ if (path14[0] === defsKey) {
14641
+ const key = path14[1];
14602
14642
  if (!key || !ctx.defs[key]) {
14603
14643
  throw new Error(`Reference not found: ${ref}`);
14604
14644
  }
@@ -15006,6 +15046,15 @@ function date4(params) {
15006
15046
  // ../../../node_modules/zod/v4/classic/external.js
15007
15047
  config(en_default());
15008
15048
 
15049
+ // ../../shared-contracts/dist/delegation-read.js
15050
+ var REMOTE_THREAD_REPLY_MAX_BYTES = 16 * 1024 * 1024;
15051
+ var delegationReadParamsSchema = external_exports.strictObject({
15052
+ threadId: external_exports.string().min(1).max(1024),
15053
+ view: external_exports.enum(["result", "messages"]),
15054
+ cursor: external_exports.string().min(1).max(8192).optional(),
15055
+ limit: external_exports.number().int().min(1).max(100).optional()
15056
+ });
15057
+
15009
15058
  // ../../shared-contracts/dist/credential-imports.js
15010
15059
  var credentialSourceSchema = external_exports.object({
15011
15060
  id: external_exports.string().min(1).max(256),
@@ -15076,6 +15125,153 @@ var harnessDisplaySetSchema = external_exports.strictObject({
15076
15125
  initializeOnly: external_exports.boolean().optional()
15077
15126
  });
15078
15127
 
15128
+ // ../../shared-contracts/dist/model-price-overrides.js
15129
+ var usdPerMillionTokens = external_exports.number().finite().nonnegative();
15130
+ var modelPriceOverrideSchema = external_exports.strictObject({
15131
+ input: usdPerMillionTokens,
15132
+ output: usdPerMillionTokens,
15133
+ cacheRead: usdPerMillionTokens.optional(),
15134
+ cacheWrite: usdPerMillionTokens.optional(),
15135
+ cacheWrite1h: usdPerMillionTokens.optional()
15136
+ });
15137
+ var modelPriceKeySchema = external_exports.string().max(512).refine((key) => key.trim() === key && key.length > 0, "Model ID is required");
15138
+ var modelPriceOverridesSchema = external_exports.strictObject({
15139
+ /** Absolute path of the Host's `pricing.json`. */
15140
+ path: external_exports.string(),
15141
+ entries: external_exports.array(external_exports.strictObject({ key: external_exports.string(), price: modelPriceOverrideSchema })),
15142
+ /** Why the existing file is unusable; the Host then ignores it and refuses to overwrite it. */
15143
+ error: external_exports.string().nullable()
15144
+ });
15145
+ var modelPriceOverridesGetSchema = external_exports.strictObject({});
15146
+ var modelPriceOverridesSetSchema = external_exports.strictObject({
15147
+ key: modelPriceKeySchema,
15148
+ price: modelPriceOverrideSchema.nullable(),
15149
+ previousKey: modelPriceKeySchema.optional()
15150
+ });
15151
+ var modelPriceDefaultParamsSchema = external_exports.strictObject({
15152
+ model: modelPriceKeySchema
15153
+ });
15154
+ var modelPriceSuggestionSchema = external_exports.strictObject({
15155
+ /** Verified from catalog canonical links, not inferred from names or equal prices. */
15156
+ official: external_exports.boolean().optional(),
15157
+ canonicalModelId: external_exports.string().min(1).optional(),
15158
+ provider: external_exports.string().min(1).max(512),
15159
+ model: external_exports.string().min(1).max(512),
15160
+ price: modelPriceOverrideSchema
15161
+ });
15162
+ var modelPriceDefaultResultSchema = external_exports.strictObject({
15163
+ price: modelPriceOverrideSchema.nullable(),
15164
+ /** Local catalog suggestions only; never used automatically for pricing. */
15165
+ suggestions: external_exports.array(modelPriceSuggestionSchema).max(6).optional()
15166
+ });
15167
+
15168
+ // ../../shared-contracts/dist/usage-statistics.js
15169
+ var USAGE_STATISTICS_RANGES = ["today", "7d", "30d", "90d", "all"];
15170
+ var count = external_exports.number().int().min(0).max(Number.MAX_SAFE_INTEGER);
15171
+ var localDate = external_exports.string().regex(/^\d{4}-\d{2}-\d{2}$/u);
15172
+ var harness = external_exports.string().min(1).max(128);
15173
+ var model = external_exports.string().min(1).max(512);
15174
+ var project = external_exports.string().min(1).max(4096);
15175
+ var usageStatisticsParamsSchema = external_exports.strictObject({
15176
+ range: external_exports.enum(USAGE_STATISTICS_RANGES),
15177
+ harness: harness.optional(),
15178
+ model: model.nullable().optional(),
15179
+ project: project.nullable().optional(),
15180
+ /** One local date inside the range. */
15181
+ date: localDate.optional()
15182
+ });
15183
+ var usageStatisticsTotalsSchema = external_exports.strictObject({
15184
+ requests: count,
15185
+ inputTokens: count,
15186
+ cachedInputTokens: count,
15187
+ cacheWriteInputTokens: count,
15188
+ cacheKnownInputTokens: count,
15189
+ outputTokens: count,
15190
+ reasoningOutputTokens: count,
15191
+ /** USD at the public price, summed over the priced requests only. */
15192
+ costUsd: external_exports.number().finite().min(0),
15193
+ /** Requests without a price (or the cache data the price needs); not in `costUsd`. */
15194
+ unpricedRequests: count,
15195
+ /**
15196
+ * Requests whose storage gave no token counts: counted as requests, with neither tokens nor
15197
+ * cost, and not as unpriced.
15198
+ */
15199
+ unmeteredRequests: count
15200
+ });
15201
+ var totals = usageStatisticsTotalsSchema.shape;
15202
+ var usageStatisticsSessionSchema = external_exports.strictObject({
15203
+ harness,
15204
+ sessionId: external_exports.string().min(1).max(512),
15205
+ project: project.nullable(),
15206
+ /** Models the session used, most requests first. */
15207
+ models: external_exports.array(model).max(16),
15208
+ firstAtMs: count,
15209
+ lastAtMs: count,
15210
+ ...totals
15211
+ });
15212
+ var usageStatisticsResultSchema = external_exports.strictObject({
15213
+ range: external_exports.enum(USAGE_STATISTICS_RANGES),
15214
+ /** First local date of the range; null for all time. */
15215
+ from: localDate.nullable(),
15216
+ to: localDate,
15217
+ /** The filters these figures apply, echoed so a late answer to older filters is recognised. */
15218
+ filters: external_exports.strictObject({
15219
+ harness: harness.nullable(),
15220
+ model: model.nullable(),
15221
+ unknownModel: external_exports.boolean(),
15222
+ project: project.nullable(),
15223
+ unknownProject: external_exports.boolean(),
15224
+ date: localDate.nullable()
15225
+ }),
15226
+ /** Reading of native storage: incomplete while the first read, or a refresh, is under way. */
15227
+ reading: external_exports.strictObject({ complete: external_exports.boolean(), sources: count, read: count }),
15228
+ /** Harnesses whose storage could not be read; their part is missing, the rest is complete. */
15229
+ failures: external_exports.array(external_exports.strictObject({ harness, message: external_exports.string().max(2048) })).max(256),
15230
+ /** Every value seen in the range, ignoring the filters, to choose filters from. */
15231
+ options: external_exports.strictObject({
15232
+ harnesses: external_exports.array(harness).max(256),
15233
+ models: external_exports.array(model.nullable()).max(4096),
15234
+ projects: external_exports.array(project.nullable()).max(4096)
15235
+ }),
15236
+ /** Current display metadata, scoped by Harness. Never a pricing or filter identity.
15237
+ * Optional for older Hosts; missing/conflicting labels fall back to the native model ID.
15238
+ */
15239
+ modelLabels: external_exports.array(external_exports.strictObject({ harness, model, label: model })).max(4096).optional(),
15240
+ /** Native credits, all filters applied, never combined across Harnesses or treated as USD.
15241
+ * Only groups with at least one reported value appear; reportedRequests exposes partial data.
15242
+ */
15243
+ credits: external_exports.array(external_exports.strictObject({
15244
+ harness,
15245
+ model: model.nullable(),
15246
+ credits: external_exports.number().finite().min(0),
15247
+ reportedRequests: count,
15248
+ requests: count
15249
+ })).max(4096).optional(),
15250
+ /** All filters applied. */
15251
+ totals: usageStatisticsTotalsSchema,
15252
+ /** Each date and Harness of the range: every filter except the day. */
15253
+ daily: external_exports.array(external_exports.strictObject({ date: localDate, harness, ...totals })).max(2e5),
15254
+ /** Local weekday (0 = Sunday) and hour, all filters applied. */
15255
+ hourly: external_exports.array(external_exports.strictObject({
15256
+ weekday: external_exports.number().int().min(0).max(6),
15257
+ hour: external_exports.number().int().min(0).max(23),
15258
+ ...totals
15259
+ })).max(168),
15260
+ byHarness: external_exports.array(external_exports.strictObject({ harness, ...totals })).max(256),
15261
+ byModel: external_exports.array(external_exports.strictObject({
15262
+ model: model.nullable(),
15263
+ ...totals,
15264
+ /** Requests priced by what the Harness recorded they cost, not by a price list. */
15265
+ harnessPricedRequests: count
15266
+ })).max(4096),
15267
+ byProject: external_exports.array(external_exports.strictObject({ project: project.nullable(), ...totals })).max(4096),
15268
+ /**
15269
+ * The sessions that spent the most, by cost and by tokens without cache, all filters applied;
15270
+ * requests without a native session are not listed here but count everywhere else.
15271
+ */
15272
+ sessions: external_exports.array(usageStatisticsSessionSchema).max(100)
15273
+ });
15274
+
15079
15275
  // ../../shared-contracts/dist/ids.js
15080
15276
  var opaqueIdSchema = external_exports.string().refine((value) => value.trim().length > 0, {
15081
15277
  message: "Identifier must not be empty or whitespace"
@@ -15123,6 +15319,10 @@ var CONSOLE_HOST_METHODS = Object.freeze([
15123
15319
  "codexhost/account/list",
15124
15320
  "codexhost/account/refresh",
15125
15321
  "codexhost/account/usage/inspect",
15322
+ "codexhost/usage/model-prices/get",
15323
+ "codexhost/usage/model-prices/set",
15324
+ "codexhost/usage/model-prices/default",
15325
+ "codexhost/usage/statistics/get",
15126
15326
  "codexhost/update/check",
15127
15327
  "codexhost/update/start",
15128
15328
  "codexhost/update/status"
@@ -15187,6 +15387,7 @@ var threadUsageSnapshotSchema = external_exports.object({
15187
15387
  cacheWriteInputTokens: nonNegativeSafeIntegerSchema.optional(),
15188
15388
  outputTokens: nonNegativeSafeIntegerSchema.optional(),
15189
15389
  outputTokensPerSecond: finiteNonNegativeNumberSchema.optional(),
15390
+ apiOutputTokensPerSecond: finiteNonNegativeNumberSchema.optional(),
15190
15391
  reasoningOutputTokens: nonNegativeSafeIntegerSchema.optional(),
15191
15392
  totalTokens: nonNegativeSafeIntegerSchema.optional(),
15192
15393
  totalCostUsd: finiteNonNegativeNumberSchema.optional(),
@@ -15198,7 +15399,11 @@ var threadUsageSnapshotSchema = external_exports.object({
15198
15399
  planFiveHourUsedPercent: cacheHitRatePercentSchema.optional(),
15199
15400
  planFiveHourResetsAtUnix: nonNegativeSafeIntegerSchema.optional(),
15200
15401
  planSevenDayUsedPercent: cacheHitRatePercentSchema.optional(),
15201
- planSevenDayResetsAtUnix: nonNegativeSafeIntegerSchema.optional()
15402
+ planSevenDayResetsAtUnix: nonNegativeSafeIntegerSchema.optional(),
15403
+ sessionCacheHitRatePercent: cacheHitRatePercentSchema.optional(),
15404
+ timeToFirstOutputMs: nonNegativeSafeIntegerSchema.optional(),
15405
+ costSource: external_exports.enum(["publicPrice", "native"]).optional(),
15406
+ unpricedModels: external_exports.array(external_exports.string().min(1)).min(1).optional()
15202
15407
  }).strict().superRefine((usage, context) => {
15203
15408
  if (Object.keys(usage).length === 0) {
15204
15409
  context.addIssue({ code: "custom", message: "Thread Usage must contain a reliable field" });
@@ -15219,6 +15424,20 @@ var threadUsageSnapshotSchema = external_exports.object({
15219
15424
  path: ["contextWindowTokens"]
15220
15425
  });
15221
15426
  }
15427
+ if (usage.costSource !== void 0 && usage.totalCostUsd === void 0) {
15428
+ context.addIssue({
15429
+ code: "custom",
15430
+ message: "Thread Usage costSource must be provided with totalCostUsd",
15431
+ path: ["costSource"]
15432
+ });
15433
+ }
15434
+ if (usage.unpricedModels !== void 0 && usage.costSource !== "publicPrice") {
15435
+ context.addIssue({
15436
+ code: "custom",
15437
+ message: "Thread Usage unpricedModels must be provided with a publicPrice cost",
15438
+ path: ["unpricedModels"]
15439
+ });
15440
+ }
15222
15441
  if (usage.planFiveHourResetsAtUnix !== void 0 && usage.planFiveHourUsedPercent === void 0) {
15223
15442
  context.addIssue({
15224
15443
  code: "custom",
@@ -15473,27 +15692,27 @@ var harnessModelCatalogSchema = external_exports.object({
15473
15692
  }).strict().superRefine((catalog, context) => {
15474
15693
  const refs = /* @__PURE__ */ new Set();
15475
15694
  const thinkingIds = new Set(catalog.thinkingOptions.map(({ id }) => id));
15476
- for (const [index, model] of catalog.models.entries()) {
15477
- if (refs.has(model.ref.id)) {
15695
+ for (const [index, model2] of catalog.models.entries()) {
15696
+ if (refs.has(model2.ref.id)) {
15478
15697
  context.addIssue({
15479
15698
  code: "custom",
15480
15699
  message: "Model Catalog refs must be unique",
15481
15700
  path: ["models", index, "ref", "id"]
15482
15701
  });
15483
15702
  }
15484
- refs.add(model.ref.id);
15485
- if (model.fastModel) {
15486
- if (refs.has(model.fastModel.id) || catalog.models.some((entry) => entry.ref.id === model.fastModel?.id)) {
15703
+ refs.add(model2.ref.id);
15704
+ if (model2.fastModel) {
15705
+ if (refs.has(model2.fastModel.id) || catalog.models.some((entry) => entry.ref.id === model2.fastModel?.id)) {
15487
15706
  context.addIssue({
15488
15707
  code: "custom",
15489
15708
  message: "Fast Model refs must be distinct and unique",
15490
15709
  path: ["models", index, "fastModel"]
15491
15710
  });
15492
15711
  }
15493
- refs.add(model.fastModel.id);
15712
+ refs.add(model2.fastModel.id);
15494
15713
  }
15495
15714
  const supportedThinkingIds = /* @__PURE__ */ new Set();
15496
- for (const [optionIndex, optionId] of (model.supportedThinkingOptionIds ?? []).entries()) {
15715
+ for (const [optionIndex, optionId] of (model2.supportedThinkingOptionIds ?? []).entries()) {
15497
15716
  if (supportedThinkingIds.has(optionId)) {
15498
15717
  context.addIssue({
15499
15718
  code: "custom",
@@ -15687,13 +15906,40 @@ var HARNESS_PLUGIN_LIMIT = 128;
15687
15906
  var harnessPluginIdSchema = external_exports.string().min(1).max(128).regex(/^[a-z][a-z0-9]*(?:[._-][a-z0-9]+)*$/u).refine((id) => id !== "codex", "The official Codex identity is reserved").pipe(harnessIdSchema);
15688
15907
  var relativeResourceSchema = external_exports.string().min(1).max(512).refine((value) => !/[\\\u0000:#?]/u.test(value) && !value.startsWith("/") && !value.split("/").some((part) => part === ".." || part === ""), "Plugin resources must be relative paths inside the plugin");
15689
15908
  var documentationUrlSchema = external_exports.url().refine((value) => /^https:\/\/[^/?#@]+(?:[/?#]|$)/iu.test(value), "Plugin documentation links must be credential-free HTTPS URLs");
15909
+ var localizedTextSchema = external_exports.object({ en: external_exports.string().max(4096), "zh-CN": external_exports.string().max(4096).optional() }).strict();
15910
+ var harnessInstallationGuideSchema = external_exports.object({
15911
+ commands: external_exports.array(external_exports.object({ terminal: external_exports.string().max(256), command: external_exports.string().max(4096) }).strict()).max(8),
15912
+ before: localizedTextSchema.optional(),
15913
+ after: localizedTextSchema.optional(),
15914
+ downloads: external_exports.array(external_exports.object({ label: external_exports.string().max(128), url: documentationUrlSchema }).strict()).max(8).optional()
15915
+ }).strict();
15690
15916
  var pluginPresentationShape = {
15691
15917
  id: harnessPluginIdSchema,
15692
15918
  name: external_exports.string().trim().min(1).max(128),
15693
15919
  version: external_exports.string().min(1).max(128),
15920
+ /** Capability-only plugin; omitted for existing session-capable plugins. */
15921
+ kind: external_exports.literal("usage").optional(),
15922
+ /** Original image styling or bounded vector paths; never arbitrary CSS/SVG markup. */
15923
+ iconStyle: external_exports.object({
15924
+ vector: external_exports.object({
15925
+ viewBox: external_exports.string().max(128).regex(/^-?\d+(?:\.\d+)?(?: +-?\d+(?:\.\d+)?){3}$/u),
15926
+ color: external_exports.string().regex(/^(?:currentColor|#[a-f0-9]{6})$/iu),
15927
+ paths: external_exports.array(external_exports.object({
15928
+ d: external_exports.string().min(1).max(32768).regex(/^[MmLlHhVvCcSsQqTtAaZz\d.,+eE\s-]+$/u),
15929
+ fillRule: external_exports.enum(["evenodd", "nonzero"]).optional(),
15930
+ fill: external_exports.string().regex(/^(?:currentColor|#[a-f0-9]{6})$/iu).optional()
15931
+ }).strict()).min(1).max(32)
15932
+ }).strict().optional(),
15933
+ background: external_exports.string().regex(/^#[a-f0-9]{6}$/iu).optional(),
15934
+ borderRadius: external_exports.number().min(0).max(50).optional(),
15935
+ paddingRatio: external_exports.number().min(0).max(0.25).optional()
15936
+ }).strict().optional(),
15937
+ installation: harnessInstallationGuideSchema.optional(),
15938
+ notice: localizedTextSchema.optional(),
15694
15939
  /** The factory accepts a persisted local entrypoint through its construction context. */
15695
15940
  launchCommand: external_exports.literal(true).optional(),
15696
15941
  links: external_exports.object({
15942
+ website: documentationUrlSchema.optional(),
15697
15943
  documentation: documentationUrlSchema.optional(),
15698
15944
  installation: documentationUrlSchema.optional()
15699
15945
  }).strict().optional()
@@ -16112,6 +16358,11 @@ var codexSshDraftSchema = external_exports.strictObject({
16112
16358
  });
16113
16359
  var remoteConnectionsRequestSchema = external_exports.discriminatedUnion("action", [
16114
16360
  external_exports.strictObject({ action: external_exports.literal("list") }),
16361
+ external_exports.strictObject({
16362
+ action: external_exports.literal("read-thread"),
16363
+ hostId: hostId.refine((id) => id !== "local"),
16364
+ input: delegationReadParamsSchema
16365
+ }),
16115
16366
  external_exports.strictObject({
16116
16367
  action: external_exports.literal("save"),
16117
16368
  draft: codexSshDraftSchema,
@@ -16250,10 +16501,12 @@ var tokenFields = [
16250
16501
  ];
16251
16502
  var safeIntegerFields = [
16252
16503
  "planFiveHourResetsAtUnix",
16253
- "planSevenDayResetsAtUnix"
16504
+ "planSevenDayResetsAtUnix",
16505
+ "timeToFirstOutputMs"
16254
16506
  ];
16255
16507
  var percentFields = [
16256
16508
  "cacheHitRatePercent",
16509
+ "sessionCacheHitRatePercent",
16257
16510
  "planFiveHourUsedPercent",
16258
16511
  "planSevenDayUsedPercent"
16259
16512
  ];
@@ -16261,10 +16514,14 @@ var usageFields = /* @__PURE__ */ new Set([
16261
16514
  ...tokenFields,
16262
16515
  ...safeIntegerFields,
16263
16516
  ...percentFields,
16517
+ "sessionCacheUsage",
16264
16518
  "totalCostUsd",
16265
16519
  "totalCredits",
16266
16520
  "contextUsagePercent",
16267
- "outputTokensPerSecond"
16521
+ "outputTokensPerSecond",
16522
+ "apiOutputTokensPerSecond",
16523
+ "costSource",
16524
+ "unpricedModels"
16268
16525
  ]);
16269
16526
  function isRecord(value) {
16270
16527
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -16280,7 +16537,11 @@ function parseHostUsage(value) {
16280
16537
  throw new Error(`Harness Usage contains unknown field '${key}'`);
16281
16538
  }
16282
16539
  }
16283
- for (const field of ["totalCredits", "contextUsagePercent"]) {
16540
+ for (const field of [
16541
+ "totalCredits",
16542
+ "contextUsagePercent",
16543
+ "apiOutputTokensPerSecond"
16544
+ ]) {
16284
16545
  const candidate2 = value[field];
16285
16546
  if (candidate2 !== void 0 && (typeof candidate2 !== "number" || !Number.isFinite(candidate2) || candidate2 < 0)) {
16286
16547
  throw new Error(`Harness Usage '${field}' must be a finite non-negative number`);
@@ -16310,6 +16571,12 @@ function parseHostUsage(value) {
16310
16571
  throw new Error(`Harness Usage '${field}' must be between 0 and 100`);
16311
16572
  }
16312
16573
  }
16574
+ if (value.sessionCacheUsage !== void 0) {
16575
+ const totals2 = value.sessionCacheUsage;
16576
+ if (!isRecord(totals2) || Object.keys(totals2).some((key) => key !== "inputTokens" && key !== "cachedInputTokens") || typeof totals2.inputTokens !== "number" || !Number.isSafeInteger(totals2.inputTokens) || totals2.inputTokens < 0 || typeof totals2.cachedInputTokens !== "number" || !Number.isSafeInteger(totals2.cachedInputTokens) || totals2.cachedInputTokens < 0 || totals2.cachedInputTokens > totals2.inputTokens) {
16577
+ throw new Error("Harness Usage 'sessionCacheUsage' must contain complete bounded token totals");
16578
+ }
16579
+ }
16313
16580
  const hasContextUsed = value.contextUsedTokens !== void 0;
16314
16581
  const hasContextWindow = value.contextWindowTokens !== void 0;
16315
16582
  if (hasContextUsed !== hasContextWindow) {
@@ -16324,8 +16591,217 @@ function parseHostUsage(value) {
16324
16591
  if (value.planSevenDayResetsAtUnix !== void 0 && value.planSevenDayUsedPercent === void 0) {
16325
16592
  throw new Error("Harness Usage 'planSevenDayResetsAtUnix' must be provided with 'planSevenDayUsedPercent'");
16326
16593
  }
16594
+ if (value.costSource !== void 0) {
16595
+ if (value.costSource !== "publicPrice" && value.costSource !== "native") {
16596
+ throw new Error("Harness Usage 'costSource' must be 'publicPrice' or 'native'");
16597
+ }
16598
+ if (value.totalCostUsd === void 0) {
16599
+ throw new Error("Harness Usage 'costSource' must be provided with 'totalCostUsd'");
16600
+ }
16601
+ }
16602
+ if (value.unpricedModels !== void 0) {
16603
+ const models = value.unpricedModels;
16604
+ if (!Array.isArray(models) || models.length === 0 || !models.every((model2) => typeof model2 === "string" && model2.length > 0)) {
16605
+ throw new Error("Harness Usage 'unpricedModels' must be a non-empty list of Model IDs");
16606
+ }
16607
+ if (value.costSource !== "publicPrice") {
16608
+ throw new Error("Harness Usage 'unpricedModels' must be provided with a 'publicPrice' cost");
16609
+ }
16610
+ return { ...value, unpricedModels: [...models] };
16611
+ }
16327
16612
  return { ...value };
16328
16613
  }
16614
+ var requestTokenFields = [
16615
+ "inputTokens",
16616
+ "cachedInputTokens",
16617
+ "cacheWriteInputTokens",
16618
+ "cacheWrite1hInputTokens",
16619
+ "outputTokens",
16620
+ "reasoningOutputTokens",
16621
+ "startedAtMs",
16622
+ "completedAtMs"
16623
+ ];
16624
+ var requestFields = /* @__PURE__ */ new Set([
16625
+ ...requestTokenFields,
16626
+ "requestId",
16627
+ "historical",
16628
+ "model",
16629
+ "provider"
16630
+ ]);
16631
+ function parseHostUsageRequest(value) {
16632
+ if (!isRecord(value))
16633
+ throw new Error("Harness Usage request must be an object");
16634
+ for (const key of Object.keys(value)) {
16635
+ if (!requestFields.has(key)) {
16636
+ throw new Error(`Harness Usage request contains unknown field '${key}'`);
16637
+ }
16638
+ }
16639
+ if (typeof value.requestId !== "string" || value.requestId.length === 0) {
16640
+ throw new Error("Harness Usage request 'requestId' must be a non-empty string");
16641
+ }
16642
+ for (const field of ["model", "provider"]) {
16643
+ const candidate2 = value[field];
16644
+ if (candidate2 !== void 0 && (typeof candidate2 !== "string" || candidate2.length === 0)) {
16645
+ throw new Error(`Harness Usage request '${field}' must be a non-empty string`);
16646
+ }
16647
+ }
16648
+ if (value.historical !== void 0 && typeof value.historical !== "boolean") {
16649
+ throw new Error("Harness Usage request 'historical' must be a boolean");
16650
+ }
16651
+ for (const field of requestTokenFields) {
16652
+ const candidate2 = value[field];
16653
+ if (candidate2 !== void 0 && (typeof candidate2 !== "number" || !Number.isSafeInteger(candidate2) || candidate2 < 0)) {
16654
+ throw new Error(`Harness Usage request '${field}' must be a non-negative safe integer`);
16655
+ }
16656
+ }
16657
+ if (value.inputTokens === void 0 || value.outputTokens === void 0) {
16658
+ throw new Error("Harness Usage request must contain 'inputTokens' and 'outputTokens'");
16659
+ }
16660
+ const request = value;
16661
+ if ((request.cachedInputTokens ?? 0) + (request.cacheWriteInputTokens ?? 0) > request.inputTokens) {
16662
+ throw new Error("Harness Usage request cache Tokens must not exceed 'inputTokens'");
16663
+ }
16664
+ if ((request.reasoningOutputTokens ?? 0) > request.outputTokens) {
16665
+ throw new Error("Harness Usage request 'reasoningOutputTokens' must not exceed 'outputTokens'");
16666
+ }
16667
+ if (request.cacheWrite1hInputTokens !== void 0 && request.cacheWrite1hInputTokens > (request.cacheWriteInputTokens ?? -1)) {
16668
+ throw new Error("Harness Usage request 'cacheWrite1hInputTokens' must not exceed 'cacheWriteInputTokens'");
16669
+ }
16670
+ if (request.startedAtMs === void 0 !== (request.completedAtMs === void 0)) {
16671
+ throw new Error("Harness Usage request timing fields must be provided together");
16672
+ }
16673
+ if (request.startedAtMs !== void 0 && request.completedAtMs !== void 0 && request.completedAtMs < request.startedAtMs) {
16674
+ throw new Error("Harness Usage request 'completedAtMs' must not precede 'startedAtMs'");
16675
+ }
16676
+ return { ...request };
16677
+ }
16678
+
16679
+ // dist/v2/usage.js
16680
+ function v2UsageRequest(message, historical, firstOutputAtMs) {
16681
+ if (message.type !== "assistant" || !message.tokens)
16682
+ return null;
16683
+ const { input, output, reasoning, cache } = message.tokens;
16684
+ const { streamed } = message.time;
16685
+ return parseHostUsageRequest({
16686
+ requestId: message.id,
16687
+ ...historical ? { historical: true } : {},
16688
+ model: message.model.id,
16689
+ // Built-in OpenCode providers use models.dev IDs. A custom provider ID matches no price
16690
+ // entry, so Host falls back to the exact model ID.
16691
+ provider: message.model.providerID,
16692
+ inputTokens: input + cache.read + cache.write,
16693
+ cachedInputTokens: cache.read,
16694
+ cacheWriteInputTokens: cache.write,
16695
+ outputTokens: output + reasoning,
16696
+ reasoningOutputTokens: reasoning,
16697
+ // End at stream completion, not step completion, which can include tool execution.
16698
+ // Without a native stream end, keep the usage but do not guess its generation duration.
16699
+ ...!historical && firstOutputAtMs !== void 0 && streamed !== void 0 && streamed >= firstOutputAtMs ? { startedAtMs: firstOutputAtMs, completedAtMs: streamed } : {}
16700
+ });
16701
+ }
16702
+
16703
+ // dist/usage-statistics.js
16704
+ function parseRowData(data) {
16705
+ try {
16706
+ return JSON.parse(String(data));
16707
+ } catch {
16708
+ return null;
16709
+ }
16710
+ }
16711
+ function isRecord2(value) {
16712
+ return typeof value === "object" && value !== null && !Array.isArray(value);
16713
+ }
16714
+ function openCodeDatabasePath(environment) {
16715
+ const home = environment.HOME || environment.USERPROFILE || os2.homedir();
16716
+ const directory = path5.join(environment.XDG_DATA_HOME || path5.join(home, ".local", "share"), "opencode");
16717
+ const configured = environment.OPENCODE_DB;
16718
+ if (configured === ":memory:")
16719
+ return null;
16720
+ return configured ? path5.resolve(directory, configured) : path5.join(directory, "opencode.db");
16721
+ }
16722
+ async function fingerprint(file2) {
16723
+ const info = await lstat(file2).catch(() => null);
16724
+ if (!info?.isFile())
16725
+ return null;
16726
+ const wal = await lstat(`${file2}-wal`).catch(() => null);
16727
+ return `${info.ino}:${info.size}:${info.mtimeMs}:${wal ? `${wal.size}:${wal.mtimeMs}` : "-"}`;
16728
+ }
16729
+ async function readOpenCodeUsage(file2) {
16730
+ const { DatabaseSync } = await import("node:sqlite");
16731
+ const database = new DatabaseSync(file2, { readOnly: true });
16732
+ try {
16733
+ const tables = new Set(database.prepare("SELECT name FROM sqlite_master WHERE type = 'table'").all().map((row) => String(row.name)));
16734
+ const directories = /* @__PURE__ */ new Map();
16735
+ for (const table of ["session", "session_v2"]) {
16736
+ if (!tables.has(table))
16737
+ continue;
16738
+ for (const row of database.prepare(`SELECT id, directory FROM ${table}`).iterate()) {
16739
+ if (typeof row.directory === "string")
16740
+ directories.set(String(row.id), row.directory);
16741
+ }
16742
+ }
16743
+ const entries = /* @__PURE__ */ new Map();
16744
+ const add = (message, createdAtMs, session) => {
16745
+ let request;
16746
+ try {
16747
+ request = v2UsageRequest(message, true);
16748
+ } catch {
16749
+ return;
16750
+ }
16751
+ const at = nativeTimeMs(createdAtMs);
16752
+ const entry = request && at !== null && usageEntryFromRequest(request, at);
16753
+ if (entry && !entries.has(entry.id)) {
16754
+ const sessionId = typeof session === "string" ? session : void 0;
16755
+ entries.set(entry.id, withUsageSession(entry, {
16756
+ sessionId,
16757
+ cwd: sessionId === void 0 ? void 0 : directories.get(sessionId)
16758
+ }));
16759
+ }
16760
+ };
16761
+ if (tables.has("session_message")) {
16762
+ for (const row of database.prepare("SELECT id, session_id, data FROM session_message WHERE type = 'assistant'").iterate()) {
16763
+ const data = parseRowData(row.data);
16764
+ if (!isRecord2(data))
16765
+ continue;
16766
+ add({ ...data, id: String(row.id), type: "assistant" }, isRecord2(data.time) ? data.time.created : void 0, row.session_id);
16767
+ }
16768
+ }
16769
+ const migrated = tables.has("kv") && /"phase"\s*:\s*"completed"/u.test(String(database.prepare("SELECT value FROM kv WHERE key = 'migration.v1-v2'").get()?.value ?? ""));
16770
+ if (tables.has("message") && !migrated) {
16771
+ for (const row of database.prepare("SELECT id, session_id, data FROM message").iterate()) {
16772
+ const data = parseRowData(row.data);
16773
+ if (!isRecord2(data) || data.role !== "assistant" || typeof data.modelID !== "string") {
16774
+ continue;
16775
+ }
16776
+ add({
16777
+ id: String(row.id),
16778
+ type: "assistant",
16779
+ model: { id: data.modelID, providerID: data.providerID },
16780
+ tokens: data.tokens,
16781
+ time: data.time
16782
+ }, isRecord2(data.time) ? data.time.created : void 0, row.session_id);
16783
+ }
16784
+ }
16785
+ return [...entries.values()];
16786
+ } finally {
16787
+ database.close();
16788
+ }
16789
+ }
16790
+ function createOpenCodeUsageStatistics(environment) {
16791
+ return Object.freeze({
16792
+ async listSources() {
16793
+ const file2 = openCodeDatabasePath(environment);
16794
+ const stamp = file2 ? await fingerprint(file2) : null;
16795
+ return file2 && stamp ? [{ id: file2, fingerprint: stamp }] : [];
16796
+ },
16797
+ readSource: (id) => readOpenCodeUsage(id)
16798
+ });
16799
+ }
16800
+
16801
+ // dist/opencode-adapter.js
16802
+ import { randomUUID } from "node:crypto";
16803
+ import fs4 from "node:fs";
16804
+ import path9 from "node:path";
16329
16805
 
16330
16806
  // dist/model-catalog.js
16331
16807
  import { Buffer as Buffer2 } from "node:buffer";
@@ -16336,10 +16812,10 @@ function assertNonBlank(value, label) {
16336
16812
  if (!value.trim())
16337
16813
  throw new Error(`OpenCode ${label} must not be empty`);
16338
16814
  }
16339
- function encodeOpenCodeModelRef(model) {
16340
- assertNonBlank(model.providerID, "Provider ID");
16341
- assertNonBlank(model.modelID, "Model ID");
16342
- const encoded = Buffer2.from(JSON.stringify([model.providerID, model.modelID]), "utf8").toString("base64url");
16815
+ function encodeOpenCodeModelRef(model2) {
16816
+ assertNonBlank(model2.providerID, "Provider ID");
16817
+ assertNonBlank(model2.modelID, "Model ID");
16818
+ const encoded = Buffer2.from(JSON.stringify([model2.providerID, model2.modelID]), "utf8").toString("base64url");
16343
16819
  const id = `${MODEL_REF_PREFIX}${encoded}`;
16344
16820
  if (id.length > HARNESS_MODEL_REF_MAX_LENGTH) {
16345
16821
  throw new Error("OpenCode Model identity is too long for a Model Ref");
@@ -16397,26 +16873,26 @@ function compareText(left, right) {
16397
16873
  }
16398
16874
  function modelsForConnectedProviders(catalog) {
16399
16875
  const connected = new Set(catalog.connected);
16400
- return catalog.all.flatMap((provider) => connected.has(provider.id) ? Object.values(provider.models).map((model) => ({ provider, model })) : []);
16876
+ return catalog.all.flatMap((provider) => connected.has(provider.id) ? Object.values(provider.models).map((model2) => ({ provider, model: model2 })) : []);
16401
16877
  }
16402
16878
  function normalizeOpenCodeModelCatalog(catalog) {
16403
16879
  const nativeModels = modelsForConnectedProviders(catalog);
16404
16880
  const variants = /* @__PURE__ */ new Set();
16405
- for (const { model } of nativeModels) {
16406
- for (const variant of Object.keys(model.variants ?? {}))
16881
+ for (const { model: model2 } of nativeModels) {
16882
+ for (const variant of Object.keys(model2.variants ?? {}))
16407
16883
  variants.add(variant);
16408
16884
  }
16409
16885
  const thinkingOptions = [
16410
16886
  variantOption(void 0),
16411
16887
  ...[...variants].sort(compareText).map((variant) => variantOption(variant))
16412
16888
  ];
16413
- const models = nativeModels.map(({ provider, model }) => ({
16414
- ref: encodeOpenCodeModelRef({ providerID: provider.id, modelID: model.id }),
16415
- label: `${provider.name} / ${model.name}`,
16416
- resolvedModelLabel: `${provider.id}/${model.id}`,
16889
+ const models = nativeModels.map(({ provider, model: model2 }) => ({
16890
+ ref: encodeOpenCodeModelRef({ providerID: provider.id, modelID: model2.id }),
16891
+ label: `${provider.name} / ${model2.name}`,
16892
+ resolvedModelLabel: `${provider.id}/${model2.id}`,
16417
16893
  supportedThinkingOptionIds: [
16418
16894
  DEFAULT_VARIANT_ID,
16419
- ...Object.keys(model.variants ?? {}).sort(compareText).map(encodeOpenCodeVariant)
16895
+ ...Object.keys(model2.variants ?? {}).sort(compareText).map(encodeOpenCodeVariant)
16420
16896
  ]
16421
16897
  })).sort((left, right) => compareText(left.label, right.label) || compareText(left.ref.id, right.ref.id));
16422
16898
  const defaultNative = catalog.connected.map((providerID) => ({ providerID, modelID: catalog.default[providerID] })).find((candidate2) => typeof candidate2.modelID === "string" && candidate2.modelID.length > 0);
@@ -16428,9 +16904,9 @@ function normalizeOpenCodeModelCatalog(catalog) {
16428
16904
  defaultThinkingOptionId: DEFAULT_VARIANT_ID
16429
16905
  });
16430
16906
  }
16431
- function openCodeContextWindow(catalog, model) {
16432
- const provider = catalog.all.find(({ id }) => id === model.providerID);
16433
- const context = provider?.models[model.modelID]?.limit.context;
16907
+ function openCodeContextWindow(catalog, model2) {
16908
+ const provider = catalog.all.find(({ id }) => id === model2.providerID);
16909
+ const context = provider?.models[model2.modelID]?.limit.context;
16434
16910
  return typeof context === "number" && Number.isSafeInteger(context) && context > 0 ? context : void 0;
16435
16911
  }
16436
16912
 
@@ -16753,7 +17229,7 @@ import { spawn, spawnSync } from "node:child_process";
16753
17229
  import fs2 from "node:fs";
16754
17230
  import { createServer } from "node:net";
16755
17231
  import { homedir as homedir2, tmpdir as tmpdir2 } from "node:os";
16756
- import path6 from "node:path";
17232
+ import path7 from "node:path";
16757
17233
 
16758
17234
  // ../../../node_modules/@opencode-ai/sdk/dist/v2/gen/core/serverSentEvents.gen.js
16759
17235
  var createSseClient = ({ onRequest, onSseError, onSseEvent, responseTransformer, responseValidator, sseDefaultRetryDelay, sseMaxRetryAttempts, sseMaxRetryDelay, sseSleepFn, url: url2, ...options }) => {
@@ -16979,7 +17455,7 @@ var serializeObjectParam = ({ allowReserved, explode, name, style, value, valueO
16979
17455
 
16980
17456
  // ../../../node_modules/@opencode-ai/sdk/dist/v2/gen/core/utils.gen.js
16981
17457
  var PATH_PARAM_RE = /\{[^{}]+\}/g;
16982
- var defaultPathSerializer = ({ path: path13, url: _url2 }) => {
17458
+ var defaultPathSerializer = ({ path: path14, url: _url2 }) => {
16983
17459
  let url2 = _url2;
16984
17460
  const matches = _url2.match(PATH_PARAM_RE);
16985
17461
  if (matches) {
@@ -16998,7 +17474,7 @@ var defaultPathSerializer = ({ path: path13, url: _url2 }) => {
16998
17474
  name = name.substring(1);
16999
17475
  style = "matrix";
17000
17476
  }
17001
- const value = path13[name];
17477
+ const value = path14[name];
17002
17478
  if (value === void 0 || value === null) {
17003
17479
  continue;
17004
17480
  }
@@ -17029,11 +17505,11 @@ var defaultPathSerializer = ({ path: path13, url: _url2 }) => {
17029
17505
  }
17030
17506
  return url2;
17031
17507
  };
17032
- var getUrl = ({ baseUrl, path: path13, query, querySerializer, url: _url2 }) => {
17508
+ var getUrl = ({ baseUrl, path: path14, query, querySerializer, url: _url2 }) => {
17033
17509
  const pathUrl = _url2.startsWith("/") ? _url2 : `/${_url2}`;
17034
17510
  let url2 = (baseUrl ?? "") + pathUrl;
17035
- if (path13) {
17036
- url2 = defaultPathSerializer({ path: path13, url: url2 });
17511
+ if (path14) {
17512
+ url2 = defaultPathSerializer({ path: path14, url: url2 });
17037
17513
  }
17038
17514
  let search = query ? querySerializer(query) : "";
17039
17515
  if (search.startsWith("?")) {
@@ -22156,7 +22632,7 @@ function createOpencodeClient(config2) {
22156
22632
  }
22157
22633
 
22158
22634
  // dist/command.js
22159
- import path5 from "node:path";
22635
+ import path6 from "node:path";
22160
22636
  var OpenCodeExecutableError = class extends Error {
22161
22637
  code = "OPENCODE_NOT_FOUND";
22162
22638
  constructor(message = "OpenCode CLI is not installed") {
@@ -22190,7 +22666,7 @@ function resolveOpenCodeExecutable(input = {}, dependencies = {}) {
22190
22666
  }, dependencies);
22191
22667
  if (!resolution)
22192
22668
  throw new OpenCodeExecutableError();
22193
- return targetPath(platform).isAbsolute(resolution.executable) ? resolution.executable : path5.resolve(resolution.executable);
22669
+ return targetPath(platform).isAbsolute(resolution.executable) ? resolution.executable : path6.resolve(resolution.executable);
22194
22670
  }
22195
22671
  function openCodeServerInvocation(executable, environment, platform = process.platform, port = 0) {
22196
22672
  return commandInvocation(executable, ["serve", "--hostname=127.0.0.1", `--port=${port}`], environment, platform);
@@ -22218,14 +22694,14 @@ function freeLoopbackPort() {
22218
22694
  });
22219
22695
  });
22220
22696
  }
22221
- function isRecord2(value) {
22697
+ function isRecord3(value) {
22222
22698
  return typeof value === "object" && value !== null && !Array.isArray(value);
22223
22699
  }
22224
22700
  function errorText(error51) {
22225
22701
  return error51 instanceof Error ? error51.message : String(error51);
22226
22702
  }
22227
22703
  function isMissingExecutable(error51) {
22228
- return isRecord2(error51) && error51.code === "ENOENT";
22704
+ return isRecord3(error51) && error51.code === "ENOENT";
22229
22705
  }
22230
22706
  function classifySdkError(error51, operation) {
22231
22707
  if (error51 instanceof OpenCodeTransportError)
@@ -22280,14 +22756,14 @@ function signalProcessTree(child, signal) {
22280
22756
  try {
22281
22757
  process.kill(-child.pid, signal);
22282
22758
  } catch (error51) {
22283
- if (!isRecord2(error51) || error51.code !== "ESRCH")
22759
+ if (!isRecord3(error51) || error51.code !== "ESRCH")
22284
22760
  throw error51;
22285
22761
  }
22286
22762
  }
22287
22763
  function safeOpenCodeServerCwd(environment) {
22288
22764
  const candidates = [environment.USERPROFILE, environment.HOME, homedir2(), tmpdir2()];
22289
22765
  for (const candidate2 of candidates) {
22290
- if (!candidate2 || !path6.isAbsolute(candidate2))
22766
+ if (!candidate2 || !path7.isAbsolute(candidate2))
22291
22767
  continue;
22292
22768
  try {
22293
22769
  if (!fs2.statSync(candidate2).isDirectory())
@@ -22311,7 +22787,7 @@ function managedOpenCodeEnvironment(environment, executionPolicy = "default") {
22311
22787
  if (existing !== void 0) {
22312
22788
  try {
22313
22789
  const parsed = JSON.parse(existing);
22314
- if (!isRecord2(parsed))
22790
+ if (!isRecord3(parsed))
22315
22791
  throw new Error("OpenCode config content must be an object");
22316
22792
  config2 = { ...parsed };
22317
22793
  } catch (error51) {
@@ -22634,11 +23110,11 @@ var SdkOpenCodeTransport = class {
22634
23110
  parts: [{ type: "text", text: input.text }]
22635
23111
  }), this.#commandTimeoutMs, "OpenCode prompt admission"), "prompt admission");
22636
23112
  }
22637
- async summarize(sessionID, model) {
23113
+ async summarize(sessionID, model2) {
22638
23114
  const client2 = await this.#getClient();
22639
23115
  responseData2(await withTimeout2(client2.session.summarize({
22640
23116
  sessionID,
22641
- ...model ? { providerID: model.providerID, modelID: model.modelID } : {}
23117
+ ...model2 ? { providerID: model2.providerID, modelID: model2.modelID } : {}
22642
23118
  }), this.#commandTimeoutMs, "OpenCode context compaction"), "context compaction");
22643
23119
  }
22644
23120
  async abort(sessionID) {
@@ -22736,7 +23212,7 @@ var SdkOpenCodeTransport = class {
22736
23212
 
22737
23213
  // dist/file-change-verification.js
22738
23214
  import fs3 from "node:fs";
22739
- import path7 from "node:path";
23215
+ import path8 from "node:path";
22740
23216
  function missingPath(error51) {
22741
23217
  if (!error51 || typeof error51 !== "object")
22742
23218
  return false;
@@ -22748,33 +23224,33 @@ function hasDotPathSegment(value) {
22748
23224
  return segments.some((segment) => segment === "." || segment === "..");
22749
23225
  }
22750
23226
  function canonicalDirectoryPath(value) {
22751
- let candidate2 = path7.resolve(value);
23227
+ let candidate2 = path8.resolve(value);
22752
23228
  const missingSegments = [];
22753
23229
  for (; ; ) {
22754
23230
  try {
22755
- return path7.join(fs3.realpathSync.native(candidate2), ...missingSegments);
23231
+ return path8.join(fs3.realpathSync.native(candidate2), ...missingSegments);
22756
23232
  } catch (error51) {
22757
23233
  if (!missingPath(error51))
22758
23234
  return void 0;
22759
- const parent = path7.dirname(candidate2);
23235
+ const parent = path8.dirname(candidate2);
22760
23236
  if (parent === candidate2)
22761
23237
  return void 0;
22762
- missingSegments.unshift(path7.basename(candidate2));
23238
+ missingSegments.unshift(path8.basename(candidate2));
22763
23239
  candidate2 = parent;
22764
23240
  }
22765
23241
  }
22766
23242
  }
22767
23243
  function canonicalFilePath(value) {
22768
- const absolute = path7.resolve(value);
22769
- const parent = canonicalDirectoryPath(path7.dirname(absolute));
22770
- return parent ? path7.join(parent, path7.basename(absolute)) : void 0;
23244
+ const absolute = path8.resolve(value);
23245
+ const parent = canonicalDirectoryPath(path8.dirname(absolute));
23246
+ return parent ? path8.join(parent, path8.basename(absolute)) : void 0;
22771
23247
  }
22772
23248
  function pathIsWithin(root, candidate2, allowRoot) {
22773
- const relative = path7.relative(root, candidate2);
22774
- return allowRoot && relative === "" || relative !== "" && relative !== ".." && !relative.startsWith(`..${path7.sep}`) && !path7.isAbsolute(relative);
23249
+ const relative = path8.relative(root, candidate2);
23250
+ return allowRoot && relative === "" || relative !== "" && relative !== ".." && !relative.startsWith(`..${path8.sep}`) && !path8.isAbsolute(relative);
22775
23251
  }
22776
23252
  function verifiedOpenCodeWorktree(sessionDirectory, paths) {
22777
- if (!paths || typeof paths !== "object" || typeof sessionDirectory !== "string" || typeof paths.directory !== "string" || typeof paths.worktree !== "string" || hasDotPathSegment(sessionDirectory) || hasDotPathSegment(paths.directory) || hasDotPathSegment(paths.worktree) || !path7.isAbsolute(sessionDirectory) || !path7.isAbsolute(paths.directory) || !path7.isAbsolute(paths.worktree)) {
23253
+ if (!paths || typeof paths !== "object" || typeof sessionDirectory !== "string" || typeof paths.directory !== "string" || typeof paths.worktree !== "string" || hasDotPathSegment(sessionDirectory) || hasDotPathSegment(paths.directory) || hasDotPathSegment(paths.worktree) || !path8.isAbsolute(sessionDirectory) || !path8.isAbsolute(paths.directory) || !path8.isAbsolute(paths.worktree)) {
22778
23254
  return void 0;
22779
23255
  }
22780
23256
  const session = canonicalDirectoryPath(sessionDirectory);
@@ -22786,10 +23262,10 @@ function verifiedOpenCodeWorktree(sessionDirectory, paths) {
22786
23262
  return worktree;
22787
23263
  }
22788
23264
  function openCodeFileIdentity(file2, worktree) {
22789
- if (typeof file2 !== "string" || typeof worktree !== "string" || hasDotPathSegment(file2) || hasDotPathSegment(worktree) || !path7.isAbsolute(worktree) || !file2 || file2.includes("\0") || file2.includes("\n") || file2.includes("\r")) {
23265
+ if (typeof file2 !== "string" || typeof worktree !== "string" || hasDotPathSegment(file2) || hasDotPathSegment(worktree) || !path8.isAbsolute(worktree) || !file2 || file2.includes("\0") || file2.includes("\n") || file2.includes("\r")) {
22790
23266
  return void 0;
22791
23267
  }
22792
- const candidate2 = canonicalFilePath(path7.isAbsolute(file2) ? file2 : path7.resolve(worktree, file2));
23268
+ const candidate2 = canonicalFilePath(path8.isAbsolute(file2) ? file2 : path8.resolve(worktree, file2));
22793
23269
  return candidate2 && pathIsWithin(worktree, candidate2, false) ? candidate2 : void 0;
22794
23270
  }
22795
23271
 
@@ -22847,12 +23323,12 @@ function storedSelection(session) {
22847
23323
  }
22848
23324
  return { providerID, modelID, ...typeof variant === "string" ? { variant } : {} };
22849
23325
  }
22850
- function selectionMetadata(session, model, variant) {
23326
+ function selectionMetadata(session, model2, variant) {
22851
23327
  return {
22852
23328
  ...session.metadata,
22853
23329
  [SELECTION_METADATA_KEY]: {
22854
- providerID: model.providerID,
22855
- modelID: model.modelID,
23330
+ providerID: model2.providerID,
23331
+ modelID: model2.modelID,
22856
23332
  ...variant ? { variant } : {}
22857
23333
  }
22858
23334
  };
@@ -22948,17 +23424,17 @@ async function readProjection(transport, sessionID, providerCatalog, toolOutputL
22948
23424
  diffsByUserMessageId: new Map(diffEntries),
22949
23425
  toolOutputLimit
22950
23426
  });
22951
- const model = nativeModelFromSession(session, messages);
23427
+ const model2 = nativeModelFromSession(session, messages);
22952
23428
  const nativeVariant = nativeVariantFromSession(session, messages);
22953
- const nativeModel = model ? providerCatalog.all.find(({ id }) => id === model.providerID)?.models[model.modelID] : void 0;
23429
+ const nativeModel = model2 ? providerCatalog.all.find(({ id }) => id === model2.providerID)?.models[model2.modelID] : void 0;
22954
23430
  const variant = nativeVariant === "default" && nativeModel && !Object.hasOwn(nativeModel.variants ?? {}, "default") ? void 0 : nativeVariant;
22955
- const usage = projectOpenCodeUsage(openCodeAssistantMessages(session, messages), model ? openCodeContextWindow(providerCatalog, model) : void 0);
23431
+ const usage = projectOpenCodeUsage(openCodeAssistantMessages(session, messages), model2 ? openCodeContextWindow(providerCatalog, model2) : void 0);
22956
23432
  return {
22957
23433
  session,
22958
23434
  messages,
22959
23435
  snapshot,
22960
23436
  usage,
22961
- ...model ? { model } : {},
23437
+ ...model2 ? { model: model2 } : {},
22962
23438
  ...variant ? { variant } : {}
22963
23439
  };
22964
23440
  }
@@ -23084,13 +23560,13 @@ function sameCwd(left, right) {
23084
23560
  try {
23085
23561
  return fs4.realpathSync.native(value);
23086
23562
  } catch {
23087
- return path8.resolve(value);
23563
+ return path9.resolve(value);
23088
23564
  }
23089
23565
  };
23090
23566
  return canonical(left) === canonical(right);
23091
23567
  }
23092
- function sessionState(session, modelCatalog, model, variant, executionPolicy = "default", permissionModeId = OPENCODE_DEFAULT_PERMISSION_MODE_ID) {
23093
- const effectiveModel = model ? encodeOpenCodeModelRef(model) : void 0;
23568
+ function sessionState(session, modelCatalog, model2, variant, executionPolicy = "default", permissionModeId = OPENCODE_DEFAULT_PERMISSION_MODE_ID) {
23569
+ const effectiveModel = model2 ? encodeOpenCodeModelRef(model2) : void 0;
23094
23570
  const modelEntry = effectiveModel ? modelCatalog.models.find(({ ref }) => ref.id === effectiveModel.id) : void 0;
23095
23571
  const availableThinkingOptions = modelEntry?.supportedThinkingOptionIds?.map((id) => modelCatalog.thinkingOptions.find((option) => option.id === id)).filter((option) => Boolean(option));
23096
23572
  const effectiveThinkingOptionId = encodeOpenCodeVariant(variant);
@@ -23492,8 +23968,8 @@ var OpenCodeHarnessSession = class {
23492
23968
  };
23493
23969
  }
23494
23970
  const modelRef = this.#model ? encodeOpenCodeModelRef(this.#model) : void 0;
23495
- const model = modelRef ? this.#modelCatalog.models.find(({ ref }) => ref.id === modelRef.id) : void 0;
23496
- if (!model?.supportedThinkingOptionIds?.includes(command.thinkingOptionId)) {
23971
+ const model2 = modelRef ? this.#modelCatalog.models.find(({ ref }) => ref.id === modelRef.id) : void 0;
23972
+ if (!model2?.supportedThinkingOptionIds?.includes(command.thinkingOptionId)) {
23497
23973
  return {
23498
23974
  ok: false,
23499
23975
  error: {
@@ -24343,14 +24819,14 @@ var OpenCodeAdapter = class {
24343
24819
  const modelCatalog = normalizeOpenCodeModelCatalog(providers);
24344
24820
  let session;
24345
24821
  if (input.kind === "create") {
24346
- const model = input.model ? decodeOpenCodeModelRef(input.model) : void 0;
24822
+ const model2 = input.model ? decodeOpenCodeModelRef(input.model) : void 0;
24347
24823
  const variant = input.thinkingOptionId ? decodeOpenCodeVariant(input.thinkingOptionId) : void 0;
24348
24824
  if (input.model && !modelCatalog.models.some(({ ref }) => ref.id === input.model?.id)) {
24349
24825
  throw new OpenCodeTransportError("protocolError", "Requested OpenCode Model is absent from the connected Provider catalog");
24350
24826
  }
24351
24827
  const permission = requestedPermissionMode && requestedPermissionMode !== "default" ? requestedPermissionRules(void 0, requestedPermissionMode) : void 0;
24352
24828
  session = await transport.createSession({
24353
- ...model ? { model } : {},
24829
+ ...model2 ? { model: model2 } : {},
24354
24830
  ...variant ? { variant } : {},
24355
24831
  ...permission ? { permission } : {}
24356
24832
  });
@@ -24465,7 +24941,7 @@ import { isDeepStrictEqual as isDeepStrictEqual2 } from "node:util";
24465
24941
 
24466
24942
  // dist/v2/state.js
24467
24943
  import fs5 from "node:fs";
24468
- import path9 from "node:path";
24944
+ import path10 from "node:path";
24469
24945
  var harnessId = harnessIdSchema.parse("opencode");
24470
24946
  function failure(message, code = "nativeFailure") {
24471
24947
  return {
@@ -24485,7 +24961,7 @@ function sameDirectory(left, right) {
24485
24961
  try {
24486
24962
  return fs5.realpathSync(value);
24487
24963
  } catch {
24488
- return path9.resolve(value);
24964
+ return path10.resolve(value);
24489
24965
  }
24490
24966
  };
24491
24967
  return canonical(left) === canonical(right);
@@ -24507,17 +24983,17 @@ function v2Locator(ref) {
24507
24983
  return { directory: locator.directory, executionPolicy: locator.executionPolicy };
24508
24984
  }
24509
24985
  function v2Catalog(models, defaultModel) {
24510
- const enabled = models.filter((model) => model.enabled);
24511
- const variants = [...new Set(enabled.flatMap((model) => model.variants.map((v) => v.id)))].sort();
24512
- const ref = (model) => encodeOpenCodeModelRef({ providerID: model.providerID, modelID: model.id });
24986
+ const enabled = models.filter((model2) => model2.enabled);
24987
+ const variants = [...new Set(enabled.flatMap((model2) => model2.variants.map((v) => v.id)))].sort();
24988
+ const ref = (model2) => encodeOpenCodeModelRef({ providerID: model2.providerID, modelID: model2.id });
24513
24989
  return harnessModelCatalogSchema.parse({
24514
- models: enabled.map((model) => ({
24515
- ref: ref(model),
24516
- label: `${model.providerID} / ${model.name}`,
24517
- resolvedModelLabel: `${model.providerID}/${model.id}`,
24990
+ models: enabled.map((model2) => ({
24991
+ ref: ref(model2),
24992
+ label: `${model2.providerID} / ${model2.name}`,
24993
+ resolvedModelLabel: `${model2.providerID}/${model2.id}`,
24518
24994
  supportedThinkingOptionIds: [
24519
24995
  encodeOpenCodeVariant(void 0),
24520
- ...model.variants.map((v) => encodeOpenCodeVariant(v.id))
24996
+ ...model2.variants.map((v) => encodeOpenCodeVariant(v.id))
24521
24997
  ]
24522
24998
  })),
24523
24999
  ...defaultModel && enabled.some((m) => ref(m).id === ref(defaultModel).id) ? { defaultModel: ref(defaultModel) } : {},
@@ -24534,12 +25010,12 @@ function v2Permissions(current = [], mode) {
24534
25010
  return selected === "default" ? rules : [...rules, { action: "*", resource: "*", effect: selected }];
24535
25011
  }
24536
25012
  function v2State(session, catalog, policy) {
24537
- const model = session.model ? encodeOpenCodeModelRef({ providerID: session.model.providerID, modelID: session.model.id }) : void 0;
24538
- const entry = catalog.models.find((candidate2) => candidate2.ref.id === model?.id);
25013
+ const model2 = session.model ? encodeOpenCodeModelRef({ providerID: session.model.providerID, modelID: session.model.id }) : void 0;
25014
+ const entry = catalog.models.find((candidate2) => candidate2.ref.id === model2?.id);
24539
25015
  const mode = session.permissions?.findLast((rule) => rule.action === "*" && rule.resource === "*");
24540
25016
  return {
24541
25017
  nativeRef: v2Ref(session, policy),
24542
- ...model ? { effectiveModel: model } : {},
25018
+ ...model2 ? { effectiveModel: model2 } : {},
24543
25019
  ...entry ? {
24544
25020
  resolvedModelLabel: entry.resolvedModelLabel ?? entry.label,
24545
25021
  availableThinkingOptions: catalog.thinkingOptions.filter((v) => entry.supportedThinkingOptionIds?.includes(v.id)),
@@ -26400,7 +26876,7 @@ var V2Connection = class {
26400
26876
  };
26401
26877
 
26402
26878
  // dist/v2/history.js
26403
- import path10 from "node:path";
26879
+ import path11 from "node:path";
26404
26880
  async function readMessages(client2, sessionID) {
26405
26881
  const messages = [];
26406
26882
  let cursor;
@@ -26419,11 +26895,12 @@ async function readMessages(client2, sessionID) {
26419
26895
  } while (cursor);
26420
26896
  return messages;
26421
26897
  }
26422
- var contentId = (messageID, index) => hostItemIdSchema.parse(`${messageID}:${index}`);
26898
+ var contentId = (messageID, type, ordinal) => hostItemIdSchema.parse(`${messageID}:${type}:${ordinal}`);
26423
26899
  function assistantItems2(message, limit) {
26424
- return message.content.map((part, index) => {
26425
- const itemId2 = contentId(message.id, index);
26900
+ const ordinals = { text: 0, reasoning: 0 };
26901
+ return message.content.map((part) => {
26426
26902
  if (part.type === "text" || part.type === "reasoning") {
26903
+ const itemId2 = contentId(message.id, part.type, ordinals[part.type]++);
26427
26904
  return {
26428
26905
  item: {
26429
26906
  type: part.type === "text" ? "agentMessage" : "reasoning",
@@ -26438,7 +26915,7 @@ function assistantItems2(message, limit) {
26438
26915
  return {
26439
26916
  item: {
26440
26917
  type: "toolExecution",
26441
- itemId: itemId2,
26918
+ itemId: hostItemIdSchema.parse(`${message.id}:tool:${part.id}`),
26442
26919
  toolName: part.name,
26443
26920
  namespace: "opencode",
26444
26921
  arguments: typeof state.input === "string" ? state.input : state.input,
@@ -26525,9 +27002,9 @@ function fileChanges(session, turn, diffs) {
26525
27002
  if (!diffs.length)
26526
27003
  return void 0;
26527
27004
  const changes = diffs.map((diff) => {
26528
- const absolute = path10.resolve(session.location.directory, diff.file);
26529
- const relative = path10.relative(session.location.directory, absolute);
26530
- if (relative.startsWith(`..${path10.sep}`) || relative === ".." || path10.isAbsolute(relative))
27005
+ const absolute = path11.resolve(session.location.directory, diff.file);
27006
+ const relative = path11.relative(session.location.directory, absolute);
27007
+ if (relative.startsWith(`..${path11.sep}`) || relative === ".." || path11.isAbsolute(relative))
26531
27008
  throw new Error("OpenCode v2 diff escaped the Session directory");
26532
27009
  return {
26533
27010
  path: absolute,
@@ -26570,7 +27047,7 @@ function terminalItemOutcome(outcome) {
26570
27047
 
26571
27048
  // dist/v2/session-import.js
26572
27049
  import fs6 from "node:fs";
26573
- import path11 from "node:path";
27050
+ import path12 from "node:path";
26574
27051
 
26575
27052
  // ../../harness-adapter/dist/session-import.js
26576
27053
  function sessionImportTitle(value, maxLength = HARNESS_SESSION_IMPORT_TITLE_MAX_LENGTH) {
@@ -26603,7 +27080,7 @@ function sessionImportCandidate(input) {
26603
27080
  var PAGE_SIZE = 200;
26604
27081
  var MAX_PAGES = 1e4;
26605
27082
  function existingDirectory(directory) {
26606
- if (typeof directory !== "string" || !path11.isAbsolute(directory))
27083
+ if (typeof directory !== "string" || !path12.isAbsolute(directory))
26607
27084
  return null;
26608
27085
  try {
26609
27086
  return fs6.statSync(directory).isDirectory() ? directory : null;
@@ -26803,6 +27280,14 @@ function v2Capabilities(catalog) {
26803
27280
  history: { fork: true, forkAcrossCwd: false, rollbackLastTurn: true }
26804
27281
  };
26805
27282
  }
27283
+ var FIRST_OUTPUT_EVENTS = /* @__PURE__ */ new Set([
27284
+ "session.reasoning.started",
27285
+ "session.reasoning.delta",
27286
+ "session.text.started",
27287
+ "session.text.delta",
27288
+ "session.tool.input.started",
27289
+ "session.tool.input.delta"
27290
+ ]);
26806
27291
  var V2Session = class {
26807
27292
  client;
26808
27293
  connection;
@@ -26826,6 +27311,11 @@ var V2Session = class {
26826
27311
  #reconciling;
26827
27312
  #timer;
26828
27313
  #configuring = false;
27314
+ #cacheHitRatePercent;
27315
+ /** Assistant messages already published as usage requests. */
27316
+ #meteredMessages = /* @__PURE__ */ new Set();
27317
+ /** Adapter receive time of each assistant message's first reasoning, text or tool input. */
27318
+ #firstOutputAt = /* @__PURE__ */ new Map();
26829
27319
  constructor(client2, connection, info, catalog, policy, limit, onClosed) {
26830
27320
  this.client = client2;
26831
27321
  this.connection = connection;
@@ -26870,6 +27360,7 @@ var V2Session = class {
26870
27360
  }
26871
27361
  })();
26872
27362
  });
27363
+ await this.#replayUsage();
26873
27364
  this.#timer = setInterval(() => {
26874
27365
  void this.#refresh();
26875
27366
  }, 400);
@@ -26938,22 +27429,22 @@ var V2Session = class {
26938
27429
  permissions: v2Permissions(this.info.permissions, command.permissionModeId)
26939
27430
  });
26940
27431
  } else {
26941
- let model = this.info.model;
27432
+ let model2 = this.info.model;
26942
27433
  if (command.type === "model.select") {
26943
27434
  if (!this.catalog.models.some((m) => m.ref.id === command.model.id))
26944
27435
  throw new Error("OpenCode Model is not available");
26945
27436
  const decoded = decodeOpenCodeModelRef(command.model);
26946
- model = { providerID: decoded.providerID, id: decoded.modelID };
27437
+ model2 = { providerID: decoded.providerID, id: decoded.modelID };
26947
27438
  } else {
26948
- if (!model)
27439
+ if (!model2)
26949
27440
  throw new Error("Select a Model before a Thinking option");
26950
27441
  const state = v2State(this.info, this.catalog, this.policy);
26951
27442
  if (!state.availableThinkingOptions?.some((v) => v.id === command.thinkingOptionId))
26952
27443
  throw new Error("Thinking option is unavailable for this Model");
26953
27444
  const variant = decodeOpenCodeVariant(command.thinkingOptionId);
26954
- model = { providerID: model.providerID, id: model.id, ...variant ? { variant } : {} };
27445
+ model2 = { providerID: model2.providerID, id: model2.id, ...variant ? { variant } : {} };
26955
27446
  }
26956
- await this.client.session.switchModel({ sessionID: this.info.id, model });
27447
+ await this.client.session.switchModel({ sessionID: this.info.id, model: model2 });
26957
27448
  }
26958
27449
  this.info = await this.client.session.get({ sessionID: this.info.id });
26959
27450
  this.#emit({
@@ -27036,11 +27527,14 @@ var V2Session = class {
27036
27527
  const active = this.#active;
27037
27528
  if (!active || !("data" in event) || !("sessionID" in event.data) || event.data.sessionID !== this.info.id)
27038
27529
  return;
27530
+ if (FIRST_OUTPUT_EVENTS.has(event.type) && "assistantMessageID" in event.data && typeof event.data.assistantMessageID === "string" && !this.#firstOutputAt.has(event.data.assistantMessageID))
27531
+ this.#firstOutputAt.set(event.data.assistantMessageID, Date.now());
27039
27532
  if (event.type === "session.step.started")
27040
27533
  active.assistants.add(event.data.assistantMessageID);
27041
27534
  if ((event.type === "session.text.delta" || event.type === "session.reasoning.delta") && active.assistants.has(event.data.assistantMessageID)) {
27042
- const itemId2 = contentId(event.data.assistantMessageID, event.data.ordinal);
27043
- const type = event.type === "session.text.delta" ? "agentMessage" : "reasoning";
27535
+ const contentType = event.type === "session.text.delta" ? "text" : "reasoning";
27536
+ const itemId2 = contentId(event.data.assistantMessageID, contentType, event.data.ordinal);
27537
+ const type = contentType === "text" ? "agentMessage" : "reasoning";
27044
27538
  const previous = active.transient.get(itemId2);
27045
27539
  const item = {
27046
27540
  type,
@@ -27054,6 +27548,56 @@ var V2Session = class {
27054
27548
  if (!event.type.endsWith(".delta"))
27055
27549
  void this.#refresh();
27056
27550
  }
27551
+ /** Publishes assistant messages not yet metered; returns false when one is unusable. */
27552
+ #meterUsage(messages, historical) {
27553
+ let usable = true;
27554
+ const previousCacheHitRate = this.#cacheHitRatePercent;
27555
+ for (const message of messages) {
27556
+ let request;
27557
+ try {
27558
+ request = v2UsageRequest(message, historical, this.#firstOutputAt.get(message.id));
27559
+ } catch {
27560
+ this.#cacheHitRatePercent = void 0;
27561
+ if (this.#meteredMessages.has(message.id))
27562
+ continue;
27563
+ this.#meteredMessages.add(message.id);
27564
+ if (!historical)
27565
+ this.#emit({ type: "usage.history", complete: false });
27566
+ usable = false;
27567
+ continue;
27568
+ }
27569
+ if (!request)
27570
+ continue;
27571
+ this.#cacheHitRatePercent = request.inputTokens > 0 && request.cachedInputTokens !== void 0 ? request.cachedInputTokens / request.inputTokens * 100 : void 0;
27572
+ if (this.#meteredMessages.has(message.id))
27573
+ continue;
27574
+ this.#meteredMessages.add(message.id);
27575
+ this.#firstOutputAt.delete(message.id);
27576
+ this.#emit({ type: "usage.request", request });
27577
+ }
27578
+ if (this.#cacheHitRatePercent !== previousCacheHitRate)
27579
+ this.#emit({
27580
+ type: "session.usage.changed",
27581
+ usage: this.#usage()
27582
+ });
27583
+ return usable;
27584
+ }
27585
+ #usage() {
27586
+ const usage = v2Usage(this.info);
27587
+ if (this.#cacheHitRatePercent !== void 0)
27588
+ usage.cacheHitRatePercent = this.#cacheHitRatePercent;
27589
+ return usage;
27590
+ }
27591
+ /** Replays every metered request of the native history, then declares it complete. */
27592
+ async #replayUsage() {
27593
+ let complete = false;
27594
+ try {
27595
+ complete = this.#meterUsage(await readMessages(this.client, this.info.id), true);
27596
+ } catch {
27597
+ complete = false;
27598
+ }
27599
+ this.#emit({ type: "usage.history", complete });
27600
+ }
27057
27601
  #refresh() {
27058
27602
  if (this.#closed || !this.#active?.admitted)
27059
27603
  return Promise.resolve();
@@ -27072,6 +27616,7 @@ var V2Session = class {
27072
27616
  if (this.#active !== active || this.#closed)
27073
27617
  return;
27074
27618
  this.info = info;
27619
+ this.#meterUsage(messages, false);
27075
27620
  const turns = snapshot.turns.filter((t) => !active.baseline.has(t.nativeTurnRef.nativeTurnKey));
27076
27621
  if (turns.length > 1)
27077
27622
  throw new Error("Concurrent native prompts cannot be assigned to one Host Turn");
@@ -27168,7 +27713,7 @@ var V2Session = class {
27168
27713
  });
27169
27714
  this.#emit({
27170
27715
  type: "session.usage.changed",
27171
- usage: v2Usage(this.info),
27716
+ usage: this.#usage(),
27172
27717
  observedForTurnId: active.turnId
27173
27718
  });
27174
27719
  this.#active = void 0;
@@ -27364,10 +27909,10 @@ var V2Adapter = class {
27364
27909
  const catalog = await this.#catalog(client2, input.cwd);
27365
27910
  let info;
27366
27911
  if (input.kind === "create") {
27367
- const model = selectedModel(input, catalog);
27912
+ const model2 = selectedModel(input, catalog);
27368
27913
  info = await client2.session.create({
27369
27914
  location: { directory: input.cwd },
27370
- ...model ? { model } : {},
27915
+ ...model2 ? { model: model2 } : {},
27371
27916
  permissions: v2Permissions([], input.permissionModeId ?? harnessPermissionModeIdSchema.parse(policy === "unattended-full-access" ? "allow" : "default"))
27372
27917
  });
27373
27918
  created = info.id;
@@ -27384,19 +27929,19 @@ var V2Adapter = class {
27384
27929
  if (input.kind !== "resume") {
27385
27930
  const parent = info;
27386
27931
  const turns = source.snapshot.turns;
27387
- let count;
27932
+ let count2;
27388
27933
  if (input.kind === "rollbackLastTurn") {
27389
27934
  if (!turns.length)
27390
27935
  throw new Error("OpenCode history is empty");
27391
- count = turns.length - 1;
27936
+ count2 = turns.length - 1;
27392
27937
  } else {
27393
27938
  if (input.checkpoint.harnessId !== harnessId || input.checkpoint.nativeSessionId !== info.id)
27394
27939
  throw new Error("Checkpoint belongs to another Session");
27395
- count = turns.findIndex((turn) => turn.checkpoint?.checkpointId === input.checkpoint.checkpointId) + 1;
27396
- if (!count || JSON.stringify(turns[count - 1]?.checkpoint) !== JSON.stringify(input.checkpoint))
27940
+ count2 = turns.findIndex((turn) => turn.checkpoint?.checkpointId === input.checkpoint.checkpointId) + 1;
27941
+ if (!count2 || JSON.stringify(turns[count2 - 1]?.checkpoint) !== JSON.stringify(input.checkpoint))
27397
27942
  throw new Error("OpenCode checkpoint does not match native history");
27398
27943
  }
27399
- const before = turns[count]?.nativeTurnRef.nativeTurnKey;
27944
+ const before = turns[count2]?.nativeTurnRef.nativeTurnKey;
27400
27945
  info = await client2.session.fork({ sessionID: parent.id, ...before ? { before } : {} });
27401
27946
  if (info.id === parent.id)
27402
27947
  throw new Error("OpenCode fork returned its source Session");
@@ -27411,7 +27956,7 @@ var V2Adapter = class {
27411
27956
  await client2.session.switchModel({ sessionID: info.id, model: parent.model });
27412
27957
  info = await client2.session.get({ sessionID: info.id });
27413
27958
  const derived = await readHistory(client2, info, this.options.toolOutputLimit ?? 64e3);
27414
- if (historyContent(derived.snapshot, false) !== historyContent({ turns: turns.slice(0, count) }, false))
27959
+ if (historyContent(derived.snapshot, false) !== historyContent({ turns: turns.slice(0, count2) }, false))
27415
27960
  throw new Error("OpenCode fork did not preserve the exact history prefix");
27416
27961
  if (!isDeepStrictEqual2(info.permissions ?? [], parent.permissions ?? []) || !isDeepStrictEqual2(info.model, parent.model))
27417
27962
  throw new Error("OpenCode fork did not preserve the current configuration");
@@ -27460,14 +28005,14 @@ function selectedModel(input, catalog) {
27460
28005
  throw new Error("Thinking selection requires a Model");
27461
28006
  return void 0;
27462
28007
  }
27463
- const entry = catalog.models.find((model2) => model2.ref.id === selected.id);
28008
+ const entry = catalog.models.find((model3) => model3.ref.id === selected.id);
27464
28009
  if (!entry)
27465
28010
  throw new Error("OpenCode Model is not available");
27466
28011
  if (input.thinkingOptionId && !entry.supportedThinkingOptionIds?.includes(input.thinkingOptionId))
27467
28012
  throw new Error("OpenCode Thinking option is not available for this Model");
27468
- const model = decodeOpenCodeModelRef(selected);
28013
+ const model2 = decodeOpenCodeModelRef(selected);
27469
28014
  const variant = input.thinkingOptionId ? decodeOpenCodeVariant(input.thinkingOptionId) : void 0;
27470
- return { providerID: model.providerID, id: model.modelID, ...variant ? { variant } : {} };
28015
+ return { providerID: model2.providerID, id: model2.modelID, ...variant ? { variant } : {} };
27471
28016
  }
27472
28017
  function historyContent(snapshot, identities = true) {
27473
28018
  return JSON.stringify(snapshot.turns.map((turn) => ({
@@ -27491,9 +28036,11 @@ var OpenCodeAdapter2 = class {
27491
28036
  commandCatalog = openCodeCommandCatalog;
27492
28037
  #adapters = /* @__PURE__ */ new Set();
27493
28038
  #closed = false;
28039
+ usageStatistics;
27494
28040
  constructor(options = {}, dependencies) {
27495
28041
  this.options = options;
27496
28042
  this.dependencies = dependencies;
28043
+ this.usageStatistics = createOpenCodeUsageStatistics(options.environment ?? process.env);
27497
28044
  }
27498
28045
  async #select(environment, input) {
27499
28046
  if (this.#closed)
@@ -27603,7 +28150,7 @@ function normalize(error51) {
27603
28150
  // dist/installation.js
27604
28151
  import { realpath as realpath2 } from "node:fs/promises";
27605
28152
  import { homedir as homedir3 } from "node:os";
27606
- import path12 from "node:path";
28153
+ import path13 from "node:path";
27607
28154
  function createOpenCodeInstallation(environment, command) {
27608
28155
  let update;
27609
28156
  return createInstallationManager({
@@ -27624,8 +28171,8 @@ function createOpenCodeInstallation(environment, command) {
27624
28171
  const release = JSON.parse(await fetchInstallationText("https://api.github.com/repos/anomalyco/opencode/releases/latest"));
27625
28172
  latestVersion = installationVersion(release.tag_name);
27626
28173
  const home = environment.HOME ?? environment.USERPROFILE ?? homedir3();
27627
- const standard = path12.join(home, ".opencode", "bin", process.platform === "win32" ? "opencode.exe" : "opencode");
27628
- canUpdate = process.platform !== "win32" && path12.resolve(executable) === standard && await realpath2(executable) === standard;
28174
+ const standard = path13.join(home, ".opencode", "bin", process.platform === "win32" ? "opencode.exe" : "opencode");
28175
+ canUpdate = process.platform !== "win32" && path13.resolve(executable) === standard && await realpath2(executable) === standard;
27629
28176
  update = async (version2) => {
27630
28177
  await runInstallationCommand(executable, ["upgrade", version2, "--method", "curl"], environment, 3e5);
27631
28178
  };