@v587d/capital-generation 2.8.3 → 2.9.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.
Files changed (164) hide show
  1. package/CHANGELOG.md +54 -1
  2. package/README.md +40 -19
  3. package/chart-ui/README.md +1 -1
  4. package/chart-ui/client.src.cjs +7 -16
  5. package/chart-ui/index.js +12 -33
  6. package/chart-ui/package.json +2 -2
  7. package/config/client.js +18 -39
  8. package/config/client.src.cjs +79 -217
  9. package/config/index.js +22 -72
  10. package/config/package.json +2 -2
  11. package/cordis.patch.yml +46 -51
  12. package/lib/agents/bash-guard.d.ts +9 -55
  13. package/lib/agents/bash-guard.js +27 -67
  14. package/lib/agents/preset-roster.d.ts +22 -0
  15. package/lib/agents/preset-roster.js +87 -0
  16. package/lib/agents/role-tool-policy.d.ts +46 -0
  17. package/lib/agents/role-tool-policy.js +205 -0
  18. package/lib/agents/root-tool-policy.d.ts +28 -124
  19. package/lib/agents/root-tool-policy.js +164 -237
  20. package/lib/agents/selected-skills-provider.d.ts +2 -6
  21. package/lib/agents/selected-skills-provider.js +27 -84
  22. package/lib/capital-settings.d.ts +27 -0
  23. package/lib/capital-settings.js +23 -0
  24. package/lib/chart/artifact-ref.d.ts +3 -8
  25. package/lib/chart/artifact-ref.js +3 -8
  26. package/lib/chart/downsample.d.ts +2 -5
  27. package/lib/chart/downsample.js +3 -8
  28. package/lib/chart/errors.d.ts +3 -7
  29. package/lib/chart/errors.js +1 -2
  30. package/lib/chart/event-context.d.ts +8 -0
  31. package/lib/chart/event-context.js +39 -0
  32. package/lib/chart/events.d.ts +21 -78
  33. package/lib/chart/events.js +40 -189
  34. package/lib/chart/html.d.ts +2 -5
  35. package/lib/chart/html.js +8 -15
  36. package/lib/chart/runtime.d.ts +5 -18
  37. package/lib/chart/runtime.js +14 -34
  38. package/lib/chart/series.d.ts +10 -17
  39. package/lib/chart/series.js +22 -47
  40. package/lib/chart/source-token.d.ts +5 -13
  41. package/lib/chart/source-token.js +18 -17
  42. package/lib/chart/spec.d.ts +6 -12
  43. package/lib/chart/spec.js +7 -31
  44. package/lib/chart/tool.d.ts +6 -29
  45. package/lib/chart/tool.js +9 -23
  46. package/lib/chart-render-entry.d.ts +9 -0
  47. package/lib/chart-render-entry.js +17 -0
  48. package/lib/chart-source-entry.d.ts +13 -0
  49. package/lib/chart-source-entry.js +20 -0
  50. package/lib/collect-entry.d.ts +9 -0
  51. package/lib/collect-entry.js +10 -0
  52. package/lib/collector-runtime.d.ts +22 -0
  53. package/lib/collector-runtime.js +97 -0
  54. package/lib/data-collector/args.d.ts +6 -24
  55. package/lib/data-collector/args.js +6 -24
  56. package/lib/data-collector/dataset-tools.d.ts +7 -1
  57. package/lib/data-collector/dataset-tools.js +27 -56
  58. package/lib/data-collector/describe.d.ts +8 -33
  59. package/lib/data-collector/describe.js +17 -70
  60. package/lib/data-collector/hub.d.ts +27 -85
  61. package/lib/data-collector/hub.js +19 -85
  62. package/lib/data-collector/query-time.d.ts +7 -26
  63. package/lib/data-collector/query-time.js +8 -27
  64. package/lib/data-collector/store.d.ts +40 -117
  65. package/lib/data-collector/store.js +32 -111
  66. package/lib/data-collector/time-axis.d.ts +16 -76
  67. package/lib/data-collector/time-axis.js +25 -111
  68. package/lib/data-collector/tools.d.ts +6 -6
  69. package/lib/data-collector/tools.js +34 -43
  70. package/lib/dataset-read-entry.d.ts +9 -0
  71. package/lib/dataset-read-entry.js +7 -0
  72. package/lib/index.d.ts +7 -117
  73. package/lib/index.js +43 -422
  74. package/lib/net/eastmoney-client.d.ts +13 -65
  75. package/lib/net/eastmoney-client.js +12 -53
  76. package/lib/net/throttle.d.ts +2 -13
  77. package/lib/net/throttle.js +3 -14
  78. package/lib/ocr/client.d.ts +12 -21
  79. package/lib/ocr/client.js +23 -40
  80. package/lib/ocr/markdown.d.ts +20 -26
  81. package/lib/ocr/markdown.js +23 -36
  82. package/lib/ocr/store.d.ts +14 -47
  83. package/lib/ocr/store.js +15 -45
  84. package/lib/ocr-entry.d.ts +9 -0
  85. package/lib/ocr-entry.js +10 -0
  86. package/lib/policy-entry.d.ts +17 -0
  87. package/lib/policy-entry.js +22 -0
  88. package/lib/preset-claim.d.ts +22 -0
  89. package/lib/preset-claim.js +24 -0
  90. package/lib/preset-ids.d.ts +38 -0
  91. package/lib/preset-ids.js +46 -0
  92. package/lib/retriever-config.d.ts +37 -0
  93. package/lib/retriever-config.js +36 -0
  94. package/lib/retriever-runtime.d.ts +31 -0
  95. package/lib/retriever-runtime.js +82 -0
  96. package/lib/root-extras-entry.d.ts +17 -0
  97. package/lib/root-extras-entry.js +25 -0
  98. package/lib/runtime-entry.d.ts +15 -0
  99. package/lib/runtime-entry.js +5 -0
  100. package/lib/runtime.d.ts +21 -0
  101. package/lib/runtime.js +33 -0
  102. package/lib/search-entry.d.ts +9 -0
  103. package/lib/search-entry.js +9 -0
  104. package/lib/sources/eastmoney-http.js +20 -68
  105. package/lib/sources/ftshare-rest.d.ts +6 -34
  106. package/lib/sources/ftshare-rest.js +84 -292
  107. package/lib/sources/fuyao-core.d.ts +8 -18
  108. package/lib/sources/fuyao-core.js +10 -21
  109. package/lib/sources/fuyao-rest.d.ts +2 -6
  110. package/lib/sources/fuyao-rest.js +23 -102
  111. package/lib/sources/security-code.d.ts +6 -12
  112. package/lib/sources/security-code.js +6 -12
  113. package/lib/sources/security-identity.d.ts +1 -4
  114. package/lib/sources/security-identity.js +3 -8
  115. package/lib/sources/tencent-http.js +14 -28
  116. package/lib/sources/tencent-public-core.d.ts +8 -60
  117. package/lib/sources/tencent-public-core.js +12 -77
  118. package/lib/sources/wind-mcp.d.ts +0 -5
  119. package/lib/sources/wind-mcp.js +23 -78
  120. package/lib/sources-entry.d.ts +9 -0
  121. package/lib/sources-entry.js +9 -0
  122. package/lib/time/tools.d.ts +8 -31
  123. package/lib/time/tools.js +30 -66
  124. package/lib/time-entry.d.ts +9 -0
  125. package/lib/time-entry.js +7 -0
  126. package/lib/tool-exec.d.ts +45 -11
  127. package/lib/tool-exec.js +59 -6
  128. package/lib/user-customization.d.ts +14 -0
  129. package/lib/user-customization.js +47 -0
  130. package/lib/watchlist/tools.d.ts +3 -13
  131. package/lib/watchlist/tools.js +10 -30
  132. package/lib/watchlist-entry.d.ts +9 -0
  133. package/lib/watchlist-entry.js +6 -0
  134. package/lib/web-retriever/engines.d.ts +6 -11
  135. package/lib/web-retriever/engines.js +9 -14
  136. package/lib/web-retriever/html-markdown.d.ts +14 -34
  137. package/lib/web-retriever/html-markdown.js +39 -75
  138. package/lib/web-retriever/local-fetch.d.ts +22 -58
  139. package/lib/web-retriever/local-fetch.js +33 -77
  140. package/lib/web-retriever/retriever.d.ts +6 -18
  141. package/lib/web-retriever/retriever.js +7 -7
  142. package/lib/web-retriever/sources.d.ts +37 -124
  143. package/lib/web-retriever/sources.js +64 -196
  144. package/lib/web-retriever/tools.d.ts +43 -27
  145. package/lib/web-retriever/tools.js +99 -137
  146. package/lib/web-retriever/wind-client.d.ts +14 -31
  147. package/lib/web-retriever/wind-client.js +16 -32
  148. package/locale/zh.json +1 -1
  149. package/package.json +67 -7
  150. package/preset/capital-generation/README.md +87 -53
  151. package/preset/capital-generation/agent.patch.yml +526 -337
  152. package/preset/capital-generation/skills/capital-data-profile/SKILL.md +2 -2
  153. package/preset/capital-generation/skills/capital-data-protocol/SKILL.md +1 -1
  154. package/preset/capital-generation/skills/capital-equity-research/SKILL.md +1 -1
  155. package/preset/capital-generation/skills/capital-event-impact/SKILL.md +1 -1
  156. package/preset/capital-generation/skills/capital-orchestration/SKILL.md +15 -19
  157. package/preset/capital-generation/skills/capital-portfolio-review/SKILL.md +1 -1
  158. package/preset/capital-generation/skills/capital-visualization-protocol/SKILL.md +9 -12
  159. package/preset/capital-generation/skills/capital-web-evidence/SKILL.md +1 -1
  160. package/watchlist/client.js +15 -148
  161. package/watchlist/client.src.cjs +148 -662
  162. package/watchlist/holding-rules.js +11 -38
  163. package/watchlist/index.js +127 -397
  164. package/watchlist/package.json +2 -2
