Skip to content

Integrate OpenCodex v2.78.0 with Haly features and bundled RTK - #3

Draft
WanxTitanx wants to merge 1012 commits into
halysondev:devfrom
WanxTitanx:codex/haly-sync-v2.73.0-20260930
Draft

WanxTitanx wants to merge 1012 commits into
halysondev:devfrom
WanxTitanx:codex/haly-sync-v2.73.0-20260930

Conversation

@WanxTitanx

@WanxTitanx WanxTitanx commented Sep 30, 2026 •

Copy link
Copy Markdown

Summary

  • Update the existing Haly integration proposal to stable OpenCodex v2.78.0 (93cdffd6ac7f125d4b932a6d45af5c3ab1de5156). The new merge head is 5f1052c00a39d8154a438768c45acfbee3af3783, preserving both the old Haly/RTK candidate and the new release as ancestors.
  • Preserve Headroom, API-key estimated-spend quotas and model scopes, account-owned compatibility metadata, and native bundled RTK 0.50.0 via ocx rtk.
  • Reconcile the new upstream GUI: retain its eight navigation groups and Claude surfaces, place the dedicated API-key page under Connect, and Headroom under Usage & Logs. Carry all 83 extension strings into the new Portuguese locale.
  • Preserve upstream credential-continuity fences, typed 429/403 recovery, transient admission policy, send budgets and model-family recovery. Retain Haly's legacy named-family compatibility without claiming the upstream-owned Fable 7d_oi policy.
  • Move RTK/Headroom discovery metadata into the new modular capability structure and regenerate the operating-skill chapters. Keep RTK packaging, target hashes, notices, resource lookup and signing hooks.
  • Use 2.79.0 as the development version, matching upstream dev policy; this is a candidate based on the stable 2.78.0 release, not an official 2.79.0 release.

Haly's dev was reconfirmed at dac1d25f48fad18420aa856631ff9ee9c1775b0f; no newer Haly release was listed. The historical branch name is retained to keep this existing proposal and discussion together.

Verification

Current candidate, pinned Bun 1.4.0:

Check Result
bun run typecheck Passed
GUI bun run build Passed; existing large-chunk advisory remains
GUI bun run lint and bun run lint:i18n Passed
docs-site bun run build Passed
bun run structure:check Passed
bun scripts/file-size-ratchet.ts Passed without raising caps
bun run skill:surface:check Passed, all 9 generated references current
bun run privacy:scan Passed
TypeScript syntax compilation 1,112 changed source files parsed, 0 syntax errors; tests were not executed
bun run prepare:package and npm pack --ignore-scripts Passed; package contents inspected
Integration whitespace check against v2.78.0 Passed; inherited upstream EOF blank lines left outside this delta

The npm candidate contains all five pinned RTK executables with executable modes, LICENSE/NOTICE, built GUI and compatibility metadata. Artifact: bitkyc08-opencodex-2.79.0.tgz, 37,033,376 bytes, SHA256 7341208399185b44bb3bcaa2078fd422000c8ef0995cecf2bc28cdfbea48cc0c.

Automated unit/integration test suites were not run in this session. Compilation, static checks and screenshot rendering do not replace them. Historical tests of the previous candidate are not claimed for this head. Focused/full tests required by repository policy, exact-head CI, independent security review, Windows/macOS runtime execution and live provider inference remain pending. No release, live installation, provider reconfiguration or service restart was performed.

GUI evidence

Built candidate, isolated local fixture, synthetic providers/key. Headroom and API-key detail controls rendered in Portuguese with no captured browser error/warning entries. The fixture logged an Anthropic model-discovery HTTP 401. This proves the displayed UI only, not successful provider discovery or real inference.

Headroom in the Usage and Logs group

API-key quota and model-access controls in Connect

Review evidence and limitations. Images are on the separate pr-assets branch, not in the feature branch.

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed.
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults. Independent security review remains required for authentication, dependency, packaging and workflow boundaries.

