@danceiny/gotry 0.0.1-rc.15 → 0.0.1-rc.17

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.
Files changed (238) hide show
  1. package/README.md +51 -13
  2. package/README.zh-CN.md +26 -12
  3. package/bin/gotry-booking-copilot.js +53 -0
  4. package/bin/gotry-bootstrap.js +357 -8
  5. package/bin/gotry-inner.js +442 -60
  6. package/bin/gotry-runtime-resolution.d.ts +27 -0
  7. package/bin/gotry-runtime-resolution.js +50 -0
  8. package/bin/gotry.js +1 -1
  9. package/cordis.gotry-patch.yml +15 -1
  10. package/data/airline-airports.json +39 -0
  11. package/dist/capabilities/agent-reach-deep.js +1 -1
  12. package/dist/capabilities/agent-reach.js +1 -1
  13. package/dist/capabilities/anything.js +1 -1
  14. package/dist/capabilities/artifacts.js +1 -1
  15. package/dist/capabilities/effect.js +293 -0
  16. package/dist/capabilities/fact-log.js +41 -0
  17. package/dist/capabilities/flyai.js +20 -6
  18. package/dist/capabilities/hbcli.js +43 -1
  19. package/dist/capabilities/incident-log.js +1 -1
  20. package/dist/capabilities/model-override.js +18 -0
  21. package/dist/capabilities/opensky.js +1 -1
  22. package/dist/capabilities/resilience.js +90 -0
  23. package/dist/capabilities/session/action-cache.js +1 -1
  24. package/dist/capabilities/session/adapters/ctrip-flight.js +1 -1
  25. package/dist/capabilities/session/adapters/meituan-local.js +1 -1
  26. package/dist/capabilities/session/benchmark.js +2 -1
  27. package/dist/capabilities/session/extension-bridge.js +358 -0
  28. package/dist/capabilities/session/extension-channel.js +93 -0
  29. package/dist/capabilities/session/extension-distribution.js +234 -0
  30. package/dist/capabilities/session/extract.js +1 -1
  31. package/dist/capabilities/session/golden-score.js +92 -0
  32. package/dist/capabilities/session/health-watch.js +216 -0
  33. package/dist/capabilities/session/read-guard.js +1 -1
  34. package/dist/capabilities/session/static-flight-golden.js +137 -0
  35. package/dist/capabilities/session/transport.js +1 -1
  36. package/dist/capabilities/session/wizard.js +147 -0
  37. package/dist/capabilities/session-consent.js +1 -1
  38. package/dist/capabilities/session-login.js +83 -1
  39. package/dist/capabilities/session-search.js +111 -2
  40. package/dist/capabilities/weather.js +168 -46
  41. package/dist/data/session-golden-20.json +25 -0
  42. package/dist/data/sf-golden-manifest.json +102 -0
  43. package/dist/data/sf-static-routes.json +91 -0
  44. package/dist/scripts/action-cache-tests.js +1 -1
  45. package/dist/scripts/agent-planning-budget-e2e.js +227 -0
  46. package/dist/scripts/agent-planning-budget-tests.js +173 -0
  47. package/dist/scripts/agent-reach-deep-tests.js +1 -1
  48. package/dist/scripts/agent-reach-tests.js +1 -1
  49. package/dist/scripts/agent-reach-wrapper-tests.js +1 -1
  50. package/dist/scripts/anything-tests.js +1 -1
  51. package/dist/scripts/async-collect.js +1 -1
  52. package/dist/scripts/benchmark-environment-bridge-e2e.js +981 -0
  53. package/dist/scripts/benchmark-environment-bridge-tests.js +2544 -0
  54. package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +335 -0
  55. package/dist/scripts/booking-copilot-availability-policy-v2-tests.js +1355 -0
  56. package/dist/scripts/booking-copilot-bin-proof-tests.js +89 -0
  57. package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +113 -0
  58. package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +356 -0
  59. package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +557 -0
  60. package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +140 -0
  61. package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +202 -0
  62. package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +102 -0
  63. package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +374 -0
  64. package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +447 -0
  65. package/dist/scripts/booking-copilot-runtime-proof-tests.js +205 -0
  66. package/dist/scripts/booking-copilot-server-proof-tests.js +317 -0
  67. package/dist/scripts/booking-copilot-startup-proof-tests.js +283 -0
  68. package/dist/scripts/booking-copilot-v2-runtime-proof-tests.js +3935 -0
  69. package/dist/scripts/booking-saga-tests.js +1 -1
  70. package/dist/scripts/booking-surface-contract-proof-tests.js +393 -0
  71. package/dist/scripts/booking-surface-v2-contract-proof-tests.js +1174 -0
  72. package/dist/scripts/bootstrap-tests.js +59 -3
  73. package/dist/scripts/build-changelog.js +279 -0
  74. package/dist/scripts/changelog-tests.js +165 -0
  75. package/dist/scripts/companion-tests.js +1 -1
  76. package/dist/scripts/diff-test.js +1 -1
  77. package/dist/scripts/dsh-runtime-closure-tests.js +225 -0
  78. package/dist/scripts/dsh-runtime-closure.js +150 -0
  79. package/dist/scripts/effect-tests.js +474 -0
  80. package/dist/scripts/engine-run.js +1 -1
  81. package/dist/scripts/engine-tests.js +1 -1
  82. package/dist/scripts/evaluation-cadence-tests.js +347 -0
  83. package/dist/scripts/evaluation-contract-tests.js +574 -0
  84. package/dist/scripts/extension-distribution-cli.js +35 -0
  85. package/dist/scripts/extension-distribution-tests.js +341 -0
  86. package/dist/scripts/extension-tests.js +573 -0
  87. package/dist/scripts/fact-gate-tests.js +318 -0
  88. package/dist/scripts/flyai-tests.js +1 -1
  89. package/dist/scripts/hbcli-e2e-tests.js +180 -0
  90. package/dist/scripts/hbcli-tests.js +1 -1
  91. package/dist/scripts/health-watch-cli.js +51 -0
  92. package/dist/scripts/i18n-tests.js +1 -1
  93. package/dist/scripts/incident-tests.js +1 -1
  94. package/dist/scripts/journey-tests.js +1 -1
  95. package/dist/scripts/ledger-tests.js +1 -1
  96. package/dist/scripts/ledger-workflow-crash.js +1 -1
  97. package/dist/scripts/memory-capture-tests.js +1 -1
  98. package/dist/scripts/memory-decay-tests.js +1 -1
  99. package/dist/scripts/memory-metrics.js +1 -1
  100. package/dist/scripts/memory-value-report.js +1 -1
  101. package/dist/scripts/model-override-e2e.js +176 -0
  102. package/dist/scripts/nightly-evidence-tests.js +67 -4
  103. package/dist/scripts/nightly-evidence.js +59 -3
  104. package/dist/scripts/nudge-digest.js +1 -1
  105. package/dist/scripts/onboarding-tests.js +186 -0
  106. package/dist/scripts/opensky-check.js +1 -1
  107. package/dist/scripts/opensky-tests.js +1 -1
  108. package/dist/scripts/pnpm-dsh-closure-proof.js +20 -0
  109. package/dist/scripts/price-drift-tests.js +441 -0
  110. package/dist/scripts/price-drift-watch.js +491 -0
  111. package/dist/scripts/probe-poi-tests.js +1 -1
  112. package/dist/scripts/product-metrics.js +1 -1
  113. package/dist/scripts/publish-preverify.js +40 -4
  114. package/dist/scripts/realtime-pricing-tests.js +1 -1
  115. package/dist/scripts/replay-async.js +1 -1
  116. package/dist/scripts/replay-real.js +1 -1
  117. package/dist/scripts/replay.js +1 -1
  118. package/dist/scripts/session-attach-diagnose.js +1 -1
  119. package/dist/scripts/session-attach-poc.js +1 -1
  120. package/dist/scripts/session-benchmark.js +1 -1
  121. package/dist/scripts/session-extract-tests.js +1 -1
  122. package/dist/scripts/session-login.js +1 -1
  123. package/dist/scripts/session-tests.js +70 -20
  124. package/dist/scripts/sf-live-benchmark.js +338 -0
  125. package/dist/scripts/sf-live-cli-tests.js +21 -0
  126. package/dist/scripts/sf-soft-score-tests.js +108 -0
  127. package/dist/scripts/sf-summary.js +93 -0
  128. package/dist/scripts/skeleton-check.js +1 -1
  129. package/dist/scripts/skeleton-integration-test.js +1 -1
  130. package/dist/scripts/skills-contract-tests.js +1 -1
  131. package/dist/scripts/smoke-session-gate-tests.js +29 -0
  132. package/dist/scripts/smoke.js +154 -33
  133. package/dist/scripts/state-cli-tests.js +1 -1
  134. package/dist/scripts/state-cli.js +1 -1
  135. package/dist/scripts/static-golden-tests.js +299 -0
  136. package/dist/scripts/time-eval-tests.js +1 -1
  137. package/dist/scripts/travel-timeline-tests.js +1 -1
  138. package/dist/scripts/unified-tests.js +1 -1
  139. package/dist/scripts/weather-tests.js +694 -44
  140. package/dist/scripts/z3-race-tests.js +1 -1
  141. package/dist/src/artifact-gate.js +310 -0
  142. package/dist/src/benchmark-agent-conformance.js +370 -0
  143. package/dist/src/benchmark-environment-bridge.js +384 -0
  144. package/dist/src/benchmark-headless-child-diagnostics.js +173 -0
  145. package/dist/src/benchmark-tool-isolation.js +124 -0
  146. package/dist/src/bookable-facts.js +349 -0
  147. package/dist/src/booking-saga.js +1 -1
  148. package/dist/src/booking-surface/availability-policy-v2.js +830 -0
  149. package/dist/src/booking-surface/canonical-schema.js +113 -0
  150. package/dist/src/booking-surface/contracts-v2.js +89 -0
  151. package/dist/src/booking-surface/contracts.js +46 -0
  152. package/dist/src/booking-surface/dsh-planner.js +453 -0
  153. package/dist/src/booking-surface/dsh-plugin.js +93 -0
  154. package/dist/src/booking-surface/error-codes.js +94 -0
  155. package/dist/src/booking-surface/index.js +15 -0
  156. package/dist/src/booking-surface/profile.js +68 -0
  157. package/dist/src/booking-surface/runtime-v2.js +1771 -0
  158. package/dist/src/booking-surface/runtime.js +351 -0
  159. package/dist/src/booking-surface/server-v2.js +334 -0
  160. package/dist/src/booking-surface/server.js +302 -0
  161. package/dist/src/booking-surface/startup.js +159 -0
  162. package/dist/src/booking-surface/validation-v2.js +319 -0
  163. package/dist/src/booking-surface/validation.js +809 -0
  164. package/dist/src/bridge.js +1 -1
  165. package/dist/src/companions.js +1 -1
  166. package/dist/src/contracts.js +1 -1
  167. package/dist/src/dsh-llm.js +1 -1
  168. package/dist/src/engine.js +1 -1
  169. package/dist/src/evaluation-cadence.js +234 -0
  170. package/dist/src/evaluation-contracts.js +906 -0
  171. package/dist/src/i18n.js +1 -1
  172. package/dist/src/index.js +234 -60
  173. package/dist/src/journey.js +1 -1
  174. package/dist/src/loop.js +1 -1
  175. package/dist/src/memory-capture.js +1 -1
  176. package/dist/src/memory-decay.js +1 -1
  177. package/dist/src/memory-utility.js +1 -1
  178. package/dist/src/mock-llm.js +1 -1
  179. package/dist/src/model.js +1 -1
  180. package/dist/src/realtime-pricing.js +14 -7
  181. package/dist/src/slot-spec.js +1 -1
  182. package/dist/src/state-ledger.js +2 -1
  183. package/dist/src/time-anchor.js +1 -1
  184. package/dist/src/tool-budget.js +136 -0
  185. package/dist/src/tool-packet.js +1 -1
  186. package/dist/src/travel-slots.js +1 -1
  187. package/dist/src/travel-timeline.js +1 -1
  188. package/dist/src/unified.js +1 -1
  189. package/dist/src/wish-pool.js +1 -1
  190. package/dist/src/z3-shared.js +1 -1
  191. package/extension/README.md +50 -0
  192. package/extension/background.js +160 -0
  193. package/extension/content-bridge.js +41 -0
  194. package/extension/content-main.js +62 -0
  195. package/extension/manifest.json +32 -0
  196. package/package.json +291 -12
  197. package/schemas/booking.surface.v1.schema.json +927 -0
  198. package/schemas/booking.surface.v2.schema.json +61 -0
  199. package/ts/capabilities/fact-log.ts +54 -0
  200. package/ts/capabilities/flyai.ts +16 -3
  201. package/ts/capabilities/hbcli.ts +46 -0
  202. package/ts/capabilities/session/benchmark.ts +4 -1
  203. package/ts/capabilities/session/extension-bridge.ts +377 -0
  204. package/ts/capabilities/session/extension-channel.ts +95 -0
  205. package/ts/capabilities/session/extension-distribution.ts +264 -0
  206. package/ts/capabilities/session/golden-score.ts +139 -0
  207. package/ts/capabilities/session/health-watch.ts +257 -0
  208. package/ts/capabilities/session/static-flight-golden.ts +209 -0
  209. package/ts/capabilities/session/wizard.ts +140 -0
  210. package/ts/capabilities/session-login.ts +63 -2
  211. package/ts/capabilities/session-search.ts +105 -3
  212. package/ts/capabilities/weather.ts +141 -52
  213. package/ts/package.json +3 -3
  214. package/ts/src/artifact-gate.ts +365 -0
  215. package/ts/src/benchmark-agent-conformance.ts +448 -0
  216. package/ts/src/benchmark-environment-bridge.ts +348 -0
  217. package/ts/src/benchmark-headless-child-diagnostics.ts +184 -0
  218. package/ts/src/benchmark-tool-isolation.ts +166 -0
  219. package/ts/src/bookable-facts.ts +557 -0
  220. package/ts/src/booking-surface/availability-policy-v2.ts +523 -0
  221. package/ts/src/booking-surface/canonical-schema.js +113 -0
  222. package/ts/src/booking-surface/contracts-v2.ts +118 -0
  223. package/ts/src/booking-surface/contracts.ts +380 -0
  224. package/ts/src/booking-surface/dsh-planner.ts +452 -0
  225. package/ts/src/booking-surface/dsh-plugin.js +93 -0
  226. package/ts/src/booking-surface/error-codes.ts +101 -0
  227. package/ts/src/booking-surface/index.ts +12 -0
  228. package/ts/src/booking-surface/profile.ts +42 -0
  229. package/ts/src/booking-surface/runtime-v2.ts +1466 -0
  230. package/ts/src/booking-surface/runtime.ts +483 -0
  231. package/ts/src/booking-surface/server-v2.ts +247 -0
  232. package/ts/src/booking-surface/server.ts +324 -0
  233. package/ts/src/booking-surface/startup.ts +196 -0
  234. package/ts/src/booking-surface/validation-v2.ts +205 -0
  235. package/ts/src/booking-surface/validation.ts +453 -0
  236. package/ts/src/index.ts +161 -14
  237. package/ts/src/state-ledger.ts +1 -0
  238. package/ts/src/tool-budget.ts +165 -0