@@ -1,23 +1,13 @@
1
1
  /**
2
- * Wind 金融文档检索客户端(JSON-RPC over HTTP,零依赖)。
3
- *
4
- * 线格式为 JSON-RPC 2.0(即 MCP 线协议):initialize → tools/call,无会话态、
5
- * 无 SDK、无框架依赖——与 fuyao-rest / anysearch engines 同构的普通 HTTP 客户端。
6
- * 协议蓝本(Wind 官方 CLI):github.com/Wind-Alice/AliceMarket 的
7
- * skills/wind-mcp-skill/scripts/cli.mjs(本地参考副本在 docs/reference/,不入库)。
2
+ * Wind financial-document client: JSON-RPC 2.0 (MCP wire protocol) over plain
3
+ * HTTP. initialize -> tools/call, no session state, no SDK.
8
4
  */
9
5
  export declare const DEFAULT_WIND_ENDPOINT = "https://mcp.wind.com.cn/vserver_financial_docs/mcp/";
10
6
  export declare const WIND_REQUEST_TIMEOUT_MS = 60000;
11
7
  export declare const WIND_MAX_CONTENT_CHARS = 20000;
12
8
  /**
13
- * 七台托管 MCP server 的端点(`server_type` → URL)。
14
- *
15
- * 这里是**事实**(端点常量),不是代码搬运:上游仓库未声明 LICENSE,蓝本
16
- * (官方 CLI 的 `SERVERS` 表)按惯例只作本地参考副本、不入库,见
17
- * `docs/design/wind-market-source.md` §1.1。
18
- *
19
- * `analytics_data` 一并列出是为了记下"它存在但不可用":2026-10-05 实测连 `initialize`
20
- * 都挂满 60 秒(同文档 §6.1),所以数据源侧不接它。
9
+ * Hosted MCP servers (`server_type` -> URL). `analytics_data` is listed to record
10
+ * that it exists but is unusable (initialize hangs), so no data source uses it.
21
11
  */
