mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-24 15:31:13 +00:00
* 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.