fix(ci): clear base-reds on release/v3.8.50 (round 4)

Drains the HARD failures reported by Release-Green run 31693210948 on issue #9985
(ESLint errors: 2) plus the merge-integrity red every open PR is inheriting.

- ESLint error 1: @omniroute/opencode-plugin/src/index.ts had a stray extra
  '});' (introduced by #9316) that broke parsing with 'unexpected file in NFT list'
  on the build path.
- ESLint error 2: cli-env-inline-comment-10100.test.ts used new Function to extract
  parseEnvValue from the bin entrypoint (no-new-func, Hard Rule #3). Extracted the
  helper to bin/cli/utils/parseEnvValue.mjs and import it from both the entrypoint
  and the test (same behavior, no eval).
- open-sse-typecheck (Fast Quality Gates): open-sse/utils/stream.ts imported
  sseCommentsEnabled twice (#9378) causing TS2300 Duplicate identifier; removed the
  duplicate import.
- Merge integrity (changelog + generated skills): skills/omni-settings/SKILL.md was
  edited manually by #10169 without updating the generator source, so
  check:agent-skills-sync failed on every PR (Generated: 1). Moved the curated
  thinking-budget content into a <!-- skill:custom-start --> block (the documented
  preservation mechanism), which the generator now keeps in sync.

Refs #9985
This commit is contained in:
adevwithpurpose
2026-08-13 09:49:21 -03:00
parent 6143da70d1
commit 26096e6706
6 changed files with 53 additions and 69 deletions

View File

@@ -5478,7 +5478,6 @@ export function createOmniRouteConfigHook(
rawConnections: localRawConnections,
expiresAt: now() + resolved.modelCacheTtl,
});
});
// Startup diagnostics (file-based) — fires at startup via config hook
if (resolved.features?.startupDebug === true) {

View File

@@ -0,0 +1,21 @@
/**
* Parse a `.env` value with dotenv-compatible comment handling.
*
* Without this, `KEY=value # note` stored the comment text as part of the
* value. The shipped .env ships exactly such a line for QUOTA_STORE_DRIVER, and
* consumers compare it with `===`, so annotating a variable inline silently
* disabled it (#10100).
*
* Quoted values are returned verbatim — a `#` inside quotes is data. For
* unquoted values a `#` *preceded by whitespace* starts a comment, so
* `pass#word` is preserved.
*/
export function parseEnvValue(raw) {
const value = String(raw).trim();
const quoted = value.match(/^(['"])([\s\S]*)\1\s*(?:#.*)?$/);
if (quoted) return quoted[2];
const commentIdx = value.search(/\s#/);
return (commentIdx === -1 ? value : value.slice(0, commentIdx)).trim();
}

View File

@@ -23,6 +23,7 @@ import { getNodeRuntimeSupport, getNodeRuntimeWarning } from "./nodeRuntimeSuppo
import { getDefaultDataDir } from "./cli/data-dir.mjs";
import { shouldProvisionStorageKey } from "./cli/utils/storageKeyProvision.mjs";
import { isVersionFastPath } from "./cli/utils/versionFastPath.mjs";
import { parseEnvValue } from "./cli/utils/parseEnvValue.mjs";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
@@ -93,28 +94,6 @@ function migrateElectronServerEnv(dataDir) {
}
}
/**
* Parse a `.env` value with dotenv-compatible comment handling.
*
* Without this, `KEY=value # note` stored the comment text as part of the
* value. The shipped .env ships exactly such a line for QUOTA_STORE_DRIVER, and
* consumers compare it with `===`, so annotating a variable inline silently
* disabled it (#10100).
*
* Quoted values are returned verbatim — a `#` inside quotes is data. For
* unquoted values a `#` *preceded by whitespace* starts a comment, so
* `pass#word` is preserved.
*/
function parseEnvValue(raw) {
const value = String(raw).trim();
const quoted = value.match(/^(['"])([\s\S]*)\1\s*(?:#.*)?$/);
if (quoted) return quoted[2];
const commentIdx = value.search(/\s#/);
return (commentIdx === -1 ? value : value.slice(0, commentIdx)).trim();
}
function loadEnvFile() {
const envPaths = [];
const loadedEnvPaths = [];

View File

@@ -74,7 +74,6 @@ import {
hasUnsupportedReasoningSignal,
} from "./reasoningFields.ts";
import { applyThinkTag, flushThink, initThinkState } from "./thinkTagParser.ts";
import { sseCommentsEnabled } from "./sseHeartbeat.ts";
import {
caseInsensitiveToolNameLookup,
restoreOpenAIToolNames,

View File

@@ -319,15 +319,7 @@ curl -X PUT https://localhost:20128/api/settings/system-prompt \
Get thinking budget configuration
Returns proxy-level thinking/reasoning **request rewrite** settings:
| Field | Meaning |
|-------|---------|
| `mode` | `passthrough` (leave client reasoning alone — **required for Codex visible thinking**), `auto` (**strips** all client thinking fields), `custom`, `adaptive` |
| `customBudget` | Fixed budget when `mode=custom` |
| `effortLevel` | Base effort when `mode=adaptive` |
**Not** compression and **not** “decrypt encrypted reasoning”. Full guide: `docs/guides/THINKING_BUDGET.md`.
Returns the current thinking/reasoning budget settings for AI models.
```bash
curl https://localhost:20128/api/settings/thinking-budget \
@@ -338,17 +330,13 @@ curl https://localhost:20128/api/settings/thinking-budget \
Update thinking budget configuration
Example — keep client-controlled reasoning (Codex/Desktop):
```bash
curl -X PUT https://localhost:20128/api/settings/thinking-budget \
-H "Authorization: Bearer $OMNIROUTE_TOKEN" \
-H "Authorization: Bearer $OMNIROUTE_TOKEN"
-H "Content-Type: application/json" \
-d '{"mode":"passthrough","customBudget":10240,"effortLevel":"medium"}'
-d '{}'
```
Warning: `mode=auto` deletes `reasoning` / `reasoning_effort` / Claude `thinking` from the outbound body before upstream. That can empty thinking panels even when the client requested Ultra + summary.
### GET /api/tags
List Ollama-compatible model tags
@@ -398,3 +386,30 @@ curl -X POST https://localhost:20128/api/settings/purge-usage-history \
## Payloads
See the full OpenAPI specification at `GET /api/openapi/spec` or `docs/openapi.yaml` for detailed request/response schemas.
<!-- skill:custom-start -->
<!-- Thinking budget behavior (preserved curated content — #10169) -->
### GET /api/settings/thinking-budget — behavior
Returns proxy-level thinking/reasoning **request rewrite** settings:
| Field | Meaning |
|-------|---------|
| `mode` | `passthrough` (leave client reasoning alone — **required for Codex visible thinking**), `auto` (**strips** all client thinking fields), `custom`, `adaptive` |
| `customBudget` | Fixed budget when `mode=custom` |
| `effortLevel` | Base effort when `mode=adaptive` |
**Not** compression and **not** "decrypt encrypted reasoning". Full guide: `docs/guides/THINKING_BUDGET.md`.
Example — keep client-controlled reasoning (Codex/Desktop):
```bash
curl -X PUT https://localhost:20128/api/settings/thinking-budget \
-H "Authorization: Bearer $OMNIROUTE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"mode":"passthrough","customBudget":10240,"effortLevel":"medium"}'
```
Warning: `mode=auto` deletes `reasoning` / `reasoning_effort` / Claude `thinking` from the outbound body before upstream. That can empty thinking panels even when the client requested Ultra + summary.
<!-- skill:custom-end -->

View File

@@ -2,6 +2,7 @@ import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import path from "node:path";
import { parseEnvValue } from "../../bin/cli/utils/parseEnvValue.mjs";
// #10100 — the .env loader kept inline comments inside values, so the shipped
// `QUOTA_STORE_DRIVER=sqlite # sqlite | redis` line produced the literal value
@@ -9,36 +10,6 @@ import path from "node:path";
// user annotating `QUOTA_STORE_DRIVER=redis # ...` silently got SQLite with no
// warning (the existing warning lives inside the `redis` branch).
const LOADER = path.resolve("bin/omniroute.mjs");
/**
* The loader is a CLI entrypoint with side effects on import, so exercise the
* pure helper by extracting it from source rather than importing the module.
*/
function loadParseEnvValue(): (raw: string) => string {
const source = fs.readFileSync(LOADER, "utf8");
const start = source.indexOf("function parseEnvValue(");
assert.ok(start > -1, "parseEnvValue should exist in bin/omniroute.mjs");
// Walk to the end of the function body.
let depth = 0;
let end = start;
for (let i = source.indexOf("{", start); i < source.length; i++) {
if (source[i] === "{") depth++;
else if (source[i] === "}") {
depth--;
if (depth === 0) {
end = i + 1;
break;
}
}
}
return new Function(`${source.slice(start, end)}; return parseEnvValue;`)() as (
raw: string
) => string;
}
const parseEnvValue = loadParseEnvValue();
test("an unquoted inline comment is stripped", () => {
assert.equal(parseEnvValue("sqlite # sqlite | redis"), "sqlite");
assert.equal(parseEnvValue("redis # sqlite | redis"), "redis");