@v587d/capital-generation 2.8.3 → 2.9.1
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 +81 -1
- package/README.md +40 -19
- package/chart-ui/README.md +5 -4
- 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 +13 -8
- package/lib/chart/artifact-ref.js +27 -10
- 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 +43 -189
- package/lib/chart/html.d.ts +2 -5
- package/lib/chart/html.js +8 -15
- package/lib/chart/present-tool.d.ts +28 -0
- package/lib/chart/present-tool.js +128 -0
- 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 +7 -29
- package/lib/chart/tool.js +15 -25
- package/lib/chart-render-entry.d.ts +10 -0
- package/lib/chart-render-entry.js +14 -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 +41 -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/present-entry.d.ts +9 -0
- package/lib/present-entry.js +13 -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 +72 -7
- package/preset/capital-generation/README.md +87 -53
- package/preset/capital-generation/agent.patch.yml +532 -337
- package/preset/capital-generation/skills/capital-chart-protocol/SKILL.md +6 -4
- 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 +4 -2
- package/preset/capital-generation/skills/capital-event-impact/SKILL.md +1 -1
- package/preset/capital-generation/skills/capital-orchestration/SKILL.md +30 -33
- package/preset/capital-generation/skills/capital-portfolio-review/SKILL.md +1 -1
- package/preset/capital-generation/skills/capital-visualization-protocol/SKILL.md +14 -16
- 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,8 @@
|
|
|
1
1
|
import type { SessionLike } from '../data-collector/store.js';
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* Subagent children carry `origin: 'subagent'`; a user fork/branch root also has `parentSession`
|
|
4
|
+
* (seed lineage) and must stay its own scope. One hop: the token lets a nested child reuse its owner.
|
|
5
|
+
*/
|
|
3
6
|
export declare function chartSessionScopeId(session: SessionLike): string;
|
|
4
7
|
export interface ChartArtifactRef {
|
|
5
8
|
chart_ref: string;
|
|
@@ -10,6 +13,7 @@ export interface ChartArtifactRef {
|
|
|
10
13
|
captured_at: number | null;
|
|
11
14
|
kind: string;
|
|
12
15
|
axis: 'time' | 'index';
|
|
16
|
+
title: string;
|
|
13
17
|
chart_url: string | null;
|
|
14
18
|
spec_path: string;
|
|
15
19
|
series_path: string;
|
|
@@ -23,13 +27,8 @@ export interface ChartArtifactRegistryOptions {
|
|
|
23
27
|
newRef?: () => string;
|
|
24
28
|
}
|
|
25
29
|
/**
|
|
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.
|
|
30
|
+
* In-process chart_ref capabilities: session/task/workspace binding and the deliverable owner
|
|
31
|
+
* scope. Process restart invalidates them; chart.html remains the offline fallback.
|
|
33
32
|
*/
|
|
34
33
|
export declare class ChartArtifactRegistry {
|
|
35
34
|
private readonly records;
|
|
@@ -47,6 +46,7 @@ export declare class ChartArtifactRegistry {
|
|
|
47
46
|
captured_at?: number | null;
|
|
48
47
|
kind: string;
|
|
49
48
|
axis: 'time' | 'index';
|
|
49
|
+
title: string;
|
|
50
50
|
chart_url: string | null;
|
|
51
51
|
spec_path: string;
|
|
52
52
|
series_path: string;
|
|
@@ -60,6 +60,11 @@ export declare class ChartArtifactRegistry {
|
|
|
60
60
|
task_id?: string | null;
|
|
61
61
|
}): ChartArtifactRef;
|
|
62
62
|
revoke(chartRef: string): boolean;
|
|
63
|
+
/** Charts of one session scope, for the model's final-turn delivery step; newest last. */
|
|
64
|
+
list(input: {
|
|
65
|
+
session: SessionLike;
|
|
66
|
+
task_id?: string | null;
|
|
67
|
+
}): ChartArtifactRef[];
|
|
63
68
|
size(): number;
|
|
64
69
|
private publicRecord;
|
|
65
70
|
}
|
|
@@ -8,19 +8,17 @@ function defaultChartRef() {
|
|
|
8
8
|
: `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 10)}`;
|
|
9
9
|
return `chart_${suffix}`;
|
|
10
10
|
}
|
|
11
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* Subagent children carry `origin: 'subagent'`; a user fork/branch root also has `parentSession`
|
|
13
|
+
* (seed lineage) and must stay its own scope. One hop: the token lets a nested child reuse its owner.
|
|
14
|
+
*/
|
|
12
15
|
export function chartSessionScopeId(session) {
|
|
13
|
-
const parent = session.header?.parentSession;
|
|
16
|
+
const parent = session.header?.origin === 'subagent' ? session.header.parentSession : undefined;
|
|
14
17
|
return typeof parent === 'string' && parent.length > 0 ? parent : session.id;
|
|
15
18
|
}
|
|
16
19
|
/**
|
|
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.
|
|
20
|
+
* In-process chart_ref capabilities: session/task/workspace binding and the deliverable owner
|
|
21
|
+
* scope. Process restart invalidates them; chart.html remains the offline fallback.
|
|
24
22
|
*/
|
|
25
23
|
export class ChartArtifactRegistry {
|
|
26
24
|
records = new Map();
|
|
@@ -61,6 +59,7 @@ export class ChartArtifactRegistry {
|
|
|
61
59
|
captured_at: input.captured_at ?? null,
|
|
62
60
|
kind: input.kind,
|
|
63
61
|
axis: input.axis,
|
|
62
|
+
title: input.title,
|
|
64
63
|
chart_url: input.chart_url,
|
|
65
64
|
spec_path: input.spec_path,
|
|
66
65
|
series_path: input.series_path,
|
|
@@ -96,12 +95,30 @@ export class ChartArtifactRegistry {
|
|
|
96
95
|
revoke(chartRef) {
|
|
97
96
|
return this.records.delete(chartRef);
|
|
98
97
|
}
|
|
98
|
+
/** Charts of one session scope, for the model's final-turn delivery step; newest last. */
|
|
99
|
+
list(input) {
|
|
100
|
+
const now = this.now();
|
|
101
|
+
this.purgeExpired(now);
|
|
102
|
+
const scope = chartSessionScopeId(input.session);
|
|
103
|
+
const cwd = input.session.header?.cwd ?? null;
|
|
104
|
+
const records = [];
|
|
105
|
+
for (const record of this.records.values()) {
|
|
106
|
+
if (record.owner_scope_id !== scope || record.owner_cwd !== cwd)
|
|
107
|
+
continue;
|
|
108
|
+
if (input.task_id !== undefined && input.task_id !== null && record.task_id !== input.task_id)
|
|
109
|
+
continue;
|
|
110
|
+
records.push(record);
|
|
111
|
+
}
|
|
112
|
+
return records
|
|
113
|
+
.sort((left, right) => left.created_at - right.created_at)
|
|
114
|
+
.map((record) => this.publicRecord(record));
|
|
115
|
+
}
|
|
99
116
|
size() {
|
|
100
117
|
this.purgeExpired(this.now());
|
|
101
118
|
return this.records.size;
|
|
102
119
|
}
|
|
103
120
|
publicRecord(record) {
|
|
104
|
-
const { owner_scope_id: _ownerScope, ...publicRecord } = record;
|
|
121
|
+
const { owner_scope_id: _ownerScope, owner_cwd: _ownerCwd, ...publicRecord } = record;
|
|
105
122
|
return publicRecord;
|
|
106
123
|
}
|
|
107
124
|
}
|
|
@@ -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
|
+
}
|