Commit Graph
43 Commits
Author SHA1 Message Date
Tam Nhu Tran fae8716900 fix(cursor): fallback when requested model is unavailable
- resolve request model against current available catalog

- choose safe default when configured default id is not present

- add tests and docs for daemon request-model fallback behavior
2026-02-17 20:53:03 +07:00
Tam Nhu Tran 4798741a99 fix(cursor): resolve review feedback and harden edge cases 2026-02-17 16:33:21 +07:00
Tam Nhu Tran c639cefa7b feat(cursor): harden daemon integration and model discovery 2026-02-17 04:09:06 +07:00
Kai (Tam Nhu) TranandGitHub 16aeddfb11 Merge pull request #568 from kaitranntt/fix/555-cursor-e2e-recovery
feat(cursor): recover lost Cursor dashboard and model-mapping work
2026-02-14 17:50:57 +07:00
Tam Nhu Tran 7b73658f87 feat(cursor): sync model mapping across config and raw settings
- add cursor model fields to unified config defaults and YAML comments

- expand Cursor model catalog/defaults and return configured current model

- keep cursor.settings.json env model fields in sync with config updates

- align unit tests for new model defaults and route merge behavior

Refs #555
2026-02-14 16:57:04 +07:00
Tam Nhu Tran 08a3e0bae6 fix(cursor): split daemon helpers to satisfy maintainability gate 2026-02-14 10:36:13 +07:00
Tam Nhu Tran f02e7dc5c6 fix(cliproxy): address lifecycle port and thinking regressions 2026-02-14 10:23:39 +07:00
Tam Nhu Tran 0e55db88a5 fix(cursor): address CI gate and review regressions 2026-02-14 06:41:57 +07:00
Tam Nhu Tran be9d7cf73e feat(cursor): complete daemon wiring and add dedicated dashboard page 2026-02-14 06:22:28 +07:00
Tam Nhu Tran 36a67c4837 fix(cursor): close ReadableStream controller on abort to prevent consumer hangs
When abort fires after streaming begins, onAbort closed HTTP/2 handles
but never closed the ReadableStream controller. Consumers waiting on
reader.read() could hang indefinitely since end/error handlers were
gated by streamClosed flag.

