Commit Graph
238 Commits
Author SHA1 Message Date
Kai (Tam Nhu) Tran 87eb4f2154 Merge pull request #1414 from cerebrixos/tuning-engines-provider
Add Tuning Engines provider
2026-06-22 17:18:57 -04:00
Tam Nhu Tran b3a9abffbc ci(bar): auto-build and publish CCS Bar on main via self-hosted macOS runner
Releasing the macOS bar app was fully manual (run package_app.sh on a Mac, then
gh release upload --clobber), so Swift-side changes never reached users until
someone remembered to rebuild and re-upload the floating ccs-bar-latest asset.

Add a tightly-scoped Bar Release workflow that does it automatically:
- triggers ONLY on push to main touching macos-bar/**, or manual dispatch, so
  regular PRs, dev pushes, and non-bar changes never start it
- runs ONLY on the dedicated self-hosted macOS runner (label ccs-bar); the Linux
  CI runners never match it and it never competes for them
- least-privilege contents:write, single-flight via concurrency

Version is sourced from a new macos-bar/VERSION single-line file (the workflow
reads it; the asset is always the latest build regardless). package_app.sh now
defaults to that file when no version arg is passed, so the local manual path and
CI share one source of truth. Documents the release process in docs/ccs-bar.md.
2026-06-20 22:17:40 -04:00
Tam Nhu Tran 1462823be8 fix(logging): harden structured trace redaction
Redact StageOptions error payloads and summarize debug launch args.

Propagate request IDs through Cursor daemon and dashboard completion logs.

Mark remaining P2/P3 maintainability targets as partial instead of overclaiming.
2026-06-18 18:48:13 -04:00
Tam Nhu Tran 2d48488475 docs(hardening): finalize epic metrics + progress log (P1-P7) 2026-06-18 18:48:13 -04:00
Tam Nhu Tran 2f94f35ec3 feat(lint): P7 enforcement gates (no-new-throw-error + max-lines) + docs
Epic P7. Locks in the epic's gains with ESLint gates so the adoption work
does not regress.

- ccs/no-new-throw-error (error): custom flat-config rule that flags NEW
  throw new Error(...) outside a generated baseline allowlist. Forces the
  typed-error taxonomy (src/errors/error-types.ts). Existing 338 sites are
  grandfathered in eslint-rules/throw-error-baseline.json; only NEW violations
  error. Rule normalizes the filename to repo-root-relative to match baseline
  keys regardless of how ESLint reports paths.
- max-lines (warn, 400, skipBlankLines/skipComments): warns on files over
  400 LOC (goal of P5/P6 god-file splits). Currently 51 warnings on the
  not-yet-split god-files (P6 territory).
- scripts/generate-throw-error-baseline.js: emits the allowlist from raw
  source (superset of real throws; never undercounts). Run after intentionally
  grandfathering a site, or quarterly to prune.
- tests/unit/eslint-rules/no-throw-new-error.test.ts: rule logic (flags
  off-allowlist, passes on-allowlist/typed/rethrow, line-sensitivity).
- docs/code-standards.md: Lint Enforcement Gates section.
- docs/logging-contract.md: error.code -> ExitCode table (from P4).

validate + validate:ci-parity green.
2026-06-18 18:48:13 -04:00
Tam Nhu Tran 7234ef8fcf feat(errors): P4 typed-error taxonomy adoption (0->91% locked) + erasable-syntax fix
Epic P4. Migrates plain throw new Error to the typed-error classes in the four
locked subdomains, and makes the taxonomy erasable-syntax-compatible so it can
be adopted across UI-reachable code.

Migration (cliproxy/auth, web-server/routes, auth):
- 21 of 23 throws in the locked subdomains now use typed subclasses
  (ProfileError, AuthError, ConfigError, ValidationError, ProviderError).
- Typed adoption in locked subdomains: 0/23 -> 21/23 (91.3%), > 40% target.
- Overall typed adoption: 0.9% -> 8.6%.
- Messages preserved exactly (message-based tests stable). Exit codes now
  differentiate via handleError (ProfileError=7, AuthError=4, ConfigError=2,
  ProviderError=6). ccs doctor 0/1 contract untouched (outside scope).

Erasable-syntax fix (unblocks the migration in the UI build graph):
- exit-codes.ts: enum ExitCode -> const object + union type (value and type
  usage both preserved; no Object.values(ExitCode) consumers).
- error-types.ts: constructor parameter properties -> explicit readonly field
  declarations + body assignment.
- The web UI build enforces erasableSyntaxOnly (ui/tsconfig.app.json) and
  reaches src/errors via the @shared -> src/auth graph; pre-erasable
  error-types blocked the build once profile-registry adopted typed errors.

Compat audit: docs/reports/typed-error-exit-code-compat-audit.md (Q1 resolved:
migrate freely; only documented contract is ccs doctor, which is untouched).
Behavior-lock: src/errors/__tests__/typed-error-migration-exit-codes.test.ts
(taxonomy -> exit-code mapping, instanceof chains, context fields).

validate + validate:ci-parity green (incl. UI build).
2026-06-18 18:48:12 -04:00
Tam Nhu Tran 87aeb8f193 feat(logging): P3 hotpath console.error migration + redaction gate (928->267)
Epic P3. Migrates hotpath console.error/warn to the structured logger
(diagnostics) or process.stderr.write (user-facing), and adds a redaction
safety gate so the migration cannot leak credentials.

Redaction gate (MR1):
- log-redaction: scrub known credential token shapes (sk-ant, sk-, xoxb,
  ghp, glpat, AIza, JWT bodies, api_key=, Bearer/Basic/Token scheme) in
  string values, Error.message, AND the log message string (defense-in-depth).
- logger: message now passes through maskSecretTokens.

tool-sanitization-proxy: deleted the private file-logging subsystem
(initLogFile/writeLog/log/warn, logFilePath, debugMode); 13 call sites now
route through the existing createLogger('cliproxy:tool-sanitization-proxy').

Sweep (~120 diagnostic -> structured createLogger; ~540 user-facing -> stderr):
- diagnostics converted across proxy, web-server/routes, glmt pipeline, quota
  fetchers, executors, delegation, session-bridge, https-tunnel-proxy.
- user-facing CLI output (flows, arg-parser usage, installers, prompts, adapter
  launch errors, error display) moved to process.stderr.write (preserves stderr).
- src/utils/error-manager.ts reclassified CLI-UX-exempt (user-facing display).

Metric: hotpath console.error 928 -> 267 (71%); createLogger files 35 -> 64.
Residual 267 is user-facing CLI output (not diagnostics); documented in
docs/hardening-debt-burndown.md. Redaction gate makes further conversion safe.

Tests: hotpath-redaction-regression (12 token shapes); updated delegation-handler,
arg-parser, model-warnings spies (console.error -> process.stderr.write).
validate + validate:ci-parity green.
2026-06-18 18:48:12 -04:00
Tam Nhu Tran 95a2864ef3 feat(hardening): P1 maintainability metrics baseline + freshness gate (#1561)
Epic P1. Adds maintainability-metrics script (typed-error adoption, createLogger coverage, hotpath console.error, files>400 LOC), merges maintainability block into hardening-inventory report, adds 30-day freshness gate to ci-parity-gate.sh, re-baselines burndown 2026-06-18. Local validate + validate:ci-parity green.
2026-06-18 18:48:12 -04:00
Kai (Tam Nhu) Tran c776e18434 fix(bar): preserve Gatekeeper quarantine on install (#1534)
Preserves the Gatekeeper quarantine attribute on the installed CCS Bar app so the user makes the right-click to Open trust decision, instead of silently clearing it.
2026-06-15 23:28:24 -04:00
kcfang 8f9795bce2 fix(proxy): keep undici timeouts above the upstream request timeout (#1524)
Sets undici headersTimeout/bodyTimeout to request_timeout+30s so the AbortController is the single authority on upstream request lifetime, preventing premature socket closes on slow self-hosted upstreams. Verified undici v5 ProxyAgent object-signature compat.
2026-06-15 21:57:23 -04:00
Kai (Tam Nhu) Tran b03e2e1cb2 docs(bar): document detached launch model and serve/stop/status (#1529)
Reflect the seamless-launch change: the app self-starts the background
server, ccs bar runs it detached, and add the serve/stop/status commands
plus the launch.json/server.pid/serve.log files.
2026-06-15 19:58:03 -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 db1d125f83 docs(bar): troubleshooting reflects reuse-first launch behavior 2026-06-10 11:09:51 -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 1e7ad7e75e feat(bar): add Get CCS Bar dashboard banner and ccs bar docs page
Add a 'Get CCS Bar' promo banner + card to the dashboard (mirroring the
OpenRouter promo pattern + design system) so users discover the macOS menu-bar
app, with a macOS-aware install CTA. Add a user-facing docs/ccs-bar.md covering
what it is, install via 'ccs bar install', launch, what it shows, uninstall,
and the loopback requirement -- closing the docs-sync gap for the new ccs bar
command.
2026-06-09 18:04:53 -04:00
Kai (Tam Nhu) Tran 04dc97aaa4 fix: persist codex target selections 2026-05-30 14:57:07 -04:00
Kai (Tam Nhu) Tran 923bfee6fa fix: pause exhausted CLIProxy rotation accounts
Refs #1337
2026-05-23 00:08:53 -04:00
Tam Nhu Tran 37a14525cc fix: repair ccsx codex profile resources 2026-05-22 16:27:00 -04:00
Tam Nhu Tran f667628411 fix: resolve ccsx auth profiles before CCS profiles 2026-05-22 15:54:55 -04:00
VC 949792f41e Add Tuning Engines provider 2026-05-22 08:57:14 -04:00
Tam Nhu Tran 6569eed15b feat: support minimal codex effort aliases 2026-05-20 11:11:46 -04:00
Kai (Tam Nhu) Tran 67fe6d9c7f fix(persist): print recovery receipt after settings write (#1302) 2026-05-19 15:23:37 -04:00
Kai (Tam Nhu) Tran 9a2a1dde31 fix(browser): redact observed event URLs
Squash merge PR #1296 into dev.
2026-05-19 08:54:57 -04:00
Kai (Tam Nhu) Tran 538b6444ff fix(browser): gate response fulfillment opt-in
Squash merge PR #1295 into dev.
2026-05-19 08:41:00 -04:00
Kai (Tam Nhu) Tran 3b2016462a fix(persist): block codex claude settings bridge 2026-05-19 07:32:04 -04:00
Kai (Tam Nhu) Tran 8a37578702 fix(codex): pass native ccsx subcommands through (#1290) 2026-05-18 10:48:44 -04:00
Kai (Tam Nhu) Tran 5a54c1b536 fix(codex): pass ccsx resume through to native codex
Closes #1287
2026-05-18 09:45:20 -04:00
Tam Nhu Tran 85521018bf fix(codex-auth): close local review gaps 2026-05-17 17:41:23 -04:00
Tam Nhu Tran ea421c4a20 chore: merge origin/dev into codex auth profile branch 2026-05-17 15:33:06 -04:00
Tam Nhu Tran 631c799322 feat(codex-auth): add import-default migration + integration tests + docs
Adds opt-in `ccsx auth import-default <name>` to migrate the existing
~/.codex/auth.json into a new profile, plus the cross-system integration
tests and user-facing documentation.

- import-default-command (C3 torn-write protection):
  - readFileSync + JSON.parse with 3x retry / 100ms backoff to survive
    Codex's truncate-then-write auth.json refresh race
  - decode-id-token sanity-check on JWT shape (catches mid-write JWT
    corruption that JSON.parse alone wouldn't notice)
  - pgrep -f codex best-effort detection; warns + refuses without
    --force-while-running flag if a live codex process is found
  - rejects cliproxy-format auth files ({type: "codex", ...} wrapper)
    with a clear "use ccs cliproxy ..." pointer
  - atomic write to <dest>.tmp.<pid>.<rand> + rename
  - --with-history defaults to false per D8 (auth-only is the safer
    default; opt in for bulkier data)
  - --force backs up existing auth.json to .bak-<ts> before overwrite
  - non-destructive — never modifies ~/.codex/; legacy mode keeps
    working without ever running this command
- integration tests:
  - two-terminal-isolation: two profiles with separate CODEX_HOMEs
    write to their own auth.json/history.jsonl with no crosstalk
  - ccsxp-independence: codex-auth profile set; ccsxp still uses its
    own CCSXP_CODEX_HOME / ~/.codex pool (H5 stderr notice present)
  - legacy-fallback: no profiles registered → codex-runtime-router
    leaves CODEX_HOME unset → codex falls back to ~/.codex
  - import-default.integration: real fs copy + decode + register
- docs/codex-auth.md: user guide covering quick start, two-terminal
  example, migration, dashboard, and caveats (cmd.exe, Windows
  symlinks, ccsx vs ccsxp distinction)

155 codex-auth-scope tests green (45 Phase 1 + 57 Phase 2 + 19 Phase 3
+ 15 Phase 4 + 19 Phase 5). Full suite 3051/3082 — the 1 failure is a
pre-existing test-pollution issue between ccsxp-runtime.test.ts and
codex-runtime-integration.test.ts that exists on dev today; the test
passes in isolation.
2026-05-17 14:46:16 -04:00
Kai (Tam Nhu) Tran d68ee37590 fix(codex): preserve custom ccsxp cliproxy base URLs
Preserve valid custom model_providers.cliproxy.base_url values during ccsxp Codex provider repair while keeping local fallback repair for missing or invalid URLs.\n\nCloses #1281
2026-05-17 06:59:09 -04:00
Kai (Tam Nhu) Tran 4e9c14b64a fix(release)!: decouple npm @latest from Docker rc.1 soak (REV11) (#1277)
Reverts the loop-1 prerelease channel that was publishing npm as
vX.Y.Z-rc.N to the `rc` dist-tag instead of `latest`.

`main` is now a stable semantic-release channel again: every merge
publishes vX.Y.Z immediately to npm @latest. The rc.1 soak window
that guards Docker mutable tags is moved entirely into the Docker
publish workflow:

- `.releaserc.cjs`: remove `prerelease: 'rc'` from productionConfig,
  restore `branches: ['main']` (stable). Restore full successComment
  and `released` label. Keep loop-1 releaseNotesGenerator additions
  (revert section, breaking change comment).

- `docker-release.yml`: every `release: published` event publishes
  only the immutable `:<ver>` Docker tag. `promote-mutable-tags` job
  now gates exclusively on `workflow_dispatch` with
  `promote_to_latest=true` — no longer triggered automatically by
  non-prerelease release events.

- `promote-release.yml`: rewritten as a dispatch wrapper that validates
  the stable tag exists and is not a prerelease, verifies the immutable
  Docker image is in the registry, then dispatches docker-release.yml
  with `promote_to_latest=true`. Removes the `gh release edit
  --prerelease=false` approach that required the rc soak to be wired
  through GitHub release state.

- `docs/release-process.md`: updated to reflect the decoupled model —
  npm @latest is immediate; Docker :latest requires manual promote after
  soak. Documents the `why` split between npm and Docker soak windows.
2026-05-17 05:46:48 -04:00
Kai (Tam Nhu) Tran 107b5b5db4 fix(docker): apply red-team findings — drop :full, rc.1 soak, healthcheck, signing (#1251) (#1262)
* docs(quickstart): fix raw URL for corporate-proxy fallback (H1)

* feat(docker)!: drop :full image variant — use sibling containers on ccs-net (Q3)

No AI CLIs (claude-code/gemini-cli/grok-cli/opencode) are bundled in the image.
Use sibling containers attached to ccs-net instead.
See docker/README.md#connect-your-app-to-cliproxy.

Also removes bash from apk deps (entrypoint uses #!/bin/sh — L2).

ci(docker): publish only immutable :<ver> tag pre-smoke; promote-mutable-tags
job adds :latest/:MAJOR/:MINOR aliases only after smoke tests pass (H3)

ci(docker): smoke-test-compose-url runs network-contract.sh against the
downloaded /tmp/ccs-compose.yaml instead of re-cloning the repo (H4)

ci(docker): sign published images with cosign keyless OIDC + attach
provenance/SBOM via build-push-action (M8)

test(docker): network-contract.sh now accepts compose-file and image-ref
positional args; replaces python3 healthcheck parser with jq (L4)

* chore(release): cut every main release as rc.N prerelease, manual promote flow (H2)

- .releaserc.cjs: main branch now uses prerelease 'rc' channel — every
  semantic-release cut becomes vX.Y.Z-rc.N
- add promote-release.yml: workflow_dispatch flips rc → stable via
  'gh release edit --prerelease=false'; triggers docker promote-mutable-tags
- add docs/release-process.md: full soak + promote procedure, rollback steps,
  cosign verification command
- releaseNotesGenerator: add revert section, document chore hidden behaviour (L8)

* fix(docker): healthcheck probes both dashboard and cliproxy ports (M1)

compose.yaml healthcheck now checks :3000 and :8317 concurrently with
a 4.5s internal timeout, within Docker's 5s timeout budget.

Also:
- docs(docker): document npm lockfile ephemeral tradeoff above install
  layer; note size-budget regression test as the practical safeguard (M3)
- docs(docker): drop :full row from Choosing an image table; add sibling
  container note pointing to connect-your-app-to-cliproxy (Q3/docs)
- docs(docker): remove :full docker run block; fix release-tag sentence (Q3)
- docs(docker): fix raw URL in migration section (H1 parity)
- docs(docker): add Volume warning — 'down -v' deletes named volumes (L13)
- docs(docker): update What changes table — remove :full reference (Q3)
- docs(docker): add Image Signatures and SBOM section with cosign verify
  and sbom download commands (M8/docs)
- changelog: add Unreleased entries for rc soak, cosign signing, :full
  removal with migration guidance

* ci(docker): assert image-size budget per platform; add compose parity + breaking-change guard (M6/L9/L12)

- image-size.sh: add --platform flag; uses 'docker buildx imagetools
  inspect' to sum compressed layer sizes from registry manifest for
  linux/amd64 and linux/arm64 separately (M6)
- docker-release.yml smoke-test: runs size check for both platforms
- compose-parity.sh: diffs docker/compose.yaml vs
  docker/docker-compose.integrated.yml for image name, ports 3000/8317,
  volume mounts /root/.ccs and /var/log/ccs, ccs-net definition (L12)
- ci.yml: add compose-parity job wired to cliproxy runner (L12)
- breaking-change-guard.yml: fails PR if compose.yaml changes image name,
  network name, or container_name without a feat!/fix! commit (L9)

* chore(ci): fix cosign shell substitution — use tr instead of bash @L expansion (L6/nit)

* test(docker): fix compose-parity port regex for variable-interpolated host ports
2026-05-16 13:33:12 -04:00
Kai (Tam Nhu) Tran b50c2db3ce docs(docker): P3 — hoist two-command quickstart, restructure docker/README, add parity CI (#1260)
* docs: hoist Docker zero-install quickstart above npm install path

- Create docs/quickstart-snippet.md as canonical source for the
  two-command flow (curl + docker compose up -d), wrapped in
  <!-- quickstart-snippet-start/end --> markers
- Hoist the snippet into README.md immediately below the deprecation
  banner, above all other install paths
- Rename old npm-only "## Quick Start" to "## Install on Host (npm)"
  and move it below the Docker quickstart

* docs(docker): restructure README with zero-install first and migration section

- Reorder top-level sections: zero-install (canonical snippet with
  markers), choosing an image, power-user ccs docker, prebuilt image,
  connect your app to CLIProxy, migration, env vars, troubleshooting
- Add deprecation banner at the top pointing at the migration section
- Add ## Migration from ccs-dashboard:latest section with step-by-step
  instructions covering compose down, data preservation, named volume
  vs bind-mount path, and compose up with the new image
- Keep P1's Choosing an image table and P5's Connect Your App to
  CLIProxy section intact, just repositioned

* test(docs): parity check for quickstart snippet across README files

Assert README.md and docker/README.md both contain the canonical
quickstart block verbatim, anchored by marker comments. Exits non-zero
and prints a diff on any drift.

* ci(docs): wire quickstart-parity test on push and PR

Runs tests/docs/quickstart-parity.sh on self-hosted runner whenever
docs/quickstart-snippet.md, README.md, docker/README.md, or the
test/workflow files themselves change. Fails fast on snippet drift.
2026-05-16 12:56:09 -04:00
Kai (Tam Nhu) Tran 4748c452bd fix(codex): self-heal ccsxp cliproxy provider (#1243) 2026-05-14 12:35:31 -04:00
Kai (Tam Nhu) Tran d61469edcb fix(config): bind dashboard to loopback by default 2026-05-12 10:59:49 -04:00
Kai (Tam Nhu) Tran 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
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 64e1d1f815 feat(auth): add shared resource controls 2026-05-08 11:15:28 -04:00
Kai (Tam Nhu) Tran 74d73748ee feat: support Codex fast service-tier aliases
* feat: support Codex fast service-tier aliases

* fix: send Codex fast tier as priority
2026-05-07 15:34:05 -04:00
Kai (Tam Nhu) Tran 19a50a8dd8 feat: deprecate GitHub Copilot compatibility surfaces (#1196) 2026-05-07 13:06:03 -04:00
Kai (Tam Nhu) Tran 8b681df455 fix: route Cursor auth through browser polling
Closes #1194
2026-05-07 11:25:17 -04:00
Kai (Tam Nhu) Tran 1b5376239f fix: preserve native Claude passthrough args
Closes #1189
2026-05-07 06:14:12 -04:00
Kai (Tam Nhu) Tran 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
Kai (Tam Nhu) Tran 923683bf30 feat(cliproxy): route plus dashboard to maintained fork (#1173) 2026-05-03 13:01:04 -04:00
Tam Nhu Tran e5fe86f520 feat: add native Claude effort override 2026-04-30 22:36:47 -04:00
Tam Nhu Tran c0c856af98 docs(logging): add structured contract reference and bump Node engines to 18+
docs/logging-contract.md defines the canonical LogEntry shape, the 8
lifecycle stages, requestId propagation rules, redaction policy, and the
backend ordering guarantee (per-requestId monotonic ts at emit time) that
the dashboard logs UI consumes.

CLAUDE.md updated: Node.js 14+ -> 18+ (AsyncLocalStorage is more stable on
18+ across timer / microtask / dynamic-import boundaries).

Refs #1141, #1138
2026-04-30 13:01:21 -04:00
Tam Nhu Tran 5013d411a7 feat(cliproxy): self-pause exhausted quota accounts 2026-04-28 20:35:15 -04:00
Tam Nhu Tran a38c1a75ba feat: integrate models.dev pricing metadata 2026-04-28 14:50:26 -04:00