Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Windows では、#32111 クラッシュを回避するために、opencodex は
- **メモリ ウォッチドッグ** - プロキシは、毎分自身のメモリをサンプリングし、ログに記録します。
観測されたメモリが 4 GiB を超えると、レート制限の警告が表示されます。 Windows ワーキング セット/RSS カウンターがコミットされた外部保持を過小報告する可能性があるため、観測されたメモリは RSS、`external`、および `arrayBuffers` の最大値になります (これらの合計ではありません)。
- **`ocx doctor`** — 「メモリ / ランタイム」セクションには *サービス* が表示されます
プロセスの Bun バージョン、RSS、外部/ArrayBuffers カウンター、JS ヒープ コンテキスト、およびストリーム モードの決定。バンドルされている Bun 1.3.14 ランタイムでは、`heapUsed` / `jscHeap` 単独ではリーク識別子ではありません。アプリレベルのリークを割り当てる前に、観察されたメモリを `responseState` および繰り返しサンプルと比較します。
プロセスの Bun バージョン、RSS、外部/ArrayBuffers カウンター、JS ヒープ コンテキスト、ストリーム モードの決定、Bun のリビジョン、およびランタイムがバンドル版か `OPENCODEX_BUN_PATH` オーバーライドかも表示します。アクティブなオーバーライドはそのように識別され、同じオーバーライドを再度設定するよう促されることはありません。バンドルされている Bun 1.3.14 ランタイムでは、`heapUsed` / `jscHeap` 単独ではリーク識別子ではありません。アプリレベルのリークを割り当てる前に、観察されたメモリを `responseState` および繰り返しサンプルと比較します。
- **`GET /api/system/memory`** — 認証済みの同じデータ
ダッシュボードまたはスクリプトの管理 API。 RSS/ヒープ/外部カウンターとともに、プロキシのメモリ内 `previous_response_id` 継続ストアのスカラー `responseState` ブロック (エントリ数、シリアル化された合計/最大バイト数、最も古いエントリの経過時間) を報告します。これはさらに成長に起因します。観察された記憶の上昇下での `responseState.totalBytes` の上昇は会話の保持を指します (長い `store:false` チェーンはターンごとに再拡張します)。一方、観察された記憶の上昇の下での横ばいの `responseState` はそのストアから遠ざかることを示します。値はスカラーのみであり、リクエスト本文、トークン、パス、アカウント識別子はありません。また、読み取りには副作用はありません (プルーニングや削除は行われません)。ダッシュボードの **メモリ可観測性** カードは同じフィールドをレンダリングし、確認ゲート付き **ドレインと再起動** アクションを提供します。現在のアクティブ ターン数を表示し、アクティブ ターンを最大 60 秒待機し (既存の 503 + `Retry-After` ドレインを再利用)、残りのターンを中止し、ライブ ポート (または障害専用サービス スーパーバイザ) 上の `ocx start` 経由でプロキシを再起動します。 respawn)Codex インジェクションを破棄せずに。これは、`POST /api/stop` の短いドレインよりも長く、情報に基づいたリサイクルです。
- **ゲートされた代替ストリーム パス** — 制限された単一リーダー リレー。
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Windows에서는 opencodex가 #32111 충돌을 피하기 위해 스트리밍 응
완화와 가시성만 제공합니다. **해결책은 아닙니다**. 번들된 1.3.14 런타임에서는 누수 자체가 여전히 상위 문제입니다.

