@khalilgharbaoui/opencode-claude-code-plugin 0.13.1 → 0.14.0

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/dist/index.js CHANGED
@@ -731,6 +731,251 @@ Now continuing with the current message:
731
731
  });
732
732
  }
733
733
 
734
+ // src/models.ts
735
+ var PROVIDER_ID = "claude-code";
736
+ var NPM = "@khalilgharbaoui/opencode-claude-code-plugin";
737
+ var reasoningVariants = {
738
+ low: { reasoningEffort: "low" },
739
+ medium: { reasoningEffort: "medium" },
740
+ high: { reasoningEffort: "high" },
741
+ xhigh: { reasoningEffort: "xhigh" },
742
+ max: { reasoningEffort: "max" }
743
+ };
744
+ var baseCapabilities = {
745
+ temperature: false,
746
+ attachment: true,
747
+ toolcall: true,
748
+ input: { text: true, audio: false, image: true, video: false, pdf: false },
749
+ output: { text: true, audio: false, image: false, video: false, pdf: false },
750
+ interleaved: false
751
+ };
752
+ function defineModel(opts) {
753
+ return {
754
+ id: opts.id,
755
+ providerID: PROVIDER_ID,
756
+ api: { id: opts.id, url: "", npm: NPM },
757
+ name: `${opts.name} (${opts.multiplier}\xD7)`,
758
+ family: opts.family,
759
+ capabilities: { ...baseCapabilities, reasoning: opts.reasoning },
760
+ cost: {
761
+ input: opts.cost.input,
762
+ output: opts.cost.output,
763
+ cache: { read: opts.cost.cacheRead, write: opts.cost.cacheWrite }
764
+ },
765
+ limit: { context: opts.context, output: opts.output },
766
+ status: opts.status ?? "active",
767
+ options: {},
768
+ headers: {},
769
+ release_date: opts.releaseDate,
770
+ variants: opts.reasoning ? reasoningVariants : void 0
771
+ };
772
+ }
773
+ var haikuCost = { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 };
774
+ var sonnetCost = { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 };
775
+ var sonnet5Cost = { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 };
776
+ var opusCost = { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 };
777
+ var fableCost = { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 };
778
+ var opusFastCost = { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 };
779
+ function toConfigModel(model) {
780
+ const inputMods = [];
781
+ const outputMods = [];
782
+ for (const [k, v] of Object.entries(model.capabilities.input)) {
783
+ if (v) inputMods.push(k);
784
+ }
785
+ for (const [k, v] of Object.entries(model.capabilities.output)) {
786
+ if (v) outputMods.push(k);
787
+ }
788
+ return {
789
+ id: model.api.id,
790
+ name: model.name,
791
+ status: model.status,
792
+ family: model.family ?? "",
793
+ release_date: model.release_date,
794
+ temperature: model.capabilities.temperature,
795
+ reasoning: model.capabilities.reasoning,
796
+ attachment: model.capabilities.attachment,
797
+ tool_call: model.capabilities.toolcall,
798
+ modalities: { input: inputMods, output: outputMods },
799
+ cost: {
800
+ input: model.cost.input,
801
+ output: model.cost.output,
802
+ cache_read: model.cost.cache.read,
803
+ cache_write: model.cost.cache.write
804
+ },
805
+ limit: model.limit,
806
+ options: model.options,
807
+ headers: model.headers,
808
+ variants: model.variants
809
+ };
810
+ }
811
+ var defaultModels = {
812
+ "claude-haiku-4-5": defineModel({
813
+ id: "claude-haiku-4-5",
814
+ name: "Claude Haiku 4.5",
815
+ family: "haiku",
816
+ reasoning: false,
817
+ context: 2e5,
818
+ output: 64e3,
819
+ cost: haikuCost,
820
+ multiplier: 1,
821
+ releaseDate: "2025-10-01"
822
+ }),
823
+ "claude-sonnet-4-5": defineModel({
824
+ id: "claude-sonnet-4-5",
825
+ name: "Claude Sonnet 4.5",
826
+ family: "sonnet",
827
+ reasoning: true,
828
+ context: 2e5,
829
+ output: 64e3,
830
+ cost: sonnetCost,
831
+ multiplier: 3,
832
+ releaseDate: "2025-09-29"
833
+ }),
834
+ "claude-sonnet-4-6": defineModel({
835
+ id: "claude-sonnet-4-6",
836
+ name: "Claude Sonnet 4.6",
837
+ family: "sonnet",
838
+ reasoning: true,
839
+ context: 1e6,
840
+ output: 128e3,
841
+ cost: sonnetCost,
842
+ multiplier: 3,
843
+ releaseDate: "2025-06-19"
844
+ }),
845
+ "claude-sonnet-5": defineModel({
846
+ id: "claude-sonnet-5",
847
+ name: "Claude Sonnet 5",
848
+ family: "sonnet",
849
+ reasoning: true,
850
+ context: 1e6,
851
+ output: 128e3,
852
+ cost: sonnet5Cost,
853
+ multiplier: 2,
854
+ releaseDate: "2026-06-30"
855
+ }),
856
+ "claude-opus-4-5": defineModel({
857
+ id: "claude-opus-4-5",
858
+ name: "Claude Opus 4.5",
859
+ family: "opus",
860
+ reasoning: true,
861
+ context: 2e5,
862
+ output: 64e3,
863
+ cost: opusCost,
864
+ multiplier: 5,
865
+ releaseDate: "2025-11-01"
866
+ }),
867
+ "claude-opus-4-6": defineModel({
868
+ id: "claude-opus-4-6",
869
+ name: "Claude Opus 4.6",
870
+ family: "opus",
871
+ reasoning: true,
872
+ context: 1e6,
873
+ output: 128e3,
874
+ cost: opusCost,
875
+ multiplier: 5,
876
+ releaseDate: "2025-06-19"
877
+ }),
878
+ "claude-opus-4-7": defineModel({
879
+ id: "claude-opus-4-7",
880
+ name: "Claude Opus 4.7",
881
+ family: "opus",
882
+ reasoning: true,
883
+ context: 1e6,
884
+ output: 128e3,
885
+ cost: opusCost,
886
+ multiplier: 5,
887
+ releaseDate: "2025-07-16"
888
+ }),
889
+ "claude-opus-4-8": defineModel({
890
+ id: "claude-opus-4-8",
891
+ name: "Claude Opus 4.8",
892
+ family: "opus",
893
+ reasoning: true,
894
+ context: 1e6,
895
+ output: 128e3,
896
+ cost: opusCost,
897
+ multiplier: 5,
898
+ releaseDate: "2026-05-28"
899
+ }),
900
+ // Fast mode. The `-fast` suffix is OUR marker, not a model name Anthropic
901
+ // serves: `parseModelId` strips it before `--model` and turns it into
902
+ // `--settings {"fastMode":true}` on the spawn. Retired `-fast` model strings
903
+ // (`claude-opus-4-6-fast`) are a different thing and are not registered here.
904
+ //
905
+ // Only Opus 4.8 and Opus 5 qualify: the CLI gates fast mode on the resolved
906
+ // model name containing `opus-4-8` or `opus-5`, so registering a fast entry
907
+ // for any other model would produce a picker option that silently runs at
908
+ // standard speed while displaying the 10x price.
909
+ "claude-opus-4-8-fast": defineModel({
910
+ id: "claude-opus-4-8-fast",
911
+ name: "Claude Opus 4.8 Fast",
912
+ family: "opus",
913
+ reasoning: true,
914
+ context: 1e6,
915
+ output: 128e3,
916
+ cost: opusFastCost,
917
+ multiplier: 10,
918
+ releaseDate: "2026-05-28"
919
+ }),
920
+ "claude-opus-5": defineModel({
921
+ id: "claude-opus-5",
922
+ name: "Claude Opus 5",
923
+ family: "opus",
924
+ reasoning: true,
925
+ context: 1e6,
926
+ output: 128e3,
927
+ cost: opusCost,
928
+ multiplier: 5,
929
+ releaseDate: "2026-07-24"
930
+ }),
931
+ "claude-opus-5-fast": defineModel({
932
+ id: "claude-opus-5-fast",
933
+ name: "Claude Opus 5 Fast",
934
+ family: "opus",
935
+ reasoning: true,
936
+ context: 1e6,
937
+ output: 128e3,
938
+ cost: opusFastCost,
939
+ multiplier: 10,
940
+ releaseDate: "2026-07-24"
941
+ }),
942
+ "claude-fable-5": defineModel({
943
+ id: "claude-fable-5",
944
+ name: "Claude Fable 5",
945
+ family: "fable",
946
+ reasoning: true,
947
+ context: 1e6,
948
+ output: 128e3,
949
+ cost: fableCost,
950
+ multiplier: 10,
951
+ releaseDate: "2026-06-09"
952
+ }),
953
+ // Mythos 5 shares Fable 5's capabilities and pricing without the safety
954
+ // classifiers; limited availability via Project Glasswing. `claude --model
955
+ // claude-mythos-5` simply errors for accounts without access, so it's safe to
956
+ // register unconditionally.
957
+ "claude-mythos-5": defineModel({
958
+ id: "claude-mythos-5",
959
+ name: "Claude Mythos 5",
960
+ family: "mythos",
961
+ reasoning: true,
962
+ context: 1e6,
963
+ output: 128e3,
964
+ cost: fableCost,
965
+ multiplier: 10,
966
+ releaseDate: "2026-06-09"
967
+ })
968
+ };
969
+ var FAST_SUFFIX = "-fast";
970
+ function parseModelId(modelId) {
971
+ const at = modelId.indexOf("@");
972
+ const base = at === -1 ? modelId : modelId.slice(0, at);
973
+ const account = at === -1 ? "" : modelId.slice(at);
974
+ if (!base.endsWith(FAST_SUFFIX)) return { model: modelId, fast: false };
975
+ if (!Object.hasOwn(defaultModels, base)) return { model: modelId, fast: false };
976
+ return { model: base.slice(0, -FAST_SUFFIX.length) + account, fast: true };
977
+ }
978
+
734
979
  // src/plan-mode-question.ts
