Skip to content

sync: upstream v2.39.0 (af6113a) - #187

Merged
yansigit merged 182 commits into
devfrom
sync/upstream-v2.39.0-af6113a
Sep 1, 2026
Merged

yansigit merged 182 commits into
devfrom
sync/upstream-v2.39.0-af6113a

Conversation

@cursor

@cursor cursor Bot commented Sep 1, 2026 •

Copy link
Copy Markdown

Summary

  • Sync exact upstream release v2.39.0 at af6113a0381d6fff2e4dce587652825c7eeb6423 into fork dev while preserving fork-owned routing, retry, credential, storage, and automation contracts.
  • Rebuild the sync as a true two-parent merge from current origin/dev, then reconcile upstream Anthropic quota-window routing, Cursor protobuf requests, compaction, tool-call validation, update stop contracts, and dashboard controls.
  • Harden the repository test supervisor with monotonic deadlines, complete subprocess-tree cleanup, and isolated lanes for measured load-sensitive suites.
  • Add release-version repair automation that opens a review-required dev bump PR and creates a deduplicated Jules-queued issue with the exact failed run when repair fails.
  • Exact tested head: dd6318eb9.

v2.39 dashboard changes

Verification

  • bun run prepush — pass: typecheck, changed-GUI lint, 18,089 runtime tests, privacy scan, and changed-GUI doctor.
  • cd gui && bun test tests — 1,226 unaffected tests passed; the one stale reconciliation assertion was corrected and its 13-test file then passed.
  • bun run build:gui — pass, including frozen install, TypeScript/Vite production build, and package preparation.
  • bun run skill:surface:check — pass.
  • All Node-based GitHub automation validator commands from issue-quality-tests.yml — pass.
  • Focused Anthropic account-pool suite — 47 passed.
  • Focused account-pool/config/runner suite — 276 passed, 2 Windows-only skips.
  • Apple Container suite was not run because the container command is not installed on this host.
  • Security review: workflow permissions are job-scoped; external actions are commit-pinned; protected dev is never pushed directly; pre-existing bot branches are content-validated and updated only with an exact lease; failure alerts contain run URLs but no secrets.

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.

Human merge only. Preserve the merge commit; do not squash or rebase this upstream sync.

lidge-jun and others added 30 commits August 29, 2026 01:24
…lidge-jun#2832)

* release: v2.32.1

* release: v2.33.0

* chore: add Cloud Agent dev environment config

Add .cursor/environment.json so Cloud Agents boot ready for the
Bun-native runtime: install bun + project/gui dependencies, expose the
proxy on port 8899, and run 'ocx start' as a persistent terminal.

Co-authored-by: JUN <jun@lidgeai.com>

* docs: record Cloud Agent setup in AGENTS.md instead of environment.json

Drop the .cursor/environment.json added earlier on this branch and document
the same knowledge as a 'Cursor Cloud specific instructions' section: Bun is
not preinstalled (install via the official installer), how to run the proxy,
and the five environment-only test failures (no systemd init; container
filesystem mtime granularity) so future agents do not re-investigate them.

Co-authored-by: JUN <jun@lidgeai.com>

* docs: generalize sandbox setup notes beyond Cursor Cloud

Retitle the section 'Minimal containers and agent sandboxes' and phrase the
guidance so it covers any fresh dev container or agent sandbox (Cursor Cloud,
devcontainers, CI images): Bun is often absent, service tests need a running
systemd init, and two integrity tests need fine mtime granularity.

Co-authored-by: JUN <jun@lidgeai.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
dev's package.json said 2.35.0 while the repository had already published
v2.36.0-preview.20260829 (npm dist-tags: preview=2.36.0-preview.20260829,
latest=2.35.0). The preview bump was cut on the prerelease train and never came
back to dev, so tests/release-version-line.test.ts fails on every commit that
descends from dev:

  release version line > the in-tree version is never behind a released one
  package.json version 2.35.0 is BEHIND the highest release tag
  v2.36.0-preview.20260829

That is inherited red, not a defect in any of the pull requests hitting it. It
currently fails test 2/4, test 3/4, test 4/4, and macos on lidge-jun#2835, lidge-jun#2822, lidge-jun#2821,
lidge-jun#2796, lidge-jun#2797, and lidge-jun#2785 - six bug PRs whose own diffs are unrelated to release
tooling. Rebasing them onto an unrepaired dev cannot turn them green, which is
why this lands first.

2.36.0 rather than a preview suffix follows the precedent this repository set
twice: e4a85d1 moved dev to 2.34.0 when it trailed a published 2.33.0, and
076ad30 moved dev to 2.35.0 right after v2.34.0 shipped. dev carries the next
stable version; the preview train adds its own suffix at release time.