@@ -8,25 +8,45 @@
8
8
  * dsh web 侧栏工作台(文件浏览/Markdown/Mermaid/PDF 预览)——
9
9
  * gotry 产物(工单交付 md/行程 md)的成熟查看面(issue #25)。
10
10
  * 宿主层安装(dsh plugin → ~/.dsh/profiles/web),不进 gotry 依赖。
11
+ * gotry-session-bridge → 会话检索浏览器扩展(issue #21 传输层方案 C,2026-08-29 定案):
12
+ * 一次性安装替代逐连接 CDP 弹窗;已上架 Chrome Web Store
13
+ * (2026-09-02,一键装+自动更新)。**gory 不介入浏览器**——
14
+ * 商店页安装是浏览器的事;`gotry setup wizard` 仅作离线检测的
15
+ * 进程护栏(打印商店 URL + 健康探活等待),不动剪贴板、
16
+ * 不弹 osascript、不 open 浏览器。
11
17
  *
12
18
  * 用法:
13
19
  * node bin/gotry-bootstrap.js # 显式安装(缺啥装啥;失败 exit 1)
14
20
  * node bin/gotry-bootstrap.js --auto # postinstall 模式:CI/跳过开关检测,任何失败不挡安装(exit 0)
15
21
  * node bin/gotry-bootstrap.js --check-only # 只探测报告,不安装(测试钩子)
22
+ * node bin/gotry-bootstrap.js --extension-from=github
23
+ * # 扩展改走 GitHub Releases 下载通道(ADR-21):
24
+ * # dist-manifest → tar.gz → SHA256 → key 钉扎 → 原子交换;
25
+ * # 任何失败显式降级回包内副本(离线确定性不变)。
26
+ * node bin/gotry-bootstrap.js wizard # 会话扩展 onboarding 闭环(issue #21 onboarding UX,§3.3):
27
+ * # 5 步编排 + 后台 health-watch 等扩展心跳,
28
+ * # 扩展一就位 stdout 翻绿并自动重放同 query。
29
+ * # 详见 docs/user-session-data-rfc.md §3.3 / RFC P3.6。
16
30
  *
17
31
  * 环境开关:
18
32
  * GOTRY_SETUP_SKIP=1 全部跳过
19
33
  * GOTRY_SETUP_HBCLI=0 跳过 hbcli
20
34
  * GOTRY_SETUP_REACH=0 跳过 agent-reach
21
35
  * GOTRY_SETUP_SIDEBAR=0 跳过 dsh-better-sidebar
36
+ * GOTRY_SETUP_EXTENSION=0 跳过会话检索扩展落位
37
+ * GOTRY_EXTENSION_SOURCE=github 等效 --extension-from=github(显式 opt-in,默认 bundled)
38
+ * GOTRY_EXTENSION_RELEASE_BASE=<url> 下载通道基址覆盖(镜像/测试;缺省 GitHub 官方)
39
+ * GOTRY_ONBOARDING_HEADLESS=1 wizard 仅 stdout(SSH/CI 默认探测)
22
40
  *
23
- * 契约:安装外部依赖永远不挡 gotry 本体——能力层各有降级路径(静态包/not-installed
24
- * verdict),自举失败只降级体验,不产生故障。凭证(hbcli auth / agent-reach 渠道
25
- * cookie)属用户资产,不自动配置,装完二进制后给指引。
41
+ * 设计纪律(wizard 子命令,2026-09-02 商店上架后):
42
+ * **浏览器自己当安装器**——浏览器商店页直达,点「添加至 Chrome」即完事;gotry
43
+ * 不扮演 GUI/CLI 越界者:不动剪贴板、不动 osascript/zenity/msg、不 open 浏览器。
44
+ * dsh host UI 是 gotry 工具渲染面,needs-extension 时 URL 走 verdict 字段给 UI
45
+ * 自渲。wizard 子命令退化为「离线健康探活等待」,只输出 stdout,不挡用户。
26
46
  */
27
47
 
28
48
  import { spawn } from 'node:child_process'
29
- import { existsSync } from 'node:fs'
49
+ import { copyFileSync, existsSync, mkdirSync, readFileSync } from 'node:fs'
30
50
  import { homedir } from 'node:os'
31
51
  import { join, dirname } from 'node:path'
32
52
  import { fileURLToPath } from 'node:url'
@@ -34,6 +54,12 @@ import { fileURLToPath } from 'node:url'
34
54
  const repoRoot = join(dirname(fileURLToPath(import.meta.url)), '..')
35
55
  const AUTO = process.argv.includes('--auto')
36
56
  const CHECK_ONLY = process.argv.includes('--check-only')
57
+ const WIZARD = process.argv.includes('wizard') || process.argv.includes('--wizard')
58
+ const WIZARD_DRY_RUN = process.argv.includes('--dry-run')
59
+ // 扩展分发源(ADR-21):默认 bundled(包内副本,离线确定性);github 显式 opt-in
60
+ // (镜像 GOTRY_SESSION_TRANSPORT=cdp 的显式 opt-in 文化——不静默引入网络依赖)
61
+ const EXT_FROM_ARG = (process.argv.find((a) => a.startsWith('--extension-from=')) ?? '').split('=')[1]
62
+ const EXTENSION_FROM = EXT_FROM_ARG === 'github' || EXT_FROM_ARG === 'bundled' ? EXT_FROM_ARG : process.env.GOTRY_EXTENSION_SOURCE === 'github' ? 'github' : 'bundled'
37
63
 
38
64
  const HBCLI_INSTALL_CMD = 'curl -fsSL https://github.com/hotelbyte-com/docs/releases/latest/download/install.sh | bash'
39
65
  const REACH_INSTALL_URL = 'git+https://github.com/Panniantong/Agent-Reach.git'
@@ -68,7 +94,14 @@ async function setupHbcli() {
68
94
  say('[gotry-setup] hbcli(hotelbyte-cli,可选酒店实时源)')
69
95
  const candidates = ['hbcli', join(homedir(), '.local/bin/hbcli'), join(homedir(), '.staicli/current/hbcli')]
70
96
  const present = candidates.some((p) => existsSync(p)) && (await probe(candidates[0], ['version']) || await probe(candidates[1], ['version']) || await probe(candidates[2], ['version']))
71
- if (present) { say(' ✓ 已安装'); return { ok: true } }
97
+ const credFile = join(homedir(), '.staicli', 'credentials.json')
98
+ if (present) {
99
+ say(' ✓ 已安装')
100
+ if (existsSync(credFile)) say(' ✓ 凭证已配置(自检: hbcli auth whoami)')
101
+ else say(' ✗ 凭证未配置——酒店检索将用内置静态包(非实时),账号配置见下方指引')
102
+ if (CHECK_ONLY) say(' (--check-only 只报告,不安装)')
103
+ return { ok: true }
104
+ }
72
105
  if (CHECK_ONLY) { say(' ✗ 未安装(--check-only 只报告)'); return { ok: true } }
73
106
  say(` 安装中(官方脚本): ${HBCLI_INSTALL_CMD}`)
74
107
  const r = await run('bash', ['-c', HBCLI_INSTALL_CMD], { timeoutMs: 120_000 })
@@ -77,7 +110,11 @@ async function setupHbcli() {
77
110
  if (!process.env.PATH.split(':').includes(binDir)) {
78
111
  say(` ⚠ ${binDir} 不在当前 PATH —— gotry 工具已内建候选路径回退,无需手动处理;其他程序可用: export PATH="${binDir}:$PATH"`)
79
112
  }
80
- say(' ✓ 安装完成(凭证选配: hbcli auth set-credentials --app-key ... --app-secret ...,或 HOTELBYTE_TOKEN;未配时酒店检索自动用静态包)')
113
+ say(' ✓ 安装完成——账号配置(未配时酒店检索自动用静态包,非实时):')
114
+ say(' · 快速试用(官方沙箱演示账号): hbcli auth set-credentials --app-key hotelbyte_api_demo --app-secret hotelbyte_api_demo')
115
+ say(' · 正式接入: 向 HotelByte 申请专属 appKey/appSecret 后用同一命令替换')
116
+ say(' · 门户账号(权限更大,酒店搜索无必要): hbcli auth login --username <email>')
117
+ say(' 自检: hbcli auth whoami(api_key.configured=true 即就位)')
81
118
  return { ok: true }
82
119
  }
83
120
 
@@ -98,8 +135,7 @@ async function setupReach() {
98
135
  return { ok: true }
99
136
  }
100
137
 
101
- async function setupSidebar() {
102
- say('[gotry-setup] dsh-better-sidebar(dsh web 侧栏工作台,产物查看面 issue #25)')
138
+ async function setupSidebar() { say('[gotry-setup] dsh-better-sidebar(dsh web 侧栏工作台,产物查看面 issue #25)')
103
139
  const installed = existsSync(join(homedir(), '.dsh/profiles/web/node_modules/dsh-better-sidebar/package.json'))
104
140
  if (installed) { say(' ✓ 已安装(~/.dsh/profiles/web)'); return { ok: true } }
105
141
  if (CHECK_ONLY) { say(' ✗ 未安装(--check-only 只报告)'); return { ok: true } }
@@ -129,11 +165,322 @@ async function setupSidebar() {
129
165
  return { ok: true }
130
166
  }
131
167
 
168
+ const EXTENSION_FILES = ['manifest.json', 'background.js', 'content-main.js', 'content-bridge.js', 'README.md']
169
+
170
+ function readManifestVersion(manifestPath) {
171
+ try { return JSON.parse(readFileSync(manifestPath, 'utf8')).version ?? null } catch { return null }
172
+ }
173
+
174
+ function copyExtensionDir(srcDir, dstDir) {
175
+ mkdirSync(dstDir, { recursive: true })
176
+ for (const f of EXTENSION_FILES) {
177
+ const s = join(srcDir, f)
178
+ if (!existsSync(s)) continue
179
+ copyFileSync(s, join(dstDir, f))
180
+ }
181
+ }
182
+
183
+ /** 会话检索扩展(issue #21 方案 C):包内 extension/ → ~/.gotry/extension 幂等落位 + 一次性加载指引 */
184
+ async function setupExtension() {
185
+ say('[gotry-setup] GoTry Session Bridge 扩展(会话检索数据面 issue #21;一次性安装,替代逐连接弹窗)')
186
+ const srcDir = join(repoRoot, 'extension')
187
+ const srcManifest = join(srcDir, 'manifest.json')
188
+ if (!existsSync(srcManifest)) {
189
+ say(` ✗ 包内未找到扩展文件(${srcDir})——不影响 gotry:会话检索降级,重装 npx gotry 可恢复`)
190
+ return { ok: false }
191
+ }
192
+ const srcVersion = readManifestVersion(srcManifest)
193
+ const dstDir = join(homedir(), '.gotry', 'extension')
194
+ const dstVersion = readManifestVersion(join(dstDir, 'manifest.json'))
195
+ if (dstVersion != null && dstVersion === srcVersion) {
196
+ say(` ✓ 已就位(~/.gotry/extension,v${dstVersion};若浏览器里尚未加载:chrome://extensions → 开发者模式 → 加载已解压的扩展程序 → 选 ~/.gotry/extension)`)
197
+ return { ok: true }
198
+ }
199
+ if (CHECK_ONLY) { say(` ✗ ${dstVersion == null ? `未安装(落位 ${dstDir})` : `待更新 v${dstVersion} → v${srcVersion},落位 ${dstDir}`}(--check-only 只报告)`); return { ok: true } }
200
+ try {
201
+ copyExtensionDir(srcDir, dstDir)
202
+ } catch (e) {
203
+ say(` ✗ 落位失败(${e.message})——不影响 gotry:会话检索降级;可手动拷贝 ${srcDir} → ${dstDir}`)
204
+ return { ok: false }
205
+ }
206
+ say(` ✓ 已落位 ${dstDir}(v${srcVersion};manifest 带固定 key,unpacked 扩展 ID 恒为 olpgkofjhhiiiahdkkbcninhjmegghfe)`)
207
+ say(' 推荐(免下面三步):Chrome 应用商店一键安装 GoTry Session Bridge(自动更新): https://chromewebstore.google.com/detail/gotry-session-bridge/oeajpiccmonococjcegddlooeeohlbgd')
208
+ say(' 本地加载(每台浏览器一次,约 30 秒):Chrome 打开 chrome://extensions → 右上角开启「开发者模式」→「加载已解压的扩展程序」→ 选择 ~/.gotry/extension')
209
+ say(' 获取/更新本地通道扩展可走 GitHub Releases:npx gotry setup --extension-from=github(自动下载校验落位;手动下载: github.com/Danceiny/gotry/releases 标签 ext-*)')
210
+ say(' 装好即生效,零系统弹窗;扩展卡片开关=总闸(与 gotry 授权闸 sessionAccess 双重控制)')
211
+ return { ok: true }
212
+ }
213
+
214
+ /**
215
+ * GitHub Releases 下载通道(ADR-21 分发 A,--extension-from=github 显式 opt-in):
216
+ * repo 态 spawn tsx CLI(与 wizard/health-watch 同款单行 JSON 回传),npm 态 import dist JS;
217
+ * 任何失败显式降级 bundled 包内副本——安装外部产物永远不挡 gotry 本体。
218
+ */
219
+ async function setupExtensionFromGithub() {
220
+ say('[gotry-setup] GoTry Session Bridge 扩展 · GitHub Releases 下载通道(dist-manifest → tar.gz → SHA256 → key 钉扎)')
221
+ const destDir = join(homedir(), '.gotry', 'extension')
222
+ const cliScript = join(repoRoot, 'ts', 'scripts', 'extension-distribution-cli.ts')
223
+ const releaseBase = process.env.GOTRY_EXTENSION_RELEASE_BASE // 镜像/测试基址覆盖;缺省 GitHub 官方
224
+ let r = null
225
+ if (existsSync(cliScript)) {
226
+ r = await new Promise((resolve) => {
227
+ const child = spawn('npx', ['--yes', 'tsx', cliScript, '--dest', destDir, '--source-dir', join(repoRoot, 'extension'), ...(releaseBase ? ['--release-base', releaseBase] : []), ...(CHECK_ONLY ? ['--check-only'] : [])], {
228
+ cwd: join(repoRoot, 'ts'),
229
+ stdio: ['ignore', 'pipe', 'inherit'],
230
+ })
231
+ let buf = ''
232
+ child.stdout.on('data', (c) => { buf += c.toString('utf8') })
233
+ child.on('close', () => {
234
+ const line = (buf.trim().split('\n').pop() ?? '')
235
+ if (line.startsWith('{')) { try { resolve(JSON.parse(line)); return } catch { /* 落到下一行 */ } }
236
+ resolve({ ok: false, action: 'fallback-bundled', error: `CLI 无 JSON 输出(末行:${line.slice(0, 120)})` })
237
+ })
238
+ child.on('error', (e) => resolve({ ok: false, action: 'fallback-bundled', error: `CLI 启动失败 ${e.message}` }))
239
+ })
240
+ } else {
241
+ try {
242
+ const mod = await import('../dist/capabilities/session/extension-distribution.js')
243
+ r = await mod.installExtensionFromGithub({ destDir, pinnedSourceDir: join(repoRoot, 'extension'), ...(releaseBase ? { releaseBase } : {}), checkOnly: CHECK_ONLY })
244
+ } catch (e) {
245
+ r = { ok: false, action: 'fallback-bundled', error: `dist 模块不可用:${e.message}` }
246
+ }
247
+ }
248
+ if (r && r.ok) {
249
+ if (r.action === 'installed') {
250
+ say(` ✓ 已从 GitHub Releases 落位 ${destDir}(v${r.version}${r.previousVersion ? `,旧 v${r.previousVersion}` : ''})`)
251
+ say(' 已装过旧版的浏览器:chrome://extensions → GoTry Session Bridge 卡片 → 「重新加载」一次即生效(新装跳过)。')
252
+ return { ok: true }
253
+ }
254
+ // up-to-date(check-only 下远端更新也会走到这里,只报告不落盘)
255
+ if (r.version != null && r.previousVersion != null && r.version !== r.previousVersion) {
256
+ say(` ✓ 远端有新版 v${r.version}(本地 v${r.previousVersion})${CHECK_ONLY ? '(--check-only 只报告)' : ''}`)
257
+ return { ok: true }
258
+ }
259
+ say(` ✓ 已是最新(v${r.version ?? '?'});若浏览器里尚未加载:chrome://extensions → 开发者模式 → 加载已解压 → 选 ${destDir}`)
260
+ return { ok: true }
261
+ }
262
+ say(` ✗ GitHub 通道失败(${r && r.error ? r.error : '未知'})——显式降级包内副本:`)
263
+ return setupExtension()
264
+ }
265
+
266
+ /**
267
+ * 调 (npm 安装态降级)只确保扩展落位后跑扩展分支 hydration。wizard.ts 现在
268
+ * 只做 ensure + watch precheck(Node 端职责),不 spawn 任何 GUI;真正的浏览器
269
+ * 商店页安装走 dsh UI 渲染的 verdict.installUrl,健康探活走 runHealthWatch。
270
+ *
271
+ * 历史:wizard-bootstrap.ts(此文件之前 spawn 的 tsx 子进程)已删除;
272
+ * run-all §40 onboarding-tests 直接 import wizard.ts 的 runOnboardingWizard。
273
+ */
274
+ async function runWizardBootstrap() {
275
+ // wizard.ts 已退化为纯 Node 2 步(ensure + watch precheck),不 spawn 任何东西;
276
+ // tsx 子进程路径 = <repoRoot>/ts;npm 安装态(wizard-bootstrap.ts 已删除)走包内 setupExtension。
277
+ const wizardScript = join(repoRoot, 'ts', 'scripts', 'wizard-bootstrap.ts')
278
+ if (!existsSync(wizardScript)) {
279
+ say('[gotry-wizard] 内置 wizard 脚本缺失(已装 npm 包态;npm 安装态应在浏览器商店一键装,不需要 wizard 跑落位)——只跑包内扩展落位:')
280
+ await setupExtension()
281
+ return { ok: true }
282
+ }
283
+ return new Promise((resolve) => {
284
+ const child = spawn('npx', ['--yes', 'tsx', wizardScript, '--extension-dir', join(homedir(), '.gotry', 'extension'), '--source-dir', join(repoRoot, 'extension')], {
285
+ cwd: join(repoRoot, 'ts'),
286
+ stdio: ['ignore', 'pipe', 'inherit'],
287
+ })
288
+ let stdoutBuf = ''
289
+ let resolved = false
290
+ const finish = (r) => {
291
+ if (resolved) return
292
+ resolved = true
293
+ resolve(r)
294
+ }
295
+ child.stdout.on('data', (c) => {
296
+ stdoutBuf += c.toString('utf8')
297
+ let nl = stdoutBuf.indexOf('\n')
298
+ while (nl >= 0) {
299
+ const line = stdoutBuf.slice(0, nl).trim()
300
+ stdoutBuf = stdoutBuf.slice(nl + 1)
301
+ if (line.startsWith('{')) {
302
+ try {
303
+ const o = JSON.parse(line)
304
+ // 打印 2 步 status(wizard 自己的 print 已在子进程跑了;此处父进程再 human-friendly 一次)
305
+ if (Array.isArray(o.steps)) {
306
+ for (const s of o.steps) {
307
+ const tag = s.status === 'ok' ? '✅' : s.status === 'skip' ? '⏭ ' : '❌'
308
+ say(`[gotry-wizard] ${tag} ${s.step}: ${s.summary}`)
309
+ }
310
+ }
311
+ say(`[gotry-wizard] extensionDir=${o.extensionDir}; ok=${o.ok}`)
312
+ finish({ ok: o.ok === true })
313
+ } catch {
314
+ say('[gotry-wizard] ✗ wizard JSON 解析失败')
315
+ finish({ ok: false })
316
+ }
317
+ try { child.kill('SIGTERM') } catch { /* ignore */ }
318
+ return
319
+ }
320
+ nl = stdoutBuf.indexOf('\n')
321
+ }
322
+ })
323
+ child.on('exit', (code) => {
324
+ if (!resolved) {
325
+ say(`[gotry-wizard] ✗ wizard 子进程 exit ${code}(stdout 无 JSON)`)
326
+ finish({ ok: code === 0 })
327
+ }
328
+ })
329
+ child.on('error', (e) => {
330
+ say(`[gotry-wizard] ✗ wizard 子进程启动失败: ${e.message}`)
331
+ finish({ ok: false })
332
+ })
333
+ })
334
+ }
335
+
336
+ /**
337
+ * 后台探活扩展心跳(wizard 闭环「装完零重跑」,§3.3):
338
+ * spawn tsx 跑 health-watch.ts(纯 TS 探活,run-all §40 同一份代码),接 stdout JSON 结果行。
339
+ * 探活期间每 5s stdout 一行 `.`,用户看见 stdout 持续推进,不卡死假象。
340
+ * 默认 120s 超时;若用户提前 Ctrl+C,timeoutMs 走 0 立即返回 cancelled。
341
+ */
342
+ async function runHealthWatch() {
343
+ // 跨语言:bootstrap 是纯 JS,health-watch 是 TS;走 spawn npx tsx 子进程,stdout 解析。
344
+ // tsx 子进程路径 = <repoRoot>/ts;不在 npm 包里跑(发布面只走 src/bin,不走 wizard 自动化)
345
+ const watcherScript = join(repoRoot, 'ts', 'scripts', 'health-watch-cli.ts')
346
+ // 默认 120s / 5s,§3.3 设计值;env 可覆盖(bootstrap-tests 跑真实路径用)
347
+ const timeoutMs = parseInt(process.env.GOTRY_ONBOARDING_TIMEOUT_MS ?? '120000', 10) || 120_000
348
+ const probeIntervalMs = parseInt(process.env.GOTRY_ONBOARDING_INTERVAL_MS ?? '5000', 10) || 5_000
349
+ return new Promise((resolve) => {
350
+ const args = [watcherScript, '--timeout', String(timeoutMs), '--interval', String(probeIntervalMs), '--json']
351
+ // 先确认 watcher 脚本存在(npm 安装态可能未带 ts/目录——降级:走内联 node:http 短探活,避免挡用户)
352
+ if (!existsSync(watcherScript)) {
353
+ say(`[gotry-wizard] 内置探活脚本缺失(${watcherScript})——改用内置 5s 轮询`)
354
+ resolve(runInlineHealthWatch(timeoutMs))
355
+ return
356
+ }
357
+ const child = spawn('npx', ['--yes', 'tsx', ...args], {
358
+ cwd: join(repoRoot, 'ts'),
359
+ stdio: ['ignore', 'pipe', 'inherit'],
360
+ env: { ...process.env, GOTRY_ONBOARDING_HEADLESS: process.env.GOTRY_ONBOARDING_HEADLESS ?? '1' },
361
+ })
362
+ let stdoutBuf = ''
363
+ let heartbeatTicker = 0
364
+ const hbInterval = setInterval(() => {
365
+ heartbeatTicker += 1
366
+ process.stdout.write('.')
367
+ if (heartbeatTicker % 12 === 0) process.stdout.write(`(${Math.round(heartbeatTicker * probeIntervalMs / 1000)}s)\n`)
368
+ }, probeIntervalMs)
369
+ child.stdout.on('data', (c) => {
370
+ const s = c.toString('utf8')
371
+ stdoutBuf += s
372
+ // JSON 结果行以 \n 分隔;watcher 一次性 stdout 一行 JSON 退出
373
+ let nl = stdoutBuf.indexOf('\n')
374
+ while (nl >= 0) {
375
+ const line = stdoutBuf.slice(0, nl).trim()
376
+ stdoutBuf = stdoutBuf.slice(nl + 1)
377
+ if (line.startsWith('{')) {
378
+ clearInterval(hbInterval)
379
+ try {
380
+ const o = JSON.parse(line)
381
+ resolve({ ready: o.ready === true, attempts: o.attempts ?? 0, waitedMs: o.waitedMs ?? 0, reason: o.reason ?? 'timeout', timeoutMs })
382
+ } catch {
383
+ resolve({ ready: false, attempts: 0, waitedMs: 0, reason: 'parse-error', timeoutMs })
384
+ }
385
+ try { child.kill('SIGTERM') } catch { /* ignore */ }
386
+ return
387
+ }
388
+ nl = stdoutBuf.indexOf('\n')
389
+ }
390
+ })
391
+ child.on('exit', (code) => {
392
+ clearInterval(hbInterval)
393
+ process.stdout.write('\n')
394
+ if (code !== 0 && stdoutBuf.trim() === '') {
395
+ resolve({ ready: false, attempts: 0, waitedMs: 0, reason: `watcher-exit-${code}`, timeoutMs })
396
+ }
397
+ })
398
+ child.on('error', () => {
399
+ clearInterval(hbInterval)
400
+ resolve({ ready: false, attempts: 0, waitedMs: 0, reason: 'watcher-spawn-error', timeoutMs })
401
+ })
402
+ })
403
+ }
404
+
405
+ /** npm 安装态(无 ts/目录)降级:内置 5s 轮询 node:http,与 health-watch 同节奏 */
406
+ async function runInlineHealthWatch(timeoutMs) {
407
+ const intervalMs = parseInt(process.env.GOTRY_ONBOARDING_INTERVAL_MS ?? '5000', 10) || 5_000
408
+ const ports = [8791, 8792, 8793, 8794, 8795]
409
+ const http = await import('node:http')
410
+ const startedAt = Date.now()
411
+ let attempts = 0
412
+ while (Date.now() - startedAt < timeoutMs) {
413
+ attempts += 1
414
+ for (const port of ports) {
415
+ const ok = await new Promise((resolve) => {
416
+ const req = http.request({ host: '127.0.0.1', port, path: '/status', method: 'GET', timeout: 2_000 }, (res) => {
417
+ if (!res.statusCode || res.statusCode >= 400) { resolve(false); return }
418
+ let buf = ''
419
+ res.setEncoding('utf8')
420
+ res.on('data', (c) => { buf += c })
421
+ res.on('end', () => {
422
+ try { resolve(JSON.parse(buf).extensionConnected === true) } catch { resolve(false) }
423
+ })
424
+ res.on('error', () => resolve(false))
425
+ })
426
+ req.on('error', () => resolve(false))
427
+ req.on('timeout', () => { req.destroy(); resolve(false) })
428
+ req.end()
429
+ })
430
+ if (ok) {
431
+ process.stdout.write('\n')
432
+ return { ready: true, attempts, waitedMs: Date.now() - startedAt, reason: 'ready', timeoutMs }
433
+ }
434
+ }
435
+ process.stdout.write('.')
436
+ await new Promise((r) => setTimeout(r, intervalMs))
437
+ }
438
+ process.stdout.write('\n')
439
+ return { ready: false, attempts, waitedMs: Date.now() - startedAt, reason: 'timeout', timeoutMs }
440
+ }
441
+
132
442
  async function main() {
443
+ // wizard 子命令(2026-09-02 商店上架后退化):**只走 stdout 提示 + 健康探活等待**;
444
+ // 不 spawn 任何 GUI 工具(不动 pbcopy / osascript / open / xdg-open / zenity),
445
+ // 不打开 chrome://extensions,不动扩展路径——浏览器自己当安装器,gotry 不越界。
446
+ // 期望用户路径:`npx gotry web` → dsh UI → 调 gotry_session_search 遇 needs-extension
447
+ // → dsh UI 渲商店 URL → 用户点链接 → 装好 → 同会话内自动 retry(health-watch)。
448
+ if (WIZARD) {
449
+ if (WIZARD_DRY_RUN) {
450
+ say('[gotry-wizard] dry-run(零网络零浏览器零剪贴板;run-all §40 走这条)')
451
+ say(' 步骤: ensure-extension-files → watch-extension-ready(2 步纯 Node 端)')
452
+ say(' 平台: 不依赖 darwin/linux/win32(只 stdout)')
453
+ say(' ✅ exit 0')
454
+ process.exit(0)
455
+ }
456
+ say('')
457
+ say('[gotry-wizard] ────────────────────────────────')
458
+ say('[gotry-wizard] GoTry Session Bridge 是浏览器的事——在 Chrome 应用商店一键装:')
459
+ say('[gotry-wizard] https://chromewebstore.google.com/detail/gotry-session-bridge/oeajpiccmonococjcegddlooeeohlbgd')
460
+ say('[gotry-wizard] 装好即生效;装完后我会自动检测到(下方探活等待,最长 120s)。')
461
+ say('[gotry-wizard] 全过程 gotry 不动你的剪贴板、不开你的 Chrome、不弹任何面板。')
462
+ say('[gotry-wizard] ────────────────────────────────')
463
+ say('')
464
+ say('[gotry-wizard] 探活中(Ctrl+C 立即退出)…')
465
+
466
+ // 健康探活等待:扩展一就位即返回;无 GUI/剪贴板副作用
467
+ const watchResult = await runHealthWatch()
468
+ if (watchResult.ready) {
469
+ say(`[gotry-wizard] ✅ 扩展就绪(${watchResult.attempts} 次探活,等待 ${watchResult.waitedMs}ms)`)
470
+ say('[gotry-wizard] 现在 `npx gotry web` → dsh UI → 调 gotry_session_search 即可拿到结果。')
471
+ process.exit(0)
472
+ } else {
473
+ say(`[gotry-wizard] ✗ ${watchResult.reason}——未在 ${watchResult.timeoutMs}ms 内就绪`)
474
+ say('[gotry-wizard] dsh UI 中 `gotry_session_search` 的 needs-extension 仍带商店链接;无需重跑,wizard 完全幂等。')
475
+ process.exit(1)
476
+ }
477
+ }
478
+
133
479
  if (process.platform === 'win32') {
134
480
  say('[gotry-setup] Windows 暂不支持自动安装(hbcli 上游仅 darwin/linux)。手动指引:')
135
481
  say(` hbcli: ${HBCLI_INSTALL_CMD}(WSL);agent-reach: python -m venv .venv && .venv/Scripts/pip install ${REACH_INSTALL_URL}`)
136
482
  say(' dsh-better-sidebar: npx -y --package @deepseek-ai/dsh dsh plugin --profile web add dsh-better-sidebar@latest')
483
+ say(' GoTry Session Bridge 扩展:推荐 Chrome 应用商店一键安装 https://chromewebstore.google.com/detail/gotry-session-bridge/oeajpiccmonococjcegddlooeeohlbgd ;本地通道:手动把包内 extension/ 目录拷到 %USERPROFILE%\\.gotry\\extension,再在 chrome://extensions 开发者模式「加载已解压的扩展程序」')
137
484
  process.exit(AUTO ? 0 : 1)
138
485
  }
139
486
  if (AUTO && (process.env.CI || process.env.GOTRY_SETUP_SKIP === '1')) {
@@ -149,6 +496,8 @@ async function main() {
149
496
  else say('[gotry-setup] agent-reach:GOTRY_SETUP_REACH=0 跳过')
150
497
  if (process.env.GOTRY_SETUP_SIDEBAR !== '0') results.push(await setupSidebar())
151
498
  else say('[gotry-setup] dsh-better-sidebar:GOTRY_SETUP_SIDEBAR=0 跳过')
499
+ if (process.env.GOTRY_SETUP_EXTENSION !== '0') results.push(await (EXTENSION_FROM === 'github' ? setupExtensionFromGithub() : setupExtension()))
500
+ else say('[gotry-setup] GoTry Session Bridge 扩展:GOTRY_SETUP_EXTENSION=0 跳过')
152
501
  say('[gotry-setup] flyai:无需安装(npx 每次自拉 @fly-ai/flyai-cli,免 key)')
153
502
  const failed = results.filter((r) => !r.ok).length
154
503
  if (failed > 0) {