@co0ontty/wand 4.23.0 → 4.24.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.
@@ -1,6 +1,6 @@
1
1
  {
2
- "commit": "2814c6ba1030b82a600d3f42d74befdf60801e4c",
3
- "builtAt": "2026-07-24T23:00:20.185Z",
4
- "version": "4.23.0",
2
+ "commit": "090ceecd30c3ef681295a17b38285bb22d37ce54",
3
+ "builtAt": "2026-07-25T01:03:54.326Z",
4
+ "version": "4.24.0",
5
5
  "channel": "stable"
6
6
  }
@@ -1,3 +1,4 @@
1
+ import { type Options as SdkOptions } from "@anthropic-ai/claude-agent-sdk";
1
2
  export type ClaudeRunErrorCode = "CLAUDE_CLI_MISSING" | "CLAUDE_TIMEOUT" | "CLAUDE_CLI_FAILED" | "CLAUDE_EMPTY_RESULT";
2
3
  export declare class ClaudeRunError extends Error {
3
4
  readonly code: ClaudeRunErrorCode;
@@ -8,6 +9,8 @@ export interface RunClaudePrintOptions {
8
9
  timeoutMs: number;
9
10
  /** Optional Claude model id / alias. Empty or "default" keeps Claude Code's own default. */
10
11
  model?: string;
12
+ /** Optional adaptive-thinking effort, aligned with the active Claude session. */
13
+ effort?: SdkOptions["effort"];
11
14
  /**
12
15
  * 用户偏好的回复语言(取自 config.language)。传进来时会以
13
16
  * `appendSystemPrompt` 形式灌给 Claude,保证 quick-commit / prompt-optimizer
@@ -129,6 +129,7 @@ export async function runClaudePrint(prompt, options) {
129
129
  ...(sdkClaudeBinary ? { pathToClaudeCodeExecutable: sdkClaudeBinary } : {}),
130
130
  ...(languageDirective ? { appendSystemPrompt: languageDirective } : {}),
131
131
  ...(model && model !== "default" ? { model } : {}),
132
+ ...(options.effort ? { effort: options.effort } : {}),
132
133
  };
133
134
  // 单条 user message → AsyncGenerator,SDK 的 streaming input 协议要求。
134
135
  async function* singleShot() {
package/dist/config.d.ts CHANGED
@@ -40,8 +40,12 @@ export declare function applyStoragePreferences(config: WandConfig, storage: Wan
40
40
  export declare function writePreferenceToStorage(config: WandConfig, storage: WandStorage, key: PreferenceKey, value: unknown, options?: {
41
41
  deferCommitAiValidation?: boolean;
42
42
  }): void;
43
- /** Validate the cross-field contract for Commit's direct-API source. */
44
- export declare function validateCommitAiConfig(config: Pick<WandConfig, "commitAiSource" | "systemAi">): void;
43
+ /**
44
+ * Kept as a compatibility seam for callers that validate preference batches.
45
+ * Commit API profiles are discovered from the configured tools at request time,
46
+ * so selecting API is valid even when no manual systemAi profile is stored.
47
+ */
48
+ export declare function validateCommitAiConfig(_config: Pick<WandConfig, "commitAiSource" | "systemAi">): void;
45
49
  export declare function normalizeCardDefaults(input: unknown): CardExpandDefaults;
46
50
  export declare function isExecutionMode(value: unknown): value is ExecutionMode;
47
51
  export declare function getProviderDefaultModels(config: Pick<WandConfig, "defaultModel" | "defaultCodexModel" | "defaultOpenCodeModel" | "defaultGrokModel" | "defaultQoderModel">): {
package/dist/config.js CHANGED
@@ -4,7 +4,7 @@ import { chmod, mkdir, readFile, rename, unlink, writeFile } from "node:fs/promi
4
4
  import path from "node:path";
5
5
  import process from "node:process";
6
6
  import { isRunningAsRoot } from "./env-utils.js";
7
- import { normalizeSystemAiConfig, systemAiProfiles } from "./system-ai.js";
7
+ import { normalizeSystemAiConfig } from "./system-ai.js";
8
8
  function isThinkingEffort(value) {
9
9
  return value === "off"
10
10
  || value === "standard"
@@ -509,14 +509,12 @@ export function writePreferenceToStorage(config, storage, key, value, options =
509
509
  }
510
510
  }
511
511
  }
512
- /** Validate the cross-field contract for Commit's direct-API source. */
513
- export function validateCommitAiConfig(config) {
514
- if (config.commitAiSource !== "api")
515
- return;
516
- if (!systemAiProfiles(config.systemAi, true).length) {
517
- throw new Error("选择直连 API 生成 Commit 时,必须先填写 API 地址、API Key 和模型。");
518
- }
519
- }
512
+ /**
513
+ * Kept as a compatibility seam for callers that validate preference batches.
514
+ * Commit API profiles are discovered from the configured tools at request time,
515
+ * so selecting API is valid even when no manual systemAi profile is stored.
516
+ */
517
+ export function validateCommitAiConfig(_config) { }
520
518
  function defaultCardExpandDefaults() {
521
519
  return {
522
520
  editCards: false,
@@ -10,8 +10,6 @@ interface QuickCommitOptions {
10
10
  model?: string | null;
11
11
  thinkingEffort?: SessionSnapshot["thinkingEffort"];
12
12
  inheritEnv?: boolean;
13
- /** Direct API to try when the selected Commit source is a CLI. */
14
- fallbackSystemAi?: import("./types.js").SystemAiConfig;
15
13
  systemAi?: import("./types.js").SystemAiConfig;
16
14
  autoMessage: boolean;
17
15
  customMessage?: string;
@@ -30,7 +28,6 @@ export interface QuickCommitAiOptions {
30
28
  model?: string | null;
31
29
  thinkingEffort?: SessionSnapshot["thinkingEffort"];
32
30
  inheritEnv?: boolean;
33
- fallbackSystemAi?: import("./types.js").SystemAiConfig;
34
31
  systemAi?: import("./types.js").SystemAiConfig;
35
32
  }
36
33
  export declare class QuickCommitError extends Error {
@@ -38,8 +35,9 @@ export declare class QuickCommitError extends Error {
38
35
  constructor(message: string, code: QuickCommitErrorCode);
39
36
  }
40
37
  /**
41
- * Run a lightweight AI request through the same source ordering used by quick
42
- * commit: the user's selected source first, then the reciprocal source once.
38
+ * Run a lightweight AI request through the selected Commit source. API mode
39
+ * exhausts its profile chain and then falls back once to the current-session
40
+ * CLI. CLI mode uses only that CLI.
43
41
  */
44
42
  export declare function callConfiguredAiText(prompt: string, cwd: string, language: string, opts: QuickCommitAiOptions): Promise<string>;
45
43
  export interface GenerateCommitMessageResult {
@@ -55,7 +53,6 @@ interface TagHeadOptions {
55
53
  model?: string | null;
56
54
  thinkingEffort?: SessionSnapshot["thinkingEffort"];
57
55
  inheritEnv?: boolean;
58
- fallbackSystemAi?: import("./types.js").SystemAiConfig;
59
56
  systemAi?: import("./types.js").SystemAiConfig;
60
57
  /** Explicit tag name. If empty and `autoTag` is true, ask the session provider to generate one. */
61
58
  tag?: string;
@@ -4,7 +4,7 @@ import { ClaudeRunError, runClaudePrint } from "./claude-sdk-runner.js";
4
4
  import { callSystemAiTextWithFallback } from "./system-ai.js";
5
5
  import { buildChildEnv } from "./env-utils.js";
6
6
  import { runGit as runGitBase, runGitAsync as runGitAsyncBase, runGitRaw as runGitRawBase, runGitRawAsync as runGitRawAsyncBase, getGitErrorMessage, } from "./git-utils.js";
7
- import { thinkingEffortToClaudeCliEffort, thinkingEffortToCodexReasoningEffort, thinkingEffortToOpenCodeVariant } from "./structured-provider-common.js";
7
+ import { thinkingEffortToClaudeCliEffort, thinkingEffortToCodexReasoningEffort, thinkingEffortToGrokEffort, thinkingEffortToOpenCodeVariant, thinkingEffortToQoderEffort, } from "./structured-provider-common.js";
8
8
  const GIT_TIMEOUT_MS = 1500;
9
9
  const GIT_PUSH_TIMEOUT_MS = 30_000;
10
10
  const MAX_FILE_ENTRIES = 200;
@@ -12,6 +12,10 @@ const MAX_FILE_ENTRIES = 200;
12
12
  // 30s 在 API 抖动时不够用,放宽到 60s。
13
13
  const CLAUDE_MESSAGE_TIMEOUT_MS = 60_000;
14
14
  const CODEX_MESSAGE_TIMEOUT_MS = 60_000;
15
+ // API mode can contain several profiles. Keep each probe bounded so the whole
16
+ // chain can still reach the current-session CLI before native clients' 180s
17
+ // request deadline.
18
+ const DIRECT_API_PROFILE_TIMEOUT_MS = 20_000;
15
19
  const QUICK_COMMIT_CLI_TIMEOUT_MS = 120_000;
16
20
  const MAX_DIFF_FOR_AI = 100_000;
17
21
  const GIT_MAX_BUFFER = 16 * 1024 * 1024;
@@ -454,9 +458,16 @@ export class QuickCommitError extends Error {
454
458
  }
455
459
  }
456
460
  // ── AI commit message generation ──
457
- async function callClaudeText(prompt, cwd, language, model) {
461
+ async function callClaudeText(prompt, cwd, language, opts) {
458
462
  try {
459
- return await runClaudePrint(prompt, { cwd, timeoutMs: CLAUDE_MESSAGE_TIMEOUT_MS, language, model: model ?? undefined });
463
+ const effort = thinkingEffortToClaudeCliEffort(opts.thinkingEffort ?? "off");
464
+ return await runClaudePrint(prompt, {
465
+ cwd,
466
+ timeoutMs: CLAUDE_MESSAGE_TIMEOUT_MS,
467
+ language,
468
+ model: opts.model ?? undefined,
469
+ ...(effort ? { effort } : {}),
470
+ });
460
471
  }
461
472
  catch (error) {
462
473
  if (error instanceof ClaudeRunError) {
@@ -473,7 +484,12 @@ async function callClaudeText(prompt, cwd, language, model) {
473
484
  }
474
485
  }
475
486
  function normalizeProvider(provider) {
476
- return provider === "codex" || provider === "opencode" ? provider : "claude";
487
+ return provider === "codex"
488
+ || provider === "opencode"
489
+ || provider === "grok"
490
+ || provider === "qoder"
491
+ ? provider
492
+ : "claude";
477
493
  }
478
494
  function stripFences(raw) {
479
495
  return raw.trim().replace(/^```(?:json)?\s*/i, "").replace(/\s*```$/i, "").trim();
@@ -525,6 +541,77 @@ function extractOpenCodeText(stdout) {
525
541
  }
526
542
  return texts.join("\n").trim();
527
543
  }
544
+ function extractGrokText(stdout) {
545
+ let text = "";
546
+ for (const line of stdout.split(/\r?\n/)) {
547
+ const trimmed = line.trim();
548
+ if (!trimmed.startsWith("{"))
549
+ continue;
550
+ try {
551
+ const parsed = JSON.parse(trimmed);
552
+ if (parsed.type === "text" && typeof parsed.data === "string")
553
+ text += parsed.data;
554
+ }
555
+ catch {
556
+ // ignore diagnostics mixed into stdout
557
+ }
558
+ }
559
+ return text.trim();
560
+ }
561
+ function extractQoderText(stdout) {
562
+ let resultText = "";
563
+ const assistantTexts = [];
564
+ for (const line of stdout.split(/\r?\n/)) {
565
+ const trimmed = line.trim();
566
+ if (!trimmed.startsWith("{"))
567
+ continue;
568
+ try {
569
+ const parsed = JSON.parse(trimmed);
570
+ if (parsed.type === "result" && parsed.subtype === "success" && typeof parsed.result === "string") {
571
+ resultText = parsed.result;
572
+ continue;
573
+ }
574
+ if (parsed.type !== "assistant" || !Array.isArray(parsed.message?.content))
575
+ continue;
576
+ for (const block of parsed.message.content) {
577
+ if (block
578
+ && typeof block === "object"
579
+ && block.type === "text"
580
+ && typeof block.text === "string") {
581
+ assistantTexts.push(block.text);
582
+ }
583
+ }
584
+ }
585
+ catch {
586
+ // ignore diagnostics mixed into stdout
587
+ }
588
+ }
589
+ return (resultText || assistantTexts.join("\n")).trim();
590
+ }
591
+ function buildGrokTextArgs(prompt, opts, allowTools = false) {
592
+ const args = ["--no-auto-update", "-p", prompt, "--output-format", "streaming-json"];
593
+ const model = opts.model?.trim();
594
+ if (model && model !== "default")
595
+ args.push("--model", model);
596
+ const effort = thinkingEffortToGrokEffort(opts.thinkingEffort ?? "off");
597
+ if (effort)
598
+ args.push("--effort", effort);
599
+ if (allowTools)
600
+ args.push("--always-approve");
601
+ return args;
602
+ }
603
+ function buildQoderTextArgs(prompt, opts, allowTools = false) {
604
+ const args = ["-p", prompt, "--output-format", "stream-json", "--no-session-persistence"];
605
+ const model = opts.model?.trim();
606
+ if (model && model !== "default")
607
+ args.push("--model", model);
608
+ const effort = thinkingEffortToQoderEffort(opts.thinkingEffort ?? "off");
609
+ if (effort)
610
+ args.push("--reasoning-effort", effort);
611
+ if (allowTools)
612
+ args.push("--permission-mode", "bypass_permissions");
613
+ return args;
614
+ }
528
615
  function runCliText(command, args, prompt, opts) {
529
616
  return new Promise((resolve, reject) => {
530
617
  const child = spawn(command, args, {
@@ -605,6 +692,28 @@ async function callOpenCodeText(prompt, cwd, opts) {
605
692
  throw new QuickCommitError("OpenCode 返回了空的 commit message。", "EMPTY_AI_MESSAGE");
606
693
  return text;
607
694
  }
695
+ async function callGrokText(prompt, cwd, opts) {
696
+ const stdout = await runCliText("grok", buildGrokTextArgs(prompt, opts), "", {
697
+ cwd,
698
+ timeoutMs: CODEX_MESSAGE_TIMEOUT_MS,
699
+ inheritEnv: opts.inheritEnv,
700
+ });
701
+ const text = extractGrokText(stdout);
702
+ if (!text)
703
+ throw new QuickCommitError("Grok 返回了空的 commit message。", "EMPTY_AI_MESSAGE");
704
+ return text;
705
+ }
706
+ async function callQoderText(prompt, cwd, opts) {
707
+ const stdout = await runCliText("qodercli", buildQoderTextArgs(prompt, opts), "", {
708
+ cwd,
709
+ timeoutMs: CODEX_MESSAGE_TIMEOUT_MS,
710
+ inheritEnv: opts.inheritEnv,
711
+ });
712
+ const text = extractQoderText(stdout);
713
+ if (!text)
714
+ throw new QuickCommitError("Qoder 返回了空的 commit message。", "EMPTY_AI_MESSAGE");
715
+ return text;
716
+ }
608
717
  async function callCliAiText(prompt, cwd, language, opts) {
609
718
  const provider = normalizeProvider(opts.provider);
610
719
  if (provider === "codex") {
@@ -612,10 +721,14 @@ async function callCliAiText(prompt, cwd, language, opts) {
612
721
  }
613
722
  if (provider === "opencode")
614
723
  return callOpenCodeText(prompt, cwd, opts);
615
- return callClaudeText(prompt, cwd, language, opts.model);
724
+ if (provider === "grok")
725
+ return callGrokText(prompt, cwd, opts);
726
+ if (provider === "qoder")
727
+ return callQoderText(prompt, cwd, opts);
728
+ return callClaudeText(prompt, cwd, language, opts);
616
729
  }
617
730
  async function callDirectApiText(prompt, systemAi) {
618
- const text = await callSystemAiTextWithFallback(prompt, systemAi);
731
+ const text = await callSystemAiTextWithFallback(prompt, systemAi, DIRECT_API_PROFILE_TIMEOUT_MS);
619
732
  if (!text.trim()) {
620
733
  throw new QuickCommitError("直连 API 返回了空结果。", "EMPTY_AI_MESSAGE");
621
734
  }
@@ -626,8 +739,9 @@ function aiFallbackFailed(primary, primaryError, fallbackError) {
626
739
  return new QuickCommitError(`${primary} 与 ${fallback} 均失败:${getGitErrorMessage(primaryError)};${getGitErrorMessage(fallbackError)}`, "AI_FALLBACK_FAILED");
627
740
  }
628
741
  /**
629
- * Run a lightweight AI request through the same source ordering used by quick
630
- * commit: the user's selected source first, then the reciprocal source once.
742
+ * Run a lightweight AI request through the selected Commit source. API mode
743
+ * exhausts its profile chain and then falls back once to the current-session
744
+ * CLI. CLI mode uses only that CLI.
631
745
  */
632
746
  export async function callConfiguredAiText(prompt, cwd, language, opts) {
633
747
  if (opts.systemAi?.enabled) {
@@ -645,21 +759,7 @@ export async function callConfiguredAiText(prompt, cwd, language, opts) {
645
759
  }
646
760
  }
647
761
  }
648
- try {
649
- return await callCliAiText(prompt, cwd, language, opts);
650
- }
651
- catch (cliError) {
652
- if (!opts.fallbackSystemAi?.enabled)
653
- throw cliError;
654
- try {
655
- // The user selected the CLI first. A complete direct-API profile is only
656
- // provided here as the reciprocal fallback, never as a second CLI try.
657
- return await callDirectApiText(prompt, opts.fallbackSystemAi);
658
- }
659
- catch (apiError) {
660
- throw aiFallbackFailed("CLI", cliError, apiError);
661
- }
662
- }
762
+ return callCliAiText(prompt, cwd, language, opts);
663
763
  }
664
764
  async function collectStagedDiff(cwd) {
665
765
  let diff;
@@ -899,7 +999,6 @@ export async function runTagHead(opts) {
899
999
  model: opts.model,
900
1000
  thinkingEffort: opts.thinkingEffort,
901
1001
  inheritEnv: opts.inheritEnv,
902
- fallbackSystemAi: opts.fallbackSystemAi,
903
1002
  systemAi: opts.systemAi,
904
1003
  });
905
1004
  }
@@ -1265,6 +1364,20 @@ async function runQuickCommitFallbackCli(opts, priorError) {
1265
1364
  inheritEnv: opts.inheritEnv,
1266
1365
  });
1267
1366
  }
1367
+ else if (provider === "grok") {
1368
+ await runCliText("grok", buildGrokTextArgs(prompt, opts, true), "", {
1369
+ cwd: opts.cwd,
1370
+ timeoutMs: QUICK_COMMIT_CLI_TIMEOUT_MS,
1371
+ inheritEnv: opts.inheritEnv,
1372
+ });
1373
+ }
1374
+ else if (provider === "qoder") {
1375
+ await runCliText("qodercli", buildQoderTextArgs(prompt, opts, true), "", {
1376
+ cwd: opts.cwd,
1377
+ timeoutMs: QUICK_COMMIT_CLI_TIMEOUT_MS,
1378
+ inheritEnv: opts.inheritEnv,
1379
+ });
1380
+ }
1268
1381
  else {
1269
1382
  const args = [
1270
1383
  "-p",
@@ -1333,7 +1446,6 @@ export async function runQuickCommit(opts) {
1333
1446
  model: opts.model,
1334
1447
  thinkingEffort: opts.thinkingEffort,
1335
1448
  inheritEnv: opts.inheritEnv,
1336
- fallbackSystemAi: opts.fallbackSystemAi,
1337
1449
  systemAi: opts.systemAi,
1338
1450
  };
1339
1451
  await assertGitWorkTreeAsync(cwd);
@@ -123,11 +123,7 @@ export function registerSettingsRoutes(app, deps) {
123
123
  res.json({ inheritEnv, total: entries.length, reveal, entries });
124
124
  });
125
125
  app.post("/api/settings/system-ai/import", requireAdmin, (req, res) => {
126
- const body = (req.body ?? {});
127
- const source = body.source === "codex" || body.source === "opencode" || body.source === "claude"
128
- ? body.source
129
- : config.commitCli;
130
- const imported = discoverCliSystemAiConfigs(source);
126
+ const imported = discoverCliSystemAiConfigs();
131
127
  if (!imported.length) {
132
128
  res.status(404).json({ error: "没有在已配置的 CLI 文件中找到可直连的 API 地址、密钥和模型。" });
133
129
  return;
@@ -1,11 +1,10 @@
1
+ import { discoverCliSystemAiConfigs } from "./system-ai.js";
1
2
  import type { SessionProvider, SessionSnapshot, SystemAiConfig, WandConfig } from "./types.js";
2
3
  export interface SessionAiContext {
3
4
  provider: SessionProvider;
4
5
  model?: string;
5
6
  thinkingEffort: SessionSnapshot["thinkingEffort"];
6
7
  inheritEnv?: boolean;
7
- /** Direct API to try when Commit is configured to prefer its CLI. */
8
- fallbackSystemAi?: SystemAiConfig;
9
8
  systemAi?: SystemAiConfig;
10
9
  }
11
10
  /**
@@ -19,4 +18,4 @@ export declare function resolveSessionAiContext(snapshot: Pick<SessionSnapshot,
19
18
  /** Build the source order for Wand-owned AI features such as titles. */
20
19
  export declare function resolveSystemAiContext(snapshot: Parameters<typeof resolveSessionAiContext>[0], config: Parameters<typeof resolveSessionAiContext>[1] & Pick<WandConfig, "systemAi" | "commitCli" | "commitModel">): SessionAiContext;
21
20
  /** Build the AI context for quick-commit actions from their global preferences. */
22
- export declare function resolveCommitAiContext(snapshot: Pick<SessionSnapshot, "provider" | "structuredState" | "runner" | "command" | "selectedModel" | "thinkingEffort">, config: Pick<WandConfig, "defaultModel" | "defaultCodexModel" | "defaultOpenCodeModel" | "defaultGrokModel" | "defaultQoderModel" | "defaultThinkingEffort" | "inheritEnv" | "commitCli" | "commitModel" | "commitAiSource" | "systemAi">): SessionAiContext;
21
+ export declare function resolveCommitAiContext(snapshot: Pick<SessionSnapshot, "provider" | "structuredState" | "runner" | "command" | "selectedModel" | "thinkingEffort">, config: Pick<WandConfig, "defaultModel" | "defaultCodexModel" | "defaultOpenCodeModel" | "defaultGrokModel" | "defaultQoderModel" | "defaultThinkingEffort" | "inheritEnv" | "commitAiSource" | "systemAi">, discoverApis?: typeof discoverCliSystemAiConfigs): SessionAiContext;
@@ -1,5 +1,5 @@
1
1
  import { getDefaultModelForProvider } from "./config.js";
2
- import { systemAiProfiles } from "./system-ai.js";
2
+ import { discoverCliSystemAiConfigs, mergeSystemAiConfigs, systemAiProfiles, } from "./system-ai.js";
3
3
  /**
4
4
  * Resolve the provider from every representation used by current and legacy
5
5
  * sessions. Older persisted sessions may not have the top-level provider, but
@@ -74,22 +74,20 @@ export function resolveSystemAiContext(snapshot, config) {
74
74
  return directApi && config.systemAi?.enabled ? { ...cliContext, systemAi: directApi } : cliContext;
75
75
  }
76
76
  /** Build the AI context for quick-commit actions from their global preferences. */
77
- export function resolveCommitAiContext(snapshot, config) {
77
+ export function resolveCommitAiContext(snapshot, config, discoverApis = discoverCliSystemAiConfigs) {
78
78
  const sessionContext = resolveSessionAiContext(snapshot, config);
79
- const directApi = config.systemAi ?? {
80
- enabled: true,
81
- protocol: "openai",
82
- baseUrl: "",
83
- apiKey: "",
84
- model: "",
79
+ const commitContext = {
80
+ ...sessionContext,
81
+ // Commit messages and tags are short classification/summarization tasks.
82
+ // Keep them on the minimum explicit provider effort instead of inheriting
83
+ // an expensive deep/max setting from the conversation.
84
+ thinkingEffort: "standard",
85
85
  };
86
- const readyDirectApi = usableSystemAi(directApi);
86
+ if (config.commitAiSource !== "api")
87
+ return commitContext;
88
+ const directApi = mergeSystemAiConfigs(discoverApis(commitContext.provider), config.systemAi);
87
89
  return {
88
- ...sessionContext,
89
- provider: config.commitCli === "codex" || config.commitCli === "opencode" ? config.commitCli : "claude",
90
- model: normalizeModel(config.commitModel),
91
- ...(config.commitAiSource === "api"
92
- ? { systemAi: { ...directApi, enabled: true } }
93
- : readyDirectApi ? { fallbackSystemAi: readyDirectApi } : {}),
90
+ ...commitContext,
91
+ ...(directApi ? { systemAi: directApi } : {}),
94
92
  };
95
93
  }
@@ -5,8 +5,9 @@ export declare function resolveStructuredRunner(provider: SessionProvider, reque
5
5
  export declare function defaultStructuredState(provider: SessionProvider, runner?: SessionRunner): StructuredSessionState;
6
6
  export declare function normalizeThinkingEffort(value: unknown): SessionSnapshot["thinkingEffort"];
7
7
  export declare function thinkingEffortToSdkBudget(effort: SessionSnapshot["thinkingEffort"]): number;
8
- export declare function thinkingEffortToClaudeCliEffort(effort: SessionSnapshot["thinkingEffort"]): string | null;
8
+ export declare function thinkingEffortToClaudeCliEffort(effort: SessionSnapshot["thinkingEffort"]): "low" | "medium" | "max" | null;
9
9
  export declare function thinkingEffortToClaudeSlashEffort(effort: SessionSnapshot["thinkingEffort"]): string;
10
10
  export declare function thinkingEffortToCodexReasoningEffort(effort: SessionSnapshot["thinkingEffort"]): string | null;
11
11
  export declare function thinkingEffortToOpenCodeVariant(effort: SessionSnapshot["thinkingEffort"]): string | null;
12
12
  export declare function thinkingEffortToGrokEffort(effort: SessionSnapshot["thinkingEffort"]): string | null;
13
+ export declare function thinkingEffortToQoderEffort(effort: SessionSnapshot["thinkingEffort"]): string | null;
@@ -94,3 +94,14 @@ export function thinkingEffortToGrokEffort(effort) {
94
94
  return "max";
95
95
  return effort.startsWith("codex:") ? effort.slice("codex:".length) || null : null;
96
96
  }
97
+ export function thinkingEffortToQoderEffort(effort) {
98
+ if (!effort || effort === "off")
99
+ return null;
100
+ if (effort === "standard")
101
+ return "low";
102
+ if (effort === "deep")
103
+ return "high";
104
+ if (effort === "max")
105
+ return "max";
106
+ return effort.startsWith("codex:") ? effort.slice("codex:".length) || null : null;
107
+ }
@@ -10,6 +10,11 @@ export declare function discoverCliSystemAiConfigs(preferred?: SessionProvider,
10
10
  export declare function discoverCliSystemAiConfig(preferred?: SessionProvider, home?: string): SystemAiConfig | null;
11
11
  /** Return the configured API chain in call order, excluding incomplete entries. */
12
12
  export declare function systemAiProfiles(config: SystemAiConfig | undefined, forceEnabled?: boolean): SystemAiConfig[];
13
+ /**
14
+ * Flatten and combine direct-API groups in priority order. Dynamically discovered
15
+ * profiles can be passed first, followed by stored/legacy settings.
16
+ */
17
+ export declare function mergeSystemAiConfigs(...groups: Array<SystemAiConfig | SystemAiConfig[] | undefined>): SystemAiConfig | undefined;
13
18
  export declare function callSystemAiText(prompt: string, config: SystemAiConfig, timeoutMs?: number): Promise<string>;
14
19
  /** Try every configured API in order. Empty responses are treated as unavailable. */
15
20
  export declare function callSystemAiTextWithFallback(prompt: string, config: SystemAiConfig, timeoutMs?: number): Promise<string>;