Hoist controller reference to outer scope so abort handler can close it.
2026-02-13 05:33:56 +07:00
Tam Nhu Tran 27badb2584 fix(cursor): validate fetch status before streaming fallback and register abort early
- Check response.status before calling transformProtobufToSSE in fetch fallback
- Move abort signal registration before response headers to handle early cancellation
2026-02-13 04:21:13 +07:00
Tam Nhu Tran 4e5b502fc9 feat(cursor): namespace FIELD constants and implement true streaming SSE (#531, #535) 2026-02-13 04:12:29 +07:00
Tam Nhu Tran bfc9361701 fix(cursor): fix router fall-through, add daemon marker, use random test port
- Route all `ccs cursor *` to handleCursorCommand (no profile-switching)
- Add --ccs-daemon marker to spawned process for stable PID validation
- Use random port in lifecycle integration test to prevent CI conflicts
- Remove unnecessary .toFixed(1) on integer tokenAge
2026-02-12 08:37:01 +07:00
Tam Nhu Tran 760a5c3ca4 fix(cursor): harden stopDaemon PID validation, tighten regex, add lifecycle test
- Validate PID belongs to cursor daemon via /proc before signaling
- Tighten detectProvider regex to avoid over-matching o-prefixed models
- Add integration test for daemon start→health→stop lifecycle
- Add void cast on discarded handleHelp() return value
- Update model catalog date comment
2026-02-12 08:28:32 +07:00
Tam Nhu Tran 934238740e fix(cursor): export missing symbols, eliminate subcommand sync risk, improve tests
- Export detectProvider and formatModelName from barrel index
- Export CURSOR_SUBCOMMANDS from cursor-command.ts, import in ccs.ts
- Use getCcsDir() in tests instead of manual path construction
- Add handleCursorCommand routing test for unknown subcommand
2026-02-12 08:21:39 +07:00
Tam Nhu Tran cda037e7e5 fix(cursor): clean up PID file on startDaemon failure and improve daemon robustness
- Add removePidFile() in safeResolve on failure to prevent stale PIDs
- Only send SIGKILL in stopDaemon if SIGTERM wait loop exhausted
- Check isDaemonRunning before model fetch to avoid 5s timeout
- Add port validation unit tests for startDaemon
2026-02-12 08:11:41 +07:00
Tam Nhu Tran ce1915366d fix(cursor): use stdio ignore, sequential polling, move CursorConfig to types
- Change spawn stdio from piped to 'ignore' preventing buffer deadlock
- Replace setInterval with sequential setTimeout polling
- Fix TOCTOU in SIGKILL escalation (send directly without probing)
- Move CursorConfig interface to types.ts
- Change detectProvider default from 'openai' to 'unknown'
- Remove redundant removePidFile() when PID is null
2026-02-12 07:51:22 +07:00
Tam Nhu Tran 94789676b9 fix(cursor): use process.execPath and add safeResolve to model fetcher
- Replace 'node' with process.execPath for cross-platform reliability
- Add safeResolve guard in fetchModelsFromDaemon matching startDaemon pattern
2026-02-12 07:37:20 +07:00
Tam Nhu Tran 36f0308a72 fix(cursor): add response body handling and size limit
- Drain health check response body with res.resume()
- Add 1MB body size limit in fetchModelsFromDaemon
2026-02-12 07:24:10 +07:00
Tam Nhu Tran 88ad13ee7b fix(cursor): kill orphaned daemon on timeout and fix exit codes
MEDIUM fixes:
- Kill orphaned process when health check times out after 30s
- Prevents zombie processes from consuming resources

LOW fixes:
- Return exit code 1 for unknown cursor subcommands (was 0)
- Simplify exit handler dead code branch (else if code !== null → else)
2026-02-12 07:17:03 +07:00
Tam Nhu Tran 7d4e6d6b65 fix(cursor): add resolve guard, port validation, and daemon tests
- Add double-resolve guard in startDaemon with safeResolve wrapper
- Add port validation (1-65535) before Node.js script interpolation
- Fix misleading comment in stopDaemon (no PID file handling)
- Add getDaemonStatus test for no daemon running case
- Add stopDaemon tests for graceful non-existent PID handling
2026-02-12 04:27:35 +07:00
Tam Nhu Tran afb5e746b3 fix(cursor): address remaining PR #527 review feedback
- Add SIGKILL escalation in stopDaemon after SIGTERM timeout
- Document router difference between cursor/copilot help behavior
- Fix detectProvider to handle o1/o4 models via regex pattern
- Add fetchModelsFromDaemon fallback test for unreachable daemon
- Update CLAUDE.md help table with cursor command entry
2026-02-12 04:14:28 +07:00
Tam Nhu Tran 9f9db7dcea fix(cursor): save credentials after auto-detect and fix signal hang
- handleAuth() now calls saveCredentials() after successful auto-detect
- Handle code === null (signal kill) in daemon exit handler to prevent
  promise from hanging indefinitely
- Remove unnecessary await on synchronous functions
2026-02-12 04:11:31 +07:00
Tam Nhu Tran 9f0ea25448 fix(cursor): address PR #527 review feedback
- Wire cursor command into main router (ccs.ts) following copilot pattern
- Centralize default port (4242) and model (gpt-4.1) as constants
- Remove duplicate types already in cursor-protobuf-schema from dev
- Handle daemon exit code 0 before health check succeeds
- Export PID helpers and model utils for testability
- Add unit tests for cursor-daemon (PID file ops, isDaemonRunning)
- Add unit tests for cursor-models (detectProvider, formatModelName, defaults)
2026-02-12 04:03:01 +07:00
Tam Nhu Tran 83894f43c6 Merge remote-tracking branch 'origin/dev' into kai/feat/520-cursor-daemon-cli
# Conflicts:
#	src/cursor/cursor-auth.ts
#	src/cursor/cursor-executor.ts
#	src/cursor/cursor-protobuf-decoder.ts
#	src/cursor/cursor-protobuf-encoder.ts
#	src/cursor/cursor-protobuf-schema.ts
#	src/cursor/cursor-protobuf.ts
#	src/cursor/cursor-translator.ts
#	src/cursor/types.ts
2026-02-12 03:55:01 +07:00
Kai (Tam Nhu) TranandGitHub 5df2965642 Merge pull request #525 from kaitranntt/kai/feat/518-cursor-protobuf-executor
feat(cursor): add ConnectRPC protobuf encoder/decoder and HTTP/2 executor
2026-02-12 03:48:23 +07:00
Tam Nhu Tran 79ba1de4e2 fix(cursor): tighten rate limit detection string matching
Use specific patterns ('rate limit', 'resource_exhausted', 'too many
requests') instead of broad 'rate' or 'limit' substrings that would
false-positive on unrelated errors like 'character limit exceeded'.
2026-02-12 03:38:31 +07:00
Tam Nhu Tran c5e8241393 fix(cursor): address fourth-round review feedback for protobuf module 2026-02-12 03:27:58 +07:00
Tam Nhu Tran 66a93ee46f fix(cursor): address third-round review feedback for protobuf module
HIGH PRIORITY FIXES:
- Extract shared buffer parsing logic into parseProtobufFrames generator
  method (DRY violation fix) - both JSON and SSE transformers now use
  common frame parsing loop, eliminating ~60% code duplication
- Use COMPRESS_FLAG constants instead of hardcoded 0x01/0x02/0x03 in
  parseConnectRPCFrame for better maintainability

MEDIUM PRIORITY FIXES:
- Return empty buffer on gzip decompression failure (prevents silent
  data corruption) - ALREADY FIXED
- Add debug warning for unknown message roles in convertMessages
- Create GitHub issue #535 for FIELD namespace refactoring follow-up
- Add test coverage: transformProtobufToSSE, error paths, unknown roles

LOW PRIORITY FIXES:
- Rename checksum test to clarify timestamp granularity (~16 min)
- Fix debug log function name in SSE transformer - FIXED BY REFACTOR
- Add comment to TOOL_RESULT_RESULT field documenting future use

All tests pass (1593 pass, 0 fail)
All validation checks pass (typecheck + lint + format + tests)
2026-02-12 03:15:24 +07:00
Tam Nhu Tran a8a68c9599 fix(cursor): address third-round review feedback for auth module 2026-02-12 03:09:35 +07:00
Tam Nhu Tran e177a4b097 fix(cursor): address second-round review feedback for protobuf module
HIGH Priority:
- Add comprehensive unit tests (27 tests covering encoder, decoder, translator, executor)
  * encodeVarint/decodeVarint round-trip (0, 1, 127, 128, 16383, 0xFFFFFFFF)
  * encodeField/decodeField round-trip (VARINT, LEN string, LEN binary)
  * wrapConnectRPCFrame/parseConnectRPCFrame (compressed/uncompressed)
  * buildCursorRequest message translation (system, user, assistant, tool)
  * generateChecksum header format validation
  * buildHeaders output validation
  * transformProtobufToJSON basic conversion
- Create GitHub issue #531 for true streaming implementation
- Update TODO comment to reference issue #531

MEDIUM Priority:
- Export CursorCredentials from cursor-protobuf-schema.ts
- Add JSDoc grouping comments to FIELD constant for clarity
- Make hardcoded values configurable (CURSOR_CLIENT_VERSION, CURSOR_USER_AGENT)
- Add debug logging to 9 silent catch blocks (respects CCS_DEBUG env var)
- Fix stream check: stream !== false → stream === true

Bug Fixes:
- Fix decodeVarint to return unsigned values (>>> 0)
- Fix test assertion for Response.text() async API
2026-02-12 01:26:47 +07:00
Tam Nhu Tran 84a256d0ac fix(cursor): address second-round review feedback for auth module
- Add comprehensive unit tests for cursor-auth.test.ts
  - validateToken: valid/invalid tokens, short tokens, UUID formats, empty strings
  - extractUserInfo: JWT parsing, email handling, non-JWT tokens, malformed base64
  - saveCredentials/loadCredentials: round-trip, invalid JSON/types, missing fields
  - checkAuthStatus: authenticated/not authenticated, expired tokens, JWT exp, invalid dates
  - deleteCredentials: delete existing/non-existent files, multiple deletes
  - All tests use CCS_HOME env var for isolation, real file I/O, no mocks

- Fix dead try-catch around new Date() in checkAuthStatus()
  - Replace try-catch with isNaN check (new Date('garbage') returns Invalid Date, not throw)
  - Properly handle Invalid Date by checking isNaN(getTime())

- Fix email populated with sub claim in extractUserInfo()
  - Change email: decoded.email || decoded.sub to email: decoded.email || undefined
  - Prevent non-email values (UUIDs) from populating email field

- Add type guards for JSON.parse result in extractUserInfo()
  - Cast to Record<string, unknown> and validate types
  - Use typeof checks for email, userId, exp fields
2026-02-12 01:23:29 +07:00
Tam Nhu Tran b412ba2a9e fix(cursor): address remaining review items in auth module
- Enhanced extractUserInfo to return JWT exp claim for expiry detection
- Updated checkAuthStatus to use JWT exp when available, fallback to importedAt heuristic
- Added typeof validation for loadCredentials fields
- Added ENOENT detection for sqlite3 availability in queryStateDb
- Added deleteCredentials function for cleanup
- Updated PR #526 description to remove refreshToken mention
2026-02-12 01:07:25 +07:00
Tam Nhu Tran f3d532afd9 fix(cursor): address remaining LOW review items in protobuf module 2026-02-12 01:06:33 +07:00
Tam Nhu Tran 7e4f08004c fix(cursor): address code review feedback on auth module
- Sanitize SQL key parameter in queryStateDb to prevent injection
- Fix UUID regex: use exact {32} length, remove redundant hyphen from
  stripped character class
- Remove unused types from types.ts (YAGNI): CursorDaemonStatus,
  CursorModel, MessageRole, CursorMessage, CursorToolCall,
  CursorToolResult, ProtobufExtractResult — belong in their respective
  module PRs
2026-02-11 19:31:04 +07:00
Tam Nhu Tran 31f574118d fix(cursor): address code review feedback (attempt 1/5)
- Fix bitwise shift overflow in generateChecksum: use Math.trunc
  division for >>40/>>32 which wrap modulo 32 in JS
- Add FIXED64/FIXED32 bounds checks in protobuf decoder to prevent
  out-of-bounds slice on truncated buffers
- Consolidate COMPRESS_FLAG to single definition in schema (DRY):
  executor now imports from schema, added GZIP_ALT/GZIP_BOTH values
- Fix token split edge case: use indexOf+slice instead of split('::')[1]
  to handle tokens containing multiple :: delimiters
- Fix AbortSignal listener leak: store handler ref, use once:true,
  remove listener on request end/error
2026-02-11 19:27:39 +07:00
Tam Nhu Tran cc5a9039e4 fix(cursor): address code review edge cases in protobuf and executor
CRITICAL FIX:
- CursorCredentials interface now matches types.ts (machineId, ghostMode as top-level)
- Fixes runtime error when cursor-auth saves credentials and cursor-executor reads them

HIGH:
- Replace 18+ non-null assertions with guard clauses across executor and decoder
- Prefix unused params in translator (_model, _stream, _credentials)
- HTTP/2 client closes on connection error to prevent leak
- AbortSignal listener leak documented with TODO (inline arrow prevents cleanup)

MEDIUM:
- Export concatArrays from encoder, remove duplicate from protobuf.ts
- Varint decoder now enforces 5-byte max to prevent overflow
- Buffer slice bounds check prevents out-of-range read
- Empty messages array validation with explicit error
- Buffered streaming limitation documented with TODO comment

All edge cases from code review now addressed.
2026-02-11 19:13:58 +07:00
Tam Nhu Tran fe97d720d4 fix(cursor): fix test isolation and daemon exit handling
- Convert PID_FILE constant to getPidFilePath() function to respect CCS_HOME changes at runtime
- Add proc.on('exit') handler to clear interval on silent process crashes
- Ensures test isolation by computing paths dynamically
2026-02-11 19:06:59 +07:00
Tam Nhu Tran aeb580281f fix(cursor): harden auth security and add token expiry warning 2026-02-11 19:06:57 +07:00
Tam Nhu Tran aaa31c6427 feat(cursor): add daemon lifecycle, models catalog, and CLI commands
Implements #520 - Cursor IDE daemon, models catalog, module index, and CLI.

Files created:
- src/cursor/cursor-daemon.ts (~230 LOC) - Lifecycle management (start/stop/status)
- src/cursor/cursor-models.ts (~145 LOC) - Model catalog with Anthropic/OpenAI/Google/Cursor models
- src/cursor/index.ts (~30 LOC) - Module barrel exports
- src/commands/cursor-command.ts (~230 LOC) - CLI commands (auth/status/models/start/stop)

Key features:
- Daemon health checks via HTTP /health endpoint
- PID file management in ~/.ccs/cursor/daemon.pid
- Model catalog with fetchModelsFromDaemon() and fallback defaults
- CLI subcommand routing following copilot-command.ts pattern
- ASCII-only output ([OK], [X], [i] markers)

Temporary defaults for config (port: 4242, model: gpt-4.1) until #521 adds
cursor to unified config schema.

Note: Actual daemon server implementation (CursorExecutor integration) deferred
to #522 - this creates the lifecycle structure only.
2026-02-11 18:06:46 +07:00
Tam Nhu Tran 75095bde1b chore: merge cursor core (#518) and auth (#519) as base for daemon+CLI 2026-02-11 18:01:20 +07:00
Tam Nhu Tran 9daf9430bb feat(cursor): add core protobuf encoder/decoder and executor
- Split protobuf into 3 files: schema, encoder, decoder for <200 LOC constraint
- Implement ConnectRPC wire format encoding (varint, fields, messages, frames)
- Implement protobuf decoder with gzip decompression support
- Port Cursor executor with HTTP/2 support and checksum generation (Jyh cipher)
- Add OpenAI to Cursor message translator (system→user, tool results handling)
- Transform protobuf responses to both SSE and JSON formats
- Use Node.js built-in crypto/zlib (no uuid dependency)
- All files TypeScript strict mode compliant
2026-02-11 17:59:44 +07:00
Tam Nhu Tran 56270d99f3 feat(cursor): add auth module with SQLite auto-detect and types
- Add CursorCredentials, CursorAuthStatus, and related types
- Implement autoDetectTokens() using sqlite3 CLI (no native deps)
- Add validateToken() for token format validation
- Add extractUserInfo() for JWT decoding
- Add saveCredentials/loadCredentials using getCcsDir()
- Add checkAuthStatus() for auth verification
- Platform-specific state.vscdb paths (Linux/macOS/Windows)
- Graceful error handling for missing database/tokens

Refs: #519 (sub-task of #517)
2026-02-11 17:55:15 +07:00