@aipanel/dsh-plugin 1.2.9 → 1.2.11
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 +168 -31
- package/package.json +6 -4
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 MUTATING_TOOLS = /* @__PURE__ */ new Set(["write", "edit", "apply_patch"]);
|
|
30
|
+
var OPENCODE_ENV = {
|
|
31
|
+
CONFIG_DIR: "OPENCODE_CONFIG_DIR",
|
|
32
|
+
CONTEXT_API_URL: "OPENCODE_CONTEXT_API_URL",
|
|
33
|
+
VITE_LOGS_API_URL: "OPENCODE_VITE_LOGS_API_URL",
|
|
34
|
+
LOG_FILES_JSON: "OPENCODE_LOG_FILES_JSON",
|
|
35
|
+
VERBOSE: "OPENCODE_VERBOSE",
|
|
36
|
+
ENABLE_LINT: "OPENCODE_ENABLE_LINT",
|
|
37
|
+
VUE_DEVTOOLS_API_URL: "OPENCODE_VUE_DEVTOOLS_API_URL",
|
|
38
|
+
WORKSPACE: "OPENCODE_WORKSPACE"
|
|
39
|
+
};
|
|
29
40
|
|
|
30
41
|
// ../../core/es/common/logger-core.mjs
|
|
31
42
|
var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
|
|
@@ -36,6 +47,28 @@ var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
|
|
|
36
47
|
LogLevel2[LogLevel2["NONE"] = 4] = "NONE";
|
|
37
48
|
return LogLevel2;
|
|
38
49
|
})(LogLevel || {});
|
|
50
|
+
var LEVEL_NAMES = {
|
|
51
|
+
[
|
|
52
|
+
0
|
|
53
|
+
/* DEBUG */
|
|
54
|
+
]: "DEBUG",
|
|
55
|
+
[
|
|
56
|
+
1
|
|
57
|
+
/* INFO */
|
|
58
|
+
]: "INFO",
|
|
59
|
+
[
|
|
60
|
+
2
|
|
61
|
+
/* WARN */
|
|
62
|
+
]: "WARN",
|
|
63
|
+
[
|
|
64
|
+
3
|
|
65
|
+
/* ERROR */
|
|
66
|
+
]: "ERROR",
|
|
67
|
+
[
|
|
68
|
+
4
|
|
69
|
+
/* NONE */
|
|
70
|
+
]: "NONE"
|
|
71
|
+
};
|
|
39
72
|
var globalConfig = {
|
|
40
73
|
verbose: false,
|
|
41
74
|
level: 1,
|
|
@@ -47,6 +80,14 @@ var globalConfig = {
|
|
|
47
80
|
function getConfig() {
|
|
48
81
|
return globalConfig;
|
|
49
82
|
}
|
|
83
|
+
function getTimestamp() {
|
|
84
|
+
const now = /* @__PURE__ */ new Date();
|
|
85
|
+
const hours = String(now.getHours()).padStart(2, "0");
|
|
86
|
+
const minutes = String(now.getMinutes()).padStart(2, "0");
|
|
87
|
+
const seconds = String(now.getSeconds()).padStart(2, "0");
|
|
88
|
+
const ms = String(now.getMilliseconds()).padStart(3, "0");
|
|
89
|
+
return `${hours}:${minutes}:${seconds}.${ms}`;
|
|
90
|
+
}
|
|
50
91
|
function formatValue(value, depth = 0) {
|
|
51
92
|
if (depth > 3) return "...";
|
|
52
93
|
if (value === null) return "null";
|
|
@@ -119,21 +160,6 @@ var LEVEL_COLORS = {
|
|
|
119
160
|
[LogLevel.ERROR]: COLORS.red,
|
|
120
161
|
[LogLevel.NONE]: COLORS.reset
|
|
121
162
|
};
|
|
122
|
-
var LEVEL_NAMES = {
|
|
123
|
-
[LogLevel.DEBUG]: "DEBUG",
|
|
124
|
-
[LogLevel.INFO]: "INFO",
|
|
125
|
-
[LogLevel.WARN]: "WARN",
|
|
126
|
-
[LogLevel.ERROR]: "ERROR",
|
|
127
|
-
[LogLevel.NONE]: "NONE"
|
|
128
|
-
};
|
|
129
|
-
function getTimestamp() {
|
|
130
|
-
const now = /* @__PURE__ */ new Date();
|
|
131
|
-
const hours = String(now.getHours()).padStart(2, "0");
|
|
132
|
-
const minutes = String(now.getMinutes()).padStart(2, "0");
|
|
133
|
-
const seconds = String(now.getSeconds()).padStart(2, "0");
|
|
134
|
-
const ms = String(now.getMilliseconds()).padStart(3, "0");
|
|
135
|
-
return `${hours}:${minutes}:${seconds}.${ms}`;
|
|
136
|
-
}
|
|
137
163
|
function getCallerInfo(depth = 3) {
|
|
138
164
|
const stack = new Error().stack;
|
|
139
165
|
if (!stack) return "";
|
|
@@ -279,6 +305,19 @@ var JS_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
279
305
|
function isJsFile(filePath) {
|
|
280
306
|
return JS_EXTENSIONS.has(path.extname(filePath));
|
|
281
307
|
}
|
|
308
|
+
var DIAGNOSTICS_TOOL_DESCRIPTION = [
|
|
309
|
+
"\u8FD0\u884C ESLint \u4E0E TypeScript \u7C7B\u578B\u8BCA\u65AD\uFF0C\u8FD4\u56DE\u8BCA\u65AD\u7ED3\u679C\u3002",
|
|
310
|
+
"",
|
|
311
|
+
"**\u652F\u6301\u7684\u6587\u4EF6\u7C7B\u578B**\uFF1A",
|
|
312
|
+
`- ESLint\uFF1AJavaScript / TypeScript / Vue \u6E90\u7801\uFF08${[...JS_EXTENSIONS].map((e) => `*${e}`).join(" ")}\uFF09`,
|
|
313
|
+
"- TypeScript \u7C7B\u578B\u68C0\u67E5\uFF1A*.ts *.tsx *.vue",
|
|
314
|
+
"",
|
|
315
|
+
"**\u4F55\u65F6\u4F7F\u7528\u6B64\u5DE5\u5177**\uFF1A",
|
|
316
|
+
"- \u521A\u5B8C\u6210\u4EE3\u7801\u4FEE\u6539\uFF0C\u60F3\u9A8C\u8BC1\u662F\u5426\u6709 ESLint \u9519\u8BEF\u6216\u7C7B\u578B\u9519\u8BEF",
|
|
317
|
+
"- \u5728\u63D0\u4EA4\u4EE3\u7801\u524D\u8FDB\u884C\u8D28\u91CF\u68C0\u67E5",
|
|
318
|
+
"- \u6392\u67E5\u7F16\u8F91\u5668\u672A\u663E\u793A\u4F46\u5B9E\u9645\u5B58\u5728\u7684\u7C7B\u578B\u95EE\u9898",
|
|
319
|
+
"- \u4E0D\u4F20\u53C2\u6570\u53EF\u5168\u91CF\u8BCA\u65AD\u6574\u4E2A\u9879\u76EE"
|
|
320
|
+
].join("\n");
|
|
282
321
|
var ESLintClass;
|
|
283
322
|
function loadESLint(workspace) {
|
|
284
323
|
if (ESLintClass) return;
|
|
@@ -294,7 +333,12 @@ function loadESLint(workspace) {
|
|
|
294
333
|
}
|
|
295
334
|
async function lintFiles(pattern, cwd, warnLimit = 5) {
|
|
296
335
|
loadESLint(cwd);
|
|
297
|
-
if (!ESLintClass)
|
|
336
|
+
if (!ESLintClass) {
|
|
337
|
+
return {
|
|
338
|
+
text: `[ESLint] \u672A\u8FD0\u884C\uFF1A\u65E0\u6CD5\u5728 workspace "${cwd}" \u89E3\u6790\u5230 eslint\uFF08\u4EC5\u663E\u793A TypeScript \u8BCA\u65AD\uFF09`,
|
|
339
|
+
diagnostics: []
|
|
340
|
+
};
|
|
341
|
+
}
|
|
298
342
|
try {
|
|
299
343
|
const eslint = new ESLintClass({ cwd });
|
|
300
344
|
const results = await eslint.lintFiles(pattern);
|
|
@@ -342,7 +386,10 @@ async function lintFiles(pattern, cwd, warnLimit = 5) {
|
|
|
342
386
|
return { text: lines.length > 0 ? lines.join("\n") : void 0, diagnostics };
|
|
343
387
|
} catch (err) {
|
|
344
388
|
log2.warn("ESLint failed", { pattern, error: err.message });
|
|
345
|
-
return {
|
|
389
|
+
return {
|
|
390
|
+
text: `[ESLint] \u8FD0\u884C\u5931\u8D25\uFF1A${err.message}\uFF08\u4EC5\u663E\u793A TypeScript \u8BCA\u65AD\uFF09`,
|
|
391
|
+
diagnostics: []
|
|
392
|
+
};
|
|
346
393
|
}
|
|
347
394
|
}
|
|
348
395
|
var _vueTscBin;
|
|
@@ -506,6 +553,21 @@ async function runProjectDiagnostics(workspace) {
|
|
|
506
553
|
return { eslintOutput, tscOutput: mergedTsc };
|
|
507
554
|
}
|
|
508
555
|
|
|
556
|
+
// ../../core/es/common/utils.mjs
|
|
557
|
+
var NODE_MENTION_RE = /@节点\[(n[0-9a-z]+)\]/g;
|
|
558
|
+
function parseNodeMentions(text) {
|
|
559
|
+
const out = [];
|
|
560
|
+
const seen = /* @__PURE__ */ new Set();
|
|
561
|
+
for (const m of text.matchAll(NODE_MENTION_RE)) {
|
|
562
|
+
const id = m[1];
|
|
563
|
+
if (!seen.has(id)) {
|
|
564
|
+
seen.add(id);
|
|
565
|
+
out.push(id);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
return out;
|
|
569
|
+
}
|
|
570
|
+
|
|
509
571
|
// dsh-plugin/src/events-relay.ts
|
|
510
572
|
var log3 = createNodeLogger("DshEventRelay");
|
|
511
573
|
var FLUSH_DELAY_MS = 120;
|
|
@@ -532,6 +594,8 @@ function setupEventRelay(ctx, config) {
|
|
|
532
594
|
const lastSent = /* @__PURE__ */ new Map();
|
|
533
595
|
const lastTitles = /* @__PURE__ */ new Map();
|
|
534
596
|
const dirty = /* @__PURE__ */ new Set();
|
|
597
|
+
const childOf = /* @__PURE__ */ new Map();
|
|
598
|
+
const subagentRunningByParent = /* @__PURE__ */ new Map();
|
|
535
599
|
let flushTimer = null;
|
|
536
600
|
let lastPostErrorAt = 0;
|
|
537
601
|
const scheduleFlush = () => {
|
|
@@ -549,15 +613,48 @@ function setupEventRelay(ctx, config) {
|
|
|
549
613
|
const ensureState = (sessionId) => {
|
|
550
614
|
let s = states.get(sessionId);
|
|
551
615
|
if (s === void 0) {
|
|
552
|
-
s = { running: false, thinking: false };
|
|
616
|
+
s = { running: false, thinking: false, pending: false, subagentRunning: 0 };
|
|
553
617
|
states.set(sessionId, s);
|
|
554
618
|
}
|
|
555
619
|
return s;
|
|
556
620
|
};
|
|
621
|
+
const updateSubagentCount = (parentId, childId, running) => {
|
|
622
|
+
let set = subagentRunningByParent.get(parentId);
|
|
623
|
+
if (running) {
|
|
624
|
+
if (set === void 0) {
|
|
625
|
+
set = /* @__PURE__ */ new Set();
|
|
626
|
+
subagentRunningByParent.set(parentId, set);
|
|
627
|
+
}
|
|
628
|
+
set.add(childId);
|
|
629
|
+
} else if (set !== void 0) {
|
|
630
|
+
set.delete(childId);
|
|
631
|
+
}
|
|
632
|
+
const count = set === void 0 || set.size === 0 ? 0 : set.size;
|
|
633
|
+
if (set !== void 0 && set.size === 0) subagentRunningByParent.delete(parentId);
|
|
634
|
+
const s = ensureState(parentId);
|
|
635
|
+
if (s.subagentRunning !== count) {
|
|
636
|
+
s.subagentRunning = count;
|
|
637
|
+
markDirty(parentId);
|
|
638
|
+
}
|
|
639
|
+
};
|
|
640
|
+
const setPending = (sessionId, pending, kind) => {
|
|
641
|
+
const s = ensureState(sessionId);
|
|
642
|
+
if (s.pending === pending && s.pendingKind === kind) return;
|
|
643
|
+
s.pending = pending;
|
|
644
|
+
s.pendingKind = pending ? kind : void 0;
|
|
645
|
+
markDirty(sessionId);
|
|
646
|
+
};
|
|
557
647
|
const handleAgentStatus = ({ agent, status }) => {
|
|
558
648
|
const sessionId = String(agent.session.id);
|
|
559
649
|
if (!sessionId) return;
|
|
560
650
|
const running = status === "running";
|
|
651
|
+
const header = agent.session.header;
|
|
652
|
+
if (header?.origin === "subagent" && header.parentSession !== void 0) {
|
|
653
|
+
const parentId = String(header.parentSession);
|
|
654
|
+
childOf.set(sessionId, parentId);
|
|
655
|
+
updateSubagentCount(parentId, sessionId, running);
|
|
656
|
+
return;
|
|
657
|
+
}
|
|
561
658
|
const s = ensureState(sessionId);
|
|
562
659
|
if (s.running === running) return;
|
|
563
660
|
s.running = running;
|
|
@@ -610,8 +707,25 @@ function setupEventRelay(ctx, config) {
|
|
|
610
707
|
if (last === void 0 || last.thinking !== s.thinking) {
|
|
611
708
|
events.push({ type: "thinking", sessionId, thinking: s.thinking });
|
|
612
709
|
}
|
|
710
|
+
if (last === void 0 || last.pending !== s.pending || last.pendingKind !== s.pendingKind) {
|
|
711
|
+
events.push({
|
|
712
|
+
type: "session.pending",
|
|
713
|
+
sessionId,
|
|
714
|
+
pending: s.pending,
|
|
715
|
+
...s.pendingKind === void 0 ? {} : { kind: s.pendingKind }
|
|
716
|
+
});
|
|
717
|
+
}
|
|
718
|
+
if (last === void 0 || last.subagentRunning !== s.subagentRunning) {
|
|
719
|
+
events.push({ type: "session.subagents", sessionId, running: s.subagentRunning });
|
|
720
|
+
}
|
|
613
721
|
if (events.length === 0) continue;
|
|
614
|
-
lastSent.set(sessionId, {
|
|
722
|
+
lastSent.set(sessionId, {
|
|
723
|
+
running: s.running,
|
|
724
|
+
thinking: s.thinking,
|
|
725
|
+
pending: s.pending,
|
|
726
|
+
pendingKind: s.pendingKind,
|
|
727
|
+
subagentRunning: s.subagentRunning
|
|
728
|
+
});
|
|
615
729
|
for (const event of events) post(event);
|
|
616
730
|
}
|
|
617
731
|
};
|
|
@@ -637,22 +751,45 @@ function setupEventRelay(ctx, config) {
|
|
|
637
751
|
}
|
|
638
752
|
});
|
|
639
753
|
};
|
|
640
|
-
ctx.on("agent/status", handleAgentStatus);
|
|
754
|
+
ctx.on("agent/status", handleAgentStatus, { global: true });
|
|
641
755
|
ctx.on("session/event", handleSessionEvent, { global: true });
|
|
756
|
+
ctx.on(
|
|
757
|
+
"approval/request",
|
|
758
|
+
async (request, next) => {
|
|
759
|
+
const sessionId = String(request.agent?.session?.id ?? "");
|
|
760
|
+
if (!sessionId) return next();
|
|
761
|
+
setPending(sessionId, true, "approval");
|
|
762
|
+
try {
|
|
763
|
+
return await next();
|
|
764
|
+
} finally {
|
|
765
|
+
setPending(sessionId, false);
|
|
766
|
+
}
|
|
767
|
+
},
|
|
768
|
+
// scoped(Scoped<Agent>)事件:root ctx 需 global 才能收到所有 agent
|
|
769
|
+
{ global: true }
|
|
770
|
+
);
|
|
771
|
+
ctx.on(
|
|
772
|
+
"user-questions/request",
|
|
773
|
+
async (request, next) => {
|
|
774
|
+
const sessionId = String(request.agent?.session?.id ?? "");
|
|
775
|
+
if (!sessionId) return next();
|
|
776
|
+
const isPlanReview = request.questions?.some((q) => q.intent?.kind === "plan-review");
|
|
777
|
+
setPending(sessionId, true, isPlanReview ? "plan-review" : "question");
|
|
778
|
+
try {
|
|
779
|
+
return await next();
|
|
780
|
+
} finally {
|
|
781
|
+
setPending(sessionId, false);
|
|
782
|
+
}
|
|
783
|
+
},
|
|
784
|
+
// scoped(Scoped<Agent>)事件:root ctx 需 global 才能收到所有 agent
|
|
785
|
+
{ global: true }
|
|
786
|
+
);
|
|
642
787
|
}
|
|
643
788
|
|
|
644
789
|
// dsh-plugin/src/index.ts
|
|
645
790
|
var name = "aipanel";
|
|
646
791
|
var inject = ["tools"];
|
|
647
792
|
var log4 = createNodeLogger("DshPlugin");
|
|
648
|
-
var MUTATING_TOOLS = /* @__PURE__ */ new Set(["write", "edit", "apply_patch"]);
|
|
649
|
-
function collectNodeIds(text) {
|
|
650
|
-
const ids = [];
|
|
651
|
-
const re = new RegExp("@\u8282\u70B9\\[(n[0-9a-z]+)\\]", "g");
|
|
652
|
-
let m;
|
|
653
|
-
while ((m = re.exec(text)) !== null) ids.push(m[1]);
|
|
654
|
-
return ids;
|
|
655
|
-
}
|
|
656
793
|
function buildNodeContext(e) {
|
|
657
794
|
const lines = [`\u8282\u70B9 ID\uFF1A${e.id ?? ""}`];
|
|
658
795
|
const loc = e.line ? e.column ? `:${e.line}:${e.column}` : `:${e.line}` : "";
|
|
@@ -757,14 +894,14 @@ function applyProviderSettings(ctx, config) {
|
|
|
757
894
|
function apply(ctx, config = {}) {
|
|
758
895
|
const cwd = config.cwd ?? process.cwd();
|
|
759
896
|
const enableDiagnostics = config.enableDiagnostics ?? false;
|
|
760
|
-
const autoDiagnose = config.autoDiagnose ?? process.env.
|
|
897
|
+
const autoDiagnose = config.autoDiagnose ?? process.env[OPENCODE_ENV.ENABLE_LINT] === "1";
|
|
761
898
|
const vitePort = config.vitePort ?? 0;
|
|
762
899
|
const contextApiPath = config.contextApiPath ?? CONTEXT_API_PATH;
|
|
763
900
|
const tools = ctx.tools;
|
|
764
901
|
if (enableDiagnostics) {
|
|
765
902
|
const diagnosticsTool = {
|
|
766
903
|
name: "run_diagnostics",
|
|
767
|
-
description:
|
|
904
|
+
description: DIAGNOSTICS_TOOL_DESCRIPTION,
|
|
768
905
|
parameters: {
|
|
769
906
|
type: "object",
|
|
770
907
|
additionalProperties: false,
|
|
@@ -885,7 +1022,7 @@ ${diagText}` }]
|
|
|
885
1022
|
if (message.source.kind !== "user") continue;
|
|
886
1023
|
for (const block of message.content) {
|
|
887
1024
|
if (block.type !== "text") continue;
|
|
888
|
-
for (const id of
|
|
1025
|
+
for (const id of parseNodeMentions(block.text)) ids.add(id);
|
|
889
1026
|
}
|
|
890
1027
|
}
|
|
891
1028
|
if (ids.size === 0) return decision;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aipanel/dsh-plugin",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.11",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AIPanel for DeepSeek Harness (dsh):注入审查工具 run_diagnostics、编辑后自动诊断。",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -16,14 +16,16 @@
|
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
18
18
|
"@deepseek-ai/cordis": "^4.0.2",
|
|
19
|
-
"@deepseek-ai/dsh-settings": "^0.1.2-rc.1",
|
|
20
19
|
"@deepseek-ai/dsh-agent": "^0.1.2-rc.1",
|
|
21
20
|
"@deepseek-ai/dsh-llm": "^0.1.2-rc.1",
|
|
21
|
+
"@deepseek-ai/dsh-session": "^0.1.2-rc.1",
|
|
22
|
+
"@deepseek-ai/dsh-settings": "^0.1.2-rc.1",
|
|
22
23
|
"@deepseek-ai/dsh-tools": "^0.1.2-rc.1",
|
|
24
|
+
"@deepseek-ai/dsh-user-approval": "^0.1.2-rc.1",
|
|
25
|
+
"@deepseek-ai/dsh-user-questions": "^0.1.2-rc.1",
|
|
23
26
|
"@deepseek-ai/dsh-util-values": "^0.1.2-rc.1",
|
|
24
|
-
"@deepseek-ai/dsh-session": "^0.1.2-rc.1",
|
|
25
27
|
"esbuild": "^0.25.0",
|
|
26
|
-
"@aipanel/core": "1.2.
|
|
28
|
+
"@aipanel/core": "1.2.11"
|
|
27
29
|
},
|
|
28
30
|
"scripts": {
|
|
29
31
|
"build": "esbuild src/index.ts --bundle --outfile=dist/index.js --platform=node --format=esm --target=node18 --external:@deepseek-ai/* --external:node:* --external:vue-tsc",
|