@danceiny/gotry 0.0.1-rc.9 → 0.2.0-rc.28

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 (533) hide show
  1. package/README.md +172 -219
  2. package/README.zh-CN.md +222 -0
  3. package/bin/gotry-backend.js +53 -0
  4. package/bin/gotry-booking-copilot.js +53 -0
  5. package/bin/gotry-bootstrap.js +1788 -0
  6. package/bin/gotry-inner.js +733 -83
  7. package/bin/gotry-process-liveness.d.ts +27 -0
  8. package/bin/gotry-process-liveness.js +97 -0
  9. package/bin/gotry-runtime-resolution.d.ts +27 -0
  10. package/bin/gotry-runtime-resolution.js +49 -0
  11. package/bin/gotry.js +1 -1
  12. package/client/client.js +203 -0
  13. package/cordis.gotry-patch.yml +80 -56
  14. package/data/airline-airports.json +39 -0
  15. package/data/stations-12306-verify.json +524 -0
  16. package/dist/capabilities/agent-reach-deep.js +45 -122
  17. package/dist/capabilities/agent-reach.js +101 -146
  18. package/dist/capabilities/anything.js +161 -94
  19. package/dist/capabilities/artifacts.js +370 -0
  20. package/dist/capabilities/channel-health.js +131 -0
  21. package/dist/capabilities/channel-registry.js +256 -0
  22. package/dist/capabilities/doctor.js +553 -0
  23. package/dist/capabilities/effect.js +394 -0
  24. package/dist/capabilities/external-event.js +149 -0
  25. package/dist/capabilities/fact-log.js +55 -0
  26. package/dist/capabilities/flyai-config.js +337 -0
  27. package/dist/capabilities/flyai.js +947 -110
  28. package/dist/capabilities/fx-contract.js +293 -0
  29. package/dist/capabilities/geo-atlas.js +246 -0
  30. package/dist/capabilities/ground-transfer.js +676 -0
  31. package/dist/capabilities/hbcli.js +260 -123
  32. package/dist/capabilities/hotelbyte-transaction.js +194 -0
  33. package/dist/capabilities/incident-log.js +131 -61
  34. package/dist/capabilities/itinerary-artifact.js +190 -0
  35. package/dist/capabilities/itinerary-deck-artifact.js +194 -0
  36. package/dist/capabilities/itinerary-deck-export.js +339 -0
  37. package/dist/capabilities/lavish-local.js +924 -0
  38. package/dist/capabilities/model-override.js +38 -0
  39. package/dist/capabilities/opensky.js +54 -43
  40. package/dist/capabilities/provider-detail-sanitize.js +64 -0
  41. package/dist/capabilities/resilience.js +191 -0
  42. package/dist/capabilities/route-provider-conformance.js +341 -0
  43. package/dist/capabilities/session/action-cache.js +50 -44
  44. package/dist/capabilities/session/adapters/ctrip-flight.js +120 -62
  45. package/dist/capabilities/session/adapters/ctrip-hotel.js +222 -0
  46. package/dist/capabilities/session/adapters/dida-portal.js +274 -0
  47. package/dist/capabilities/session/adapters/meituan-local.js +35 -54
  48. package/dist/capabilities/session/adapters/rail-12306.js +342 -0
  49. package/dist/capabilities/session/benchmark.js +189 -0
  50. package/dist/capabilities/session/bridge-ledger.js +224 -0
  51. package/dist/capabilities/session/extension-bridge.js +636 -0
  52. package/dist/capabilities/session/extension-channel.js +109 -0
  53. package/dist/capabilities/session/extension-distribution.js +230 -0
  54. package/dist/capabilities/session/extract.js +31 -21
  55. package/dist/capabilities/session/golden-score.js +114 -0
  56. package/dist/capabilities/session/health-watch.js +215 -0
  57. package/dist/capabilities/session/read-guard.js +75 -24
  58. package/dist/capabilities/session/static-flight-golden.js +150 -0
  59. package/dist/capabilities/session/transport.js +97 -83
  60. package/dist/capabilities/session/wizard.js +117 -0
  61. package/dist/capabilities/session-consent.js +178 -0
  62. package/dist/capabilities/session-login.js +170 -0
  63. package/dist/capabilities/session-search.js +635 -44
  64. package/dist/capabilities/spawn-bounded.js +203 -0
  65. package/dist/capabilities/sponsor-plugin.js +341 -0
  66. package/dist/capabilities/visa-policy.js +140 -0
  67. package/dist/capabilities/weather.js +243 -138
  68. package/dist/data/session-golden-20.json +25 -0
  69. package/dist/data/sf-golden-manifest.json +103 -0
  70. package/dist/data/sf-static-routes.json +91 -0
  71. package/dist/scripts/action-cache-tests.js +24 -59
  72. package/dist/scripts/agent-planning-turn-deadline-e2e.js +242 -0
  73. package/dist/scripts/agent-planning-turn-deadline-tests.js +185 -0
  74. package/dist/scripts/agent-reach-deep-tests.js +30 -40
  75. package/dist/scripts/agent-reach-error-tests.js +354 -0
  76. package/dist/scripts/agent-reach-tests.js +26 -18
  77. package/dist/scripts/agent-reach-wrapper-tests.js +50 -50
  78. package/dist/scripts/anything-path-measure-tests.js +133 -0
  79. package/dist/scripts/anything-path-measure.js +150 -0
  80. package/dist/scripts/anything-tests.js +250 -60
  81. package/dist/scripts/artifact-client-contract-tests.js +220 -0
  82. package/dist/scripts/artifacts-capability-tests.js +727 -0
  83. package/dist/scripts/async-collect.js +50 -11
  84. package/dist/scripts/benchmark-environment-bridge-e2e.js +741 -0
  85. package/dist/scripts/benchmark-environment-bridge-tests.js +1452 -0
  86. package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +126 -0
  87. package/dist/scripts/booking-copilot-availability-policy-tests.js +265 -0
  88. package/dist/scripts/booking-copilot-bin-proof-tests.js +66 -0
  89. package/dist/scripts/booking-copilot-cleanup-proof-helper.js +76 -0
  90. package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +144 -0
  91. package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +424 -0
  92. package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +2839 -0
  93. package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +309 -0
  94. package/dist/scripts/booking-copilot-dsh-readiness-proof.js +238 -0
  95. package/dist/scripts/booking-copilot-dsh-warmer-proof.js +126 -0
  96. package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +156 -0
  97. package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +70 -0
  98. package/dist/scripts/booking-copilot-intent-proof-tests.js +422 -0
  99. package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +184 -0
  100. package/dist/scripts/booking-copilot-planner-live-probe.js +95 -0
  101. package/dist/scripts/booking-copilot-proof-runtime.js +42 -0
  102. package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +210 -0
  103. package/dist/scripts/booking-copilot-runtime-proof-tests.js +2349 -0
  104. package/dist/scripts/booking-copilot-server-proof-tests.js +784 -0
  105. package/dist/scripts/booking-copilot-startup-proof-tests.js +94 -0
  106. package/dist/scripts/booking-executor-tests.js +80 -0
  107. package/dist/scripts/booking-recovery-chain-tests.js +182 -0
  108. package/dist/scripts/booking-saga-tests.js +125 -0
  109. package/dist/scripts/booking-surface-contract-proof-tests.js +212 -0
  110. package/dist/scripts/bootstrap-tests.js +1549 -0
  111. package/dist/scripts/bridge-events-tests.js +239 -0
  112. package/dist/scripts/bridge-ledger-tests.js +428 -0
  113. package/dist/scripts/build-changelog.js +238 -0
  114. package/dist/scripts/build-metrics-report.js +331 -0
  115. package/dist/scripts/changelog-tests.js +118 -0
  116. package/dist/scripts/channel-probe-tests.js +103 -0
  117. package/dist/scripts/channel-probe.js +169 -0
  118. package/dist/scripts/channel-registry-tests.js +208 -0
  119. package/dist/scripts/city-scenario-tier-tests.js +234 -0
  120. package/dist/scripts/companion-tests.js +25 -70
  121. package/dist/scripts/dida-cookie-probe.js +87 -0
  122. package/dist/scripts/dida-runner-stop-tests.js +311 -0
  123. package/dist/scripts/dida-sw-probe.js +114 -0
  124. package/dist/scripts/diff-test.js +17 -12
  125. package/dist/scripts/doctor-tests.js +600 -0
  126. package/dist/scripts/drill-multiuser-ledger-tests.js +1076 -0
  127. package/dist/scripts/drill-sdk-descendant-cleanup-tests.js +606 -0
  128. package/dist/scripts/drill-w2a-sensor-tests.js +788 -0
  129. package/dist/scripts/dsh-artifact-e2e.js +279 -0
  130. package/dist/scripts/dsh-artifact-web-e2e.js +675 -0
  131. package/dist/scripts/dsh-http-proxy-sse-proof.js +90 -0
  132. package/dist/scripts/dsh-llm-tests.js +437 -0
  133. package/dist/scripts/dsh-runtime-closure-tests.js +182 -0
  134. package/dist/scripts/dsh-runtime-closure.js +162 -0
  135. package/dist/scripts/dsh-session-v3-migration-proof.js +109 -0
  136. package/dist/scripts/dsh-subprocess-local-proof.js +150 -0
  137. package/dist/scripts/dsh-target-closure-proof.js +178 -0
  138. package/dist/scripts/effect-tests.js +539 -0
  139. package/dist/scripts/engine-run.js +1 -3
  140. package/dist/scripts/engine-tests.js +16 -10
  141. package/dist/scripts/evaluation-cadence-tests.js +174 -0
  142. package/dist/scripts/evaluation-contract-tests.js +268 -0
  143. package/dist/scripts/extension-distribution-cli.js +39 -0
  144. package/dist/scripts/extension-distribution-tests.js +443 -0
  145. package/dist/scripts/extension-tests.js +988 -0
  146. package/dist/scripts/external-event-tests.js +350 -0
  147. package/dist/scripts/fact-gate-tests.js +869 -0
  148. package/dist/scripts/fixtures/extension-bridge-unref-child.mjs +21 -0
  149. package/dist/scripts/flight-hotel-anchor-363-registered-e2e.js +169 -0
  150. package/dist/scripts/flight-malformed-tests.js +159 -0
  151. package/dist/scripts/flyai-setup-tests.js +228 -0
  152. package/dist/scripts/flyai-setup-tool-tests.js +54 -0
  153. package/dist/scripts/flyai-tests.js +692 -0
  154. package/dist/scripts/flyai-tool-registration-contract-tests.js +91 -0
  155. package/dist/scripts/fx-contract-tests.js +201 -0
  156. package/dist/scripts/g5-guard-tests.js +150 -0
  157. package/dist/scripts/g5-guard.js +193 -0
  158. package/dist/scripts/gen-lunar-anchors.js +106 -0
  159. package/dist/scripts/geo-atlas-tests.js +283 -0
  160. package/dist/scripts/gotry-backend-kernel-tests.js +206 -0
  161. package/dist/scripts/gotry-try-demo-tests.js +79 -0
  162. package/dist/scripts/gotry-try-demo.js +49 -0
  163. package/dist/scripts/ground-transfer-tests.js +956 -0
  164. package/dist/scripts/hbcli-e2e-tests.js +159 -0
  165. package/dist/scripts/hbcli-live-optin-tests.js +96 -0
  166. package/dist/scripts/hbcli-release-contract-tests.js +122 -0
  167. package/dist/scripts/hbcli-tests.js +121 -69
  168. package/dist/scripts/health-watch-cli.js +73 -0
  169. package/dist/scripts/hotel-date-gate-tests.js +496 -0
  170. package/dist/scripts/hotelbyte-reconcile-tests.js +141 -0
  171. package/dist/scripts/hotelbyte-spawn-e2e-tests.js +373 -0
  172. package/dist/scripts/i18n-tests.js +41 -0
  173. package/dist/scripts/incident-tests.js +281 -87
  174. package/dist/scripts/issue-194-job-id-guard-tests.js +106 -0
  175. package/dist/scripts/issue-233-cancel-refund-commission-tests.js +392 -0
  176. package/dist/scripts/issue-271-liveness-tests.js +569 -0
  177. package/dist/scripts/issue-289-model-retry-real-tests.js +296 -0
  178. package/dist/scripts/issue-289-model-retry-tests.js +441 -0
  179. package/dist/scripts/issue-289-web-retry-e2e.js +630 -0
  180. package/dist/scripts/issue-338-home-city-e2e.js +577 -0
  181. package/dist/scripts/issue343-real-entry-e2e.js +160 -0
  182. package/dist/scripts/issue436-persisted-routing-e2e.js +247 -0
  183. package/dist/scripts/itinerary-artifact-tests.js +368 -0
  184. package/dist/scripts/itinerary-deck-artifact-tests.js +416 -0
  185. package/dist/scripts/itinerary-deck-export-tests.js +552 -0
  186. package/dist/scripts/itinerary-deck-tests.js +435 -0
  187. package/dist/scripts/itinerary-html-tests.js +426 -0
  188. package/dist/scripts/journey-tests.js +22 -27
  189. package/dist/scripts/kernel-manifest-evidence.js +109 -0
  190. package/dist/scripts/kernel-manifest-gate.js +126 -0
  191. package/dist/scripts/kernel-manifest-tests.js +212 -0
  192. package/dist/scripts/kernel-manifest-trace-entry.js +7 -0
  193. package/dist/scripts/kernel-manifest-trace-hook.mjs +28 -0
  194. package/dist/scripts/kernel-manifest.js +369 -0
  195. package/dist/scripts/lavish-local-tests.js +1226 -0
  196. package/dist/scripts/lavish-product-tools-tests.js +537 -0
  197. package/dist/scripts/ledger-repair-apply-tests.js +316 -0
  198. package/dist/scripts/ledger-repair-plan-tests.js +375 -0
  199. package/dist/scripts/ledger-tests.js +382 -246
  200. package/dist/scripts/ledger-workflow-crash.js +10 -20
  201. package/dist/scripts/m3-cohort-tests.js +714 -0
  202. package/dist/scripts/m3-cohort.js +310 -0
  203. package/dist/scripts/managed-dsh-cleanup-diagnostic-proof.js +184 -0
  204. package/dist/scripts/managed-dsh-close-failure-proof.js +172 -0
  205. package/dist/scripts/managed-dsh-run-port-proof.js +153 -0
  206. package/dist/scripts/managed-dsh-terminal-proof.js +252 -0
  207. package/dist/scripts/map-tools-vendor-package-proof.js +365 -0
  208. package/dist/scripts/memory-capture-tests.js +242 -61
  209. package/dist/scripts/memory-decay-tests.js +18 -52
  210. package/dist/scripts/memory-lifecycle-tests.js +657 -0
  211. package/dist/scripts/memory-lifecycle.js +196 -0
  212. package/dist/scripts/memory-metrics.js +24 -12
  213. package/dist/scripts/memory-value-report.js +631 -0
  214. package/dist/scripts/memory-value-tests.js +328 -0
  215. package/dist/scripts/metrics-report-tests.js +151 -0
  216. package/dist/scripts/model-override-e2e.js +137 -0
  217. package/dist/scripts/nightly-evidence-tests.js +203 -0
  218. package/dist/scripts/nightly-evidence.js +303 -0
  219. package/dist/scripts/nudge-digest.js +39 -28
  220. package/dist/scripts/observability-tests.js +381 -0
  221. package/dist/scripts/onboarding-tests.js +161 -0
  222. package/dist/scripts/opensky-check.js +18 -13
  223. package/dist/scripts/opensky-tests.js +28 -28
  224. package/dist/scripts/outcome-projection-tests.js +427 -0
  225. package/dist/scripts/persona-sim-tests.js +603 -0
  226. package/dist/scripts/persona-sim.js +1081 -0
  227. package/dist/scripts/persona-surface-guard-tests.js +49 -0
  228. package/dist/scripts/pnpm-dsh-closure-proof.js +17 -0
  229. package/dist/scripts/policy-anchor-359-registered-e2e.js +214 -0
  230. package/dist/scripts/price-drift-tests.js +340 -0
  231. package/dist/scripts/price-drift-watch.js +447 -0
  232. package/dist/scripts/probe-poi-tests.js +53 -45
  233. package/dist/scripts/product-metrics.js +483 -0
  234. package/dist/scripts/publish-preverify.js +110 -0
  235. package/dist/scripts/realtime-pricing-tests.js +76 -0
  236. package/dist/scripts/recall-tests.js +513 -0
  237. package/dist/scripts/replay-async.js +22 -18
  238. package/dist/scripts/replay-real.js +18 -18
  239. package/dist/scripts/replay.js +54 -82
  240. package/dist/scripts/route-provider-conformance-tests.js +391 -0
  241. package/dist/scripts/session-attach-diagnose.js +20 -20
  242. package/dist/scripts/session-attach-poc.js +34 -37
  243. package/dist/scripts/session-benchmark.js +180 -0
  244. package/dist/scripts/session-dida-live-e2e.js +199 -0
  245. package/dist/scripts/session-extract-tests.js +14 -35
  246. package/dist/scripts/session-link-tests.js +478 -0
  247. package/dist/scripts/session-login.js +27 -46
  248. package/dist/scripts/session-tests.js +796 -96
  249. package/dist/scripts/session-zone-crash.js +49 -0
  250. package/dist/scripts/session-zone-ledger-tests.js +432 -0
  251. package/dist/scripts/session-zone-observation-tests.js +492 -0
  252. package/dist/scripts/session-zone-observe.js +135 -0
  253. package/dist/scripts/session-zone-wiring-tests.js +566 -0
  254. package/dist/scripts/session-zones-tests.js +374 -0
  255. package/dist/scripts/sf-live-benchmark.js +367 -0
  256. package/dist/scripts/sf-live-challenge-stop-tests.js +453 -0
  257. package/dist/scripts/sf-live-cli-tests.js +92 -0
  258. package/dist/scripts/sf-live-options.js +46 -0
  259. package/dist/scripts/sf-manifest-tests.js +30 -0
  260. package/dist/scripts/sf-manifest.js +33 -0
  261. package/dist/scripts/sf-soft-score-tests.js +67 -0
  262. package/dist/scripts/sf-summary-tests.js +324 -0
  263. package/dist/scripts/sf-summary.js +525 -0
  264. package/dist/scripts/share-tests.js +432 -0
  265. package/dist/scripts/skeleton-check.js +16 -14
  266. package/dist/scripts/skeleton-integration-test.js +28 -11
  267. package/dist/scripts/skills-contract-tests.js +51 -46
  268. package/dist/scripts/smoke-session-gate-tests.js +21 -0
  269. package/dist/scripts/smoke.js +690 -246
  270. package/dist/scripts/spawn-bounded-abort-tests.js +244 -0
  271. package/dist/scripts/sponsor-reuse-tests.js +262 -0
  272. package/dist/scripts/state-cli-tests.js +226 -101
  273. package/dist/scripts/state-cli.js +565 -198
  274. package/dist/scripts/state-repair-cli.js +66 -0
  275. package/dist/scripts/state-repair-tests.js +140 -0
  276. package/dist/scripts/static-golden-tests.js +165 -0
  277. package/dist/scripts/time-eval-tests.js +212 -192
  278. package/dist/scripts/travel-timeline-tests.js +29 -93
  279. package/dist/scripts/turn-handoff-collect-tests.js +169 -0
  280. package/dist/scripts/turn-handoff-collect.js +161 -0
  281. package/dist/scripts/turn-policy-tests.js +55 -0
  282. package/dist/scripts/typed-contract-canary.js +176 -0
  283. package/dist/scripts/tz-resolver-sanity.js +50 -0
  284. package/dist/scripts/tz-resolver-tests.js +584 -0
  285. package/dist/scripts/unified-tests.js +60 -20
  286. package/dist/scripts/visa-policy-tests.js +62 -0
  287. package/dist/scripts/weather-tests.js +276 -41
  288. package/dist/scripts/wish-channel-gate-tests.js +54 -0
  289. package/dist/scripts/write-gate-tests.js +522 -0
  290. package/dist/scripts/z3-lifecycle-fault-tests.js +188 -0
  291. package/dist/scripts/z3-lifecycle-tests.js +170 -0
  292. package/dist/scripts/z3-race-repeat-tests.js +39 -0
  293. package/dist/scripts/z3-race-tests.js +46 -0
  294. package/dist/src/artifact-gate.js +829 -0
  295. package/dist/src/backend/kernel.js +91 -0
  296. package/dist/src/backend/modules/booking-copilot.js +92 -0
  297. package/dist/src/backend/modules/booking-executor.js +124 -0
  298. package/dist/src/backend/modules/session-search.js +551 -0
  299. package/dist/src/benchmark-agent-conformance.js +578 -0
  300. package/dist/src/benchmark-environment-bridge.js +515 -0
  301. package/dist/src/benchmark-headless-child-diagnostics.js +166 -0
  302. package/dist/src/benchmark-tool-isolation.js +151 -0
  303. package/dist/src/bookable-facts.js +533 -0
  304. package/dist/src/booking-saga.js +97 -0
  305. package/dist/src/booking-surface/availability-policy.js +697 -0
  306. package/dist/src/booking-surface/booking-intent.js +43 -0
  307. package/dist/src/booking-surface/cancel-refund-commission.js +379 -0
  308. package/dist/src/booking-surface/canonical-schema.js +116 -0
  309. package/dist/src/booking-surface/contracts.js +75 -0
  310. package/dist/src/booking-surface/dsh-planner.js +1854 -0
  311. package/dist/src/booking-surface/dsh-plugin.js +378 -0
  312. package/dist/src/booking-surface/dsh-worker.js +98 -0
  313. package/dist/src/booking-surface/error-codes.js +231 -0
  314. package/dist/src/booking-surface/index.js +9 -0
  315. package/dist/src/booking-surface/managed-dsh-cleanup-diagnostic.js +97 -0
  316. package/dist/src/booking-surface/managed-dsh-run-port.js +244 -0
  317. package/dist/src/booking-surface/profile.js +24 -0
  318. package/dist/src/booking-surface/recovery-chain.js +367 -0
  319. package/dist/src/booking-surface/runtime.js +1968 -0
  320. package/dist/src/booking-surface/server.js +674 -0
  321. package/dist/src/booking-surface/startup.js +168 -0
  322. package/dist/src/booking-surface/validation.js +261 -0
  323. package/dist/src/bridge.js +20 -13
  324. package/dist/src/city-scenario-tier.js +378 -0
  325. package/dist/src/companions.js +48 -74
  326. package/dist/src/contracts.js +21 -43
  327. package/dist/src/dsh-llm.js +171 -115
  328. package/dist/src/engine.js +276 -193
  329. package/dist/src/evaluation-cadence.js +97 -0
  330. package/dist/src/evaluation-contracts.js +283 -0
  331. package/dist/src/flight-pack-adapter.js +54 -0
  332. package/dist/src/flight-pack-contract.js +2 -0
  333. package/dist/src/flyai-setup-tool.js +70 -0
  334. package/dist/src/gotry-backend.js +125 -0
  335. package/dist/src/hotel-date-gate.js +118 -0
  336. package/dist/src/i18n.js +88 -0
  337. package/dist/src/index.js +2385 -881
  338. package/dist/src/itinerary-deck.js +139 -0
  339. package/dist/src/itinerary-doc-shared.js +661 -0
  340. package/dist/src/itinerary-html.js +131 -0
  341. package/dist/src/journey.js +155 -108
  342. package/dist/src/lavish-tools.js +400 -0
  343. package/dist/src/ledger-repair-apply.js +538 -0
  344. package/dist/src/ledger-repair-plan.js +463 -0
  345. package/dist/src/loop.js +331 -161
  346. package/dist/src/m3-cohort.js +1577 -0
  347. package/dist/src/memory-capture.js +180 -32
  348. package/dist/src/memory-decay.js +30 -14
  349. package/dist/src/memory-lifecycle.js +1310 -0
  350. package/dist/src/memory-utility.js +27 -40
  351. package/dist/src/mock-llm.js +36 -61
  352. package/dist/src/model.js +81 -36
  353. package/dist/src/outcome-projection.js +746 -0
  354. package/dist/src/realtime-pricing.js +103 -0
  355. package/dist/src/recall/card.js +74 -0
  356. package/dist/src/recall/evaluator.js +140 -0
  357. package/dist/src/recall/integration.js +17 -0
  358. package/dist/src/recall/tick.js +166 -0
  359. package/dist/src/session-link/plan-it-action.js +48 -0
  360. package/dist/src/session-link/session-link.js +248 -0
  361. package/dist/src/session-zone-ledger.js +312 -0
  362. package/dist/src/session-zone-observation.js +354 -0
  363. package/dist/src/session-zone-wiring.js +658 -0
  364. package/dist/src/session-zones.js +510 -0
  365. package/dist/src/share/adapters.js +51 -0
  366. package/dist/src/share/share-consent.js +76 -0
  367. package/dist/src/share/share-deck.js +58 -0
  368. package/dist/src/share/share-token.js +146 -0
  369. package/dist/src/slot-spec.js +84 -106
  370. package/dist/src/state-ledger.js +696 -524
  371. package/dist/src/state-repair.js +299 -0
  372. package/dist/src/subagent-job-id-guard.js +58 -0
  373. package/dist/src/time-anchor.js +231 -33
  374. package/dist/src/tool-packet.js +20 -8
  375. package/dist/src/travel-slots.js +58 -35
  376. package/dist/src/travel-timeline.js +44 -63
  377. package/dist/src/turn-deadline.js +287 -0
  378. package/dist/src/turn-policy.js +118 -0
  379. package/dist/src/tz-resolver.js +143 -0
  380. package/dist/src/unified.js +600 -360
  381. package/dist/src/wish-pool.js +42 -12
  382. package/dist/src/write-gate.js +495 -0
  383. package/dist/src/z3-shared.js +284 -0
  384. package/extension/README.md +21 -0
  385. package/extension/README.zh-CN.md +21 -0
  386. package/extension/background.js +463 -0
  387. package/extension/content-bridge.js +270 -0
  388. package/extension/content-main.js +111 -0
  389. package/extension/manifest.json +60 -0
  390. package/package.json +407 -14
  391. package/schemas/booking.intent.schema.json +193 -0
  392. package/schemas/booking.surface.schema.json +2622 -0
  393. package/ts/capabilities/agent-reach-deep.ts +114 -0
  394. package/ts/capabilities/agent-reach.ts +198 -0
  395. package/ts/capabilities/anything.ts +282 -0
  396. package/ts/capabilities/artifacts.ts +428 -0
  397. package/ts/capabilities/fact-log.ts +54 -0
  398. package/ts/capabilities/flyai-config.ts +388 -0
  399. package/ts/capabilities/flyai.ts +1274 -0
  400. package/ts/capabilities/hbcli.ts +253 -71
  401. package/ts/capabilities/incident-log.ts +88 -59
  402. package/ts/capabilities/itinerary-artifact.ts +214 -0
  403. package/ts/capabilities/itinerary-deck-artifact.ts +218 -0
  404. package/ts/capabilities/itinerary-deck-export.ts +378 -0
  405. package/ts/capabilities/opensky.ts +121 -0
  406. package/ts/capabilities/session/action-cache.ts +148 -0
  407. package/ts/capabilities/session/adapters/ctrip-flight.ts +181 -0
  408. package/ts/capabilities/session/adapters/ctrip-hotel.ts +238 -0
  409. package/ts/capabilities/session/adapters/dida-portal.ts +338 -0
  410. package/ts/capabilities/session/adapters/meituan-local.ts +70 -0
  411. package/ts/capabilities/session/adapters/rail-12306.ts +392 -0
  412. package/ts/capabilities/session/benchmark.ts +276 -0
  413. package/ts/capabilities/session/bridge-ledger.ts +333 -0
  414. package/ts/capabilities/session/extension-bridge.ts +794 -0
  415. package/ts/capabilities/session/extension-channel.ts +144 -0
  416. package/ts/capabilities/session/extension-distribution.ts +266 -0
  417. package/ts/capabilities/session/extract.ts +54 -0
  418. package/ts/capabilities/session/golden-score.ts +139 -0
  419. package/ts/capabilities/session/health-watch.ts +264 -0
  420. package/ts/capabilities/session/read-guard.ts +141 -0
  421. package/ts/capabilities/session/static-flight-golden.ts +209 -0
  422. package/ts/capabilities/session/transport.ts +146 -0
  423. package/ts/capabilities/session/wizard.ts +140 -0
  424. package/ts/capabilities/session-consent.ts +211 -0
  425. package/ts/capabilities/session-login.ts +208 -0
  426. package/ts/capabilities/session-search.ts +893 -0
  427. package/ts/capabilities/weather.ts +330 -0
  428. package/ts/dsh-runtime/vendor/README.md +68 -0
  429. package/ts/dsh-runtime/vendor/dsh-map-tools/LICENSE +21 -0
  430. package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +405 -0
  431. package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +404 -0
  432. package/ts/dsh-runtime/vendor/dsh-map-tools/client/client.js +1584 -0
  433. package/ts/dsh-runtime/vendor/dsh-map-tools/cordis.patch.yml +5 -0
  434. package/ts/dsh-runtime/vendor/dsh-map-tools/icon.svg +5 -0
  435. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/amap.js +595 -0
  436. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/nominatim.js +63 -0
  437. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/osrm.js +58 -0
  438. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/photon.js +55 -0
  439. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-file.js +87 -0
  440. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-route.js +131 -0
  441. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config.js +16 -0
  442. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/geo.js +232 -0
  443. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/index.js +120 -0
  444. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +40 -0
  445. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/staticmap-route.js +115 -0
  446. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/geocode.js +127 -0
  447. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/poi.js +84 -0
  448. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/routes.js +267 -0
  449. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/amap.d.ts +90 -0
  450. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/nominatim.d.ts +17 -0
  451. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/osrm.d.ts +15 -0
  452. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/photon.d.ts +22 -0
  453. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-file.d.ts +33 -0
  454. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-route.d.ts +23 -0
  455. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config.d.ts +23 -0
  456. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/geo.d.ts +61 -0
  457. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/index.d.ts +18 -0
  458. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +14 -0
  459. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/staticmap-route.d.ts +31 -0
  460. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/geocode.d.ts +11 -0
  461. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/poi.d.ts +9 -0
  462. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/routes.d.ts +75 -0
  463. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/types.d.ts +68 -0
  464. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types.js +16 -0
  465. package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +97 -0
  466. package/ts/package.json +293 -3
  467. package/ts/scripts/async-collect.ts +91 -0
  468. package/ts/scripts/map-tools-vendor-package-proof.ts +404 -0
  469. package/ts/scripts/skeleton-check.ts +1 -1
  470. package/ts/scripts/skeleton-integration-test.ts +23 -1
  471. package/ts/scripts/state-cli.ts +586 -0
  472. package/ts/scripts/turn-handoff-collect.ts +178 -0
  473. package/ts/src/artifact-gate.ts +991 -0
  474. package/ts/src/benchmark-agent-conformance.ts +619 -0
  475. package/ts/src/benchmark-environment-bridge.ts +538 -0
  476. package/ts/src/benchmark-headless-child-diagnostics.ts +184 -0
  477. package/ts/src/benchmark-tool-isolation.ts +166 -0
  478. package/ts/src/bookable-facts.ts +837 -0
  479. package/ts/src/booking-saga.ts +133 -0
  480. package/ts/src/booking-surface/availability-policy.ts +522 -0
  481. package/ts/src/booking-surface/booking-intent.ts +86 -0
  482. package/ts/src/booking-surface/cancel-refund-commission.ts +488 -0
  483. package/ts/src/booking-surface/canonical-schema.js +116 -0
  484. package/ts/src/booking-surface/contracts.ts +475 -0
  485. package/ts/src/booking-surface/dsh-planner.ts +1949 -0
  486. package/ts/src/booking-surface/dsh-plugin.js +378 -0
  487. package/ts/src/booking-surface/dsh-worker.ts +110 -0
  488. package/ts/src/booking-surface/error-codes.ts +241 -0
  489. package/ts/src/booking-surface/index.ts +9 -0
  490. package/ts/src/booking-surface/managed-dsh-cleanup-diagnostic.ts +151 -0
  491. package/ts/src/booking-surface/managed-dsh-run-port.ts +273 -0
  492. package/ts/src/booking-surface/profile.ts +42 -0
  493. package/ts/src/booking-surface/recovery-chain.ts +409 -0
  494. package/ts/src/booking-surface/runtime.ts +1793 -0
  495. package/ts/src/booking-surface/server.ts +733 -0
  496. package/ts/src/booking-surface/startup.ts +201 -0
  497. package/ts/src/booking-surface/validation.ts +217 -0
  498. package/ts/src/companions.ts +113 -0
  499. package/ts/src/contracts.ts +17 -3
  500. package/ts/src/dsh-llm.ts +152 -17
  501. package/ts/src/flyai-setup-tool.ts +77 -0
  502. package/ts/src/index.ts +2123 -200
  503. package/ts/src/itinerary-deck.ts +189 -0
  504. package/ts/src/itinerary-doc-shared.ts +741 -0
  505. package/ts/src/itinerary-html.ts +171 -0
  506. package/ts/src/loop.ts +234 -26
  507. package/ts/src/memory-capture.ts +283 -0
  508. package/ts/src/memory-decay.ts +55 -0
  509. package/ts/src/memory-utility.ts +70 -0
  510. package/ts/src/mock-llm.ts +4 -8
  511. package/ts/src/model.ts +88 -2
  512. package/ts/src/recall/card.ts +106 -0
  513. package/ts/src/recall/evaluator.ts +170 -0
  514. package/ts/src/recall/integration.ts +35 -0
  515. package/ts/src/recall/tick.ts +213 -0
  516. package/ts/src/session-link/plan-it-action.ts +78 -0
  517. package/ts/src/session-link/session-link.ts +275 -0
  518. package/ts/src/share/adapters.ts +93 -0
  519. package/ts/src/share/share-consent.ts +105 -0
  520. package/ts/src/share/share-deck.ts +85 -0
  521. package/ts/src/share/share-token.ts +166 -0
  522. package/ts/src/slot-spec.ts +172 -0
  523. package/ts/src/state-ledger.ts +1166 -0
  524. package/ts/src/subagent-job-id-guard.ts +72 -0
  525. package/ts/src/time-anchor.ts +338 -0
  526. package/ts/src/tool-packet.ts +32 -0
  527. package/ts/src/travel-slots.ts +219 -0
  528. package/ts/src/travel-timeline.ts +83 -0
  529. package/ts/src/turn-deadline.ts +366 -0
  530. package/ts/src/turn-policy.ts +154 -0
  531. package/ts/src/unified.ts +444 -105
  532. package/ts/src/wish-pool.ts +79 -0
  533. package/dist/scripts/session-attach-wait.js +0 -41
