Commit Graph
923 Commits
Author SHA1 Message Date
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
Tam Nhu Tran 5b664d2105 hotfix(codex): tolerate BOM in Codex TOML config 2026-05-14 13:13:55 -04:00
Kai (Tam Nhu) TranandGitHub 4748c452bd fix(codex): self-heal ccsxp cliproxy provider (#1243) 2026-05-14 12:35:31 -04:00
walker1211andGitHub 35b6210cd2 fix: support Claude subcommands and background sessions
Squash merge PR #1240.\n\nValidated locally from the PR head because trusted-author GitHub CI was skipped for this fork PR:\n- bun run validate\n- bun run build:all\n- bun run test:all\n- CCS_E2E_SKIP_BUILD=1 bun run test:e2e
2026-05-14 10:18:23 -04:00
Tam Nhu Tran 1932b2ca61 fix(proxy): strip stale encoding from upstream error responses 2026-05-13 09:13:28 -04:00
Kai (Tam Nhu) TranandGitHub 667b1d1e1f fix: ignore internal instance directories in health scans
Closes #1236
2026-05-12 22:17:16 -04:00
Kai (Tam Nhu) TranandGitHub 40300c286e fix(security): constrain image fallback hook to workspace (#1232) 2026-05-12 18:13:32 -04:00
Kai (Tam Nhu) TranandGitHub 349db830df fix(settings): confine dashboard settings paths (#1231) 2026-05-12 18:13:26 -04:00
Kai (Tam Nhu) TranandGitHub a840793a9b fix(proxy): avoid exposing local auth token in daemon argv (#1230) 2026-05-12 18:13:20 -04:00
Kai (Tam Nhu) TranandGitHub 9c5d4976c5 fix(windows): pin cmd shell for wrapper launches (#1229) 2026-05-12 18:13:13 -04:00
Tam Nhu Tran c2b00b7ad6 feat(dispatcher): pass through Claude subcommands without interactive-session args
Closes #1218.

When the user invokes `ccs <profile> agents` (and other Claude subcommands
like `mcp`, `doctor`, `plugin`, ...), CCS was unconditionally injecting
session-only Claude flags (`--append-system-prompt`, `--disallowedTools`,
`--settings`, official-channels plugin specs) and forwarding the
`DISABLE_TELEMETRY=1` env var from profile settings. Each of those
either errored out the subcommand (`error: unknown option
'--append-system-prompt'`) or silently flipped Claude into
non-interactive list mode, so the new `claude agents` agent view never
opened under CCS.

Add a small `claude-subcommand-detector` that recognizes the documented
Claude subcommand set after skipping known value-taking flags, then have
the three steering-prompt injectors (websearch, image-analysis, browser),
the cliproxy and settings launchers, and the official-channels plan
short-circuit when a subcommand invocation is detected. Also strip
`DISABLE_TELEMETRY` from the spawned env only for subcommand
invocations — upstream Claude Code uses that var as a kill switch for
the subcommand TUIs, and the user's telemetry preference still applies
to every normal interactive session.

Verified end-to-end against `ccs glm agents` and `ccs ck agents`: the
agent view opens correctly, no `unknown option` error, and all 1938
existing tests pass.
2026-05-12 16:35:37 -04:00
Tam Nhu Tran 4c0aa83c82 chore(sync): merge main into dev after release
# Conflicts:
#	.github/workflows/ci.yml
#	package.json
2026-05-12 12:43:02 -04:00
Kai (Tam Nhu) TranandGitHub 2273757c83 fix(ci): harden self-hosted workflow trust boundaries
Keep active CCS workflows on self-hosted runners, gate self-hosted PR execution to trusted authors, and scope privileged release credentials to the exact git operations that need them.
2026-05-12 12:34:15 -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 f09cdfcf2b fix(security): protect dashboard WebSocket upgrades 2026-05-12 10:42:05 -04:00
Kai (Tam Nhu) TranandGitHub e7174d63bb fix(ci): run pull request validation on hosted runners 2026-05-12 10:33:47 -04:00
Kai (Tam Nhu) TranandGitHub bd588a271d fix(codex): require local access for dashboard config routes 2026-05-12 10:24:25 -04:00
Kai (Tam Nhu) TranandGitHub eb4bbfddf3 security(browser-mcp): restrict model-callable local file uploads/downloads to safe roots and deny sensitive paths (#1220)
* fix(browser): restrict file transfer paths

* fix(browser): normalize safe transfer paths

* fix(browser): reject sensitive transfer roots
2026-05-12 08:57:33 -04:00
Kai (Tam Nhu) TranandGitHub 29da75c0d4 fix(cliproxy): explain headless Codex OAuth recovery
Closes #1213
2026-05-11 14:25:34 -04:00
Tam Nhu Tran a983332016 refactor(web-server): modularize shared-routes and Windows-aware symlink status 2026-05-10 22:15:33 -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 43ece40c21 Revert "ci(ai-review): move PR-Agent jobs to ubuntu-latest"
This reverts the runs-on change for ai-review.yml. All CI/CD must
stay on home infra (claw, docker LXC, etc); GitHub-hosted runners
are forbidden. The qodo-ai/pr-agent docker action mount issue will
be addressed by either configuring the self-hosted runner image to
use path-identical bind mounts so nested-docker volume sources
resolve correctly, or by switching to native CLI invocation
(pip install pr-agent) instead of the docker action.

Tracked separately; not blocking PR #1209.
2026-05-10 18:30:05 -04:00
Tam Nhu Tran c02c66dcd1 ci(ai-review): move PR-Agent jobs to ubuntu-latest
The qodo-ai/pr-agent Docker action requires the GitHub event payload
at /github/workflow/event.json inside the action container. On
self-hosted runners that themselves run inside a Docker container
(e.g. myoung34/github-runner), the host docker daemon resolves the
volume mount /tmp/runner/work/_temp/_github_workflow:/github/workflow
against the host filesystem, where the runner's /tmp path does not
exist. The action container starts with an empty /github/workflow
mount and fails with FileNotFoundError on event.json.

AI review jobs do not need self-hosted runner access (no bun cache,
no internal infra). Switch both dispatch-review and pr-agent jobs
to ubuntu-latest so the volume mount resolves on the same host where
the action expects it.
2026-05-10 18:26:17 -04:00
Tam Nhu Tran 8b34060294 fix(dashboard): show real shared plugin registry state 2026-05-09 03:18:20 -04:00
Tam Nhu Tran 2a422b3bd3 feat(dashboard): add shared resource controls 2026-05-09 02:29:08 -04:00
Tam Nhu Tran 3b550205dd fix(auth): require resource mode value 2026-05-08 23:36:12 -04:00
Tam Nhu Tran bfe32257b6 fix(auth): reject resource mode outside resources command 2026-05-08 23:29:03 -04:00
Tam Nhu Tran 64e1d1f815 feat(auth): add shared resource controls 2026-05-08 11:15:28 -04:00
Kai (Tam Nhu) TranandGitHub 8b681df455 fix: route Cursor auth through browser polling
Closes #1194
2026-05-07 11:25:17 -04:00
Kai (Tam Nhu) TranandGitHub 1b5376239f fix: preserve native Claude passthrough args
Closes #1189
2026-05-07 06:14:12 -04:00
Kai (Tam Nhu) TranandGitHub be9effcce3 feat: clarify account history sync route (#1187)
* feat: clarify account history sync route

* fix: clarify shared context command examples

* fix: report missing bare profile settings
2026-05-05 13:33:04 -04:00
Tam Nhu Tran dc8bbd85e7 fix: route OpenRouter profiles through v1 API 2026-05-05 11:44:58 -04:00
d6b705e6a9 fix(dispatcher): re-inject anthropic auth env for anthropic-compatible api profiles (#1181)
* fix(dispatcher): preserve anthropic auth env for settings profiles on non-proxy path

API profiles whose `ANTHROPIC_BASE_URL` is classified as `'anthropic'`
(anthropic.com, paths containing `/anthropic`, ollama.com) skip the
local OpenAI-compat proxy. The non-proxy launch path stripped
`ANTHROPIC_BASE_URL` / `ANTHROPIC_AUTH_TOKEN` / `ANTHROPIC_API_KEY`
from the subprocess env without re-injecting them, so Claude Code
launched with no routing/auth in `process.env` and failed with
`Not logged in - Please run /login`. The `--settings` env block does
not satisfy Claude Code's auth check.

Pre-existing for `anthropic.com` and `/anthropic` profiles. Newly
broken in v7.77.0 for Ollama Cloud profiles - PR #1175 reclassified
`ollama.com` from `generic-chat-completion-api` to `anthropic`,
moving it from the proxy path onto this broken non-proxy path.

Fix by extending `stripAnthropicRoutingEnv` with an optional
`preserveFrom` parameter. Routing keys present in `preserveFrom`
survive the strip (with values from `preserveFrom`). Settings-type
profiles pass their own `settings.env` as the preserve source so
routing they explicitly supplied is kept while routing leaked from
the parent shell or `global.env` is dropped.

Wired into both call sites:
- `headless-executor.ts` (the `-p` headless executor)
- `settings-flow.ts` (the interactive flow, which then calls
  `execClaude` - whose own `stripAnthropicRoutingEnv` pass on the
  merged env now also takes `envVars` as the preserve source so the
  caller-supplied routing is not stripped a second time before spawn)

Native Anthropic / Bedrock / Vertex profiles are unaffected (they
don't put routing keys in `settings.env`). The OpenAI-compat proxy
path is unaffected because `buildOpenAICompatProxyEnv` overrides
`BASE_URL` / `AUTH_TOKEN` with localhost values and explicitly deletes
`API_KEY` after this strip.

Replaces the Apr 21 defensive double-strip test (which was the
mechanism causing this regression on the interactive path) with a
test asserting the new contract: caller-supplied routing in `envVars`
survives, parent-process routing is still stripped.

* test: harden anthropic settings env preservation coverage

* fix: preserve explicit blank anthropic routing env

---------

Co-authored-by: Tam Nhu Tran <kaitran.ntt@gmail.com>
2026-05-04 20:22:13 -04:00
Tam Nhu Tran 5f05dea5ac fix: harden cursor daemon model fallback 2026-05-04 11:51:22 -04:00
4e2def6769 feat: support ollama cloud anthropic compatible api (#1175)
* feat(droid-provider): support ollama cloud anthropic compatible api

* fix(droid-provider): move ollama.com to anthropic block to prevent model inference override

* fix(droid-provider): move pathname-based generic checks before host-based anthropic check

* test(proxy): cover ollama cloud native routing boundaries

---------

Co-authored-by: Tam Nhu Tran <kaitran.ntt@gmail.com>
2026-05-03 22:28:38 -04:00
Tam Nhu Tran 3862411bb7 fix(cliproxy): harden custom local port handling 2026-05-03 14:07:31 -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
Tam Nhu Tran 164dcabd20 Merge remote-tracking branch 'origin/dev' into kai/refactor/1135-structural-maintainability 2026-05-03 12:00:48 -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 4f6e61739c refactor(config): adopt config-loader-facade across the codebase
Issue #1161. Sweeps 127 files to import from
src/config/config-loader-facade.ts instead of unified-config-loader or
utils/config-manager directly.

WRITE callers (32 files): replaced raw saveUnifiedConfig /
mutateUnifiedConfig / updateUnifiedConfig calls with the facade's
cache-coherent wrappers saveConfig / mutateConfig / updateConfig. This
fixes a latent stale-cache window where direct writes through the
underlying loader bypassed the facade's memoization.

READ callers (95 files): mechanical import-path migration only —
function names unchanged because the facade re-exports them. No
behavior change.

Also updated:
- tests/unit/utils/browser/browser-setup.test.ts (DI interface rename)
- src/management/checks/image-analysis-check.ts (dynamic import rename)
- src/web-server/health-service.ts (dynamic require rename)
- src/ccs.ts (path prefix fix from sweep script)

After sweep: zero raw write callers remain outside src/config/. Direct
imports of config-manager remain only for symbols not in the facade
(getConfigPath, getCcsDirSource, etc). Behavior unchanged; full suite
passes 1824/1824.

Out of scope: switching loadOrCreateUnifiedConfig() callers to
getCachedConfig() — needs per-callsite cache-safety analysis. Tracked
as follow-up.

Refs #1161
2026-05-03 01:42:53 -04:00
walker1211andGitHub 11b12f146d fix(analytics): cache native Codex usage scans
Cache parsed native Codex rollout usage entries per file fingerprint to avoid repeated full-history JSONL parsing on dashboard refreshes.

Add regression coverage for cache reuse, invalid cache fallback, cliproxy cache separation, and scoped cache fixtures.
2026-05-02 21:16:07 -04:00
Tam Nhu Tran e5fe86f520 feat: add native Claude effort override 2026-04-30 22:36:47 -04:00
Kai (Tam Nhu) TranandGitHub b892739756 Merge pull request #1146 from kaitranntt/kai/feat/1138-logs-ui-redesign
feat(ui): redesign dashboard logs page (#1142)
2026-04-30 13:14:47 -04:00
Tam Nhu Tran c0a019bf7e test(logging): add cross-stage requestId correlation integration test in slow bucket
Verifies that a single requestId propagates across at least 3 lifecycle
stages emitted from different modules, and that ALS context survives across
async boundaries (setImmediate, microtask, promise.then). Registered in
test:slow bucket per validate:ci-parity gate.

Refs #1141, #1138
2026-04-30 13:01:05 -04:00
Tam Nhu Tran 7a22e89046 feat(logging): add structured contract, ALS context, stage helpers, and redaction coverage
Establish the structured-log foundation that downstream modules consume:
- LogStage union (intake|route|auth|dispatch|upstream|transform|respond|cleanup)
- AsyncLocalStorage-backed log-context for end-to-end requestId propagation
- Logger.stage() emit helper with optional latencyMs and structured metadata
- Extended log-redaction patterns for proxy-authorization, x-goog-api-key,
  oauth-code, refresh-token classes; Bearer/Basic/Token value-shape masking
- Public exports: getRecentLogEntries, withRequestContext, runWithRequestId,
  getRequestId

Refs #1141, #1138
2026-04-30 12:59:42 -04:00
Tam Nhu Tran 33a1553431 test: include colocated cliproxy tests in buckets 2026-04-30 12:49:57 -04:00
Tam Nhu Tran d9ace607e5 fix(proxy): shape direct OpenAI reasoning chat payloads 2026-04-30 12:33:02 -04:00
Tam Nhu Tran 31dc18657c fix(cliproxy): fix base-config-loader __dirname path and stale mock.module paths
- base-config-loader.ts moved from src/cliproxy/ to src/cliproxy/config/,
  so __dirname relative path needs one more .. to reach config/ dir
- Update mock.module paths for proxy-detector and routing-strategy
  in non-colocated test files
2026-04-29 17:40:33 -04:00
Tam Nhu Tran 2c817fae48 fix(cliproxy): update remaining stale imports in non-colocated tests
Fix auth-token-manager, quota-response-cache, stats-fetcher,
and proxy-detector import paths in tests/ outside cliproxy.
2026-04-29 17:26:51 -04:00