Commit Graph

1198 Commits

Author SHA1 Message Date
Peter Steinberger
2afa9de438 fix(codex): structured abort detection, tool-schema repair, native-result middleware relay (#108105)
* fix(codex): use structured turn status for aborts, repair tool schemas, relay native results to middleware

- turn aborts are detected from the correlated turn/completed status instead
  of byte-matching private codex-rs prose; the <turn_aborted> marker remains a
  non-terminal user-interrupt hint (tags only, wording-independent) because the
  app-server collapses all abort reasons into "interrupted" (#99268)
- dynamic-tool schemas are repaired before projection via the shared OpenAI
  normalizer: annotation nulls stripped, type:null inferred from object/array
  shape hints; unrepairable null constraints stay quarantined instead of
  widening the schema (#106277, #97913)
- Codex-native tool results now flow through agentToolResultMiddleware at the
  post_tool_use relay boundary (observe-only: the Codex PostToolUse contract
  cannot replace a native tool response) (#95597)

* test(codex): regenerate prompt snapshots for normalized dynamic-tool schemas

The shared OpenAI strict-compat normalization now runs on Codex dynamic tools,
so empty object schemas gain additionalProperties:false and required:[] in the
snapshot payloads, matching what the OpenAI provider family sends.
2026-07-15 00:51:24 -07:00
Yuval Dinodia
7974def3fd fix(codex): restore shell for restricted turns (#92294)
* fix(codex): keep OpenClaw exec when native surface has no environment (#92238)

* chore: keep release note in PR

* fix(codex): keep shell tool type internal

Co-authored-by: yetval <yetvald@gmail.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-15 00:37:04 -07:00
Peter Steinberger
80e1509fe8 fix(codex): keep parent binding on cross-key handoff and stop foreign-transcript mirror warns (#108042)
- session_end with a provably different nextSessionKey (dashboard "New Chat",
  fork child) no longer permanently retires the still-live parent Codex
  binding; same-key rollovers, unknown-key ends, and terminal ends retire as
  before (#106778)
- mirrored session-history reads treat well-formed non-Codex transcripts as an
  empty mirror instead of a read failure, so codex harness hooks stop warning
  on every non-Codex model run; corrupted session headers stay on the warn
  path (#106556)
2026-07-14 23:50:01 -07:00
Peter Steinberger
7f1baa6d75 refactor(codex): trim session catalog exports (#108045)
* refactor(codex): privatize session catalog helpers

* chore(deadcode): refresh export baseline
2026-07-14 22:59:46 -07:00
Kyle Klouzal
2333bd59db fix: keep yielded parent turns nonterminal (#95996)
* fix: keep yielded parent turns nonterminal

* fix: type chat final stop reasons

* test: isolate yielded session reconciliation

* fix: refresh yielded lifecycle generated surfaces

* test: register Codex lifecycle test shard

---------

Co-authored-by: FullerStackDev <263060202+fuller-stack-dev@users.noreply.github.com>
2026-07-14 20:35:33 -06:00
Peter Steinberger
57d926b4fd fix: connect resumed native terminals reliably (#107688)
* fix: render resumed paired-node terminals

* fix(control-ui): connect native catalog terminals reliably

* chore: keep release notes in PR body

* fix(control-ui): require terminal reconnect cancellation

* fix(gateway): cancel timed-out terminal opens safely

* fix(control-ui): recover stalled terminal opens

* chore(ui): refresh i18n fallback baseline

* fix: preserve login shell path for resumed terminals

* refactor(plugin-sdk): avoid extra resolver export

* fix(gateway): normalize terminal open failures

* test(control-ui): split terminal readiness coverage

* docs: explain catalog terminal PATH restoration

* fix(control-ui): complete terminal readiness release gates

* fix(ci): remove unused shell resolver exports

* chore(plugin-sdk): refresh API baseline after rebase
2026-07-14 19:18:19 -07:00
Shakker
4887cf55b4 fix: classify Codex tool results through shared contract (#107807)
Successful Codex dynamic-tool results now use the shared failure classifier, preventing Skill Workshop and plugin lifecycle metadata from being persisted as failed calls.

Refs #107684.
Prepared head SHA: e5bfcdb085
Co-authored-by: Shakker <165377636+shakkernerd@users.noreply.github.com>
Reviewed-by: @shakkernerd
2026-07-14 23:24:36 +01:00
Peter Steinberger
a6a0716486 feat(setup): rename Crestodian to OpenClaw system agent
User-facing name is now OpenClaw (the system speaks); internal code name is
system-agent. Gateway methods crestodian.* -> openclaw.chat/openclaw.setup.*,
agent tool -> openclaw, reserved agent ids openclaw + retired crestodian.
openclaw setup routes: onboarding flags -> onboard, -m/--yes -> system agent,
bare configured interactive -> OpenClaw chat, unconfigured -> onboarding.
Hidden crestodian CLI and /crestodian TUI aliases kept; docs moved to
docs/cli/openclaw.md with redirect stub. macOS/Android strings in lockstep.

Refs #107237
2026-07-14 11:03:02 -07:00
Peter Steinberger
e20c029efd refactor(codex): split app-server event projection (#107680)
* refactor(codex): split app-server event projector

* fix(codex): preserve raw event projection ordering

* chore(codex): remove projector max-lines exemption

* refactor(codex): split stateful projector owners
2026-07-14 11:00:08 -07:00
Jesse Merhi
00364ee777 improve: warn before non-ClawHub plugin installs (#102197)
Merged via squash.

Prepared head SHA: e08d9e737d
Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
Co-authored-by: jesse-merhi <79823012+jesse-merhi@users.noreply.github.com>
Reviewed-by: @jesse-merhi
2026-07-15 03:25:36 +10:00
Peter Steinberger
f81f9d8570 chore: enforce max-lines suppression ratchet (#107315)
* ci: enforce max-lines suppression ratchet

* chore: prune stale max-lines suppression

* fix: close max-lines ratchet enforcement gaps

* fix: harden max-lines ratchet checks

* fix(ci): satisfy max-lines ratchet checks

* style: format max-lines declarations

* fix(ci): match oxlint suppression grammar

* test: isolate max-lines git fixtures

* chore: prune resolved max-lines debt

* test: skip newline path fixture on Windows

* fix: harden max-lines suppression ratchet

* chore: refresh max-lines baseline

* fix: close max-lines ratchet bypasses

* fix: derive ratchet base from PR merge tree

* fix: support older Git in staged ratchet

* fix: align max-lines declarations and baseline

* chore: refresh max-lines baseline for current main

* fix: exclude generated wizard locales from max-lines

* chore: prune resolved max-lines debt
2026-07-14 09:27:02 -07:00
pash-openai
cbbccb8952 Recover large Codex app-server messages (#107369) 2026-07-14 07:07:52 -07:00
Ayaan Zaidi
8b66fe773f feat(mcp): deliver requester-scoped MCP to shared-thread harnesses
Requester-scoped servers never enter harness-native MCP config: Codex
thread and CLI user-MCP projections partition them out (fail-closed,
static-partition fingerprints stay sender-independent so shared threads
never rotate). Codex delivers them as per-attempt dynamic tools through
a scoped-only runtime path on the same core manager, with a
session-stable advertised catalog so authed and unauthed senders share
one spec surface; unauthed calls get a clean not-connected tool error.
New SDK seam materializeRequesterScopedMcpToolsForHarnessRun lets any
future harness consume the same contract.
2026-07-14 17:09:53 +05:30
Peter Steinberger
0604903f88 fix(session-catalog): authorize paired-node reads (#107410) 2026-07-14 04:19:09 -07:00
Peter Steinberger
e488dc0012 feat(sessions): signal watchers when an adopted upstream disappears (#107356) 2026-07-14 03:51:20 -07:00
Peter Steinberger
bb6874fddf feat(sessions): upstream liveness for adopted catalog sessions (#107009) 2026-07-14 01:09:05 -07:00
Peter Steinberger
644d4c3d23 fix: explain and control native session discovery (#107162)
* fix: make native session discovery configurable

* refactor: split native session discovery helpers

* chore: keep release notes in PR body

* fix: refresh generated session protocol models

* test(ui): avoid shared lazy-element mock race
2026-07-14 00:18:18 -07:00
Peter Steinberger
69eb20871d chore(codex): update Codex CLI to 0.144.4 (#107208)
* chore(codex): update Codex CLI to 0.144.4

* fix(codex): validate interrupt params through request map
2026-07-13 23:58:19 -07:00
Peter Steinberger
6625ea92f0 refactor(codex): evaluate startup deadlines first 2026-07-13 23:40:39 -07:00
Peter Steinberger
c953d8ec41 fix(codex): gate startup phases before deadlines 2026-07-13 23:40:39 -07:00
Peter Steinberger
d8d2f83cc1 feat(terminal): open Codex/Claude catalog sessions in a terminal on their owning host
Catalog session rows (sidebar context menu + click), the built-in viewer
header, and a new "Open Codex/Claude sessions in" preference can launch the
native CLI (codex resume / claude --resume) in the operator terminal on the
machine that owns the session.

- Gateway-local sessions spawn through the existing terminal launch policy
  (sandbox/enabled gates preserved) with the resume command in the session cwd.
- Paired-node sessions run through a new seq-ordered node PTY relay: a
  duplex node-host command streams PTY output via node.invoke.progress and
  receives keystrokes/resize via a new node.invoke.input event, behind the
  unchanged terminal.* client protocol (TerminalSessionManager gains a backend
  abstraction; node relay reuses the streaming-invoke controller).
- Owner boundary: each plugin owns its resume command and builds argv from a
  validated thread id; the gateway routes node opens through the node command
  allowlist and plugin invoke policy (no advertisement-only trust), and nodes
  re-verify session eligibility before spawning.
- UI setting catalogOpenTarget + canOpenTerminal capability gate every entry
  point; capability requires the owning host to actually have the CLI.

Node PATH is normalized before command-availability probes, Windows .cmd/.bat
shims spawn via ComSpec, and catalog terminal opens reattach persisted tabs
before opening the new tab.
2026-07-13 22:20:50 -07:00
Peter Steinberger
111b3a157e refactor(codex): use native SemVer floor comparison 2026-07-13 21:42:23 -07:00
Peter Steinberger
27f2a45c54 fix(onboarding): harden live inference handoff (#107041)
* fix(onboarding): harden live inference handoff

* fix(crestodian): preserve auto runtime probes

* fix(ci): restore current main lint gates
2026-07-13 21:15:36 -07:00
Peter Steinberger
4da0eb19c5 fix(state): converge legacy startup migrations (#107002)
* fix(state): converge legacy startup migrations

Co-authored-by: Eva <eva@100yen.org>

* refactor(state): split legacy migration helpers

* fix(memory): persist legacy source acknowledgements

* fix(state): remove stale migration imports

* fix(memory): recognize numbered migration archives

* fix(matrix): downgrade archived migration residue

* fix(memory): satisfy migration lint

---------

Co-authored-by: Eva <eva@100yen.org>
2026-07-13 20:05:24 -07:00
Peter Steinberger
877af700bf feat(codex): continue paired-node Codex catalog sessions from the Control UI (#106927)
* feat(codex): continue paired-node Codex catalog sessions from the Control UI

Codex catalog rows on paired nodes were view-only. Node rows are now
continuable when the node advertises and permits the codex threads.list,
thread.turns.list, and cli.session.resume commands. Continue adopts the
session into a locked codex OpenClaw session (deterministic
harness:codex:node-session key, bounded native-history import, two-phase
initializing marker) and installs a webchat conversation binding
(codex-cli-node-session) through the new generic
bindPluginSessionConversation seam with attempt-ID guarded rollback, so
each web turn runs codex exec resume on the owning node via the existing
inbound_claim path. Local continue/archive semantics are unchanged;
archived rows are no longer offered as continuable.

* fix(plugins): serialize plugin session binds per session

Review P2: the bind rollback checked the attempt id and then awaited the
unbind, so a concurrent Continue could install a newer binding between the
two and lose it to the older attempt's rollback. All session binds for one
session key now queue through an in-process tail, so a failing attempt can
only ever roll back its own binding; the attempt-id guard stays as defense
against out-of-band rebinds.

* refactor(codex): extract node-continue and session-bind modules for the LOC ratchet

Pure movement to satisfy the changed-file TypeScript size ratchet: the
paired-node continue flow moves to session-catalog-node-continue.ts and
session-catalog-node-adoption.ts, catalog paging/parsing helpers to
session-catalog-parsing.ts, the Control UI session-bind seam to
session-conversation-binding.ts (+ session-key helpers), and the internal
conversation-id/channel-prefix helpers to utils. transcript-mirror.ts is
restored to main byte-for-byte; the node history builder constructs a plain
CodexThread (only id is required) instead of widening signatures.

* fix(plugins): satisfy preserve-caught-error in the session-bind rollback

* fix(codex): gate node continue on operator.admin and resume by CLI session id

Second review round: (1) bound node turns pass canMutateCodexHost only for
owners/admins, while sessions.catalog.continue is operator.write — a
write-scoped Control UI client could adopt a node session whose every turn
would then be rejected. The gateway now forwards the caller's scopes to the
provider (SessionCatalogContinueProviderParams.clientScopes) and codex fails
node continues closed without operator.admin, before the dedupe join so a
non-admin cannot ride an admin's in-flight operation. (2) The node binding
stored the app-server threadId, but codex exec resume takes the CLI session
id and forked threads share a session tree where the two differ; the binding
now prefers record.sessionId.

* fix(codex): defer node-session restore until the binding is durable

Third review round: continuing an archived adopted node session unarchived
it before the gateway installed the conversation binding, so a failed bind
left a visible session with no node routing. The unarchive now rides
afterConversationBound; finalizeNodeAdoptedSession already covers both the
initializing and finalized marker states, so the eager restore helper is
deleted.
2026-07-13 19:54:31 -07:00
Peter Steinberger
5c9e09af3a style(codex): format prompt projection 2026-07-13 15:32:59 -07:00
Peter Steinberger
51fece4960 fix(codex): preserve failure-path ownership 2026-07-13 15:32:59 -07:00
Peter Steinberger
323a9fbe29 refactor(codex): split app server run attempt 2026-07-13 15:32:59 -07:00
Peter Steinberger
4319ddbe8c feat(control-ui): import Codex and Claude Code memory (#106406)
* feat(control-ui): import coding assistant memory

* test(migrate): clean memory import temp dirs

* chore: move memory import note to PR body

* build: refresh memory import generated artifacts

* fix(control-ui): complete memory import checks

* build(control-ui): localize memory recovery labels

* fix(control-ui): harden memory import recovery

* refactor(migrate): keep memory import surfaces bounded

* fix(control-ui): use canonical agent row type

* fix(codex): drop dead migration type exports

* fix(migrate): restrict imported memory permissions

* fix(control-ui): preserve memory import recovery state

* fix(control-ui): retain memory import results

* build(control-ui): preserve translation memory history

* fix(control-ui): bind memory import state to agent

* fix(control-ui): unlock memory import after refresh

* test(gateway): preserve memory method suffix

* fix(migrate): bind reviewed memory imports

* fix(migrate): make memory imports retry-safe

* perf(ui): keep memory import lazy

* build: refresh generated artifacts after rebase

* chore: keep migration runtime within LOC guard

* build: refresh Swift protocol model
2026-07-13 15:30:06 -07:00
Peter Steinberger
db02a96c4c refactor(process): route bounded commands through Execa (#106495)
* refactor(process): centralize bounded command execution

* refactor(process): migrate core one-shot commands

* refactor(plugins): migrate one-shot commands

* fix(process): await Windows tree termination

* chore(plugin-sdk): refresh process runtime surface

* refactor(process): migrate remaining bounded commands

* refactor(process): normalize command result handling

* refactor(process): split execution responsibilities

* chore(plugin-sdk): refresh API baseline

* chore(process): remove release-owned changelog entry

* fix(process): narrow binary command input checks

* fix(process): cap sandbox command output

* fix(qa-lab): preserve exact node probe env

* chore(ci): refresh dead export baseline

* fix(process): preserve force-kill command deadlines

* fix(process): avoid post-exit timeout reclassification

* test(process): update scp staging wrapper mock

* test(process): update remaining wrapper mocks

* refactor(qa-lab): preserve Execa tar execution
2026-07-13 11:07:35 -07:00
Peter Steinberger
e8290c699e refactor(codex): split app-server attempt helpers (#106550)
* refactor(codex): split app-server attempt helpers

* fix(codex): mark harness imports type-only
2026-07-13 09:58:01 -07:00
Peter Steinberger
fc4b6a4254 feat(codex): show the account email with app-server usage windows (#106500)
* feat(codex): read the account email with app-server usage

The Codex-harness usage snapshot now carries the account identity: the
usage fetch runs account/rateLimits/read and account/read over one
app-server session (new withCodexAppServerJsonClient seam, which the
single-request helper now delegates to), so the email is guaranteed to
belong to the same account as the windows. Identity stays best-effort;
rate limits survive an account read failure.

* style(test): scanner-safe app-server marker fixture

* test(codex): keep scanner-neutral hunks around app-server marker literals

* fix(codex): bound the best-effort account read within the usage deadline

Review P2: account/read shared the outer usage deadline, so a slow or hung
identity read could reject the whole snapshot with a timeout instead of
returning the already-fetched rate-limit windows. Race the account read
against a local timer bounded to min(4s, usageTimeoutMs/3) and drop the
identity on timeout; a regression test hangs account/read and asserts the
windows still return.

* fix(codex): send account/read params and bound identity by the remaining deadline

Second review round: account/read (GetAccount) requires a params object per
the app-server protocol, so send an empty {} (refreshToken defaults false);
without it a real app-server rejects the request. Bound the best-effort
identity read by the time left before the shared usage deadline (minus a
margin) instead of the original budget, so a slow rate-limit read can no
longer let the identity read trip the outer timeout and discard the
already-fetched windows.

* fix(codex): reserve the isolated shutdown budget in the usage deadline

Third review round: withCodexAppServerJsonClient awaits the isolated
client's closeAndWait inside the outer timeout, so a hung account/read
could reach the deadline during force-kill/exit cleanup and discard the
already-fetched windows. The usage read now passes a cheap isolatedShutdown
(force-kill 200ms + exit 300ms) and the identity bound reserves that plus a
250ms margin (750ms) of the remaining deadline, so cleanup always finishes
before the outer timeout.

* style(codex): rename scoped-request generic to avoid shadowing
2026-07-13 09:56:47 -07:00
Peter Steinberger
0ff265838b fix(codex): preserve shutdown cleanup across live builds (#106418) 2026-07-13 06:41:19 -07:00
Peter Steinberger
a17058d191 feat(usage): show the account email with plan windows in the chat context popover (#106200)
* feat(usage): surface plan windows and account email in the chat context popover

The context-window popover now shows which account a session runs on:
provider usage snapshots carry an accountEmail resolved from the auth
profile when stored, the ChatGPT access-token JWT claims (openai/codex),
or the Claude CLI config file (~/.claude.json oauthAccount) for
keychain-synced logins. models.authStatus embeds it, quota groups keep
distinct accounts separate, and the popover renders the email under the
plan header for local CLI sessions and OpenClaw-configured subscriptions
alike.

* test(openai): assemble the fake usage JWT from parts

* test(usage): keep fixture tokens and identity plumbing scanner-safe

* fix(usage): verify the Claude CLI login before labeling usage with its email

Review findings: the CLI-config email fallback now requires the usage token
to match the cached CLI credential (and honors CLAUDE_CONFIG_DIR), so an
ambient login for another account never labels a snapshot; token-type
credentials propagate their stored email alongside oauth ones.

* style(anthropic): scanner-safe local for the CLI login read

* fix(usage): capture the Claude CLI account email on the credential

Review findings: reading ambient CLI config at usage-fetch time could not
verify keychain-only logins and could go stale across account switches.
The credential reader now captures oauthAccount.emailAddress next to the
credential it belongs to, the synced claude-cli profile carries it, and
the anthropic fetcher uses only the credential-borne identity.

* style(usage): scanner-safe credential fixtures and helper naming

* fix(auth): backfill the CLI account email onto existing synced profiles

Profiles synced before identity capture stay usable and skip CLI reads,
so upgraded installs would never gain the email until token rotation.
While the stored token material matches the CLI login, merge the
non-secret email onto the stored profile.

* style(test): scanner-safe email assertion

* test(auth): pin the no-reread invariant to identity-complete profiles
2026-07-13 03:39:16 -07:00
Peter Steinberger
2e622491eb style(codex): restore event projector formatting 2026-07-13 09:48:42 +01:00
wuqxuan
6739b9fa07 fix(codex): do not promote missing_tool_result on abort/interrupt (#104955)
* fix(codex): do not promote missing_tool_result on abort/interrupt

Keep synthetic tool.result rows for transcript integrity, but skip
promoting the missing-tool invariant to promptError when the turn is
already aborted or interrupted so mid-exec cancel paths keep abort
classification and assistant text (#104898).

* fix(codex): preserve explicit abort outcome

---------

Co-authored-by: Altay <altay@hey.com>
2026-07-13 11:34:47 +03:00
Peter Steinberger
0bae4e0e43 fix(codex): update managed app-server to 0.144.3 [AI] (#106098)
* fix(codex): update managed app-server to 0.144.2

* fix(codex): update managed app-server to 0.144.3
2026-07-13 01:27:42 -07:00
Peter Steinberger
6410e33cb0 refactor(ci): restore LOC ratchet headroom (#106063)
* refactor(ci): restore TypeScript LOC ratchet

* fix(ci): keep source reply item type internal
2026-07-12 23:09:25 -07:00
Peter Steinberger
a5883c33d1 refactor: use semver package for version ordering (#105944)
* refactor: use semver package for version ordering

* refactor: centralize semver validation

* chore: keep release notes in PR body

* refactor: update semver LOC ratchet
2026-07-12 23:02:25 -07:00
Peter Steinberger
26210c1600 refactor: remove browser and codex dead exports (#105867)
* refactor(browser): collapse Playwright export paths

* refactor(browser): remove dead plugin exports

* refactor(codex): remove dead app-server exports

* refactor(codex): remove remaining dead exports

* test(codex): use canonical private-type owners

* test(browser): isolate proxy startup state

* test(browser): remove stale chrome imports

* refactor(codex): privatize remaining helpers

* chore(deadcode): refresh export baseline after rebase

* refactor(browser): finish canonical helper ownership

* refactor: fix dead-export cleanup gates

* refactor(codex): keep runtime facades LOC-neutral

* chore(ci): refresh TypeScript LOC baseline

* chore(deadcode): refresh ratchets after rebase

* chore(ci): refresh LOC baseline after main advance

* chore(deadcode): align ratchets with latest main
2026-07-12 22:23:11 -07:00
Peter Steinberger
7c99322e3f chore(ci): shrink TypeScript LOC guard files 2026-07-13 05:58:32 +01:00
Ayaan Zaidi
4dc6e182c3 fix(codex): preserve legacy termination when final is omitted
Omitted final on a confirmed message-tool-only source reply keeps main's terminate-on-delivery semantics and records a completed marker; only explicit final=false defers termination. Project the Codex-only final schema property in place on attempt-fresh tools instead of adding a public plugin-SDK clone export, resolving the SDK surface budget failure.
2026-07-13 10:09:52 +05:30
Glucksberg
d8a84a29cb fix(codex): require explicit final source delivery
Distinguish progress from terminal source delivery across Codex telemetry,
payload suppression, terminal failure routing, and stranded-reply recovery.
Preserve legacy behavior when explicit markers are absent.
2026-07-13 10:09:52 +05:30
Markus
d00ed02f62 fix(outbound): bound message timeout reconciliation 2026-07-13 09:12:03 +05:30
Peter Steinberger
81941f2d68 test: enable noUncheckedIndexedAccess for extension tests (#105343) 2026-07-12 12:48:22 +01:00
Peter Steinberger
0350b87f06 test(ci): repair plugin prerelease contracts (#105272)
* test(ci): repair plugin prerelease contracts

* docs(agents): clarify stale Testbox recovery

* docs(agents): require Bash for Testbox compounds
2026-07-12 11:13:08 +01:00
Peter Steinberger
5b56a1f664 feat(gateway): land remaining durable-approvals stack and repair main gates (#104837)
* feat(gateway): propagate approvals to ancestor sessions with replay

Squash-rebased #103921 segment onto the native-clients tip on current main.
Session-scoped approval events publish sanitized pending/terminal
transitions to opted-in session audiences, with authoritative pending
replay on stream subscribe and durable-expiry reconciliation through the
owning manager. SessionApprovalEvent/Replay wire types export from the
approvals owner module; Swift models regenerated.

(cherry picked from commit 2d1dcf9747044710111d0c730fc46ba6013a165c)
(cherry picked from commit ccf88efd56b513d07599ffcee997bf0cddaf9adc)
(cherry picked from commit 8eb33f59f00ec9ee4625259b76bd7ae60d2cd480)
(cherry picked from commit c297cbc93c8401e9c79c20f242245a194f5dd236)
(cherry picked from commit 93d68f28601ff37d863da4db009504993a22533a)
(cherry picked from commit d285ccd8b2f212bb57e814107e7709c896e96b7d)
(cherry picked from commit 5c536982231402b1b58d1683794ea9948b32d077)
(cherry picked from commit 1646e5b6dc4dd20de54e10f110a5909be18d7d50)
(cherry picked from commit 35cf1b705b247fb282f4d56ffe74bd2fb238221f)
(cherry picked from commit 4f8ef3699d)
(cherry picked from commit 74fbdcc99d5fff062d67760a51dba4ee9e84479b)
(cherry picked from commit 222b285502681d2be14b1819798e9ee5555f431e)
(cherry picked from commit b9e744951f676b600e7c5322bfd04b0e99797c07)
(cherry picked from commit 9e904efde5)
(cherry picked from commit 678f2384fa)
(cherry picked from commit 72842e5cf6)
(cherry picked from commit be74c25e80e84a1f065053766f23efb84822e811)
(cherry picked from commit 93ba8c4b09)
(cherry picked from commit 8f23761372)

* feat(gateway): fail-closed plugin and tool approval gates

Squash-rebased #103932 segment onto the ancestor-propagation tip on
current main. Plugin node.invoke approvals claim a one-shot allow-once
decision before handing execution authority to the policy, so observation
or retry cannot replay a consumed approval; sibling tool gates bind
approval ids to their originating reviewer identity.

(cherry picked from commit 122df0d75281f572c012b6484ed5daf085d1d577)
(cherry picked from commit f23d8ac240a8dcf2a42c4daaae962263975a0ae8)
(cherry picked from commit 8632fb6436a224dac7a9a9ef0216884530de2c24)
(cherry picked from commit d9fe2dd5c53665e5732f5f3da5ed1907a686ade8)
(cherry picked from commit bb139f2c8aa36ddad70413e1ef79ff491a6f2ecd)
(cherry picked from commit 9b3e056b68ea515c7d4baef269289b6670570480)
(cherry picked from commit b11e66b59a7af1f3b08712de06864aed64d349e4)
(cherry picked from commit a12916ee592d03dfa35e86a2aaede4476a5d4e5d)
(cherry picked from commit d699de840fc8346892b9ae244fe3c3e8c4413032)
(cherry picked from commit 9b7e5a9608)
(cherry picked from commit 4b507593f1b2f10b4496984c84a2803b853e5c5e)
(cherry picked from commit 56408a186733c4eeb5aa76bd5907cde7b0cd3d5b)
(cherry picked from commit a4051d6d8353d39d6fa0b5d69c36e06c3cd3e796)
(cherry picked from commit 76829805a7)
(cherry picked from commit a8b493f934)
(cherry picked from commit aceb990597)
(cherry picked from commit a29b0e75482470c53a9fb4fe3f204e14cf71868f)
(cherry picked from commit 2e3be08653)
(cherry picked from commit c9ae3d7202)

* fix: main-gate repairs for the durable-approvals stack

- android: capture createdAtMs on the pending exec-approval write at
  registration; canonical readback after a refresh that already replaced
  the visible rows was dropping the approval instead of surfacing the
  still-pending reconciliation message (#104913 merged without this)
- android: generous CI timeout ceilings in GatewayExecApprovalRuntimeTest
- agents: hermetic model-discovery test via the plugins/provider-runtime
  boundary (lazy plugin-runtime resolution hangs vitest workers since #104770)
- cli: usage-cost settle-budget test asserts the budget bound on every call
  instead of pinning the poll count (fast hosts fit a second poll in 50ms)
- protocol coverage: allowlist session.approval for ios/android (native
  review rides exec.approval push/nudge delivery)
- docs map, native i18n inventory, plugin-sdk api baseline regenerated
2026-07-12 10:51:38 +01:00
Peter Steinberger
218dcd815a feat(tooling): enforce noUncheckedIndexedAccess in the extensions lane (NUIA phase 4) (#105132)
* fix(extensions): make indexed access explicit across channel plugins

Transport-payload-safe burn-down: malformed Telegram/Discord/QQ/LINE
and sibling channel input keeps existing skip paths; no synthesized
fields, no new throws in delivery loops. Zalo escape sentinels preserve
literal matches instead of undefined replacements.

* fix(extensions): make indexed access explicit across provider and memory plugins

Stream and model iteration, tool-block guards, capture guards, and
sparse accumulators; singleton model reads carry named invariants.

* fix(extensions): make indexed access explicit across tooling plugins, flip the extensions lane

Remaining plugins (oc-path, qa-lab, browser, logbook, and siblings) plus
the tsconfig.extensions.json flag flip. Cleanup: logbook sampleFrames
NaN index at max=1, QA retry clamp at non-positive attempts, dead Canvas
probe and OpenShell no-op slice removed, twitch test setup leak excluded
from the prod lane.

* refactor(plugin-sdk): expose expectDefined via a focused SDK subpath

Extensions imported @openclaw/normalization-core directly, crossing the
external-plugin packaging boundary (it only worked because the runtime
builder bundles undeclared workspace helpers). expect-runtime joins the
canonical entrypoints JSON, generated exports, API baseline, docs, and
subpath contract test; all 78 extension imports now use the SDK seam.
Two scanner-shaped locals renamed for review-bundle hygiene.

* chore(plugin-sdk): raise surface budgets for the expect-runtime subpath

One new entrypoint with one callable export, added intentionally as the
packaging-honest seam for extension invariant helpers.
2026-07-12 09:17:31 +01:00
Peter Steinberger
401ae11b71 fix(codex): preserve native subagent results after parent cleanup (#102060)
Codex native subagent results now survive parent cleanup, app-server persistence races, resumptions, and transient delivery failures. The monitor treats app-server thread/read and thread/turns/list history as canonical recovery state (works on non-stdio transports), retains the shared physical client only while detached children need monitoring, fences stale reads across lifecycle changes, keeps interrupted children resumable, preserves multi-agent V2 subAgentActivity lineage, and bounds terminal delivery retries with a durable failed state. Removes rollout-file discovery, transcript parsing, periodic whole-client rescans, and the deferred one-shot cleanup path.

Adds an opt-in live E2E lane (OPENCLAW_LIVE_CODEX_NATIVE_SUBAGENT=1) proving detached delivery and history-only recovery against a real app-server with an OpenAI key, restores the registered-child user-spoof regression test, and registers both codex opt-in live files in the release shard optional-env map.

Closes #97593
Related: #93313
2026-07-12 08:27:40 +01:00
pick-cat
3c7edce61e fix(codex): preserve UTF-16 pairs in tool output delta truncation (#104116)
* fix(codex): preserve UTF-16 pairs in tool output delta truncation

* chore: trigger CI re-run

* test(codex): add UTF-16 safety regression test for progress message cap

* chore: trigger CI re-run

Co-Authored-By: Claude <noreply@anthropic.com>

* test(codex): tighten UTF-16 progress regression

* test(codex): match progress label

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-12 06:40:48 +01:00