@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
package/README.md
CHANGED
|
@@ -7,13 +7,14 @@
|
|
|
7
7
|
|
|
8
8
|
GoTry is an AI travel agent for **"departure to next departure."** You tell it where you want to go and why; it interviews you about your working hours and existing bookings, then hands you a **formally verified itinerary** — computed by a Z3 solver, not guessed by a model.
|
|
9
9
|
|
|
10
|
+
[](https://github.com/Danceiny/gotry/stargazers)
|
|
10
11
|
[](https://github.com/Danceiny/gotry/actions/workflows/ci.yml)
|
|
11
12
|
[](https://www.npmjs.com/package/@danceiny/gotry)
|
|
12
13
|
[](LICENSE)
|
|
13
14
|
[](https://www.npmjs.com/package/@danceiny/gotry)
|
|
14
15
|
[](docs/architecture.md)
|
|
15
16
|
|
|
16
|
-
**[What GoTry Does](#what-gotry-does)** · **[How It Works](#how-it-works)** · **[Tools](#tools)** · **[Demo](#demo)** · **[Benchmark](#how-mainstream-ai-answers-the-same-trip)** · **[Quick Start](#quick-start)** · **[Consent and Privacy](#consent-and-privacy)** · **[Trustworthy by Construction](#trustworthy-by-construction)** · **[Project Status](#project-status)** · **[Roadmap](#roadmap)** · **[For AI Agents](#for-ai-agents)** · **[Documentation](#documentation)** · **[License](#license)**
|
|
17
|
+
**[What GoTry Does](#what-gotry-does)** · **[How It Works](#how-it-works)** · **[Tools](#tools)** · **[Demo](#demo)** · **[Benchmark](#how-mainstream-ai-answers-the-same-trip)** · **[Quick Start](#quick-start)** · **[Consent and Privacy](#consent-and-privacy)** · **[Trustworthy by Construction](#trustworthy-by-construction)** · **[Project Status](#project-status)** · **[Roadmap](#roadmap)** · **[For AI Agents](#for-ai-agents)** · **[Documentation](#documentation)** · **[License](#license)** · **[Star History](#star-history)**
|
|
17
18
|
|
|
18
19
|
> **Tip for newcomers:** one command is enough to feel the difference — `npx @danceiny/gotry web`, open `http://127.0.0.1:3080`, and say *"I want three relaxing days in Dali."* The agent interviews you first; then the solver, not the model, decides what is feasible. Full walkthrough: [`docs/user-guide.md`](docs/user-guide.md).
|
|
19
20
|
|
|
@@ -194,7 +195,7 @@ Current release: **v0.0.1-rc.18** (npm `latest` and `rc` both point here; regist
|
|
|
194
195
|
|
|
195
196
|
- **Z3 solving engine** — feasibility verdicts + door-to-door whole-cost; the historical concurrency race is fixed and regression-gated
|
|
196
197
|
- **Realtime retrieval** — flights/trains/hotels (Fliggy official channel), destination/hotel catalogs, weather, live flight observation, route connectivity; realtime prices can overwrite solver prices (`GOTRY_REALTIME_PRICING=1`); exhausted FlyAI anonymous trial quota is classified `needs-setup` with key guidance (no blind retries)
|
|
197
|
-
- **Dependency doctor** — `npx gotry doctor` (CLI) / `gotry_doctor` (in-chat tool): read-only health check of optional dependencies (extension / Agent-Reach / hbcli / FlyAI key / sidebar / dsh-calendar mount / dsh-map-tools & dsh-tool-ask-user presence) with exact repair guidance; `--fix` installs; LLM keys stay with the dsh host
|
|
198
|
+
- **Dependency doctor** — `npx gotry doctor` (CLI) / `gotry_doctor` (in-chat tool): read-only health check of optional dependencies (extension / Agent-Reach / hbcli / FlyAI key / sidebar / dsh-calendar mount / dsh-map-tools & dsh-tool-ask-user presence) with exact repair guidance; map tools ship as a bundled MIT payload rather than an incompatible external npm peer; `--fix` installs; LLM keys stay with the dsh host
|
|
198
199
|
- **Account-session search** — Ctrip flights **and hotels** + 12306 trains on your Chrome (hotels 2026-09-03: real logged-in prices via passive sniffing; trains 2026-09-03: public left-ticket query; interface surfaces calibrate with the first live session); observed runs scored every landed hit 13/13 with zero write attempts, while non-hits stay explicit `miss` records — no live-availability claim beyond that
|
|
199
200
|
- **Extension install on demand** — `[GoTry Session Bridge](https://chromewebstore.google.com/detail/gotry-session-bridge/oeajpiccmonococjcegddlooeeohlbgd)` is offered as a clickable link in the dsh UI when an account-session tool first needs it (one-click install + auto-update); the gotry side never runs a setup wizard
|
|
200
201
|
- **Memory & reachability** — motivation profile / wish pool / companions / travel timeline; English solve output via `GOTRY_LOCALE=en`
|
|
@@ -205,7 +206,7 @@ Current release: **v0.0.1-rc.18** (npm `latest` and `rc` both point here; regist
|
|
|
205
206
|
- **M3 Exit not closed** — engineering & distribution are ready, but real seed-user evidence (50–200 person cohort) has not been accumulated; automated tests prove contracts and formulas, not business pass
|
|
206
207
|
- **Hotel session adapters** — Ctrip-hotel / Meituan logged-in surfaces await real login-state backfill; flights are done
|
|
207
208
|
- **Interface language** — English covers the deterministic solve-output layer; the dsh host UI and dialogue surface belong to the host / calibration samples
|
|
208
|
-
- **External benchmark generalization** — every frozen external run to date remains diagnostic-only (no score, no uplift claim); the round-by-round engineering ledger lives in [`docs/evaluation/benchmark-environment-bridge.md`](docs/evaluation/benchmark-environment-bridge.md)
|
|
209
|
+
- **External benchmark generalization** — every frozen external run to date remains diagnostic-only (no score, no uplift claim). After the Round 10 `glm-5.3-flash` visibility diagnosis on main `c843fae` (57 empty `{}` calls), Round 11 keeps execution validation exact against frozen descriptors while exposing a flat model-facing `tools/call/errors` wire with descriptor-derived tool names and generic object arguments; the round-by-round engineering ledger lives in [`docs/evaluation/benchmark-environment-bridge.md`](docs/evaluation/benchmark-environment-bridge.md)
|
|
209
210
|
- **Booking** — nothing bookable ships today; M5 opens only through WriteGate and the booking-saga FSM
|
|
210
211
|
|
|
211
212
|
<details>
|
|
@@ -280,6 +281,16 @@ Program-level context: [`docs/gotry-master-outline.md`](docs/gotry-master-outlin
|
|
|
280
281
|
|
|
281
282
|
**MIT** — same as upstream dsh. See [LICENSE](LICENSE).
|
|
282
283
|
|
|
284
|
+
## Star History
|
|
285
|
+
|
|
286
|
+
<a href="https://www.star-history.com/?repos=danceiny%2Fgotry&type=date&legend=top-left">
|
|
287
|
+
<picture>
|
|
288
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=danceiny/gotry&type=date&theme=dark&legend=top-left" />
|
|
289
|
+
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=danceiny/gotry&type=date&legend=top-left" />
|
|
290
|
+
<img alt="Star History Chart" src="https://api.star-history.com/chart?repos=danceiny/gotry&type=date&legend=top-left" />
|
|
291
|
+
</picture>
|
|
292
|
+
</a>
|
|
293
|
+
|
|
283
294
|
---
|
|
284
295
|
|
|
285
296
|
**Built with**: DeepSeek Harness 0.1.2-alpha.3 (root-pinned) · Cordis · Z3 (WASM) · loopx (pipx) · hotelbyte-cli · Agent-Reach v1.5.0 · OpenFlights · TypeScript
|
package/README.zh-CN.md
CHANGED
|
@@ -7,13 +7,14 @@
|
|
|
7
7
|
|
|
8
8
|
**GoTry 是「从出发到下一次出发」的 AI 旅行 Agent**:你用一句话说想去哪、为什么想出发;它先问清楚你的工作窗口和已订资源,再用 **Z3 数学求解器**给你一份经过形式化验证的行程方案——是算出来的,不是模型猜的。
|
|
9
9
|
|
|
10
|
+
[](https://github.com/Danceiny/gotry/stargazers)
|
|
10
11
|
[](https://github.com/Danceiny/gotry/actions/workflows/ci.yml)
|
|
11
12
|
[](https://www.npmjs.com/package/@danceiny/gotry)
|
|
12
13
|
[](LICENSE)
|
|
13
14
|
[](https://www.npmjs.com/package/@danceiny/gotry)
|
|
14
15
|
[](docs/architecture.md)
|
|
15
16
|
|
|
16
|
-
**[它做什么](#它做什么)** · **[工作原理](#工作原理)** · **[工具](#工具)** · **[一段对话](#一段对话)** · **[同题横评](#与主流-ai-同题横评产品人格从哪来)** · **[快速开始](#快速开始)** · **[账号会话:授权与隐私](#账号会话授权与隐私)** · **[构造上可信](#构造上可信)** · **[状态与限制](#状态与限制)** · **[路线图](#路线图)** · **[给 AI Agent](#给-ai-agent)** · **[文档](#文档)** · **[License](#license)**
|
|
17
|
+
**[它做什么](#它做什么)** · **[工作原理](#工作原理)** · **[工具](#工具)** · **[一段对话](#一段对话)** · **[同题横评](#与主流-ai-同题横评产品人格从哪来)** · **[快速开始](#快速开始)** · **[账号会话:授权与隐私](#账号会话授权与隐私)** · **[构造上可信](#构造上可信)** · **[状态与限制](#状态与限制)** · **[路线图](#路线图)** · **[给 AI Agent](#给-ai-agent)** · **[文档](#文档)** · **[License](#license)** · **[Star History](#star-history)**
|
|
17
18
|
|
|
18
19
|
> **新读者提示**:一条命令就能感受差别——`npx @danceiny/gotry web`,打开 `http://127.0.0.1:3080`,说一句「我想去大理躺三天」。Agent 会先访谈你;然后由求解器(而非模型)判定什么可行。完整走查见 [`docs/user-guide.md`](docs/user-guide.md)。
|
|
19
20
|
|
|
@@ -143,7 +144,7 @@ npx @danceiny/gotry web
|
|
|
143
144
|
|---|---|---|
|
|
144
145
|
| Web 对话(推荐) | `npx @danceiny/gotry web` | 持续多轮规划,看推理可视化 → `:3080` |
|
|
145
146
|
| headless 一问一答 | `npx @danceiny/gotry "我想从深圳休整两天,预算 3000"` | 脚本 / CI / 定向调试 → stdout |
|
|
146
|
-
| 依赖体检 | `npx @danceiny/gotry doctor`(`--fix` 补装) | 可选渠道不好使时:体检扩展 / Agent-Reach / hbcli / FlyAI key / sidebar,逐项给精确修复指引,报告落 `gotry-state/doctor-report.md`(侧栏工作台可预览) |
|
|
147
|
+
| 依赖体检 | `npx @danceiny/gotry doctor`(`--fix` 补装) | 可选渠道不好使时:体检扩展 / Agent-Reach / hbcli / FlyAI key / sidebar / dsh-calendar / dsh-map-tools / dsh-tool-ask-user,逐项给精确修复指引,报告落 `gotry-state/doctor-report.md`(侧栏工作台可预览) |
|
|
147
148
|
|
|
148
149
|
前置:Node ≥ 22.15。LLM 凭证由 dsh 宿主 UI 配,OpenAI 兼容端点(MiniMax/中转/自建网关)走 dsh 的模型设置。首启 6–15 秒属正常冷启动;`:3080` 被占先腾端口;异常退出会留证据到 `gotry-state/incidents.jsonl`(不静默)。
|
|
149
150
|
|
|
@@ -190,7 +191,7 @@ node scripts/build-dist.mjs # 构建 JS runtime
|
|
|
190
191
|
|
|
191
192
|
- **Z3 求解引擎** —— 可行性判决 + 门到门全成本;历史并发竞态已根治并进回归闸
|
|
192
193
|
- **实时检索** —— 机票/火车/酒店(飞猪官方通道)、目的地/酒店目录、天气、航班观测、通航性校验;实时票价可覆写求解价(`GOTRY_REALTIME_PRICING=1`);飞猪匿名试用额度达限归类 `needs-setup` 并带配 key 指引(不盲重试)
|
|
193
|
-
- **依赖体检** —— `npx gotry doctor`(CLI)/ `gotry_doctor`(对话内工具):可选依赖(扩展 / Agent-Reach / hbcli / FlyAI key / sidebar)只读体检 +
|
|
194
|
+
- **依赖体检** —— `npx gotry doctor`(CLI)/ `gotry_doctor`(对话内工具):可选依赖(扩展 / Agent-Reach / hbcli / FlyAI key / sidebar / dsh-calendar / dsh-map-tools / dsh-tool-ask-user)只读体检 + 精确补装指引;地图工具以 MIT payload 随包交付,不再引入与 alpha.3 冲突的外部 npm peer;`--fix` 补装;LLM key 仍归 dsh 宿主管
|
|
194
195
|
- **账号会话检索** —— 你本人登录态查携程机票/酒店 + 12306 火车(酒/火 2026-09-03 实装:酒店为被动嗅探登录态真实价,火车为 12306 公开余票查询面;接口面随首个真会话校准);观测轮次中所有可评分 hit 全过、ReadGuard 零写,非 hit 保持显式 `miss` 记录——不作超出此口径的实时可售声明
|
|
195
196
|
- **扩展按需装** —— `[GoTry Session Bridge](https://chromewebstore.google.com/detail/gotry-session-bridge/oeajpiccmonococjcegddlooeeohlbgd)` 由 dsh 宿主 UI 在账号会话工具首次需要时以可点链接给出(Chrome 商店一键装 + 自动更新);gotry 这边不跑 setup wizard、不开 chrome://extensions、不动剪贴板
|
|
196
197
|
- **记忆与触达** —— 动机画像 / 愿望池 / 同行人 / 旅行时间线;英文输出一键切换(`GOTRY_LOCALE=en`)
|
|
@@ -201,7 +202,7 @@ node scripts/build-dist.mjs # 构建 JS runtime
|
|
|
201
202
|
- **M3 Exit 未关闭** —— 工程与分发面就绪,但真实种子用户证据(50–200 人 cohort)尚未积累;自动化测试证明的是合同与公式,不是 business pass
|
|
202
203
|
- **酒店会话适配** —— 携程酒店/美团登录态面等实测回填;机票已通
|
|
203
204
|
- **界面语言** —— 英文仅覆盖求解确定性输出层;dsh 宿主界面与对话面属宿主/校准件
|
|
204
|
-
- **外部 benchmark 泛化** —— 迄今所有冻结外部运行均仅 diagnostic
|
|
205
|
+
- **外部 benchmark 泛化** —— 迄今所有冻结外部运行均仅 diagnostic(无分数、无 uplift 声明)。Round 10 的 `glm-5.3-flash`(main `c843fae`)已诊断为可见性失败(57 次空 `{}` 调用);Round 11 仅把模型面对的 wire 展平为 `tools/call/errors`、descriptor 派生工具名枚举和 generic object 参数,执行时仍对冻结 descriptor 做 exact 校验;逐轮工程台账见 [`docs/evaluation/benchmark-environment-bridge.md`](docs/evaluation/benchmark-environment-bridge.md)
|
|
205
206
|
- **预订** —— 今天没有任何可下单路径;M5 只经 WriteGate 与 booking-saga 状态机启封
|
|
206
207
|
|
|
207
208
|
<details>
|
|
@@ -276,6 +277,16 @@ npx tsx scripts/evaluation-cadence-tests.ts # 确定性节奏策略/planner
|
|
|
276
277
|
|
|
277
278
|
**MIT**——与上游 dsh 一致。文本见 [LICENSE](LICENSE)。
|
|
278
279
|
|
|
280
|
+
## Star History
|
|
281
|
+
|
|
282
|
+
<a href="https://www.star-history.com/?repos=danceiny%2Fgotry&type=date&legend=top-left">
|
|
283
|
+
<picture>
|
|
284
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=danceiny/gotry&type=date&theme=dark&legend=top-left" />
|
|
285
|
+
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=danceiny/gotry&type=date&legend=top-left" />
|
|
286
|
+
<img alt="Star History Chart" src="https://api.star-history.com/chart?repos=danceiny/gotry&type=date&legend=top-left" />
|
|
287
|
+
</picture>
|
|
288
|
+
</a>
|
|
289
|
+
|
|
279
290
|
---
|
|
280
291
|
|
|
281
292
|
**Built with**: DeepSeek Harness 0.1.2-alpha.3 (root-pinned) · Cordis · Z3 (WASM) · loopx (pipx) · hotelbyte-cli · Agent-Reach v1.5.0 · OpenFlights · TypeScript
|
package/bin/gotry-bootstrap.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
3
|
* gotry 外部依赖自举(founder 2026-08-29 指令:安装 gotry 时按上游本身的方式装好外部依赖):
|
|
4
|
-
* hbcli(hotelbyte-cli) →
|
|
4
|
+
* hbcli(hotelbyte-cli) → npm 优先(staicli@npmjs;Node ≥ 20),原生二进制 install.sh 兜底
|
|
5
5
|
* agent-reach → 官方 pip 安装 git+ upstream(包内 .venv,与 z3-solver 同址原则)
|
|
6
6
|
* flyai → 无需安装(npx 每次自拉 @fly-ai/flyai-cli)
|
|
7
7
|
* dsh-better-sidebar → dsh 宿主层插件市场组件(dshmarket.com #1 UI,18.9 万周装):
|
|
@@ -58,6 +58,7 @@ import { copyFileSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSyn
|
|
|
58
58
|
import { homedir } from 'node:os'
|
|
59
59
|
import { join, dirname } from 'node:path'
|
|
60
60
|
import { fileURLToPath } from 'node:url'
|
|
61
|
+
import { createRequire } from 'node:module'
|
|
61
62
|
|
|
62
63
|
const repoRoot = join(dirname(fileURLToPath(import.meta.url)), '..')
|
|
63
64
|
const AUTO = process.argv.includes('--auto')
|
|
@@ -69,13 +70,15 @@ const WIZARD_DRY_RUN = process.argv.includes('--dry-run')
|
|
|
69
70
|
const EXT_FROM_ARG = (process.argv.find((a) => a.startsWith('--extension-from=')) ?? '').split('=')[1]
|
|
70
71
|
const EXTENSION_FROM = EXT_FROM_ARG === 'github' || EXT_FROM_ARG === 'bundled' ? EXT_FROM_ARG : process.env.GOTRY_EXTENSION_SOURCE === 'github' ? 'github' : 'bundled'
|
|
71
72
|
|
|
72
|
-
|
|
73
|
+
// hbcli 安装通道:npm 优先(staicli@npmjs 双轨;显式 registry 防 bnpm 404),install.sh 兜底
|
|
74
|
+
const HBCLI_NPM_INSTALL_CMD = 'npm install -g staicli --registry=https://registry.npmjs.org/'
|
|
75
|
+
const HBCLI_INSTALL_CMD = HBCLI_NPM_INSTALL_CMD
|
|
73
76
|
const REACH_INSTALL_URL = 'git+https://github.com/Panniantong/Agent-Reach.git'
|
|
74
77
|
|
|
75
78
|
/** 带超时的子进程(inherit stdio 让用户看见上游安装进度) */
|
|
76
|
-
function run(cmd, args, { timeoutMs, cwd } = {}) {
|
|
79
|
+
function run(cmd, args, { timeoutMs, cwd, env } = {}) {
|
|
77
80
|
return new Promise((resolve) => {
|
|
78
|
-
const child = spawn(cmd, args, { stdio: 'inherit', cwd, env: process.env })
|
|
81
|
+
const child = spawn(cmd, args, { stdio: 'inherit', cwd, env: env ?? process.env })
|
|
79
82
|
let done = false
|
|
80
83
|
const timer = setTimeout(() => {
|
|
81
84
|
if (!done) { done = true; try { child.kill('SIGKILL') } catch { /* ignore */ } }
|
|
@@ -98,20 +101,58 @@ function probe(cmd, args, timeoutMs = 10_000) {
|
|
|
98
101
|
|
|
99
102
|
const say = (s) => console.log(s)
|
|
100
103
|
|
|
104
|
+
/** hbcli 最低版本(可用 GOTRY_MIN_HBCLI_VERSION 覆盖)。
|
|
105
|
+
* 0.0.3 修了 portal-ticket fallback bug(issue #142):低于该版本的 hbcli
|
|
106
|
+
* 会把 literal "stored-ticket" 当 bearer 发到 hotel-be,让 trade.* /
|
|
107
|
+
* search/checkAvail 等 @permission: openapi 端点全部 401。 */
|
|
108
|
+
const MIN_HBCLI_VERSION = process.env.GOTRY_MIN_HBCLI_VERSION ?? '0.0.3'
|
|
109
|
+
|
|
110
|
+
function parseVersion(v) {
|
|
111
|
+
const m = String(v || '').match(/(\d+)\.(\d+)\.(\d+)/)
|
|
112
|
+
return m ? [Number(m[1]), Number(m[2]), Number(m[3])] : null
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function versionAtLeast(v, min) {
|
|
116
|
+
const a = parseVersion(v); const b = parseVersion(min)
|
|
117
|
+
if (!a || !b) return false
|
|
118
|
+
for (let i = 0; i < 3; i++) { if (a[i] !== b[i]) return a[i] > b[i] }
|
|
119
|
+
return true
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async function hbcliVersion(bin) {
|
|
123
|
+
const cmd = bin === 'hbcli(PATH)' ? 'hbcli' : bin
|
|
124
|
+
return new Promise((resolve) => {
|
|
125
|
+
const child = spawn(cmd, ['--version'], { stdio: ['ignore', 'pipe', 'ignore'] })
|
|
126
|
+
let out = ''
|
|
127
|
+
let done = false
|
|
128
|
+
const timer = setTimeout(() => { if (!done) { done = true; try { child.kill('SIGKILL') } catch { /* ignore */ } resolve(null) } }, 10_000)
|
|
129
|
+
child.on('error', () => { if (!done) { done = true; clearTimeout(timer); resolve(null) } })
|
|
130
|
+
child.stdout?.on('data', (d) => { out += d.toString() })
|
|
131
|
+
child.on('exit', (code) => { if (!done) { done = true; clearTimeout(timer); resolve(code === 0 ? parseVersion(out.trim()) : null) } })
|
|
132
|
+
})
|
|
133
|
+
}
|
|
134
|
+
|
|
101
135
|
async function setupHbcli() {
|
|
102
|
-
say(
|
|
136
|
+
say(`[gotry-setup] hbcli(hotelbyte-cli,可选酒店实时源;需 ≥ v${MIN_HBCLI_VERSION},低于会踩 issue #142 的 401)`)
|
|
103
137
|
const candidates = ['hbcli', join(homedir(), '.local/bin/hbcli'), join(homedir(), '.staicli/current/hbcli')]
|
|
104
138
|
const present = candidates.some((p) => existsSync(p)) && (await probe(candidates[0], ['version']) || await probe(candidates[1], ['version']) || await probe(candidates[2], ['version']))
|
|
105
139
|
const credFile = join(homedir(), '.staicli', 'credentials.json')
|
|
106
140
|
if (present) {
|
|
107
|
-
|
|
141
|
+
const hit = candidates.find((p) => existsSync(p)) || 'hbcli'
|
|
142
|
+
const v = await hbcliVersion(hit)
|
|
143
|
+
if (v && !versionAtLeast(v, MIN_HBCLI_VERSION)) {
|
|
144
|
+
say(` ✗ 版本过旧(v${v.join('.')} < v${MIN_HBCLI_VERSION})——@permission: openapi 端点(trade.* / search/checkAvail)会 401(issue #142)`)
|
|
145
|
+
say(` 升级: npm install -g staicli --registry=https://registry.npmjs.org/`)
|
|
146
|
+
return { ok: CHECK_ONLY ? true : false }
|
|
147
|
+
}
|
|
148
|
+
say(` ✓ 已安装(v${v ? v.join('.') : '?'})`)
|
|
108
149
|
if (existsSync(credFile)) say(' ✓ 凭证已配置(自检: hbcli auth whoami)')
|
|
109
150
|
else say(' ✗ 凭证未配置——酒店检索将用内置静态包(非实时),账号配置见下方指引')
|
|
110
151
|
if (CHECK_ONLY) say(' (--check-only 只报告,不安装)')
|
|
111
152
|
return { ok: true }
|
|
112
153
|
}
|
|
113
154
|
if (CHECK_ONLY) { say(' ✗ 未安装(--check-only 只报告)'); return { ok: true } }
|
|
114
|
-
say(` 安装中(
|
|
155
|
+
say(` 安装中(npm,staicli@npmjs): ${HBCLI_INSTALL_CMD}`)
|
|
115
156
|
const r = await run('bash', ['-c', HBCLI_INSTALL_CMD], { timeoutMs: 120_000 })
|
|
116
157
|
if (!r.ok) { say(` ✗ 安装失败(${r.error})——不影响 gotry,酒店检索将用内置静态包;可稍后重试: npx gotry setup`); return { ok: false } }
|
|
117
158
|
const binDir = join(homedir(), '.local/bin')
|
|
@@ -143,34 +184,56 @@ async function setupReach() {
|
|
|
143
184
|
return { ok: true }
|
|
144
185
|
}
|
|
145
186
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
187
|
+
/** sidebar 落盘状态 = 与 doctor 检查同口径的唯一事实面(profile 里的 package.json) */
|
|
188
|
+
function sidebarInstalled() {
|
|
189
|
+
return existsSync(join(homedir(), '.dsh/profiles/web/node_modules/dsh-better-sidebar/package.json'))
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** dsh plugin 在 profile 目录里跑 pnpm;pnpm ≥10.5 默认不执行依赖构建脚本,严格态
|
|
193
|
+
* (pnpm 11 默认 / strict-dep-builds)下 ERR_PNPM_IGNORED_BUILDS 直接 exit 1——
|
|
194
|
+
* 但包本身已完整落盘(2026-09-08 实测:exit 1 而 167 包全部就位,doctor 复检即绿)。
|
|
195
|
+
* 对该调用降回警告态(env 只作用于这一次 spawn,不改用户全局 pnpm 配置);
|
|
196
|
+
* 老版本 pnpm 不认识此配置,零影响。 */
|
|
197
|
+
const SIDEBAR_PNPM_ENV = { ...process.env, npm_config_strict_dep_builds: 'false' }
|
|
198
|
+
|
|
199
|
+
async function setupSidebar(attemptInstall) { say('[gotry-setup] dsh-better-sidebar(dsh web 侧栏工作台,产物查看面 issue #25)')
|
|
200
|
+
if (sidebarInstalled()) { say(' ✓ 已安装(~/.dsh/profiles/web)'); return { ok: true } }
|
|
149
201
|
if (CHECK_ONLY) { say(' ✗ 未安装(--check-only 只报告)'); return { ok: true } }
|
|
150
202
|
const SIDEBAR_PKG = 'dsh-better-sidebar@latest'
|
|
151
|
-
// dsh CLI:本包依赖里的 @deepseek-ai/dsh 优先;解析不到走 npx 自拉(官方安装途径同款)
|
|
152
|
-
|
|
203
|
+
// dsh CLI:本包依赖里的 @deepseek-ai/dsh 优先;解析不到走 npx 自拉(官方安装途径同款)。
|
|
204
|
+
// attemptInstall 注入位供测试模拟「安装器失败但状态落盘」(pnpm 忽略构建脚本策略)。
|
|
153
205
|
const require_ = createRequire(join(repoRoot, 'package.json'))
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
if (r.ok) {
|
|
161
|
-
say(' ✓ 安装完成(gotry web 刷新浏览器即见右侧工作台;工作区里的产物 md 可直接预览)')
|
|
162
|
-
return { ok: true }
|
|
163
|
-
}
|
|
164
|
-
say(` ✗ dsh plugin 安装失败(${r.error})——尝试 npx 途径`)
|
|
165
|
-
} catch { /* 本包未携带 @deepseek-ai/dsh */ }
|
|
166
|
-
if (!launched) say(' 本包未携带 @deepseek-ai/dsh,走 npx 途径安装')
|
|
167
|
-
const r2 = await run('npx', ['-y', '--package', '@deepseek-ai/dsh', 'dsh', 'plugin', '--profile', 'web', 'add', SIDEBAR_PKG], { timeoutMs: 300_000 })
|
|
168
|
-
if (!r2.ok) {
|
|
169
|
-
say(' ✗ 安装失败——不影响 gotry:产物仍可在对话里说「看看我生成的行程」经 gotry_artifacts_list/read 查看;可稍后重试: npx gotry doctor --fix')
|
|
170
|
-
return { ok: false }
|
|
206
|
+
const defaultAttempt = async () => {
|
|
207
|
+
try {
|
|
208
|
+
const dshBin = require_.resolve('@deepseek-ai/dsh/lib/bin.js')
|
|
209
|
+
say(` 安装中(dsh plugin → web profile): ${SIDEBAR_PKG}`)
|
|
210
|
+
return await run(process.execPath, [dshBin, 'plugin', '--profile', 'web', 'add', SIDEBAR_PKG], { timeoutMs: 300_000, env: SIDEBAR_PNPM_ENV })
|
|
211
|
+
} catch { return { ok: false, noDsh: true } }
|
|
171
212
|
}
|
|
172
|
-
|
|
173
|
-
|
|
213
|
+
const r = await (attemptInstall ?? defaultAttempt)()
|
|
214
|
+
if (r.ok) {
|
|
215
|
+
say(' ✓ 安装完成(gotry web 刷新浏览器即见右侧工作台;工作区里的产物 md 可直接预览)')
|
|
216
|
+
return { ok: true }
|
|
217
|
+
}
|
|
218
|
+
// exit 非 0 ≠ 没装上(pnpm 忽略构建脚本策略):先按落盘状态复核,再决定是否回退 npx 途径
|
|
219
|
+
if (sidebarInstalled()) {
|
|
220
|
+
say(' ✓ 安装完成(安装器 exit 非 0,但按落盘状态复核已就位;gotry web 刷新浏览器即见右侧工作台)')
|
|
221
|
+
say(' ⚠ pnpm 跳过了 node-pty(侧栏内嵌终端)的构建脚本——预览功能不受影响;如需内嵌终端:cd ~/.dsh/profiles/web && pnpm approve-builds 勾选 node-pty')
|
|
222
|
+
return { ok: true }
|
|
223
|
+
}
|
|
224
|
+
if (r.noDsh) say(' 本包未携带 @deepseek-ai/dsh,走 npx 途径安装')
|
|
225
|
+
else say(' ✗ dsh plugin 安装失败且未落盘——尝试 npx 途径')
|
|
226
|
+
const r2 = await run('npx', ['-y', '--package', '@deepseek-ai/dsh', 'dsh', 'plugin', '--profile', 'web', 'add', SIDEBAR_PKG], { timeoutMs: 300_000, env: SIDEBAR_PNPM_ENV })
|
|
227
|
+
if (r2.ok) {
|
|
228
|
+
say(' ✓ 安装完成(gotry web 刷新浏览器即见右侧工作台)')
|
|
229
|
+
return { ok: true }
|
|
230
|
+
}
|
|
231
|
+
if (sidebarInstalled()) {
|
|
232
|
+
say(' ✓ 安装完成(npx 途径 exit 非 0,但按落盘状态复核已就位)')
|
|
233
|
+
return { ok: true }
|
|
234
|
+
}
|
|
235
|
+
say(' ✗ 安装失败——不影响 gotry:产物仍可在对话里说「看看我生成的行程」经 gotry_artifacts_list/read 查看;可稍后重试: npx gotry doctor --fix')
|
|
236
|
+
return { ok: false }
|
|
174
237
|
}
|
|
175
238
|
|
|
176
239
|
// ---------------------------------------------------------------------------
|
|
@@ -255,23 +318,27 @@ async function doctorChecks() {
|
|
|
255
318
|
const reachOk = existsSync(reachBin)
|
|
256
319
|
const reachLevel = reachOk ? 'ok' : existsSync(venvPython) ? 'degraded' : 'missing'
|
|
257
320
|
items.push({ label: 'Agent Reach(网页/社媒读取)', ok: reachOk, level: reachLevel, detail: reachOk ? `已安装(${reachBin})` : reachLevel === 'degraded' ? '.venv 在但缺 agent-reach 包——gotry_agent_reach / gotry_web_search 读页会失败' : '未装配——gotry_agent_reach / gotry_web_search(读网页)/ gotry_video_subtitle / gotry_github_search 全部不可用', fix: reachOk ? undefined : 'npx gotry doctor --fix' })
|
|
258
|
-
// hbcli(裸名靠 PATH 探测;绝对路径 existsSync)
|
|
321
|
+
// hbcli(裸名靠 PATH 探测;绝对路径 existsSync;版本 < MIN_HBCLI_VERSION 视为 missing,见 issue #142)
|
|
259
322
|
let hbBin = ''
|
|
260
323
|
for (const p of ['hbcli', join(homedir(), '.local/bin/hbcli'), join(homedir(), '.staicli/current/hbcli')]) {
|
|
261
324
|
if (p === 'hbcli') { if (await probe(p, ['version'])) { hbBin = 'hbcli(PATH)'; break } } else if (existsSync(p)) { hbBin = p; break }
|
|
262
325
|
}
|
|
263
326
|
if (hbBin) {
|
|
264
|
-
const
|
|
265
|
-
|
|
327
|
+
const v = await hbcliVersion(hbBin)
|
|
328
|
+
if (v && !versionAtLeast(v, MIN_HBCLI_VERSION)) {
|
|
329
|
+
items.push({ label: 'hbcli(酒店实时源)', ok: false, level: 'missing', detail: `版本过旧(v${v.join('.')} < v${MIN_HBCLI_VERSION})——trade.* / search/checkAvail 会 401(issue #142)`, fix: 'npm install -g staicli --registry=https://registry.npmjs.org/' })
|
|
330
|
+
} else {
|
|
331
|
+
const whoami = await probe(hbBin === 'hbcli(PATH)' ? 'hbcli' : hbBin, ['auth', 'whoami'])
|
|
332
|
+
items.push({ label: 'hbcli(酒店实时源)', ok: whoami, level: whoami ? 'ok' : 'degraded', detail: whoami ? `已安装且凭证有效(${hbBin}, v${v ? v.join('.') : '?'})` : '二进制在,但凭证未配置/失效——酒店检索将降级静态包(非实时)', fix: whoami ? undefined : 'hbcli auth set-credentials --app-key hotelbyte_api_demo --app-secret hotelbyte_api_demo(快速试用沙箱;正式 key 向 HotelByte 申请)' })
|
|
333
|
+
}
|
|
266
334
|
} else {
|
|
267
335
|
items.push({ label: 'hbcli(酒店实时源)', ok: false, level: 'missing', detail: '未安装——酒店检索降级静态包(公开渠道估算,非实时,仅覆盖内置场景)', fix: 'npx gotry doctor --fix' })
|
|
268
336
|
}
|
|
269
337
|
// flyai key(匿名试用额度共享易达限;正式 key 即免)
|
|
270
338
|
const flyaiKey = (process.env.FLYAI_API_KEY ?? '').trim()
|
|
271
339
|
items.push({ label: 'FlyAI(飞猪官方检索)', ok: Boolean(flyaiKey), level: flyaiKey ? 'ok' : 'degraded', detail: flyaiKey ? 'FLYAI_API_KEY 已配(正式 key,无试用额度限制)' : '未配 FLYAI_API_KEY——走匿名试用额度(共享,易达限;达限报 "Trial limit reached")', fix: flyaiKey ? undefined : '到 flyai.open.fliggy.com 控制台申请正式 key,配进环境变量 FLYAI_API_KEY' })
|
|
272
|
-
// sidebar
|
|
273
|
-
const
|
|
274
|
-
const sbOk = existsSync(sidebarPkg)
|
|
340
|
+
// sidebar(状态面与 setupSidebar 的落盘复核同一口径)
|
|
341
|
+
const sbOk = sidebarInstalled()
|
|
275
342
|
items.push({ label: 'dsh-better-sidebar(侧栏工作台)', ok: sbOk, level: sbOk ? 'ok' : 'missing', detail: sbOk ? '已安装——web UI 右侧工作台可预览产物与 doctor 报告(gotry-state/doctor-report.md)' : '未安装——dsh web 无右侧工作台,产物与 doctor 报告只能在对话里看(gotry_artifacts_list)', fix: sbOk ? undefined : 'npx gotry doctor --fix' })
|
|
276
343
|
// dsh-calendar(setup 状态面;默认不挂载=ok 是合法态,opt-in 未配置才 degraded)
|
|
277
344
|
const calState = readCalendarState()
|
|
@@ -279,24 +346,42 @@ async function doctorChecks() {
|
|
|
279
346
|
const calConfigured = calOn && calendarProfileConfigured()
|
|
280
347
|
items.push({ label: 'dsh-calendar(日历工作窗口)', ok: !calOn || calConfigured, level: !calOn ? 'ok' : calConfigured ? 'ok' : 'degraded', detail: calendarDetail(calState), fix: !calOn ? undefined : calConfigured ? undefined : '在 ~/.dsh/profiles/web/cordis.patch.yml 覆盖 calendar 行 config 填 username(或 npx gotry setup calendar --off 恢复默认不挂载)' })
|
|
281
348
|
// dsh-map-tools(patch 分发面宿主插件,issue #139):解析失败启动时整块静默剔除,
|
|
282
|
-
// doctor 把两态照亮。候选清单与 bin/gotry-inner.js 解析链、ts/capabilities/doctor.ts
|
|
349
|
+
// doctor 把两态照亮。候选清单与 bin/gotry-inner.js 解析链、ts/capabilities/doctor.ts 同口径:
|
|
350
|
+
// tarball vendor 副本优先(随 files[] 分发,不进 npm 依赖——其 peerDependencies 要求
|
|
351
|
+
// dsh-settings/dsh-tools >=0.1.2-rc.1,与锁定的 0.1.2-alpha.3 家族在 npm 严格 peer
|
|
352
|
+
// 解析下 ERESOLVE,依赖形态会弄坏 npx 安装),其余覆盖 source/提升/profile 布局。
|
|
353
|
+
const rootRequire = createRequire(join(repoRoot, 'package.json'))
|
|
283
354
|
const mapCandidates = [
|
|
355
|
+
join(repoRoot, 'ts/dsh-runtime/vendor/dsh-map-tools/lib/index.js'),
|
|
284
356
|
join(repoRoot, 'ts/dsh-runtime/node_modules/dsh-map-tools/lib/index.js'),
|
|
285
357
|
join(repoRoot, 'node_modules/dsh-map-tools/package.json'),
|
|
286
358
|
join(repoRoot, 'ts/node_modules/dsh-map-tools/package.json'),
|
|
287
359
|
join(homedir(), '.dsh/profiles/web/node_modules/dsh-map-tools/package.json'),
|
|
288
360
|
]
|
|
289
|
-
|
|
361
|
+
let mapHit = mapCandidates.find((p) => existsSync(p))
|
|
362
|
+
// npm 提升布局:gotry 的依赖不在包目录 node_modules 里,而在同级提升位——
|
|
363
|
+
// 与 inner 的 require_.resolve 同机制(createRequire 从包位置向上走查)
|
|
364
|
+
if (!mapHit) { try { mapHit = rootRequire.resolve('dsh-map-tools') } catch { mapHit = undefined } }
|
|
290
365
|
items.push(mapHit
|
|
291
366
|
? { label: 'dsh-map-tools(地图/路线/POI)', ok: true, level: 'ok', detail: `已就位(${mapHit})——地图工具可用(零 key,走 OSM/OSRM)`, fix: undefined }
|
|
292
|
-
: { label: 'dsh-map-tools(地图/路线/POI)', ok: false, level: 'missing', detail: '未随包解析——启动时该 patch 条目被静默剔除,地图/路线/POI 工具不会出现在模型工具箱(缺地图不挡旅行规划,只少能力)', fix: '
|
|
367
|
+
: { label: 'dsh-map-tools(地图/路线/POI)', ok: false, level: 'missing', detail: '未随包解析——启动时该 patch 条目被静默剔除,地图/路线/POI 工具不会出现在模型工具箱(缺地图不挡旅行规划,只少能力)', fix: '重装 @danceiny/gotry(地图插件随包 vendor 分发,缺失多为安装不完整)' })
|
|
293
368
|
// dsh-tool-ask-user(结构化澄清卡,人格契约 (5) 的卡片形态载体)
|
|
294
369
|
const askCandidates = [
|
|
295
370
|
join(repoRoot, 'ts/dsh-runtime/vendor/deepseek-ai-dsh-tool-ask-user/package.json'),
|
|
296
371
|
join(repoRoot, 'node_modules/@deepseek-ai/dsh-tool-ask-user/package.json'),
|
|
297
372
|
join(homedir(), '.dsh/profiles/web/node_modules/@deepseek-ai/dsh-tool-ask-user/package.json'),
|
|
298
373
|
]
|
|
299
|
-
|
|
374
|
+
let askHit = askCandidates.find((p) => existsSync(p))
|
|
375
|
+
// 与 inner 同口径:优先从 dsh 包上下文解析(pnpm 嵌套布局只有 dsh 看得见),再从包根上下文
|
|
376
|
+
// (npm/npx 提升布局),最后静态候选(source vendored / profile)
|
|
377
|
+
if (!askHit) {
|
|
378
|
+
try {
|
|
379
|
+
const reqFromDsh = createRequire(rootRequire.resolve('@deepseek-ai/dsh/lib/bin.js'))
|
|
380
|
+
askHit = reqFromDsh.resolve('@deepseek-ai/dsh-tool-ask-user')
|
|
381
|
+
} catch {
|
|
382
|
+
try { askHit = rootRequire.resolve('@deepseek-ai/dsh-tool-ask-user') } catch { askHit = undefined }
|
|
383
|
+
}
|
|
384
|
+
}
|
|
300
385
|
items.push(askHit
|
|
301
386
|
? { label: 'dsh-tool-ask-user(结构化澄清卡)', ok: true, level: 'ok', detail: `已就位(${askHit})——ask_user_question 澄清卡可用(web 原生卡片;headless+TTY 用 stdio 提供方)`, fix: undefined }
|
|
302
387
|
: { label: 'dsh-tool-ask-user(结构化澄清卡)', ok: false, level: 'missing', detail: '未解析——启动时澄清卡注入被静默剔除,模型只能散文追问(人格契约 (5) 退化文本形态)', fix: '重装 @danceiny/gotry——该依赖随 dsh 闭包自带,缺失多为安装不完整' })
|
|
@@ -728,7 +813,13 @@ if (WIZARD) {
|
|
|
728
813
|
process.exit(0)
|
|
729
814
|
}
|
|
730
815
|
|
|
731
|
-
main(
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
816
|
+
// 直接执行才跑 main(bootstrap-tests import 本模块做 setupSidebar 单测时不触发安装面;
|
|
817
|
+
// bin/gotry-inner.js 始终以 `node …/gotry-bootstrap.js` 直接 spawn,不受影响)
|
|
818
|
+
if (process.argv[1] && process.argv[1].endsWith('gotry-bootstrap.js')) {
|
|
819
|
+
main().catch((e) => {
|
|
820
|
+
say(`[gotry-setup] 异常:${e.message}(不影响 gotry 本体;可重试 npx gotry setup)`)
|
|
821
|
+
process.exit(AUTO ? 0 : 1)
|
|
822
|
+
})
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
export { setupSidebar, sidebarInstalled }
|
package/bin/gotry-inner.js
CHANGED
|
@@ -82,10 +82,7 @@ if (help) {
|
|
|
82
82
|
Usage:
|
|
83
83
|
gotry web # dsh Web UI on http://127.0.0.1:3080
|
|
84
84
|
gotry setup # 扩展就位检查/指引(商店一键装)
|
|
85
|
-
<<<<<<< HEAD
|
|
86
85
|
gotry setup calendar # 可选日历(CalDAV 工作窗口)挂载开关:默认关;--off 关闭;--status 查看
|
|
87
|
-
=======
|
|
88
|
-
>>>>>>> origin/main
|
|
89
86
|
gotry doctor # 可选依赖体检:扩展/agent-reach/hbcli/flyai/sidebar 状态 + 补装指引
|
|
90
87
|
gotry doctor --fix # 体检 + 按报告补装(hbcli 官方脚本 / agent-reach pip / sidebar 插件)
|
|
91
88
|
gotry "一段完整任务..." # headless 一问一答
|
|
@@ -368,13 +365,21 @@ if (benchmarkEnvironmentConfig) {
|
|
|
368
365
|
process.exit(1)
|
|
369
366
|
}
|
|
370
367
|
}
|
|
371
|
-
// dsh-map-tools 宿主插件(地图/路线/POI,零 key 走 OSM/OSRM):
|
|
372
|
-
//
|
|
368
|
+
// dsh-map-tools 宿主插件(地图/路线/POI,零 key 走 OSM/OSRM):tarball 随包 vendor,
|
|
369
|
+
// repo 工作副本走 runtime workspace 链接/依赖解析;都找不到就整块剔除 patch 条目
|
|
370
|
+
// (缺地图不挡旅行规划)。不能改成 npm 依赖:其 peerDependencies 要求
|
|
371
|
+
// dsh-settings/dsh-tools >=0.1.2-rc.1,与本包锁定的 0.1.2-alpha.3 家族在 npm
|
|
372
|
+
// 严格 peer 解析下 ERESOLVE,会直接弄坏 npx 安装。
|
|
373
373
|
let mapEntry = ''
|
|
374
374
|
if (!benchmarkEnvironmentConfig) {
|
|
375
|
-
const vendoredMap = join(repoRoot, 'ts/dsh-runtime/
|
|
375
|
+
const vendoredMap = join(repoRoot, 'ts/dsh-runtime/vendor/dsh-map-tools/lib/index.js')
|
|
376
|
+
// (随 tarball 分发;source 布局同一份文件)
|
|
377
|
+
const runtimeMap = join(repoRoot, 'ts/dsh-runtime/node_modules/dsh-map-tools/lib/index.js')
|
|
378
|
+
// (ts/dsh-runtime pnpm workspace vendor/* 链接形态)
|
|
376
379
|
if (existsSync(vendoredMap)) {
|
|
377
380
|
mapEntry = vendoredMap
|
|
381
|
+
} else if (existsSync(runtimeMap)) {
|
|
382
|
+
mapEntry = runtimeMap
|
|
378
383
|
} else {
|
|
379
384
|
// npm 布局:子路径可能被 exports 挡(resolve 抛错不能留下旧值),裸包名返回真实入口
|
|
380
385
|
try { mapEntry = require_.resolve('dsh-map-tools/lib/index.js') } catch { mapEntry = '' }
|
package/cordis.gotry-patch.yml
CHANGED
|
@@ -17,10 +17,10 @@
|
|
|
17
17
|
# {ask-user-insert} ← inner 运行时填充(dsh-user-questions 服务 + ask_user_question
|
|
18
18
|
# 工具,结构化澄清卡);解析失败整块剔除
|
|
19
19
|
|
|
20
|
-
# 注:insert 里 dsh-map-tools 的 name 是占位符,bin/gotry-inner.js
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
20
|
+
# 注:insert 里 dsh-map-tools 的 name 是占位符,bin/gotry-inner.js 运行时优先重写为
|
|
21
|
+
# 随包 ts/dsh-runtime/vendor/dsh-map-tools/lib/index.js 的绝对路径(source/package
|
|
22
|
+
# 均可用;旧 source/npm 依赖路径仅作兼容回退)。payload 缺失时该条目整块剔除,
|
|
23
|
+
# 不挡启动。地图/路线/POI 工具,零 key 走 OSM/OSRM。
|
|
24
24
|
|
|
25
25
|
# GoTry 成品人格:行为契约=产品语义
|
|
26
26
|
- id: system-prompt
|
|
@@ -52,7 +52,9 @@
|
|
|
52
52
|
直接点明(如「现在正是雨季」而非把当前月份当成远期选项);用户给的绝对日期
|
|
53
53
|
早于今天时,主动点明已过并请用户裁决(笔误还是指明年),不静默顺延;
|
|
54
54
|
周/月/节日表述一律按锚点卡换算,不自算;用户说「在 X 年内完成」时,
|
|
55
|
-
|
|
55
|
+
只推荐今天之后的时段,今天之前的一律排除;
|
|
56
|
+
澄清卡/访谈/选项里向用户列出的候选时段示例(节日/周末/月份)同样只取
|
|
57
|
+
今天之后的——已过的节日不进示例枚举,不拿过去节日当「想用的时候」的候选。
|
|
56
58
|
(9)年界断言:「元旦/新年/春节」先断年再谈——今天是 {{current_date}},
|
|
57
59
|
「2026 年内」不含 2027-01-01 元旦;农历节日先换算公历日期再判断归属年份。
|
|
58
60
|
(10)不重复问:预算/日期/窗口/出发地等已问过或用户已给的信息,会话内
|
|
@@ -109,9 +111,18 @@
|
|
|
109
111
|
**交付任何含可下单事实的行程产物(markdown 文件或长方案)前,必须调
|
|
110
112
|
gotry_fact_gate**;闸 blocked 时逐条修正为可回溯事实或降级措辞,
|
|
111
113
|
不得宣称「已验证方案」。
|
|
112
|
-
(21)
|
|
113
|
-
|
|
114
|
-
|
|
114
|
+
(21)工具循环收敛(wall-clock,ADR-24 v2):工具按需取用,没有「次数预算」,
|
|
115
|
+
也**永远不要**向用户宣称「工具预算已耗尽」——每轮唯一的边界是运行时时间闸,
|
|
116
|
+
只认三种信号:收到 TURN_DEADLINE_SOFT = 时间过半,立即停止发起新工具,开始
|
|
117
|
+
整理已有结果;收到 TURN_DEADLINE_EXHAUSTED = 本轮时间到,只能基于已有结果
|
|
118
|
+
输出最终答复,不得重试或改调其他工具,更不得用记忆/常识填充工具没查到的
|
|
119
|
+
实时事实(如实说明哪部分未能核实);收到 TURN_DEADLINE_HANDOFF = 深规划
|
|
120
|
+
转入后台,按提示告知用户预计时间与回访方式(附工单号),本轮给简短确认。
|
|
115
121
|
(22)到达账必达:红眼/凌晨起飞、或落地当天有硬安排(上班/办事)的航段,解释方案时必须
|
|
116
122
|
显式给出到达账——当地到达时刻(含日期偏移)、时差、到达精力与落地后可用时长,并主动给
|
|
117
123
|
前一晚落脚建议;时刻表正确不等于行程可行。
|
|
124
|
+
(23)子任务等待纪律:派发后台子任务(subagent)后,它的回执 id 是子代理会话 id,
|
|
125
|
+
不是 job_output/job_kill 的后台 job id——对子代理绝不调用 job_output/job_kill
|
|
126
|
+
轮询或停止(会撞 unknown job 硬错误);子任务完成通知会自动送达当前会话,耐心做
|
|
127
|
+
别的独立步骤;要给子代理追加输入用 send_message。job_output/job_kill 只用于
|
|
128
|
+
回执明写「background job」的后台任务。
|
|
@@ -1,4 +1,24 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
|
+
import { hbcliBinCandidates } from './hbcli.js';
|
|
3
|
+
function i18nText(v) {
|
|
4
|
+
if (!v) return '';
|
|
5
|
+
if (typeof v === 'string') return v;
|
|
6
|
+
return v.zh || v.en || v.ar || '';
|
|
7
|
+
}
|
|
8
|
+
function latlngOf(coord) {
|
|
9
|
+
for (const src of [
|
|
10
|
+
coord?.google,
|
|
11
|
+
coord?.gaode
|
|
12
|
+
]){
|
|
13
|
+
const lat = typeof src?.lat === 'number' ? src.lat : undefined;
|
|
14
|
+
const lng = typeof src?.lng === 'number' ? src.lng : undefined;
|
|
15
|
+
if (lat !== undefined && lng !== undefined && (lat !== 0 || lng !== 0)) return {
|
|
16
|
+
latitude: lat,
|
|
17
|
+
longitude: lng
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
return {};
|
|
21
|
+
}
|
|
2
22
|
function sh(cmd, args, opts) {
|
|
3
23
|
const ctrl = new AbortController();
|
|
4
24
|
const timer = setTimeout(()=>{
|
|
@@ -48,8 +68,20 @@ function sh(cmd, args, opts) {
|
|
|
48
68
|
});
|
|
49
69
|
});
|
|
50
70
|
}
|
|
51
|
-
|
|
52
|
-
const
|
|
71
|
+
function buildArgs(keyword, q) {
|
|
72
|
+
const args = [
|
|
73
|
+
'--json',
|
|
74
|
+
'search',
|
|
75
|
+
'anything',
|
|
76
|
+
keyword
|
|
77
|
+
];
|
|
78
|
+
if (q.contentType) args.push('--content-type', q.contentType);
|
|
79
|
+
if (q.parentDestinationId !== undefined) args.push('--destination-id', String(q.parentDestinationId));
|
|
80
|
+
return args;
|
|
81
|
+
}
|
|
82
|
+
function upgradeHint(stderr) {
|
|
83
|
+
return /unknown command/i.test(stderr) ? 'hbcli 版本过旧(无 search anything 子命令)——请升级:hbcli update,或重跑 npx gotry setup' : null;
|
|
84
|
+
}
|
|
53
85
|
export async function anythingSearch(q) {
|
|
54
86
|
const started = Date.now();
|
|
55
87
|
const ts = new Date().toISOString();
|
|
@@ -64,30 +96,30 @@ export async function anythingSearch(q) {
|
|
|
64
96
|
error: 'keyword is required'
|
|
65
97
|
};
|
|
66
98
|
}
|
|
67
|
-
const
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
'
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
99
|
+
const args = buildArgs(kw, q);
|
|
100
|
+
const candidates = hbcliBinCandidates(q.hbcliBin ?? 'hbcli');
|
|
101
|
+
let r = {
|
|
102
|
+
code: -1,
|
|
103
|
+
stdout: '',
|
|
104
|
+
stderr: ''
|
|
105
|
+
};
|
|
106
|
+
for(let i = 0; i < candidates.length; i++){
|
|
107
|
+
r = await sh(candidates[i], args, {
|
|
108
|
+
timeoutMs: q.timeoutMs ?? 12_000,
|
|
109
|
+
env: process.env
|
|
110
|
+
});
|
|
111
|
+
if (!(r.error && i < candidates.length - 1)) break;
|
|
77
112
|
}
|
|
78
|
-
const r = await sh(bin, args.slice(1), {
|
|
79
|
-
timeoutMs: q.timeoutMs ?? 12_000,
|
|
80
|
-
env: process.env
|
|
81
|
-
});
|
|
82
113
|
const latencyMs = Date.now() - started;
|
|
83
114
|
if (r.error || r.code !== 0) {
|
|
115
|
+
const raw = r.error ?? `${r.stderr.slice(0, 200)} (exit ${r.code})`;
|
|
84
116
|
return {
|
|
85
117
|
ok: false,
|
|
86
118
|
via: 'hbcli-anything-error',
|
|
87
|
-
evidence: `[实时API:hbcli-anything@error@${ts}] ${
|
|
119
|
+
evidence: `[实时API:hbcli-anything@error@${ts}] ${raw}`,
|
|
88
120
|
latencyMs,
|
|
89
121
|
verdict: 'error',
|
|
90
|
-
error: r.
|
|
122
|
+
error: upgradeHint(r.stderr) ?? raw
|
|
91
123
|
};
|
|
92
124
|
}
|
|
93
125
|
let data;
|
|
@@ -109,15 +141,19 @@ export async function anythingSearch(q) {
|
|
|
109
141
|
const hits = rawItems.map((it)=>{
|
|
110
142
|
const region = it.region ?? {};
|
|
111
143
|
const hotel = it.hotel ?? {};
|
|
112
|
-
const isHotel = it.type === 'hotel' ||
|
|
144
|
+
const isHotel = it.type === 'hotel' || Boolean(hotel.id);
|
|
145
|
+
const hotelCoords = latlngOf(hotel.latlngCoordinator);
|
|
146
|
+
const placeCoords = latlngOf(it.place?.latlngCoordinator);
|
|
147
|
+
const center = region.coordinates ?? {};
|
|
113
148
|
return {
|
|
114
|
-
type: isHotel ? 'hotel' : it.type === 'place'
|
|
115
|
-
name:
|
|
116
|
-
score: it.
|
|
117
|
-
latitude:
|
|
118
|
-
longitude:
|
|
119
|
-
destinationId: region.id,
|
|
120
|
-
hotelId: hotel.id
|
|
149
|
+
type: isHotel ? 'hotel' : it.type === 'place' ? 'place' : 'city',
|
|
150
|
+
name: i18nText(hotel.name) || i18nText(region.name) || '?',
|
|
151
|
+
score: it.matchScore,
|
|
152
|
+
latitude: hotelCoords.latitude ?? placeCoords.latitude ?? (typeof center.centerLat === 'number' ? center.centerLat : undefined),
|
|
153
|
+
longitude: hotelCoords.longitude ?? placeCoords.longitude ?? (typeof center.centerLng === 'number' ? center.centerLng : undefined),
|
|
154
|
+
destinationId: hotel.destinationId !== undefined ? String(hotel.destinationId) : region.id !== undefined ? String(region.id) : undefined,
|
|
155
|
+
hotelId: hotel.id !== undefined ? String(hotel.id) : undefined,
|
|
156
|
+
star: typeof hotel.star === 'number' && hotel.star > 0 ? hotel.star : undefined
|
|
121
157
|
};
|
|
122
158
|
});
|
|
123
159
|
const verdict = hits.length > 0 ? 'hit' : 'miss';
|
|
@@ -131,9 +167,6 @@ export async function anythingSearch(q) {
|
|
|
131
167
|
totalCandidates: rawItems.length
|
|
132
168
|
};
|
|
133
169
|
}
|
|
134
|
-
export const _ = {
|
|
135
|
-
upperFirst
|
|
136
|
-
};
|
|
137
170
|
|
|
138
171
|
|
|
139
172
|
//# sourceURL=ts/capabilities/anything.ts
|