@co0ontty/wand 4.76.0 → 4.77.0-beta.g7fb0b70
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/agent-dispatch.d.ts +46 -0
- package/dist/agent-dispatch.js +84 -0
- package/dist/ai-team-availability.d.ts +69 -0
- package/dist/ai-team-availability.js +100 -0
- package/dist/ai-team-prompts.d.ts +113 -0
- package/dist/ai-team-prompts.js +435 -0
- package/dist/ai-team-runner.d.ts +241 -0
- package/dist/ai-team-runner.js +1370 -0
- package/dist/ai-team-types.d.ts +147 -0
- package/dist/ai-team-types.js +32 -0
- package/dist/attention.d.ts +40 -0
- package/dist/attention.js +86 -0
- package/dist/build-info.json +4 -4
- package/dist/claude-sdk-runner.d.ts +5 -0
- package/dist/claude-sdk-runner.js +2 -1
- package/dist/commit-task-archive.d.ts +3 -0
- package/dist/commit-task-archive.js +43 -0
- package/dist/config.js +0 -2
- package/dist/git-quick-commit.d.ts +2 -1
- package/dist/git-quick-commit.js +72 -60
- package/dist/message-truncator.d.ts +41 -5
- package/dist/message-truncator.js +255 -38
- package/dist/missions.d.ts +4 -2
- package/dist/missions.js +2 -2
- package/dist/process-manager.d.ts +1 -0
- package/dist/process-manager.js +17 -8
- package/dist/prompt-optimizer.js +13 -13
- package/dist/server-ai-team-routes.d.ts +11 -0
- package/dist/server-ai-team-routes.js +283 -0
- package/dist/server-attention-routes.d.ts +9 -0
- package/dist/server-attention-routes.js +26 -0
- package/dist/server-file-routes.js +1 -1
- package/dist/server-session-routes.js +41 -5
- package/dist/server-settings-routes.js +1 -1
- package/dist/server-task-routes.d.ts +2 -0
- package/dist/server-task-routes.js +6 -40
- package/dist/server-workspace-routes.js +13 -5
- package/dist/server.js +43 -0
- package/dist/session-topic.js +13 -13
- package/dist/session-transport.d.ts +3 -0
- package/dist/session-transport.js +1 -0
- package/dist/storage.d.ts +54 -1
- package/dist/storage.js +413 -2
- package/dist/structured-claude-adapter.d.ts +5 -0
- package/dist/structured-claude-adapter.js +13 -2
- package/dist/structured-claude-protocol.d.ts +2 -0
- package/dist/structured-claude-protocol.js +4 -0
- package/dist/structured-codex-adapter.js +2 -2
- package/dist/structured-grok-adapter.js +2 -1
- package/dist/structured-opencode-adapter.js +2 -2
- package/dist/structured-pi-adapter.js +2 -1
- package/dist/structured-provider-common.d.ts +17 -0
- package/dist/structured-provider-common.js +52 -0
- package/dist/structured-qoder-adapter.js +2 -1
- package/dist/structured-session-manager.d.ts +18 -1
- package/dist/structured-session-manager.js +67 -10
- package/dist/system-ai.d.ts +13 -2
- package/dist/system-ai.js +9 -5
- package/dist/task-title.js +10 -10
- package/dist/types.d.ts +25 -2
- package/dist/wand-task-sync.d.ts +1 -0
- package/dist/wand-task-sync.js +1 -0
- package/dist/web-ui/content/ai-teams.js +12 -0
- package/dist/web-ui/content/scripts.js +86 -5301
- package/dist/web-ui/content/styles.css +1 -1
- package/dist/web-ui/embedded-assets.d.ts +1 -0
- package/dist/web-ui/embedded-assets.js +3 -2
- package/dist/web-ui/scripts.d.ts +8 -0
- package/dist/web-ui/scripts.js +28 -2
- package/dist/ws-broadcast.js +52 -19
- package/package.json +1 -1
package/dist/git-quick-commit.js
CHANGED
|
@@ -5,7 +5,7 @@ import { callSystemAiTextWithFallback } from "./system-ai.js";
|
|
|
5
5
|
import { buildChildEnv } from "./env-utils.js";
|
|
6
6
|
import { isSessionProvider } from "./session-provider.js";
|
|
7
7
|
import { runGitAsync as runGitAsyncBase, runGitRawAsync as runGitRawAsyncBase, getGitErrorMessage, } from "./git-utils.js";
|
|
8
|
-
import { thinkingEffortToClaudeCliEffort, thinkingEffortToCodexReasoningEffort, thinkingEffortToGrokEffort, thinkingEffortToOpenCodeVariant, thinkingEffortToQoderEffort, thinkingEffortToPiLevel, } from "./structured-provider-common.js";
|
|
8
|
+
import { composeSystemFallback, systemPromptFlag, thinkingEffortToClaudeCliEffort, thinkingEffortToCodexReasoningEffort, thinkingEffortToGrokEffort, thinkingEffortToOpenCodeVariant, thinkingEffortToQoderEffort, thinkingEffortToPiLevel, } from "./structured-provider-common.js";
|
|
9
9
|
/** provider 缺省值:无法识别时回落到 Claude。 */
|
|
10
10
|
function defaultProvider(provider) {
|
|
11
11
|
return isSessionProvider(provider) ? provider : "claude";
|
|
@@ -283,13 +283,14 @@ export class QuickCommitError extends Error {
|
|
|
283
283
|
}
|
|
284
284
|
}
|
|
285
285
|
// ── AI commit message generation ──
|
|
286
|
-
async function callClaudeText(
|
|
286
|
+
async function callClaudeText(request, cwd, language, opts) {
|
|
287
287
|
try {
|
|
288
288
|
const effort = thinkingEffortToClaudeCliEffort(opts.thinkingEffort ?? "off");
|
|
289
|
-
return await runClaudePrint(prompt, {
|
|
289
|
+
return await runClaudePrint(request.prompt, {
|
|
290
290
|
cwd,
|
|
291
291
|
timeoutMs: CLAUDE_MESSAGE_TIMEOUT_MS,
|
|
292
292
|
language,
|
|
293
|
+
systemInstructions: request.system,
|
|
293
294
|
model: opts.model ?? undefined,
|
|
294
295
|
...(effort ? { effort } : {}),
|
|
295
296
|
});
|
|
@@ -421,7 +422,7 @@ function extractPiText(stdout) {
|
|
|
421
422
|
}
|
|
422
423
|
return text.trim();
|
|
423
424
|
}
|
|
424
|
-
function buildPiTextArgs(
|
|
425
|
+
function buildPiTextArgs(request, opts, allowTools = false) {
|
|
425
426
|
const args = ["--mode", "json", "--print", "--no-session"];
|
|
426
427
|
if (!allowTools)
|
|
427
428
|
args.push("--no-tools");
|
|
@@ -431,33 +432,48 @@ function buildPiTextArgs(prompt, opts, allowTools = false) {
|
|
|
431
432
|
const level = thinkingEffortToPiLevel(opts.thinkingEffort ?? "off");
|
|
432
433
|
if (level)
|
|
433
434
|
args.push("--thinking", level);
|
|
434
|
-
args.push(
|
|
435
|
+
args.push(...systemPromptArgsFrom("pi", request.system));
|
|
436
|
+
args.push(request.prompt);
|
|
435
437
|
return args;
|
|
436
438
|
}
|
|
437
|
-
function buildGrokTextArgs(
|
|
438
|
-
const args = ["--no-auto-update", "-p", prompt, "--output-format", "streaming-json"];
|
|
439
|
+
function buildGrokTextArgs(request, opts, allowTools = false) {
|
|
440
|
+
const args = ["--no-auto-update", "-p", request.prompt, "--output-format", "streaming-json"];
|
|
439
441
|
const model = opts.model?.trim();
|
|
440
442
|
if (model && model !== "default")
|
|
441
443
|
args.push("--model", model);
|
|
442
444
|
const effort = thinkingEffortToGrokEffort(opts.thinkingEffort ?? "off");
|
|
443
445
|
if (effort)
|
|
444
446
|
args.push("--effort", effort);
|
|
447
|
+
args.push(...systemPromptArgsFrom("grok", request.system));
|
|
445
448
|
if (allowTools)
|
|
446
449
|
args.push("--always-approve");
|
|
447
450
|
return args;
|
|
448
451
|
}
|
|
449
|
-
function buildQoderTextArgs(
|
|
450
|
-
const args = ["-p", prompt, "--output-format", "stream-json", "--no-session-persistence"];
|
|
452
|
+
function buildQoderTextArgs(request, opts, allowTools = false) {
|
|
453
|
+
const args = ["-p", request.prompt, "--output-format", "stream-json", "--no-session-persistence"];
|
|
451
454
|
const model = opts.model?.trim();
|
|
452
455
|
if (model && model !== "default")
|
|
453
456
|
args.push("--model", model);
|
|
454
457
|
const effort = thinkingEffortToQoderEffort(opts.thinkingEffort ?? "off");
|
|
455
458
|
if (effort)
|
|
456
459
|
args.push("--reasoning-effort", effort);
|
|
460
|
+
args.push(...systemPromptArgsFrom("qoder", request.system));
|
|
457
461
|
if (allowTools)
|
|
458
462
|
args.push("--permission-mode", "bypass_permissions");
|
|
459
463
|
return args;
|
|
460
464
|
}
|
|
465
|
+
/** provider 自己的系统提示开关 + 规则文本;没有开关的 provider 返回空。 */
|
|
466
|
+
function systemPromptArgsFrom(provider, system) {
|
|
467
|
+
const text = system?.trim();
|
|
468
|
+
if (!text)
|
|
469
|
+
return [];
|
|
470
|
+
const flag = systemPromptFlag(provider);
|
|
471
|
+
return flag ? [flag, text] : [];
|
|
472
|
+
}
|
|
473
|
+
/** 没有系统提示开关的 provider(codex / opencode):规则只能并进内容前面。 */
|
|
474
|
+
function contentWithSystemPrompt(provider, request) {
|
|
475
|
+
return systemPromptFlag(provider) ? request.prompt : composeSystemFallback(request.system, request.prompt);
|
|
476
|
+
}
|
|
461
477
|
function runCliText(command, args, prompt, opts) {
|
|
462
478
|
return new Promise((resolve, reject) => {
|
|
463
479
|
const child = spawn(command, args, {
|
|
@@ -509,7 +525,7 @@ function runCliText(command, args, prompt, opts) {
|
|
|
509
525
|
child.stdin?.end(prompt);
|
|
510
526
|
});
|
|
511
527
|
}
|
|
512
|
-
async function callCodexText(
|
|
528
|
+
async function callCodexText(request, cwd, opts) {
|
|
513
529
|
// Quick commit is an internal one-shot request, not a user conversation. Keep
|
|
514
530
|
// Codex from persisting it into ~/.codex/sessions, where Wand would otherwise
|
|
515
531
|
// surface the generated prompt as a recoverable session.
|
|
@@ -521,7 +537,7 @@ async function callCodexText(prompt, cwd, opts) {
|
|
|
521
537
|
if (reasoningEffort)
|
|
522
538
|
args.push("-c", `model_reasoning_effort=${reasoningEffort}`);
|
|
523
539
|
args.push("-");
|
|
524
|
-
const stdout = await runCliText("codex", args,
|
|
540
|
+
const stdout = await runCliText("codex", args, contentWithSystemPrompt("codex", request), {
|
|
525
541
|
cwd,
|
|
526
542
|
timeoutMs: CODEX_MESSAGE_TIMEOUT_MS,
|
|
527
543
|
inheritEnv: opts.inheritEnv,
|
|
@@ -532,7 +548,7 @@ async function callCodexText(prompt, cwd, opts) {
|
|
|
532
548
|
}
|
|
533
549
|
return text;
|
|
534
550
|
}
|
|
535
|
-
async function callOpenCodeText(
|
|
551
|
+
async function callOpenCodeText(request, cwd, opts) {
|
|
536
552
|
const args = ["run", "--format", "json"];
|
|
537
553
|
const model = opts.model?.trim();
|
|
538
554
|
if (model && model !== "default")
|
|
@@ -540,7 +556,7 @@ async function callOpenCodeText(prompt, cwd, opts) {
|
|
|
540
556
|
const variant = thinkingEffortToOpenCodeVariant(opts.thinkingEffort ?? "off");
|
|
541
557
|
if (variant)
|
|
542
558
|
args.push("--variant", variant);
|
|
543
|
-
const stdout = await runCliText("opencode", args,
|
|
559
|
+
const stdout = await runCliText("opencode", args, contentWithSystemPrompt("opencode", request), {
|
|
544
560
|
cwd,
|
|
545
561
|
timeoutMs: CODEX_MESSAGE_TIMEOUT_MS,
|
|
546
562
|
inheritEnv: opts.inheritEnv,
|
|
@@ -550,8 +566,8 @@ async function callOpenCodeText(prompt, cwd, opts) {
|
|
|
550
566
|
throw new QuickCommitError("OpenCode 返回了空的 commit message。", "EMPTY_AI_MESSAGE");
|
|
551
567
|
return text;
|
|
552
568
|
}
|
|
553
|
-
async function callGrokText(
|
|
554
|
-
const stdout = await runCliText("grok", buildGrokTextArgs(
|
|
569
|
+
async function callGrokText(request, cwd, opts) {
|
|
570
|
+
const stdout = await runCliText("grok", buildGrokTextArgs(request, opts), "", {
|
|
555
571
|
cwd,
|
|
556
572
|
timeoutMs: CODEX_MESSAGE_TIMEOUT_MS,
|
|
557
573
|
inheritEnv: opts.inheritEnv,
|
|
@@ -561,8 +577,8 @@ async function callGrokText(prompt, cwd, opts) {
|
|
|
561
577
|
throw new QuickCommitError("Grok 返回了空的 commit message。", "EMPTY_AI_MESSAGE");
|
|
562
578
|
return text;
|
|
563
579
|
}
|
|
564
|
-
async function callQoderText(
|
|
565
|
-
const stdout = await runCliText("qodercli", buildQoderTextArgs(
|
|
580
|
+
async function callQoderText(request, cwd, opts) {
|
|
581
|
+
const stdout = await runCliText("qodercli", buildQoderTextArgs(request, opts), "", {
|
|
566
582
|
cwd,
|
|
567
583
|
timeoutMs: CODEX_MESSAGE_TIMEOUT_MS,
|
|
568
584
|
inheritEnv: opts.inheritEnv,
|
|
@@ -572,30 +588,30 @@ async function callQoderText(prompt, cwd, opts) {
|
|
|
572
588
|
throw new QuickCommitError("Qoder 返回了空的 commit message。", "EMPTY_AI_MESSAGE");
|
|
573
589
|
return text;
|
|
574
590
|
}
|
|
575
|
-
async function callPiText(
|
|
576
|
-
const stdout = await runCliText("pi", buildPiTextArgs(
|
|
591
|
+
async function callPiText(request, cwd, opts) {
|
|
592
|
+
const stdout = await runCliText("pi", buildPiTextArgs(request, opts), "", { cwd, timeoutMs: CODEX_MESSAGE_TIMEOUT_MS, inheritEnv: opts.inheritEnv });
|
|
577
593
|
const text = extractPiText(stdout);
|
|
578
594
|
if (!text)
|
|
579
595
|
throw new QuickCommitError("Pi 返回了空的 commit message。", "EMPTY_AI_MESSAGE");
|
|
580
596
|
return text;
|
|
581
597
|
}
|
|
582
|
-
async function callCliAiText(
|
|
598
|
+
async function callCliAiText(request, cwd, language, opts) {
|
|
583
599
|
const provider = defaultProvider(opts.provider);
|
|
584
600
|
if (provider === "codex") {
|
|
585
|
-
return callCodexText(
|
|
601
|
+
return callCodexText(request, cwd, opts);
|
|
586
602
|
}
|
|
587
603
|
if (provider === "opencode")
|
|
588
|
-
return callOpenCodeText(
|
|
604
|
+
return callOpenCodeText(request, cwd, opts);
|
|
589
605
|
if (provider === "grok")
|
|
590
|
-
return callGrokText(
|
|
606
|
+
return callGrokText(request, cwd, opts);
|
|
591
607
|
if (provider === "qoder")
|
|
592
|
-
return callQoderText(
|
|
608
|
+
return callQoderText(request, cwd, opts);
|
|
593
609
|
if (provider === "pi")
|
|
594
|
-
return callPiText(
|
|
595
|
-
return callClaudeText(
|
|
610
|
+
return callPiText(request, cwd, opts);
|
|
611
|
+
return callClaudeText(request, cwd, language, opts);
|
|
596
612
|
}
|
|
597
|
-
async function callDirectApiText(
|
|
598
|
-
const text = await callSystemAiTextWithFallback(
|
|
613
|
+
async function callDirectApiText(request, systemAi) {
|
|
614
|
+
const text = await callSystemAiTextWithFallback(request, systemAi, DIRECT_API_PROFILE_TIMEOUT_MS);
|
|
599
615
|
if (!text.trim()) {
|
|
600
616
|
throw new QuickCommitError("直连 API 返回了空结果。", "EMPTY_AI_MESSAGE");
|
|
601
617
|
}
|
|
@@ -610,23 +626,23 @@ function aiFallbackFailed(primary, primaryError, fallbackError) {
|
|
|
610
626
|
* exhausts its profile chain and then falls back once to the current-session
|
|
611
627
|
* CLI. CLI mode uses only that CLI.
|
|
612
628
|
*/
|
|
613
|
-
export async function callConfiguredAiText(
|
|
629
|
+
export async function callConfiguredAiText(request, cwd, language, opts) {
|
|
614
630
|
if (opts.systemAi?.enabled) {
|
|
615
631
|
try {
|
|
616
|
-
return await callDirectApiText(
|
|
632
|
+
return await callDirectApiText(request, opts.systemAi);
|
|
617
633
|
}
|
|
618
634
|
catch (apiError) {
|
|
619
635
|
try {
|
|
620
636
|
// The user selected the direct API first. If it is unavailable or
|
|
621
637
|
// empty, retry this exact request through their selected CLI.
|
|
622
|
-
return await callCliAiText(
|
|
638
|
+
return await callCliAiText(request, cwd, language, opts);
|
|
623
639
|
}
|
|
624
640
|
catch (cliError) {
|
|
625
641
|
throw aiFallbackFailed("直连 API", apiError, cliError);
|
|
626
642
|
}
|
|
627
643
|
}
|
|
628
644
|
}
|
|
629
|
-
return callCliAiText(
|
|
645
|
+
return callCliAiText(request, cwd, language, opts);
|
|
630
646
|
}
|
|
631
647
|
/** Read the unstaged + staged tree without touching the index. */
|
|
632
648
|
async function collectWorkingTreeDiff(cwd) {
|
|
@@ -717,8 +733,7 @@ function commitTaskLine(lang, usedIteration) {
|
|
|
717
733
|
async function generateCommitMessage(cwd, language, ai = {}, options = {}) {
|
|
718
734
|
const { input, usedIteration } = await buildCommitPromptInput(cwd, options);
|
|
719
735
|
const lang = language.trim() || "中文";
|
|
720
|
-
const
|
|
721
|
-
const raw = await callConfiguredAiText(prompt, cwd, language, ai);
|
|
736
|
+
const raw = await callConfiguredAiText({ system: commitTaskLine(lang, usedIteration), prompt: input }, cwd, language, ai);
|
|
722
737
|
const message = normalizeAiText(raw);
|
|
723
738
|
if (!message) {
|
|
724
739
|
throw new QuickCommitError("AI 返回了空的 commit message。", "EMPTY_AI_MESSAGE");
|
|
@@ -765,15 +780,13 @@ async function generateCommitMessageWithTag(cwd, language, ai = {}, options = {}
|
|
|
765
780
|
const tagHint = latestTag
|
|
766
781
|
? `当前最新 tag 是 \`${latestTag}\`,请基于它给出下一个版本号(保持原有前缀风格,例如有 \`v\` 就保留 \`v\`)。`
|
|
767
782
|
: `仓库还没有任何 tag,请直接给一个起始版本号(建议 \`v0.0.1\` / \`v0.1.0\` / \`v1.0.0\` 之一,按改动幅度选择)。`;
|
|
768
|
-
const
|
|
783
|
+
const system = `阅读本轮用户消息,完成两件事:
|
|
769
784
|
1. 用${lang}写一条简洁的 commit message(祈使句,不超过 50 字,描述「做了什么」)。
|
|
770
|
-
2. 根据改动幅度推荐下一个语义化版本 tag(破坏性变更 → 升 major;新增功能 → 升 minor;修复 / 文档 / 重构 / 维护 → 升 patch
|
|
785
|
+
2. 根据改动幅度推荐下一个语义化版本 tag(破坏性变更 → 升 major;新增功能 → 升 minor;修复 / 文档 / 重构 / 维护 → 升 patch)。
|
|
771
786
|
|
|
772
787
|
请严格输出**单行 JSON 对象**,不要 Markdown 代码块、不要任何解释文字、不要多余引号。格式:
|
|
773
|
-
{"message":"...","tag":"v1.2.3"}
|
|
774
|
-
|
|
775
|
-
${input}`;
|
|
776
|
-
const raw = await callConfiguredAiText(prompt, cwd, language, ai);
|
|
788
|
+
{"message":"...","tag":"v1.2.3"}`;
|
|
789
|
+
const raw = await callConfiguredAiText({ system, prompt: `${tagHint}\n\n${input}` }, cwd, language, ai);
|
|
777
790
|
const parsed = tryParseJson(raw);
|
|
778
791
|
let message;
|
|
779
792
|
let suggestedTag;
|
|
@@ -833,16 +846,12 @@ async function generateTagAfterCommit(cwd, language, commitMessage, ai = {}) {
|
|
|
833
846
|
const tagHint = latestTag
|
|
834
847
|
? `当前最新 tag 是 \`${latestTag}\`,请基于它给出下一个版本号(保持原有前缀风格,例如有 \`v\` 就保留 \`v\`)。`
|
|
835
848
|
: `仓库还没有任何 tag,请给一个起始版本号(建议 \`v0.0.1\` / \`v0.1.0\` / \`v1.0.0\` 之一,按改动幅度选择)。`;
|
|
836
|
-
const
|
|
849
|
+
const system = `根据本轮用户消息里的 commit message 和 git diff 推荐一个语义化版本 tag(破坏性变更 → 升 major;新增功能 → 升 minor;修复 / 文档 / 重构 / 维护 → 升 patch)。
|
|
837
850
|
|
|
838
851
|
请用${lang}思考但严格输出**单行 JSON 对象**,不要 Markdown 代码块、不要任何解释文字、不要多余引号。格式:
|
|
839
|
-
{"tag":"v1.2.3"}
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
git diff:
|
|
844
|
-
${diff}`;
|
|
845
|
-
const raw = await callConfiguredAiText(prompt, cwd, language, ai);
|
|
852
|
+
{"tag":"v1.2.3"}`;
|
|
853
|
+
const prompt = `${tagHint}\n\ncommit message:${commitMessage}\n\ngit diff:\n${diff}`;
|
|
854
|
+
const raw = await callConfiguredAiText({ system, prompt }, cwd, language, ai);
|
|
846
855
|
const parsed = tryParseJson(raw);
|
|
847
856
|
let suggested;
|
|
848
857
|
if (parsed && typeof parsed.tag === "string") {
|
|
@@ -1212,15 +1221,18 @@ function buildFallbackPrompt(opts, priorError) {
|
|
|
1212
1221
|
const submoduleLine = opts.submodule
|
|
1213
1222
|
? "- 如果 submodule 内部也有改动,先在对应 submodule 内 add/commit,再提交父仓库里的 submodule 指针"
|
|
1214
1223
|
: "- 不进入 submodule 内部提交,只提交父仓库自身已纳入的改动";
|
|
1215
|
-
|
|
1224
|
+
// 角色、约束、输出格式走系统提示;本次要做什么、为什么走到兜底走用户消息。
|
|
1225
|
+
const system = [
|
|
1216
1226
|
"你正在作为 Wand 的快捷提交兜底执行器运行。前置的内置快捷提交流程失败了,现在请直接用 CLI 工具完成同一件事。",
|
|
1217
1227
|
"",
|
|
1218
1228
|
"约束:",
|
|
1219
1229
|
"- 只允许执行与 git 快捷提交直接相关的命令,例如 git status、git diff、git add、git commit、git tag、git push、git submodule status。",
|
|
1220
1230
|
"- 不要修改源代码内容,不要运行测试,不要安装依赖,不要重构文件。",
|
|
1221
1231
|
"- 如果没有可提交改动,明确说明并停止,不要创建空 commit。",
|
|
1222
|
-
"-
|
|
1223
|
-
|
|
1232
|
+
"- 完成后只输出一行 JSON:{\"ok\":true,\"message\":\"...\",\"tag\":\"...\"}。失败时输出一行 JSON:{\"ok\":false,\"error\":\"...\"}。",
|
|
1233
|
+
`- commit message 和自然语言输出使用 ${lang}。`,
|
|
1234
|
+
].join("\n");
|
|
1235
|
+
const prompt = [
|
|
1224
1236
|
"任务:",
|
|
1225
1237
|
"- 执行 git add -A 纳入当前改动。",
|
|
1226
1238
|
messageLine,
|
|
@@ -1232,9 +1244,8 @@ function buildFallbackPrompt(opts, priorError) {
|
|
|
1232
1244
|
: []),
|
|
1233
1245
|
"",
|
|
1234
1246
|
`内置流程失败原因:${priorError}`,
|
|
1235
|
-
"",
|
|
1236
|
-
"完成后只输出一行 JSON:{\"ok\":true,\"message\":\"...\",\"tag\":\"...\"}。失败时输出一行 JSON:{\"ok\":false,\"error\":\"...\"}。",
|
|
1237
1247
|
].join("\n");
|
|
1248
|
+
return { system, prompt };
|
|
1238
1249
|
}
|
|
1239
1250
|
async function getHead(cwd) {
|
|
1240
1251
|
try {
|
|
@@ -1265,7 +1276,7 @@ async function getLatestTagAtHead(cwd) {
|
|
|
1265
1276
|
async function runQuickCommitFallbackCli(opts, priorError) {
|
|
1266
1277
|
await assertGitWorkTreeAsync(opts.cwd);
|
|
1267
1278
|
const beforeHead = await getHead(opts.cwd);
|
|
1268
|
-
const
|
|
1279
|
+
const request = buildFallbackPrompt(opts, priorError);
|
|
1269
1280
|
const provider = defaultProvider(opts.provider);
|
|
1270
1281
|
if (provider === "codex") {
|
|
1271
1282
|
const args = ["exec", "--ephemeral", "--json", "--color", "never", "--skip-git-repo-check", "--dangerously-bypass-approvals-and-sandbox"];
|
|
@@ -1276,7 +1287,7 @@ async function runQuickCommitFallbackCli(opts, priorError) {
|
|
|
1276
1287
|
if (reasoningEffort)
|
|
1277
1288
|
args.push("-c", `model_reasoning_effort=${reasoningEffort}`);
|
|
1278
1289
|
args.push("-");
|
|
1279
|
-
await runCliText("codex", args,
|
|
1290
|
+
await runCliText("codex", args, contentWithSystemPrompt("codex", request), {
|
|
1280
1291
|
cwd: opts.cwd,
|
|
1281
1292
|
timeoutMs: QUICK_COMMIT_CLI_TIMEOUT_MS,
|
|
1282
1293
|
inheritEnv: opts.inheritEnv,
|
|
@@ -1290,28 +1301,28 @@ async function runQuickCommitFallbackCli(opts, priorError) {
|
|
|
1290
1301
|
const variant = thinkingEffortToOpenCodeVariant(opts.thinkingEffort ?? "off");
|
|
1291
1302
|
if (variant)
|
|
1292
1303
|
args.push("--variant", variant);
|
|
1293
|
-
await runCliText("opencode", args,
|
|
1304
|
+
await runCliText("opencode", args, contentWithSystemPrompt("opencode", request), {
|
|
1294
1305
|
cwd: opts.cwd,
|
|
1295
1306
|
timeoutMs: QUICK_COMMIT_CLI_TIMEOUT_MS,
|
|
1296
1307
|
inheritEnv: opts.inheritEnv,
|
|
1297
1308
|
});
|
|
1298
1309
|
}
|
|
1299
1310
|
else if (provider === "grok") {
|
|
1300
|
-
await runCliText("grok", buildGrokTextArgs(
|
|
1311
|
+
await runCliText("grok", buildGrokTextArgs(request, opts, true), "", {
|
|
1301
1312
|
cwd: opts.cwd,
|
|
1302
1313
|
timeoutMs: QUICK_COMMIT_CLI_TIMEOUT_MS,
|
|
1303
1314
|
inheritEnv: opts.inheritEnv,
|
|
1304
1315
|
});
|
|
1305
1316
|
}
|
|
1306
1317
|
else if (provider === "qoder") {
|
|
1307
|
-
await runCliText("qodercli", buildQoderTextArgs(
|
|
1318
|
+
await runCliText("qodercli", buildQoderTextArgs(request, opts, true), "", {
|
|
1308
1319
|
cwd: opts.cwd,
|
|
1309
1320
|
timeoutMs: QUICK_COMMIT_CLI_TIMEOUT_MS,
|
|
1310
1321
|
inheritEnv: opts.inheritEnv,
|
|
1311
1322
|
});
|
|
1312
1323
|
}
|
|
1313
1324
|
else if (provider === "pi") {
|
|
1314
|
-
await runCliText("pi", buildPiTextArgs(
|
|
1325
|
+
await runCliText("pi", buildPiTextArgs(request, opts, true), "", {
|
|
1315
1326
|
cwd: opts.cwd,
|
|
1316
1327
|
timeoutMs: QUICK_COMMIT_CLI_TIMEOUT_MS,
|
|
1317
1328
|
inheritEnv: opts.inheritEnv,
|
|
@@ -1334,7 +1345,8 @@ async function runQuickCommitFallbackCli(opts, priorError) {
|
|
|
1334
1345
|
const claudeEffort = thinkingEffortToClaudeCliEffort(opts.thinkingEffort ?? "off");
|
|
1335
1346
|
if (claudeEffort)
|
|
1336
1347
|
args.push("--effort", claudeEffort);
|
|
1337
|
-
|
|
1348
|
+
args.push(...systemPromptArgsFrom("claude", request.system));
|
|
1349
|
+
await runCliText("claude", args, request.prompt, {
|
|
1338
1350
|
cwd: opts.cwd,
|
|
1339
1351
|
timeoutMs: QUICK_COMMIT_CLI_TIMEOUT_MS,
|
|
1340
1352
|
inheritEnv: opts.inheritEnv,
|
|
@@ -17,14 +17,50 @@ export interface BlockWindowedMessages extends WindowedMessages {
|
|
|
17
17
|
leadingBlockOffset: number;
|
|
18
18
|
/** turn messageOffset 的完整块数(客户端据此判断该 turn 是否已全部加载)。 */
|
|
19
19
|
leadingBlockTotal: number;
|
|
20
|
+
/**
|
|
21
|
+
* 被切掉的头部里「用户可感知」的块数:默认收起的工具 / 思考块不计入(它们在客户端
|
|
22
|
+
* 合并成一条折叠条,不该被当成一条更早消息)。客户端据此显示「还有 N 条」。
|
|
23
|
+
*/
|
|
24
|
+
leadingVisibleCount: number;
|
|
20
25
|
}
|
|
21
26
|
/**
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* 客户端先按块翻完这条 turn 的头部,再按 turn 往前翻更早的整条。
|
|
27
|
+
* 首次下发(首屏)的载荷上限:截断后的聊天 JSON 体积。整段历史在这个体积内就不做窗口化 ——
|
|
28
|
+
* 一条提示词 + 一段长回复的会话不该因为几十个默认收起的工具块就出现「更早消息」。
|
|
29
|
+
* 超出的会话才按下面的预算从尾部切:客户端先翻这条 turn 的头部块,再按 turn 往前翻。
|
|
26
30
|
*/
|
|
27
|
-
export declare
|
|
31
|
+
export declare const MESSAGE_FIRST_PAINT_BYTES: number;
|
|
32
|
+
/** 每个块在客户端是否「默认收起」(思考块 + 默认收起的工具卡片,与传输截断同一口径)。 */
|
|
33
|
+
export declare function collapsedBlockFlags(content: ContentBlock[], cardDefaults: CardExpandDefaults): boolean[];
|
|
34
|
+
/**
|
|
35
|
+
* 一段内容在传输层的估算体积。`limit` 用来提前收尾:一旦确认超过它就不再往下算
|
|
36
|
+
* (预算判定只需要知道「超了」,不需要精确值)。
|
|
37
|
+
*/
|
|
38
|
+
export declare function contentTransportBytes(content: ContentBlock[], cardDefaults: CardExpandDefaults, limit?: number): number;
|
|
39
|
+
/**
|
|
40
|
+
* 把块级窗口 / 翻页的起点吸附到「语义干净」的位置:
|
|
41
|
+
*
|
|
42
|
+
* 1. 起点落在默认收起的折叠段中间 → 回到该段起点(整段入窗)。半截工具段在客户端
|
|
43
|
+
* 会渲染成一个少了前几个调用的折叠条,用户看着就是「更早消息缺了一块」。
|
|
44
|
+
* 2. 起点是配对的 tool_result(它的 tool_use 被切在前面)→ 回到 tool_use,否则客户端
|
|
45
|
+
* 顶部会冒出一张「无头结果」卡。
|
|
46
|
+
* 3. 需要往回吃掉的体积超过 MAX_BLOCK_SNAP_BACK_BYTES(或本页范围内吃不下)时不再
|
|
47
|
+
* 往回吸附,改为跳到该段之后(整段都是默认收起的内容,跳过去不会藏掉可见内容)。
|
|
48
|
+
*
|
|
49
|
+
* 返回吸附后的起点;起点越界时回退到 0(整条 turn 入窗,保证窗口不为空)。
|
|
50
|
+
*/
|
|
51
|
+
export declare function alignedBlockStart(content: ContentBlock[], cardDefaults: CardExpandDefaults, rawStart: number, forwardLimit?: number): number;
|
|
52
|
+
/** [0, end) 里用户可感知的块数(默认收起的工具 / 思考块不计入)。 */
|
|
53
|
+
export declare function visibleBlockCount(content: ContentBlock[], cardDefaults: CardExpandDefaults, end: number): number;
|
|
54
|
+
/**
|
|
55
|
+
* 块级窗口:默认取整段历史(只要它在预算内),超出的才从最新 turn 往回累计,
|
|
56
|
+
* 能整条放下就整条放,放不下的那条(最旧的入窗 turn)只取其尾部若干块,
|
|
57
|
+
* 并通过 leadingBlockOffset 告知客户端「这条 turn 还有更早的块」。
|
|
58
|
+
*
|
|
59
|
+
* 预算口径:`blockBudget` 数的是**用户可感知的条数**(默认收起的工具 / 思考块不计入),
|
|
60
|
+
* 另外叠加一层载荷上限 —— 否则一段长工具调用会把预算吃光,把用户自己的提示词挤出首屏,
|
|
61
|
+
* 一条提示词的会话也会莫名出现「更早消息」。
|
|
62
|
+
*/
|
|
63
|
+
export declare function blockWindowMessagesForTransport(all: ConversationTurn[] | undefined, cardDefaults: CardExpandDefaults, blockBudget?: number, byteBudget?: number): BlockWindowedMessages;
|
|
28
64
|
/**
|
|
29
65
|
* 块级翻页:取某条 turn 的 content[start, end) 这一段(已做 transport 截断)。
|
|
30
66
|
* 客户端滚动到顶、且当前最旧 turn 仍有更早块时调用,end = 客户端当前 leadingBlockOffset。
|