@danceiny/gotry 0.0.1-rc.19 → 0.0.1-rc.21
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/README.md +14 -3
- package/README.zh-CN.md +15 -4
- package/bin/gotry-bootstrap.js +136 -45
- package/bin/gotry-inner.js +11 -6
- package/cordis.gotry-patch.yml +19 -8
- package/dist/capabilities/anything.js +62 -29
- package/dist/capabilities/doctor.js +113 -19
- package/dist/capabilities/hbcli.js +28 -2
- package/dist/capabilities/session/health-watch.js +10 -3
- package/dist/scripts/agent-planning-turn-deadline-e2e.js +2 -1
- package/dist/scripts/anything-tests.js +70 -21
- package/dist/scripts/benchmark-environment-bridge-e2e.js +178 -33
- package/dist/scripts/benchmark-environment-bridge-tests.js +1480 -271
- package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +211 -2
- package/dist/scripts/booking-copilot-runtime-proof-tests.js +132 -2
- package/dist/scripts/bootstrap-tests.js +30 -3
- package/dist/scripts/doctor-tests.js +55 -1
- package/dist/scripts/hbcli-e2e-tests.js +1 -1
- package/dist/scripts/hbcli-tests.js +38 -1
- package/dist/scripts/health-watch-cli.js +9 -1
- package/dist/scripts/map-tools-vendor-package-proof.js +276 -0
- package/dist/scripts/persona-surface-guard-tests.js +8 -3
- package/dist/src/benchmark-agent-conformance.js +187 -17
- package/dist/src/benchmark-environment-bridge.js +287 -102
- package/dist/src/booking-surface/dsh-planner.js +24 -8
- package/dist/src/index.js +5 -2
- package/extension/manifest.json +2 -2
- package/package.json +3 -1
- package/ts/capabilities/anything.ts +89 -38
- package/ts/capabilities/hbcli.ts +53 -4
- package/ts/capabilities/session/health-watch.ts +9 -2
- package/ts/dsh-runtime/vendor/README.md +60 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/LICENSE +21 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +200 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +202 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/client/client.js +216 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/cordis.patch.yml +5 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/amap.js +371 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/nominatim.js +63 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/osrm.js +56 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/photon.js +55 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-file.js +87 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-route.js +126 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config.js +16 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/index.js +109 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +27 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/geocode.js +127 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/poi.js +84 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/routes.js +170 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/amap.d.ts +53 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/nominatim.d.ts +17 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/osrm.d.ts +15 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/photon.d.ts +22 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-file.d.ts +33 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-route.d.ts +20 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config.d.ts +23 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/index.d.ts +18 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +14 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/geocode.d.ts +11 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/poi.d.ts +9 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/routes.d.ts +16 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/types.d.ts +55 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types.js +16 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +91 -0
- package/ts/package.json +17 -1
- package/ts/scripts/map-tools-vendor-package-proof.ts +268 -0
- package/ts/src/benchmark-agent-conformance.ts +175 -13
- package/ts/src/benchmark-environment-bridge.ts +220 -66
- package/ts/src/booking-surface/dsh-planner.ts +25 -13
- package/ts/src/index.ts +4 -2
- package/ts/src/turn-deadline.ts +4 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="assets/banner.svg" width="100%" alt="dsh-map-tools — Map & routing tools for DeepSeek Harness" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# dsh-map-tools
|
|
6
|
+
|
|
7
|
+
<p align="center"><a href="README.en.md">English</a> | 中文</p>
|
|
8
|
+
|
|
9
|
+
<p align="center">地图与路径规划工具插件,为 <a href="https://github.com/deepseek-ai/deepseek-harness">DeepSeek Harness</a> 提供驾车/公交/步行/骑行路线规划、地理编码、逆地理编码和 POI 搜索等<strong>原生工具</strong>——模型可直接调用,无需 MCP 服务器。</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://www.npmjs.com/package/dsh-map-tools"><img src="https://img.shields.io/npm/v/dsh-map-tools?style=flat-square&label=npm&color=cb3837" alt="npm"></a>
|
|
13
|
+
<a href="https://www.npmjs.com/package/dsh-map-tools"><img src="https://img.shields.io/npm/dw/dsh-map-tools?style=flat-square&label=downloads&color=cb3837" alt="npm downloads"></a>
|
|
14
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue?style=flat-square" alt="License"></a>
|
|
15
|
+
<a href="https://github.com/HorusJiang/dsh-map-tools/actions/workflows/ci.yml"><img src="https://github.com/HorusJiang/dsh-map-tools/actions/workflows/ci.yml/badge.svg?style=flat-square" alt="CI"></a>
|
|
16
|
+
<a href="https://github.com/HorusJiang/dsh-map-tools/releases"><img src="https://img.shields.io/github/v/release/HorusJiang/dsh-map-tools?style=flat-square&label=release" alt="Release"></a>
|
|
17
|
+
<a href="https://github.com/topics/dsh-plugin"><img src="https://img.shields.io/badge/dsh--plugin-%E5%8F%AF%E5%AE%89%E8%A3%85-2A6BE8?style=flat-square" alt="dsh-plugin"></a>
|
|
18
|
+
<a href="https://github.com/awesome-dsh-plugin/awesome-dsh-plugin"><img src="https://img.shields.io/badge/dshmarket-%E6%94%B6%E5%BD%95-22C55E?style=flat-square&logo=shopify&logoColor=white" alt="dshmarket"></a>
|
|
19
|
+
<img src="https://img.shields.io/badge/node-%3E%3D20-339933?style=flat-square&logo=node.js&logoColor=white" alt="Node.js >= 20">
|
|
20
|
+
</p>
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 特性
|
|
25
|
+
|
|
26
|
+
- **7 个原生工具**:路线规划(驾车/公交/步行/骑行)、地理编码、逆地理编码、POI 搜索——模型通过 `map_*` 直接调用,无需 MCP。
|
|
27
|
+
- **高德数据源(推荐)**:配置免费的高德 Web 服务 key 后,使用国内最全的地图数据(含公交换乘、POI、稳定的中文地理编码)。
|
|
28
|
+
- **零 key 兜底**:不配置 key 时,驾车/步行/骑行路线自动走免费的 OSM/OSRM;中文地址解析不可靠时给出清晰引导。
|
|
29
|
+
- **开箱即用的配置卡片**:设置 → 插件 → dsh-map-tools,图形化配置,内置"如何获取高德 Key?"申请链接,保存即生效(无需重启)。
|
|
30
|
+
- **面向国内网络**:免费源不可达、key 无效等场景均有清晰的中文提示与补救路径。
|
|
31
|
+
|
|
32
|
+
## 安装
|
|
33
|
+
|
|
34
|
+
支持两种安装方式,二选一:
|
|
35
|
+
|
|
36
|
+
### 方式一:npm 安装(推荐,预构建免授权)
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
dsh plugin --profile web add dsh-map-tools
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 方式二:从 GitHub 安装(源码构建,需授权)
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
dsh plugin --profile web add github:HorusJiang/dsh-map-tools
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
> 发布包不含 `prepare`/`postinstall` 等构建脚本,pnpm ≥10 安装时**无需**放行构建脚本、也无需配置 `allowBuilds`。
|
|
49
|
+
|
|
50
|
+
> **版本要求**:自 0.5.0 起,本插件兼容 **DeepSeek Harness 0.1.2-rc.1 及以上**
|
|
51
|
+
> (含源码构建的 0.1.3-alpha.1)。更早的 Harness 发布线因
|
|
52
|
+
> `@deepseek-ai/dsh-settings` 移除旧 API 而不再支持。
|
|
53
|
+
|
|
54
|
+
安装后**重启 `dsh web`**(或等待 HMR 热加载),在会话中即可使用 `map_*` 工具。
|
|
55
|
+
|
|
56
|
+
> **开发模式**:在本地 clone 后使用 `dsh plugin add <本地路径>` 会以 `link:` 方式安装——改动源码即生效,适合插件迭代。
|
|
57
|
+
|
|
58
|
+
## 快速开始
|
|
59
|
+
|
|
60
|
+
配置高德 key(约 2 分钟):
|
|
61
|
+
|
|
62
|
+
1. 打开 [高德开放平台](https://console.amap.com/dev/key/app) → 创建应用 → 申请 **"Web 服务"** 类型 key(个人开发者免费)。
|
|
63
|
+
2. 在 DSH 的 **设置 → 插件 → dsh-map-tools** 填入 key,选择数据源 `amap`,保存。
|
|
64
|
+
3. 在会话中直接提问:
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
从北京南站到首都机场T3,规划驾车路线
|
|
68
|
+
把"西湖区文三路478号"转成经纬度
|
|
69
|
+
116.397428,39.90923 附近 1 公里内有什么加油站?
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## 工具
|
|
73
|
+
|
|
74
|
+
| 工具 | 功能 | 免费 OSM | 高德 |
|
|
75
|
+
|---|---|---|---|
|
|
76
|
+
| `map_driving_route` | 驾车路线规划 | ✅ | ✅ |
|
|
77
|
+
| `map_transit_route` | 公交/地铁换乘 | — | ✅ |
|
|
78
|
+
| `map_walking_route` | 步行路线规划 | ✅ | ✅ |
|
|
79
|
+
| `map_bicycling_route` | 骑行路线规划 | ✅ | ✅ |
|
|
80
|
+
| `map_geocode` | 地址 → 经纬度 | 中文不可靠 | ✅ |
|
|
81
|
+
| `map_reverse_geocode` | 经纬度 → 地址 | 中文不可靠 | ✅ |
|
|
82
|
+
| `map_poi_search` | 兴趣点搜索 | — | ✅ |
|
|
83
|
+
|
|
84
|
+
起点/终点统一接受 **地址文本** 或 **`"lng,lat"` 坐标** 两种形式,插件自动归一化。
|
|
85
|
+
|
|
86
|
+
## 配置
|
|
87
|
+
|
|
88
|
+
### 设置页配置卡片(推荐)
|
|
89
|
+
|
|
90
|
+
DSH 的 **设置 → 插件 → dsh-map-tools** 提供图形化卡片:数据源选择、高德 key 输入(脱敏显示)、超时设置、申请链接。保存后立即生效。
|
|
91
|
+
|
|
92
|
+
配置实际存储于 **`~/.dsh-map-tools/config.json`**(用户目录,权限 0600),与 DSH 设置文档解耦,跨 profile 共享:
|
|
93
|
+
|
|
94
|
+
```jsonc
|
|
95
|
+
// ~/.dsh-map-tools/config.json
|
|
96
|
+
{
|
|
97
|
+
"provider": "amap", // "amap" | "osm"
|
|
98
|
+
"amapKey": "你的高德Web服务key",
|
|
99
|
+
"timeoutMs": 15000
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
> key 只以布尔标记(`hasAmapKey`)呈现给前端,**永远不会回显到页面或日志**。
|
|
104
|
+
|
|
105
|
+
### cordis.yml 默认值
|
|
106
|
+
|
|
107
|
+
也可以在 profile 的 `cordis.yml` 中提供默认值(**配置文件中的值优先于 cordis.yml**):
|
|
108
|
+
|
|
109
|
+
```yaml
|
|
110
|
+
- id: map-tools
|
|
111
|
+
name: dsh-map-tools
|
|
112
|
+
config:
|
|
113
|
+
provider: amap
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## 架构
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
┌─ 模型 ──────────────────────────────────────┐
|
|
120
|
+
│ map_driving_route / map_geocode / ... │ 7 个原生工具(ctx.tools)
|
|
121
|
+
└──────────────┬───────────────────────────────┘
|
|
122
|
+
│
|
|
123
|
+
┌──────────────▼───────────────────────────────┐
|
|
124
|
+
│ src/tools/ 工具定义(参数校验/输出渲染) │
|
|
125
|
+
│ src/clients/ 数据源客户端 │
|
|
126
|
+
│ amap.ts 高德 Web 服务 API(推荐) │
|
|
127
|
+
│ osrm.ts OSRM 免费路线(兜底) │
|
|
128
|
+
│ photon.ts Photon 免费地理编码(兜底) │
|
|
129
|
+
│ nominatim.ts Nominatim 免费地理编码(兜底) │
|
|
130
|
+
└──────────────┬───────────────────────────────┘
|
|
131
|
+
│
|
|
132
|
+
┌──────────────▼───────────────────────────────┐
|
|
133
|
+
│ src/config-file.ts ~/.dsh-map-tools/config.json(0600) │
|
|
134
|
+
│ src/config-route.ts 回环路由 /dsh-map-tools/config │
|
|
135
|
+
│ src/settings-ns.ts 设置页 namespace 注册 │
|
|
136
|
+
│ client/client.js 设置页配置卡片(前端,手写零依赖) │
|
|
137
|
+
└──────────────────────────────────────────────┘
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
- **配置优先级**:配置文件(设置卡片写入)→ `cordis.yml` 默认值。
|
|
141
|
+
- **保存即生效**:配置变更后工具自动重建,无需重启。
|
|
142
|
+
- **无 MCP**:全部能力为原生工具,不依赖外部 MCP 服务器进程。
|
|
143
|
+
|
|
144
|
+
## 数据源
|
|
145
|
+
|
|
146
|
+
| 数据源 | 用途 | Key | 备注 |
|
|
147
|
+
|---|---|---|---|
|
|
148
|
+
| 高德(Amap) | 全部工具(推荐) | 免费申请 | 国内数据最全,含公交/POI/中文地理编码 |
|
|
149
|
+
| OSRM | 驾车/步行/骑行路线 | 无 | 免费公开服务,有频率限制 |
|
|
150
|
+
| Photon / Nominatim | 地理编码 | 无 | 免费公开服务;**中文地址解析不可靠**,部分网络不可达 |
|
|
151
|
+
|
|
152
|
+
> 免费源的局限(中文地理编码不稳定)是刻意设计:不配 key 时给出明确引导,配 key 后体验无缝升级。
|
|
153
|
+
|
|
154
|
+
## FAQ
|
|
155
|
+
|
|
156
|
+
**Q: 配置了高德 key,但路线还是走 OSM?**
|
|
157
|
+
A: 检查配置文件的 `provider` 是否为 `amap`(不是 `osm`),且 `amapKey` 非空。
|
|
158
|
+
|
|
159
|
+
**Q: 为什么公交换乘/POI 搜索提示需要 key?**
|
|
160
|
+
A: OSM 免费源不提供公交换乘与 POI 数据;这两项能力需要高德 key。
|
|
161
|
+
|
|
162
|
+
**Q: 高德 key 无效怎么办?**
|
|
163
|
+
A: 确认申请的是 **"Web 服务"** 类型 key(不是 JS API / Web 端 key),并在高德控制台确认已启用相应服务。
|
|
164
|
+
|
|
165
|
+
**Q: 中文地址解析报"免费数据源不可用"?**
|
|
166
|
+
A: 免费源(Photon/Nominatim)对中文地址支持差,且部分国内网络不可达。这是设计行为——配置高德 key 后自动解决。
|
|
167
|
+
|
|
168
|
+
## 开发
|
|
169
|
+
|
|
170
|
+
```sh
|
|
171
|
+
pnpm install
|
|
172
|
+
pnpm run build # tsc 构建到 lib/
|
|
173
|
+
pnpm test # vitest 单元测试(mock 网络)
|
|
174
|
+
node scripts/smoke.mjs # 冒烟:7 工具注册
|
|
175
|
+
node scripts/integration.mjs # 集成:真实网络请求(免费源)
|
|
176
|
+
node scripts/amap-e2e.mjs # 高德 e2e:需设置 AMAP_API_KEY
|
|
177
|
+
node scripts/config-e2e.mjs # 配置读写回环验证
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
详细约定见 [CONTRIBUTING.md](CONTRIBUTING.md) 与 [AGENTS.md](AGENTS.md)。
|
|
181
|
+
|
|
182
|
+
## 发布
|
|
183
|
+
|
|
184
|
+
```sh
|
|
185
|
+
npm config set registry https://registry.npmjs.org/
|
|
186
|
+
npm login # 需要 npm 账号(建议配置 bypass-2FA 的发布 token)
|
|
187
|
+
node scripts/publish.mjs # 一键:构建 → 打包检查 → 发布 → 验证
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
版本语义遵循 [SemVer](https://semver.org/lang/zh-CN/),变更记录见 [CHANGELOG.md](CHANGELOG.md)。
|
|
191
|
+
|
|
192
|
+
## 安全
|
|
193
|
+
|
|
194
|
+
API key 存储与漏洞报告流程见 [SECURITY.md](SECURITY.md)。
|
|
195
|
+
|
|
196
|
+
## 贡献
|
|
197
|
+
|
|
198
|
+
欢迎 Issue 与 PR!请阅读 [CONTRIBUTING.md](CONTRIBUTING.md) 了解开发约定与提交规范。
|
|
199
|
+
|
|
200
|
+
## 许可
|
|
201
|
+
|
|
202
|
+
[MIT](LICENSE) © HorusJiang
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-map-tools browser half: the 设置 → 插件 configuration card.
|
|
3
|
+
*
|
|
4
|
+
* Hand-written lazy-CJS bundle (window.__ModuleLoader__.load), zero build
|
|
5
|
+
* step, zero imports from dsh client packages beyond react + ui-primitives —
|
|
6
|
+
* the same stance as the modlens client half. Data flows through the host
|
|
7
|
+
* loopback route /dsh-map-tools/config, never through the DSH settings
|
|
8
|
+
* document: keys are stored in ~/.dsh-map-tools/config.json and never echoed
|
|
9
|
+
* back to the card (only hasAmapKey boolean).
|
|
10
|
+
*/
|
|
11
|
+
window.__ModuleLoader__.load({
|
|
12
|
+
id: 'dsh-map-tools',
|
|
13
|
+
factory: (require) => {
|
|
14
|
+
var module = { exports: {} }
|
|
15
|
+
var exports = module.exports
|
|
16
|
+
|
|
17
|
+
/** Whether the host route is mounted (a 404 or network failure = absent). */
|
|
18
|
+
function hostRoutePresent() {
|
|
19
|
+
return fetch('/dsh-map-tools/config').then((response) => {
|
|
20
|
+
if (response.status === 404) return false
|
|
21
|
+
return response.ok || response.status === 405 || response.status === 200
|
|
22
|
+
}).catch(() => false)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function registerCard(ctx) {
|
|
26
|
+
if (typeof ctx.inject !== 'function') return
|
|
27
|
+
ctx.inject(['slots'], (scope) => {
|
|
28
|
+
hostRoutePresent().then((present) => {
|
|
29
|
+
if (!present) return
|
|
30
|
+
try {
|
|
31
|
+
mountCard(scope)
|
|
32
|
+
} catch (error) {
|
|
33
|
+
console.error(`[dsh-map-tools] settings card skipped: ${error}`)
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function mountCard(ctx) {
|
|
40
|
+
var react
|
|
41
|
+
try {
|
|
42
|
+
react = require('react')
|
|
43
|
+
} catch (error) {
|
|
44
|
+
console.error(`[dsh-map-tools] settings card skipped: ${error}`)
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
var ui = require('@deepseek-ai/dsh-client-ui-primitives')
|
|
48
|
+
var Card = ConfigCard(react, ui)
|
|
49
|
+
ctx.slots.inject('settings.plugin.item', function* () {
|
|
50
|
+
yield ctx.slots.register({ name: 'settings.plugin.item', id: 'map-tools', key: 'dsh-map-tools', order: 25 }, Card)
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function ConfigCard(react, ui) {
|
|
55
|
+
var h = react.createElement
|
|
56
|
+
var Input = ui.Input
|
|
57
|
+
var AMAP_URL = 'https://console.amap.com/dev/key/app'
|
|
58
|
+
var PROVIDERS = [
|
|
59
|
+
{ id: 'amap', label: '高德地图(推荐)' },
|
|
60
|
+
{ id: 'osm', label: '免费 OSM(无需 key,能力有限)' },
|
|
61
|
+
]
|
|
62
|
+
|
|
63
|
+
function maskProps() {
|
|
64
|
+
// Hidden characters without being a password field: keeps the key out
|
|
65
|
+
// of Safari's keychain offer (same trade the modlens card makes).
|
|
66
|
+
var p = { autoComplete: 'off' }
|
|
67
|
+
if (typeof CSS !== 'undefined' && 'textSecurity' in document.documentElement.style) {
|
|
68
|
+
p.style = { textSecurity: 'disc', WebkitTextSecurity: 'disc' }
|
|
69
|
+
} else {
|
|
70
|
+
p.type = 'password'
|
|
71
|
+
}
|
|
72
|
+
return p
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function Chevron(open) {
|
|
76
|
+
return h('svg', {
|
|
77
|
+
width: 16, height: 16, viewBox: '0 0 16 16',
|
|
78
|
+
style: { color: 'var(--dsw-alias-label-tertiary, rgba(127,127,127,0.8))', flex: 'none', transition: 'transform .16s', transform: open ? 'rotate(180deg)' : 'none' },
|
|
79
|
+
}, h('path', { d: 'M4 6l4 4 4-4', fill: 'none', stroke: 'currentColor', strokeWidth: 1.5, strokeLinecap: 'round', strokeLinejoin: 'round' }))
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function ApplyLink(url, text) {
|
|
83
|
+
return h('a', { href: url, target: '_blank', rel: 'noreferrer', style: { color: 'var(--dsw-alias-accent, #4f8cff)', fontSize: '12px', textDecoration: 'none' } }, text)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return function MapToolsCard() {
|
|
87
|
+
var openState = react.useState(false)
|
|
88
|
+
var summaryState = react.useState(null)
|
|
89
|
+
var draftState = react.useState(null)
|
|
90
|
+
var noteState = react.useState('')
|
|
91
|
+
var savingState = react.useState(false)
|
|
92
|
+
var open = openState[0]
|
|
93
|
+
var summary = summaryState[0]
|
|
94
|
+
var draft = draftState[0]
|
|
95
|
+
var note = noteState[0]
|
|
96
|
+
var saving = savingState[0]
|
|
97
|
+
|
|
98
|
+
var load = react.useCallback(() => {
|
|
99
|
+
fetch('/dsh-map-tools/config').then((r) => r.json()).then((data) => {
|
|
100
|
+
summaryState[1](data)
|
|
101
|
+
draftState[1]({
|
|
102
|
+
provider: data.provider || 'amap',
|
|
103
|
+
amapKey: '',
|
|
104
|
+
timeoutMs: data.timeoutMs || 15000,
|
|
105
|
+
})
|
|
106
|
+
}).catch(() => {})
|
|
107
|
+
}, [])
|
|
108
|
+
|
|
109
|
+
react.useEffect(() => {
|
|
110
|
+
// Load the summary on mount (not only on expand) so the collapsed
|
|
111
|
+
// header shows the provider status immediately instead of "加载中…".
|
|
112
|
+
if (summary === null) load()
|
|
113
|
+
}, [summary, load])
|
|
114
|
+
|
|
115
|
+
var save = function () {
|
|
116
|
+
if (!draft) return
|
|
117
|
+
savingState[1](true)
|
|
118
|
+
var payload = {}
|
|
119
|
+
if (draft.provider !== summary.provider) payload.provider = draft.provider
|
|
120
|
+
if (draft.amapKey !== '') payload.amapKey = draft.amapKey
|
|
121
|
+
if (draft.timeoutMs && draft.timeoutMs !== summary.timeoutMs) payload.timeoutMs = draft.timeoutMs
|
|
122
|
+
fetch('/dsh-map-tools/config', {
|
|
123
|
+
method: 'POST',
|
|
124
|
+
headers: { 'content-type': 'application/json' },
|
|
125
|
+
body: JSON.stringify(payload),
|
|
126
|
+
}).then((r) => r.json()).then((data) => {
|
|
127
|
+
summaryState[1](data)
|
|
128
|
+
noteState[1]('已保存 — 工具已重建,直接可用')
|
|
129
|
+
savingState[1](false)
|
|
130
|
+
}).catch((error) => {
|
|
131
|
+
noteState[1](`保存失败:${String(error?.message ?? error)}`)
|
|
132
|
+
savingState[1](false)
|
|
133
|
+
})
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
var discard = function () {
|
|
137
|
+
draftState[1](null)
|
|
138
|
+
noteState[1]('')
|
|
139
|
+
summaryState[1](null)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
var cardStyle = {
|
|
143
|
+
border: '1px solid var(--dsw-alias-border-l2, rgba(127,127,127,0.35))',
|
|
144
|
+
borderRadius: '12px',
|
|
145
|
+
marginBottom: '8px', overflow: 'hidden',
|
|
146
|
+
transition: 'border-color .16s, background .16s',
|
|
147
|
+
}
|
|
148
|
+
var rowStyle = { padding: '14px 16px', display: 'flex', alignItems: 'center', gap: '12px' }
|
|
149
|
+
var fieldStyle = { display: 'flex', flexDirection: 'column', gap: '6px', padding: '4px 14px 10px' }
|
|
150
|
+
var labelStyle = { fontSize: '12px', color: 'var(--dsw-alias-label-secondary, rgba(127,127,127,0.9))' }
|
|
151
|
+
|
|
152
|
+
return h('div', { style: Object.assign({}, cardStyle, {
|
|
153
|
+
background: open ? 'var(--dsw-alias-bg-layer-2, rgba(127,127,127,0.10))' : 'var(--dsw-alias-bg-layer-3, rgba(127,127,127,0.05))',
|
|
154
|
+
}) },
|
|
155
|
+
h('button', {
|
|
156
|
+
type: 'button',
|
|
157
|
+
'aria-expanded': open,
|
|
158
|
+
style: { ...rowStyle, width: '100%', background: 'none', border: 'none', cursor: 'pointer', color: 'inherit', textAlign: 'left' },
|
|
159
|
+
onClick: function () { openState[1](!open) },
|
|
160
|
+
},
|
|
161
|
+
h('div', { style: { flex: '1', minWidth: '0' } },
|
|
162
|
+
h('div', { style: { fontSize: '14px', fontWeight: 600 } }, '地图引擎 (dsh-map-tools)'),
|
|
163
|
+
h('div', { style: { fontSize: '13px', lineHeight: 1.5, color: 'var(--dsw-alias-label-tertiary, rgba(127,127,127,0.8))' } }, '地图定位与路径规划:驾车/公交/步行/骑行路线、地理编码、POI 搜索'),
|
|
164
|
+
),
|
|
165
|
+
h('span', { style: { flex: 'none', fontSize: '12px', color: 'var(--dsw-alias-label-tertiary, rgba(127,127,127,0.8))' } },
|
|
166
|
+
summary ? (summary.provider ? (summary.provider === 'amap' ? '高德' : 'OSM') : '未配置') + (summary.hasAmapKey ? ' ✓' : '') : ''),
|
|
167
|
+
Chevron(open),
|
|
168
|
+
),
|
|
169
|
+
open && h('div', {},
|
|
170
|
+
h('div', { style: { padding: '0 14px 10px', fontSize: '12px', color: 'var(--dsw-alias-label-secondary, rgba(127,127,127,0.9))' } },
|
|
171
|
+
'地图定位与路径规划:驾车/公交/步行/骑行路线、地理编码、POI 搜索。配置数据存于 ~/.dsh-map-tools/config.json。'),
|
|
172
|
+
h('div', { style: fieldStyle },
|
|
173
|
+
h('span', { style: labelStyle }, '数据源'),
|
|
174
|
+
h('select', {
|
|
175
|
+
value: draft ? draft.provider : 'amap',
|
|
176
|
+
onChange: function (e) { draftState[1]({ ...(draft || {}), provider: e.target.value }) },
|
|
177
|
+
style: { padding: '6px 8px', borderRadius: '6px', border: '1px solid var(--dsw-alias-border, rgba(127,127,127,0.25))', background: 'var(--dsw-alias-bg-elevated, #262626)', color: 'inherit' },
|
|
178
|
+
}, PROVIDERS.map(function (p) { return h('option', { key: p.id, value: p.id }, p.label) })),
|
|
179
|
+
),
|
|
180
|
+
h('div', { style: fieldStyle },
|
|
181
|
+
h('span', { style: labelStyle }, '高德 key(Web 服务) — ', ApplyLink(AMAP_URL, '如何获取高德 Key?')),
|
|
182
|
+
h(Input, {
|
|
183
|
+
...maskProps(),
|
|
184
|
+
placeholder: summary && summary.hasAmapKey ? '已配置(留空保持不变)' : 'amapKey',
|
|
185
|
+
value: draft ? draft.amapKey : '',
|
|
186
|
+
onChange: function (e) { draftState[1]({ ...(draft || {}), amapKey: e.target.value }) },
|
|
187
|
+
}),
|
|
188
|
+
),
|
|
189
|
+
h('div', { style: fieldStyle },
|
|
190
|
+
h('span', { style: labelStyle }, '超时(毫秒)'),
|
|
191
|
+
h(Input, {
|
|
192
|
+
inputMode: 'numeric',
|
|
193
|
+
value: draft ? String(draft.timeoutMs) : '15000',
|
|
194
|
+
onChange: function (e) { draftState[1]({ ...(draft || {}), timeoutMs: Number(e.target.value) || 15000 }) },
|
|
195
|
+
}),
|
|
196
|
+
),
|
|
197
|
+
note && h('div', { style: { padding: '0 14px 8px', fontSize: '12px', color: note.indexOf('失败') >= 0 ? '#e05c5c' : 'var(--dsw-alias-label-secondary, rgba(127,127,127,0.9))' } }, note),
|
|
198
|
+
h('div', { style: { ...rowStyle, justifyContent: 'flex-end', borderTop: '1px solid var(--dsw-alias-border, rgba(127,127,127,0.2))' } },
|
|
199
|
+
h('button', { type: 'button', onClick: discard, disabled: saving, style: { background: 'none', border: 'none', cursor: 'pointer', color: 'var(--dsw-alias-label-secondary, rgba(127,127,127,0.9))', fontSize: '13px' } }, '放弃'),
|
|
200
|
+
h('button', { type: 'button', onClick: save, disabled: saving || !draft, style: { background: 'var(--dsw-alias-accent, #4f8cff)', color: '#fff', border: 'none', borderRadius: '6px', padding: '6px 14px', cursor: 'pointer', fontSize: '13px' } }, saving ? '保存中…' : '保存'),
|
|
201
|
+
),
|
|
202
|
+
),
|
|
203
|
+
)
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function apply(ctx) {
|
|
208
|
+
registerCard(ctx)
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
exports.apply = apply
|
|
212
|
+
exports.inject = []
|
|
213
|
+
exports.__card = { ConfigCard: ConfigCard }
|
|
214
|
+
return module.exports
|
|
215
|
+
},
|
|
216
|
+
})
|