@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.
- package/CHANGELOG.md +54 -1
- package/README.md +40 -19
- package/chart-ui/README.md +1 -1
- package/chart-ui/client.src.cjs +7 -16
- package/chart-ui/index.js +12 -33
- package/chart-ui/package.json +2 -2
- package/config/client.js +18 -39
- package/config/client.src.cjs +79 -217
- package/config/index.js +22 -72
- package/config/package.json +2 -2
- package/cordis.patch.yml +46 -51
- package/lib/agents/bash-guard.d.ts +9 -55
- package/lib/agents/bash-guard.js +27 -67
- package/lib/agents/preset-roster.d.ts +22 -0
- package/lib/agents/preset-roster.js +87 -0
- package/lib/agents/role-tool-policy.d.ts +46 -0
- package/lib/agents/role-tool-policy.js +205 -0
- package/lib/agents/root-tool-policy.d.ts +28 -124
- package/lib/agents/root-tool-policy.js +164 -237
- package/lib/agents/selected-skills-provider.d.ts +2 -6
- package/lib/agents/selected-skills-provider.js +27 -84
- package/lib/capital-settings.d.ts +27 -0
- package/lib/capital-settings.js +23 -0
- package/lib/chart/artifact-ref.d.ts +3 -8
- package/lib/chart/artifact-ref.js +3 -8
- package/lib/chart/downsample.d.ts +2 -5
- package/lib/chart/downsample.js +3 -8
- package/lib/chart/errors.d.ts +3 -7
- package/lib/chart/errors.js +1 -2
- package/lib/chart/event-context.d.ts +8 -0
- package/lib/chart/event-context.js +39 -0
- package/lib/chart/events.d.ts +21 -78
- package/lib/chart/events.js +40 -189
- package/lib/chart/html.d.ts +2 -5
- package/lib/chart/html.js +8 -15
- package/lib/chart/runtime.d.ts +5 -18
- package/lib/chart/runtime.js +14 -34
- package/lib/chart/series.d.ts +10 -17
- package/lib/chart/series.js +22 -47
- package/lib/chart/source-token.d.ts +5 -13
- package/lib/chart/source-token.js +18 -17
- package/lib/chart/spec.d.ts +6 -12
- package/lib/chart/spec.js +7 -31
- package/lib/chart/tool.d.ts +6 -29
- package/lib/chart/tool.js +9 -23
- package/lib/chart-render-entry.d.ts +9 -0
- package/lib/chart-render-entry.js +17 -0
- package/lib/chart-source-entry.d.ts +13 -0
- package/lib/chart-source-entry.js +20 -0
- package/lib/collect-entry.d.ts +9 -0
- package/lib/collect-entry.js +10 -0
- package/lib/collector-runtime.d.ts +22 -0
- package/lib/collector-runtime.js +97 -0
- package/lib/data-collector/args.d.ts +6 -24
- package/lib/data-collector/args.js +6 -24
- package/lib/data-collector/dataset-tools.d.ts +7 -1
- package/lib/data-collector/dataset-tools.js +27 -56
- package/lib/data-collector/describe.d.ts +8 -33
- package/lib/data-collector/describe.js +17 -70
- package/lib/data-collector/hub.d.ts +27 -85
- package/lib/data-collector/hub.js +19 -85
- package/lib/data-collector/query-time.d.ts +7 -26
- package/lib/data-collector/query-time.js +8 -27
- package/lib/data-collector/store.d.ts +40 -117
- package/lib/data-collector/store.js +32 -111
- package/lib/data-collector/time-axis.d.ts +16 -76
- package/lib/data-collector/time-axis.js +25 -111
- package/lib/data-collector/tools.d.ts +6 -6
- package/lib/data-collector/tools.js +34 -43
- package/lib/dataset-read-entry.d.ts +9 -0
- package/lib/dataset-read-entry.js +7 -0
- package/lib/index.d.ts +7 -117
- package/lib/index.js +43 -422
- package/lib/net/eastmoney-client.d.ts +13 -65
- package/lib/net/eastmoney-client.js +12 -53
- package/lib/net/throttle.d.ts +2 -13
- package/lib/net/throttle.js +3 -14
- package/lib/ocr/client.d.ts +12 -21
- package/lib/ocr/client.js +23 -40
- package/lib/ocr/markdown.d.ts +20 -26
- package/lib/ocr/markdown.js +23 -36
- package/lib/ocr/store.d.ts +14 -47
- package/lib/ocr/store.js +15 -45
- package/lib/ocr-entry.d.ts +9 -0
- package/lib/ocr-entry.js +10 -0
- package/lib/policy-entry.d.ts +17 -0
- package/lib/policy-entry.js +22 -0
- package/lib/preset-claim.d.ts +22 -0
- package/lib/preset-claim.js +24 -0
- package/lib/preset-ids.d.ts +38 -0
- package/lib/preset-ids.js +46 -0
- package/lib/retriever-config.d.ts +37 -0
- package/lib/retriever-config.js +36 -0
- package/lib/retriever-runtime.d.ts +31 -0
- package/lib/retriever-runtime.js +82 -0
- package/lib/root-extras-entry.d.ts +17 -0
- package/lib/root-extras-entry.js +25 -0
- package/lib/runtime-entry.d.ts +15 -0
- package/lib/runtime-entry.js +5 -0
- package/lib/runtime.d.ts +21 -0
- package/lib/runtime.js +33 -0
- package/lib/search-entry.d.ts +9 -0
- package/lib/search-entry.js +9 -0
- package/lib/sources/eastmoney-http.js +20 -68
- package/lib/sources/ftshare-rest.d.ts +6 -34
- package/lib/sources/ftshare-rest.js +84 -292
- package/lib/sources/fuyao-core.d.ts +8 -18
- package/lib/sources/fuyao-core.js +10 -21
- package/lib/sources/fuyao-rest.d.ts +2 -6
- package/lib/sources/fuyao-rest.js +23 -102
- package/lib/sources/security-code.d.ts +6 -12
- package/lib/sources/security-code.js +6 -12
- package/lib/sources/security-identity.d.ts +1 -4
- package/lib/sources/security-identity.js +3 -8
- package/lib/sources/tencent-http.js +14 -28
- package/lib/sources/tencent-public-core.d.ts +8 -60
- package/lib/sources/tencent-public-core.js +12 -77
- package/lib/sources/wind-mcp.d.ts +0 -5
- package/lib/sources/wind-mcp.js +23 -78
- package/lib/sources-entry.d.ts +9 -0
- package/lib/sources-entry.js +9 -0
- package/lib/time/tools.d.ts +8 -31
- package/lib/time/tools.js +30 -66
- package/lib/time-entry.d.ts +9 -0
- package/lib/time-entry.js +7 -0
- package/lib/tool-exec.d.ts +45 -11
- package/lib/tool-exec.js +59 -6
- package/lib/user-customization.d.ts +14 -0
- package/lib/user-customization.js +47 -0
- package/lib/watchlist/tools.d.ts +3 -13
- package/lib/watchlist/tools.js +10 -30
- package/lib/watchlist-entry.d.ts +9 -0
- package/lib/watchlist-entry.js +6 -0
- package/lib/web-retriever/engines.d.ts +6 -11
- package/lib/web-retriever/engines.js +9 -14
- package/lib/web-retriever/html-markdown.d.ts +14 -34
- package/lib/web-retriever/html-markdown.js +39 -75
- package/lib/web-retriever/local-fetch.d.ts +22 -58
- package/lib/web-retriever/local-fetch.js +33 -77
- package/lib/web-retriever/retriever.d.ts +6 -18
- package/lib/web-retriever/retriever.js +7 -7
- package/lib/web-retriever/sources.d.ts +37 -124
- package/lib/web-retriever/sources.js +64 -196
- package/lib/web-retriever/tools.d.ts +43 -27
- package/lib/web-retriever/tools.js +99 -137
- package/lib/web-retriever/wind-client.d.ts +14 -31
- package/lib/web-retriever/wind-client.js +16 -32
- package/locale/zh.json +1 -1
- package/package.json +67 -7
- package/preset/capital-generation/README.md +87 -53
- package/preset/capital-generation/agent.patch.yml +526 -337
- package/preset/capital-generation/skills/capital-data-profile/SKILL.md +2 -2
- package/preset/capital-generation/skills/capital-data-protocol/SKILL.md +1 -1
- package/preset/capital-generation/skills/capital-equity-research/SKILL.md +1 -1
- package/preset/capital-generation/skills/capital-event-impact/SKILL.md +1 -1
- package/preset/capital-generation/skills/capital-orchestration/SKILL.md +15 -19
- package/preset/capital-generation/skills/capital-portfolio-review/SKILL.md +1 -1
- package/preset/capital-generation/skills/capital-visualization-protocol/SKILL.md +9 -12
- package/preset/capital-generation/skills/capital-web-evidence/SKILL.md +1 -1
- package/watchlist/client.js +15 -148
- package/watchlist/client.src.cjs +148 -662
- package/watchlist/holding-rules.js +11 -38
- package/watchlist/index.js +127 -397
- package/watchlist/package.json +2 -2
|
@@ -3,49 +3,27 @@ import { readFileSync } from 'node:fs';
|
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
5
|
import { agentSessionId, isRootAgent } from './root-tool-policy.js';
|
|
6
|
-
//
|
|
7
|
-
// import so the published lib resolves the same metadata beside the pinned snapshots.
|
|
6
|
+
// Catalog is package data outside the TS root; the runtime import keeps lib resolving it beside pinned snapshots.
|
|
8
7
|
// @ts-expect-error catalog.js is intentionally maintained as package data.
|
|
9
8
|
import { SELECTED_SKILL_CATALOG as CATALOG, SELECTED_SKILL_SKILL_DIRS, SELECTED_SKILL_TASK_IDS, selectedSkillsForTask } from '../../selected-skills/catalog.js';
|
|
10
9
|
export const SELECTED_SKILL_CATALOG = CATALOG;
|
|
11
10
|
const PROVIDER_NAME = 'capital-selected-skills';
|
|
12
|
-
/** 本 preset 的身份:两条注册路径(`agent/created` 与 `agent-preset/selected`)共用一份。 */
|
|
13
11
|
const CAPITAL_PRESET_ID = 'capital-generation';
|
|
14
|
-
//
|
|
15
|
-
// plugins/us-stock-analysis/skills,不在 <repo>/skills 底下。写死目录列表的表现不是报错,
|
|
16
|
-
// 而是"用户在卡片上勾了那一格、技能永远不出现"(AGENTS.md §9.7)。
|
|
12
|
+
// Derive roots from the catalog: a hardcoded list silently hides checked boxes (upstream layouts differ).
|
|
17
13
|
const SKILL_ROOTS = Object.entries(SELECTED_SKILL_SKILL_DIRS).map(([repository, skillsDir]) => fileURLToPath(new URL(`../../selected-skills/${repository}/${skillsDir}`, import.meta.url)));
|
|
18
|
-
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* 索引**不改磁盘**:`preset/.../SKILL.md` 一个字节都不动,正文在 `get()` 读取期拼上索引块。
|
|
22
|
-
* 三个理由,缺一都不是洁癖:装好的包常常整棵只读(全局安装更糟);`skill-filesystem` 的 watcher
|
|
23
|
-
* 会被写文件搅动,多会话并行时互相打架;`test/persona.test.mjs` 正钉着这些文件的 frontmatter 与
|
|
24
|
-
* 体积,运行期改写会让那些闸门失去意义。
|
|
25
|
-
*/
|
|
14
|
+
/** Built-in task skill root; the index is appended at read time, never written to disk:
|
|
15
|
+
* installs may be read-only, watchers would churn, and tests pin frontmatter and size. */
|
|
26
16
|
const TASK_SKILL_ROOT = fileURLToPath(new URL('../../preset/capital-generation/skills', import.meta.url));
|
|
27
|
-
/**
|
|
28
|
-
*
|
|
29
|
-
* 同层自定义根是 `CUSTOM_RANK = 300`,这里取 150 保证同层时压过 fs provider。
|
|
30
|
-
*
|
|
31
|
-
* 跨层本来也轮不到 rank:`dsh-agent-preset-registry` 把 preset 的 standing scope 挂成
|
|
32
|
-
* **agent scope 的 parent**(`standingKey = scopeParentOf(agentKey)`),而 `chainLayers` 的注释写明
|
|
33
|
-
* "farthest ancestor first, the nearest scope has the final word"、`scopeChainOf(...).reverse()` 后
|
|
34
|
-
* 逐层 `merged.set(name, ...)` —— 本 provider 注册在 agent scope 里,是最近的一层,同名天然覆盖。
|
|
35
|
-
* 两条机制取其一即可,取两条是因为遮蔽失败的症状是"索引静默消失",没有第二个人会发现。
|
|
36
|
-
*/
|
|
17
|
+
/** Smaller rank wins: 150 beats the same-layer custom root (300). The agent scope usually
|
|
18
|
+
* shadows anyway; both are cheap insurance because failure is silent. */
|
|
37
19
|
const TASK_SKILL_SHADOW_RANK = 150;
|
|
38
20
|
const INDEX_HEADING = '## 附:本轮可用的外部精选 Skill(索引)';
|
|
39
|
-
/**
|
|
40
|
-
* 索引块的框。它把**外部方法论**塞进了**宿主契约 skill** 的正文里,框架被拉平了,所以这四句必须
|
|
41
|
-
* 写在块内而不是别的文档里:冲突判据、不可动摇的三处边界、以及"这里只有摘要"。
|
|
42
|
-
*/
|
|
21
|
+
/** Conflict precedence and the three untouchable boundaries must live inside the block. */
|
|
43
22
|
const INDEX_FRAME = [
|
|
44
23
|
'以下是你(用户)在设置里启用的外部精选 Skill,按能力标签与本次任务关联后列出。它们是**方法论材料**,',
|
|
45
24
|
'需要正文时照常用 `skill` 工具按名加载。它们**不改变**本 skill 的证据门、工具委派路径、输出通道与报告形状;',
|
|
46
25
|
'与本 skill 冲突时**以本 skill 为准**。这里只给名称与摘要,摘要不等于全文,未加载前不要照它行事。',
|
|
47
26
|
];
|
|
48
|
-
/** 最小 frontmatter 读取:只要 `name` / `description` / 正文。完整策略解析仍归 fs provider。 */
|
|
49
27
|
function readFrontmatter(raw) {
|
|
50
28
|
const match = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(raw);
|
|
51
29
|
if (match === null)
|
|
@@ -58,10 +36,7 @@ function readFrontmatter(raw) {
|
|
|
58
36
|
}
|
|
59
37
|
return { fields, body: raw.slice(match[0].length) };
|
|
60
38
|
}
|
|
61
|
-
/**
|
|
62
|
-
* 载入三颗任务型 skill 的正文。**读不到就不遮蔽**:`list()` 不会列出这个候选,fs provider 照常
|
|
63
|
-
* 供原文,用户看到的是"没有索引",而不是"这颗 skill 不见了"(AGENTS.md §9.7 ⑤ 失败要留余地)。
|
|
64
|
-
*/
|
|
39
|
+
/** Unreadable means no shadow, never a missing skill: the fs provider still serves the original. */
|
|
65
40
|
function loadTaskSkillBases(root = TASK_SKILL_ROOT) {
|
|
66
41
|
const bases = new Map();
|
|
67
42
|
for (const name of SELECTED_SKILL_TASK_IDS) {
|
|
@@ -74,16 +49,11 @@ function loadTaskSkillBases(root = TASK_SKILL_ROOT) {
|
|
|
74
49
|
bases.set(name, { name, description, content: parsed.body.trim(), directory: join(root, name) });
|
|
75
50
|
}
|
|
76
51
|
catch {
|
|
77
|
-
// 读不到是 fail-open,不是错误路径:默认态(一颗都没启用)本来就不遮蔽任何东西。
|
|
78
52
|
}
|
|
79
53
|
}
|
|
80
54
|
return bases;
|
|
81
55
|
}
|
|
82
|
-
/**
|
|
83
|
-
* 索引块正文。**唯一实现**:条目集合来自 catalog 的 `selectedSkillsForTask`(与目录、闸门同源),
|
|
84
|
-
* 描述用**运行时那一份**(上游 frontmatter,也就是会话目录里模型看到的那句话),不是设置卡片里
|
|
85
|
-
* 策展过的中文摘要——同一个 skill 在同一段上下文里出现两种描述,只会让模型两处对照。
|
|
86
|
-
*/
|
|
56
|
+
/** Sole index renderer; descriptions use runtime frontmatter (what the model sees), not card summaries. */
|
|
87
57
|
export function renderTaskSkillIndex(taskId, summaries) {
|
|
88
58
|
if (summaries.length === 0)
|
|
89
59
|
return undefined;
|
|
@@ -106,13 +76,11 @@ function selectedNames(selection) {
|
|
|
106
76
|
function readSelection(source) {
|
|
107
77
|
return typeof source === 'function' ? source() : source;
|
|
108
78
|
}
|
|
109
|
-
//
|
|
110
|
-
// 变了才失效目录缓存,未变就零成本放行。
|
|
79
|
+
// Fingerprint only the catalog key set: refresh the cache only when the selection changes.
|
|
111
80
|
function selectionFingerprint(selection) {
|
|
112
81
|
return SELECTED_SKILL_CATALOG.map(({ key }) => (selection[key] === true ? '1' : '0')).join('');
|
|
113
82
|
}
|
|
114
|
-
// agent/pre-step
|
|
115
|
-
// Agent context(其 scope tag 就是该 Agent,dispatch 的 scope filter 才放行这条监听)。
|
|
83
|
+
// `agent/pre-step` belongs to dsh-agent; attach via the injected Agent context so scope filtering admits it.
|
|
116
84
|
function onPreStepEvent(ctx, listener) {
|
|
117
85
|
const events = ctx;
|
|
118
86
|
return events.on?.('agent/pre-step', listener);
|
|
@@ -127,19 +95,16 @@ function strictCapitalPreset(ctx, agent) {
|
|
|
127
95
|
return false;
|
|
128
96
|
}
|
|
129
97
|
}
|
|
130
|
-
/**
|
|
98
|
+
/** Registers selected community experiments on the Capital root Agent only. */
|
|
131
99
|
export function registerRootSelectedSkills(ctx, selection, createFilesystemProvider = createFilesystemSkillProvider) {
|
|
132
|
-
// Static callers
|
|
133
|
-
//
|
|
134
|
-
// live root Agent: list()/get() filter against the current selection, and the
|
|
135
|
-
// pre-step hook below refreshes the visible catalog when the selection changes.
|
|
100
|
+
// Static callers keep the all-off fast path; the plugin passes a reader so live toggles apply
|
|
101
|
+
// at the next step (list/get filter by selection, pre-step refreshes the visible catalog).
|
|
136
102
|
if (typeof selection !== 'function' && selectedNames(selection).size === 0)
|
|
137
103
|
return;
|
|
138
104
|
const listenCtx = ctx.root ?? ctx;
|
|
139
105
|
if (typeof listenCtx.on !== 'function')
|
|
140
106
|
return;
|
|
141
|
-
//
|
|
142
|
-
// 预设 → `agent/created`;先按默认预设建、再 select 到 Capital → `agent-preset/selected`)。
|
|
107
|
+
// One registration per root Agent: both event paths can observe the same Agent.
|
|
143
108
|
const registered = new WeakSet();
|
|
144
109
|
const registerFor = async (agent) => {
|
|
145
110
|
if (!agent || registered.has(agent))
|
|
@@ -154,8 +119,7 @@ export function registerRootSelectedSkills(ctx, selection, createFilesystemProvi
|
|
|
154
119
|
ctx.logger?.warn?.('capital-generation: selected skills are unavailable (root Agent cannot inject skills)');
|
|
155
120
|
return;
|
|
156
121
|
}
|
|
157
|
-
// agent/created
|
|
158
|
-
// provider 与 pre-step 钩子都在首轮 prompt 前落位(首轮 catalog 不与注册竞态)。
|
|
122
|
+
// agent/created is serial: DSH awaits listeners, so this inject lands before the first prompt.
|
|
159
123
|
await agentCtx.inject(['skills'], (injectedCtx) => {
|
|
160
124
|
const skills = injectedCtx.skills;
|
|
161
125
|
if (typeof skills?.registerProvider !== 'function') {
|
|
@@ -164,9 +128,7 @@ export function registerRootSelectedSkills(ctx, selection, createFilesystemProvi
|
|
|
164
128
|
}
|
|
165
129
|
let filesystemProvider;
|
|
166
130
|
let control;
|
|
167
|
-
//
|
|
168
|
-
// 全关也照常注册 provider(否则会话创建后打开开关永远不出现),靠下面的 pre-step
|
|
169
|
-
// 钩子每轮对齐设置。
|
|
131
|
+
// Register even when all toggles are off; otherwise a later enable would never surface. Pre-step aligns settings.
|
|
170
132
|
let served = selectionFingerprint(readSelection(selection));
|
|
171
133
|
injectedCtx.effect(() => {
|
|
172
134
|
const unregister = skills.registerProvider((registration) => {
|
|
@@ -177,15 +139,11 @@ export function registerRootSelectedSkills(ctx, selection, createFilesystemProvi
|
|
|
177
139
|
customSkillDirs: SKILL_ROOTS,
|
|
178
140
|
watch: true,
|
|
179
141
|
});
|
|
180
|
-
// 遮蔽用的底稿只在注册时读一次(三份小文件,读不到就不遮蔽)。
|
|
181
142
|
const taskBases = loadTaskSkillBases();
|
|
182
|
-
//
|
|
183
|
-
// 再枚举一遍快照目录;为空就退回"没有索引",也就是把整颗让给 fs provider 的原文。
|
|
143
|
+
// Summaries from the last `list()`; `get()` reuses them instead of rescanning dirs.
|
|
184
144
|
let runtimeSummaries = [];
|
|
185
145
|
const indexFor = (taskId) => {
|
|
186
146
|
const byName = new Map(runtimeSummaries.map((entry) => [entry.name, entry]));
|
|
187
|
-
// 条目集合来自 catalog 的唯一实现(与目录、闸门同源),顺序取 catalog 顺序:
|
|
188
|
-
// 同一仓库的几颗排在一起,读起来比按名字打散更像一份索引。
|
|
189
147
|
const summaries = selectedSkillsForTask(taskId, [...byName.keys()])
|
|
190
148
|
.map((entry) => byName.get(entry.name))
|
|
191
149
|
.filter((entry) => entry !== undefined);
|
|
@@ -194,11 +152,9 @@ export function registerRootSelectedSkills(ctx, selection, createFilesystemProvi
|
|
|
194
152
|
const provider = {
|
|
195
153
|
name: PROVIDER_NAME,
|
|
196
154
|
async list(options) {
|
|
197
|
-
//
|
|
155
|
+
// Read at call time: toggles are settings, not fixed at Agent creation.
|
|
198
156
|
const enabled = selectedNames(readSelection(selection));
|
|
199
|
-
//
|
|
200
|
-
// 里才启动,短路保证默认关闭的会话不起任何 watcher),**也不遮蔽任何内置 skill**:
|
|
201
|
-
// 一颗都没启用时用户看到的必须与没有这个 provider 时逐字相同。
|
|
157
|
+
// All-off is the default: skip snapshot dirs (no watcher starts) and shadow nothing, matching no-provider output.
|
|
202
158
|
if (enabled.size === 0) {
|
|
203
159
|
runtimeSummaries = [];
|
|
204
160
|
return [];
|
|
@@ -207,9 +163,7 @@ export function registerRootSelectedSkills(ctx, selection, createFilesystemProvi
|
|
|
207
163
|
const candidates = Array.isArray(result) ? result : result.candidates;
|
|
208
164
|
const selected = candidates.filter((candidate) => enabled.has(candidate.name));
|
|
209
165
|
runtimeSummaries = selected.map((candidate) => ({ name: candidate.name, description: candidate.description }));
|
|
210
|
-
//
|
|
211
|
-
// 没有索引就整颗让给 fs provider(正文照旧),因此"索引缺失"永远不会演变成
|
|
212
|
-
// "这颗 skill 不见了"——遮蔽是加法,不是替换。
|
|
166
|
+
// Shadow a task skill only when it has an index; otherwise the fs provider's original wins.
|
|
213
167
|
const shadows = [...taskBases.values()]
|
|
214
168
|
.filter((base) => indexFor(base.name) !== undefined)
|
|
215
169
|
.map((base) => ({
|
|
@@ -228,7 +182,6 @@ export function registerRootSelectedSkills(ctx, selection, createFilesystemProvi
|
|
|
228
182
|
get(candidate, options) {
|
|
229
183
|
const base = taskBases.get(candidate.name);
|
|
230
184
|
if (base !== undefined) {
|
|
231
|
-
// 索引在**读取期**算:开关是 settings 偏好,加载这一刻才是最新的。
|
|
232
185
|
const index = indexFor(base.name);
|
|
233
186
|
const content = index === undefined ? base.content : `${base.content}\n\n${index}`;
|
|
234
187
|
return Promise.resolve({
|
|
@@ -250,11 +203,8 @@ export function registerRootSelectedSkills(ctx, selection, createFilesystemProvi
|
|
|
250
203
|
};
|
|
251
204
|
return provider;
|
|
252
205
|
});
|
|
253
|
-
//
|
|
254
|
-
//
|
|
255
|
-
// 重算;未变则 digest 不变、catalog 不重发。必须在放行 next() 之前做完——
|
|
256
|
-
// waterfall 里 tool-skill 是 await next() 之后才快照,但监听器注册顺序不归我们
|
|
257
|
-
// 管,先做完再放行在两种顺序下都赶得上本轮快照。设置读取失败只降级,不阻断本轮。
|
|
206
|
+
// Invalidate before next() so this turn's snapshot sees the change regardless of listener order.
|
|
207
|
+
// A settings read failure only degrades this hook.
|
|
258
208
|
const stopPreStep = onPreStepEvent(injectedCtx, (_payload, next) => {
|
|
259
209
|
try {
|
|
260
210
|
const fingerprint = selectionFingerprint(readSelection(selection));
|
|
@@ -279,20 +229,14 @@ export function registerRootSelectedSkills(ctx, selection, createFilesystemProvi
|
|
|
279
229
|
});
|
|
280
230
|
}
|
|
281
231
|
catch (error) {
|
|
282
|
-
//
|
|
283
|
-
// 同时撤掉登记,让后面的事件(下一次 select、别的注册路径)还有重试的余地。
|
|
232
|
+
// Optional capability: degrade with a warning, never block Agent creation; clear so a later event can retry.
|
|
284
233
|
registered.delete(agent);
|
|
285
234
|
ctx.logger?.warn?.(`capital-generation: selected skills are unavailable (${String(error)})`);
|
|
286
235
|
}
|
|
287
236
|
};
|
|
288
237
|
const stop = listenCtx.on('agent/created', ({ agent }) => registerFor(agent));
|
|
289
|
-
//
|
|
290
|
-
//
|
|
291
|
-
// `agentPresets.select('capital-generation')`,而 `agent/created` 在 select 之前就已经发完——
|
|
292
|
-
// 只挂那一条时本插件的 `apply()` 是在**这次 recompose 的 mount 里**才跑的,监听器出生就错过了
|
|
293
|
-
// 自己这个 Agent:设置卡 10 个开关全开、会话目录仍只有 preset 自带的 8 颗(真 boot graph 探针:
|
|
294
|
-
// create→select 8 颗 / 建会话时 mount 同一 preset 18 颗)。preset registry 在 mount 完成后才
|
|
295
|
-
// `session.append('agent-preset/selected')`,所以本行一定早于这条事件落位。
|
|
238
|
+
// Second path: GUI creates with the default preset, then selects Capital. `agent/created`
|
|
239
|
+
// already fired and apply() runs inside that remount, so `agent-preset/selected` arrives after mount.
|
|
296
240
|
const onPresetEvent = listenCtx.on;
|
|
297
241
|
const stopPreset = onPresetEvent?.('agent-preset/selected', (sessionId, agentPreset) => {
|
|
298
242
|
if (agentPreset !== CAPITAL_PRESET_ID)
|
|
@@ -301,8 +245,7 @@ export function registerRootSelectedSkills(ctx, selection, createFilesystemProvi
|
|
|
301
245
|
const agent = agents?.get?.(String(sessionId));
|
|
302
246
|
if (agent === undefined)
|
|
303
247
|
return;
|
|
304
|
-
//
|
|
305
|
-
// 自兜异常(失败只降级告警并撤登记,下一次事件还有重试的余地),这里不会产生未处理拒绝。
|
|
248
|
+
// Emit-style event: the promise only lets tests await registration; errors are handled inside.
|
|
306
249
|
return registerFor(agent);
|
|
307
250
|
});
|
|
308
251
|
ctx.effect?.(() => () => {
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sole reader of the bundled `capital-config` entry. The id must match the host row,
|
|
3
|
+
* settings card and preset row; drift is caught by the four-way assertion in
|
|
4
|
+
* `test/capital-config.test.mjs`. Unreadable returns `{}` and callers fill defaults;
|
|
5
|
+
* only reference names are read here, never resolved secrets.
|
|
6
|
+
*/
|
|
7
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
8
|
+
import type { RetrieverConfig } from './retriever-config.js';
|
|
9
|
+
import type { SelectedSkillSelection } from './agents/selected-skills-provider.js';
|
|
10
|
+
export declare const CAPITAL_CONFIG_ENTRY_ID = "capital-config";
|
|
11
|
+
/** Fields this repo consumes (the host half owns the rest). */
|
|
12
|
+
export interface CapitalConfigSlice {
|
|
13
|
+
fuyaoCredentialRef?: string;
|
|
14
|
+
ftshareCredentialRef?: string;
|
|
15
|
+
customPersona?: string;
|
|
16
|
+
retriever?: RetrieverConfig;
|
|
17
|
+
selectedSkills?: SelectedSkillSelection;
|
|
18
|
+
}
|
|
19
|
+
export declare function readCapitalConfig(ctx: Context): CapitalConfigSlice;
|
|
20
|
+
/** Flat credential refs needed by the collector domain (same shape as `CollectorConfig`). */
|
|
21
|
+
export declare function readCollectorConfig(ctx: Context): {
|
|
22
|
+
fuyaoCredentialRef?: string;
|
|
23
|
+
ftshareCredentialRef?: string;
|
|
24
|
+
windCredentialRef?: string;
|
|
25
|
+
};
|
|
26
|
+
/** Retriever config slice (baseURL, credential ref, Wind endpoint, local fallback switch). */
|
|
27
|
+
export declare function readRetrieverConfig(ctx: Context): RetrieverConfig;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export const CAPITAL_CONFIG_ENTRY_ID = 'capital-config';
|
|
2
|
+
export function readCapitalConfig(ctx) {
|
|
3
|
+
try {
|
|
4
|
+
const settings = ctx.get('settings');
|
|
5
|
+
return settings?.describe?.().find((entry) => entry?.ns === CAPITAL_CONFIG_ENTRY_ID)?.value ?? {};
|
|
6
|
+
}
|
|
7
|
+
catch {
|
|
8
|
+
return {};
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
/** Flat credential refs needed by the collector domain (same shape as `CollectorConfig`). */
|
|
12
|
+
export function readCollectorConfig(ctx) {
|
|
13
|
+
const config = readCapitalConfig(ctx);
|
|
14
|
+
return {
|
|
15
|
+
fuyaoCredentialRef: config.fuyaoCredentialRef,
|
|
16
|
+
ftshareCredentialRef: config.ftshareCredentialRef,
|
|
17
|
+
windCredentialRef: config.retriever?.windDocs?.credentialRef,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/** Retriever config slice (baseURL, credential ref, Wind endpoint, local fallback switch). */
|
|
21
|
+
export function readRetrieverConfig(ctx) {
|
|
22
|
+
return readCapitalConfig(ctx).retriever ?? {};
|
|
23
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SessionLike } from '../data-collector/store.js';
|
|
2
|
-
/**
|
|
2
|
+
/** One-hop scope: a token lets a nested child reuse its owner's scope. */
|
|
3
3
|
export declare function chartSessionScopeId(session: SessionLike): string;
|
|
4
4
|
export interface ChartArtifactRef {
|
|
5
5
|
chart_ref: string;
|
|
@@ -23,13 +23,8 @@ export interface ChartArtifactRegistryOptions {
|
|
|
23
23
|
newRef?: () => string;
|
|
24
24
|
}
|
|
25
25
|
/**
|
|
26
|
-
* In-process
|
|
27
|
-
*
|
|
28
|
-
* The chart files live in the workspace, while this registry keeps the
|
|
29
|
-
* session/task binding that makes a chart safe to present to its own session
|
|
30
|
-
* (and to derive the `deliverables/presented` owner scope).
|
|
31
|
-
* Process restart invalidates chart_ref capabilities; chart.html remains the
|
|
32
|
-
* explicit offline fallback.
|
|
26
|
+
* In-process chart_ref capabilities: session/task/workspace binding and the deliverable owner
|
|
27
|
+
* scope. Process restart invalidates them; chart.html remains the offline fallback.
|
|
33
28
|
*/
|
|
34
29
|
export declare class ChartArtifactRegistry {
|
|
35
30
|
private readonly records;
|
|
@@ -8,19 +8,14 @@ function defaultChartRef() {
|
|
|
8
8
|
: `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 10)}`;
|
|
9
9
|
return `chart_${suffix}`;
|
|
10
10
|
}
|
|
11
|
-
/**
|
|
11
|
+
/** One-hop scope: a token lets a nested child reuse its owner's scope. */
|
|
12
12
|
export function chartSessionScopeId(session) {
|
|
13
13
|
const parent = session.header?.parentSession;
|
|
14
14
|
return typeof parent === 'string' && parent.length > 0 ? parent : session.id;
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
17
|
-
* In-process
|
|
18
|
-
*
|
|
19
|
-
* The chart files live in the workspace, while this registry keeps the
|
|
20
|
-
* session/task binding that makes a chart safe to present to its own session
|
|
21
|
-
* (and to derive the `deliverables/presented` owner scope).
|
|
22
|
-
* Process restart invalidates chart_ref capabilities; chart.html remains the
|
|
23
|
-
* explicit offline fallback.
|
|
17
|
+
* In-process chart_ref capabilities: session/task/workspace binding and the deliverable owner
|
|
18
|
+
* scope. Process restart invalidates them; chart.html remains the offline fallback.
|
|
24
19
|
*/
|
|
25
20
|
export class ChartArtifactRegistry {
|
|
26
21
|
records = new Map();
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* 为什么返回下标而不是点:一张图上可能同时有主序列、K 线、成交量副图与标记点,
|
|
5
|
-
* 它们必须**共用同一组时间轴**。若各自下采样,同一时刻会在不同子图上错位。
|
|
6
|
-
* 于是只对"主序列"跑一次 LTTB 求下标,再把这组下标套用到所有子序列上。
|
|
2
|
+
* LTTB downsampling returning kept row indices. All subplots share one time axis, so indices
|
|
3
|
+
* are computed once from the primary series and applied everywhere.
|
|
7
4
|
*/
|
|
8
5
|
export declare function largestTriangleThreeBuckets(values: readonly number[], threshold: number): number[];
|
package/lib/chart/downsample.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* 为什么返回下标而不是点:一张图上可能同时有主序列、K 线、成交量副图与标记点,
|
|
5
|
-
* 它们必须**共用同一组时间轴**。若各自下采样,同一时刻会在不同子图上错位。
|
|
6
|
-
* 于是只对"主序列"跑一次 LTTB 求下标,再把这组下标套用到所有子序列上。
|
|
2
|
+
* LTTB downsampling returning kept row indices. All subplots share one time axis, so indices
|
|
3
|
+
* are computed once from the primary series and applied everywhere.
|
|
7
4
|
*/
|
|
8
5
|
export function largestTriangleThreeBuckets(values, threshold) {
|
|
9
6
|
const count = values.length;
|
|
@@ -14,7 +11,6 @@ export function largestTriangleThreeBuckets(values, threshold) {
|
|
|
14
11
|
let anchor = 0;
|
|
15
12
|
sampled.push(anchor);
|
|
16
13
|
for (let bucket = 0; bucket < threshold - 2; bucket += 1) {
|
|
17
|
-
// 下一个桶的均值,作为三角形的一个顶点。
|
|
18
14
|
const averageStart = Math.floor((bucket + 1) * every) + 1;
|
|
19
15
|
const averageEnd = Math.min(Math.floor((bucket + 2) * every) + 1, count);
|
|
20
16
|
const averageLength = Math.max(averageEnd - averageStart, 1);
|
|
@@ -26,7 +22,6 @@ export function largestTriangleThreeBuckets(values, threshold) {
|
|
|
26
22
|
}
|
|
27
23
|
averageX /= averageLength;
|
|
28
24
|
averageY /= averageLength;
|
|
29
|
-
// 当前桶里与 anchor、均值构成最大三角形面积的点。
|
|
30
25
|
const rangeStart = Math.floor(bucket * every) + 1;
|
|
31
26
|
const rangeEnd = Math.min(Math.floor((bucket + 1) * every) + 1, count);
|
|
32
27
|
const anchorX = anchor;
|
|
@@ -44,7 +39,7 @@ export function largestTriangleThreeBuckets(values, threshold) {
|
|
|
44
39
|
anchor = maxAreaIndex;
|
|
45
40
|
}
|
|
46
41
|
sampled.push(count - 1);
|
|
47
|
-
//
|
|
42
|
+
// Bucket edges can yield duplicate indices at extreme thresholds; keep ascending order.
|
|
48
43
|
const unique = [];
|
|
49
44
|
for (const index of sampled)
|
|
50
45
|
if (unique.length === 0 || index > unique[unique.length - 1])
|
package/lib/chart/errors.d.ts
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* 错误码是**模型可见契约**的一部分:模型据此修正一次即可重试(见
|
|
5
|
-
* preset/capital-generation/skills/capital-chart-protocol/SKILL.md)。
|
|
6
|
-
* 因此 detail 必须可操作(点名缺哪个字段、可用字段有哪些),而不是笼统的 invalid。
|
|
2
|
+
* Chart errors are model-visible contract: detail must name the missing field and list
|
|
3
|
+
* candidates, not merely say "invalid".
|
|
7
4
|
*/
|
|
8
5
|
export type ChartErrorCode = 'chart_source_invalid' | 'chart_source_expired' | 'chart_source_scope_mismatch' | 'chart_source_not_found' | 'chart_ref_invalid' | 'chart_ref_scope_mismatch' | 'chart_ref_task_mismatch' | 'chart_spec_invalid' | 'chart_field_not_found' | 'chart_no_rows' | 'chart_too_large' | 'chart_write_failed' | 'chart_runtime_unavailable';
|
|
9
6
|
export declare class ChartError extends Error {
|
|
10
7
|
readonly code: ChartErrorCode;
|
|
11
|
-
/**
|
|
8
|
+
/** Machine-readable extras (e.g. available fields), serialized back to the model. */
|
|
12
9
|
readonly details: Record<string, unknown>;
|
|
13
10
|
constructor(code: ChartErrorCode, detail: string, details?: Record<string, unknown>);
|
|
14
|
-
/** 工具边界统一把错误转成结构化信封,让模型能一次修正。 */
|
|
15
11
|
toEnvelope(): Record<string, unknown>;
|
|
16
12
|
}
|
package/lib/chart/errors.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export class ChartError extends Error {
|
|
2
2
|
code;
|
|
3
|
-
/**
|
|
3
|
+
/** Machine-readable extras (e.g. available fields), serialized back to the model. */
|
|
4
4
|
details;
|
|
5
5
|
constructor(code, detail, details = {}) {
|
|
6
6
|
super(`${code}: ${detail}`);
|
|
@@ -8,7 +8,6 @@ export class ChartError extends Error {
|
|
|
8
8
|
this.code = code;
|
|
9
9
|
this.details = details;
|
|
10
10
|
}
|
|
11
|
-
/** 工具边界统一把错误转成结构化信封,让模型能一次修正。 */
|
|
12
11
|
toEnvelope() {
|
|
13
12
|
return { error: this.code, detail: this.message.slice(this.message.indexOf(':') + 2), ...this.details };
|
|
14
13
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapt a cordis ctx into ChartEventContext.
|
|
3
|
+
* Never spread ctx (`{ ...ctx }`): get/on/effect live on the prototype, so spreading drops them
|
|
4
|
+
* and delivery silently disappears. Forward each method with the original ctx as receiver.
|
|
5
|
+
* One assembly path serves both the monolith plugin and the tools/chart entry.
|
|
6
|
+
*/
|
|
7
|
+
import type { ChartEventContext } from './events.js';
|
|
8
|
+
export declare function chartEventContextOf(ctx: unknown): ChartEventContext;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export function chartEventContextOf(ctx) {
|
|
2
|
+
const raw = ctx;
|
|
3
|
+
const context = {
|
|
4
|
+
get: (name) => raw.get(name),
|
|
5
|
+
// Failed registration returns undefined so events.ts can fall back to turn/start.
|
|
6
|
+
on: (event, listener) => {
|
|
7
|
+
if (typeof raw.on !== 'function')
|
|
8
|
+
return undefined;
|
|
9
|
+
return raw.on.call(ctx, event, (...args) => { listener(...args); });
|
|
10
|
+
},
|
|
11
|
+
onTurnStopping: (listener) => {
|
|
12
|
+
if (typeof raw.on !== 'function')
|
|
13
|
+
return undefined;
|
|
14
|
+
try {
|
|
15
|
+
return raw.on.call(ctx, 'agent/turn-stopping', (...args) => { listener(...args); });
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
// root/effect are cordis getters: forward only when present.
|
|
23
|
+
try {
|
|
24
|
+
if (raw.root !== undefined) {
|
|
25
|
+
Object.defineProperty(context, 'root', { get: () => raw.root, enumerable: true });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
catch { /* root unavailable: events.ts falls back to self */ }
|
|
29
|
+
try {
|
|
30
|
+
if (typeof raw.effect === 'function') {
|
|
31
|
+
Object.defineProperty(context, 'effect', {
|
|
32
|
+
value: (callback, label) => raw.effect.call(ctx, callback, label),
|
|
33
|
+
enumerable: true,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch { /* no disposer support */ }
|
|
38
|
+
return context;
|
|
39
|
+
}
|
package/lib/chart/events.d.ts
CHANGED
|
@@ -1,17 +1,11 @@
|
|
|
1
1
|
import type { SessionLike } from '../data-collector/store.js';
|
|
2
|
-
/**
|
|
3
|
-
* 登记本轮交付物用的官方事件名。
|
|
4
|
-
*
|
|
5
|
-
* 必须留在 `KNOWN_SESSION_EVENT_TYPES` 内——它是 `dsh-tool-present` 追加的同一类型,
|
|
6
|
-
* 因此在**任何** harness 版本上都能被读回。改这里等于改会话日志契约,
|
|
7
|
-
* `test/chart-turn-events.test.mjs` 有一条断言把它钉在 first-party 词汇表上。
|
|
8
|
-
*/
|
|
2
|
+
/** Must stay in `KNOWN_SESSION_EVENT_TYPES`; test/chart-turn-events.test.mjs pins it. */
|
|
9
3
|
export declare const CHART_DELIVERABLE_EVENT = "deliverables/presented";
|
|
10
|
-
/** `callId`
|
|
4
|
+
/** `callId` only needs to be a non-empty string; carries the chart handle for log tracing. */
|
|
11
5
|
export declare const CHART_CALL_ID_PREFIX = "capital-chart:";
|
|
12
|
-
/**
|
|
6
|
+
/** Per (session, turn) cap: stops model loops; overflow warns only. */
|
|
13
7
|
export declare const MAX_CHARTS_PER_TURN = 8;
|
|
14
|
-
/**
|
|
8
|
+
/** Root lookup cap (main → data_junior → specialist is one hop, plus headroom). */
|
|
15
9
|
export declare const MAX_OWNER_HOPS = 4;
|
|
16
10
|
interface AppendableSession extends SessionLike {
|
|
17
11
|
append(type: string, data: unknown): unknown;
|
|
@@ -19,102 +13,51 @@ interface AppendableSession extends SessionLike {
|
|
|
19
13
|
interface SessionsService {
|
|
20
14
|
get(id: string): unknown;
|
|
21
15
|
}
|
|
22
|
-
/**
|
|
16
|
+
/** Subset of host ctx used here; structural so tests can inject fakes. */
|
|
23
17
|
export interface ChartEventContext {
|
|
24
18
|
get(name: string): unknown;
|
|
25
|
-
/**
|
|
19
|
+
/** Fallback flush listener; must be registered on the unscoped root context. */
|
|
26
20
|
on?(event: string, listener: (...args: unknown[]) => void): unknown;
|
|
27
|
-
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* 为什么必须是它而不是 `turn/start`:一轮是否"最终"在事件发生的那一刻不可知——子 Agent 的
|
|
31
|
-
* 结算随时会再触发新一轮。实测(2026-09-20 真机 session `38bad3f9`):图表在 turn 4 与 5 之间
|
|
32
|
-
* 寄存,旧规则在下一次 `turn/start` 立刻冲刷,于是交付行落进了**空的过程轮** turn 5,而主 Agent
|
|
33
|
-
* 写下总结答复的是 turn 6——卡片出现在中间步骤。`agent/turn-stopping` 是官方"该轮即将关闭"的
|
|
34
|
-
* 钩子(`@mode serial`,轮仍打开、可安全 append),在它上面冲刷,交付行就落进**消费这份图的那一轮**。
|
|
35
|
-
*
|
|
36
|
-
* 必须注册在未打 scope 标签的 root context 上:`dsh-scope` 的准入规则会让 standing-scope 的
|
|
37
|
-
* 监听器收不到子 Agent 的事件,而我们要的正是 owner 自己那轮关闭的事实。
|
|
38
|
-
*/
|
|
21
|
+
/** Preferred flush hook: open-but-closing turn, on the unscoped root ctx (scoped listeners miss
|
|
22
|
+
* child events). A missing disposer must keep the turn/start fallback active. */
|
|
39
23
|
onTurnStopping?(listener: (...args: unknown[]) => void): unknown;
|
|
40
24
|
effect?(callback: () => unknown, label?: string): unknown;
|
|
41
|
-
/**
|
|
25
|
+
/** Unscoped root context; falls back to self when absent. */
|
|
42
26
|
readonly root?: ChartEventContext;
|
|
43
27
|
logger?: {
|
|
44
28
|
warn(message: string): void;
|
|
45
29
|
};
|
|
46
30
|
}
|
|
47
31
|
export interface ChartTurnEventInput {
|
|
48
|
-
/**
|
|
32
|
+
/** chart_ref owner scope (same semantics as ChartArtifactRegistry). */
|
|
49
33
|
ownerSessionId: string;
|
|
50
34
|
chart_id: string;
|
|
51
35
|
title: string;
|
|
52
|
-
/**
|
|
36
|
+
/** Workspace-relative chart.html path; the official preview resolves it against session.cwd. */
|
|
53
37
|
html_path: string;
|
|
54
38
|
}
|
|
55
39
|
export interface ChartEventPublisher {
|
|
56
|
-
/**
|
|
57
|
-
* 记录一张图。
|
|
58
|
-
* @returns 是否已受理:立即写入、或已寄存等下一个回合都算受理。
|
|
59
|
-
*/
|
|
60
40
|
publish(input: ChartTurnEventInput): boolean;
|
|
61
|
-
/**
|
|
41
|
+
/** Diagnostics: queued charts not yet written. */
|
|
62
42
|
pendingCount?(ownerSessionId?: string): number;
|
|
63
|
-
/**
|
|
64
|
-
* 诊断:最近一次 publish 的逐步结论(给回执/落盘用)。
|
|
65
|
-
*
|
|
66
|
-
* 为什么需要它:交付行"静默不出现"是本项目最难查的故障,而宿主终端并不总能拿到
|
|
67
|
-
* (cordis logger 只进内存;stderr 也可能落在用户看不到的地方)。把结论带回
|
|
68
|
-
* `render_chart` 的回执 / 落盘产物,就能**从磁盘**定位,不必依赖终端。
|
|
69
|
-
*/
|
|
43
|
+
/** Diagnostics: last publish trace, surfaced in receipts / disk so failures are visible without a terminal. */
|
|
70
44
|
lastTrace?(): string;
|
|
71
45
|
}
|
|
72
|
-
/** 只读:最近一次 publish 轨迹。 */
|
|
73
46
|
export declare function chartEventPublishTrace(): string;
|
|
74
|
-
/**
|
|
75
|
-
* 交付通道的**诊断开关**:`CAPITAL_CHART_TRACE=1` 时才输出进度日志与落盘 trace。
|
|
76
|
-
*
|
|
77
|
-
* 默认关闭——对外发布不该往用户终端刷进度、也不该往 workspace 写调试文件。
|
|
78
|
-
* 排查"图表/交付行不出现"时打开它(见 `deliverable-trace.txt` 与 docs/dev/chart-delivery-events.md §6.3 的说明)。
|
|
79
|
-
*/
|
|
47
|
+
/** Diagnostic switch; off by default to keep terminals and workspaces clean. */
|
|
80
48
|
export declare function chartTraceEnabled(): boolean;
|
|
81
|
-
/**
|
|
82
|
-
* 从 owner scope 出发向上走到根会话:用户看的是根会话的对话流,卡片必须挂在它上面。
|
|
83
|
-
* 找不到(会话已回收)时返回 undefined,调用方静默跳过。
|
|
84
|
-
*/
|
|
49
|
+
/** Walk up to the root session — the user watches the root conversation. Missing session → undefined. */
|
|
85
50
|
export declare function resolveOwnerSession(sessions: SessionsService, ownerSessionId: string, maxHops?: number): AppendableSession | undefined;
|
|
86
|
-
/**
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
* 形状与 `dsh-tool-present` 逐字段对齐(那边是 `{ turn, callId, files }`,
|
|
90
|
-
* 客户端 `isPresentedData()` 要求 `turn` 是 >=1 的安全整数、`callId` 非空字符串、
|
|
91
|
-
* `files` 是数组)。`files[].path` 必须是**工作区相对**路径:官方打开动作会拿它去
|
|
92
|
-
* `workspaceFiles.stat({ sessionId, workspaceRoot: session.cwd })` 解析,绝对路径过不了
|
|
93
|
-
* 「Presented file has no verified Host path」这一关。
|
|
94
|
-
*
|
|
95
|
-
* `callId` 只是官方契约里的一个非空字符串句柄,没有配对约束(`present` 那边用来关联
|
|
96
|
-
* tool/result),这里借它携带 `chart_id`,便于在日志里把一条交付回溯到具体图表。
|
|
97
|
-
*/
|
|
51
|
+
/** Matches `dsh-tool-present` ({ turn, callId, files }); files[].path must be workspace-relative
|
|
52
|
+
* because the official open action resolves it against session.cwd. */
|
|
98
53
|
export declare function buildChartEventPayload(input: ChartTurnEventInput, turn: number): Record<string, unknown>;
|
|
99
|
-
/**
|
|
100
|
-
* 进程内待登记条目的总量上限(安全阀)。
|
|
101
|
-
*
|
|
102
|
-
* 正常流程下条目会在 owner 那一轮关闭时被冲刷清空;但如果冲刷时机始终没接上
|
|
103
|
-
* (上游事件名消失、监听注册失败且 turn/start 也没来),模块级 Map 会一直攒着。
|
|
104
|
-
* 这是纯内存元数据(只有 chart_id / 标题 / 相对路径),上限只为防无界增长,
|
|
105
|
-
* 与 `MAX_CHARTS_PER_TURN` 的"防模型循环"是两件事。
|
|
106
|
-
*/
|
|
54
|
+
/** Safety valve if flushing never fires; metadata only, bounded against unbounded growth. */
|
|
107
55
|
export declare const MAX_PENDING_CHARTS = 64;
|
|
108
|
-
/**
|
|
109
|
-
* 只给测试用:清空待登记队列。
|
|
110
|
-
*
|
|
111
|
-
* `pending` 是模块级的(必须跨发布器实例存活,见下方说明),因此进程内所有测试
|
|
112
|
-
* 共享它。测试之间要隔离,就在用例开始时调用一次。
|
|
113
|
-
*/
|
|
56
|
+
/** Test-only: clear the shared queue between cases. */
|
|
114
57
|
export declare function resetChartEventPending(): void;
|
|
115
58
|
export declare function createChartEventPublisher(ctx: ChartEventContext): ChartEventPublisher | undefined;
|
|
116
|
-
/**
|
|
59
|
+
/** Test-only: drop the singleton cache. */
|
|
117
60
|
export declare function resetChartEventPublisher(): void;
|
|
118
|
-
/**
|
|
61
|
+
/** Owner scope at render time; same source as chart_ref (specialist renders land on the main session). */
|
|
119
62
|
export declare function chartEventOwnerSessionId(session: SessionLike, sourceSession?: SessionLike): string;
|
|
120
63
|
export {};
|