@@ -0,0 +1,140 @@
1
+ /**
2
+ * 政策事实生产端 v1(issue #141,D-26 收口切片)——C 档数据源:中国领事服务网
3
+ * (cs.mfa.gov.cn,外交部一手口径,免费权威)的「了解目的地」国家指南树。
4
+ *
5
+ * 形态:VISA_POLICY_FETCH 效应(effect 注册表行,礼貌抓取:UA 标识 + 超时 +
6
+ * 永不重试 + 断路器护站)→ 国家页 HTML → 「签证入境」章节文本 → PolicyFact[]
7
+ * (as_of + review_by + cs.mfa.gov.cn 来源证据链)。
8
+ *
9
+ * 纪律(ADR-19 + 抓取红线):
10
+ * - 永不抛错(永不抛错能力层契约);传输失败 → {ok:false, via:'visa-policy-error'},
11
+ * **不落负事实**(无结论不是证据);
12
+ * - 抓取失败/页面缺失 → 结构化降级,不猜不填;
13
+ * - 政策事实恒带 review_by 复核 gate(默认 D-30);
14
+ * - 礼貌抓取:单站点串行 + 调用方控制频率;站点不可达不重试(策略表 null)。
15
+ *
16
+ * 升级路径:D-31 后可切 B 档 Sherpa° 商业源(effect 注册表行可插拔替换)。
17
+ *
18
+ * @module capabilities/visa-policy
19
+ */
20
+ import { readFileSync } from 'node:fs';
21
+ import { BOOKABLE_FACT_SCHEMA, makeFactId } from '../src/bookable-facts.js';
22
+ const SOURCE_HOST = 'https://cs.mfa.gov.cn';
23
+ const SOURCE_ID = 'cs-mfa';
24
+ const USER_AGENT = 'GoTry/0.0.1 (+https://github.com/Danceiny/gotry; polite policy reader)';
25
+ const CONTINENTS = [
26
+ 'yz_645708', // 亚洲
27
+ 'feizhou_645714', // 非洲
28
+ 'ouzhou_645711', // 欧洲
29
+ 'bz_645718', // 美洲(北/南)
30
+ 'dyz_645717', // 大洋洲
31
+ ];
32
+ /** 国家路径 → 政策页 URL(抓取纪律:仅此两种 URL 形态,不拼接任意输入) */
33
+ export function countryPageUrl(continent, country) {
34
+ if (!/^[a-z0-9_]+$/.test(continent) || !/^[a-z0-9_]+$/.test(country))
35
+ return null;
36
+ return `${SOURCE_HOST}/zggmcg/ljmdd/${continent}/${country}/`;
37
+ }
38
+ /** 剥 HTML 标签 → 纯文本(保守:不执行任何内嵌脚本/样式) */
39
+ function stripTags(html) {
40
+ return html
41
+ .replace(/<(script|style)[\s\S]*?<\/\1>/gi, ' ')
42
+ .replace(/<[^>]+>/g, ' ')
43
+ .replace(/&nbsp;/g, ' ')
44
+ .replace(/&amp;/g, '&')
45
+ .replace(/\s+/g, ' ');
46
+ }
47
+ /**
48
+ * 从国家页文本抽取「签证入境」章节(到下一个同级标题为止)。
49
+ * 页面为 MFA 编辑器产出的散文(如中泰互免协定生效日期/停留期限条款),逐段保留原句。
50
+ */
51
+ export function extractVisaSection(pageText) {
52
+ const text = stripTags(pageText);
53
+ const start = text.indexOf('签证入境');
54
+ if (start < 0)
55
+ return null;
56
+ const rest = text.slice(start + '签证入境'.length);
57
+ // 下一大节标题探测:中文数字编号(非签证词)+已知下一节名(不用正文高频词做边界)
58
+ const sectionEnds = ['海关检查', '海关申报', '医疗条件', '交通出行', '实用信息', '领事保护', '国家安全', '特别提醒']
59
+ .map(kw => rest.indexOf(kw))
60
+ .filter(i => i > 0);
61
+ const numHeaders = Array.from(rest.matchAll(/[一二三四五六七八九十]+、(?!免签|落地签|签证|入境规定)/g)).map(m => m.index).filter(i => i > 0);
62
+ const allEnds = [...sectionEnds, ...numHeaders].sort((a, b) => a - b);
63
+ const end = allEnds.length > 0 ? allEnds[0] : Math.min(rest.length, 4_000);
64
+ const section = rest.slice(0, end).trim();
65
+ return section.length > 20 ? section : null;
66
+ }
67
+ /**
68
+ * 章节 → 政策陈述条目:按中文序号段落切分(一、二、…),每段一条 PolicyFact 原料。
69
+ * 免签/落地签/签证要求各成一条,供闸侧逐条回溯。
70
+ */
71
+ export function splitPolicyEntries(section) {
72
+ const parts = section.split(/(?:[一二三四五六七八九十]+、|[((]\s*[一二三四五六七八九十]+\s*[))])\s*/).map(p => p.trim());
73
+ return parts.filter(p => p.length > 30);
74
+ }
75
+ export function policyFactsFromMfa(input) {
76
+ const entries = splitPolicyEntries(input.section);
77
+ const asOf = input.fetchedAt.slice(0, 10);
78
+ const queryId = `visa-policy:${SOURCE_ID}:${input.countryPath}:${asOf}`;
79
+ return entries.map((entry, i) => ({
80
+ schema: BOOKABLE_FACT_SCHEMA,
81
+ fact_id: makeFactId([input.countryPath, String(i), entry.slice(0, 64), queryId]),
82
+ kind: 'policy',
83
+ subject: `${input.countryLabel} 签证入境(条款 ${i + 1})`,
84
+ statement: entry,
85
+ source: `${SOURCE_ID}@${input.fetchedAt}`,
86
+ query_id: queryId,
87
+ fetched_at: input.fetchedAt,
88
+ as_of: asOf,
89
+ review_by: defaultReviewBy(input.fetchedAt),
90
+ }));
91
+ }
92
+ /** 政策复核 gate:抓取日 +30 天(D-30 族) */
93
+ export function defaultReviewBy(fetchedAt) {
94
+ const d = new Date(fetchedAt);
95
+ d.setDate(d.getDate() + 30);
96
+ return d.toISOString().slice(0, 10);
97
+ }
98
+ /** 从洲列表页 HTML 提取国家路径段(相对形态 ./tg_647570/ → tg_647570;仅收本站链接) */
99
+ export function listCountryPaths(continentListHtml, continent) {
100
+ const hits = continentListHtml.matchAll(new RegExp(`href="(\\./([a-z0-9_]+)/)"[^>]*>([^<]{2,20})<`, 'g'));
101
+ const out = [];
102
+ for (const m of hits) {
103
+ if (!m[2] || !m[3])
104
+ continue;
105
+ out.push({ path: m[2], label: m[3].trim() });
106
+ }
107
+ return out.map(x => x.path).filter(p => /^[a-z0-9_]+$/.test(p));
108
+ }
109
+ /** 洲路径段 → 洲列表页 URL(形态受控,不拼接任意输入) */
110
+ export function continentListUrl(continent) {
111
+ if (!/^[a-z0-9_]+$/.test(continent))
112
+ return null;
113
+ return `${SOURCE_HOST}/zggmcg/ljmdd/${continent}/`;
114
+ }
115
+ /** 从本地 fixture 读页面(测试确定性;生产走 fetchVisaPolicyPage) */
116
+ export function readPageFixture(path) {
117
+ return readFileSync(path, 'utf-8');
118
+ }
119
+ /** 礼貌抓取国家页(永不抛错;失败 = 结构化降级,不落负事实) */
120
+ export async function fetchVisaPolicyPage(url, timeoutMs = 20_000) {
121
+ const controller = new AbortController();
122
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
123
+ try {
124
+ const res = await fetch(url, {
125
+ headers: { 'user-agent': USER_AGENT, 'accept-language': 'zh-CN,zh' },
126
+ signal: controller.signal,
127
+ redirect: 'follow',
128
+ });
129
+ if (!res.ok)
130
+ return { ok: false, error: `HTTP ${res.status}` };
131
+ return { ok: true, html: await res.text() };
132
+ }
133
+ catch (e) {
134
+ const msg = controller.signal.aborted ? `timeout after ${timeoutMs}ms` : String(e.message ?? e);
135
+ return { ok: false, error: msg };
136
+ }
137
+ finally {
138
+ clearTimeout(timer);
139
+ }
140
+ }
@@ -1,180 +1,285 @@
1
+ /**
2
+ * Open-Meteo 天气能力层(免费无 key):预报 + 历史气候回退。
3
+ *
4
+ * 产品定位:替代 LLM 的「雨季常识」——季节性建议、窗口内降雨概率、
5
+ * 体感温度范围,全部走真实数据并带证据标注 [实时API:open-meteo@ts]。
6
+ *
7
+ * 契约(与 hbcli.ts 同构,能力层不变量):
8
+ * - 永不抛错:网络失败/超时/解析失败一律降级返回,不穿透到调用方;
9
+ * - 证据链标注:成功带 [实时API:open-meteo@ts],失败带 [实时API:open-meteo@error@ts];
10
+ * - 免费源无配额概念,但仍记录 latency(供 L5 成本工程度量)。
11
+ *
12
+ * 端点(全部免费,无 key):
13
+ * 预报: https://api.open-meteo.com/v1/forecast (≤16 天)
14
+ * 历史气候: https://archive-api.open-meteo.com/v1/archive (1940→,做季节性)
15
+ * 地理编码: https://geocoding-api.open-meteo.com/v1/search (地名→坐标)
16
+ */
1
17
  const FORECAST_BASE = 'https://api.open-meteo.com/v1/forecast';
