Commit Graph
4392 Commits
Author SHA1 Message Date
Tam Nhu Tran 7b8a6f5cce fix(cliproxy): close second-round review gaps in pool onboarding and remote env
- create-command: show the pool onboarding hint only after profile
  creation fully succeeds; the pre-create placement burned the
  once-per-install dismissal when creation failed or rolled back
- remote env (claude): skip the read-level stale-pin filter once the
  migration marker exists - a post-migration pin is user-intentional
  (e.g. an explicit --config pick equal to a historical default)
- unified-config loader: document that loadOrCreateUnifiedConfig never
  writes to disk, so read paths on legacy installs stay side-effect free
2026-06-11 19:32:51 -04:00
Tam Nhu Tran cff9008f49 fix(cliproxy): silence legacy-config skip in pool opt-in prompt
Legacy profiles.json-only installs get pool guidance exclusively from
ccs doctor (once-per-install semantics); printing a migrate notice on
every account add nagged with no dismissal available. Also document why
type === 'account' profiles are Claude by schema in the onboarding
counter, so the filter is not misread as over-counting.
2026-06-11 19:03:56 -04:00
Tam Nhu Tran 1c90388b5d fix(cliproxy): harden account pools per pre-merge usefulness review
- pool --enable/--disable: refuse remote targets with manual config
  guidance; resolve the lifecycle port instead of assuming 8317
- enablePoolRouting: roll back the pool flag when config regeneration
  fails; already-enabled path re-runs regeneration (repairable state)
- pool opt-in prompt: gate on hasUnifiedConfig (legacy installs skip);
  never auto-accept consent under --yes/CCS_YES
- order show (file mode): render selector pick order incl. residual
  on-disk priorities and surface drift instead of alphabetical order
- order --reset: clear residual priority fields via management-API
  PATCH when proxy runs, atomic direct write when stopped
- quota pool section: classify in-proxy 429 cooldowns as cooling with
  reset times (graceful degradation when proxy or endpoint is absent);
  honest paused label plus resume hint
- routing state: remote targets report pool as not manageable instead
  of echoing the local flag; strategy/affinity apply warns when pool
  routing overrides the change (CLI, API message, and dashboard)
- claude model-neutral: --config explicit pins survive the stale-pin
  migration; remote env path filters historical default pins read from
  claude.settings.json without mutating the file
- cross-lane guard: also checks account-profile CLAUDE_CONFIG_DIR lanes
  for email overlap, not only the ambient ~/.claude login
- onboarding hint: opt-in copy naming ccs cliproxy pool --enable
- dashboard card: pool-ON shows drain-order pointer, pool-OFF shows the
  enable command, local-only note for remote proxies (i18n x5)
