Commit Graph
913 Commits
Author SHA1 Message Date
bfd8c7e3fd fix(codex): use supported safe-yolo approval policy (#1079)
Co-authored-by: NPUlrk <21106497+NPUlrk@users.noreply.github.com>
2026-07-19 14:16:03 +08:00
AnanovoandGitHub 2623a51b0b feat(web): filter sessions by last activity (#1083)
* feat(web): filter sessions by last activity

* test(web): make session date filter tests deterministic
2026-07-19 14:15:24 +08:00
64834467e3 feat(codex): import and resume sessions from runners (#1088)
* fix codex import resume flow

* fix hub restart session active state

* fix codex transcript workspace scoping

* Address Codex import review findings

* Fix Codex import machine selection

* Update Codex sessions error test

* Address Codex import review findings

* Preserve forked Codex session id on sync

* Make Codex duplicate cleanup source-aware

* Handle Codex archive failures

* Limit existing session flag to Codex

* Preserve Codex import machine binding

* fix: rebase runner Codex import onto current main

* fix: preserve runner-scoped Codex import behavior

---------

Co-authored-by: syy <815728149@qq.com>
2026-07-19 14:14:42 +08:00
weishu 651c83a1d9 feat(web): replace agent flavor letter badges with brand logos
Use @lobehub/icons (already a dependency) for per-agent SVG logos in the
session list, session header, and new-session agent selector.

- Color variants for claude/codex/gemini; Mono (currentColor) for
  cursor/grok/opencode so glyphs track the theme text color
- kimi uses Mono as well: KimiColor's main glyph is hard-coded #fff and
  vanishes on the light theme
- pi and unknown flavors keep the letter-badge fallback (no logo shipped)
- Deep component imports avoid the package root's ./features re-export,
  which pulls uninstalled peer deps (antd, @lobehub/ui)
2026-07-19 13:05:25 +08:00
Junmo KimandGitHub 289c9f2218 feat(cli,web): show Claude Code's away recap in local-mode chat (#1089)
* feat(shared,cli): whitelist away_summary so auto recap reaches the hub

Claude Code's local TUI writes an automatic away-summary recap to the
session transcript on window blur/focus (5min+ idle), but
VISIBLE_CLAUDE_SYSTEM_SUBTYPES dropped it before it ever reached the
hub. Add it to the whitelist so the local launcher forwards it like
the other system subtypes, and cover the forwarding + Zod passthrough
of the recap `content` field with tests.

* feat(web): render Claude Code's automatic away recap in the chat

Once away_summary reaches the hub (previous commit), the web chat
still dropped it silently: normalizeAgent had no branch for the
subtype, so it fell through to `return null`. Add a `recap` AgentEvent,
a normalizeAgent branch mirroring the existing turn_duration/compact
subtype branches, and a presentation entry that prefixes the text with
`recap:` so it reads distinctly from the manual /recap assistant
bubble (which already renders as a normal message). No new render
component needed: it flows through the existing generic system-event
row (SystemMessage.tsx + getEventPresentation) that every other system
subtype already uses.

* fix(web): drop inaccurate manual-/recap comparison from recap comments
2026-07-19 12:24:32 +08:00
77f94ef738 fix(web): keep machine names visible and health tooltips touchable (#1049)
* fix(web): improve machine health sidebar UX

Keep machine names visible, align health metrics, and make nested health tooltips usable with touch and keyboard input.

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>

* fix(web): preserve tooltip focus reveal groups

Keep the unnamed group used by existing focus reveal classes while retaining named hover groups for nested machine health tooltips.

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>

* fix(web): add exec* timestamps to ToolCard test fixture

Unblocks typecheck after #1036 made execStartedAt/execCompletedAt
required on ChatToolCall; fixture was missing both fields.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web): align machine health status with meters

Right-align the capacity status with the utilization meter edge to balance the tooltip header without shortening the bars.

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>

* fix(web): restore machine health disclosure semantics

Expose the machine group's expanded state on its toggle and describe the health trigger with the tooltip body for assistive technologies.

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>

---------

Co-authored-by: HAPI <noreply@hapi.run>
Co-authored-by: Debian <heavygee@oos-linux.in.lockhouse>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-19 12:24:09 +08:00
AnanovoandGitHub f1b5ed5e5d fix(claude): preserve native titles and add a remote fallback (#1080)
* fix(claude): preserve native titles and add remote fallback

* fix(claude): write fallback titles as metadata only
2026-07-19 12:23:39 +08:00
Junmo KimandGitHub 95eee432d4 perf(claude): scan transcripts incrementally (#1081)
* perf(claude): scan transcripts incrementally

The claude session scanner re-read the entire transcript JSONL on every
scan, so the cost of each poll grew with the length of the conversation.
Track a byte offset per file instead and parse only the bytes appended
since the previous scan.

A trailing partial line — a write still in progress — is held back until
its newline arrives. A file that shrank resets the cursor to 0; the base
scanner's uuid dedup absorbs the re-sent events. A read that fails
returns no events and leaves the cursor where it was, so a transient
error is retried on the next scan rather than skipping content.

The codex scanner received this in #1031; this extends the same
improvement to the claude scanner. readSessionLog is exported for tests,
mirroring readTranscriptRange there.

* fix(claude): forward a complete final record with no trailing newline

The incremental reader consumed only through the last newline, so a final
JSONL record flushed without its terminating newline — at shutdown or on
import — was held back as if it were a partial write and never forwarded
until a later append supplied the newline. The previous whole-file reader
parsed such a record.

Consume a trailing segment when it already parses as a complete JSON value,
and keep holding back a genuinely partial line (which parses as incomplete).
2026-07-19 12:23:09 +08:00
AnanovoandGitHub fdf1342cb9 fix(web): keep mobile session header compact (#1082) 2026-07-19 12:22:46 +08:00
weishu 2211888f04 Release version 0.23.0 2026-07-18 12:29:28 +08:00
DullJZandGitHub e737d67aaa fix(opencode): treat empty tool input as missing and recover late tool-calls (#1052)
* fix(opencode): stop treating empty tool input as final args

OpenCode emits input/rawInput as {} on tool start (and sometimes again
during permission), then fills real arguments on running/completed.
Treat empty objects as unusable so ACP and local hooks keep waiting for
real args, never clobber them, and ignore non-tool parts as fake results.

* fix(web): add exec timing fields to ToolCard test fixture

ChatToolCall now requires execStartedAt/execCompletedAt; update the
fixture so typecheck passes.

* fix(opencode): recover late tool-call after empty execute.before

Skip empty before under name-only queue pairing, emit tool-call on after when
still missing, and reject content JSON {} on ACP initial tool_call.
2026-07-18 12:26:23 +08:00
AnanovoandGitHub 058a375e6d feat(web): enhance directory browser with metadata and sorting (#1055)
* feat(web): enhance directory browser with metadata and sorting

* test(web): update ToolCard fixture timestamps
2026-07-18 12:26:03 +08:00
Junmo KimandGitHub 2c559373c9 fix(claude): preserve resume anchor and report real /compact outcome (#1056)
* fix(claude): consume the one-time --resume flag only once it is used or discarded

Reopening a remote Claude session and hitting a relaunch trigger (e.g.
/compact, or a mode/model/effort change) before the first turn is ever
processed loses the original --resume session id and starts a brand new
Claude session with no prior context. With /compact this also shows up as
the compaction ending immediately with "Not enough messages to compact.",
because the session it lands in is empty.

claudeRemoteLauncher called session.consumeOneTimeFlags() right after every
claudeRemote() call, including calls that returned before spawning Claude
(nextMessage() resolves null when the relaunch trigger arrives before any
turn was handled, so the message is parked as pending). That retired the
one-time --resume flag before the SDK ever had a chance to use it, so the
next launch started fresh instead of resuming.

Tie the flag's lifetime to the invariant it needs: retire it only once it
has been used, or once the context it points at has been explicitly
discarded. It is now consumed from onSessionFound (Claude reported a
session id back) and from onSessionReset (/clear dropped the context, and
/clear likewise returns before spawning Claude, so without this the flag
would outlive the reset and the next launch would resume the very session
the user just cleared). Attempts that reach neither outcome never touched
the anchor, so the flag survives for the next launch.

* fix(claude): report the actual /compact outcome instead of always success

When Claude cannot compact a session it says so on a system/status message
carrying compact_result: "failed" and a compact_error reason (for example
"Not enough messages to compact."), which arrives shortly before the result
message. The completion event was emitted from the result message alone, so
a compaction that did not happen was still surfaced to the user as
"Compaction completed".

Record the reported outcome when the status message arrives and use it when
the result message is handled, mirroring the wording the Codex launcher
already uses for the same situation ("Compaction failed: <reason>").

Only an explicitly reported failure is recorded: a status shape without
compact_result, or one reporting anything other than "failed", leaves the
existing success path untouched, so an unrecognised or unseen status can
never invent a failure.
2026-07-18 12:25:35 +08:00
AnanovoandGitHub f2e3149ea8 feat(web): align session action menus (#1061) 2026-07-18 12:24:47 +08:00
AnanovoandGitHub bc2545d303 fix(web): clarify token usage labels in message details (#1062) 2026-07-18 12:19:03 +08:00
Shawn TianandGitHub d809fca433 fix: reconcile stale queued messages (#1063)
Recover missed messages-consumed events from authoritative Hub state after session SSE reconnects.
2026-07-18 12:18:47 +08:00
weishu 22e9b38f70 fix(kimi): sync local sessions to web and adapt to new kimi-code architecture
hapi kimi local mode spawned the kimi TUI with no transcript sync, so
terminal conversations never reached the hub and the web UI stayed empty.
After the kimi-code rewrite (data moved from ~/.kimi to ~/.kimi-code),
model resolution also broke: hapi read the gone ~/.kimi/config.toml and
fell back to the invalid hardcoded default kimi-k2, and the KIMI_MODEL /
KIMI_PROJECT_DIR env vars it set no longer exist upstream.

Local sync (mirrors the codex transcript scanner):
- kimiWireLocator: derive the kimi-code workspace id
  (wd_<slug>_<sha256(cwd).12>, ported verbatim from upstream workdir-slug),
  poll for the session dir created by the just-spawned process, and watch
  its agents/main/wire.jsonl. Pre-existing sessions are snapshotted and
  excluded (awaited before spawn) so a retry cannot bind to a stale
  session; multiple fresh candidates are refused as ambiguous.
- kimiWireScanner: incrementally read wire.jsonl and convert events into
  hapi messages (user prompts/steers, assistant text/thinking, tool
  call/result incl. is_error, step.end usage with cached input summed
  into inputTokens).
- kimiLocalLauncher: attach locator+scanner, report kimiSessionId on
  discovery (enables web resume and local<->remote handoff).

Model handling:
- config.ts: read <KIMI_CODE_HOME|~/.kimi-code>/config.toml (legacy
  ~/.kimi fallback); drop the hardcoded kimi-k2 default and the dead
  KIMI_MODEL env source - when nothing is configured, omit --model so
  kimi-code uses its own default_model.
- kimiBackend/kimiLocal: stop setting KIMI_MODEL and KIMI_PROJECT_DIR
  (both unused by new kimi-code).
- kimiRemoteLauncher: apply the resolved model over ACP after session
  creation (session/set_model, falling back to the advertised model
  config option), and display the agent-reported current model instead
  of the env guess.

Verified against live kimi-code 0.26.0: ACP initialize/session-new/
prompt probes, locator discovery of a running session, and converter
robustness over a real 800-line wire.jsonl.
2026-07-18 12:18:15 +08:00
Junmo KimandGitHub d5aeeb57a4 fix(web): add missing exec timestamps to ToolCard test fixture (#1057)
The ChatToolCall fixture in ToolCard.test.ts does not set execStartedAt
and execCompletedAt, which became required fields, so bun typecheck fails
on main with TS2739.

The fixture was added while those fields did not exist yet, and the change
that introduced them landed a minute earlier, so each side type-checked
against its own base and the gap only appears once both are on main.

Set both to null, matching the sibling fixtures in ToolGroupCard.test.ts
and groupedPresentation.test.ts, since these cases do not exercise tool
execution duration.
2026-07-17 11:46:15 +08:00
weishu 80a26c1f75 fix(web): update tool call test fixture 2026-07-17 10:43:30 +08:00
SSU-WEI HUANGandGitHub 6f5ecde2c4 fix(codex): expose HAPI threads to Codex Desktop (#1022)
* test(codex): reproduce desktop thread classification gap

* fix(codex): classify HAPI threads as user sessions

* test(codex): cover thread source creation paths
2026-07-16 12:35:04 +08:00
SSU-WEI HUANGandGitHub 520c3f511a fix: verify Cursor chat store before reopen (#1037)
* test: reproduce issue #841

* test: cover Cursor chat store discovery

* fix: verify Cursor chat store before resume (closes #841)

* test: preserve non-Cursor resume behavior

* test: cover conservative Cursor resume gating

* fix: gate Cursor reopen until store verification

* test: cover legacy Cursor drawer fallback

* fix: scan unique legacy Cursor store drawer

* test: preserve raw Cursor workspace path hashing

* fix: hash raw Cursor workspace path

* test: pin Cursor probe owner and machine

* fix: probe Cursor store on recorded owner

* test: normalize Cursor probe owner home

* fix: normalize Cursor probe owner home
2026-07-16 12:34:41 +08:00
Junmo KimandGitHub adb6f41858 fix(web): extend hover-reveal info affordance to touch devices (#1046)
MessageInfoPopover's trigger button carried the same
happy-message-actions-desktop-only class as the other hover-reveal
actions from 4c76668a, so it never rendered on touch-only viewports
(no hover: hover match). Switch it to the always-visible flex pattern
the sibling copy button already uses, matching desktop's hover-reveal
opacity animation on the parent row.

Also widen the action row's desktop-only-row guard to stay reachable
when a tool-only response (no copyable text) still carries model/
duration metadata from its first tool block, so the info popover isn't
hidden behind an empty row on mobile.
2026-07-16 12:33:51 +08:00
Junmo KimandGitHub 89df3fd5f2 feat(web): show subagent's executed model in Task/Agent card header (#1045)
* feat(web): show subagent's executed model in Task/Agent card header

Task/Agent trace cards previously gave no indication of which model a
subagent actually ran under, even though the model can differ from the
calling session's (e.g. main session on opus, subagent on haiku) and
can even change mid-run when --fallback-model kicks in under overload.

The data already reaches the frontend: each child block produced from
a subagent's own sidechain carries the model of the assistant message
it came from. Derive it in getSubagentModel() from the tool call's own
children (not the parent ToolCallBlock.model, which reflects the
calling session and would misattribute the model), collecting distinct
raw values in first-seen order and joining them the same way
aggregateResponseGroups already does for top-level multi-turn message
metadata.

Full SDK model ids (e.g. claude-sonnet-4-5-20250929) are long and not
great for a compact label, so formatSubagentModelLabel() extends this
repo's existing "friendly label, else raw fallback" idiom
(getClaudeModelLabel(model) ?? model in claudeModelOptions.ts, which
only covers the short preset aliases) with a narrow second fallback
that extracts just the name and version from the SDK id shape and
drops the date suffix (-> "Sonnet 4.5"). Anything else is left as-is.

Renders the result as a small chip in the header's existing right-side
meta cluster (next to ElapsedView/status icon), always visible without
opening the detail dialog.

* fix(web): cap subagent model badge width to avoid squeezing the card header

Addresses HAPI Bot review on #1045: formatSubagentModelLabel() returns
unrecognized model ids (Gemini, Codex, future formats) unchanged, and
those can be long. Bound the chip with max-w + truncate so it can't
push the title/status area off narrow cards, with a title attribute
so the full value is still reachable on hover.
2026-07-16 12:33:22 +08:00
NightWatcher314andGitHub f8657dae3a feat(web): add color theme presets (#1040)
* feat(web): add color theme presets

* fix(web): preserve presets with custom colors

* fix(web): sync color theme across tabs

* fix(web): clear boot theme background

* feat(web): integrate palette presets with display settings
2026-07-16 12:32:54 +08:00
SSU-WEI HUANGandGitHub dd2684a4e7 fix(web): distinguish worktree sessions in sidebar (#1039)
* test: reproduce issue #782

* fix: distinguish worktree sessions in sidebar (closes #782)

* test: cover worktree label fallback

* test: cover worktree session search

* fix: search worktree session details
2026-07-16 12:32:37 +08:00
Junmo KimandGitHub 2ce6d3ef3a feat(web): show tool call duration in the detail dialog (#1036)
* refactor(web): export formatDuration for reuse

* feat(web): show tool call duration in the detail dialog

Show a completed tool's execution duration at the top of its detail
dialog. The value is derived from the Claude entry's own timestamps
(the execution machine's wall clock) rather than the hub's
message-receive time, and is used only when both the tool_use and
tool_result entries carry a real timestamp — otherwise it falls back to
the hub receive times on both sides, so the two clocks are never mixed.
Running/pending tools show nothing, the running-state live timer is
unchanged, and clock skew is guarded against. Reuses the existing
formatDuration formatter. No schema changes.

* fix(web): backfill hub startedAt on reorder so duration isn't 0.0s

When a tool_result entry is reduced before its tool_use, the tool block
is created from the result, so the hub startedAt is the result receive
time. The tool_use path only lowered the exec start, not the hub
startedAt, so a timestamp-less pair (no exec duration available) fell
back to startedAt === completedAt and the detail dialog showed 0.0s.
Lower the hub startedAt to the earlier tool_use receive time as well.
2026-07-16 12:32:00 +08:00
SSU-WEI HUANGandGitHub f457156bd1 feat(cli): add skill_lookup MCP for non-native agents (#1035)
* test: reproduce issue #752

* fix: expose skill lookup MCP tool (closes #752)

* test: cover ACP skill lookup instructions

* fix: inject ACP skill lookup instruction

* test: narrow skill lookup auto-approval

* fix: restrict skill lookup auto-approval

* test: cover exact skill lookup tool names
2026-07-16 12:31:36 +08:00
KorenKritaandGitHub e342d97177 fix(pi): use per-model context window for status bar display (#1033)
Use provider-qualified model lookup (provider + modelId) to resolve the
correct context window for the Pi status bar, falling back to legacy
modelId when selected-model metadata is absent. This prevents showing
the wrong context window when two providers share the same modelId.
2026-07-16 12:31:12 +08:00
KorenKritaandGitHub 3290bc9ca9 feat(pi): add 'max' thinking level (#1032)
* feat(pi): add 'max' thinking level

Pi's --thinking flag accepts 7 levels: off, minimal, low, medium, high,
xhigh, max. The shared constant and UI only exposed 6 levels (missing max).

Add 'max' to PI_THINKING_LEVELS and PI_THINKING_LEVEL_LABELS. Like xhigh,
max requires explicit opt-in via the model's thinkingLevelMap — models that
support it will include max in their map and the UI will show it
accordingly.

* fix(pi): close max thinking-level branch
2026-07-16 12:30:55 +08:00
SSU-WEI HUANGandGitHub 53406b2e97 fix(web): sync browser tab title with session (#1034)
* test: reproduce issue #712

* fix: sync browser title with session (closes #712)
2026-07-16 12:30:21 +08:00
SSU-WEI HUANGandGitHub 553b3492f1 fix(codex): wait for manual compaction to finish (#1038)
* test: reproduce issue #982

* fix: wait for Codex manual compaction (closes #982)

* test: cover Codex compaction turn completion
2026-07-16 12:30:04 +08:00
SSU-WEI HUANGandGitHub c87720ab4d fix(cli): load extra headers from settings (#1041)
* test: reproduce issue #786

* fix: load extra headers from settings (closes #786)

* test: cover extra header precedence and redaction

* fix: redact persisted extra headers in diagnostics

* test: cover runner extra header identity

* fix: restart runner when extra headers change
2026-07-16 12:27:50 +08:00
DullJZandGitHub e87e875d72 feat(opencode): accept -s/--session as resume aliases (#1042)
Map OpenCode-native session flags to resumeSessionId so
`hapi opencode -s <id>` restores the session like --resume.
2026-07-16 12:26:19 +08:00
87f5c78ab2 fix(codex): scan transcripts incrementally (#1031)
Co-authored-by: zj1123581321 <zj1123581321@users.noreply.github.com>
2026-07-13 15:51:40 +08:00
weishu 1c834607a2 Release version 0.22.3 2026-07-13 09:03:39 +08:00
8ee04500b9 fix(hub,cli): coerce null session activeAt so resume cannot 500 (#1026)
Legacy rows and inserts left sessions.active_at NULL while SessionSchema
required a number, so CLI GET /cli/sessions/:id failed Zod and resume
surfaced HTTP 500. Persist active_at on insert, harden hub read coerce,
and nullish-transform activeAt in SessionSchema (output stays number).

Fixes #1025

Co-authored-by: Debian <heavygee@oos-linux.in.lockhouse>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-13 09:00:17 +08:00
SSU-WEI HUANGandGitHub f6ad345339 feat(web): redesign responsive settings navigation (#1027) 2026-07-13 08:42:25 +08:00
SSU-WEI HUANGandGitHub b9eed7c071 feat: add Grok Build support (#1030)
* test: define Grok Build integration behavior

* feat: add Grok Build agent integration

* test: cover Grok permissions and resume paths

* docs: add Grok Build setup guide

* fix: scope Grok ACP discovery to session cwd

* fix: align Grok permission UI semantics

* docs: clarify Grok runner setup

* test: require Grok create model and effort options

* feat: add Grok create model and effort pickers

* test: define Grok runtime parity behavior

* feat: add Grok runtime ACP controls and discovery

* fix: tighten Grok runtime controls

* fix: suppress nonfatal Grok title quota errors

* feat: support Grok Auto permission mode

* feat: forward ACP native session titles for Grok

* fix: guard Grok Windows shell arguments
2026-07-13 08:41:30 +08:00
de07643828 fix(codex): improve local session import compatibility (#995)
Co-authored-by: LIUZHIRU <ryuu@fine-net.co.jp>
2026-07-12 18:44:39 +08:00
SSU-WEI HUANGandGitHub d97b270ba8 fix(codex): bridge MCP elicitation through user input (#1008)
* fix(codex): bridge MCP elicitation through user input

* fix(codex): allow MCP elicitation in yolo mode

* fix(codex): preserve MCP form semantics

* fix(codex): accept implicit MCP form mode

* fix(codex): harden MCP elicitation prompts

* fix(codex): require valid MCP choice answers

* fix(codex): round-trip MCP array elicitation

* fix(web): require explicit MCP URL confirmation

* fix(codex): preserve MCP array item types

* fix(codex): support multi-select MCP elicitation

* fix(codex): allow MCP elicitation in read-only mode

* fix(codex): route MCP tool approvals through permissions
2026-07-12 18:42:55 +08:00
SSU-WEI HUANGandGitHub 474db94136 test(cli): stabilize runner integration timeouts (#1011) 2026-07-12 18:42:05 +08:00
73584e925a feat(cursor): multitask slash, autoReview mode, native worktree/add-dir (#1014)
* feat(cursor): multitask slash, autoReview mode, native worktree/add-dir

Close the highest-value Cursor Agent gaps for remote HAPI: expand ACP-safe
slash pass-through (/multitask, worktree, add-dir, …), add autoReview
permission mode (--auto-review spawn + mid-session slash), and route Cursor
New Session worktrees through agent --worktree instead of HAPI sibling trees.

Fixes #1013

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(cli): accept --mode autoReview for hapi cursor

Align --mode parsing with CURSOR_PERMISSION_MODES so documented
`hapi cursor --mode autoReview` enables Smart Auto instead of silently
falling back to default.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-12 18:41:52 +08:00
b104c38f3a fix(web): show Codex reasoning effort in SessionHeader (#1016)
Surface the same reasoning label already shown in the composer StatusBar
in the top SessionHeader for codex/opencode sessions. Also show an
explicit Fast badge only when serviceTier is fast (#1004-aligned).

Closes #1015 (header display portion).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-12 18:41:10 +08:00
HaoandGitHub d0c8391261 fix(opencode): preserve ACP text deltas (#1023) 2026-07-12 18:40:18 +08:00
SSU-WEI HUANGandGitHub d9ea9db507 fix(codex): preserve native safety behavior (#1024)
* test: reproduce issue #1020

* fix: preserve Codex safety behavior (closes #1020)

* test: cover Codex safety buffering dismissal

* test: cover Codex safety retry edge cases

* fix: keep dismissed safety buffering prompts hidden
2026-07-12 18:39:56 +08:00
ejj.ccandGitHub d160203bb2 fix(codex): support dynamic reasoning efforts (#1012)
* fix(codex): support model-reported reasoning efforts

* fix(web): prevent service worker edge caching

* ci: retrigger stuck Actions run

* fix(codex): accept dynamic reasoning effort values

* fix(web): restore reasoning effort on model switch failure
2026-07-12 18:38:56 +08:00
weishu 4c76668a6c refine message actions and metadata 2026-07-12 18:36:43 +08:00
weishu 8782b8a110 fix(codex): align local transcript message projection
Use semantic events as the visible text source and preserve completed plans as ordered plan proposal cards.
2026-07-12 14:33:37 +08:00
weishu 942a1dfff8 Release version 0.21.0 2026-07-12 11:05:13 +08:00
weishu 5a377e38b9 fix(codex): defer session persistence until user activity 2026-07-12 11:00:08 +08:00