Commit Graph
155 Commits
Author SHA1 Message Date
Tam Nhu Tran 3aab14ca85 fix(bar): correct the already-running reinstall hint
'open -a' only activates a running app, so suggesting 'ccs bar' as an
alternative to quitting could not load the new binary. The hint now
says to quit from the menu bar first, then run 'ccs bar' to relaunch
the updated app.
2026-06-10 15:25:55 -04:00
Tam Nhu Tran cf3bd8a5ef fix(bar): stage downloads and swap so reinstall never strands the user
The reinstall guard deleted the existing bundle before download, so a
transient download or extraction failure left no app on disk. The
archive now extracts into a hidden staging directory inside the
Applications folder; the old bundle is removed only after the new one
is verified in staging, then renamed into place. Every failure before
the swap leaves the previous install untouched, and staging is cleaned
up on all paths.
2026-06-10 14:09:28 -04:00
Tam Nhu Tran f68c08ede3 fix(bar): verify server compat before Gatekeeper steps and harden reinstall
Three review/CI corrections to the install flow:

The compat handshake now runs before the quarantine-clear and launch
block. It is a server-side check unrelated to Gatekeeper, and the
previous ordering let a failed quarantine clear (always the case where
xattr is absent, e.g. Linux CI) skip the handshake entirely.

Reinstalls remove the existing bundle before extraction so the
post-extraction existence check actually proves the fresh bundle
landed; an unremovable bundle aborts install instead of extracting
over it.

Declining the launch prompt now prints the same run-ccs-bar hint as
the non-TTY path instead of ending silently. Install tests inject the
newer deps (clearQuarantine, isBarRunning, promptLaunch) everywhere
the defaults could touch host binaries, keeping results identical on
macOS and Linux runners.
2026-06-10 13:59:08 -04:00
Tam Nhu Tran 015cc4dd32 fix(bar): stop install at the manual step when quarantine clearing fails
A failed quarantine clear previously fell through to the launch
handoff, so a default-yes prompt (or --launch) opened the still
quarantined app straight into the Gatekeeper block. Install now ends
after printing the manual xattr guidance, with a hint to run 'ccs bar'
once quarantine is cleared; --launch does not override a failed clear.
2026-06-10 13:42:52 -04:00
Tam Nhu Tran dfc8b7d1dc fix(bar): harden install handoff per review
Pin xattr and pgrep to absolute /usr/bin paths so quarantine clearing
and process detection cannot be hijacked through a caller-controlled
PATH. Gate the launch prompt on stdin being a TTY instead of stdout, so
piping install output through tee no longer silently skips the
handoff. Detect an already-running CCS Bar via pgrep before prompting:
a running instance gets a quit-and-reopen hint instead of a redundant
launch prompt, while --launch still proceeds explicitly.
2026-06-10 13:36:35 -04:00
Tam Nhu Tran 4eef3f77a4 feat(bar): one-flow install with quarantine automation and launch handoff
'ccs bar install' previously ended with two manual steps: clearing the
Gatekeeper quarantine by hand and running 'ccs bar' separately.

Install now detects an existing installation and says so before
reinstalling, clears the quarantine attribute itself via execFile with
a graceful fallback to the printed hint when xattr fails, and ends with
a TTY-aware 'Launch CCS Bar now?' prompt (default yes) that hands off
to the existing launch flow. --launch forces the handoff and
--no-launch suppresses it for scripted installs; non-TTY runs skip the
prompt and print the manual command instead.

Closes #1504
2026-06-10 13:25:07 -04:00
Tam Nhu Tran 2fd90fff9b perf(bar): probe reuse candidates concurrently to avoid launch stalls
Sequential probing of up to 10 loopback targets at 1.5s timeout each
could stall 'ccs bar' for ~15s when a non-CCS service occupied a
candidate port without answering. All probes now run concurrently and
the first success in priority order (bar.json port first, IPv4 before
IPv6 per port) is selected, bounding detection at roughly one probe
timeout.
2026-06-10 12:57:39 -04:00
Tam Nhu Tran 3569297b6d fix(bar): probe IPv6 loopback when detecting a running CCS server
'ccs config' starts the web-server on host 'localhost', which macOS
resolves to ::1, so a reuse probe limited to 127.0.0.1 missed the most
common already-running server and launch started a redundant second
instance. Each candidate port is now probed on 127.0.0.1 first and then
[::1]; an IPv6 hit writes the bracketed-literal baseUrl into bar.json,
which URLSession in the Swift app resolves correctly.
2026-06-10 12:04:10 -04:00
Tam Nhu Tran af1a2a0f5d fix(bar): reuse a running CCS web-server and probe ports on the bind host
'ccs bar' always tried to start its own web-server. With a CCS server
already listening on 127.0.0.1:3000, get-port (probing the unspecified
address, which macOS allows to bind alongside a specific loopback
listener) reported 3000 as free, and the subsequent 127.0.0.1 bind
failed with EADDRINUSE, aborting launch.

