@codexhost/cli-darwin-x64 0.13.2 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/README.md +1 -1
  2. package/app/codexhost-distribution.json +1 -1
  3. package/app/console-server.mjs +94 -8
  4. package/app/console-web.js +537 -146
  5. package/app/desktop-controller.mjs +108 -12
  6. package/app/host-runtime.mjs +847 -235
  7. package/app/plugins/antigravity/plugin.mjs +143 -20
  8. package/app/plugins/claude-code/plugin.mjs +601 -71
  9. package/app/plugins/codebuddy/plugin.mjs +227 -30
  10. package/app/plugins/codex-usage/plugin.mjs +212 -77
  11. package/app/plugins/copilot/assets/icon.png +0 -0
  12. package/app/plugins/copilot/manifest.json +26 -0
  13. package/app/plugins/copilot/plugin.mjs +34546 -0
  14. package/app/plugins/cursor-cli/plugin.mjs +20805 -44862
  15. package/app/plugins/deepseek-harness/manifest.json +2 -2
  16. package/app/plugins/deepseek-harness/plugin.mjs +202 -21
  17. package/app/plugins/enabled.json +1 -0
  18. package/app/plugins/grok/plugin.mjs +278 -29
  19. package/app/plugins/hermes/plugin.mjs +143 -12
  20. package/app/plugins/kimi-code/plugin.mjs +140 -16
  21. package/app/plugins/kiro-cli/plugin.mjs +121 -10
  22. package/app/plugins/omp/plugin.mjs +2200 -2002
  23. package/app/plugins/opencode/plugin.mjs +137 -16
  24. package/app/plugins/pi/plugin.mjs +2563 -2282
  25. package/app/plugins/qoder/plugin.mjs +133 -14
  26. package/app/plugins/qoder-cn/plugin.mjs +133 -14
  27. package/app/plugins/workbuddy/plugin.mjs +603 -56
  28. package/app/plugins/zcode/plugin.mjs +133 -14
  29. package/app/renderer-extension.js +1171 -529
  30. package/bin/codexhost +0 -0
  31. package/libexec/codexhost-shim +0 -0
  32. package/libexec/codexhost-updater +0 -0
  33. package/package.json +1 -1
@@ -14604,6 +14604,15 @@ var harnessDisplaySetSchema = external_exports.strictObject({
14604
14604
  initializeOnly: external_exports.boolean().optional()
14605
14605
  });
14606
14606
 
