Commit Graph
15 Commits
Author SHA1 Message Date
Junmo KimandGitHub e6eaff83c5 fix(hub,cli): forward permissionMode on session resume (#460)
* feat(hub,cli): forward permissionMode on session resume

When a session is resumed, the cached permissionMode is now forwarded
through the Hub → Runner → CLI pipeline via a new --permission-mode
flag. Previously the mode was lost on resume, resetting to 'default'.

Each CLI flavor validates the flag value against its own allowed
permission modes (e.g. CLAUDE_PERMISSION_MODES) and rejects unknown
values. The existing --yolo flag is preserved as a shorthand.

* refactor(cli): extract buildCliArgs from startRunner

Extract the CLI argument construction logic into a standalone
exported function so it can be unit-tested independently.
No behavior change.

* test(cli): add buildCliArgs unit tests for --permission-mode

Verify that the runner correctly forwards valid permission modes
via --permission-mode, rejects invalid values, and falls back to
--yolo when no permission mode is set.

* fix(cli): let --permission-mode take precedence over --yolo

When both flags are present, --permission-mode was silently
overwritten by a later --yolo. Guard legacy flag branches with
a hasExplicitPermissionMode check so the explicit flag wins.
2026-04-15 11:13:21 +08:00
Haoqing WangandGitHub 7c6a7fa8ef fix(hub,web): deduplicate sessions by agent session ID (#448)
* fix(hub,web): deduplicate sessions by agent session ID

When multiple CLI wrappers independently resume the same Codex thread,
each generates a random tag, causing the hub to create duplicate session
records for a single underlying thread. This leads to duplicate
conversations in the web UI and messages routing to the wrong session.

Add two-layer deduplication:
- Hub: when a metadata update sets an agent session ID (codexSessionId,
  claudeSessionId, etc.) that already exists on another session in the
  same namespace, automatically merge the duplicate into the current
  session using the existing mergeSessions logic.
- Web: deduplicate the session list display by agentSessionId as a
  safety net, keeping the active/most-recent session visible.

Closes #446

* chore: add review-driven comments for dedup clarity

- Explain single-threaded assumption in before/after metadata comparison
- Document merge direction rationale (duplicate → active session)
- Document deduplicateInProgress guard as known limitation
- Add catch comment explaining web safety net fallback

* fix: address review feedback from bot, Opus, and Codex

- Skip active duplicates during hub-side dedup to avoid deleting
  sessions with live CLI sockets and pending agent state
- Pass selectedSessionId into web dedup sort to prevent hiding
  the session the user is currently viewing
- Add test for active-duplicate-not-merged case

* fix: retry dedup on session-end and preserve agentState in merge

- Trigger dedup when a session ends (handleSessionEnd), so active
  duplicates skipped during earlier dedup get merged once they disconnect
- Preserve agentState from old session during mergeSessions when the
  new session has no agentState (mirrors existing model/effort/todos
  preservation pattern)
- Extract triggerDedupIfNeeded helper for reuse across trigger points

* fix(web): prefer active session over selected in dedup sort

Active session always wins the dedup tie-break so the live connection
is never hidden in favor of a selected inactive duplicate. Among
inactive duplicates the selected one is still preferred.

* fix: dedup on inactivity timeout and deep-merge agentState

- expireInactive now returns expired session IDs so SyncEngine can
  trigger dedup for sessions that timed out (crash/network drop)
  instead of only on explicit session-end
- mergeSessions now deep-merges agentState requests/completedRequests
  from both sessions instead of only copying when new is null

* fix: exclude completed requests from merged pending set

Filter out request IDs that already appear in completedRequests when
merging agentState, preventing completed permission prompts from
resurrecting as pending after session dedup.

* fix: guard resume merge against prior auto-dedup

The automatic dedup (triggered when the spawned CLI sets its agent
session ID) can delete the old session before resumeSession reaches
its own explicit mergeSessions call. Skip the merge if the old session
no longer exists instead of failing the resume with a false error.

* test: add coverage for dedup retry paths and web dedup sort

Hub tests:
- session-end triggers dedup retry for previously-active duplicates
- inactivity timeout expiry triggers dedup retry
- agentState deep merge filters completed requests from pending set

Web tests:
- basic dedup by agentSessionId
- active session wins over inactive duplicate
- selected session preferred among inactive duplicates
- active always wins over selected inactive
- sessions without agentSessionId pass through
- independent dedup across different agentSessionIds

* fix: read latest agentState before merge write to avoid overwriting live updates

Re-read the target session's agentState right before writing the merged
result, with a version-mismatch retry loop, so concurrent update-state
events from the active CLI are not lost during dedup merge.

* fix: sort expired sessions by recency before dedup

When multiple duplicates for the same agent thread expire in a single
sweep, process the most recent one first so it becomes the merge target
and survives, rather than keeping the oldest by arbitrary iteration order.

* fix: select most recent session as merge target in dedup

deduplicateByAgentSessionId now collects all inactive candidates
(including the caller) and picks the one with the highest activeAt
(then updatedAt) as the merge target. This ensures the newest session
survives regardless of which trigger point or ordering calls the dedup.
2026-04-13 19:56:22 +08:00
weishu 79a13d26c6 Fix Codex reasoning effort resume and updates 2026-04-10 11:50:03 +08:00
MimoandGitHub 0e1b653d43 feat: display background task count in status bar (#421) 2026-04-09 20:17:12 +08:00
a200fe9628 feat(claude): add effort setting parity with model across stack (#353)
Co-authored-by: Xiaoyi <xiaoyizhang@microsoft.com>
2026-03-24 21:15:48 +08:00
xyzhang626andGitHub b6ecdc7b44 fix(hub): pass resumeSessionId when resuming session (#337) 2026-03-22 06:49:14 +08:00
ROOOOandGitHub cb09f0b898 feat: add codex reasoning effort option (#297) 2026-03-17 22:55:55 +08:00
weishu 16829b7c78 Add support for codex plan mode 2026-03-16 20:48:39 +08:00
weishu 329d28a93c remove , using instead 2026-03-16 18:29:09 +08:00
weishu 02c8e12e80 unify model selection 2026-03-16 18:29:09 +08:00
JlovecandGitHub ef3328f48f fix(cli): support project slash command completion (#245)
Add project-level slash command discovery with recursive nested command scanning, pass workingDirectory through slash-command handlers, and align hub/web source unions to include project commands.
2026-03-05 12:50:59 +08:00
Mao MrandGitHub c9be2894ac feat(cursor): add support for Cursor Agent CLI integration (#236)
* feat(cursor): add support for Cursor Agent CLI integration

- Introduced new command `hapi cursor` to start Cursor Agent sessions.
- Added functionality for resuming sessions and managing permission modes.
- Updated documentation to include Cursor Agent usage and installation instructions.
- Enhanced existing codebase to accommodate Cursor as a recognized agent flavor.
- Implemented local and remote session handling for Cursor Agent.

This update expands HAPI's capabilities by integrating support for the Cursor Agent, allowing users to leverage its features alongside existing agents.

* Remove TODO.md file as it is no longer needed following the integration of Cursor Agent CLI support. This cleanup helps streamline project documentation and reflects the completion of the associated tasks.

* feat(cursor): implement remote mode and fix --hapi-starting-mode

- Consume --hapi-starting-mode in cursor command (do not forward to agent)
- Implement cursorRemoteLauncher: spawn agent -p with stream-json, --trust
- Add cursorEventConverter for NDJSON parsing (system/assistant/tool_call/result)
- Multi-turn via --resume session_id
- Update docs: cursor supports both local and remote modes

Made-with: Cursor

* fix: type error

* fix(cursor): address PR review - model UI, sessionId metadata, duplicate flags

- HappyComposer: use isClaudeFlavor for model mode (cursor has no model modes)
- cursorLocalLauncher: call onSessionFound for resume so cursorSessionId in metadata
- cursorCommand: do not forward parsed flags to cursorArgs (avoid duplicates)

Made-with: Cursor
2026-03-03 10:02:47 +08:00
weishu fb9abc18d4 feat: Add directory tree tab to session files 2026-02-06 20:18:46 +08:00
weishu 70b5c22c8f feat: support opencode 2026-01-29 10:34:57 +08:00
weishu 37e10a831b feat: rename server package to hub
Rename the `server/` directory to `hub/` and update all references
across CLI, docs, web, and workspace configuration.
2026-01-27 19:51:21 +08:00