@mars-sea/dsh-commandcode-provider 0.10.0-alpha.2 → 0.10.0-alpha.4

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/lib/index.d.ts CHANGED
@@ -2,6 +2,7 @@ import z from "@deepseek-ai/schemastery";
2
2
  import { GenerateOptions, LlmAdapter, LlmModelInfo, LlmProviderInfo, LlmResolvedModelInfo, ResolvedRetryPolicy, StreamChunk } from "@deepseek-ai/dsh-llm";
3
3
  import { CredentialRef } from "@deepseek-ai/dsh-credentials";
4
4
  import { TypertRemoteService, TypertSchema } from "@deepseek-ai/dsh-typert-protocol";
5
+ import { WebRuntime, WebSearchProvider, WebSearchRequest, WebSearchResult } from "@deepseek-ai/dsh-web";
5
6
  import { Context } from "@deepseek-ai/cordis";
6
7
  import { AttachmentStore } from "@deepseek-ai/dsh-attachment";
7
8
  import { CommandDefinition } from "@deepseek-ai/dsh-commands";
@@ -24,7 +25,7 @@ declare const KNOWN_EFFORTS: Readonly<Record<string, readonly string[]>>;
24
25
  */
25
26
  declare const KNOWN_IMAGE_MODELS: ReadonlySet<string>;
26
27
  /**
27
- * Models the official CLI's model table (command-code@1.38.2) marks
28
+ * Models the official CLI's model table (command-code@1.39.2) marks
28
29
  * `reasoning:!0` but defines no selectable `reasoning_effort` levels — they
29
30
  * think automatically, with Command Code driving the depth. This is the
30
31
  * authoritative "thinks, effort not adjustable" set: `KNOWN_EFFORTS` (which
@@ -32,7 +33,7 @@ declare const KNOWN_IMAGE_MODELS: ReadonlySet<string>;
32
33
  * effort levels, and this snapshot is not surfaced in the picker's compact
33
34
  * description — it exists for programmatic consumers.
34
35
  *
35
- * Source: the command-code@1.38.2 bundled model table (dist/cli.mjs),
36
+ * Source: the command-code@1.39.2 bundled model table (dist/cli.mjs),
36
37
  * cross-checked with https://commandcode.ai/docs/reference/cli/models.
37
38
  * (`stealth/ox-alpha` left this set in command-code@1.32.1, which gave it
38
39
  * selectable `['low', 'high', 'max']` efforts; the preview then ended in
@@ -191,7 +192,7 @@ declare function peakPricingState(modelId: string, now?: number): 'peak' | 'off-
191
192
  * for models without time-of-day pricing.
192
193
  */
193
194
  declare function peakPricingLabel(modelId: string, now?: number): string | undefined;
194
- declare const COMMAND_CODE_CLI_VERSION = "1.38.2";
195
+ declare const COMMAND_CODE_CLI_VERSION = "1.39.2";
195
196
  declare const DEFAULT_API_BASE = "https://api.commandcode.ai";
196
197
  declare const DEFAULT_GENERATE_MAX_TOKENS = 64000;
197
198
  declare const DEFAULT_MAX_OUTPUT_TOKENS = 65536;
@@ -948,6 +949,48 @@ declare class CommandCodeLoginFlow {
948
949
  private teardown;
949
950
  }
950
951
  //#endregion