2
18
  const ARCHIVE_BASE = 'https://archive-api.open-meteo.com/v1/archive';
3
19
  const GEOCODE_BASE = 'https://geocoding-api.open-meteo.com/v1/search';
20
+ /** WMO weather code → 中文描述(节选最常用的码) */
4
21
  const WMO_ZH = {
5
- 0: '晴',
6
- 1: '大致晴',
7
- 2: '多云',
8
- 3: '阴',
9
- 45: '雾',
10
- 48: '冻雾',
11
- 51: '毛毛雨',
12
- 53: '毛毛雨',
13
- 55: '密集毛毛雨',
14
- 61: '小雨',
15
- 63: '中雨',
16
- 65: '大雨',
17
- 66: '冻雨',
18
- 67: '强冻雨',
19
- 71: '小雪',
20
- 73: '中雪',
21
- 75: '大雪',
22
- 77: '雪粒',
23
- 80: '阵雨',
24
- 81: '强阵雨',
25
- 82: '暴雨',
26
- 85: '阵雪',
27
- 86: '强阵雪',
28
- 95: '雷暴',
29
- 96: '雷暴伴小冰雹',
30
- 99: '雷暴伴大冰雹'
22
+ 0: '晴', 1: '大致晴', 2: '多云', 3: '阴',
23
+ 45: '雾', 48: '冻雾',
24
+ 51: '毛毛雨', 53: '毛毛雨', 55: '密集毛毛雨',
25
+ 61: '小雨', 63: '中雨', 65: '大雨',
26
+ 66: '冻雨', 67: '强冻雨',
27
+ 71: '小雪', 73: '中雪', 75: '大雪', 77: '雪粒',
28
+ 80: '阵雨', 81: '强阵雨', 82: '暴雨',
29
+ 85: '阵雪', 86: '强阵雪',
30
+ 95: '雷暴', 96: '雷暴伴小冰雹', 99: '雷暴伴大冰雹',
31
31
  };