22
12
  export declare const WIND_SERVER_ENDPOINTS: {
23
13
  readonly stock_data: "https://mcp.wind.com.cn/vserver_stock_data/mcp/";
@@ -30,40 +20,33 @@ export declare const WIND_SERVER_ENDPOINTS: {
30
20
  };
31
21
  export type WindServerType = keyof typeof WIND_SERVER_ENDPOINTS;
32
22
  /**
33
- * 错误分类(persona/主 Agent 依据它决定 fallback):
34
- * AUTH=Key 缺失或无效;RATE_LIMIT=429;NETWORK=网络错误/5xx/超时;
35
- * BACKEND=接口层与业务错误;INVALID=响应不可解析。
23
+ * Error classes drive fallback: AUTH=missing/invalid key; RATE_LIMIT=429;
24
+ * NETWORK=network/5xx/timeout; BACKEND=API/business; INVALID=unparseable.
36
25
  */
37
26
  export type WindErrorCode = 'AUTH' | 'RATE_LIMIT' | 'NETWORK' | 'BACKEND' | 'INVALID';
38
27
  export interface WindCallResult {
39
28
  ok: boolean;
40
- /** 成功且正文可解析为 JSON 时:Wind 返回结果(字符串字段裁剪到 WIND_MAX_CONTENT_CHARS)。 */
29
+ /** Parsed JSON result; string fields clipped to WIND_MAX_CONTENT_CHARS. */
41
30
  data?: unknown;
42
- /** 成功但正文非 JSON 时:原文透传(≤WIND_MAX_CONTENT_CHARS)。 */
31
+ /** Non-JSON body passed through (<= WIND_MAX_CONTENT_CHARS). */
43
32
  content?: string;
44
33
  content_chars?: number;
45
34
  error?: string;
46
35
  code?: WindErrorCode;
47
36
  }
48
- /**
49
- * 报给 Wind 的客户端版本(`initialize.clientInfo.version` 与 `tools/call._meta.clientVersion`)。
50
- *
51
- * ⚠️ 必须与 `package.json` 的 `version` 一致:嵌套包 `chart-ui/package.json` 的版本由
52
- * `test/chart-composition.test.mjs` 守着(会因漂移而失败),这里原本是写死的第二处,
53
- * 一次发版就得记得改两遍。所以本常量由测试一并核对(见 `test/wind-client.test.mjs`)。
54
- */
55
- export declare const WIND_CLIENT_VERSION = "2.8.3";
37
+ /** Must match `package.json` version; a test pins the two together. */
38
+ export declare const WIND_CLIENT_VERSION = "2.9.0";
56
39
  export interface WindClient {
57
40
  callTool(toolName: string, args: Record<string, unknown>, signal?: AbortSignal): Promise<WindCallResult>;
58
41
  }
59
42
  export interface WindClientOptions {
60
43
  endpoint?: string;
61
- /** 每次调用重新解析 Key,不缓存(与 anysearch engines 同策略)。 */
44
+ /** Re-resolve the key on every call, never cache it. */
62
45
  resolveApiKey: () => Promise<string | undefined>;
63
- /** 单次请求超时毫秒(initialize 与 tools/call 各自适用);默认 60000。 */
46
+ /** Per-request timeout (initialize and tools/call separately); default 60000. */
64
47
  timeoutMs?: number;
65
- /** 网络错误重试间隔毫秒;默认 [300, 1000],仅供测试注入缩短。 */
48
+ /** Network-error retry delays; default [300, 1000], shortened only in tests. */
66
49
  retryDelaysMs?: number[];
67
50
  }
68
- /** 创建 Wind 文档检索客户端;端点在构造时校验(配置错误立即暴露,与 anysearch 同策略)。 */
51
+ /** Endpoint is validated at construction so config errors surface immediately. */
69
52
  export declare function createWindClient(options: WindClientOptions): WindClient;
@@ -1,23 +1,13 @@
1
1
  /**
2
- * Wind 金融文档检索客户端(JSON-RPC over HTTP,零依赖)。
3
- *
4
- * 线格式为 JSON-RPC 2.0(即 MCP 线协议):initialize → tools/call,无会话态、
5
- * 无 SDK、无框架依赖——与 fuyao-rest / anysearch engines 同构的普通 HTTP 客户端。
6
- * 协议蓝本(Wind 官方 CLI):github.com/Wind-Alice/AliceMarket 的
7
- * skills/wind-mcp-skill/scripts/cli.mjs(本地参考副本在 docs/reference/,不入库)。
2
+ * Wind financial-document client: JSON-RPC 2.0 (MCP wire protocol) over plain
3
+ * HTTP. initialize -> tools/call, no session state, no SDK.
8
4
  */
9
5
  export const DEFAULT_WIND_ENDPOINT = 'https://mcp.wind.com.cn/vserver_financial_docs/mcp/';
10
6
  export const WIND_REQUEST_TIMEOUT_MS = 60_000;
11
7
  export const WIND_MAX_CONTENT_CHARS = 20_000;
12
8
  /**
13
- * 七台托管 MCP server 的端点(`server_type` → URL)。
14
- *
15
- * 这里是**事实**(端点常量),不是代码搬运:上游仓库未声明 LICENSE,蓝本
16
- * (官方 CLI 的 `SERVERS` 表)按惯例只作本地参考副本、不入库,见
17
- * `docs/design/wind-market-source.md` §1.1。
18
- *
19
- * `analytics_data` 一并列出是为了记下"它存在但不可用":2026-10-05 实测连 `initialize`
20
- * 都挂满 60 秒(同文档 §6.1),所以数据源侧不接它。
9
+ * Hosted MCP servers (`server_type` -> URL). `analytics_data` is listed to record
10
+ * that it exists but is unusable (initialize hangs), so no data source uses it.
21
11
  */
22
12
  export const WIND_SERVER_ENDPOINTS = {
23
13
  stock_data: 'https://mcp.wind.com.cn/vserver_stock_data/mcp/',
@@ -28,14 +18,8 @@ export const WIND_SERVER_ENDPOINTS = {
28
18
  economic_data: 'https://mcp.wind.com.cn/vserver_economic_data/mcp/',
29
19
  analytics_data: 'https://mcp.wind.com.cn/vserver_analytics_data/mcp/',
30
20
  };
31
- /**
32
- * 报给 Wind 的客户端版本(`initialize.clientInfo.version` 与 `tools/call._meta.clientVersion`)。
33
- *
34
- * ⚠️ 必须与 `package.json` 的 `version` 一致:嵌套包 `chart-ui/package.json` 的版本由
35
- * `test/chart-composition.test.mjs` 守着(会因漂移而失败),这里原本是写死的第二处,
36
- * 一次发版就得记得改两遍。所以本常量由测试一并核对(见 `test/wind-client.test.mjs`)。
37
- */
38
- export const WIND_CLIENT_VERSION = '2.8.3';
21
+ /** Must match `package.json` version; a test pins the two together. */
22
+ export const WIND_CLIENT_VERSION = '2.9.0';
39
23
  function errorText(error) {
40
24
  return error instanceof Error ? error.message : String(error);
41
25
  }
@@ -46,7 +30,7 @@ class WindTransportError extends Error {
46
30
  this.code = code;
47
31
  }
48
32
  }
49
- /** HTTP 状态 → 错误分类(蓝本 HTTP_ERROR_MAP;其余状态一律 NETWORK)。 */
33
+ /** HTTP status -> error class; anything else is NETWORK. */
50
34
  const HTTP_ERROR_CODES = {
51
35
  401: 'AUTH',
52
36
  429: 'RATE_LIMIT',
@@ -70,7 +54,7 @@ function normalizeEndpoint(endpoint) {
70
54
  }
71
55
  return raw;
72
56
  }
73
- /** 响应可能是纯 JSON 或 SSE(取最后一个 data: 行);蓝本 parseSSE 的等价实现。 */
57
+ /** Body may be pure JSON or SSE (last `data:` line). */
74
58
  function parseResponsePayload(text) {
75
59
  const trimmed = text.trim();
76
60
  if (trimmed.startsWith('{')) {
@@ -78,7 +62,7 @@ function parseResponsePayload(text) {
78
62
  return JSON.parse(trimmed);
79
63
  }
80
64
  catch {
81
- // 非 JSON 对象落到下面的 SSE 解析。
65
+ // Not a JSON object: fall through to the SSE parse below.
82
66
  }
83
67
  }
84
68
  let last;
@@ -96,7 +80,7 @@ function parseResponsePayload(text) {
96
80
  }
97
81
  throw new Error(`响应格式无法识别(既非 JSON 也非 SSE);原文前 200 字符:${text.slice(0, 200)}`);
98
82
  }
99
- /** 深度裁剪:对象/数组内的字符串字段超过上限时截断(保持结构;超长响应另有 harness 剪枝兜底)。 */
83
+ /** Deep-clip long string fields, preserving structure. */
100
84
  function trimDeep(value, maxChars) {
101
85
  if (typeof value === 'string')
102
86
  return value.length > maxChars ? value.slice(0, maxChars) : value;
@@ -123,7 +107,7 @@ function firstContentText(result) {
123
107
  }
124
108
  return undefined;
125
109
  }
126
- /** JSON-RPC error 字段 → 可读文本。 */
110
+ /** Render a JSON-RPC error field as text. */
127
111
  function rpcErrorText(payload) {
128
112
  if (!payload || typeof payload !== 'object' || Array.isArray(payload))
129
113
  return undefined;
@@ -141,8 +125,8 @@ function rpcErrorText(payload) {
141
125
  return JSON.stringify(error).slice(0, 2_000);
142
126
  }
143
127
  /**
144
- * 三层业务错误解包(蓝本 mcpRequest 后半段):Wind 把业务错误包在 content[0].text
145
- * 的 JSON 字符串里,必须二次解析——mcp_tool_error_code / error{} / data.code 三种形态。
128
+ * Wind wraps business errors inside content[0].text JSON, so unpack a second time:
129
+ * mcp_tool_error_code / error{} / data.code.
146
130
  */
147
131
  function innerBusinessError(data) {
148
132
  if (!data || typeof data !== 'object' || Array.isArray(data))
@@ -174,7 +158,7 @@ function innerBusinessError(data) {
174
158
  }
175
159
  return undefined;
176
160
  }
177
- /** JSON-RPC result → WindCallResult:含 isError 与内层业务错误解包。 */
161
+ /** JSON-RPC result -> WindCallResult, including isError and inner business errors. */
178
162
  function interpretResult(payload) {
179
163
  if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
180
164
  return { ok: false, code: 'INVALID', error: 'Wind 返回不可解析(非 JSON-RPC 对象)' };
@@ -211,7 +195,7 @@ function interpretResult(payload) {
211
195
  return { ok: false, code: 'BACKEND', error: businessError };
212
196
  return { ok: true, data: trimDeep(parsed, WIND_MAX_CONTENT_CHARS) };
213
197
  }
214
- /** 创建 Wind 文档检索客户端;端点在构造时校验(配置错误立即暴露,与 anysearch 同策略)。 */
198
+ /** Endpoint is validated at construction so config errors surface immediately. */
215
199
  export function createWindClient(options) {
216
200
  const endpoint = normalizeEndpoint(options.endpoint);
217
201
  const timeoutMs = options.timeoutMs && options.timeoutMs > 0 ? options.timeoutMs : WIND_REQUEST_TIMEOUT_MS;
@@ -256,7 +240,7 @@ export function createWindClient(options) {
256
240
  signal?.removeEventListener('abort', onExternalAbort);
257
241
  }
258
242
  }
259
- /** 网络级错误按退避重试;HTTP 状态错误与调用方取消不重试(蓝本同款行为)。 */
243
+ /** Retry network errors with backoff; HTTP status errors and caller cancels do not retry. */
260
244
  async function postRpc(method, params, apiKey, signal) {
261
245
  let lastError;
262
246
  for (let attempt = 1; attempt <= RETRY_ATTEMPTS; attempt += 1) {
package/locale/zh.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "meta": {
3
3
  "title": "Capital Generation(证券研究)",
4
- "description": "面向 A 股个人投资者的证券研究插件:查行情与财务数据、看公告和新闻、做分析、出图表。安装后在新会话选择 Capital 模式。"
4
+ "description": "面向 A 股个人投资者的证券研究插件:查行情与财务数据、看公告和新闻、做分析、出图表。安装后在新会话选择自动模式。"
5
5
  }
6
6
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@v587d/capital-generation",
3
- "version": "2.8.3",
4
- "description": "Capital Generation:面向中国散户的 AI 投资助手插件(Capital mode Agent Preset)",
3
+ "version": "2.9.0",
4
+ "description": "Capital Generation:面向中国散户的 AI 投资助手插件(自动模式 Agent Preset)",
5
5
  "icon": "assets/cg-icon.png",
6
6
  "author": "v587d",
7
7
  "license": "MIT",
@@ -22,6 +22,66 @@
22
22
  "import": "./lib/index.js",
23
23
  "default": "./lib/index.js"
24
24
  },
25
+ "./runtime": {
26
+ "types": "./lib/runtime-entry.d.ts",
27
+ "import": "./lib/runtime-entry.js",
28
+ "default": "./lib/runtime-entry.js"
29
+ },
30
+ "./policy": {
31
+ "types": "./lib/policy-entry.d.ts",
32
+ "import": "./lib/policy-entry.js",
33
+ "default": "./lib/policy-entry.js"
34
+ },
35
+ "./tools/chart-render": {
36
+ "types": "./lib/chart-render-entry.d.ts",
37
+ "import": "./lib/chart-render-entry.js",
38
+ "default": "./lib/chart-render-entry.js"
39
+ },
40
+ "./tools/chart-source": {
41
+ "types": "./lib/chart-source-entry.d.ts",
42
+ "import": "./lib/chart-source-entry.js",
43
+ "default": "./lib/chart-source-entry.js"
44
+ },
45
+ "./tools/collect": {
46
+ "types": "./lib/collect-entry.d.ts",
47
+ "import": "./lib/collect-entry.js",
48
+ "default": "./lib/collect-entry.js"
49
+ },
50
+ "./tools/dataset-read": {
51
+ "types": "./lib/dataset-read-entry.d.ts",
52
+ "import": "./lib/dataset-read-entry.js",
53
+ "default": "./lib/dataset-read-entry.js"
54
+ },
55
+ "./tools/ocr": {
56
+ "types": "./lib/ocr-entry.d.ts",
57
+ "import": "./lib/ocr-entry.js",
58
+ "default": "./lib/ocr-entry.js"
59
+ },
60
+ "./tools/retrieve-search": {
61
+ "types": "./lib/search-entry.d.ts",
62
+ "import": "./lib/search-entry.js",
63
+ "default": "./lib/search-entry.js"
64
+ },
65
+ "./tools/retrieve-sources": {
66
+ "types": "./lib/sources-entry.d.ts",
67
+ "import": "./lib/sources-entry.js",
68
+ "default": "./lib/sources-entry.js"
69
+ },
70
+ "./tools/root-extras": {
71
+ "types": "./lib/root-extras-entry.d.ts",
72
+ "import": "./lib/root-extras-entry.js",
73
+ "default": "./lib/root-extras-entry.js"
74
+ },
75
+ "./tools/time": {
76
+ "types": "./lib/time-entry.d.ts",
77
+ "import": "./lib/time-entry.js",
78
+ "default": "./lib/time-entry.js"
79
+ },
80
+ "./tools/watchlist": {
81
+ "types": "./lib/watchlist-entry.d.ts",
82
+ "import": "./lib/watchlist-entry.js",
83
+ "default": "./lib/watchlist-entry.js"
84
+ },
25
85
  "./package.json": "./package.json",
26
86
  "./locale/*.json": "./locale/*.json"
27
87
  },
@@ -79,14 +139,14 @@
79
139
  },
80
140
  "peerDependencies": {
81
141
  "@deepseek-ai/cordis": "^4.0.2",
82
- "@deepseek-ai/dsh-skill": "0.2.0-rc.2",
83
- "@deepseek-ai/dsh-skill-filesystem": "0.2.0-rc.2"
142
+ "@deepseek-ai/dsh-skill": "0.2.1-rc.2",
143
+ "@deepseek-ai/dsh-skill-filesystem": "0.2.1-rc.2"
84
144
  },
85
145
  "devDependencies": {
86
146
  "@deepseek-ai/cordis": "^4.0.2",
87
- "@deepseek-ai/dsh-skill": "^0.2.0-rc.2",
88
- "@deepseek-ai/dsh-skill-filesystem": "^0.2.0-rc.2",
89
- "@deepseek-ai/dsh-system-prompt": "^0.2.0-rc.2",
147
+ "@deepseek-ai/dsh-skill": "^0.2.1-rc.2",
148
+ "@deepseek-ai/dsh-skill-filesystem": "^0.2.1-rc.2",
149
+ "@deepseek-ai/dsh-system-prompt": "^0.2.1-rc.2",
90
150
  "@deepseek-ai/schemastery": "^3.18.4",
91
151
  "esbuild": "^0.28.2",
92
152
  "js-yaml": "^5.4.1",
@@ -1,14 +1,15 @@
1
- # Capital 模式 preset:组合设计说明
1
+ # 自动模式 preset:组合设计说明
2
2
 
3
- 本文件是 `agent.patch.yml`(那颗 `@deepseek-ai/dsh-agent-preset` 声明行)的**维护者文档**(人类可读),
3
+ 本文件是 `agent.patch.yml`(那六颗 `@deepseek-ai/dsh-agent-preset` 声明行)的**维护者文档**(人类可读),
4
4
  不是模型可见内容:`skill-filesystem` 只扫 `skills/`,本文件既不会进 skill 目录,也不会被注入上下文。
5
5
  组合文件里只留"就地必需"的一行注(realm、`!!js`、disabled 行),其余设计理由都在这里。
6
6
 
7
7
  - 本目录由 `@v587d/capital-generation` 随包分发,`agent.patch.yml` 走 `package.json` 的
8
- `dsh.bundle.patch`(**数组**:主 patch + 这颗)以 `trust=system` 挂载;**不要**手抄进
9
- `~/.dsh/.agent-presets`。
8
+ `dsh.bundle.patch`(**数组**:主 patch + 这一份 yml,六颗声明行都在里面)以 `trust=system`
9
+ 挂载;**不要**手抄进 `~/.dsh/.agent-presets`。
10
10
  - 长协议在 `skills/`(同目录),由本 preset 自己的 `skill-filesystem` 行发现;`capital-visualization-protocol` 同时供 data_junior 的 gate 和 visualization_specialist 按需加载。
11
- - visualization_specialist 是 data_junior 创建的 one-shot 前台子 Agent,不进入主 Agent 的 direct-child 复用清单;它只消费 chart_source_ref 并使用受控 render_chart。
11
+ - visualization_specialist 是 data_junior 委派出图的子 Agent(0.2.1 起所有子会话都是异步 continuable,没有 one-shot / 前台模式),不进入主 Agent 的 direct-child 复用清单;它只消费 chart_source_ref 并使用受控 render_chart。
12
+ - data_junior 的质检与可视化 gate 对每份结构化 Dataset 都执行,用户是否要图不是触发条件;显式「不要图」只收窄出图,不跳过 profile。
12
13
  - 验证方式与"改 preset 前后的必做检查"见仓库根 `AGENTS.md` §8.3;设计理由与「不许改」全表见
13
14
  `docs/dev/preset-persona.md`。
14
15
 
@@ -22,23 +23,27 @@
22
23
 
23
24
  ## 2. 人设(persona)承载与官方语义
24
25
 
25
- 实测 `dsh 0.1.5-rc.1`,`0.1.7-rc.2` 复核字段未变(`test/persona.test.mjs` 对着本机 dsh 核对),
26
- 三层载体注册的是**同一个 system-prompt 节名**:
26
+ 实测 `dsh 0.2.1-rc.2`(`test/persona.test.mjs` 对着本机 dsh 核对字段名),两层载体注册的是
27
+ **同一个 system-prompt 节名**:
27
28
 
28
29
  | 载体 | 位置 | 字段 | 生效范围 |
29
30
  |---|---|---|---|
30
31
  | `dsh-system-prompt` 行 | 部署(web profile) | `personaPrefix` / `personaSuffix` | 全局 |
31
- | `dsh-persona` 行 | 本 preset | `prefix`(必填)/ `suffix` / `complete` / `includeRuntimeContext` | preset 内全部 agent(主 + 子) |
32
- | `dsh-tool-subagent` 行 | 本 preset 委派行 | `config.persona` | 该子 Agent 自己 |
32
+ | `dsh-persona` 行 | **每颗 preset 自己**(根 + 五颗角色,各一行) | `prefix`(必填)/ `suffix` / `complete` / `includeRuntimeContext` | 该 preset 组出来的 agent |
33
33
 
34
34
  - 节名是 `deployment:persona-prefix`(order 0)与 `deployment:persona-suffix`(order
35
- 10200)。**最近 scope 胜出 ⇒ 是覆盖不是追加**;`dsh-subagent` 把 `config.persona` 注册进
36
- 子 Agent 自己的 scope,所以子人设**替换**(不是扩展)主 persona。
37
- - `prefix`/`suffix` 是模板,渲染时对 `{{…}}` **严格插值**:未注册或 undefined 的变量会抛错。
38
- `provider` / `model` / `cwd` 由 `dsh-agent-loop` 全局注册,可以直接用。
35
+ 10200)。**最近 scope 胜出 ⇒ 是覆盖不是追加**:0.2.1 起委派行**不再带 `config.persona`**
36
+ (`tool-subagent: persona is no longer supported; configure persona … in an Agent Preset and
37
+ select it with agentPreset`),子人设因此住在角色 preset 自己的 `dsh-persona` 行里,子 Agent
38
+ 组出来的那一颗 generation 覆盖同名节——效果与旧写法一致:**替换**(不是扩展)主 persona。
39
+ - `prefix`/`suffix` 是模板,渲染时对 `{{…}}` **严格插值**:未注册或 undefined 的变量会抛错,
40
+ 而且抛的是**整个会话的系统提示组装**,不是"这一段不显示"。可注册的变量以本机为准——
41
+ 0.2.1 的 `dsh-agent-loop` 只注册 `provider` / `model`(0.2.0 还有的 `cwd` **已被上游删掉**,
42
+ 真机踩过一次:`unknown prompt variable "{{cwd}}" in section "deployment:persona-prefix"`)。
43
+ `test/persona.test.mjs` 现读本机注册表钉这条闸门,正文里写了少掉的变量会在 `npm test` 就红。
39
44
  - 本 preset **不设 `suffix`**:按官方语义,空模板**仍然遮蔽**部署级后缀,所以部署那句
40
- `Your working directory is {{cwd}}.` 在 Capital 会话里不出现(主 persona 自己写了
41
- `{{cwd}}`)。这是有意为之,不是漏配。
45
+ "Your working directory is …" 在 Capital 会话里不出现;工作目录改由主 persona 自己用
46
+ **文字**说明(本会话选定的 workspace 根目录),不再引用已经不存在的变量。这是有意为之,不是漏配。
42
47
  - `complete: true` 会把其余所有段落(身份、工具引导、后缀)一并抑制;`includeRuntimeContext:
43
48
  false` 全有全无地关掉沙箱/审批/委派等 runtime context。本 preset 都不用。
44
49
  - 成本:persona 正文每个请求都重复;`prefix` 变化会让 KV cache 从第一个变化 token 起失效。
@@ -51,7 +56,8 @@
51
56
  而 skill 只在模型决定加载时才生效。
52
57
  - **按需进 `skills/`**:载荷 JSON 样例、字段级规则、`error/code → 处置`表、四态事实怎么读、
53
58
  QuerySpec 细则、检索收敛法则、官方域名核验清单、回传格式范例。
54
- - **子 Agent 也能按需加载**:子行的 `toolFilter.allow` 里写了 `skill`,子 Agent 就同时拿到
59
+ - **子 Agent 也能按需加载**:每颗角色 preset 自己挂 `@deepseek-ai/dsh-tool-skill` 行(四颗在用角色都有;预留的
60
+ `capital-data-analyst` declaration 已 disabled,恢复时要去掉 `disabled`),子 Agent 就同时拿到
55
61
  目录与加载器。判据在 `dsh-tools` 的 `view()`:restriction 过滤**继承层(全局 + 全部祖先
56
62
  scope,含 preset 层)**,只豁免"本 scope 自己注册的"工具;而 `dsh-tool-skill` 发布目录的
57
63
  条件正是 `ctx.tools.get('skill', agent) === 该注册对象`。源码注释里记着这段历史坑
@@ -93,32 +99,54 @@
93
99
  **能力目录与工具结果超过阈值时中间段被剪掉**;`test/data-collector-hub.test.mjs` 因此用
94
100
  "目录 6144 + 单能力详情 4096"两道测试预算,让测试先失败而不是运行时静默截断。该阈值
95
101
  **不能按 Agent 区分**(全仓只有这一个 pruner 实例),主/子 Agent 共用。
96
- - `toolFilter.allow` 只能写**真实注册**的全局工具名:`tools.restrict()` 对未知名字直接报错,
97
- 且它在**子 Agent 创建窗口**执行——写错的表现是"创建子 Agent 失败",不是挂载失败。
98
- - **通用 `subagent` 行必须写 `toolFilter.deny`(2026-09 review)**:`dsh-subagent` 只在
99
- `composition.toolFilter !== void 0` 时才 `restrict`,而 child 用 `composeFrom(childCtx,
100
- parent.ctx)` 加入父 Agent **同一份 standing composition**,因此没有 filter 的通用 child
101
- 会继承 standing 的全部工具——只带 `parentSession` 的 child 就能自己 `prepare_chart_source`
102
- 再 `render_chart`,把"出图只有一个入口"降级成 persona 建议。这里的 `deny` 与子角色的
103
- `allow` 不冲突:`allow`/`deny` 都只是继承层交集过滤,专用行各自的白名单照常生效。
104
- 通用行只能有一个 filter,所以用 `deny` 列全敏感工具(数据管线 + Dataset 系列 + 出图 +
105
- 专用角色创建工具);`deny` 里的名字同样必须真实注册。回归断言见
106
- `test/persona.test.mjs` 的「通用 subagent 行」用例。
107
- - **同一份 `deny` 也覆盖出网(2026-09-24)**:本插件 14 个检索 / 来源 / 文档解析工具全部列进来,否则只带
108
- `parentSession` 的通用 child 能自己抓网页,「外部检索只经 web_retriever」又是一条 persona 文案。
109
- 名字的唯一事实来源是 `src/agents/root-tool-policy.ts` 的 `RETRIEVAL_DENIED_TOOLS`(根 Agent 逐名
110
- deny 用的就是它),测试把两处对齐成同一份名单。**`ocr` 是根侧收敛的唯一例外(2026-09-26)**:它
111
- 不进 `RETRIEVAL_DENIED_TOOLS`(主 Agent 要能解析用户 `@` 进来的本地文档),改由调用级 guard 只拒
112
- `url` 形态;但通用 child 的这份 `deny` 里它**必须在**——连本地形态一起拿掉,否则通用 child
113
- 继承它能自己解析文档(见 §4.3 → `docs/dev/web-retriever.md`)。**宿主自己挂的 `web_search` / `web_fetch` 绝不能
114
- 写进这里的 `deny`**:它们不由本插件注册,未注册名字在 `deny` 里的表现是"创建子 Agent 失败";
115
- 它们只出现在根侧 `ROOT_AGENT_DENIED_TOOLS`(逐名 `restrict` 的 try/catch 容忍"这个 scope 里没有")。
102
+ - **工具面 = preset 挂的行**(D0,2026-10-19):`toolFilter` 已从委派行删除,上游报错原文指明的
103
+ 替代是「persona 与工具插件改住 Agent Preset,委派行只用 `agentPreset` 选它」——这一条我们做到底:
104
+ 本仓当前由 preset 族行暴露的 27 颗模型工具,按族拆成
105
+ `@v587d/capital-generation/tools/<family>` 的 subpath 入口行
106
+ (`package.json` 的 `exports`),每颗 preset 只挂自己那几族,**不再有运行期名字级 allow 名单**。
107
+ 行契约(那一行注册哪些名字)只有一份,住 `test/family-rows.mjs`:`test/family-entries.test.mjs`
108
+ 拿它实测每个入口注册了什么,`test/persona.test.mjs` 拿它核对 YAML 的组合结果。
109
+ - collector:`tools/collect` + `tools/time`;junior:`tools/dataset-read` + `tools/chart-source` +
110
+ `tools/time`;specialist:`tools/chart-render` + `tools/time`;retriever:`tools/retrieve-search` +
111
+ `tools/retrieve-sources` + `tools/ocr` + `tools/time`;根:`tools/time` +
112
+ `tools/ocr` + `tools/watchlist` + `tools/root-extras`(最后一行一颗工具都不带,只挂精选
113
+ skills 的 provider 与用户自定义人设分节)。**`tools/time` 每颗 preset 都挂、且不带任何行配置**:
114
+ 通用能力不按角色裁(2026-10-19 决策,retriever 那颗继承自 0.2.0 `toolFilter` 的
115
+ `localDatetime: false` 已删——行契约里没有开关,写了就是"以为裁了、其实没人读")。
116
+ - 运行期只剩**一格**:`tool-subagent-control` 把 `send_message` 与 `interrupt_agent` 焊在同一行,
117
+ 而宿主没给那颗行开成员开关,叶子角色逐名 tolerant deny 减掉那个兄弟
118
+ (`src/agents/role-tool-policy.ts` 的 `SIBLING_DENIED_TOOLS`)。它不是工具面清单。⛔ 那一格只减
119
+ **被委派子会话**的可见面:手开的角色会话上 restrict 减不掉它(时机见账本 L32),所以执行期另有
120
+ 一颗全局 `tools.guard()`(`registerRoleSiblingGuard`)兜住同一颗名字。
121
+ - **⛔ 行名与 deny 名的两种失效形状都是静默的**:族行名写错 / 包导出漏了 ⇒ 那一行装载失败
122
+ (只打一行 warn),该角色**少一整族**工具;`deny` 里的名字本作用域看不见 ⇒ 逐名跳过,只少减
123
+ 那一个并记进 `failed`(这是它相对旧"整批 allow"的差别:错一个名字不再等于完全不收敛)。
124
+ 两道补偿:`test/family-entries.test.mjs` 把 `package.json` 的 `exports` 与行契约对表,
125
+ `dc_status` 的 `agent_tool_policy` + `session_identity` 把现场带回会话侧。
126
+ - **⛔ 没有通用 `subagent` 行**(2026-10-18 用户决策:没有明确场景就不该有「其他」,它的 34 名
127
+ `deny` 名单一起删)。"谁能碰什么"因此始终是**正面清单**:deny 是 fail-open(漏写就等于有权限,
128
+ 2026-09 的出图绕过就是这么走的),行组合是 fail-closed(多挂一行才越权)。**禁止**以任何形式
129
+ 恢复通用委派行,也禁止把那一格兄弟 deny 长成工具面清单;回归 `test/persona.test.mjs`
130
+ 「委派出口只有专用角色」「组合表:每颗 preset 挂的族行必须恰好是这几行」与
131
+ `test/role-tool-policy.test.mjs`。
132
+ - **出网那十三颗只由 retriever 挂的两行带出来**,其余角色没挂就拿不到;根 preset 不挂
133
+ `tools/retrieve-search` / `tools/retrieve-sources`,可见性在组合期封闭。
134
+ `src/agents/root-tool-policy.ts` 的 `RETRIEVAL_DENIED_TOOLS` / `ROOT_AGENT_DENIED_TOOLS` 作为
135
+ 单体载体与回归兜底保留(host policy 对 root 传 `deny:false`),**新增来源只改族行与行契约**。
136
+ **`ocr` 那一行由根与 retriever 各挂一次**:主 Agent 要能解析用户 `@` 进来的本地文档;host 的
137
+ `installRootOcrGuard` 只拒它的 `url` 形态,retriever 侧拿到完整形态
138
+ (见 §4.3 → `docs/dev/web-retriever.md`)。
139
+ **宿主自己挂的 `web_search` / `web_fetch` 不由本插件注册**:2026-09-30 双端实测当时的作用域里
140
+ 没有这两个名字,所以从 `ROOT_AGENT_DENIED_TOOLS` 清掉;但 2026-10-20 的 web profile 里 AnySearch
141
+ 会补注册 `web_fetch`,它因此出现在所有 preset 的工具表里。**没挂行不等于看不见**:要收窄就加回根侧/
142
+ 角色名单(逐名 restrict 容忍 absent),或关掉宿主 provider;别拿组合表当宿主工具的隔离证明。
116
143
  - 不用 `dsh-time-context` 行:它每个 step 自动注入时钟读数,与自研 `get_local_datetime`
117
144
  重复;时间读数只来自后者(会话组作用域内注册,主 Agent 与全部子 Agent 共享,支持
118
145
  `timezone` 换算)。
119
- - `data_analyst` 行保持 `disabled`。启用前置条件(缺一不可):宿主先实现 Python runner 与
120
- coding 工具;插件注册 `read_profile`(allow 里的名字必须先真实存在);更新 `AGENTS.md` 与 `docs/dev/data-roles.md`
121
- 的角色边界与 `test/persona.test.mjs` 的预留期断言。
146
+ - `data_analyst` 的 preset 与委派行都保持 `disabled`(2026-10-18 用户要求先停用,等价于注释)。
147
+ 恢复前置条件(缺一不可):宿主先实现 Python runner 与 coding 工具;插件注册 `read_profile`
148
+ (新工具必须先有族行带它、行契约同步);更新 `AGENTS.md`、`docs/dev/data-roles.md` 与
149
+ `test/persona.test.mjs` 的预留期断言。
122
150
 
123
151
  ## 5.1 shell 与文件口:开 read、保留 bash、不给写(2026-10-15 用户决策)
124
152
 
@@ -129,19 +157,23 @@
129
157
  2026-09-30 的"主 Agent 不给 shell"):主 Agent 需要 `read` 读 skill 分册与工作区文件
130
158
  (此前只能 `bash cat`,能力等价但绕远),shell 保留纯计算兜底。`ROOT_AGENT_DENIED_TOOLS`
131
159
  里的 `bash` / `pwsh` 随之移出,名单改为出图三件套 + 十三个出网工具 + `write` / `edit`。
132
- - **文件写口不开**:`write` / `edit` 被两层拦住——根侧逐名收敛(主 Agent 视图层)+ 全局
133
- `tools.guard()`(`registerFsWriteGuard`,调用期按 `composedPreset` 认领,fail-open,细节见
134
- `docs/dev/bash-gate.md` §1.6)。理由:主 Agent 唯一对用户说话、又会读到子 Agent 回传(含网页
135
- 材料),写文件等于给"注入 → 落盘 → 被别的环节读回"开口;业务落盘本来就有正路
136
- (`store.writeContext` 等工具实现),模型手里的写口没有正当用途。通用 `subagent` 行的
137
- `toolFilter.deny` 同步含 `read` / `write` / `edit`(通用 child 不得读 raw.json,原始 rows
138
- 永不出工具层)。
160
+ - **文件写口不开,但"不开"靠的是调用级闸门,不是行配置**:根 preset 那行 `read: true /
161
+ write: false / edit: false` 只决定**本层变体**——2026-10-19 实测手开 Capital 里 `write` 仍在工具表
162
+ 中且真的落盘,缺席不等于移除(`ScopedLayers.merge` 用 global 打底,账本 L33)。所以拦下写口的只有一颗:全局 `tools.guard()`
163
+ (`registerFsWriteGuard`,判据 = 调用期 `composedPreset` ∈ 本插件任一 preset,fail-open,细节见
164
+ `docs/dev/bash-gate.md` §1.6)。`ROOT_AGENT_DENIED_TOOLS` 里的 `write` / `edit` 只在**被委派**
165
+ 那一支减得到可见面,且生产装配以 `deny: false` 注册、不提交名单。理由:主 Agent 唯一对用户说话、
166
+ 又会读到子 Agent 回传(含网页材料),写文件等于给"注入 → 落盘 → 被别的环节读回"开口;业务落盘
167
+ 本来就有正路(`store.writeContext` 等工具实现)。角色一侧同一条判据:本插件的六颗 preset 一律
168
+ 不许直接写文件,原始 rows 也永不出工具层。
139
169
  - **平台成对挂载**:Windows 上 host 层挂的是 `pwsh-sandbox`,没有 `bash-sandbox`;只挂
140
- `tool-bash` 会让名为 bash 的工具实际执行 PowerShell。所以两行互补 `disabled`,allow / deny
141
- 里的名字用 `!!js` 三元表达式按平台选。`tools.restrict()` 对未注册名字报错,所以表达式与行必须
142
- 同进同退(回归:`test/persona.test.mjs`「shell 行:平台成对挂载……」)。
170
+ `tool-bash` 会让名为 bash 的工具实际执行 PowerShell。所以两行互补 `disabled: !!js`。0.2.1 起
171
+ 这份 YAML 里不再出现工具名,shell 名改为在 `src/agents/role-tool-policy.ts` 按平台取一颗
172
+ (`SHELL_TOOL`)进 data_junior 的清单——取错那颗会整批 restrict 报错、该角色完全不收敛,
173
+ 所以 `test/bash-guard.test.mjs` 另钉一条"preset 挂的每一行 shell,闸门与角色工具面都必须认",
174
+ 成对挂载与后台执行那一格仍由 `test/persona.test.mjs`「shell 行:平台成对挂载……」看着。
143
175
  - **不给后台执行**:`enableRunInBackground: false`。本 preset 不挂 `tool-jobs`,开着后台只会让
144
- 模型拿到一个永远读不回来的 jobId(`job_output` / `job_kill` 不在任何 allow 里)。
176
+ 模型拿到一个永远读不回来的 jobId(本 preset 压根没挂 `tool-jobs` 那一行)。
145
177
  - **shell 闸门只剩一层,且不是安全边界**(`src/agents/bash-guard.ts`):拦掉
146
178
  `sandbox_permissions` / `justification`——被委派会话的审批策略由框架固定为 `never`,升级必然
147
179
  失败,而且模型会收到「the user rejected…」这种把系统拒绝说成用户拒绝的文案;被委派或身份
@@ -160,9 +192,11 @@
160
192
  ## 6. 改动流程
161
193
 
162
194
  1. 先判断内容属于"每轮硬规则"(→ persona)还是"按需协议"(→ `skills/`)。
163
- 2. 专用角色六处齐改(判据与顺序见 `docs/dev/preset-persona.md` §8.5):委派行(provider /
164
- toolName / backgroundMode / persona / toolFilter,allow 必须含 `skill`)、子 persona(骨架 +
165
- 第一条 duty `skill <name>`)、`skills/<name>/SKILL.md`、主 persona 的路由与复用规则、
195
+ 2. 专用角色**七处齐改**(判据与顺序见 `docs/dev/preset-persona.md` §8.5):角色 preset 声明行
196
+ (`dsh-persona` 正文:骨架 + 第一条 duty `skill <name>`;以及它自己需要的工具行)、主 preset
197
+ 里的委派行(`provider` / `toolName` / `agentPreset`)、该角色 preset 挂哪几族行
198
+ (`test/family-rows.mjs` 的行契约 + `test/persona.test.mjs` 的组合表;只有同行焊死的兄弟才写
199
+ `src/agents/role-tool-policy.ts` 那份逐名 deny)、`skills/<name>/SKILL.md`、主 persona 的路由与复用规则、
166
200
  `docs/dev/data-roles.md` §1.1 的角色边界、测试断言。
167
201
  3. `npm test` 全绿 + `agentPresets.resolve('capital-generation')` 结果里没有 `broken`(挂载成功),
168
202
  再开一个 Capital 会话确认工具表、首轮预检,以及子 Agent 是否真的按第一条 duty 先加载 skill。