The PR remains draft. The contributor has read-only access to this repository and cannot apply its maintainer sponsorship or merge decision. The existing unsponsored_surface hygiene gate requires a maintainer-applied maintainer-sponsored label following review. That label does not replace independent security review, required tests or exact-head CI. CodeRabbit's success status on a draft is not independent-review evidence.

Co-authored-by: halysondev halysoncesar2020@gmail.com

Review readiness checklist

This PR stays in draft until every box below is ticked. Tick all four boxes once the requirements are met:

  • Required local validation passed; commands, results, and any full-suite exception are documented.

  • I pushed my PR to a recent dev commit (at most 10 behind; a maintainer may still ask for the exact tip before merge).

  • I resolved all correct Codex and CodeRabbit findings.

  • My PR is ready for review.

@coderabbitai

coderabbitai Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the intake: hygiene-blocked Deterministic PR hygiene checks failed label Sep 30, 2026
@github-actions

Copy link
Copy Markdown

⚠️ Deterministic hygiene checks failed.

  • unsponsored_surface — This changes an authentication, workflow, release-automation, or dependency surface. MAINTAINERS.md requires security review for these; ask a maintainer to apply maintainer-sponsored once they have reviewed it. Paths: .github/workflows/ci.yml, .github/workflows/codex-queue-helpers.yml, .github/workflows/enforce-pr-target.yml, .github/workflows/release.yml, bun.lock, package.json, scripts/prepare-package.ts, src/cli/account-auth.ts, src/oauth/account-quota-rank.ts, src/oauth/anthropic-account-threshold.ts, src/oauth/anthropic-import.ts, src/oauth/anthropic-local-adoption.ts, src/oauth/anthropic-model-cooldown.ts, src/oauth/anthropic-model-routes.ts, src/oauth/anthropic-routing.ts, src/oauth/anthropic.ts, src/oauth/chatgpt.ts, src/oauth/devin.ts, src/oauth/generic-account-failover.ts, src/oauth/index.ts, src/oauth/kiro-account-load.ts, src/oauth/kiro-device-login.ts, src/oauth/kiro-terminal-failover.ts, src/oauth/local-token-detect.ts, src/oauth/login-flow-state.ts, src/oauth/pool-settings-capability.ts, src/oauth/store.ts, src/oauth/token-guardian.ts, src/oauth/types.ts, src/server/auth-cors.ts, src/server/management-api.ts, src/server/management-auth.ts, src/server/management/oauth-account-routes.ts.

@github-actions

github-actions Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

⏳ DRAFT

  • hygiene: unsponsored_surface.

What to do

  • Fix unsponsored_surface — This changes an authentication, workflow, release-automation, or dependency surface. MAINTAINERS.md requires security review for these; ask a maintainer to apply maintainer-sponsored once they have reviewed it. Paths: .github/workflows/ci.yml, .github/workflows/codex-queue-helpers.yml, .github/workflows/enforce-pr-target.yml, .github/workflows/release.yml, bun.lock, package.json, scripts/prepare-package.ts, src/cli/account-auth.ts, src/cli/status-oauth.ts, src/codex/auth-context.ts, src/oauth/account-quota-rank.ts, src/oauth/anthropic-account-refusal.ts, src/oauth/anthropic-account-threshold.ts, src/oauth/anthropic-continuity.ts, src/oauth/anthropic-identity.ts, src/oauth/anthropic-import.ts, src/oauth/anthropic-local-adoption.ts, src/oauth/anthropic-model-cooldown.ts, src/oauth/anthropic-model-quota.ts, src/oauth/anthropic-model-routes.ts, src/oauth/anthropic-rate-limit-policy.ts, src/oauth/anthropic-routing.ts, src/oauth/anthropic.ts, src/oauth/chatgpt.ts, src/oauth/devin.ts, src/oauth/generic-account-failover.ts, src/oauth/health.ts, src/oauth/index.ts, src/oauth/kiro-account-load.ts, src/oauth/kiro-device-login.ts, src/oauth/kiro-terminal-failover.ts, src/oauth/local-token-detect.ts, src/oauth/login-flow-state.ts, src/oauth/pool-settings-capability.ts, src/oauth/refresh-policy.ts, src/oauth/store.ts, src/oauth/token-guardian.ts, src/oauth/types.ts, src/oauth/zed.ts, src/server/auth-cors.ts, src/server/management-api.ts, src/server/management-auth.ts, src/server/management/oauth-account-routes.ts.
  • Tick all four boxes in the PR description once you're done (currently 1/4).