735
980
  var QUESTION_TOOL_NAME = "question";
736
981
  var APPROVED_EXIT_PLAN_MODE_MESSAGE = "User has approved your plan. You can now start coding. Start with updating your todo list if applicable.";
@@ -1386,6 +1631,10 @@ function cliSupportsThinkingDisplay(v) {
1386
1631
  if (!v) return false;
1387
1632
  return gte(v, { major: 2, minor: 1, patch: 142 });
1388
1633
  }
1634
+ function cliSupportsFastMode(v) {
1635
+ if (!v) return false;
1636
+ return gte(v, { major: 2, minor: 1, patch: 220 });
1637
+ }
1389
1638
  function cliSupportsThinking(v) {
1390
1639
  if (!v) return false;
1391
1640
  return gte(v, { major: 2, minor: 0, patch: 0 });
@@ -1609,6 +1858,7 @@ function buildCliArgs(opts) {
1609
1858
  appendSystemPromptFile,
1610
1859
  thinking,
1611
1860
  thinkingDisplay,
1861
+ fastMode,
1612
1862
  cliVersion
1613
1863
  } = opts;
1614
1864
  const args = [
@@ -1654,6 +1904,9 @@ function buildCliArgs(opts) {
1654
1904
  if (appendSystemPromptFile) {
1655
1905
  args.push("--append-system-prompt-file", appendSystemPromptFile);
1656
1906
  }
1907
+ if (fastMode && cliSupportsFastMode(cliVersion ?? null)) {
1908
+ args.push("--settings", JSON.stringify({ fastMode: true }));
1909
+ }
1657
1910
  if (skipPermissions) {
1658
1911
  args.push("--dangerously-skip-permissions");
1659
1912
  }
@@ -2081,11 +2334,15 @@ function spawnInteractiveProcess(opts) {
2081
2334
  "--strict-mcp-config"
2082
2335
  );
2083
2336
  }
2337
+ const flagSettings = {};
2084
2338
  if (opts.permissionsAllow && opts.permissionsAllow.length > 0) {
2085
- extraArgs.push(
2086
- "--settings",
2087
- JSON.stringify({ permissions: { allow: opts.permissionsAllow } })
2088
- );
2339
+ flagSettings.permissions = { allow: opts.permissionsAllow };
2340
+ }
2341
+ if (opts.fastMode) {
2342
+ flagSettings.fastMode = true;
2343
+ }
2344
+ if (Object.keys(flagSettings).length > 0) {
2345
+ extraArgs.push("--settings", JSON.stringify(flagSettings));
2089
2346
  }
2090
2347
  if (opts.permissionMode === "bypassPermissions") {
2091
2348
  log.warn(
@@ -2541,10 +2798,50 @@ var DEFAULT_PROXY_TOOLS = [
2541
2798
  async function createProxyMcpServer(tools = DEFAULT_PROXY_TOOLS, timeoutOverrides, interceptors) {
2542
2799
  const calls = new EventEmitter3();
2543
2800
  const pending = /* @__PURE__ */ new Map();
2801
+ const authToken = crypto2.randomBytes(32).toString("hex");
2802
+ const expectedAuth = Buffer.from(`Bearer ${authToken}`);
2803
+ let boundAuthority = "";
2804
+ function authOk(req) {
2805
+ const got = req.headers.authorization;
2806
+ if (typeof got !== "string") return false;
2807
+ const candidate = Buffer.from(got);
2808
+ if (candidate.length !== expectedAuth.length) return false;
2809
+ return crypto2.timingSafeEqual(candidate, expectedAuth);
2810
+ }
2811
+ function reject(req, res, statusCode, reason) {
2812
+ log.notice("proxy-mcp rejected a request", {
2813
+ statusCode,
2814
+ reason,
2815
+ method: req.method,
2816
+ hasAuthorization: typeof req.headers.authorization === "string"
2817
+ });
2818
+ res.statusCode = statusCode;
2819
+ res.setHeader("Connection", "close");
2820
+ res.on("finish", () => {
2821
+ req.socket?.destroy();
2822
+ });
2823
+ res.end();
2824
+ }
2544
2825
  const server2 = createServer(async (req, res) => {
2545
2826
  if (req.method !== "POST" || !req.url?.startsWith("/mcp")) {
2546
- res.statusCode = 404;
2547
- res.end();
2827
+ reject(req, res, 404, "not a POST to /mcp");
2828
+ return;
2829
+ }
2830
+ if (req.headers.host !== boundAuthority) {
2831
+ reject(req, res, 403, "host header is not the bound authority");
2832
+ return;
2833
+ }
2834
+ if (req.headers.origin !== void 0) {
2835
+ reject(req, res, 403, "origin header present");
2836
+ return;
2837
+ }
2838
+ const contentType = String(req.headers["content-type"] ?? "").split(";")[0].trim().toLowerCase();
2839
+ if (contentType !== "application/json") {
2840
+ reject(req, res, 415, "content-type is not application/json");
2841
+ return;
2842
+ }
2843
+ if (!authOk(req)) {
2844
+ reject(req, res, 401, "missing or invalid bearer token");
2548
2845
  return;
2549
2846
  }
2550
2847
  let requestId = null;
@@ -2636,13 +2933,13 @@ async function createProxyMcpServer(tools = DEFAULT_PROXY_TOOLS, timeoutOverride
2636
2933
  });
2637
2934
  let timer = null;
2638
2935
  const result = await new Promise(
2639
- (resolve4, reject) => {
2936
+ (resolve4, reject2) => {
2640
2937
  const entry = {
2641
2938
  id: callId,
2642
2939
  toolName,
2643
2940
  input,
2644
2941
  resolve: resolve4,
2645
- reject
2942
+ reject: reject2
2646
2943
  };
2647
2944
  pending.set(callId, entry);
2648
2945
  const deadlineMs = resolveProxyCallTimeoutMs(
@@ -2658,7 +2955,7 @@ async function createProxyMcpServer(tools = DEFAULT_PROXY_TOOLS, timeoutOverride
2658
2955
  toolName,
2659
2956
  deadlineMs
2660
2957
  });
2661
- reject(buildProxyTimeoutError(toolName, deadlineMs));
2958
+ reject2(buildProxyTimeoutError(toolName, deadlineMs));
2662
2959
  }, deadlineMs);
2663
2960
  calls.emit("call", entry);
2664
2961
  }
@@ -2717,10 +3014,10 @@ async function createProxyMcpServer(tools = DEFAULT_PROXY_TOOLS, timeoutOverride
2717
3014
  }
2718
3015
  }
2719
3016
  });
2720
- await new Promise((resolve4, reject) => {
2721
- server2.once("error", reject);
3017
+ await new Promise((resolve4, reject2) => {
3018
+ server2.once("error", reject2);
2722
3019
  server2.listen(0, "127.0.0.1", () => {
2723
- server2.off("error", reject);
3020
+ server2.off("error", reject2);
2724
3021
  resolve4();
2725
3022
  });
2726
3023
  });
@@ -2729,7 +3026,8 @@ async function createProxyMcpServer(tools = DEFAULT_PROXY_TOOLS, timeoutOverride
2729
3026
  server2.close();
2730
3027
  throw new Error("Failed to bind proxy MCP server");
2731
3028
  }
2732
- const url = `http://127.0.0.1:${addr.port}/mcp`;
3029
+ boundAuthority = `127.0.0.1:${addr.port}`;
3030
+ const url = `http://${boundAuthority}/mcp`;
2733
3031
  log.info("proxy-mcp server started", {
2734
3032
  url,
2735
3033
  tools: tools.map((t) => t.name)
@@ -2739,6 +3037,7 @@ async function createProxyMcpServer(tools = DEFAULT_PROXY_TOOLS, timeoutOverride
2739
3037
  url,
2740
3038
  serverName: SERVER_NAME,
2741
3039
  tools,
3040
+ authToken,
2742
3041
  calls,
2743
3042
  configPath() {
2744
3043
  if (configFilePath) return configFilePath;
@@ -2748,6 +3047,10 @@ async function createProxyMcpServer(tools = DEFAULT_PROXY_TOOLS, timeoutOverride
2748
3047
  [SERVER_NAME]: {
2749
3048
  type: "http",
2750
3049
  url,
3050
+ // Claude CLI replays these headers on every request to this
3051
+ // server, which is what lets the handler above reject anyone
3052
+ // who did not read this 0600 file.
3053
+ headers: { Authorization: `Bearer ${authToken}` },
2751
3054
  timeout: resolveProxyClientCeilingMs(timeoutOverrides)
2752
3055
  }
2753
3056
  }
@@ -3290,6 +3593,47 @@ ${options.compressionSummary.trim()}`
3290
3593
  return void 0;
3291
3594
  }
3292
3595
  }
3596
+ var FAST_MODE_REASONS = {
3597
+ sdk_opt_in_required: "the CLI did not receive the headless opt-in (--settings). This is a plugin bug, please report it",
3598
+ extra_usage_disabled: "your account has usage credits turned off. Run /usage-credits in an interactive `claude` session to enable them",
3599
+ free: "fast mode requires a paid subscription or purchased credits",
3600
+ preference: "fast mode is turned off for your organization",
3601
+ model_not_allowed: "this model is not in your organization's allowed models",
3602
+ not_first_party: "fast mode only works against the Anthropic API directly, not Bedrock / Vertex / Foundry",
3603
+ network_error: "the CLI could not reach Anthropic to check availability",
3604
+ disabled_by_env: "CLAUDE_CODE_DISABLE_FAST_MODE is set in the environment",
3605
+ pending: "the CLI is still checking availability"
3606
+ };
3607
+ var warnedFastModeReasons = /* @__PURE__ */ new Set();
3608
+ function reportFastModeState(msg, requested) {
3609
+ const state = msg.fast_mode_state;
3610
+ if (!state) return;
3611
+ if (!requested) {
3612
+ log.debug("fast mode state", { state });
3613
+ return;
3614
+ }
3615
+ if (state === "on") {
3616
+ log.info("fast mode active", { state });
3617
+ return;
3618
+ }
3619
+ const reason = msg.fast_mode_disabled_reason;
3620
+ if (state === "cooldown") {
3621
+ log.notice(
3622
+ "fast mode is in cooldown after a rate limit; this turn runs at standard speed and is billed at standard Opus rates, not the 10x shown in the model picker.",
3623
+ { state, reason: reason ?? null }
3624
+ );
3625
+ return;
3626
+ }
3627
+ const key = reason ?? "unknown";
3628
+ const explanation = reason ? FAST_MODE_REASONS[reason] : void 0;
3629
+ const message = `fast mode was requested but is off${explanation ? `: ${explanation}` : reason ? ` (${reason})` : ""}. Turns run at standard speed and are billed at standard Opus rates, not the 10x shown in the model picker. Switch to the non-fast model id to make the picker's price accurate.`;
3630
+ if (warnedFastModeReasons.has(key)) {
3631
+ log.debug(message, { state, reason: reason ?? null });
3632
+ return;
3633
+ }
3634
+ warnedFastModeReasons.add(key);
3635
+ log.warn(message, { state, reason: reason ?? null });
3636
+ }
3293
3637
  var ClaudeCodeLanguageModel = class {
3294
3638
  specificationVersion = "v3";
3295
3639
  modelId;
@@ -3899,17 +4243,19 @@ var ClaudeCodeLanguageModel = class {
3899
4243
  // An existing summary still carries: it is this key's prior context.
3900
4244
  { compressEnabled: false, compressionSummary: getCompressionSummary(sk) }
3901
4245
  );
4246
+ const { model: spawnModelId, fast: fastMode } = parseModelId(this.modelId);
3902
4247
  const cliArgs = buildCliArgs({
3903
4248
  sessionKey: sk,
3904
4249
  skipPermissions: this.config.skipPermissions !== false,
3905
4250
  includeSessionId: false,
3906
- model: this.modelId,
4251
+ model: spawnModelId,
3907
4252
  permissionMode: this.config.permissionMode,
3908
4253
  mcpConfig: this.effectiveMcpConfig(cwd, void 0, runtimeStatus).paths,
3909
4254
  strictMcpConfig: this.config.strictMcpConfig,
3910
4255
  disallowedTools: this.config.webSearch === "disabled" ? ["WebSearch"] : void 0,
3911
4256
  appendSystemPromptFile: systemPromptFile,
3912
4257
  ...this.thinkingCliOptions(),
4258
+ fastMode,
3913
4259
  cliVersion
3914
4260
  });
3915
4261
  log.info("doGenerate starting", {
@@ -3963,6 +4309,7 @@ var ClaudeCodeLanguageModel = class {
3963
4309
  if (msg.session_id) {
3964
4310
  setClaudeSessionId(sk, msg.session_id);
3965
4311
  }
4312
+ reportFastModeState(msg, fastMode);
3966
4313
  }
3967
4314
  if (msg.type === "assistant" && msg.message?.content && !gotPartialEvents) {
3968
4315
  for (const block of msg.message.content) {
@@ -4200,6 +4547,7 @@ ${plan}
4200
4547
  const affinity = this.sessionAffinity(options);
4201
4548
  const compactionMode = this.isCompactionCall(options);
4202
4549
  const effectiveModelId = compactionMode ? this.resolveCompactionModel() : this.modelId;
4550
+ const { model: spawnModelId, fast: fastMode } = parseModelId(effectiveModelId);
4203
4551
  const sk = compactionMode ? sessionKey(cwd, `${effectiveModelId}::compaction::${affinity}`) : sessionKey(cwd, `${this.modelId}::${scope}::${affinity}`);
4204
4552
  const toUsage = this.toUsage.bind(this);
4205
4553
  const toFinishReason = this.toFinishReason.bind(this);
@@ -4395,7 +4743,8 @@ ${plan}
4395
4743
  cwd,
4396
4744
  cliPath,
4397
4745
  configDir: self.config.configDir,
4398
- model: effectiveModelId,
4746
+ model: spawnModelId,
4747
+ fastMode,
4399
4748
  mcpConfigPaths: mcp.paths,
4400
4749
  permissionsAllow: allow,
4401
4750
  systemPromptFile,
@@ -4422,8 +4771,9 @@ ${plan}
4422
4771
  sessionKey: sk,
4423
4772
  skipPermissions,
4424
4773
  includeSessionId: false,
4425
- model: effectiveModelId,
4774
+ model: spawnModelId,
4426
4775
  permissionMode: self.config.permissionMode,
4776
+ fastMode,
4427
4777
  cliVersion
4428
4778
  });
4429
4779
  } else {
@@ -4510,13 +4860,14 @@ ${plan}
4510
4860
  cliArgs = buildCliArgs({
4511
4861
  sessionKey: sk,
4512
4862
  skipPermissions,
4513
- model: self.modelId,
4863
+ model: spawnModelId,
4514
4864
  permissionMode: self.config.permissionMode,
4515
4865
  mcpConfig: mcp.paths,
4516
4866
  strictMcpConfig: self.config.strictMcpConfig,
4517
4867
  disallowedTools: allDisallowed.length > 0 ? allDisallowed : void 0,
4518
4868
  appendSystemPromptFile: systemPromptFile,
4519
4869
  ...self.thinkingCliOptions(),
4870
+ fastMode,
4520
4871
  cliVersion
4521
4872
  });
4522
4873
  spawnSystemPromptFile = systemPromptFile;
@@ -4948,6 +5299,7 @@ ${plan}
4948
5299
  claudeSessionId: msg.session_id
4949
5300
  });
4950
5301
  }
5302
+ reportFastModeState(msg, fastMode);
4951
5303
  }
4952
5304
  if (msg.type === "content_block_start" && msg.content_block && msg.index !== void 0) {
4953
5305
  const block = msg.content_block;
@@ -5699,210 +6051,6 @@ ${plan}
5699
6051
  }
5700
6052
  };
5701
6053
 
5702
- // src/models.ts
5703
- var PROVIDER_ID = "claude-code";
5704
- var NPM = "@khalilgharbaoui/opencode-claude-code-plugin";
5705
- var reasoningVariants = {
5706
- low: { reasoningEffort: "low" },
5707
- medium: { reasoningEffort: "medium" },
5708
- high: { reasoningEffort: "high" },
5709
- xhigh: { reasoningEffort: "xhigh" },
5710
- max: { reasoningEffort: "max" }
5711
- };
5712
- var baseCapabilities = {
5713
- temperature: false,
5714
- attachment: true,
5715
- toolcall: true,
5716
- input: { text: true, audio: false, image: true, video: false, pdf: false },
5717
- output: { text: true, audio: false, image: false, video: false, pdf: false },
5718
- interleaved: false
5719
- };
5720
- function defineModel(opts) {
5721
- return {
5722
- id: opts.id,
5723
- providerID: PROVIDER_ID,
5724
- api: { id: opts.id, url: "", npm: NPM },
5725
- name: `${opts.name} (${opts.multiplier}\xD7)`,
5726
- family: opts.family,
5727
- capabilities: { ...baseCapabilities, reasoning: opts.reasoning },
5728
- cost: {
5729
- input: opts.cost.input,
5730
- output: opts.cost.output,
5731
- cache: { read: opts.cost.cacheRead, write: opts.cost.cacheWrite }
5732
- },
5733
- limit: { context: opts.context, output: opts.output },
5734
- status: opts.status ?? "active",
5735
- options: {},
5736
- headers: {},
5737
- release_date: opts.releaseDate,
5738
- variants: opts.reasoning ? reasoningVariants : void 0
5739
- };
5740
- }
5741
- var haikuCost = { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 };
5742
- var sonnetCost = { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 };
5743
- var sonnet5Cost = { input: 2, output: 10, cacheRead: 0.2, cacheWrite: 2.5 };
5744
- var opusCost = { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 };
5745
- var fableCost = { input: 10, output: 50, cacheRead: 1, cacheWrite: 12.5 };
5746
- function toConfigModel(model) {
5747
- const inputMods = [];
5748
- const outputMods = [];
5749
- for (const [k, v] of Object.entries(model.capabilities.input)) {
5750
- if (v) inputMods.push(k);
5751
- }
5752
- for (const [k, v] of Object.entries(model.capabilities.output)) {
5753
- if (v) outputMods.push(k);
5754
- }
5755
- return {
5756
- id: model.api.id,
5757
- name: model.name,
5758
- status: model.status,
5759
- family: model.family ?? "",
5760
- release_date: model.release_date,
5761
- temperature: model.capabilities.temperature,
5762
- reasoning: model.capabilities.reasoning,
5763
- attachment: model.capabilities.attachment,
5764
- tool_call: model.capabilities.toolcall,
5765
- modalities: { input: inputMods, output: outputMods },
5766
- cost: {
5767
- input: model.cost.input,
5768
- output: model.cost.output,
5769
- cache_read: model.cost.cache.read,
5770
- cache_write: model.cost.cache.write
5771
- },
5772
- limit: model.limit,
5773
- options: model.options,
5774
- headers: model.headers,
5775
- variants: model.variants
5776
- };
5777
- }
5778
- var defaultModels = {
5779
- "claude-haiku-4-5": defineModel({
5780
- id: "claude-haiku-4-5",
5781
- name: "Claude Haiku 4.5",
5782
- family: "haiku",
5783
- reasoning: false,
5784
- context: 2e5,
5785
- output: 64e3,
5786
- cost: haikuCost,
5787
- multiplier: 1,
5788
- releaseDate: "2025-10-01"
5789
- }),
5790
- "claude-sonnet-4-5": defineModel({
5791
- id: "claude-sonnet-4-5",
5792
- name: "Claude Sonnet 4.5",
5793
- family: "sonnet",
5794
- reasoning: true,
5795
- context: 2e5,
5796
- output: 64e3,
5797
- cost: sonnetCost,
5798
- multiplier: 3,
5799
- releaseDate: "2025-09-29"
5800
- }),
5801
- "claude-sonnet-4-6": defineModel({
5802
- id: "claude-sonnet-4-6",
5803
- name: "Claude Sonnet 4.6",
5804
- family: "sonnet",
5805
- reasoning: true,
5806
- context: 1e6,
5807
- output: 128e3,
5808
- cost: sonnetCost,
5809
- multiplier: 3,
5810
- releaseDate: "2025-06-19"
5811
- }),
5812
- "claude-sonnet-5": defineModel({
5813
- id: "claude-sonnet-5",
5814
- name: "Claude Sonnet 5",
5815
- family: "sonnet",
5816
- reasoning: true,
5817
- context: 1e6,
5818
- output: 128e3,
5819
- cost: sonnet5Cost,
5820
- multiplier: 2,
5821
- releaseDate: "2026-06-30"
5822
- }),
5823
- "claude-opus-4-5": defineModel({
5824
- id: "claude-opus-4-5",
5825
- name: "Claude Opus 4.5",
5826
- family: "opus",
5827
- reasoning: true,
5828
- context: 2e5,
5829
- output: 64e3,
5830
- cost: opusCost,
5831
- multiplier: 5,
5832
- releaseDate: "2025-11-01"
5833
- }),
5834
- "claude-opus-4-6": defineModel({
5835
- id: "claude-opus-4-6",
5836
- name: "Claude Opus 4.6",
5837
- family: "opus",
5838
- reasoning: true,
5839
- context: 1e6,
5840
- output: 128e3,
5841
- cost: opusCost,
5842
- multiplier: 5,
5843
- releaseDate: "2025-06-19"
5844
- }),
5845
- "claude-opus-4-7": defineModel({
5846
- id: "claude-opus-4-7",
5847
- name: "Claude Opus 4.7",
5848
- family: "opus",
5849
- reasoning: true,
5850
- context: 1e6,
5851
- output: 128e3,
5852
- cost: opusCost,
5853
- multiplier: 5,
5854
- releaseDate: "2025-07-16"
5855
- }),
5856
- "claude-opus-4-8": defineModel({
5857
- id: "claude-opus-4-8",
5858
- name: "Claude Opus 4.8",
5859
- family: "opus",
5860
- reasoning: true,
5861
- context: 1e6,
5862
- output: 128e3,
5863
- cost: opusCost,
5864
- multiplier: 5,
5865
- releaseDate: "2026-05-28"
5866
- }),
5867
- "claude-opus-5": defineModel({
5868
- id: "claude-opus-5",
5869
- name: "Claude Opus 5",
5870
- family: "opus",
5871
- reasoning: true,
5872
- context: 1e6,
5873
- output: 128e3,
5874
- cost: opusCost,
5875
- multiplier: 5,
5876
- releaseDate: "2026-07-24"
5877
- }),
5878
- "claude-fable-5": defineModel({
5879
- id: "claude-fable-5",
5880
- name: "Claude Fable 5",
5881
- family: "fable",
5882
- reasoning: true,
5883
- context: 1e6,
5884
- output: 128e3,
5885
- cost: fableCost,
5886
- multiplier: 10,
5887
- releaseDate: "2026-06-09"
5888
- }),
5889
- // Mythos 5 shares Fable 5's capabilities and pricing without the safety
5890
- // classifiers; limited availability via Project Glasswing. `claude --model
5891
- // claude-mythos-5` simply errors for accounts without access, so it's safe to
5892
- // register unconditionally.
5893
- "claude-mythos-5": defineModel({
5894
- id: "claude-mythos-5",
5895
- name: "Claude Mythos 5",
5896
- family: "mythos",
5897
- reasoning: true,
5898
- context: 1e6,
5899
- output: 128e3,
5900
- cost: fableCost,
5901
- multiplier: 10,
5902
- releaseDate: "2026-06-09"
5903
- })
5904
- };
5905
-
5906
6054
  // src/accounts.ts
5907
6055
  import { chmod, lstat, mkdir, readlink, symlink, writeFile } from "fs/promises";
5908
6056
  import path5 from "path";