pi-commandcode-provider 0.6.0 → 0.6.2
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 +34 -0
- package/CONTRIBUTING.md +11 -0
- package/README.md +6 -4
- package/index.ts +47 -3
- package/package.json +1 -1
- package/src/commandcode-catalog-overrides.ts +23 -0
- package/src/commandcode-catalog.ts +17 -6
- package/src/converters.ts +6 -1
- package/src/models.ts +20 -2
- package/src/pricing.ts +16 -19
- package/src/quota-format.ts +35 -3
- package/src/quota.ts +9 -2
- package/src/runtime.ts +39 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,40 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.6.2 - 2026-09-02
|
|
6
|
+
|
|
7
|
+
- Fix `omp plugin install` on Oh My Pi 18.x, which rejected 0.6.1 because its pi-ai lacks the `registerApiProvider` export; the compat registration now resolves at runtime and is skipped on hosts that register custom APIs themselves.
|
|
8
|
+
- Run the Oh My Pi compatibility suite against a real `omp` binary in CI as a required check, and assert there that the extension loads against OMP's bundled pi packages.
|
|
9
|
+
- Pin the CI memory benchmark and Oh My Pi jobs to Bun 1.4.0, Node 22.23.2, and pi 0.84.4.
|
|
10
|
+
|
|
11
|
+
### Contributors
|
|
12
|
+
|
|
13
|
+
- @AmeMizuki — reported the failing `omp plugin install` on Oh My Pi 18.1.2.
|
|
14
|
+
|
|
15
|
+
## 0.6.1 - 2026-09-01
|
|
16
|
+
|
|
17
|
+
- Expose selectable thinking levels (`minimal`, `low`, `medium`, `high`, `xhigh`) for `meta/muse-spark-1.1`, `meta/muse-spark-1.2`, and `meta/muse-spark-1.2-contributor` through a manual catalog override, so `/thinking` and `Shift+Tab` no longer stay locked on `off` for these reasoning models.
|
|
18
|
+
- Start from the cached model catalog and refresh it in the background instead of blocking host startup on the catalog request; a first start without a cache still waits for the live catalog.
|
|
19
|
+
- Register the `commandcode-custom` API in the `@earendil-works/pi-ai/compat` registry so sibling extensions that stream with the active Command Code model no longer fail with `No API provider registered for api: commandcode-custom` on plain pi.
|
|
20
|
+
- Assert structural catalog invariants in the model tests so the daily catalog sync no longer fails on every upstream change.
|
|
21
|
+
- Display the monthly renewal date and remaining days in `/commandcode-quota`.
|
|
22
|
+
- Stop silently dropping `role: "developer"` messages (for example OMP advisor steering notes, reminders, and nudges). `/alpha/generate` only accepts `user`, `assistant`, and `tool` roles, so developer messages are now forwarded as `user` messages with identical content in the same chronological position instead of disappearing from the request.
|
|
23
|
+
- Add `Qwen/Qwen3.8-Flash` and `z-ai/glm-5.3-flash` with their verified reasoning efforts (`low, medium, xhigh` and `low, high, max`) and display pricing.
|
|
24
|
+
- Refresh static model capabilities from `command-code@1.40.1`, adding `claude-fable-5-1`, `deepseek/deepseek-v4-flash-fast`, and `tencent/hy4-preview` with their reasoning efforts, adding `moonshotai/Kimi-K3` efforts and the `z-ai/glm-5.3-flash` output limit, and dropping the retired `stealth/ox-alpha` and `minimax/minimax-m3-free`.
|
|
25
|
+
- Refresh display pricing for the current 62-model catalog, adding `claude-fable-5-1`, `deepseek/deepseek-v4-flash-fast`, and `tencent/hy4-preview`, removing the retired `stealth/ox-alpha`, `minimax/minimax-m3-free`, and `minimax/minimax-m2.7-free`, and ending the expired Claude Sonnet 5 introductory and Gemini 3.7 Flash promotional windows.
|
|
26
|
+
- Fix `npm run sync:commandcode-catalog` and `npm run check:commandcode-catalog` on Windows by spawning npm through the shell.
|
|
27
|
+
- Add a `refresh-model-catalog` agent skill with cross-platform helper scripts that snapshot the live model catalog and regenerate the pricing fixture from `MODEL_COSTS`.
|
|
28
|
+
|
|
29
|
+
### Contributors
|
|
30
|
+
|
|
31
|
+
- @warc0s — preserved developer messages on the `/alpha/generate` transport with OMP advisory coverage.
|
|
32
|
+
- @jagaliano — added the quota renewal date and diagnosed the failing daily catalog sync.
|
|
33
|
+
- @ThomasByr — added GLM 5.3 Flash and Qwen 3.8 Flash and contributed the `refresh-model-catalog` skill.
|
|
34
|
+
- @hjshin-ubob — proposed selectable thinking levels for the Muse Spark models.
|
|
35
|
+
- @Sokoshy — analyzed the `commandcode-custom` compat registry failure on plain pi.
|
|
36
|
+
- @CoderTCY — measured and proposed the cache-first catalog startup.
|
|
37
|
+
- @MertSoylu — reported the missing GLM 5.3 Flash effort levels.
|
|
38
|
+
|
|
5
39
|
## 0.6.0 - 2026-08-25
|
|
6
40
|
|
|
7
41
|
- Allow switching from a vision-capable model to a text-only model by omitting historical image tool results while preserving their text output; direct image prompts still fail clearly.
|
package/CONTRIBUTING.md
CHANGED
|
@@ -52,6 +52,17 @@ COMMANDCODE_E2E_PROVIDER_API_KEY_FILE=/path/to/provider-key npm run test:e2e:liv
|
|
|
52
52
|
|
|
53
53
|
Use `npm run test:e2e:live:all` with the Go and GOAT file variables to run both subscription transports sequentially. Store keys in a secret manager and export each one to a new mode-`0600` temporary file for the test; never add key files to the repository. Direct `*_API_KEY` variables are intended primarily for protected CI secrets.
|
|
54
54
|
|
|
55
|
+
### Oh My Pi compatibility
|
|
56
|
+
|
|
57
|
+
`tests/test-omp-compat.mjs` runs the extension inside a real `omp` binary against a mock Command Code API. It skips locally when `omp` is not on `PATH`; CI installs Oh My Pi and runs it as a required check with `OMP_COMPAT_REQUIRED=1`, so a change that only loads on pi fails CI instead of the next `omp plugin install`.
|
|
58
|
+
|
|
59
|
+
To run it locally, point `OMP_BIN` at an omp executable (Oh My Pi needs Bun ≥ 1.3.14):
|
|
60
|
+
|
|
61
|
+
```sh
|
|
62
|
+
npm install -g @oh-my-pi/pi-coding-agent
|
|
63
|
+
OMP_BIN="$(npm prefix -g)/bin/omp" node tests/test-omp-compat.mjs
|
|
64
|
+
```
|
|
65
|
+
|
|
55
66
|
Before opening a PR, run:
|
|
56
67
|
|
|
57
68
|
```sh
|
package/README.md
CHANGED
|
@@ -82,9 +82,11 @@ Supported examples:
|
|
|
82
82
|
|
|
83
83
|
Open `/model` and select one of the models provided by Command Code. Model availability changes over time and is refreshed from the Provider API when the extension loads.
|
|
84
84
|
|
|
85
|
+
Other extensions that stream with the active Command Code model, such as background agents or memory workers, use the same connection and the same credentials as the chat, so their requests count against your Command Code usage.
|
|
86
|
+
|
|
85
87
|
### Reasoning support
|
|
86
88
|
|
|
87
|
-
Reasoning capability and selectable effort levels follow the official CLI catalog independently. Models can therefore be marked as reasoning-capable even when Command Code chooses their depth automatically. Models with explicit effort support
|
|
89
|
+
Reasoning capability and selectable effort levels follow the official CLI catalog independently. Models can therefore be marked as reasoning-capable even when Command Code chooses their depth automatically. Models with explicit effort support register a model-specific `thinkingLevelMap`, so pi and OMP expose only valid levels. For a few reasoning models the CLI catalog ships no effort levels although the endpoint accepts `reasoning_effort`; `src/commandcode-catalog-overrides.ts` adds a manual level set for those (currently `meta/muse-spark-1.1`, `meta/muse-spark-1.2`, and `meta/muse-spark-1.2-contributor`) on top of the generated catalog, and the tests fail once upstream publishes its own levels so the override gets removed. Pi's native OpenAI- and Anthropic-compatible providers translate the selected level for Provider API accounts; the existing Command Code generate transport sends the matching `reasoning_effort` for Go accounts.
|
|
88
90
|
|
|
89
91
|
List Command Code models from the terminal:
|
|
90
92
|
|
|
@@ -114,7 +116,7 @@ https://api.commandcode.ai/provider/v1/models
|
|
|
114
116
|
|
|
115
117
|
The last successful catalog is cached at `<agent-dir>/commandcode-models.json`. For pi this is `~/.pi/agent/commandcode-models.json` by default. Compatible hosts such as OMP use their own agent directory.
|
|
116
118
|
|
|
117
|
-
If the endpoint is temporarily unavailable, the
|
|
119
|
+
When a valid cache exists, the provider registers the cached catalog immediately and refreshes it from the endpoint in the background, so startup does not wait for the network. The refreshed catalog replaces the cached one as soon as it arrives; `/commandcode-status` reports `source: cache` until then. If the endpoint is temporarily unavailable, the cached catalog stays active. On a first start without a cache, the provider waits for the live catalog; if that fails offline, pi still loads, but Command Code models remain unavailable until the connection is restored and `/commandcode-refresh` succeeds.
|
|
118
120
|
|
|
119
121
|
While pi is running, use these provider commands without restarting:
|
|
120
122
|
|
|
@@ -135,7 +137,7 @@ The following environment variables are intended for tests, local mocks, and com
|
|
|
135
137
|
|
|
136
138
|
## Image input
|
|
137
139
|
|
|
138
|
-
The provider advertises image input only for models marked with the `image` input modality in the official Command Code CLI model catalog. The capability snapshot currently follows `command-code@1.
|
|
140
|
+
The provider advertises image input only for models marked with the `image` input modality in the official Command Code CLI model catalog. The capability snapshot currently follows `command-code@1.40.1`; unknown models default to text-only until their upstream metadata is reviewed. A daily GitHub Actions job synchronizes the CLI version, image capabilities, reasoning flags, reasoning efforts, and model-specific output limits with the latest published CLI package and opens or updates a reviewable pull request when they change. Pricing remains manually reviewed because temporary promotions and long-context tiers require explicit review.
|
|
139
141
|
|
|
140
142
|
For vision-capable models, Pi's native provider adapters forward image blocks from user messages and tool results using the documented OpenAI or Anthropic message schema. Unknown and text-only models remain marked text-only in Pi.
|
|
141
143
|
|
|
@@ -205,7 +207,7 @@ COMMANDCODE_E2E_GOAT_API_KEY_FILE=/path/to/goat-key \
|
|
|
205
207
|
|
|
206
208
|
Each profile runs with an isolated Pi agent directory and asserts transport selection, reasoning across turns, quota plan identity, abort handling, tool calls, and the packed npm artifact. Go must select `generate` and reject unsupported images; GOAT must select `provider` and complete a live vision request. The profile-specific `*_API_KEY` environment variables are also supported for CI secrets, but key files are preferred for local use.
|
|
207
209
|
|
|
208
|
-
The Go profile defaults to DeepSeek V4 Flash; GOAT defaults to Grok 4.6 because its Provider API stream exposes reasoning consistently across consecutive turns. Override them with `COMMANDCODE_E2E_GO_MODEL`, `COMMANDCODE_E2E_GOAT_MODEL`, or `COMMANDCODE_E2E_PROVIDER_MODEL`. A successful live Anthropic `/provider/v1/messages` test requires a paid account whose plan includes the selected Claude model.
|
|
210
|
+
The Go profile defaults to DeepSeek V4 Flash; GOAT defaults to Grok 4.6 because its Provider API stream exposes reasoning consistently across consecutive turns. Override them with `COMMANDCODE_E2E_GO_MODEL`, `COMMANDCODE_E2E_GOAT_MODEL`, or `COMMANDCODE_E2E_PROVIDER_MODEL`. The GOAT vision phase defaults to GPT-5.6 Luna and can be overridden with `COMMANDCODE_E2E_GOAT_VISION_MODEL`. A successful live Anthropic `/provider/v1/messages` test requires a paid account whose plan includes the selected Claude model.
|
|
209
211
|
|
|
210
212
|
See [CONTRIBUTING.md](CONTRIBUTING.md) for local setup and tests. See [RELEASE.md](RELEASE.md) for the release process.
|
|
211
213
|
|
package/index.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { AssistantMessageEventStream } from "@earendil-works/pi-ai"
|
|
9
|
+
import * as piAiCompat from "@earendil-works/pi-ai/compat"
|
|
9
10
|
import { streamSimple as streamNativeProvider } from "@earendil-works/pi-ai/compat"
|
|
10
11
|
import {
|
|
11
12
|
getAgentDir,
|
|
@@ -25,6 +26,7 @@ import {
|
|
|
25
26
|
DEFAULT_PROVIDER_API_BASE,
|
|
26
27
|
getModelsTimeoutMs,
|
|
27
28
|
inputModalitiesForModel,
|
|
29
|
+
loadCachedCommandCodeModels,
|
|
28
30
|
loadCommandCodeModels,
|
|
29
31
|
MODEL_EFFORTS,
|
|
30
32
|
thinkingMetadataForModel,
|
|
@@ -37,6 +39,27 @@ import { registerCommandCodeQuota } from "./src/quota-command.ts"
|
|
|
37
39
|
import { createCommandCodeRuntime } from "./src/runtime.ts"
|
|
38
40
|
import { createCommandCodeTransportRouter } from "./src/transport.ts"
|
|
39
41
|
|
|
42
|
+
const COMMAND_CODE_API = "commandcode-custom"
|
|
43
|
+
const COMPAT_SOURCE_ID = "pi-commandcode-provider"
|
|
44
|
+
|
|
45
|
+
type CompatStreamFunction = (
|
|
46
|
+
model: Parameters<typeof streamNativeProvider>[0],
|
|
47
|
+
context: Parameters<typeof streamNativeProvider>[1],
|
|
48
|
+
options?: Parameters<typeof streamNativeProvider>[2],
|
|
49
|
+
) => AssistantMessageEventStream
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* pi's compat entrypoint exposes `registerApiProvider`; Oh My Pi maps
|
|
53
|
+
* `@earendil-works/pi-ai/compat` onto its own pi-ai, which lacks that export
|
|
54
|
+
* and registers custom APIs itself inside `registerProvider`. Resolve the
|
|
55
|
+
* function at runtime so the extension loads on both hosts.
|
|
56
|
+
*/
|
|
57
|
+
function registerCompatApiProvider(stream: CompatStreamFunction): void {
|
|
58
|
+
const register = (piAiCompat as { registerApiProvider?: unknown }).registerApiProvider
|
|
59
|
+
if (typeof register !== "function") return
|
|
60
|
+
register({ api: COMMAND_CODE_API, stream, streamSimple: stream }, COMPAT_SOURCE_ID)
|
|
61
|
+
}
|
|
62
|
+
|
|
40
63
|
function commandCodeHeaders(): Record<string, string> | undefined {
|
|
41
64
|
if (process.env.CMD_ZDR === "1" || process.env.COMMANDCODE_ZDR === "1") {
|
|
42
65
|
return { "x-cmd-zdr": "1" }
|
|
@@ -54,7 +77,7 @@ function createProviderConfig(
|
|
|
54
77
|
name: "Command Code",
|
|
55
78
|
baseUrl: apiBase,
|
|
56
79
|
apiKey: getConfiguredApiKey() ?? "$COMMAND_CODE_API_KEY",
|
|
57
|
-
api:
|
|
80
|
+
api: COMMAND_CODE_API,
|
|
58
81
|
streamSimple: streamCommandCode,
|
|
59
82
|
headers,
|
|
60
83
|
oauth: {
|
|
@@ -66,7 +89,7 @@ function createProviderConfig(
|
|
|
66
89
|
models: models.map((model) => ({
|
|
67
90
|
id: model.id,
|
|
68
91
|
name: model.name,
|
|
69
|
-
api:
|
|
92
|
+
api: COMMAND_CODE_API,
|
|
70
93
|
baseUrl: baseUrlForModel(apiBase, model.api),
|
|
71
94
|
reasoning: model.reasoning,
|
|
72
95
|
...(thinkingMetadataForModel(model.id) ?? {}),
|
|
@@ -120,6 +143,21 @@ export default async function (pi: ExtensionAPI) {
|
|
|
120
143
|
streamGenerate,
|
|
121
144
|
})
|
|
122
145
|
|
|
146
|
+
// pi dispatches the main chat through the registered provider, but sibling
|
|
147
|
+
// extensions that call `streamSimple` from `@earendil-works/pi-ai/compat`
|
|
148
|
+
// with a Command Code model resolve `model.api` through the compat
|
|
149
|
+
// api-registry, which knows nothing about extension providers. Register the
|
|
150
|
+
// custom api there so those calls reach the same transport. The registry
|
|
151
|
+
// resolves no credentials for extension providers, so fall back to the
|
|
152
|
+
// configured key when the caller passes none.
|
|
153
|
+
const compatStream: CompatStreamFunction = (model, context, options) =>
|
|
154
|
+
transport.stream(
|
|
155
|
+
model,
|
|
156
|
+
context,
|
|
157
|
+
options?.apiKey ? options : { ...options, apiKey: getConfiguredApiKey() },
|
|
158
|
+
) as AssistantMessageEventStream
|
|
159
|
+
registerCompatApiProvider(compatStream)
|
|
160
|
+
|
|
123
161
|
pi.on("message_end", async (event, ctx) => {
|
|
124
162
|
if (event.message.role !== "assistant") return
|
|
125
163
|
const normalized = normalizeCommandCodeMessage(event.message, ctx.model?.provider)
|
|
@@ -134,15 +172,21 @@ export default async function (pi: ExtensionAPI) {
|
|
|
134
172
|
const runtime = createCommandCodeRuntime<ProviderConfig, ExtensionCommandContext>(pi, {
|
|
135
173
|
endpoint: modelsUrl,
|
|
136
174
|
cachePath: modelsCachePath,
|
|
137
|
-
loadModels: () =>
|
|
175
|
+
loadModels: (signal) =>
|
|
138
176
|
loadCommandCodeModels({
|
|
139
177
|
url: modelsUrl,
|
|
140
178
|
cachePath: modelsCachePath,
|
|
141
179
|
timeoutMs: modelsTimeoutMs,
|
|
180
|
+
signal,
|
|
142
181
|
}),
|
|
182
|
+
loadCachedModels: () => loadCachedCommandCodeModels(modelsCachePath),
|
|
143
183
|
createProviderConfig: (models) => createProviderConfig(models, apiBase, transport.stream),
|
|
144
184
|
getTransport: transport.getTransport,
|
|
145
185
|
})
|
|
146
186
|
|
|
187
|
+
pi.on("session_shutdown", () => {
|
|
188
|
+
runtime.dispose()
|
|
189
|
+
})
|
|
190
|
+
|
|
147
191
|
await runtime.initialize()
|
|
148
192
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { CommandCodeReasoningEffort } from "./commandcode-catalog.ts"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Manual reasoning-effort policy for models the official CLI marks as
|
|
5
|
+
* reasoning-capable without publishing selectable efforts.
|
|
6
|
+
*
|
|
7
|
+
* `src/commandcode-catalog.ts` is generated from the CLI package and must stay
|
|
8
|
+
* byte-identical to upstream so the daily drift check works. Entries here are
|
|
9
|
+
* merged over the generated catalog at load time and are not touched by
|
|
10
|
+
* `npm run sync:commandcode-catalog`.
|
|
11
|
+
*
|
|
12
|
+
* Add a model only when the effort parameter is known to be accepted by the
|
|
13
|
+
* Command Code endpoint; remove it once the CLI catalog ships its own efforts.
|
|
14
|
+
*/
|
|
15
|
+
export const MODEL_EFFORT_OVERRIDES: Readonly<
|
|
16
|
+
Record<string, readonly CommandCodeReasoningEffort[]>
|
|
17
|
+
> = {
|
|
18
|
+
// Meta Muse Spark: the CLI ships no effort levels, but the endpoint accepts
|
|
19
|
+
// `reasoning_effort` for these models and other hosts expose the same set.
|
|
20
|
+
"meta/muse-spark-1.1": ["minimal", "low", "medium", "high", "xhigh"],
|
|
21
|
+
"meta/muse-spark-1.2": ["minimal", "low", "medium", "high", "xhigh"],
|
|
22
|
+
"meta/muse-spark-1.2-contributor": ["minimal", "low", "medium", "high", "xhigh"],
|
|
23
|
+
}
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
export const COMMAND_CODE_CLI_VERSION = "1.
|
|
1
|
+
export const COMMAND_CODE_CLI_VERSION = "1.40.1"
|
|
2
2
|
|
|
3
3
|
export type CommandCodeInputType = "text" | "image"
|
|
4
4
|
export type CommandCodeReasoningEffort = "minimal" | "low" | "medium" | "high" | "xhigh" | "max"
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Generated from command-code@1.
|
|
7
|
+
* Generated from command-code@1.40.1 by `npm run sync:commandcode-catalog`.
|
|
8
8
|
* Do not edit manually.
|
|
9
9
|
*/
|
|
10
10
|
export const MODEL_INPUT_MODALITIES: Readonly<Record<string, readonly CommandCodeInputType[]>> = {
|
|
11
11
|
"claude-fable-5": ["text", "image"],
|
|
12
|
+
"claude-fable-5-1": ["text", "image"],
|
|
12
13
|
"claude-haiku-4-5-20251001": ["text", "image"],
|
|
13
14
|
"claude-opus-4-7": ["text", "image"],
|
|
14
15
|
"claude-opus-4-8": ["text", "image"],
|
|
@@ -41,24 +42,27 @@ export const MODEL_INPUT_MODALITIES: Readonly<Record<string, readonly CommandCod
|
|
|
41
42
|
"Qwen/Qwen3.7-Flash": ["text", "image"],
|
|
42
43
|
"Qwen/Qwen3.7-Plus": ["text", "image"],
|
|
43
44
|
"Qwen/Qwen3.8-27B": ["text", "image"],
|
|
45
|
+
"Qwen/Qwen3.8-Flash": ["text", "image"],
|
|
44
46
|
"Qwen/Qwen3.8-Max": ["text", "image"],
|
|
45
47
|
"sakana/fugu-ultra": ["text", "image"],
|
|
46
|
-
"stealth/ox-alpha": ["text", "image"],
|
|
47
48
|
"stepfun/Step-3.7-Flash": ["text", "image"],
|
|
48
49
|
"thinkingmachines/inkling": ["text", "image"],
|
|
49
50
|
"thinkingmachines/inkling-small": ["text", "image"],
|
|
50
51
|
"xai/grok-4.5": ["text", "image"],
|
|
51
52
|
"xiaomi/mimo-v2.5": ["text", "image"],
|
|
53
|
+
"z-ai/glm-5.3-flash": ["text", "image"],
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
export const MODEL_REASONING: Readonly<Record<string, true>> = {
|
|
55
57
|
"claude-fable-5": true,
|
|
58
|
+
"claude-fable-5-1": true,
|
|
56
59
|
"claude-opus-4-7": true,
|
|
57
60
|
"claude-opus-4-8": true,
|
|
58
61
|
"claude-opus-5": true,
|
|
59
62
|
"claude-sonnet-4-6": true,
|
|
60
63
|
"claude-sonnet-5": true,
|
|
61
64
|
"deepseek/deepseek-v4-flash": true,
|
|
65
|
+
"deepseek/deepseek-v4-flash-fast": true,
|
|
62
66
|
"deepseek/deepseek-v4-flash-vision-exp": true,
|
|
63
67
|
"deepseek/deepseek-v4-pro": true,
|
|
64
68
|
"google/gemini-3.1-flash-lite": true,
|
|
@@ -88,28 +92,32 @@ export const MODEL_REASONING: Readonly<Record<string, true>> = {
|
|
|
88
92
|
"Qwen/Qwen3.7-Max": true,
|
|
89
93
|
"Qwen/Qwen3.7-Plus": true,
|
|
90
94
|
"Qwen/Qwen3.8-27B": true,
|
|
95
|
+
"Qwen/Qwen3.8-Flash": true,
|
|
91
96
|
"Qwen/Qwen3.8-Max": true,
|
|
92
97
|
"sakana/fugu-ultra": true,
|
|
93
|
-
"stealth/ox-alpha": true,
|
|
94
98
|
"stepfun/Step-3.5-Flash": true,
|
|
95
99
|
"stepfun/Step-3.7-Flash": true,
|
|
96
100
|
"tencent/hy3-paid": true,
|
|
101
|
+
"tencent/hy4-preview": true,
|
|
97
102
|
"thinkingmachines/inkling": true,
|
|
98
103
|
"thinkingmachines/inkling-small": true,
|
|
99
104
|
"xai/grok-4.5": true,
|
|
100
105
|
"xai/grok-4.6": true,
|
|
106
|
+
"z-ai/glm-5.3-flash": true,
|
|
101
107
|
"zai-org/GLM-5.2": true,
|
|
102
108
|
"zai-org/GLM-5.3": true,
|
|
103
109
|
}
|
|
104
110
|
|
|
105
111
|
export const MODEL_EFFORTS: Readonly<Record<string, readonly CommandCodeReasoningEffort[]>> = {
|
|
106
112
|
"claude-fable-5": ["low", "medium", "high", "xhigh", "max"],
|
|
113
|
+
"claude-fable-5-1": ["low", "medium", "high", "xhigh", "max"],
|
|
107
114
|
"claude-opus-4-7": ["low", "medium", "high", "xhigh", "max"],
|
|
108
115
|
"claude-opus-4-8": ["low", "medium", "high", "xhigh", "max"],
|
|
109
116
|
"claude-opus-5": ["low", "medium", "high", "xhigh", "max"],
|
|
110
117
|
"claude-sonnet-4-6": ["low", "medium", "high", "xhigh", "max"],
|
|
111
118
|
"claude-sonnet-5": ["low", "medium", "high", "xhigh", "max"],
|
|
112
119
|
"deepseek/deepseek-v4-flash": ["high", "max"],
|
|
120
|
+
"deepseek/deepseek-v4-flash-fast": ["low", "high", "max"],
|
|
113
121
|
"deepseek/deepseek-v4-flash-vision-exp": ["high", "max"],
|
|
114
122
|
"deepseek/deepseek-v4-pro": ["high", "max"],
|
|
115
123
|
"google/gemini-3.1-flash-lite": ["low", "medium", "high"],
|
|
@@ -124,12 +132,15 @@ export const MODEL_EFFORTS: Readonly<Record<string, readonly CommandCodeReasonin
|
|
|
124
132
|
"gpt-5.6-luna": ["low", "medium", "high", "xhigh", "max"],
|
|
125
133
|
"gpt-5.6-sol": ["low", "medium", "high", "xhigh", "max"],
|
|
126
134
|
"gpt-5.6-terra": ["low", "medium", "high", "xhigh", "max"],
|
|
135
|
+
"moonshotai/Kimi-K3": ["low", "high", "max"],
|
|
127
136
|
"Qwen/Qwen3.8-27B": ["low", "medium", "xhigh"],
|
|
137
|
+
"Qwen/Qwen3.8-Flash": ["low", "medium", "xhigh"],
|
|
128
138
|
"Qwen/Qwen3.8-Max": ["low", "medium", "xhigh"],
|
|
129
139
|
"sakana/fugu-ultra": ["high", "xhigh"],
|
|
130
|
-
"
|
|
140
|
+
"tencent/hy4-preview": ["low", "medium", "high"],
|
|
131
141
|
"xai/grok-4.5": ["low", "medium", "high"],
|
|
132
142
|
"xai/grok-4.6": ["low", "medium", "high", "xhigh"],
|
|
143
|
+
"z-ai/glm-5.3-flash": ["low", "high", "max"],
|
|
133
144
|
"zai-org/GLM-5.2": ["high", "max"],
|
|
134
145
|
"zai-org/GLM-5.3": ["low", "high", "max"],
|
|
135
146
|
}
|
|
@@ -137,5 +148,5 @@ export const MODEL_EFFORTS: Readonly<Record<string, readonly CommandCodeReasonin
|
|
|
137
148
|
export const MODEL_MAX_OUTPUT_TOKENS: Readonly<Record<string, number>> = {
|
|
138
149
|
"poolside/laguna-s-2.1-free": 32_768,
|
|
139
150
|
"Qwen/Qwen3.8-27B": 32_768,
|
|
140
|
-
"
|
|
151
|
+
"z-ai/glm-5.3-flash": 131_072,
|
|
141
152
|
}
|
package/src/converters.ts
CHANGED
|
@@ -229,7 +229,12 @@ export function messagesToCC(
|
|
|
229
229
|
const { callIds, resultIds } = toolCallState(messages)
|
|
230
230
|
|
|
231
231
|
for (const message of messages ?? []) {
|
|
232
|
-
if (message.role === "user") {
|
|
232
|
+
if (message.role === "user" || message.role === "developer") {
|
|
233
|
+
// Hosts such as OMP steer the agent by injecting developer-role messages
|
|
234
|
+
// (advisor notes, reminders, nudges) mid-conversation. /alpha/generate
|
|
235
|
+
// only accepts user, assistant, and tool roles, so degrade the role to
|
|
236
|
+
// user instead of dropping the message. Content and chronological
|
|
237
|
+
// position are preserved; system-prompt hoisting would change semantics.
|
|
233
238
|
out.push({
|
|
234
239
|
role: "user",
|
|
235
240
|
content: userContentToCommandCode(message.content, allowImages),
|
package/src/models.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises"
|
|
2
2
|
import { dirname } from "node:path"
|
|
3
3
|
|
|
4
|
+
import { MODEL_EFFORT_OVERRIDES } from "./commandcode-catalog-overrides.ts"
|
|
4
5
|
import {
|
|
5
|
-
MODEL_EFFORTS,
|
|
6
|
+
MODEL_EFFORTS as CATALOG_MODEL_EFFORTS,
|
|
6
7
|
MODEL_INPUT_MODALITIES,
|
|
7
8
|
MODEL_MAX_OUTPUT_TOKENS,
|
|
8
9
|
MODEL_REASONING,
|
|
@@ -10,7 +11,13 @@ import {
|
|
|
10
11
|
type CommandCodeReasoningEffort,
|
|
11
12
|
} from "./commandcode-catalog.ts"
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
/** Upstream CLI efforts with the manual overrides merged over them. */
|
|
15
|
+
export const MODEL_EFFORTS: Readonly<Record<string, readonly CommandCodeReasoningEffort[]>> = {
|
|
16
|
+
...CATALOG_MODEL_EFFORTS,
|
|
17
|
+
...MODEL_EFFORT_OVERRIDES,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export { MODEL_INPUT_MODALITIES, MODEL_MAX_OUTPUT_TOKENS, MODEL_REASONING }
|
|
14
21
|
export type { CommandCodeInputType }
|
|
15
22
|
|
|
16
23
|
export const DEFAULT_PROVIDER_API_BASE = "https://api.commandcode.ai/provider/v1"
|
|
@@ -332,6 +339,17 @@ async function readCommandCodeModelsCache(cachePath: string): Promise<readonly C
|
|
|
332
339
|
return commandCodeModelsFromCache(parsed)
|
|
333
340
|
}
|
|
334
341
|
|
|
342
|
+
/** Reads the cached catalog without touching the network; empty when missing or invalid. */
|
|
343
|
+
export async function loadCachedCommandCodeModels(
|
|
344
|
+
cachePath: string,
|
|
345
|
+
): Promise<readonly CommandCodeModel[]> {
|
|
346
|
+
try {
|
|
347
|
+
return await readCommandCodeModelsCache(cachePath)
|
|
348
|
+
} catch {
|
|
349
|
+
return []
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
335
353
|
async function writeCommandCodeModelsCache(
|
|
336
354
|
cachePath: string,
|
|
337
355
|
models: readonly CommandCodeModel[],
|
package/src/pricing.ts
CHANGED
|
@@ -20,7 +20,7 @@ export interface TemporaryPricing {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
export const PRICING_SOURCE_URL = "https://commandcode.ai/docs/resources/pricing-limits"
|
|
23
|
-
export const PRICING_LAST_VERIFIED = "2026-
|
|
23
|
+
export const PRICING_LAST_VERIFIED = "2026-09-01"
|
|
24
24
|
|
|
25
25
|
export const ZERO_MODEL_COST: CommandCodeModelCost = {
|
|
26
26
|
input: 0,
|
|
@@ -40,10 +40,10 @@ export const ZERO_MODEL_COST: CommandCodeModelCost = {
|
|
|
40
40
|
export const MODEL_COSTS: Readonly<Record<string, CommandCodeModelCost>> = {
|
|
41
41
|
// Free models
|
|
42
42
|
"poolside/laguna-s-2.1-free": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
43
|
-
"stealth/ox-alpha": { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
44
43
|
|
|
45
44
|
// Open and open-weight models
|
|
46
45
|
"tencent/hy3-paid": { input: 0.14, output: 0.58, cacheRead: 0.035, cacheWrite: 0 },
|
|
46
|
+
"tencent/hy4-preview": { input: 0.834, output: 2.501, cacheRead: 0.042, cacheWrite: 0 },
|
|
47
47
|
"moonshotai/Kimi-K3": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 0 },
|
|
48
48
|
"moonshotai/Kimi-K2.7-Code": { input: 0.95, output: 4, cacheRead: 0.19, cacheWrite: 0 },
|
|
49
49
|
"moonshotai/Kimi-K2.7-Code-Highspeed": {
|
|
@@ -54,6 +54,7 @@ export const MODEL_COSTS: Readonly<Record<string, CommandCodeModelCost>> = {
|
|
|
54
54
|
},
|
|
55
55
|
"moonshotai/Kimi-K2.6": { input: 0.95, output: 4, cacheRead: 0.16, cacheWrite: 0 },
|
|
56
56
|
"moonshotai/Kimi-K2.5": { input: 0.6, output: 3, cacheRead: 0.1, cacheWrite: 0 },
|
|
57
|
+
"z-ai/glm-5.3-flash": { input: 0.15, output: 0.5, cacheRead: 0.03, cacheWrite: 0 },
|
|
57
58
|
"zai-org/GLM-5.3": { input: 1.4, output: 4.4, cacheRead: 0.26, cacheWrite: 0 },
|
|
58
59
|
"zai-org/GLM-5.2": { input: 1.4, output: 4.4, cacheRead: 0.26, cacheWrite: 0 },
|
|
59
60
|
"zai-org/GLM-5.2-Fast": { input: 3, output: 10.25, cacheRead: 0.5, cacheWrite: 0 },
|
|
@@ -82,8 +83,15 @@ export const MODEL_COSTS: Readonly<Record<string, CommandCodeModelCost>> = {
|
|
|
82
83
|
cacheRead: 0.007,
|
|
83
84
|
cacheWrite: 0,
|
|
84
85
|
},
|
|
86
|
+
"deepseek/deepseek-v4-flash-fast": {
|
|
87
|
+
input: 0.28,
|
|
88
|
+
output: 0.56,
|
|
89
|
+
cacheRead: 0.07,
|
|
90
|
+
cacheWrite: 0,
|
|
91
|
+
},
|
|
85
92
|
"Qwen/Qwen3.8-Max": { input: 2, output: 6, cacheRead: 0.25, cacheWrite: 2.5 },
|
|
86
93
|
"Qwen/Qwen3.8-27B": { input: 0.4, output: 3, cacheRead: 0.04, cacheWrite: 0 },
|
|
94
|
+
"Qwen/Qwen3.8-Flash": { input: 0.16, output: 0.47, cacheRead: 0.016, cacheWrite: 0 },
|
|
87
95
|
"Qwen/Qwen3.7-Max": { input: 2.5, output: 7.5, cacheRead: 0.5, cacheWrite: 3.13 },
|
|
88
96
|
"Qwen/Qwen3.7-Plus": {
|
|
89
97
|
input: 0.4,
|
|
@@ -158,9 +166,9 @@ export const MODEL_COSTS: Readonly<Record<string, CommandCodeModelCost>> = {
|
|
|
158
166
|
},
|
|
159
167
|
|
|
160
168
|
// Anthropic
|
|
161
|
-
// Introductory pricing through 2026-08-31.
|
|
162
169
|
"claude-sonnet-5": { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 },
|
|
163
170
|
"claude-sonnet-4-6": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },
|
|
171
|
+
"claude-fable-5-1": { input: 10, output: 50, cacheRead: 0.25, cacheWrite: 12.5 },
|
|
164
172
|
"claude-fable-5": { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 },
|
|
165
173
|
"claude-opus-5": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 },
|
|
166
174
|
"claude-opus-4-8": { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 },
|
|
@@ -183,10 +191,10 @@ export const MODEL_COSTS: Readonly<Record<string, CommandCodeModelCost>> = {
|
|
|
183
191
|
|
|
184
192
|
// Google and xAI
|
|
185
193
|
"google/gemini-3.7-flash": {
|
|
186
|
-
input:
|
|
187
|
-
output:
|
|
188
|
-
cacheRead: 0.
|
|
189
|
-
cacheWrite: 0.
|
|
194
|
+
input: 1.5,
|
|
195
|
+
output: 7.5,
|
|
196
|
+
cacheRead: 0.15,
|
|
197
|
+
cacheWrite: 0.08334,
|
|
190
198
|
},
|
|
191
199
|
"google/gemini-3.6-flash": { input: 1.5, output: 7.5, cacheRead: 0.15, cacheWrite: 0 },
|
|
192
200
|
"google/gemini-3.5-flash": { input: 1.5, output: 9, cacheRead: 0.15, cacheWrite: 0 },
|
|
@@ -220,15 +228,4 @@ export const MODEL_COSTS: Readonly<Record<string, CommandCodeModelCost>> = {
|
|
|
220
228
|
},
|
|
221
229
|
}
|
|
222
230
|
|
|
223
|
-
export const TEMPORARY_PRICING: readonly TemporaryPricing[] = [
|
|
224
|
-
{
|
|
225
|
-
models: ["claude-sonnet-5"],
|
|
226
|
-
expiresOn: "2026-08-31",
|
|
227
|
-
description: "introductory pricing",
|
|
228
|
-
},
|
|
229
|
-
{
|
|
230
|
-
models: ["google/gemini-3.7-flash"],
|
|
231
|
-
expiresOn: "2026-12-31",
|
|
232
|
-
description: "50% promotional pricing",
|
|
233
|
-
},
|
|
234
|
-
]
|
|
231
|
+
export const TEMPORARY_PRICING: readonly TemporaryPricing[] = []
|
package/src/quota-format.ts
CHANGED
|
@@ -49,10 +49,42 @@ function creditsDetail(credits: CommandCodeCredits | null): string | undefined {
|
|
|
49
49
|
return `Sources: ${parts.join(" / ")}`
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
function
|
|
52
|
+
function parsePeriodEnd(value: string): Date | null {
|
|
53
|
+
const trimmed = value.trim()
|
|
54
|
+
const timestamp = /^\d+$/.test(trimmed) ? Number(trimmed) : Date.parse(trimmed)
|
|
55
|
+
if (!Number.isFinite(timestamp) || timestamp < 0) return null
|
|
56
|
+
const milliseconds = timestamp >= 1e12 ? timestamp : timestamp * 1000
|
|
57
|
+
const date = new Date(milliseconds)
|
|
58
|
+
return Number.isNaN(date.getTime()) ? null : date
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function subscriptionLine(
|
|
62
|
+
subscription: CommandCodeSubscription,
|
|
63
|
+
now: () => number = Date.now,
|
|
64
|
+
): string {
|
|
53
65
|
const plan = (subscription.planId ?? "Unknown").replace(/[_-]+/g, " ").trim()
|
|
54
66
|
const status = subscription.status ? ` (${subscription.status})` : ""
|
|
55
|
-
|
|
67
|
+
let renewal = ""
|
|
68
|
+
if (subscription.currentPeriodEnd) {
|
|
69
|
+
const end = parsePeriodEnd(subscription.currentPeriodEnd)
|
|
70
|
+
if (end) {
|
|
71
|
+
const diffMs = end.getTime() - now()
|
|
72
|
+
const days = Math.ceil(diffMs / 86_400_000)
|
|
73
|
+
const dateStr = end.toLocaleDateString("en-US", {
|
|
74
|
+
month: "short",
|
|
75
|
+
day: "numeric",
|
|
76
|
+
timeZone: "UTC",
|
|
77
|
+
})
|
|
78
|
+
if (days > 0) {
|
|
79
|
+
renewal = ` · renews ${dateStr} (${days}d)`
|
|
80
|
+
} else if (days === 0) {
|
|
81
|
+
renewal = ` · renews ${dateStr} (today)`
|
|
82
|
+
} else {
|
|
83
|
+
renewal = ` · renewed ${dateStr}`
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return `Plan: ${plan}${status}${renewal}`
|
|
56
88
|
}
|
|
57
89
|
|
|
58
90
|
function formatTokens(tokens: number): string {
|
|
@@ -77,7 +109,7 @@ export function formatQuota(quota: CommandCodeQuota, now: () => number = Date.no
|
|
|
77
109
|
|
|
78
110
|
const detail = creditsDetail(quota.credits)
|
|
79
111
|
if (detail) lines.push(detail)
|
|
80
|
-
if (quota.subscription) lines.push(subscriptionLine(quota.subscription))
|
|
112
|
+
if (quota.subscription) lines.push(subscriptionLine(quota.subscription, now))
|
|
81
113
|
|
|
82
114
|
if (quota.summary) {
|
|
83
115
|
lines.push("")
|
package/src/quota.ts
CHANGED
|
@@ -43,6 +43,13 @@ function stringValue(value: unknown): string | undefined {
|
|
|
43
43
|
return typeof value === "string" && value.length > 0 ? value : undefined
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
function timestampValue(value: unknown): string | undefined {
|
|
47
|
+
const text = stringValue(value)
|
|
48
|
+
if (text) return text
|
|
49
|
+
const number = numberValue(value)
|
|
50
|
+
return number === undefined ? undefined : String(number)
|
|
51
|
+
}
|
|
52
|
+
|
|
46
53
|
function errorMessage(error: unknown): string {
|
|
47
54
|
return error instanceof Error ? error.message : String(error)
|
|
48
55
|
}
|
|
@@ -100,8 +107,8 @@ function parseSubscription(value: unknown): CommandCodeSubscription | null {
|
|
|
100
107
|
const data = value.data
|
|
101
108
|
const planId = stringValue(data.planId)
|
|
102
109
|
const status = stringValue(data.status)
|
|
103
|
-
const currentPeriodStart =
|
|
104
|
-
const currentPeriodEnd =
|
|
110
|
+
const currentPeriodStart = timestampValue(data.currentPeriodStart)
|
|
111
|
+
const currentPeriodEnd = timestampValue(data.currentPeriodEnd)
|
|
105
112
|
if (!planId && !status && !currentPeriodStart && !currentPeriodEnd) return null
|
|
106
113
|
return {
|
|
107
114
|
planId: planId ?? null,
|
package/src/runtime.ts
CHANGED
|
@@ -26,7 +26,9 @@ export interface CommandCodeRuntimeApi<
|
|
|
26
26
|
export interface CommandCodeRuntimeOptions<TProviderConfig> {
|
|
27
27
|
endpoint: string
|
|
28
28
|
cachePath: string
|
|
29
|
-
loadModels: () => Promise<LoadCommandCodeModelsResult>
|
|
29
|
+
loadModels: (signal: AbortSignal) => Promise<LoadCommandCodeModelsResult>
|
|
30
|
+
/** Cached catalog only; resolves to an empty list when no valid cache exists. */
|
|
31
|
+
loadCachedModels: () => Promise<readonly CommandCodeModel[]>
|
|
30
32
|
createProviderConfig: (models: readonly CommandCodeModel[]) => TProviderConfig
|
|
31
33
|
getTransport?: () => "unknown" | "provider" | "generate"
|
|
32
34
|
now?: () => number
|
|
@@ -108,6 +110,7 @@ export class CommandCodeRuntime<TProviderConfig, TContext extends CommandCodeCom
|
|
|
108
110
|
private status: CommandCodeRuntimeStatus
|
|
109
111
|
private providerRegistered = false
|
|
110
112
|
private refreshPromise: Promise<CommandCodeRefreshResult> | undefined
|
|
113
|
+
private readonly shutdown = new AbortController()
|
|
111
114
|
|
|
112
115
|
constructor(
|
|
113
116
|
private readonly pi: CommandCodeRuntimeApi<TProviderConfig, TContext>,
|
|
@@ -133,9 +136,34 @@ export class CommandCodeRuntime<TProviderConfig, TContext extends CommandCodeCom
|
|
|
133
136
|
}
|
|
134
137
|
}
|
|
135
138
|
|
|
139
|
+
/**
|
|
140
|
+
* Registers the cached catalog immediately and refreshes it in the
|
|
141
|
+
* background so host startup does not wait for the network. Without a
|
|
142
|
+
* valid cache the live refresh is awaited so models are available at once.
|
|
143
|
+
*/
|
|
136
144
|
async initialize(): Promise<void> {
|
|
137
145
|
this.registerCommands()
|
|
138
|
-
|
|
146
|
+
|
|
147
|
+
const cached = await this.options.loadCachedModels()
|
|
148
|
+
if (cached.length === 0) {
|
|
149
|
+
await this.refresh()
|
|
150
|
+
return
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
this.pi.registerProvider("commandcode", this.options.createProviderConfig(cached))
|
|
154
|
+
this.providerRegistered = true
|
|
155
|
+
this.status = {
|
|
156
|
+
...this.status,
|
|
157
|
+
source: "cache",
|
|
158
|
+
modelCount: cached.length,
|
|
159
|
+
lastSuccess: this.now(),
|
|
160
|
+
}
|
|
161
|
+
void this.refresh()
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** Aborts any background refresh so a stopping host does not wait for the network. */
|
|
165
|
+
dispose(): void {
|
|
166
|
+
this.shutdown.abort(new Error("Command Code provider shut down"))
|
|
139
167
|
}
|
|
140
168
|
|
|
141
169
|
refresh(): Promise<CommandCodeRefreshResult> {
|
|
@@ -156,7 +184,7 @@ export class CommandCodeRuntime<TProviderConfig, TContext extends CommandCodeCom
|
|
|
156
184
|
}
|
|
157
185
|
|
|
158
186
|
try {
|
|
159
|
-
const loaded = await this.options.loadModels()
|
|
187
|
+
const loaded = await this.options.loadModels(this.shutdown.signal)
|
|
160
188
|
const warning = loaded.warning ? redactDiagnosticText(loaded.warning) : undefined
|
|
161
189
|
|
|
162
190
|
const shouldRegister =
|
|
@@ -217,6 +245,14 @@ export class CommandCodeRuntime<TProviderConfig, TContext extends CommandCodeCom
|
|
|
217
245
|
warning: preservedWarning,
|
|
218
246
|
}
|
|
219
247
|
} catch (error) {
|
|
248
|
+
if (this.shutdown.signal.aborted) {
|
|
249
|
+
this.status = { ...this.status, refreshing: false }
|
|
250
|
+
return {
|
|
251
|
+
refreshed: false,
|
|
252
|
+
source: this.status.source,
|
|
253
|
+
modelCount: this.status.modelCount,
|
|
254
|
+
}
|
|
255
|
+
}
|
|
220
256
|
const warning = redactDiagnosticText(
|
|
221
257
|
`Could not refresh the Command Code model catalog: ${errorMessage(error)}`,
|
|
222
258
|
)
|