Review readiness checklist

  • ⬜ Required local validation passed; commands, results, and any full-suite exception are documented.
  • ✅ I pushed my PR to a recent dev commit (at most 10 behind; a maintainer may still ask for the exact tip before merge).
  • ⬜ I resolved all correct Codex and CodeRabbit findings.
  • ⬜ My PR is ready for review.

1/4 boxes ticked.

This pull request was already a draft. Its draft status will be preserved after every issue above is resolved.
@WanxTitanx Tick the boxes once required local validation has passed with commands, results, and any full-suite exception documented, your branch is on the latest dev commit, and every correct Codex and CodeRabbit finding is resolved.

lidge-jun and others added 26 commits October 3, 2026 23:51
Carry legacy fallback and refresh skew from lidge-jun#6378 at 3db2ab4. Verify fully rotated Claude pairs against bearer-bound account identity and capture ownership from one coherent store snapshot. Preserve unresolved history and refresh intent without guessing account ownership.

Co-authored-by: Epinephrine <luvs01@hanmail.net>
fix(responses): stabilize large native HTTP uploads (carry lidge-jun#6508)
…-c-ollama

fix(ollama-native): retain tool batches across assistant commentary
Retain standalone pairing carry and its unique real-HTTP regression after shared registry normalization and upload integration.
…-a-messages

fix(claude): keep native context failures terminal in Messages
fix(antigravity): group Claude 5.5 usage and derive reference prices
fix(codex): classify revoked native sessions without stale attribution
Carry the credential-provenance and refresh work from lidge-jun#6507 (6108244 and 7ffd1a8). Bind native refusal to the physical profile and grant, preserve caller-owned credentials across preview and retry, and retain only fixed refresh diagnostics. Keep terminal-probe attribution from the parent lidge-jun#6515 correction.

Co-authored-by: Vadym O <bolein95@gmail.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…-e-identity

fix(oauth): preserve Claude identity across token rotation (carry lidge-jun#6378)
…i-parity-foundation

# Conflicts:
#	scripts/test-layout/layout.json
#	tests/fixtures/test-layout-expected.json
lidge-jun and others added 29 commits October 5, 2026 04:09
…ounts-settings

feat(cli): complete account policy and runtime settings workflows
…egrations-maintenance

feat(cli): complete integration recovery and maintenance workflows
…ervation-api

feat(cli): complete observation and explicit-key API workflows
…to Windows (lidge-jun#6599)

cli-access-audio: /dev/null does not exist on Windows, so the stat fails as a read error (exit 1) instead of a usage refusal (exit 2). Keep the directory case strict everywhere, use NUL on Windows, and assert the device is refused with no request sent on every platform.

cli-account-login-options: new URL(..., import.meta.url).pathname is /D:/... on Windows and cannot be imported by the --eval child. Use pathToFileURL(repoPath(...)).href.
…ge-jun#6596)

* docs(devlog): plan Claude settings single page and Desktop model roles

* feat(gui): lay Claude Code settings out as one page with a sticky save bar

* fix(gui): make a successful Claude Code save the baseline before its refresh

* feat(gui): lead Claude Desktop with default and quick task models, tiers under Advanced

* fix(gui): keep Claude Desktop import and export reachable with no models

* docs: describe the one-page Claude settings and Desktop model roles

* perf(gui): single pass for Desktop role defaults, toSorted for the list order

* fix(gui): show the normalized interception rows once a Claude Code save succeeds

* refactor(gui): build the Claude Code save body from the submitted draft

* fix(gui): drop Claude Code reads that a successful write has superseded

* fix(gui): keep reads that overlap a Claude Code save out of the session cache

* fix(gui): publish the Claude Code save cache from the latest confirmed switches

* fix(gui): show a committed Claude switch even when its reread fails

* fix(gui): share the Claude Code write epoch across mounts

* fix(gui): build the Claude Code save cache from the shared session copy

* fix(gui): fold shared Claude Code reads into the draft of the page on screen

* fix(gui): deliver Claude switch acknowledgements to the page on screen

* fix(gui): deliver Claude Code save confirmations to the page on screen

* fix(gui): keep edits made while a Claude Code save is out

* docs(devlog): record the Claude Code save hardening from review
…ge-jun#6600)

* test(oauth): remove proxy keys case-insensitively in startup-proxy children

The startup-proxy refresh cases failed on Windows (dev dadc232, CI run
37227252582, shard 6/9): after the child deleted the six fixed proxy key
spellings, outboundProxyConfigured() still returned true. Windows environment
names are case-insensitive, so an inherited spelling outside that fixed list
survives. Both the parent env handed to the child and the child's own cleanup
now remove every key whose upper-cased name is HTTPS_PROXY, HTTP_PROXY or
ALL_PROXY, and the precondition assertion names any proxy key still visible.
The production startup-proxy guard is unchanged.

* test(oauth): only require an observably proxy-free env where deletion is observable

Windows CI run 37229867142 showed the real cause of the shard 6/9 failure: on
win32 Bun 1.4.0, deleting a process.env variable removes it from enumeration
(no proxy key remains in Object.keys(process.env)), but property reads still
return its value, so outboundProxyConfigured() stays true. The "deleted" child
therefore keeps its strict current-env precondition on every other platform,
and the "empty" child keeps it everywhere. The startup snapshot and intent
retention assertions run on all platforms. Production behavior is unchanged;
on Windows a runtime deletion simply leaves the guard closed.
…; state unhealthy in-place shim status (lidge-jun#6602)

* test: make catalog audit and provider proxy fixture robust on Windows runners

Compare the audit opencodexHome with redactUserPath of the same path, so long, 8.3 and non-home temp roots all hold. Fail only the audit file ACL in the Windows audit privacy cases; the catalog writer legitimately hardens its own backup on real Windows. Bound the provider proxy fixture child at 45s on Windows (12s elsewhere) under a deadline 3s above it, and report signal, elapsed time and bound when it is killed.

* fix(codex): state the unhealthy verdict in in-place shim status

diagnoseCodexShim computed healthy:false for a damaged Windows in-place wrapper, but its summary only said "shim present", so ocx codex-shim status read a broken wrapper as fine. Append the unhealthy verdict and repair command when the diagnosis is unhealthy, matching the overlay summary. A host-independent regression records a legacy win32 in-place state; it fails without the fix.
…come (lidge-jun#6595)

* docs(devlog): close the CLI update restart unit with its delivery outcome

lidge-jun#6556 merged as 7cf1b76, so its devlog unit moves from _plan to _fin with
the recorded outcome: the final-head unmocked POSIX acceptance and its limits,
the runtime-readiness gate and lidge-jun#6548 message carry, the test isolation fix,
and the lidge-jun#6548 disposition.

Co-authored-by: agentHits <140916359+agentHits@users.noreply.github.com>

* docs(devlog): record lidge-jun#6548 closure in the restart unit delivery outcome

---------

Co-authored-by: agentHits <140916359+agentHits@users.noreply.github.com>
…idge-jun#6597)

* fix(integrations): write DSH routes to the Desktop profile patch it reads

DSH 0.1.7+ imports $DSH_HOME/settings.yaml once into the first profile
that boots and renames it to settings.yaml.imported. From then on it reads
provider routes from the llm-pi-ai row of a profile patch (a top-level
YAML list of loader rows) and hot reloads that file. The integration kept
writing settings.yaml, so after that first import a catalog refresh, a
model change or a disable reached nobody, and status read the renamed file
as absent.

Declare the Desktop profile's cordis.patch.yml as DSH's currentStore (the
seam from lidge-jun#5348), addressed through a leading [id=llm-pi-ai] selector.
The home patch is not an alternative: a home row replaces the profile
row's whole config, the user's own routes with it.

- merge.ts keeps a sequence root, and prunes an element it seeded once
  only its selector fields remain.
- The source-preserving YAML patcher edits one top-level list entry as the
  block map it holds and restores its "- " and two-space indent byte for
  byte. DSH's empty `[]` is the only flow form adopted, and a disable that
  empties the list writes it back.
- IntegrationTarget carries its own sourcePreservingYaml, so the legacy
  file and the store are patched along their own paths, and a coordinated
  write also holds DSH's config-editor lock (the profile's
  package.json.lock) whenever the profile directory exists.
- Without a Desktop profile the legacy settings.yaml stays the target.
- The dashboard accepts the new plan path; GUI text, docs and the
  integrations structure doc describe the new location.

* test(gui): pin the DSH ownership copy to the Desktop profile path

The locale-parity fixture still held the settings.yaml sentence in every
locale, and the DSH surface test asserted the old llm-pi-ai.providers
spelling. Both now follow the copy: the llm-pi-ai row, the Desktop
profile patch, and the settings.yaml fallback.

* fix(integrations): keep DSH profile refresh order and lock late profiles

Refreshing a Desktop profile row that OpenCodex created no longer deletes and
re-appends it in the expected merge, so a row DSH appended afterwards no longer
turns a routine catalog refresh into an "unsafe" refusal. The created-row
provenance is kept so disable still removes it.

The profile manifest lock is now chosen after the settings lock is held and
re-checked after every revalidation await, so a profile that appears mid-write
is locked and revalidated before it is read or written. Removing the last
managed row also keeps the file's original final-newline and CRLF convention.

* fix(integrations): refuse restoring into a missing DSH profile directory

A confirmed restore of a journaled Desktop profile write used to recreate a
removed profiles/desktop directory and write it without the profile's
package.json.lock. Preview and restore now refuse as unsafe when the declared
locked store's directory is missing, and the structure doc records the lock
re-probe, row-order, and restore contracts.

* docs(structure): fit the DSH store paragraph inside the integrations budget

Merging lidge-jun#6577 put structure/clients/integrations.md four lines over its
600-line budget. Tighten the DSH paragraph without dropping any contract.

* fix(integrations): report a booted DSH profile without a patch instead of writing settings.yaml

With profiles/desktop/package.json present and cordis.patch.yml missing,
the target fell back to $DSH_HOME/settings.yaml with no ineffective
marker. DSH imported that file when it booted the profile and never
reads it again, so the write was lost without a word. A store
declaration can now name a missing store the client still reads; DSH's
does, and the write is refused as an ineffective one with the remedy
(create the patch as `[]`).

* docs(integrations): state why a DSH profile without a patch is refused

The comments, structure doc, and refusal message said DSH imports
settings.yaml once and never reads it again. Upstream DSH's
importLegacyDocument renames settings.yaml to settings.yaml.imported and
imports it on every startup where it exists. The refusal stays: a block
written there would be moved out from under opencodex's ownership record.
Only wording changes; behavior and tests' assertions are unchanged.

* feat(integrations): show the missing-store remedy in the dashboard

A DSH Desktop profile whose cordis.patch.yml is missing is refused as
superseded_store, and the CLI names the fix: create the patch containing
`[]`. The dashboard only had the generic superseded-store copy, which says
the client reads a file opencodex does not write and offers no way out.

- The missingStore declaration publishes its empty document (`[]` for DSH)
  beside the remedy text, and IneffectiveWrite carries it.
- Status rows carry supersededReason beside supersededBy, plus
  missingStoreDocument for a missing store.
- A superseded_store plan carries the same two fields. The plan still names
  no file (the path stays on the status row), and the fingerprint does not
  change: the bound ineffective-write token already covers this finding.
- The GUI accepts the fields only on a superseded_store refusal, the
  document only for missing-store and only as one short line, and renders
  copy that names the file and the document in all eleven locales.

* fix(integrations): name the missing store in the dialog and decode it in the CLI

- The apply dialog covers the page's status notice, so a refused DSH
  preview now names the patch path as well as `[]`. The path comes from
  the status row; the plan still names no file. Bulk dialogs, which have
  no single status row, keep the pathless copy.
- The Turkish copy names the legacy settings file explicitly instead of
  "that file".
- The CLI plan decoder from lidge-jun#6542 accepts supersededReason and
  missingStoreDocument under the same contract as the GUI, and
  `ocx integration client preview` prints the remedy. Both decoders now
  reject a non-string reason and a document that is not one short
  printable-ASCII line, since the CLI echoes it to a terminal.

* fix(gui): wrap long missing-store paths in the DSH notice and plan dialog

---------

Co-authored-by: JUN <jun@lidgeai.com>
…-list next steps (lidge-jun#6611)

* fix(cli): show account health actions, paid-credit consent, and empty-list next steps

* fix(cli): never echo an id that fails the selector allowlist in account recovery lines
… in leaf help (lidge-jun#6609)

* fix(cli): correct help and CLI reference text and show declared flags in leaf help

* test(cli): follow the corrected restart help summary
…ss (lidge-jun#6601)

* fix(management): keep inference ports independent of management ingress

* fix(management): keep Cursor gateway on the bound inference port; cover ingress export

Cursor status now prefers the lifecycle-bound public port, then the PID-matched runtime record, then config, so a management-only ingress port can never become the advertised gateway. Adds a real-server regression that exports a client config through hub management ingress and asserts the public bound port, plus Cursor precedence cases, and records resolver ownership and known limitations in ADR-6598.

* fix(management): use the live bound port for Desktop provider-change auto-apply

autoApplyDesktopBestEffort wrote the Desktop 3P config from config.port, so a CLI override or ephemeral bind could leave Desktop pointing at a port nothing serves. It now uses managementInferencePort like the other management writers; the roster-update fixture asserts the live port reaches the writer.

---------

Co-authored-by: Ingwannu <ingwannu@users.noreply.github.com>
Co-authored-by: JUN <jun@lidgeai.com>
…6588)

* fix(responses): normalize native upstream session aliases

* test(responses): expect normalized session_id for caller aliases; state alias precedence

Canonical ChatGPT egress now fills session_id from session-id/thread-id, so the Claude affinity and Chat affinity wire expectations follow it. Adds a two-alias precedence case and documents exact precedence, the bridges' empty-value filtering, and that aliases are forwarded raw like an explicit session_id.

* fix(responses): treat empty session headers as absent when normalizing aliases

Upstream auth header selection already drops empty values, so the alias helper now does the same. First attempts and retries rebuilt from raw caller headers pick the same upstream session_id. Docs state the precedence for non-empty headers.

* test(responses): cover caller session identity across auth replay

---------

Co-authored-by: JUN <jun@lidgeai.com>
… #debug after the GUI regroup (lidge-jun#6612)

* fix(gui): keep short sidebars, Claude sidecar rows and Save errors usable; open legacy #debug on Debug

Audit follow-up for the GUI merged since v2.77.0 (lidge-jun#6579, lidge-jun#6593, lidge-jun#6596):

- A short or zoomed desktop window no longer collapses the sidebar menu to its padding: the menu keeps about three rows and the whole rail scrolls only when it cannot fit, with the language menu kept on screen.
- The Claude web search and vision sidecar rows wrap their controls under the copy instead of covering the title (French at 768px) or clipping the model input (390px).
- A failed Save on the one-page Claude settings reports in the Save bar, where it was clicked; the bar status wraps instead of sliding under Revert.
- Cold-loading a legacy #debug bookmark selects the Debug tab, reading the canonical hash like Connect and Providers do.

Findings and plan: devlog/_plan/261005_r4_gui_audit/.

* fix(gui): keep the short-window language menu on screen in every engine

Review on lidge-jun#6612: the rail backdrop-filter makes the sidebar the containing block of the fixed language menu, so an engine that treats it like an absolute child would scroll and clip it with the rail. In windows 480px tall or less the rail is now opaque, as in the existing no-backdrop-filter fallback, which anchors the menu to the window; the menu is opaque too.
… the dashboard (lidge-jun#6613)

* docs: sync Connect, Claude settings and DSH profile-patch guides with the dashboard

The integration guides still sent readers to an Integrations tab that is called Connect since lidge-jun#6593, the DSH sections named the legacy settings.yaml mapping as the only owned path after lidge-jun#6522 moved it to the Desktop profile patch, and the Claude GUI sections listed the pre-lidge-jun#6596 order without the Save bar contract. English and the seven translations now match the shipped dashboard.

* docs: name the DSH missing-patch refusal and finish the Connect → API Keys rename

Review on lidge-jun#6613: a Desktop profile without cordis.patch.yml makes Apply refuse with the create-[] remedy rather than write the patch or fall back to settings.yaml, and the remote-hub, CLI lifecycle and Codex integration pages still pointed at Integrations → API Keys or the Integrations overview.
…e-jun#6591)

* fix(test): keep armed test processes out of the real Codex home

A local suite run rewrote the real ~/.codex catalog twice (lidge-jun#6529): a
convergence ran with OPENCODEX_HOME in the test temp tree and
CODEX_HOME unset, so it resolved os.homedir()/.codex, which ignores
the preload's HOME on macOS. The real-home guard covered the OpenCodex
home and native auth.json, not the catalog, models cache, journal or
config.toml.

atomicWriteFile now refuses any write whose directory is the real Codex
home in an armed test process, and K refuses it before the owner
precheck, so a test never gets a catalog permit for it.

Refs lidge-jun#6529

* test: probe the unset-CODEX_HOME fallback against the real-home guard

Run the probe child with CODEX_HOME absent and HOME/USERPROFILE at the
sentinel home, check getCodexHome() resolves there, and check every
Codex-home write and K are refused. This is the path the incident took.

---------

Co-authored-by: JUN <jun@lidgeai.com>
…ot starve claude.ai (lidge-jun#6511) (lidge-jun#6610)

* fix(claude): serve the Desktop picker over HTTP/2 so SSE streams cannot starve claude.ai (lidge-jun#6511)

The picker listener terminated claude.ai with an HTTP/1.1-only TLS server.
Claude Desktop keeps several messages/stream SSE subscriptions open, each
holding one of Chromium's six per-origin HTTP/1.1 connections, so later
claude.ai requests queued in the client and timed out before reaching
OpenCodex. Blind tunnels negotiate HTTP/2 with Anthropic and multiplex.

The listener port is now a TCP front that reads the TLS ClientHello ALPN
offer (bounded multi-record reassembly) and splices the untouched
connection to an HTTP/2 server when the client offers h2, or to the
existing native HTTP/1.1 relay otherwise (WebSockets included). HTTP/2
requests are translated for the HTTP/1.1 upstream (:authority -> Host,
cookie crumbs joined) and cancellation follows the underlying stream.
Shutdown force-closes every front, bridge, h2 and HTTP/1.1 socket.

* fix(claude): bound picker h2 fan-out and refuse unrelayable h2 targets

Security review of lidge-jun#6610: an HTTP/2 :method or :path that the HTTP/1.1
client cannot express threw before cleanup was installed, and one
connection could open unbounded streams, each dialing upstream. Validate
h2 targets and guard request construction (empty 400, fixed log line),
advertise maxConcurrentStreams 100 per session and cap in-flight upstream
requests at 256 listener-wide (empty 503 without dialing).

* fix(claude): refuse picker targets the URL parser rejects

Security re-review of lidge-jun#6610: an origin-form h2 path such as //[ passed
the target check but threw in new URL() before the refusal boundary.
Parse the pathname inside it and answer an empty 400.

* fix(claude): do not log a client-cancelled picker request as 502

Hosted CI on lidge-jun#6610: cancelling an h2 HEAD before upstream headers closed
upstream as intended, but the teardown error then wrote a 502 log line
for a client that had already gone. Ignore upstream errors once the
client side closed first. The ALPN test now asserts only that HTTP/1.1
clients never get h2: Bun's native HTTP/1.1 server does not report its
ALPN choice.
…lidge-jun#6618)

* fix(cli): stop echoing values in claude desktop apply argument errors

parseDesktopApplyArgs printed unknown arguments verbatim, so an inline
--token=<value> or a stray credential operand reached the terminal.
Show options by name only and bare operands as <redacted>.

* fix(cli): never echo rejected claude desktop arguments

Security review of lidge-jun#6618: option names can still carry values (-tVALUE,
dash-prefixed operands) and control characters. Apply errors now count
unknown arguments and list the valid options; move/default show a route
operand only when it is a plain provider/model id.

* fix(cli): keep desktop bind and profile file errors free of operands

Security re-review of lidge-jun#6618: bind errors echoed a rejected picker id and
an unavailable route, and import/export printed filesystem errors that
carry the user-supplied path. Binding errors now omit the id and show a
route only as a plain provider/model id; profile file failures report
the operation and error code.

* fix(cli): drop rejected route operands from desktop errors

Security re-review of lidge-jun#6618: a route that only looks like provider/model
is still a rejected operand. move/default and bind now say the route is
unavailable and point to ocx claude desktop show, without echoing it.
…dge-jun#6625)

* fix(gui): keep Claude Desktop role selects inside the Models card

A long unavailable stored model plus its status overflowed the role
select at 390px (chevron and status clipped) and squeezed the label
column to nothing at 768px. Bound the controls column, let the route
truncate inside the trigger while the translated status and chevron
stay whole, and put the full text in the trigger tooltip.

* test(gui): cover the unavailable role choice label and tooltip

The route sits in its own truncating span, the translated status in a
separate element, and the trigger's tooltip carries the full text.
…ffers Retry (lidge-jun#6623)

* fix(gui): start the integration dialog on Close and offer Retry when client status fails

Found by the R4 audit of lidge-jun#6597: showModal() focused the invisible backdrop dismiss button, so the dialog opened with no visible focus and Space dismissed it unseen; and a cold status-load failure on a client page had no way to retry.

* docs(devlog): record the lidge-jun#6597 GUI audit and the R4 CI plan

* test(gui): cover the dialog's initial focus and the client-status Retry
…oxy (lidge-jun#6622)

* fix(cli): name ocx start when integration preview finds no running proxy

* test(cli): pass preview stopped-proxy cases as object rows
…in argument errors (lidge-jun#6608)

* fix(cli): reject arguments to uninstall and redact credential values in argument errors

* fix(cli): keep adjacent credential options and option-shaped positionals redacted; cover models leftovers

* fix(cli): redact bare leftovers whenever argv carried a credential option

* fix(cli): scrub argv credential operands from console diagnostics as a last-line guard

* fix(cli): scrub only diagnostics streams and always collect inline credential operands

* fix(cli): redact credential-shaped unknown provider subcommands at the output site
…th, update; validate provider add before saving (lidge-jun#6614)

* fix(cli): honest exit codes and JSON receipts for config, alias, health, update; validate provider add before saving

* fix(cli): name the recovery path when provider changes are refused by config validation
… management refusals (lidge-jun#6615)

* fix(cli): name the real cause and next action in restart, update, and management refusals

* fix(cli): stop the owning proxy before reinstall advice; scope integration writer detail to the normalized route

* fix(cli): render fixed integration recovery guidance instead of writer prose

* test(cli): expect the no-request stopped-proxy guidance on Codex login routing
Preserve upstream grouped navigation, Haly API-key quotas and model scopes, Headroom, and bundled RTK. Reconcile credential continuity and typed recovery; translate extension controls into Portuguese and align the development version at 2.79.0.
@WanxTitanx WanxTitanx changed the title Sync Haly with OpenCodex v2.73.0 and bundle RTK Integrate OpenCodex v2.78.0 with Haly features and bundled RTK Oct 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

intake: hygiene-blocked Deterministic PR hygiene checks failed

Projects

None yet

Development

Successfully merging this pull request may close these issues.