Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions gui/public/provider-icons/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ Export-client marks (used by the API tab's connect rows, not the provider list):
carries its authoring tool's generator comment).
- `kimi-color.svg` — already in the baseline as a provider icon; the API tab reuses
it for the Kimi Code client, which is the same Moonshot AI brand.
- `cline-color.svg` — the Cline mark introduced by
[`ec81f7fef9bb`](https://github.com/lidge-jun/opencodex/blob/ec81f7fef9bb0086d3d527cac234d3845ce4d559/gui/public/provider-icons/cline-color.svg),
whose commit identifies it as the official brand mark but records no download
URL. That Git object preserves the original 92x96 SVG. `b4820478fcea` removed
its fixed dimensions and normalized it to `viewBox="0 0 24 24"` with
`translate(0.5000 0.0000) scale(0.25000)`. The path, circle, rectangles, and
purple `#9F58FA` fill/strokes are unchanged. The Cline client reuses this
provider icon as an image, preserving its brand color.
- `aside.svg` — extracted 2026-08-31 from the installed Aside application, module
`Contents/Frameworks/Aside Framework.framework/Versions/1.0.825.1/Libraries/AsideAgentManager/assets/official-brand-symbol-*.js`.
It is Aside's own brand symbol, named as such by the vendor and rendered by
Expand Down
3 changes: 3 additions & 0 deletions gui/tests/fr-localization.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ const INTENTIONAL_ENGLISH = new Set<TKey>([
"api.clientConfig.clientRaycast",
"integrations.tab.omo",
"api.clientConfig.clientOmo",
// Cline CLI is the product name, identical in French and English.
"integrations.tab.cline",
"api.clientConfig.clientCline",
"models.reasoningEffort.minimal",
"models.reasoningEffort.max",
"pws.pacingRpmUnit",
Expand Down
4 changes: 2 additions & 2 deletions gui/tests/integrations-api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ import {

const originalFetch = globalThis.fetch;

test("DSH, Aside, Raycast and omo are file integration clients", () => {
test("the complete file integration client registry includes Cline", () => {
expect(FILE_INTEGRATION_CLIENTS).toEqual([
"opencode", "pi", "omp", "hermes", "openclaw", "kimi", "gajae", "dsh", "mcode", "zcode", "prime", "aside", "raycast", "omo",
"opencode", "pi", "omp", "hermes", "openclaw", "kimi", "gajae", "dsh", "mcode", "zcode", "prime", "aside", "raycast", "omo", "cline",
]);
});

Expand Down
3 changes: 3 additions & 0 deletions gui/tests/locale-parity.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ const ZH_TW_KEEP_ENGLISH: ReadonlySet<string> = new Set([
// "omo" is the product's own lowercase spelling, identical in every locale.
"integrations.tab.omo",
"api.clientConfig.clientOmo",
// Cline CLI is the product name, kept in English like the other client brands.
"integrations.tab.cline",
"api.clientConfig.clientCline",
"integrations.codex.title",
// Provider proper nouns kept in English
"provider.name.commandCodeAuth",
Expand Down
5 changes: 3 additions & 2 deletions scripts/test-layout/layout.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"domains": {
"providers": {
"match": [
"^(?:aside(?!-profile)|auto|azure|baseten|chutes|cline|command|commandcode|context|cyber|deepinfra|deepseek|digitalocean|exa|featherless|forward|hyperbolic|kimi|meta|mimo|minimax|moonshot|muse|new|nous|novita|nscale|nvidia|opencode|openrouter|qwen38|sambanova|umans|vercel|zcode|zhipu)-"
"^(?:aside(?!-profile)|auto|azure|baseten|chutes|cline(?!-(?:client|writer)(?:[.-]|$))|command|commandcode|context|cyber|deepinfra|deepseek|digitalocean|exa|featherless|forward|hyperbolic|kimi|meta|mimo|minimax|moonshot|muse|new|nous|novita|nscale|nvidia|opencode|openrouter|qwen38|sambanova|umans|vercel|zcode|zhipu)-"
],
"children": {
"cursor": [
Expand Down Expand Up @@ -109,6 +109,7 @@
"clients": {
"match": [
"^aside-profile(?!s-routes)",
"^cline-(?:client|writer)(?:[.-]|$)",
"^(?:desktop|omp|pi|prime|remote|sync)-"
]
},
Expand Down Expand Up @@ -1389,4 +1390,4 @@
"web-search",
"windows"
]
}
}
2 changes: 1 addition & 1 deletion src/cli/help.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ Usage:
ocx memory [--json] Alias of ocx observe memory
ocx api-key <sub> Alias of ocx access key
ocx access <sub> External API keys and endpoint information
ocx export --client <id> Print a client config wired to the running proxy (14 clients)
ocx export --client <id> Print a client config wired to the running proxy (15 clients)
ocx integration client <sub> Enable, disable, inspect or roll back a client integration
ocx grok <sub> Grok Build model selection and apply
ocx system <sub> Runtime settings, startup, sync, OpenCodex updates, and Codex CLI inspection
Expand Down
6 changes: 3 additions & 3 deletions tests/gui/integrations-invariants.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ afterEach(() => {
});

describe("the client registries cannot drift apart", () => {
test("every list of clients holds exactly the same thirteen ids", async () => {
test("every list of clients holds exactly the same fifteen ids", async () => {
/*
* Five lists name the same thirteen clients, and two of them are maintained by
* Five lists name the same fifteen clients, and two of them are maintained by
* hand: the GUI cannot import the backend registry, because that would
* pull node:os and node:path into the browser bundle. A client added
* server-side renders no row until someone remembers the tuple, and the
Expand All @@ -93,7 +93,7 @@ describe("the client registries cannot drift apart", () => {
const guiRouting = await import("../../gui/src/app-routing");

const expected = [...EXPORT_CLIENT_IDS].sort();
expect(expected).toHaveLength(14);
expect(expected).toHaveLength(15);

expect([...INTEGRATION_CLIENT_IDS].sort()).toEqual(expected);
expect([...gui.CLIENTS].sort()).toEqual(expected);
Expand Down
Loading