Codex/260729 security md reporting path - #799
Conversation
Persist a default-OFF archived cleanup policy, evaluate it on startup/schedule/manual runs via Phase 2 helpers, and surface controls on the Storage page.
Keep live config synced after background policy runs, execute exact reduceToBytes candidate sets, preserve nextRun on unchanged schedules, and harden the Storage policy UI against invalid drafts and raw errors.
Reject cleared thresholds, fail closed on malformed targets, tear down scheduler on shutdown, and defer startup policy off the microtask queue.
Move archive scan/FS/SQLite cleanup into a Bun Worker behind a single-flight job controller so POST /run returns immediately and /healthz stays responsive.
Replace the 100-file FS fixture with synthetic over-select math plus a small exact-path check, and raise timeouts on concurrent satellite restore cases that measure multi-second on Windows runners.
…tion Reload persisted policy before saving lastRun/nextRun so concurrent PUTs during a long worker run are not silently reverted.
Abort/reset now cancel the active worker promise and generation-guard late completions; GUI distinguishes already_running, aborts poll on unmount, and test-stream returns 404 when disabled.
…-policy feat(storage): opt-in auto-cleanup policy (phase 3, lidge-jun#42)
…idge-jun#491) * fix(oauth): stop OAuth login from deleting a stored provider API key `upsertOAuthProvider` replaced the provider entry with the bare preset on every OAuth login. For providers that can be billed either way (`allowKeyAuthOverride`: xai, github-copilot) this deleted `apiKey` and `apiKeyPool` from config.json and silently flipped an explicit `authMode: "key"` billing choice back to the subscription — the key was gone and had to be pasted again. Carry the key fields over and keep an explicitly chosen `authMode: "key"`, so logging in never changes which credential bills the request. OAuth-only providers and fresh logins still get the untouched preset. * fix(oauth): restore OAuth mode after final key removal * fix(oauth): promote safe pool key and keep key mode when authMode is omitted Address review follow-ups so OAuth login preserves key billing when a usable key remains, including pool promotion and shared API-key sanitization. * fix(oauth): sync active key into pool and gate key mode on resolved env Keep list/switch/remove aligned with routing after OAuth upsert, and only restore authMode key when resolveEnvValue yields a usable secret. * fix(oauth): push merged provider config to running proxy after CLI login Avoid POST /api/providers with the bare OAuth preset, which dropped preserved apiKey/authMode and wrote that stripped state back to disk. * fix(oauth): persist key intent without CLI env and route env keys at runtime Stop upsertOAuthProvider from gating authMode on resolveEnvValue in the login CLI; router falls back to OAuth when the proxy cannot resolve an env-backed active key without rewriting stored mode. --------- Co-authored-by: wonsh42 <wonsh42@users.noreply.github.com> Co-authored-by: wonsh42 <300028278+wonsh42@users.noreply.github.com> Co-authored-by: Wibias <37517432+Wibias@users.noreply.github.com>
The .codexclaw/ goalplans and ledgers are per-machine agent state. They were committed with 'git add -f' despite the ignore rule, and once tracked the rule stopped applying, so they rode along into main and preview. Untrack them (files stay on disk), drop two .DS_Store files that got in the same way, and add tests/repo-hygiene.test.ts so a forced add fails CI instead of landing silently. Also drop a registry.ts comment pointing at a .codexclaw evidence file that was never committed and cannot be resolved by any reader.
* feat(cli): add `ocx opencode` launcher
opencode reads providers from a JSON config rather than env slots, so the
`ocx claude` env-injection pattern does not transfer. This adds a launcher that
generates a provider block from the proxy's visible catalog and points
OPENCODE_CONFIG at it.
The user's own opencode.json is never written to. Their effective config is read
(explicit OPENCODE_CONFIG first, then the XDG global path), merged forward into
a generated copy under the opencodex config dir, and only the `opencodex`
provider key is overwritten. Carrying the base config forward keeps the command
correct whether opencode merges the OPENCODE_CONFIG layer or replaces it, and
leaves plain `opencode` completely unchanged.
Credential handling: the generated file is written to disk and outlives the
child, so it carries opencode's documented `{env:VAR}` reference instead of the
admission key, and the real value is passed only through the child environment.
The key resolves OPENCODEX_API_AUTH_TOKEN before config.apiKeys, matching
fetchClaudeContextWindows — a non-loopback bind requires the env token and may
have no apiKeys at all, where a placeholder would 401 every request.
Model limits: limit.context is emitted only from an authoritative context
window, including native slugs via nativeOpenAiContextWindow. opencode's schema
rejects a limit block carrying context without output and CatalogModel has no
authoritative output field, so a documented budget rides along, clamped to the
context window so a small-context model is never emitted with output > context.
Robustness: opencode.json is parsed as JSONC (strict JSON first, tolerant only
on failure) because opencode documents that syntax and a commented config would
otherwise be rejected as malformed; the generated file is written atomically so
a concurrent launch cannot read a torn file; the detached proxy-start child gets
an error listener so a failed spawn reports through the health poll instead of
throwing; and a project-level opencode.json defining provider.opencodex is
detected and warned about, since opencode loads that layer last and it outranks
the generated block.
Verified against a live proxy: 76 models registered, 47 carrying authoritative
limits with no output > context violations, `opencode models opencodex` lists
all of them, and an end-to-end run through opencodex/kiro/claude-haiku-4.5
returns a completion.
* fix(cli): harden ocx opencode launcher review follow-ups
Merge inherited OPENCODE_CONFIG_CONTENT instead of replacing it, probe the
live proxy hostname for baseURL, resolve admission from env/service token/
config keys, add x-opencodex-api-key on non-loopback binds, omit native slugs
in Codex Direct mode, and widen global override detection. Stabilize the
Windows storage-policy concurrency test timing.
* fix(cli): pass service token file to ocx opencode auto-start
When ocx opencode spawns a detached ocx start and OPENCODEX_API_AUTH_TOKEN
is absent, propagate OCX_API_TOKEN_FILE (or the default hardened path) so
handleStart can load the service token before a non-loopback bind.
* fix(cli): address CodeRabbit opencode review follow-ups
Use a deterministic loopback default config in provider-block helpers instead
of loadConfig(), send proxy admission via apiKey on loopback and only
x-opencodex-api-key on non-loopback binds, and split the docs/help examples
accordingly.
* fix(cli): build ocx opencode catalog from proxy /api/models
Fetch the live model list from the running proxy instead of calling fetchAllModels in the CLI process, so env-backed provider keys resolve in the proxy environment and namespaced selectors carry display metadata.
* fix(cli): bound ocx opencode /api/models fetch deadline
Abort stalled proxy catalog requests after 8s so ocx opencode fails fast instead of hanging before OpenCode launches.
---------
Co-authored-by: mihneaptu <223163739+mihneaptu@users.noreply.github.com>
…dge-jun#42) (lidge-jun#558) * feat(storage): restore quarantined archived sessions (phase 2.1 of lidge-jun#42) Add trash list/restore APIs, Storage GUI quarantine panel, and round-trip tests so default cleanup can be undone without Phase 3 purge. * fix(storage): address PR lidge-jun#558 restore review and GUI loading races Keep satellite backups for quarantine restore, snapshot full thread rows and state dependents, remap satellite DB paths, and make satellite failures retryable. Drop duplicate trash probing so Storage abort/generation ownership stays correct. * fix(storage): harden restore moves and Windows lock-test timeouts Use link+unlink no-replace for trash restore so a raced dest cannot be overwritten, and raise timeouts for multi-satellite cleanup tests that overrun 5s on Windows CI. * fix(storage): atomic trash parse and legacy thread restore Reject malformed manifests wholesale, gate stage deletion on restore completeness, and reconstruct production thread rows from rollout session_meta when satellite snapshots are missing. * fix(storage): release memories lock before post-image backup write Holding BEGIN IMMEDIATE across writeFileSync let Windows CI disk/AV latency stall the watermark concurrent-restore test past bun's 5s default. Persist consolidatePostImage after COMMIT and raise the two concurrent restore test budgets to match the other multi-satellite cases. * fix(storage): compensate restore metadata on late failure Restage files then delete rows this restore committed so satellite/leftover failures leave a clean retryable trash entry. * fix(storage): enforce restore compensation success and preserve pre-existing rows Track exact conflict-ignored inserts, require compensating DB txs to commit before restaging, and leave accurate partial counts when compensation is busy. * fix(storage): resume incomplete restore instead of non-atomic compensation Late failures after file moves now persist restore-pending.json and keep restored files in place, so retries accept destinations and finish only missing metadata without deleting rows before a guaranteed restage. * fix(storage): write restore-pending atomically before file moves Persist the resume marker with stage-local temp+fsync+rename before any rollout leaves quarantine, distinguish missing/valid/invalid markers, and fail closed when a resume still owes satellite work but satellite-backup.json is gone. * fix(storage): keep placed dests on mid-move restore failure Once restore-pending is durable, a later rename failure must not reverse successful moves or drop the planned acceptedDestRels marker so resume can finish staged files. * fix(storage): close PR lidge-jun#558 restore blockers (fail-closed resume, tombstone finalize, worker job) Fail closed per owed satellite section on resume, finalize successful restores via non-listable tombstone rename, and run restoreTrashEntry in a serialized Bun Worker so the event loop stays responsive. * fix(storage): serialize cleanup and restore via shared mutation gate Route manual cleanup and trash restore through one per-CODEX_HOME coordinator that returns 409 storage_mutation_busy instead of queuing. Stub runPolicyStorageMutation for Phase 3 policy worker integration. * fix(storage): export policy overlap guard for pending restore * fix(storage): surface restore worker failures and gate test-stream route Map worker rejections to distinct restore error codes end-to-end (API, GUI, i18n) instead of generic restore_failed, and register the restore test-stream endpoint only when OPENCODEX_CLEANUP_TEST_HOOKS=1. * fix(storage): drop broken pending-overlap hooks from cleanup preview Keep only restore worker error types in cleanup.ts; remove calls to undefined pending-restore guard helpers introduced in the prior commit. * fix(storage): guard cleanup against pending restore overlap Reject cleanup when selected archives overlap acceptedDestRels from valid restore-pending markers, fail closed on unfinished satellite sections, and address tip CodeRabbit nits (healthz flake, preview status). * fix(tests): stabilize Windows CI storage policy and rollback cases Raise injected satellite rollback test timeout for slow Windows SQLite reconcile, and delay concurrent policy PUT until the worker has loaded the enabled snapshot inside holdAfterLoadMs. * fix(storage): hold policy mutation slot in parent and backfill pending-safe selection Acquire the shared CODEX_HOME mutation slot in the policy job controller before spawning the worker and release it on success, failure, timeout, and abort. Pending-restore destinations no longer consume percent or reduceToBytes selection budget; cleanup backfills with the next oldest safe archives. Adds API regressions for policy, restore, and manual cleanup contention in both orderings. * fix(storage): clear policy-job inflight after busy-path settle The request handler assignment overwrote executeJob's inflight=null on mutation-busy returns, leaving a settled Promise latched forever. Clear inflight in a finally on the assigned job promise instead.
Based on the original report and patch from @Aciredy. Removes Cursor user/developer prompt mutation for shell-alias hints (guidance stays in the system note) and rejects empty/invalid shell_command and exec_command payloads before they reach the bridge. Co-authored-by: Aciredy <254986922+Aciredy@users.noreply.github.com>
isLoopbackRequestHost() required the Host header's port to equal the proxy's own port, so a proxy reached through `ssh -L 20100:localhost:10100` arrived as `Host: localhost:20100` and was refused. That gate sits in front of the whole data plane — /v1/models, /v1/responses, /v1/messages, /v1/chat/completions, /v1/live and the Responses WebSocket upgrade — not just CORS, and it fires with no Origin header at all, so Codex CLI, Claude Code and curl all saw a proxy that looked completely dead rather than one with a CORS problem. Loopback is a trust boundary by hostname, not by port. The sibling isLoopbackOriginValue() dropped its own port check for exactly this reason in e4e0612. Port equality was never the rebinding defense either: a rebinding browser connects to the real port and sends it verbatim, so the hostname check is what rejected it before and still does. Verified against 40 Host forms — localhost.attacker.com, 127.0.0.1.nip.io, localtest.me, 0.0.0.0, 127.0.0.2, [::ffff:127.0.0.1] and a Cyrillic homograph all stay refused. Also accepts the FQDN form `localhost.`, which curl sends verbatim and which was refused for the same class of reason. The predicate had no test coverage at all. The new file pins both directions, including a characterization test for the pre-existing fail-open on an unparseable Host so tightening it later needs a deliberate failing test. Docs: forwarding is now documented, with the caveats that a forwarded loopback is unauthenticated (ssh -g / container publishing expose it), that the client base URL must be set by hand, and that provider OAuth login needs its own forward.
…store (lidge-jun#571) * fix(storage): harden lidge-jun#558 satellite backup writes and zst restore Make every satellite-backup.json update crash-safe (tmp + fsync + rename + best-effort dir fsync) so a failed post-memories rewrite cannot truncate the last valid snapshot. Restore legacy compressed-only quarantine entries by decompressing a lone .jsonl.zst in memory and reconstructing the thread row. * fix(storage): harden satellite-backup write retries for lidge-jun#558 follow-up Loop short writes to completion and rename via renameAtomicFile so Windows sharing violations cannot replace a durable temp with a truncated backup.
) * test(storage): cover restore test-stream route gate cases Address CodeRabbit on lidge-jun#571: assert JSON 404 when the stream hook is null under OPENCODEX_CLEANUP_TEST_HOOKS=1, and that the enabled stream path returns the text/plain chunked response. * test(storage): isolate restore test-stream route env and hooks Reset OPENCODEX_CLEANUP_TEST_HOOKS and restore-job hooks in a nested finally so enableTestStream cannot leak across cases in the responsive suite.
…idge-jun#493) Anthropic OAuth usage is per credential: probe each logged-in account for 5h/weekly bars, use canonical fiveHour fields, and refresh overview quotas after active-account switches. Maintainer takeover on latest dev with CodeRabbit/Codex/Wibias review harden (unavailable+TTL, local-cli fail-closed, health rebuild, probe sharing, GUI/docs, cache/inflight/login invalidation, async account-list load). Credit: @wonsh42 (original feature). Co-authored-by: wonsh42 <wonsh42@users.noreply.github.com>
Co-authored-by: wonsh42 <wonsh42@users.noreply.github.com>
Make Kiro Add-account run a transactional kiro-cli browser login with durable session recovery, account-scoped routing metadata, and generation-safe refresh. Co-authored-by: coseung2 <120152615+coseung2@users.noreply.github.com>
Gemini chat image models emit authenticated opaque artifact URLs via responseModalities, with CCA Images fallback hardening and focused regressions. Maintainer takeover on latest dev with CodeRabbit/Codex/Wibias review harden (admission bearer CCA path, n=1 + RECITATION, base64/magic validation, explicit allowlists, artifact HTTP route, size caps). Credit: @tizerluo (original feature). Co-authored-by: tizerluo <192086140+tizerluo@users.noreply.github.com>
lidge-jun#577) Credit: @tizerluo for the original feature on lidge-jun#424. Folds stacked lidge-jun#528 hardening and maintainer review/security follow-ups. Reconciled with lidge-jun#355 artifact helpers on latest dev. Closes lidge-jun#424 Closes lidge-jun#528
…dge-jun#578) * feat(anthropic): opt-in Claude OAuth account pool (lidge-jun#294) Add experimental, default-off routing across stored Anthropic OAuth accounts: sticky session affinity, 429 cooldown failover, and new-session lowest 5h-usage pick. Includes GUI toggle with an explicit not-battle-tested warning, management API, docs, and focused regressions. * fix(anthropic): address pool review feedback for lidge-jun#294 Return 429 when all accounts are cooling, bound per-request failover, skip unsafe local-cli refresh, and keep affinity/GUI/docs aligned with the reliability contract.
…#579) * fix(release): baseline preview notes on last prior release Preview generate-notes was channel-isolated (preview to preview only), so cutting 2.7.43-preview after a stable 2.7.42 with no matching preview restated the stable changelog. Preview baselines now use the newest prior stable or preview tag; stable still baselines prior stable and carries matching preview notes. * fix(release): SemVer-order prior tags for notes baseline Exclude tags newer than the target and rank stable after matching previews so generate-notes does not pick the wrong previous release.
…back-gate fix(server): treat forwarded loopback ports as loopback
…dge-jun#563) (lidge-jun#580) * feat(dashboard): drain-and-restart from memory observability card Expose a longer 60s informed recycle on the memory card (POST /api/system/restart) that reuses drainAndShutdown and respawns via ensure/service without Codex teardown (lidge-jun#563). * fix(dashboard): harden drain-and-restart respawn and exit cleanup Address Codex review: use failure-exit for supervised service children, spawn start with the live port (not ensure), suppress injection teardown on recycle, and clear the GUI draining state on pid change. * fix(dashboard): arm drain immediately and harden reconnect polling Set draining before the 200ms flush delay, bound reconnect /healthz polls, announce restart status to assistive tech, and clarify docs around active-turn drain timeout abort.
…un#584) (lidge-jun#585) * fix(codex): same-request pool failover on pre-stream 429/402 Retry exhausted primary accounts once on an eligible alternate within the same turn, and rebind over-threshold sticky threads immediately so Codex CLI does not stall when a secondary still has quota (lidge-jun#584). * fix(codex): attribute pool-retry transport failures to alternate account Also classify HTTP 402 as quota so same-request failover cools the depleted account consistently with 429. * fix(codex): keep subagent quota health scoped to the retried account After a successful same-request pool failover, update subagentFallbackAccountId so streamed terminal 429s attribute health to the account that actually served.
… follow-up) (lidge-jun#594) * fix(server): exit cleanly when drain-and-restart spawn fails Follow-up to lidge-jun#580: wait for detached start spawn success, and on sync throw or pre-start error exit(1) without markRecycling so we never leave a drained process latched or exit(0) with no replacement. * fix(server): sanitize restart spawn errors and restore fences Address Codex review on lidge-jun#594: log only errno codes (no pathful messages), and clear inherited OCX_SERVICE on spawn failure so ensure/tray daemons still run syncCleanup restore.
* chore(gui): restore React Doctor 100 and gate CI on findings Clear the post-cleanup regressions, pin react-doctor 0.9.2, and fail CI/prepush on any doctor finding so the score cannot silently drift again. * fix(gui): address CI/Codex follow-ups for React Doctor gate Keep Response-like test doubles working, preserve Grok/message error text, honor reconnect deadlines on non-OK healthz, and soft-skip offline npx/registry failures without letting real findings through. * fix(gui): address CodeRabbit follow-ups on doctor gate PR Extract boundedSignal, serialize Claude Desktop status polls, keep storage percent as a draft string, map trash list errors through i18n, and tighten React Doctor workflow assertions to active YAML. * fix(gui): tighten doctor offline classifier and Grok apply errors Make apply failures keep server message text, cover the fetch-json fallback path, and only soft-skip prepush on concrete registry/network signatures so findings with words like network still gate. * fix(gui): bound polls and harden doctor prepush gate Restore manual timeout fallbacks via shared createBoundedFetch, raise doctor maxBuffer and fail on ENOBUFS, recognize ECONNRESET registry failures, and tighten action SHA pinning assertions. * fix(gui): match nonterminal npm ERR! soft-skip signatures Give npm ERR! its own alternative so trailing whitespace after the bang still counts as an offline/registry failure instead of gating the push. * fix(gui): treat stdio maxBuffer overflows as doctor gate failures Also recognize Node's ERR_CHILD_PROCESS_STDIO_MAXBUFFER so oversized doctor output cannot soft-skip the prepush findings gate. * fix(gui): run React Doctor via spawnSync with explicit maxBuffer Replace execFileSync so prepush classification uses spawnSync status/error channels and cannot soft-skip oversized doctor output. * test(gui): cover bounded fetch and doctor maxBuffer hard-fail Add regression tests CodeRabbit asked for, and check AbortSignal helpers with typeof so the manual timeout fallback actually runs when any/timeout are missing.
…idge-jun#600) Stop accepting bug reports that only fill Summary — empty or ellipsis-only Reproduction must fail the issue-quality gate (lidge-jun#598).
…idge-jun#597) * feat(kimi): forward prompt_cache_key on the Kimi Coding Plan presets Kimi's Chat Completions API documents prompt_cache_key as required for Kimi Code Plan cache hits (a stable session/task id, unchanged across exit and resume). Opt the canonical `kimi` OAuth and `kimi-code` API-key presets into the existing openai-chat forwarding flag so the caller-supplied key reaches https://api.kimi.com/coding/v1. The adapter never invents a key: it forwards what the internal request already carries (Codex's session key on /v1/responses, or the session-scoped key the Claude /v1/messages inbound derives), an absent field stays absent, and an explicit provider-level `promptCacheKey: false` still opts out. All other OpenAI-compatible presets remain deny-by-default because strict backends reject the OpenAI-specific field. Also persist the flag through providerConfigSeed / enrichProviderFromRegistry like the sibling scalars (parallelToolCalls, modelSuffixBracketStrip): key-pool 429 rotation rebuilds the provider from the persisted config rather than the routed one, so without seeding the retried request would silently drop the key on exactly the quota-sensitive turns that need affinity most. Evidence: https://platform.kimi.com/docs/api/chat Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Preserve Kimi prompt cache key on failover * fix(server): inherit routed provider config across 429 key rotation Generalize the promptCacheKey preservation from the previous commit: the narrow registry backfill in rotateProviderTransportOn429 covered only that one scalar, while every OTHER registry backfill routedProviderConfig merges at request time was still lost when the four 429-failover sites in src/server/responses/core.ts assigned the persisted-config snapshot to route.provider wholesale. Concretely: kimi-code's noTemperatureModels / modelReasoningEfforts / modelSuffixBracketStrip merges, NVIDIA NIM's parallelToolCalls: false, and a registry-pinned baseUrl all silently reverted on the rotated retry and later continuations in the turn. rotateProviderTransportOn429 now takes the request's routed provider and swaps ONLY the API key onto it before re-applying transport metadata, mirroring the OAuth-401 replay path (which already spreads route.provider). The registry lookup becomes unnecessary and is removed. Other failover paths were audited and are sound: Codex multi-account retry strips runtime fields off route.provider, and the Anthropic account pool spreads route.provider directly. Regression coverage: the existing Kimi unit test keeps asserting the wire body on both attempts; a new unit test proves arbitrary registry-backfilled fields survive rotation; a new e2e test on the kimi-code preset asserts prompt_cache_key is present on BOTH the initial attempt and the post-rotation retry (verified to fail against the pre-fix behavior). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…jun#614) * docs(devlog): live state sync unit for 2026-07-28 (branches, PRs, issues) Measured snapshot of origin/dev=7710185c0, 15 open PRs, 27 open issues, and the delta against the 260727 owner-decision ledger and 260728 bug-bundle plan. The audit round demoted two items the first draft got wrong: lidge-jun#570 is only partially fixed (items 1a/2 of its six-item hardening plan; the myhost.lan alias case still 403s), and lidge-jun#612 is credential-handling work under MAINTAINERS.md's security-review rule rather than a decision-free patch. * docs(devlog): rebuild-unit roadmap — screen 16 open PRs, lock 4 work-phases Two audit rounds moved this a long way from the draft. The conflict set for lidge-jun#576 was inverted (logic files, not i18n), the proposed usage-debug size gate would have elided 0.9% of reads, and lidge-jun#610's P1 turned out to be author-resolved while the same defect survived on dev's own test. * docs(devlog): record the WP2 measurement — the lidge-jun#610 P1 does not reproduce PATH="" never reaches the child because runCodexDebugModels calls execFile without an env option, so the launcher keeps working and the catalog loads. The isolation that line intends is decorative; the test stays safe through CODEX_CLI_PATH instead. Closing WP2 as NOOP with the observation sent to lidge-jun#610. * test(usage): give the rolling-file bound test room on Windows The 325 appends this test needs cost ~1,954 synchronous fs calls (measured: mkdir 325, chmod 652, append 325, exists 325, read 325, write 2). On windows-latest under full-suite load that took 13.6s and tripped the 5s default, while ubuntu and macos stayed well under it. The cost is per-open rather than per-byte, so removing one of the six calls would not close a 2.7x overshoot. Reducing the append count would trade away coverage -- 325 is already the minimum that crosses the rotate threshold twice. Both assertions and the rotation contract are unchanged. * docs(devlog): record the lidge-jun#576 rebase outcome and the regression it surfaced The three conflicts were the predicted logic files. What the audit caught was separate: the pre-rebase commit already deleted dev's grokSyncFailureMessage and its three handlers, and no test in the repo asserts that string, so a full green suite would not have stopped it.
…idge-jun#576) A long-lived Codex app-server keeps serving its in-memory model list, so ocx sync could write a correct catalog and Codex would still show the old models (lidge-jun#476). Restarting the proxy or re-running sync did not help; only killing the app-server did, which is why rebooting appeared to fix it. Detect those processes and say so, gated on the catalogWritten/cacheSynced signal from the first half of this change so a no-op sync stays quiet. ocx sync --restart-codex and ocx sync-cache --restart-codex opt into a SIGTERM, never SIGKILL. Process matching is the risky part and is deliberately narrow: UID-scoped on Unix, exact cmdline match rather than a broad *codex* sweep, and it understands quoted paths and value-taking globals so it cannot mistake a neighbouring process for an app-server.
The project is moving its primary runtime to the Go native port, so dev2-go has to keep receiving everything that lands on dev. Nothing changes for contributors: pull requests still target dev. The extra step belongs to the maintainer who merges one — rebase the work onto dev2-go, port whatever needs a Go counterpart under go/, and merge that. The item is finished only when both lines carry the change. An unported dev merge is the failure mode this rule exists to prevent: dev2-go silently falls behind and the divergence surfaces later as a conflict nobody has context for. So the port happens in the same session as the merge; a change with no Go counterpart gets that decision recorded; a port that has to wait gets a tracking issue against dev2-go naming the source commits. MAINTAINERS.md carries the authoritative wording and the other seven files summarise it. The maintainer table widens both maintainers' integration duty to dev and dev2-go, since that is what the rule actually asks of them. Also correct the 2026-07-27 change-log entry. It claimed requirement 2 (review by another current maintainer) would be satisfied "when this change is reviewed and merged". It never was: a2693c0, dc3a4ad and 02bbd47 landed on dev as direct owner pushes with no associated pull request. The addition is in effect regardless — @Wibias holds write access and has been merging since 2026-07-26 — so the entry now records the gap instead of asserting a procedure that did not happen.
Adds nested AGENTS.md files and CODEOWNERS coverage for agent guidance. Keeps the owner Transition intake rule already on dev (merge to dev, carry onto dev2-go, port go/ only when needed).
) * feat(videos): add Grok video bridge for non-OpenAI models Extends the image bridge to support asynchronous video generation via xAI Grok Imagine Video. Video generation uses a submit→poll→download pattern (POST /v1/videos/generations → GET /v1/videos/{id}) with heartbeat forwarding to keep the SSE stream alive during the 30-180s generation window. New files: - src/images/xai-video-client.ts: submitVideoJob + pollVideoJob - src/images/fulfill-video.ts: arg parsing, async polling generator, result builder - tests/videos/: 32 tests (xai-video-client, fulfill-video, plan-video) - docs-site/.../video-bridge.md: user guide Modified files: - src/images/loop.ts: unified image+video fulfillment, per-turn call caps - src/images/types.ts: VideoBridgePlan/VideoCallResult shared types - src/images/synthetic-tool.ts: buildVideoTool, VIDEO_GEN_TOOL_NAME - src/images/plan.ts: planVideoBridge (opt-in via videoBridgeEnabled) - src/images/artifacts.ts: downloadVideoToArtifact (200MB cap, SSRF-protected) - src/server/responses/core.ts: video bridge wiring + tool dedup - src/types.ts: videoGeneration flag, video config fields Video bridge is opt-in (videoBridgeEnabled defaults to false). All upstream image-bridge hardening preserved (SSRF, size caps, abort linking, pinned HTTPS). * fix(videos): address Codex P1/P2 + CodeRabbit review findings P1 fixes: - Non-streaming requests no longer 400 when video bridge is enabled (only image bridge requires stream=true; video-only skips bridge for non-stream requests) - Restore globalThis.fetch after video client tests (afterEach cleanup) P2 fixes: - Use clamped vidPlan.timeoutMs instead of raw config value - Honor videoMaxRounds when both image+video bridges active (tighter wins) - guessVideoExtFromMagic throws on unrecognized magic (was defaulting to mp4) - Poll 4xx permanent failures (except 429) fail fast instead of retrying - buildVideoResult uses pathToFileURL for cross-platform markdown links - Initial poll interval restored to 5s (was 200ms) - done-without-videoUrl returns error instead of spinning until timeout - VideoBudget charges every streamed chunk (was only first chunk) - downloadVideoToArtifact: reader cleanup on file-open failure - readBoundedText: cancel reader body on size cap breach - Namespaced video_gen tools preserved in dedup filter - Fix JSON missing closing brace in docs - Clarify API key auth requirement in docs prerequisites * fix(videos): encode requestId, defer paidVideoCalls, guard plan! assertion - Encode requestId in poll URL to prevent path injection (CodeRabbit) - Move paidVideoCalls++ past arg validation so malformed calls don't burn budget - Add early guard for undefined plan in image branch, removing non-null assertions * fix(videos): batch-aware artifact pruning + clarify provider key docs - Move pruneArtifacts from per-download to post-batch so multi-video turns don't delete earlier videos before tool results are injected (Codex P2) - Document that video bridge requires providers.xai with apiKey authMode, not OAuth from 'ocx login xai' (Codex P2) * fix(videos): web search coexistence, unified timeout budget, VideoBudget ceiling Address Wibias CHANGES_REQUESTED review: 1. Web search coexistence (P1): - When wsPlan is active, media bridge is skipped (existing behavior) - Now emits console.warn so the user sees the skip instead of silent loss - Documented priority rule in video-bridge.md 2. Timeout budget (P2): - Start deadline BEFORE submitVideoJob, not after - Poll receives remaining budget (deadline - now), min 5s floor - Submit (60s) + poll now share one videoTimeoutMs deadline 3. VideoBudget aggregate ceiling (optional, addressed): - VideoBudget now has a cap (600 MiB = 3 × single-download max) - chargeVideoBudget() enforces the ceiling per-chunk during streaming - Exceeding the budget throws mid-download (partial file is cleaned up) 4. New tests: done-without-videoUrl, permanent 4xx poll stop, requestId encoding * fix(videos): gate tool_choice on imgPlan, shared deadline signal, buffer magic sniff Address Wibias second CHANGES_REQUESTED review: Required: B. Gate image tool_choice rewriting on imgPlan — video-only turns no longer rewrite image_generation/image_gen aliases to an undeclared tool (core.ts) C. Shared timeout complete — deadline-bound AbortSignal passed into submitVideoJob; if budget expired after submit, poll is skipped with timeout error (no 5s floor) Preferred: A. Buffer ≥12 bytes before magic-byte sniff — accumulate chunks until sniff minimum so short first reads don't crash guessVideoExtFromMagic (artifacts.ts) Optional: D. Docs: scope web-search priority to runnable sidecar / non-runTurn path * fix(videos): pass deadline-bound signal into poll generator Pass linkedDeadline (not raw client signal) into pollVideoWithHeartbeats so in-flight pollVideoJob fetches and sleep() calls abort when the wall-clock budget expires. Abort error messages now distinguish deadline-expiry from client-cancel based on elapsed time vs timeoutMs threshold. * fix(videos): deadline abort classification, pruned-path guard, video aliases, DNS noun Address Wibias fourth CHANGES_REQUESTED review: 1. Deadline abort classification (required lidge-jun#1): - Replace 0.95 wall-clock heuristic with signal.reason.name === 'TimeoutError' - deadlineSignal declared outside try so catch can check deadlineSignal.aborted - Submit catch returns timeout error when deadlineSignal fires (not generic abort) 2. Don't deliver pruned artifact paths (required lidge-jun#2): - After batch prune, scan fulfilled results and rewrite any whose path no longer exists to ok:false with explanatory error 3. Wire video aliases (required lidge-jun#3): - planVideoBridge seeds toolNames with VIDEO_GEN_TOOL_NAME + any request function tools matching isVideoGenName (image-bridge parity) - core.ts filter only strips unnamespaced video_gen aliases (namespaced MCP tools are left alone) 4. Fix test fixtures (required lidge-jun#4): - authMode 'api_key' → 'key' (valid OcxProviderConfig value) 5. DNS error noun (small): - resolvePublicAddresses accepts optional noun param (default 'image') - downloadVideoToArtifact passes 'video' * fix(videos): complete pruned-path guard, skip namespaced aliases, mock sleep in tests Address Wibias fifth CHANGES_REQUESTED review: 1. Finish pruned-path guard: - Filter files[] through existsSync, not just path - If all pruned: ok:false with no markdown/path - If some survive: refresh path/files/count/markdown from survivors 2. Skip namespaced tools when seeding videoPlan.toolNames: - if (t.namespace) continue — matches core.ts filter rule 3. Fix ubuntu CI timeout: - Mock setTimeout in heartbeat test so 5s poll interval resolves instantly - Suite now runs in ~156ms (was ~5s) * fix(videos): stop hanging ubuntu CI with global setTimeout mock cf76fb1 mocked globalThis.setTimeout to skip the 5s poll sleep. That races parallel Bun workers and cancelled ubuntu-latest at the 12m job cap (938f25e was green; cf76fb1 hung). Inject sleep/poll seams instead and drop mock.module so video tests no longer poison each other. --------- Co-authored-by: Your Name <your.email@example.com> Co-authored-by: Wibias <37517432+Wibias@users.noreply.github.com>
* Merge remote-tracking branch 'origin/dev' into fix/codex-spark-quota-scope-dev * fix: retain affinity per Codex quota scope * fix: address scoped affinity review feedback * fix: restore dev version and harden compact test
* feat(gui): show reset credit expiration time * fix(gui): respect selected locale for credit dates
…#638) * fix(adapters): neutralize Codex CLI 0.145 identity wording Closes lidge-jun#622 * fix(adapters): consume full GPT-5.x.y identity versions
Maintainer takeover of lidge-jun#565. Persisted pause exclusion, bulk pause-exhausted, GUI controls, docs. Integrated with account namespaces and Spark quota scopes on current dev.
Name the tracking-issue label in MAINTAINERS; mirror it in the AGENTS Transition summary.
…lidge-jun#627) * fix(cursor): steer Windows bridge shell away from PS 5.1 syntax loops Native-shell rejection told the model to replay the same bash/CMD command through the Codex bridge, which on Windows PowerShell 5.1 fails and loops (lidge-jun#604). Adapt for the host shell and inject PS-safe guidance instead. * fix(cursor): address lidge-jun#604 review — host-shell-neutral retry-stop guidance Drop proxy-OS platform branching and `;`-as-`&&` advice; use if ($?) and one corrected bridge attempt for Codex/CodeRabbit feedback on lidge-jun#627. * fix(cursor): state PowerShell 5.1 has no &&/|| in lidge-jun#604 guidance CodeRabbit follow-up: make unsupported-parser-error wording explicit and assert it in rejection/guidance tests.
…e-jun#651) Fixes lidge-jun#647. Single shared 401 token refresh gate; no prompt storm on concurrent /api/* 401s.
…gates (lidge-jun#631) Hardens wrong-base PR drafting so the required check fails even when draft GraphQL soft-fails, and tightens bug-form Version/OS/reproduction gates. Go port: none — CI/workflows and issue-quality scripts only; no Go counterpart.
* fix(catalog): accept Together top-level /models arrays Closes lidge-jun#617 * fix(catalog): keep models[] for probe only; array+data for discovery
Fixes lidge-jun#618. Prefer findLiveProxy over ocx.pid alone; keep status/doctor read-only on malformed config; preserve authoritative null live pids and runtime vs config listen source.
…jun#643) Fixes lidge-jun#636. Skip bare gpt-*/native OpenAI catalog rows when no enabled canonical openai provider exists; make NoEnabledOpenAiProviderError actionable.
…n#648) * docs: spec PR quality gates for ancestry and descriptions Capture the approved design for rejecting main-based PRs into dev/dev2-go and empty/thin/malformed PR bodies in the enforcer. * docs: plan PR ancestry and description quality gates Break the approved spec into TDD tasks for pr-quality.cjs, enforcer wiring, harness coverage, and contributing docs. * feat(ci): add pure PR ancestry and description quality checks * test(ci): cover wrong_base plus bad_description together * feat(ci): enforce PR ancestry and description in target gate * fix(ci): strip WRONG BRANCH prefix when base is corrected * test(ci): cover PR ancestry and description enforcement paths * docs: document PR ancestry and description quality gates * fix(ci): address CodeRabbit findings on PR quality gates Treat removed new-form Version/OS headings as missing, soft-fail ancestry compares, tighten harness require/write allowlists, and clarify enforce-target is convention until branch protection. * fix(ci): address Codex findings on PR quality gates Reject untouched PR templates, require low ahead-of-main for ancestry, and checkpoint draft/title ownership before mutations.
Co-authored-by: hanbinnoh <282618027+hanbinnoh@users.noreply.github.com>
Fixes lidge-jun#612. Async ACL runner for response-state writes; destination-path timeout memo; owner-first grant. Conflict-resolved onto current dig.
* fix(anthropic): reorder interleaved text before tool_use Closes lidge-jun#620 * test(anthropic): rename wire body var for review clarity
Private vulnerability reporting was disabled on the repository, but SECURITY.md told reporters to prefer it "when that option is available in the repository UI" and stated no private security email exists. Every private channel it named was therefore unreachable, leaving a public issue as the only route for undisclosed vulnerabilities. Private vulnerability reporting is now enabled. Replace the conditional wording with the direct advisory URL, keep the minimal-public-issue text as a fallback rather than the default, and surface the same link from the issue-template chooser and README.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. 🗂️ Base branches to auto review (2)
Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
|
Closing. This pull request contains no work by its author. The head commit here is byte-identical to a branch that already exists in this repository and was authored by the maintainer. All six of these pull requests have the same shape: fork the repository, push the upstream branches back unchanged, and open them as incoming contributions.
Every listed SHA resolves to the same commit on the upstream branch of the same name. The commit authors inside them are This is not a rebase, a resubmission of stalled work, or a fork that drifted. It burns maintainer review time and CI minutes on a diff that is already in the tree, and it presents other people's commits under a new author's pull request. Repository access is being revoked for this account. |
Summary
Verification
Checklist