@bitkyc08/opencodex 2.74.0 → 2.75.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 (48) hide show
  1. package/gui/dist/assets/{App-KLz1TAXi.css → App-ia4U0ufY.css} +1 -1
  2. package/gui/dist/assets/{App-B00Yq11u.js → App-xm0zGNOe.js} +3 -3
  3. package/gui/dist/assets/{Tray-D3Ij1Cvf.js → Tray-CGAD2AGk.js} +1 -1
  4. package/gui/dist/assets/{index-BYQQfBGK.js → index-D_RGAT6Q.js} +2 -2
  5. package/gui/dist/assets/{quota-summary-yPtcEhGI.js → quota-summary-CUFq48t-.js} +1 -1
  6. package/gui/dist/index.html +1 -1
  7. package/package.json +1 -1
  8. package/src/adapters/devin/cloud-direct/chat.ts +38 -6
  9. package/src/adapters/devin/live-models.ts +28 -8
  10. package/src/adapters/devin.ts +1 -1
  11. package/src/claude/devin-output-order.ts +98 -0
  12. package/src/codex/auth-api/pool-quota-probe.ts +2 -1
  13. package/src/codex/catalog/retained-sync.ts +9 -0
  14. package/src/codex/inject/config-toml.ts +179 -248
  15. package/src/codex/inject/provider-table.ts +5 -2
  16. package/src/codex/inject/remove.ts +23 -8
  17. package/src/codex/injected-marker.ts +28 -23
  18. package/src/codex/quota-auto-refresh.ts +1 -1
  19. package/src/codex/quota.ts +12 -4
  20. package/src/codex/toml-source-lines.ts +93 -1
  21. package/src/config/live-reconcile.ts +18 -0
  22. package/src/config/rebase-provenance.ts +12 -0
  23. package/src/config.ts +4 -3
  24. package/src/generated/compatibility-version.json +50 -38
  25. package/src/images/loop.ts +2 -0
  26. package/src/integrations/cursor-local-installer.ts +29 -2
  27. package/src/lib/redact.ts +54 -8
  28. package/src/oauth/anthropic-account-refusal.ts +76 -0
  29. package/src/oauth/anthropic-routing.ts +38 -10
  30. package/src/providers/new-model-policy-runtime.ts +83 -0
  31. package/src/providers/new-model-policy.ts +25 -0
  32. package/src/providers/registry/entries-core.ts +3 -0
  33. package/src/providers/registry/model-seeds.ts +31 -2
  34. package/src/providers/xai-transport.ts +2 -2
  35. package/src/server/claude-messages.ts +33 -10
  36. package/src/server/management/agent-settings-routes.ts +3 -1
  37. package/src/server/management/model-rows.ts +34 -4
  38. package/src/server/management/shared.ts +18 -2
  39. package/src/server/responses/adapter-continuation.ts +13 -21
  40. package/src/server/responses/adapter-delivery.ts +2 -2
  41. package/src/server/responses/adapter-dispatch.ts +10 -21
  42. package/src/server/responses/compact.ts +3 -2
  43. package/src/server/responses/core-codex-account.ts +4 -2
  44. package/src/server/responses/passthrough-delivery.ts +2 -1
  45. package/src/server/responses/request-transport.ts +2 -0
  46. package/src/server/responses/run-turn-execution.ts +25 -5
  47. package/src/server/responses/sidecar-execution.ts +9 -14
  48. package/src/web-search/loop.ts +7 -2
@@ -3,23 +3,22 @@ import { existsSync, readFileSync } from "node:fs";
3
3
  import { contextCompatibleBaseLine } from "../context-compat";
4
4
  import { resolveEffectiveProjectModelProvider } from "../project-config-warnings";
5
5
  import {
6
- OCX_SECTION_MARKER,
7
6
  OCX_ROUTING_MARKER_LINE,
8
7
  REALTIME_WS_BASE_URL_KEY,
8
+ isOcxRoutingMarkerLine,
9
9
  isRootOpenaiBaseUrlLine,
10
10
  isRootRealtimeWsBaseUrlLine,
11
11
  providerTableStart,
12
12
  providerTableString,
13
13
  rootTomlString,
14
- tomlStringPattern,
15
14
  } from "../injected-marker";
16
15
  import {
17
16
  CODEX_CONFIG_PATH,
18
17
  DEFAULT_CATALOG_PATH,
19
- parseTomlString,
20
18
  resolveCodexConfigPath,
21
19
  tomlString,
22
20
  } from "../paths";
21
+ import { normalizeStructuralWhitespace, rootAssignmentKey, rootSourceLines, sourceAssignment, sourceAssignmentSpan, sourceText, type SourceLine } from "../toml-source-lines";
23
22
  import { readBoundedCodexConfig } from "./bounded-config-reader";
