@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.
- package/dist/build-info.json +3 -3
- package/dist/claude-sdk-runner.d.ts +3 -0
- package/dist/claude-sdk-runner.js +1 -0
- package/dist/config.d.ts +6 -2
- package/dist/config.js +7 -9
- package/dist/git-quick-commit.d.ts +3 -6
- package/dist/git-quick-commit.js +137 -25
- package/dist/server-settings-routes.js +1 -5
- package/dist/session-ai-context.d.ts +2 -3
- package/dist/session-ai-context.js +13 -15
- package/dist/structured-provider-common.d.ts +2 -1
- package/dist/structured-provider-common.js +11 -0
- package/dist/system-ai.d.ts +5 -0
- package/dist/system-ai.js +153 -13
- package/dist/types.d.ts +1 -1
- package/dist/web-ui/content/scripts.js +60 -60
- package/dist/web-ui/content/styles.css +1 -1
- package/dist/web-ui/embedded-assets.d.ts +1 -1
- package/dist/web-ui/embedded-assets.js +3 -3
- package/package.json +1 -1
package/dist/build-info.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"commit": "
|
|
3
|
-
"builtAt": "2026-07-
|
|
4
|
-
"version": "4.
|
|
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
|
-
/**
|
|
44
|
-
|
|
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
|
|
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
|
-
/**
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
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
|
|
42
|
-
*
|
|
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;
|
package/dist/git-quick-commit.js
CHANGED
|
@@ -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,
|
|
461
|
+
async function callClaudeText(prompt, cwd, language, opts) {
|
|
458
462
|
try {
|
|
459
|
-
|
|
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"
|
|
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
|
-
|
|
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
|
|
630
|
-
*
|
|
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
|
-
|
|
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
|
|
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" | "
|
|
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
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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
|
-
|
|
86
|
+
if (config.commitAiSource !== "api")
|
|
87
|
+
return commitContext;
|
|
88
|
+
const directApi = mergeSystemAiConfigs(discoverApis(commitContext.provider), config.systemAi);
|
|
87
89
|
return {
|
|
88
|
-
...
|
|
89
|
-
|
|
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"]):
|
|
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
|
+
}
|
package/dist/system-ai.d.ts
CHANGED
|
@@ -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>;
|