@morlay/dsh-preset 0.0.1 → 0.0.3
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
CHANGED
|
@@ -47,10 +47,44 @@ preset 自带的 `persona` 行会在 agent scope 注册 `deployment:persona-pref
|
|
|
47
47
|
固化了该语义),所以生成器把那一行**删掉**,而不是复制一份改过的 persona——同一份
|
|
48
48
|
文案只维护一处。
|
|
49
49
|
|
|
50
|
+
### 指令遵循设计
|
|
51
|
+
|
|
52
|
+
`personaPrefix` 位于 order 0(prompt 最前,紧跟被关掉的 harness identity 之后):
|
|
53
|
+
声明指令优先级(直接用户指令 > 工作区 `AGENTS.md` > 本系统提示词)与执行协议。其中
|
|
54
|
+
点名 `AGENTS.md` 是**强制约束**——官方 `agent-instructions` 注入模板的措辞
|
|
55
|
+
("may be relevant" / "as guidance" / "do not override…")是上游的通用保守表述,会让
|
|
56
|
+
模型把仓库规则当参考而不是规则,所以这里显式反制。协议一行覆盖:动手前读相关
|
|
57
|
+
`AGENTS.md`、过程自检、交付前核对红线与验证证据、无法遵守时明确说明、派发子代理时
|
|
58
|
+
把约束写进任务说明。
|
|
59
|
+
|
|
60
|
+
`personaSuffix` 位于 order 10200(prompt 最后):一句话复述"结束任务前对照本提示词与
|
|
61
|
+
`AGENTS.md` 自检"。长 prompt 里中段指令会被稀释,首尾各放一次最关键的约束,用近因
|
|
62
|
+
位置兜住遵循度;细节只在 prefix 维护,避免两处重复。
|
|
63
|
+
|
|
64
|
+
改这两段后**必须重启 dsh 才能生效**:profile 在进程启动时装载,`system-prompt` 的
|
|
65
|
+
section 在插件构造时注册;dev 模式重启 `just custom dev`/`just custom desktop`,打包
|
|
66
|
+
形态需重新 `just custom bundle`(patch 随 seed 快照复制)。
|
|
67
|
+
|
|
50
68
|
自建 preset 仍然必要,但只为别的事:`includeShippedRoot: false` 之后需要一份自己的
|
|
51
69
|
roster(id 沿用官方名以走客户端语言字典),以及桌面形态下 preset 必须落在 dsh 包的
|
|
52
70
|
`config/agent-presets` 挂载点(见 dsh-desktopify 的 `dsh.desktop.agentPresets`)。
|
|
53
71
|
|
|
72
|
+
## 工作区指令走官方行为,候选收紧为 AGENTS 系列
|
|
73
|
+
|
|
74
|
+
preset 里的 `agent-instructions` 行仍是官方 `@deepseek-ai/dsh-agent-instructions`:
|
|
75
|
+
本仓库的 fork `@morlay/dsh-agent-instructions-as-prompt` 暂不接入默认打包,baseline
|
|
76
|
+
仍按官方语义作为 user 消息注入一次。生成器只覆盖该行 config 的两个字段:
|
|
77
|
+
|
|
78
|
+
```yaml
|
|
79
|
+
instructionFileCandidates: ["AGENTS.md"] # 上游默认 ['AGENTS.md','CLAUDE.md']
|
|
80
|
+
localInstructionFileCandidates: ["AGENTS.local.md"] # 上游默认还含 CLAUDE.local.md
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
即**不读 CLAUDE 系列**(本部署不需要 CLAUDE 兼容);`maxBytes` 等其余字段跟随上游。
|
|
84
|
+
|
|
85
|
+
fork 源码保留在 `packages/preset/dsh-agent-instructions-as-prompt/`;后续要恢复时按
|
|
86
|
+
它的 README 操作:生成器把该行 `name` 换成 fork 名,profile 侧再禁用上游行。
|
|
87
|
+
|
|
54
88
|
## preset 由构建生成,不是手工副本
|
|
55
89
|
|
|
56
90
|
产物落在 `dist/`,由 tsdown 的 `build:done` hook 在每次 `pnpm build` 时生成
|
|
@@ -68,11 +102,10 @@ pnpm --filter @morlay/dsh-preset run generate-presets [outDir]
|
|
|
68
102
|
```
|
|
69
103
|
|
|
70
104
|
脚本把上游 composition 当**数据**读入:`js-yaml` 用 include 的
|
|
71
|
-
`entryListSchema` 解析(`!!js` 标签保留为表达式节点)→ 在 JS
|
|
72
|
-
`persona`
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
通过。
|
|
105
|
+
`entryListSchema` 解析(`!!js` 标签保留为表达式节点)→ 在 JS 里改一处(删掉
|
|
106
|
+
`persona` 行)→ `dump` 回 YAML。因此上游任何结构性改动(新增 / 重命名 row、改字段)
|
|
107
|
+
都自动跟随,不依赖易碎的文本锚点;上游若删掉 `persona` 行,目标(preset 不自带
|
|
108
|
+
persona)本就达成,脚本照常通过。
|
|
76
109
|
|
|
77
110
|
脚本先**整目录清空**输出目录再生成:产物完全派生自脚本,残留目录(改过
|
|
78
111
|
`source`、旧命名)不该留下——否则 discovery 会把它们当有效 preset 扫出来。
|
package/cordis.patch.yml
CHANGED
|
@@ -2,15 +2,21 @@
|
|
|
2
2
|
config:
|
|
3
3
|
includeHarnessIdentity: false
|
|
4
4
|
includeRuntimeContext: false
|
|
5
|
-
personaSuffix:
|
|
5
|
+
personaSuffix: 你的工作目录在 `{{cwd}}`
|
|
6
6
|
personaPrefix: |-
|
|
7
7
|
你是一个经验丰富的编程专家,YAGNI 是你的编程哲学,PDCA 是你的行为规范
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## 指令遵循(强制)
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
-
|
|
11
|
+
以下指令都是**约束**而非建议;冲突时按 用户的直接指令 > 工作区 `AGENTS.md` > 全局提示词 取舍并说明:
|
|
12
|
+
|
|
13
|
+
- **工作区 `AGENTS.md`**(仓库根与目录链,随 `<system-reminder>` 注入):「红线」与命令约定必须遵守。模板里的 "may be relevant"、"as guidance" 是通用保守措辞,不表示可以跳过。
|
|
14
|
+
- **全局提示词**:
|
|
15
|
+
- 所有思考、分析、推理过程、工具调用描述等必须使用中文,专有名词除外
|
|
16
|
+
- 思考不要陷入重复循环,一旦循环,立即退出
|
|
17
|
+
- 思考聚焦需求理解与方案设计(要点、流程、验证策略),不预演具体代码实现;代码在 Do 阶段基于实际文件状态输出,正确性由 Check 验证
|
|
18
|
+
|
|
19
|
+
协议:动手前读相关 `AGENTS.md`(不凭记忆);过程中自检、违反即纠正;交付前核对红线与验证证据,未验证项必须标注;无法遵守时立即说明(不静默忽略、不自行判定「不适用」);派发子代理时把约束写进任务说明。
|
|
14
20
|
|
|
15
21
|
- id: agent-presets
|
|
16
22
|
config:
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
# 本文件由 packages/dsh-preset/tool/generate-presets.ts 生成,请勿手工编辑
|
|
2
2
|
- id: agent-instructions
|
|
3
|
-
name: "@
|
|
3
|
+
name: "@deepseek-ai/dsh-agent-instructions"
|
|
4
4
|
config:
|
|
5
5
|
maxBytes: 65536
|
|
6
|
+
instructionFileCandidates:
|
|
7
|
+
- AGENTS.md
|
|
8
|
+
localInstructionFileCandidates:
|
|
9
|
+
- AGENTS.local.md
|
|
6
10
|
- id: tool-bash
|
|
7
11
|
name: "@deepseek-ai/dsh-tool-bash"
|
|
8
12
|
disabled: !!js process.platform === 'win32'
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
# 本文件由 packages/dsh-preset/tool/generate-presets.ts 生成,请勿手工编辑
|
|
2
2
|
- id: agent-instructions
|
|
3
|
-
name: "@
|
|
3
|
+
name: "@deepseek-ai/dsh-agent-instructions"
|
|
4
4
|
config:
|
|
5
5
|
maxBytes: 65536
|
|
6
|
+
instructionFileCandidates:
|
|
7
|
+
- AGENTS.md
|
|
8
|
+
localInstructionFileCandidates:
|
|
9
|
+
- AGENTS.local.md
|
|
6
10
|
- id: tool-bash
|
|
7
11
|
name: "@deepseek-ai/dsh-tool-bash"
|
|
8
12
|
disabled: !!js process.platform === 'win32'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@morlay/dsh-preset",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "Personal dsh profile bundle: disables the shipped agent presets, builds generated standard / ptc presets into dist, and declares personal llm-pi-ai provider routes.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dsh",
|
|
@@ -25,9 +25,6 @@
|
|
|
25
25
|
"./package.json": "./package.json",
|
|
26
26
|
"./cordis.patch.yml": "./cordis.patch.yml"
|
|
27
27
|
},
|
|
28
|
-
"dependencies": {
|
|
29
|
-
"@morlay/dsh-agent-instructions-as-prompt": "^0.0.1"
|
|
30
|
-
},
|
|
31
28
|
"devDependencies": {
|
|
32
29
|
"@deepseek-ai/cordis-plugin-include": "^1.0.7",
|
|
33
30
|
"@deepseek-ai/dsh-agent-presets": "^0.1.5-rc.2",
|
|
@@ -40,7 +37,14 @@
|
|
|
40
37
|
"dsh": {
|
|
41
38
|
"bundle": {
|
|
42
39
|
"patch": "./cordis.patch.yml"
|
|
43
|
-
}
|
|
40
|
+
},
|
|
41
|
+
"configTrees": [
|
|
42
|
+
{
|
|
43
|
+
"mount": "config/agent-presets",
|
|
44
|
+
"path": "dist/presets",
|
|
45
|
+
"scanRoster": true
|
|
46
|
+
}
|
|
47
|
+
]
|
|
44
48
|
},
|
|
45
49
|
"scripts": {
|
|
46
50
|
"build": "pnpm exec tsdown"
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 生成产物的回归测试:`dist/presets/standard` / `dist/presets/ptc` 必须等于
|
|
3
|
-
* 「上游 composition
|
|
3
|
+
* 「上游 composition 删 persona 行、指令候选收紧为 AGENTS 系列」的版本。
|
|
4
4
|
*
|
|
5
5
|
* 断言方式是把产物与**现算的**期望值比较,而不是与一份快照比——上游升级后
|
|
6
|
-
* 忘记重跑构建时,这条测试会失败并指出 drift
|
|
6
|
+
* 忘记重跑构建时,这条测试会失败并指出 drift,而不是继续绿着。期望值由测试
|
|
7
|
+
* 自己解析上游推出、不经过被测的 `renderComposition`:生成器多删 / 改任何
|
|
8
|
+
* 一行都会失败,而不是自证。
|
|
7
9
|
*
|
|
8
10
|
* 产物在 dist(构建输出,gitignore),因此测试自身调用 `generatePresets` 到
|
|
9
11
|
* 临时目录,不依赖 build 是否跑过。
|
|
@@ -13,47 +15,112 @@
|
|
|
13
15
|
import { mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync } from "node:fs";
|
|
14
16
|
import { tmpdir } from "node:os";
|
|
15
17
|
import { join } from "node:path";
|
|
18
|
+
import { entryListSchema } from "@deepseek-ai/cordis-plugin-include";
|
|
19
|
+
import yaml from "js-yaml";
|
|
16
20
|
import { afterAll, describe, expect, it } from "vitest";
|
|
17
21
|
import {
|
|
18
22
|
PRESET_SOURCES,
|
|
19
|
-
INSTRUCTIONS_PLUGIN,
|
|
20
23
|
PERSONA_ROW_ID,
|
|
21
24
|
UPSTREAM_PRESETS,
|
|
22
25
|
generatePresets,
|
|
23
|
-
renderComposition,
|
|
24
26
|
renderMetadata,
|
|
25
27
|
} from "../../tool/generate-presets.ts";
|
|
26
28
|
|
|
29
|
+
/** 上游 preset 里承载工作区指令的行 id。 */
|
|
30
|
+
const INSTRUCTIONS_ROW_ID = "agent-instructions";
|
|
31
|
+
|
|
32
|
+
/** 上游那行指向的官方插件(fork 暂未接入,产物须保持官方名)。 */
|
|
33
|
+
const UPSTREAM_INSTRUCTIONS_PLUGIN = "@deepseek-ai/dsh-agent-instructions";
|
|
34
|
+
|
|
35
|
+
/** 产物里指令候选的文件名(字面量:不读 CLAUDE 系列)。 */
|
|
36
|
+
const PRODUCT_INSTRUCTION_CANDIDATES = ["AGENTS.md"];
|
|
37
|
+
const PRODUCT_LOCAL_INSTRUCTION_CANDIDATES = ["AGENTS.local.md"];
|
|
38
|
+
|
|
39
|
+
/** 上游 composition 的一行;比较只看结构。 */
|
|
40
|
+
type CompositionRow = {
|
|
41
|
+
id?: string;
|
|
42
|
+
name?: string;
|
|
43
|
+
config?: Record<string, unknown>;
|
|
44
|
+
[key: string]: unknown;
|
|
45
|
+
};
|
|
46
|
+
|
|
27
47
|
const OUT_DIR = mkdtempSync(join(tmpdir(), "dsh-preset-"));
|
|
28
48
|
afterAll(() => {
|
|
29
49
|
rmSync(OUT_DIR, { recursive: true, force: true });
|
|
30
50
|
});
|
|
31
51
|
generatePresets(OUT_DIR);
|
|
32
52
|
|
|
53
|
+
/** 独立解析 composition 文本(include 的 schema,`!!js` 标签保留为表达式节点)。 */
|
|
54
|
+
function parseRows(text: string): CompositionRow[] {
|
|
55
|
+
return yaml.load(text, { schema: entryListSchema }) as CompositionRow[];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** 解析上游 preset 与生成产物。 */
|
|
59
|
+
function readPair(source: string): { upstream: CompositionRow[]; product: CompositionRow[] } {
|
|
60
|
+
return {
|
|
61
|
+
upstream: parseRows(readFileSync(join(UPSTREAM_PRESETS, source, "agent.cordis.yml"), "utf8")),
|
|
62
|
+
product: parseRows(readFileSync(join(OUT_DIR, source, "agent.cordis.yml"), "utf8")),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** 生成器对上游 composition 的期望改动:删 persona 行、收紧指令候选。 */
|
|
67
|
+
function expectedRows(upstream: CompositionRow[]): CompositionRow[] {
|
|
68
|
+
return upstream
|
|
69
|
+
.filter((row) => row.id !== PERSONA_ROW_ID)
|
|
70
|
+
.map((row) =>
|
|
71
|
+
row.id === INSTRUCTIONS_ROW_ID
|
|
72
|
+
? {
|
|
73
|
+
...row,
|
|
74
|
+
config: {
|
|
75
|
+
...row.config,
|
|
76
|
+
instructionFileCandidates: PRODUCT_INSTRUCTION_CANDIDATES,
|
|
77
|
+
localInstructionFileCandidates: PRODUCT_LOCAL_INSTRUCTION_CANDIDATES,
|
|
78
|
+
},
|
|
79
|
+
}
|
|
80
|
+
: row,
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
33
84
|
describe("generated presets", () => {
|
|
34
85
|
it.each(PRESET_SOURCES)(
|
|
35
|
-
"$source
|
|
86
|
+
"$source equals its upstream source with only the persona row dropped and the instruction candidates narrowed",
|
|
36
87
|
(entry) => {
|
|
37
|
-
const upstream =
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
);
|
|
41
|
-
const actual = readFileSync(join(OUT_DIR, entry.source, "agent.cordis.yml"), "utf8");
|
|
42
|
-
expect(actual).toBe(renderComposition(entry.source, upstream));
|
|
88
|
+
const { upstream, product } = readPair(entry.source);
|
|
89
|
+
// 期望由测试自行推出:上游删 persona 行 + 收紧候选,其余逐行不动。
|
|
90
|
+
expect(product).toEqual(expectedRows(upstream));
|
|
43
91
|
},
|
|
44
92
|
);
|
|
45
93
|
|
|
46
|
-
it.each(PRESET_SOURCES)(
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
94
|
+
it.each(PRESET_SOURCES)(
|
|
95
|
+
"$source keeps the agent-instructions row on the upstream plugin with AGENTS-only candidates",
|
|
96
|
+
(entry) => {
|
|
97
|
+
const { upstream, product } = readPair(entry.source);
|
|
98
|
+
const upstreamRow = upstream.find((row) => row.id === INSTRUCTIONS_ROW_ID);
|
|
99
|
+
const productRow = product.find((row) => row.id === INSTRUCTIONS_ROW_ID);
|
|
100
|
+
// 官方插件名保持(fork 一旦接入即失败,改名也不失效)。
|
|
101
|
+
expect(upstreamRow?.name).toBe(UPSTREAM_INSTRUCTIONS_PLUGIN);
|
|
102
|
+
expect(productRow?.name).toBe(upstreamRow?.name);
|
|
103
|
+
// 候选收紧为 AGENTS 系列:CLAUDE 系列不再被读取。
|
|
104
|
+
expect(productRow?.config?.instructionFileCandidates).toEqual(["AGENTS.md"]);
|
|
105
|
+
expect(productRow?.config?.localInstructionFileCandidates).toEqual(["AGENTS.local.md"]);
|
|
106
|
+
// 其余 config 字段跟随上游(如 maxBytes 的字节预算)。
|
|
107
|
+
expect(productRow?.config?.maxBytes).toBe(upstreamRow?.config?.maxBytes);
|
|
108
|
+
// 产物里不应出现本仓库的插件行。
|
|
109
|
+
expect(
|
|
110
|
+
product.some((row) => typeof row.name === "string" && row.name.startsWith("@morlay/")),
|
|
111
|
+
).toBe(false);
|
|
112
|
+
},
|
|
113
|
+
);
|
|
53
114
|
|
|
54
115
|
it.each(PRESET_SOURCES)("$source carries generated metadata", (entry) => {
|
|
55
116
|
const actual = readFileSync(join(OUT_DIR, entry.source, "preset.yml"), "utf8");
|
|
56
117
|
expect(actual).toBe(renderMetadata(entry));
|
|
118
|
+
// 字段级校验:多写 / 漏写字段在这里失败(上面的逐字比较是自指的)。
|
|
119
|
+
expect(yaml.load(actual)).toEqual({
|
|
120
|
+
name: entry.name,
|
|
121
|
+
description: entry.description,
|
|
122
|
+
order: entry.order,
|
|
123
|
+
});
|
|
57
124
|
});
|
|
58
125
|
|
|
59
126
|
it("drops the persona row: the deployment system-prompt owns the persona", () => {
|
package/tool/generate-presets.ts
CHANGED
|
@@ -6,8 +6,11 @@
|
|
|
6
6
|
* 必须随包发布;但手工维护副本会与上游 drift。这里把上游 `standard` / `ptc`
|
|
7
7
|
* 当数据读入——`js-yaml` 用 include 的 `entryListSchema` 解析(`!!js` 标签
|
|
8
8
|
* 因此保留为表达式节点)——在 JS 里改两处(删掉自带的 `persona` 行、把
|
|
9
|
-
* `agent-instructions`
|
|
10
|
-
*
|
|
9
|
+
* `agent-instructions` 行的指令候选收紧为 AGENTS 系列),再 `dump` 回 YAML。
|
|
10
|
+
* 上游任何结构性改动(新增/重命名 row、改字段)都自动跟随,不依赖易碎的文本锚点。
|
|
11
|
+
*
|
|
12
|
+
* `agent-instructions` 行仍是上游官方插件:fork
|
|
13
|
+
* (`@morlay/dsh-agent-instructions-as-prompt`)暂不接入,工作区指令走官方行为。
|
|
11
14
|
*
|
|
12
15
|
* 产物落在 `dist/` 而非源码树:dist 是构建输出(gitignore),既不会与 oxfmt
|
|
13
16
|
* 互相改格式,也不会把派生文件混进源码。
|
|
@@ -75,39 +78,41 @@ export const PERSONA_ROW_ID = "persona";
|
|
|
75
78
|
export const INSTRUCTIONS_ROW_ID = "agent-instructions";
|
|
76
79
|
|
|
77
80
|
/**
|
|
78
|
-
*
|
|
81
|
+
* 工作区指令的候选文件:只要 AGENTS 系列,不要 CLAUDE 系列。
|
|
79
82
|
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
+
* 上游默认是 `['AGENTS.md','CLAUDE.md']` 与 `['AGENTS.local.md','CLAUDE.local.md']`;
|
|
84
|
+
* 本部署不读 CLAUDE 系文件(覆盖上游 config 的这两个字段,其余字段如 `maxBytes`
|
|
85
|
+
* 保持上游值)。行本身仍是官方 `@deepseek-ai/dsh-agent-instructions`——fork 暂未
|
|
86
|
+
* 接入,见模块注释。
|
|
83
87
|
*/
|
|
84
|
-
export const
|
|
88
|
+
export const INSTRUCTIONS_CONFIG = {
|
|
89
|
+
instructionFileCandidates: ["AGENTS.md"],
|
|
90
|
+
localInstructionFileCandidates: ["AGENTS.local.md"],
|
|
91
|
+
} as const;
|
|
85
92
|
|
|
86
93
|
/**
|
|
87
|
-
* 把上游 composition 文本渲染成产物文本:解析 →
|
|
88
|
-
* @param source - 上游 preset id,用于 header 与诊断。
|
|
94
|
+
* 把上游 composition 文本渲染成产物文本:解析 → 删 persona 行、收紧指令候选 → dump。
|
|
89
95
|
* @param upstream - 上游 composition 文本。
|
|
90
96
|
* @returns 带 header 的产物文本。
|
|
91
97
|
*/
|
|
92
|
-
export function renderComposition(
|
|
98
|
+
export function renderComposition(upstream: string): string {
|
|
93
99
|
const rows = yaml.load(upstream, {
|
|
94
100
|
schema: entryListSchema,
|
|
95
101
|
}) as CompositionRow[];
|
|
96
|
-
const instructions = rows.find((row) => row.id === INSTRUCTIONS_ROW_ID);
|
|
97
|
-
if (instructions === undefined) {
|
|
98
|
-
throw new Error(
|
|
99
|
-
`generate-presets: upstream \`${source}\` has no \`${INSTRUCTIONS_ROW_ID}\` row; ` +
|
|
100
|
-
"upstream changed — re-check which plugin loads the workspace instructions",
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
instructions.name = INSTRUCTIONS_PLUGIN;
|
|
105
102
|
// 删掉 preset 自带的 `persona` 行:它会在 agent scope 注册
|
|
106
103
|
// `deployment:persona-prefix` 并**遮蔽**部署级 persona(system-prompt 的
|
|
107
104
|
// personaPrefix,见上游 system-prompt 的 Config 文档)。个人提示词只由
|
|
108
105
|
// `cordis.patch.yml` 的 system-prompt 行提供,这里不再复制一份。
|
|
109
106
|
const persona = rows.findIndex((row) => row.id === PERSONA_ROW_ID);
|
|
110
107
|
if (persona >= 0) rows.splice(persona, 1);
|
|
108
|
+
const instructions = rows.find((row) => row.id === INSTRUCTIONS_ROW_ID);
|
|
109
|
+
if (instructions === undefined) {
|
|
110
|
+
throw new Error(
|
|
111
|
+
`generate-presets: upstream composition has no \`${INSTRUCTIONS_ROW_ID}\` row; ` +
|
|
112
|
+
"upstream changed — re-check which plugin loads the workspace instructions",
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
instructions.config = { ...instructions.config, ...INSTRUCTIONS_CONFIG };
|
|
111
116
|
// `quotingType: '"'` 是刻意选择:yaml.dump 默认用单引号,而仓库的 oxfmt 会把
|
|
112
117
|
// YAML 单引号改成双引号——不显式指定就会 fmt 与生成器来回改。指定后产物与
|
|
113
118
|
// `oxfmt --check` 零差异(实测),故 `presets/**` 无需 fmt 忽略。
|
|
@@ -144,7 +149,7 @@ export function generatePresets(outDir: string = join(PACKAGE_ROOT, PRESETS_OUT_
|
|
|
144
149
|
const dir = join(outDir, entry.source);
|
|
145
150
|
mkdirSync(dir, { recursive: true });
|
|
146
151
|
const compositionPath = join(dir, "agent.cordis.yml");
|
|
147
|
-
writeFileSync(compositionPath, renderComposition(
|
|
152
|
+
writeFileSync(compositionPath, renderComposition(upstream));
|
|
148
153
|
const metadataPath = join(dir, "preset.yml");
|
|
149
154
|
writeFileSync(metadataPath, renderMetadata(entry));
|
|
150
155
|
written.push(compositionPath, metadataPath);
|