@aipanel/dsh-plugin 1.3.2 → 1.3.4
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 +170 -69
- package/package.json +12 -12
package/dist/index.js
CHANGED
|
@@ -329,23 +329,48 @@ var DIAGNOSTICS_TOOL_DESCRIPTION = [
|
|
|
329
329
|
"- \u6392\u67E5\u7F16\u8F91\u5668\u672A\u663E\u793A\u4F46\u5B9E\u9645\u5B58\u5728\u7684\u7C7B\u578B\u95EE\u9898",
|
|
330
330
|
"- \u4E0D\u4F20\u53C2\u6570\u53EF\u5168\u91CF\u8BCA\u65AD\u6574\u4E2A\u9879\u76EE"
|
|
331
331
|
].join("\n");
|
|
332
|
-
|
|
332
|
+
function cachedResolve(cache, key, resolve) {
|
|
333
|
+
const hit = cache.get(key);
|
|
334
|
+
if (hit !== void 0) return hit;
|
|
335
|
+
const value = resolve();
|
|
336
|
+
cache.set(key, value);
|
|
337
|
+
return value;
|
|
338
|
+
}
|
|
339
|
+
var _packageBinCache = /* @__PURE__ */ new Map();
|
|
340
|
+
function resolvePackageBin(basePkgJson, pkgName, binName) {
|
|
341
|
+
return cachedResolve(_packageBinCache, `${basePkgJson}\0${pkgName}`, () => {
|
|
342
|
+
try {
|
|
343
|
+
const req = createRequire(basePkgJson);
|
|
344
|
+
const pkgJsonPath = req.resolve(`${pkgName}/package.json`);
|
|
345
|
+
const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, "utf8"));
|
|
346
|
+
const binRel = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.[binName];
|
|
347
|
+
return binRel ? path.join(path.dirname(pkgJsonPath), binRel) : null;
|
|
348
|
+
} catch {
|
|
349
|
+
return null;
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
var _eslintClassByBase = /* @__PURE__ */ new Map();
|
|
333
354
|
function loadESLint(workspace) {
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
355
|
+
const basePkgJson = path.join(workspace, "package.json");
|
|
356
|
+
return cachedResolve(_eslintClassByBase, basePkgJson, () => {
|
|
357
|
+
log2.debug("Loading eslint", { workspace });
|
|
358
|
+
try {
|
|
359
|
+
const req = createRequire(basePkgJson);
|
|
360
|
+
const eslintModule = req("eslint");
|
|
361
|
+
const eslintClass = eslintModule.ESLint ?? eslintModule.FlatESLint ?? null;
|
|
362
|
+
log2.debug("eslint loaded", { hasClass: !!eslintClass });
|
|
363
|
+
return eslintClass;
|
|
364
|
+
} catch (e) {
|
|
365
|
+
log2.warn("eslint not found", { error: e.message });
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
});
|
|
344
369
|
}
|
|
345
370
|
async function lintFiles(pattern, cwd, warnLimit = 5) {
|
|
346
|
-
loadESLint(cwd);
|
|
371
|
+
const eslintClass = loadESLint(cwd);
|
|
347
372
|
const [eslintOutput, oxlintOutput] = await Promise.all([
|
|
348
|
-
|
|
373
|
+
eslintClass ? runEslintFiles(eslintClass, pattern, cwd, warnLimit) : Promise.resolve(null),
|
|
349
374
|
runOxlintFiles(pattern, cwd, warnLimit)
|
|
350
375
|
]);
|
|
351
376
|
const engines = [];
|
|
@@ -405,9 +430,9 @@ function formatLintMessages(messages, engine, warnLimit) {
|
|
|
405
430
|
engines: [engine.label]
|
|
406
431
|
};
|
|
407
432
|
}
|
|
408
|
-
async function runEslintFiles(pattern, cwd, warnLimit) {
|
|
433
|
+
async function runEslintFiles(eslintClass, pattern, cwd, warnLimit) {
|
|
409
434
|
try {
|
|
410
|
-
const eslint = new
|
|
435
|
+
const eslint = new eslintClass({ cwd });
|
|
411
436
|
const results = await eslint.lintFiles(pattern);
|
|
412
437
|
const messages = results.flatMap(
|
|
413
438
|
(r) => (r.messages ?? []).map((m) => ({ ...m, filePath: r.filePath }))
|
|
@@ -427,19 +452,8 @@ async function runEslintFiles(pattern, cwd, warnLimit) {
|
|
|
427
452
|
};
|
|
428
453
|
}
|
|
429
454
|
}
|
|
430
|
-
var _oxlintBin;
|
|
431
455
|
function resolveOxlintBin(workspace) {
|
|
432
|
-
|
|
433
|
-
try {
|
|
434
|
-
const req = createRequire(path.join(workspace, "package.json"));
|
|
435
|
-
const pkgJsonPath = req.resolve("oxlint/package.json");
|
|
436
|
-
const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, "utf8"));
|
|
437
|
-
const binRel = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.oxlint;
|
|
438
|
-
_oxlintBin = binRel ? path.join(path.dirname(pkgJsonPath), binRel) : null;
|
|
439
|
-
} catch {
|
|
440
|
-
_oxlintBin = null;
|
|
441
|
-
}
|
|
442
|
-
return _oxlintBin;
|
|
456
|
+
return resolvePackageBin(path.join(workspace, "package.json"), "oxlint", "oxlint");
|
|
443
457
|
}
|
|
444
458
|
function oxlintRuleName(code) {
|
|
445
459
|
if (!code) return null;
|
|
@@ -516,18 +530,9 @@ async function runOxlintFiles(pattern, cwd, warnLimit) {
|
|
|
516
530
|
};
|
|
517
531
|
}
|
|
518
532
|
}
|
|
519
|
-
var
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
try {
|
|
523
|
-
const req = createRequire(import.meta.url);
|
|
524
|
-
_vueTscBin = req.resolve("vue-tsc/bin/vue-tsc.js");
|
|
525
|
-
} catch {
|
|
526
|
-
_vueTscBin = null;
|
|
527
|
-
}
|
|
528
|
-
return _vueTscBin;
|
|
529
|
-
}
|
|
530
|
-
var _tscBinByPkgDir = /* @__PURE__ */ new Map();
|
|
533
|
+
var BUNDLED_ENGINE_KEY = "<bundled>";
|
|
534
|
+
var _engineCache = /* @__PURE__ */ new Map();
|
|
535
|
+
var _tsVersionCache = /* @__PURE__ */ new Map();
|
|
531
536
|
function nearestPackageJsonDir(startDir) {
|
|
532
537
|
let dir = path.resolve(startDir);
|
|
533
538
|
while (true) {
|
|
@@ -546,26 +551,53 @@ function isVuePackage(pkgDir) {
|
|
|
546
551
|
return false;
|
|
547
552
|
}
|
|
548
553
|
}
|
|
549
|
-
function
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
return
|
|
554
|
+
function readPackageMeta(pkgJsonPath) {
|
|
555
|
+
try {
|
|
556
|
+
return JSON.parse(fs.readFileSync(pkgJsonPath, "utf8"));
|
|
557
|
+
} catch {
|
|
558
|
+
return null;
|
|
554
559
|
}
|
|
555
|
-
|
|
556
|
-
|
|
560
|
+
}
|
|
561
|
+
function resolveEngineTsVersion(bin) {
|
|
562
|
+
const pkgDir = nearestPackageJsonDir(path.dirname(bin));
|
|
563
|
+
if (!pkgDir) return null;
|
|
564
|
+
return cachedResolve(_tsVersionCache, pkgDir, () => {
|
|
565
|
+
const own = readPackageMeta(path.join(pkgDir, "package.json"));
|
|
566
|
+
if (own?.name === "typescript" && own.version) return own.version;
|
|
557
567
|
try {
|
|
558
568
|
const req = createRequire(path.join(pkgDir, "package.json"));
|
|
559
|
-
|
|
569
|
+
return readPackageMeta(req.resolve("typescript/package.json"))?.version ?? null;
|
|
560
570
|
} catch {
|
|
561
|
-
|
|
571
|
+
return null;
|
|
562
572
|
}
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
function toEngine(bin, source, origin) {
|
|
576
|
+
return bin ? { bin, source, origin, tsVersion: resolveEngineTsVersion(bin) } : null;
|
|
577
|
+
}
|
|
578
|
+
function resolveWorkspaceEngine(pkgDir, kind) {
|
|
579
|
+
const basePkgJson = path.join(pkgDir, "package.json");
|
|
580
|
+
return kind === "tsc" ? toEngine(resolvePackageBin(basePkgJson, "typescript", "tsc"), "tsc", "workspace") : toEngine(resolvePackageBin(basePkgJson, "vue-tsc", "vue-tsc"), "vue-tsc", "workspace");
|
|
581
|
+
}
|
|
582
|
+
function resolveBundledVueTscEngine() {
|
|
583
|
+
return toEngine(resolvePackageBin(import.meta.url, "vue-tsc", "vue-tsc"), "vue-tsc", "bundled");
|
|
584
|
+
}
|
|
585
|
+
function resolveTypeCheckEngine(projectDir) {
|
|
586
|
+
const pkgDir = nearestPackageJsonDir(projectDir);
|
|
587
|
+
return cachedResolve(_engineCache, pkgDir ?? BUNDLED_ENGINE_KEY, () => {
|
|
588
|
+
if (!pkgDir) return resolveBundledVueTscEngine();
|
|
589
|
+
const candidates = isVuePackage(pkgDir) ? [resolveWorkspaceEngine(pkgDir, "vue-tsc")] : [resolveWorkspaceEngine(pkgDir, "tsc"), resolveWorkspaceEngine(pkgDir, "vue-tsc")];
|
|
590
|
+
for (const engine of candidates) {
|
|
591
|
+
if (engine) return engine;
|
|
592
|
+
}
|
|
593
|
+
return resolveBundledVueTscEngine();
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
var BUILD_NO_EMIT_MIN_TS = { major: 5, minor: 6 };
|
|
597
|
+
function supportsBuildNoEmit(tsVersion) {
|
|
598
|
+
if (!tsVersion) return false;
|
|
599
|
+
const [major, minor] = tsVersion.split(".").map((part) => Number.parseInt(part, 10));
|
|
600
|
+
return major > BUILD_NO_EMIT_MIN_TS.major || major === BUILD_NO_EMIT_MIN_TS.major && minor >= BUILD_NO_EMIT_MIN_TS.minor;
|
|
569
601
|
}
|
|
570
602
|
function findTsconfigDir(filePath) {
|
|
571
603
|
const resolved = path.resolve(filePath);
|
|
@@ -655,6 +687,77 @@ function filterTscOutputForFile(rawOutput, filePath, projectDir) {
|
|
|
655
687
|
}
|
|
656
688
|
return filtered.join("\n");
|
|
657
689
|
}
|
|
690
|
+
async function readResolvedTsconfig(engine, configPath, projectDir) {
|
|
691
|
+
const result = await execa(
|
|
692
|
+
"node",
|
|
693
|
+
[
|
|
694
|
+
engine.bin,
|
|
695
|
+
"-p",
|
|
696
|
+
projectRelativeConfig(projectDir, configPath),
|
|
697
|
+
"--showConfig",
|
|
698
|
+
"--pretty",
|
|
699
|
+
"false"
|
|
700
|
+
],
|
|
701
|
+
{ cwd: projectDir, timeout: 3e4, maxBuffer: 10 * 1024 * 1024, reject: false }
|
|
702
|
+
).catch(() => null);
|
|
703
|
+
if (!result || result.timedOut || result.isTerminated || result.isMaxBuffer) return null;
|
|
704
|
+
const stdout = result.stdout ?? "";
|
|
705
|
+
const start = stdout.indexOf("{");
|
|
706
|
+
const end = stdout.lastIndexOf("}");
|
|
707
|
+
if (start < 0 || end <= start) return null;
|
|
708
|
+
try {
|
|
709
|
+
return JSON.parse(stdout.slice(start, end + 1));
|
|
710
|
+
} catch {
|
|
711
|
+
return null;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
async function resolveProjectConfigs(engine, projectDir) {
|
|
715
|
+
const configs = [];
|
|
716
|
+
const visited = /* @__PURE__ */ new Set();
|
|
717
|
+
const visit = async (configPath) => {
|
|
718
|
+
const resolved = path.resolve(configPath);
|
|
719
|
+
if (visited.has(resolved)) return;
|
|
720
|
+
visited.add(resolved);
|
|
721
|
+
const config = await readResolvedTsconfig(engine, resolved, projectDir);
|
|
722
|
+
const hasProgram = !config || (config.files?.length ?? 0) > 0 || (config.include?.length ?? 0) > 0;
|
|
723
|
+
if (hasProgram) configs.push(resolved);
|
|
724
|
+
for (const ref of config?.references ?? []) {
|
|
725
|
+
if (ref.path) await visit(path.resolve(path.dirname(resolved), ref.path));
|
|
726
|
+
}
|
|
727
|
+
};
|
|
728
|
+
const rootConfig = path.join(projectDir, "tsconfig.json");
|
|
729
|
+
await visit(fs.existsSync(rootConfig) ? rootConfig : projectDir);
|
|
730
|
+
return configs;
|
|
731
|
+
}
|
|
732
|
+
function projectRelativeConfig(projectDir, configPath) {
|
|
733
|
+
return path.relative(projectDir, configPath) || ".";
|
|
734
|
+
}
|
|
735
|
+
async function typeCheckArgGroups(engine, projectDir) {
|
|
736
|
+
const pretty = ["--pretty", "false"];
|
|
737
|
+
if (supportsBuildNoEmit(engine.tsVersion)) return [["--build", "--noEmit", ...pretty]];
|
|
738
|
+
const configs = await resolveProjectConfigs(engine, projectDir);
|
|
739
|
+
return configs.map((config) => [
|
|
740
|
+
"-p",
|
|
741
|
+
projectRelativeConfig(projectDir, config),
|
|
742
|
+
"--noEmit",
|
|
743
|
+
...pretty
|
|
744
|
+
]);
|
|
745
|
+
}
|
|
746
|
+
async function runTypeCheckCli(engine, args, cwd, timeout, maxBuffer) {
|
|
747
|
+
const result = await execa("node", [engine.bin, ...args], {
|
|
748
|
+
cwd,
|
|
749
|
+
timeout,
|
|
750
|
+
maxBuffer,
|
|
751
|
+
reject: false
|
|
752
|
+
});
|
|
753
|
+
let rawOutput = result.stdout + result.stderr;
|
|
754
|
+
const killed = result.timedOut || result.isTerminated || result.isMaxBuffer;
|
|
755
|
+
const exitCode = typeof result.exitCode === "number" ? result.exitCode : killed ? 1 : 0;
|
|
756
|
+
if (killed && !rawOutput) {
|
|
757
|
+
rawOutput = `${engine.source} \u68C0\u67E5\u8D85\u65F6\uFF0C\u8BF7\u5C1D\u8BD5\u7F29\u5C0F\u68C0\u67E5\u8303\u56F4\u6216\u4F18\u5316\u9879\u76EE\u914D\u7F6E\u3002`;
|
|
758
|
+
}
|
|
759
|
+
return { rawOutput, exitCode };
|
|
760
|
+
}
|
|
658
761
|
async function runTypeCheck(filePath, cwd) {
|
|
659
762
|
const dir = cwd;
|
|
660
763
|
const projectDir = filePath ? findTsconfigDir(filePath) ?? dir : dir;
|
|
@@ -664,31 +767,27 @@ async function runTypeCheck(filePath, cwd) {
|
|
|
664
767
|
projectDir,
|
|
665
768
|
processCwd: process.cwd()
|
|
666
769
|
});
|
|
667
|
-
const engine =
|
|
770
|
+
const engine = resolveTypeCheckEngine(projectDir);
|
|
668
771
|
if (!engine) {
|
|
669
772
|
log2.warn("type-check bin not found", { projectDir });
|
|
670
773
|
return { rawOutput: "", exitCode: 0 };
|
|
671
774
|
}
|
|
672
775
|
const timeout = filePath ? 6e4 : 12e4;
|
|
673
776
|
const maxBuffer = filePath ? 10 * 1024 * 1024 : 50 * 1024 * 1024;
|
|
674
|
-
const
|
|
675
|
-
|
|
676
|
-
timeout,
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
let rawOutput = result.stdout + result.stderr;
|
|
681
|
-
const killed = result.timedOut || result.isTerminated || result.isMaxBuffer;
|
|
682
|
-
const exitCode = typeof result.exitCode === "number" ? result.exitCode : killed ? 1 : 0;
|
|
683
|
-
if (killed && !rawOutput) {
|
|
684
|
-
rawOutput = `${engine.source} \u68C0\u67E5\u8D85\u65F6\uFF0C\u8BF7\u5C1D\u8BD5\u7F29\u5C0F\u68C0\u67E5\u8303\u56F4\u6216\u4F18\u5316\u9879\u76EE\u914D\u7F6E\u3002`;
|
|
685
|
-
}
|
|
777
|
+
const argGroups = await typeCheckArgGroups(engine, projectDir);
|
|
778
|
+
const results = await Promise.all(
|
|
779
|
+
argGroups.map((args) => runTypeCheckCli(engine, args, projectDir, timeout, maxBuffer))
|
|
780
|
+
);
|
|
781
|
+
let rawOutput = results.map((result) => result.rawOutput).filter(Boolean).join("\n");
|
|
782
|
+
const exitCode = results.reduce((max, result) => Math.max(max, result.exitCode), 0);
|
|
686
783
|
const diagnostics = parseTscDiags(rawOutput, filePath, projectDir, engine.source);
|
|
687
784
|
if (filePath) {
|
|
688
785
|
rawOutput = filterTscOutputForFile(rawOutput, filePath, projectDir);
|
|
689
786
|
}
|
|
690
787
|
log2.debug("type-check finished", {
|
|
691
788
|
engine: engine.source,
|
|
789
|
+
engineOrigin: engine.origin,
|
|
790
|
+
tsVersion: engine.tsVersion,
|
|
692
791
|
filePath: filePath || "(all)",
|
|
693
792
|
exitCode,
|
|
694
793
|
outputLength: rawOutput.length
|
|
@@ -1025,7 +1124,8 @@ function setupEventRelay(ctx, config) {
|
|
|
1025
1124
|
}
|
|
1026
1125
|
|
|
1027
1126
|
// dsh-plugin/src/index.ts
|
|
1028
|
-
var
|
|
1127
|
+
var SOURCE_KIND = "aipanel";
|
|
1128
|
+
var name = SOURCE_KIND;
|
|
1029
1129
|
var inject = ["tools"];
|
|
1030
1130
|
var log4 = createNodeLogger("DshPlugin");
|
|
1031
1131
|
function buildNodeContext(e) {
|
|
@@ -1041,11 +1141,12 @@ function buildNodeContext(e) {
|
|
|
1041
1141
|
return lines.join("\n");
|
|
1042
1142
|
}
|
|
1043
1143
|
function buildPluginMessage(text, notice) {
|
|
1144
|
+
const source = notice ? { kind: SOURCE_KIND, form: "notice", summary: notice.summary } : { kind: SOURCE_KIND };
|
|
1044
1145
|
return {
|
|
1045
1146
|
role: "user",
|
|
1046
1147
|
id: randomUUID(),
|
|
1047
1148
|
content: [{ type: "text", text }],
|
|
1048
|
-
source
|
|
1149
|
+
source
|
|
1049
1150
|
};
|
|
1050
1151
|
}
|
|
1051
1152
|
var DIAGNOSTICS_MESSAGE_MAX_CHARS = 4e3;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aipanel/dsh-plugin",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AIPanel for DeepSeek Harness (dsh):注入审查工具 run_diagnostics、编辑后自动诊断。",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -16,17 +16,17 @@
|
|
|
16
16
|
"vue-tsc": "^3.3.9"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"@aipanel/core": "1.3.
|
|
20
|
-
"@deepseek-ai/cordis": "
|
|
21
|
-
"@deepseek-ai/dsh-agent": "^0.1.
|
|
22
|
-
"@deepseek-ai/dsh-llm": "^0.1.
|
|
23
|
-
"@deepseek-ai/dsh-session": "^0.1.
|
|
24
|
-
"@deepseek-ai/dsh-session-title": "^0.1.
|
|
25
|
-
"@deepseek-ai/dsh-settings": "^0.1.
|
|
26
|
-
"@deepseek-ai/dsh-tools": "^0.1.
|
|
27
|
-
"@deepseek-ai/dsh-user-approval": "^0.1.
|
|
28
|
-
"@deepseek-ai/dsh-user-questions": "^0.1.
|
|
29
|
-
"@deepseek-ai/dsh-util-values": "^0.1.
|
|
19
|
+
"@aipanel/core": "1.3.4",
|
|
20
|
+
"@deepseek-ai/cordis": "~4.0.4",
|
|
21
|
+
"@deepseek-ai/dsh-agent": "^0.1.7-alpha.2",
|
|
22
|
+
"@deepseek-ai/dsh-llm": "^0.1.7-alpha.2",
|
|
23
|
+
"@deepseek-ai/dsh-session": "^0.1.7-alpha.2",
|
|
24
|
+
"@deepseek-ai/dsh-session-title": "^0.1.7-alpha.2",
|
|
25
|
+
"@deepseek-ai/dsh-settings": "^0.1.7-alpha.2",
|
|
26
|
+
"@deepseek-ai/dsh-tools": "^0.1.7-alpha.2",
|
|
27
|
+
"@deepseek-ai/dsh-user-approval": "^0.1.7-alpha.2",
|
|
28
|
+
"@deepseek-ai/dsh-user-questions": "^0.1.7-alpha.2",
|
|
29
|
+
"@deepseek-ai/dsh-util-values": "^0.1.7-alpha.2",
|
|
30
30
|
"esbuild": "^0.25.0"
|
|
31
31
|
},
|
|
32
32
|
"scripts": {
|