proxitor 0.17.0 → 0.18.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.
package/README.md CHANGED
@@ -197,6 +197,8 @@ Common flags: `--port`, `--host`, `--config <path>`, `--openrouter-key <key>` /
197
197
 
198
198
  **Anthropic returns `400` about mixed TTLs when `cacheControlTtl: 1h`.** Set `rewriteBlockTtl: auto` (or `always`) to normalize the client's block-level `cache_control` breakpoints to the same TTL — see the [configuration reference](./docs/configuration.md#prompt-caching).
199
199
 
200
+ **OpenRouter returns `400 invalid_prompt | Invalid Responses API request` on `/v1/responses`.** Some clients send Responses `input` items without the `type` field OpenRouter requires. `normalizeResponses: auto` (the default) tags them, lifts `role:"system"` into `instructions`, and adds the `id`/`status` OpenRouter wants on assistant history. Set it to `skip` only for raw passthrough.
201
+
200
202
  **The provider keeps switching between requests.** Make sure `sessionId` is not `skip` — both `auto` (default) and `always` inject a sticky session ID; without it OpenRouter only pins after the first cache hit.
201
203
 
202
204
  **Config edits don't take effect.** They should — proxitor hot-reloads on save. If the file is invalid the proxy keeps the last valid config; `proxitor config validate` shows what was rejected.
package/dist/cli.mjs CHANGED
@@ -14,7 +14,7 @@ import { STATUS_CODES, createServer as createServer$1 } from "node:http";
14
14
  import { Http2ServerRequest, constants } from "node:http2";
15
15
  import { Readable } from "node:stream";
16
16
  import { readFile, writeFile } from "node:fs/promises";
17
- import { createHash } from "node:crypto";
17
+ import { createHash, randomUUID } from "node:crypto";
18
18
  //#region \0rolldown/runtime.js
19
19
  var __defProp = Object.defineProperty;
20
20
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -12217,7 +12217,7 @@ const allowsEval = /* @__PURE__*/ cached(() => {
12217
12217
  return false;
12218
12218
  }
12219
12219
  });
12220
- function isPlainObject$2(o) {
12220
+ function isPlainObject$3(o) {
12221
12221
  if (isObject(o) === false) return false;
12222
12222
  const ctor = o.constructor;
12223
12223
  if (ctor === void 0) return true;
@@ -12228,7 +12228,7 @@ function isPlainObject$2(o) {
12228
12228
  return true;
12229
12229
  }
12230
12230
  function shallowClone(o) {
12231
- if (isPlainObject$2(o)) return { ...o };
12231
+ if (isPlainObject$3(o)) return { ...o };
12232
12232
  if (Array.isArray(o)) return [...o];
12233
12233
  if (o instanceof Map) return new Map(o);
12234
12234
  if (o instanceof Set) return new Set(o);
@@ -12311,7 +12311,7 @@ function omit(schema, mask) {
12311
12311
  }));
12312
12312
  }
12313
12313
  function extend(schema, shape) {
12314
- if (!isPlainObject$2(shape)) throw new Error("Invalid input to extend: expected a plain object");
12314
+ if (!isPlainObject$3(shape)) throw new Error("Invalid input to extend: expected a plain object");
12315
12315
  const checks = schema._zod.def.checks;
12316
12316
  if (checks && checks.length > 0) {
12317
12317
  const existingShape = schema._zod.def.shape;
@@ -12327,7 +12327,7 @@ function extend(schema, shape) {
12327
12327
  } }));
12328
12328
  }