32
32
  export function wmoLabel(code) {
33
33
  return WMO_ZH[code] ?? `天气码${code}`;
34
34
  }
35
- async function fetchJson(url, timeoutMs) {
35
+ const monotonicNow = () => performance.now();
36
+ const MIN_TIMER_MS = 1;
37
+ const TIMEOUT_ERROR = 'timeoutMs must be a finite positive integer';
38
+ const BUDGET_EXHAUSTED_ERROR = 'total timeout budget exhausted';
39
+ const REQUEST_ERROR = 'request failed';
40
+ const normalizeTimeout = (value) => Number.isInteger(value) && value > 0 ? value : null;
41
+ /** Rejection values are untrusted: only a real string message is safe to expose. */
42
+ const normalizeError = (value) => {
43
+ try {
44
+ if (value instanceof Error && typeof value.message === 'string' && value.message.length > 0) {
45
+ return value.message.slice(0, 200);
46
+ }
47
+ if (typeof value === 'string' && value.length > 0)
48
+ return value.slice(0, 200);
49
+ }
50
+ catch {
51
+ return REQUEST_ERROR;
52
+ }
53
+ return REQUEST_ERROR;
54
+ };
55
+ async function fetchJson(url, timeoutMs, headers = {}, fetchImpl = globalThis.fetch) {
56
+ if (!Number.isFinite(timeoutMs) || timeoutMs < MIN_TIMER_MS)
57
+ return { ok: false, error: BUDGET_EXHAUSTED_ERROR };
36
58
  const ctrl = new AbortController();
37
- const timer = setTimeout(()=>ctrl.abort(), timeoutMs);
59
+ const timerDelay = Math.floor(timeoutMs);
60
+ if (timerDelay < MIN_TIMER_MS)
61
+ return { ok: false, error: BUDGET_EXHAUSTED_ERROR };
62
+ let timer;
63
+ let timedOut = false;
64
+ const timeout = new Promise((_, reject) => {
65
+ timer = setTimeout(() => {
66
+ timedOut = true;
67
+ ctrl.abort();
68
+ reject(new Error(`timeout after ${timeoutMs}ms`));
69
+ }, timerDelay);
70
+ });
71
+ const operation = (async () => {
72
+ const res = await fetchImpl(url, { signal: ctrl.signal, headers: { Accept: 'application/json', ...headers } });
73
+ if (!res.ok)
74
+ return { ok: false, error: `HTTP ${res.status}` };
75
+ return { ok: true, data: await res.json() };
76
+ })();
38
77
  try {
39
- const res = await fetch(url, {
40
- signal: ctrl.signal,
41
- headers: {
42
- Accept: 'application/json'
43
- }
44
- });
45
- if (!res.ok) return {
46
- ok: false,
47
- error: `HTTP ${res.status}`
48
- };
49
- return {
50
- ok: true,
51
- data: await res.json()
52
- };
53
- } catch (e) {
54
- return {
55
- ok: false,
56
- error: e.message.slice(0, 200)
57
- };
58
- } finally{
59
- clearTimeout(timer);
78
+ return await Promise.race([operation, timeout]);
79
+ }
80
+ catch (e) {
81
+ return { ok: false, error: normalizeError(e), ...(timedOut ? { timedOut: true } : {}) };
60
82
  }
83
+ finally {
84
+ if (timer !== undefined)
85
+ clearTimeout(timer);
86
+ void operation.catch(() => undefined);
87
+ }
88
+ }
89
+ const NOMINATIM_BASE = 'https://nominatim.openstreetmap.org/search';
90
+ /** 行政级/人口重镇 feature_code(open-meteo 命名惯例):PPLC=首都 PPLA*=首府 PPLB=城镇 PPLX=区片 */
91
+ const MAJOR_FEATURE = /^(PPLC|PPLA|PPLB|PPLX)/;
92
+ const isRecord = (value) => value !== null && typeof value === 'object' && !Array.isArray(value);
93
+ function stripHits(hits) {
94
+ return hits.map(({ name, latitude, longitude, country, admin1 }) => ({ ...(country ? { country } : {}), ...(admin1 ? { admin1 } : {}), name, latitude, longitude }));
61
95
  }
96
+ /** 地名 → 坐标(双源,供 dsh 工具把「大理」转成经纬度):
97
+ * 1. Open-Meteo(主源):命中按人口/行政级降序——「大理」会同时命中云南州府与四川同名乡,不能盲信次序;
98
+ * 2. Nominatim(兜底):open-meteo 的中文名覆盖有洞(实测(issue #24)「普吉岛」0 结果、
99
+ * 裸词「普吉」错配西藏林芝同名村),弱命中/零结果时走 Nominatim 拿正确目标,
100
+ * 兜底仍空则回退 open-meteo 弱结果(不比此前更差)。 */
62
101
  export async function geocodePlace(name, opts = {}) {
63
102
  const ts = new Date().toISOString();
64
103
  const count = opts.count ?? 5;
65
- const url = `${GEOCODE_BASE}?name=${encodeURIComponent(name)}&count=${count}&language=zh&format=json`;
66
- const r = await fetchJson(url, opts.timeoutMs ?? 15_000);
67
- if (!r.ok) {
68
- return {
69
- ok: false,
70
- evidence: `[实时API:open-meteo-geo@error@${ts}]`,
71
- results: [],
72
- error: r.error
73
- };
104
+ const query = name.trim();
105
+ const timeoutMs = normalizeTimeout(opts.timeoutMs ?? 15_000);
106
+ if (timeoutMs === null)
107
+ return { ok: false, evidence: `[实时API:open-meteo-geo@error@${ts}]`, results: [], error: TIMEOUT_ERROR };
108
+ const omUrl = `${GEOCODE_BASE}?name=${encodeURIComponent(query)}&count=${count}&language=zh&format=json`;
109
+ // timeoutMs is a budget for the complete primary→fallback chain, not per request.
110
+ const deadline = monotonicNow() + timeoutMs;
111
+ const remaining = () => {
112
+ const value = deadline - monotonicNow();
113
+ return Number.isFinite(value) && value >= MIN_TIMER_MS ? value : null;
114
+ };
115
+ const primaryRemaining = remaining();
116
+ const r = primaryRemaining === null
117
+ ? { ok: false, error: BUDGET_EXHAUSTED_ERROR }
118
+ : await fetchJson(omUrl, primaryRemaining, {}, opts.fetchImpl);
119
+ const primaryPayload = r.ok && isRecord(r.data) && Array.isArray(r.data['results']) ? r.data['results'] : null;
120
+ const omResults = primaryPayload
121
+ ? primaryPayload.map((item) => {
122
+ if (!isRecord(item))
123
+ return null;
124
+ const it = item;
125
+ return {
126
+ name: String(it['name'] ?? ''),
127
+ latitude: Number(it['latitude']),
128
+ longitude: Number(it['longitude']),
129
+ country: it['country'] ? String(it['country']) : undefined,
130
+ admin1: it['admin1'] ? String(it['admin1']) : undefined,
131
+ population: Number(it['population'] ?? 0) || 0,
132
+ featureCode: String(it['feature_code'] ?? ''),
133
+ };
134
+ }).filter((h) => !!h && !!h.name && Number.isFinite(h.latitude) && Number.isFinite(h.longitude))
135
+ : [];
136
+ omResults.sort((a, b) => (b.population - a.population) || (Number(MAJOR_FEATURE.test(b.featureCode)) - Number(MAJOR_FEATURE.test(a.featureCode))));
137
+ const top = omResults[0];
138
+ // 强命中:有人口规模或主要行政级,直接采信(「深圳市」「曼谷」路径不变)
139
+ if (top && (top.population > 0 || MAJOR_FEATURE.test(top.featureCode))) {
140
+ return { ok: true, evidence: `[实时API:open-meteo-geo@${ts}]`, via: 'open-meteo', results: stripHits(omResults) };
141
+ }
142
+ // 弱命中/零结果/主源请求失败:Nominatim 兜底(免费无 key;中文 accept-language)
143
+ const nomTs = new Date().toISOString();
144
+ const nomUrl = `${NOMINATIM_BASE}?q=${encodeURIComponent(query)}&format=jsonv2&limit=${count}&accept-language=zh&addressdetails=1`;
145
+ const fallbackRemaining = primaryRemaining === null || r.timedOut ? null : remaining();
146
+ const nom = fallbackRemaining === null
147
+ ? { ok: false, error: BUDGET_EXHAUSTED_ERROR }
148
+ : await fetchJson(nomUrl, fallbackRemaining, { 'User-Agent': 'gotry-travel-agent/0.1 (+https://github.com/Danceiny/gotry)' }, opts.fetchImpl);
149
+ const nomResults = [];
150
+ if (nom.ok && Array.isArray(nom.data)) {
151
+ const parsedNom = nom.data.map((item) => {
152
+ if (!isRecord(item))
153
+ return null;
154
+ const it = item;
155
+ const addr = isRecord(it['address']) ? it['address'] : {};
156
+ const country = typeof addr['country'] === 'string' ? addr['country'] : undefined;
157
+ const admin1 = [addr['province'], addr['state'], addr['county']].find(v => typeof v === 'string');
158
+ return { name: String(it['name'] ?? ''), latitude: Number(it['lat']), longitude: Number(it['lon']), ...(country ? { country } : {}), ...(admin1 ? { admin1 } : {}) };
159
+ }).filter((h) => !!h && !!h.name && Number.isFinite(h.latitude) && Number.isFinite(h.longitude));
160
+ nomResults.push(...parsedNom);
161
+ }
162
+ if (nomResults.length) {
163
+ const omNote = r.ok
164
+ ? `open-meteo ${omResults.length} 条弱命中(无人口/行政级,不足采信)`
165
+ : `open-meteo 失败:${r.error ?? 'HTTP error'}`;
166
+ return { ok: true, evidence: `[实时API:nominatim@${nomTs}](兜底层: ${omNote})`, via: 'nominatim', results: nomResults };
167
+ }
168
+ // 双源皆空/兜底失败:open-meteo 有弱结果仍返回(同构「降级不阻塞」契约),否则维持失败终态
169
+ if (omResults.length) {
170
+ return { ok: true, evidence: `[实时API:open-meteo-geo@${ts}]`, via: 'open-meteo', results: stripHits(omResults) };
74
171
  }
75
- const results = (r.data?.results ?? []).map((item)=>{
76
- const it = item;
77
- return {
78
- name: String(it['name'] ?? ''),
79
- latitude: Number(it['latitude']),
80
- longitude: Number(it['longitude']),
81
- country: it['country'] ? String(it['country']) : undefined,
82
- admin1: it['admin1'] ? String(it['admin1']) : undefined
83
- };
84
- });
85
172
  return {
86
- ok: true,
87
- evidence: `[实时API:open-meteo-geo@${ts}]`,
88
- results
173
+ ok: false,
174
+ evidence: `[实时API:open-meteo-geo@error@${ts}];[实时API:nominatim@error@${nomTs}]`,
175
+ results: [],
176
+ error: r.ok ? `双源无结果:${nom.error ?? 'nominatim empty'}` : (r.error),
89
177
  };
90
178
  }
179
+ /** 未来天气预报(≤16 天) */
91
180
  export async function getForecast(point, opts = {}) {
92
- const started = Date.now();
181
+ const started = monotonicNow();
93
182
  const ts = new Date().toISOString();
94
- const days = Math.min(opts.days ?? 7, 16);
95
- const url = `${FORECAST_BASE}?latitude=${point.latitude}&longitude=${point.longitude}` + `&daily=temperature_2m_max,temperature_2m_min,precipitation_probability_max,weathercode` + `&forecast_days=${days}&timezone=auto`;
96
- const r = await fetchJson(url, opts.timeoutMs ?? 15_000);
97
- const latencyMs = Date.now() - started;
183
+ const requestedDays = opts.days ?? 7;
184
+ const days = Number.isInteger(requestedDays) && requestedDays > 0 ? Math.min(requestedDays, 16) : 0;
185
+ const timeoutMs = normalizeTimeout(opts.timeoutMs ?? 15_000);
186
+ if (days < 1 || timeoutMs === null)
187
+ return { ok: false, via: 'open-meteo-error', evidence: `[实时API:open-meteo@error@${ts}]`, latencyMs: monotonicNow() - started, error: days < 1 ? 'days must be valid positive values' : TIMEOUT_ERROR };
188
+ const url = `${FORECAST_BASE}?latitude=${point.latitude}&longitude=${point.longitude}`
189
+ + `&daily=temperature_2m_max,temperature_2m_min,precipitation_probability_max,weathercode`
190
+ + `&forecast_days=${days}&timezone=auto`;
191
+ const r = await fetchJson(url, timeoutMs, {}, opts.fetchImpl);
192
+ const latencyMs = monotonicNow() - started;
98
193
  if (!r.ok) {
99
- return {
100
- ok: false,
101
- via: 'open-meteo-error',
102
- evidence: `[实时API:open-meteo@error@${ts}]`,
103
- latencyMs,
104
- error: r.error
105
- };
194
+ return { ok: false, via: 'open-meteo-error', evidence: `[实时API:open-meteo@error@${ts}]`, latencyMs, error: r.error };
106
195
  }
107
- const daily = r.data.daily;
108
- if (!daily) {
109
- return {
110
- ok: false,
111
- via: 'open-meteo-error',
112
- evidence: `[实时API:open-meteo@error@${ts}]`,
113
- latencyMs,
114
- error: 'empty daily payload'
115
- };
196
+ const payload = isRecord(r.data) ? r.data : null;
197
+ const daily = isRecord(payload?.['daily']) ? payload['daily'] : null;
198
+ if (!daily || !Array.isArray(daily.time) || !Array.isArray(daily.temperature_2m_max)
199
+ || !Array.isArray(daily.temperature_2m_min) || !Array.isArray(daily.weathercode)
200
+ || daily.time.length !== days || daily.temperature_2m_max.length !== days
201
+ || daily.temperature_2m_min.length !== days || daily.weathercode.length !== days
202
+ || daily.time.some(v => typeof v !== 'string')
203
+ || daily.temperature_2m_max.some(v => typeof v !== 'number' || !Number.isFinite(v))
204
+ || daily.temperature_2m_min.some(v => typeof v !== 'number' || !Number.isFinite(v))
205
+ || daily.weathercode.some(v => typeof v !== 'number' || !Number.isFinite(v))
206
+ || (daily.precipitation_probability_max !== undefined && daily.precipitation_probability_max !== null
207
+ && !Array.isArray(daily.precipitation_probability_max))
208
+ || (Array.isArray(daily.precipitation_probability_max)
209
+ && (daily.precipitation_probability_max.length !== days
210
+ || daily.precipitation_probability_max.some(v => v !== null && (typeof v !== 'number' || !Number.isFinite(v)))))) {
211
+ return { ok: false, via: 'open-meteo-error', evidence: `[实时API:open-meteo@error@${ts}]`, latencyMs, error: 'empty daily payload' };
116
212
  }
117
- const rows = daily.time.map((date, i)=>({
118
- date,
119
- tempMaxC: daily.temperature_2m_max[i] ?? NaN,
120
- tempMinC: daily.temperature_2m_min[i] ?? NaN,
121
- precipProbMaxPct: daily.precipitation_probability_max?.[i] ?? null,
122
- weatherCode: daily.weathercode[i] ?? -1
123
- }));
213
+ const times = daily.time;
214
+ const maxes = daily.temperature_2m_max;
215
+ const mins = daily.temperature_2m_min;
216
+ const codes = daily.weathercode;
217
+ const precip = Array.isArray(daily.precipitation_probability_max)
218
+ ? daily.precipitation_probability_max
219
+ : undefined;
220
+ const rows = times.map((date, i) => ({
221
+ date, tempMaxC: maxes[i], tempMinC: mins[i], precipProbMaxPct: precip?.[i] ?? null, weatherCode: codes[i],
222
+ }));
124
223
  return {
125
- ok: true,
126
- via: 'open-meteo',
224
+ ok: true, via: 'open-meteo',
127
225
  evidence: `[实时API:open-meteo@${ts}]`,
128
226
  latencyMs,
129
- timezone: r.data.timezone,
130
- daily: rows
227
+ timezone: typeof payload?.['timezone'] === 'string' ? payload['timezone'] : undefined,
228
+ daily: rows,
131
229
  };
132
230
  }
231
+ /** 历史气候(季节性推荐底座:去年同期日均温/降雨概率) */
133
232
  export async function getClimate(point, month, opts = {}) {
134
- const started = Date.now();
233
+ const started = monotonicNow();
135
234
  const ts = new Date().toISOString();
136
- const year = opts.year ?? new Date().getFullYear() - 1;
235
+ const timeoutMs = normalizeTimeout(opts.timeoutMs ?? 15_000);
236
+ if (timeoutMs === null)
237
+ return { ok: false, via: 'open-meteo-error', evidence: `[实时API:open-meteo-climate@error@${ts}]`, latencyMs: monotonicNow() - started, error: TIMEOUT_ERROR };
238
+ // 默认取去年同月做气候基线
239
+ const year = opts.year ?? (new Date().getUTCFullYear() - 1);
240
+ if (!Number.isInteger(month) || month < 1 || month > 12 || !Number.isInteger(year) || year < 1940 || year > new Date().getUTCFullYear()) {
241
+ return { ok: false, via: 'open-meteo-error', evidence: `[实时API:open-meteo-climate@error@${ts}]`, latencyMs: monotonicNow() - started, error: 'month/year must be valid historical calendar values' };
242
+ }
137
243
  const lastDay = new Date(Date.UTC(year, month, 0)).getUTCDate();
244
+ const expectedDates = Array.from({ length: lastDay }, (_, i) => `${year}-${String(month).padStart(2, '0')}-${String(i + 1).padStart(2, '0')}`);
138
245
  const start = `${year}-${String(month).padStart(2, '0')}-01`;
139
246
  const end = `${year}-${String(month).padStart(2, '0')}-${String(lastDay).padStart(2, '0')}`;
140
- const url = `${ARCHIVE_BASE}?latitude=${point.latitude}&longitude=${point.longitude}` + `&start_date=${start}&end_date=${end}` + `&daily=temperature_2m_max,temperature_2m_min,precipitation_sum,weathercode&timezone=auto`;
141
- const r = await fetchJson(url, opts.timeoutMs ?? 15_000);
142
- const latencyMs = Date.now() - started;
247
+ const url = `${ARCHIVE_BASE}?latitude=${point.latitude}&longitude=${point.longitude}`
248
+ + `&start_date=${start}&end_date=${end}`
249
+ + `&daily=temperature_2m_max,temperature_2m_min,precipitation_sum,weathercode&timezone=auto`;
250
+ const r = await fetchJson(url, timeoutMs, {}, opts.fetchImpl);
251
+ const latencyMs = monotonicNow() - started;
143
252
  if (!r.ok) {
144
- return {
145
- ok: false,
146
- via: 'open-meteo-error',
147
- evidence: `[实时API:open-meteo-climate@error@${ts}]`,
148
- latencyMs,
149
- error: r.error
150
- };
253
+ return { ok: false, via: 'open-meteo-error', evidence: `[实时API:open-meteo-climate@error@${ts}]`, latencyMs, error: r.error };
151
254
  }
152
- const daily = r.data.daily;
153
- if (!daily) {
154
- return {
155
- ok: false,
156
- via: 'open-meteo-error',
157
- evidence: `[实时API:open-meteo-climate@error@${ts}]`,
158
- latencyMs,
159
- error: 'empty daily payload'
160
- };
255
+ const payload = isRecord(r.data) ? r.data : null;
256
+ const daily = isRecord(payload?.['daily']) ? payload['daily'] : null;
257
+ if (!daily || !Array.isArray(daily.time) || !Array.isArray(daily.temperature_2m_max)
258
+ || !Array.isArray(daily.temperature_2m_min) || !Array.isArray(daily.weathercode)
259
+ || daily.time.length !== lastDay
260
+ || daily.time.length !== daily.temperature_2m_max.length
261
+ || daily.time.length !== daily.temperature_2m_min.length
262
+ || daily.time.length !== daily.weathercode.length
263
+ || daily.time.some(v => typeof v !== 'string')
264
+ || daily.time.some((v, i) => v !== expectedDates[i])
265
+ || daily.temperature_2m_max.some(v => typeof v !== 'number' || !Number.isFinite(v))
266
+ || daily.temperature_2m_min.some(v => typeof v !== 'number' || !Number.isFinite(v))
267
+ || daily.weathercode.some(v => typeof v !== 'number' || !Number.isFinite(v))) {
268
+ return { ok: false, via: 'open-meteo-error', evidence: `[实时API:open-meteo-climate@error@${ts}]`, latencyMs, error: 'empty daily payload' };
161
269
  }
162
- const rows = daily.time.map((date, i)=>({
163
- date,
164
- tempMaxC: daily.temperature_2m_max[i] ?? NaN,
165
- tempMinC: daily.temperature_2m_min[i] ?? NaN,
166
- precipProbMaxPct: null,
167
- weatherCode: daily.weathercode[i] ?? -1
168
- }));
270
+ const times = daily.time;
271
+ const maxes = daily.temperature_2m_max;
272
+ const mins = daily.temperature_2m_min;
273
+ const codes = daily.weathercode;
274
+ const rows = times.map((date, i) => ({
275
+ date, tempMaxC: maxes[i], tempMinC: mins[i], precipProbMaxPct: null, // archive 端点没有概率,用降水量另行估算
276
+ weatherCode: codes[i],
277
+ }));
169
278
  return {
170
- ok: true,
171
- via: 'open-meteo',
279
+ ok: true, via: 'open-meteo',
172
280
  evidence: `[实时API:open-meteo-climate@${ts}]`,
173
281
  latencyMs,
174
- timezone: r.data.timezone,
175
- daily: rows
282
+ timezone: typeof payload?.['timezone'] === 'string' ? payload['timezone'] : undefined,
283
+ daily: rows,
176
284
  };
177
285
  }
178
-
179
-
180
- //# sourceURL=/Users/bytedance/work/gotry/ts/capabilities/weather.ts
@@ -0,0 +1,25 @@
1
+ {
2
+ "comment": "会话数据面金标准查询集(RFC P2 监控面输入;只增不改语义,对齐 time-slot-eval 惯例)。city 字段约束:from/to 必须同时命中 ctrip 城市码表与美团拼音表(双适配器通用)。",
3
+ "queries": [
4
+ { "id": "sf-01", "kind": "flight", "from": "上海", "to": "丽江", "date": "2026-10-01" },
5
+ { "id": "sf-02", "kind": "flight", "from": "北京", "to": "大理", "date": "2026-10-02" },
6
+ { "id": "sf-03", "kind": "flight", "from": "上海", "to": "三亚", "date": "2026-11-11" },
7
+ { "id": "sf-04", "kind": "flight", "from": "广州", "to": "昆明", "date": "2026-12-20" },
8
+ { "id": "sf-05", "kind": "flight", "from": "深圳", "to": "成都", "date": "2026-10-05" },
9
+ { "id": "sf-06", "kind": "flight", "from": "杭州", "to": "厦门", "date": "2026-10-06" },
10
+ { "id": "sf-07", "kind": "flight", "from": "西安", "to": "桂林", "date": "2026-10-07" },
11
+ { "id": "sf-08", "kind": "flight", "from": "重庆", "to": "贵阳", "date": "2026-10-08" },
12
+ { "id": "mt-01", "kind": "meituan-hotel", "city": "上海", "keyword": "陆家嘴" },
13
+ { "id": "mt-02", "kind": "meituan-hotel", "city": "大理", "keyword": "洱海" },
14
+ { "id": "mt-03", "kind": "meituan-hotel", "city": "成都", "keyword": "太古里" },
15
+ { "id": "mt-04", "kind": "meituan-hotel", "city": "北京", "keyword": "故宫" },
16
+ { "id": "mt-05", "kind": "meituan-minsu", "city": "丽江", "keyword": "古城" },
17
+ { "id": "mt-06", "kind": "meituan-minsu", "city": "厦门", "keyword": "鼓浪屿" },
18
+ { "id": "mt-07", "kind": "meituan-minsu", "city": "杭州", "keyword": "西湖" },
19
+ { "id": "mt-08", "kind": "meituan-minsu", "city": "三亚", "keyword": "亚龙湾" },
20
+ { "id": "fa-01", "kind": "flyai-flight", "from": "上海", "to": "丽江", "date": "2026-10-01" },
21
+ { "id": "fa-02", "kind": "flyai-flight", "from": "北京", "to": "大理", "date": "2026-10-02" },
22
+ { "id": "fa-03", "kind": "flyai-train", "from": "上海", "to": "大理", "date": "2026-10-01" },
23
+ { "id": "fa-04", "kind": "flyai-train", "from": "北京", "to": "昆明", "date": "2026-10-03" }
24
+ ]
25
+ }