Launch now probes candidate ports (bar.json port first, then the
default list) with a short-timeout GET /api/bar/summary and reuses the
first live CCS server it finds; only when none responds does it start a
new server. The get-port probe also passes host 127.0.0.1 so the
availability check matches the actual bind target. Probe failures are
treated as no-server-found and never break launch.

Closes #1500
2026-06-10 11:09:41 -04:00
Tam Nhu Tran c572d9f860 fix(bar): read app version from Info.plist and verify bar API instead of version majors
The floating ccs-bar-latest release tag carries no version, so deriving the
app version from tag_name printed 'vccs-bar-latest' and pinned that literal
string. The version now comes from CFBundleShortVersionString in the
extracted bundle's Info.plist; an unreadable plist skips pinning and clears
any stale pin.

The post-install check compared app semver major against the CCS server
major, but the app is versioned independently of the CLI, so the mismatch
warning fired on every install. It is now a capability handshake against
GET /api/bar/summary: 200 confirms the server serves the bar API, 404 warns
the server predates CCS Bar, and anything else keeps the soft warning.
Install never hard-fails on the handshake.

Closes #1497
2026-06-10 00:11:29 -04:00
Tam Nhu Tran 7d3a11a452 fix(bar): resolve pre-dev review findings (security gate, honesty, correctness)
Gate /api/bar/* behind the localhost-when-auth-disabled guard (single DRY
choke point) so native quota/tier/cost can't leak on a non-loopback bind with
auth disabled; add a guard test. Delete the dishonest maxRedirections test that
asserted the opposite of the production redirect hardening. Key per-account
today-cost on the local day (matching analytics) instead of UTC. Stop the
inner 429 retry in the Claude usage fetch so the outer cache + circuit breaker
honor Retry-After. Narrow the usage-transformer map type and fix stale
doc-comments; clarify the one-alert-per-reset-window quota rule; gitignore the
local demo scaffolding.
2026-06-09 18:04:31 -04:00
Tam Nhu Tran 63d10cb2d0 fix(cli): harden ccs bar install + align launch path
Resolve the app path via os.homedir() in launch to match install/uninstall;
validate the host on every redirect hop (manual follow, not blind
maxRedirections); reject zip-slip entries before extracting into ~/Applications.
2026-06-07 16:38:08 -04:00
Tam Nhu Tran 205c2f3cd6 feat(cli): add ccs bar command for the macOS menu bar app
Add ccs bar (install/launch/uninstall/version) and the ~/.ccs/bar.json
discovery handshake the app reads. install resolves a floating release asset,
follows redirects, validates the download host over HTTPS, checks status,
verifies the extracted app, and runs a real version-compat handshake against
/api/overview.
2026-06-07 15:32:51 -04:00
Kai (Tam Nhu) TranandGitHub dce968fdf7 Merge pull request #1425 from kaitranntt/codex/fix-unvalidated-codex-quota-labels
fix(cliproxy): sanitize Codex quota labels
2026-05-30 16:12:22 -04:00
Kai (Tam Nhu) TranandGitHub e2d487883f Merge pull request #1430 from kaitranntt/codex/fix-vulnerability-in-shell-completion-scripts
fix: avoid relative completion backend execution
2026-05-30 16:12:15 -04:00
Kai (Tam Nhu) TranandGitHub e7db1d65f5 Merge pull request #1452 from kaitranntt/codex/propose-fix-for-codex-target-rejection
Mark Codex as a persisted target and align UI/validation
2026-05-30 16:12:03 -04:00
Kai (Tam Nhu) TranandGitHub 41e550e92f Merge pull request #1428 from kaitranntt/codex/propose-fix-for-symlinked-cleanup-issue
fix: reject symlinked cleanup directories
2026-05-30 16:05:05 -04:00
Kai (Tam Nhu) TranandGitHub 93756489a5 Merge pull request #1434 from kaitranntt/codex/fix-unbounded-recursion-in-receipt-generation
fix(persist): bound Codex translator receipt scan
2026-05-30 15:46:29 -04:00
Tam Nhu Tran f93cb36da6 fix: surface cleanup directory read errors 2026-05-30 15:40:31 -04:00
Tam Nhu Tran a0870aa404 fix(cliproxy): fall back from invalid Codex feature labels 2026-05-30 15:38:50 -04:00
Kai (Tam Nhu) TranandGitHub f815db391d Merge pull request #1308 from simonsmh/feat/add-qoder-provider
feat(cliproxy): Qoder provider
2026-05-30 15:35:55 -04:00
Kai (Tam Nhu) TranandTam Nhu Tran 5da6334736 fix(persist): bound Codex translator receipt scan 2026-05-30 15:20:22 -04:00
Kai (Tam Nhu) TranandTam Nhu Tran 4f2dd70b8c fix: avoid relative completion backend execution 2026-05-30 15:19:59 -04:00
Kai (Tam Nhu) Tran 04dc97aaa4 fix: persist codex target selections 2026-05-30 14:57:07 -04:00
Kai (Tam Nhu) Tran 920fba7e13 fix: reject symlinked cleanup directories 2026-05-30 14:53:59 -04:00
Kai (Tam Nhu) Tran 457412277b fix(cliproxy): sanitize Codex quota labels 2026-05-30 14:53:53 -04:00
Kai (Tam Nhu) TranandGitHub 88fbac3a32 fix(channels): avoid secrets in --set-token argv (#1389) 2026-05-23 22:37:55 -04:00
Tam Nhu Tran bbcf9e8b15 fix: mask Docker key rotation banner 2026-05-22 17:04:19 -04:00
Tam Nhu Tran 30971ebb28 fix: preserve Docker legacy API key during rotation 2026-05-22 16:49:16 -04:00
Tam Nhu Tran 3dc1810540 feat: report permission mode persist receipt status 2026-05-22 11:14:17 -04:00
Simon Shi 43c830469a feat(cliproxy): add Qoder as a CLIProxy provider channel
Add Qoder AI coding assistant as a supported CLIProxy provider:
- Device code OAuth flow with --qoder-login flag
- Plus-only backend (CLIProxyAPIPlus required)
- No built-in token refresh (unsupported, like Kilo)
- Auth URL: https://qoder.com/device/selectAccounts
- Auth file prefix: qoder-
- Token type: qoder
2026-05-21 01:35:08 +09:00
Kai (Tam Nhu) TranandGitHub 67fe6d9c7f fix(persist): print recovery receipt after settings write (#1302) 2026-05-19 15:23:37 -04:00
Kai (Tam Nhu) TranandGitHub 3b2016462a fix(persist): block codex claude settings bridge 2026-05-19 07:32:04 -04:00
Kai (Tam Nhu) TranandGitHub d61469edcb fix(config): bind dashboard to loopback by default 2026-05-12 10:59:49 -04:00
Kai (Tam Nhu) TranandGitHub 248b6b735d Merge pull request #1200 from kaitranntt/kai/feat/1199-shared-resource-controls
feat(auth): add shared resource controls
2026-05-10 22:01:57 -04:00
Tam Nhu Tran 9d0690e1a8 test(ci): make routing mock complete and websearch trace path env-robust
Two pre-existing test bugs surfaced under CCS CI on the new claw self-
hosted runners but stayed hidden locally:

1. tests/unit/commands/cliproxy-routing-subcommand.test.ts mocks the
   routing-subcommand module with only 3 exports, but
   src/commands/cliproxy/index.ts statically imports 6. Bun resolves
   the static import graph against the mock and reports
     SyntaxError: Export named 'handleRoutingAffinitySet' not found
   for every test in the file. Add the missing 3 exports
   (handleRoutingAffinityStatus, handleRoutingAffinityHelp,
   handleRoutingAffinitySet) to the mock and document why the mock
   must mirror every named export of the target module.

2. tests/unit/hooks/websearch-transformer.test.ts builds the
   "disallowed" trace path from process.cwd() and from os.homedir().
   Both fall under the os.tmpdir() safe-prefix in two real
   environments: CI runners with cwd == /tmp/runner/work/... and Bun
   test isolation that re-roots HOME under tmpdir. The hook treats
   them as safe, writes the trace, and the assertion that the file
   does NOT exist fails. Anchor disallowedTracePath under /etc/...
   instead so it cannot satisfy the tmpdir, /var/log, or
   <CCS_HOME>/.ccs/logs prefixes in any host environment.

Both fixes are independent of the OAuth callback traceability change
that this branch otherwise carries, but ship together so the PR
clears CI on the new runner stack.
2026-05-10 20:23:02 -04:00
Tam Nhu Tran 64e1d1f815 feat(auth): add shared resource controls 2026-05-08 11:15:28 -04:00
Tam Nhu Tran a7c10be72e Merge origin/dev into fix/cliproxy-local-port-config
Resolve the dispatcher and dashboard conflicts from origin/dev while preserving the configured local CLIProxy port behavior. Also harden lifecycle port fallback and wait for the actual stopped port during binary installs.
2026-05-03 13:56:43 -04:00
MolkoandClaude Opus 4.7 509bd5dbef fix(cliproxy): respect configured local port instead of hardcoding 8317
All call sites that spawn or probe CLIProxyApiPlus now read
cliproxy_server.local.port from config via resolveLifecyclePort()
instead of using the hardcoded CLIPROXY_DEFAULT_PORT constant.

- Move resolveLifecyclePort helper to src/cliproxy/config/port-manager.ts
- Fix 7 call sites: ccs.ts, config-command.ts, copilot-executor.ts,
  lifecycle.ts, binary-manager.ts, cliproxy-stats-routes.ts,
  cliproxy-local-proxy.ts
- Remove duplicate resolveLocalCliproxyPort helper
- Cache port resolution in /proxy-status handler to avoid repeated I/O

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-03 07:40:48 -04:00
Tam Nhu Tran e5fe86f520 feat: add native Claude effort override 2026-04-30 22:36:47 -04:00
Tam Nhu Tran 1c72b4b8d5 refactor(cliproxy): flatten module structure and colocate tests (#1135)
- Split types.ts (331 LOC) into 4 concern-based files under types/:
  platform-types, binary-types, provider-types, config-types
- Preserve backward compat via barrel re-export (types.ts → types/index)
- Reorganize 53 root-level files into 8 subdirectories:
  accounts/, ai-providers/, auth/, binary/, config/, executor/,
  management/, proxy/, quota/, routing/, services/, sync/
- Reduce src/cliproxy/ root from 65 to 8 files (target: ≤10)
- Colocate 87 unit tests from tests/unit/cliproxy/ into
  src/cliproxy/*/__tests__/ (13 colocated test directories)