12329
12329
  function safeExtend(schema, shape) {
12330
- if (!isPlainObject$2(shape)) throw new Error("Invalid input to safeExtend: expected a plain object");
12330
+ if (!isPlainObject$3(shape)) throw new Error("Invalid input to safeExtend: expected a plain object");
12331
12331
  return clone(schema, mergeDefs(schema._zod.def, { get shape() {
12332
12332
  const _shape = {
12333
12333
  ...schema._zod.def.shape,
@@ -13862,7 +13862,7 @@ function mergeValues(a, b) {
13862
13862
  valid: true,
13863
13863
  data: a
13864
13864
  };
13865
- if (isPlainObject$2(a) && isPlainObject$2(b)) {
13865
+ if (isPlainObject$3(a) && isPlainObject$3(b)) {
13866
13866
  const bKeys = Object.keys(b);
13867
13867
  const sharedKeys = Object.keys(a).filter((key) => bKeys.indexOf(key) !== -1);
13868
13868
  const newObj = {
@@ -13938,7 +13938,7 @@ const $ZodRecord = /*@__PURE__*/ $constructor("$ZodRecord", (inst, def) => {
13938
13938
  $ZodType.init(inst, def);
13939
13939
  inst._zod.parse = (payload, ctx) => {
13940
13940
  const input = payload.value;
13941
- if (!isPlainObject$2(input)) {
13941
+ if (!isPlainObject$3(input)) {
13942
13942
  payload.issues.push({
13943
13943
  expected: "record",
13944
13944
  code: "invalid_type",
@@ -16293,6 +16293,7 @@ const modelOverrideSchema = object({
16293
16293
  cacheControlTtl: ttlSchema.optional(),
16294
16294
  rewriteBlockTtl: triStateSchema.optional(),
16295
16295
  sessionId: triStateSchema.optional(),
16296
+ normalizeResponses: triStateSchema.optional(),
16296
16297
  normalizeVolatileSystem: boolean().optional()
16297
16298
  }).strict();
16298
16299
  const proxyConfigSchema = object({
@@ -16312,6 +16313,7 @@ const proxyConfigSchema = object({
16312
16313
  cacheControlTtl: ttlSchema.optional(),
16313
16314
  rewriteBlockTtl: triStateSchema.default("skip"),
16314
16315
  sessionId: triStateSchema.default("auto"),
16316
+ normalizeResponses: triStateSchema.default("auto"),
16315
16317
  normalizeVolatileSystem: boolean().default(false),
16316
16318
  observability: observabilityConfigSchema,
16317
16319
  modelOverrides: record(string$1().min(1), modelOverrideSchema).optional()
@@ -16488,6 +16490,7 @@ function resolveModelConfig(config, modelName) {
16488
16490
  cacheControlTtl: config.cacheControlTtl,
16489
16491
  rewriteBlockTtl: config.rewriteBlockTtl,
16490
16492
  sessionId: config.sessionId,
16493
+ normalizeResponses: config.normalizeResponses,
16491
16494
  normalizeVolatileSystem: config.normalizeVolatileSystem
16492
16495
  };
16493
16496
  if (!modelName || !config.modelOverrides) return result;
@@ -16521,6 +16524,7 @@ function applyOverride(result, override) {
16521
16524
  if (override.cacheControlTtl !== void 0) result.cacheControlTtl = override.cacheControlTtl;
16522
16525
  if (override.rewriteBlockTtl !== void 0) result.rewriteBlockTtl = override.rewriteBlockTtl;
16523
16526
  if (override.sessionId !== void 0) result.sessionId = override.sessionId;
16527
+ if (override.normalizeResponses !== void 0) result.normalizeResponses = override.normalizeResponses;
16524
16528
  if (override.normalizeVolatileSystem !== void 0) result.normalizeVolatileSystem = override.normalizeVolatileSystem;
16525
16529
  }
16526
16530
  /** Reject base URLs ending in /v1 — paths are forwarded as-is, so /v1 suffix causes doubled paths. */
@@ -16822,11 +16826,11 @@ function createDefu(merger) {
16822
16826
  return (...arguments_) => arguments_.reduce((p, c) => _defu(p, c, "", merger), {});
16823
16827
  }
16824
16828
  const defu = createDefu();
16825
- function isPlainObject(obj) {
16829
+ function isPlainObject$2(obj) {
16826
16830
  return Object.prototype.toString.call(obj) === "[object Object]";
16827
16831
  }
16828
16832
  function isLogObj(arg) {
16829
- if (!isPlainObject(arg)) return false;
16833
+ if (!isPlainObject$2(arg)) return false;
16830
16834
  if (!arg.message && !arg.args) return false;
16831
16835
  if (arg.stack) return false;
16832
16836
  return true;
@@ -18119,6 +18123,12 @@ const REWRITE_HINTS = {
18119
18123
  always: "All models",
18120
18124
  skip: "Leave client block ttl as-is (may mismatch root)"
18121
18125
  };
18126
+ /** Shared hint texts for the normalize-responses tri-state — used in the Fixes menu + override editor. */
18127
+ const NORMALIZE_RESPONSES_HINTS = {
18128
+ auto: "/v1/responses only (default)",
18129
+ always: "All endpoints",
18130
+ skip: "Off — raw passthrough (OpenRouter may reject)"
18131
+ };
18122
18132
  const NORMALIZE_HINTS = {
18123
18133
  on: "Rewrite cch → stable prefix cache",
18124
18134
  off: "Passthrough — rewrite nothing"
@@ -18223,6 +18233,12 @@ async function collectSessionTriState(currentSid) {
18223
18233
  if (sid === "reset") return { sessionId: { remove: true } };
18224
18234
  return { sessionId: { value: sid } };
18225
18235
  }
18236
+ async function collectNormalizeResponsesTriState(currentNr) {
18237
+ const nr = await askTriState("normalizeResponses mode", currentNr, NORMALIZE_RESPONSES_HINTS, { removable: true });
18238
+ if (typeof nr === "symbol") return null;
18239
+ if (nr === "reset") return { normalizeResponses: { remove: true } };
18240
+ return { normalizeResponses: { value: nr } };
18241
+ }
18226
18242
  /**
18227
18243
  * Collects cacheControl mode, TTL, and rewriteBlockTtl.
18228
18244
  * Mode-cancel aborts; TTL-cancel keeps existing TTL; rewrite-cancel keeps existing rewrite.
@@ -18670,6 +18686,13 @@ async function editSessionId(current) {
18670
18686
  applyField(next, "sessionId", result.sessionId);
18671
18687
  return next;
18672
18688
  }
18689
+ async function editNormalizeResponses(current) {
18690
+ const result = await collectNormalizeResponsesTriState(current.normalizeResponses);
18691
+ if (result === null) return current;
18692
+ const next = { ...current };
18693
+ applyField(next, "normalizeResponses", result.normalizeResponses);
18694
+ return next;
18695
+ }
18673
18696
  async function editCacheControl(current, configPath) {
18674
18697
  const globalTtl = readGlobalTtl(configPath);
18675
18698
  const result = await collectCacheTriState(current.cacheControl, current.cacheControlTtl, globalTtl, current.rewriteBlockTtl);
@@ -18777,6 +18800,83 @@ async function cachingCommand(opts) {
18777
18800
  outro("Bye!");
18778
18801
  }
18779
18802
  //#endregion
18803
+ //#region src/commands/config/normalize-responses.ts
18804
+ async function normalizeResponsesCommand(opts) {
18805
+ const configPath = requireConfigPath(opts?.configPath);
18806
+ const raw = readConfigFileRaw(configPath).normalizeResponses;
18807
+ const effective = raw ?? DEFAULTS.normalizeResponses;
18808
+ log.info(`Current: normalizeResponses = ${raw === void 0 ? `(default -> ${effective})` : effective}`);
18809
+ const result = await askTriState("normalizeResponses mode", raw, NORMALIZE_RESPONSES_HINTS, { removable: true });
18810
+ if (typeof result === "symbol") return;
18811
+ if (result === "reset") {
18812
+ setGlobalConfigField(configPath, "normalizeResponses", void 0);
18813
+ log.success("normalizeResponses reset to default (auto)");
18814
+ return;
18815
+ }
18816
+ setGlobalConfigField(configPath, "normalizeResponses", result);
18817
+ log.success(`normalizeResponses set to ${result}`);
18818
+ }
18819
+ //#endregion
18820
+ //#region src/commands/config/fixes-menu.ts
18821
+ /** Compatibility fixes for request bodies OpenRouter rejects. Mirrors caching-menu's lever table. */
18822
+ const FIXES_LEVERS = [{
18823
+ value: "normalizeResponses",
18824
+ label: "Repair /v1/responses bodies (normalizeResponses)",
18825
+ global: (configPath) => normalizeResponsesCommand({ configPath }),
18826
+ perModel: (current) => editNormalizeResponses(current)
18827
+ }];
18828
+ async function runFixesLeverMenu(opts) {
18829
+ for (;;) {
18830
+ note(opts.renderNote(), opts.noteTitle);
18831
+ const choice = await select({
18832
+ message: "Tune which fix?",
18833
+ options: [...FIXES_LEVERS.map((lever) => ({
18834
+ value: lever.value,
18835
+ label: lever.label
18836
+ })), {
18837
+ value: "back",
18838
+ label: opts.backLabel
18839
+ }]
18840
+ });
18841
+ if (isCancel(choice) || choice === "back") return;
18842
+ const chosen = FIXES_LEVERS.find((l) => l.value === choice);
18843
+ if (chosen) await opts.onLever(chosen);
18844
+ }
18845
+ }
18846
+ async function globalFixesMenu(opts) {
18847
+ const configPath = requireConfigPath(opts?.configPath);
18848
+ await runFixesLeverMenu({
18849
+ noteTitle: "Fixes",
18850
+ backLabel: "← Back",
18851
+ renderNote: () => {
18852
+ return `normalizeResponses: ${readConfigFileRaw(configPath).normalizeResponses ?? "(default → auto)"}`;
18853
+ },
18854
+ onLever: (lever) => lever.global(configPath)
18855
+ });
18856
+ }
18857
+ /** Self-persists each lever; returns the latest override. */
18858
+ async function perModelFixesMenu(opts) {
18859
+ let current = opts.current;
18860
+ await runFixesLeverMenu({
18861
+ noteTitle: `Fixes for "${opts.modelKey}"`,
18862
+ backLabel: "← Back to override edit",
18863
+ renderNote: () => `normalizeResponses: ${current.normalizeResponses ?? "(inherit)"}`,
18864
+ onLever: async (lever) => {
18865
+ const next = await lever.perModel(current);
18866
+ if (!overridesEqual(next, current)) {
18867
+ setModelOverride(opts.configPath, opts.modelKey, next);
18868
+ current = next;
18869
+ }
18870
+ }
18871
+ });
18872
+ return current;
18873
+ }
18874
+ async function fixesCommand(opts) {
18875
+ intro("Proxitor · Fixes");
18876
+ await globalFixesMenu(opts);
18877
+ outro("Bye!");
18878
+ }
18879
+ //#endregion
18780
18880
  //#region src/commands/config/edit.ts
18781
18881
  function nvsHint(value) {
18782
18882
  if (value === void 0) return "(inherit)";
@@ -18792,12 +18892,16 @@ function formatOverrideHint(override) {
18792
18892
  if (override.sessionId) parts.push(`session: ${override.sessionId}`);
18793
18893
  if (override.cacheControl) parts.push(`cache: ${override.cacheControl}`);
18794
18894
  if (override.normalizeVolatileSystem !== void 0) parts.push(`normalize: ${nvsHint(override.normalizeVolatileSystem)}`);
18895
+ if (override.normalizeResponses) parts.push(`fix: ${override.normalizeResponses}`);
18795
18896
  if (override.headers) parts.push(`${Object.keys(override.headers).length} header(s)`);
18796
18897
  return parts.join(", ") || "(empty)";
18797
18898
  }
18798
18899
  function formatCachingHint(current) {
18799
18900
  return `cc ${current.cacheControl ?? "inherit"} · ttl ${current.cacheControlTtl ? describeTtl(current.cacheControlTtl) : "inherit"} · sid ${current.sessionId ?? "inherit"} · nvs ${nvsHint(current.normalizeVolatileSystem)}`;
18800
18901
  }
18902
+ function formatFixesHint(current) {
18903
+ return `normalizeResponses: ${current.normalizeResponses ?? "inherit"}`;
18904
+ }
18801
18905
  async function editProvider(modelKey, current, client) {
18802
18906
  const isPattern = modelKey.includes("*");
18803
18907
  const mode = await selectRoutingMode("Routing mode");
@@ -18851,6 +18955,11 @@ async function editOverrideCommand(client, configPath) {
18851
18955
  label: "💾 Caching",
18852
18956
  hint: formatCachingHint(current)
18853
18957
  },
18958
+ {
18959
+ value: "fixes",
18960
+ label: "🛠 Fixes",
18961
+ hint: formatFixesHint(current)
18962
+ },
18854
18963
  {
18855
18964
  value: "done",
18856
18965
  label: "✓ Done"
@@ -18866,6 +18975,14 @@ async function editOverrideCommand(client, configPath) {
18866
18975
  });
18867
18976
  continue;
18868
18977
  }
18978
+ if (field === "fixes") {
18979
+ current = await perModelFixesMenu({
18980
+ modelKey,
18981
+ current,
18982
+ configPath: resolvedConfigPath
18983
+ });
18984
+ continue;
18985
+ }
18869
18986
  const before = current;
18870
18987
  current = await editProvider(modelKey, current, client);
18871
18988
  if (!overridesEqual(current, before)) setModelOverride(resolvedConfigPath, modelKey, current);
@@ -19493,6 +19610,10 @@ async function runConfigMenu(client) {
19493
19610
  value: "caching",
19494
19611
  label: "💾 Caching"
19495
19612
  },
19613
+ {
19614
+ value: "fixes",
19615
+ label: "🛠 Fixes"
19616
+ },
19496
19617
  {
19497
19618
  value: "_sep2",
19498
19619
  label: "── Model Overrides ──",
@@ -19547,6 +19668,9 @@ async function runConfigMenu(client) {
19547
19668
  case "caching":
19548
19669
  await globalCachingMenu();
19549
19670
  break;
19671
+ case "fixes":
19672
+ await globalFixesMenu();
19673
+ break;
19550
19674
  case "add":
19551
19675
  await addOverrideCommand({ client });
19552
19676
  break;
@@ -19570,7 +19694,7 @@ async function runConfigMenu(client) {
19570
19694
  }
19571
19695
  //#endregion
19572
19696
  //#region src/version.ts
19573
- const version = "0.17.0";
19697
+ const version = "0.18.0";
19574
19698
  //#endregion
19575
19699
  //#region src/commands/doctor.ts
19576
19700
  const DEFAULT_TIMEOUT_MS = 3e3;
@@ -23426,7 +23550,12 @@ function rewriteBlockTtls(body, ttl, isAnthropic) {
23426
23550
  visitBlocks(body.system);
23427
23551
  visitBlocks(body.tools);
23428
23552
  const messages = body.messages;
23429
- for (const m of messages ?? []) visitBlocks(m?.content);
23553
+ for (const m of messages ?? []) {
23554
+ if (m === null || typeof m !== "object" || Array.isArray(m)) continue;
23555
+ rewriteNode(m);
23556
+ visitBlocks(m.content);
23557
+ visitBlocks(m.tool_calls);
23558
+ }
23430
23559
  return mutated;
23431
23560
  }
23432
23561
  //#endregion
@@ -23527,6 +23656,105 @@ const injectSessionId = createMiddleware(async (c, next) => {
23527
23656
  await next();
23528
23657
  });
23529
23658
  //#endregion
23659
+ //#region src/proxy/utils/responses-input.ts
23660
+ /**
23661
+ * Whether to normalize a Responses-api body. Mirrors the other tri-states:
23662
+ * `auto` acts only on /v1/responses, `always` acts everywhere, `skip` never.
23663
+ */
23664
+ function shouldNormalizeResponses(mode, path) {
23665
+ if (mode === "skip") return false;
23666
+ if (mode === "always") return true;
23667
+ return classifyEndpoint(path) === "responses";
23668
+ }
23669
+ function isPlainObject(value) {
23670
+ return value !== null && typeof value === "object" && !Array.isArray(value);
23671
+ }
23672
+ /** Flatten a Responses content value (string or block array) to plain text. */
23673
+ function contentToText(content) {
23674
+ if (typeof content === "string") return content;
23675
+ if (!Array.isArray(content)) return void 0;
23676
+ const parts = [];
23677
+ for (const block of content) {
23678
+ const text = isPlainObject(block) ? block.text : void 0;
23679
+ if (typeof text === "string") parts.push(text);
23680
+ }
23681
+ return parts.length > 0 ? parts.join("\n") : void 0;
23682
+ }
23683
+ function appendInstructions(current, text) {
23684
+ return typeof current === "string" ? `${current}\n\n${text}` : text;
23685
+ }
23686
+ /** Tag a role-bearing message item and complete assistant-history metadata. */
23687
+ function tagMessageItem(obj) {
23688
+ let changed = false;
23689
+ if (typeof obj.role === "string" && obj.type === void 0) {
23690
+ obj.type = "message";
23691
+ changed = true;
23692
+ }
23693
+ if (obj.type === "message" && obj.role === "assistant") {
23694
+ if (obj.id === void 0) {
23695
+ obj.id = `msg_${randomUUID().slice(0, 12)}`;
23696
+ changed = true;
23697
+ }
23698
+ if (obj.status === void 0) {
23699
+ obj.status = "completed";
23700
+ changed = true;
23701
+ }
23702
+ }
23703
+ return changed;
23704
+ }
23705
+ /**
23706
+ * Lift a `role: "system"` item: OpenRouter Responses has no system role in
23707
+ * `input`, so its text moves to `instructions`. Items with no extractable text
23708
+ * (image-only/empty) can't be represented there and are dropped — keeping them
23709
+ * as `role: "system"` would reproduce the rejection this normalizer exists to fix.
23710
+ */
23711
+ function handleSystemItem(obj, state) {
23712
+ const text = contentToText(obj.content);
23713
+ if (text !== void 0) state.instructions = appendInstructions(state.instructions, text);
23714
+ }
23715
+ /**
23716
+ * Make a Responses body satisfy OpenRouter's `input` schema. Each item is a
23717
+ * `type`-discriminated union, so items missing `type` (OpenAI infers "message")
23718
+ * are rejected as `invalid_prompt`. Also relocates `role: "system"` items to
23719
+ * `instructions` and synthesizes the `id`/`status` assistant history requires.
23720
+ * Idempotent; returns whether the body changed.
23721
+ */
23722
+ function normalizeResponsesInput(body) {
23723
+ const input = body.input;
23724
+ if (!Array.isArray(input)) return false;
23725
+ let mutated = false;
23726
+ const state = {
23727
+ instructions: body.instructions,
23728
+ next: []
23729
+ };
23730
+ for (const raw of input) {
23731
+ if (!isPlainObject(raw)) {
23732
+ state.next.push(raw);
23733
+ continue;
23734
+ }
23735
+ if (raw.role === "system") {
23736
+ handleSystemItem(raw, state);
23737
+ mutated = true;
23738
+ continue;
23739
+ }
23740
+ if (tagMessageItem(raw)) mutated = true;
23741
+ state.next.push(raw);
23742
+ }
23743
+ if (mutated) {
23744
+ body.input = state.next;
23745
+ if (state.instructions !== void 0) body.instructions = state.instructions;
23746
+ }
23747
+ return mutated;
23748
+ }
23749
+ //#endregion
23750
+ //#region src/proxy/middleware/normalize-responses-input.ts
23751
+ /** Normalize Responses-API input for OpenRouter's schema (see normalizeResponsesInput); no-op for chat/messages. */
23752
+ const normalizeResponsesInputMiddleware = createMiddleware(async (c, next) => {
23753
+ const parsedBody = c.var.parsedBody;
23754
+ if (parsedBody && shouldNormalizeResponses(c.var.resolvedConfig.normalizeResponses, c.req.path) && normalizeResponsesInput(parsedBody)) c.set("bodyMutated", true);
23755
+ await next();
23756
+ });
23757
+ //#endregion
23530
23758
  //#region src/proxy/middleware/normalize-volatile-system.ts
23531
23759
  /** Normalize Claude Code's per-request volatile hashes in system[0] to constants; they drift every turn and break prefix-cache for non-Anthropic providers:
23532
23760
  * - `cch=…` per-turn hash
@@ -23844,6 +24072,7 @@ const injectChain = [
23844
24072
  injectProvider,
23845
24073
  injectCacheControl,
23846
24074
  normalizeVolatileSystemMiddleware,
24075
+ normalizeResponsesInputMiddleware,
23847
24076
  injectSessionId
23848
24077
  ];
23849
24078
  function createProxyServer(source, onReady) {
@@ -24075,6 +24304,14 @@ const configCli = (0, import_cjs.subcommands)({
24075
24304
  await cachingCommand({ configPath: args.configPath });
24076
24305
  }
24077
24306
  }),
24307
+ fixes: (0, import_cjs.command)({
24308
+ name: "fixes",
24309
+ description: "Tune compatibility fixes (interactive)",
24310
+ args: { ...configArgs },
24311
+ handler: async (args) => {
24312
+ await fixesCommand({ configPath: args.configPath });
24313
+ }
24314
+ }),
24078
24315
  edit: (0, import_cjs.command)({
24079
24316
  name: "edit",
24080
24317
  description: "Edit an existing model override (interactive)",