- **메모리 감시기** - 프록시는 1분마다 자체 메모리를 샘플링하고, 관측된 메모리가 4 GiB를 넘으면 속도 제한이 걸린 경고를 기록합니다. 관측된 메모리는 RSS, `external`, `arrayBuffers`의 합이 아니라 그중 가장 큰 값입니다. Windows의 working-set/RSS 카운터가 커밋된 external 잔존량을 낮게 잡을 수 있기 때문입니다.
- **`ocx doctor`** - "Memory / runtime" 섹션에서 *서비스* 프로세스의 Bun 버전, RSS, external/ArrayBuffers 카운터, JS 힙 문맥, 스트림 모드 결정을 보여줍니다. 번들된 Bun 1.3.14 런타임에서는 `heapUsed` / `jscHeap`만으로 누수를 판별할 수 없습니다. 애플리케이션 수준 누수로 단정하기 전에 관측된 메모리, `responseState`, 반복 샘플을 함께 보아야 합니다.
- **`ocx doctor`** - "Memory / runtime" 섹션에서 *서비스* 프로세스의 Bun 버전, RSS, external/ArrayBuffers 카운터, JS 힙 문맥, 스트림 모드 결정, Bun 리비전, 런타임이 번들판인지 `OPENCODEX_BUN_PATH` 오버라이드인지도 보여줍니다. 활성 오버라이드는 그 자체로 식별되며, 같은 오버라이드를 다시 설정하라는 안내는 반복되지 않습니다. 번들된 Bun 1.3.14 런타임에서는 `heapUsed` / `jscHeap`만으로 누수를 판별할 수 없습니다. 애플리케이션 수준 누수로 단정하기 전에 관측된 메모리, `responseState`, 반복 샘플을 함께 보아야 합니다.
- **`GET /api/system/memory`** - 대시보드나 스크립트에서 쓸 수 있도록 같은 데이터를 인증된 관리 API로 제공합니다. RSS/heap/external 카운터와 함께, 프록시의 메모리 내 `previous_response_id` 이어받기 저장소에 대한 스칼라 `responseState` 블록(항목 수, 직렬화된 총/최대 바이트, 가장 오래된 항목의 경과 시간)을 보고합니다. 이를 통해 증가 원인을 더 잘 구분할 수 있습니다. 관측된 메모리가 함께 증가하면서 `responseState.totalBytes`도 늘면 대화 보존(long `store:false` 체인이 매 턴 다시 확장되는 경우)을 가리키고, 관측된 메모리는 늘지만 `responseState`는 평평하면 그 저장소와는 무관한 원인을 가리킵니다. 값은 스칼라만 포함하며 요청 본문, 토큰, 경로, 계정 식별자는 포함하지 않습니다. 또한 읽기 동작은 부작용이 없습니다. 절대 prune하거나 evict하지 않습니다. 대시보드의 **Memory observability** 카드는 같은 필드를 렌더링하고, 확인을 거쳐야 하는 **Drain & restart** 동작도 제공합니다. 현재 활성 턴 수를 보여주고, 기존 503 + `Retry-After` 드레인과 같은 방식으로 최대 60초 동안 활성 턴을 기다린 뒤, 남아 있는 턴을 강제로 중단하고 Codex 주입을 해제하지 않은 채 라이브 포트의 `ocx start`(또는 실패했을 때만 동작하는 서비스 슈퍼바이저 재기동)를 통해 프록시를 재시작합니다. 이는 `POST /api/stop`의 짧은 드레인보다 더 길고, 더 많은 정보를 반영한 재순환입니다.
- **가드된 대체 스트림 경로** - unbounded buffering 형태를 완전히 제거하는 bounded single-reader relay입니다. Windows에서는 번들된 Bun 릴리스가 #32111 수정을 실제로 포함하고 있음이 확인되면 자동으로 기본값이 됩니다. 지금은 아래에서 설명하는 opt-in만 가능합니다. macOS에서는 그런 릴리스 이후에도 계속 opt-in입니다. macOS의 `auto`를 바꾸는 것은 별도의 결정입니다.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ opencodex поставляет рантайм Bun (сейчас это **1.3.14*
RSS, `external` и `arrayBuffers` (а не их сумма), потому что счётчики working set/RSS на Windows
могут занижать коммит удерживаемой external-памяти.
- **`ocx doctor`** — раздел "Memory / runtime" показывает версию Bun у *service*-процесса, RSS,
счётчики external/ArrayBuffers, контекст JS-heap и выбранный stream mode. На комплектном Bun
счётчики external/ArrayBuffers, контекст JS-heap, выбранный stream mode, ревизию Bun и источник
рантайма (комплектный или через `OPENCODEX_BUN_PATH`); активный оверрайд идентифицируется как
таковой, и инструкция по его установке не повторяется. На комплектном Bun
1.3.14 одних только `heapUsed` / `jscHeap` недостаточно, чтобы отличить утечку; сравнивайте
наблюдаемую память с `responseState` и повторными сэмплами, прежде чем записывать это на
app-level leak.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ runtime the leak itself remains an upstream problem:
retention.
- **`ocx doctor`** — a "Memory / runtime" section shows the *service*
process's Bun version, RSS, external/ArrayBuffers counters, JS-heap context,
and stream-mode decision. On the bundled Bun 1.3.14 runtime, `heapUsed` /
stream-mode decision, the Bun revision, and whether the runtime is bundled
or an `OPENCODEX_BUN_PATH` override. An active override is identified as
such instead of being told to set the same override again. On the bundled
Bun 1.3.14 runtime, `heapUsed` /
`jscHeap` alone are not a leak discriminator; compare observed memory with
`responseState` and repeated samples before assigning an app-level leak.
- **`GET /api/system/memory`** — the same data over the authenticated
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ opencodex 打包了 Bun 运行时(当前为 **1.3.14**)。这类内存增长
这是有界缓解和可见性措施,不是修复。对于捆绑的 1.3.14 运行时,泄漏本身仍然是上游问题:

