@mars-sea/dsh-commandcode-provider 0.11.2 → 0.11.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/lib/client.js +221 -141
- package/lib/client.js.map +1 -1
- package/lib/index.d.ts +25 -0
- package/lib/index.js +258 -8
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,18 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.11.3] - 2026-09-16
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- **Thinking text is also read from `reasoning_details`.** The gateway does not normalize the reasoning field across model families, and the difference is per family rather than global: DeepSeek answers with the scalar `reasoning` **plus** an OpenRouter-shaped `reasoning_details` array (`[{ type: 'reasoning.text', text, format, index }]`), while GLM, Qwen and Kimi answer with the DeepSeek-native `reasoning_content` (all measured against the live API on 2026-09-16, alongside the catalog sweep below). The adapter already read the first two spellings, so nothing was broken; the array is now a third fallback, so a family whose thinking arrives only that way is not silently dropped. Entries are read by their `text` member rather than filtered on `type === 'reasoning.text'`: the sibling shapes in that protocol carry `summary` or an encrypted blob instead of `text`, so a plain read already ignores them, while a type filter would drop a text-bearing variant added later — and losing thinking is the failure this exists to prevent.
|
|
13
|
+
- **`transportMaxRetries`: how many transport failures one request absorbs before the failure surfaces** (default 5, 0–50; Settings → Command Code → Advanced). It exists because the route's retry policy cannot express this: `providerRetryPolicy()` is captured once per route, so `TRANSPORT` had to share the near-unbounded window that `RATE_LIMIT`/`SERVER` need, and a connection that cannot be established is not a failure that asks to be waited out. The retries still run on the policy's own cadence (500 ms doubling), so the default spends ~15.5 s (0.5+1+2+4+8) on a blip before reporting it.
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- **Claude models work again on Provider API accounts** ([#46](https://github.com/Mars-Sea/dsh-commandcode-provider/issues/46)). The Provider API serves the whole Claude family only through `/provider/v1/messages`: posted to `/provider/v1/chat/completions`, every catalog Claude id — all eight, verified by posting all 69 models to that endpoint on 2026-09-16 — answers `400 Model "<id>" must be called via /provider/v1/messages (Anthropic Messages shape)`. The adapter's only pre-stream fallback was the Go-plan `upgrade_required` 403, so the rejection surfaced to the user as `PROVIDER_HTTP_ERROR`; and because the non-Go tiers are exactly the ones `resolveProtocol()` sends to the Provider API, the accounts ENTITLED to Claude were the ones that could never use it. Those models now take the CLI transport, which routes every one of them (a lower-plan key gets the ordinary `MODEL_NOT_IN_PLAN` 403 there, never a routing error), so no Messages transport is needed in the adapter. The decision is deliberately NOT written to `protocolCache`, which is keyed by API key alone: remembering it would pin the whole ACCOUNT to the CLI transport and drag DeepSeek, GLM and Qwen — all correctly served by the Provider API — along with it, which is why `rememberProtocol()` is not called on that path. `MESSAGES_ONLY_MODELS` in `src/capabilities.ts` records the measured set, and `requiresMessagesEndpoint()` also treats any `claude-*` id as Messages-only, so a Claude model shipping after this release is routed correctly by an un-updated plugin instead of hard-failing with the 400 above. The same sweep also confirmed the neighbouring report is a non-issue for this plugin: the reasoning-replay and thinking-display paths read every field spelling the gateway emits (see Added).
|
|
17
|
+
- **A transport failure no longer retries toward the 1000-attempt budget** ([#39](https://github.com/Mars-Sea/dsh-commandcode-provider/issues/39), second report). The report after 0.11.1 showed no context-window rejection at all: at ~710k tokens the adapter failed with undici's own `Connect Timeout Error ... timeout: 10000ms` (its default connect timeout — this plugin's `requestTimeoutMs` is 60 s and the connection phase never runs against the body upload) and, on another attempt, `read ECONNRESET` against `/alpha/generate`. Both are `TRANSPORT`, which the retry policy whitelists, so each entered the same 1000-attempt loop the 0.11.2 context-window fix left untouched: with waits doubling from 500 ms, the wait before attempt 11 alone is 512 s and the cumulative wait before it is ~500 s — the `模型请求重试已取消(11/1000)· 482s` row in the report is that 512 s countdown, 30 s in. `TRANSPORT` failures now consume a bounded budget on the `agent/request-error` hook: the first five are retried (~15.5 s of grace — 0.5+1+2+4+8 s waits, and the reporter's own first screenshot, a single `read ECONNRESET` that recovered on the next attempt, stays invisible), and the sixth surfaces the turn with a diagnosis that says what it is (connectivity, *not* a context-window or request-size rejection) and what usually fixes it. The check runs before the budget, so a cancelled turn is never retried and never spends a slot; the budget resets at each new step (one step *is* one model request, so the cap is per request and every step of a turn gets its own grace); and the accounting is keyed per agent, so one session's outage cannot disable another's retries. Everything else — the rate-limit window, a gateway 520, account rotation, the 413 image step-down — is unchanged. The report's "long context" correlation is a red herring, and this change does not depend on ruling it in or out: verified against the live endpoint, request bodies of 1/8/30 MB all returned the provider's own `401` in 1.9/2.7/5.7 s. `tests/transport-retry.test.ts` pins the budget, the per-agent isolation, the cancellation ordering and the message.
|
|
18
|
+
- **A message with no `source` tag no longer kills the whole stream** ([#47](https://github.com/Mars-Sea/dsh-commandcode-provider/issues/47)). `messagesToCC` read `message.source.kind` at four sites to tell a tool result from a plain user message. `source` is producer-supplied and nothing validates it — dsh-llm's type declares it required, but the runtime never checks it and every adapter shipped before this one ignored the field entirely (`dsh-llm-deepseek` never reads it) — so a third-party plugin that assembles its own history can omit it and keep working everywhere else. This adapter, the first to actually read the field, was therefore the first to crash on such a message: `TypeError: Cannot read properties of undefined (reading 'kind')` in the serialization phase, 0–8 ms in, before a request was sent, with an error naming neither the message nor the producer. Both transports now classify a message through one predicate (`isToolResultMessage()`): a PRESENT tag stays authoritative, while an ABSENT one falls back to the content shape — a `user` message whose first block is a `tool-result` is still a tool result, because `pairedToolCalls()` counts such a block from ANY message and dropping it at emission would leave the assistant's tool call unanswered, which the gateway rejects. An untagged plain user message (the reported case, from dsh-mneme's memory pipeline) is now simply converted as the user message it is. Pinned by three tests in `tests/adapter.test.ts`, each run through both transports: the untagged user message, the untagged tool result, and the authoritative tag.
|
|
19
|
+
- **The plugin's stylesheet no longer reaches into other components' markup** ([#48](https://github.com/Mars-Sea/dsh-commandcode-provider/issues/48)). Installing the plugin stacked the `ask_user_question` dialog's side-by-side buttons vertically. The cause was one rule in the panel stylesheet, `[class*="_footerActions"]{flex-direction:column}`, written for the sidebar's footer-action container so this card's full-width line and ui-cordis's chip stack instead of overflowing the shell's flex ROW. `footerActions` is not a stem the sidebar owns alone: `@deepseek-ai/dsh-client-ui-user-questions` renders that dialog's button row as `Mbwy4a_footerActions`, so the unanchored attribute-substring selector matched it too and overrode the row's `display:flex`. The rule is now anchored to the sidebar's own foot area (`[class*="_footArea"] [class*="_footerActions"]`), a stem declared by dsh-client-ui-sidebar alone — audited across every client bundle of the 0.1.6-alpha.1 engine, together with our own `cc-`/`ccp-` class names, which collide with no engine class — so the sidebar layout fix is unchanged and no other component can be reached. The settings-page stylesheet moved to `src/client/page-styles.ts` so both sheets can be audited without importing the React tree, and `tests/styles.test.ts` now enforces the containment in two layers: a structural audit of every selector compound in both sheets, and a simulation against the real foreign class stems proving the dialog's row is no longer matched while the sidebar's still is.
|
|
20
|
+
|
|
9
21
|
## [0.11.2] - 2026-09-15
|
|
10
22
|
|
|
11
23
|
### Added
|
package/lib/client.js
CHANGED
|
@@ -157,6 +157,10 @@ window.__ModuleLoader__.load({
|
|
|
157
157
|
min: 1,
|
|
158
158
|
max: MAX_TIMEOUT_MS
|
|
159
159
|
}),
|
|
160
|
+
numberField$1("transportMaxRetries", {
|
|
161
|
+
min: 0,
|
|
162
|
+
max: 50
|
|
163
|
+
}),
|
|
160
164
|
booleanField$1("filterModelsByPlan"),
|
|
161
165
|
booleanField$1("webSearch"),
|
|
162
166
|
booleanField$1("showSidebarQuota"),
|
|
@@ -310,6 +314,7 @@ window.__ModuleLoader__.load({
|
|
|
310
314
|
defaultWorkingDir: this.defaultWorkingDir,
|
|
311
315
|
requestTimeoutMs: this.field("requestTimeoutMs"),
|
|
312
316
|
streamIdleTimeoutMs: this.field("streamIdleTimeoutMs"),
|
|
317
|
+
transportMaxRetries: this.field("transportMaxRetries"),
|
|
313
318
|
filterModelsByPlan: this.field("filterModelsByPlan"),
|
|
314
319
|
webSearch: this.field("webSearch"),
|
|
315
320
|
showSidebarQuota: this.field("showSidebarQuota"),
|
|
@@ -2150,7 +2155,7 @@ window.__ModuleLoader__.load({
|
|
|
2150
2155
|
}
|
|
2151
2156
|
//#endregion
|
|
2152
2157
|
//#region package.json
|
|
2153
|
-
var version = "0.11.
|
|
2158
|
+
var version = "0.11.3";
|
|
2154
2159
|
var repository = {
|
|
2155
2160
|
"type": "git",
|
|
2156
2161
|
"url": "git+https://github.com/Mars-Sea/dsh-commandcode-provider.git"
|
|
@@ -2349,6 +2354,7 @@ window.__ModuleLoader__.load({
|
|
|
2349
2354
|
"workingDir",
|
|
2350
2355
|
"requestTimeoutMs",
|
|
2351
2356
|
"streamIdleTimeoutMs",
|
|
2357
|
+
"transportMaxRetries",
|
|
2352
2358
|
"filterModelsByPlan",
|
|
2353
2359
|
"webSearch",
|
|
2354
2360
|
"showSidebarQuota"
|
|
@@ -2494,6 +2500,17 @@ window.__ModuleLoader__.load({
|
|
|
2494
2500
|
onReset: () => onReset("streamIdleTimeoutMs"),
|
|
2495
2501
|
t
|
|
2496
2502
|
}),
|
|
2503
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
2504
|
+
id: "cc-transport-max-retries",
|
|
2505
|
+
label: t("transportMaxRetries"),
|
|
2506
|
+
hint: t("transportMaxRetriesHint"),
|
|
2507
|
+
state: state.transportMaxRetries,
|
|
2508
|
+
disabled,
|
|
2509
|
+
numeric: true,
|
|
2510
|
+
onEdit: (text) => onEdit("transportMaxRetries", text),
|
|
2511
|
+
onReset: () => onReset("transportMaxRetries"),
|
|
2512
|
+
t
|
|
2513
|
+
}),
|
|
2497
2514
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToggleField, {
|
|
2498
2515
|
id: "cc-filter-models-by-plan",
|
|
2499
2516
|
label: t("filterModelsByPlan"),
|
|
@@ -5582,6 +5599,165 @@ window.__ModuleLoader__.load({
|
|
|
5582
5599
|
"data-ccp-session-cost-anchor": ""
|
|
5583
5600
|
});
|
|
5584
5601
|
}
|
|
5602
|
+
//#endregion
|
|
5603
|
+
//#region src/client/page-styles.ts
|
|
5604
|
+
/**
|
|
5605
|
+
* Stylesheet for the Command Code settings page — and the Models-page provider
|
|
5606
|
+
* card, which shares its `cc-` classes.
|
|
5607
|
+
*
|
|
5608
|
+
* Returned as a string rather than injected here so the modules stay free of
|
|
5609
|
+
* DOM side effects at import time: `./index.ts` installs it once, keyed by
|
|
5610
|
+
* `PAGE_CSS_ID`. It is a module of its own rather than a literal inside the
|
|
5611
|
+
* client entry so `tests/styles.test.ts` can audit every rule without importing
|
|
5612
|
+
* the React tree (which pulls `*.module.css` through the primitives package and
|
|
5613
|
+
* needs a loader registered first).
|
|
5614
|
+
*
|
|
5615
|
+
* Every colour comes from a harness theme alias with a neutral fallback, so the
|
|
5616
|
+
* page follows the active theme (light/dark and any brand pack) without
|
|
5617
|
+
* hardcoded values. Classes are `cc-` prefixed to stay clear of the panel's
|
|
5618
|
+
* `ccp-` set.
|
|
5619
|
+
*
|
|
5620
|
+
* @module dsh-commandcode-provider/client/page-styles
|
|
5621
|
+
*/
|
|
5622
|
+
/**
|
|
5623
|
+
* Stylesheet id (the `data-plugin-css` value that makes injection idempotent).
|
|
5624
|
+
*
|
|
5625
|
+
* The package prefix must match the one the panel stylesheet uses
|
|
5626
|
+
* (`PANEL_CSS_ID` in `./panel-styles.ts`) and this package's real name: an id is
|
|
5627
|
+
* the injection's identity, so a stale fork prefix would let a second copy of
|
|
5628
|
+
* the plugin inject the same rules twice and would misreport the owner in the
|
|
5629
|
+
* DOM. The two ids must also stay distinct from each other — they key two
|
|
5630
|
+
* separate style tags, and a shared id would make the second injection a no-op
|
|
5631
|
+
* that silently drops one stylesheet.
|
|
5632
|
+
*/
|
|
5633
|
+
const PAGE_CSS_ID = "@mars-sea/dsh-commandcode-provider/CommandCodeSettingsPage.module.css";
|
|
5634
|
+
/** The settings-page stylesheet. */
|
|
5635
|
+
const PAGE_CSS = `
|
|
5636
|
+
.cc-section{max-width:720px;color:var(--dsw-alias-label-primary);flex-direction:column;gap:12px;display:flex}
|
|
5637
|
+
.cc-title{margin:0;font-size:18px;font-weight:600}
|
|
5638
|
+
.cc-intro{color:var(--dsw-alias-label-tertiary);margin:0;font-size:13px;line-height:1.5}
|
|
5639
|
+
.cc-readOnly{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}
|
|
5640
|
+
.cc-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;padding:4px 16px}
|
|
5641
|
+
.cc-field{flex-direction:column;gap:6px;padding:12px 0;display:flex}
|
|
5642
|
+
.cc-field+.cc-field{border-top:1px solid var(--dsw-alias-border-l2)}
|
|
5643
|
+
.cc-fieldHead{align-items:center;gap:8px;display:flex}
|
|
5644
|
+
.cc-label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}
|
|
5645
|
+
.cc-badges{align-items:center;gap:8px;display:inline-flex}
|
|
5646
|
+
.cc-badge{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}
|
|
5647
|
+
.cc-badgeMuted{white-space:nowrap;color:var(--dsw-alias-label-tertiary);border-radius:999px;padding:1px 8px;font-size:11px;line-height:17px}
|
|
5648
|
+
.cc-reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}
|
|
5649
|
+
.cc-reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}
|
|
5650
|
+
.cc-reset:disabled{cursor:default;opacity:.5}
|
|
5651
|
+
.cc-input{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}
|
|
5652
|
+
.cc-input:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}
|
|
5653
|
+
.cc-input:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}
|
|
5654
|
+
/* The routing-rule model multi-select: a button trigger that opens an
|
|
5655
|
+
* anchored Menu of checkbox rows. The trigger mirrors .cc-input sizing so it
|
|
5656
|
+
* sits flush with the sibling account select. */
|
|
5657
|
+
.cc-ruleTrigger{align-items:center;gap:8px;display:flex;width:100%;text-align:left;cursor:pointer}
|
|
5658
|
+
.cc-ruleTrigger:disabled{cursor:default}
|
|
5659
|
+
.cc-ruleTriggerText{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
5660
|
+
.cc-ruleCaret{flex-shrink:0;border-right:1.5px solid var(--dsw-alias-label-tertiary);border-bottom:1.5px solid var(--dsw-alias-label-tertiary);width:6px;height:6px;margin-right:4px;margin-bottom:2px;transform:rotate(45deg)}
|
|
5661
|
+
.cc-checkRow{align-items:center;gap:8px;display:inline-flex;min-width:0}
|
|
5662
|
+
.cc-checkRow:hover{cursor:pointer}
|
|
5663
|
+
.cc-check{appearance:none;flex-shrink:0;width:15px;height:15px;margin:0;border:1px solid var(--dsw-alias-border-l2);border-radius:4px;background:var(--dsw-alias-bg-layer-1);position:relative}
|
|
5664
|
+
.cc-check:checked{background:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary)}
|
|
5665
|
+
.cc-check:checked::after{content:'';position:absolute;top:2px;left:5px;width:3px;height:7px;border:solid #fff;border-width:0 1.5px 1.5px 0;transform:rotate(45deg)}
|
|
5666
|
+
.cc-checkName{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
5667
|
+
/* The model multi-select search box: stacked under the trigger while the
|
|
5668
|
+
* dropdown is open, same input sizing so the pair reads as one control. The
|
|
5669
|
+
* box lives inside the Menu anchor (which renders inside the Menu's root
|
|
5670
|
+
* span), so focusing/typing it never trips the Menu's outside-click close. */
|
|
5671
|
+
.cc-modelSelectAnchor{flex-direction:column;gap:6px;display:flex;width:100%}
|
|
5672
|
+
.cc-modelSearch{width:100%}
|
|
5673
|
+
.cc-modelSearch::-webkit-search-cancel-button{cursor:pointer}
|
|
5674
|
+
/* Selects need their own treatment to sit flush with the text inputs:
|
|
5675
|
+
* the UA stylesheet renders <select> border-box (34px total vs the inputs'
|
|
5676
|
+
* 36px) and forces its own menulist text metrics, so drop the native
|
|
5677
|
+
* chrome entirely (appearance:none), restore content-box so the outer box
|
|
5678
|
+
* matches the inputs again, and draw the chevron ourselves. Longhand
|
|
5679
|
+
* background-* only — the shorthand would reset .cc-input's background. */
|
|
5680
|
+
select.cc-input{appearance:none;-webkit-appearance:none;-moz-appearance:none;box-sizing:content-box;padding-right:32px;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='7' viewBox='0 0 12 7'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%23888f98' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 11px center}
|
|
5681
|
+
.cc-inputInvalid{border-color:var(--dsw-alias-label-error)}
|
|
5682
|
+
.cc-invalid{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}
|
|
5683
|
+
/* The Advanced card: its header row is one full-width toggle button; the
|
|
5684
|
+
* chevron is two borders on a rotated square (no icon dependency). */
|
|
5685
|
+
.cc-advancedHead{align-items:center;gap:8px;display:flex;width:100%;padding:12px 0;background:0 0;border:none;cursor:pointer;font:inherit;text-align:left}
|
|
5686
|
+
.cc-advancedHead:hover .cc-advancedTitle{color:var(--dsw-alias-label-primary)}
|
|
5687
|
+
.cc-advancedTitle{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500;line-height:1.5}
|
|
5688
|
+
.cc-advancedSpacer{flex:1}
|
|
5689
|
+
.cc-chevron{flex-shrink:0;border-right:1.5px solid var(--dsw-alias-label-tertiary);border-bottom:1.5px solid var(--dsw-alias-label-tertiary);width:8px;height:8px;margin-right:4px;margin-bottom:2px;transform:rotate(45deg);transition:transform .15s ease}
|
|
5690
|
+
.cc-chevronUp{transform:rotate(-135deg);margin-bottom:-3px}
|
|
5691
|
+
.cc-advancedBody{flex-direction:column;display:flex}
|
|
5692
|
+
.cc-advancedBody>.cc-field:first-of-type{border-top:1px solid var(--dsw-alias-border-l2)}
|
|
5693
|
+
.cc-hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}
|
|
5694
|
+
.cc-footer{justify-content:flex-end;align-items:center;gap:8px;display:flex}
|
|
5695
|
+
.cc-toggleRow{align-items:center;gap:8px;cursor:pointer;display:flex}
|
|
5696
|
+
.cc-toggleRow:has(.cc-toggle:disabled){cursor:default}
|
|
5697
|
+
.cc-toggle{appearance:none;flex-shrink:0;background:var(--dsw-alias-border-l2);border-radius:999px;width:30px;height:18px;margin:0;cursor:pointer;position:relative;transition:background .15s ease}
|
|
5698
|
+
.cc-toggle:checked{background:var(--dsw-alias-brand-primary)}
|
|
5699
|
+
.cc-toggle::after{content:'';background:#fff;border-radius:50%;width:14px;height:14px;position:absolute;top:2px;left:2px;transition:left .15s ease}
|
|
5700
|
+
.cc-toggle:checked::after{left:14px}
|
|
5701
|
+
.cc-toggle:disabled{cursor:default;opacity:.5}
|
|
5702
|
+
.cc-failed{min-width:0;color:var(--dsw-alias-label-error);flex:1;margin:0;font-size:12px;line-height:1.5}
|
|
5703
|
+
.cc-usageCard{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;padding:14px 16px;flex-direction:column;gap:12px;display:flex}
|
|
5704
|
+
.cc-usageHead{align-items:center;gap:8px;display:flex}
|
|
5705
|
+
.cc-usageTitle{color:var(--dsw-alias-label-primary);flex:1;margin:0;font-size:13px;font-weight:600;line-height:1.5}
|
|
5706
|
+
.cc-usageAccount{max-width:40%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}
|
|
5707
|
+
.cc-usagePlan{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-brand-primary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:600;line-height:17px}
|
|
5708
|
+
.cc-usagePlanStatus{white-space:nowrap;color:var(--dsw-alias-label-error);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}
|
|
5709
|
+
.cc-usageRefresh{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}
|
|
5710
|
+
.cc-usageRefresh:hover:not(:disabled){color:var(--dsw-alias-label-primary)}
|
|
5711
|
+
.cc-usageRefresh:disabled{cursor:default;opacity:.5}
|
|
5712
|
+
.cc-usageHint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}
|
|
5713
|
+
.cc-usageError{align-items:center;gap:8px;color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5;display:flex}
|
|
5714
|
+
.cc-usageStats{grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:8px;display:grid}
|
|
5715
|
+
.cc-usageStat{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:8px;padding:8px 10px;flex-direction:column;gap:2px;display:flex}
|
|
5716
|
+
.cc-usageStatLabel{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.5}
|
|
5717
|
+
.cc-usageStatValue{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}
|
|
5718
|
+
.cc-usageStatSub{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.5}
|
|
5719
|
+
.cc-usageWindows{flex-direction:column;gap:16px;display:flex}
|
|
5720
|
+
.cc-usageWindow{flex-direction:column;gap:6px;display:flex}
|
|
5721
|
+
.cc-usageWindowHead{align-items:baseline;gap:8px;display:flex}
|
|
5722
|
+
.cc-usageWindowLabel{color:var(--dsw-alias-label-secondary);flex:1;font-size:12px;font-weight:500;line-height:1.5}
|
|
5723
|
+
.cc-usageWindowValue{color:var(--dsw-alias-label-primary);font-size:12px;font-weight:500;line-height:1.5}
|
|
5724
|
+
.cc-usageExceeded{color:var(--dsw-alias-label-error);font-size:11px;font-weight:500;line-height:1.5}
|
|
5725
|
+
.cc-usageBar{overflow:hidden;background:var(--dsw-alias-bg-layer-1);border-radius:999px;height:6px}
|
|
5726
|
+
.cc-usageBarFill{background:var(--dsw-alias-brand-primary);border-radius:999px;height:100%;transition:width .3s ease}
|
|
5727
|
+
.cc-usageBarFillWarn{background:var(--dsw-alias-label-error)}
|
|
5728
|
+
@media (prefers-reduced-motion:reduce){.cc-chevron,.cc-toggle,.cc-toggle::after,.cc-usageBarFill{transition:none}}.cc-usageWindowReset{color:var(--dsw-alias-label-tertiary);margin:0;font-size:11px;line-height:1.5}
|
|
5729
|
+
.cc-usageMeta{align-items:center;gap:8px;display:flex}
|
|
5730
|
+
.cc-accountReport{flex-direction:column;gap:12px;display:flex}
|
|
5731
|
+
.cc-tabs{flex-wrap:wrap;gap:6px;display:flex}
|
|
5732
|
+
.cc-tab{align-items:center;font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);border-radius:999px;padding:2px 10px;font-size:12px;line-height:18px;display:inline-flex;gap:6px}
|
|
5733
|
+
.cc-tab:hover:not(.cc-tabActive){color:var(--dsw-alias-label-primary)}
|
|
5734
|
+
.cc-tabActive{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-brand-primary)}
|
|
5735
|
+
.cc-tabDotOk{background:var(--dsw-alias-brand-primary);border-radius:50%;width:6px;height:6px}
|
|
5736
|
+
.cc-tabDotWarn{background:#d97706;border-radius:50%;width:6px;height:6px}
|
|
5737
|
+
.cc-tabDotError{background:var(--dsw-alias-label-error);border-radius:50%;width:6px;height:6px}
|
|
5738
|
+
.cc-usageMetaSpacer{flex:1}
|
|
5739
|
+
.cc-usageUpdated{color:var(--dsw-alias-label-tertiary);margin:0;font-size:11px;line-height:1.5}
|
|
5740
|
+
.cc-usagePartial{color:var(--dsw-alias-label-error);margin:0;font-size:11px;line-height:1.5}
|
|
5741
|
+
.cc-usageBlocked{border:1px solid var(--dsw-alias-label-error);border-radius:10px;padding:10px 12px;display:flex;flex-direction:column;gap:4px}
|
|
5742
|
+
.cc-usageBlockedTitle{color:var(--dsw-alias-label-error);margin:0;font-size:13px;font-weight:600;line-height:1.5}
|
|
5743
|
+
.cc-usageBlockedHint{color:var(--dsw-alias-label-secondary);margin:0;font-size:12px;line-height:1.5}
|
|
5744
|
+
.cc-version{margin:4px 0 0;text-align:center;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:1.5}
|
|
5745
|
+
/* The Models-page provider panel root: unstyled by design — the row card the
|
|
5746
|
+
* Models page owns supplies the surface, the panel only stacks its controls. */
|
|
5747
|
+
.cc-providerCard{flex-direction:column;display:flex}
|
|
5748
|
+
/* The update hint rides the footer version line: warning-tinted (with a
|
|
5749
|
+
* muted fallback for themes without the alias), quiet until hovered. */
|
|
5750
|
+
.cc-versionLink{color:var(--dsw-alias-state-warning-primary,var(--dsw-alias-label-secondary));text-decoration:none}
|
|
5751
|
+
.cc-versionLink:hover{color:var(--dsw-alias-label-primary);text-decoration:underline;text-underline-position:under}
|
|
5752
|
+
/* The login panel rides the connection card as one more field row; the
|
|
5753
|
+
* authorization link is the only branded element on it. */
|
|
5754
|
+
.cc-loginLink{color:var(--dsw-alias-brand-primary);text-decoration:none;font-size:12px;line-height:1.5}
|
|
5755
|
+
.cc-loginLink:hover{text-decoration:underline;text-underline-position:under}
|
|
5756
|
+
.cc-loginDone{color:var(--dsw-alias-state-success-primary,var(--dsw-alias-label-secondary))}
|
|
5757
|
+
.cc-loginError{color:var(--dsw-alias-label-error)}
|
|
5758
|
+
.cc-saved{color:var(--dsw-alias-state-success-primary,var(--dsw-alias-label-secondary));margin:0;font-size:12px;font-weight:500;line-height:1.5}
|
|
5759
|
+
.cc-badgeWarn{background:var(--dsw-alias-state-warning-secondary,var(--dsw-alias-bg-module-platform));color:var(--dsw-alias-state-warning-primary,var(--dsw-alias-label-secondary))}
|
|
5760
|
+
`;
|
|
5585
5761
|
//#endregion
|
|
5586
5762
|
//#region src/client/panel-styles.ts
|
|
5587
5763
|
/**
|
|
@@ -5590,8 +5766,16 @@ window.__ModuleLoader__.load({
|
|
|
5590
5766
|
*
|
|
5591
5767
|
* Returned as a string rather than injected here so the modules stay free of
|
|
5592
5768
|
* DOM side effects at import time — the client entry installs it once, keyed
|
|
5593
|
-
* by the same `data-plugin-css` attribute the settings-page stylesheet
|
|
5594
|
-
* and removes it again when the plugin's fiber
|
|
5769
|
+
* by the same `data-plugin-css` attribute the settings-page stylesheet
|
|
5770
|
+
* (`./page-styles.ts`) uses, and removes it again when the plugin's fiber
|
|
5771
|
+
* unwinds.
|
|
5772
|
+
*
|
|
5773
|
+
* These rules are GLOBAL CSS: every selector in here can match markup this
|
|
5774
|
+
* plugin did not render. So each one is either qualified by a `ccp-` class of
|
|
5775
|
+
* our own, or anchored to the sidebar region it has to lay out — and the one
|
|
5776
|
+
* foreign anchor carries its justification in place (see the footer card
|
|
5777
|
+
* block; issue #48). `tests/styles.test.ts` audits that containment for both
|
|
5778
|
+
* stylesheets and simulates it against the real foreign class stems.
|
|
5595
5779
|
*
|
|
5596
5780
|
* Every colour comes from a harness theme alias with a neutral fallback, so
|
|
5597
5781
|
* the panel follows the active theme (light/dark and any brand pack) without
|
|
@@ -5604,9 +5788,12 @@ window.__ModuleLoader__.load({
|
|
|
5604
5788
|
* Stylesheet id (the `data-plugin-css` value that makes injection idempotent).
|
|
5605
5789
|
*
|
|
5606
5790
|
* The package prefix must match the one the settings-page stylesheet uses
|
|
5607
|
-
* (`
|
|
5608
|
-
* injection's identity, so a stale fork prefix would let a second copy of
|
|
5609
|
-
* plugin inject the same rules twice and would misreport the owner in the
|
|
5791
|
+
* (`PAGE_CSS_ID` in `./page-styles.ts`) and this package's real name: an id is
|
|
5792
|
+
* the injection's identity, so a stale fork prefix would let a second copy of
|
|
5793
|
+
* the plugin inject the same rules twice and would misreport the owner in the
|
|
5794
|
+
* DOM. The two ids must also stay distinct from each other — they key two
|
|
5795
|
+
* separate style tags, and a shared id would make the second injection a no-op
|
|
5796
|
+
* that silently drops one stylesheet.
|
|
5610
5797
|
*/
|
|
5611
5798
|
const PANEL_CSS_ID = "@mars-sea/dsh-commandcode-provider/CommandCodePanel.module.css";
|
|
5612
5799
|
/** The panel stylesheet. */
|
|
@@ -5620,11 +5807,28 @@ window.__ModuleLoader__.load({
|
|
|
5620
5807
|
|
|
5621
5808
|
The shell's container is a flex ROW whose occupants (this card and ui-cordis's
|
|
5622
5809
|
footer chip) each declare a full-width line and shrink-proof flex, so as a row
|
|
5623
|
-
it would overflow the column
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
5810
|
+
it would overflow the column: this card's flex:0 0 auto cannot shrink, and the
|
|
5811
|
+
chip's width:100% basis would absorb the whole overflow and collapse to
|
|
5812
|
+
nothing. Both were written for a full-width line, which is exactly what a
|
|
5813
|
+
column gives them. Matched by the CSS-module class STEM — never a hashed name
|
|
5814
|
+
— so a dsh that renames it degrades to the shell's own row rather than
|
|
5815
|
+
breaking.
|
|
5816
|
+
|
|
5817
|
+
THE ANCHOR IS LOAD-BEARING, and it is the whole reason this selector is not
|
|
5818
|
+
just [class*="_footerActions"] (issue #48). "footerActions" is NOT a stem this
|
|
5819
|
+
shell owns alone: @deepseek-ai/dsh-client-ui-user-questions renders the
|
|
5820
|
+
ask-user-question dialog's button row as Mbwy4a_footerActions, so the
|
|
5821
|
+
unanchored rule forced THAT row into a column too and stacked the dialog's
|
|
5822
|
+
side-by-side buttons on every page. "footArea" is declared by
|
|
5823
|
+
dsh-client-ui-sidebar alone — verified against every client bundle of the
|
|
5824
|
+
0.1.6-alpha.1 engine, and against our own cc-/ccp- class names, which collide
|
|
5825
|
+
with no engine class — so anchoring under it keeps the sidebar layout fix and
|
|
5826
|
+
cannot reach another component's markup. The descendant combinator (rather
|
|
5827
|
+
than a child one) deliberately survives a wrapper element appearing between
|
|
5828
|
+
the two: a renamed or restructured shell should degrade to its own row, not
|
|
5829
|
+
lose the fix. tests/styles.test.ts pins both halves of this — the dialog row
|
|
5830
|
+
is no longer matched, the sidebar row still is. */
|
|
5831
|
+
[class*="_footArea"] [class*="_footerActions"]{flex-direction:column}
|
|
5628
5832
|
.ccp-foot{box-sizing:border-box;flex:0 0 auto;width:100%;min-width:0;font:inherit;color:var(--dsw-alias-label-secondary);text-align:left;cursor:pointer;background:0 0;border:1px solid transparent;border-radius:10px;flex-direction:column;gap:6px;margin:0 0 4px;padding:8px;display:flex}
|
|
5629
5833
|
.ccp-foot:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover);border-color:var(--dsw-alias-border-l2)}
|
|
5630
5834
|
.ccp-foot:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}
|
|
@@ -5750,6 +5954,8 @@ window.__ModuleLoader__.load({
|
|
|
5750
5954
|
requestTimeoutMsHint: "等待响应首个字节的超时;默认 60000。",
|
|
5751
5955
|
streamIdleTimeoutMs: "流空闲超时(毫秒)",
|
|
5752
5956
|
streamIdleTimeoutMsHint: "生成流停滞多久视为断连;默认 300000(长思考模型可静默数分钟,默认值刻意放宽)。",
|
|
5957
|
+
transportMaxRetries: "网络失败重试次数",
|
|
5958
|
+
transportMaxRetriesHint: "连接失败时自动重试几次,默认 5(各次等待 0.5+1+2+4+8 秒,合计约 15 秒)。超过后直接报错,不再按指数退避长时间等待;填 0 表示不重试。限流、5xx 等由服务端要求重试的失败不受此项影响。",
|
|
5753
5959
|
advancedSettings: "高级设置",
|
|
5754
5960
|
advancedSettingsHint: "API 地址、工作目录、超时、模型过滤、联网搜索与侧边栏额度卡片等不常修改的选项。",
|
|
5755
5961
|
advancedOverriddenOne: "已自定义 1 项",
|
|
@@ -5884,6 +6090,8 @@ window.__ModuleLoader__.load({
|
|
|
5884
6090
|
requestTimeoutMsHint: "Time to wait for the first response byte; default 60000.",
|
|
5885
6091
|
streamIdleTimeoutMs: "Stream idle timeout (ms)",
|
|
5886
6092
|
streamIdleTimeoutMsHint: "How long a stalled stream is treated as dead; default 300000 (deliberately generous — long-thinking models can stay silent for minutes).",
|
|
6093
|
+
transportMaxRetries: "Transport retries",
|
|
6094
|
+
transportMaxRetriesHint: "How many times a failed connection is retried automatically; default 5 (waits of 0.5+1+2+4+8s, ~15s in total). After that the failure is reported instead of waiting on the exponential backoff. 0 disables the retries. Rate limits and 5xx answers keep their own, longer retry window.",
|
|
5887
6095
|
advancedSettings: "Advanced",
|
|
5888
6096
|
advancedSettingsHint: "Rarely touched options: API base URL, working directory, timeouts, model filtering, web search, and the sidebar quota card.",
|
|
5889
6097
|
advancedOverriddenOne: "1 customized",
|
|
@@ -6003,141 +6211,13 @@ window.__ModuleLoader__.load({
|
|
|
6003
6211
|
};
|
|
6004
6212
|
//#endregion
|
|
6005
6213
|
//#region src/client/index.ts
|
|
6006
|
-
/** CSS for the settings page, injected once (harness bundle convention). */
|
|
6007
|
-
const PAGE_CSS = `
|
|
6008
|
-
.cc-section{max-width:720px;color:var(--dsw-alias-label-primary);flex-direction:column;gap:12px;display:flex}
|
|
6009
|
-
.cc-title{margin:0;font-size:18px;font-weight:600}
|
|
6010
|
-
.cc-intro{color:var(--dsw-alias-label-tertiary);margin:0;font-size:13px;line-height:1.5}
|
|
6011
|
-
.cc-readOnly{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}
|
|
6012
|
-
.cc-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;padding:4px 16px}
|
|
6013
|
-
.cc-field{flex-direction:column;gap:6px;padding:12px 0;display:flex}
|
|
6014
|
-
.cc-field+.cc-field{border-top:1px solid var(--dsw-alias-border-l2)}
|
|
6015
|
-
.cc-fieldHead{align-items:center;gap:8px;display:flex}
|
|
6016
|
-
.cc-label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}
|
|
6017
|
-
.cc-badges{align-items:center;gap:8px;display:inline-flex}
|
|
6018
|
-
.cc-badge{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}
|
|
6019
|
-
.cc-badgeMuted{white-space:nowrap;color:var(--dsw-alias-label-tertiary);border-radius:999px;padding:1px 8px;font-size:11px;line-height:17px}
|
|
6020
|
-
.cc-reset{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}
|
|
6021
|
-
.cc-reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}
|
|
6022
|
-
.cc-reset:disabled{cursor:default;opacity:.5}
|
|
6023
|
-
.cc-input{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);height:34px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 12px;font-size:13px;line-height:1.5}
|
|
6024
|
-
.cc-input:focus-visible{border-color:var(--dsw-alias-brand-primary);outline:none}
|
|
6025
|
-
.cc-input:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}
|
|
6026
|
-
/* The routing-rule model multi-select: a button trigger that opens an
|
|
6027
|
-
* anchored Menu of checkbox rows. The trigger mirrors .cc-input sizing so it
|
|
6028
|
-
* sits flush with the sibling account select. */
|
|
6029
|
-
.cc-ruleTrigger{align-items:center;gap:8px;display:flex;width:100%;text-align:left;cursor:pointer}
|
|
6030
|
-
.cc-ruleTrigger:disabled{cursor:default}
|
|
6031
|
-
.cc-ruleTriggerText{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
6032
|
-
.cc-ruleCaret{flex-shrink:0;border-right:1.5px solid var(--dsw-alias-label-tertiary);border-bottom:1.5px solid var(--dsw-alias-label-tertiary);width:6px;height:6px;margin-right:4px;margin-bottom:2px;transform:rotate(45deg)}
|
|
6033
|
-
.cc-checkRow{align-items:center;gap:8px;display:inline-flex;min-width:0}
|
|
6034
|
-
.cc-checkRow:hover{cursor:pointer}
|
|
6035
|
-
.cc-check{appearance:none;flex-shrink:0;width:15px;height:15px;margin:0;border:1px solid var(--dsw-alias-border-l2);border-radius:4px;background:var(--dsw-alias-bg-layer-1);position:relative}
|
|
6036
|
-
.cc-check:checked{background:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary)}
|
|
6037
|
-
.cc-check:checked::after{content:'';position:absolute;top:2px;left:5px;width:3px;height:7px;border:solid #fff;border-width:0 1.5px 1.5px 0;transform:rotate(45deg)}
|
|
6038
|
-
.cc-checkName{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
6039
|
-
/* The model multi-select search box: stacked under the trigger while the
|
|
6040
|
-
* dropdown is open, same input sizing so the pair reads as one control. The
|
|
6041
|
-
* box lives inside the Menu anchor (which renders inside the Menu's root
|
|
6042
|
-
* span), so focusing/typing it never trips the Menu's outside-click close. */
|
|
6043
|
-
.cc-modelSelectAnchor{flex-direction:column;gap:6px;display:flex;width:100%}
|
|
6044
|
-
.cc-modelSearch{width:100%}
|
|
6045
|
-
.cc-modelSearch::-webkit-search-cancel-button{cursor:pointer}
|
|
6046
|
-
/* Selects need their own treatment to sit flush with the text inputs:
|
|
6047
|
-
* the UA stylesheet renders <select> border-box (34px total vs the inputs'
|
|
6048
|
-
* 36px) and forces its own menulist text metrics, so drop the native
|
|
6049
|
-
* chrome entirely (appearance:none), restore content-box so the outer box
|
|
6050
|
-
* matches the inputs again, and draw the chevron ourselves. Longhand
|
|
6051
|
-
* background-* only — the shorthand would reset .cc-input's background. */
|
|
6052
|
-
select.cc-input{appearance:none;-webkit-appearance:none;-moz-appearance:none;box-sizing:content-box;padding-right:32px;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='7' viewBox='0 0 12 7'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%23888f98' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 11px center}
|
|
6053
|
-
.cc-inputInvalid{border-color:var(--dsw-alias-label-error)}
|
|
6054
|
-
.cc-invalid{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}
|
|
6055
|
-
/* The Advanced card: its header row is one full-width toggle button; the
|
|
6056
|
-
* chevron is two borders on a rotated square (no icon dependency). */
|
|
6057
|
-
.cc-advancedHead{align-items:center;gap:8px;display:flex;width:100%;padding:12px 0;background:0 0;border:none;cursor:pointer;font:inherit;text-align:left}
|
|
6058
|
-
.cc-advancedHead:hover .cc-advancedTitle{color:var(--dsw-alias-label-primary)}
|
|
6059
|
-
.cc-advancedTitle{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500;line-height:1.5}
|
|
6060
|
-
.cc-advancedSpacer{flex:1}
|
|
6061
|
-
.cc-chevron{flex-shrink:0;border-right:1.5px solid var(--dsw-alias-label-tertiary);border-bottom:1.5px solid var(--dsw-alias-label-tertiary);width:8px;height:8px;margin-right:4px;margin-bottom:2px;transform:rotate(45deg);transition:transform .15s ease}
|
|
6062
|
-
.cc-chevronUp{transform:rotate(-135deg);margin-bottom:-3px}
|
|
6063
|
-
.cc-advancedBody{flex-direction:column;display:flex}
|
|
6064
|
-
.cc-advancedBody>.cc-field:first-of-type{border-top:1px solid var(--dsw-alias-border-l2)}
|
|
6065
|
-
.cc-hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}
|
|
6066
|
-
.cc-footer{justify-content:flex-end;align-items:center;gap:8px;display:flex}
|
|
6067
|
-
.cc-toggleRow{align-items:center;gap:8px;cursor:pointer;display:flex}
|
|
6068
|
-
.cc-toggleRow:has(.cc-toggle:disabled){cursor:default}
|
|
6069
|
-
.cc-toggle{appearance:none;flex-shrink:0;background:var(--dsw-alias-border-l2);border-radius:999px;width:30px;height:18px;margin:0;cursor:pointer;position:relative;transition:background .15s ease}
|
|
6070
|
-
.cc-toggle:checked{background:var(--dsw-alias-brand-primary)}
|
|
6071
|
-
.cc-toggle::after{content:'';background:#fff;border-radius:50%;width:14px;height:14px;position:absolute;top:2px;left:2px;transition:left .15s ease}
|
|
6072
|
-
.cc-toggle:checked::after{left:14px}
|
|
6073
|
-
.cc-toggle:disabled{cursor:default;opacity:.5}
|
|
6074
|
-
.cc-failed{min-width:0;color:var(--dsw-alias-label-error);flex:1;margin:0;font-size:12px;line-height:1.5}
|
|
6075
|
-
.cc-usageCard{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;padding:14px 16px;flex-direction:column;gap:12px;display:flex}
|
|
6076
|
-
.cc-usageHead{align-items:center;gap:8px;display:flex}
|
|
6077
|
-
.cc-usageTitle{color:var(--dsw-alias-label-primary);flex:1;margin:0;font-size:13px;font-weight:600;line-height:1.5}
|
|
6078
|
-
.cc-usageAccount{max-width:40%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}
|
|
6079
|
-
.cc-usagePlan{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-brand-primary);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:600;line-height:17px}
|
|
6080
|
-
.cc-usagePlanStatus{white-space:nowrap;color:var(--dsw-alias-label-error);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}
|
|
6081
|
-
.cc-usageRefresh{font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;padding:0;font-size:12px;line-height:1.5}
|
|
6082
|
-
.cc-usageRefresh:hover:not(:disabled){color:var(--dsw-alias-label-primary)}
|
|
6083
|
-
.cc-usageRefresh:disabled{cursor:default;opacity:.5}
|
|
6084
|
-
.cc-usageHint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}
|
|
6085
|
-
.cc-usageError{align-items:center;gap:8px;color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5;display:flex}
|
|
6086
|
-
.cc-usageStats{grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:8px;display:grid}
|
|
6087
|
-
.cc-usageStat{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);border-radius:8px;padding:8px 10px;flex-direction:column;gap:2px;display:flex}
|
|
6088
|
-
.cc-usageStatLabel{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.5}
|
|
6089
|
-
.cc-usageStatValue{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}
|
|
6090
|
-
.cc-usageStatSub{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:1.5}
|
|
6091
|
-
.cc-usageWindows{flex-direction:column;gap:16px;display:flex}
|
|
6092
|
-
.cc-usageWindow{flex-direction:column;gap:6px;display:flex}
|
|
6093
|
-
.cc-usageWindowHead{align-items:baseline;gap:8px;display:flex}
|
|
6094
|
-
.cc-usageWindowLabel{color:var(--dsw-alias-label-secondary);flex:1;font-size:12px;font-weight:500;line-height:1.5}
|
|
6095
|
-
.cc-usageWindowValue{color:var(--dsw-alias-label-primary);font-size:12px;font-weight:500;line-height:1.5}
|
|
6096
|
-
.cc-usageExceeded{color:var(--dsw-alias-label-error);font-size:11px;font-weight:500;line-height:1.5}
|
|
6097
|
-
.cc-usageBar{overflow:hidden;background:var(--dsw-alias-bg-layer-1);border-radius:999px;height:6px}
|
|
6098
|
-
.cc-usageBarFill{background:var(--dsw-alias-brand-primary);border-radius:999px;height:100%;transition:width .3s ease}
|
|
6099
|
-
.cc-usageBarFillWarn{background:var(--dsw-alias-label-error)}
|
|
6100
|
-
@media (prefers-reduced-motion:reduce){.cc-chevron,.cc-toggle,.cc-toggle::after,.cc-usageBarFill{transition:none}}.cc-usageWindowReset{color:var(--dsw-alias-label-tertiary);margin:0;font-size:11px;line-height:1.5}
|
|
6101
|
-
.cc-usageMeta{align-items:center;gap:8px;display:flex}
|
|
6102
|
-
.cc-accountReport{flex-direction:column;gap:12px;display:flex}
|
|
6103
|
-
.cc-tabs{flex-wrap:wrap;gap:6px;display:flex}
|
|
6104
|
-
.cc-tab{align-items:center;font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);border-radius:999px;padding:2px 10px;font-size:12px;line-height:18px;display:inline-flex;gap:6px}
|
|
6105
|
-
.cc-tab:hover:not(.cc-tabActive){color:var(--dsw-alias-label-primary)}
|
|
6106
|
-
.cc-tabActive{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-brand-primary)}
|
|
6107
|
-
.cc-tabDotOk{background:var(--dsw-alias-brand-primary);border-radius:50%;width:6px;height:6px}
|
|
6108
|
-
.cc-tabDotWarn{background:#d97706;border-radius:50%;width:6px;height:6px}
|
|
6109
|
-
.cc-tabDotError{background:var(--dsw-alias-label-error);border-radius:50%;width:6px;height:6px}
|
|
6110
|
-
.cc-usageMetaSpacer{flex:1}
|
|
6111
|
-
.cc-usageUpdated{color:var(--dsw-alias-label-tertiary);margin:0;font-size:11px;line-height:1.5}
|
|
6112
|
-
.cc-usagePartial{color:var(--dsw-alias-label-error);margin:0;font-size:11px;line-height:1.5}
|
|
6113
|
-
.cc-usageBlocked{border:1px solid var(--dsw-alias-label-error);border-radius:10px;padding:10px 12px;display:flex;flex-direction:column;gap:4px}
|
|
6114
|
-
.cc-usageBlockedTitle{color:var(--dsw-alias-label-error);margin:0;font-size:13px;font-weight:600;line-height:1.5}
|
|
6115
|
-
.cc-usageBlockedHint{color:var(--dsw-alias-label-secondary);margin:0;font-size:12px;line-height:1.5}
|
|
6116
|
-
.cc-version{margin:4px 0 0;text-align:center;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:1.5}
|
|
6117
|
-
/* The Models-page provider panel root: unstyled by design — the row card the
|
|
6118
|
-
* Models page owns supplies the surface, the panel only stacks its controls. */
|
|
6119
|
-
.cc-providerCard{flex-direction:column;display:flex}
|
|
6120
|
-
/* The update hint rides the footer version line: warning-tinted (with a
|
|
6121
|
-
* muted fallback for themes without the alias), quiet until hovered. */
|
|
6122
|
-
.cc-versionLink{color:var(--dsw-alias-state-warning-primary,var(--dsw-alias-label-secondary));text-decoration:none}
|
|
6123
|
-
.cc-versionLink:hover{color:var(--dsw-alias-label-primary);text-decoration:underline;text-underline-position:under}
|
|
6124
|
-
/* The login panel rides the connection card as one more field row; the
|
|
6125
|
-
* authorization link is the only branded element on it. */
|
|
6126
|
-
.cc-loginLink{color:var(--dsw-alias-brand-primary);text-decoration:none;font-size:12px;line-height:1.5}
|
|
6127
|
-
.cc-loginLink:hover{text-decoration:underline;text-underline-position:under}
|
|
6128
|
-
.cc-loginDone{color:var(--dsw-alias-state-success-primary,var(--dsw-alias-label-secondary))}
|
|
6129
|
-
.cc-loginError{color:var(--dsw-alias-label-error)}
|
|
6130
|
-
.cc-saved{color:var(--dsw-alias-state-success-primary,var(--dsw-alias-label-secondary));margin:0;font-size:12px;font-weight:500;line-height:1.5}
|
|
6131
|
-
.cc-badgeWarn{background:var(--dsw-alias-state-warning-secondary,var(--dsw-alias-bg-module-platform));color:var(--dsw-alias-state-warning-primary,var(--dsw-alias-label-secondary))}
|
|
6132
|
-
`;
|
|
6133
6214
|
/** Inject the page stylesheet once (idempotent per tag). */
|
|
6134
6215
|
function injectPageCss() {
|
|
6135
6216
|
if (typeof document === "undefined") return;
|
|
6136
|
-
|
|
6137
|
-
if (document.querySelector(`style[data-plugin-css="${id}"]`) !== null) return;
|
|
6217
|
+
if (document.querySelector(`style[data-plugin-css="@mars-sea/dsh-commandcode-provider/CommandCodeSettingsPage.module.css"]`) !== null) return;
|
|
6138
6218
|
const tag = document.createElement("style");
|
|
6139
6219
|
tag.dataset.plugin = "@mars-sea/dsh-commandcode-provider";
|
|
6140
|
-
tag.dataset.pluginCss =
|
|
6220
|
+
tag.dataset.pluginCss = PAGE_CSS_ID;
|
|
6141
6221
|
tag.textContent = PAGE_CSS;
|
|
6142
6222
|
document.head.appendChild(tag);
|
|
6143
6223
|
}
|