- Update import paths across 40+ consumer files
- Add TDD backward-compat test for types split

Refs #1135
2026-04-29 17:06:39 -04:00
Kai (Tam Nhu) TranandGitHub a8e0d95bc8 Merge pull request #1117 from kaitranntt/kai/feat/1115-session-affinity
feat: add local CLIProxy session affinity controls
2026-04-28 13:37:37 -04:00
Tam Nhu Tran c277955762 fix(cliproxy): tighten session affinity review issues 2026-04-28 12:33:12 -04:00
Tam Nhu Tran 119aa3be98 fix: keep config dashboard alive when interface detection fails 2026-04-28 11:39:40 -04:00
Tam Nhu Tran 7f14c565df test: cover --extra-models parsing and CLIProxy sync dedup 2026-04-25 11:30:44 -04:00
Tam Nhu Tran b3bc17639c fix(ui): surface the max thinking level in settings and help 2026-04-22 21:43:32 -04:00
Tam Nhu Tran 6604357b22 fix(browser): default browser tooling to manual opt-in 2026-04-20 21:15:31 -04:00
Tam Nhu Tran 039ed63a39 fix(browser): harden runtime policy edge cases 2026-04-20 21:01:19 -04:00
Tam Nhu Tran 7d02f55f9f feat(browser): add explicit runtime policy controls 2026-04-20 21:01:19 -04:00
Wooseong Kim 6928d8bb65 fix(proxy): parse flag options before profile args 2026-04-20 15:44:20 +09:00