952
+ //#region src/web-search.d.ts
953
+ /** Stable id this provider registers under in `ctx.web`. */
954
+ declare const COMMANDCODE_SEARCH_PROVIDER_ID = "commandcode";
955
+ /**
956
+ * The factory-declared search provider id dsh ships by default (from
957
+ * `dsh-base`'s cordis patch `web.config.searchProvider`). A plugin that wants
958
+ * its own backend to win rewrites `WebRuntime.searchProviderId` to its own id;
959
+ * disabling that plugin restores this value.
960
+ */
961
+ declare const DEFAULT_WEB_SEARCH_PROVIDER_ID = "deepseek-official";
962
+ /**
963
+ * Point the web seam's search selection at this plugin's provider (`commandcode`).
964
+ * Sets the runtime field; the next search call honours it because `search()`
965
+ * re-reads `searchProviderId` each time. Returns the prior id (or undefined).
966
+ */
967
+ declare function selectCommandCodeSearchProvider(web: WebRuntime, enable: boolean): string | undefined;
968
+ /** Per-request facts the provider needs, all injected so the class stays cordis-free and testable. */
969
+ interface CommandCodeSearchProviderDeps {
970
+ /** Resolve one usable Command Code key (credential seam → env → auth file), or undefined when none. */
971
+ resolveKey(): Promise<string | undefined>;
972
+ /** The API base host (defaults to `https://api.commandcode.ai`). */
973
+ apiBase(): string;
974
+ /** Injectable fetch for tests; defaults to the global fetch. */
975
+ fetchImpl?: typeof fetch;
976
+ }
977
+ /**
978
+ * A `ctx.web` search provider backed by the Command Code Provider API. Reuses
979
+ * the plugin's credential chain and `apiBase`, so search "just works" with the
980
+ * existing key — the model-facing `web_search` tool needs no separate
981
+ * configuration. Selection between multiple search providers is the web seam's
982
+ * job (pin `searchProvider: commandcode` if ambiguous).
983
+ */
984
+ declare class CommandCodeSearchProvider implements WebSearchProvider {
985
+ private readonly deps;
986
+ readonly id = "commandcode";
987
+ constructor(deps: CommandCodeSearchProviderDeps);
988
+ /** Cheap local check; must not make network calls. Presence of a key path + a parseable base is enough. */
989
+ available(): boolean;
990
+ search(request: WebSearchRequest, signal?: AbortSignal): Promise<WebSearchResult>;
991
+ private resolveKey;
992
+ }
993
+ //#endregion
951
994
  //#region src/index.d.ts
952
995
  declare const name = "llm-commandcode";
953
996
  declare const inject: string[];
