@xia-sc/dsh-git 0.5.2 → 0.6.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/LICENSE +21 -0
- package/README.en.md +51 -8
- package/README.md +34 -8
- package/lib/client.js +748 -255
- package/lib/index.js +27 -7
- package/package.json +3 -2
package/lib/index.js
CHANGED
|
@@ -84,8 +84,15 @@ const LLM_TIMEOUT_MS = 120000;
|
|
|
84
84
|
const LLM_DIFF_MAX_CHARS = 12000;
|
|
85
85
|
/** Diff-stat characters sent to the model. */
|
|
86
86
|
const LLM_STAT_MAX_CHARS = 2000;
|
|
87
|
-
/**
|
|
88
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Output cap for one generated commit message. A reasoning model spends this
|
|
89
|
+
* budget on its thinking BEFORE any text exists and reports the two together as
|
|
90
|
+
* `completion_tokens`, so a cap sized for the message alone truncates every
|
|
91
|
+
* call that thinks a little. 8192 leaves room for a long think plus a
|
|
92
|
+
* subject+body; the model still stops on its own well before it (an unset cap
|
|
93
|
+
* would fall back to the adapter's own default, which is larger still).
|
|
94
|
+
*/
|
|
95
|
+
const LLM_MAX_TOKENS = 8192;
|
|
89
96
|
/** Accepted `generateMessage` modes. */
|
|
90
97
|
const GENERATE_MODES = ["staged", "unstaged", "all"];
|
|
91
98
|
/** Default mode: the only one whose content is what `commit` will actually record. */
|
|
@@ -535,7 +542,7 @@ async function gitFetch(rawCwd, rawRemote, signal) {
|
|
|
535
542
|
return fail("fetch-failed", cleanMessage(error), {});
|
|
536
543
|
}
|
|
537
544
|
const detail = [out.stdout, out.stderr].join("\n").trim();
|
|
538
|
-
return ok({ message: detail
|
|
545
|
+
return ok({ message: detail.slice(0, 800) });
|
|
539
546
|
}
|
|
540
547
|
|
|
541
548
|
/**
|
|
@@ -555,7 +562,7 @@ async function gitPull(rawCwd, signal) {
|
|
|
555
562
|
return fail("pull-failed", cleanMessage(error), {});
|
|
556
563
|
}
|
|
557
564
|
const detail = [out.stdout, out.stderr].join("\n").trim();
|
|
558
|
-
return ok({ message: detail
|
|
565
|
+
return ok({ message: detail.slice(0, 800) });
|
|
559
566
|
}
|
|
560
567
|
|
|
561
568
|
/** Read the repo's configured author (user.name / user.email) or null. */
|
|
@@ -624,7 +631,7 @@ async function gitPush(rawCwd, signal) {
|
|
|
624
631
|
return fail("push-failed", cleanMessage(error), {});
|
|
625
632
|
}
|
|
626
633
|
const detail = [out.stdout, out.stderr].join("\n").trim();
|
|
627
|
-
return ok({ message: detail
|
|
634
|
+
return ok({ message: detail.slice(0, 800) });
|
|
628
635
|
}
|
|
629
636
|
|
|
630
637
|
/**
|
|
@@ -759,7 +766,9 @@ async function gitStage(rawCwd, signal) {
|
|
|
759
766
|
return fail("stage-failed", cleanMessage(error), {});
|
|
760
767
|
}
|
|
761
768
|
const detail = [out.stdout, out.stderr].join("\n").trim();
|
|
762
|
-
|
|
769
|
+
// `message` is git's own output and nothing else: an operation git says
|
|
770
|
+
// nothing about reports an empty string, and the panel words its own summary.
|
|
771
|
+
return ok({ message: detail.slice(0, 800) });
|
|
763
772
|
}
|
|
764
773
|
|
|
765
774
|
/**
|
|
@@ -1049,7 +1058,8 @@ function generationMessage(text) {
|
|
|
1049
1058
|
* @param route - `{ provider, model }` from {@link resolveLlmRoute}.
|
|
1050
1059
|
* @param signal - cancellation (browser abort plus the server ceiling).
|
|
1051
1060
|
* @returns the trimmed message.
|
|
1052
|
-
* @throws on a terminal stream failure
|
|
1061
|
+
* @throws on a terminal stream failure, an output cap hit before any text
|
|
1062
|
+
* existed (`llm-truncated`), or genuinely empty output (`llm-empty`).
|
|
1053
1063
|
*/
|
|
1054
1064
|
async function requestCommitMessage(ctx, prompt, route, signal) {
|
|
1055
1065
|
const options = {
|
|
@@ -1076,6 +1086,16 @@ async function requestCommitMessage(ctx, prompt, route, signal) {
|
|
|
1076
1086
|
const ordered = (map) => [...map.entries()].sort((left, right) => left[0] - right[0]).map((entry) => entry[1]);
|
|
1077
1087
|
const message = (blocks.size > 0 ? ordered(blocks) : ordered(deltas)).join("").trim();
|
|
1078
1088
|
if (message === "") {
|
|
1089
|
+
// "Nothing came back" and "the budget ran out before any text did" are
|
|
1090
|
+
// different failures with different fixes; a reasoning model hits the
|
|
1091
|
+
// second one routinely (its thinking shares `completion_tokens` with the
|
|
1092
|
+
// message), so report the cap instead of a misleading generic empty.
|
|
1093
|
+
if (finish !== undefined && finish.kind === "max-tokens") {
|
|
1094
|
+
throw Object.assign(
|
|
1095
|
+
new Error(`the model hit the ${LLM_MAX_TOKENS}-token output cap before writing any commit message (a reasoning model spends that budget on its thinking first)`),
|
|
1096
|
+
{ pluginCode: "llm-truncated" }
|
|
1097
|
+
);
|
|
1098
|
+
}
|
|
1079
1099
|
throw Object.assign(new Error("the model returned no commit message"), { pluginCode: "llm-empty" });
|
|
1080
1100
|
}
|
|
1081
1101
|
return message;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xia-sc/dsh-git",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Complete Git management for the DeepSeek Harness Web GUI: branch switch, new-branch-from-base, fetch, pull, stage-all, commit (with AI-drafted message), push, status, and a click-to-open diff viewer (staged/unstaged, resizable) — as a collapsible floating panel that follows the current session's workspace.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
"files": [
|
|
13
13
|
"lib",
|
|
14
14
|
"cordis.patch.yml",
|
|
15
|
-
"README.en.md"
|
|
15
|
+
"README.en.md",
|
|
16
|
+
"LICENSE"
|
|
16
17
|
],
|
|
17
18
|
"license": "MIT",
|
|
18
19
|
"author": "xia-sc",
|