@danceiny/gotry 0.0.1-rc.21 → 0.0.1-rc.24

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 (327) hide show
  1. package/README.md +102 -194
  2. package/README.zh-CN.md +115 -210
  3. package/bin/gotry-backend.js +53 -0
  4. package/bin/gotry-bootstrap.js +466 -35
  5. package/bin/gotry-inner.js +255 -36
  6. package/bin/gotry-process-liveness.d.ts +27 -0
  7. package/bin/gotry-process-liveness.js +97 -0
  8. package/bin/gotry-runtime-resolution.d.ts +1 -1
  9. package/bin/gotry-runtime-resolution.js +2 -2
  10. package/client/client.js +174 -0
  11. package/cordis.gotry-patch.yml +70 -93
  12. package/dist/capabilities/agent-reach-deep.js +45 -122
  13. package/dist/capabilities/agent-reach.js +63 -148
  14. package/dist/capabilities/anything.js +89 -75
  15. package/dist/capabilities/artifacts.js +123 -104
  16. package/dist/capabilities/channel-health.js +65 -45
  17. package/dist/capabilities/channel-registry.js +108 -87
  18. package/dist/capabilities/doctor.js +357 -235
  19. package/dist/capabilities/effect.js +223 -309
  20. package/dist/capabilities/fact-log.js +28 -14
  21. package/dist/capabilities/flyai.js +245 -156
  22. package/dist/capabilities/ground-transfer.js +509 -0
  23. package/dist/capabilities/hbcli.js +144 -148
  24. package/dist/capabilities/hotelbyte-transaction.js +194 -0
  25. package/dist/capabilities/incident-log.js +131 -61
  26. package/dist/capabilities/model-override.js +30 -10
  27. package/dist/capabilities/opensky.js +54 -43
  28. package/dist/capabilities/resilience.js +50 -32
  29. package/dist/capabilities/session/action-cache.js +50 -44
  30. package/dist/capabilities/session/adapters/ctrip-flight.js +119 -62
  31. package/dist/capabilities/session/adapters/ctrip-hotel.js +125 -110
  32. package/dist/capabilities/session/adapters/dida-portal.js +206 -0
  33. package/dist/capabilities/session/adapters/meituan-local.js +35 -54
  34. package/dist/capabilities/session/adapters/rail-12306.js +169 -112
  35. package/dist/capabilities/session/benchmark.js +85 -149
  36. package/dist/capabilities/session/extension-bridge.js +320 -259
  37. package/dist/capabilities/session/extension-channel.js +57 -76
  38. package/dist/capabilities/session/extension-distribution.js +115 -119
  39. package/dist/capabilities/session/extract.js +31 -21
  40. package/dist/capabilities/session/golden-score.js +55 -33
  41. package/dist/capabilities/session/health-watch.js +146 -154
  42. package/dist/capabilities/session/read-guard.js +55 -47
  43. package/dist/capabilities/session/static-flight-golden.js +49 -36
  44. package/dist/capabilities/session/transport.js +54 -61
  45. package/dist/capabilities/session/wizard.js +63 -93
  46. package/dist/capabilities/session-consent.js +143 -47
  47. package/dist/capabilities/session-login.js +95 -126
  48. package/dist/capabilities/session-search.js +391 -253
  49. package/dist/capabilities/sponsor-plugin.js +341 -0
  50. package/dist/capabilities/visa-policy.js +87 -73
  51. package/dist/capabilities/weather.js +163 -235
  52. package/dist/scripts/action-cache-tests.js +24 -59
  53. package/dist/scripts/agent-planning-turn-deadline-e2e.js +91 -142
  54. package/dist/scripts/agent-planning-turn-deadline-tests.js +80 -176
  55. package/dist/scripts/agent-reach-deep-tests.js +30 -40
  56. package/dist/scripts/agent-reach-tests.js +26 -18
  57. package/dist/scripts/agent-reach-wrapper-tests.js +46 -50
  58. package/dist/scripts/anything-tests.js +58 -62
  59. package/dist/scripts/artifact-client-contract-tests.js +69 -0
  60. package/dist/scripts/artifacts-capability-tests.js +235 -0
  61. package/dist/scripts/async-collect.js +26 -15
  62. package/dist/scripts/benchmark-environment-bridge-e2e.js +287 -684
  63. package/dist/scripts/benchmark-environment-bridge-tests.js +818 -3123
  64. package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +66 -279
  65. package/dist/scripts/booking-copilot-availability-policy-tests.js +153 -1257
  66. package/dist/scripts/booking-copilot-bin-proof-tests.js +22 -45
  67. package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +64 -76
  68. package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +69 -199
  69. package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +393 -759
  70. package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +33 -75
  71. package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +60 -110
  72. package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +28 -66
  73. package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +72 -271
  74. package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +73 -275
  75. package/dist/scripts/booking-copilot-runtime-proof-tests.js +784 -3398
  76. package/dist/scripts/booking-copilot-server-proof-tests.js +63 -168
  77. package/dist/scripts/booking-copilot-startup-proof-tests.js +38 -124
  78. package/dist/scripts/booking-executor-tests.js +80 -0
  79. package/dist/scripts/booking-recovery-chain-tests.js +182 -0
  80. package/dist/scripts/booking-saga-tests.js +61 -123
  81. package/dist/scripts/booking-surface-contract-proof-tests.js +152 -1167
  82. package/dist/scripts/bootstrap-tests.js +1383 -128
  83. package/dist/scripts/build-changelog.js +89 -130
  84. package/dist/scripts/build-metrics-report.js +135 -143
  85. package/dist/scripts/changelog-tests.js +35 -82
  86. package/dist/scripts/channel-probe-tests.js +44 -116
  87. package/dist/scripts/channel-probe.js +84 -167
  88. package/dist/scripts/channel-registry-tests.js +97 -185
  89. package/dist/scripts/companion-tests.js +25 -70
  90. package/dist/scripts/dida-cookie-probe.js +87 -0
  91. package/dist/scripts/dida-sw-probe.js +114 -0
  92. package/dist/scripts/diff-test.js +17 -12
  93. package/dist/scripts/doctor-tests.js +428 -120
  94. package/dist/scripts/dsh-artifact-e2e.js +150 -0
  95. package/dist/scripts/dsh-artifact-web-e2e.js +443 -0
  96. package/dist/scripts/dsh-http-proxy-sse-proof.js +90 -0
  97. package/dist/scripts/dsh-runtime-closure-tests.js +110 -153
  98. package/dist/scripts/dsh-runtime-closure.js +75 -63
  99. package/dist/scripts/dsh-session-v3-migration-proof.js +106 -0
  100. package/dist/scripts/dsh-subprocess-local-proof.js +149 -0
  101. package/dist/scripts/dsh-target-closure-proof.js +178 -0
  102. package/dist/scripts/effect-tests.js +165 -552
  103. package/dist/scripts/engine-run.js +1 -3
  104. package/dist/scripts/engine-tests.js +16 -10
  105. package/dist/scripts/evaluation-cadence-tests.js +69 -242
  106. package/dist/scripts/evaluation-contract-tests.js +193 -499
  107. package/dist/scripts/extension-distribution-cli.js +19 -15
  108. package/dist/scripts/extension-distribution-tests.js +98 -211
  109. package/dist/scripts/extension-tests.js +366 -389
  110. package/dist/scripts/fact-gate-tests.js +725 -263
  111. package/dist/scripts/fixtures/extension-bridge-unref-child.mjs +21 -0
  112. package/dist/scripts/flight-hotel-anchor-363-registered-e2e.js +169 -0
  113. package/dist/scripts/flight-malformed-tests.js +159 -0
  114. package/dist/scripts/flyai-tests.js +325 -68
  115. package/dist/scripts/g5-guard-tests.js +131 -0
  116. package/dist/scripts/g5-guard.js +189 -0
  117. package/dist/scripts/gen-lunar-anchors.js +106 -0
  118. package/dist/scripts/gotry-backend-kernel-tests.js +79 -0
  119. package/dist/scripts/ground-transfer-tests.js +956 -0
  120. package/dist/scripts/hbcli-e2e-tests.js +71 -90
  121. package/dist/scripts/hbcli-live-optin-tests.js +96 -0
  122. package/dist/scripts/hbcli-release-contract-tests.js +122 -0
  123. package/dist/scripts/hbcli-tests.js +41 -115
  124. package/dist/scripts/health-watch-cli.js +42 -28
  125. package/dist/scripts/hotel-date-gate-tests.js +496 -0
  126. package/dist/scripts/hotelbyte-reconcile-tests.js +141 -0
  127. package/dist/scripts/hotelbyte-spawn-e2e-tests.js +373 -0
  128. package/dist/scripts/i18n-tests.js +16 -9
  129. package/dist/scripts/incident-tests.js +281 -87
  130. package/dist/scripts/issue-194-job-id-guard-tests.js +106 -0
  131. package/dist/scripts/issue-233-cancel-refund-commission-tests.js +392 -0
  132. package/dist/scripts/issue-271-liveness-tests.js +547 -0
  133. package/dist/scripts/issue-289-model-retry-real-tests.js +296 -0
  134. package/dist/scripts/issue-289-model-retry-tests.js +441 -0
  135. package/dist/scripts/issue-289-web-retry-e2e.js +630 -0
  136. package/dist/scripts/issue-338-home-city-e2e.js +577 -0
  137. package/dist/scripts/issue343-real-entry-e2e.js +160 -0
  138. package/dist/scripts/journey-tests.js +22 -27
  139. package/dist/scripts/kernel-manifest-evidence.js +109 -0
  140. package/dist/scripts/kernel-manifest-gate.js +126 -0
  141. package/dist/scripts/kernel-manifest-tests.js +212 -0
  142. package/dist/scripts/kernel-manifest-trace-entry.js +7 -0
  143. package/dist/scripts/kernel-manifest-trace-hook.mjs +28 -0
  144. package/dist/scripts/kernel-manifest.js +369 -0
  145. package/dist/scripts/ledger-repair-apply-tests.js +316 -0
  146. package/dist/scripts/ledger-repair-plan-tests.js +375 -0
  147. package/dist/scripts/ledger-tests.js +325 -340
  148. package/dist/scripts/ledger-workflow-crash.js +10 -20
  149. package/dist/scripts/map-tools-vendor-package-proof.js +206 -134
  150. package/dist/scripts/memory-capture-tests.js +242 -61
  151. package/dist/scripts/memory-decay-tests.js +18 -52
  152. package/dist/scripts/memory-lifecycle-tests.js +657 -0
  153. package/dist/scripts/memory-lifecycle.js +196 -0
  154. package/dist/scripts/memory-metrics.js +24 -12
  155. package/dist/scripts/memory-value-report.js +474 -222
  156. package/dist/scripts/memory-value-tests.js +328 -0
  157. package/dist/scripts/metrics-report-tests.js +62 -199
  158. package/dist/scripts/model-override-e2e.js +66 -105
  159. package/dist/scripts/nightly-evidence-tests.js +64 -89
  160. package/dist/scripts/nightly-evidence.js +108 -111
  161. package/dist/scripts/nudge-digest.js +39 -28
  162. package/dist/scripts/onboarding-tests.js +63 -88
  163. package/dist/scripts/opensky-check.js +18 -13
  164. package/dist/scripts/opensky-tests.js +28 -28
  165. package/dist/scripts/persona-surface-guard-tests.js +37 -12
  166. package/dist/scripts/pnpm-dsh-closure-proof.js +2 -5
  167. package/dist/scripts/policy-anchor-359-registered-e2e.js +214 -0
  168. package/dist/scripts/price-drift-tests.js +126 -227
  169. package/dist/scripts/price-drift-watch.js +209 -253
  170. package/dist/scripts/probe-poi-tests.js +52 -45
  171. package/dist/scripts/product-metrics.js +187 -273
  172. package/dist/scripts/publish-preverify.js +47 -41
  173. package/dist/scripts/realtime-pricing-tests.js +37 -76
  174. package/dist/scripts/replay-async.js +20 -18
  175. package/dist/scripts/replay-real.js +16 -18
  176. package/dist/scripts/replay.js +52 -82
  177. package/dist/scripts/session-attach-diagnose.js +16 -12
  178. package/dist/scripts/session-attach-poc.js +34 -37
  179. package/dist/scripts/session-benchmark.js +66 -147
  180. package/dist/scripts/session-dida-live-e2e.js +151 -0
  181. package/dist/scripts/session-extract-tests.js +14 -35
  182. package/dist/scripts/session-login.js +14 -13
  183. package/dist/scripts/session-tests.js +545 -583
  184. package/dist/scripts/sf-live-benchmark.js +92 -110
  185. package/dist/scripts/sf-live-cli-tests.js +2 -9
  186. package/dist/scripts/sf-soft-score-tests.js +19 -60
  187. package/dist/scripts/sf-summary-tests.js +149 -0
  188. package/dist/scripts/sf-summary.js +466 -84
  189. package/dist/scripts/skeleton-check.js +16 -14
  190. package/dist/scripts/skeleton-integration-test.js +11 -10
  191. package/dist/scripts/skills-contract-tests.js +51 -46
  192. package/dist/scripts/smoke-session-gate-tests.js +12 -20
  193. package/dist/scripts/smoke.js +541 -422
  194. package/dist/scripts/sponsor-reuse-tests.js +262 -0
  195. package/dist/scripts/state-cli-tests.js +226 -101
  196. package/dist/scripts/state-cli.js +549 -212
  197. package/dist/scripts/static-golden-tests.js +46 -180
  198. package/dist/scripts/time-eval-tests.js +210 -192
  199. package/dist/scripts/travel-timeline-tests.js +29 -93
  200. package/dist/scripts/turn-handoff-collect-tests.js +46 -93
  201. package/dist/scripts/turn-handoff-collect.js +71 -99
  202. package/dist/scripts/turn-policy-tests.js +28 -29
  203. package/dist/scripts/typed-contract-canary.js +77 -162
  204. package/dist/scripts/tz-resolver-sanity.js +50 -0
  205. package/dist/scripts/tz-resolver-tests.js +584 -0
  206. package/dist/scripts/unified-tests.js +23 -19
  207. package/dist/scripts/visa-policy-tests.js +31 -44
  208. package/dist/scripts/weather-tests.js +121 -543
  209. package/dist/scripts/wish-channel-gate-tests.js +29 -86
  210. package/dist/scripts/write-gate-tests.js +522 -0
  211. package/dist/scripts/z3-lifecycle-fault-tests.js +188 -0
  212. package/dist/scripts/z3-lifecycle-tests.js +170 -0
  213. package/dist/scripts/z3-race-repeat-tests.js +39 -0
  214. package/dist/scripts/z3-race-tests.js +18 -12
  215. package/dist/src/artifact-gate.js +652 -221
  216. package/dist/src/backend/kernel.js +91 -0
  217. package/dist/src/backend/modules/booking-copilot.js +55 -0
  218. package/dist/src/backend/modules/booking-executor.js +124 -0
  219. package/dist/src/backend/modules/session-search.js +194 -0
  220. package/dist/src/benchmark-agent-conformance.js +296 -262
  221. package/dist/src/benchmark-environment-bridge.js +298 -413
  222. package/dist/src/benchmark-headless-child-diagnostics.js +93 -100
  223. package/dist/src/benchmark-tool-isolation.js +94 -67
  224. package/dist/src/bookable-facts.js +299 -174
  225. package/dist/src/booking-saga.js +64 -120
  226. package/dist/src/booking-surface/availability-policy.js +443 -576
  227. package/dist/src/booking-surface/cancel-refund-commission.js +379 -0
  228. package/dist/src/booking-surface/contracts.js +24 -80
  229. package/dist/src/booking-surface/dsh-planner.js +510 -281
  230. package/dist/src/booking-surface/dsh-plugin.js +17 -1
  231. package/dist/src/booking-surface/error-codes.js +82 -10
  232. package/dist/src/booking-surface/index.js +0 -3
  233. package/dist/src/booking-surface/profile.js +10 -54
  234. package/dist/src/booking-surface/recovery-chain.js +367 -0
  235. package/dist/src/booking-surface/runtime.js +765 -891
  236. package/dist/src/booking-surface/server.js +200 -251
  237. package/dist/src/booking-surface/startup.js +58 -54
  238. package/dist/src/booking-surface/validation.js +150 -218
  239. package/dist/src/bridge.js +20 -13
  240. package/dist/src/companions.js +48 -74
  241. package/dist/src/contracts.js +21 -43
  242. package/dist/src/dsh-llm.js +82 -120
  243. package/dist/src/engine.js +253 -239
  244. package/dist/src/evaluation-cadence.js +72 -209
  245. package/dist/src/evaluation-contracts.js +220 -843
  246. package/dist/src/flight-pack-adapter.js +54 -0
  247. package/dist/src/flight-pack-contract.js +2 -0
  248. package/dist/src/gotry-backend.js +70 -0
  249. package/dist/src/hotel-date-gate.js +118 -0
  250. package/dist/src/i18n.js +18 -7
  251. package/dist/src/index.js +1425 -1629
  252. package/dist/src/journey.js +132 -81
  253. package/dist/src/ledger-repair-apply.js +538 -0
  254. package/dist/src/ledger-repair-plan.js +463 -0
  255. package/dist/src/loop.js +257 -166
  256. package/dist/src/memory-capture.js +180 -32
  257. package/dist/src/memory-decay.js +30 -14
  258. package/dist/src/memory-lifecycle.js +1310 -0
  259. package/dist/src/memory-utility.js +27 -40
  260. package/dist/src/mock-llm.js +36 -61
  261. package/dist/src/model.js +81 -36
  262. package/dist/src/realtime-pricing.js +63 -72
  263. package/dist/src/slot-spec.js +84 -106
  264. package/dist/src/state-ledger.js +310 -471
  265. package/dist/src/subagent-job-id-guard.js +58 -0
  266. package/dist/src/time-anchor.js +231 -33
  267. package/dist/src/tool-packet.js +20 -8
  268. package/dist/src/travel-slots.js +58 -35
  269. package/dist/src/travel-timeline.js +44 -63
  270. package/dist/src/turn-deadline.js +121 -127
  271. package/dist/src/turn-policy.js +61 -89
  272. package/dist/src/tz-resolver.js +143 -0
  273. package/dist/src/unified.js +504 -381
  274. package/dist/src/wish-pool.js +39 -14
  275. package/dist/src/write-gate.js +495 -0
  276. package/dist/src/z3-shared.js +273 -7
  277. package/extension/README.md +4 -3
  278. package/extension/background.js +125 -14
  279. package/extension/content-bridge.js +23 -1
  280. package/extension/content-main.js +15 -4
  281. package/extension/manifest.json +16 -8
  282. package/package.json +251 -220
  283. package/ts/capabilities/agent-reach.ts +4 -4
  284. package/ts/capabilities/anything.ts +1 -1
  285. package/ts/capabilities/artifacts.ts +46 -9
  286. package/ts/capabilities/flyai.ts +156 -37
  287. package/ts/capabilities/hbcli.ts +1 -1
  288. package/ts/capabilities/incident-log.ts +88 -59
  289. package/ts/capabilities/session/adapters/ctrip-flight.ts +99 -36
  290. package/ts/capabilities/session/adapters/dida-portal.ts +250 -0
  291. package/ts/capabilities/session/adapters/rail-12306.ts +123 -24
  292. package/ts/capabilities/session/extension-bridge.ts +226 -101
  293. package/ts/capabilities/session/extension-channel.ts +22 -9
  294. package/ts/capabilities/session/wizard.ts +2 -2
  295. package/ts/capabilities/session-consent.ts +98 -14
  296. package/ts/capabilities/session-login.ts +1 -0
  297. package/ts/capabilities/session-search.ts +315 -31
  298. package/ts/dsh-runtime/vendor/README.md +8 -4
  299. package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +7 -1
  300. package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +5 -3
  301. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +1 -1
  302. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +1 -1
  303. package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +6 -6
  304. package/ts/package.json +236 -16
  305. package/ts/scripts/map-tools-vendor-package-proof.ts +152 -31
  306. package/ts/scripts/state-cli.ts +418 -51
  307. package/ts/src/artifact-gate.ts +561 -15
  308. package/ts/src/benchmark-environment-bridge.ts +37 -20
  309. package/ts/src/bookable-facts.ts +183 -7
  310. package/ts/src/booking-surface/cancel-refund-commission.ts +488 -0
  311. package/ts/src/booking-surface/dsh-planner.ts +240 -32
  312. package/ts/src/booking-surface/dsh-plugin.js +17 -1
  313. package/ts/src/booking-surface/error-codes.ts +75 -0
  314. package/ts/src/booking-surface/recovery-chain.ts +409 -0
  315. package/ts/src/booking-surface/server.ts +84 -51
  316. package/ts/src/booking-surface/validation.ts +2 -0
  317. package/ts/src/contracts.ts +12 -2
  318. package/ts/src/dsh-llm.ts +4 -8
  319. package/ts/src/index.ts +609 -90
  320. package/ts/src/loop.ts +116 -7
  321. package/ts/src/memory-capture.ts +227 -3
  322. package/ts/src/mock-llm.ts +4 -8
  323. package/ts/src/model.ts +88 -2
  324. package/ts/src/state-ledger.ts +47 -29
  325. package/ts/src/subagent-job-id-guard.ts +72 -0
  326. package/ts/src/time-anchor.ts +217 -13
  327. package/ts/src/unified.ts +316 -54