14607
+ // ../../shared-contracts/dist/harness-presentation.js
14608
+ var localeSchema = external_exports.string().max(64).regex(/^[a-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$/u);
14609
+ var displayText = (maximum) => external_exports.string().min(1).max(maximum).refine((text2) => text2.trim().length > 0);
14610
+ var harnessLocalizationsSchema = external_exports.record(localeSchema, external_exports.object({
14611
+ label: displayText(256).optional(),
14612
+ description: displayText(1024).optional()
14613
+ }).strict()).refine((entries) => Object.keys(entries).length <= 16, "Too many locales");
14614
+ var harnessLocalizedTextSchema = external_exports.record(localeSchema, displayText(4096)).refine((entries) => typeof entries.en === "string", "English fallback is required").refine((entries) => Object.keys(entries).length <= 16, "Too many locales");
14615
+
14607
14616
  // ../../shared-contracts/dist/model-price-overrides.js
14608
14617
  var usdPerMillionTokens = external_exports.number().finite().nonnegative();
14609
14618
  var modelPriceOverrideSchema = external_exports.strictObject({
@@ -14653,10 +14662,19 @@ var model = external_exports.string().min(1).max(512);
14653
14662
  var project = external_exports.string().min(1).max(4096);
14654
14663
  var usageStatisticsParamsSchema = external_exports.strictObject({
14655
14664
  range: external_exports.enum(USAGE_STATISTICS_RANGES),
14665
+ /** Display timezone for ranges, dates and hourly buckets; omitted means the Host's local zone. */
14666
+ timeZone: external_exports.string().min(1).max(128).refine((value) => {
14667
+ try {
14668
+ new Intl.DateTimeFormat("en", { timeZone: value });
14669
+ return true;
14670
+ } catch {
14671
+ return false;
14672
+ }
14673
+ }, "Unsupported usage statistics timezone").optional(),
14656
14674
  harness: harness.optional(),
14657
14675
  model: model.nullable().optional(),
14658
14676
  project: project.nullable().optional(),
14659
- /** One local date inside the range. */
14677
+ /** One date in the query timezone inside the range. */
14660
14678
  date: localDate.optional()
14661
14679
  });
14662
14680
  var usageStatisticsTotalsSchema = external_exports.strictObject({
@@ -14692,7 +14710,7 @@ var usageStatisticsSessionSchema = external_exports.strictObject({
14692
14710
  });
14693
14711
  var usageStatisticsResultSchema = external_exports.strictObject({
14694
14712
  range: external_exports.enum(USAGE_STATISTICS_RANGES),
14695
- /** First local date of the range; null for all time. */
14713
+ /** First date in the query timezone (Host local when omitted); null for all time. */
14696
14714
  from: localDate.nullable(),
14697
14715
  to: localDate,
14698
14716
  /** The filters these figures apply, echoed so a late answer to older filters is recognised. */
@@ -14732,7 +14750,7 @@ var usageStatisticsResultSchema = external_exports.strictObject({
14732
14750
  totals: usageStatisticsTotalsSchema,
14733
14751
  /** Each date and Harness of the range: every filter except the day. */
14734
14752
  daily: external_exports.array(external_exports.strictObject({ date: localDate, harness, ...totals })).max(2e5),
14735
- /** Local weekday (0 = Sunday) and hour, all filters applied. */
14753
+ /** Weekday (0 = Sunday) and hour in the query timezone, all filters applied. */
14736
14754
  hourly: external_exports.array(external_exports.strictObject({
14737
14755
  weekday: external_exports.number().int().min(0).max(6),
14738
14756
  hour: external_exports.number().int().min(0).max(23),
@@ -14792,6 +14810,8 @@ var CONSOLE_HOST_METHODS = Object.freeze([
14792
14810
  "codexhost/harness/display-settings/set",
14793
14811
  "codexhost/harness/inspect",
14794
14812
  "codexhost/harness/installation",
14813
+ "codexhost/harness/installation/start",
14814
+ "codexhost/harness/installation/status",
14795
14815
  "codexhost/harness/launch-settings/get",
14796
14816
  "codexhost/harness/launch-settings/set",
14797
14817
  "codexhost/harness/web-ui/open",
@@ -14867,7 +14887,18 @@ var threadManualCompactionStartedSchema = external_exports.strictObject({
14867
14887
  var nonNegativeSafeIntegerSchema = external_exports.number().int().safe().nonnegative();
14868
14888
  var finiteNonNegativeNumberSchema = external_exports.number().finite().nonnegative();
14869
14889
  var cacheHitRatePercentSchema = external_exports.number().finite().min(0).max(100);
14890
+ var indicatorTextSchema = (maximum) => harnessLocalizedTextSchema.refine((entries) => Object.values(entries).every((text2) => text2.length <= maximum));
14891
+ var composerIndicatorsSchema = external_exports.array(external_exports.object({
14892
+ kind: external_exports.literal("countdown"),
14893
+ id: external_exports.string().min(1).max(64),
14894
+ expiresAtUnix: nonNegativeSafeIntegerSchema,
14895
+ label: indicatorTextSchema(256).optional(),
14896
+ tooltip: indicatorTextSchema(1024).optional()
14897
+ }).strict()).max(2).refine((entries) => new Set(entries.map(({ id }) => id)).size === entries.length, {
14898
+ message: "Composer indicator IDs must be unique"
14899
+ });
14870
14900
  var threadUsageSnapshotSchema = external_exports.object({
14901
+ composerIndicators: composerIndicatorsSchema.optional(),
14871
14902
  inputTokens: nonNegativeSafeIntegerSchema.optional(),
14872
14903
  cachedInputTokens: nonNegativeSafeIntegerSchema.optional(),
14873
14904
  cacheWriteInputTokens: nonNegativeSafeIntegerSchema.optional(),
@@ -14940,8 +14971,24 @@ var threadUsageSnapshotSchema = external_exports.object({
14940
14971
  }
14941
14972
  });
14942
14973
  var usagePercentSchema = external_exports.number().finite().min(0).max(100);
14974
+ var accountCreditsPeriodSchema = external_exports.enum([
14975
+ "weekly",
14976
+ "monthly",
14977
+ "five_hour",
14978
+ "seven_day",
14979
+ "unknown"
14980
+ ]);
14981
+ var accountCreditsScopeSchema = external_exports.object({
14982
+ id: external_exports.string().min(1).max(256),
14983
+ label: external_exports.string().min(1).max(256),
14984
+ localizations: harnessLocalizationsSchema.optional()
14985
+ }).strict();
14943
14986
  var accountCreditsProductUsageSchema = external_exports.object({
14944
14987
  product: external_exports.string().min(1),
14988
+ /** Native period and scope, never inferred from the display name. */
14989
+ periodType: accountCreditsPeriodSchema.optional(),
14990
+ scope: accountCreditsScopeSchema.optional(),
14991
+ localizations: harnessLocalizationsSchema.optional(),
14945
14992
  used: external_exports.number().finite().nonnegative().optional(),
14946
14993
  // Zero is a real empty cap, not an absent field.
14947
14994
  limit: external_exports.number().finite().nonnegative().optional(),
@@ -14961,9 +15008,11 @@ var accountCreditsSnapshotSchema = external_exports.object({
14961
15008
  unit: external_exports.string().min(1).max(32).optional(),
14962
15009
  /** Native label when the primary limit is scoped to a model or product group. */
14963
15010
  label: external_exports.string().min(1).optional(),
15011
+ scope: accountCreditsScopeSchema.optional(),
15012
+ localizations: harnessLocalizationsSchema.optional(),
14964
15013
  usedPercent: usagePercentSchema,
14965
15014
  resetsAt: external_exports.string().min(1).optional(),
14966
- periodType: external_exports.enum(["weekly", "monthly", "five_hour", "seven_day", "unknown"]),
15015
+ periodType: accountCreditsPeriodSchema,
14967
15016
  productUsage: external_exports.array(accountCreditsProductUsageSchema).min(1).optional(),
14968
15017
  resetCredits: accountResetCreditsSchema.optional()
14969
15018
  }).strict();
@@ -14974,7 +15023,9 @@ var threadUsageInspectionParamsSchema = external_exports.object({
14974
15023
  var threadUsageInspectionSchema = external_exports.object({
14975
15024
  threadId: hostThreadIdSchema,
14976
15025
  usage: threadUsageSnapshotSchema.nullable(),
14977
- accountCredits: accountCreditsSnapshotSchema.optional()
15026
+ accountCredits: accountCreditsSnapshotSchema.optional(),
15027
+ /** Whether this source can provide cached account quota independently of usage. */
15028
+ accountCreditsSupported: external_exports.boolean().optional()
14978
15029
  }).strict();
14979
15030
 
14980
15031
  // ../../shared-contracts/dist/harness-accounts.js
@@ -15101,7 +15152,8 @@ var harnessPermissionModeSchema = external_exports.object({
15101
15152
  id: harnessPermissionModeIdSchema,
15102
15153
  label: nonBlankTextSchema.max(HARNESS_PERMISSION_MODE_LABEL_MAX_LENGTH),
15103
15154
  description: nonBlankTextSchema.max(HARNESS_PERMISSION_MODE_DESCRIPTION_MAX_LENGTH).optional(),
15104
- dangerous: external_exports.boolean().optional()
15155
+ dangerous: external_exports.boolean().optional(),
15156
+ localizations: harnessLocalizationsSchema.optional()
15105
15157
  }).strict();
15106
15158
  var harnessPermissionModeCatalogSchema = external_exports.object({
15107
15159
  modes: external_exports.array(harnessPermissionModeSchema).min(1).max(HARNESS_PERMISSION_MODE_CATALOG_MAX_LENGTH),
@@ -15254,7 +15306,9 @@ var harnessSessionCapabilitiesSchema = external_exports.object({
15254
15306
  }).strict().optional(),
15255
15307
  autonomousTurns: external_exports.object({
15256
15308
  observe: external_exports.boolean()
15257
- }).strict().optional()
15309
+ }).strict().optional(),
15310
+ /** True only when `turn.steer` delivers input into the active Turn through a native primitive. */
15311
+ steer: external_exports.boolean().optional()
15258
15312
  }).strict();
15259
15313
  var harnessConfigurationStateSchema = external_exports.object({
15260
15314
  effectiveModel: harnessModelRefSchema.optional(),
@@ -15301,7 +15355,9 @@ var harnessInspectionSchema = external_exports.union([
15301
15355
  var harnessInspectParamsSchema = external_exports.object({
15302
15356
  harnessId: harnessIdSchema,
15303
15357
  cwd: nonBlankTextSchema2.max(16384).optional(),
15304
- refresh: external_exports.boolean().optional()
15358
+ refresh: external_exports.boolean().optional(),
15359
+ /** `availability` asks only whether the Harness can run; see `InspectHarnessInput.purpose`. */
15360
+ purpose: external_exports.literal("availability").optional()
15305
15361
  }).strict();
15306
15362
  var harnessWebUiOpenParamsSchema = external_exports.object({
15307
15363
  harnessId: harnessIdSchema
@@ -15384,6 +15440,15 @@ var threadOwnershipListResultSchema = external_exports.object({
15384
15440
  seen.add(thread.threadId);
15385
15441
  }
15386
15442
  });
15443
+ var threadSteeringInspectParamsSchema = external_exports.object({
15444
+ threadId: hostThreadIdSchema,
15445
+ /** The text about to be steered; a Harness command always stops and restarts. */
15446
+ text: external_exports.string().optional()
15447
+ }).strict();
15448
+ var threadSteerDeliverySchema = external_exports.enum(["activeTurn", "newTurn"]);
15449
+ var threadSteeringInspectResultSchema = external_exports.object({
15450
+ delivery: external_exports.enum(["official", "activeTurn", "newTurn"])
15451
+ }).strict();
15387
15452
 
15388
15453
  // ../../shared-contracts/dist/harness-plugins.js
15389
15454
  var HARNESS_PLUGIN_MANIFEST_MAX_BYTES = 32 * 1024;
@@ -15485,11 +15550,31 @@ var harnessInstallationStateSchema = external_exports.object({
15485
15550
  latestVersion: external_exports.string().min(1).max(128),
15486
15551
  updateAvailable: external_exports.boolean(),
15487
15552
  canUpdate: external_exports.boolean(),
15553
+ /** Defaults to CLI; some Harnesses ship only inside a desktop application. */
15554
+ versionKind: external_exports.enum(["cli", "application"]).optional(),
15555
+ /** Official download opened by the user; does not imply an automatic installation. */
15556
+ manualUpdateUrl: external_exports.url().max(2048).refine((value) => /^https:\/\/[^/?#@]+(?:[/?#]|$)/iu.test(value), "Manual updates require a credential-free HTTPS URL").optional(),
15488
15557
  // Adapter-owned diagnostic text; UI uses messageCode rather than displaying it verbatim.
15489
15558
  message: external_exports.string().max(2048).optional(),
15490
15559
  messageCode: external_exports.string().min(1).max(128).optional(),
15560
+ /** Safe plugin-owned explanation, distinct from raw diagnostic message. */
15561
+ notice: harnessLocalizedTextSchema.optional(),
15491
15562
  latestVersionKind: external_exports.enum(["unknown", "tracking-branch"]).optional()
15492
15563
  }).strict();
15564
+ var harnessInstallationTaskParamsSchema = external_exports.object({ taskId: external_exports.string().uuid() }).strict();
15565
+ var harnessInstallationTaskSchema = external_exports.discriminatedUnion("status", [
15566
+ external_exports.object({ taskId: external_exports.string().uuid(), status: external_exports.literal("running") }).strict(),
15567
+ external_exports.object({
15568
+ taskId: external_exports.string().uuid(),
15569
+ status: external_exports.literal("succeeded"),
15570
+ result: harnessInstallationStateSchema
15571
+ }).strict(),
15572
+ external_exports.object({
15573
+ taskId: external_exports.string().uuid(),
15574
+ status: external_exports.literal("failed"),
15575
+ error: external_exports.object({ code: external_exports.number().int(), message: external_exports.string().min(1).max(2048) }).strict()
15576
+ }).strict()
15577
+ ]);
15493
15578
 
15494
15579
  // ../../shared-contracts/dist/codex-accounts.js
15495
15580
  var accountIdSchema = external_exports.string().min(1).max(256).regex(/^[A-Za-z0-9._~-]+$/u);
@@ -15614,6 +15699,7 @@ var harnessCommandDescriptorSchema = external_exports.object({
15614
15699
  invocation: commandInvocationSchema,
15615
15700
  label: commandLabelSchema,
15616
15701
  description: commandDescriptionSchema.optional(),
15702
+ localizations: harnessLocalizationsSchema.optional(),
15617
15703
  argumentMode: external_exports.enum(["none", "text"]),
15618
15704
  /**
15619
15705
  * Native distinction reported by the Harness. Omitted when the Harness does
@@ -15991,6 +16077,18 @@ function sanitizeDiagnosticTail(value) {
15991
16077
  return redacted.length <= DIAGNOSTIC_TAIL_MAX_LENGTH ? redacted : redacted.slice(-DIAGNOSTIC_TAIL_MAX_LENGTH);
15992
16078
  }
15993
16079
 
16080
+ // ../../harness-adapter/dist/steer.js
16081
+ function unsupportedSteer(harnessLabel) {
16082
+ return {
16083
+ ok: false,
16084
+ error: {
16085
+ code: "unsupported",
16086
+ message: `${harnessLabel} cannot steer an active Turn natively`,
16087
+ retryable: false
16088
+ }
16089
+ };
16090
+ }
16091
+
15994
16092
  // ../../harness-adapter/dist/usage.js
15995
16093
  var tokenFields = [
15996
16094
  "inputTokens",
@@ -16018,6 +16116,7 @@ var usageFields = /* @__PURE__ */ new Set([
16018
16116
  ...safeIntegerFields,
16019
16117
  ...percentFields,
16020
16118
  "sessionCacheUsage",
16119
+ "composerIndicators",
16021
16120
  "totalCostUsd",
16022
16121
  "totalCredits",
16023
16122
  "contextUsagePercent",
@@ -16040,6 +16139,7 @@ function parseHostUsage(value) {
16040
16139
  throw new Error(`Harness Usage contains unknown field '${key}'`);
16041
16140
  }
16042
16141
  }
16142
+ const indicators = value.composerIndicators === void 0 ? {} : { composerIndicators: composerIndicatorsSchema.parse(value.composerIndicators) };
16043
16143
  for (const field of [
16044
16144
  "totalCredits",
16045
16145
  "contextUsagePercent",
@@ -16110,9 +16210,9 @@ function parseHostUsage(value) {
16110
16210
  if (value.costSource !== "publicPrice") {
16111
16211
  throw new Error("Harness Usage 'unpricedModels' must be provided with a 'publicPrice' cost");
16112
16212
  }
16113
- return { ...value, unpricedModels: [...models] };
16213
+ return { ...value, ...indicators, unpricedModels: [...models] };
16114
16214
  }
16115
- return { ...value };
16215
+ return { ...value, ...indicators };
16116
16216
  }
16117
16217
  var requestTokenFields = [
16118
16218
  "inputTokens",
@@ -16269,6 +16369,7 @@ var harnessBrokerMethodSchema = external_exports.enum([
16269
16369
  "adapter.open",
16270
16370
  "adapter.subagent.readSnapshot",
16271
16371
  "session.readSnapshot",
16372
+ "session.readCapabilities",
16272
16373
  "session.refreshUsage",
16273
16374
  "session.execute",
16274
16375
  "session.commands.list",
@@ -16449,6 +16550,11 @@ var turnStartSchema = external_exports.object({
16449
16550
  turnId: hostTurnIdSchema,
16450
16551
  input: external_exports.array(textInputSchema)
16451
16552
  }).strict();
16553
+ var turnSteerSchema = external_exports.object({
16554
+ type: external_exports.literal("turn.steer"),
16555
+ turnId: hostTurnIdSchema,
16556
+ input: external_exports.array(textInputSchema)
16557
+ }).strict();
16452
16558
  var turnCancelSchema = external_exports.object({ type: external_exports.literal("turn.cancel"), turnId: hostTurnIdSchema }).strict();
16453
16559
  var interactionResponseSchema = external_exports.union([
16454
16560
  external_exports.object({
@@ -16474,6 +16580,7 @@ var permissionSelectSchema = external_exports.object({
16474
16580
  }).strict();
16475
16581
  var brokerHostCommandSchema = external_exports.discriminatedUnion("type", [
16476
16582
  turnStartSchema,
16583
+ turnSteerSchema,
16477
16584
  turnCancelSchema,
16478
16585
  interactionRespondSchema,
16479
16586
  modelSelectSchema,
@@ -16666,6 +16773,7 @@ function parseSessionMetadata(value) {
16666
16773
  sessionId: candidate.sessionId,
16667
16774
  sessionGeneration: candidate.sessionGeneration,
16668
16775
  capabilities: harnessSessionCapabilitiesSchema.parse(candidate.capabilities),
16776
+ readCapabilities: candidate.readCapabilities === true,
16669
16777
  initialState: state,
16670
16778
  initialUsage: candidate.initialUsage === null ? null : parseHostUsage(candidate.initialUsage),
16671
16779
  commands: candidate.commands === true
@@ -17017,6 +17125,11 @@ var BrokeredHarnessSession = class {
17017
17125
  event: { type: "session.faulted", error: unavailable(error51.message) }
17018
17126
  });
17019
17127
  }
17128
+ async readCapabilities() {
17129
+ if (!this.#metadata.readCapabilities)
17130
+ return { ...this.capabilities, steer: false };
17131
+ return harnessSessionCapabilitiesSchema.parse(await this.#request("session.readCapabilities", {}));
17132
+ }
17020
17133
  async refreshUsage() {
17021
17134
  await this.#request("session.refreshUsage", {});
17022
17135
  }
@@ -17048,6 +17161,8 @@ var BrokeredHarnessSession = class {
17048
17161
  try {
17049
17162
  return parseHarnessResult(await this.#request("session.execute", { command }));
17050
17163
  } catch (error51) {
17164
+ if (command.type === "turn.steer")
17165
+ throw error51;
17051
17166
  return {
17052
17167
  ok: false,
17053
17168
  error: unavailable(error51 instanceof Error ? error51.message : String(error51))
@@ -17135,6 +17250,8 @@ var BrokeredHarnessAdapter = class {
17135
17250
  commandCatalog;
17136
17251
  liveCommandCatalog;
17137
17252
  harnessId;
17253
+ credits;
17254
+ refreshCredits;
17138
17255
  #descriptorPath;
17139
17256
  #forwardEnvironment;
17140
17257
  #isInstalled;
@@ -17155,6 +17272,10 @@ var BrokeredHarnessAdapter = class {
17155
17272
  };
17156
17273
  constructor(input = {}) {
17157
17274
  this.harnessId = harnessPluginIdSchema.parse(input.harnessId ?? "claude-code");
17275
+ if (input.accountCredits !== false) {
17276
+ this.credits = () => this.#credits;
17277
+ this.refreshCredits = () => this.#refreshAccountCredits();
17278
+ }
17158
17279
  this.#forwardEnvironment = input.forwardDelegationEnvironment === true;
17159
17280
  if (input.commandCatalog)
17160
17281
  this.commandCatalog = input.commandCatalog;
@@ -17166,10 +17287,7 @@ var BrokeredHarnessAdapter = class {
17166
17287
  this.#startBroker = input.startBroker === false ? void 0 : input.startBroker ?? (process.platform === "darwin" && !input.descriptorPath ? () => startBrokerLaunchAgent(this.harnessId, environment) : void 0);
17167
17288
  this.#startTimeoutMs = input.startTimeoutMs ?? BROKER_START_TIMEOUT_MS;
17168
17289
  }
17169
- credits() {
17170
- return this.#credits;
17171
- }
17172
- refreshCredits() {
17290
+ #refreshAccountCredits() {
17173
17291
  if (this.#closed)
17174
17292
  return Promise.resolve(null);
17175
17293
  if (this.#creditsRefresh)
@@ -17355,10 +17473,13 @@ function usageSessionTitle(value) {
17355
17473
  return void 0;
17356
17474
  if (normalized.length <= MAX_SESSION_TITLE_LENGTH)
17357
17475
  return normalized;
17358
- const characters = [...normalized];
17359
- if (characters.length <= MAX_SESSION_TITLE_LENGTH)
17360
- return normalized;
17361
- return `${characters.slice(0, MAX_SESSION_TITLE_LENGTH - 1).join("").trimEnd()}…`;
17476
+ let title = "";
17477
+ for (const character of normalized) {
17478
+ if (title.length + character.length >= MAX_SESSION_TITLE_LENGTH)
17479
+ break;
17480
+ title += character;
17481
+ }
17482
+ return `${title.trimEnd()}…`;
17362
17483
  }
17363
17484
  function sessionIdOk(value) {
17364
17485
  return typeof value === "string" && value.length > 0 && value.length <= MAX_SESSION_ID_LENGTH;
@@ -17487,6 +17608,27 @@ function nativeError(error51, profile = CODEBUDDY_RUNTIME_PROFILE) {
17487
17608
  function failure(code, message, profile = CODEBUDDY_RUNTIME_PROFILE) {
17488
17609
  return { ok: false, error: nativeError(new CodeBuddyError(code, message), profile) };
17489
17610
  }
17611
+ function nativeTurnError(stopReason, meta3, profile) {
17612
+ const fallback = `Native Turn stopped: ${text(stopReason) || "unknown"} (${text(meta3["codebuddy.ai/outcome"]) || "no native outcome"})`;
17613
+ const raw = text(meta3["codebuddy.ai/errorMessage"]).trim();
17614
+ let diagnostic = "";
17615
+ let category;
17616
+ if (raw) {
17617
+ try {
17618
+ const error51 = record2(JSON.parse(raw));
17619
+ const data = record2(error51.data);
17620
+ diagnostic = text(data.details).trim() || text(error51.message).trim();
17621
+ category = data.category;
17622
+ } catch {
17623
+ diagnostic = raw;
17624
+ }
17625
+ }
17626
+ return nativeError(new CodeBuddyError(
17627
+ // -32000 is shared by native refusals; the category identifies authentication failures.
17628
+ category === "auth" ? "authenticationRequired" : "nativeFailure",
17629
+ diagnostic ? `${fallback}: ${diagnostic}` : fallback
17630
+ ), profile);
17631
+ }
17490
17632
  async function bounded(operation, milliseconds, label, onTimeout) {
17491
17633
  let timer;
17492
17634
  try {
@@ -17508,6 +17650,40 @@ async function bounded(operation, milliseconds, label, onTimeout) {
17508
17650
  }
17509
17651
  }
17510
17652
 
17653
+ // ../codebuddy/dist/permission-presentation.js
17654
+ var labels = {
17655
+ "Always Ask": "始终询问",
17656
+ "Accept Edits": "接受编辑",
17657
+ Plan: "规划模式",
17658
+ Auto: "自动",
17659
+ "Auto mode": "自动模式",
17660
+ "Don't Ask": "不询问",
17661
+ "Bypass Permissions": "绕过权限",
17662
+ "Full Access": "完全访问",
17663
+ Delegate: "由父会话管理",
17664
+ Default: "默认"
17665
+ };
17666
+ var descriptions = {
17667
+ "Prompts for permission on first use of each tool": "首次使用每种工具时请求权限。",
17668
+ "Automatically accepts file edit permissions for the session": "自动接受本会话中的文件编辑权限。",
17669
+ "Agent can analyze but not modify files or execute commands": "Agent 可以分析,但不能修改文件或执行命令。",
17670
+ "An AI classifier reviews actions that would normally prompt: safe ones are auto-approved, risky ones are denied. If the classifier is unavailable, the action falls back to a prompt (or is denied when prompts cannot be shown)": "由 AI 分类器评估原本需要询问的操作:安全操作自动批准,风险操作拒绝。分类器不可用时改为询问;无法显示询问时拒绝。",
17671
+ "Does not show permission prompts; pre-approved and safe read-only actions run, everything else that would prompt is denied": "不显示权限询问;已获批准和安全的只读操作可以执行,其余原本需要询问的操作会被拒绝。",
17672
+ "Skips all permission prompts": "跳过常规权限询问。",
17673
+ "Skips ALL permission checks including dangerous commands for all agents": "为所有 Agent 跳过全部权限检查,包括危险命令。",
17674
+ "Permissions managed by parent session": "由父会话管理权限。"
17675
+ };
17676
+ function permissionLocalizations(label, description) {
17677
+ const localizedLabel = Object.hasOwn(labels, label) ? labels[label] : void 0;
17678
+ const localizedDescription = Object.hasOwn(descriptions, description) ? descriptions[description] : void 0;
17679
+ return {
17680
+ "zh-CN": {
17681
+ ...localizedLabel ? { label: localizedLabel } : {},
17682
+ ...localizedDescription ? { description: localizedDescription } : {}
17683
+ }
17684
+ };
17685
+ }
17686
+
17511
17687
  // ../codebuddy/dist/configuration.js
17512
17688
  var CODEBUDDY_CAPABILITIES = {
17513
17689
  configuration: {
@@ -17565,6 +17741,7 @@ function configuration(value, profile = CODEBUDDY_RUNTIME_PROFILE) {
17565
17741
  modes: rows(mode.options).map((option) => ({
17566
17742
  id: option.value,
17567
17743
  label: option.name,
17744
+ localizations: permissionLocalizations(text(option.name), text(option.description)),
17568
17745
  ...option.description ? { description: option.description } : {},
17569
17746
  ...["bypassPermissions", "fullAccess"].includes(text(option.value)) ? { dangerous: true } : {}
17570
17747
  })),
@@ -18051,6 +18228,11 @@ function commandCatalog(value, profile = CODEBUDDY_RUNTIME_PROFILE) {
18051
18228
  id: `${profile.harnessId}.${name}`,
18052
18229
  invocation: `/${name}`,
18053
18230
  label: name,
18231
+ ...name === "compact" && !skill ? {
18232
+ localizations: {
18233
+ "zh-CN": { label: "压缩上下文", description: "压缩当前对话上下文" }
18234
+ }
18235
+ } : {},
18054
18236
  ...text(entry.description).trim() ? { description: text(entry.description).trim().slice(0, 512) } : {},
18055
18237
  argumentMode: name === "compact" || record2(entry.input).hint || record2(entry._meta).type === "skill" ? "text" : "none",
18056
18238
  ...record2(entry._meta).type === "skill" ? { kind: "skill" } : {}
@@ -18939,7 +19121,7 @@ function createCodeBuddyUsageStatistics(environment, profile) {
18939
19121
  import { stat as stat3 } from "node:fs/promises";
18940
19122
 
18941
19123
  // ../codebuddy/dist/acp-client.js
18942
- import { execFile as execFile2, spawn } from "node:child_process";
19124
+ import { execFile as execFile3, spawn } from "node:child_process";
18943
19125
  import { Readable as Readable2, Writable } from "node:stream";
18944
19126
 
18945
19127
  // ../../../node_modules/@agentclientprotocol/sdk/dist/schema/index.js
@@ -23104,9 +23286,23 @@ var ClientSideConnection = class {
23104
23286
 
23105
23287
  // ../codebuddy/dist/copy-cleanup.js
23106
23288
  import { randomBytes } from "node:crypto";
23289
+
23290
+ // ../codebuddy/dist/acp-stdio.js
23107
23291
  import { createInterface as createInterface2 } from "node:readline";
23108
- import { stripVTControlCharacters } from "node:util";
23109
23292
  import { Readable } from "node:stream";
23293
+ import { stripVTControlCharacters } from "node:util";
23294
+ function codeBuddyAcpOutput(stdout, onLine) {
23295
+ return Readable.from((async function* () {
23296
+ for await (const line of createInterface2({ input: stdout })) {
23297
+ onLine?.(stripVTControlCharacters(line));
23298
+ if (line.trimStart().startsWith("{"))
23299
+ yield Buffer.from(`${line}
23300
+ `);
23301
+ }
23302
+ })());
23303
+ }
23304
+
23305
+ // ../codebuddy/dist/copy-cleanup.js
23110
23306
  var CodeBuddyCopyCleanup = class {
23111
23307
  copyId;
23112
23308
  cwd;
@@ -23136,17 +23332,11 @@ var CodeBuddyCopyCleanup = class {
23136
23332
  }
23137
23333
  /** Native --serve banners include its password; never pass them to the ACP parser/logs. */
23138
23334
  protocolOutput(stdout) {
23139
- return Readable.from(this.#protocolLines(stdout));
23140
- }
23141
- async *#protocolLines(stdout) {
23142
- for await (const line of createInterface2({ input: stdout })) {
23143
- const endpoint = /^\s*Endpoint\s+(http:\/\/127\.0\.0\.1:\d+)\s*$/u.exec(stripVTControlCharacters(line));
23335
+ return codeBuddyAcpOutput(stdout, (line) => {
23336
+ const endpoint = /^\s*Endpoint\s+(http:\/\/127\.0\.0\.1:\d+)\s*$/u.exec(line);
23144
23337
  if (endpoint)
23145
23338
  this.#endpoint = endpoint[1];
23146
- if (line.trimStart().startsWith("{"))
23147
- yield Buffer.from(`${line}
23148
- `);
23149
- }
23339
+ });
23150
23340
  }
23151
23341
  async remove() {
23152
23342
  if (!this.#endpoint)
@@ -23411,6 +23601,88 @@ function resolveHarnessExecutable(spec, input, dependencies = {}) {
23411
23601
  return void 0;
23412
23602
  }
23413
23603
 
23604
+ // ../../harness-discovery/dist/installation.js
23605
+ import { execFile as execFile2 } from "node:child_process";
23606
+ import { homedir as homedir2 } from "node:os";
23607
+ function runInstallationCommand(command, args, environment, timeout = 3e4) {
23608
+ const env = withNodeRuntimeOnPath(environment);
23609
+ const invocation = /\.[cm]?js$/i.test(command) ? commandInvocation(process.execPath, [command, ...args], env) : commandInvocation(command, args, env);
23610
+ return new Promise((resolve, reject) => {
23611
+ const child = execFile2(invocation.command, invocation.arguments, {
23612
+ env,
23613
+ cwd: env.HOME ?? env.USERPROFILE ?? homedir2(),
23614
+ encoding: "utf8",
23615
+ timeout,
23616
+ killSignal: "SIGKILL",
23617
+ maxBuffer: 1024 * 1024,
23618
+ windowsHide: true,
23619
+ windowsVerbatimArguments: invocation.windowsVerbatimArguments
23620
+ }, (error51, stdout, stderr) => {
23621
+ if (error51)
23622
+ reject(new Error(error51.killed ? "Harness command timed out" : "Harness command failed; check the native installation and retry"));
23623
+ else
23624
+ resolve((stdout || stderr).trim());
23625
+ });
23626
+ child.stdin?.end();
23627
+ });
23628
+ }
23629
+ function installationVersion(value) {
23630
+ if (typeof value !== "string" || !/^v?\d+(?:\.\d+){1,3}(?:-[\w.-]+)?(?:\+[\w.-]+)?$/.test(value.trim()))
23631
+ throw new Error("Harness returned an invalid version");
23632
+ return value.trim().replace(/^v/, "");
23633
+ }
23634
+ function versionFromOutput(output) {
23635
+ return installationVersion(output.match(/\b\d+(?:\.\d+){1,3}(?:-[\w.-]+)?(?:\+[\w.-]+)?\b/)?.[0]);
23636
+ }
23637
+ function newerInstallationVersion(current, latest) {
23638
+ const a = installationVersion(current).replace(/\+.*/, "");
23639
+ const b = installationVersion(latest).replace(/\+.*/, "");
23640
+ const coreA = a.replace(/-.*/, "").split(".").map(BigInt);
23641
+ const coreB = b.replace(/-.*/, "").split(".").map(BigInt);
23642
+ for (let i = 0; i < Math.max(coreA.length, coreB.length); i++) {
23643
+ if ((coreA[i] ?? 0n) !== (coreB[i] ?? 0n))
23644
+ return (coreB[i] ?? 0n) > (coreA[i] ?? 0n);
23645
+ }
23646
+ const preA = a.includes("-") ? a.slice(a.indexOf("-") + 1).split(".") : [];
23647
+ const preB = b.includes("-") ? b.slice(b.indexOf("-") + 1).split(".") : [];
23648
+ if (!preA.length || !preB.length)
23649
+ return !!preA.length && !preB.length;
23650
+ for (let i = 0; i < Math.max(preA.length, preB.length); i++) {
23651
+ const x = preA[i];
23652
+ const y = preB[i];
23653
+ if (x === y)
23654
+ continue;
23655
+ if (x === void 0 || y === void 0)
23656
+ return x === void 0;
23657
+ const numericX = /^\d+$/.test(x);
23658
+ const numericY = /^\d+$/.test(y);
23659
+ if (numericX && numericY) {
23660
+ if (BigInt(x) === BigInt(y))
23661
+ continue;
23662
+ return BigInt(y) > BigInt(x);
23663
+ }
23664
+ if (numericX !== numericY)
23665
+ return numericX;
23666
+ return y > x;
23667
+ }
23668
+ return false;
23669
+ }
23670
+ async function fetchInstallationText(url2) {
23671
+ const request = async () => {
23672
+ const response = await fetch(url2, { signal: AbortSignal.timeout(15e3) });
23673
+ if (!response.ok)
23674
+ throw new Error("Could not check the latest Harness version");
23675
+ return response.text();
23676
+ };
23677
+ try {
23678
+ return await request();
23679
+ } catch (error51) {
23680
+ if (error51 instanceof DOMException && (error51.name === "AbortError" || error51.name === "TimeoutError"))
23681
+ throw error51;
23682
+ return request();
23683
+ }
23684
+ }
23685
+
23414
23686
  // ../codebuddy/dist/command.js
23415
23687
  var codeBuddyDiscoverySpec = {
23416
23688
  id: "codebuddy",
@@ -23510,7 +23782,7 @@ var CodeBuddyAcpClient = class {
23510
23782
  return { outcome: "cancelled" };
23511
23783
  return options.handlers.question(params);
23512
23784
  }
23513
- }), ndJsonStream2(Writable.toWeb(this.#child.stdin), Readable2.toWeb(this.#copyCleanup?.protocolOutput(this.#child.stdout) ?? this.#child.stdout)));
23785
+ }), ndJsonStream2(Writable.toWeb(this.#child.stdin), Readable2.toWeb(this.#copyCleanup?.protocolOutput(this.#child.stdout) ?? (invocation.arguments.includes("--serve") ? codeBuddyAcpOutput(this.#child.stdout) : this.#child.stdout))));
23514
23786
  void this.#connection.closed.then(() => {
23515
23787
  this.#fault(new CodeBuddyError("processExited", "ACP connection closed"));
23516
23788
  }).catch((error51) => {
@@ -23603,7 +23875,7 @@ var CodeBuddyAcpClient = class {
23603
23875
  }
23604
23876
  const pid = this.#child.pid;
23605
23877
  if (pid && process.platform === "win32") {
23606
- await new Promise((resolve) => execFile2("taskkill", ["/PID", String(pid), "/T", "/F"], { windowsHide: true, timeout: 3e3 }, () => resolve()));
23878
+ await new Promise((resolve) => execFile3("taskkill", ["/PID", String(pid), "/T", "/F"], { windowsHide: true, timeout: 3e3 }, () => resolve()));
23607
23879
  } else if (pid) {
23608
23880
  try {
23609
23881
  process.kill(-pid, "SIGKILL");
@@ -23616,7 +23888,7 @@ var CodeBuddyAcpClient = class {
23616
23888
 
23617
23889
  // ../codebuddy/dist/derivation.js
23618
23890
  import { randomUUID as randomUUID3 } from "node:crypto";
23619
- import { execFile as execFile3, spawn as spawn2 } from "node:child_process";
23891
+ import { execFile as execFile4, spawn as spawn2 } from "node:child_process";
23620
23892
  import { lstat as lstat3, mkdir, readFile as readFile3, realpath as realpath4, unlink, writeFile } from "node:fs/promises";
23621
23893
  import path8 from "node:path";
23622
23894
  import { isDeepStrictEqual as isDeepStrictEqual3 } from "node:util";
@@ -23866,7 +24138,7 @@ async function copyCodeBuddySession(cwd, sourceId, targetId, environment, signal
23866
24138
  child.stderr.destroy();
23867
24139
  } else if (process.platform === "win32" && child.pid) {
23868
24140
  termination = new Promise((done) => {
23869
- execFile3("taskkill", ["/PID", String(child.pid), "/T", "/F"], { windowsHide: true, timeout: 3e3 }, () => {
24141
+ execFile4("taskkill", ["/PID", String(child.pid), "/T", "/F"], { windowsHide: true, timeout: 3e3 }, () => {
23870
24142
  child.kill();
23871
24143
  done();
23872
24144
  });
@@ -25537,6 +25809,8 @@ var CodeBuddySession = class {
25537
25809
  async #execute(command, nativeCommand = false) {
25538
25810
  if (this.#closed || this.#fault)
25539
25811
  return failure("invalidState", "Session is closed or faulted", this.profile);
25812
+ if (command.type === "turn.steer")
25813
+ return unsupportedSteer(this.profile.displayName);
25540
25814
  if (command.type === "interaction.respond")
25541
25815
  return this.#interactions.respond(command);
25542
25816
  if (command.type === "turn.cancel") {
@@ -25606,7 +25880,7 @@ var CodeBuddySession = class {
25606
25880
  // Those remain visible on individual Items; they do not fail the completed Turn.
25607
25881
  (!meta3["codebuddy.ai/outcome"] || meta3["codebuddy.ai/outcome"] === "SUCCESS" || meta3["codebuddy.ai/outcome"] === "PARTIAL_SUCCESS") ? { status: "succeeded" } : {
25608
25882
  status: "failed",
25609
- error: nativeError(new CodeBuddyError("nativeFailure", `Native Turn stopped: ${text(stop) || "unknown"} (${text(meta3["codebuddy.ai/outcome"]) || "no native outcome"})`), this.profile)
25883
+ error: nativeTurnError(stop, meta3, this.profile)
25610
25884
  };
25611
25885
  const snapshot = await this.#snapshot();
25612
25886
  const added = snapshot.turns.filter((turn) => !active.before.has(turn.nativeTurnRef.nativeTurnKey));
@@ -25895,8 +26169,9 @@ var CodeBuddyAdapter = class {
25895
26169
  };
25896
26170
 
25897
26171
  // dist/command.js
25898
- import { lstatSync } from "node:fs";
25899
- import { homedir as homedir2 } from "node:os";
26172
+ import { lstatSync, statSync } from "node:fs";
26173
+ import { randomBytes as randomBytes2 } from "node:crypto";
26174
+ import { homedir as homedir3 } from "node:os";
25900
26175
 
25901
26176
  // dist/delegation.js
25902
26177
  var DELEGATION_ENVIRONMENT_KEYS = [
@@ -25913,6 +26188,170 @@ function workBuddyDelegationArguments(environment, ephemeral) {
25913
26188
  return ["--append-system-prompt", WORKBUDDY_DELEGATION_INSTRUCTIONS];
25914
26189
  }
25915
26190
 
26191
+ // dist/credential-bootstrap.js
26192
+ var WORKBUDDY_CREDENTIAL_PRELOAD = String.raw`
26193
+ (() => {
26194
+ const env = process.env;
26195
+ const bootstrapEnvironment = [
26196
+ "CODEBUDDY_SIDECAR_CREDENTIAL_BOOTSTRAP_SOCKET",
26197
+ "CODEBUDDY_SIDECAR_READY_SOCKET",
26198
+ "CODEBUDDY_SIDECAR_READY_TOKEN",
26199
+ "CODEBUDDY_SIDECAR_READY_SESSION_ID",
26200
+ ];
26201
+ if (bootstrapEnvironment.some(name => env[name] !== undefined)) {
26202
+ if (!["WORKBUDDY_AT_REST_ENCRYPTION", ...bootstrapEnvironment].every(name => env[name]?.trim())) {
26203
+ throw Error("WorkBuddy credential bootstrap environment is incomplete");
26204
+ }
26205
+ return;
26206
+ }
26207
+ const policy = env.WORKBUDDY_AT_REST_ENCRYPTION?.trim();
26208
+ // Other explicit policies remain owned by the native CLI.
26209
+ if (policy && policy !== "fields") return;
26210
+
26211
+ let provider;
26212
+ try {
26213
+ provider = process._linkedBinding("electron_browser_workbuddy_storage");
26214
+ } catch {
26215
+ // Older app runtimes predate encrypted credential fields.
26216
+ return;
26217
+ }
26218
+ const crypto = require("node:crypto");
26219
+ const net = require("node:net");
26220
+ const fs = require("node:fs");
26221
+ const path = require("node:path");
26222
+ let payload;
26223
+ try { payload = JSON.parse(provider.loggerGet()); }
26224
+ catch { throw Error("WorkBuddy credential key provider is unavailable"); }
26225
+ let secret = payload && payload.atRestSecretKey;
26226
+ const decoded = typeof secret === "string" ? Buffer.from(secret, "base64") : Buffer.alloc(0);
26227
+ const valid = payload && payload.version === 1 && decoded.length === 32 &&
26228
+ decoded.toString("base64") === secret && !decoded.every(byte => byte === 0);
26229
+ decoded.fill(0);
26230
+ if (!valid) throw Error("WorkBuddy credential key payload is unsupported");
26231
+ // Match the native normalizeAtRestKeyPayload; the base64 text is hashed, not its decoded bytes.
26232
+ const key = crypto.createHash("sha256").update(secret, "utf8").digest();
26233
+ secret = undefined;
26234
+ payload = undefined;
26235
+ const token = crypto.randomBytes(24).toString("hex");
26236
+ const sessionId = crypto.randomUUID();
26237
+ let directory;
26238
+ let socketPath;
26239
+ if (process.platform === "win32") {
26240
+ socketPath = "\\\\.\\pipe\\codexhost-wb-" + process.pid + "-" + token;
26241
+ } else {
26242
+ let root = require("node:os").tmpdir();
26243
+ if (Buffer.byteLength(root) > 65) root = "/tmp";
26244
+ directory = fs.mkdtempSync(path.join(root, "ch-wb-"));
26245
+ fs.chmodSync(directory, 0o700);
26246
+ socketPath = path.join(directory, "c");
26247
+ }
26248
+ const cleanup = () => {
26249
+ clearTimeout(readyTimer);
26250
+ readyServer && readyServer.close();
26251
+ for (const connection of readyConnections) connection.destroy();
26252
+ if (directory) try { fs.rmSync(directory, {recursive:true,force:true}); } catch {}
26253
+ };
26254
+ const needsReady = process.argv.includes("--serve");
26255
+ let credentialReady = false;
26256
+ let runtimeReady = !needsReady;
26257
+ let readyTimer;
26258
+ let readyServer;
26259
+ const readyConnections = new Set();
26260
+ const cleanupWhenReady = () => {
26261
+ if (!credentialReady || !runtimeReady) return;
26262
+ cleanup();
26263
+ process.removeListener("exit", cleanup);
26264
+ };
26265
+ if (needsReady) {
26266
+ readyServer = net.createServer(connection => {
26267
+ readyConnections.add(connection);
26268
+ connection.once("close", () => readyConnections.delete(connection));
26269
+ connection.on("error", () => connection.destroy());
26270
+ let input = "";
26271
+ connection.on("data", chunk => {
26272
+ input += chunk;
26273
+ if (input.length > 4096) return connection.destroy();
26274
+ if (!input.includes("\n")) return;
26275
+ try {
26276
+ const request = JSON.parse(input.slice(0, input.indexOf("\n")));
26277
+ const params = request.params;
26278
+ if (request.jsonrpc !== "2.0" || request.method !== "session.ready" ||
26279
+ typeof request.id !== "string" || params?.protocolVersion !== 1 ||
26280
+ params.token !== token || params.sessionId !== sessionId || params.pid !== process.pid ||
26281
+ !Number.isInteger(params.port) || params.port < 1 || params.port > 65535) {
26282
+ connection.destroy();
26283
+ return;
26284
+ }
26285
+ runtimeReady = true;
26286
+ connection.end(JSON.stringify({jsonrpc:"2.0",id:request.id,result:{ok:true}}) + "\n", cleanupWhenReady);
26287
+ } catch { connection.destroy(); }
26288
+ });
26289
+ });
26290
+ readyServer.once("error", () => {
26291
+ process.stderr.write("WorkBuddy runtime readiness listener failed\n");
26292
+ process.exit(1);
26293
+ });
26294
+ readyServer.listen(socketPath + "-ready");
26295
+ readyTimer = setTimeout(() => {
26296
+ process.stderr.write("WorkBuddy runtime readiness timed out\n");
26297
+ process.exit(1);
26298
+ }, 15000);
26299
+ }
26300
+ process.once("exit", cleanup);
26301
+ Object.assign(env, {
26302
+ WORKBUDDY_AT_REST_ENCRYPTION: "fields",
26303
+ CODEBUDDY_SIDECAR_CREDENTIAL_BOOTSTRAP_SOCKET: socketPath,
26304
+ CODEBUDDY_SIDECAR_READY_SOCKET: socketPath + "-ready",
26305
+ CODEBUDDY_SIDECAR_READY_TOKEN: token,
26306
+ CODEBUDDY_SIDECAR_READY_SESSION_ID: sessionId,
26307
+ });
26308
+ let message = JSON.stringify({version:1,sessionId,token,pid:process.pid,bootstrap:{
26309
+ version:1,policy:"fields",
26310
+ symmetricKey:{keyId:crypto.createHash("sha256").update(key).digest("hex").slice(0,16),keyBase64:key.toString("base64")},
26311
+ asymmetricUnavailable:"missing-key",
26312
+ }}) + "\n";
26313
+ key.fill(0);
26314
+ let done = false;
26315
+ let socket;
26316
+ const finish = success => {
26317
+ if (done) return;
26318
+ done = true;
26319
+ clearTimeout(timer);
26320
+ socket && socket.destroy();
26321
+ message = "";
26322
+ credentialReady = success;
26323
+ if (success) cleanupWhenReady();
26324
+ if (!success) {
26325
+ process.stderr.write("WorkBuddy credential bootstrap failed\n");
26326
+ process.exit(1);
26327
+ }
26328
+ };
26329
+ const timer = setTimeout(() => finish(false), 4500);
26330
+ const connect = () => {
26331
+ if (done) return;
26332
+ socket = net.createConnection(socketPath);
26333
+ let reply = "";
26334
+ socket.once("connect", () => socket.end(message, () => { message = ""; }));
26335
+ socket.on("data", chunk => {
26336
+ reply += chunk;
26337
+ if (reply.length > 1024) return finish(false);
26338
+ if (!reply.includes("\n")) return;
26339
+ try {
26340
+ const result = JSON.parse(reply.slice(0, reply.indexOf("\n")));
26341
+ finish(result.ok === true && result.policy === "fields");
26342
+ } catch { finish(false); }
26343
+ });
26344
+ socket.once("end", () => { if (!done) finish(false); });
26345
+ socket.once("error", error => {
26346
+ socket.destroy();
26347
+ if (error.code === "ENOENT" || error.code === "ECONNREFUSED") setTimeout(connect, 20);
26348
+ else finish(false);
26349
+ });
26350
+ };
26351
+ setImmediate(connect);
26352
+ })();
26353
+ `;
26354
+
25916
26355
  // dist/discovery.js
25917
26356
  var WORKBUDDY_MACOS_ELECTRON = "/Applications/WorkBuddy AI.app/Contents/MacOS/Electron";
25918
26357
  var windowsRoots = [
@@ -26020,7 +26459,7 @@ function bundledProductConfigPath(environment, platform, dependencies) {
26020
26459
  function workBuddyEnvironment(environment, platform = process.platform) {
26021
26460
  const paths = targetPath(platform);
26022
26461
  const configuredRoot = environment.WORKBUDDY_CONFIG_DIR;
26023
- const root = paths.resolve(configuredRoot?.trim() ? configuredRoot : paths.join(environment.HOME || environment.USERPROFILE || homedir2(), ".workbuddy-ai"));
26462
+ const root = paths.resolve(configuredRoot?.trim() ? configuredRoot : paths.join(environment.HOME || environment.USERPROFILE || homedir3(), ".workbuddy-ai"));
26024
26463
  return {
26025
26464
  ...environment,
26026
26465
  // The bundled core reads CODEBUDDY_CONFIG_DIR. Force both names to one
@@ -26030,9 +26469,7 @@ function workBuddyEnvironment(environment, platform = process.platform) {
26030
26469
  DISABLE_AUTOUPDATER: environment.DISABLE_AUTOUPDATER ?? "1"
26031
26470
  };
26032
26471
  }
26033
- function workBuddyInvocation(environment, ephemeral, dependenciesOrArguments = {}, argumentsOverride) {
26034
- const dependencies = Array.isArray(dependenciesOrArguments) ? {} : dependenciesOrArguments;
26035
- const nativeArguments = Array.isArray(dependenciesOrArguments) ? dependenciesOrArguments : argumentsOverride;
26472
+ function resolveWorkBuddyLaunch(environment, dependencies = {}) {
26036
26473
  const platform = dependencies.platform ?? process.platform;
26037
26474
  const configured = environmentValue(environment, "CODEXHOST_WORKBUDDY_COMMAND")?.trim() || void 0;
26038
26475
  if (!configured && platform !== "darwin" && platform !== "win32")
@@ -26045,6 +26482,29 @@ function workBuddyInvocation(environment, ephemeral, dependenciesOrArguments = {
26045
26482
  const executable = configured && !explicitDesktop && !configuredDirectory ? explicitExecutable : bundle?.executable;
26046
26483
  if (!executable)
26047
26484
  throw new CodeBuddyError("notInstalled", "WorkBuddy AI app or its bundled CLI is unavailable");
26485
+ return { executable, bundle };
26486
+ }
26487
+ function workBuddyInvocation(environment, ephemeral, dependenciesOrArguments = {}, argumentsOverride) {
26488
+ const dependencies = Array.isArray(dependenciesOrArguments) ? {} : dependenciesOrArguments;
26489
+ const nativeArguments = Array.isArray(dependenciesOrArguments) ? dependenciesOrArguments : argumentsOverride;
26490
+ const platform = dependencies.platform ?? process.platform;
26491
+ const { executable, bundle } = resolveWorkBuddyLaunch(environment, dependencies);
26492
+ const paths = targetPath(platform);
26493
+ const cliDist = bundle && paths.join(paths.dirname(paths.dirname(bundle.cli)), "dist");
26494
+ const isFile = dependencies.isFile ?? ((candidate) => {
26495
+ try {
26496
+ return statSync(candidate).isFile();
26497
+ } catch {
26498
+ return false;
26499
+ }
26500
+ });
26501
+ const liteOnly = Boolean(cliDist && isFile(paths.join(cliDist, "codebuddy-lite-wb.mjs")) && !isFile(paths.join(cliDist, "codebuddy.js")) && !isFile(paths.join(cliDist, "codebuddy-headless.js")));
26502
+ const acpArguments = nativeArguments ?? [
26503
+ "--acp",
26504
+ ...ephemeral ? ["--no-session-persistence"] : [],
26505
+ ...workBuddyDelegationArguments(environment, ephemeral)
26506
+ ];
26507
+ const serve = liteOnly && acpArguments.includes("--acp") && !acpArguments.includes("--serve");
26048
26508
  const configuredEnvironment = withNodeRuntimeOnPath(workBuddyEnvironment(environment, platform), process.execPath, platform);
26049
26509
  const productConfigPath = bundle ? bundledProductConfigPath(configuredEnvironment, platform, dependencies) : void 0;
26050
26510
  const childEnvironment = bundle ? {
@@ -26053,16 +26513,20 @@ function workBuddyInvocation(environment, ephemeral, dependenciesOrArguments = {
26053
26513
  // waits for its telemetry channel before copying; normal ACP keeps its policy.
26054
26514
  ...nativeArguments?.includes("--print") && nativeArguments.includes("--fork-session") && configuredEnvironment.DISABLE_TELEMETRY === void 0 ? { DISABLE_TELEMETRY: "1" } : {},
26055
26515
  ...productConfigPath ? { [WORKBUDDY_PRODUCT_CONFIG_PATH_ENV]: productConfigPath } : {},
26516
+ ...liteOnly ? { CODEBUDDY_FORCE_LITE_WB_BUNDLE: "1" } : {},
26517
+ ...serve ? {
26518
+ CODEBUDDY_GATEWAY_AUTH: "password",
26519
+ CODEBUDDY_GATEWAY_PASSWORD: randomBytes2(32).toString("base64url"),
26520
+ CODEBUDDY_GATEWAY_BASE_PATH: ""
26521
+ } : {},
26056
26522
  ELECTRON_RUN_AS_NODE: "1"
26057
26523
  } : configuredEnvironment;
26058
26524
  return {
26059
26525
  ...commandInvocation(executable, [
26060
- ...bundle ? [bundle.cli] : [],
26061
- ...nativeArguments ?? [
26062
- "--acp",
26063
- ...ephemeral ? ["--no-session-persistence"] : [],
26064
- ...workBuddyDelegationArguments(childEnvironment, ephemeral)
26065
- ]
26526
+ ...bundle ? ["--eval", `${WORKBUDDY_CREDENTIAL_PRELOAD}
26527
+ require(process.argv[1]);`, bundle.cli] : [],
26528
+ ...acpArguments,
26529
+ ...serve ? ["--serve", "--host", "127.0.0.1", "--port", "0", "--auth", "password"] : []
26066
26530
  ], childEnvironment, platform),
26067
26531
  environment: childEnvironment
26068
26532
  };
@@ -26075,6 +26539,7 @@ var WORKBUDDY_COMMAND_CATALOG = harnessCommandCatalogSchema.parse({
26075
26539
  {
26076
26540
  id: "workbuddy.compact",
26077
26541
  invocation: "/compact",
26542
+ localizations: { "zh-CN": { label: "压缩上下文", description: "压缩当前对话上下文" } },
26078
26543
  label: "Compact context",
26079
26544
  description: "Compact the current WorkBuddy Session context",
26080
26545
  argumentMode: "text"
@@ -26202,15 +26667,15 @@ function normalizedLabel(value) {
26202
26667
  }
26203
26668
  function mergeWorkBuddyProductModels(catalog, productModels) {
26204
26669
  const refs = new Set(catalog.models.map((model2) => model2.ref.id));
26205
- const labels = new Set(catalog.models.map((model2) => normalizedLabel(model2.label)));
26670
+ const labels2 = new Set(catalog.models.map((model2) => normalizedLabel(model2.label)));
26206
26671
  const models = [...catalog.models];
26207
26672
  for (const productModel of productModels) {
26208
26673
  const ref = modelRef(productModel.id);
26209
26674
  const labelKey = normalizedLabel(productModel.name);
26210
- if (refs.has(ref.id) || labels.has(labelKey))
26675
+ if (refs.has(ref.id) || labels2.has(labelKey))
26211
26676
  continue;
26212
26677
  refs.add(ref.id);
26213
- labels.add(labelKey);
26678
+ labels2.add(labelKey);
26214
26679
  const creditLabel = productModel.credits?.replace(/^x/iu, "").replace(/\s*credits$/iu, "x");
26215
26680
  const annotatedLabel = creditLabel ? `${productModel.name} · ${creditLabel}` : productModel.name;
26216
26681
  models.push({
@@ -26266,21 +26731,102 @@ var WorkBuddyAdapter = class extends CodeBuddyAdapter {
26266
26731
  }
26267
26732
  };
26268
26733
 
26734
+ // dist/installation.js
26735
+ import { readFile as readFile6, stat as stat5 } from "node:fs/promises";
26736
+ var applicationNotice = {
26737
+ en: "These are WorkBuddy desktop app versions. Its bundled CLI updates with the app. Download the official installer, complete installation, then reopen Connections to verify the version. Existing sessions keep their running CLI.",
26738
+ "zh-CN": "此处显示 WorkBuddy 桌面应用版本,内置 CLI 随应用更新。请下载官方安装包并完成安装,再重新打开连接页确认版本。已有会话继续使用运行中的 CLI。"
26739
+ };
26740
+ function appVersion(value) {
26741
+ const version2 = installationVersion(value);
26742
+ return version2.replace(/^(\d+\.\d+\.\d+)\.\d+$/u, "$1");
26743
+ }
26744
+ async function readProduct(file2) {
26745
+ const metadata = await stat5(file2);
26746
+ if (!metadata.isFile() || metadata.size <= 0 || metadata.size > 8 * 1024 * 1024)
26747
+ throw new Error("WorkBuddy product metadata is unavailable");
26748
+ return JSON.parse(await readFile6(file2, "utf8"));
26749
+ }
26750
+ function createWorkBuddyInstallation(environment, dependencies = {}) {
26751
+ const platform = dependencies.platform ?? process.platform;
26752
+ const arch = dependencies.arch ?? process.arch;
26753
+ return async (action) => {
26754
+ if (action === "update")
26755
+ throw new Error("Complete the update with WorkBuddy's official desktop installer");
26756
+ const { executable, bundle } = resolveWorkBuddyLaunch(environment, { platform });
26757
+ if (!bundle)
26758
+ return {
26759
+ currentVersion: versionFromOutput(await runInstallationCommand(executable, ["--version"], environment)),
26760
+ latestVersion: "Unknown",
26761
+ latestVersionKind: "unknown",
26762
+ updateAvailable: false,
26763
+ canUpdate: false,
26764
+ notice: {
26765
+ en: "This is a custom CLI. Use its original installer to update; WorkBuddy desktop releases do not identify this CLI's latest version.",
26766
+ "zh-CN": "当前使用自定义 CLI,请通过原安装方式更新;WorkBuddy 桌面应用版本不代表此 CLI 的最新版本。"
26767
+ }
26768
+ };
26769
+ const paths = targetPath(platform);
26770
+ const product = await (dependencies.readProduct ?? readProduct)(paths.join(paths.dirname(paths.dirname(bundle.cli)), "product.json"));
26771
+ const currentVersion = appVersion(product.genieVersion);
26772
+ const unknown2 = {
26773
+ currentVersion,
26774
+ versionKind: "application",
26775
+ latestVersion: "Unknown",
26776
+ latestVersionKind: "unknown",
26777
+ updateAvailable: false,
26778
+ canUpdate: false,
26779
+ notice: {
26780
+ en: "The installed WorkBuddy desktop app version is shown. Check and install updates in WorkBuddy itself; this installation's update channel could not be checked here.",
26781
+ "zh-CN": "此处显示已安装的 WorkBuddy 桌面应用版本。当前无法查询此安装的更新渠道,请在 WorkBuddy 应用内检查并安装更新。"
26782
+ }
26783
+ };
26784
+ const root = product.applicationName === "workbuddy-ai" && product.updateUrl === "https://www.workbuddy.ai" ? "https://www.workbuddy.ai" : product.applicationName === "workbuddy" && product.updateUrl === "https://www.workbuddy.cn" ? "https://www.workbuddy.cn" : void 0;
26785
+ const target = platform === "darwin" && (arch === "arm64" || arch === "x64") ? `darwin-${arch}` : platform === "win32" && arch === "x64" ? "win32-x64-user" : void 0;
26786
+ if (!root || !target || environment.WORKBUDDY_UPDATE_URL?.trim() && environment.WORKBUDDY_UPDATE_URL.trim() !== root)
26787
+ return unknown2;
26788
+ try {
26789
+ const feed = JSON.parse(await (dependencies.fetchText ?? fetchInstallationText)(`${root}/v2/update?platform=workbuddy-${target}`));
26790
+ const feedVersion = installationVersion(feed.version);
26791
+ const latestVersion = appVersion(feedVersion);
26792
+ const download = new URL(typeof feed.url === "string" ? feed.url : "");
26793
+ const downloadHost = root.endsWith(".ai") ? "download.codebuddy.ai" : "download.codebuddy.cn";
26794
+ if (download.origin !== `https://${downloadHost}` || download.username || download.password || download.search || download.hash || !download.pathname.startsWith(`/workbuddy/saas/${target}/WorkBuddy-${target}-${feedVersion}-`) || !download.pathname.endsWith(platform === "darwin" ? ".zip" : ".exe"))
26795
+ throw new Error("WorkBuddy update feed returned an invalid installer URL");
26796
+ if (platform === "darwin")
26797
+ download.pathname = download.pathname.replace(/\.zip$/u, ".dmg");
26798
+ const updateAvailable = newerInstallationVersion(currentVersion, latestVersion);
26799
+ return {
26800
+ currentVersion,
26801
+ versionKind: "application",
26802
+ latestVersion,
26803
+ updateAvailable,
26804
+ canUpdate: false,
26805
+ ...updateAvailable ? { manualUpdateUrl: download.href } : {},
26806
+ notice: applicationNotice
26807
+ };
26808
+ } catch {
26809
+ return unknown2;
26810
+ }
26811
+ };
26812
+ }
26813
+
26269
26814
  // dist/plugin.js
26270
26815
  function createHarnessAdapter(context) {
26271
26816
  if (context.platform === "darwin" && context.managedRemoteHost) {
26272
- const environment = {
26817
+ const environment2 = {
26273
26818
  ...context.environment,
26274
26819
  ...context.launchCommand ? { CODEXHOST_WORKBUDDY_COMMAND: context.launchCommand } : {}
26275
26820
  };
26276
26821
  return new BrokeredHarnessAdapter({
26822
+ accountCredits: false,
26277
26823
  harnessId: "workbuddy",
26278
26824
  commandCatalog: WORKBUDDY_COMMAND_CATALOG,
26279
26825
  forwardDelegationEnvironment: true,
26280
26826
  environment: { ...context.environment },
26281
26827
  isInstalled: () => {
26282
26828
  try {
26283
- workBuddyInvocation(environment, true);
26829
+ workBuddyInvocation(environment2, true);
26284
26830
  return true;
26285
26831
  } catch (error51) {
26286
26832
  return !(error51 instanceof CodeBuddyError && error51.code === "notInstalled");
@@ -26289,11 +26835,12 @@ function createHarnessAdapter(context) {
26289
26835
  ...context.brokerDescriptorPath ? { descriptorPath: context.brokerDescriptorPath } : {}
26290
26836
  });
26291
26837
  }
26292
- return new WorkBuddyAdapter({
26293
- environment: {
26294
- ...context.environment,
26295
- ...context.launchCommand ? { CODEXHOST_WORKBUDDY_COMMAND: context.launchCommand } : {}
26296
- }
26838
+ const environment = {
26839
+ ...context.environment,
26840
+ ...context.launchCommand ? { CODEXHOST_WORKBUDDY_COMMAND: context.launchCommand } : {}
26841
+ };
26842
+ return Object.assign(new WorkBuddyAdapter({ environment }), {
26843
+ installation: createWorkBuddyInstallation(environment)
26297
26844
  });
26298
26845
  }
26299
26846
  export {