- **内存监视器** — 代理每分钟采样一次自身内存,并在观测到的内存超过 4 GiB 时记录限频告警。观测到的内存取 RSS、`external` 和 `arrayBuffers` 三者中的最大值(不是它们的总和),因为 Windows 的工作集/RSS 计数可能低报已提交的外部保留。
- **`ocx doctor`** — `"Memory / runtime"` 部分会显示*服务*进程的 Bun 版本、RSS、external/ArrayBuffers 计数、JS 堆上下文以及流模式决策。在捆绑的 Bun 1.3.14 运行时上,单看 `heapUsed` / `jscHeap` 不能作为泄漏判据;在认定为应用层泄漏之前,应把观测到的内存与 `responseState` 以及多次采样一起比较。
- **`ocx doctor`** — `"Memory / runtime"` 部分会显示*服务*进程的 Bun 版本、RSS、external/ArrayBuffers 计数、JS 堆上下文、流模式决策、Bun 修订号以及运行时来源(捆绑或 `OPENCODEX_BUN_PATH` 覆盖)。当覆盖已激活时会被明确标识,而不会再次提示设置同一个环境变量。在捆绑的 Bun 1.3.14 运行时上,单看 `heapUsed` / `jscHeap` 不能作为泄漏判据;在认定为应用层泄漏之前,应把观测到的内存与 `responseState` 以及多次采样一起比较。
- **`GET /api/system/memory`** — 通过已认证的管理 API 提供同样的数据,便于仪表板或脚本使用。除了 RSS/heap/external 计数之外,它还会报告一个标量的 `responseState` 块(条目数、序列化总字节数/最大字节数、最老条目的年龄),对应代理内存中的 `previous_response_id` 续接存储。这能进一步归因增长:在观测到的内存上升时,如果 `responseState.totalBytes` 也在上升,说明是对话保留在增长(较长的 `store:false` 链在每轮中重新扩张);而在观测到的内存上升时,如果 `responseState` 保持平稳,则更像不是这个存储造成的。返回值只包含标量,不包含请求正文、token、路径或账户标识,而且读取没有副作用(不会执行 prune,也不会 evict)。仪表板中的 **Memory observability** 卡片会渲染相同字段,并提供一个需要确认的 **Drain & restart** 操作:它会显示当前活动轮次数量,最多等待 60 秒让活动轮次结束(复用现有的 503 + `Retry-After` 排空机制),然后中止剩余轮次,并通过 `ocx start` 在当前端口重启代理(或者在仅故障时由服务监督程序重新拉起),同时不拆除 Codex 注入。这是一种比 `POST /api/stop` 的短排空更长、更知情的回收方式。
- **有门控的替代流路径** — 一种有界的单读者中继,能彻底消除无界缓冲的形态。在 Windows 上,一旦某个捆绑的 Bun 版本可验证地包含 #32111 的修复,它就会自动成为默认路径;目前它仅支持显式启用(见下文)。在 macOS 上,即使到了那样的版本,它也仍然保持显式启用状态;切换 macOS 的 `auto` 是另一项独立决定。