24
23
  import {
25
24
  type CodexRoutingTarget,
@@ -67,10 +66,9 @@ export function observedExternalCodexModelProvider(): string | null {
67
66
  }
68
67
 
69
68
  /**
70
- * Detect the file's dominant line ending. Every transform in this module is LF-pure
71
- * (split("\n") + hard "\n" joins), so CRLF configs (Windows-edited config.toml) are
72
- * normalized to LF at the pipeline boundary and converted back on write — otherwise a
73
- * single inject would leave a mixed-EOL file.
69
+ * Detect the file's dominant line ending. Structural edits retain physical line endings;
70
+ * the full injection/removal pipeline still normalizes to LF at its boundary and converts
71
+ * back on write so generated blocks do not leave a mixed-EOL file.
74
72
  */
75
73
  export function dominantEol(content: string): "\r\n" | "\n" {
76
74
  const crlf = (content.match(/\r\n/g) ?? []).length;
@@ -234,66 +232,43 @@ export function setRootOpenaiBaseUrl(
234
232
  if (typeof portOrTarget !== "number") {
235
233
  return setRootOpenaiBaseUrlForTarget(content, validateCodexRoutingTarget(portOrTarget));
236
234
  }
237
- const lines = content.split("\n");
238
- const firstTable = lines.findIndex((l) => /^\s*\[/.test(l));
239
- const rootEnd = firstTable === -1 ? lines.length : firstTable;
240
- const key = contextCompatibleBaseLine(content, buildOpenaiBaseUrlLine(portOrTarget, hostname));
235
+ return setRootUrl(content, contextCompatibleBaseLine(content, buildOpenaiBaseUrlLine(portOrTarget, hostname)));
236
+ }
241
237
 
242
- for (let i = 0; i < rootEnd; i++) {
243
- if (!isRootOpenaiBaseUrlLine(lines[i])) continue;
244
- const markerOwned = i > 0 && lines[i - 1].includes(OCX_SECTION_MARKER);
245
- if (!markerOwned) return { content, keptUserBaseUrl: true };
246
- // Refresh the marker too, so a config injected by a build that predates the recovery
247
- // hint gains it on the next `ocx start` instead of keeping a bare marker forever.
248
- lines[i - 1] = OCX_ROUTING_MARKER_LINE;
249
- lines[i] = key;
250
- return { content: lines.join("\n"), keptUserBaseUrl: false };
251
- }
238
+ function ownedRootUrl(lines: SourceLine[], index: number, key: string): boolean {
239
+ return lines[index]!.structural && rootTomlString(lines[index]!.text, key) !== null
240
+ && index > 0 && lines[index - 1]!.structural && isOcxRoutingMarkerLine(lines[index - 1]!.text);
241
+ }
252
242
 
253
- if (firstTable === -1) {
254
- return {
255
- content:
256
- content.replace(/\n+$/, "") +
257
- "\n" +
258
- OCX_ROUTING_MARKER_LINE +
259
- "\n" +
260
- key +
261
- "\n",
262
- keptUserBaseUrl: false,
263
- };
243
+ function insertRootSourceLines(content: string, added: string[]): string {
244
+ const { bom, lines, rootEnd } = rootSourceLines(content);
245
+ const eol = dominantEol(content);
246
+ if (rootEnd === lines.length) {
247
+ return content.replace(/(?:\r?\n)+$/, "") + eol + added.join(eol) + eol;
248
+ }
249
+ let at = rootEnd;
250
+ while (at > 0 && lines[at - 1]!.structural && lines[at - 1]!.text.trim() === "") at -= 1;
251
+ lines.splice(at, 0, ...added.map(text => ({ text, eol, structural: true })));
252
+ return bom + sourceText(lines);
253
+ }
254
+
255
+ function setRootUrl(content: string, key: string): { content: string; keptUserBaseUrl: boolean } {
256
+ const { bom, lines, rootEnd } = rootSourceLines(content);
257
+ for (let index = 0; index < rootEnd; index++) {
258
+ if (!lines[index]!.structural || !isRootOpenaiBaseUrlLine(lines[index]!.text)) continue;
259
+ if (!ownedRootUrl(lines, index, "openai_base_url")) return { content, keptUserBaseUrl: true };
260
+ lines[index - 1]!.text = OCX_ROUTING_MARKER_LINE;
261
+ lines[index]!.text = key;
262
+ return { content: bom + sourceText(lines), keptUserBaseUrl: false };
264
263
  }
265
- let insertAt = firstTable;
266
- while (insertAt > 0 && lines[insertAt - 1].trim() === "") insertAt--;
267
- lines.splice(insertAt, 0, OCX_ROUTING_MARKER_LINE, key);
268
- return { content: lines.join("\n"), keptUserBaseUrl: false };
264
+ return { content: insertRootSourceLines(content, [OCX_ROUTING_MARKER_LINE, key]), keptUserBaseUrl: false };
269
265
  }
270
266
 
271
267
  export function setRootOpenaiBaseUrlForTarget(
272
268
  content: string,
273
269
  target: CodexRoutingTarget,
274
270
  ): { content: string; keptUserBaseUrl: boolean } {
275
- const lines = content.split("\n");
276
- const firstTable = lines.findIndex((line) => /^\s*\[/.test(line));
277
- const rootEnd = firstTable === -1 ? lines.length : firstTable;
278
- const key = contextCompatibleBaseLine(content, buildOpenaiBaseUrlLineForTarget(target));
279
- for (let index = 0; index < rootEnd; index += 1) {
280
- if (!isRootOpenaiBaseUrlLine(lines[index])) continue;
281
- const markerOwned = index > 0 && lines[index - 1].includes(OCX_SECTION_MARKER);
282
- if (!markerOwned) return { content, keptUserBaseUrl: true };
283
- lines[index - 1] = OCX_ROUTING_MARKER_LINE;
284
- lines[index] = key;
285
- return { content: lines.join("\n"), keptUserBaseUrl: false };
286
- }
287
- if (firstTable === -1) {
288
- return {
289
- content: `${content.replace(/\n+$/, "")}\n${OCX_ROUTING_MARKER_LINE}\n${key}\n`,
290
- keptUserBaseUrl: false,
291
- };
292
- }
293
- let insertAt = firstTable;
294
- while (insertAt > 0 && lines[insertAt - 1].trim() === "") insertAt -= 1;
295
- lines.splice(insertAt, 0, OCX_ROUTING_MARKER_LINE, key);
296
- return { content: lines.join("\n"), keptUserBaseUrl: false };
271
+ return setRootUrl(content, contextCompatibleBaseLine(content, buildOpenaiBaseUrlLineForTarget(target)));
297
272
  }
298
273
 
299
274
  /**
@@ -310,25 +285,22 @@ export function setRootRealtimeWsBaseUrl(
310
285
  content: string,
311
286
  target: CodexRoutingTarget,
312
287
  ): { content: string; keptUserRealtimeWsBaseUrl: boolean } {
313
- const lines = content.split("\n");
314
- const firstTable = lines.findIndex((line) => /^\s*\[/.test(line));
315
- const rootEnd = firstTable === -1 ? lines.length : firstTable;
288
+ const { bom, lines, rootEnd } = rootSourceLines(content);
316
289
  const key = buildRealtimeWsBaseUrlLine(validateCodexRoutingTarget(target));
317
- for (let index = 0; index < rootEnd; index += 1) {
318
- if (!isRootRealtimeWsBaseUrlLine(lines[index])) continue;
319
- const markerOwned = index > 0 && lines[index - 1].includes(OCX_SECTION_MARKER);
320
- if (!markerOwned) return { content, keptUserRealtimeWsBaseUrl: true };
321
- lines[index - 1] = OCX_ROUTING_MARKER_LINE;
322
- lines[index] = key;
323
- return { content: lines.join("\n"), keptUserRealtimeWsBaseUrl: false };
290
+ for (let index = 0; index < rootEnd; index++) {
291
+ if (!lines[index]!.structural || !isRootRealtimeWsBaseUrlLine(lines[index]!.text)) continue;
292
+ if (!ownedRootUrl(lines, index, REALTIME_WS_BASE_URL_KEY)) return { content, keptUserRealtimeWsBaseUrl: true };
293
+ lines[index - 1]!.text = OCX_ROUTING_MARKER_LINE;
294
+ lines[index]!.text = key;
295
+ return { content: bom + sourceText(lines), keptUserRealtimeWsBaseUrl: false };
324
296
  }
325
- for (let index = 0; index < rootEnd; index += 1) {
326
- if (!isRootOpenaiBaseUrlLine(lines[index])) continue;
327
- if (!(index > 0 && lines[index - 1].includes(OCX_SECTION_MARKER))) continue;
328
- lines.splice(index + 1, 0, OCX_ROUTING_MARKER_LINE, key);
329
- return { content: lines.join("\n"), keptUserRealtimeWsBaseUrl: false };
297
+ for (let index = 0; index < rootEnd; index++) {
298
+ if (!isRootOpenaiBaseUrlLine(lines[index]!.text) || !ownedRootUrl(lines, index, "openai_base_url")) continue;
299
+ const eol = dominantEol(content);
300
+ lines[index]!.eol ||= eol;
301
+ lines.splice(index + 1, 0, ...[OCX_ROUTING_MARKER_LINE, key].map(text => ({ text, eol, structural: true })));
302
+ return { content: bom + sourceText(lines), keptUserRealtimeWsBaseUrl: false };
330
303
  }
331
- // No marker-owned routing override to attach to: the override has no owner, so inject nothing.
332
304
  return { content, keptUserRealtimeWsBaseUrl: false };
333
305
  }
334
306
 
@@ -345,40 +317,30 @@ export const ROOT_WEB_SEARCH_DISABLED_LINE = 'web_search = "disabled"';
345
317
  export const ROOT_WEB_SEARCH_DISABLED_VALUE = "disabled";
346
318
 
347
319
  export function isRootWebSearchLine(line: string): boolean {
348
- // The quoted spellings are the same key to TOML, and `tomlStringPattern` -- which the value
349
- // evidence below goes through -- already reads them. A predicate that matched only the bare
320
+ // Quoted spellings (including escaped basic keys) name the same key to TOML.
321
+ // A predicate that matched only the bare
350
322
  // spelling would leave `"web_search" = "live"` in place while inserting our own line, and two
351
323
  // root keys of the same name stop Codex from loading the file at all.
352
- return /^\s*(?:"web_search"|'web_search'|web_search)\s*=/.test(line);
324
+ return rootAssignmentKey(line) === ROOT_WEB_SEARCH_KEY;
353
325
  }
354
326
 
355
327
  /** What an earlier injection recorded about this key, read back from the journal. */
356
328
  export interface RootWebSearchJournal {
357
329
  /** The value that injection wrote, or null when it wrote none. */
358
330
  injectedValue?: string | null;
359
- /** The user-owned line that injection had to remove, or null when there was none. */
331
+ /** The complete user-owned assignment removed (possibly multiline), or null. */
360
332
  replacedUserLine?: string | null;
361
333
  }
362
334
 
363
335
  /** What one pass of {@link ensureRootWebSearchDisabled} did, for the journal to record. */
364
336
  export interface RootWebSearchOutcome {
365
337
  content: string;
366
- /** The user-owned root line this pass removed, or null when there was none. */
338
+ /** The complete user-owned root assignment removed (possibly multiline), or null. */
367
339
  replacedUserLine: string | null;
368
340
  /** The value this pass wrote, or null when it wrote none. */
369
341
  wroteValue: string | null;
370
342
  }
371
343
 
372
- /** Insert root-level lines ahead of the first table; TOML root keys may not follow one. */
373
- function insertRootLines(lines: string[], text: string): string {
374
- const firstTable = lines.findIndex((line) => /^\s*\[/.test(line));
375
- if (firstTable === -1) return `${lines.join("\n").replace(/\n+$/, "")}\n${text}\n`;
376
- let at = firstTable;
377
- while (at > 0 && lines[at - 1].trim() === "") at -= 1;
378
- lines.splice(at, 0, ...text.split("\n"));
379
- return lines.join("\n");
380
- }
381
-
382
344
  /**
383
345
  * Ensure the root `web_search` key follows the web-search sidecar's master switch.
384
346
  *
@@ -406,14 +368,13 @@ export function ensureRootWebSearchDisabled(
406
368
  disabled: boolean,
407
369
  journal: RootWebSearchJournal = {},
408
370
  ): RootWebSearchOutcome {
409
- const lines = stripInjectedRootWebSearch(content, journal.injectedValue).split("\n");
410
- const firstTable = lines.findIndex((line) => /^\s*\[/.test(line));
411
- const rootEnd = firstTable === -1 ? lines.length : firstTable;
371
+ const stripped = stripInjectedRootWebSearch(content, journal.injectedValue);
372
+ const { bom, lines, rootEnd } = rootSourceLines(stripped);
412
373
  if (!disabled) {
413
- const restore = journal.replacedUserLine?.trim();
414
- const owned = lines.slice(0, rootEnd).some(isRootWebSearchLine);
374
+ const restore = journal.replacedUserLine;
375
+ const owned = lines.slice(0, rootEnd).some(line => line.structural && isRootWebSearchLine(line.text));
415
376
  return {
416
- content: restore && !owned ? insertRootLines(lines, restore) : lines.join("\n"),
377
+ content: restore?.trim() && !owned ? insertRootSourceLines(stripped, [applyEol(restore, dominantEol(stripped))]) : stripped,
417
378
  replacedUserLine: null,
418
379
  wroteValue: null,
419
380
  };
@@ -424,14 +385,21 @@ export function ensureRootWebSearchDisabled(
424
385
  // line keeps the one an earlier off pass recorded — the ordinary way to reach that state is a
425
386
  // second injection while the switch is still off (a model change), and the operator's mode must
426
387
  // not evaporate because the line it came from is already gone.
427
- const replacedUserLine = lines
428
- .slice(0, rootEnd)
429
- .find((line) => isRootWebSearchLine(line))
430
- ?.replace(/\r$/, "") ?? journal.replacedUserLine?.trim() ?? null;
388
+ const drop = new Set<number>();
389
+ let replacedUserLine = journal.replacedUserLine ?? null;
390
+ let foundUserAssignment = false;
391
+ for (let index = 0; index < rootEnd; index++) {
392
+ if (!lines[index]!.structural || !isRootWebSearchLine(lines[index]!.text)) continue;
393
+ const assignment = sourceAssignmentSpan(lines, index, rootEnd);
394
+ if (!assignment) throw new Error("Cannot safely rewrite an incomplete root web_search assignment.");
395
+ if (!foundUserAssignment) replacedUserLine = assignment.text;
396
+ foundUserAssignment = true;
397
+ for (let at = index; at < assignment.end; at++) drop.add(at);
398
+ }
431
399
  return {
432
- content: insertRootLines(
433
- lines.filter((line, index) => index >= rootEnd || !isRootWebSearchLine(line)),
434
- `${OCX_ROUTING_MARKER_LINE}\n${ROOT_WEB_SEARCH_DISABLED_LINE}`,
400
+ content: insertRootSourceLines(
401
+ bom + sourceText(lines.filter((_, index) => !drop.has(index))),
402
+ [OCX_ROUTING_MARKER_LINE, ROOT_WEB_SEARCH_DISABLED_LINE],
435
403
  ),
436
404
  replacedUserLine,
437
405
  wroteValue: ROOT_WEB_SEARCH_DISABLED_VALUE,
@@ -446,26 +414,20 @@ export function ensureRootWebSearchDisabled(
446
414
  * comment a Codex app reserialize dropped is still recognized as ours.
447
415
  */
448
416
  export function stripInjectedRootWebSearch(content: string, injectedValue?: string | null): string {
449
- const lines = content.split("\n");
450
- const firstTable = lines.findIndex((line) => /^\s*\[/.test(line));
451
- const rootEnd = firstTable === -1 ? lines.length : firstTable;
417
+ const { bom, lines, rootEnd } = rootSourceLines(content);
452
418
  const drop = new Set<number>();
453
- for (let i = 0; i + 1 < rootEnd; i += 1) {
454
- if (lines[i].includes(OCX_SECTION_MARKER) && isRootWebSearchLine(lines[i + 1])) {
455
- drop.add(i);
456
- drop.add(i + 1);
457
- }
419
+ for (let index = 0; index < rootEnd; index++) {
420
+ const line = lines[index]!;
421
+ if (!line.structural || !isRootWebSearchLine(line.text)) continue;
422
+ const assignment = sourceAssignment(lines, index, rootEnd);
423
+ if (!assignment || typeof assignment.value !== "string") continue;
424
+ const value = assignment.value;
425
+ const markerOwned = index > 0 && lines[index - 1]!.structural && isOcxRoutingMarkerLine(lines[index - 1]!.text);
426
+ if (!markerOwned && (!injectedValue || value !== injectedValue)) continue;
427
+ for (let at = index; at < assignment.end; at++) drop.add(at);
428
+ if (markerOwned) drop.add(index - 1);
458
429
  }
459
- if (injectedValue) {
460
- for (let i = 0; i < rootEnd; i += 1) {
461
- if (!isRootWebSearchLine(lines[i])) continue;
462
- if (rootTomlString(lines[i], ROOT_WEB_SEARCH_KEY) !== injectedValue) continue;
463
- drop.add(i);
464
- if (i > 0 && lines[i - 1].includes(OCX_SECTION_MARKER)) drop.add(i - 1);
465
- }
466
- }
467
- if (drop.size === 0) return content;
468
- return lines.filter((_, index) => !drop.has(index)).join("\n");
430
+ return drop.size ? bom + sourceText(lines.filter((_, index) => !drop.has(index))) : content;
469
431
  }
470
432
 
471
433
  /**
@@ -475,21 +437,23 @@ export function stripInjectedRootWebSearch(content: string, injectedValue?: stri
475
437
  * A marker-owned `experimental_realtime_ws_base_url` pair is removed by the same rule.
476
438
  */
477
439
  export function stripInjectedOpenaiBaseUrl(content: string): string {
478
- const lines = content.split("\n");
479
- const firstTable = lines.findIndex((l) => /^\s*\[/.test(l));
480
- const rootEnd = firstTable === -1 ? lines.length : firstTable;
440
+ const { bom, lines, rootEnd } = rootSourceLines(content);
481
441
  const drop = new Set<number>();
482
- for (let i = 0; i < rootEnd; i++) {
483
- if (!lines[i].includes(OCX_SECTION_MARKER)) continue;
484
- if (i + 1 < rootEnd && (isRootOpenaiBaseUrlLine(lines[i + 1]) || isRootRealtimeWsBaseUrlLine(lines[i + 1]))) {
485
- drop.add(i);
486
- drop.add(i + 1);
487
- } else if (i + 1 >= rootEnd || lines[i + 1].trim() === "") {
488
- drop.add(i); // orphaned marker at root
442
+ for (let index = 0; index < rootEnd; index++) {
443
+ const line = lines[index]!;
444
+ if (!line.structural || !isOcxRoutingMarkerLine(line.text)) continue;
445
+ const next = lines[index + 1];
446
+ if (index + 1 < rootEnd && next?.structural
447
+ && (isRootOpenaiBaseUrlLine(next.text) || isRootRealtimeWsBaseUrlLine(next.text))) {
448
+ const key = rootAssignmentKey(next.text)!;
449
+ if (rootTomlString(next.text, key) === null) continue;
450
+ drop.add(index);
451
+ drop.add(index + 1);
452
+ } else if (index + 1 >= rootEnd || (next?.structural && next.text.trim() === "")) {
453
+ drop.add(index);
489
454
  }
490
455
  }
491
- if (drop.size === 0) return content;
492
- return lines.filter((_, i) => !drop.has(i)).join("\n");
456
+ return drop.size ? bom + sourceText(lines.filter((_, index) => !drop.has(index))) : content;
493
457
  }
494
458
 
495
459
  /**
@@ -500,18 +464,19 @@ export function stripInjectedOpenaiBaseUrl(content: string): string {
500
464
  * untouched.
501
465
  */
502
466
  export function stripExistingModelProvider(content: string): string {
503
- const lines = content.split("\n");
504
- const firstTable = lines.findIndex((l) => /^\s*\[/.test(l));
505
- const out: string[] = [];
506
- lines.forEach((line, i) => {
507
- if (/^\s*model_provider\s*=/.test(line)) {
508
- const isOurs = /^\s*model_provider\s*=\s*"opencodex"\s*$/.test(line);
509
- const isRoot = firstTable === -1 || i < firstTable;
510
- if (isOurs || isRoot) return; // drop it
467
+ const { bom, lines, rootEnd } = rootSourceLines(content);
468
+ const drop = new Set<number>();
469
+ for (let index = 0; index < lines.length; index++) {
470
+ if (!lines[index]!.structural || rootAssignmentKey(lines[index]!.text) !== "model_provider") continue;
471
+ const assignment = sourceAssignmentSpan(lines, index, index < rootEnd ? rootEnd : lines.length);
472
+ if (!assignment) throw new Error("Cannot safely rewrite an incomplete model_provider assignment.");
473
+ if (index >= rootEnd) {
474
+ const decoded = sourceAssignment(lines, index);
475
+ if (typeof decoded?.value !== "string" || decoded.value.trim() !== "opencodex") continue;
511
476
  }
512
- out.push(line);
513
- });
514
- return out.join("\n");
477
+ for (let at = index; at < assignment.end; at++) drop.add(at);
478
+ }
479
+ return bom + sourceText(lines.filter((_, index) => !drop.has(index)));
515
480
  }
516
481
 
517
482
  /**
@@ -521,29 +486,21 @@ export function stripExistingModelProvider(content: string): string {
521
486
  * compaction limits do not alter the advertised context window and must survive reinjection.
522
487
  */
523
488
  export function stripRootContextWindowOverrides(content: string): string {
524
- const lines = content.split("\n");
525
- const firstTable = lines.findIndex((l) => /^\s*\[/.test(l));
526
- return lines
527
- .filter((line, i) => {
528
- const isRoot = firstTable === -1 || i < firstTable;
529
- return !isRoot || !/^\s*model_context_window\s*=/.test(line);
530
- })
531
- .join("\n");
489
+ const { bom, lines, rootEnd } = rootSourceLines(content);
490
+ const drop = new Set<number>();
491
+ for (let index = 0; index < rootEnd; index++) {
492
+ if (!lines[index]!.structural || rootAssignmentKey(lines[index]!.text) !== "model_context_window") continue;
493
+ const assignment = sourceAssignmentSpan(lines, index, rootEnd);
494
+ if (!assignment) throw new Error("Cannot safely rewrite an incomplete model_context_window assignment.");
495
+ for (let at = index; at < assignment.end; at++) drop.add(at);
496
+ }
497
+ return bom + sourceText(lines.filter((_, index) => !drop.has(index)));
532
498
  }
533
499
 
534
500
  export function stripRootRoutedModel(content: string): string {
535
- const lines = content.split("\n");
536
- const firstTable = lines.findIndex((l) => /^\s*\[/.test(l));
537
- return lines
538
- .filter((line, i) => {
539
- const isRoot = firstTable === -1 || i < firstTable;
540
- if (!isRoot) return true;
541
- const m = line.match(/^\s*model\s*=\s*("(?:\\.|[^"\\])*"|'[^']*')\s*$/);
542
- if (!m) return true;
543
- const model = parseTomlString(m[1]);
544
- return !model?.includes("/");
545
- })
546
- .join("\n");
501
+ const { bom, lines, rootEnd } = rootSourceLines(content);
502
+ return bom + sourceText(lines.filter((line, index) => index >= rootEnd || !line.structural
503
+ || !rootTomlString(line.text, "model")?.includes("/")));
547
504
  }
548
505
 
549
506
  /**
@@ -551,28 +508,16 @@ export function stripRootRoutedModel(content: string): string {
551
508
  * header (TOML root keys must precede all tables). If there are no tables, append it to the root body.
552
509
  */
553
510
  export function setRootModelProvider(content: string): string {
554
- const lines = content.split("\n");
555
- const firstTable = lines.findIndex((l) => /^\s*\[/.test(l));
556
- const key = 'model_provider = "opencodex"';
557
- if (firstTable === -1) {
558
- return content.replace(/\n+$/, "") + "\n" + key + "\n";
559
- }
560
- let insertAt = firstTable;
561
- while (insertAt > 0 && lines[insertAt - 1].trim() === "") insertAt--;
562
- lines.splice(insertAt, 0, key);
563
- return lines.join("\n");
511
+ return insertRootSourceLines(content, ['model_provider = "opencodex"']);
564
512
  }
565
513
 
566
514
  function readRootModelCatalogPath(content: string): string | null {
567
- const lines = content.split("\n");
568
- const firstTable = lines.findIndex((line) => /^\s*\[/.test(line));
569
- const rootEnd = firstTable === -1 ? lines.length : firstTable;
570
- const modelCatalogAssignment = tomlStringPattern("model_catalog_json");
515
+ const { lines, rootEnd } = rootSourceLines(content);
571
516
  let ownedCatalogPath: string | null = null;
572
517
  for (let index = 0; index < rootEnd; index += 1) {
573
- const match = modelCatalogAssignment.exec(lines[index]);
574
- if (!match) continue;
575
- const catalogPath = parseTomlString(match[1]);
518
+ if (!lines[index].structural) continue;
519
+ const catalogPath = rootTomlString(lines[index].text, "model_catalog_json");
520
+ if (catalogPath === null) continue;
576
521
  if (!isOpencodexCatalogPath(catalogPath)) return catalogPath;
577
522
  ownedCatalogPath ??= catalogPath;
578
523
  }
@@ -580,18 +525,14 @@ function readRootModelCatalogPath(content: string): string | null {
580
525
  }
581
526
 
582
527
  export function setRootModelCatalogPath(content: string, catalogPath: string): string {
583
- const lines = content.split("\n");
584
- const firstTable = lines.findIndex((l) => /^\s*\[/.test(l));
528
+ const { bom, lines, rootEnd } = rootSourceLines(content);
585
529
  const key = `model_catalog_json = ${tomlString(catalogPath)}`;
586
- const modelCatalogAssignment = tomlStringPattern("model_catalog_json");
587
- const rootEnd = firstTable === -1 ? lines.length : firstTable;
588
530
  const ownedAssignments: number[] = [];
589
531
  let hasUserAssignment = false;
590
532
  for (let i = 0; i < rootEnd; i++) {
591
- const m = modelCatalogAssignment.exec(lines[i]);
592
- if (!m) continue;
593
- const existing = parseTomlString(m[1]);
594
- if (isOpencodexCatalogPath(existing)) {
533
+ if (!lines[i].structural || rootAssignmentKey(lines[i].text) !== "model_catalog_json") continue;
534
+ const existing = rootTomlString(lines[i].text, "model_catalog_json");
535
+ if (existing !== null && isOpencodexCatalogPath(existing)) {
595
536
  ownedAssignments.push(i);
596
537
  } else {
597
538
  hasUserAssignment = true;
@@ -599,53 +540,38 @@ export function setRootModelCatalogPath(content: string, catalogPath: string): s
599
540
  }
600
541
  if (hasUserAssignment) {
601
542
  const owned = new Set(ownedAssignments);
602
- return lines.filter((_, index) => !owned.has(index)).join("\n");
543
+ return bom + sourceText(lines.filter((_, index) => !owned.has(index)));
603
544
  }
604
545
  if (ownedAssignments.length > 0) {
605
- lines[ownedAssignments[0]] = key;
546
+ lines[ownedAssignments[0]].text = key;
606
547
  const duplicates = new Set(ownedAssignments.slice(1));
607
- return lines.filter((_, index) => !duplicates.has(index)).join("\n");
548
+ return bom + sourceText(lines.filter((_, index) => !duplicates.has(index)));
608
549
  }
609
- if (firstTable === -1) {
610
- return content.replace(/\n+$/, "") + "\n" + key + "\n";
611
- }
612
- let insertAt = firstTable;
613
- while (insertAt > 0 && lines[insertAt - 1].trim() === "") insertAt--;
614
- lines.splice(insertAt, 0, key);
615
- return lines.join("\n");
550
+ return insertRootSourceLines(content, [key]);
616
551
  }
617
552
 
618
553
  export function removeProfileSection(content: string): string {
619
- const lines = content.split("\n");
620
- const filtered: string[] = [];
554
+ const { bom, lines } = rootSourceLines(content);
621
555
  let inProfile = false;
622
- for (const line of lines) {
623
- if (line.trim() === "[profiles.opencodex]") {
624
- inProfile = true;
625
- continue;
626
- }
627
- if (inProfile) {
628
- if (/^\s*\[/.test(line) && line.trim() !== "[profiles.opencodex]") {
629
- inProfile = false;
630
- filtered.push(line);
631
- }
632
- continue;
556
+ const kept = lines.filter(line => {
557
+ if (line.structural && /^\s*\[/.test(line.text)) {
558
+ try {
559
+ const parsed = Bun.TOML.parse(line.text) as Record<string, unknown>;
560
+ inProfile = typeof parsed.profiles === "object" && parsed.profiles !== null
561
+ && Object.hasOwn(parsed.profiles, "opencodex");
562
+ } catch { inProfile = false; }
633
563
  }
634
- filtered.push(line);
635
- }
636
- return (
637
- filtered
638
- .join("\n")
639
- .replace(/\n{3,}/g, "\n\n")
640
- .trimEnd() + "\n"
641
- );
564
+ return !inProfile;
565
+ });
566
+ return normalizeStructuralWhitespace(bom + sourceText(kept));
642
567
  }
643
568
 
644
569
  export function normalizeServiceTier(content: string): string {
645
- return content.replace(
646
- /^(\s*service_tier\s*=\s*)["']priority["']\s*$/gm,
647
- '$1"fast"',
648
- );
570
+ const { bom, lines, rootEnd } = rootSourceLines(content);
571
+ for (const line of lines.slice(0, rootEnd)) {
572
+ if (line.structural) line.text = line.text.replace(/^(\s*service_tier\s*=\s*)["']priority["']\s*$/, '$1"fast"');
573
+ }
574
+ return bom + sourceText(lines);
649
575
  }
650
576
 
651
577
  export function ensureFastModeFeature(content: string, fastMode?: boolean): string {
@@ -654,32 +580,41 @@ export function ensureFastModeFeature(content: string, fastMode?: boolean): stri
654
580
  // untouched (no [features] table is added and an existing fast_mode line is
655
581
  // preserved as-is). Table and key matching accept the valid TOML spellings
656
582
  // `[features] # comment`, `["features"]` / `['features']`, and quoted keys.
657
- const lines = content.split("\n");
658
- const featuresHeader = /^\s*\[(["']?)\s*features\s*\1\]\s*(?:#.*)?$/;
659
- const fastModeKey = /^\s*(?:"fast_mode"|'fast_mode'|fast_mode)\s*=/;
660
- const featuresStart = lines.findIndex(line => featuresHeader.test(line));
583
+ if (fastMode === undefined) return content;
584
+ const { bom, lines } = rootSourceLines(content);
585
+ const eol = lines.find(line => line.eol)?.eol || "\n";
586
+ const featuresStart = lines.findIndex(line => {
587
+ if (!line.structural || !/^\s*\[/.test(line.text)) return false;
588
+ try {
589
+ const parsed = Bun.TOML.parse(line.text) as Record<string, unknown>;
590
+ return Object.keys(parsed).length === 1 && typeof parsed.features === "object"
591
+ && parsed.features !== null && !Array.isArray(parsed.features)
592
+ && Object.keys(parsed.features).length === 0;
593
+ } catch { return false; }
594
+ });
661
595
  if (featuresStart === -1) {
662
- if (fastMode === undefined) return content;
663
- return content.trimEnd() + "\n\n[features]\nfast_mode = " + (fastMode ? "true" : "false") + "\n";
596
+ return content.replace(/[\r\n]+$/, "") + eol + eol + "[features]" + eol
597
+ + "fast_mode = " + (fastMode ? "true" : "false") + eol;
664
598
  }
665
599
 
666
600
  const nextTable = lines.findIndex(
667
- (line, index) => index > featuresStart && /^\s*\[/.test(line),
601
+ (line, index) => index > featuresStart && line.structural && /^\s*\[/.test(line.text),
668
602
  );
669
603
  const featuresEnd = nextTable === -1 ? lines.length : nextTable;
670
604
  for (let i = featuresStart + 1; i < featuresEnd; i++) {
671
- if (fastModeKey.test(lines[i])) {
672
- if (fastMode === undefined) return lines.join("\n");
673
- lines[i] = lines[i].replace(/^(\s*)(?:"fast_mode"|'fast_mode'|fast_mode)\s*=.*$/, `$1fast_mode = ${fastMode ? "true" : "false"}`);
674
- return lines.join("\n");
605
+ if (lines[i].structural && rootAssignmentKey(lines[i].text) === "fast_mode") {
606
+ // Refuse to rewrite an incomplete physical view of a collection/string value.
607
+ try { Bun.TOML.parse(lines[i].text); } catch { return content; }
608
+ lines[i].text = `${/^\s*/.exec(lines[i].text)![0]}fast_mode = ${fastMode ? "true" : "false"}`;
609
+ return bom + sourceText(lines);
675
610
  }
676
611
  }
677
612
 
678
- if (fastMode === undefined) return lines.join("\n");
679
613
  let insertAt = featuresEnd;
680
- while (insertAt > featuresStart + 1 && lines[insertAt - 1].trim() === "") insertAt--;
681
- lines.splice(insertAt, 0, `fast_mode = ${fastMode ? "true" : "false"}`);
682
- return lines.join("\n");
614
+ while (insertAt > featuresStart + 1 && lines[insertAt - 1].structural && lines[insertAt - 1].text.trim() === "") insertAt--;
615
+ if (insertAt > 0 && !lines[insertAt - 1].eol) lines[insertAt - 1].eol = eol;
616
+ lines.splice(insertAt, 0, { text: `fast_mode = ${fastMode ? "true" : "false"}`, eol, structural: true });
617
+ return bom + sourceText(lines);
683
618
  }
684
619
 
685
620
  function isOpencodexCatalogPath(path: string): boolean {
@@ -687,17 +622,13 @@ function isOpencodexCatalogPath(path: string): boolean {
687
622
  }
688
623
 
689
624
  export function stripOpencodexCatalogPath(content: string): string {
690
- const modelCatalogAssignment = tomlStringPattern("model_catalog_json");
691
- const lines = content.split("\n");
692
- const firstTable = lines.findIndex((line) => /^\s*\[/.test(line));
693
- const rootEnd = firstTable === -1 ? lines.length : firstTable;
694
- return lines
625
+ const { bom, lines, rootEnd } = rootSourceLines(content);
626
+ return bom + sourceText(lines
695
627
  .filter((line, index) => {
696
- if (index >= rootEnd) return true;
697
- const m = modelCatalogAssignment.exec(line);
698
- return !m || !isOpencodexCatalogPath(parseTomlString(m[1]));
699
- })
700
- .join("\n");
628
+ if (index >= rootEnd || !line.structural) return true;
629
+ const path = rootTomlString(line.text, "model_catalog_json");
630
+ return path === null || !isOpencodexCatalogPath(path);
631
+ }));
701
632
  }
702
633
 
703
634
  export function buildProfileFile(port: number, catalogPath?: string | null, supportsWebsockets?: boolean, includeApiAuthHeader?: boolean, hostname?: string, fastMode?: boolean): string;