@@ -1,204 +1,119 @@
1
+ /**
2
+ * agent-reach wrapper —— 上游 Panniantong/Agent-Reach 的薄壳(零渠道知识)。
3
+ *
4
+ * 分工(2026-08-22 founder 纠偏「wrapper 不是 router」):
5
+ * - 知识(渠道清单/方法签名/setup 指引)→ 上游:agent_reach.channels 注册表 + Channel.check() + guides/
6
+ * - 决策(该调哪个渠道哪个方法) → dsh 里的 LLM(靠本 wrapper 的自描述错误拿清单)
7
+ * - 管道(spawn/超时/永不抛错/证据链) → 本文件 + agent-reach-bridge.py,上游加渠道零改动
8
+ *
9
+ * 上游设计意图(Channel 基类原话):"After installation, agents call upstream tools directly."
10
+ * - python-API 渠道(web.read / v2ex.get_hot_topics / xueqiu.get_stock_quote / youtube.transcribe ...)
11
+ * 走本文件 reach() 的反射桥
12
+ * - 外部 CLI 工具渠道(github→gh / youtube 字幕→yt-dlp 等)由专用 dsh 工具(gotry_github_search /
13
+ * gotry_video_subtitle,见 agent-reach-deep.ts)充当执行面;上游无 python API 的不再自行拼命令
14
+ *
15
+ * 契约(L4 不变量,与 anything/weather/opensky 同构):
16
+ * - 永不抛错;verdict: found / not-installed / needs-setup / error
17
+ * - needs-setup 的 setup 文案 = 上游 check() 原话透传,不转述
18
+ * - 证据链 [agent-reach:<channel>.<method>@ts]
19
+ */
1
20
  import { spawn } from 'node:child_process';