Expand Down
22 changes: 17 additions & 5 deletions src/cli/doctor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,8 @@ export async function probeWham(fetchImpl: typeof fetch = fetch): Promise<WhamPr
export type ServiceMemoryData = {
pid: number;
bunVersion: string;
bunRevision?: string;
runtime?: { source: string };
Comment on lines +526 to +527

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail
rg -n -C 4 \
  'durableBunRuntime|runtime.*source|source.*override|source.*process|OPENCODEX_BUN_PATH' \
  src tests docs-site

Repository: lidge-jun/opencodex

Length of output: 50376


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- doctor outline ---'
ast-grep outline src/cli/doctor.ts --match 'ServiceMemoryData' --view expanded || true

printf '%s\n' '--- doctor type/fetch/format regions ---'
rg -n -C 12 'type ServiceMemoryData|interface ServiceMemoryData|fetchServiceMemory|formatServiceMemoryLines|runtime\.source|source ===' src/cli/doctor.ts

printf '%s\n' '--- runtime definition ---'
cat -n src/lib/bun-runtime.ts | sed -n '20,75p'

printf '%s\n' '--- doctor tests around runtime guidance ---'
cat -n tests/doctor.test.ts | sed -n '330,465p'

printf '%s\n' '--- all source and test references ---'
rg -n -C 3 'runtime:\s*\{[^}]*source|runtime\.source|source:\s*"(bundled|override|process)"|source === "(bundled|override|process)"' src tests

Repository: lidge-jun/opencodex

Length of output: 39901


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- doctor imports and report types ---'
cat -n src/cli/doctor.ts | sed -n '1,45p'
cat -n src/cli/doctor.ts | sed -n '515,550p'

printf '%s\n' '--- durable runtime call sites and service artifact behavior ---'
rg -n -C 8 'durableBunRuntime\(\)|durableBunPath\(\)|buildWindowsServiceScript|process\.execPath' src tests

printf '%s\n' '--- language-page runtime wording ---'
for f in docs-site/src/content/docs/troubleshooting/windows-memory.md \
         docs-site/src/content/docs/ja/troubleshooting/windows-memory.md \
         docs-site/src/content/docs/ko/troubleshooting/windows-memory.md \
         docs-site/src/content/docs/ru/troubleshooting/windows-memory.md \
         docs-site/src/content/docs/zh-cn/troubleshooting/windows-memory.md; do
  if [ -f "$f" ]; then
    printf '\n--- %s ---\n' "$f"
    rg -n -C 2 'bundled runtime|bundled|OPENCODEX_BUN_PATH|运行时|ランタイム|рантайм|런타임' "$f" | head -80
  else
    printf '%s\n' "MISSING: $f"
  fi
done

printf '%s\n' '--- standalone behavior verifier ---'
python3 - <<'PY'
from pathlib import Path
import re

doctor = Path("src/cli/doctor.ts").read_text()
runtime = Path("src/lib/bun-runtime.ts").read_text()

assert 'runtime?: { source: string };' in doctor
assert 'typeof body.runtime.source === "string"' in doctor
assert 'd.runtime?.source === "override"' in doctor
assert '"process"' in runtime

def parsed_source(value):
    # Mirrors fetchServiceMemory's present-string acceptance.
    return value if isinstance(value, str) else None

def guidance_branch(source):
    # Mirrors formatServiceMemoryLines's Windows auto-known-bad branch.
    return "override" if source == "override" else "bundled-guidance"

for value in ("bundled", "override", "process", "future", 17, None):
    accepted = parsed_source(value)
    print(f"input={value!r} stored={accepted!r} branch={guidance_branch(accepted)!r}")

assert guidance_branch("process") == "bundled-guidance"
assert guidance_branch("future") == "bundled-guidance"
assert parsed_source("future") == "future"
print("deterministic behavior matches the source branches")
PY

Repository: lidge-jun/opencodex

Length of output: 50376


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- Windows memory documentation files and runtime statements ---'
find docs-site/src/content/docs -type f -path '*/troubleshooting/windows-memory.md' -print
for f in $(find docs-site/src/content/docs -type f -path '*/troubleshooting/windows-memory.md' | sort); do
  printf '\n--- %s ---\n' "$f"
  rg -n -C 1 'bundled runtime|bundled|OPENCODEX_BUN_PATH' "$f" | head -40
done

printf '%s\n' '--- service script runtime selection ---'
cat -n src/service.ts | sed -n '45,53p'
cat -n src/service.ts | sed -n '1261,1315p'

printf '%s\n' '--- standalone behavior verifier ---'
python3 - <<'PY'
from pathlib import Path

doctor = Path("src/cli/doctor.ts").read_text()
runtime = Path("src/lib/bun-runtime.ts").read_text()

assert 'runtime?: { source: string };' in doctor
assert 'typeof body.runtime.source === "string"' in doctor
assert 'd.runtime?.source === "override"' in doctor
assert 'source: "process"' in runtime

def fetch_stores(value):
    return value if isinstance(value, str) else None

def format_branch(value):
    stored = fetch_stores(value)
    return "override branch" if stored == "override" else "non-override branch"

for value in ("bundled", "override", "process", "future", 17, None):
    print(f"{value!r}: stored={fetch_stores(value)!r}, {format_branch(value)}")

assert fetch_stores("future") == "future"
assert format_branch("process") == "non-override branch"
assert format_branch("future") == "non-override branch"
print("source acceptance and formatting branches match the implementation")
PY

Repository: lidge-jun/opencodex

Length of output: 11308


Preserve and validate the BunRuntimeSource contract.

src/lib/bun-runtime.ts:23-26,55-60 emits "bundled", "override", or "process". src/cli/doctor.ts:527,585 widens this value to string and accepts unknown strings. formatServiceMemoryLines handles only "override" at lines 633 and 666-670. Therefore "process" and unknown values omit the source label and show bundled-runtime guidance. "process" uses process.execPath when the bundled Bun binary is unavailable, so it is not necessarily bundled.

Export and reuse a BunRuntimeSource union. Validate the response before storing it. Handle "bundled", "override", "process", and absent or invalid values separately. Add regression tests for all three valid values and invalid input. Update the five Windows-memory pages if "process" becomes user-visible.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/cli/doctor.ts` around lines 526 - 527, Preserve the BunRuntimeSource
contract by exporting and reusing a union for bundled, override, and process
values, and validate the doctor response before storing it. Update
formatServiceMemoryLines to handle all three valid sources plus absent or
invalid values so process is not treated as bundled and unknown values remain
safe. Add regression coverage for each valid source and invalid input, and
update the five Windows-memory pages if process becomes user-visible.

Source: Path instructions

platform: string;
rss: number;
heapUsed: number;
Expand Down Expand Up @@ -579,6 +581,8 @@ export async function fetchServiceMemory(
data: {
pid: body.pid,
bunVersion: body.bunVersion,
bunRevision: typeof body.bunRevision === "string" ? body.bunRevision : undefined,
runtime: body.runtime && typeof body.runtime.source === "string" ? { source: body.runtime.source } : undefined,
platform: typeof body.platform === "string" ? body.platform : "unknown",
rss: body.rss,
heapUsed: typeof body.heapUsed === "number" ? body.heapUsed : 0,
Expand Down Expand Up @@ -625,7 +629,9 @@ export function formatServiceMemoryLines(report: ServiceMemoryReport): string[]
return lines;
}
const d = report.data;
lines.push(` ok service pid ${d.pid}: Bun ${d.bunVersion} on ${d.platform}`);
const revision = d.bunRevision ? ` (rev ${d.bunRevision.slice(0, 8)})` : "";
const source = d.runtime?.source === "override" ? " (runtime source: override via OPENCODEX_BUN_PATH)" : "";
lines.push(` ok service pid ${d.pid}: Bun ${d.bunVersion}${revision} on ${d.platform}${source}`);
const observed = observedMemory(d);
const observedBytes = d.observedBytes ?? d.watchdog?.observedBytes ?? observed.bytes;
const observedMetric = d.observedMetric ?? d.watchdog?.observedMetric ?? observed.metric;
Expand All @@ -652,12 +658,18 @@ export function formatServiceMemoryLines(report: ServiceMemoryReport): string[]
} else {
lines.push(" !! high RSS, indeterminate split — capture two doctor runs over time to see the trend");
}
// Version-claiming (never binary-claiming): the endpoint cannot distinguish
// the bundled binary from an OPENCODEX_BUN_PATH override of the same version.
// Version-claiming (never binary-claiming). The endpoint now reports the
// service process's own runtime source, so an active override is identified
// instead of being told to set the same override again.
if (d.platform === "win32" && d.eagerRelay?.reason === "auto-known-bad") {
lines.push(` service is running Bun ${d.bunVersion} on Windows — a version affected by the upstream Bun memory issue.`);
lines.push(" Options: wait for a bundled runtime update, or set OPENCODEX_BUN_PATH to a runtime you trust (unvalidated — own risk),");
lines.push(" or opt into streamMode \"eager-relay\" via PUT /api/settings (crash risk on this runtime; see docs).");
if (d.runtime?.source === "override") {
lines.push(" An OPENCODEX_BUN_PATH override is already active; it stays unvalidated for automatic eager relay (own risk).");
lines.push(" Options: replace the override with a trusted runtime, or opt into streamMode \"eager-relay\" via PUT /api/settings (crash risk on this runtime; see docs).");
} else {
lines.push(" Options: wait for a bundled runtime update, or set OPENCODEX_BUN_PATH to a runtime you trust (unvalidated — own risk),");
lines.push(" or opt into streamMode \"eager-relay\" via PUT /api/settings (crash risk on this runtime; see docs).");
}
}
return lines;
}
Expand Down
4 changes: 4 additions & 0 deletions src/server/management/system-routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
* dashboard drain-and-restart confirm UX — never request bodies or IDs.
*/
import { selectEagerPath } from "../../lib/bun-stream-caps";
import { durableBunRuntime } from "../../lib/bun-runtime";
import { getActiveTurnCount, isDraining } from "../lifecycle";
import { getActiveMemoryWatchdog, observedMemoryCounter } from "../memory-watchdog";
import { responseStateMetrics } from "../../responses/state";
Expand Down Expand Up @@ -79,6 +80,9 @@ export async function handleSystemRoutes(ctx: ManagementContext): Promise<Respon
bunVersion: Bun.version,
bunRevision: Bun.revision,
platform: process.platform,
// Scalar enum only, never the runtime path: lets diagnostics tell a
// bundled runtime from an OPENCODEX_BUN_PATH override (#848).
runtime: { source: durableBunRuntime().source },

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Derive the runtime source from the running executable

When a user follows the documented service workflow—sets OPENCODEX_BUN_PATH only in the install shell and reruns ocx service install—the Windows wrapper/WinSW definition bakes that path as the executable but does not propagate OPENCODEX_BUN_PATH into the service environment. Consequently, this call reevaluates the now-absent environment variable, reports bundled, and ocx doctor repeats the same circular override guidance that this change is intended to remove. Determine the source from process.execPath versus the bundled/override paths, or persist a non-sensitive source marker in the service definition; the new test currently masks the defect by setting the variable inside the already-running process.

AGENTS.md reference: docs-site/AGENTS.md:L7-L10

Useful? React with 👍 / 👎.

uptimeSeconds: process.uptime(),
rss: usage.rss,
heapUsed: usage.heapUsed,
Expand Down
21 changes: 21 additions & 0 deletions tests/doctor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,27 @@ describe("service memory section (#314 WP4)", () => {
expect(lines.join("\n")).not.toContain("bundled binary");
});

test("guidance gating: active override is identified, not re-suggested (#848)", () => {
const revision = "0d9b296af33f2b851fcbf4df3e9ec89751734ba4";
const overrideLines = formatServiceMemoryLines({
status: "ok",
data: { ...baseData, bunRevision: revision, runtime: { source: "override" } },
});
const rendered = overrideLines.join("\n");
expect(rendered).toContain("OPENCODEX_BUN_PATH override is already active");
expect(rendered).toContain("(rev 0d9b296a)");
expect(rendered).toContain("(runtime source: override via OPENCODEX_BUN_PATH)");
expect(rendered).not.toContain("set OPENCODEX_BUN_PATH");
expect(rendered).not.toContain("wait for a bundled runtime update");

// Same reported version on the bundled runtime still offers the override step.
const bundledLines = formatServiceMemoryLines({
status: "ok",
data: { ...baseData, bunRevision: revision, runtime: { source: "bundled" } },
});
expect(bundledLines.some(l => l.includes("set OPENCODEX_BUN_PATH"))).toBe(true);
});

test("guidance gating: darwin auto-off or fixed Windows runtime prints no override guidance", () => {
const darwin = formatServiceMemoryLines({
status: "ok",
Expand Down
Loading
Loading