@morlay/dsh-context-assembler 0.0.1-alpha.2

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 morlay
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,154 @@
1
+ # @morlay/dsh-context-assembler
2
+
3
+ 提示词注入能力组:**一个包四个能力**——主出口是组装插件(所以装配面只有一行),各能力另有子出口可单独装;
4
+ 能力名就是子出口名。装配行是 `@morlay/dsh-context-assembler`(组装)或 `@morlay/dsh-context-assembler/<capability>`(单个),
5
+ 见 [`src/rows.ts` 的 `contextChannel()`](./src/rows.ts)。引用展开原先也在这个包里,
6
+ 现在独立成 [`@morlay/dsh-reference`](../dsh-reference/README.md)(它只挂 `agent/pre-step`、不依赖通道)。
7
+
8
+ | 出口 | 行 id / 插件 name | 做什么 |
9
+ | ---------------------- | --------------------------------------------------------- | ---------------------------------------------------------------------- |
10
+ | `.` | `context-assembler`(插件 name `context-assembler-tree`) | **组装出口**:按 config 决定装哪些能力、各带什么参数(缺省即四套能力) |
11
+ | `./assembler` | `context-assembler` | 注入通道:唯一渲染者与唯一覆盖判定处,发布 `ctx.contextAssembler` |
12
+ | `./agent-instructions` | `context-agent-instructions` | 工作区指令链(`$DSH_HOME/AGENTS.md` + 项目根到 cwd 逐级) |
13
+ | `./skill-catalog` | `context-skill-catalog` | skill 目录规则块 + 模型侧 `skill` 工具 |
14
+ | `./scope` | `context-scope` | 模式收口:工具白名单、instruction 总开关、动态快照开关 |
15
+
16
+ 规则、id 表与分层的 home 在 [上下文注入规则](./.agents/designs/20260921-上下文注入规则.md);术语见
17
+ [本包 CONTEXT](./.agents/CONTEXT.md)。
18
+
19
+ ## 装配
20
+
21
+ `dsh.profile.bundles` 列出本包即装**一次**:`cordis.patch.yml` 是一行组装出口(显式给三项能力:通道本体、
22
+ `agent-instructions`、`skill-catalog`;config 的 `capabilities` 缺省是全部四项)。**不做隔离**——工具说明
23
+ ([`@morlay/dsh-agent-toolkit`](../../profile/dsh-agent-toolkit/README.md) 的 `guidance`)这类消费者住在别的包里,
24
+ 隔离会把它们挡在组外(行停在 waiting,不报错);理由见
25
+ [ADR 通道作为全局服务装配不隔离](./.agents/adrs/20260923-通道作为全局服务装配不隔离.md)。`scope` **不在这份 patch 里**
26
+ ——它是模式的开关,由 [`@morlay/dsh-agent-preset`](../../profile/dsh-agent-preset/README.md) 用 `scopeRow()` 按模式装
27
+ (它 `inject` 通道,`ctx.get("contextAssembler")` 在 agent 子树里可达)。
28
+
29
+ 工具说明(汉化 / 精简 / 用法分组)也不在这里:它归
30
+ [`@morlay/dsh-agent-toolkit`](../../profile/dsh-agent-toolkit/README.md),同样在 profile 平面装一次。
31
+
32
+ ## 装配形态
33
+
34
+ 本包是 bundle:`cordis.patch.yml` 由 [`tool/patch.ts`](./tool/patch.ts) 从 [`src/rows.ts`](./src/rows.ts) 渲染,
35
+ `rows` 出口导出同一份清单。`dsh.profile.bundles` 列出本包即装一次,**服务全局共享、不隔离**;preset 只用
36
+ `scopeRow()` 按模式收口(工具白名单 / instruction / 动态快照),别的包的行(工具说明、skill 目录)直接 `inject`
37
+ 同一份通道。
38
+
39
+ ## 为什么合成一个包
40
+
41
+ 这 4 个能力**总是一起装配**(通道在装配平面装一份、不隔离:注入方住在别的包里,隔离会把它们挡在组外),
42
+ 注入方**全都只用通道的类型与服务面**。包边界在这里只是演进留下的:合成一个包之后,加一个能力 = 加一个子出口,装配面不动
43
+ (组装出口按 config 装它)。
44
+
45
+ 工具说明(汉化精简 + 用法分组)也不住在这里:它管的是"工具怎么被讲清楚",与工具的清单同源,
46
+ 现在归 [`@morlay/dsh-agent-toolkit`](../../profile/dsh-agent-toolkit/README.md)(它也 `inject` 通道,装的是同一份
47
+ 全局通道)。本包只做上下文重排。
48
+
49
+ 引用展开不住在这里:它不依赖 `ctx.contextAssembler`(`inject` 只有 `skills`),也没有「读文件 + 字节预算」
50
+ 以外与组装出口共享的东西,所以独立成包、由 [`@morlay/better-session`](../../session/better-session/cordis.patch.yml)
51
+ 装配(见 [ADR-引用展开拆成独立包](../../../.agents/adrs/20260923-引用展开拆成独立包并按profile装配.md))。
52
+
53
+ **每个出口仍是独立的 cordis 插件**(各自的 `apply` 与 `inject`)——这一点是硬要求:合成单入口会让 `inject`
54
+ 变成并集(`agents, contextAssembler, skills, systemPrompt, tools`),任何一个可选搭档缺席都拖垮整包。
55
+
56
+ ## assembler
57
+
58
+ 注入的唯一通道。system prompt 里只留 `keep`(部署 persona + 覆盖规则),其余 section 按处置分流:丢弃
59
+ (平台说明)、改写(两段中文文案)、或降级成规则块;pre-step 时把要送的内容逐条以 `<system-reminder>`
60
+ user 消息注入(每条按文本幂等,只有变化的那条重发)。
61
+
62
+ | 声明 | 到达方式 |
63
+ | ------------------------------------- | -------------------------------------------------------------------------------- |
64
+ | `registerSkill` + `on-demand` | 注册成模型可用 skill:目录常驻一行摘要,正文由 `skill` 工具加载 |
65
+ | `registerSkill` + `auto` | 正文随 reminder 常驻;skill 标 `modelInvocable: false`(用户仍可 `skill:` 引用) |
66
+ | `registerRule({ id, text, source? })` | 规则块,幂等键是 `id`;`source` 声明对外身份 |
67
+ | `replaceSection` / `suppressSection` | 装配结果上的文本改写 / 丢弃 |
68
+ | `setInstructions` / `restrictTools` | 按会话登记模式的两处收口(不要 instruction / 工具白名单) |
69
+ | `visibleTools(agent, registered)` | 合成该会话的工具可见性:注册表可见 × 已登记的白名单(目录与组正文共用) |
70
+ | `hiddenSkills(visible)` | 声明了 `requires` 而入口工具一个都不可见的 skill 名 |
71
+
72
+ 配置(`keep` / `suppress` / `replace`)的默认值在 [`src/assembler/defaults.ts`](./src/assembler/defaults.ts)。
73
+ **全局一份、不隔离**:模式差异由 `context-scope` 登记(`setInstructions` / `restrictTools`)收口,跨包的
74
+ 消费者(工具说明、技能目录)直接 `inject` 同一份通道(见
75
+ [ADR 通道作为全局服务装配不隔离](./.agents/adrs/20260923-通道作为全局服务装配不隔离.md))。
76
+
77
+ ## agent-instructions
78
+
79
+ `$DSH_HOME/AGENTS.md` 加项目根到 cwd 的逐级 `AGENTS.md` / `AGENTS.local.md`,**一条文件一条 id**
80
+ (`agent-instructions:<根标识>:<文件>`,根标识是根目录的 8 位摘要——同进程两个项目根的同名文件因此不会互相
81
+ 顶掉),文件变化时只重发变了的那一份。取代上游 `@deepseek-ai/dsh-agent-instructions`(host 那行由上游
82
+ web-app bundle 自己设在 preset 平面)。
83
+
84
+ - **不跟踪 `read`/`write`/`edit`**:上游靠 touch 上浮触发刷新;本部署的 `AGENTS.md` 几乎不变,按
85
+ `mtime:size` 对账足够。
86
+ - **超预算可见**:单文件超过 `maxBytes` 时截断并留一行提示,不静默丢内容。
87
+ - **与上游的 baseline 认领对齐**:`source` 带 `kind: "agent-instructions"` + `baseline: true` +
88
+ `baselineIdentity`(身份与上游 `workspaceBaselineIdentity` 逐字相等)。少了后两样会出一个只在真会话里
89
+ 看得见的毛病:**同会话切到官方 preset 后出现两条 AGENTS.md**——上游认为基线不存在,再注入一条自己的模板
90
+ ("Use them as guidance…"),两条口径矛盾且模型无法理解为覆盖。
91
+ - 配置:`instructionFileCandidates` / `localInstructionFileCandidates`(覆盖成只读 `AGENTS*`,不含 CLAUDE
92
+ 系列)、`maxBytes`(65536)、`dshHome`。
93
+
94
+ ## skill-catalog
95
+
96
+ `skill-catalog` 规则块(`<available_skills>`,一行 `名字: 摘要`,只列模型可调用的 skill)加模型侧 `skill`
97
+ 工具。取代上游 `@deepseek-ai/dsh-tool-skill`(`skill-filesystem` 保留——它提供 skill 发现)。目录变更走
98
+ 同 id 覆盖;`auto` 的 skill 不进目录(正文已随提示送达)。
99
+
100
+ ## 工具说明(不在这个包里)
101
+
102
+ 工具的汉化精简与用法分组归 [`@morlay/dsh-agent-toolkit`](../../profile/dsh-agent-toolkit/README.md) 的 `guidance` 出口:
103
+ 族索引(加一个工具改一族)、组 skill、短描述投影、丢弃清单都在那边。它 `inject` 通道,装的是同一份全局通道
104
+ ——本包只提供它们要用的通道,不碰工具怎么讲。
105
+
106
+ ## scope
107
+
108
+ 预设模式的收口行:工具白名单(装配期投影 + 执行层 guard + 与工具同源的 `tool:<工具名>` 说明 section,三侧
109
+ 同判据)、`instructions`(关掉规则块与降级 section)、`runtimeContext`(关掉沙箱 / 审批那两条动态快照,按
110
+ scope 抑制)。它解决的是"preset 只能决定加什么、管不了 host 层"——模式要表达"我只有这几个工具、一条提示词
111
+ 都不要"时,唯一与来源无关的做法是在会话语义上收口。`allowTools` 为空即装配失败(该省掉整行)。
112
+
113
+ 白名单同时登记给通道(`restrictTools`):技能目录与用法组正文按 `visibleTools` 收口,所以被收窄的工具既不在
114
+ 目录、也不会被讲——注册表里"装着"不等于这个会话"能用"。
115
+
116
+ ## 装配
117
+
118
+ **profile 平面**:`dsh.profile.bundles` 列出本包即装一次,`cordis.patch.yml` 就是一行组装出口:
119
+
120
+ ```yaml
121
+ - insert:
122
+ - id: context-assembler
123
+ name: "@morlay/dsh-context-assembler"
124
+ config:
125
+ capabilities: [assembler, agent-instructions, skill-catalog]
126
+ ```
127
+
128
+ **preset 平面**:模式只装一行开关(工具白名单 / instruction / 动态快照),通道由 profile 那份共享:
129
+
130
+ ```yaml
131
+ - id: context-scope
132
+ name: "@morlay/dsh-context-assembler/scope"
133
+ config:
134
+ allowTools: [ask_user_question, web_search, web_fetch]
135
+ instructions: false
136
+ runtimeContext: false
137
+ ```
138
+
139
+ 几点硬要求:
140
+
141
+ - **每个能力仍是独立的 cordis 插件**(组装出口只是 `ctx.plugin()` 装它们),各自带自己的 `inject`;合成单入口会让
142
+ `inject` 变并集,一个可选搭档缺席就拖垮整包。
143
+ - **通道不做隔离**:消费者跨包(`@morlay/dsh-agent-toolkit` 的工具说明、本包的技能目录),隔离会把它们挡在组外
144
+ (行停在 waiting);模式差异改由 `context-scope` 登记给通道,见
145
+ [ADR 通道作为全局服务装配不隔离](./.agents/adrs/20260923-通道作为全局服务装配不隔离.md)。真装配的判据是
146
+ `pnpm exec tsx packages/desktop/dsh-desktop-host/tool/verify-preset-isolation.mts`(装配层可见一份、模式里没有第二份)。
147
+ - **子出口仍可单独装配**(`@morlay/dsh-context-assembler/assembler` 等):同一些插件,只是默认走组装出口。
148
+
149
+ ## 维护注意
150
+
151
+ - 测试落点在 `src/__tests__/<capability>/`(根 vitest 的 include 是 `packages/**/src/__tests__/**`,所以不能
152
+ 按能力就近放 `src/<capability>/__tests__/`)。
153
+ - 读上游文件的覆盖性测试用 `process.cwd()`(vitest 从仓库根跑),不要按文件深度算相对路径。
154
+ - 新增一个能力:加 `src/<capability>/`,再把它登记进 `src/index.ts` 的 `CAPABILITIES`(子出口与 tsdown 入口一起加);装配面不动。
@@ -0,0 +1,9 @@
1
+ # 本文件由 packages/context/dsh-context-assembler/tool/patch.ts 生成,请勿手工编辑
2
+ - insert:
3
+ - id: context-assembler
4
+ name: "@morlay/dsh-context-assembler"
5
+ config:
6
+ capabilities:
7
+ - assembler
8
+ - agent-instructions
9
+ - skill-catalog
@@ -0,0 +1,202 @@
1
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
+ import z from "@deepseek-ai/schemastery";
3
+ import { createHash } from "node:crypto";
4
+ import { dirname, join, relative, resolve } from "node:path";
5
+ import { readFile, stat } from "node:fs/promises";
6
+ import { homedir } from "node:os";
7
+ import { Config } from "@deepseek-ai/dsh-agent-instructions";
8
+ //#region src/agent-instructions/files.ts
9
+ /** 从 cwd 逐级向上找项目根(含标记目录的那一级)。 */
10
+ async function projectRoot(cwd, marker = ".git") {
11
+ let current = resolve(cwd);
12
+ for (;;) {
13
+ if (await stat(join(current, marker)).then(() => true, () => false)) return current;
14
+ const parent = dirname(current);
15
+ if (parent === current) return void 0;
16
+ current = parent;
17
+ }
18
+ }
19
+ function abbreviateHome(path) {
20
+ const home = homedir();
21
+ return path.startsWith(`${home}/`) ? `~${path.slice(home.length)}` : path;
22
+ }
23
+ /**
24
+ * 工作区指令链:用户全局 `$DSH_HOME/AGENTS.md`,再从项目根到 cwd 的每一级目录取
25
+ * 基础文件与本地 overlay。顺序由宽泛到具体——具体的在后面,与"更具体的优先"一致。
26
+ */
27
+ async function instructionChain(cwd, options) {
28
+ const files = [];
29
+ const global = join(options.dshHome, "AGENTS.md");
30
+ if (await isFile(global)) files.push({
31
+ root: options.dshHome,
32
+ display: abbreviateHome(global),
33
+ path: global
34
+ });
35
+ const root = await projectRoot(cwd) ?? resolve(cwd);
36
+ const levels = [];
37
+ let current = resolve(cwd);
38
+ for (;;) {
39
+ levels.unshift(current);
40
+ if (current === root) break;
41
+ const parent = dirname(current);
42
+ if (parent === current) break;
43
+ current = parent;
44
+ }
45
+ for (const level of levels) for (const name of [...options.instructionFileCandidates, ...options.localInstructionFileCandidates]) {
46
+ const path = join(level, name);
47
+ if (await isFile(path)) files.push({
48
+ root,
49
+ display: relativeDisplay(root, path),
50
+ path
51
+ });
52
+ }
53
+ return files;
54
+ }
55
+ function relativeDisplay(root, path) {
56
+ const rel = path.slice(root.length + 1);
57
+ return rel.length === 0 ? path : rel;
58
+ }
59
+ async function isFile(path) {
60
+ return (await stat(path).then((value) => value, () => void 0))?.isFile() === true;
61
+ }
62
+ /** 读一个指令文件;按 `mtimeMs:size` 缓存,未变就不重读。 */
63
+ async function readInstruction(file, cache, maxBytes) {
64
+ const info = await stat(file.path).then((value) => value, () => void 0);
65
+ if (info?.isFile() !== true) {
66
+ cache.delete(file.path);
67
+ return "";
68
+ }
69
+ const stamp = `${String(info.mtimeMs)}:${String(info.size)}`;
70
+ const cached = cache.get(file.path);
71
+ if (cached?.stamp === stamp) return cached.text;
72
+ const text = budget(await readFile(file.path, "utf8").catch(() => ""), file.display, maxBytes);
73
+ cache.set(file.path, {
74
+ stamp,
75
+ text
76
+ });
77
+ return text;
78
+ }
79
+ /** 单文件超出预算时截断并留一行可见提示(不静默丢内容)。 */
80
+ function budget(text, display, maxBytes) {
81
+ if (Buffer.byteLength(text, "utf8") <= maxBytes) return text.trimEnd();
82
+ const kept = Buffer.from(text, "utf8").subarray(0, maxBytes).toString("utf8");
83
+ const lastBreak = kept.lastIndexOf("\n");
84
+ return `${(lastBreak > 0 ? kept.slice(0, lastBreak) : kept).trimEnd()}\n\n(Workspace instruction budget ${String(maxBytes)} bytes: ${display} is truncated.)`;
85
+ }
86
+ /** 上游那行的身份基线:与 `packages/bundle/base/cordis.patch.yml` 的 `agent-instructions` 行 config 同源。 */
87
+ const UPSTREAM_BASELINE_CONFIG = { maxBytes: 65536 };
88
+ /** schema 调用会把缺省项补齐,所以这里拿到的是上游 schema 的实际默认值。 */
89
+ function resolveBaselineConfig() {
90
+ return Config({ ...UPSTREAM_BASELINE_CONFIG });
91
+ }
92
+ /** 上游 `findProjectRoot` 的语义:向上找第一个带标记的目录,找不到就用 cwd。 */
93
+ async function projectRootOf(cwd, markers) {
94
+ let current = resolve(cwd);
95
+ for (;;) {
96
+ for (const marker of markers) if (await exists(join(current, marker))) return current;
97
+ const parent = dirname(current);
98
+ if (parent === current) return resolve(cwd);
99
+ current = parent;
100
+ }
101
+ }
102
+ async function exists(path) {
103
+ try {
104
+ await stat(path);
105
+ return true;
106
+ } catch {
107
+ return false;
108
+ }
109
+ }
110
+ /** 一个会话的 baseline 身份;cwd 或项目根变了就是另一份身份(上游语义)。 */
111
+ async function baselineIdentity(cwd) {
112
+ const config = resolveBaselineConfig();
113
+ const projectRoot = await projectRootOf(cwd, config.projectRootMarkers);
114
+ return JSON.stringify({
115
+ projectRoot: relative(cwd, projectRoot),
116
+ projectRootMarkers: config.projectRootMarkers,
117
+ maxBytes: config.maxBytes,
118
+ maxSourceBytes: config.maxSourceBytes,
119
+ instructionFileCandidates: config.instructionFileCandidates,
120
+ localInstructionFileCandidates: config.localInstructionFileCandidates
121
+ });
122
+ }
123
+ //#endregion
124
+ //#region src/agent-instructions/index.ts
125
+ var agent_instructions_exports = /* @__PURE__ */ __exportAll({
126
+ Config: () => Config$1,
127
+ apply: () => apply,
128
+ inject: () => inject,
129
+ name: () => name
130
+ });
131
+ const name = "context-agent-instructions";
132
+ const inject = ["agents", "contextAssembler"];
133
+ const Config$1 = z.object({
134
+ instructionFileCandidates: z.array(z.string()).default(["AGENTS.md"]),
135
+ localInstructionFileCandidates: z.array(z.string()).default(["AGENTS.local.md"]),
136
+ maxBytes: z.number().default(65536),
137
+ dshHome: z.string().default(process.env["DSH_HOME"] ?? "")
138
+ });
139
+ /** 一个会话的指令链:路径集合与它所属的 cwd。 */
140
+ const chains = /* @__PURE__ */ new WeakMap();
141
+ /**
142
+ * 工作区指令:一条文件一个规则块(id 为 `agent-instructions:<根标识>:<文件>`),文件变化时正文变、按 id 覆盖。
143
+ *
144
+ * 与上游 `agent-instructions` 的差别:不做 read/write/edit 的 touch 跟踪(本部署的 `AGENTS.md`
145
+ * 几乎不变),只在每步按 `mtime:size` 对账;一份文件一条 id,于是变化只重发变了的那一份。
146
+ */
147
+ function apply(ctx, config) {
148
+ const options = {
149
+ instructionFileCandidates: config.instructionFileCandidates ?? ["AGENTS.md"],
150
+ localInstructionFileCandidates: config.localInstructionFileCandidates ?? ["AGENTS.local.md"],
151
+ dshHome: config.dshHome === void 0 || config.dshHome === "" ? defaultDshHome() : config.dshHome
152
+ };
153
+ const maxBytes = config.maxBytes ?? 65536;
154
+ const cache = /* @__PURE__ */ new Map();
155
+ const install = async (agent) => {
156
+ if (chains.has(agent)) return;
157
+ const cwd = agent.session.header.cwd === void 0 ? process.cwd() : agent.session.header.cwd;
158
+ const chain = {
159
+ cwd,
160
+ files: await instructionChain(cwd, options)
161
+ };
162
+ chains.set(agent, chain);
163
+ const identity = await baselineIdentity(cwd);
164
+ for (const file of chain.files) ctx.contextAssembler.registerRule({
165
+ id: `agent-instructions:${rootTag(file.root)}:${file.display}`,
166
+ source: () => ({
167
+ kind: "agent-instructions",
168
+ form: "instructions",
169
+ baseline: true,
170
+ baselineIdentity: identity,
171
+ changes: []
172
+ }),
173
+ text: (target) => {
174
+ const current = chains.get(target);
175
+ if (current === void 0 || !current.files.some((entry) => entry.path === file.path)) return "";
176
+ return readInstruction(file, cache, maxBytes);
177
+ }
178
+ });
179
+ };
180
+ ctx.on("agent/created", ({ agent }) => {
181
+ install(agent).catch((error) => {
182
+ ctx.logger.warn(`context-agent-instructions: ${String(error)}`);
183
+ });
184
+ });
185
+ for (const agent of ctx.agents.list()) install(agent).catch((error) => {
186
+ ctx.logger.warn(`context-agent-instructions: ${String(error)}`);
187
+ });
188
+ }
189
+ function defaultDshHome() {
190
+ const home = process.env["HOME"] ?? "~";
191
+ return resolve(process.env["DSH_HOME"] ?? `${home}/.dsh`);
192
+ }
193
+ /**
194
+ * 规则块 id 里的根标识:规则声明是**全局按 id 覆盖**的,而 `display` 只是根内相对路径——
195
+ * 同进程里两个项目根都有 `AGENTS.md` 时,不带根标识的 id 会互相顶掉(后注册者覆盖前者,
196
+ * 前者此后读到空正文)。8 位摘要够唯一,又不把绝对路径塞进提示词 id。
197
+ */
198
+ function rootTag(root) {
199
+ return createHash("sha256").update(root).digest("hex").slice(0, 8);
200
+ }
201
+ //#endregion
202
+ export { name as a, inject as i, agent_instructions_exports as n, apply as r, Config$1 as t };
@@ -0,0 +1,27 @@
1
+ import z from "@deepseek-ai/schemastery";
2
+ import { Context } from "@deepseek-ai/cordis";
3
+ declare namespace index_d_exports {
4
+ export { Config, apply, inject, name };
5
+ }
6
+ declare const name = "context-agent-instructions";
7
+ declare const inject: string[];
8
+ interface Config {
9
+ /** 每级目录的基础指令文件名。 */
10
+ instructionFileCandidates?: string[];
11
+ /** 基础文件之后加载的本地 overlay 名。 */
12
+ localInstructionFileCandidates?: string[];
13
+ /** 单个指令文件的渲染上限(字节)。 */
14
+ maxBytes?: number;
15
+ /** 用户全局指令所在目录(默认 `$DSH_HOME` 或 `~/.dsh`)。 */
16
+ dshHome?: string;
17
+ }
18
+ declare const Config: z<Config>;
19
+ /**
20
+ * 工作区指令:一条文件一个规则块(id 为 `agent-instructions:<根标识>:<文件>`),文件变化时正文变、按 id 覆盖。
21
+ *
22
+ * 与上游 `agent-instructions` 的差别:不做 read/write/edit 的 touch 跟踪(本部署的 `AGENTS.md`
23
+ * 几乎不变),只在每步按 `mtime:size` 对账;一份文件一条 id,于是变化只重发变了的那一份。
24
+ */
25
+ declare function apply(ctx: Context, config: Config): void;
26
+ //#endregion
27
+ export { Config, apply, inject, name, index_d_exports as t };
@@ -0,0 +1,2 @@
1
+ import { a as name, i as inject, r as apply, t as Config } from "./agent-instructions-BNEiZl0P.mjs";
2
+ export { Config, apply, inject, name };