@@ -1012,6 +1055,17 @@ interface Config {
1012
1055
  * gate. The first matching rule wins.
1013
1056
  */
1014
1057
  modelAccountRules?: CommandCodeModelAccountRule[];
1058
+ /**
1059
+ * Whether to use Command Code as the backend for dsh's model-facing
1060
+ * `web_search` tool. When enabled, the plugin registers a `commandcode`
1061
+ * search provider on `ctx.web` AND rewrites the web seam's selected
1062
+ * `searchProviderId` to `commandcode` (so it wins over the shipped
1063
+ * `deepseek-official`), using the SAME Command Code API key/base as chat.
1064
+ * The rewrite rides dsh's internal `searchProviderId`, which is read per
1065
+ * search call, so a setting change lands on the next search without a
1066
+ * restart. Defaults to true.
1067
+ */
1068
+ webSearch?: boolean;
1015
1069
  /**
1016
1070
  * Language override for the `/commandcode` Host-side command's user-facing
1017
1071
  * copy. Host commands cannot read the client's `ctx.locale`, so this is
@@ -1039,5 +1093,5 @@ interface ResolvedCommandCodeOptions extends CommandCodeConnectionOptions {
1039
1093
  declare function resolveAdapterOptions(config: Config): ResolvedCommandCodeOptions;
1040
1094
  declare function apply(ctx: Context, config: Config): void;
1041
1095
  //#endregion
1042
- export { type ApiKeyValidation, BILLING_ACCESS_TTL_MS, COMMAND_CODE_CLI_VERSION, type CommandCodeAccountConfig, CommandCodeAccountPool, type CommandCodeAccountSlot, type CommandCodeAccountState, type CommandCodeAccountUsage, type CommandCodeAccountsReport, CommandCodeAdapter, type CommandCodeAdapterDeps, type CommandCodeBillingAccess, type CommandCodeCommandDeps, type CommandCodeConnectionOptions, type CommandCodeLoginCredentials, type CommandCodeLoginFailureReason, CommandCodeLoginFlow, type CommandCodeLoginFlowDeps, type CommandCodeLoginStatus, type CommandCodeModelAccountRule, type CommandCodeUsageDeps, type CommandCodeUsageReport, CommandCodeUsageService, Config, DEFAULT_API_BASE, DEFAULT_GENERATE_MAX_TOKENS, DEFAULT_MAX_OUTPUT_TOKENS, DEFAULT_MODELS_CACHE_PATH, DEFAULT_REQUEST_TIMEOUT_MS, DEFAULT_STREAM_IDLE_TIMEOUT_MS, KNOWN_DEALS, KNOWN_EFFORTS, KNOWN_IMAGE_MODELS, KNOWN_PEAK_PRICING, KNOWN_PLANS, KNOWN_SUBSCRIPTION_PLANS, KNOWN_THINKING_MODELS, LOGIN_ALLOWED_ORIGINS, LOGIN_BEGIN_ENDPOINT, LOGIN_BODY_LIMIT_BYTES, LOGIN_CANCEL_ENDPOINT, LOGIN_MAX_PORT_ATTEMPTS, LOGIN_START_PORT, LOGIN_STATUS_ENDPOINT, LOGIN_TIMEOUT_MS, type LoginFlowFacade, PLAN_LABELS, PLAN_ORDER, PROVIDER, type ResolveAttachments, ResolvedCommandCodeOptions, USAGE_REPORT_ENDPOINT, accountUsable, apply, applyCommands, applyUsageRemote, buildCommandAuthUrl, capabilityDescription, commandDefinition, compareByPlan, dealLabel, formatContext, inject, loginStatusSchema, matchModelRule, modelVisibleInPlan, name, parseLoginStatus, peakPricingLabel, peakPricingState, planLabel, projectSlugFromPath, resolveAdapterOptions, resolveAuthFileApiKey, selectAccountForModel, selectActiveAccount, studioBaseForApiBase, subscriptionPlanInfo, usageReportSchema, validateCommandApiKey };
1096
+ export { type ApiKeyValidation, BILLING_ACCESS_TTL_MS, COMMANDCODE_SEARCH_PROVIDER_ID, COMMAND_CODE_CLI_VERSION, type CommandCodeAccountConfig, CommandCodeAccountPool, type CommandCodeAccountSlot, type CommandCodeAccountState, type CommandCodeAccountUsage, type CommandCodeAccountsReport, CommandCodeAdapter, type CommandCodeAdapterDeps, type CommandCodeBillingAccess, type CommandCodeCommandDeps, type CommandCodeConnectionOptions, type CommandCodeLoginCredentials, type CommandCodeLoginFailureReason, CommandCodeLoginFlow, type CommandCodeLoginFlowDeps, type CommandCodeLoginStatus, type CommandCodeModelAccountRule, CommandCodeSearchProvider, type CommandCodeSearchProviderDeps, type CommandCodeUsageDeps, type CommandCodeUsageReport, CommandCodeUsageService, Config, DEFAULT_API_BASE, DEFAULT_GENERATE_MAX_TOKENS, DEFAULT_MAX_OUTPUT_TOKENS, DEFAULT_MODELS_CACHE_PATH, DEFAULT_REQUEST_TIMEOUT_MS, DEFAULT_STREAM_IDLE_TIMEOUT_MS, DEFAULT_WEB_SEARCH_PROVIDER_ID, KNOWN_DEALS, KNOWN_EFFORTS, KNOWN_IMAGE_MODELS, KNOWN_PEAK_PRICING, KNOWN_PLANS, KNOWN_SUBSCRIPTION_PLANS, KNOWN_THINKING_MODELS, LOGIN_ALLOWED_ORIGINS, LOGIN_BEGIN_ENDPOINT, LOGIN_BODY_LIMIT_BYTES, LOGIN_CANCEL_ENDPOINT, LOGIN_MAX_PORT_ATTEMPTS, LOGIN_START_PORT, LOGIN_STATUS_ENDPOINT, LOGIN_TIMEOUT_MS, type LoginFlowFacade, PLAN_LABELS, PLAN_ORDER, PROVIDER, type ResolveAttachments, ResolvedCommandCodeOptions, USAGE_REPORT_ENDPOINT, accountUsable, apply, applyCommands, applyUsageRemote, buildCommandAuthUrl, capabilityDescription, commandDefinition, compareByPlan, dealLabel, formatContext, inject, loginStatusSchema, matchModelRule, modelVisibleInPlan, name, parseLoginStatus, peakPricingLabel, peakPricingState, planLabel, projectSlugFromPath, resolveAdapterOptions, resolveAuthFileApiKey, selectAccountForModel, selectActiveAccount, selectCommandCodeSearchProvider, studioBaseForApiBase, subscriptionPlanInfo, usageReportSchema, validateCommandApiKey };
1043
1097
  //# sourceMappingURL=index.d.ts.map
package/lib/index.js CHANGED
@@ -11,6 +11,7 @@ import { randomBytes, randomUUID } from "node:crypto";
11
11
  import { TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
12
12
  import { createServer } from "node:http";
13
13
  import { createServer as createServer$1 } from "node:net";
14
+ import { WebError } from "@deepseek-ai/dsh-web";
14
15
  //#region src/accounts.ts
15
16
  /**
16
17
  * Multi-account pool for the Command Code provider (host side).
@@ -243,7 +244,7 @@ var CommandCodeAccountPool = class {
243
244
  * and API key or subscription, and Command Code's terms apply.
244
245
  *
245
246
  * Wire protocol (reverse-engineered by the pi plugin, command-code@1.28.4;
246
- * re-verified against command-code@1.38.2 — endpoints, request shape, and
247
+ * re-verified against command-code@1.39.2 — endpoints, request shape, and
247
248
  * stream events unchanged):
248
249
  * POST {apiBase}/alpha/generate
249
250
  * body: { config, memory, taste, skills, params: { model, messages, tools,
@@ -314,6 +315,11 @@ const KNOWN_EFFORTS = {
314
315
  "xhigh",
315
316
  "max"
316
317
  ],
318
+ "deepseek/deepseek-v4-flash-fast": [
319
+ "low",
320
+ "high",
321
+ "max"
322
+ ],
317
323
  "deepseek/deepseek-v4-flash": ["high", "max"],
318
324
  "deepseek/deepseek-v4-flash-vision-exp": ["high", "max"],
319
325
  "deepseek/deepseek-v4-pro": ["high", "max"],
@@ -476,7 +482,7 @@ const KNOWN_IMAGE_MODELS = /* @__PURE__ */ new Set([
476
482
  "z-ai/glm-5.3-flash"
477
483
  ]);
478
484
  /**
479
- * Models the official CLI's model table (command-code@1.38.2) marks
485
+ * Models the official CLI's model table (command-code@1.39.2) marks
480
486
  * `reasoning:!0` but defines no selectable `reasoning_effort` levels — they
481
487
  * think automatically, with Command Code driving the depth. This is the
482
488
  * authoritative "thinks, effort not adjustable" set: `KNOWN_EFFORTS` (which
@@ -484,7 +490,7 @@ const KNOWN_IMAGE_MODELS = /* @__PURE__ */ new Set([
484
490
  * effort levels, and this snapshot is not surfaced in the picker's compact
485
491
  * description — it exists for programmatic consumers.
486
492
  *
487
- * Source: the command-code@1.38.2 bundled model table (dist/cli.mjs),
493
+ * Source: the command-code@1.39.2 bundled model table (dist/cli.mjs),
488
494
  * cross-checked with https://commandcode.ai/docs/reference/cli/models.
489
495
  * (`stealth/ox-alpha` left this set in command-code@1.32.1, which gave it
490
496
  * selectable `['low', 'high', 'max']` efforts; the preview then ended in
@@ -544,6 +550,7 @@ const KNOWN_PLANS = {
544
550
  "Qwen/Qwen3.8-27B": "go",
545
551
  "Qwen/Qwen3.8-Flash": "go",
546
552
  "Qwen/Qwen3.8-Max": "go",
553
+ "deepseek/deepseek-v4-flash-fast": "go",
547
554
  "deepseek/deepseek-v4-flash": "go",
548
555
  "deepseek/deepseek-v4-flash-vision-exp": "go",
549
556
  "deepseek/deepseek-v4-pro": "go",
@@ -729,16 +736,6 @@ const KNOWN_DEALS = {
729
736
  "MiniMaxAI/MiniMax-M3": { label: "50% off" },
730
737
  "xiaomi/mimo-v2.5-pro": { label: "99% off" },
731
738
  "xiaomi/mimo-v2.5": { label: "98% off" },
732
- "minimax/minimax-m3-free": {
733
- label: "FREE",
734
- free: true,
735
- expiresAt: "2026-09-05T23:59:59Z"
736
- },
737
- "minimax/minimax-m2.7-free": {
738
- label: "FREE",
739
- free: true,
740
- expiresAt: "2026-09-05T23:59:59Z"
741
- },
742
739
  "poolside/laguna-s-2.1-free": {
743
740
  label: "FREE",
744
741
  free: true
@@ -769,7 +766,8 @@ const KNOWN_DEALS = {
769
766
  const KNOWN_PEAK_PRICING = /* @__PURE__ */ new Set([
770
767
  "deepseek/deepseek-v4-pro",
771
768
  "deepseek/deepseek-v4-flash",
772
- "deepseek/deepseek-v4-flash-vision-exp"
769
+ "deepseek/deepseek-v4-flash-vision-exp",
770
+ "deepseek/deepseek-v4-flash-fast"
773
771
  ]);
774
772
  /** Peak hours (UTC, hour-of-day range end-exclusive): 01–03 and 06–09. */
775
773
  const PEAK_HOUR_RANGES = [[1, 4], [6, 10]];
@@ -794,7 +792,7 @@ function peakPricingLabel(modelId, now = Date.now()) {
794
792
  if (state === void 0) return void 0;
795
793
  return state === "peak" ? "Peak" : "Half";
796
794
  }
797
- const COMMAND_CODE_CLI_VERSION = "1.38.2";
795
+ const COMMAND_CODE_CLI_VERSION = "1.39.2";
798
796
  const DEFAULT_API_BASE = "https://api.commandcode.ai";
799
797
  const DEFAULT_GENERATE_MAX_TOKENS = 64e3;
800
798
  const DEFAULT_MAX_OUTPUT_TOKENS = 65536;
@@ -2752,6 +2750,185 @@ function corsOrigin(origin) {
2752
2750
  return origin !== void 0 && LOGIN_ALLOWED_ORIGINS.includes(origin) ? origin : "";
2753
2751
  }
2754
2752
  //#endregion
2753
+ //#region src/web-search.ts
2754
+ /**
2755
+ * dsh-commandcode-provider — Command Code web search provider over `ctx.web`.
2756
+ *
2757
+ * The official Command Code CLI ships a built-in `web_search` tool that POSTs
2758
+ * `{ query, numResults, allowedDomains?, blockedDomains? }` to
2759
+ * `{apiBase}/alpha/web-search` and reads `{ results: [{ title, url, snippet }] }`
2760
+ * back. It authenticates with the SAME `Authorization: Bearer <key>` header and
2761
+ * `x-command-code-version` the model adapter uses, so this provider reuses the
2762
+ * plugin's existing credential chain (`COMMANDCODE_API_KEY` → credentials seam →
2763
+ * `~/.commandcode/auth.json`) — no separate DeepSeek key, no extra endpoint.
2764
+ *
2765
+ * This mirrors the host-side `@deepseek-ai/dsh-web-search-deepseek` provider in
2766
+ * shape: a cordis-free class registered into the web seam, resolving its key per
2767
+ * search, mapping each server-side result to the harness's normalized
2768
+ * `WebSearchSource`. The web seam owns `maxResults` truncation.
2769
+ *
2770
+ * @module dsh-commandcode-provider/web-search
2771
+ */
2772
+ /** Stable id this provider registers under in `ctx.web`. */
2773
+ const COMMANDCODE_SEARCH_PROVIDER_ID = "commandcode";
2774
+ /**
2775
+ * The factory-declared search provider id dsh ships by default (from
2776
+ * `dsh-base`'s cordis patch `web.config.searchProvider`). A plugin that wants
2777
+ * its own backend to win rewrites `WebRuntime.searchProviderId` to its own id;
2778
+ * disabling that plugin restores this value.
2779
+ */
2780
+ const DEFAULT_WEB_SEARCH_PROVIDER_ID = "deepseek-official";
2781
+ /**
2782
+ * Point the web seam's search selection at this plugin's provider (`commandcode`).
2783
+ * Sets the runtime field; the next search call honours it because `search()`
2784
+ * re-reads `searchProviderId` each time. Returns the prior id (or undefined).
2785
+ */
2786
+ function selectCommandCodeSearchProvider(web, enable) {
2787
+ const field = web;
2788
+ const prior = field.searchProviderId;
2789
+ field.searchProviderId = enable ? COMMANDCODE_SEARCH_PROVIDER_ID : DEFAULT_WEB_SEARCH_PROVIDER_ID;
2790
+ return prior;
2791
+ }
2792
+ /** Command Code's lower/upper bound on `numResults` (from the CLI's `web_search` schema). */
2793
+ const MIN_NUM_RESULTS = 1;
2794
+ const MAX_NUM_RESULTS = 10;
2795
+ /** CLI default when the caller sets no result cap. */
2796
+ const DEFAULT_NUM_RESULTS = 5;
2797
+ /** The endpoint the search POST goes to; `{apiBase}` is prepended. */
2798
+ const SEARCH_ROUTE = "/alpha/web-search";
2799
+ /**
2800
+ * Clamp a DSH `maxResults` bound into Command Code's 1–10 range, applying the
2801
+ * CLI default of 5 when the caller supplied none.
2802
+ */
2803
+ function clampNumResults(maxResults) {
2804
+ return maxResults === void 0 ? DEFAULT_NUM_RESULTS : Math.max(MIN_NUM_RESULTS, Math.min(MAX_NUM_RESULTS, Math.round(maxResults)));
2805
+ }
2806
+ /** Build a `WebSearchSource` from one raw `{ title, url, snippet }` result, omitting empty optional fields. */
2807
+ function toSource(result) {
2808
+ const url = result.url?.trim();
2809
+ if (url === void 0 || url.length === 0) return void 0;
2810
+ const title = result.title?.trim();
2811
+ const snippet = result.snippet?.trim();
2812
+ return {
2813
+ url,
2814
+ ...title !== void 0 && title.length > 0 ? { title } : {},
2815
+ ...snippet !== void 0 && snippet.length > 0 ? { snippet } : {}
2816
+ };
2817
+ }
2818
+ function isAbortError(error) {
2819
+ return error instanceof DOMException && error.name === "AbortError";
2820
+ }
2821
+ /** Build the provider's stable cancellation error while retaining the caller's reason. */
2822
+ function searchAborted(signal, fallback) {
2823
+ return new WebError("Command Code web search aborted", "WEB_ABORTED", { cause: signal?.aborted === true ? signal.reason : fallback });
2824
+ }
2825
+ function throwIfAborted(signal) {
2826
+ if (signal?.aborted === true) throw searchAborted(signal, void 0);
2827
+ }
2828
+ /**
2829
+ * A `ctx.web` search provider backed by the Command Code Provider API. Reuses
2830
+ * the plugin's credential chain and `apiBase`, so search "just works" with the
2831
+ * existing key — the model-facing `web_search` tool needs no separate
2832
+ * configuration. Selection between multiple search providers is the web seam's
2833
+ * job (pin `searchProvider: commandcode` if ambiguous).
2834
+ */
2835
+ var CommandCodeSearchProvider = class {
2836
+ deps;
2837
+ id = COMMANDCODE_SEARCH_PROVIDER_ID;
2838
+ constructor(deps) {
2839
+ this.deps = deps;
2840
+ }
2841
+ /** Cheap local check; must not make network calls. Presence of a key path + a parseable base is enough. */
2842
+ available() {
2843
+ const base = this.deps.apiBase();
2844
+ return base.length > 0 && URL.canParse(base);
2845
+ }
2846
+ async search(request, signal) {
2847
+ throwIfAborted(signal);
2848
+ const apiBase = this.deps.apiBase();
2849
+ if (!URL.canParse(apiBase)) throw new WebError(`Command Code web search is misconfigured: apiBase ${JSON.stringify(apiBase)} is not a valid URL`, "WEB_PROVIDER_ERROR");
2850
+ const key = await this.resolveKey(signal);
2851
+ throwIfAborted(signal);
2852
+ const endpoint = `${apiBase.replace(/\/$/, "")}${SEARCH_ROUTE}`;
2853
+ const body = {
2854
+ query: request.query,
2855
+ numResults: clampNumResults(request.maxResults)
2856
+ };
2857
+ let response;
2858
+ try {
2859
+ response = await (this.deps.fetchImpl ?? fetch)(endpoint, {
2860
+ method: "POST",
2861
+ headers: {
2862
+ "Content-Type": "application/json",
2863
+ Authorization: `Bearer ${key}`,
2864
+ "x-command-code-version": COMMAND_CODE_CLI_VERSION,
2865
+ "x-cli-environment": "production",
2866
+ ...attributionHeaders()
2867
+ },
2868
+ body: JSON.stringify(body),
2869
+ ...signal !== void 0 ? { signal } : {}
2870
+ });
2871
+ } catch (error) {
2872
+ if (signal?.aborted === true || isAbortError(error)) throw searchAborted(signal, error);
2873
+ throw new WebError(`Command Code web search request failed: ${error instanceof Error ? error.message : String(error)}`, "WEB_PROVIDER_ERROR", { cause: error });
2874
+ }
2875
+ if (!response.ok) {
2876
+ let message = `Command Code web search failed (HTTP ${response.status})`;
2877
+ try {
2878
+ const parsed = await response.json();
2879
+ const detail = typeof parsed === "object" && parsed !== null ? parsed?.error : void 0;
2880
+ if (typeof detail === "string" && detail.length > 0) message += `: ${detail}`;
2881
+ else if (typeof detail === "object" && detail !== null) {
2882
+ const code = detail?.code;
2883
+ const inner = detail?.message;
2884
+ if (typeof code === "string" || typeof inner === "string") message += `: ${typeof code === "string" ? code : ""}${typeof code === "string" && typeof inner === "string" ? " — " : ""}${typeof inner === "string" ? inner : ""}`;
2885
+ }
2886
+ } catch (error) {
2887
+ if (signal?.aborted === true || isAbortError(error)) throw searchAborted(signal, error);
2888
+ }
2889
+ throw new WebError(message, "WEB_PROVIDER_ERROR");
2890
+ }
2891
+ let payload;
2892
+ try {
2893
+ payload = await response.json();
2894
+ } catch (error) {
2895
+ if (signal?.aborted === true || isAbortError(error)) throw searchAborted(signal, error);
2896
+ throw new WebError("Command Code web search returned an unparseable response body", "WEB_PROVIDER_ERROR");
2897
+ }
2898
+ const results = payload?.results;
2899
+ if (!Array.isArray(results)) throw new WebError("Command Code web search returned no results array (the server may have rejected the query)", "WEB_PROVIDER_ERROR");
2900
+ const sources = [];
2901
+ const seen = /* @__PURE__ */ new Set();
2902
+ for (const item of results) {
2903
+ if (typeof item !== "object" || item === null) continue;
2904
+ const source = toSource(item);
2905
+ if (source === void 0 || seen.has(source.url)) continue;
2906
+ seen.add(source.url);
2907
+ sources.push(source);
2908
+ }
2909
+ return {
2910
+ sources,
2911
+ truncated: false
2912
+ };
2913
+ }
2914
+ async resolveKey(signal) {
2915
+ let key;
2916
+ try {
2917
+ key = await this.deps.resolveKey();
2918
+ } catch (error) {
2919
+ if (signal?.aborted === true || isAbortError(error)) throw searchAborted(signal, error);
2920
+ if (error instanceof Error && typeof error.code === "string") {
2921
+ const code = error.code;
2922
+ if (code === "MISSING_CREDENTIAL") throw new WebError(error.message, "WEB_PROVIDER_CREDENTIAL_MISSING", { cause: error });
2923
+ if (code === "INVALID_CREDENTIAL" || code === "RATE_LIMIT") throw new WebError(error.message, "WEB_PROVIDER_ERROR", { cause: error });
2924
+ }
2925
+ throw new WebError(`Command Code web search credential resolution failed: ${error instanceof Error ? error.message : String(error)}`, "WEB_PROVIDER_ERROR", { cause: error });
2926
+ }
2927
+ if (key === void 0 || key.length === 0) throw new WebError("Command Code web search has no API key; store COMMANDCODE_API_KEY through the credentials service (the web Models page writes it), export it in the launching environment, set config.apiKey, or run `command-code login` to write ~/.commandcode/auth.json", "WEB_PROVIDER_CREDENTIAL_MISSING");
2928
+ return key;
2929
+ }
2930
+ };
2931
+ //#endregion
2755
2932
  //#region src/index.ts
2756
2933
  /**
2757
2934
  * dsh-commandcode-provider — DeepSeek Harness LLM provider plugin for Command
@@ -2797,6 +2974,7 @@ const Config = z.object({
2797
2974
  requestTimeoutMs: z.number().min(1).max(MAX_TIMER_DELAY_MS),
2798
2975
  streamIdleTimeoutMs: z.number().min(1).max(MAX_TIMER_DELAY_MS),
2799
2976
  filterModelsByPlan: z.boolean(),
2977
+ webSearch: z.boolean().default(true),
2800
2978
  accounts: z.array(z.object({
2801
2979
  label: z.string(),
2802
2980
  apiKeyEnv: z.string().role("credential-ref"),
@@ -2965,16 +3143,30 @@ function apply(ctx, config) {
2965
3143
  login: loginFlow,
2966
3144
  listModels: catalogForRules
2967
3145
  });
3146
+ let webRuntime;
3147
+ ctx.inject(["web"], (webCtx) => {
3148
+ webRuntime = webCtx.web;
3149
+ webCtx.web.registerSearchProvider(new CommandCodeSearchProvider({
3150
+ resolveKey: async () => {
3151
+ const resolved = await pool.resolveKey();
3152
+ return resolved === void 0 ? void 0 : resolved.key;
3153
+ },
3154
+ apiBase: () => options().apiBase
3155
+ }));
3156
+ selectCommandCodeSearchProvider(webCtx.web, current().webSearch ?? true);
3157
+ });
2968
3158
  ctx.inject(["settings"], (settingsCtx) => {
2969
3159
  settingsCtx.settings.installSection(ctx, NS, Config, config, {
2970
3160
  setSource: (source) => {
2971
3161
  current = source;
2972
3162
  },
2973
- onChange: () => {}
3163
+ onChange: () => {
3164
+ if (webRuntime !== void 0) selectCommandCodeSearchProvider(webRuntime, current().webSearch ?? true);
3165
+ }
2974
3166
  });
2975
3167
  });
2976
3168
  }
2977
3169
  //#endregion
2978
- export { BILLING_ACCESS_TTL_MS, COMMAND_CODE_CLI_VERSION, CommandCodeAccountPool, CommandCodeAdapter, CommandCodeLoginFlow, CommandCodeUsageService, Config, DEFAULT_API_BASE, DEFAULT_GENERATE_MAX_TOKENS, DEFAULT_MAX_OUTPUT_TOKENS, DEFAULT_MODELS_CACHE_PATH, DEFAULT_REQUEST_TIMEOUT_MS, DEFAULT_STREAM_IDLE_TIMEOUT_MS, KNOWN_DEALS, KNOWN_EFFORTS, KNOWN_IMAGE_MODELS, KNOWN_PEAK_PRICING, KNOWN_PLANS, KNOWN_SUBSCRIPTION_PLANS, KNOWN_THINKING_MODELS, LOGIN_ALLOWED_ORIGINS, LOGIN_BEGIN_ENDPOINT, LOGIN_BODY_LIMIT_BYTES, LOGIN_CANCEL_ENDPOINT, LOGIN_MAX_PORT_ATTEMPTS, LOGIN_START_PORT, LOGIN_STATUS_ENDPOINT, LOGIN_TIMEOUT_MS, PLAN_LABELS, PLAN_ORDER, PROVIDER, USAGE_REPORT_ENDPOINT, accountUsable, apply, applyCommands, applyUsageRemote, buildCommandAuthUrl, capabilityDescription, commandDefinition, compareByPlan, dealLabel, formatContext, inject, loginStatusSchema, matchModelRule, modelVisibleInPlan, name, parseLoginStatus, peakPricingLabel, peakPricingState, planLabel, projectSlugFromPath, resolveAdapterOptions, resolveAuthFileApiKey, selectAccountForModel, selectActiveAccount, studioBaseForApiBase, subscriptionPlanInfo, usageReportSchema, validateCommandApiKey };
3170
+ export { BILLING_ACCESS_TTL_MS, COMMANDCODE_SEARCH_PROVIDER_ID, COMMAND_CODE_CLI_VERSION, CommandCodeAccountPool, CommandCodeAdapter, CommandCodeLoginFlow, CommandCodeSearchProvider, CommandCodeUsageService, Config, DEFAULT_API_BASE, DEFAULT_GENERATE_MAX_TOKENS, DEFAULT_MAX_OUTPUT_TOKENS, DEFAULT_MODELS_CACHE_PATH, DEFAULT_REQUEST_TIMEOUT_MS, DEFAULT_STREAM_IDLE_TIMEOUT_MS, DEFAULT_WEB_SEARCH_PROVIDER_ID, KNOWN_DEALS, KNOWN_EFFORTS, KNOWN_IMAGE_MODELS, KNOWN_PEAK_PRICING, KNOWN_PLANS, KNOWN_SUBSCRIPTION_PLANS, KNOWN_THINKING_MODELS, LOGIN_ALLOWED_ORIGINS, LOGIN_BEGIN_ENDPOINT, LOGIN_BODY_LIMIT_BYTES, LOGIN_CANCEL_ENDPOINT, LOGIN_MAX_PORT_ATTEMPTS, LOGIN_START_PORT, LOGIN_STATUS_ENDPOINT, LOGIN_TIMEOUT_MS, PLAN_LABELS, PLAN_ORDER, PROVIDER, USAGE_REPORT_ENDPOINT, accountUsable, apply, applyCommands, applyUsageRemote, buildCommandAuthUrl, capabilityDescription, commandDefinition, compareByPlan, dealLabel, formatContext, inject, loginStatusSchema, matchModelRule, modelVisibleInPlan, name, parseLoginStatus, peakPricingLabel, peakPricingState, planLabel, projectSlugFromPath, resolveAdapterOptions, resolveAuthFileApiKey, selectAccountForModel, selectActiveAccount, selectCommandCodeSearchProvider, studioBaseForApiBase, subscriptionPlanInfo, usageReportSchema, validateCommandApiKey };
2979
3171
 
2980
3172
  //# sourceMappingURL=index.js.map