dsh-plugin-prompt-tool 0.1.5 → 0.3.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/README.md +109 -170
- package/lib/client.js +130 -10
- package/lib/client.js.map +1 -1
- package/lib/index.d.mts +22 -2
- package/lib/index.mjs +207 -24
- package/lib/preset-core.d.mts +16 -1
- package/lib/preset-core.mjs +108 -21
- package/package.json +5 -6
- package/plan.md +292 -265
- package/preset/near-anchor.mjs +114 -0
- package/preset/router-first-turn.mjs +70 -0
- package/preset/router-guide.mjs +85 -0
- package/preset.md +0 -1
- package/{vendor → upstream}/dsh-anchored-standard/NOTICE +5 -0
- package/upstream/dsh-anchored-standard/REVISION +1 -0
- package/{vendor → upstream}/dsh-anchored-standard/preset/agent.cordis.yml +53 -24
- package/upstream/dsh-anchored-standard/preset/context-gate.mjs +202 -0
- package/{vendor → upstream}/dsh-anchored-standard/preset/dev-tool-search.mjs +10 -8
- package/{vendor → upstream}/dsh-anchored-standard/preset/instruction-hint.mjs +66 -13
- package/{vendor → upstream}/dsh-anchored-standard/preset/tool-bootstrap.mjs +41 -78
- package/preset/turn-anchor.mjs +0 -83
- /package/{vendor → upstream}/dsh-anchored-standard/LICENSE +0 -0
- /package/{vendor → upstream}/dsh-anchored-standard/preset/compaction-epoch.mjs +0 -0
- /package/{vendor → upstream}/dsh-anchored-standard/preset/custom-bash.mjs +0 -0
- /package/{vendor → upstream}/dsh-anchored-standard/preset/preset.yml +0 -0
- /package/{vendor → upstream}/dsh-anchored-standard/preset/skill-search.mjs +0 -0
package/lib/index.mjs
CHANGED
|
@@ -10,7 +10,9 @@ const name = "prompt-tool";
|
|
|
10
10
|
const inject = [
|
|
11
11
|
"skills",
|
|
12
12
|
"webServer",
|
|
13
|
-
"commands"
|
|
13
|
+
"commands",
|
|
14
|
+
"llm",
|
|
15
|
+
"subagents"
|
|
14
16
|
];
|
|
15
17
|
const PRESET_FILE_URL = new URL("../preset.md", import.meta.url);
|
|
16
18
|
const PRESET_FILE_PATH = fileURLToPath(PRESET_FILE_URL);
|
|
@@ -24,10 +26,14 @@ const DEFAULT_PRESET_DIR = join(DSH_HOME, ".agent-presets", "prompt-tool");
|
|
|
24
26
|
const DEFAULT_SKILLS_DIR = SKILLS_DIR;
|
|
25
27
|
const DEFAULT_PRESET_ORDER = 5;
|
|
26
28
|
const DEFAULT_SKILL_RANK_BASE = 250;
|
|
29
|
+
/** 每轮引导文本框的默认内容:写入自动引导的两段文本。 */
|
|
30
|
+
const DEFAULT_GUIDE_TEXT = `简单任务自动引导:${"\nRouter: classify this task (build or fix) now, then adopt the matching style — build: direct production; fix: inspect-first. Think deeply first, then commit and act.".trim()}\n\n复杂任务自动引导:${"\nRouter: classify this task (build or fix) now, then adopt the matching style — build: direct production; fix: inspect-first. Think deeply about the architecture, edge cases, and integration points. Do not spend reasoning on the environment or tooling. Produce when your information is complete. End each reasoning block with a decision or an information need.".trim()}`;
|
|
27
31
|
const PRESET_TEMPLATE_META = fileURLToPath(new URL("../preset/preset.yml", import.meta.url));
|
|
28
32
|
const PRESET_TEMPLATE_INJECTOR = fileURLToPath(new URL("../preset/prompt-injector.mjs", import.meta.url));
|
|
29
|
-
const PRESET_TEMPLATE_ANCHOR = fileURLToPath(new URL("../preset/
|
|
30
|
-
const
|
|
33
|
+
const PRESET_TEMPLATE_ANCHOR = fileURLToPath(new URL("../preset/near-anchor.mjs", import.meta.url));
|
|
34
|
+
const PRESET_TEMPLATE_ROUTER = fileURLToPath(new URL("../preset/router-first-turn.mjs", import.meta.url));
|
|
35
|
+
const PRESET_TEMPLATE_GUIDE = fileURLToPath(new URL("../preset/router-guide.mjs", import.meta.url));
|
|
36
|
+
const VENDOR_PRESET_DIR = fileURLToPath(new URL("../upstream/dsh-anchored-standard/preset", import.meta.url));
|
|
31
37
|
const Config = z.object({
|
|
32
38
|
text: z.string().default(""),
|
|
33
39
|
agentsText: z.string().default(""),
|
|
@@ -37,7 +43,14 @@ const Config = z.object({
|
|
|
37
43
|
injectPrompt: z.boolean().default(true),
|
|
38
44
|
skillSwitches: z.dict(z.boolean()).default({}),
|
|
39
45
|
anchorFirstTurn: z.boolean().default(false),
|
|
40
|
-
anchorText: z.string().default("
|
|
46
|
+
anchorText: z.string().default(""),
|
|
47
|
+
anchorCustom: z.boolean().default(false),
|
|
48
|
+
guideText: z.string().default(DEFAULT_GUIDE_TEXT),
|
|
49
|
+
guideCustom: z.boolean().default(false),
|
|
50
|
+
subagentFlash: z.boolean().default(false),
|
|
51
|
+
subagentFlashProvider: z.string().default("deepseek-official"),
|
|
52
|
+
subagentFlashModel: z.string().default("deepseek-v4-flash"),
|
|
53
|
+
customBashPath: z.string().default("bash.exe"),
|
|
41
54
|
skillsDir: z.string().default(DEFAULT_SKILLS_DIR),
|
|
42
55
|
skillRankBase: z.natural().default(DEFAULT_SKILL_RANK_BASE),
|
|
43
56
|
residentAgentsPath: z.string().default(DEFAULT_RESIDENT_AGENTS_PATH),
|
|
@@ -52,7 +65,12 @@ const PromptSettingsSchema = z.object({
|
|
|
52
65
|
agentsPath: z.string().default(""),
|
|
53
66
|
injectAgentsPrompt: z.boolean().default(false),
|
|
54
67
|
anchorFirstTurn: z.boolean().default(false),
|
|
55
|
-
anchorText: z.string().default("
|
|
68
|
+
anchorText: z.string().default(""),
|
|
69
|
+
anchorCustom: z.boolean().default(false),
|
|
70
|
+
guideText: z.string().default(DEFAULT_GUIDE_TEXT),
|
|
71
|
+
guideCustom: z.boolean().default(false),
|
|
72
|
+
subagentFlash: z.boolean().default(false),
|
|
73
|
+
deepseekAvailable: z.boolean().default(true),
|
|
56
74
|
injectPrompt: z.boolean().default(true),
|
|
57
75
|
skillSwitches: z.dict(z.boolean()).default({}),
|
|
58
76
|
skillCatalog: z.array(z.object({
|
|
@@ -271,10 +289,13 @@ async function readBridgeBody(req) {
|
|
|
271
289
|
/** dsh-tui 暴露的布尔开关:键名与 settings 路径一致。 */
|
|
272
290
|
const TUI_BOOLEAN_SWITCHES = [
|
|
273
291
|
["writeAgents", "写入常驻规则 AGENTS.md"],
|
|
274
|
-
["writePreset", "
|
|
292
|
+
["writePreset", "启用锚定预设"],
|
|
275
293
|
["injectPrompt", "锚定确认后注入 preset.md"],
|
|
276
294
|
["injectAgentsPrompt", "用 AGENTS.md 替换 instruction-hint 提示"],
|
|
277
|
-
["anchorFirstTurn", "
|
|
295
|
+
["anchorFirstTurn", "追加任务引导"],
|
|
296
|
+
["anchorCustom", "使用自定义引导(首句)"],
|
|
297
|
+
["guideCustom", "使用自定义引导(每轮)"],
|
|
298
|
+
["subagentFlash", "子代理固定 Flash 模型"]
|
|
278
299
|
];
|
|
279
300
|
/** 把布尔开关渲染成 dsh-tui 命令输出。 */
|
|
280
301
|
function renderTuiStatus(source) {
|
|
@@ -285,6 +306,9 @@ function renderTuiStatus(source) {
|
|
|
285
306
|
const value = source[key];
|
|
286
307
|
return `${key.padEnd(22)}${onOff(typeof value === "boolean" ? value : false)} ${label}`;
|
|
287
308
|
}),
|
|
309
|
+
"锚点文本:",
|
|
310
|
+
` anchorText ${source.anchorText.length > 0 ? source.anchorText : "(空 = 按任务自动选择)"}`,
|
|
311
|
+
` deepseekAvailable ${source.deepseekAvailable ? "是" : "否(未检测到 DeepSeek 模型,subagentFlash 不可用)"}`,
|
|
288
312
|
"技能开关:"
|
|
289
313
|
];
|
|
290
314
|
for (const skill of source.skillCatalog) {
|
|
@@ -300,7 +324,7 @@ function parseTuiBoolean(token, current) {
|
|
|
300
324
|
if (token === "toggle") return !current;
|
|
301
325
|
}
|
|
302
326
|
/** 通过 DSH 命令注册表暴露 /prompt-tool,Web 与 dsh-tui 都能执行。 */
|
|
303
|
-
function registerTuiCommand(ctx, getSource) {
|
|
327
|
+
function registerTuiCommand(ctx, getSource, getDeepseekAvailable, getDeepseekState) {
|
|
304
328
|
ctx.inject(["settings"], (sctx) => {
|
|
305
329
|
return sctx.commands.register({
|
|
306
330
|
name: "prompt-tool",
|
|
@@ -309,14 +333,18 @@ function registerTuiCommand(ctx, getSource) {
|
|
|
309
333
|
handler: async (invocation) => {
|
|
310
334
|
const usage = () => ({
|
|
311
335
|
kind: "error",
|
|
312
|
-
text: "用法:/prompt-tool status\n /prompt-tool on|off|toggle <writeAgents|writePreset|injectPrompt|injectAgentsPrompt|anchorFirstTurn>\n /prompt-tool skill <技能目录名> on|off|toggle"
|
|
336
|
+
text: "用法:/prompt-tool status\n /prompt-tool on|off|toggle <writeAgents|writePreset|injectPrompt|injectAgentsPrompt|anchorFirstTurn|anchorCustom|guideCustom|subagentFlash>\n /prompt-tool skill <技能目录名> on|off|toggle"
|
|
313
337
|
});
|
|
314
338
|
const tokens = invocation.rawInput.trim().split(/\s+/).filter((token) => token.length > 0);
|
|
315
339
|
const source = getSource();
|
|
316
|
-
if (tokens.length === 0 || tokens[0] === "status")
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
340
|
+
if (tokens.length === 0 || tokens[0] === "status") {
|
|
341
|
+
const detection = getDeepseekState();
|
|
342
|
+
const deepseekLine = detection.available ? `检测到的 DeepSeek 模型路由: ${detection.providers.join(", ") || "(无)"}` : `未检测到 DeepSeek 模型路由。providers=[${detection.providers.join(", ") || "空"}] error=${detection.error ?? "无"}`;
|
|
343
|
+
return {
|
|
344
|
+
kind: "success",
|
|
345
|
+
text: renderTuiStatus(source) + "\n" + deepseekLine
|
|
346
|
+
};
|
|
347
|
+
}
|
|
320
348
|
if (tokens[0] === "skill") {
|
|
321
349
|
const folder = tokens[1];
|
|
322
350
|
if (folder === void 0) return usage();
|
|
@@ -339,6 +367,13 @@ ${renderTuiStatus(getSource())}`
|
|
|
339
367
|
const key = tokens[1];
|
|
340
368
|
if (action !== "on" && action !== "off" && action !== "toggle") return usage();
|
|
341
369
|
if (key === void 0 || !TUI_BOOLEAN_SWITCHES.some(([candidate]) => candidate === key)) return usage();
|
|
370
|
+
if (key === "subagentFlash" && !getDeepseekAvailable()) {
|
|
371
|
+
const detection = getDeepseekState();
|
|
372
|
+
return {
|
|
373
|
+
kind: "error",
|
|
374
|
+
text: `未检测到 DeepSeek 模型路由,subagentFlash 开关不可用。providers=[${detection.providers.join(", ") || "空"}] error=${detection.error ?? "无"}`
|
|
375
|
+
};
|
|
376
|
+
}
|
|
342
377
|
const currentValue = source[key];
|
|
343
378
|
if (typeof currentValue !== "boolean") return {
|
|
344
379
|
kind: "error",
|
|
@@ -362,7 +397,7 @@ ${renderTuiStatus(getSource())}`
|
|
|
362
397
|
});
|
|
363
398
|
}
|
|
364
399
|
/** 自建 loopback settings bridge:替代 registerConfigurableProviders,避免模型设置区出现插件条目。 */
|
|
365
|
-
function registerSettingsBridge(ctx) {
|
|
400
|
+
function registerSettingsBridge(ctx, getDeepseekAvailable, getDeepseekState) {
|
|
366
401
|
ctx.inject(["settings"], (sctx) => {
|
|
367
402
|
sctx.effect(() => {
|
|
368
403
|
const findDescriptor = () => sctx.settings.describe({ redactSecrets: true }).find((entry) => String(entry.ns) === String(NS));
|
|
@@ -400,9 +435,13 @@ function registerSettingsBridge(ctx) {
|
|
|
400
435
|
});
|
|
401
436
|
return;
|
|
402
437
|
}
|
|
438
|
+
const detection = getDeepseekState();
|
|
403
439
|
writeBridgeJson(res, 200, {
|
|
404
440
|
ok: true,
|
|
405
|
-
value: descriptor
|
|
441
|
+
value: descriptor,
|
|
442
|
+
deepseekAvailable: detection.available,
|
|
443
|
+
deepseekProviders: detection.providers,
|
|
444
|
+
deepseekError: detection.error
|
|
406
445
|
});
|
|
407
446
|
}
|
|
408
447
|
}),
|
|
@@ -516,19 +555,127 @@ function registerSettingsBridge(ctx) {
|
|
|
516
555
|
}, "prompt-tool: settings bridge");
|
|
517
556
|
});
|
|
518
557
|
}
|
|
558
|
+
/** 旧版“每块强制 we need”默认锚句;已存 settings 时归一化为自动模式。 */
|
|
559
|
+
const LEGACY_ANCHOR_TEXT = [
|
|
560
|
+
"You are a helpful software assistant.",
|
|
561
|
+
"",
|
|
562
|
+
"Begin every reasoning block with 'We need'."
|
|
563
|
+
].join("\n");
|
|
564
|
+
/** 旧默认值归一化为空(自动);用户自定义文本原样保留。 */
|
|
565
|
+
function normalizeAnchorText(text) {
|
|
566
|
+
const value = typeof text === "string" ? text : "";
|
|
567
|
+
return value.trim() === LEGACY_ANCHOR_TEXT.trim() ? "" : value;
|
|
568
|
+
}
|
|
569
|
+
/** 检测 DeepSeek 模型:live provider + 可配置 provider 目录双通道匹配。 */
|
|
570
|
+
function detectDeepseek(ctx) {
|
|
571
|
+
const empty = {
|
|
572
|
+
available: false,
|
|
573
|
+
providers: []
|
|
574
|
+
};
|
|
575
|
+
try {
|
|
576
|
+
const llm = ctx.get("llm");
|
|
577
|
+
if (llm === void 0) return {
|
|
578
|
+
...empty,
|
|
579
|
+
error: "ctx.get(\"llm\") 返回 undefined"
|
|
580
|
+
};
|
|
581
|
+
const live = llm.listProviders?.() ?? [];
|
|
582
|
+
const configured = llm.listConfigurableProviders?.() ?? [];
|
|
583
|
+
const names = /* @__PURE__ */ new Set();
|
|
584
|
+
const matches = (id, name) => /deepseek/i.test(id ?? "") || /deepseek/i.test(name ?? "");
|
|
585
|
+
for (const provider of live) {
|
|
586
|
+
const id = typeof provider.id === "string" ? provider.id : String(provider.id ?? "");
|
|
587
|
+
names.add(id || provider.name || "(unnamed)");
|
|
588
|
+
if (matches(provider.id, provider.name)) return {
|
|
589
|
+
available: true,
|
|
590
|
+
providers: [...names]
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
for (const provider of configured) {
|
|
594
|
+
const id = typeof provider.provider === "string" ? provider.provider : "";
|
|
595
|
+
if (id.length > 0) names.add(id);
|
|
596
|
+
if (matches(provider.provider, provider.displayName)) return {
|
|
597
|
+
available: true,
|
|
598
|
+
providers: [...names]
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
return {
|
|
602
|
+
available: false,
|
|
603
|
+
providers: [...names],
|
|
604
|
+
...live.length === 0 && configured.length === 0 ? { error: "llm 服务未返回任何 provider" } : {}
|
|
605
|
+
};
|
|
606
|
+
} catch (error) {
|
|
607
|
+
return {
|
|
608
|
+
...empty,
|
|
609
|
+
error: error instanceof Error ? error.message : String(error)
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
/** 给宿主直派的子代理补 Flash 路由;调用方显式 provider/model 优先,不覆盖 persona 与工具白名单。 */
|
|
614
|
+
function installSubagentFlashRoute(ctx, isEnabled, provider, model) {
|
|
615
|
+
ctx.inject(["subagents"], (sctx) => {
|
|
616
|
+
const service = sctx.get("subagents");
|
|
617
|
+
if (service === void 0 || typeof service.start !== "function") return;
|
|
618
|
+
const original = service.start;
|
|
619
|
+
const wrapped = (name, request) => {
|
|
620
|
+
if (!isEnabled() || request === null || typeof request !== "object") return original.call(service, name, request);
|
|
621
|
+
const agentOptions = request.agentOptions !== null && typeof request.agentOptions === "object" ? request.agentOptions : {};
|
|
622
|
+
if (agentOptions.provider === void 0 && agentOptions.model === void 0) return original.call(service, name, {
|
|
623
|
+
...request,
|
|
624
|
+
agentOptions: {
|
|
625
|
+
...agentOptions,
|
|
626
|
+
provider,
|
|
627
|
+
model
|
|
628
|
+
}
|
|
629
|
+
});
|
|
630
|
+
return original.call(service, name, request);
|
|
631
|
+
};
|
|
632
|
+
service.start = wrapped;
|
|
633
|
+
return () => {
|
|
634
|
+
if (service.start === wrapped) service.start = original;
|
|
635
|
+
};
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
/** prompt-tool 补丁:子代理直接全量放行(assembled.tools 本身已是动态白名单)。 */
|
|
639
|
+
function patchToolBootstrap(source) {
|
|
640
|
+
source = source.replace(/\r\n/g, "\n");
|
|
641
|
+
const original = [
|
|
642
|
+
" const assembled = await next()",
|
|
643
|
+
" try {",
|
|
644
|
+
" const status = promotion.status(context.agent)"
|
|
645
|
+
].join("\n");
|
|
646
|
+
const replacement = [
|
|
647
|
+
" const assembled = await next()",
|
|
648
|
+
" try {",
|
|
649
|
+
" // prompt-tool 补丁:子代理跳过目录裁剪,直接使用组装结果;",
|
|
650
|
+
" // 调用方(如 dsh-mnemon)的工具白名单已先行过滤 assembled.tools,",
|
|
651
|
+
" // 因此任意前缀的新插件工具都会自动出现在子代理第一次会话。",
|
|
652
|
+
" if ((context.agent?.session?.header?.delegationDepth ?? 0) > 0) return assembled",
|
|
653
|
+
" const status = promotion.status(context.agent)"
|
|
654
|
+
].join("\n");
|
|
655
|
+
if (!source.includes(original)) throw new Error("tool-bootstrap.mjs assembled marker missing");
|
|
656
|
+
return source.replace(original, replacement);
|
|
657
|
+
}
|
|
519
658
|
function writePreset(prompt, options) {
|
|
520
659
|
const presetDir = options.presetDir;
|
|
521
660
|
mkdirSync(presetDir, { recursive: true });
|
|
522
661
|
writeFileSync(join(presetDir, "agent.cordis.yml"), buildCordis(prompt, {
|
|
523
662
|
anchorFirstTurn: options.anchorFirstTurn,
|
|
524
663
|
anchorText: options.anchorText,
|
|
525
|
-
|
|
664
|
+
anchorCustom: options.anchorCustom,
|
|
665
|
+
guideText: options.guideText,
|
|
666
|
+
guideCustom: options.guideCustom,
|
|
667
|
+
injectPrompt: options.injectPrompt,
|
|
668
|
+
subagentFlash: options.subagentFlash,
|
|
669
|
+
subagentFlashProvider: options.subagentFlashProvider,
|
|
670
|
+
subagentFlashModel: options.subagentFlashModel,
|
|
671
|
+
bashPath: options.customBashPath
|
|
526
672
|
}), "utf8");
|
|
527
673
|
const meta = readFileSync(PRESET_TEMPLATE_META, "utf8").replace(/^order:.*$/m, `order: ${options.presetOrder}`);
|
|
528
674
|
writeFileSync(join(presetDir, "preset.yml"), meta, "utf8");
|
|
529
675
|
for (const file of readdirSync(VENDOR_PRESET_DIR)) {
|
|
530
676
|
if (!file.endsWith(".mjs")) continue;
|
|
531
|
-
|
|
677
|
+
const vendorSource = readFileSync(join(VENDOR_PRESET_DIR, file), "utf8");
|
|
678
|
+
writeFileSync(join(presetDir, file), file === "tool-bootstrap.mjs" ? patchToolBootstrap(vendorSource) : vendorSource, "utf8");
|
|
532
679
|
}
|
|
533
680
|
const agentsInstructionPath = join(presetDir, "agents-instruction.txt");
|
|
534
681
|
if (options.agentsInstructionText !== void 0) {
|
|
@@ -539,11 +686,17 @@ function writePreset(prompt, options) {
|
|
|
539
686
|
const injectorPath = join(presetDir, "prompt-injector.mjs");
|
|
540
687
|
if (options.injectPrompt) writeFileSync(injectorPath, readFileSync(PRESET_TEMPLATE_INJECTOR, "utf8"), "utf8");
|
|
541
688
|
else rmSync(injectorPath, { force: true });
|
|
542
|
-
|
|
689
|
+
writeFileSync(join(presetDir, "router-first-turn.mjs"), readFileSync(PRESET_TEMPLATE_ROUTER, "utf8"), "utf8");
|
|
690
|
+
writeFileSync(join(presetDir, "router-guide.mjs"), readFileSync(PRESET_TEMPLATE_GUIDE, "utf8"), "utf8");
|
|
691
|
+
rmSync(join(presetDir, "turn-anchor.mjs"), { force: true });
|
|
692
|
+
const anchorPath = join(presetDir, "near-anchor.mjs");
|
|
543
693
|
if (options.anchorFirstTurn) writeFileSync(anchorPath, readFileSync(PRESET_TEMPLATE_ANCHOR, "utf8"), "utf8");
|
|
544
694
|
else rmSync(anchorPath, { force: true });
|
|
545
695
|
}
|
|
546
696
|
function apply(ctx, config) {
|
|
697
|
+
const deepseekState = () => detectDeepseek(ctx);
|
|
698
|
+
const getDeepseekAvailable = () => deepseekState().available;
|
|
699
|
+
const getDeepseekState = () => deepseekState();
|
|
547
700
|
let current = config.text || readPromptFile(config.fallbackText);
|
|
548
701
|
let currentAgents = config.agentsText || readAgents();
|
|
549
702
|
const skillCatalog = readSkills(config.skillsDir).map((skill) => ({
|
|
@@ -598,7 +751,7 @@ function apply(ctx, config) {
|
|
|
598
751
|
}
|
|
599
752
|
};
|
|
600
753
|
});
|
|
601
|
-
registerSettingsBridge(ctx);
|
|
754
|
+
registerSettingsBridge(ctx, getDeepseekAvailable, getDeepseekState);
|
|
602
755
|
const runtime = {
|
|
603
756
|
writeAgents: config.writeAgents,
|
|
604
757
|
writePreset: config.writePreset,
|
|
@@ -606,8 +759,13 @@ function apply(ctx, config) {
|
|
|
606
759
|
injectPrompt: config.injectPrompt,
|
|
607
760
|
skillSwitches: { ...config.skillSwitches },
|
|
608
761
|
anchorFirstTurn: config.anchorFirstTurn,
|
|
609
|
-
anchorText: config.anchorText
|
|
762
|
+
anchorText: config.anchorText,
|
|
763
|
+
anchorCustom: config.anchorCustom,
|
|
764
|
+
guideText: config.guideText,
|
|
765
|
+
guideCustom: config.guideCustom,
|
|
766
|
+
subagentFlash: config.subagentFlash && getDeepseekAvailable()
|
|
610
767
|
};
|
|
768
|
+
installSubagentFlashRoute(ctx, () => runtime.subagentFlash, config.subagentFlashProvider, config.subagentFlashModel);
|
|
611
769
|
let currentSource = () => ({
|
|
612
770
|
promptText: current,
|
|
613
771
|
promptPath: PRESET_FILE_PATH,
|
|
@@ -615,14 +773,19 @@ function apply(ctx, config) {
|
|
|
615
773
|
agentsPath: AGENTS_FILE_PATH,
|
|
616
774
|
injectAgentsPrompt: runtime.injectAgentsPrompt,
|
|
617
775
|
anchorFirstTurn: runtime.anchorFirstTurn,
|
|
618
|
-
anchorText: runtime.anchorText,
|
|
776
|
+
anchorText: normalizeAnchorText(runtime.anchorText),
|
|
777
|
+
anchorCustom: runtime.anchorCustom,
|
|
778
|
+
guideText: runtime.guideText,
|
|
779
|
+
guideCustom: runtime.guideCustom,
|
|
780
|
+
subagentFlash: runtime.subagentFlash,
|
|
781
|
+
deepseekAvailable: getDeepseekAvailable(),
|
|
619
782
|
injectPrompt: runtime.injectPrompt,
|
|
620
783
|
skillSwitches: runtime.skillSwitches,
|
|
621
784
|
skillCatalog,
|
|
622
785
|
writeAgents: runtime.writeAgents,
|
|
623
786
|
writePreset: runtime.writePreset
|
|
624
787
|
});
|
|
625
|
-
registerTuiCommand(ctx, () => currentSource());
|
|
788
|
+
registerTuiCommand(ctx, () => currentSource(), getDeepseekAvailable, getDeepseekState);
|
|
626
789
|
let needsInitialApply = true;
|
|
627
790
|
const applyState = () => {
|
|
628
791
|
const next = currentSource();
|
|
@@ -633,12 +796,16 @@ function apply(ctx, config) {
|
|
|
633
796
|
injectPrompt: typeof next.injectPrompt === "boolean" ? next.injectPrompt : config.injectPrompt,
|
|
634
797
|
skillSwitches: next.skillSwitches !== void 0 ? next.skillSwitches : config.skillSwitches,
|
|
635
798
|
anchorFirstTurn: typeof next.anchorFirstTurn === "boolean" ? next.anchorFirstTurn : config.anchorFirstTurn,
|
|
636
|
-
anchorText: typeof next.anchorText === "string"
|
|
799
|
+
anchorText: normalizeAnchorText(typeof next.anchorText === "string" ? next.anchorText : config.anchorText),
|
|
800
|
+
anchorCustom: typeof next.anchorCustom === "boolean" ? next.anchorCustom : config.anchorCustom,
|
|
801
|
+
guideText: typeof next.guideText === "string" ? next.guideText : config.guideText,
|
|
802
|
+
guideCustom: typeof next.guideCustom === "boolean" ? next.guideCustom : config.guideCustom,
|
|
803
|
+
subagentFlash: (typeof next.subagentFlash === "boolean" ? next.subagentFlash : config.subagentFlash) && getDeepseekAvailable()
|
|
637
804
|
};
|
|
638
805
|
const promptChanged = next.promptText !== current;
|
|
639
806
|
const agentsChanged = next.agentsText !== currentAgents;
|
|
640
807
|
const skillSwitchesChanged = JSON.stringify(runtime.skillSwitches) !== JSON.stringify(nextRuntime.skillSwitches);
|
|
641
|
-
const settingsChanged = runtime.writeAgents !== nextRuntime.writeAgents || runtime.writePreset !== nextRuntime.writePreset || runtime.injectAgentsPrompt !== nextRuntime.injectAgentsPrompt || runtime.injectPrompt !== nextRuntime.injectPrompt || skillSwitchesChanged || runtime.anchorFirstTurn !== nextRuntime.anchorFirstTurn || runtime.anchorText !== nextRuntime.anchorText;
|
|
808
|
+
const settingsChanged = runtime.writeAgents !== nextRuntime.writeAgents || runtime.writePreset !== nextRuntime.writePreset || runtime.injectAgentsPrompt !== nextRuntime.injectAgentsPrompt || runtime.injectPrompt !== nextRuntime.injectPrompt || skillSwitchesChanged || runtime.anchorFirstTurn !== nextRuntime.anchorFirstTurn || runtime.anchorText !== nextRuntime.anchorText || runtime.anchorCustom !== nextRuntime.anchorCustom || runtime.guideText !== nextRuntime.guideText || runtime.guideCustom !== nextRuntime.guideCustom || runtime.subagentFlash !== nextRuntime.subagentFlash;
|
|
642
809
|
if (!needsInitialApply && !promptChanged && !agentsChanged && !settingsChanged) return;
|
|
643
810
|
needsInitialApply = false;
|
|
644
811
|
if (promptChanged) current = next.promptText;
|
|
@@ -650,6 +817,10 @@ function apply(ctx, config) {
|
|
|
650
817
|
runtime.skillSwitches = nextRuntime.skillSwitches;
|
|
651
818
|
runtime.anchorFirstTurn = nextRuntime.anchorFirstTurn;
|
|
652
819
|
runtime.anchorText = nextRuntime.anchorText;
|
|
820
|
+
runtime.anchorCustom = nextRuntime.anchorCustom;
|
|
821
|
+
runtime.guideText = nextRuntime.guideText;
|
|
822
|
+
runtime.guideCustom = nextRuntime.guideCustom;
|
|
823
|
+
runtime.subagentFlash = nextRuntime.subagentFlash;
|
|
653
824
|
skillSwitches = runtime.skillSwitches;
|
|
654
825
|
if (skillSwitchesChanged) invalidateSkills?.();
|
|
655
826
|
let residentAgentsWritten = false;
|
|
@@ -663,7 +834,14 @@ function apply(ctx, config) {
|
|
|
663
834
|
if (runtime.writePreset) writePreset(runtime.injectPrompt && current.length > 0 ? current : "", {
|
|
664
835
|
anchorFirstTurn: runtime.anchorFirstTurn,
|
|
665
836
|
anchorText: runtime.anchorText,
|
|
837
|
+
anchorCustom: runtime.anchorCustom,
|
|
838
|
+
guideText: runtime.guideText,
|
|
839
|
+
guideCustom: runtime.guideCustom,
|
|
666
840
|
injectPrompt: runtime.injectPrompt,
|
|
841
|
+
subagentFlash: runtime.subagentFlash,
|
|
842
|
+
subagentFlashProvider: config.subagentFlashProvider,
|
|
843
|
+
subagentFlashModel: config.subagentFlashModel,
|
|
844
|
+
customBashPath: config.customBashPath,
|
|
667
845
|
agentsInstructionText: runtime.injectAgentsPrompt && currentAgents.length > 0 ? currentAgents : void 0,
|
|
668
846
|
presetDir: config.presetDir,
|
|
669
847
|
presetOrder: config.presetOrder
|
|
@@ -685,6 +863,11 @@ function apply(ctx, config) {
|
|
|
685
863
|
injectAgentsPrompt: config.injectAgentsPrompt,
|
|
686
864
|
anchorFirstTurn: config.anchorFirstTurn,
|
|
687
865
|
anchorText: config.anchorText,
|
|
866
|
+
anchorCustom: config.anchorCustom,
|
|
867
|
+
guideText: config.guideText,
|
|
868
|
+
guideCustom: config.guideCustom,
|
|
869
|
+
subagentFlash: config.subagentFlash && getDeepseekAvailable(),
|
|
870
|
+
deepseekAvailable: getDeepseekAvailable(),
|
|
688
871
|
injectPrompt: config.injectPrompt,
|
|
689
872
|
skillSwitches: { ...config.skillSwitches },
|
|
690
873
|
skillCatalog,
|
package/lib/preset-core.d.mts
CHANGED
|
@@ -10,11 +10,26 @@ declare function parseFrontmatter(text: string): {
|
|
|
10
10
|
body: string;
|
|
11
11
|
};
|
|
12
12
|
interface BuildCordisOptions {
|
|
13
|
-
/**
|
|
13
|
+
/** 首轮近距离锚定:首条真实用户消息后追加一次性首句锚点。 */
|
|
14
14
|
anchorFirstTurn?: boolean;
|
|
15
|
+
/** 自定义锚点文本;anchorCustom=true 时固定使用。 */
|
|
15
16
|
anchorText?: string;
|
|
17
|
+
/** 自定义锚点开关:true 固定使用 anchorText;false 按任务自动选择。 */
|
|
18
|
+
anchorCustom?: boolean;
|
|
19
|
+
/** 自定义每轮引导文本;guideCustom=true 时固定使用。 */
|
|
20
|
+
guideText?: string;
|
|
21
|
+
/** 自定义每轮引导开关:true 固定使用 guideText;false 按任务自动选择。 */
|
|
22
|
+
guideCustom?: boolean;
|
|
16
23
|
/** 锚定确认后注入 preset.md;关闭时仍保留工具引导,但不注册 prompt-injector 行。 */
|
|
17
24
|
injectPrompt?: boolean;
|
|
25
|
+
/** 子代理固定 Flash 模型:true 时给 subagent/subagent_fork 行加 agentOptions。 */
|
|
26
|
+
subagentFlash?: boolean;
|
|
27
|
+
/** 子代理 Flash 路由 provider(默认 deepseek-official)。 */
|
|
28
|
+
subagentFlashProvider?: string;
|
|
29
|
+
/** 子代理 Flash 模型名(默认 deepseek-v4-flash)。 */
|
|
30
|
+
subagentFlashModel?: string;
|
|
31
|
+
/** Windows custom-bash 可执行名或路径;默认 bash.exe(PATH 查找)。 */
|
|
32
|
+
bashPath?: string;
|
|
18
33
|
}
|
|
19
34
|
declare function buildCordis(prompt: string, options?: BuildCordisOptions): string;
|
|
20
35
|
//#endregion
|
package/lib/preset-core.mjs
CHANGED
|
@@ -6,25 +6,42 @@ import { parse } from "yaml";
|
|
|
6
6
|
* prompt-tool preset 生成核心:与 dsh 插件上下文无关的纯函数,
|
|
7
7
|
* 独立成文件以便单元测试与复用。失败一律抛出(fail loud)。
|
|
8
8
|
*/
|
|
9
|
-
const VENDOR_CORDIS = fileURLToPath(new URL("../
|
|
10
|
-
const
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
9
|
+
const VENDOR_CORDIS = fileURLToPath(new URL("../upstream/dsh-anchored-standard/preset/agent.cordis.yml", import.meta.url));
|
|
10
|
+
const ROUTER_FIRST_TURN_BLOCK = `# prompt-tool 本地附加件(最优组合):首轮只保留计划段 + 训练原句,
|
|
11
|
+
# 并清空自动注入 contexts;子代理直接放行。注册在 tool-bootstrap 之后,
|
|
12
|
+
# 不参与首轮工具目录裁剪——tools 仍由原版 tool-bootstrap 负责。
|
|
13
|
+
- id: router-first-turn
|
|
14
|
+
name: ./router-first-turn.mjs
|
|
15
|
+
`;
|
|
16
|
+
const ROUTER_GUIDE_BLOCK = `# Flash 主会话每轮近距离深度引导(dsh-router-standard 方案)。
|
|
17
|
+
# 模型为 Flash 且会话晋升后,每个真实用户消息之后追加固定引导。
|
|
18
|
+
# useCustom=true 时固定使用 text;false 按任务自动选择。
|
|
19
|
+
- id: router-guide
|
|
20
|
+
name: ./router-guide.mjs
|
|
16
21
|
config:
|
|
17
|
-
|
|
18
|
-
|
|
22
|
+
text: |-
|
|
23
|
+
__GUIDE_TEXT__
|
|
24
|
+
useCustom: __USE_GUIDE_CUSTOM__
|
|
25
|
+
enabled: __GUIDE_ENABLED__
|
|
19
26
|
`;
|
|
20
|
-
const
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
- id:
|
|
24
|
-
name: ./
|
|
27
|
+
const NEAR_ANCHOR_BLOCK = `# prompt-tool 近距离首句锚定:在首条真实用户消息之后追加一次性锚点。
|
|
28
|
+
# 不拆轮、不挪任务;useCustom=false 时按任务自动选择 we/let 首句,
|
|
29
|
+
# useCustom=true 时固定使用 anchorText。
|
|
30
|
+
- id: near-anchor
|
|
31
|
+
name: ./near-anchor.mjs
|
|
25
32
|
config:
|
|
26
33
|
anchorText: |-
|
|
27
34
|
__ANCHOR_TEXT__
|
|
35
|
+
useCustom: __USE_CUSTOM__
|
|
36
|
+
`;
|
|
37
|
+
const LOCAL_INJECTOR_BLOCK = `# prompt-tool 附加件:锚定确认后注入 preset.md。注册在工具引导之后,
|
|
38
|
+
# 不参与首轮剥离顺序;tools / 上下文剥离由 tool-bootstrap 与
|
|
39
|
+
# router-first-turn 负责(首轮 = Minimal 真实 schema + 训练原句)。
|
|
40
|
+
- id: prompt-injector
|
|
41
|
+
name: ./prompt-injector.mjs
|
|
42
|
+
config:
|
|
43
|
+
promptText: |-
|
|
44
|
+
__PROMPT_TOOL_TEXT__
|
|
28
45
|
`;
|
|
29
46
|
function parseFrontmatter(text) {
|
|
30
47
|
const match = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(text);
|
|
@@ -45,12 +62,78 @@ function parseFrontmatter(text) {
|
|
|
45
62
|
body: text.slice(match[0].length)
|
|
46
63
|
};
|
|
47
64
|
}
|
|
65
|
+
/** dsh-router-standard 的 Flash 弱路由 persona(子代理版)。 */
|
|
66
|
+
const ROUTER_FLASH_PERSONA = [
|
|
67
|
+
"You are a helpful assistant.",
|
|
68
|
+
"Before acting, decide the task type (build or fix) and adopt the matching style: build → hands-on production; fix → inspect-and-plan.",
|
|
69
|
+
"Before acting, briefly review what you have already done in this session and continue from where you left off; do not repeat completed steps. Do not run environment checks (echo, whoami, uname, node --version, date) or exhaustive grep/glob scans.",
|
|
70
|
+
"Think deeply first, then produce."
|
|
71
|
+
].join("\n");
|
|
72
|
+
/** 适配上游 context-gate:保留 near-anchor 消息;子代理沿用全量放行策略。 */
|
|
73
|
+
function normalizeContextGate(source) {
|
|
74
|
+
const block = `- id: context-gate
|
|
75
|
+
name: ./context-gate.mjs
|
|
76
|
+
config:
|
|
77
|
+
promoteOn: either
|
|
78
|
+
includeSubagents: true
|
|
79
|
+
allowKinds: [skill-invocation]`;
|
|
80
|
+
const replaced = `- id: context-gate
|
|
81
|
+
name: ./context-gate.mjs
|
|
82
|
+
config:
|
|
83
|
+
promoteOn: either
|
|
84
|
+
includeSubagents: false
|
|
85
|
+
allowKinds: [skill-invocation, near-anchor, router-guide]`;
|
|
86
|
+
if (!source.includes(block)) throw new Error("vendor agent.cordis.yml missing context-gate row");
|
|
87
|
+
return source.replace(block, replaced);
|
|
88
|
+
}
|
|
89
|
+
/** 上游可能携带作者机器固定路径;生成时统一改写为可配置 bashPath。 */
|
|
90
|
+
function normalizeBashPath(source, bashPath) {
|
|
91
|
+
const marker = /bashPath:\s*'[^']*'/.exec(source);
|
|
92
|
+
if (marker === null) throw new Error("vendor agent.cordis.yml missing bashPath row");
|
|
93
|
+
return source.replace(marker[0], `bashPath: '${bashPath}'`);
|
|
94
|
+
}
|
|
95
|
+
/** 给 subagent/subagent_fork 行加 dsh-router-standard 的 Flash 子代理方案;关闭时保持继承主会话路由。 */
|
|
96
|
+
function applySubagentFlash(source, enabled, provider, model) {
|
|
97
|
+
if (!enabled) return source;
|
|
98
|
+
const agentOptions = ` agentOptions:
|
|
99
|
+
provider: ${provider}
|
|
100
|
+
model: ${model}`;
|
|
101
|
+
const persona = ROUTER_FLASH_PERSONA.split("\n").map((line) => ` ${line}`).join("\n");
|
|
102
|
+
const targets = [{
|
|
103
|
+
id: "tool-subagent",
|
|
104
|
+
toolName: "subagent",
|
|
105
|
+
provider: "spawn"
|
|
106
|
+
}, {
|
|
107
|
+
id: "tool-subagent-fork",
|
|
108
|
+
toolName: "subagent_fork",
|
|
109
|
+
provider: "fork"
|
|
110
|
+
}];
|
|
111
|
+
let out = source;
|
|
112
|
+
for (const target of targets) {
|
|
113
|
+
const block = ` - id: ${target.id}
|
|
114
|
+
name: '@deepseek-ai/dsh-tool-subagent'
|
|
115
|
+
config:
|
|
116
|
+
provider: ${target.provider}
|
|
117
|
+
toolName: ${target.toolName}
|
|
118
|
+
backgroundMode: continuable`;
|
|
119
|
+
const replaced = `${block}
|
|
120
|
+
${agentOptions}
|
|
121
|
+
persona: |-
|
|
122
|
+
${persona}`;
|
|
123
|
+
if (!out.includes(block)) throw new Error(`vendor agent.cordis.yml missing ${target.id} row`);
|
|
124
|
+
out = out.replace(block, replaced);
|
|
125
|
+
}
|
|
126
|
+
return out;
|
|
127
|
+
}
|
|
48
128
|
function buildCordis(prompt, options = {}) {
|
|
49
129
|
const anchorFirstTurn = options.anchorFirstTurn === true;
|
|
130
|
+
const anchorCustom = options.anchorCustom === true;
|
|
131
|
+
const guideCustom = options.guideCustom === true;
|
|
132
|
+
const guideText = typeof options.guideText === "string" && options.guideText.length > 0 ? options.guideText : "";
|
|
50
133
|
const injectPrompt = options.injectPrompt !== false;
|
|
51
|
-
const anchorText = typeof options.anchorText === "string" && options.anchorText.length > 0 ? options.anchorText : "
|
|
134
|
+
const anchorText = typeof options.anchorText === "string" && options.anchorText.length > 0 ? options.anchorText : "";
|
|
52
135
|
const indent = (s) => s.split(/\r?\n/).map((l) => l.length === 0 ? "" : " " + l).join("\n");
|
|
53
|
-
const up = readFileSync(VENDOR_CORDIS, "utf8").replace(/\r\n/g, "\n");
|
|
136
|
+
const up = normalizeContextGate(normalizeBashPath(applySubagentFlash(readFileSync(VENDOR_CORDIS, "utf8").replace(/\r\n/g, "\n"), options.subagentFlash === true, typeof options.subagentFlashProvider === "string" && options.subagentFlashProvider.length > 0 ? options.subagentFlashProvider : "deepseek-official", typeof options.subagentFlashModel === "string" && options.subagentFlashModel.length > 0 ? options.subagentFlashModel : "deepseek-v4-flash"), typeof options.bashPath === "string" && options.bashPath.length > 0 ? options.bashPath : "bash.exe"));
|
|
54
137
|
const bootstrap = /^-\s+id:\s+tool-bootstrap\s*$/m.exec(up);
|
|
55
138
|
if (!bootstrap) throw new Error("vendor agent.cordis.yml missing tool-bootstrap row");
|
|
56
139
|
let cursor = up.indexOf("\n", bootstrap.index);
|
|
@@ -71,11 +154,13 @@ function buildCordis(prompt, options = {}) {
|
|
|
71
154
|
const head = up.slice(0, insertAt);
|
|
72
155
|
const tail = up.slice(insertAt);
|
|
73
156
|
const separator = head.endsWith("\n\n") ? "" : head.endsWith("\n") ? "\n" : "\n\n";
|
|
74
|
-
const
|
|
157
|
+
const guideBlock = ROUTER_GUIDE_BLOCK.replace(" useCustom: __USE_GUIDE_CUSTOM__", ` useCustom: ${anchorFirstTurn && guideCustom}`).replace(" enabled: __GUIDE_ENABLED__", ` enabled: ${anchorFirstTurn}`).replace(" text: |-\n __GUIDE_TEXT__", " text: |-\n" + (guideText.length > 0 ? indent(guideText) : " "));
|
|
158
|
+
const parts = [ROUTER_FIRST_TURN_BLOCK, guideBlock];
|
|
75
159
|
if (anchorFirstTurn) {
|
|
76
160
|
const anchorMarker = " anchorText: |-\n __ANCHOR_TEXT__";
|
|
77
|
-
if (!
|
|
78
|
-
|
|
161
|
+
if (!NEAR_ANCHOR_BLOCK.includes(anchorMarker)) throw new Error("internal error: near-anchor template lost its anchorText placeholder");
|
|
162
|
+
const anchorBlock = NEAR_ANCHOR_BLOCK.replace(" useCustom: __USE_CUSTOM__", ` useCustom: ${anchorCustom}`).replace(anchorMarker, " anchorText: |-\n" + (anchorText.length > 0 ? indent(anchorText) : " "));
|
|
163
|
+
parts.push(anchorBlock);
|
|
79
164
|
}
|
|
80
165
|
if (injectPrompt) {
|
|
81
166
|
const promptMarker = " promptText: |-\n __PROMPT_TOOL_TEXT__";
|
|
@@ -84,7 +169,7 @@ function buildCordis(prompt, options = {}) {
|
|
|
84
169
|
}
|
|
85
170
|
const extra = parts.join("\n");
|
|
86
171
|
const out = head + separator + extra + "\n" + tail;
|
|
87
|
-
if (injectPrompt && out.includes("__PROMPT_TOOL_TEXT__") || anchorFirstTurn && out.includes("__ANCHOR_TEXT__")) throw new Error("internal error: preset template placeholder was not replaced");
|
|
172
|
+
if (injectPrompt && out.includes("__PROMPT_TOOL_TEXT__") || anchorFirstTurn && (out.includes("__ANCHOR_TEXT__") || out.includes("__USE_CUSTOM__")) || out.includes("__GUIDE_TEXT__") || out.includes("__USE_GUIDE_CUSTOM__") || out.includes("__GUIDE_ENABLED__")) throw new Error("internal error: preset template placeholder was not replaced");
|
|
88
173
|
let parsed;
|
|
89
174
|
try {
|
|
90
175
|
parsed = parse(out, { logLevel: "silent" });
|
|
@@ -93,9 +178,11 @@ function buildCordis(prompt, options = {}) {
|
|
|
93
178
|
}
|
|
94
179
|
if (!Array.isArray(parsed)) throw new Error("generated agent.cordis.yml is not a YAML array");
|
|
95
180
|
const ids = new Set(parsed.map((row) => row?.id));
|
|
181
|
+
if (!ids.has("router-first-turn")) throw new Error("generated agent.cordis.yml is missing the router-first-turn row");
|
|
96
182
|
if (injectPrompt && !ids.has("prompt-injector")) throw new Error("generated agent.cordis.yml is missing the prompt-injector row");
|
|
97
183
|
if (!injectPrompt && ids.has("prompt-injector")) throw new Error("generated agent.cordis.yml still contains the prompt-injector row");
|
|
98
|
-
if (anchorFirstTurn && !ids.has("
|
|
184
|
+
if (anchorFirstTurn && !ids.has("near-anchor")) throw new Error("generated agent.cordis.yml is missing the near-anchor row");
|
|
185
|
+
if (!anchorFirstTurn && ids.has("near-anchor")) throw new Error("generated agent.cordis.yml still contains the near-anchor row");
|
|
99
186
|
return out;
|
|
100
187
|
}
|
|
101
188
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-plugin-prompt-tool",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "DSH 插件:提示词工具,规范模型的思维链与回答内容,提供 Web UI 编辑 preset.md 与 AGENTS.md,并按 skills 目录注册可开关技能。",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -74,21 +74,20 @@
|
|
|
74
74
|
"cordis.patch.yml",
|
|
75
75
|
"LICENSE",
|
|
76
76
|
"preset",
|
|
77
|
-
"vendor/dsh-anchored-standard/preset",
|
|
78
|
-
"vendor/dsh-anchored-standard/LICENSE",
|
|
79
|
-
"vendor/dsh-anchored-standard/NOTICE",
|
|
80
77
|
"skills",
|
|
81
78
|
"preset.md",
|
|
82
79
|
"AGENTS.md",
|
|
83
80
|
"plan.md",
|
|
84
|
-
"README.md"
|
|
81
|
+
"README.md",
|
|
82
|
+
"upstream/dsh-anchored-standard"
|
|
85
83
|
],
|
|
86
84
|
"scripts": {
|
|
87
85
|
"build": "tsdown",
|
|
88
86
|
"prepare": "tsdown",
|
|
89
87
|
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.client.json --noEmit",
|
|
90
88
|
"lint": "oxlint src test tsdown.config.ts",
|
|
91
|
-
"test": "pnpm build && node --test \"test/*.test.mjs\""
|
|
89
|
+
"test": "pnpm build && node --test \"test/*.test.mjs\"",
|
|
90
|
+
"sync:anchored": "node scripts/sync-anchored.mjs"
|
|
92
91
|
},
|
|
93
92
|
"dependencies": {
|
|
94
93
|
"yaml": "^2.9.0"
|