@aipanel/dsh-plugin 1.2.27 → 1.3.1
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 +158 -94
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -26,6 +26,17 @@ var EXT_MSG = {
|
|
|
26
26
|
};
|
|
27
27
|
var SEVERITY_ERROR = 1;
|
|
28
28
|
var SEVERITY_WARN = 2;
|
|
29
|
+
var VUE_DEVTOOLS_TIMELINE_INCLUDE = {
|
|
30
|
+
SUMMARY: "summary",
|
|
31
|
+
SLOW: "slow",
|
|
32
|
+
ALL: "all"
|
|
33
|
+
};
|
|
34
|
+
var VUE_DEVTOOLS_TIMELINE_INCLUDES = [
|
|
35
|
+
VUE_DEVTOOLS_TIMELINE_INCLUDE.SUMMARY,
|
|
36
|
+
VUE_DEVTOOLS_TIMELINE_INCLUDE.SLOW,
|
|
37
|
+
VUE_DEVTOOLS_TIMELINE_INCLUDE.ALL
|
|
38
|
+
];
|
|
39
|
+
var DEFAULT_TIMELINE_INCLUDE = VUE_DEVTOOLS_TIMELINE_INCLUDE.SLOW;
|
|
29
40
|
var MUTATING_TOOLS = /* @__PURE__ */ new Set(["write", "edit", "apply_patch"]);
|
|
30
41
|
var OPENCODE_ENV = {
|
|
31
42
|
CONFIG_DIR: "OPENCODE_CONFIG_DIR",
|
|
@@ -628,6 +639,22 @@ function parseTscDiags(rawOutput, filePath, projectDir, source = "tsc") {
|
|
|
628
639
|
}
|
|
629
640
|
return diags;
|
|
630
641
|
}
|
|
642
|
+
function filterTscOutputForFile(rawOutput, filePath, projectDir) {
|
|
643
|
+
const resolved = path.resolve(filePath);
|
|
644
|
+
const errorLinePat = /^(.+?)\((\d+),(\d+)\):\s+(error|warning)\s+TS\d+:/;
|
|
645
|
+
const filtered = [];
|
|
646
|
+
let keep = false;
|
|
647
|
+
for (const line of rawOutput.split("\n")) {
|
|
648
|
+
const m = errorLinePat.exec(line);
|
|
649
|
+
if (m) {
|
|
650
|
+
keep = path.resolve(projectDir, m[1]) === resolved;
|
|
651
|
+
} else if (!/^\s/.test(line)) {
|
|
652
|
+
keep = false;
|
|
653
|
+
}
|
|
654
|
+
if (keep) filtered.push(line);
|
|
655
|
+
}
|
|
656
|
+
return filtered.join("\n");
|
|
657
|
+
}
|
|
631
658
|
async function runTypeCheck(filePath, cwd) {
|
|
632
659
|
const dir = cwd;
|
|
633
660
|
const projectDir = filePath ? findTsconfigDir(filePath) ?? dir : dir;
|
|
@@ -658,21 +685,7 @@ async function runTypeCheck(filePath, cwd) {
|
|
|
658
685
|
}
|
|
659
686
|
const diagnostics = parseTscDiags(rawOutput, filePath, projectDir, engine.source);
|
|
660
687
|
if (filePath) {
|
|
661
|
-
|
|
662
|
-
const errorLinePat = /^(.+?)\((\d+),(\d+)\):\s+(error|warning)\s+TS\d+:/;
|
|
663
|
-
const lines = rawOutput.split("\n");
|
|
664
|
-
const filtered = [];
|
|
665
|
-
let keep = false;
|
|
666
|
-
for (const line of lines) {
|
|
667
|
-
const m = errorLinePat.exec(line);
|
|
668
|
-
if (m) {
|
|
669
|
-
keep = path.resolve(projectDir, m[1]) === resolved;
|
|
670
|
-
} else if (!/^\s/.test(line)) {
|
|
671
|
-
keep = false;
|
|
672
|
-
}
|
|
673
|
-
if (keep) filtered.push(line);
|
|
674
|
-
}
|
|
675
|
-
rawOutput = filtered.join("\n");
|
|
688
|
+
rawOutput = filterTscOutputForFile(rawOutput, filePath, projectDir);
|
|
676
689
|
}
|
|
677
690
|
log2.debug("type-check finished", {
|
|
678
691
|
engine: engine.source,
|
|
@@ -682,6 +695,32 @@ async function runTypeCheck(filePath, cwd) {
|
|
|
682
695
|
});
|
|
683
696
|
return { rawOutput, exitCode, diagnostics, source: engine.source };
|
|
684
697
|
}
|
|
698
|
+
async function runTypeChecksForFiles(files, cwd) {
|
|
699
|
+
const groups = /* @__PURE__ */ new Map();
|
|
700
|
+
for (const file of files) {
|
|
701
|
+
const resolved = path.resolve(file);
|
|
702
|
+
const projectDir = findTsconfigDir(resolved) ?? cwd;
|
|
703
|
+
const group = groups.get(projectDir);
|
|
704
|
+
if (group) group.push(resolved);
|
|
705
|
+
else groups.set(projectDir, [resolved]);
|
|
706
|
+
}
|
|
707
|
+
const results = /* @__PURE__ */ new Map();
|
|
708
|
+
for (const [projectDir, group] of groups) {
|
|
709
|
+
const whole = await runTypeCheck(void 0, projectDir).catch(() => ({
|
|
710
|
+
rawOutput: "",
|
|
711
|
+
exitCode: 0
|
|
712
|
+
}));
|
|
713
|
+
for (const file of group) {
|
|
714
|
+
results.set(file, {
|
|
715
|
+
rawOutput: filterTscOutputForFile(whole.rawOutput, file, projectDir),
|
|
716
|
+
exitCode: whole.exitCode,
|
|
717
|
+
diagnostics: (whole.diagnostics ?? []).filter((d) => d.file === file),
|
|
718
|
+
source: whole.source
|
|
719
|
+
});
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
return results;
|
|
723
|
+
}
|
|
685
724
|
async function runAllChecks(pattern, cwd) {
|
|
686
725
|
log2.debug("runAllChecks", { pattern, cwd });
|
|
687
726
|
const [eslintOutput, tscOutput] = await Promise.all([
|
|
@@ -690,6 +729,18 @@ async function runAllChecks(pattern, cwd) {
|
|
|
690
729
|
]);
|
|
691
730
|
return { eslintOutput, tscOutput };
|
|
692
731
|
}
|
|
732
|
+
async function runAllChecksForFiles(files, cwd) {
|
|
733
|
+
const targets = [...new Set(files.map((file) => path.resolve(file)))];
|
|
734
|
+
const tscByFile = await runTypeChecksForFiles(targets, cwd);
|
|
735
|
+
const results = /* @__PURE__ */ new Map();
|
|
736
|
+
for (const file of targets) {
|
|
737
|
+
results.set(file, {
|
|
738
|
+
eslintOutput: await lintFiles(file, cwd),
|
|
739
|
+
tscOutput: tscByFile.get(file) ?? { rawOutput: "", exitCode: 0 }
|
|
740
|
+
});
|
|
741
|
+
}
|
|
742
|
+
return results;
|
|
743
|
+
}
|
|
693
744
|
async function runProjectDiagnostics(workspace) {
|
|
694
745
|
const tscDirs = fs.existsSync(path.join(workspace, "tsconfig.json")) ? [workspace] : findAllTsconfigDirs(workspace);
|
|
695
746
|
log2.debug("Tsc dirs to check", { count: tscDirs.length, dirs: tscDirs });
|
|
@@ -711,18 +762,36 @@ function tscSectionTitle(tscOutput) {
|
|
|
711
762
|
function lintSectionTitle(lintOutput) {
|
|
712
763
|
return lintOutput.engines?.length ? lintOutput.engines.join(" + ") : "ESLint";
|
|
713
764
|
}
|
|
714
|
-
function
|
|
765
|
+
function omittedFindingsHint(omitted) {
|
|
766
|
+
return `\u2026\u8FD8\u6709 ${omitted} \u6761\uFF0C\u5B8C\u6574\u7ED3\u679C\u8BF7\u8C03\u7528 run_diagnostics`;
|
|
767
|
+
}
|
|
768
|
+
function boundFindings(text, maxFindings) {
|
|
769
|
+
if (!maxFindings || !text) return text;
|
|
770
|
+
const lines = text.split("\n").filter((line) => line.trim() !== "");
|
|
771
|
+
if (lines.length <= maxFindings) return text;
|
|
772
|
+
return [...lines.slice(0, maxFindings), omittedFindingsHint(lines.length - maxFindings)].join(
|
|
773
|
+
"\n"
|
|
774
|
+
);
|
|
775
|
+
}
|
|
776
|
+
function formatDiagnosticsSections(title, eslintOutput, tscOutput, options = {}) {
|
|
777
|
+
const lintLines = boundFindings(eslintOutput.text, options.maxFindingsPerSection);
|
|
778
|
+
const tscLines = boundFindings(tscOutput.rawOutput.trim(), options.maxFindingsPerSection);
|
|
715
779
|
const parts = [];
|
|
716
|
-
|
|
780
|
+
if (!options.onlyFindings || lintLines) {
|
|
781
|
+
parts.push(`## ${lintSectionTitle(eslintOutput)}
|
|
717
782
|
|
|
718
|
-
` + (
|
|
719
|
-
|
|
720
|
-
|
|
783
|
+
` + (lintLines || "\u6CA1\u6709\u53D1\u73B0\u95EE\u9898"));
|
|
784
|
+
}
|
|
785
|
+
if (!options.onlyFindings || tscLines) {
|
|
786
|
+
parts.push(`## ${tscSectionTitle(tscOutput)}
|
|
721
787
|
|
|
722
788
|
` + (tscLines || "\u6CA1\u6709\u53D1\u73B0\u7C7B\u578B\u9519\u8BEF"));
|
|
723
|
-
|
|
789
|
+
}
|
|
790
|
+
if (parts.length === 0) return "";
|
|
791
|
+
const body = parts.join("\n\n");
|
|
792
|
+
return title ? `${title}
|
|
724
793
|
|
|
725
|
-
`
|
|
794
|
+
${body}` : body;
|
|
726
795
|
}
|
|
727
796
|
|
|
728
797
|
// ../../core/es/common/utils.mjs
|
|
@@ -971,46 +1040,66 @@ function buildNodeContext(e) {
|
|
|
971
1040
|
if (e.previewPageUrl) lines.push(`\u7528\u6237\u9009\u4E2D\u8282\u70B9\u65F6\u7684\u9875\u9762 URL\uFF1A${e.previewPageUrl}`);
|
|
972
1041
|
return lines.join("\n");
|
|
973
1042
|
}
|
|
974
|
-
function buildPluginMessage(text) {
|
|
1043
|
+
function buildPluginMessage(text, notice) {
|
|
975
1044
|
return {
|
|
976
1045
|
role: "user",
|
|
977
1046
|
id: randomUUID(),
|
|
978
1047
|
content: [{ type: "text", text }],
|
|
979
|
-
source: { kind: "plugin", plugin: name }
|
|
1048
|
+
source: { kind: "plugin", plugin: name, ...notice }
|
|
980
1049
|
};
|
|
981
1050
|
}
|
|
982
|
-
|
|
1051
|
+
var DIAGNOSTICS_MESSAGE_MAX_CHARS = 4e3;
|
|
1052
|
+
var MAX_FINDINGS_PER_SECTION = 3;
|
|
1053
|
+
function editTarget(exec) {
|
|
1054
|
+
const rawArgs = exec.arguments;
|
|
1055
|
+
const filePath = typeof rawArgs?.file_path === "string" ? rawArgs.file_path : rawArgs?.filePath;
|
|
1056
|
+
return typeof filePath === "string" && filePath ? filePath : void 0;
|
|
1057
|
+
}
|
|
1058
|
+
function registerPendingEdit(pending, exec, result, decision, cwd) {
|
|
983
1059
|
if (!MUTATING_TOOLS.has(exec.name)) return;
|
|
984
1060
|
if (result.isError) return;
|
|
985
1061
|
if (decision.kind !== "accept") return;
|
|
986
|
-
const
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
if (!
|
|
990
|
-
let files =
|
|
1062
|
+
const filePath = editTarget(exec);
|
|
1063
|
+
if (!filePath || !isJsFile(filePath)) return;
|
|
1064
|
+
const { agent } = exec;
|
|
1065
|
+
if (!agent) return;
|
|
1066
|
+
let files = pending.get(agent);
|
|
991
1067
|
if (!files) {
|
|
992
1068
|
files = /* @__PURE__ */ new Set();
|
|
993
|
-
|
|
1069
|
+
pending.set(agent, files);
|
|
994
1070
|
}
|
|
995
1071
|
files.add(path2.resolve(cwd, filePath));
|
|
996
1072
|
}
|
|
997
|
-
|
|
1073
|
+
function truncateDiagnostics(text) {
|
|
1074
|
+
if (text.length <= DIAGNOSTICS_MESSAGE_MAX_CHARS) return text;
|
|
1075
|
+
return `${text.slice(0, DIAGNOSTICS_MESSAGE_MAX_CHARS)}
|
|
1076
|
+
|
|
1077
|
+
\u2026\uFF08\u8BCA\u65AD\u8F93\u51FA\u8FC7\u957F\uFF0C\u5DF2\u622A\u65AD\uFF1B\u53EF\u8C03\u7528 run_diagnostics \u67E5\u770B\u5B8C\u6574\u7ED3\u679C\uFF09`;
|
|
1078
|
+
}
|
|
1079
|
+
async function collectPendingDiagnostics(pending, cwd) {
|
|
1080
|
+
const files = [...pending];
|
|
1081
|
+
const checks = await runAllChecksForFiles(files, cwd).catch(
|
|
1082
|
+
() => /* @__PURE__ */ new Map()
|
|
1083
|
+
);
|
|
1084
|
+
const empty = {
|
|
1085
|
+
eslintOutput: {},
|
|
1086
|
+
tscOutput: { rawOutput: "", exitCode: 0 }
|
|
1087
|
+
};
|
|
998
1088
|
const blocks = [];
|
|
999
1089
|
for (const file of files) {
|
|
1000
|
-
const { eslintOutput, tscOutput } =
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
if (!eslintOutput.text && !tscOutput.rawOutput.trim()) continue;
|
|
1007
|
-
blocks.push(
|
|
1008
|
-
formatDiagnosticsSections(`### ${path2.relative(cwd, file)}`, eslintOutput, tscOutput)
|
|
1090
|
+
const { eslintOutput, tscOutput } = checks.get(file) ?? empty;
|
|
1091
|
+
const section = formatDiagnosticsSections(
|
|
1092
|
+
`### ${path2.relative(cwd, file)}`,
|
|
1093
|
+
eslintOutput,
|
|
1094
|
+
tscOutput,
|
|
1095
|
+
{ onlyFindings: true, maxFindingsPerSection: MAX_FINDINGS_PER_SECTION }
|
|
1009
1096
|
);
|
|
1097
|
+
if (!section) continue;
|
|
1098
|
+
blocks.push(section);
|
|
1010
1099
|
}
|
|
1011
|
-
return blocks.length > 0 ? `\u81EA\u52A8\u8BCA\u65AD\
|
|
1100
|
+
return blocks.length > 0 ? truncateDiagnostics(`\u81EA\u52A8\u8BCA\u65AD\uFF08\u7F16\u8F91\u540E\uFF09\uFF1A
|
|
1012
1101
|
|
|
1013
|
-
${blocks.join("\n\n")}` : "";
|
|
1102
|
+
${blocks.join("\n\n")}`) : "";
|
|
1014
1103
|
}
|
|
1015
1104
|
function toDiagnosticEntries(items) {
|
|
1016
1105
|
return items.map((d) => ({
|
|
@@ -1189,64 +1278,39 @@ function apply(ctx, config = {}) {
|
|
|
1189
1278
|
}
|
|
1190
1279
|
};
|
|
1191
1280
|
tools.register(diagnosticsTool);
|
|
1192
|
-
const
|
|
1281
|
+
const pendingEdits = /* @__PURE__ */ new WeakMap();
|
|
1193
1282
|
ctx.on(
|
|
1194
1283
|
"tools/post-execute",
|
|
1195
1284
|
async (exec, result, next) => {
|
|
1196
1285
|
const decision = await next();
|
|
1197
1286
|
if (!autoDiagnose) return decision;
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
buildPluginMessage(ptcDiagText)
|
|
1214
|
-
]
|
|
1215
|
-
};
|
|
1216
|
-
}
|
|
1217
|
-
if (!MUTATING_TOOLS.has(exec.name)) return decision;
|
|
1218
|
-
if (result.isError) return decision;
|
|
1219
|
-
if (decision.kind !== "accept") return decision;
|
|
1220
|
-
const rawArgs = exec.arguments;
|
|
1221
|
-
const filePath = typeof rawArgs?.file_path === "string" ? rawArgs.file_path : rawArgs?.filePath;
|
|
1222
|
-
if (typeof filePath !== "string" || !filePath) return decision;
|
|
1223
|
-
if (!isJsFile(filePath)) return decision;
|
|
1224
|
-
const { eslintOutput, tscOutput } = await runAllChecks(
|
|
1225
|
-
path2.resolve(cwd, filePath),
|
|
1226
|
-
cwd
|
|
1227
|
-
).catch(() => ({
|
|
1228
|
-
eslintOutput: {},
|
|
1229
|
-
tscOutput: { rawOutput: "", exitCode: 0 }
|
|
1230
|
-
}));
|
|
1231
|
-
const parts = [];
|
|
1232
|
-
if (tscOutput.rawOutput.trim())
|
|
1233
|
-
parts.push(`## ${tscSectionTitle(tscOutput)}
|
|
1234
|
-
|
|
1235
|
-
` + tscOutput.rawOutput.trim());
|
|
1236
|
-
if (eslintOutput.text)
|
|
1237
|
-
parts.push(`## ${lintSectionTitle(eslintOutput)}
|
|
1238
|
-
|
|
1239
|
-
` + eslintOutput.text);
|
|
1240
|
-
const diagText = parts.join("\n\n");
|
|
1241
|
-
if (!diagText) return decision;
|
|
1242
|
-
const existing = decision.kind === "accept" && decision.content || result.content;
|
|
1287
|
+
registerPendingEdit(pendingEdits, exec, result, decision, cwd);
|
|
1288
|
+
return decision;
|
|
1289
|
+
}
|
|
1290
|
+
);
|
|
1291
|
+
ctx.on(
|
|
1292
|
+
"agent/pre-step",
|
|
1293
|
+
async ({ agent }, next) => {
|
|
1294
|
+
const decision = await next();
|
|
1295
|
+
if (!autoDiagnose) return decision;
|
|
1296
|
+
const files = pendingEdits.get(agent);
|
|
1297
|
+
if (!files || files.size === 0) return decision;
|
|
1298
|
+
pendingEdits.delete(agent);
|
|
1299
|
+
if (decision.kind === "reject") return decision;
|
|
1300
|
+
const text = await collectPendingDiagnostics(files, cwd);
|
|
1301
|
+
if (!text) return decision;
|
|
1243
1302
|
return {
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1303
|
+
...decision,
|
|
1304
|
+
messages: [
|
|
1305
|
+
...decision.messages,
|
|
1306
|
+
buildPluginMessage(text, {
|
|
1307
|
+
form: "notice",
|
|
1308
|
+
summary: `\u7F16\u8F91\u540E\u81EA\u52A8\u8BCA\u65AD\uFF1A${files.size} \u4E2A\u6587\u4EF6`
|
|
1309
|
+
})
|
|
1310
|
+
]
|
|
1248
1311
|
};
|
|
1249
|
-
}
|
|
1312
|
+
},
|
|
1313
|
+
{ prepend: true }
|
|
1250
1314
|
);
|
|
1251
1315
|
}
|
|
1252
1316
|
if (vitePort > 0) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aipanel/dsh-plugin",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AIPanel for DeepSeek Harness (dsh):注入审查工具 run_diagnostics、编辑后自动诊断。",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"vue-tsc": "^3.3.9"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"@aipanel/core": "1.
|
|
19
|
+
"@aipanel/core": "1.3.1",
|
|
20
20
|
"@deepseek-ai/cordis": "^4.0.2",
|
|
21
21
|
"@deepseek-ai/dsh-agent": "^0.1.6-alpha.2",
|
|
22
22
|
"@deepseek-ai/dsh-llm": "^0.1.6-alpha.2",
|