2026-06-11 18:50:12 -04:00
Tam Nhu Tran 2b7cfa32c8 ci: drop temporary epic branch from PR trigger
All phase PRs targeting kai/feat/1464-account-pools have merged; the
extra trigger entry is no longer needed and dev should not inherit it.
2026-06-11 16:44:06 -04:00
Kai (Tam Nhu) TranandGitHub be8d4e3922 Merge pull request #1513 from kaitranntt/kai/feat/1464-pool-visibility
feat(cliproxy): pool visibility (phase 6 of #1464)
2026-06-11 13:15:15 -04:00
Tam Nhu Tran 74894f61da feat(cliproxy): pool visibility in quota output and dashboard routing card
- ccs cliproxy quota: per-provider Pool context section with routing
  mode (pool on/off, strategy, affinity, effective retry cap), drain
  order resolved exactly as the selector picks (incl. residual on-disk
  priorities reordering display + drift warning), and per-account state
  named distinctly: available / cooling-until-<time> / paused - these
  produce different client errors so they read differently
- cooling visibility degrades honestly when pool cooling is disabled
  (no cooldown data exists; renderer says so)
- dashboard routing card: pool badge + retry cap + drain-order hint in
  compact and full variants via additive poolRouting state block
- no Bar summary fields, no per-session pin introspection (cut per
  plan); policy_quota_unsupported semantics untouched

Part of #1464 account pools (phase 6).
2026-06-11 13:10:31 -04:00
Kai (Tam Nhu) TranandGitHub e5cb1e6379 Merge pull request #1512 from kaitranntt/kai/feat/1464-onboarding-hints
feat(cliproxy): pool onboarding hints + credential-import verdict (phase 5 of #1464)
2026-06-11 12:16:11 -04:00
Kai (Tam Nhu) TranandGitHub 2bb7c43ace Merge pull request #1511 from kaitranntt/kai/feat/1464-drain-order
feat(cliproxy): managed drain order (phase 4 of #1464)
2026-06-11 12:16:08 -04:00
Tam Nhu Tran 0343734665 feat(cliproxy): pool onboarding hints for existing multi-profile users
- ccs doctor, native account launch, and ccs auth create now surface a
  one-line pool suggestion when >=2 native Claude profiles exist and no
  pool is enabled; shared once-per-install dismissal; TTY-gated; hint
  failures can never break a launch (guarded, single config read)
- credential import from native profiles evaluated and REJECTED:
  refresh tokens are client_id-bound and not replayable cross-client;
  pool setup requires fresh OAuth per account (verdict report in plan)

Part of #1464 account pools (phase 5).
2026-06-11 12:09:53 -04:00
Tam Nhu Tran a33e12619e feat(cliproxy): managed drain order for account pools
- ccs cliproxy accounts order <provider>: show effective drain order
  exactly as the selector resolves it (priority bucket desc, then
  file-name tie-break, Windows-only case folding to match upstream)
- --by-tier derives priorities from tier metadata where present;
  claude pools state tier-unknown and fall back to file order
- --set for manual order; duplicate IDs rejected; priority always >= 1
- dual write path: management-API PATCH when proxy running (avoids
  MarkResult persist clobber), atomic direct write when stopped
- drift warning when stored order no longer matches auth files;
  usage-attribution stability covered by regression test

Part of #1464 account pools (phase 4).
2026-06-11 12:09:42 -04:00
Kai (Tam Nhu) TranandGitHub 0f0e709b4f Merge pull request #1510 from kaitranntt/kai/feat/1464-pool-routing-rails
feat(cliproxy): pool routing defaults and safety rails (phase 3 of #1464)
2026-06-11 00:23:30 -04:00
Tam Nhu Tran 22d4c72717 test(ci): allow temporary epic branch in PR trigger assertion
The ci-workflow meta-test pinned the literal branch list [main, dev];
the account-pools epic adds its integration branch to pull_request
triggers so phase PRs get full CI. Assert main+dev coverage via
pattern instead of exact list.
2026-06-11 00:18:00 -04:00
Tam Nhu Tran fdb043083f feat(cliproxy): pool routing defaults and safety rails
- pool opt-in writes disable-cooling: false, routing.strategy fill-first,
  session-affinity on (1h TTL), max-retry-credentials 3; all emissions
  pool-gated so non-pool generated config stays content-identical
- cooling re-enable is safe on current CLIProxy binaries: the v5
  disable-cooling workaround targeted upstream cooldown bugs fixed by
  Apr 2026 (see plan archaeology report)
- informed-consent prompt at the 1->2 account-add transition enumerates
  every provider with multiple accounts (instance-global effect) and is
  gated per provider on spike-verified limit signals
- disablePoolRouting restores the non-pool config including
  disable-cooling: true and prints single-account rollback guidance
- cross-lane guard warns when a pool account email is also active in a
  native Claude profile (concurrency is the documented ban vector)
- routing strategy and affinity subcommands warn when pool routing
  manages those keys

Part of #1464 account pools (phase 3).
2026-06-11 00:12:14 -04:00
Kai (Tam Nhu) TranandGitHub 9b05481661 Merge pull request #1509 from kaitranntt/kai/feat/1464-claude-pool-gap-closure
feat(cliproxy): claude pool gap closure (phase 2 of #1464 account pools)
2026-06-10 23:14:33 -04:00
Tam Nhu Tran 5101e21ecd ci: run PR CI for account-pools epic branch
Phase PRs target kai/feat/1464-account-pools instead of dev; without
this the full CI matrix never runs on them. Revisit at the final
epic-to-dev promotion PR.
2026-06-10 23:10:55 -04:00
Tam Nhu Tran a257016ebb feat(cliproxy): claude pool gap closure - model-neutral launch, shadow warning, provider ban copy
- claude provider launch env no longer pins ANTHROPIC_MODEL/tier defaults;
  one-shot migration strips CCS-written stale pins across all historically
  shipped default generations while preserving explicit user pins
- TTY-gated once-per-install warning when a user profile named claude or
  anthropic is shadowed by the built-in provider, with rename guidance
- account-safety ban messaging parameterized by provider; Anthropic
  patterns gated to claude accounts only
- first-run notice that ccs claude routes through the local CLIProxy
  instance

Part of #1464 account pools (phase 2).
2026-06-10 22:57:24 -04:00
github-actions[bot] 17849c4a32 chore(release): 8.2.0-dev.7 2026-06-10 19:50:44 +00:00
Kai (Tam Nhu) TranandGitHub 27580bc159 Merge pull request #1508 from kaitranntt/kai/feat/bar-header-version
feat(bar): show app version in the panel header
2026-06-10 15:42:54 -04:00
Tam Nhu Tran a5c41864b3 fix(bar): keep header version label rightmost during refresh
The refresh spinner rendered after the version label, pushing the
version away from the header edge while a refresh was in progress. The
spinner now sits between the Spacer and the version label.
2026-06-10 15:33:06 -04:00
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 3438c3940e feat(bar): show running app version in the panel header
A right-aligned v{CFBundleShortVersionString} label fills the unused
header space next to the CCS name, styled like the subtitle and hidden
when no bundle version is available (e.g. swift run). The display
logic lives in CCSBarCore as a pure helper with ccs-bar-check
coverage, making the on-screen build identifiable after reinstalls.
2026-06-10 15:25:45 -04:00
github-actions[bot] 39ede638d6 chore(release): 8.2.0-dev.6 2026-06-10 19:02:13 +00:00
Kai (Tam Nhu) TranandGitHub 1892503555 Merge pull request #1506 from kaitranntt/kai/feat/1504-bar-install-ux
feat(bar): one-flow install with quarantine automation and launch handoff
2026-06-10 14:58:28 -04:00
Kai (Tam Nhu) TranandGitHub 209f4a023b Merge pull request #1505 from kaitranntt/kai/fix/1502-1503-bar-multiscreen
fix(bar): keep the menu bar panel on the clicked screen in multi-display setups
2026-06-10 14:58:17 -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 54a670c943 fix(bar): capture click location synchronously before async panel anchoring
NSEvent.mouseLocation was sampled inside the DispatchQueue.main.async
block that anchors the panel, so a cursor move between the click and
the block run could anchor to the wrong display. The location is now
captured in makeNSView at click time and threaded through apply() into
anchorToClickedScreen, making the chosen screen deterministic.
2026-06-10 13:28:34 -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 70dc53d947 fix(bar): keep menu bar panel on the clicked screen in multi-display setups
The MenuBarExtra panel's default collectionBehavior included
canJoinAllSpaces, so the bar could be visible on every Space and
display at once. The WindowAppearanceForcer bridge now strips
canJoinAllSpaces and applies moveToActiveSpace.

Panel and Settings window placement also keyed off the key-window
screen (NSScreen.main / window.center()) rather than the display where
the status item was clicked. Both now anchor to the screen under the
cursor at click time via the pure BarScreenPicker helper, covered by
new ccs-bar-check geometry assertions.

Closes #1502
Closes #1503
2026-06-10 13:23:47 -04:00
github-actions[bot] dd82f99046 chore(release): 8.2.0-dev.5 2026-06-10 17:21:08 +00:00
Kai (Tam Nhu) TranandGitHub f743677d5d Merge pull request #1501 from kaitranntt/kai/fix/1500-bar-launch-reuse
fix(bar): reuse a running CCS web-server instead of failing to bind
2026-06-10 13:17:18 -04:00
github-actions[bot] 16e8531568 chore(release): 8.2.0-dev.4 2026-06-10 17:07:50 +00:00
SergeyandGitHub 298c89f2c3 feat(catalog): add Claude Fable 5 to Anthropic model registry 2026-06-10 13:03:38 -04:00
walker1211andGitHub cf90f48240 fix(mcp): retry Claude user config locks 2026-06-10 13:03:25 -04:00
kastrupproandGitHub f59536a81f fix(cliproxy): guard upstream response timeout cleanup against detached socket 2026-06-10 13:03:17 -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 db1d125f83 docs(bar): troubleshooting reflects reuse-first launch behavior 2026-06-10 11:09:51 -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
github-actions[bot] 67d93e6722 chore(release): 8.2.0-dev.3 2026-06-10 04:22:48 +00:00
Kai (Tam Nhu) TranandGitHub 9a3cee3653 Merge pull request #1498 from kaitranntt/kai/fix/1497-bar-install-version
fix(bar): install version from app bundle and bar-API capability handshake
2026-06-10 00:19:04 -04:00
Tam Nhu Tran e7f3ec0da1 docs(bar): align install docs with Info.plist version pinning and bar-API check 2026-06-10 00:11:38 -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 9ae6f85fa7 feat(bar): add ccs bar --help with docker-style help screen
--help and -h are honored anywhere in the args so 'ccs bar install --help'
shows help instead of running the installer. Also wires the 'ccs help bar'
topic, shell-completion flag suggestions, and a more-help table entry.
2026-06-10 00:11:19 -04:00
github-actions[bot] b24c943afc chore(release): 8.2.0-dev.2 2026-06-10 03:15:32 +00:00
Kai (Tam Nhu) TranandGitHub b966ba369a Merge pull request #1495 from kaitranntt/kai/fix/bar-launch-ipv4-bind
fix(bar): real-deployment fixes from normal-user install + CI test isolation
2026-06-09 23:11:48 -04:00
Tam Nhu Tran ad9bdd5794 fix(test): restore real account modules in tier-lock to fully stop mock leak
The prior fix only corrected PROVIDERS_WITHOUT_EMAIL, but the mock still stubbed
validateNickname -> null, hasAccountNameConflict -> false, and registry paths -> '',
which leak to cliproxy-auth-routes (same bun worker) and broke nickname validation
+ registry ops (9 CI failures). Now every mock factory spreads the REAL
account-manager and overrides only the account-DATA reads + IO; afterAll restores
the real account-manager/account-safety modules. tier-lock 8/0, combined ordering
39/0, tsc clean.
2026-06-09 21:25:21 -04:00
Tam Nhu Tran 0770b89037 fix(test): stop tier-lock mock.module leaking an empty PROVIDERS_WITHOUT_EMAIL
bun's mock.module is global and sticky; this test mocked account-manager with
PROVIDERS_WITHOUT_EMAIL: [] at top level and in beforeEach, poisoning the module
registry for later files in the same bun worker. cliproxy-auth-routes imports
PROVIDERS_WITHOUT_EMAIL at load time, got [], and getStartAuthNicknameError's
guard returned null for all providers -> 9 flaky CI failures (ordering-dependent).
Use the real ['kiro','ghcp'] in every mock factory and re-register safe defaults
in afterAll. Verified: worst-case ordering 39/39, full fast bucket 2500/0.
2026-06-09 21:11:10 -04:00