The value was chosen by running the repository's own comparator rather than by
reading it. Against the highest tag v2.36.0-preview.20260829, compareReleaseTags
returns -1 for 2.35.0 and 2.35.1, 0 for 2.36.0-preview.20260829 (legal only on
the commit that tag names, which a dev merge commit is not), and +1 for 2.36.0.
npm view @bitkyc08/opencodex@2.36.0 returns E404 and git tag --list v2.36.0 is
empty, so the string is unused.

Verification on this branch:
  bun test tests/release-version-line.test.ts   3 pass 0 fail (was 2 pass 1 fail)
  bun test tests/release-helper.test.ts         5 pass 0 fail
  bun test tests/compatibility-version.test.ts  1 pass 0 fail
… an inference (lidge-jun#2835)

Kiro emits answer-shaped prose and then calls the private completion tool in the
SAME inference. The adapter released the prose as `phase: "commentary"` and the
completion answer as `phase: "final_answer"`, and `src/bridge.ts` closes the
commentary message on the phase change, so the client rendered two assistant
messages with near-identical text. That is the duplicate answer users reported
after lidge-jun#2819.

A valid completion answer supersedes prose staged during the same inference, so
consume that collection instead of releasing it: drop the redundant
`text_delta`, keep every non-text event, and release retention either way.
Applied to `deferred` in required mode and `fallbackEvents` in text_fallback,
which is already gated on a valid completion answer.

The outer drain in `parseKiroAttempt` is deliberately untouched. An independent
audit caught that it is also the leftover flush for early terminal returns, so
teaching it to discard text would hide the only commentary a failed turn ever
produces. Splicing at the inner site leaves that drain empty on the completion
path and unchanged on every failure path.

Two existing expectations pinned the duplicate as intended behaviour and now
state the new contract. A Responses-protocol assertion covers what adapter-event
coverage cannot: the split happens in the bridge, so the proof has to be taken
at the wire. Both were driven red against the unpatched adapter — two assistant
messages before, one after.
…ne-2360

fix(release): move dev's version line past the published preview
…rapper

`classifyIpv6` decodes both `::ffff:` IPv4-mapped forms and judges the embedded
address, but had no case for NAT64. RFC 6052's well-known prefix 64:ff9b::/96
leads with hextet 0x64, which sits below the 2000::/3 global-unicast window, so
it fell through to the closing `non-global address` branch.

On any IPv6-only or DNS64 network that is not an edge case: the resolver
synthesizes 64:ff9b::<ipv4> for every IPv4-only peer, so ordinary public
destinations were rejected outright. `tests/codex-catalog.test.ts` and
`tests/baseten-provider.test.ts` already carry `allowPrivateNetwork: true`
workarounds naming NAT64, and `key-login-live-update` has been red on `dev` for
the same reason: `notifyRunningProxy` got `409 provider reload target rejected`
from `providerDestinationResolvedError`, so the credential reached disk while the
running proxy kept serving the stale in-memory row.

The decode mirrors the `::ffff:` handling — extract the embedded IPv4 and run it
through `classifyIpv4` — which is what keeps this from becoming an SSRF bypass.
Verified per address: wrapped 127.0.0.1, 10/8, 172.16/12 and 192.168/16 stay
blocked, and wrapped 169.254.169.254 still lands on the stronger metadata
blocklist. Only the well-known prefix is decoded; RFC 8215 reserves
64:ff9b:1::/48 for local-use translation, so it keeps its non-global treatment.

Prefix matching needs all eight hextets rather than the leading group
`firstIpv6Hextet` returns, so `ipv6Hextets` expands the literal, handling `::`
compression and the RFC 4291 trailing dotted-quad form. Reverting the classifier
turns the new coverage and `key-login-live-update` red.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The unit reached a terminal outcome, so it moves to _fin: the duplicate answer
is fixed and merged (lidge-jun#2835, 69031f6), and the non-termination half was
measured to be a stale process rather than a code defect.

040 records both, including the audit round that rejected the original plan.
Consuming the retained prose at the outer drain would have hidden the only
commentary a failed turn produces, so suppression is confined to the inner site
that knows a completion arrived.
…idge-jun#2785)

Co-authored-by: DevonGithub <22842728+DevonGithub@users.noreply.github.com>
…-and-nat64

fix(catalog,security): land approved verbosity and NAT64 fixes (lidge-jun#2799, lidge-jun#2798)
When orphan adoption removes an excluded managed model without emitting a
replacement table, remove its semantic model references through the existing
TOML-safe transform instead of leaving dangling aliases.
…-routing

fix(codex): close drain routing follow-ups
Derive removed aliases from the previous managed block as well as adopted
orphans, then rewrite every Grok model-selector path through one declared
inventory. Cover the normal managed exclusion path across all current fields.
…ers (lidge-jun#2842)

Issue lidge-jun#2810: a Clash/Surge/Mihomo fake-IP resolver can answer with
::ffff:0:c612:1b -- the explicit-zero spelling of 198.18.0.27. That form
assesses as "non-global address", never "benchmark address", so the
allowBenchmarkAddresses opt-in could not reach it and those users were
refused outright.

The fix is deliberately NOT an equivalence in classifyIpv6. Under RFC 4291 the
IPv4-mapped prefix is ::ffff:0:0/96, so ::ffff:0:<hi>:<lo> is a reserved
address whose tail merely looks like an IPv4. Declaring the two equal would
admit ::ffff:0:5db8:d822 (tail 93.184.216.34) as a public destination -- the
blocker raised on lidge-jun#2812. Instead the benchmark gate itself recognises the
explicit-zero encoding and checks the decoded tail against the 198.18.0.0/15
benchmark range only.

classifyIpv6 is unchanged, so a public-looking tail stays blocked and a
user-configured literal URL is still refused with or without the opt-in.

Reimplements lidge-jun#2812 by @gaoran1209 with the maintainer's blocker addressed.
Closes lidge-jun#2810.
Extend managed-model cleanup to role and persona model selectors, and cover
the complete inline selector matrix with a zero-dangling-reference regression.
…urfaces (lidge-jun#3050)

The rollback journal rendered as an unbounded flat list beneath the cards on
both Integrations surfaces, so every toggle piled on another row forever and
pushed the real controls off-screen. It is now bounded and collapsed by
default: the newest entry and its undo stay reachable without expanding
anything, and older entries reveal a page at a time behind a native
details/summary disclosure, which keeps them operable by keyboard.

The overview names the client on every row because a row there is ambiguous
without it; a client tab omits it because the heading already says it.

Also drops an 'as IntegrationJournalRow' cast from the test fixture. gui/tests
sits outside every tsconfig include, so the cast was the only thing standing
between the fixture and a compile error, and it had been hiding a clientId this
build does not have.
)

CLIENT_MARKS gave a brand mark to two of eleven clients; the other nine fell
back to a monogram, so the client list read as a wall of letters. Each added
mark is the vendor's own, taken from a first-party source and recorded with its
provenance and retrieval date in gui/public/provider-icons/README.md. No mark
is borrowed from another product, and a client whose vendor publishes no usable
first-party mark keeps its monogram rather than getting an invented one.
* fix(codex): refresh expired management entitlements

* test(codex): pin negative memo publication fences
Aside was registered as an export client but had no way to reach it from the
dashboard, so connecting it meant the CLI. It now appears on the Integrations
page as a file client like the others: the card reports detection state, the
connect control toggles it, and the copy is carried across all nine locales.

Also fixes a defect CI found in the first pass: the direct writer path resolved
only one of Aside's two paths, so a write could land against a stale root.
…ng (lidge-jun#3065)

Aside publishes no favicon.svg, so it was recorded as having no first-party
mark. The installed application ships one: the vendor names the module
official-brand-symbol and renders it across Aside's own onboarding, permission,
and settings screens. The single 24x24 evenodd path was lifted verbatim into an
SVG with its original viewBox and currentColor fill.

Rendering all nine marks at 28px on both themes then exposed an older defect.
Each mark draws as an <img> over a transparent background, so a single-ink logo
is visible against only one theme: prime is white and vanishes in light mode,
opencode and kimi are near-black and vanish in dark. Monochrome marks now draw
through a CSS mask tinted with the row's text color, matching what
provider-icon-mask already does; multi-color marks stay <img> so a brand palette
is not flattened into one ink.

The uniqueness test now collects both rendering paths; it asserted <img> src
only, so a masked mark could go missing or collide and still pass.
…ted (lidge-jun#3060)

MAINTAINERS.md said no branch protection rule is configured, so code-owner
approval and the maintainer-approval requirement were a convention rather than a
gate. AGENTS.md repeated it. Both are wrong: dev, main, and preview each carry an
active repository ruleset, and Protect dev requires a reviewed pull request while
blocking force-pushes and deletion.

The claim was believable because rulesets do not appear in the classic
/branches/{branch}/protection endpoint, which returns 404 for all three.

Also documents the maintain/admin pull_request bypass, so an owner merge that
skips the approval requirement reads as an exercised bypass rather than the
documented normal case.
* fix(codex): retain entitlement refresh provenance

* feat(management): expose OpenAI entitlement status

* fix(codex): report outer entitlement refresh flights

* fix(codex): distinguish entitlement network failures
…ern (lidge-jun#3075)

CodeQL js/redos, high severity, found on the v2.38.0 promotion PR.

The prerelease section used the semver.org pattern verbatim. Its three identifier
alternatives overlap:

  0 | [1-9]\d* | [0-9A-Za-z-]*[A-Za-z-][0-9A-Za-z-]*

and wrapping that in (?:\.identifier)* lets a backtracking engine try an
exponential number of ways to split the same string.

The cost is real, not theoretical. "0.0.0-0." followed by repetitions of "--."
took 522ms for a single 125-character input — inside the 128-character ceiling
this module enforces, and inside the 96-character one its only caller passes. A
length cap does not fix superlinear growth; it only picks where on the curve the
input lands. Going from 20 to 39 repetitions moved 16ms to 524ms.

Match the prerelease in one non-backtracking pass and validate each identifier
separately with anchored regexes that contain no repeated alternation. Same
input took 0.024ms afterwards.

Behaviour is unchanged: 36 grammar cases spanning the semver.org examples and
the leading-zero, empty-identifier and malformed rejections agree with the old
pattern exactly, and the parsed core/prerelease shape is identical.

The regressions fail against the old pattern at 524ms and 520ms.
[WRONG BRANCH] promote dev onto main for v2.38.0
@github-actions github-actions Bot added the intake: hygiene-blocked Deterministic PR hygiene checks failed label Sep 1, 2026
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

⚠️ Deterministic hygiene checks failed.

  • new_suppression — A new TypeScript, lint, formatter, or similar suppression was added. Fix the underlying issue or obtain suppression-approved. Paths: gui/src/pages/Models.tsx.
  • 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/scripts/closed-pr-branch-cleanup.cjs, .github/scripts/closed-pr-branch-cleanup.test.cjs, .github/workflows/dev-version-bump.yml, bun.lock, package.json, src/codex/auth-api.ts, src/codex/auth-context.ts, src/lib/windows-secret-acl.ts, src/oauth/account-quota-rank.ts, src/oauth/anthropic-routing.ts, src/oauth/chatgpt.ts, src/oauth/generic-account-failover.ts, src/oauth/index.ts, src/oauth/login-cli.ts, src/oauth/store.ts, src/server/auth-cors.ts, src/server/management-api.ts, src/server/management/oauth-account-routes.ts.

@github-actions

github-actions Bot commented Sep 1, 2026 •

Copy link
Copy Markdown

PR automation (bot-owned)

  • Class: draft (draft)
  • Base: 27d6ec9c39bac0f35232b1af9236d2bf50bde023
  • Head: dd6318eb9d6d8c28fe2acd0430194e9b220ed3e8
  • Action: observed
  • Exact-head gate: BLOCKED (not-mergeable, check-missing, check-not-success)
  • Sensitive paths: .github/scripts/closed-pr-branch-cleanup.cjs, .github/scripts/closed-pr-branch-cleanup.test.cjs, .github/workflows/dev-version-bump.yml, package.json, src/adapters/agentrouter.ts, src/adapters/cursor.ts, src/adapters/cursor/call-id.ts, src/
  • Maintainer auto-merge approval: NO
  • Bot merge evidence: NO
  • Next action: human review required

@github-actions

github-actions Bot commented Sep 1, 2026 •

Copy link
Copy Markdown

✅ READY

  • all exact-head sync PR quality gates passed; ready for human merge.

This pull request has been marked Ready for Review.
The review-ready label marks this PR as ready; review automation runs independently.
Maintainers notified: @yansigit

@yansigit
yansigit force-pushed the sync/upstream-v2.39.0-af6113a branch from 9a0f9a2 to eae4b22 Compare September 1, 2026 13:05
@yansigit yansigit added the maintainer-sponsored Maintainer sponsors this change to an auth, workflow, release, or dependency surface label Sep 1, 2026
@github-actions github-actions Bot removed the intake: hygiene-blocked Deterministic PR hygiene checks failed label Sep 1, 2026
@github-actions
github-actions Bot marked this pull request as ready for review September 1, 2026 16:43
@github-actions
github-actions Bot requested a review from yansigit as a code owner September 1, 2026 16:43
@yansigit
yansigit merged commit 59c4896 into dev Sep 1, 2026
54 of 57 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

maintainer-sponsored Maintainer sponsors this change to an auth, workflow, release, or dependency surface review-ready

Projects

None yet

Development

Successfully merging this pull request may close these issues.