48 Commits
Author SHA1 Message Date
Sergey Galuza 4a17f034e2 docs(shared-manager): note why the CAS mismatch raises EEXIST
The code is this file's marker for "a race was detected" - the same one
the reappeared-path and concurrent-replacement guards raise - not a
report that a no-replace link() or open('wx') hit an existing path. Say
so at the throw, so debugging by err.code does not send anyone looking
for a no-replace failure that never happened.

Built [OnSteroids](https://onsteroids.ai)
2026-08-23 08:33:06 +02:00
Sergey Galuza df52662a59 refactor(shared-manager): extract the durable temp write
createFileNoReplace and publishCanonicalContent carried the same
open-wx / fchmod / write / fsync / close block and the same cleanup
handler. Extract writeDurableTempFile and discardTempFile so each
publisher is left with only what distinguishes it: a no-replace link, or
the compare-and-swap guard and the rename.

Also spell out in publishCanonicalContent that its guard is read-then-act
rather than atomic. POSIX has no compare-and-swap rename, so the window
is narrowed from the ~100 ms the old claim-and-republish path left open
to two adjacent syscalls, not closed - and the pre-image sidecar is what
keeps that last outcome recoverable. Worth stating so the guard is not
mistaken for a strict guarantee later.

Built [OnSteroids](https://onsteroids.ai)
2026-08-23 08:32:53 +02:00
Sergey Galuza fa3fd8eb3a refactor(shared-manager): tighten canonical identity capture
Build the canonical identity from the stat getCanonicalFile already
takes, instead of a second lstat of the same inode. One syscall less,
and mode, mtime and identity now describe the same moment rather than
two adjacent ones.

Assert in the adoption race tests that the foreign writer never fired.
It writes only when the canonical path is observed empty, so a zero
count states the invariant the fix establishes - the path is never left
without a regular file - instead of only checking the final content.

Built [OnSteroids](https://onsteroids.ai)
2026-08-23 08:32:39 +02:00
Sergey Galuza 00a4dceb94 fix(shared-manager): publish adopted settings by replacement
Adoption moved the canonical settings.json aside with rename() and left
the path empty until publication, roughly 100 ms later. Claude Code or a
second `ccs` starting inside that window found no file and seeded an
empty placeholder; publication then failed with EEXIST because link() is
no-replace, and the rollback published a backup and unlinked the claim,
destroying the only remaining copy of the user's settings. Recovering
meant digging through sidecar files by hand.

Publish by replacement instead: write a temp file next to the canonical
inode and rename() it over the target, so the path always holds a regular
file and no placeholder can be seeded. A compare-and-swap guard on
(ino, mtime, size) runs immediately before the rename and refuses to
publish when the canonical inode changed since it was read, so a writer
that got there first is still never clobbered. The pre-image backup is
published before the replacement, keeping the old content recoverable if
publication is interrupted.

Drops the canonical claim entirely along with restoreCanonicalClaim, and
folds the two identical sidecar publishers into one helper.
recoverOrphanedCanonicalClaim stays, since claims written by older
versions may still be on disk.

New tests cover both writers seen in the incident: Claude Code seeding
`{}` with a trailing newline, and a second `ccs` seeding the 2-byte
variant from shared-dir-linker. Four tests that pinned the claim-based
design were rewritten, among them `preserves a canonical write that
lands during no-replace publication`, whose intent is now enforced by
the CAS guard instead of by an EEXIST from a no-replace link.

Built [OnSteroids](https://onsteroids.ai)
2026-08-23 08:32:26 +02:00
Sergey Galuza 1e63c37baf feat(pricing): register Claude Sonnet 5 in the pricing registry
Add explicit `claude-sonnet-5` and `claude-sonnet-5-thinking` entries to the
web-server PRICING_REGISTRY at the standard Sonnet rates ($3/$15 in/out,
$3.75/$0.30 cache).

The model catalog and dashboard already ship Sonnet 5 (it is the Claude
default), but pricing was missing: getModelPricing() fell through to
UNKNOWN_MODEL_PRICING, which only coincidentally matches Sonnet rates. As a
result hasCustomPricing('claude-sonnet-5') returned false and getKnownModels()
omitted it, so Sonnet 5 was treated as an unknown model in cost accounting and
known-model listings.

Registering it explicitly makes the pricing intentional and consistent with
every other Claude model, without changing any resolved values.

Built [OnSteroids](https://onsteroids.ai)
2026-07-07 14:51:43 +02:00
Sergey Galuza cbcdb6ba62 fix(glmt): emit thinking signature as opaque string
generateThinkingSignature() returned an object
({type, hash, length, timestamp}) but Anthropic requires a thinking
block's `signature` to be a non-empty opaque STRING. The object made
the thinking block invalid, breaking the stream against reasoning
backends and surfacing as a false 502 "did not respond within 600s".

Return a deterministic base64 token instead (no Date.now()), and
narrow ThinkingSignature to a string alias so existing imports stay
intact. The signature is only ever assigned, never read as an object,
so consumers are unaffected. Update the existing unit test to the
corrected string contract.

Built [OnSteroids](https://onsteroids.ai)
2026-06-29 13:27:09 +02:00
Sergey Galuza 37d2bae001 test(glmt): assert thinking signature is a non-empty opaque string
Add two contract tests on the public proxy path
createAnthropicProxyResponse: JSON and SSE. Anthropic requires a
thinking block's signature to be a non-empty opaque string, but ccs
currently fabricates the signature as an object via
generateThinkingSignature(), which breaks the stream against reasoning
backends.

Built [OnSteroids](https://onsteroids.ai)
2026-06-29 13:26:16 +02:00
Sergey Galuza 1fc595f10c docs(pricing): document legacy 4-7-thinking entry; cover tier metadata
Final review polish:

- Add an inline comment on the claude-opus-4-7-thinking registry entry
  explaining it is a pricing-only id kept for historical analytics data
  (no catalog model after Opus 4.7 moved to adaptive thinking levels),
  and why it carries no fast tier.
- Add a test asserting applyServiceTier preserves the serviceTiers map on
  its result, guarding against a future simplification dropping it.

Built [OnSteroids](https://onsteroids.ai)
2026-05-31 20:23:14 +02:00
Sergey Galuza 5a79b47506 fix(pricing): restore opus version order; cover 4.6/4.7 fast-tier rates
Address presto review on the fast-tier work:

- Move the claude-opus-4-8 entry after claude-opus-4-7-thinking so the
  registry keeps chronological 4.6 -> 4.7 -> 4.8 ordering (the 4.8 insert
  had split the 4-7 / 4-7-thinking pair).
- Drop the fast serviceTier from claude-opus-4-7-thinking: that id is a
  legacy pricing-only entry with no catalog model, so a fast premium on it
  is meaningless. The active 4.6-thinking variant (agy provider) keeps its
  fast tier.
- Extend the 4.7 fast-tier test with cache-rate assertions and add an
  equivalent 4.6 fast-tier test so the derived buildRates math is covered
  for every premium-tier model.

Built [OnSteroids](https://onsteroids.ai)
2026-05-31 18:52:54 +02:00
Sergey Galuza e8057a7073 refactor(pricing): share Opus fast-tier rate constants
Hoist the fast-mode rate sets into OPUS_46_47_FAST_RATES and
OPUS_48_FAST_RATES module constants (built via buildRates) so the
registry entries reference shared values instead of repeating literal
buildRates(...) calls. Also wires the fast tier onto the -thinking
aliases (claude-opus-4-6-thinking / -4-7-thinking) so they bill at the
same premium as their base ids.

Built [OnSteroids](https://onsteroids.ai)
2026-05-31 18:16:23 +02:00
Sergey Galuza 254fc88f71 refactor(pricing): derive fast-tier cache rates via buildRates helper
Address review feedback on the per-service-tier pricing:

- Extract `buildRates(input, output)` plus named CACHE_5M_WRITE_MULTIPLIER
  / CACHE_READ_MULTIPLIER constants so fast-tier cache rates are derived
  from Anthropic's documented multipliers instead of hand-computed numbers.
  This removes the inconsistency where Opus 4.6 fast-tier lacked the
  explanatory inline comments that 4.7/4.8 carried (presto suggestion #3).
- Document in `applyServiceTier` that no production caller passes
  `serviceTier` yet (Anthropic's service_tier is not captured on
  CliproxyRequestDetail), so fast-mode usage is currently billed at the
  standard rate until the usage pipeline records the tier.
- Add a combined date-suffix + fast-tier lookup test to prove the two
  resolution stages compose.

Built [OnSteroids](https://onsteroids.ai)
2026-05-31 10:34:50 +02:00
Sergey Galuza 5157a922a5 test(accounts): align stale free-tier expectations with current behavior
Commit 72ea1fc9 ("fix(accounts): simplify codex free tier badges") split
free codex accounts out of the `personal` audience into a distinct
`free` audience and dropped the `'Personal · '` prefix on inlineLabel,
but `account-visual-groups.test.ts` was not updated and has been
failing in CI ever since.

Update expectations to match the shipped behavior:
- `audience` for `-free` tokens is `'free'`, not `'personal'`
- `inlineLabel` for a bare free account is `'Free'`, not `'Personal · Free'`
- `compactDetailLabel` is `null` when no extra parts are present
- Sort order: business -> personal -> free -> unknown

Drive-by fix unrelated to the Opus 4.8 work in this PR but caught
because these tests started failing on every push to the branch.

Built [OnSteroids](https://onsteroids.ai)
2026-05-30 23:01:58 +02:00
Sergey Galuza c74ad22bd4 Merge remote-tracking branch 'upstream/dev' into feat/claude-opus-4-8 2026-05-30 22:31:55 +02:00
Sergey Galuza 878775f5b6 feat(pricing): support per-service-tier rates; wire Opus fast mode
Extend `ModelPricing` with an optional `serviceTiers` map keyed by
Anthropic's `service_tier` request parameter. `getModelPricing(model,
{ serviceTier })` returns the matching tier rates when present and
transparently falls through to base rates otherwise — existing call
sites keep current behavior.

Registry entries added (per Anthropic Fast mode pricing docs):
- claude-opus-4-8 fast: $10/$50 input/output (2x premium)
- claude-opus-4-7 fast: $30/$150 (6x premium)
- claude-opus-4-6 fast: $30/$150 (6x premium)

Cache rates derived from the documented Prompt caching multipliers
(1.25x for 5-min cache write, 0.1x for cache read).

Note: tier tracking through CliproxyRequestDetail is not wired yet —
that's a follow-up so usage transformers can pass `serviceTier` when
Anthropic returns it on the response. Schema is in place; integration
can land independently.

Also adds a defensive `claude-opus-4-8-20260530` pricing test to exercise
`stripDateSuffix` even though Anthropic no longer issues date-stamped IDs
for the 4.6+ generation (addresses presto-review suggestion #1).

Built [OnSteroids](https://onsteroids.ai)
2026-05-30 22:17:21 +02:00
Sergey Galuza 357ce8b07a feat(catalog): add Claude Opus 4.8 to Anthropic model registry
Register `claude-opus-4-8` in the cliproxy model catalog, web-server
pricing table, and UI catalog as an additive entry next to 4.7. Defaults
are unchanged (claude provider stays on sonnet-4-6); users opt into 4.8
explicitly via ANTHROPIC_MODEL or the dashboard.

Configuration mirrors 4.7:
- adaptive thinking levels (low through max), max distinct from xhigh
- extendedContext (1M) available
- nativeImageInput
- pricing $5/$25 in/out, $6.25/$0.5 cache

Built [OnSteroids](https://onsteroids.ai)
2026-05-30 17:16:27 +02:00
Sergey Galuza a7871283d4 test(cliproxy): replace process-wide mock.module with DI seams
Bun's `mock.module()` is process-wide and is NOT undone by `mock.restore()`.
Two test files used module-level mocks that leaked across test runs,
silently breaking unrelated suites that imported the mocked modules
transitively:

- tests/unit/cliproxy/version-checker-stale-cache.test.ts mocked
  binary/version-checker, contaminating cliproxy-stats-routes-install
  and cliproxy-stats-routes-model-update suites that import a route
  module which transitively imports version-checker.
- tests/unit/cliproxy/service-manager-startup.test.ts mocked 8 modules
  at top level (binary-manager, stats-fetcher, etc.), contaminating any
  later file that imports them.

CI happens to be green because file ordering on the GitHub runner places
victim files BEFORE contaminators in `bun test`. On Linux locally the
order is reversed, producing 6 reproducible test failures on every
`bun run test:fast` run. A change in OS, bun version, or new test files
that import the mocked modules could silently flip the CI runner's
order and surface these failures unexpectedly.

Replaced module-level mocks with explicit dependency-injection seams in
production code, following the existing pattern in version-checker.ts
and version-cache.ts (`fetchJsonFn?`, `fetchLatestVersionFn?`):

- src/cliproxy/types.ts: `BinaryManagerConfig.checkForUpdatesFn` (optional)
- src/cliproxy/binary/lifecycle.ts: route through new fn with default
- src/cliproxy/service-manager.ts: `ensureCliproxyService(deps?)` with
  optional `ensureBinaryFn`, `detectRunningProxyFn`,
  `configNeedsRegenerationFn`, `withStartupLockFn`

All deps fields are optional with real-implementation defaults, so
production callers are unchanged. Tests now inject deterministic stubs
through call-site parameters instead of module-level mocks.

Verified locally: \`bun run validate\` is now 2540 pass / 0 fail
(previously 2534 pass / 6 fail at the same upstream/main HEAD).

Built [OnSteroids](https://onsteroids.ai)
2026-04-26 09:43:09 +02:00
Sergey GaluzaandOnSteroids 45fe7ab086 feat(cliproxy): add 'max' thinking level for Claude Opus 4.7
Anthropic exposes `max` as a distinct adaptive-thinking effort above
`xhigh` on Opus 4.7. Previously the validator aliased user input `max`
down to `xhigh`, so users couldn't reach the real top-tier effort
through CCS.

Extend the validator:
- Add `max` to VALID_THINKING_LEVELS and THINKING_LEVEL_RANK (rank 6,
  above xhigh)
- Add `max` to THINKING_LEVEL_BUDGETS (65536, CCS-internal numeric
  mapping for closest-level lookups)
- Widen ThinkingSupport.maxLevel union to include 'max'

The existing `max: 'xhigh'` alias in findClosestLevel is kept as a
graceful fallback for models whose levels list does not include `max`
(e.g. Codex `gpt-5.4`), because exact-match on validLevels takes
priority — so Opus 4.7 returns `max` directly while Codex still maps
`max` -> `xhigh`.

Update the claude.claude-opus-4-7 catalog entry to expose
`['low', 'medium', 'high', 'xhigh', 'max']` with `maxLevel: 'max'`.

Built [OnSteroids](https://onsteroids.ai)

Co-Authored-By: OnSteroids <[email protected]>
2026-04-22 21:32:14 +02:00
Sergey GaluzaandOnSteroids 46920dbc08 fix(cliproxy): use adaptive thinking for Claude Opus 4.7
Per Anthropic docs, Claude Opus 4.7 only supports adaptive thinking;
manual `thinking.type: "enabled"` with `budget_tokens` is rejected
with HTTP 400.

Switch the claude provider's `claude-opus-4-7` entry from
`type: 'budget'` to `type: 'levels'` with the effort tiers exposed
by the API: `low | medium | high | xhigh`. The proxy is expected to
translate these into `thinking.type: "adaptive"` with the effort
parameter.

Opus 4.6 and Sonnet 4.6 keep `type: 'budget'` for now since the
deprecated mode is still functional on those models.

Built [OnSteroids](https://onsteroids.ai)

Co-Authored-By: OnSteroids <[email protected]>
2026-04-22 21:09:21 +02:00
Sergey Galuza de0f8b3264 test(model-pricing): add cache pricing coverage for Opus 4.7
Mirrors the existing `claude-opus-4-6` cache pricing test for both
`claude-opus-4-7` and `claude-opus-4-7-thinking` to explicitly
validate cache creation/read rates in end-to-end cost calculation.

Addresses PResto atrvd/ccs#8 issue #6 (suggestion).

Built [OnSteroids](https://onsteroids.ai)
2026-04-20 19:24:43 +02:00
Sergey Galuza 7492688eff test(cliproxy): cover Claude Opus 4.7 in Claude provider catalog
Adds a unit test verifying that `claude-opus-4-7` is registered in
the `claude` provider with its provider-specific settings:

- `thinking.zeroAllowed: false` (contrasts with AGY where it is true)
- `extendedContext: true` (1M context via Anthropic API)

Addresses PResto atrvd/ccs#8 issue #4 (suggestion).

Built [OnSteroids](https://onsteroids.ai)
2026-04-20 19:00:39 +02:00
Sergey Galuza 0d09199439 fix(cliproxy): address Presto review feedback on Opus 4.7
- model-catalog: change `claude-opus-4-7` description from "Latest
  flagship without thinking" to "Latest flagship model". The model
  supports thinking budget (min 1024, max 128000) but doesn't enable
  it by default; the old wording implied no thinking support, which
  was misleading. Aligns with the `claude` provider's description.

- generator: add DEFAULT_ANTIGRAVITY_ALIASES entry for non-thinking
  `claude-opus-4-7`, restoring symmetry with `claude-sonnet-4-6`
  (which has both -thinking and non-thinking aliases). Bump
  CLIPROXY_CONFIG_VERSION 18 → 19 to trigger regeneration on upgrade.

Addresses PResto atrvd/ccs#8 issues #2 (important) and #3 (suggestion).

Built [OnSteroids](https://onsteroids.ai)
2026-04-20 18:43:15 +02:00
Sergey Galuza faca421705 docs(cliproxy): document v18 config bump for Opus 4.7
Addresses PResto review (atrvd/ccs#8, issue #1): bumping
CLIPROXY_CONFIG_VERSION 17→18 was missing a changelog entry in the
header comment. Adds the v18 line to preserve regeneration history.

Built [OnSteroids](https://onsteroids.ai)
2026-04-20 18:14:15 +02:00
Sergey Galuza 61058123e1 feat(cliproxy): add Claude Opus 4.7 support
Adds Claude Opus 4.7 as a new model to the AGY (Antigravity) and Claude
provider catalogs, with pricing, Cursor IDE support, and updated defaults
across the codebase.

- Add claude-opus-4-7-thinking and claude-opus-4-7 to AGY catalog
  (defaultModel bumped to claude-opus-4-7-thinking)
- Add claude-opus-4-7 entry to Claude provider catalog
- Register claude-opus-4-7-thinking fork alias in CLIProxy config
  (CLIPROXY_CONFIG_VERSION bumped 17 -> 18)
- Add pricing for claude-opus-4-7 and claude-opus-4-7-thinking
  ($5/$25 per million, matching Opus 4.6)
- Add claude-4.7-opus and claude-4.7-opus-fast-mode to Cursor catalog
- Update ANTHROPIC_DEFAULT_OPUS_MODEL in base-claude settings to 4.7
- Update Droid adapter and code-reviewer fallback models to 4.7
- Update unit tests for model-catalog and model-pricing

Opus 4.6 is retained as a supported fallback in both catalogs.

Built [OnSteroids](https://onsteroids.ai)
2026-04-20 17:49:18 +02:00
Sergey Galuza dea704c57d fix(husky): re-exec pre-push under bash for sh compatibility
Husky v9 invokes hooks via `sh -e` regardless of the script's shebang,
causing `set -o pipefail` and bash regex `[[ =~ ]]` in .husky/pre-push
to fail with "Illegal option -o pipefail" on systems where /bin/sh is
not bash (Debian/Ubuntu dash).

Add a POSIX-compatible preamble that re-execs the script under bash
when invoked without BASH_VERSION. No changes to gate logic.

Built [OnSteroids](https://onsteroids.ai)
2026-04-20 17:23:27 +02:00
Sergey Galuza 91acec692a Merge remote-tracking branch 'upstream/main' 2026-04-20 17:19:23 +02:00
Sergey Galuza ef564cafdf ci: retrigger validation 2026-04-11 21:08:08 +02:00
Sergey Galuza ea2b16bb66 docs(cliproxy): add catalog --json to --help output
Built [OnSteroids](https://onsteroids.ai)
2026-04-11 20:47:10 +02:00
Sergey Galuza 7bf5b4b95e fix(cliproxy): guard against undefined catalog and add issueUrl field
- Add null check for catalog entries from Partial<Record> type
- Include issueUrl in JSON output for broken model tracking

Built [OnSteroids](https://onsteroids.ai)
2026-04-11 20:12:46 +02:00
Sergey Galuza 22acd96ba4 feat(cliproxy): add thinking config to catalog --json and test false values
- Include thinking support configuration (type, min, max, levels) in
  JSON output for reasoning-capable models
- Add test verifying explicit false booleans are preserved (not omitted)
- Add test verifying thinking config appears for thinking models

Built [OnSteroids](https://onsteroids.ai)
2026-04-11 20:12:46 +02:00
Sergey Galuza 9ac1ac9804 fix(cliproxy): preserve explicit false values in catalog --json
Use !== undefined checks instead of truthy checks so that explicitly
set false booleans (e.g. extendedContext: false) appear in JSON output,
allowing consumers to distinguish "not set" from "explicitly disabled".

Built [OnSteroids](https://onsteroids.ai)
2026-04-11 20:12:46 +02:00
Sergey Galuza fbfb130f4d feat(cliproxy): include model metadata in catalog --json output
- Expose tier, description, deprecated, broken, extendedContext,
  nativeImageInput fields (omitted when undefined)
- Simplify tests to use static imports instead of dynamic cache-busting
- Add integration tests verifying --json routing through handleCliproxyCommand
- Test --json priority over refresh/reset subcommands

Built [OnSteroids](https://onsteroids.ai)
2026-04-11 20:12:46 +02:00
Sergey Galuza 509d2e4dd8 test(cliproxy): add catalog --json tests and clarify flag priority
- Add unit tests verifying JSON output structure, field filtering,
  and minified format
- Document that --json takes priority over subcommands (refresh/reset)

Built [OnSteroids](https://onsteroids.ai)
2026-04-11 20:12:46 +02:00
Sergey Galuza ac92688cc5 docs(cliproxy): clarify catalog --json output format in JSDoc
Use TypeScript-style index signature notation instead of ambiguous
placeholder name in format description.

Built [OnSteroids](https://onsteroids.ai)
2026-04-11 20:12:46 +02:00
Sergey Galuza dceb6f6d37 feat(cliproxy): add --json flag to catalog command
Add machine-readable JSON output for `ccs cliproxy catalog --json`
to enable programmatic access to available models per provider.

Output format: { "provider": [{ "id": "...", "name": "..." }, ...] }

Closes CCS-1

Built [OnSteroids](https://onsteroids.ai)
2026-04-11 20:12:46 +02:00
Sergey Galuza 02c5a5c7a1 fix(cliproxy): guard against undefined catalog and add issueUrl field
- Add null check for catalog entries from Partial<Record> type
- Include issueUrl in JSON output for broken model tracking

Built [OnSteroids](https://onsteroids.ai)
2026-04-11 19:33:00 +02:00
Sergey Galuza c1d0a4d2eb feat(cliproxy): add thinking config to catalog --json and test false values
- Include thinking support configuration (type, min, max, levels) in
  JSON output for reasoning-capable models
- Add test verifying explicit false booleans are preserved (not omitted)
- Add test verifying thinking config appears for thinking models

Built [OnSteroids](https://onsteroids.ai)
2026-04-11 19:22:05 +02:00
Sergey Galuza f5520de42a fix(cliproxy): preserve explicit false values in catalog --json
Use !== undefined checks instead of truthy checks so that explicitly
set false booleans (e.g. extendedContext: false) appear in JSON output,
allowing consumers to distinguish "not set" from "explicitly disabled".

Built [OnSteroids](https://onsteroids.ai)
2026-04-11 19:08:24 +02:00
Sergey Galuza 6fc22625ac feat(cliproxy): include model metadata in catalog --json output
- Expose tier, description, deprecated, broken, extendedContext,
  nativeImageInput fields (omitted when undefined)
- Simplify tests to use static imports instead of dynamic cache-busting
- Add integration tests verifying --json routing through handleCliproxyCommand
- Test --json priority over refresh/reset subcommands

Built [OnSteroids](https://onsteroids.ai)
2026-04-11 18:53:33 +02:00
Sergey Galuza c1d462ea41 test(cliproxy): add catalog --json tests and clarify flag priority
- Add unit tests verifying JSON output structure, field filtering,
  and minified format
- Document that --json takes priority over subcommands (refresh/reset)

Built [OnSteroids](https://onsteroids.ai)
2026-04-11 18:27:39 +02:00
Sergey Galuza f090c32c2f docs(cliproxy): clarify catalog --json output format in JSDoc
Use TypeScript-style index signature notation instead of ambiguous
placeholder name in format description.

Built [OnSteroids](https://onsteroids.ai)
2026-04-11 18:02:32 +02:00
Sergey Galuza 48634549f8 chore: trigger PResto review 2026-04-11 17:52:25 +02:00
Sergey Galuza 92d76cad89 feat(cliproxy): add --json flag to catalog command
Add machine-readable JSON output for `ccs cliproxy catalog --json`
to enable programmatic access to available models per provider.

Output format: { "provider": [{ "id": "...", "name": "..." }, ...] }

Closes CCS-1

Built [OnSteroids](https://onsteroids.ai)
2026-04-11 17:52:25 +02:00
Sergey Galuza 79251d7af8 test(ci): add env isolation comment to persist-command-handler
Align with claudecode-env-stripping.test.ts style — explain why
CLAUDE_CONFIG_DIR is cleared in beforeEach for consistency across
test files.

Built [OnSteroids](https://onsteroids.ai)
2026-04-11 17:29:15 +02:00
Sergey Galuza 1a7fc4a3f2 test(ci): improve test isolation readability per review feedback
- Extract NEUTRAL_PROFILE_TYPE constant with JSDoc explaining why
  CCS_PROFILE_TYPE must be neutralised in subprocess env blocks
- Replace 6 bare '' occurrences with the named constant (DRY)
- Group save/delete operations in beforeEach with section comments

Built [OnSteroids](https://onsteroids.ai)
2026-04-11 17:18:51 +02:00
Sergey Galuza 2cc92e8bb8 test(ci): isolate CCS-managed env vars from host session
When tests run inside a CCS-managed Claude session, host env vars
(CLAUDE_CONFIG_DIR, CCS_PROFILE_TYPE) leak into subprocess spawns
and fixture setup, causing 9 test failures:

- persist-command-handler: reads real symlinked settings.json instead
  of temp fixture because CLAUDE_CONFIG_DIR overrides scoped CCS_HOME
- websearch-transformer: hook silently exits via shouldSkipHook()
  because CCS_PROFILE_TYPE=account triggers native_account_profile skip
- claudecode-env-stripping: normalizeSharedPluginMetadataPaths receives
  leaked CLAUDE_CONFIG_DIR instead of undefined for default profiles

Fix: clear CCS-managed env vars in beforeEach and neutralize
CCS_PROFILE_TYPE in subprocess env blocks.

Built [OnSteroids](https://onsteroids.ai)
2026-04-11 07:16:50 +02:00
Sergey GaluzaandOnSteroids e055890e16 fix: address PR #4 review - HTTPS tests and timeout handling
- Fix timeout test to use HTTPS server (tunnel uses https.request)
- Fix timeout event handling - call reject directly instead of relying on destroy error event
- Fix misleading comment in remote-token-uploader (Authorization header, not X-Management-Key)
- Remove unused imports in test files

Built [OnSteroids](https://onsteroids.ai)

Co-Authored-By: OnSteroids <[email protected]>
2026-01-14 18:06:58 +01:00
Sergey GaluzaandOnSteroids c3bfa34703 fix: address PR #4 review suggestions
- Fix race condition in start() using Promise instead of boolean flag
- Document that tunnel intentionally doesn't limit response sizes (streaming)
- Improve token upload failure visibility with actionable user message

Built [OnSteroids](https://onsteroids.ai)

Co-Authored-By: OnSteroids <[email protected]>
2026-01-14 18:06:58 +01:00
Sergey GaluzaandOnSteroids e7e95e6970 fix: increase timeout in connection tracking test for CI
Built [OnSteroids](https://onsteroids.ai)

Co-Authored-By: OnSteroids <[email protected]>
2026-01-14 18:06:58 +01:00