@v587d/capital-generation 2.6.2 → 2.6.4

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 CHANGED
@@ -7,6 +7,87 @@
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.6.4] - 2026-10-08
11
+
12
+ 自选股**搜索与下拉**的一轮修复加放开:**工具入参、数据能力、四把密钥与凭据引用名、配置字段、
13
+ 会话日志格式与自选股存储 schema 一律没动**,宿主仍要求 `0.2.0-rc.2`,无需迁移。按第三位(patch)
14
+ 口径——变更全部落在自选股面板自身的输入与展示里,不破坏既有工具 / 配置 / 会话。
15
+
16
+ ### Fixed
17
+
18
+ - **A 股搜索的大小写**(用户报"港美股/指数必须严格大写",实测根因在 A 股那一路):Fuyao
19
+ `ticker_search` 的 `q` 是**区分大小写的子串匹配**——实测 `tcl` 0 条 / `TCL` 3 条、`etf` 0 条 /
20
+ `ETF` 50 条、`600519.sh` 0 条 / `600519.SH` 1 条。所以 `q` 含 ASCII 小写时**原样 + 全大写两笔
21
+ 并发**、按 canonical 键去重(原样那份在前);不含小写仍只发一笔,不白烧配额。全量 8708 条
22
+ A 股 / 指数 / ETF 名称里含小写拉丁字母的只有 8 条、且全是 `.TI` 概念指数(候选阶段就被挡掉)。
23
+ 港美股那两路实测**不区分大小写**(`aapl` / `AAPL` / `apple` 回包逐字节相同),不跟着多问。
24
+ - **点一下「添加」下拉就没了**(连续添加被这一下打断):候选行用的是真 `disabled`,浏览器随即把
25
+ 焦点踢到 body,搜索段的 `onBlur` 拿到 `relatedTarget: null` 就判"点到框外"收起下拉。改用
26
+ `aria-disabled`(不动焦点)+ `onClick` guard 承担"禁止点击",CSS 里的 `.option:disabled` 一并删掉
27
+ ——留着它就是留了一条会复发的路。
28
+ - **"还有更多"那句不再冻结、也不再说假话**:tip 从浮层里搬进**滚动区末尾**(滚到底才看得见),
29
+ 文案改成「没有更多,请输入准确的证券代码或名称。」——候选已经一行不落地画出来,"候选不止这些"
30
+ 此刻是假话。判据也只剩一种 truthful 形态:某一路回满**它自己那一档**(按笔算;两笔并起来超档时
31
+ 我们自己砍的那一刀同样算"被砍")。
32
+
33
+ ### Added
34
+
35
+ - **候选池放开到 70 条、不再切片**:上游没有第二页——smartbox 每笔硬顶 10 条(8 种抬条数写法全
36
+ 无效,`p=` / `offset=` 等 7 种分页写法回包与基线逐字节相同),Fuyao `limit` 取官方上限 50、
37
+ `offset` 被忽略。原先那刀"倒逼缩小输入"的 20 条切掉的全是我们本来能给的行(实测 `q=etf` 回
38
+ 20 条全是 `.SZ`,港美一行都不露)。上界 = 三路上游硬顶之和 `50+10+10=70`,回给浏览器约 9.6 KB。
39
+ - **下拉顶部筛选头「全部 / CN / HK / US」**:默认全部、带各市场真实条数("怎么全是 A 股,港股美股
40
+ 呢"的答案就在 `HK 10 / US 10` 这几个数字里);切档**只改显示、不出网、不收下拉**,空档另说
41
+ 「这个市场下没有匹配的标的」。合并顺序仍按 A 股 → 港 → 美不变,"让用户自己筛"落在这个头上。
42
+ - **候选行右侧两态胶囊「添加 / 已添加」**:「添加」沿用「刷新报价」那颗 verb 按钮的配方(state 色
43
+ 12% 淡底 + 25% 描边 + 同色字),整行唯一带色的元素;「已添加」透明底 + tertiary 字、点了不再出网。
44
+ 类型徽标挪到代码右边(与自选股清单第一列同款排法);行的 `title` 改成**证券全称**——旧版写的是
45
+ 「添加」,而美股长名会被截断,全称只有原生 tooltip 给得全。
46
+
47
+ ### Changed
48
+
49
+ - **一屏从 3 行到 5~6 行**:下拉 `max-height` 与清单那格的 `min-height` **同值** 246 → **320**
50
+ (不等就被卡片 `overflow: hidden` 裁掉一截,测试里有同值断言),候选行 `padding` 由 10px 14px
51
+ 收到 6px 12px、行高约 47px。两个数是配套的:只抬浮层不压行高,多出来的空间会被行高吃掉。
52
+ - **加完一条不收下拉、不清输入**:`lastQuery` 不重置 ⇒ 同一个词不会被重发;在途只拦它自己那一条
53
+ (并发添加是安全的,服务端把清单读写串在一条队列上),`searchError` / `searchPartial` 也不擦
54
+ ——下拉还开着,把真话擦掉就是让它失效。
55
+
56
+ ## [2.6.3] - 2026-10-07
57
+
58
+ 自选股并入**港股与美股**,同时补上此前整块缺失的**港美股指数点位**(面板与 Agent 用同一颗能力取数)。
59
+ **既有工具入参、已有数据能力、四把密钥与凭据引用名、配置字段与会话日志格式都没变**,无需迁移,
60
+ 宿主仍要求 `0.2.0-rc.2`。自选股存储只给报价加了两格**可选**字段(`currency` / `source_time`),
61
+ 老清单照读、不必清空重加;新增的三种代码形状(`00700.HK` / `HSI.HK` / `AAPL.OQ`)走的是同一个 v1 schema。
62
+
63
+ ### Added
64
+
65
+ - **一个搜索入口、三市合并**:一次输入并发问同花顺(A 股 / A 股指数 / 场内 ETF)与腾讯公开检索
66
+ (港、美各一次),合并后按完整代码去重、命中的那条排最前。为什么港美要各问一次而不是一次
67
+ `t=all`:实测 `t=all&q=富通` 回 9 条 A 股 + 1 条港股、**0 条美股**——共用一次会让"美股这一档
68
+ 根本没进候选"从偶发变成常态。某一路挂了其余路照常给,下拉那一行点名挂的是哪一路;
69
+ **没配 Fuyao 密钥也能加、能刷港美股**(原先 `credential_missing` 锁的是整块面板,现在它的射程
70
+ 只剩 A 股那一路)。
71
+ - **两颗指数点位能力**(`tencent_hk_index_quote` / `tencent_us_index_quote`,能力总数 92 → 94、
72
+ 腾讯公开源 7 → 9):恒生 / 恒生科技 / 国企指数 / 恒指波动率 / 纳斯达克 / 道琼斯 / 标普500
73
+ 当场回行、盘中在动。口径刻意是窄的:只取点位、昨收、涨跌与时刻,**成交量 / 成交额 / 换手率 /
74
+ 市值四列一律不进表**——实测指数行那两列相等且是万元级(美指那一列 2.1e14),谁也说不出单位。
75
+ ⛔ 指数写法不许猜:`usSSPX` 会回一只真 ETF 且**不报错**,所以只认搜索回来的写法,回包形状再核一遍。
76
+ - **种子清单换成 上证指数 / 恒生指数 / 纳斯达克 / 标普500**(只对新出现的清单生效,已有清单不动)。
77
+
78
+ ### Changed
79
+
80
+ - **面板每一行现在标市场**:`A股 / A指 / 港股 / 港指 / 美股 / 美指` 六档、三市三种底色。场内 ETF
81
+ 归进 A股那一档(它的报价就是二级市场的价格);"这是 ETF"那一层挪进行内「预测」「复盘」递进
82
+ 输入框的那句话里,Agent 仍靠它选端点。
83
+ - **一次搜索给到 20 条候选**(原先 10 条)。A 股那一路按 20 要(Fuyao `limit` 官方取值 1~50),
84
+ 腾讯那两路实测**硬顶 10 条**(`&n=` / `&count=` / `&size=` 等六种写法逐条试过,全部无效),
85
+ 所以"还有更多"分两种情形判:合并后撞一屏,或某一路被上游砍在自己那一档——后者合并结果
86
+ 不到 20 条,也照样要告诉用户缩小输入。
87
+ - 停牌 / 无成交的行上游回的是 `0.00`,那一格现在画**破折号**而不是 0.00%;港美股与港美股指数行的
88
+ tooltip 多一句**交易所当地时间**(原样给,不做时区换算)。
89
+ - README 的自选股截图换成三市同屏那一张。
90
+
10
91
  ## [2.6.2] - 2026-10-07
11
92
 
12
93
  新增一份示例报告([假期后研判报告](docs/sample/假期后研判报告.md)),README 首页的样例链接指向它;
@@ -16,12 +97,14 @@
16
97
  ### Changed
17
98
 
18
99
  - **README**:首页样例链接换成新报告;桌面端「添加插件」补上直接填 `v587d/capital-generation`
19
- 这一种写法(实测可用);FAQ 新增「刚发布的新版本装不到」——桌面端取包会**跳过刚发布不久的版本**
20
- (宿主侧包管理器的发布冷却策略,实测静默降级到上一版),这一条此前被写成了"镜像延迟",不准确。
21
- - **发版后自动通知 npmmirror 同步**。桌面端经国内镜像取 npm 包,而镜像同步是异步的:2.6.1 那次实测
22
- 镜像恰好在官方源出现新版本**前两秒**完成过一次同步,之后十几小时没再碰这个包。CI 发版成功后 PUT
23
- 一次 sync 端点(owner 的标准动作,无需鉴权,实测约 25 秒生效);同步失败不判红——官方源已可用,
24
- 镜像晚点追上只是延迟。
100
+ 这一种写法(实测可用);FAQ 新增「刚发布的新版本装不到」。原因有两条,此前只写了一条:
101
+ ① 宿主侧包管理器有**发布冷却策略**(pnpm 的 `minimumReleaseAge`),刚发布的新版本会被跳过、
102
+ 静默装成上一版——实测**写全版本号也不能绕过**;② 国内镜像同步滞后。急着用最新代码走仓库地址。
103
+ - **发版后自动通知 npmmirror 同步**。镜像同步是异步的:2.6.1 那次实测镜像恰好在官方源出现新版本
104
+ **前两秒**完成过一次同步,之后十几小时没再碰这个包。CI 发版成功后 PUT 一次 sync 端点(owner 的
105
+ 标准动作,无需鉴权);同步失败不判红——官方源已可用,镜像晚点追上只是延迟。
106
+ **踢的时机**要排在"官方源认账"之后:`npm publish` 回执是 202"处理中",官方源自己要几分钟才认
107
+ 这个版本,2.6.2 那次 CI 一发布完就踢,镜像同步到的是还没有新版本的包。
25
108
 
26
109
  ## [2.6.1] - 2026-10-06
27
110
 
package/README.md CHANGED
@@ -15,18 +15,19 @@
15
15
  <p align="center">
16
16
  <a href="https://awesome-dsh-plugin.com"><img src="https://awesome-dsh-plugin.com/badge.svg" alt="awesome · DSH plugin"></a>
17
17
  <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-green" alt="License"></a>
18
- <a href="https://github.com/v587d/capital-generation/releases"><img src="https://img.shields.io/badge/version-2.6.2-9cf" alt="Version"></a>
18
+ <a href="https://github.com/v587d/capital-generation/releases"><img src="https://img.shields.io/badge/version-2.6.4-9cf" alt="Version"></a>
19
19
  </p>
20
20
 
21
21
  # Capital Generation
22
22
 
23
23
  > Next-Gen AI-Driven Capital Generation.
24
24
 
25
- Capital Generation 是运行在 [DeepSeek Harness(DSH)](https://github.com/deepseek-ai/deepseek-harness) 里的证券研究插件,面向关注 A 股(近期开放港美股)的个人用户。安装后,在新会话中选择 **Capital 模式**,就可以用自然语言查行情、财务数据、公告和新闻,整理分析并生成图表。它不是独立应用,需要先安装 DSH。
25
+ Capital Generation 是运行在 [DeepSeek Harness(DSH)](https://github.com/deepseek-ai/deepseek-harness) 里的证券研究插件,面向关注 A股/港股/美股 的个人投资者。安装后,在新会话中选择 **Capital 模式**,就可以用自然语言查行情、财务数据、公告和新闻,整理分析并生成图表。它不是独立应用,需要先安装 DSH。
26
26
 
27
27
  **🎞️视频演示:**[安装、配置与使用](https://www.bilibili.com/video/BV1fzaZ6CE9J/)。
28
28
 
29
- 例如,你可以问:「复盘 XXXX 最近 20 个交易日的走势,结合公告和财务数据说明主要变化,并画一张量价图。」[假期后研判报告(20261007)](docs/sample/假期后研判报告.md)。
29
+ 例如,你可以问:「复盘 XXXX 最近 20 个交易日的走势,结合公告和财务数据说明主要变化,并画一张量价图。」
30
+ [样例:假期后研判报告(20261007)](docs/sample/假期后研判报告.md)。
30
31
 
31
32
  > [!IMPORTANT]
32
33
  > 本项目仍在探索中,不提供金融服务或投资建议,不保证数据完整、及时或准确,也不承诺投资回报。请自行核对来源并承担投资风险。
@@ -36,7 +37,8 @@ Capital Generation 是运行在 [DeepSeek Harness(DSH)](https://github.com/d
36
37
  > [!NOTE]
37
38
  > 适配 DSH`@0.2.0-rc.2`。已在 Linux 的 Web profile 和 Windows 桌面端验证;其他环境尚未充分测试。建议使用 `Deepseek/deepseek-flash` ,思考推理能力为 High ;GPT / Claude 尚未充分测试。
38
39
 
39
- 1. **安装插件。** Linux / macOS 的 Web 或 CLI profile 在终端执行,下面两条 **任选一条** :
40
+ 1. **安装插件。**
41
+ Linux / macOS 的 Web 或 CLI profile 在终端执行,下面两条 **任选一条** :
40
42
 
41
43
  ```bash
42
44
  dsh plugin --profile web add @v587d/capital-generation
@@ -44,7 +46,11 @@ Capital Generation 是运行在 [DeepSeek Harness(DSH)](https://github.com/d
44
46
  ```
45
47
 
46
48
  两条装完的功能一样:前者取 npm 上已发布的版本,后者取本仓库当前的代码。
47
- 安装后重启该 profile。 Windows 桌面端在「添加插件」中输入 `https://github.com/v587d/capital-generation` 或 `v587d/capital-generation`。桌面端自带 DSH 宿主,不需要单独用 npm 安装宿主。本仓库已包含构建产物,普通用户不需要克隆仓库或运行构建命令。
49
+ 安装后重启该 profile。
50
+
51
+ DSH 桌面端在 「添加插件」 中输入:
52
+ `https://github.com/v587d/capital-generation` 或 `@v587d/capital-generation`
53
+ 桌面端自带 DSH 宿主,不需要单独用 npm 安装宿主。本仓库已包含构建产物,普通用户不需要克隆仓库或运行构建命令。
48
54
 
49
55
  2. **选填密钥。** 打开 DSH 「插件」 → **Capital Generation** -> 「配置」。
50
56
 
@@ -56,7 +62,10 @@ Capital Generation 是运行在 [DeepSeek Harness(DSH)](https://github.com/d
56
62
  | [PaddleOCR AIStudio](https://aistudio.baidu.com/paddleocr) | 解析 PDF 和图片中的文字 |
57
63
 
58
64
  这些都是第三方服务的密钥,需分别向服务方申请;额度和条款以各服务方为准。
59
- **本插件所有密钥均不影响插件核心功能**,即缺哪个密钥,仅表示对应能力就不可用,其他功能照常。
65
+
66
+ > [!NOTE]
67
+ > **本插件所有密钥均不影响插件核心功能**,即缺哪个密钥,仅表示对应能力就不可用,其他功能照常。
68
+
60
69
  保存后**新建 Capital 模式会话**即可生效,无需重启。
61
70
  也可以将密钥写入 `~/.dsh/.credentials.yaml`,名称依次为 `FUYAO_API_KEY`、`ANYSEARCH_API_KEY`、`WIND_API_KEY`、`PADDLE_OCR_TOKEN`。
62
71
  密钥由 DSH 凭据服务保存,不会显示在会话配置中。
@@ -67,7 +76,7 @@ Capital Generation 是运行在 [DeepSeek Harness(DSH)](https://github.com/d
67
76
  </a>
68
77
  </p>
69
78
 
70
- 3. **新建会话。** 在 Agent Preset 选择器中选 **Capital**,然后直接描述研究问题。也可以到「设置」→「Agent 预设」把它设为默认模式。
79
+ 3. **新建会话。** 在 Agent Preset 选择器中选 **Capital 模式**,然后直接描述研究问题。也可以到「设置」→「Agent 预设」把它设为默认模式。
71
80
 
72
81
  <p align="center">
73
82
  <a href="assets/mode_selector.png">
@@ -77,10 +86,10 @@ Capital Generation 是运行在 [DeepSeek Harness(DSH)](https://github.com/d
77
86
 
78
87
  ## 能做什么
79
88
 
80
- - **查数据和资料:** 覆盖A股、港股、美股,按需获取行情、财务、指数、基金与宏观行业数据,检索公告、新闻和研报。共计 **92** 个数据收集能力和 **14** 个网页检索能力,部分公开数据源无需额外密钥;具体覆盖范围见 [数据收集能力表](docs/data-collector-capabilities.md) 和 [网页检索能力表](docs/web-retriever-capabilities.md)。
89
+ - **查数据和资料:** 覆盖A股、港股、美股,由 Agents 按需获取行情、财务、指数、基金与宏观行业数据,检索公告、新闻和研报。共计 **94** 个数据收集能力和 **14** 个网页检索能力,部分公开数据源无需额外密钥;具体覆盖范围见 [数据收集能力表](docs/data-collector-capabilities.md) 和 [网页检索能力表](docs/web-retriever-capabilities.md)。
81
90
  - **数据分析:** 所有 Agents 均不直接接触原始结构数据,Agents 按需读取数据、校验数据,并写脚本挖掘数据背后含义。
82
91
  - **可视化:** 将数据交给不同角色处理,再生成可交互图表。图表会作为本轮交付物出现在会话中,可在侧栏查看或离线打开。了解处理流程可看 [Agent 角色说明](docs/agent-roles.md)。
83
- - **管理自选股:** 在 Capital 会话中输入 `/` 或点击输入框旁的 `+`,从「指令」中打开「自选股」。刷新失败时已有报价仍显示为旧快照,并标明时间;请勿当作实时价格。
92
+ - **管理自选股:** 在 Capital 会话中输入 `/` 或点击输入框旁的 `+`,从「指令」中打开「自选股」。A股、港股、美股共用这一个入口:直接敲代码或名称,候选列表会写清它属于哪个市场;清单里每一行都带市场标注,指数另标一行。某一个市场取数失败时,其余市场照常刷新,页面会说明失败的是哪一路;整体刷新失败时已有报价仍显示为旧快照,并标明时间,请勿当作实时价格。
84
93
 
85
94
  会话中的图表效果:
86
95
 
@@ -5,7 +5,7 @@ window.__ModuleLoader__.load({
5
5
  var module = { exports: {} }
6
6
  var exports = module.exports
7
7
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' })
8
- "use strict";var{createElement:i,useEffect:x,useRef:C,useState:A}=require("react"),{createPortal:L}=require("react-dom"),{SettingsForm:S,SettingsSecretField:R,SettingsFormModel:k,Switch:D,IconRightUpOutlineRegular:_}=require("@deepseek-ai/dsh-client-ui-primitives"),v="capital-config",N="@v587d/capital-generation",F="settings.capital",O="FUYAO_API_KEY",T="ANYSEARCH_API_KEY",H="WIND_API_KEY",P="PADDLE_OCR_TOKEN",f={fuyao:"https://fuyao.aicubes.cn/docs/",anysearch:"https://www.anysearch.com/docs/auth",wind:"https://market.windalice.com/",paddleocr:"https://aistudio.baidu.com/paddleocr"},o=["fuyao","anysearch","wind","paddleocr"],r={fuyao:O,anysearch:T,wind:H,paddleocr:P},I=()=>Object.fromEntries(o.map(a=>[a,{ref:r[a],configured:!1,writable:!0}])),U={title:"\u914D\u7F6E",fuyaoLabel:"Fuyao API Key",fuyaoHint:"\u540C\u82B1\u987A Fuyao \u7ED3\u6784\u5316\u6570\u636E\u63A5\u53E3\u3002\u4FDD\u5B58\u540E\u65B0 Capital \u6A21\u5F0F\u4F1A\u8BDD\u751F\u6548\u3002",anysearchLabel:"AnySearch API Key",anysearchHint:"AnySearch \u7F51\u9875\u641C\u7D22 / \u63D0\u53D6\u63A5\u53E3\u3002\u4FDD\u5B58\u540E\u65B0 Capital \u6A21\u5F0F\u4F1A\u8BDD\u751F\u6548\u3002",localFetchLabel:"\u5141\u8BB8\u542F\u52A8\u672C\u5730\u63D0\u53D6\u7F51\u9875\u5185\u5BB9",localFetchHint:"\u5F00\u542F\u540E\u672C\u5730\u6293\u53D6\u515C\u5E95\uFF08\u56DE\u6267\u6765\u6E90 local-http\uFF09\u3002\u4FDD\u5B58\u540E\u65B0 Capital \u6A21\u5F0F\u4F1A\u8BDD\u751F\u6548\u3002",windLabel:"Wind Alice API Key",windHint:"Wind \u91D1\u878D\u4FE1\u62AB\u7C7B\u6587\u6863\u68C0\u7D22\u63A5\u53E3\u3002\u4FDD\u5B58\u540E\u65B0 Capital \u6A21\u5F0F\u4F1A\u8BDD\u751F\u6548\u3002",paddleocrLabel:"PaddleOCR \u6587\u6863\u89E3\u6790 Token",paddleocrHint:"\u914D\u7F6E Token \u540E\u81EA\u52A8\u89E3\u6790 PDF\u3001\u56FE\u7247\u3002\u4FDD\u5B58\u540E\u65B0 Capital \u6A21\u5F0F\u4F1A\u8BDD\u751F\u6548\u3002",openDocs:"\u5B98\u65B9\u6587\u6863",configured:"\u5DF2\u914D\u7F6E\u5BC6\u94A5\u3002",notConfigured:"\u672A\u914D\u7F6E\u5BC6\u94A5\u3002",save:"\u4FDD\u5B58",saving:"\u4FDD\u5B58\u4E2D\u2026",readOnly:"\u672C\u90E8\u7F72\u7684\u8BBE\u7F6E\u4E3A\u53EA\u8BFB\u3002",saveFailed:"\u672C\u90E8\u7F72\u6CA1\u6709\u63A5\u53D7\u8FD9\u4E9B\u503C\uFF0C\u5DF2\u4FDD\u7559\u4F9B\u4F60\u4FEE\u6539\u3002",unavailable:"\u8BE5\u63D2\u4EF6\u5F53\u524D\u672A\u52A0\u8F7D\uFF0C\u6682\u65F6\u65E0\u6CD5\u914D\u7F6E\u3002"},j={title:"Configuration",fuyaoLabel:"Fuyao API Key",fuyaoHint:"Tonghuashun Fuyao structured-data API. Takes effect in new Capital mode sessions.",anysearchLabel:"AnySearch API Key",anysearchHint:"AnySearch web search / extract interface. Takes effect in new Capital mode sessions.",localFetchLabel:"Allow local web page extraction",localFetchHint:"When on, a failed fetch falls back to local direct fetching (receipt via: local-http). Takes effect in new Capital mode sessions.",windLabel:"Wind Alice API Key",windHint:"Wind financial disclosure document retrieval interface. Takes effect in new Capital mode sessions.",paddleocrLabel:"PaddleOCR document token",paddleocrHint:"Configure the token to parse PDFs and images automatically. Takes effect in new Capital mode sessions.",openDocs:"Official docs",configured:"A key is configured.",notConfigured:"No key is configured.",save:"Save",saving:"Saving\u2026",readOnly:"This deployment stores settings read-only.",saveFailed:"The deployment did not accept these values; they were left for you to correct.",unavailable:"This plugin is not loaded, so it cannot be configured right now."};function h(a,e){return typeof a=="string"&&a.length>0?a:e}function K(a,e){return e==="fuyao"?h(a.value?.fuyaoCredentialRef,r.fuyao):e==="wind"?h(a.value?.retriever?.windDocs?.credentialRef,r.wind):e==="paddleocr"?h(a.value?.retriever?.paddleOcr?.credentialRef,r.paddleocr):h(a.value?.retriever?.credentialRef,r.anysearch)}function W(){if(typeof document>"u"||document.querySelector("style[data-capital-config]"))return()=>{};let a=document.createElement("style");return a.dataset.capitalConfig="true",a.textContent=`
8
+ "use strict";var{createElement:i,useEffect:E,useRef:A,useState:S}=require("react"),{createPortal:R}=require("react-dom"),{SettingsForm:_,SettingsSecretField:D,SettingsFormModel:N,Switch:H,IconRightUpOutlineRegular:P}=require("@deepseek-ai/dsh-client-ui-primitives"),g="capital-config",y="@v587d/capital-generation",b="settings.capital",x="plugins.detail.badge",O="https://github.com/v587d/capital-generation",T=`https://www.npmjs.com/package/${y}`,I="FUYAO_API_KEY",U="ANYSEARCH_API_KEY",j="WIND_API_KEY",K="PADDLE_OCR_TOKEN",f={fuyao:"https://fuyao.aicubes.cn/docs/",anysearch:"https://www.anysearch.com/docs/auth",wind:"https://market.windalice.com/",paddleocr:"https://aistudio.baidu.com/paddleocr"},o=["fuyao","anysearch","wind","paddleocr"],r={fuyao:I,anysearch:U,wind:j,paddleocr:K},W=()=>Object.fromEntries(o.map(a=>[a,{ref:r[a],configured:!1,writable:!0}])),z={title:"\u914D\u7F6E",fuyaoLabel:"Fuyao API Key",fuyaoHint:"\u540C\u82B1\u987A Fuyao \u7ED3\u6784\u5316\u6570\u636E\u63A5\u53E3\u3002\u4FDD\u5B58\u540E\u65B0 Capital \u6A21\u5F0F\u4F1A\u8BDD\u751F\u6548\u3002",anysearchLabel:"AnySearch API Key",anysearchHint:"AnySearch \u7F51\u9875\u641C\u7D22 / \u63D0\u53D6\u63A5\u53E3\u3002\u4FDD\u5B58\u540E\u65B0 Capital \u6A21\u5F0F\u4F1A\u8BDD\u751F\u6548\u3002",localFetchLabel:"\u5141\u8BB8\u542F\u52A8\u672C\u5730\u63D0\u53D6\u7F51\u9875\u5185\u5BB9",localFetchHint:"\u5F00\u542F\u540E\u672C\u5730\u6293\u53D6\u515C\u5E95\uFF08\u56DE\u6267\u6765\u6E90 local-http\uFF09\u3002\u4FDD\u5B58\u540E\u65B0 Capital \u6A21\u5F0F\u4F1A\u8BDD\u751F\u6548\u3002",windLabel:"Wind Alice API Key",windHint:"Wind \u91D1\u878D\u4FE1\u62AB\u7C7B\u6587\u6863\u68C0\u7D22\u63A5\u53E3\u3002\u4FDD\u5B58\u540E\u65B0 Capital \u6A21\u5F0F\u4F1A\u8BDD\u751F\u6548\u3002",paddleocrLabel:"PaddleOCR \u6587\u6863\u89E3\u6790 Token",paddleocrHint:"\u914D\u7F6E Token \u540E\u81EA\u52A8\u89E3\u6790 PDF\u3001\u56FE\u7247\u3002\u4FDD\u5B58\u540E\u65B0 Capital \u6A21\u5F0F\u4F1A\u8BDD\u751F\u6548\u3002",openDocs:"\u5B98\u65B9\u6587\u6863",configured:"\u5DF2\u914D\u7F6E\u5BC6\u94A5\u3002",notConfigured:"\u672A\u914D\u7F6E\u5BC6\u94A5\u3002",save:"\u4FDD\u5B58",saving:"\u4FDD\u5B58\u4E2D\u2026",readOnly:"\u672C\u90E8\u7F72\u7684\u8BBE\u7F6E\u4E3A\u53EA\u8BFB\u3002",saveFailed:"\u672C\u90E8\u7F72\u6CA1\u6709\u63A5\u53D7\u8FD9\u4E9B\u503C\uFF0C\u5DF2\u4FDD\u7559\u4F9B\u4F60\u4FEE\u6539\u3002",unavailable:"\u8BE5\u63D2\u4EF6\u5F53\u524D\u672A\u52A0\u8F7D\uFF0C\u6682\u65F6\u65E0\u6CD5\u914D\u7F6E\u3002",githubLabel:"GitHub \u4ED3\u5E93",npmLabel:"npm \u5305\u9875\u9762"},Y={title:"Configuration",fuyaoLabel:"Fuyao API Key",fuyaoHint:"Tonghuashun Fuyao structured-data API. Takes effect in new Capital mode sessions.",anysearchLabel:"AnySearch API Key",anysearchHint:"AnySearch web search / extract interface. Takes effect in new Capital mode sessions.",localFetchLabel:"Allow local web page extraction",localFetchHint:"When on, a failed fetch falls back to local direct fetching (receipt via: local-http). Takes effect in new Capital mode sessions.",windLabel:"Wind Alice API Key",windHint:"Wind financial disclosure document retrieval interface. Takes effect in new Capital mode sessions.",paddleocrLabel:"PaddleOCR document token",paddleocrHint:"Configure the token to parse PDFs and images automatically. Takes effect in new Capital mode sessions.",openDocs:"Official docs",configured:"A key is configured.",notConfigured:"No key is configured.",save:"Save",saving:"Saving\u2026",readOnly:"This deployment stores settings read-only.",saveFailed:"The deployment did not accept these values; they were left for you to correct.",unavailable:"This plugin is not loaded, so it cannot be configured right now.",githubLabel:"GitHub repository",npmLabel:"npm package page"};function h(a,e){return typeof a=="string"&&a.length>0?a:e}function M(a,e){return e==="fuyao"?h(a.value?.fuyaoCredentialRef,r.fuyao):e==="wind"?h(a.value?.retriever?.windDocs?.credentialRef,r.wind):e==="paddleocr"?h(a.value?.retriever?.paddleOcr?.credentialRef,r.paddleocr):h(a.value?.retriever?.credentialRef,r.anysearch)}function $(){if(typeof document>"u"||document.querySelector("style[data-capital-config]"))return()=>{};let a=document.createElement("style");return a.dataset.capitalConfig="true",a.textContent=`
9
9
  .capital-config-card { display: flex; flex-direction: column; gap: 12px; }
10
10
  .capital-config-title { margin: 0; font-size: 14px; font-weight: 500; line-height: 20px; }
11
11
  .capital-config-secret-row { display: flex; flex-direction: column; gap: 2px; }
@@ -22,7 +22,13 @@ window.__ModuleLoader__.load({
22
22
  .capital-config-switch-label { color: var(--dsw-alias-label-primary); font-size: 13px; font-weight: 500; line-height: 20px; }
23
23
  .capital-config-hint { margin: 0; color: var(--dsw-alias-label-tertiary); font-size: 12px; line-height: 18px; }
24
24
  .capital-config-write-failed { margin: 0; color: var(--dsw-alias-label-error); font-size: 12px; line-height: 18px; }
25
- `,document.head.appendChild(a),()=>a.remove()}var g=class{constructor(e,t){this.scope=e,this.ctx=t,this.status=I(),this.localFetchWriting=!1,this.localFetchFailed=!1,this.model=new k(e,[],o.map(n=>({field:n,write:s=>this.writeKey(n,s)}))),this.store=this.model.bind(()=>this.projection()),this.unsubscribe=e.subscribe(()=>{this.refreshRefs(),this.store.set(this.projection()),this.readCredentials()}),this.refreshRefs(),this.readCredentials()}dispose(){this.unsubscribe?.(),this.model.dispose()}projection(){let e=this.scope.getSnapshot();return{...this.model.shell(),...Object.fromEntries(o.map(t=>[t,{...this.model.field(t),configured:this.status[t].configured,writable:this.status[t].writable}])),localFetch:{on:e.value?.retriever?.localFetch?.enabled!==!1,writing:this.localFetchWriting,failed:this.localFetchFailed}}}refreshRefs(){let e=this.scope.getSnapshot();for(let t of o){let n=K(e,t);this.status[t].ref!==n&&(this.status[t]={ref:n,configured:!1,writable:!0},this.model.edit(t,""))}}async readCredentials(){let e=o.map(t=>this.status[t].ref);try{let t=await this.ctx.remote.credentials.describe(e);if(!t?.ok||o.some((s,l)=>e[l]!==this.status[s].ref))return;let n=t.value??{};for(let s of o){let l=this.status[s],c=n[l.ref];c!==void 0&&(this.status[s]={ref:l.ref,configured:c.configured===!0,writable:c.writable!==!1})}this.store.set(this.projection())}catch{}}refresh(e){o.some(t=>e===this.status[t].ref)&&this.readCredentials()}async writeKey(e,t){try{return await this.ctx.remote.credentials.set(this.status[e].ref,t.trim()),await this.readCredentials(),this.status[e].configured===!0}catch{return!1}}async toggleLocalFetch(e){if(this.localFetchWriting)return;let t=this.scope.getSnapshot();if(t.status!=="ready"||!t.writable)return;this.localFetchWriting=!0,this.localFetchFailed=!1,this.store.set(this.projection());try{await this.scope.mutate([{op:"set",path:["retriever","localFetch","enabled"],value:e}])}catch{}this.localFetchWriting=!1,this.scope.getSnapshot().value?.retriever?.localFetch?.enabled===e||(this.localFetchFailed=!0),this.store.set(this.projection())}inject(){return{hooks:{capitalCard:this.store},...this.model.actions(),toggleLocalFetch:e=>this.toggleLocalFetch(e)}}};function u({field:a,label:e,hint:t,docsUrl:n,state:s,disabled:l,onEdit:c,t:d}){let y=C(null),[w,E]=A(null);x(()=>{let m=y.current,p=m?m.querySelector("label"):null;p&&p.parentElement&&E(p.parentElement)},[]);let b=i("a",{href:n,target:"_blank",rel:"noopener noreferrer","aria-label":`${e} ${d("openDocs")}`,"data-capital-config-doc":"true",className:"capital-config-doc-link"},d("openDocs"),i(_,{size:12}));return i("div",{className:"capital-config-secret-row",key:a,ref:y},i(R,{id:`capital-config-${a}-key`,label:e,hint:t,text:s.text,configured:s.configured,stateLabel:s.configured?d("configured"):d("notConfigured"),disabled:l,onEdit:c}),w?L(b,w):b)}function Y(a){let e=a.t,t=a.useCapitalCard(l=>l),n=!t.writable,s=i(S,{labels:{unavailable:e("unavailable"),readOnly:e("readOnly"),saveFailed:e("saveFailed"),save:e("save"),saving:e("saving")},state:t,onSave:a.save,onDiscard:a.discard},i(u,{field:"fuyao",label:e("fuyaoLabel"),hint:e("fuyaoHint"),docsUrl:f.fuyao,state:t.fuyao,disabled:n||t.saving||!t.fuyao.writable,onEdit:l=>a.edit("fuyao",l),t:e}),i(u,{field:"anysearch",label:e("anysearchLabel"),hint:e("anysearchHint"),docsUrl:f.anysearch,state:t.anysearch,disabled:n||t.saving||!t.anysearch.writable,onEdit:l=>a.edit("anysearch",l),t:e}),i(u,{field:"wind",label:e("windLabel"),hint:e("windHint"),docsUrl:f.wind,state:t.wind,disabled:n||t.saving||!t.wind.writable,onEdit:l=>a.edit("wind",l),t:e}),i(u,{field:"paddleocr",label:e("paddleocrLabel"),hint:e("paddleocrHint"),docsUrl:f.paddleocr,state:t.paddleocr,disabled:n||t.saving||!t.paddleocr.writable,onEdit:l=>a.edit("paddleocr",l),t:e}),i("div",{className:"capital-config-field"},i("div",{className:"capital-config-switch-row"},i("div",{className:"capital-config-switch-text"},i("span",{className:"capital-config-switch-label"},e("localFetchLabel")),i("p",{className:"capital-config-hint"},e("localFetchHint"))),i(D,{label:e("localFetchLabel"),checked:t.localFetch?.on!==!1,disabled:n||t.saving||t.localFetch?.writing===!0,onChange:a.toggleLocalFetch})),t.localFetch?.failed?i("p",{role:"status",className:"capital-config-write-failed"},e("saveFailed")):null));return i("div",{className:"capital-config-card"},i("h4",{className:"capital-config-title"},e("title")),s)}function z(a){a.effect(W,"capital-config: styles"),a.effect(()=>a.locale.register(F,{zh:U,en:j}),"capital-config: dictionaries");let e=new g(a.configForms.get(v),a);a.effect(()=>()=>e.dispose(),"capital-config: form subscription"),a.effect(()=>a.remote.$on("credentials/reference-updated",t=>e.refresh(t)),"capital-config: credential invalidations"),a.effect(()=>a.configForms.whileServed([v],()=>a.slots.inject("plugins.bundle.config",()=>a.slots.register({name:"plugins.bundle.config",key:N,locale:F,inject:()=>e.inject()},Y))),"capital-config: page"),a.logger?.info?.("capital-config: settings card mounted")}exports.name="capital-config";exports.inject=["slots","locale","remote","remote.credentials","configForms"];exports.apply=z;
25
+ /* \u6807\u9898\u53F3\u4FA7\u7684\u4E24\u679A\u5916\u94FE\uFF1A\u5B98\u65B9\u90A3\u4E00\u683C\u662F flex-wrap + gap:8px\uFF0C\u6574\u7EC4\u81EA\u5DF1\u6536\u6210\u4E00\u4E2A inline-flex \u9879\uFF0C
26
+ \u514D\u5F97\u6807\u9898\u53D8\u957F\u65F6\u88AB\u6362\u884C\u62C6\u6210\u4E24\u622A\u3002\u989C\u8272\u53EA\u8D70 --dsw-* \u53D8\u91CF\uFF0C\u660E\u6697\u4E24\u5957\u90FD\u8DDF\u7740\u5BBF\u4E3B\u3002 */
27
+ .capital-config-plugin-links { flex: none; align-items: center; gap: 2px; display: inline-flex; }
28
+ .capital-config-plugin-link { border-radius: var(--dsw-radius-sm); width: 24px; height: 24px; color: var(--dsw-alias-label-tertiary); justify-content: center; align-items: center; display: inline-flex; text-decoration: none; }
29
+ .capital-config-plugin-link:hover { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); }
30
+ .capital-config-plugin-link:focus-visible { outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color, var(--dsw-alias-brand-primary)); outline-offset: 1px; }
31
+ `,document.head.appendChild(a),()=>a.remove()}var w=class{constructor(e,t){this.scope=e,this.ctx=t,this.status=W(),this.localFetchWriting=!1,this.localFetchFailed=!1,this.model=new N(e,[],o.map(n=>({field:n,write:s=>this.writeKey(n,s)}))),this.store=this.model.bind(()=>this.projection()),this.unsubscribe=e.subscribe(()=>{this.refreshRefs(),this.store.set(this.projection()),this.readCredentials()}),this.refreshRefs(),this.readCredentials()}dispose(){this.unsubscribe?.(),this.model.dispose()}projection(){let e=this.scope.getSnapshot();return{...this.model.shell(),...Object.fromEntries(o.map(t=>[t,{...this.model.field(t),configured:this.status[t].configured,writable:this.status[t].writable}])),localFetch:{on:e.value?.retriever?.localFetch?.enabled!==!1,writing:this.localFetchWriting,failed:this.localFetchFailed}}}refreshRefs(){let e=this.scope.getSnapshot();for(let t of o){let n=M(e,t);this.status[t].ref!==n&&(this.status[t]={ref:n,configured:!1,writable:!0},this.model.edit(t,""))}}async readCredentials(){let e=o.map(t=>this.status[t].ref);try{let t=await this.ctx.remote.credentials.describe(e);if(!t?.ok||o.some((s,l)=>e[l]!==this.status[s].ref))return;let n=t.value??{};for(let s of o){let l=this.status[s],c=n[l.ref];c!==void 0&&(this.status[s]={ref:l.ref,configured:c.configured===!0,writable:c.writable!==!1})}this.store.set(this.projection())}catch{}}refresh(e){o.some(t=>e===this.status[t].ref)&&this.readCredentials()}async writeKey(e,t){try{return await this.ctx.remote.credentials.set(this.status[e].ref,t.trim()),await this.readCredentials(),this.status[e].configured===!0}catch{return!1}}async toggleLocalFetch(e){if(this.localFetchWriting)return;let t=this.scope.getSnapshot();if(t.status!=="ready"||!t.writable)return;this.localFetchWriting=!0,this.localFetchFailed=!1,this.store.set(this.projection());try{await this.scope.mutate([{op:"set",path:["retriever","localFetch","enabled"],value:e}])}catch{}this.localFetchWriting=!1,this.scope.getSnapshot().value?.retriever?.localFetch?.enabled===e||(this.localFetchFailed=!0),this.store.set(this.projection())}inject(){return{hooks:{capitalCard:this.store},...this.model.actions(),toggleLocalFetch:e=>this.toggleLocalFetch(e)}}};function p({field:a,label:e,hint:t,docsUrl:n,state:s,disabled:l,onEdit:c,t:d}){let m=A(null),[v,C]=S(null);E(()=>{let L=m.current,u=L?L.querySelector("label"):null;u&&u.parentElement&&C(u.parentElement)},[]);let F=i("a",{href:n,target:"_blank",rel:"noopener noreferrer","aria-label":`${e} ${d("openDocs")}`,"data-capital-config-doc":"true",className:"capital-config-doc-link"},d("openDocs"),i(P,{size:12}));return i("div",{className:"capital-config-secret-row",key:a,ref:m},i(D,{id:`capital-config-${a}-key`,label:e,hint:t,text:s.text,configured:s.configured,stateLabel:s.configured?d("configured"):d("notConfigured"),disabled:l,onEdit:c}),v?R(F,v):F)}function q(a){let e=a.t,t=a.useCapitalCard(l=>l),n=!t.writable,s=i(_,{labels:{unavailable:e("unavailable"),readOnly:e("readOnly"),saveFailed:e("saveFailed"),save:e("save"),saving:e("saving")},state:t,onSave:a.save,onDiscard:a.discard},i(p,{field:"fuyao",label:e("fuyaoLabel"),hint:e("fuyaoHint"),docsUrl:f.fuyao,state:t.fuyao,disabled:n||t.saving||!t.fuyao.writable,onEdit:l=>a.edit("fuyao",l),t:e}),i(p,{field:"anysearch",label:e("anysearchLabel"),hint:e("anysearchHint"),docsUrl:f.anysearch,state:t.anysearch,disabled:n||t.saving||!t.anysearch.writable,onEdit:l=>a.edit("anysearch",l),t:e}),i(p,{field:"wind",label:e("windLabel"),hint:e("windHint"),docsUrl:f.wind,state:t.wind,disabled:n||t.saving||!t.wind.writable,onEdit:l=>a.edit("wind",l),t:e}),i(p,{field:"paddleocr",label:e("paddleocrLabel"),hint:e("paddleocrHint"),docsUrl:f.paddleocr,state:t.paddleocr,disabled:n||t.saving||!t.paddleocr.writable,onEdit:l=>a.edit("paddleocr",l),t:e}),i("div",{className:"capital-config-field"},i("div",{className:"capital-config-switch-row"},i("div",{className:"capital-config-switch-text"},i("span",{className:"capital-config-switch-label"},e("localFetchLabel")),i("p",{className:"capital-config-hint"},e("localFetchHint"))),i(H,{label:e("localFetchLabel"),checked:t.localFetch?.on!==!1,disabled:n||t.saving||t.localFetch?.writing===!0,onChange:a.toggleLocalFetch})),t.localFetch?.failed?i("p",{role:"status",className:"capital-config-write-failed"},e("saveFailed")):null));return i("div",{className:"capital-config-card"},i("h4",{className:"capital-config-title"},e("title")),s)}var G={github:"M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12",npm:"M1.763 0C.786 0 0 .786 0 1.763v20.474C0 23.214.786 24 1.763 24h20.474c.977 0 1.763-.786 1.763-1.763V1.763C24 .786 23.214 0 22.237 0zM5.13 5.323l13.837.019-.009 13.836h-3.464l.01-10.382h-3.456L12.04 19.17H5.113z"};function k({kind:a,href:e,label:t}){return i("a",{className:"capital-config-plugin-link",href:e,target:"_blank",rel:"noopener noreferrer","aria-label":t,title:t,"data-capital-plugin-link":a},i("svg",{viewBox:"0 0 24 24",width:16,height:16,fill:"currentColor","aria-hidden":"true",focusable:"false"},i("path",{d:G[a]})))}function B({subject:a,t:e}){return a?.kind!=="bundle"||a.pkg?.name!==y?null:i("span",{className:"capital-config-plugin-links"},i(k,{kind:"github",href:O,label:e("githubLabel")}),i(k,{kind:"npm",href:T,label:e("npmLabel")}))}function V(a){a.effect($,"capital-config: styles"),a.effect(()=>a.locale.register(b,{zh:z,en:Y}),"capital-config: dictionaries");let e=new w(a.configForms.get(g),a);a.effect(()=>()=>e.dispose(),"capital-config: form subscription"),a.effect(()=>a.remote.$on("credentials/reference-updated",t=>e.refresh(t)),"capital-config: credential invalidations"),a.effect(()=>a.configForms.whileServed([g],()=>a.slots.inject("plugins.bundle.config",()=>a.slots.register({name:"plugins.bundle.config",key:y,locale:b,inject:()=>e.inject()},q))),"capital-config: page"),a.effect(()=>a.slots.inject(x,()=>a.slots.register({name:x,id:`${g}-plugin-links`,locale:b},B)),"capital-config: plugin links"),a.logger?.info?.("capital-config: settings card + \u6807\u9898\u5916\u94FE mounted")}exports.name="capital-config";exports.inject=["slots","locale","remote","remote.credentials","configForms"];exports.apply=V;
26
32
  return module.exports
27
33
  },
28
34
  })
@@ -28,6 +28,21 @@ const BUNDLE_NAME = '@v587d/capital-generation'
28
28
  /** 文案字典的命名空间(与配置条目 id 是两回事,按官方 settings 页的 `settings.*` 惯例)。 */
29
29
  const LOCALE_NS = 'settings.capital'
30
30
 
31
+ /**
32
+ * 详情页标题旁那两枚外链坐的是槽 `plugins.detail.badge`(list,`scope: root`):页面把它渲染在
33
+ * `.titleRow` 里**官方自己画的版本 / beta / 问题标签之后**,正是标题右侧那一格。座位是 list,
34
+ * 注册必须带 `id`(同 id 二次注册直接抛错),且组件收到的是 owner props `subject`——
35
+ * 同一格在**行详情页**与**官方插件页**也会渲染,所以 `subject.kind` 与包名两道都要过,
36
+ * 否则会在别人的页面上挂自己的链接。
37
+ *
38
+ * 两个地址的真值各只有一处:`REPO_URL` 逐字等于根 `package.json` 的 `repository.url`(去掉
39
+ * `git+` 前缀与 `.git` 后缀),`NPM_URL` 由 `BUNDLE_NAME` 拼出。两条同字链由
40
+ * `test/capital-config.test.mjs` 钉住。
41
+ */
42
+ const BADGE_SLOT = 'plugins.detail.badge'
43
+ const REPO_URL = 'https://github.com/v587d/capital-generation'
44
+ const NPM_URL = `https://www.npmjs.com/package/${BUNDLE_NAME}`
45
+
31
46
  const FUYAO_DEFAULT_REF = 'FUYAO_API_KEY'
32
47
  const ANYSEARCH_DEFAULT_REF = 'ANYSEARCH_API_KEY'
33
48
  const WIND_DEFAULT_REF = 'WIND_API_KEY'
@@ -74,6 +89,8 @@ const zh = {
74
89
  readOnly: '本部署的设置为只读。',
75
90
  saveFailed: '本部署没有接受这些值,已保留供你修改。',
76
91
  unavailable: '该插件当前未加载,暂时无法配置。',
92
+ githubLabel: 'GitHub 仓库',
93
+ npmLabel: 'npm 包页面',
77
94
  }
78
95
 
79
96
  const en = {
@@ -96,6 +113,8 @@ const en = {
96
113
  readOnly: 'This deployment stores settings read-only.',
97
114
  saveFailed: 'The deployment did not accept these values; they were left for you to correct.',
98
115
  unavailable: 'This plugin is not loaded, so it cannot be configured right now.',
116
+ githubLabel: 'GitHub repository',
117
+ npmLabel: 'npm package page',
99
118
  }
100
119
 
101
120
  function text(value, fallback) {
@@ -130,6 +149,12 @@ function installStyles() {
130
149
  .capital-config-switch-label { color: var(--dsw-alias-label-primary); font-size: 13px; font-weight: 500; line-height: 20px; }
131
150
  .capital-config-hint { margin: 0; color: var(--dsw-alias-label-tertiary); font-size: 12px; line-height: 18px; }
132
151
  .capital-config-write-failed { margin: 0; color: var(--dsw-alias-label-error); font-size: 12px; line-height: 18px; }
152
+ /* 标题右侧的两枚外链:官方那一格是 flex-wrap + gap:8px,整组自己收成一个 inline-flex 项,
153
+ 免得标题变长时被换行拆成两截。颜色只走 --dsw-* 变量,明暗两套都跟着宿主。 */
154
+ .capital-config-plugin-links { flex: none; align-items: center; gap: 2px; display: inline-flex; }
155
+ .capital-config-plugin-link { border-radius: var(--dsw-radius-sm); width: 24px; height: 24px; color: var(--dsw-alias-label-tertiary); justify-content: center; align-items: center; display: inline-flex; text-decoration: none; }
156
+ .capital-config-plugin-link:hover { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); }
157
+ .capital-config-plugin-link:focus-visible { outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color, var(--dsw-alias-brand-primary)); outline-offset: 1px; }
133
158
  `
134
159
  document.head.appendChild(style)
135
160
  return () => style.remove()
@@ -365,6 +390,47 @@ function CapitalCard(props) {
365
390
  )
366
391
  }
367
392
 
393
+ /**
394
+ * 官方 primitives 的图标表里没有 GitHub / npm 字形(整表核过),所以两枚图标自带 path 数据,
395
+ * 取 simple-icons(CC0)。`fill="currentColor"` + 外层 `color: var(--dsw-*)` ⇒ 明暗两套都跟
396
+ * 宿主,功能 CSS 不写主题选择器。
397
+ */
398
+ const GLYPHS = {
399
+ github: 'M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12',
400
+ npm: 'M1.763 0C.786 0 0 .786 0 1.763v20.474C0 23.214.786 24 1.763 24h20.474c.977 0 1.763-.786 1.763-1.763V1.763C24 .786 23.214 0 22.237 0zM5.13 5.323l13.837.019-.009 13.836h-3.464l.01-10.382h-3.456L12.04 19.17H5.113z',
401
+ }
402
+
403
+ function PluginLink({ kind, href, label }) {
404
+ return h('a', {
405
+ className: 'capital-config-plugin-link',
406
+ href,
407
+ target: '_blank',
408
+ rel: 'noopener noreferrer',
409
+ 'aria-label': label,
410
+ title: label,
411
+ 'data-capital-plugin-link': kind,
412
+ }, h('svg', {
413
+ viewBox: '0 0 24 24',
414
+ width: 16,
415
+ height: 16,
416
+ fill: 'currentColor',
417
+ 'aria-hidden': 'true',
418
+ focusable: 'false',
419
+ }, h('path', { d: GLYPHS[kind] })))
420
+ }
421
+
422
+ /**
423
+ * 标题右侧的外链组。同一格座位在**行详情页**与**官方插件页**也会渲染,所以 `subject.kind`
424
+ * 与包名两道闸门都要过;不匹配就 `return null`(list 座位的"我对这个主题没话说")。
425
+ */
426
+ function PluginLinks({ subject, t }) {
427
+ if (subject?.kind !== 'bundle' || subject.pkg?.name !== BUNDLE_NAME) return null
428
+ return h('span', { className: 'capital-config-plugin-links' },
429
+ h(PluginLink, { kind: 'github', href: REPO_URL, label: t('githubLabel') }),
430
+ h(PluginLink, { kind: 'npm', href: NPM_URL, label: t('npmLabel') }),
431
+ )
432
+ }
433
+
368
434
  function apply(ctx) {
369
435
  ctx.effect(installStyles, 'capital-config: styles')
370
436
  ctx.effect(() => ctx.locale.register(LOCALE_NS, { zh, en }), 'capital-config: dictionaries')
@@ -380,7 +446,14 @@ function apply(ctx) {
380
446
  locale: LOCALE_NS,
381
447
  inject: () => card.inject(),
382
448
  }, CapitalCard))), 'capital-config: page')
383
- ctx.logger?.info?.('capital-config: settings card mounted')
449
+ // 外链与配置段是同一页面的两格,但**门控不同**:链接是这个插件的属性,Host 有没有在服务
450
+ // `capital-config` 这条配置条目与它无关,所以不进 whileServed。
451
+ ctx.effect(() => ctx.slots.inject(BADGE_SLOT, () => ctx.slots.register({
452
+ name: BADGE_SLOT,
453
+ id: `${ENTRY_ID}-plugin-links`,
454
+ locale: LOCALE_NS,
455
+ }, PluginLinks)), 'capital-config: plugin links')
456
+ ctx.logger?.info?.('capital-config: settings card + 标题外链 mounted')
384
457
  }
385
458
 
386
459
  exports.name = 'capital-config'
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@v587d/capital-config",
3
- "version": "2.6.2",
3
+ "version": "2.6.4",
4
4
  "description": "Capital 模式的取数凭据与偏好配置行:卡片坐在 @v587d/capital-generation 插件主页的「配置」段,点这一行本身没有表单。",
5
5
  "license": "MIT",
6
6
  "type": "module",