@v587d/capital-generation 2.7.6 → 2.7.7
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 +19 -0
- package/README.md +3 -3
- package/capital-config/package.json +1 -1
- package/capital-watchlist/package.json +1 -1
- package/chart-ui/package.json +1 -1
- package/lib/agents/selected-skills-provider.js +91 -41
- package/lib/index.js +3 -2
- package/lib/web-retriever/local-fetch.d.ts +1 -1
- package/lib/web-retriever/local-fetch.js +1 -1
- package/lib/web-retriever/wind-client.d.ts +1 -1
- package/lib/web-retriever/wind-client.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,25 @@
|
|
|
7
7
|
- **第三位(patch)**:不破坏既有工具 / 配置 / 会话的新增与修复(如 2.1.1、2.1.2)。
|
|
8
8
|
- **第二位(minor)**:有需要用户知晓的行为变更,且段内附迁移说明(如 2.1.0 的图表呈现通道重做、2.2.0 的数据源与检索来源扩容、2.4.0 的**必须换宿主版本**——本插件自己的工具与数据契约没变,所以只抬第二位)。
|
|
9
9
|
|
|
10
|
+
## [2.7.7] - 2026-10-12
|
|
11
|
+
|
|
12
|
+
精选 Skills 的开关改为**每轮生效**,并修掉首轮注入竞态。既有契约完全没动:工具入参与返回、能力清单、
|
|
13
|
+
四把密钥与凭据引用名、配置字段、会话日志格式、你已有的自选股数据与**已经开启的那几项 Skill**,全部照旧;
|
|
14
|
+
宿主要求与 2.7.6 相同(DSH`@0.2.0-rc.2`),不必换版本,升级无需迁移。**更正 2.7.6 的说法**:
|
|
15
|
+
切换开关不再需要新开一份 Capital 会话——正在使用的会话里改完设置、发下一条指令,Skill 列表就按
|
|
16
|
+
最新选择刷新(2.7.6 写的"照旧要新开一份 Capital 会话才读得到"随本版作废)。
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- **精选 Skills 随开随用**:开关现在每轮对话开始时重读,Skill 列表跟着设置走——打开哪颗,
|
|
21
|
+
下一条指令就出现在可用列表里;关掉哪颗,下一条指令就不再出现。"建好会话再打开开关永远看不到"
|
|
22
|
+
与"关掉后旧列表还挂在会话里"两种情况一并消失。默认仍是全关;全关的会话不扫快照、不起 watcher。
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- **首轮 Skill 列表与注册竞态**:Agent 建立时的注入现在等技能注册真正落位才放行,首轮可用列表
|
|
27
|
+
不再可能赶在注册之前被读到(此前文档这样承诺,实现并没有等)。
|
|
28
|
+
|
|
10
29
|
## [2.7.6] - 2026-10-12
|
|
11
30
|
|
|
12
31
|
精选 Skills 的**收录判据纠正一处**,并据此放开 5 颗。既有契约完全没动:工具入参与返回、能力清单、
|
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
<p align="center">
|
|
17
17
|
<a href="https://awesome-dsh-plugin.com"><img src="https://awesome-dsh-plugin.com/badge.svg" alt="awesome · DSH plugin"></a>
|
|
18
18
|
<a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-green" alt="License"></a>
|
|
19
|
-
<a href="https://github.com/v587d/capital-generation/releases"><img src="https://img.shields.io/badge/version-2.7.
|
|
19
|
+
<a href="https://github.com/v587d/capital-generation/releases"><img src="https://img.shields.io/badge/version-2.7.7-9cf" alt="Version"></a>
|
|
20
20
|
</p>
|
|
21
21
|
|
|
22
22
|
# Capital Generation
|
|
@@ -144,7 +144,7 @@ https://github.com/v587d/capital-generation
|
|
|
144
144
|
| :---: | :---: |
|
|
145
145
|
| <a href="assets/watchlist-popup.png"><img src="assets/watchlist-popup.png" alt="管理自选股" width="400"></a> | <a href="assets/watchlist-more.png"><img src="assets/watchlist-more.png" alt="标记持仓" width="400"></a> |
|
|
146
146
|
|
|
147
|
-
- **精选 Skills:** 当前收录 6 个开源项目、共 59 个 Skill
|
|
147
|
+
- **精选 Skills:** 当前收录 6 个开源项目、共 59 个 Skill(默认全部关闭,在配置页按需打开;随时切换,无需新建会话,正在使用的 Capital 会话下一条指令即生效)
|
|
148
148
|
|
|
149
149
|
| 项目名称 | 收录边界 |
|
|
150
150
|
| :---: | :---: |
|
|
@@ -165,7 +165,7 @@ https://github.com/v587d/capital-generation
|
|
|
165
165
|
|
|
166
166
|
- **安装后找不到 Capital 模式?** 确认插件出现在「插件」→ 已安装列表;Web / CLI profile 安装后要重启该 profile,并在新会话选择模式。
|
|
167
167
|
- **配置在哪?** 打开「插件」→ 已安装的 **Capital Generation**,页面顶部就是「数据源 / 精选 Skills / 包含的组件」三格,四把密钥都在第一格;不在 DSH 的普通「设置」页面,也不用点进任何一行组件。保存密钥后新建会话再试。
|
|
168
|
-
- **桌面端升级后仍是旧版?** 桌面端安装时会固定所解析的版本,不会自动升级。卸载后重新安装,再到插件详情查看版本号;如需指定版本,可在地址末尾加 `#v2.7.
|
|
168
|
+
- **桌面端升级后仍是旧版?** 桌面端安装时会固定所解析的版本,不会自动升级。卸载后重新安装,再到插件详情查看版本号;如需指定版本,可在地址末尾加 `#v2.7.7` 或 `@2.7.7`。
|
|
169
169
|
- **刚发布的新版本装不到?** 桌面端取包时会跳过**刚发布不久**的版本(宿主侧包管理器的发布冷却策略,实测会静默装成上一个版本),国内镜像的同步也可能滞后一段时间。急着用最新代码,改用仓库地址安装最直接。
|
|
170
170
|
- **网页抓取失败?** 配置卡片中的「允许启动本地提取网页内容」默认开启:AnySearch 提取失败时可尝试本机直连。关闭后,本机直连的具名来源查询也不可用;请检查该开关和网络连接。
|
|
171
171
|
- **Wind 那部分会消耗积分?** 会。公告与新闻检索、宏观 / 行业 / 汇率指标、按日期区间取的历史 K 线都按次消耗你在 Wind 侧的额度;额度与条款以 Wind 为准,插件不做用量封顶。没配 `WIND_API_KEY` 时这几类不可用,其余功能照常。
|
package/chart-ui/package.json
CHANGED
|
@@ -22,6 +22,17 @@ function selectedNames(selection) {
|
|
|
22
22
|
function readSelection(source) {
|
|
23
23
|
return typeof source === 'function' ? source() : source;
|
|
24
24
|
}
|
|
25
|
+
// 选择指纹只认 catalog 的 key 集合:pre-step 每轮拿它对比"上次交给注册表的选择",
|
|
26
|
+
// 变了才失效目录缓存,未变就零成本放行。
|
|
27
|
+
function selectionFingerprint(selection) {
|
|
28
|
+
return SELECTED_SKILL_CATALOG.map(({ key }) => (selection[key] === true ? '1' : '0')).join('');
|
|
29
|
+
}
|
|
30
|
+
// agent/pre-step 是 dsh-agent 声明的事件,类型不在本包的 import 面里;按结构挂到注入后的
|
|
31
|
+
// Agent context(其 scope tag 就是该 Agent,dispatch 的 scope filter 才放行这条监听)。
|
|
32
|
+
function onPreStepEvent(ctx, listener) {
|
|
33
|
+
const events = ctx;
|
|
34
|
+
return events.on?.('agent/pre-step', listener);
|
|
35
|
+
}
|
|
25
36
|
function strictCapitalPreset(ctx, agent) {
|
|
26
37
|
try {
|
|
27
38
|
const presets = ctx.get?.('agentPresets');
|
|
@@ -35,62 +46,101 @@ function strictCapitalPreset(ctx, agent) {
|
|
|
35
46
|
/** Register explicitly selected community experiments on the Capital root Agent only. */
|
|
36
47
|
export function registerRootSelectedSkills(ctx, selection, createFilesystemProvider = createFilesystemSkillProvider) {
|
|
37
48
|
// Static callers retain the cheap all-disabled fast path. The Capital plugin
|
|
38
|
-
// passes a reader so a settings toggle is observed
|
|
49
|
+
// passes a reader so a settings toggle is observed at the next step of every
|
|
50
|
+
// live root Agent: list()/get() filter against the current selection, and the
|
|
51
|
+
// pre-step hook below refreshes the visible catalog when the selection changes.
|
|
39
52
|
if (typeof selection !== 'function' && selectedNames(selection).size === 0)
|
|
40
53
|
return;
|
|
41
54
|
const listenCtx = ctx.root ?? ctx;
|
|
42
55
|
if (typeof listenCtx.on !== 'function')
|
|
43
56
|
return;
|
|
44
|
-
const stop = listenCtx.on('agent/created', ({ agent }) => {
|
|
57
|
+
const stop = listenCtx.on('agent/created', async ({ agent }) => {
|
|
45
58
|
if (!agent || !isRootAgent(agent) || !strictCapitalPreset(ctx, agent))
|
|
46
59
|
return;
|
|
47
|
-
const enabled = selectedNames(readSelection(selection));
|
|
48
|
-
if (enabled.size === 0)
|
|
49
|
-
return;
|
|
50
60
|
const agentCtx = agent.ctx;
|
|
51
61
|
if (!agentCtx || typeof agentCtx.inject !== 'function') {
|
|
52
62
|
ctx.logger?.warn?.('capital-generation: selected skills are unavailable (root Agent cannot inject skills)');
|
|
53
63
|
return;
|
|
54
64
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
try {
|
|
66
|
+
// agent/created 是串行事件、DSH 等监听器 settle 才继续创建:await 注入 Fiber,
|
|
67
|
+
// provider 与 pre-step 钩子都在首轮 prompt 前落位(首轮 catalog 不与注册竞态)。
|
|
68
|
+
await agentCtx.inject(['skills'], (injectedCtx) => {
|
|
69
|
+
const skills = injectedCtx.skills;
|
|
70
|
+
if (typeof skills?.registerProvider !== 'function') {
|
|
71
|
+
ctx.logger?.warn?.('capital-generation: selected skills are unavailable (root Agent has no skills registry)');
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
let filesystemProvider;
|
|
75
|
+
let control;
|
|
76
|
+
// 上次交给 skills 注册表的选择指纹。开关是 settings 偏好,不在 Agent 创建时定格:
|
|
77
|
+
// 全关也照常注册 provider(否则会话创建后打开开关永远不出现),靠下面的 pre-step
|
|
78
|
+
// 钩子每轮对齐设置。
|
|
79
|
+
let served = selectionFingerprint(readSelection(selection));
|
|
80
|
+
injectedCtx.effect(() => {
|
|
81
|
+
const unregister = skills.registerProvider((registration) => {
|
|
82
|
+
control = registration;
|
|
83
|
+
filesystemProvider = createFilesystemProvider(injectedCtx, registration, {
|
|
84
|
+
providerName: PROVIDER_NAME,
|
|
85
|
+
includeDefaultRoots: false,
|
|
86
|
+
customSkillDirs: SKILL_ROOTS,
|
|
87
|
+
watch: true,
|
|
88
|
+
});
|
|
89
|
+
const provider = {
|
|
90
|
+
name: PROVIDER_NAME,
|
|
91
|
+
async list(options) {
|
|
92
|
+
// 调用期现读:开关是 settings 偏好,不许在 Agent 创建时定格。
|
|
93
|
+
const enabled = selectedNames(readSelection(selection));
|
|
94
|
+
// 全关是默认常态:短路掉,不碰快照目录(filesystem watcher 在它的 list()
|
|
95
|
+
// 里才启动,短路保证默认关闭的会话不起任何 watcher)。
|
|
96
|
+
if (enabled.size === 0)
|
|
97
|
+
return [];
|
|
98
|
+
const result = await filesystemProvider.list(options);
|
|
99
|
+
if (Array.isArray(result))
|
|
100
|
+
return result.filter((candidate) => enabled.has(candidate.name));
|
|
101
|
+
return { ...result, candidates: result.candidates.filter((candidate) => enabled.has(candidate.name)) };
|
|
102
|
+
},
|
|
103
|
+
get(candidate, options) {
|
|
104
|
+
if (!selectedNames(readSelection(selection)).has(candidate.name)) {
|
|
105
|
+
throw new Error(`selected skill is not enabled: ${candidate.name}`);
|
|
106
|
+
}
|
|
107
|
+
return filesystemProvider.get(candidate, options);
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
return provider;
|
|
69
111
|
});
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
112
|
+
// 每轮 pre-step 重读开关:集合变了就调 provider control 的 invalidate(),失效
|
|
113
|
+
// skills 的目录缓存(revision++),tool-skill 随后的 catalog 快照因此按最新开关
|
|
114
|
+
// 重算;未变则 digest 不变、catalog 不重发。必须在放行 next() 之前做完——
|
|
115
|
+
// waterfall 里 tool-skill 是 await next() 之后才快照,但监听器注册顺序不归我们
|
|
116
|
+
// 管,先做完再放行在两种顺序下都赶得上本轮快照。设置读取失败只降级,不阻断本轮。
|
|
117
|
+
const stopPreStep = onPreStepEvent(injectedCtx, (_payload, next) => {
|
|
118
|
+
try {
|
|
119
|
+
const fingerprint = selectionFingerprint(readSelection(selection));
|
|
120
|
+
if (fingerprint !== served) {
|
|
121
|
+
served = fingerprint;
|
|
122
|
+
control?.invalidate();
|
|
81
123
|
}
|
|
82
|
-
|
|
83
|
-
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
ctx.logger?.warn?.(`capital-generation: selected skill settings unreadable (${String(error)})`);
|
|
127
|
+
}
|
|
128
|
+
return next();
|
|
129
|
+
});
|
|
130
|
+
return () => {
|
|
131
|
+
if (typeof stopPreStep === 'function')
|
|
132
|
+
stopPreStep();
|
|
133
|
+
unregister();
|
|
134
|
+
void filesystemProvider?.dispose();
|
|
135
|
+
filesystemProvider = undefined;
|
|
84
136
|
};
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}, `capital-generation: selected skills for ${agentSessionId(agent) ?? 'root'}`);
|
|
93
|
-
});
|
|
137
|
+
}, `capital-generation: selected skills for ${agentSessionId(agent) ?? 'root'}`);
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
// selected skills 是可选能力:注入失败只降级告警,不能把整个 Agent 创建挡掉。
|
|
142
|
+
ctx.logger?.warn?.(`capital-generation: selected skills are unavailable (${String(error)})`);
|
|
143
|
+
}
|
|
94
144
|
});
|
|
95
145
|
ctx.effect?.(() => () => {
|
|
96
146
|
if (typeof stop === 'function')
|
package/lib/index.js
CHANGED
|
@@ -205,8 +205,9 @@ export function apply(ctx, config) {
|
|
|
205
205
|
return resolvedConfig;
|
|
206
206
|
};
|
|
207
207
|
const effectiveConfig = readEffectiveConfig();
|
|
208
|
-
// selectedSkills 是 live 的 settings
|
|
209
|
-
//
|
|
208
|
+
// selectedSkills 是 live 的 settings 偏好:provider 在每轮 agent/pre-step 与每次
|
|
209
|
+
// list()/get() 调用现读,切换开关不需要新建会话(见 docs/dev/selected-skills.md);
|
|
210
|
+
// 无 settings 服务时沿用 preset 配置,避免为静态关闭配置额外挂一个永远空转的监听器。
|
|
210
211
|
const selectedSkills = typeof settings?.describe === 'function'
|
|
211
212
|
? () => readEffectiveConfig().selectedSkills ?? {}
|
|
212
213
|
: effectiveConfig.selectedSkills ?? {};
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* between validation and connect. Closing that window would require a custom
|
|
7
7
|
* dispatcher; this module keeps the same explicit trade-off as dsh-search-first.
|
|
8
8
|
*/
|
|
9
|
-
export declare const LOCAL_FETCH_CLIENT_VERSION = "2.7.
|
|
9
|
+
export declare const LOCAL_FETCH_CLIENT_VERSION = "2.7.7";
|
|
10
10
|
export declare const LOCAL_FETCH_MAX_URL_LENGTH = 2048;
|
|
11
11
|
export type LocalFetchErrorCode = 'ABORTED' | 'TIMEOUT' | 'INVALID_URL' | 'BLOCKED_URL' | 'DNS' | 'REDIRECT' | 'HTTP' | 'TOO_LARGE' | 'UNSUPPORTED_CONTENT_TYPE';
|
|
12
12
|
export declare class LocalFetchError extends Error {
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* dispatcher; this module keeps the same explicit trade-off as dsh-search-first.
|
|
8
8
|
*/
|
|
9
9
|
import { htmlToMarkdown, stripInvisibleText } from './html-markdown.js';
|
|
10
|
-
export const LOCAL_FETCH_CLIENT_VERSION = '2.7.
|
|
10
|
+
export const LOCAL_FETCH_CLIENT_VERSION = '2.7.7';
|
|
11
11
|
export const LOCAL_FETCH_MAX_URL_LENGTH = 2048;
|
|
12
12
|
export class LocalFetchError extends Error {
|
|
13
13
|
code;
|
|
@@ -52,7 +52,7 @@ export interface WindCallResult {
|
|
|
52
52
|
* `test/chart-composition.test.mjs` 守着(会因漂移而失败),这里原本是写死的第二处,
|
|
53
53
|
* 一次发版就得记得改两遍。所以本常量由测试一并核对(见 `test/wind-client.test.mjs`)。
|
|
54
54
|
*/
|
|
55
|
-
export declare const WIND_CLIENT_VERSION = "2.7.
|
|
55
|
+
export declare const WIND_CLIENT_VERSION = "2.7.7";
|
|
56
56
|
export interface WindClient {
|
|
57
57
|
callTool(toolName: string, args: Record<string, unknown>, signal?: AbortSignal): Promise<WindCallResult>;
|
|
58
58
|
}
|
|
@@ -35,7 +35,7 @@ export const WIND_SERVER_ENDPOINTS = {
|
|
|
35
35
|
* `test/chart-composition.test.mjs` 守着(会因漂移而失败),这里原本是写死的第二处,
|
|
36
36
|
* 一次发版就得记得改两遍。所以本常量由测试一并核对(见 `test/wind-client.test.mjs`)。
|
|
37
37
|
*/
|
|
38
|
-
export const WIND_CLIENT_VERSION = '2.7.
|
|
38
|
+
export const WIND_CLIENT_VERSION = '2.7.7';
|
|
39
39
|
function errorText(error) {
|
|
40
40
|
return error instanceof Error ? error.message : String(error);
|
|
41
41
|
}
|