Commit Graph
63 Commits
Author SHA1 Message Date
SSU-WEI HUANGandGitHub 91022539d9 feat(web): show explicit subagent model (#1223) 2026-07-29 10:01:22 +08:00
AnanovoandGitHub 8a77d2f84d fix(web): align tool detail layout (#1204)
* fix(web): align inline tool detail spacing

* fix(web): polish tool detail alignment
2026-07-28 17:29:43 +08:00
SSU-WEI HUANGandGitHub 0e3b4394ff fix(web): label terminal cards with concise command names (#1201)
* fix(web): label terminal cards with command names

* fix(web): honor concise titles across shell cards
2026-07-28 11:03:09 +08:00
Junmo KimandGitHub e52443f4cf feat(web): global word-wrap toggle for code and diff views (#985)
* refactor(web): add per-line shiki line-splitting helper

* feat(web): add global word-wrap toggle for code, markdown, and diff views

* feat(web): add a shaded gutter background behind line numbers

* fix(web): make DiffView compact rows follow the global wrap setting
2026-07-27 19:09:59 +08:00
AnanovoandGitHub d90bde0b88 feat(web): show tool execution timing (#1140) 2026-07-26 15:08:40 +08:00
SSU-WEI HUANGandGitHub aa5beb3af2 feat(codex): preserve native exploration actions (#1139) 2026-07-24 10:52:24 +08:00
weishu 74ad25ec57 feat(codex): refine tool activity display 2026-07-24 09:39:22 +08:00
SSU-WEI HUANGandGitHub 6bedd0d924 feat(tooling): preserve native tool titles (#1133) 2026-07-23 08:41:33 +08:00
SSU-WEI HUANGandGitHub e69ca0782f feat(web): make grouped tool summaries specific (#1134) 2026-07-23 08:41:02 +08:00
weishu 80a26c1f75 fix(web): update tool call test fixture 2026-07-17 10:43:30 +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
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 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
3a8693f380 feat(cursor): migrate remote sessions to ACP with model/variant pickers (#799)
* feat(cli,web,hub): migrate Cursor remote sessions to ACP with model/effort pickers

Move stream-json remote launcher to legacy path and add ACP launcher with
set_config_option model/mode sync, optimistic keepalive on config changes, and
shared catalog caching. Web gets dual base/effort Cursor pickers for session and
new-session flows; hide composer status bar when Cursor sends no usage_update.

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

* fix(cli,web,shared): Cursor model picker — ACP wires + CLI sku variants

Enrich the web/mobile picker with agent --list-models SKUs grouped under
ACP wire bases, fix session-open base highlight, and keep catalog discovery
safe while the ACP transport holds the CLI lock.

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

* fix(cursor-acp): apply ACP default model when web resets to Default

Web sends model: null for Default; push session/set_config_option with the
ACP default[] wire so Cursor backend matches hub state. Regression tests
for setModel(null) and applyModelConfig(null).

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

* fix(acp): clear stale agent-acp lock when owning process is gone

Check lock pid with signal 0; remove orphaned lock dirs after SIGKILL or
crash so listCursorModels can run cold probes again. Regression tests for
guard and catalog discovery.

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

* test(cursor): use live pid for ACP lock handler tests

Stale-lock cleanup clears dead pids; handler tests must simulate an
active lock with the current process pid to avoid cold probes/timeouts.

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

* fix(acp): scope agent CLI lock guard to Cursor agent command only

Gemini/OpenCode/Kimi ACP sessions must not register agent-acp-active;
that blocked listCursorModels while unrelated backends were running.

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

* fix(hub,web): reject Cursor model changes for local sessions

Hub returns 409 when controlledByUser is set, matching Codex. Web hides
model and variant pickers for local Cursor sessions so users do not hit
a dead RPC path. Document pre-push-review in AGENTS.md.

Verified: bun typecheck; bun run test (919 cli + 243 hub + 768 web + 46 shared).
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web): send stable ids for Cursor ask_question replies

Parse and submit question.id and option.id so ACP receives keys like
{ approach: ['a'] } instead of index/label. Verified: bun typecheck && bun run test.

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

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-06 19:51:35 +08:00
AnanovoandGitHub c78785a0b2 fix(web): open tool details from inline previews (#725)
* fix(web): open tool details from inline previews

* fix(web): ignore nested controls in tool previews
2026-05-29 10:22:54 +08:00
763f45acdd feat: add support for Kimi Code CLI and fixed some bugs (#659)
* Add Kimi agent support via ACP protocol

Add full integration for the Kimi Code CLI agent using the standard
Agent Client Protocol (ACP). Includes:

- kimi command and CLI registry wiring
- Local launcher spawning kimi directly
- Remote launcher with ACP stdio transport via AcpSdkBackend
- Session management with resume support
- Permission handler supporting all Kimi permission modes
- Terminal UI display component
- Runtime config resolving model from env and ~/.kimi/config.toml

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

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

* Fix Kimi ACP tool call input decoding on web

Kimi streams tool arguments as JSON text inside the content array
(e.g. {\"command\": \"df -h\"}) instead of rawInput/kind. The handler
now extracts input from three sources in priority order:

1. rawInput (Claude/Codex path)
2. kind + title fallback (Gemini path)
3. content JSON text (Kimi path)

Also handles:
- rawInput: null no longer blocks the kind+title fallback
- Title prefixes like \"Shell: free -h\" are stripped to extract args
- Stale placeholder inputs are re-derived when the title updates
- Normalized kind aliases (shell, run, read_file, write, etc.)

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

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

* Add kimi support to web UI

* Fix some bugs

* fix(kimi): dedupe repeated tool_call display in terminal UI

* fix(web): keep tool block immutable so React detects input/state changes

* fix(web): recognise Kimi subagent titles like 'Agent: ...' as subagent tools

* fix(web): allow-for-session for ACP agents (kimi, cursor)

PermissionFooter treated all non-codex sessions as Claude, sending
Claude-specific acceptEdits/allowTools to ACP agents that don't
support them. Hub rejected acceptEdits for kimi, and the ACP
PermissionAdapter ignored allowTools.

- Only show 'allow all edits' for Claude sessions
- Send decision: approved_for_session for non-Claude ACP agents
- Update status display to check decision field

* fix(web): lookup subagent sidechains by tool-call id instead of msg id

* fix(web): don't trim newest messages when loading older history

fetchOlderMessages was using trimVisible(merged, 'prepend') which kept
the oldest 400 messages and dropped the newest ones. This caused:
1. Latest messages to disappear when user loaded older history
2. User to see no visible change when new old messages were drowned
   in the 400-message window.

Remove the incorrect trim so all fetched older messages are retained
alongside the current window. Subsequent ingestIncomingMessages
(append mode) will naturally keep the window bounded when new agent
messages arrive.

* fix(cli): route Kimi session resume to runKimi instead of runCursor

Kimi was present in AGENT_FLAVORS but dispatchLocalResume had no branch
for it, so resuming a Kimi session fell through to the Cursor launcher.

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

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

* fix(cli): pass selected model to Kimi ACP backend via KIMI_MODEL env

createKimiBackend was ignoring opts.model and only setting KIMI_PROJECT_DIR.
Use buildKimiEnv so the selected model reaches the subprocess as KIMI_MODEL.

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

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

* fix(web): bound message window on older loads with dedicated larger cap

fetchOlderMessages was keeping all messages unbounded, causing
sessionStorage bloat on repeated pagination. Reintroduce trimming
with OLDER_LOAD_WINDOW_SIZE (800) so growth is capped while the
newest messages are still preserved for far longer than before.

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

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

* fix(web): revert sidechain lookup to message id, matching tracer/grouping pipeline

tracer.ts sets sidechainId to the parent message id, and reducer.ts groups
by sidechainId. A prior commit changed reducerTimeline.ts to look up by
tool-call id (c.id), which broke sidechain attachment. Revert to msg.id
so the lookup matches the actual grouping key end-to-end.

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

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

* fix(cli): gate ACP title prefix stripping to known tool-kind labels

extractTitleArgument stripped at the first colon unconditionally,
corrupting commands/paths like curl http://localhost:3000 or
Windows paths. Now it only strips when the prefix normalizes to
the same tool kind as the event, verified via regex.

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

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

* fix(shared): include kimi in isCodexFamilyFlavor for ACP permission UI

Kimi is an ACP-style agent that supports the abort decision, but
isCodexFamilyFlavor excluded it, so PermissionFooter rendered the
non-Codex Allow/Deny UI without the Abort button.

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

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

---------

Co-authored-by: HAPI <noreply@hapi.run>
2026-05-22 10:08:14 +08:00
weishu eed7c9b0b3 refactor: rely on tool view registry for inputs 2026-05-21 14:44:30 +08:00
weishu 6759cf4657 Remove old protocol compatibility layers 2026-05-20 17:45:28 +08:00
weishu f31c591f33 Improve grouped tool card labels 2026-05-18 11:02:07 +08:00
junesandGitHub 60af9835b4 feat(web): 优化聚合 tool use 展示与聊天背景设置 (#619) 2026-05-13 13:04:31 +08:00
junesandGitHub af3491e046 feat(web): group consecutive tool-use cards (#604)
* feat(web): group consecutive tool-use cards

Add a web-only visible projection that groups consecutive root-level execution tools into expandable cards.
Keep approval and question tools standalone, reuse older-history loading on expand, and add regression coverage for grouping and UI behavior.

* fix(web): hydrate oldest visible tool group

Mark needsOlderHistory on the first visible grouped tool run even when earlier visible blocks are non-tool content, and add regression coverage for the boundary.

* fix(web): continue grouped history hydration

Decouple ToolGroupCard older-history chaining from the shared loading flag, invalidate stale hydration runs safely, and add regression coverage for multi-page hydration.

* fix(web): harden grouped tool hydration

- retry incomplete group hydration after transient pagination contention\n- keep approved and denied permissioned tool cards eligible for grouping\n- cover both regressions with targeted web tests

* fix(web): keep Codex permission cards standalone

- treat CodexPermission as a semantic grouping boundary even after approval\n- keep permissioned execution tools groupable while preserving permission milestones\n- add regression coverage for Codex permission eligibility and boundary behavior

* fix(web): narrow incomplete tool-group hydration

- only mark groups at the oldest visible boundary as needing older history\n- avoid auto-paginating complete groups behind text, standalone tools, or permission milestones\n- add regression coverage for the adjacent boundary cases
2026-05-11 09:25:49 +08:00
junesandGitHub 3a6574f2b9 fix(web): compact terminal tool cards by default (#601) 2026-05-09 09:00:18 +08:00
SmallSpiderandGitHub 841b7cc035 Add Codex multi-agent timeline support (#588)
* checkpoint codex multiagent UI state

* fix codex multiagent event scoping

* fix: stabilize codex subagent timeline

* chore: remove codex subagent nesting prompt

* test(web): stabilize tool result rendering tests

* fix: collapse codex agent trace rows by default

* fix(web): keep chat scrolled to bottom

* fix(web): backfill agent-run-heavy message loads

* fix(codex): fail stuck subagent spawns

* fix(codex): preserve wrapped child event scope

* fix(codex): surface agent tool completions
2026-05-07 10:46:16 +08:00
Junmo KimandGitHub e17d7e5995 fix(web): align Agent tool dialog with TUI ctrl+o expand (#585) 2026-05-07 08:28:03 +08:00
f7a40bd573 feat(web): polish chat rendering and fix remote session interactions (#567)
* feat(web): polish chat rendering

Refresh the web chat presentation across user messages, tool cards, code blocks, diffs, reasoning, and Mermaid diagrams.\n\nAdd focused regression coverage for bubble/status behavior, code and diff rendering, clipboard output, Mermaid theming, and message-window updates.

* fix(web): stabilize chat tool rendering

Preserve manual scroll anchors while older messages and tool dialogs update, and align code, diff, and tool result rendering with chat typography.

Add chat font-weight settings, ignore local Playwright CLI artifacts, document the Angular commit-message convention, and cover the scroll, result, code, diff, and settings behavior with focused tests.

Constraint: User requested committing all current workspace diffs with Angular-style commit messaging

Tested: bun run typecheck:web && bun run test:web && git diff --check

Co-authored-by: OmX <omx@oh-my-codex.dev>

* style(tool-card): polish question and permission card styles

Align AskUserQuestion option surfaces and permission action hierarchy with the existing tool card visual language while preserving interaction logic. Extract shared option presentation helpers and theme-driven hover/muted colors to reduce duplication.

Constraint: Frontend style-only polish; preserve existing permission and answer submission behavior

Rejected: Keep screenshot artifacts in the repo | they are local visual review output, not source

Confidence: high

Scope-risk: narrow

Tested: git diff --check; bun run typecheck:web; bun run test:web; bun run build:web

Not-tested: manual cross-browser visual QA beyond local Playwright inspection

Co-authored-by: OmX <omx@oh-my-codex.dev>

* fix(cli): keep Claude remote plan prompts actionable

Handle Claude remote /plan locally so HAPI switches plan permission mode before forwarding any prompt text. This avoids Claude Code treating /plan as an unknown skill and ending with only a ready event.

Constraint: Claude SDK result messages are not conversation log entries, so command handling must happen before the prompt reaches Claude.\nRejected: surfacing SDK result summaries in web chat | would expose transport-level summaries broadly instead of fixing the slash-command path.\nConfidence: high\nScope-risk: narrow\nDirective: Keep Claude remote slash commands that alter runtime mode in the CLI special-command parser.\nTested: bun test cli/src/parsers/specialCommands.test.ts; bun typecheck; git diff --check\nNot-tested: Manual GitHub-hosted runner deployment.

* fix(web): polish tool result rendering

* fix(web): preserve collapsed session order

* fix(chat): settle initial thread scroll

* fix(settings): remove chat font weight option

* fix(web): remove font weight bootstrap code

* chore: remove unrelated branch artifacts

* test(web): update consumed message invocation test

* fix(chat): cancel initial scroll settling on manual scroll

---------

Co-authored-by: huhaoyu.hahahu <huhaoyu.hahahu@bytedance.com>
Co-authored-by: OmX <omx@oh-my-codex.dev>
2026-05-06 09:18:27 +08:00
Junmo KimandGitHub 136badb86e fix(gemini): surface tool_call input on Gemini ACP cards (#562)
* fix(acp): derive tool_call input from kind+title fallback

Gemini 2.5 Flash and 3 Flash Preview omit rawInput entirely on
tool_call events while emitting prose (non-JSON) thoughts. Neither
the existing rawInput path nor JSON-thought hoisting fires, so the
UI shows "Input: null" alongside a perfectly readable title like
"README.md" or "ls -la /tmp".

Add a conservative fallback that maps known kinds to a minimal
input shape:

  read     -> { file_path: title }
  execute  -> { command: title }
  search   -> { pattern: title }
  think    -> null  (topic-update prose has no clean arg mapping)
  unknown  -> null  (no guessing on shapes we have not verified)

Priority: rawInput > hoisted JSON thought > kind+title derive.

Lock the new behaviour with synthetic unit tests (8 cases) and a
real-Gemini fixture suite captured from gemini-3-flash-preview
and gemini-2.5-flash via ACP stdio (4 fixtures, 33/27/13/4 raw
sessionUpdate events). The fixtures double as regression guards
against future ACP handler changes.

* fix(web): suppress duplicate subtitle when equal to tool title

Gemini ACP emits a tool_call whose title field is a human-readable
summary (often the verbatim shell command or file path). Combined with
the kind+title input fallback, an unknown-tool card ends up with the
same string in both the title and subtitle slots — e.g. title
"cat /tmp/hello.txt" over subtitle "cat /tmp/hello.txt".

Add a guard in getToolPresentation's unknown-tool branch: emit
subtitle only when it differs from toolName. The known-tool and
mcp__* branches are unaffected.

* test(acp): align Gemini fixtures to current model set

- Drop gemini-2.5-flash fixtures: the captures came from a model that
  is not part of the PR's evidence model set, and re-running the
  capture is gated on quota that is not currently available.
- Refresh gemini-3-flash-preview read_file / run_shell fixtures with
  a fresh live capture so they reflect the latest ACP shape (e.g.
  a `kind: think` tool_call expressing reasoning when the model emits
  no agent_thought_chunk).
- Update fixture-replay expectations: read_file no longer requires
  reasoning chunks (zero are emitted on this path) and now requires
  >= 2 tool_calls (think + read).

* feat(web): promote semantic title for Gemini ACP tool cards

When the unknown-tool ToolCard would render the same string as both
the title and the subtitle, promote a semantic label to the title
slot so the card reads like a sentence:

  cat /tmp/hello.txt   →   Run shell  / cat /tmp/hello.txt
  README.md            →   Read file  / README.md
  *.ts                 →   Search     / *.ts

This is a web-only ergonomic change; the underlying ACP message
shape (tool_name = title, input = derived from kind+title) is
unchanged. Builds on the dedup guard so the title-equals-subtitle
case is now handled by promotion rather than by hiding the subtitle.

* fix(acp): derive tool_call.input for kind=edit from locations[0].path

Gemini's write_file and replace tools both surface as ACP tool_call
with kind="edit" and rawInput omitted. The path lives on locations[0]
from the very first event; the title is prose like "Writing to foo.txt"
or "foo.txt: old => new", which is not safely usable as a file_path.

Extend the kind+title fallback to read locations[0].path when kind is
"edit", and synthesize { file_path } from it. Title fallback is
intentionally not used here so we never feed prose into file_path.

Lock the behaviour in with two new fixtures captured live from
gemini-3-flash-preview (write_file and replace) plus two synthetic
unit tests covering the locations-present and locations-empty paths.

* test(acp): add gemini-3.1-pro-preview fixtures for regression coverage

Captured 4 raw ACP `sessionUpdate` sequences from a live
`gemini-3.1-pro-preview` session via the same isolated hub +
runner + spawn pattern used for the existing flash captures
(read_file 31 events / run_shell 83 events / write_file 4 events /
edit_file 11 events).

The pro tier reuses the same kind/title shape as flash:
`rawInput` is omitted on every tool_call across read / execute /
edit kinds, so the kind+title (and locations[0].path for edit)
fallback is exactly what derives the modal Input. Locking these
fixtures in guards against future regressions on a second model.

The fixture-based regression test gains 4 entries (read / shell /
write / edit) mirroring the flash matrix; assertions are unchanged.
ACP handler suite: 53 -> 57 pass.
2026-05-05 18:20:54 +08:00
CoColateandGitHub e76738aa5a fix(codex): improve web rendering for Codex events (#544)
* test(codex): add web event rendering harness

* fix(codex): surface plan updates in web

* fix(codex): render MCP tool calls in web

* fix(codex): improve terminal and context display

* fix(codex): format token usage events

* fix(codex): show status context in web

* fix(codex): preserve tool result errors
2026-04-29 17:22:45 +08:00
CoColateandGitHub 9c117679f0 feat(web): collapse long code and terminal output previews (#546)
* feat(web): collapse long code and terminal output previews

* fix(web): keep fallback tool output complete

* fix(web): keep raw json details uncollapsed
2026-04-29 09:19:57 +08:00
Junmo KimandGitHub 52ec08b6cb feat(web): show subagent task trace in tool dialog (#539)
* refactor(web): extract shared task tool helpers

* feat(web): show subagent task trace in tool dialog

Task tool modals previously showed only Input and Result. This adds a
Trace section between them that surfaces the child tool calls already
wired through the reducer into block.children.

- TraceSection collapses by default when completed, expands when
  running or error so the relevant state is visible on open
- Each child row toggles an inline expand (Input/Result) to avoid
  nested Dialogs
- Header summarises call count, token total and duration via
  readSummaryFields() typed parser, falling back gracefully when any
  value is absent
- formatTaskChildLabel / TaskStateIcon imported from shared helpers.tsx
  (extracted in prior refactor commit) — no local duplicates
- Task name guard: getTaskTraceChildren returns null for non-Task blocks
- children prop renamed to items in TraceSectionInner / TraceChildList
  (react/no-children-prop anti-pattern removed)
- i18n: tool.trace and tool.trace.callsSuffix keys added for en and
  zh-CN; useTranslation hooked up to header label and calls suffix
- 15 unit tests: getTaskTraceChildren (guard, filter, non-Task null),
  getTraceSummaryText (3 branches), TraceSection (open/close/toggle/
  summary/empty)

* feat(web): include input view in trace row expand

Expanded child rows in the Task trace section now render both an Input
section and a Result section, matching the pattern used in the parent
ToolCard dialog. Tools with a registered FullInputView use it; all
others fall back to a JSON CodeBlock. Closes bot review on PR #539.
2026-04-28 10:55:10 +08:00
f408608db0 fix(web): exclude brackets from CJK autolink punctuation stripping (#486)
* fix(web): exclude brackets from CJK autolink punctuation stripping

Fullwidth brackets and parentheses (()【】「」etc.) can appear in
valid URL paths, so they should not be stripped. Narrow the regex to
only sentence-ending punctuation: comma, period, semicolon, colon,
exclamation, question mark.

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

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

* fix(web): always show 'Agent launched' for internal metadata results

The tool state is set to 'completed' immediately when the result
arrives, so the state-based label was always showing 'Done' for
internal launch metadata. Remove the state check and always show
'Agent launched'.

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

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

* fix(web): handle sentence-ending punctuation followed by closing brackets

The regex was missing cases like 。) where a sentence-ender is followed
by a closing bracket. Use a pattern that matches sentence-ending
punctuation optionally followed by trailing closing brackets/parens.
A bare closing bracket without a preceding sentence-ender is still
preserved as a valid URL character.

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

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

---------

Co-authored-by: HAPI <noreply@hapi.run>
2026-04-17 11:37:06 +08:00
9248b6825f fix(web): hide raw internals in Agent tool card (#481)
* fix(web): hide raw internals in Agent tool card (#480)

The Agent tool card was exposing raw JSON input (including full prompts)
and internal system messages (agentId, output_file paths, system
instructions) in the details dialog. Register dedicated views:

- knownTools: show description as title, subagent_type as subtitle
- AgentFullView: show description, type, background status (not prompt)
- AgentResultView: detect internal launch messages and show "Agent
  launched" instead; render actual results as markdown for completed
  agents

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

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

* fix: widen Agent result redaction to catch more internal metadata variants

Use || instead of && so any single internal marker (agentId:,
output_file:, internal ID) triggers redaction, not just the combination
of all markers.

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

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

* fix: use structural checks for Agent metadata redaction

Replace loose substring matching (which could false-positive on
legitimate agent output) with:
1. Structural check: result object has agentId/output_file keys
2. Strict text pattern: starts with the exact launch message prefix

Also make the label state-aware: "Done" for completed, "Agent launched"
for running.

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

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

---------

Co-authored-by: HAPI <noreply@hapi.run>
2026-04-17 11:14:30 +08:00
40e51cb8d4 fix(web): hide filesystem path and raw prompt in Skill tool card (#455)
* fix(web): hide filesystem path and raw prompt in Skill tool card (#453)

The Skill tool card was exposing the full absolute filesystem path
(including username, plugin cache structure, and version numbers) and
the raw SKILL.md prompt content. Register a dedicated Skill presentation
in knownTools with a friendly title showing only the skill name, and add
a SkillResultView that displays "Skill loaded" instead of the raw output.

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

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

* fix(web): register Skill full view to hide raw input in details dialog

Add SkillFullView to toolFullViewRegistry so the details dialog shows
only the skill name instead of falling back to renderToolInput which
would expose raw JSON input.

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

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

* fix(web): handle non-text error payloads in SkillResultView

When the error payload is not text-extractable, fall back to a generic
"Failed to load skill" message instead of falling through to the success
path showing "Skill loaded".

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

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

---------

Co-authored-by: HAPI <noreply@hapi.run>
2026-04-14 17:40:21 +08:00
Haoqing WangandGitHub 2216f98c58 fix(web): render multiline mutation results as code blocks to prevent markdown mis-parsing (#371) 2026-03-27 16:05:10 +08:00
dotblueandGitHub bcc2558dff feat: Render question text and options with markdown (#339) 2026-03-23 05:02:52 +08:00
weishu 4f06cdfd7c Support codex plan tool 2026-03-08 12:11:19 +08:00
06b71dbe98 feat: Add Claude Code Agent Teams support (#258)
* feat: Add Claude Code Agent Teams support

- Add TeamState schemas and types for team collaboration
- Extract team state from TeamCreate, SendMessage, Task tools
- Add database migration V3→V4 for team_state storage
- Add TeamPanel component to display team members, tasks, messages
- Add team tool icons and presentation rules
- Support vite proxy configuration via VITE_HUB_PROXY env var

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

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

* fix: Add timestamp protection for team_state updates

Prevent old messages from overwriting newer team state by checking
team_state_updated_at before updating.

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

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

* fix: Extract team tasks from Task/TaskCreate/TaskUpdate tools

- Enhance processTaskToolWithTeam to also generate task entries from
  the Task tool's description field when spawning teammates
- Add processTaskCreate handler for TaskCreate tool calls
- Add processTaskUpdate handler for TaskUpdate tool calls
- Register both new tools in the extraction switch statement

This fixes the gap where the Tasks section in TeamPanel could never
populate because team task data was not being extracted from the
message stream.

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

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

* fix: Skip orphan TaskUpdate without title to prevent schema validation failure

When TaskUpdate arrives before TaskCreate (message ordering), skip inserting
incomplete tasks that lack required title field, preventing entire teamState
from being dropped by schema validation.

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

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

* test: Add unit tests for orphan TaskUpdate handling

Verify that applyTeamStateDelta correctly skips inserting tasks without
title field (orphan TaskUpdate) while still allowing normal task creation
and updates to existing tasks.

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

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

---------

Co-authored-by: tfq <tfq@gmail.com>
Co-authored-by: HAPI <noreply@hapi.run>
2026-03-08 11:26:11 +08:00
weishu b7c06db327 refactor: extract agent flavor utility functions into shared module 2026-01-29 15:41:19 +08:00
weishu cdf8226a9d refactor: extract tool input utility functions into shared module
Move getInputString, getInputStringAny, and truncate functions from
individual ToolCard components into a dedicated toolInputUtils module
to eliminate duplication across PermissionFooter, ToolCard, and
knownTools components.
2026-01-29 14:37:06 +08:00
weishu 70b5c22c8f feat: support opencode 2026-01-29 10:34:57 +08:00
weishu 40c232ef8b fix: handle option highlighting in request_user_input component
- Trim selected value to match option labels during comparison
- Parse tool.result as JSON when loaded from history, as it's stored as string
2026-01-26 14:08:35 +08:00
weishu ae9650ca7c feat: add support for Codex's request_user_input tool
Implement full support for the request_user_input tool with both Web UI and CLI
components. This includes:

- New view and footer components for request_user_input tool UI
- Tool registration in knownTools and view registries
- Nested answer format support (Record<string, { answers: string[] }>)
- Backward compatibility with flat answer format (Record<string, string[]>)
- Permission handler updates for CLI request_user_input acceptance
- Type definitions and schema updates across shared/cli/server/web packages
- Translation strings for request_user_input UI elements
- Conditional footer rendering in ToolCard for question tools
2026-01-26 11:58:36 +08:00
weishu 9922588c6f refactor: consolidate utility functions into shared package
Move duplicate isObject, asString, asNumber, and safeStringify functions from multiple modules into a centralized shared/src/utils.ts module and update imports across cli, server, and web packages. This eliminates code duplication and improves maintainability.
2026-01-23 16:04:37 +08:00
weishu 251b04ec2d fix: use message field for Codex permission card subtitle
Codex elicitation requests from MCP use the 'message' field (from
ElicitRequest schema), not 'command' or 'cwd'. Update the permission
handler to extract and pass this field, and display it as the card
subtitle with fallback to command.
2026-01-13 11:06:50 +08:00
weishu 41d8844c00 fix: implement permission handler callbacks and add CodexPermission UI support
Adds onRequest and onComplete callbacks to CodexPermissionHandler to track
permission request/response lifecycle. Includes helper functions to normalize
command and cwd inputs, and displays permission requests in the web UI.
2026-01-13 11:06:50 +08:00
weishu a6e35eaf65 fix: add shell_command tool to knownTools registry
Codex API sends 'shell_command' as the tool name for bash commands, but
the web app didn't recognize it, falling back to a generic wrench icon.
This adds proper presentation with a terminal icon, matching Claude's
Bash tool display.
2026-01-13 11:06:50 +08:00
weishu d260ea86f0 fix: parse codex bash output format in web app display
Parse the "Exit code: X\nWall time: Y\nOutput:\n..." format from bash tool
results and display metadata (exit code and wall time) separately from the
output content as a code block.
2026-01-13 11:06:50 +08:00
ChenandGitHub aaaad33e61 feat: add i18n support and enhance session UI (#50) 2026-01-10 22:07:22 +08:00
weishu 77eefcd8da refactor: move path utilities to utils directory 2026-01-05 13:00:48 +08:00
weishu 7f2a36117c feat: add Spinner and LoadingState components for unified loading UX
Introduces two reusable loading components to standardize loading states:
- Spinner: Base spinner with accessibility support (role, aria-label)
- LoadingState: Semantic loading indicator combining spinner and label

Updates loading patterns across the app:
- Full-screen/block loading now uses LoadingState (App, router, files, file)
- Inline button loading states show spinner + text with aria-busy
- Message list loading replaced with MessageSkeleton component
- Removes duplicate SpinnerIcon definition from PermissionFooter

Improves UX and accessibility:
- Loading screens centered and full-height
- Consistent ellipsis character (…)
- Semantic accessibility (role="status", aria-live, aria-busy)
- Adds CSS variables for banner styling
2025-12-24 17:23:39 +08:00
weishu 4f03f29ac3 docs: rebrand Happy to HAPI and add component documentation
This commit rebrands the project from "Happy" to "HAPI" throughout the codebase, including documentation, comments, logs, and tool references. It also adds comprehensive README files for the server and web components, clarifies the monorepo structure in AGENTS.md and root README.md, and removes the outdated roadmap.md file.

Changes include:
- Rebrand references from Happy to HAPI in CLI, server, and web components
- MCP tool names updated from mcp__happy__ to mcp__hapi__
- Process/service names updated consistently
- New server/README.md with deployment and configuration guide
- New web/README.md with stack and development instructions
- Updated root README.md with quickstart guide
- Updated AGENTS.md with cleaner structure documentation
- Removed cli/roadmap.md (now superseded by documentation)
2025-12-21 18:49:04 +08:00