2
21
  import { existsSync } from 'node:fs';
3
22
  import { resolve } from 'node:path';
4
- const ts = ()=>new Date().toISOString();
5
- const repoRoot = ()=>resolve(import.meta.dirname, '..', '..');
6
- const venvPython = ()=>resolve(repoRoot(), '.venv/bin/python');
7
- const bridgeScript = ()=>resolve(import.meta.dirname, 'agent-reach-bridge.py');
23
+ const ts = () => new Date().toISOString();
24
+ const repoRoot = () => resolve(import.meta.dirname, '..', '..');
25
+ const venvPython = () => resolve(repoRoot(), '.venv/bin/python');
26
+ const bridgeScript = () => resolve(import.meta.dirname, 'agent-reach-bridge.py');
8
27
  function run(bin, args, timeoutMs) {
9
- return new Promise((resolveRun)=>{
10
- const child = spawn(bin, args, {
11
- env: process.env
12
- });
28
+ return new Promise((resolveRun) => {
29
+ const child = spawn(bin, args, { env: process.env });
13
30
  let stdout = '';
14
31
  let stderr = '';
15
32
  let err;
16
- const timer = setTimeout(()=>{
17
- try {
18
- child.kill('SIGKILL');
19
- } catch {}
20
- }, timeoutMs);
21
- child.stdout.on('data', (d)=>{
22
- stdout += d.toString();
23
- });
24
- child.stderr.on('data', (d)=>{
25
- stderr += d.toString();
26
- });
27
- child.on('error', (e)=>{
28
- err = e.message;
29
- });
30
- child.on('close', (code)=>{
31
- clearTimeout(timer);
32
- resolveRun({
33
- code,
34
- stdout,
35
- stderr,
36
- err
37
- });
38
- });
33
+ const timer = setTimeout(() => { try {
34
+ child.kill('SIGKILL');
35
+ }
36
+ catch { /* ignore */ } }, timeoutMs);
37
+ child.stdout.on('data', (d) => { stdout += d.toString(); });
38
+ child.stderr.on('data', (d) => { stderr += d.toString(); });
39
+ child.on('error', (e) => { err = e.message; });
40
+ child.on('close', (code) => { clearTimeout(timer); resolveRun({ code, stdout, stderr, err }); });
39
41
  });
40
42
  }
43
+ /** 通用入口:反射调上游任意渠道方法;永不抛错 */
41
44
  export async function reach(q) {
42
45
  const started = Date.now();
43
- const evidence = (state)=>`[agent-reach:${q.channel}.${q.method}@${state === 'found' ? ts() : `${state}@${ts()}`}]`;
44
- const base = {
45
- channel: q.channel,
46
- method: q.method
47
- };
46
+ const evidence = (state) => `[agent-reach:${q.channel}.${q.method}@${state === 'found' ? ts() : `${state}@${ts()}`}]`;
47
+ const base = { channel: q.channel, method: q.method };
48
48
  if (!q.channel || !q.method) {
49
- return {
50
- ...base,
51
- ok: false,
52
- verdict: 'error',
53
- evidence: evidence('error'),
54
- latencyMs: 0,
55
- error: 'channel 与 method 必填(渠道/方法清单:先随便调一次,inventory 会带回上游清单)'
56
- };
49
+ return { ...base, ok: false, verdict: 'error', evidence: evidence('error'), latencyMs: 0, error: 'channel 与 method 必填(渠道/方法清单:先随便调一次,inventory 会带回上游清单)' };
57
50
  }
58
51
  const py = venvPython();
59
52
  if (!existsSync(py)) {
60
- return {
61
- ...base,
62
- ok: false,
63
- verdict: 'not-installed',
64
- evidence: evidence('not-installed'),
65
- latencyMs: 0,
66
- setup: 'gotry .venv 缺 python——可选依赖未装配。补装:终端跑 npx gotry doctor --fix,或让用户看体检报告 npx gotry doctor'
67
- };
53
+ return { ...base, ok: false, verdict: 'not-installed', evidence: evidence('not-installed'), latencyMs: 0, setup: 'gotry .venv 缺 python——可选依赖未装配。补装:终端跑 npx @danceiny/gotry doctor --fix,或让用户看体检报告 npx @danceiny/gotry doctor' };
68
54
  }
69
- const args = Array.isArray(q.args) ? q.args : q.args ? q.args.split(/\s+/).filter(Boolean) : [];
70
- const r = await run(py, [
71
- bridgeScript(),
72
- q.channel,
73
- q.method,
74
- ...args
75
- ], q.timeoutMs ?? 30_000);
55
+ const args = Array.isArray(q.args) ? q.args : (q.args ? q.args.split(/\s+/).filter(Boolean) : []);
56
+ const r = await run(py, [bridgeScript(), q.channel, q.method, ...args], q.timeoutMs ?? 30_000);
76
57
  const latencyMs = Date.now() - started;
77
58
  let parsed = {};
78
59
  try {
79
60
  parsed = JSON.parse((r.stdout || '').trim().split('\n').filter(Boolean).pop() ?? '{}');
80
- } catch {}
61
+ }
62
+ catch { /* 走下面的兜底 */ }
81
63
  if (r.err?.includes('ENOENT')) {
82
- return {
83
- ...base,
84
- ok: false,
85
- verdict: 'not-installed',
86
- evidence: evidence('not-installed'),
87
- latencyMs,
88
- setup: '.venv/bin/python 不可执行——补装:终端跑 npx gotry doctor --fix'
89
- };
64
+ return { ...base, ok: false, verdict: 'not-installed', evidence: evidence('not-installed'), latencyMs, setup: '.venv/bin/python 不可执行——补装:终端跑 npx @danceiny/gotry doctor --fix' };
90
65
  }
91
66
  if (parsed.ok === true) {
92
- return {
93
- ...base,
94
- ok: true,
95
- verdict: 'found',
96
- evidence: evidence('found'),
97
- latencyMs,
98
- data: parsed.data
99
- };
67
+ return { ...base, ok: true, verdict: 'found', evidence: evidence('found'), latencyMs, data: parsed.data };
100
68
  }
69
+ // 上游 agent_reach 包未装(bridge 自己的 exit 3 输出)
101
70
  if (parsed.error?.includes('agent_reach 未安装')) {
102
- return {
103
- ...base,
104
- ok: false,
105
- verdict: 'not-installed',
106
- evidence: evidence('not-installed'),
107
- latencyMs,
108
- setup: '.venv 缺 agent-reach 包——补装:终端跑 npx gotry doctor --fix'
109
- };
71
+ return { ...base, ok: false, verdict: 'not-installed', evidence: evidence('not-installed'), latencyMs, setup: '.venv 缺 agent-reach 包——补装:终端跑 npx @danceiny/gotry doctor --fix' };
110
72
  }
73
+ // 未知渠道/方法:自描述,附上游清单(不拦 LLM,让它看清单自纠)
111
74
  if (r.code === 2) {
112
75
  return {
113
- ...base,
114
- ok: false,
115
- verdict: 'error',
116
- evidence: evidence('error'),
117
- latencyMs,
76
+ ...base, ok: false, verdict: 'error', evidence: evidence('error'), latencyMs,
118
77
  error: parsed.error,
119
- inventory: parsed.channels ? {
120
- channels: parsed.channels
121
- } : {
122
- channel: parsed.channel,
123
- methods: parsed.methods
124
- }
78
+ inventory: parsed.channels ? { channels: parsed.channels } : { channel: parsed.channel, methods: parsed.methods },
125
79
  };
126
80
  }
81
+ // 调用抛错:若上游 check() 给出 warn/off,把上游原话作为 setup 透传
127
82
  const checkStatus = parsed.check?.status;
128
83
  if (checkStatus === 'warn' || checkStatus === 'off') {
129
- return {
130
- ...base,
131
- ok: false,
132
- verdict: 'needs-setup',
133
- evidence: evidence('needs-setup'),
134
- latencyMs,
135
- error: parsed.error,
136
- setup: parsed.check?.message
137
- };
84
+ return { ...base, ok: false, verdict: 'needs-setup', evidence: evidence('needs-setup'), latencyMs, error: parsed.error, setup: parsed.check?.message };
138
85
  }
139
- return {
140
- ...base,
141
- ok: false,
142
- verdict: 'error',
143
- evidence: evidence('error'),
144
- latencyMs,
145
- error: parsed.error ?? r.stderr.slice(0, 200)
146
- };
86
+ return { ...base, ok: false, verdict: 'error', evidence: evidence('error'), latencyMs, error: parsed.error ?? r.stderr.slice(0, 200) };
147
87
  }
88
+ /** 读网页:委托上游 WebChannel.read(Jina Reader 后端);供 gotry web 读取工具使用 */
148
89
  export async function readUrl(q) {
149
90
  if (!/^https?:\/\//.test(q.url.trim())) {
150
- return {
151
- ok: false,
152
- via: 'r.jina.ai-error',
153
- evidence: `[agent-reach:web.read@error@${ts()}] 非法 URL(需 http(s)://)`,
154
- latencyMs: 0,
155
- error: 'url 必须以 http(s):// 开头'
156
- };
91
+ return { ok: false, via: 'r.jina.ai-error', evidence: `[agent-reach:web.read@error@${ts()}] 非法 URL(需 http(s)://)`, latencyMs: 0, error: 'url 必须以 http(s):// 开头' };
157
92
  }
158
- const r = await reach({
159
- channel: 'web',
160
- method: 'read',
161
- args: [
162
- q.url.trim()
163
- ],
164
- timeoutMs: q.timeoutMs
165
- });
93
+ const r = await reach({ channel: 'web', method: 'read', args: [q.url.trim()], timeoutMs: q.timeoutMs });
166
94
  const content = typeof r.data === 'string' ? r.data.slice(0, 8000) : undefined;
95
+ // 上游 Jina Reader 输出首行 "Title: ...",提取为标题(展示层逻辑,非渠道知识)
167
96
  const title = content?.match(/^Title: (.+)$/m)?.[1];
168
97
  return {
169
- ok: r.ok,
170
- via: r.ok ? 'r.jina.ai' : 'r.jina.ai-error',
171
- title,
172
- content,
173
- evidence: r.evidence,
174
- latencyMs: r.latencyMs,
175
- error: r.error
98
+ ok: r.ok, via: r.ok ? 'r.jina.ai' : 'r.jina.ai-error',
99
+ title, content, evidence: r.evidence, latencyMs: r.latencyMs,
100
+ error: r.error,
176
101
  };
177
102
  }
103
+ /** 渠道体检:spawn 真 agent-reach doctor,输出原样透传 */
178
104
  export async function reachStatus(timeoutMs = 90_000) {
179
105
  const started = Date.now();
180
106
  const bin = resolve(repoRoot(), '.venv/bin/agent-reach');
181
107
  if (!existsSync(bin)) {
182
- return {
183
- ok: false,
184
- via: 'not-installed',
185
- evidence: `[agent-reach:doctor@not-installed@${ts()}]`,
186
- latencyMs: 0,
187
- output: 'Agent Reach 未装配(.venv 缺失)——可选依赖,补装:终端跑 npx gotry doctor --fix;或让助手调 gotry_doctor 看整体体检报告'
188
- };
108
+ return { ok: false, via: 'not-installed', evidence: `[agent-reach:doctor@not-installed@${ts()}]`, latencyMs: 0, output: 'Agent Reach 未装配(.venv 缺失)——可选依赖,补装:终端跑 npx @danceiny/gotry doctor --fix;或让助手调 gotry_doctor 看整体体检报告' };
189
109
  }
190
- const r = await run(bin, [
191
- 'doctor'
192
- ], timeoutMs);
110
+ const r = await run(bin, ['doctor'], timeoutMs);
193
111
  const output = (r.stdout || r.stderr).trim();
194
112
  return {
195
113
  ok: !r.err?.includes('ENOENT') && r.code === 0,
196
114
  via: 'agent-reach-cli',
197
115
  evidence: `[agent-reach:doctor@${ts()}] via .venv/bin/agent-reach`,
198
116
  latencyMs: Date.now() - started,
199
- output: output.slice(0, 4000)
117
+ output: output.slice(0, 4000),
200
118
  };
201
119
  }
202
-
203
-
204
- //# sourceURL=ts/capabilities/agent-reach.ts
@@ -1,114 +1,132 @@
1
+ /**
2
+ * Anything 通用搜索能力层:hbcli → hotel-be Anything 函数。
3
+ *
4
+ * 链路(同构 hbcli.ts):
5
+ * gotry capabilities/anything.ts
6
+ * → spawn hbcli --json search anything <kw> [opts]
7
+ * → hotel-be /api/search/anything(httpdispatch 自动注册;httpdispatch 路由面)
8
+ * → search/service/geography.go func Anything (mixed 城市+酒店搜索)
9
+ *
10
+ * wire 契约(2026-09-07 对齐上游源码;SearchItem = FuzzySearchItem + hotel):
11
+ * req { keyword, contentType?, context.destinationId?, minHotelCount? }
12
+ * resp { candidates: [{ type: 'city'|'place'|'hotel',
13
+ * region?: { id, name:{en,zh,ar}, coordinates:{centerLat,centerLng}, countryCode, … },
14
+ * place?: { latlngCoordinator },
15
+ * matchScore?, hotel?: { id, name:{en,zh,ar}, star, latlngCoordinator:{google|gaode:{lat,lng} } } }] }
16
+ *
17
+ * 三值语义:
18
+ * - hit: 命中候选(混合 city/hotel,maybe-coords)
19
+ * - miss: hbcli exit 0,但 candidates 为空(查无结果)
20
+ * - err: hbcli exit ≠ 0 或超时(降级,降级产物 标 [实时API:hbcli-anything@error@ts])
21
+ *
22
+ * 契约(与 hbcli/weather/opensky 同构,L4 不变量):
23
+ * - 永不抛错:网络/超时/解析失败一律降级返回;
24
+ * - 证据链标注:成功 [实时API:hbcli-anything@ts];失败 [实时API:hbcli-anything@error@ts];
25
+ * - 永不阻塞调用方:周边有 12s 默认超时,LLM 不等。
26
+ *
27
+ * 第 7 个能力层(与 hbcli.ts / weather.ts / opensky.ts 平级),data-sources.md §4
28
+ * Google Place 链路的「酒店-be 中间层」入口。
29
+ */
1
30
  import { spawn } from 'node:child_process';
2
31
  import { hbcliBinCandidates } from './hbcli.js';
3
32
  function i18nText(v) {
4
- if (!v) return '';
5
- if (typeof v === 'string') return v;
33
+ if (!v)
34
+ return '';
35
+ if (typeof v === 'string')
36
+ return v;
6
37
  return v.zh || v.en || v.ar || '';
7
38
  }
39
+ /** hotel-be Latlng:{lat,lng};google/gaode 双源取先非零者 */
8
40
  function latlngOf(coord) {
9
- for (const src of [
10
- coord?.google,
11
- coord?.gaode
12
- ]){
41
+ for (const src of [coord?.google, coord?.gaode]) {
13
42
  const lat = typeof src?.lat === 'number' ? src.lat : undefined;
14
43
  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
- };
44
+ if (lat !== undefined && lng !== undefined && (lat !== 0 || lng !== 0))
45
+ return { latitude: lat, longitude: lng };
19
46
  }
20
47
  return {};
21
48
  }
22
49
  function sh(cmd, args, opts) {
23
50
  const ctrl = new AbortController();
24
- const timer = setTimeout(()=>{
51
+ const timer = setTimeout(() => {
25
52
  ctrl.abort();
53
+ // AbortSignal on spawn 会发 SIGTERM;对于不响应 SIGTERM 的子进程,需要在外部再发一次 SIGKILL。
54
+ // Node 不能直接通过 AbortController 拿 child pid,所以需要借助外部变量保存 child。
26
55
  }, opts.timeoutMs);
27
56
  let child = null;
28
57
  let killTimer = null;
29
- return new Promise((resolve)=>{
58
+ return new Promise((resolve) => {
30
59
  child = spawn(cmd, args, {
31
60
  env: opts.env,
32
61
  cwd: process.cwd(),
33
- signal: ctrl.signal
62
+ signal: ctrl.signal,
34
63
  });
35
64
  let stdout = '';
36
65
  let stderr = '';
37
66
  let error;
38
67
  let killed = false;
39
- child.stdout?.on('data', (d)=>{
40
- stdout += d.toString();
41
- });
42
- child.stderr?.on('data', (d)=>{
43
- stderr += d.toString();
44
- });
45
- child.on('error', (e)=>{
46
- error = e.message.slice(0, 200);
47
- });
48
- child.on('close', (code)=>{
68
+ child.stdout?.on('data', (d) => { stdout += d.toString(); });
69
+ child.stderr?.on('data', (d) => { stderr += d.toString(); });
70
+ child.on('error', (e) => { error = e.message.slice(0, 200); });
71
+ child.on('close', (code) => {
49
72
  clearTimeout(timer);
50
- if (killTimer) clearTimeout(killTimer);
51
- resolve({
52
- code: killed ? -2 : code ?? -1,
53
- stdout,
54
- stderr,
55
- error
56
- });
73
+ if (killTimer)
74
+ clearTimeout(killTimer);
75
+ resolve({ code: killed ? -2 : (code ?? -1), stdout, stderr, error });
57
76
  });
58
- ctrl.signal.addEventListener('abort', ()=>{
59
- if (!child) return;
77
+ // Abort 后 500ms 内若子进程仍活,发 SIGKILL 强杀。
78
+ ctrl.signal.addEventListener('abort', () => {
79
+ if (!child)
80
+ return;
60
81
  try {
61
82
  child.kill('SIGTERM');
62
- } catch {}
63
- killTimer = setTimeout(()=>{
83
+ }
84
+ catch { /* ignore */ }
85
+ killTimer = setTimeout(() => {
64
86
  try {
65
87
  child?.kill('SIGKILL');
66
- } catch {}
88
+ }
89
+ catch { /* ignore */ }
67
90
  }, 500);
68
91
  });
69
92
  });
70
93
  }
94
+ /** --json 必须在子命令前(cli.ts 全局旗标预扫描只认子命令前位置;JSON 错误也走结构化 stderr) */
71
95
  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));
96
+ const args = ['--json', 'search', 'anything', keyword];
97
+ if (q.contentType)
98
+ args.push('--content-type', q.contentType);
99
+ if (q.parentDestinationId !== undefined)
100
+ args.push('--destination-id', String(q.parentDestinationId));
80
101
  return args;
81
102
  }
103
+ /** 旧版 CLI 无 search anything 子命令时的可行动升级指引(issue #195:裸 unknown command 读起来像工具坏了) */
82
104
  function upgradeHint(stderr) {
83
- return /unknown command/i.test(stderr) ? 'hbcli 版本过旧(无 search anything 子命令)——请升级:hbcli update,或重跑 npx gotry setup' : null;
105
+ return /unknown command/i.test(stderr)
106
+ ? 'hbcli 版本过旧(无 search anything 子命令)——请升级:hbcli update,或重跑 npx @danceiny/gotry setup'
107
+ : null;
84
108
  }
109
+ /** Anything 通用搜索 — 任何搜索失败走降级;不抛错 */
85
110
  export async function anythingSearch(q) {
86
111
  const started = Date.now();
87
112
  const ts = new Date().toISOString();
88
113
  const kw = (q.keyword ?? '').trim();
89
114
  if (!kw) {
90
115
  return {
91
- ok: false,
92
- via: 'hbcli-anything-error',
116
+ ok: false, via: 'hbcli-anything-error',
93
117
  evidence: `[实时API:hbcli-anything@error@${ts}] keyword empty`,
94
- latencyMs: Date.now() - started,
95
- verdict: 'error',
96
- error: 'keyword is required'
118
+ latencyMs: Date.now() - started, verdict: 'error',
119
+ error: 'keyword is required',
97
120
  };
98
121
  }
99
122
  const args = buildArgs(kw, q);
123
+ // spawn 级失败(ENOENT)按已知安装位回退(hbcli.ts callHbcliJson 同款);其余失败无重试意义
100
124
  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;
125
+ let r = { code: -1, stdout: '', stderr: '' };
126
+ for (let i = 0; i < candidates.length; i++) {
127
+ r = await sh(candidates[i], args, { timeoutMs: q.timeoutMs ?? 12_000, env: process.env });
128
+ if (!(r.error && i < candidates.length - 1))
129
+ break;
112
130
  }
113
131
  const latencyMs = Date.now() - started;
114
132
  if (r.error || r.code !== 0) {
@@ -119,7 +137,7 @@ export async function anythingSearch(q) {
119
137
  evidence: `[实时API:hbcli-anything@error@${ts}] ${raw}`,
120
138
  latencyMs,
121
139
  verdict: 'error',
122
- error: upgradeHint(r.stderr) ?? raw
140
+ error: upgradeHint(r.stderr) ?? raw,
123
141
  };
124
142
  }
125
143
  let data;
@@ -127,18 +145,18 @@ export async function anythingSearch(q) {
127
145
  const jStart = r.stdout.indexOf('{') >= 0 ? r.stdout.indexOf('{') : r.stdout.indexOf('[');
128
146
  const json = jStart >= 0 ? r.stdout.slice(jStart) : r.stdout;
129
147
  data = JSON.parse(json);
130
- } catch {
148
+ }
149
+ catch {
131
150
  return {
132
- ok: false,
133
- via: 'hbcli-anything-error',
151
+ ok: false, via: 'hbcli-anything-error',
134
152
  evidence: `[实时API:hbcli-anything@error@${ts}] parse failed`,
135
153
  latencyMs,
136
154
  verdict: 'error',
137
- error: 'failed to parse hbcli output as JSON'
155
+ error: 'failed to parse hbcli output as JSON',
138
156
  };
139
157
  }
140
158
  const rawItems = data.candidates ?? [];
141
- const hits = rawItems.map((it)=>{
159
+ const hits = rawItems.map((it) => {
142
160
  const region = it.region ?? {};
143
161
  const hotel = it.hotel ?? {};
144
162
  const isHotel = it.type === 'hotel' || Boolean(hotel.id);
@@ -146,27 +164,23 @@ export async function anythingSearch(q) {
146
164
  const placeCoords = latlngOf(it.place?.latlngCoordinator);
147
165
  const center = region.coordinates ?? {};
148
166
  return {
149
- type: isHotel ? 'hotel' : it.type === 'place' ? 'place' : 'city',
167
+ type: (isHotel ? 'hotel' : (it.type === 'place' ? 'place' : 'city')),
150
168
  name: i18nText(hotel.name) || i18nText(region.name) || '?',
151
169
  score: it.matchScore,
152
170
  latitude: hotelCoords.latitude ?? placeCoords.latitude ?? (typeof center.centerLat === 'number' ? center.centerLat : undefined),
153
171
  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,
172
+ destinationId: hotel.destinationId !== undefined ? String(hotel.destinationId) : (region.id !== undefined ? String(region.id) : undefined),
155
173
  hotelId: hotel.id !== undefined ? String(hotel.id) : undefined,
156
- star: typeof hotel.star === 'number' && hotel.star > 0 ? hotel.star : undefined
174
+ star: typeof hotel.star === 'number' && hotel.star > 0 ? hotel.star : undefined,
157
175
  };
158
176
  });
159
177
  const verdict = hits.length > 0 ? 'hit' : 'miss';
160
178
  return {
161
- ok: true,
162
- via: 'hbcli-anything',
179
+ ok: true, via: 'hbcli-anything',
163
180
  evidence: `[实时API:hbcli-anything@${ts}] ${hits.length}/${rawItems.length} candidates`,
164
181
  latencyMs,
165
182
  verdict,
166
183
  hits,
167
- totalCandidates: rawItems.length
184
+ totalCandidates: rawItems.length,
168
185
  };
169
186
  }
170
-
171
-
172
- //# sourceURL=ts/capabilities/anything.ts