@danceiny/gotry 0.0.1-rc.18 → 0.0.1-rc.20
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 +42 -16
- package/README.zh-CN.md +37 -15
- package/bin/gotry-bootstrap.js +309 -30
- package/bin/gotry-inner.js +74 -23
- package/bin/gotry-runtime-resolution.d.ts +1 -1
- package/bin/gotry-runtime-resolution.js +7 -8
- package/cordis.gotry-patch.yml +22 -8
- package/data/stations-12306-verify.json +524 -0
- package/dist/capabilities/agent-reach.js +4 -4
- package/dist/capabilities/anything.js +62 -29
- package/dist/capabilities/channel-health.js +103 -0
- package/dist/capabilities/channel-registry.js +213 -0
- package/dist/capabilities/doctor.js +307 -0
- package/dist/capabilities/effect.js +178 -5
- package/dist/capabilities/flyai.js +13 -0
- package/dist/capabilities/hbcli.js +28 -2
- package/dist/capabilities/session/adapters/ctrip-hotel.js +207 -0
- package/dist/capabilities/session/adapters/rail-12306.js +285 -0
- package/dist/capabilities/session/extension-bridge.js +14 -1
- package/dist/capabilities/session/extension-channel.js +4 -2
- package/dist/capabilities/session/extension-distribution.js +1 -1
- package/dist/capabilities/session-search.js +311 -0
- package/dist/capabilities/visa-policy.js +126 -0
- package/dist/scripts/agent-planning-turn-deadline-e2e.js +305 -0
- package/dist/scripts/agent-planning-turn-deadline-tests.js +281 -0
- package/dist/scripts/anything-tests.js +70 -21
- package/dist/scripts/benchmark-environment-bridge-e2e.js +139 -37
- package/dist/scripts/benchmark-environment-bridge-tests.js +1099 -306
- package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +26 -26
- package/dist/scripts/{booking-copilot-availability-policy-v2-tests.js → booking-copilot-availability-policy-tests.js} +115 -115
- package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +41 -1
- package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +75 -120
- package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +370 -61
- package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +2 -2
- package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +7 -3
- package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +15 -9
- package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +19 -11
- package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +16 -52
- package/dist/scripts/booking-copilot-runtime-proof-tests.js +3953 -155
- package/dist/scripts/booking-copilot-server-proof-tests.js +58 -23
- package/dist/scripts/booking-copilot-startup-proof-tests.js +10 -119
- package/dist/scripts/booking-surface-contract-proof-tests.js +1154 -326
- package/dist/scripts/bootstrap-tests.js +113 -2
- package/dist/scripts/build-metrics-report.js +339 -0
- package/dist/scripts/channel-probe-tests.js +148 -0
- package/dist/scripts/channel-probe.js +252 -0
- package/dist/scripts/channel-registry-tests.js +262 -0
- package/dist/scripts/doctor-tests.js +175 -0
- package/dist/scripts/effect-tests.js +274 -1
- package/dist/scripts/extension-tests.js +129 -11
- package/dist/scripts/fact-gate-tests.js +91 -2
- package/dist/scripts/flyai-tests.js +17 -1
- package/dist/scripts/hbcli-e2e-tests.js +1 -3
- package/dist/scripts/hbcli-tests.js +38 -1
- package/dist/scripts/metrics-report-tests.js +288 -0
- package/dist/scripts/persona-surface-guard-tests.js +19 -0
- package/dist/scripts/session-tests.js +401 -1
- package/dist/scripts/smoke.js +100 -83
- package/dist/scripts/turn-handoff-collect-tests.js +216 -0
- package/dist/scripts/turn-handoff-collect.js +189 -0
- package/dist/scripts/turn-policy-tests.js +56 -0
- package/dist/scripts/typed-contract-canary.js +261 -0
- package/dist/scripts/visa-policy-tests.js +75 -0
- package/dist/scripts/wish-channel-gate-tests.js +111 -0
- package/dist/src/artifact-gate.js +91 -3
- package/dist/src/benchmark-agent-conformance.js +39 -16
- package/dist/src/benchmark-environment-bridge.js +316 -52
- package/dist/src/bookable-facts.js +62 -3
- package/dist/src/booking-surface/{availability-policy-v2.js → availability-policy.js} +89 -89
- package/dist/src/booking-surface/canonical-schema.js +8 -22
- package/dist/src/booking-surface/contracts.js +70 -19
- package/dist/src/booking-surface/dsh-planner.js +310 -177
- package/dist/src/booking-surface/dsh-plugin.js +3 -3
- package/dist/src/booking-surface/index.js +1 -5
- package/dist/src/booking-surface/profile.js +1 -1
- package/dist/src/booking-surface/runtime.js +1682 -247
- package/dist/src/booking-surface/server.js +371 -185
- package/dist/src/booking-surface/startup.js +17 -27
- package/dist/src/booking-surface/validation.js +270 -760
- package/dist/src/index.js +739 -150
- package/dist/src/turn-deadline.js +292 -0
- package/dist/src/turn-policy.js +146 -0
- package/dist/src/wish-pool.js +5 -0
- package/extension/background.js +23 -4
- package/extension/content-main.js +47 -9
- package/extension/manifest.json +27 -9
- package/package.json +7 -26
- package/schemas/booking.surface.schema.json +2593 -0
- package/ts/capabilities/agent-reach.ts +4 -4
- package/ts/capabilities/anything.ts +89 -38
- package/ts/capabilities/flyai.ts +21 -3
- package/ts/capabilities/hbcli.ts +53 -4
- package/ts/capabilities/session/action-cache.ts +1 -1
- package/ts/capabilities/session/adapters/ctrip-hotel.ts +238 -0
- package/ts/capabilities/session/adapters/rail-12306.ts +293 -0
- package/ts/capabilities/session/extension-bridge.ts +32 -2
- package/ts/capabilities/session/extension-channel.ts +9 -8
- package/ts/capabilities/session/extension-distribution.ts +3 -1
- package/ts/capabilities/session/health-watch.ts +1 -1
- package/ts/capabilities/session/read-guard.ts +1 -1
- package/ts/capabilities/session/wizard.ts +1 -1
- package/ts/capabilities/session-search.ts +323 -1
- 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 +9 -0
- package/ts/scripts/turn-handoff-collect.ts +178 -0
- package/ts/src/artifact-gate.ts +82 -2
- package/ts/src/benchmark-agent-conformance.ts +54 -15
- package/ts/src/benchmark-environment-bridge.ts +234 -46
- package/ts/src/bookable-facts.ts +109 -5
- package/ts/src/booking-saga.ts +1 -1
- package/ts/src/booking-surface/{availability-policy-v2.ts → availability-policy.ts} +124 -125
- package/ts/src/booking-surface/canonical-schema.js +8 -22
- package/ts/src/booking-surface/contracts.ts +278 -239
- package/ts/src/booking-surface/dsh-planner.ts +333 -194
- package/ts/src/booking-surface/dsh-plugin.js +3 -3
- package/ts/src/booking-surface/index.ts +1 -5
- package/ts/src/booking-surface/profile.ts +11 -11
- package/ts/src/booking-surface/runtime.ts +1351 -351
- package/ts/src/booking-surface/server.ts +282 -175
- package/ts/src/booking-surface/startup.ts +36 -48
- package/ts/src/booking-surface/validation.ts +194 -442
- package/ts/src/contracts.ts +1 -1
- package/ts/src/index.ts +492 -172
- package/ts/src/loop.ts +1 -1
- package/ts/src/state-ledger.ts +1 -1
- package/ts/src/turn-deadline.ts +365 -0
- package/ts/src/turn-policy.ts +154 -0
- package/ts/src/wish-pool.ts +17 -4
- package/dist/scripts/agent-planning-budget-e2e.js +0 -227
- package/dist/scripts/agent-planning-budget-tests.js +0 -173
- package/dist/scripts/booking-copilot-v2-runtime-proof-tests.js +0 -3935
- package/dist/scripts/booking-surface-v2-contract-proof-tests.js +0 -1174
- package/dist/src/booking-surface/contracts-v2.js +0 -89
- package/dist/src/booking-surface/runtime-v2.js +0 -1771
- package/dist/src/booking-surface/server-v2.js +0 -334
- package/dist/src/booking-surface/validation-v2.js +0 -319
- package/dist/src/tool-budget.js +0 -136
- package/schemas/booking.surface.v1.schema.json +0 -927
- package/schemas/booking.surface.v2.schema.json +0 -61
- package/ts/src/booking-surface/contracts-v2.ts +0 -118
- package/ts/src/booking-surface/runtime-v2.ts +0 -1466
- package/ts/src/booking-surface/server-v2.ts +0 -247
- package/ts/src/booking-surface/validation-v2.ts +0 -205
- package/ts/src/tool-budget.ts +0 -165
package/bin/gotry-bootstrap.js
CHANGED
|
@@ -23,10 +23,18 @@
|
|
|
23
23
|
* # 扩展改走 GitHub Releases 下载通道(ADR-21):
|
|
24
24
|
* # dist-manifest → tar.gz → SHA256 → key 钉扎 → 原子交换;
|
|
25
25
|
* # 任何失败显式降级回包内副本(离线确定性不变)。
|
|
26
|
+
* node bin/gotry-bootstrap.js calendar # 可选日历挂载开关(D-9,setup 状态面):
|
|
27
|
+
* # 默认写 ~/.gotry/calendar.json {"enabled":true};
|
|
28
|
+
* # --off 删除恢复默认不挂载;--status 只读查看。
|
|
29
|
+
* node bin/gotry-bootstrap.js doctor # 可选依赖体检(2026-09-02 迪拜 session 复盘):
|
|
30
|
+
* # 扩展/agent-reach/.venv/hbcli/flyai key/sidebar/calendar
|
|
31
|
+
* # 逐项只读检查 + 精确补装指引;
|
|
32
|
+
* # 报告落 gotry-state/doctor-report.md(侧栏工作台可预览)。
|
|
33
|
+
* node bin/gotry-bootstrap.js doctor --fix # 体检后按缺失项补装(复用下方三个安装器;LLM key 永不管)。
|
|
26
34
|
* node bin/gotry-bootstrap.js wizard # 会话扩展 onboarding 闭环(issue #21 onboarding UX,§3.3):
|
|
27
35
|
* # 5 步编排 + 后台 health-watch 等扩展心跳,
|
|
28
36
|
* # 扩展一就位 stdout 翻绿并自动重放同 query。
|
|
29
|
-
* # 详见 docs/user-session-data-rfc.md §3.3 / RFC P3.6。
|
|
37
|
+
* # 详见 docs/rfc/user-session-data-rfc.md §3.3 / RFC P3.6。
|
|
30
38
|
*
|
|
31
39
|
* 环境开关:
|
|
32
40
|
* GOTRY_SETUP_SKIP=1 全部跳过
|
|
@@ -46,10 +54,11 @@
|
|
|
46
54
|
*/
|
|
47
55
|
|
|
48
56
|
import { spawn } from 'node:child_process'
|
|
49
|
-
import { copyFileSync, existsSync, mkdirSync, readFileSync } from 'node:fs'
|
|
57
|
+
import { copyFileSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
|
50
58
|
import { homedir } from 'node:os'
|
|
51
59
|
import { join, dirname } from 'node:path'
|
|
52
60
|
import { fileURLToPath } from 'node:url'
|
|
61
|
+
import { createRequire } from 'node:module'
|
|
53
62
|
|
|
54
63
|
const repoRoot = join(dirname(fileURLToPath(import.meta.url)), '..')
|
|
55
64
|
const AUTO = process.argv.includes('--auto')
|
|
@@ -65,9 +74,9 @@ const HBCLI_INSTALL_CMD = 'curl -fsSL https://github.com/hotelbyte-com/docs/rele
|
|
|
65
74
|
const REACH_INSTALL_URL = 'git+https://github.com/Panniantong/Agent-Reach.git'
|
|
66
75
|
|
|
67
76
|
/** 带超时的子进程(inherit stdio 让用户看见上游安装进度) */
|
|
68
|
-
function run(cmd, args, { timeoutMs, cwd } = {}) {
|
|
77
|
+
function run(cmd, args, { timeoutMs, cwd, env } = {}) {
|
|
69
78
|
return new Promise((resolve) => {
|
|
70
|
-
const child = spawn(cmd, args, { stdio: 'inherit', cwd, env: process.env })
|
|
79
|
+
const child = spawn(cmd, args, { stdio: 'inherit', cwd, env: env ?? process.env })
|
|
71
80
|
let done = false
|
|
72
81
|
const timer = setTimeout(() => {
|
|
73
82
|
if (!done) { done = true; try { child.kill('SIGKILL') } catch { /* ignore */ } }
|
|
@@ -135,34 +144,291 @@ async function setupReach() {
|
|
|
135
144
|
return { ok: true }
|
|
136
145
|
}
|
|
137
146
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
147
|
+
/** sidebar 落盘状态 = 与 doctor 检查同口径的唯一事实面(profile 里的 package.json) */
|
|
148
|
+
function sidebarInstalled() {
|
|
149
|
+
return existsSync(join(homedir(), '.dsh/profiles/web/node_modules/dsh-better-sidebar/package.json'))
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** dsh plugin 在 profile 目录里跑 pnpm;pnpm ≥10.5 默认不执行依赖构建脚本,严格态
|
|
153
|
+
* (pnpm 11 默认 / strict-dep-builds)下 ERR_PNPM_IGNORED_BUILDS 直接 exit 1——
|
|
154
|
+
* 但包本身已完整落盘(2026-09-08 实测:exit 1 而 167 包全部就位,doctor 复检即绿)。
|
|
155
|
+
* 对该调用降回警告态(env 只作用于这一次 spawn,不改用户全局 pnpm 配置);
|
|
156
|
+
* 老版本 pnpm 不认识此配置,零影响。 */
|
|
157
|
+
const SIDEBAR_PNPM_ENV = { ...process.env, npm_config_strict_dep_builds: 'false' }
|
|
158
|
+
|
|
159
|
+
async function setupSidebar(attemptInstall) { say('[gotry-setup] dsh-better-sidebar(dsh web 侧栏工作台,产物查看面 issue #25)')
|
|
160
|
+
if (sidebarInstalled()) { say(' ✓ 已安装(~/.dsh/profiles/web)'); return { ok: true } }
|
|
141
161
|
if (CHECK_ONLY) { say(' ✗ 未安装(--check-only 只报告)'); return { ok: true } }
|
|
142
162
|
const SIDEBAR_PKG = 'dsh-better-sidebar@latest'
|
|
143
|
-
// dsh CLI:本包依赖里的 @deepseek-ai/dsh 优先;解析不到走 npx 自拉(官方安装途径同款)
|
|
144
|
-
|
|
163
|
+
// dsh CLI:本包依赖里的 @deepseek-ai/dsh 优先;解析不到走 npx 自拉(官方安装途径同款)。
|
|
164
|
+
// attemptInstall 注入位供测试模拟「安装器失败但状态落盘」(pnpm 忽略构建脚本策略)。
|
|
145
165
|
const require_ = createRequire(join(repoRoot, 'package.json'))
|
|
146
|
-
|
|
166
|
+
const defaultAttempt = async () => {
|
|
167
|
+
try {
|
|
168
|
+
const dshBin = require_.resolve('@deepseek-ai/dsh/lib/bin.js')
|
|
169
|
+
say(` 安装中(dsh plugin → web profile): ${SIDEBAR_PKG}`)
|
|
170
|
+
return await run(process.execPath, [dshBin, 'plugin', '--profile', 'web', 'add', SIDEBAR_PKG], { timeoutMs: 300_000, env: SIDEBAR_PNPM_ENV })
|
|
171
|
+
} catch { return { ok: false, noDsh: true } }
|
|
172
|
+
}
|
|
173
|
+
const r = await (attemptInstall ?? defaultAttempt)()
|
|
174
|
+
if (r.ok) {
|
|
175
|
+
say(' ✓ 安装完成(gotry web 刷新浏览器即见右侧工作台;工作区里的产物 md 可直接预览)')
|
|
176
|
+
return { ok: true }
|
|
177
|
+
}
|
|
178
|
+
// exit 非 0 ≠ 没装上(pnpm 忽略构建脚本策略):先按落盘状态复核,再决定是否回退 npx 途径
|
|
179
|
+
if (sidebarInstalled()) {
|
|
180
|
+
say(' ✓ 安装完成(安装器 exit 非 0,但按落盘状态复核已就位;gotry web 刷新浏览器即见右侧工作台)')
|
|
181
|
+
say(' ⚠ pnpm 跳过了 node-pty(侧栏内嵌终端)的构建脚本——预览功能不受影响;如需内嵌终端:cd ~/.dsh/profiles/web && pnpm approve-builds 勾选 node-pty')
|
|
182
|
+
return { ok: true }
|
|
183
|
+
}
|
|
184
|
+
if (r.noDsh) say(' 本包未携带 @deepseek-ai/dsh,走 npx 途径安装')
|
|
185
|
+
else say(' ✗ dsh plugin 安装失败且未落盘——尝试 npx 途径')
|
|
186
|
+
const r2 = await run('npx', ['-y', '--package', '@deepseek-ai/dsh', 'dsh', 'plugin', '--profile', 'web', 'add', SIDEBAR_PKG], { timeoutMs: 300_000, env: SIDEBAR_PNPM_ENV })
|
|
187
|
+
if (r2.ok) {
|
|
188
|
+
say(' ✓ 安装完成(gotry web 刷新浏览器即见右侧工作台)')
|
|
189
|
+
return { ok: true }
|
|
190
|
+
}
|
|
191
|
+
if (sidebarInstalled()) {
|
|
192
|
+
say(' ✓ 安装完成(npx 途径 exit 非 0,但按落盘状态复核已就位)')
|
|
193
|
+
return { ok: true }
|
|
194
|
+
}
|
|
195
|
+
say(' ✗ 安装失败——不影响 gotry:产物仍可在对话里说「看看我生成的行程」经 gotry_artifacts_list/read 查看;可稍后重试: npx gotry doctor --fix')
|
|
196
|
+
return { ok: false }
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// ---------------------------------------------------------------------------
|
|
200
|
+
// doctor(可选依赖体检;与 ts/capabilities/doctor.ts 同一状态面,-bootstrap 是
|
|
201
|
+
// CLI 执行面纯 JS、capabilities 是 MCP 工具面 TS——两边清单/口径成对修改)
|
|
202
|
+
// ---------------------------------------------------------------------------
|
|
203
|
+
|
|
204
|
+
const DOCTOR = process.argv.includes('doctor')
|
|
205
|
+
const DOCTOR_FIX = process.argv.includes('--fix')
|
|
206
|
+
// calendar 子命令(issue #106/D-9):可选日历挂载的 setup 状态管理面。
|
|
207
|
+
// `gotry setup calendar`=开启;`--off`=关闭(删状态文件恢复默认);`--status`=只读查看。
|
|
208
|
+
const CALENDAR_CMD = process.argv.includes('calendar')
|
|
209
|
+
const CALENDAR_OFF = process.argv.includes('--off')
|
|
210
|
+
const CALENDAR_STATUS = process.argv.includes('--status')
|
|
211
|
+
|
|
212
|
+
// --- calendar setup 状态面(与扩展 manifest 同居 ~/.gotry;运行时 inner 与
|
|
213
|
+
// doctor 两端同读这一份,禁止 env 控制产品行为——founder 2026-09-03 纠偏)---
|
|
214
|
+
function calendarStatePath() { return join(homedir(), '.gotry', 'calendar.json') }
|
|
215
|
+
function readCalendarState() {
|
|
216
|
+
try { return JSON.parse(readFileSync(calendarStatePath(), 'utf8')) } catch { return null }
|
|
217
|
+
}
|
|
218
|
+
function calendarProfileConfigured() {
|
|
147
219
|
try {
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
220
|
+
const patch = readFileSync(join(homedir(), '.dsh', 'profiles', 'web', 'cordis.patch.yml'), 'utf8')
|
|
221
|
+
return /calendar/.test(patch) && /username\s*:/.test(patch)
|
|
222
|
+
} catch { return false }
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/** 挂载/配置双态人话(bootstrap doctor 与 calendar 子命令共用) */
|
|
226
|
+
function calendarDetail(state) {
|
|
227
|
+
if (!state || state.enabled !== true) return '默认未挂载(D-9:未配置的日历工具不进工具箱;工作窗口由访谈覆盖,不影响任何检索)'
|
|
228
|
+
return calendarProfileConfigured()
|
|
229
|
+
? `已挂载且已配置(${calendarStatePath()})`
|
|
230
|
+
: '已挂载但 calendar 未配置 username——日历工具会话中会报「未配置」'
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
async function runCalendar() {
|
|
234
|
+
say('[gotry-setup] dsh-calendar(可选日历,CalDAV 工作窗口读取;默认不挂载)')
|
|
235
|
+
if (CALENDAR_STATUS) {
|
|
236
|
+
const state = readCalendarState()
|
|
237
|
+
say(` 状态: ${calendarDetail(state)}`)
|
|
238
|
+
say(` 状态文件: ${calendarStatePath()}`)
|
|
239
|
+
say(' 说明: 挂载=`npx gotry setup calendar`;关闭=`npx gotry setup calendar --off`;配置在 dsh profile 的 cordis.patch.yml 覆盖 calendar 行 config 填 username')
|
|
240
|
+
return 0
|
|
241
|
+
}
|
|
242
|
+
if (CALENDAR_OFF) {
|
|
243
|
+
try { rmSync(calendarStatePath()) } catch { /* 本就未开启 */ }
|
|
244
|
+
say(' ✓ 已关闭——恢复默认不挂载(状态文件已删除;如需再开: npx gotry setup calendar)')
|
|
245
|
+
return 0
|
|
246
|
+
}
|
|
247
|
+
mkdirSync(dirname(calendarStatePath()), { recursive: true })
|
|
248
|
+
writeFileSync(calendarStatePath(), `${JSON.stringify({ enabled: true, updatedAt: new Date().toISOString() }, null, 2)}\n`, 'utf8')
|
|
249
|
+
say(` ✓ 已开启挂载(状态文件 ${calendarStatePath()};重启 gotry web/headless 生效)`)
|
|
250
|
+
if (calendarProfileConfigured()) {
|
|
251
|
+
say(' ✓ calendar 已在 dsh profile 配置 username——全部就绪')
|
|
252
|
+
} else {
|
|
253
|
+
say(' ⚠ 还差最后一步:在 dsh profile 的 cordis.patch.yml 覆盖 calendar 行的 config,填你的 CalDAV username,例如:')
|
|
254
|
+
say(' - id: dsh-calendar')
|
|
255
|
+
say(' config:')
|
|
256
|
+
say(' username: <你的日历账号>')
|
|
257
|
+
say(' 未配置时日历工具会话中会报「未配置」;不需要日历时可用 --off 恢复默认不挂载。')
|
|
258
|
+
}
|
|
259
|
+
return 0
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/** 逐项只读检查(永不抛错;LLM key 显式让渡给 dsh 宿主,不体检)。
|
|
263
|
+
* level 与 ts/capabilities/doctor.ts DoctorStatus 同构:ok / missing / degraded。 */
|
|
264
|
+
async function doctorChecks() {
|
|
265
|
+
const items = []
|
|
266
|
+
// Node 运行时
|
|
267
|
+
const nv = process.versions.node
|
|
268
|
+
const [maj, min] = nv.split('.').map(Number)
|
|
269
|
+
const nodeFine = maj > 22 || (maj === 22 && min >= 15)
|
|
270
|
+
items.push({ label: 'Node 运行时', ok: nodeFine, level: nodeFine ? 'ok' : 'missing', detail: `Node ${nv}(需 ≥22.15)`, fix: nodeFine ? undefined : '升级 Node.js 至 22.15+(https://nodejs.org)' })
|
|
271
|
+
// 扩展
|
|
272
|
+
const extManifest = join(homedir(), '.gotry', 'extension', 'manifest.json')
|
|
273
|
+
const extOk = existsSync(extManifest)
|
|
274
|
+
items.push({ label: 'GoTry Session Bridge 扩展', ok: extOk, level: extOk ? 'ok' : 'missing', detail: extOk ? `已就位(${extManifest})` : '未安装——gotry_session_search / gotry_session_login(账号会话通道)不可用,其余工具不受影响', fix: extOk ? undefined : '在 Chrome 应用商店一键安装(自动更新): https://chromewebstore.google.com/detail/gotry-session-bridge/oeajpiccmonococjcegddlooeeohlbgd' })
|
|
275
|
+
// agent-reach(.venv 装在包内)
|
|
276
|
+
const venvPython = join(repoRoot, '.venv/bin/python')
|
|
277
|
+
const reachBin = join(repoRoot, '.venv/bin/agent-reach')
|
|
278
|
+
const reachOk = existsSync(reachBin)
|
|
279
|
+
const reachLevel = reachOk ? 'ok' : existsSync(venvPython) ? 'degraded' : 'missing'
|
|
280
|
+
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' })
|
|
281
|
+
// hbcli(裸名靠 PATH 探测;绝对路径 existsSync)
|
|
282
|
+
let hbBin = ''
|
|
283
|
+
for (const p of ['hbcli', join(homedir(), '.local/bin/hbcli'), join(homedir(), '.staicli/current/hbcli')]) {
|
|
284
|
+
if (p === 'hbcli') { if (await probe(p, ['version'])) { hbBin = 'hbcli(PATH)'; break } } else if (existsSync(p)) { hbBin = p; break }
|
|
285
|
+
}
|
|
286
|
+
if (hbBin) {
|
|
287
|
+
const whoami = await probe(hbBin === 'hbcli(PATH)' ? 'hbcli' : hbBin, ['auth', 'whoami'])
|
|
288
|
+
items.push({ label: 'hbcli(酒店实时源)', ok: whoami, level: whoami ? 'ok' : 'degraded', detail: whoami ? `已安装且凭证有效(${hbBin})` : '二进制在,但凭证未配置/失效——酒店检索将降级静态包(非实时)', fix: whoami ? undefined : 'hbcli auth set-credentials --app-key hotelbyte_api_demo --app-secret hotelbyte_api_demo(快速试用沙箱;正式 key 向 HotelByte 申请)' })
|
|
289
|
+
} else {
|
|
290
|
+
items.push({ label: 'hbcli(酒店实时源)', ok: false, level: 'missing', detail: '未安装——酒店检索降级静态包(公开渠道估算,非实时,仅覆盖内置场景)', fix: 'npx gotry doctor --fix' })
|
|
291
|
+
}
|
|
292
|
+
// flyai key(匿名试用额度共享易达限;正式 key 即免)
|
|
293
|
+
const flyaiKey = (process.env.FLYAI_API_KEY ?? '').trim()
|
|
294
|
+
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' })
|
|
295
|
+
// sidebar(状态面与 setupSidebar 的落盘复核同一口径)
|
|
296
|
+
const sbOk = sidebarInstalled()
|
|
297
|
+
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' })
|
|
298
|
+
// dsh-calendar(setup 状态面;默认不挂载=ok 是合法态,opt-in 未配置才 degraded)
|
|
299
|
+
const calState = readCalendarState()
|
|
300
|
+
const calOn = calState?.enabled === true
|
|
301
|
+
const calConfigured = calOn && calendarProfileConfigured()
|
|
302
|
+
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 恢复默认不挂载)' })
|
|
303
|
+
// dsh-map-tools(patch 分发面宿主插件,issue #139):解析失败启动时整块静默剔除,
|
|
304
|
+
// doctor 把两态照亮。候选清单与 bin/gotry-inner.js 解析链、ts/capabilities/doctor.ts 同口径:
|
|
305
|
+
// tarball vendor 副本优先(随 files[] 分发,不进 npm 依赖——其 peerDependencies 要求
|
|
306
|
+
// dsh-settings/dsh-tools >=0.1.2-rc.1,与锁定的 0.1.2-alpha.3 家族在 npm 严格 peer
|
|
307
|
+
// 解析下 ERESOLVE,依赖形态会弄坏 npx 安装),其余覆盖 source/提升/profile 布局。
|
|
308
|
+
const rootRequire = createRequire(join(repoRoot, 'package.json'))
|
|
309
|
+
const mapCandidates = [
|
|
310
|
+
join(repoRoot, 'ts/dsh-runtime/vendor/dsh-map-tools/lib/index.js'),
|
|
311
|
+
join(repoRoot, 'ts/dsh-runtime/node_modules/dsh-map-tools/lib/index.js'),
|
|
312
|
+
join(repoRoot, 'node_modules/dsh-map-tools/package.json'),
|
|
313
|
+
join(repoRoot, 'ts/node_modules/dsh-map-tools/package.json'),
|
|
314
|
+
join(homedir(), '.dsh/profiles/web/node_modules/dsh-map-tools/package.json'),
|
|
315
|
+
]
|
|
316
|
+
let mapHit = mapCandidates.find((p) => existsSync(p))
|
|
317
|
+
// npm 提升布局:gotry 的依赖不在包目录 node_modules 里,而在同级提升位——
|
|
318
|
+
// 与 inner 的 require_.resolve 同机制(createRequire 从包位置向上走查)
|
|
319
|
+
if (!mapHit) { try { mapHit = rootRequire.resolve('dsh-map-tools') } catch { mapHit = undefined } }
|
|
320
|
+
items.push(mapHit
|
|
321
|
+
? { label: 'dsh-map-tools(地图/路线/POI)', ok: true, level: 'ok', detail: `已就位(${mapHit})——地图工具可用(零 key,走 OSM/OSRM)`, fix: undefined }
|
|
322
|
+
: { label: 'dsh-map-tools(地图/路线/POI)', ok: false, level: 'missing', detail: '未随包解析——启动时该 patch 条目被静默剔除,地图/路线/POI 工具不会出现在模型工具箱(缺地图不挡旅行规划,只少能力)', fix: '重装 @danceiny/gotry(地图插件随包 vendor 分发,缺失多为安装不完整)' })
|
|
323
|
+
// dsh-tool-ask-user(结构化澄清卡,人格契约 (5) 的卡片形态载体)
|
|
324
|
+
const askCandidates = [
|
|
325
|
+
join(repoRoot, 'ts/dsh-runtime/vendor/deepseek-ai-dsh-tool-ask-user/package.json'),
|
|
326
|
+
join(repoRoot, 'node_modules/@deepseek-ai/dsh-tool-ask-user/package.json'),
|
|
327
|
+
join(homedir(), '.dsh/profiles/web/node_modules/@deepseek-ai/dsh-tool-ask-user/package.json'),
|
|
328
|
+
]
|
|
329
|
+
let askHit = askCandidates.find((p) => existsSync(p))
|
|
330
|
+
// 与 inner 同口径:优先从 dsh 包上下文解析(pnpm 嵌套布局只有 dsh 看得见),再从包根上下文
|
|
331
|
+
// (npm/npx 提升布局),最后静态候选(source vendored / profile)
|
|
332
|
+
if (!askHit) {
|
|
333
|
+
try {
|
|
334
|
+
const reqFromDsh = createRequire(rootRequire.resolve('@deepseek-ai/dsh/lib/bin.js'))
|
|
335
|
+
askHit = reqFromDsh.resolve('@deepseek-ai/dsh-tool-ask-user')
|
|
336
|
+
} catch {
|
|
337
|
+
try { askHit = rootRequire.resolve('@deepseek-ai/dsh-tool-ask-user') } catch { askHit = undefined }
|
|
155
338
|
}
|
|
156
|
-
say(` ✗ dsh plugin 安装失败(${r.error})——尝试 npx 途径`)
|
|
157
|
-
} catch { /* 本包未携带 @deepseek-ai/dsh */ }
|
|
158
|
-
if (!launched) say(' 本包未携带 @deepseek-ai/dsh,走 npx 途径安装')
|
|
159
|
-
const r2 = await run('npx', ['-y', '--package', '@deepseek-ai/dsh', 'dsh', 'plugin', '--profile', 'web', 'add', SIDEBAR_PKG], { timeoutMs: 300_000 })
|
|
160
|
-
if (!r2.ok) {
|
|
161
|
-
say(' ✗ 安装失败——不影响 gotry:产物仍可在对话里说「看看我生成的行程」经 gotry_artifacts_list/read 查看;可稍后重试: npx gotry setup')
|
|
162
|
-
return { ok: false }
|
|
163
339
|
}
|
|
164
|
-
|
|
165
|
-
|
|
340
|
+
items.push(askHit
|
|
341
|
+
? { label: 'dsh-tool-ask-user(结构化澄清卡)', ok: true, level: 'ok', detail: `已就位(${askHit})——ask_user_question 澄清卡可用(web 原生卡片;headless+TTY 用 stdio 提供方)`, fix: undefined }
|
|
342
|
+
: { label: 'dsh-tool-ask-user(结构化澄清卡)', ok: false, level: 'missing', detail: '未解析——启动时澄清卡注入被静默剔除,模型只能散文追问(人格契约 (5) 退化文本形态)', fix: '重装 @danceiny/gotry——该依赖随 dsh 闭包自带,缺失多为安装不完整' })
|
|
343
|
+
// LLM key:显式让渡(founder 2026-09-02:doctor 不管 key)
|
|
344
|
+
items.push({ label: 'LLM key', ok: true, level: 'ok', detail: '由 dsh 宿主 UI 管理——不在体检范围(gotry 不接触、不回显凭证)', fix: undefined })
|
|
345
|
+
return items
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
const doctorIcon = { ok: '✅', missing: '❌', degraded: '⚠️' }
|
|
349
|
+
|
|
350
|
+
/** 修复指引入表:命令类才加反引号( prose 类如「到控制台申请 key」原样) */
|
|
351
|
+
const fixCell = (fix) => (!fix ? '—' : /^(npx|hbcli|curl|pip|python|\$)/.test(fix) ? `\`${fix}\`` : fix)
|
|
352
|
+
|
|
353
|
+
/** 启动一次性摘要行(issue #114,design §3.1③):全 ok 返回 null(静默零输出);
|
|
354
|
+
* 有待处理项给一行人话 + 指路(对话里 gotry_doctor 看详情 / 终端 npx gotry doctor)。
|
|
355
|
+
* 纯函数,bootstrap-tests 直接断言。 */
|
|
356
|
+
function startupDoctorLine(items) {
|
|
357
|
+
const broken = (items ?? []).filter((i) => i.level && i.level !== 'ok')
|
|
358
|
+
if (broken.length === 0) return null
|
|
359
|
+
const human = (lv) => (lv === 'missing' ? '缺' : '半可用')
|
|
360
|
+
return `[gotry] doctor: ${broken.length} 项待处理(${broken.map((i) => `${i.label}=${human(i.level)}`).join('、')})——对话里让助手调 gotry_doctor 看详情与指引,或终端跑 npx gotry doctor`
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/** 体检报告 markdown(与 ts/capabilities/doctor.ts renderDoctorReportMd 同形) */
|
|
364
|
+
function renderDoctorReportMd(items) {
|
|
365
|
+
const broken = items.filter((i) => i.level !== 'ok' && i.label !== 'LLM key')
|
|
366
|
+
const lines = [
|
|
367
|
+
'# GoTry 依赖体检报告(doctor)',
|
|
368
|
+
'',
|
|
369
|
+
`> 生成于 ${new Date().toISOString()};重新生成:终端 \`npx gotry doctor\`,或在对话里让助手调 gotry_doctor。`,
|
|
370
|
+
'',
|
|
371
|
+
'| 状态 | 依赖 | 现状 | 修复指引 |',
|
|
372
|
+
'|---|---|---|---|',
|
|
373
|
+
...items.map((i) => `| ${doctorIcon[i.level]} | ${i.label} | ${i.detail} | ${fixCell(i.fix)} |`),
|
|
374
|
+
'',
|
|
375
|
+
`**结论**:${broken.length === 0 ? '全部就绪(可选依赖齐,LLM key 归 dsh 宿主管)。' : `${broken.length} 项待处理:${broken.map((i) => i.label).join('、')}。补装: npx gotry doctor --fix`}`,
|
|
376
|
+
'',
|
|
377
|
+
'---',
|
|
378
|
+
'',
|
|
379
|
+
'- `npx gotry doctor` 随时可重跑(只读,不改任何东西);',
|
|
380
|
+
'- `npx gotry doctor --fix` 按上表补装(hbcli 官方脚本 / agent-reach pip / dsh-better-sidebar 插件);',
|
|
381
|
+
'- LLM key 由 dsh 宿主 UI 管理,gotry 永不体检、不回显。',
|
|
382
|
+
'',
|
|
383
|
+
]
|
|
384
|
+
return lines.join('\n')
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/** doctor 主流程:体检 → 打印 →(可选)fix → 报告落盘。
|
|
388
|
+
* exit 0=就绪(或仅剩有自动回退的降级项);exit 1=仍有缺失类问题。 */
|
|
389
|
+
async function runDoctor() {
|
|
390
|
+
let items = await doctorChecks()
|
|
391
|
+
// 启动一次性摘要(issue #114):inner 分离子进程带 --summary 调用——只读体检,
|
|
392
|
+
// 有待处理项打一行 stderr,零写盘零 header;全 ok 静默。与完整体检面(逐项/报告落盘/exit 语义)分离。
|
|
393
|
+
if (process.argv.includes('--summary')) {
|
|
394
|
+
const line = startupDoctorLine(items)
|
|
395
|
+
if (line) console.error(line)
|
|
396
|
+
return 0
|
|
397
|
+
}
|
|
398
|
+
say('[gotry-doctor] GoTry 可选依赖体检(只读;LLM key 归 dsh 宿主管,不在范围)')
|
|
399
|
+
for (const i of items) {
|
|
400
|
+
say(` ${doctorIcon[i.level]} ${i.label}:${i.detail}`)
|
|
401
|
+
if (i.level !== 'ok' && i.fix) say(` ↳ 修复: ${i.fix}`)
|
|
402
|
+
}
|
|
403
|
+
if (DOCTOR_FIX) {
|
|
404
|
+
if (process.platform === 'win32') {
|
|
405
|
+
say('[gotry-doctor] --fix 在 Windows 暂不支持自动安装(hbcli/agent-reach 上游无 win 安装面);请按各项修复指引手动处理')
|
|
406
|
+
} else {
|
|
407
|
+
say('[gotry-doctor] 开始补装缺失项(--fix)…')
|
|
408
|
+
const results = []
|
|
409
|
+
if (process.env.GOTRY_SETUP_HBCLI !== '0') results.push(await setupHbcli())
|
|
410
|
+
if (process.env.GOTRY_SETUP_REACH !== '0') results.push(await setupReach())
|
|
411
|
+
if (process.env.GOTRY_SETUP_SIDEBAR !== '0') results.push(await setupSidebar())
|
|
412
|
+
const failedFix = results.filter((r) => !r.ok).length
|
|
413
|
+
say(failedFix === 0 ? '[gotry-doctor] 补装完成;下面是补装后复检。' : `[gotry-doctor] ${failedFix} 项补装失败——见上方安装器输出;可重跑 npx gotry doctor --fix`)
|
|
414
|
+
items = await doctorChecks()
|
|
415
|
+
for (const i of items) {
|
|
416
|
+
say(` ${doctorIcon[i.level]} ${i.label}:${i.detail}`)
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
// 报告落盘(侧栏工作台预览面;写失败不挡体检结论)
|
|
421
|
+
try {
|
|
422
|
+
const stateDir = join(repoRoot, 'gotry-state')
|
|
423
|
+
mkdirSync(stateDir, { recursive: true })
|
|
424
|
+
writeFileSync(join(stateDir, 'doctor-report.md'), renderDoctorReportMd(items), 'utf8')
|
|
425
|
+
say(`[gotry-doctor] 报告已写: ${join(stateDir, 'doctor-report.md')}(dsh 侧栏工作台可直接预览)`)
|
|
426
|
+
} catch (e) {
|
|
427
|
+
say(`[gotry-doctor] 报告写盘失败(${e.message})——体检结论仍有效`)
|
|
428
|
+
}
|
|
429
|
+
// 降级类(凭证未配/flyai 试用)不挡 exit 0——降级有自动回退路径,缺失类才挡
|
|
430
|
+
const stillMissing = items.filter((i) => i.level === 'missing').length
|
|
431
|
+
return stillMissing === 0 ? 0 : 1
|
|
166
432
|
}
|
|
167
433
|
|
|
168
434
|
const EXTENSION_FILES = ['manifest.json', 'background.js', 'content-main.js', 'content-bridge.js', 'README.md']
|
|
@@ -440,6 +706,13 @@ async function runInlineHealthWatch(timeoutMs) {
|
|
|
440
706
|
}
|
|
441
707
|
|
|
442
708
|
async function main() {
|
|
709
|
+
// calendar 子命令(issue #106/D-9):可选日历挂载的 setup 状态管理(on/off/status)
|
|
710
|
+
if (CALENDAR_CMD) process.exit(await runCalendar())
|
|
711
|
+
|
|
712
|
+
// doctor 子命令(2026-09-02 迪拜 session 复盘):可选依赖体检 + 补装指引/补装执行;
|
|
713
|
+
// 只读体检零副作用(--fix 才装),win32 也可跑体检(fix 面另有提示)。
|
|
714
|
+
if (DOCTOR) process.exit(await runDoctor())
|
|
715
|
+
|
|
443
716
|
// wizard 子命令(2026-09-02 商店上架后退化):**只走 stdout 提示 + 健康探活等待**;
|
|
444
717
|
// 不 spawn 任何 GUI 工具(不动 pbcopy / osascript / open / xdg-open / zenity),
|
|
445
718
|
// 不打开 chrome://extensions,不动扩展路径——浏览器自己当安装器,gotry 不越界。
|
|
@@ -495,7 +768,13 @@ if (WIZARD) {
|
|
|
495
768
|
process.exit(0)
|
|
496
769
|
}
|
|
497
770
|
|
|
498
|
-
main(
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
771
|
+
// 直接执行才跑 main(bootstrap-tests import 本模块做 setupSidebar 单测时不触发安装面;
|
|
772
|
+
// bin/gotry-inner.js 始终以 `node …/gotry-bootstrap.js` 直接 spawn,不受影响)
|
|
773
|
+
if (process.argv[1] && process.argv[1].endsWith('gotry-bootstrap.js')) {
|
|
774
|
+
main().catch((e) => {
|
|
775
|
+
say(`[gotry-setup] 异常:${e.message}(不影响 gotry 本体;可重试 npx gotry setup)`)
|
|
776
|
+
process.exit(AUTO ? 0 : 1)
|
|
777
|
+
})
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
export { setupSidebar, sidebarInstalled }
|
package/bin/gotry-inner.js
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
* 1. 解析 argv + .env(provider-neutral → DEEPSEEK_API_KEY/DEEPSEEK_BASE_URL)
|
|
10
10
|
* 2. 定位 dsh runtime:
|
|
11
11
|
* a. repo checkout / npm 安装 → root package 解析锁定的 @deepseek-ai/dsh
|
|
12
|
-
* b.
|
|
13
|
-
*
|
|
12
|
+
* b. legacy vendored fallback 已按 D-27 移除(issue #120)——root 缺失即
|
|
13
|
+
* fail-closed 报错指重装,不再有「解析成功却跑不起来」的玄学形态
|
|
14
14
|
* 3. 运行时生成 patch(os.tmpdir):把 gotry-tools 插件路径重写为按本包
|
|
15
15
|
* 位置解析的绝对路径 —— 仓内 cordis.gotry-patch.yml 里的 name 行只是
|
|
16
16
|
* 占位(本机绝对路径),随 tarball 分发后对其他机器必错。
|
|
@@ -20,7 +20,7 @@ import { spawn, spawnSync } from 'node:child_process'
|
|
|
20
20
|
import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
|
21
21
|
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
22
22
|
import { dirname, join } from 'node:path'
|
|
23
|
-
import { tmpdir } from 'node:os'
|
|
23
|
+
import { homedir, tmpdir } from 'node:os'
|
|
24
24
|
import { createRequire } from 'node:module'
|
|
25
25
|
import {
|
|
26
26
|
benchmarkRuntimeSupported,
|
|
@@ -39,8 +39,7 @@ const rootRequire = createRequire(join(repoRoot, 'package.json'))
|
|
|
39
39
|
// --- 环境 .env 加载(provider-neutral) ---
|
|
40
40
|
// npm 安装模式优先读用户当前目录的 .env(包目录内不该有凭证);repo 检出读仓根。
|
|
41
41
|
const sourceDshEarly = resolveDshPackage(rootRequire)
|
|
42
|
-
const
|
|
43
|
-
const envCandidates = sourceCheckoutMode || vendoredDshEarly
|
|
42
|
+
const envCandidates = sourceCheckoutMode || sourceDshEarly
|
|
44
43
|
? [join(repoRoot, '.env')]
|
|
45
44
|
: [join(process.cwd(), '.env'), join(repoRoot, '.env')]
|
|
46
45
|
const envLines = []
|
|
@@ -82,24 +81,34 @@ if (help) {
|
|
|
82
81
|
|
|
83
82
|
Usage:
|
|
84
83
|
gotry web # dsh Web UI on http://127.0.0.1:3080
|
|
85
|
-
gotry setup #
|
|
84
|
+
gotry setup # 扩展就位检查/指引(商店一键装)
|
|
85
|
+
gotry setup calendar # 可选日历(CalDAV 工作窗口)挂载开关:默认关;--off 关闭;--status 查看
|
|
86
|
+
gotry doctor # 可选依赖体检:扩展/agent-reach/hbcli/flyai/sidebar 状态 + 补装指引
|
|
87
|
+
gotry doctor --fix # 体检 + 按报告补装(hbcli 官方脚本 / agent-reach pip / sidebar 插件)
|
|
86
88
|
gotry "一段完整任务..." # headless 一问一答
|
|
87
89
|
gotry help # this help
|
|
90
|
+
gotry --version # 版本号(bug 报告必填项)
|
|
88
91
|
|
|
89
92
|
Detail: https://github.com/Danceiny/gotry — README
|
|
90
93
|
`)
|
|
91
94
|
process.exit(0)
|
|
92
95
|
}
|
|
93
96
|
|
|
94
|
-
//
|
|
95
|
-
|
|
97
|
+
// repoRoot 在 npm 安装与源码检出两种形态下都是包根,version 统一从这里取
|
|
98
|
+
if (args[0] === '-v' || args[0] === '--version') {
|
|
99
|
+
console.log(JSON.parse(readFileSync(join(repoRoot, 'package.json'), 'utf-8')).version)
|
|
100
|
+
process.exit(0)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// mode 决定路径: 'web'/'setup'/'doctor'/'help' 是字面命令;否则第一段 args[0] 是任务本身的一部分
|
|
104
|
+
const literal = new Set(['web', 'setup', 'doctor', 'help', '-h', '--help'])
|
|
96
105
|
const isLiteral = literal.has(args[0])
|
|
97
106
|
const mode = isLiteral ? args[0] : 'headless'
|
|
98
107
|
const rest = isLiteral ? args.slice(1) : args
|
|
99
108
|
|
|
100
|
-
// setup
|
|
101
|
-
if (mode === 'setup') {
|
|
102
|
-
const r = spawnSync(process.execPath, [join(here, 'gotry-bootstrap.js'), ...rest], { stdio: 'inherit' })
|
|
109
|
+
// setup/doctor:外部依赖自举与体检,不需要 dsh runtime 与 LLM key,同步分发后即退
|
|
110
|
+
if (mode === 'setup' || mode === 'doctor') {
|
|
111
|
+
const r = spawnSync(process.execPath, [join(here, 'gotry-bootstrap.js'), mode, ...rest], { stdio: 'inherit' })
|
|
103
112
|
process.exit(r.status ?? (r.error ? 1 : 0))
|
|
104
113
|
}
|
|
105
114
|
|
|
@@ -109,8 +118,7 @@ if (!supportsNodeVersion(process.versions.node)) {
|
|
|
109
118
|
process.exit(1)
|
|
110
119
|
}
|
|
111
120
|
|
|
112
|
-
// --- dsh runtime
|
|
113
|
-
const vendoredDsh = join(repoRoot, 'ts/dsh-runtime/node_modules/@deepseek-ai/dsh/lib/bin.js')
|
|
121
|
+
// --- dsh runtime 定位(D-27 清偿,issue #120):仅 root manifest/依赖解析;legacy vendored 回退已移除 ---
|
|
114
122
|
const installedPackageMode = !sourceCheckoutMode
|
|
115
123
|
const selectedDsh = selectDshRuntime({
|
|
116
124
|
repoRoot,
|
|
@@ -133,7 +141,7 @@ if (!dshBin) {
|
|
|
133
141
|
console.error('[gotry] benchmark dsh runtime unavailable')
|
|
134
142
|
process.exit(1)
|
|
135
143
|
}
|
|
136
|
-
console.error(
|
|
144
|
+
console.error('[gotry] 找不到 dsh runtime(依赖里没有 @deepseek-ai/dsh;legacy vendored 回退已按 D-27 移除)。')
|
|
137
145
|
console.error('repo checkout: npm ci && npm --prefix ts ci && node scripts/build-dist.mjs;npm 安装: npm install(检查 node_modules)。')
|
|
138
146
|
process.exit(1)
|
|
139
147
|
}
|
|
@@ -144,12 +152,12 @@ if (benchmarkEnvironmentConfig && !benchmarkRuntimeSupported(selectedDsh)) {
|
|
|
144
152
|
|
|
145
153
|
// --- 运行时 patch:插件路径按本包位置重写为绝对路径 ---
|
|
146
154
|
// 安装包始终指向 dist/ 纯 JS(Node 拒绝 strip node_modules 下的 .ts)。
|
|
147
|
-
// repo
|
|
155
|
+
// repo 检出仅在显式 tsx loader 可用时走 .ts;否则
|
|
148
156
|
// 使用当前 worktree 已构建的 dist,避免 Node strip-only 拒绝参数属性语法。
|
|
149
157
|
const distEntry = join(repoRoot, 'dist/src/index.js')
|
|
150
158
|
const tsEntry = join(repoRoot, 'ts/src/index.ts')
|
|
151
159
|
const tsxLoaderActive = /(?:^|\s)--(?:import|loader)(?:=|\s)(?:"[^"]*tsx[^"]*"|'[^']*tsx[^']*'|\S*tsx\S*)/.test(process.env.NODE_OPTIONS ?? '')
|
|
152
|
-
const sourceTypeScriptMode = !installedPackageMode &&
|
|
160
|
+
const sourceTypeScriptMode = !installedPackageMode && tsxLoaderActive
|
|
153
161
|
const pluginEntry = !sourceTypeScriptMode && existsSync(distEntry) ? distEntry : tsEntry
|
|
154
162
|
const distModuleMode = pluginEntry === distEntry
|
|
155
163
|
const staticPatch = join(repoRoot, 'cordis.gotry-patch.yml')
|
|
@@ -357,17 +365,29 @@ if (benchmarkEnvironmentConfig) {
|
|
|
357
365
|
process.exit(1)
|
|
358
366
|
}
|
|
359
367
|
}
|
|
360
|
-
// dsh-map-tools 宿主插件(地图/路线/POI,零 key 走 OSM/OSRM):
|
|
361
|
-
//
|
|
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 安装。
|
|
362
373
|
let mapEntry = ''
|
|
363
374
|
if (!benchmarkEnvironmentConfig) {
|
|
364
|
-
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/* 链接形态)
|
|
365
379
|
if (existsSync(vendoredMap)) {
|
|
366
380
|
mapEntry = vendoredMap
|
|
381
|
+
} else if (existsSync(runtimeMap)) {
|
|
382
|
+
mapEntry = runtimeMap
|
|
367
383
|
} else {
|
|
368
384
|
// npm 布局:子路径可能被 exports 挡(resolve 抛错不能留下旧值),裸包名返回真实入口
|
|
369
385
|
try { mapEntry = require_.resolve('dsh-map-tools/lib/index.js') } catch { mapEntry = '' }
|
|
370
386
|
if (!mapEntry) { try { mapEntry = require_.resolve('dsh-map-tools') } catch { mapEntry = '' } }
|
|
387
|
+
if (!mapEntry) {
|
|
388
|
+
// ts/node_modules 回退(source 模式:dsh-map-tools 安装在 ts/package.json)
|
|
389
|
+
try { mapEntry = require_.resolve(join(repoRoot, 'ts/node_modules/dsh-map-tools')) } catch { mapEntry = '' }
|
|
390
|
+
}
|
|
371
391
|
}
|
|
372
392
|
}
|
|
373
393
|
// 结构化澄清卡(T2):ask_user_question 工具 + user-questions 服务,从 dsh 包
|
|
@@ -399,8 +419,16 @@ if (mapEntry) {
|
|
|
399
419
|
patchRaw = patchRaw.replace(/\n\s*- id: dsh-map-tools\n\s*name: 'placeholder\/dsh-map-tools'\n/, '\n')
|
|
400
420
|
}
|
|
401
421
|
|
|
402
|
-
// dsh-calendar 宿主插件(CalDAV
|
|
403
|
-
//
|
|
422
|
+
// dsh-calendar 宿主插件(CalDAV 工作窗口读取)——D-9 拍板(issue #106):默认不挂载。
|
|
423
|
+
// 未配置的日历工具是纯负资产(会话中段才撞「未配置 username」报错),gotry 对它的
|
|
424
|
+
// 唯一诉求(工作窗口)由访谈首轮覆盖。挂载与否由 **setup 状态面**决定(founder
|
|
425
|
+
// 2026-09-03 纠偏:禁止环境变量控制产品行为;可选依赖进 setup 状态管理,与扩展
|
|
426
|
+
// manifest 同居 ~/.gotry)——`npx gotry setup calendar` 写 ~/.gotry/calendar.json,
|
|
427
|
+
// `--off` 删除恢复默认;doctor 报告三态。
|
|
428
|
+
let calEnabled = false
|
|
429
|
+
try {
|
|
430
|
+
calEnabled = JSON.parse(readFileSync(join(homedir(), '.gotry', 'calendar.json'), 'utf-8'))?.enabled === true
|
|
431
|
+
} catch { /* 缺文件/坏文件 = 默认不挂载 */ }
|
|
404
432
|
let calEntry = ''
|
|
405
433
|
if (!benchmarkEnvironmentConfig) {
|
|
406
434
|
const vendoredCal = join(repoRoot, 'ts/dsh-runtime/node_modules/dsh-calendar/lib/index.js')
|
|
@@ -411,7 +439,7 @@ if (!benchmarkEnvironmentConfig) {
|
|
|
411
439
|
if (!calEntry) { try { calEntry = require_.resolve('dsh-calendar') } catch { calEntry = '' } }
|
|
412
440
|
}
|
|
413
441
|
}
|
|
414
|
-
if (calEntry &&
|
|
442
|
+
if (calEntry && calEnabled) {
|
|
415
443
|
patchRaw = patchRaw.replace(/(name:\s*)'placeholder\/dsh-calendar'/, `$1'${calEntry}'`)
|
|
416
444
|
} else {
|
|
417
445
|
patchRaw = patchRaw.replace(/\n\s*- id: dsh-calendar\n\s*name: 'placeholder\/dsh-calendar'\n/, '\n')
|
|
@@ -423,9 +451,21 @@ if (calEntry && process.env.GOTRY_DISABLE_OPTIONAL_CALENDAR !== '1') {
|
|
|
423
451
|
// 两条目标在 headless/web profile 均有(dsh-base 声明 llm-deepseek、两 profile 均声明
|
|
424
452
|
// agent-default-model)。llm-deepseek 目录整体替换为单条目:显式指定模型的场景多为
|
|
425
453
|
// 中转/兼容端点,默认 v4-* 目录对其是误导;不硬编码上游 DEFAULT_MODELS 防漂移。
|
|
454
|
+
let llmMaxTokens
|
|
426
455
|
if (process.env.GOTRY_LLM_MODEL) {
|
|
456
|
+
const rawMax = process.env.LLM_MAX_TOKENS
|
|
457
|
+
if (rawMax !== undefined && rawMax !== '') {
|
|
458
|
+
llmMaxTokens = Number.parseInt(rawMax, 10)
|
|
459
|
+
if (!Number.isSafeInteger(llmMaxTokens) || llmMaxTokens <= 0) {
|
|
460
|
+
throw new Error(`invalid LLM_MAX_TOKENS: ${JSON.stringify(rawMax)} (expected a positive safe integer)`)
|
|
461
|
+
}
|
|
462
|
+
}
|
|
427
463
|
const modelYaml = `'${process.env.GOTRY_LLM_MODEL.replace(/'/g, "''")}'`
|
|
428
|
-
|
|
464
|
+
// LLM_MAX_TOKENS(Round 9,#100/#102):中转/兼容端点模型常带低于 dsh 未知模型
|
|
465
|
+
// 默认 256K 预算的输出上限(MiniMax 2013 实测);目录条目 maxTokens 元数据是
|
|
466
|
+
// dsh-llm-deepseek defaultMaxTokens 的官方通道(web UI 模型同源)。
|
|
467
|
+
const maxTokensYaml = llmMaxTokens === undefined ? '' : `\n maxTokens: ${llmMaxTokens}`
|
|
468
|
+
patchRaw += `\n# LLM_MODEL 指定模型(issue #77):dsh 会话面默认模型 + 模型目录\n- id: agent-default-model\n config:\n provider: deepseek-official\n model: ${modelYaml}\n- id: llm-deepseek\n config:\n models:\n - id: ${modelYaml}\n name: ${modelYaml}${maxTokensYaml}\n`
|
|
429
469
|
}
|
|
430
470
|
// Keep the patch private and short-lived. mkdtempSync creates a 0700 directory;
|
|
431
471
|
// wx prevents accidental reuse/races if a process is started concurrently.
|
|
@@ -477,6 +517,17 @@ const childStdio = mode === 'web'
|
|
|
477
517
|
let benchmarkCapturedBytes = 0
|
|
478
518
|
let benchmarkDiagnosticBuffer = Buffer.alloc(0)
|
|
479
519
|
let benchmarkOutputTruncated = false
|
|
520
|
+
// 启动一次性 doctor 摘要(issue #114,design §3.1③):分离子进程后台跑只读体检,
|
|
521
|
+
// 有待处理项打一行 stderr(stderr 继承,不污染 stdout;benchmark 面保持零杂音)。
|
|
522
|
+
// detached+unref:不阻塞不拖慢启动;inner 生命周期天然一次,不重复刷;失败静默。
|
|
523
|
+
if (!benchmarkEnvironmentConfig) {
|
|
524
|
+
try {
|
|
525
|
+
spawn(process.execPath, [join(here, 'gotry-bootstrap.js'), 'doctor', '--summary'], {
|
|
526
|
+
detached: true,
|
|
527
|
+
stdio: ['ignore', 'ignore', 'inherit'],
|
|
528
|
+
}).unref()
|
|
529
|
+
} catch { /* 体检不可用不挡启动 */ }
|
|
530
|
+
}
|
|
480
531
|
child = spawn(process.execPath, [dshBin, ...binJs], {
|
|
481
532
|
stdio: childStdio,
|
|
482
533
|
env: childEnv,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readFileSync } from 'node:fs'
|
|
2
2
|
import { dirname, join } from 'node:path'
|
|
3
3
|
|
|
4
4
|
export const REQUIRED_BENCHMARK_DSH_VERSION = '0.1.2-alpha.3'
|
|
@@ -29,15 +29,14 @@ export function supportsNodeVersion(version) {
|
|
|
29
29
|
return major > 22 || (major === 22 && minor >= 15)
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
export function selectDshRuntime({
|
|
32
|
+
export function selectDshRuntime({ rootResolver }) {
|
|
33
33
|
const root = resolveDshPackage(rootResolver)
|
|
34
34
|
if (root) return { ...root, source: 'root' }
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
return vendored ? { ...vendored, source: 'legacy-vendored' } : null
|
|
35
|
+
// D-27 清偿(issue #120):legacy vendored 回退路径已移除——该形态的 Node 兼容窗口
|
|
36
|
+
// 断裂(Round 5 起「不承诺可运行」),解析成功只会把「dsh 缺失」变成下游玄学失败。
|
|
37
|
+
// 唯一受支持形态 = root manifest / 依赖解析(216 精确依赖闭包);找不到即 fail-closed,
|
|
38
|
+
// 由调用方给明确重装指引。benchmark 原本就禁用回退,语义不变(入参保留以稳调用面)。
|
|
39
|
+
return null
|
|
41
40
|
}
|
|
42
41
|
|
|
43
42
|
export function benchmarkRuntimeSupported(runtime) {
|