Commit Graph
44 Commits
Author SHA1 Message Date
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
HeavyGeeandGitHub dc0d21e05b fix(cursor): intercept fabricated Questions skipped AskQuestion result in headless mode (#784) (#801)
* fix(cursor): intercept fabricated 'Questions skipped' AskQuestion result in headless mode (#784)

When cursor-agent runs under `--print --output-format stream-json` (HAPI's
current Cursor remote launcher), the CLI returns a synthetic
`Questions skipped by the user, continue with the information you already have`
response for the `AskQuestion` tool in ~zero seconds with no error flag,
because there is no IDE surface to render the question. The underlying
model can interpret this as legitimate user consent and act on it.

This patch intercepts the synthetic result in
`cli/src/cursor/utils/cursorEventConverter.ts` and rewrites the
`tool_call`/completed event to a structured `no_input_surface` failure
(`status: 'failed'`, which downstream becomes `is_error: true`).

Detection has two strategies:

1. String match - any `tool_call`/completed payload whose serialized form
   contains the synthetic-skip marker is rewritten. This is robust to
   wherever cursor-agent stuffs the marker inside the `tool_call` object.
2. Timing + name heuristic (defense in depth) - any completion that arrives
   within 500 ms of its 'started' event with a trivial result, for a tool
   call named `AskQuestion`, `askQuestion`, `ask_question`, or the
   converter's `unknown` fallback, is also rewritten. This catches the case
   where cursor-agent changes the synthetic-string text in a future release.

The converter tracks per-call timestamps in a bounded `Map` (`<= 1024`
entries, oldest evicted on overflow) and clears entries when the
corresponding 'completed' event arrives. A small test-only reset hook
isolates state between Vitest cases.

This is a transitional safety patch. It auto-deletes when #781's ACP
launcher replaces the stream-json launcher and `cursor/ask_question`
becomes a proper bidirectional ACP method where fabrication is
structurally impossible.

Scope is intentionally tiny: only `cli/src/cursor/utils/cursorEventConverter.ts`,
its colocated Vitest file, and a section in `docs/guide/cursor.md`. No
changes to `cursorRemoteLauncher.ts`, ACP code, web normalizer, or
permission UI.

Refs: tiann/hapi#781 (long-term resolution via ACP migration)
Closes: tiann/hapi#784

* fix(cursor): gate AskQuestion intercept on tool name (#784 PR #801 review)

Address regression flagged by the HAPI auto-review bot on #801:

`containsSyntheticSkipMarker` previously stringified the entire `tool_call`
payload and matched the literal marker substring. Because this PR also adds
that exact marker to `docs/guide/cursor.md` (to document the intercept), a
Cursor `read_file` of that documentation page would surface the marker
inside `readToolCall.result.content` and be rewritten as a
`no_input_surface` failure, corrupting an unrelated, legitimate result.

The intercept is now gated on the tool name resolving to an
AskQuestion-shaped call (`AskQuestion`, `askQuestion`, `ask_question`, or
the converter's `unknown` fallback for unnamed function-shaped tools).
`read_file` / `write_file` tool calls - which have explicit `read_file`
and `write_file` names from `extractToolName` - no longer fall under the
intercept, regardless of what their payload contains.

The marker check itself now walks values recursively (string / array /
object), guarded by a `WeakSet` against cycles, instead of relying on
`JSON.stringify`. Slightly tidier; behaviour is otherwise unchanged for
the AskQuestion path.

Regression tests added:

- `read_file` result whose `content` contains the marker -> passes
  through with `status: 'completed'` and no `no_input_surface`.
- `write_file` whose serialized `args` contain the marker -> same.
- A non-AskQuestion function tool (`MyCustomTool`) whose result quotes
  the marker -> same.

All 846 cli tests pass (17 in this file). `bun run typecheck` exits 0.

* fix(cursor): scope synthetic-skip check to extracted result (#784 PR #801 review-2)

Address second Major finding from the HAPI auto-review bot on #801:

After the previous fix gated the intercept on the tool name, the marker
check still recursed into the entire `tool_call` object - which includes
`function.arguments`, the agent's own prompt text. A legitimate
AskQuestion whose prompt quotes the synthetic-skip marker (e.g. an agent
debugging this exact bug, or any prompt that pastes the marker verbatim)
would have been rewritten as `no_input_surface` even when the operator
actually answered.

Changes:

1. `extractToolResult` now extracts the cursor-side response from
   function-shaped tool calls. Previously it returned `{}` for anything
   that wasn't `readToolCall` or `writeToolCall`. It now returns
   `function.result` when present, otherwise every field of `function`
   except `name` and `arguments`. This excludes the agent's input from
   what downstream sees as the tool result, and as a side effect surfaces
   the actual cursor response for function-shaped tools (which was
   previously lost - see the #784 incident note about HAPI storing
   `output: {}` for AskQuestion in the message DB).

2. `shouldRewriteAsNoInputSurface` now searches only the extracted
   `result`, not the whole `tool_call`. The bot's exact recommendation.

3. Test added: an AskQuestion whose `arguments` quote the marker but
   whose `result` is a real user answer, with elapsed time past the
   500 ms threshold so the timing heuristic does not apply. Asserts the
   tool_result passes through with `status: 'completed'` and the
   operator's actual answer.

All 847 cli tests pass (18 in `cursorEventConverter.test.ts`).
`bun run typecheck` exits 0.

The widened `extractToolResult` scope is necessary for the marker check
to actually find the synthetic string (it lives inside `function.result`
or a sibling field), and is the bot's explicit recommendation. It also
removes the long-standing data-loss bug where AskQuestion responses were
surfaced to the message DB as opaque `{}` - regardless of fabrication.
2026-06-05 21:44:37 +08:00
lekoandGitHub db934a9d5b Update hapi runner command to use start-sync (#685)
* Update hapi runner command to use start-sync

* Update installation instructions for start command
2026-05-26 16:13:25 +08:00
weishu 35044cde50 remove unused docs 2026-05-22 09:01:14 +08:00
lekoandGitHub ce2e76a42e Add Windows remote terminal support (#642) 2026-05-19 07:54:12 +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 08d3d9e111 feat(web): add composer enter behavior setting (#586) 2026-05-07 08:27:13 +08:00
ShujakuinandGitHub 0bffb03b05 feat(cli): support optional extra headers for hub requests (#445)
* feat(cli): support extra headers for hub requests

* fix(types): normalize missing session fields to null

* refactor(cli): simplify socket extra headers config
2026-04-14 13:54:51 +08:00
lifu963andGitHub 895654ddf6 fix(terminal): prevent infinite reconnect loop on Windows hosts (#336) 2026-03-21 21:45:40 +08:00
weishu bfc9ad9f0c docs: for localhost access 2026-03-16 08:54:04 +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 91d03e481f docs: add npm registry recommendation for installation
Update installation guides to specify the official npm registry
and add a recommendation to use it for global installs, as some
mirrors may not sync platform packages in time.
2026-03-02 12:00:19 +08:00
weishu 857f625ce3 docs: Self-signed certificates 2026-02-07 11:41:43 +08:00
weishu 4242c508c1 docs: update Cloudflare Tunnel section and add relay TCP configuration tip
- Remove Quick Tunnel (TryCloudflare) documentation as it doesn't support SSE which HAPI uses for real-time updates
- Add warning note explaining the limitation with link to Cloudflare docs
- Keep only Named Tunnel as the recommended approach
- Add tip about HAPI_RELAY_FORCE_TCP environment variable for users experiencing connectivity issues
2026-02-04 10:28:08 +08:00
weishu 8dfc8749eb fix schema url 2026-01-31 11:06:39 +08:00
weishu effe033c4f docs: unify ENV and settings.json configuration documentation (#113)
- Add settings.json column to environment variables table with key name mappings
- Document missing ENV variables: TELEGRAM_BOT_TOKEN, TELEGRAM_NOTIFICATION,
  HAPI_RELAY_FORCE_TCP, VAPID_SUBJECT
- Add settings.json example with configuration priority explanation
- Create JSON Schema file for settings.json validation and editor autocompletion
  with all fields, descriptions, and ENV variable references

clsoe #113
2026-01-31 11:01:59 +08:00
weishu 70b5c22c8f feat: support opencode 2026-01-29 10:34:57 +08:00
weishu aef4da9ea9 docs: update cli, hub, and web README files with new features and configuration
- cli/README.md: Remove non-existent runner commands, add codex resume and worktree config
- hub/README.md: Document auto-generated CLI_API_TOKEN, add session/machines/events endpoints and push notifications
- web/README.md: Add settings and terminal routes, terminal and voice assistant sections
- docs/guide: Fix broken anchor link and add terminal FAQ entry
- AGENTS.md: Add new source directory references
2026-01-27 20:46:39 +08:00
weishu 1d56a7cf34 docs: update why-hapi guide with accurate architecture and encryption details
Corrects outdated information about HAPI's decentralized architecture compared
to Happy's centralized approach. Updates user model, encryption strategy,
and deployment details to reflect current design. Clarifies that HAPI supports
both self-hosted and relay modes with proper security implications.
2026-01-27 20:27:53 +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
weishu 0ea5b5f8f6 docs: add background service deployment section with nohup, pm2, launchd, and systemd examples 2026-01-22 20:43:16 +08:00
weishu cd6cbe2686 docs: add Architecture section explaining HAPI components and workflows 2026-01-22 20:37:48 +08:00
weishu 8793362b5f docs: update installation guide and fix environment variable references (#85)
- Replace outdated WEBAPP_URL with HAPI_PUBLIC_URL in server and web READMEs
- Add CLI version verification steps in prerequisites section
- Enhance Cloudflare Tunnel documentation with quick and named tunnel examples
- Add --protocol http2 recommendation for tunnel stability
- Include pm2 alternative for runner process management
- Add Telegram Mini App troubleshooting notes and verification steps
2026-01-21 20:08:10 +08:00
weishu e9db67e18b docs: add voice assistant documentation 2026-01-19 18:48:13 +08:00
weishu 9e335fa305 refactor: rename configuration variables for clarity
Standardize naming across CLI and server components:
- CLI: serverUrl → apiUrl, HAPI_SERVER_URL → HAPI_API_URL
- Server: webapp* → listen*, miniAppUrl → publicUrl, WEBAPP_* → HAPI_LISTEN_*, WEBAPP_URL → HAPI_PUBLIC_URL
- Rename serverUrlInit.ts → apiUrlInit.ts with updated logic for backward compatibility
- Update all imports, function calls, and documentation accordingly
2026-01-19 12:57:37 +08:00
weishu 0228146b99 refactor: rename daemon to runner throughout codebase 2026-01-19 11:12:48 +08:00
weishu c3c89a2773 docs: default to --relay for simplified remote access with E2EE
Update documentation across README, installation, and quick-start guides
to highlight the new relay-based access method with WireGuard + TLS
end-to-end encryption. Changes include:
- Recommend `hapi server --relay` as the default startup command
- Explain URL and QR code generation in terminal for instant access
- Note end-to-end encryption for security assurance
- Reorganize self-hosted tunnel options (Cloudflare, Tailscale, IP)
- Update website installation steps and add E2EE badge
2026-01-14 10:36:46 +08:00
weishu db8482d586 chore: rename PWA to App 2026-01-10 22:15:28 +08:00
weishu 70242041d5 docs: fix documentation links to work on GitHub and VitePress
Use relative paths with .md extension for docs/guide/*.md files and
relative paths in README.md to support both GitHub rendering and
VitePress website (which has base: '/docs/'). Fixes #36
2026-01-07 15:18:15 +08:00
weishu 37c6bc83d7 chore: migrate to AGPL-3.0-only 2026-01-04 20:45:15 +08:00
weishu c112f3f93e docs: add push notifications documentation 2026-01-02 19:35:15 +08:00
weishu 8cacd04db4 docs: add Seamless Handoff documentation and showcase
Introduce comprehensive documentation of HAPI's Seamless Handoff feature:

- README: Add Seamless Handoff to Features section
- how-it-works: Add complete Seamless Handoff guide with local/remote modes and switching workflow
- quick-start: Add Seamless Handoff link to Next steps
- AppShowcase: Add third card featuring "Switch Freely" mode switching capability
- Locales: Update English and Chinese translations for showcase content
2026-01-02 13:24:05 +08:00
weishu 8258885cdc docs: clarify HAPI supports single user and small teams via namespaces 2026-01-02 13:00:40 +08:00
weishu 68f4f336c9 docs: clarify server deployment options and remote access methods
- Support both local and remote server deployment
- Add direct public IP access option for remote servers
- Remove tunnel requirement messaging
- Organize remote access options with details sections
2026-01-02 12:56:44 +08:00
weishu 2e9cb46a39 docs: add Steps component and refactor quick-start guide 2026-01-01 19:12:16 +08:00
weishu 0e98dadd50 docs: improve quick-start guide with next steps section 2026-01-01 14:44:13 +08:00
weishu 1e46bd3295 fix: update documentation routing and simplify navigation
- Replace VitePress router with window.location for docs index redirect
- Add redirect rules for /docs and /docs/ paths to quick-start guide
- Simplify navigation by removing section anchor links
- Update all CTA buttons to link directly to /docs/ instead of home sections
- Consolidate navigation layout on both desktop and mobile views
2026-01-01 14:23:44 +08:00
weishu 77a2eee236 site: Add official website source
- Set VitePress base to '/docs/' for serving documentation at /docs/ route
- Update favicon path in head config to '/docs/favicon.ico'
- Add build:site script to build website and docs, then merge outputs
2026-01-01 12:48:45 +08:00
weishu 7ae7158127 fix: improve namespace-based multi-user 2025-12-31 23:28:29 +08:00
weishu 460c393006 docs: add documentation site with VitePress setup
- Initialize VitePress documentation site with config, index, and guides
- Add guides for quick-start, installation, PWA, how-it-works, FAQ, and why HAPI
- Update .gitignore to exclude VitePress cache directory
- Update logo.svg with actual icon from web/public/icon.svg
- Simplify README.md with link to full installation guide
- Remove redundant WHY_NOT_HAPPY.md (content migrated to why-hapi guide)
2025-12-31 20:41:02 +08:00
weishuandGitHub d083a73cb0 Revise diagrams and data flow for Happy and HAPI
Updated diagrams and data flow descriptions for Happy and HAPI models in WHY_NOT_HAPPY.md.
2025-12-25 20:40:36 +08:00
weishu 73f5a51548 fix url of happy project 2025-12-25 17:42:22 +08:00
weishu 6829ca35a4 docs: add architectural comparison with Happy and update README
Add comprehensive WHY_NOT_HAPPY.md documenting the architectural
differences between HAPI's local-first design and Happy's cloud-first
approach. Update README with clearer project description and link to
new documentation.
2025-12-25 14:01:13 +08:00