@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,551 @@
1
+ /**
2
+ * session-search 模块(gotry-backend 的能力单元之一;账号会话检索,hotel-be portal
3
+ * 聚合工作台 M0)。travel agent 能力全部落 gotry——本模块是「一个 gotry 服务」里的
4
+ * 会话检索面,hotel-be 只做网关包装与上下文拼接。
5
+ *
6
+ * 执行环境(2026-09-11 founder 定案):**浏览器客户端**,服务端零 Chrome
7
+ * (headless 易风控 + 资源开销大,双双出局)。本模块内嵌桥作业队列
8
+ * (createBridgeJobQueue)并挂载桥协议端点;管理员浏览器里的 GoTry Session
9
+ * Bridge 扩展经 bearer 鉴权远程连入,长轮询取活,在自己浏览器的登录态里
10
+ * 被动嗅探 dida 回包。登录也在管理员自己浏览器完成(login/open 让扩展把
11
+ * dida 登录页置前台打开,人过验证码)——零 Xvfb、零 noVNC、零 SSH 隧道。
12
+ *
13
+ * 路由(鉴权:Bearer GOTRY_BACKEND_SESSION_API_KEY;缺 key = fail-closed 503):
14
+ * GET /v1/session/status → 扩展在线态 + 各供应商登录态(票据 cookie 名级;值零过手)
15
+ * POST /v1/session/search → 会话面检索(dida:multiCollect 嗅探推荐流双接口)
16
+ * POST /v1/session/login/open → 让扩展在管理员浏览器置前台打开 dida 登录入口页
17
+ * GET /v1/session/bridge/health → 桥健康(扩展启动探测)
18
+ * GET /v1/session/bridge/status → 桥诊断(队列/在线态快照)
19
+ * POST /v1/session/bridge/jobs → 扩展长轮询取活(hold ≤20s)
20
+ * POST /v1/session/bridge/results → 扩展回包(?jobId=;内核只支持精确路由)
21
+ * POST /v1/session/bridge/events → 扩展 workspace 事件批量上行(批次 B,2026-10-01;
22
+ * body ≤256KB,逐条落 bridge_events,响应 {accepted,rejected})
23
+ *
24
+ * 红线继承:登录在供应商官网由人完成;challenged 即停;节律闸在 sessionDidaSearch
25
+ * 内;本模块再加单飞锁(同供应商串行,防并发打站点)。桥端点在 bearer 之上再强制
26
+ * Origin ∈ 扩展白名单(网页跨域请求必带邪恶 Origin,双保险)。
27
+ *
28
+ * verdict 结构化日志(#272 观测缺口,2026-10-02 UAT 只读实查证实:verdict 此前
29
+ * 无任何日志载体——BFF 代理日志与 gotry 应用日志均不落):search/status 每次
30
+ * 结算在 stderr 落一行 `[session-search] verdict {json}`(ts/supplier/verdict/
31
+ * latencyMs/error 摘要,脱敏)。与桥账本(bridge_jobs,PR #601)互补——日志管
32
+ * 「看」,账本管「恢复」,verdict 不写 bridge_jobs。
33
+ */
34
+ import { sessionDidaSearch } from '../../../capabilities/session-search.js';
35
+ import { DIDA_LOGIN_COOKIE_NAMES, DIDA_SITE_DOMAIN } from '../../../capabilities/session/adapters/dida-portal.js';
36
+ import { CLIENT_ID_RE, createBridgeJobQueue, EXTENSION_ORIGINS } from '../../../capabilities/session/extension-bridge.js';
37
+ import { openBridgeLedgerStore } from '../../../capabilities/session/bridge-ledger.js';
38
+ import { extensionCookieNames, extensionOpenLogin, classifyBridgeFailure } from '../../../capabilities/session/extension-channel.js';
39
+ /** 事件上行端点路径(批次 B;导出供 extension-tests §38 与扩展侧 background.js 防漂移对账) */
40
+ export const BRIDGE_EVENTS_PATH = '/v1/session/bridge/events';
41
+ /** 事件上行 body 上限(事件是活动上下文非权威事实,256KB 足够一个批次;超限 400 整批拒绝) */
42
+ export const BRIDGE_EVENTS_BODY_LIMIT = 256 * 1024;
43
+ /** verdict 行 error 摘要上限(#272:结构化行的脱敏摘要,不是传输面文案) */
44
+ const VERDICT_ERROR_SUMMARY_LIMIT = 200;
45
+ /**
46
+ * error 摘要里必须脱敏的形状(#272):凭据词出现在键名里(含复合键,如
47
+ * SESSION_TICKET=…)时其赋值整体替换为 [REDACTED];独立 Bearer 头单列。
48
+ * 只换值、保留键名——键名本身是脱敏证据,值才是泄漏面。
49
+ */
50
+ const VERDICT_ERROR_REDACTION_ASSIGNMENT = /\b([\w-]*(?:cookie|ticket|token|sessionid|authorization|credential)[\w-]*)(\s*[:=]\s*)[^\s;,"'&]+/gi;
51
+ const VERDICT_ERROR_REDACTION_BEARER = /\b(bearer)(\s+)[^\s;,"'&]+/gi;
52
+ /**
53
+ * verdict 行的 error 摘要(#272):单行化(防日志注入)+ 凭据形状脱敏 + 截断到
54
+ * 200 字符。绝不携带 rates/evidence/回包内容——那些字段根本不进本行;能力层的
55
+ * error 按合同是主机固定文案,这里再做一道防御性脱敏(离线哨兵在
56
+ * observability-tests 里锁)。
57
+ */
58
+ function redactVerdictErrorSummary(error) {
59
+ if (!error)
60
+ return undefined;
61
+ const flattened = error.replaceAll(/[\r\n\t]+/g, ' ').trim();
62
+ const redacted = flattened
63
+ .replace(VERDICT_ERROR_REDACTION_BEARER, (_match, scheme, sep) => `${scheme}${sep}[REDACTED]`)
64
+ .replace(VERDICT_ERROR_REDACTION_ASSIGNMENT, (_match, name, sep) => `${name}${sep}[REDACTED]`);
65
+ if (!redacted)
66
+ return undefined;
67
+ return redacted.length > VERDICT_ERROR_SUMMARY_LIMIT
68
+ ? `${redacted.slice(0, VERDICT_ERROR_SUMMARY_LIMIT - 1)}…`
69
+ : redacted;
70
+ }
71
+ function formatSessionVerdictLine(entry) {
72
+ const record = {
73
+ ts: new Date().toISOString(),
74
+ surface: entry.surface,
75
+ supplier: entry.supplier,
76
+ verdict: entry.verdict,
77
+ latencyMs: Math.max(0, Math.round(entry.latencyMs)),
78
+ };
79
+ const error = redactVerdictErrorSummary(entry.error);
80
+ if (error !== undefined)
81
+ record.error = error;
82
+ return `[session-search] verdict ${JSON.stringify(record)}`;
83
+ }
84
+ function sendJson(res, status, body) {
85
+ res.statusCode = status;
86
+ res.setHeader('content-type', 'application/json');
87
+ res.end(JSON.stringify(body));
88
+ }
89
+ async function readAndParseObjectBody(req) {
90
+ let raw;
91
+ try {
92
+ raw = await readBody(req);
93
+ }
94
+ catch {
95
+ return { code: 'body-read' };
96
+ }
97
+ let parsed;
98
+ try {
99
+ parsed = JSON.parse(raw);
100
+ }
101
+ catch {
102
+ return { code: 'parse' };
103
+ }
104
+ if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
105
+ return { code: 'shape' };
106
+ }
107
+ return { obj: parsed };
108
+ }
109
+ function validationMessage(code) {
110
+ switch (code) {
111
+ case 'body-read': return 'body 读取失败';
112
+ case 'parse': return 'body 不是 JSON';
113
+ case 'shape': return 'body 必须是 JSON 对象';
114
+ case 'supplier-type': return 'supplier 必须是字符串';
115
+ case 'url-type': return 'url 必须是字符串';
116
+ }
117
+ }
118
+ function ensureStringField(obj, key) {
119
+ const v = obj[key];
120
+ if (v !== undefined && typeof v !== 'string')
121
+ return key === 'supplier' ? 'supplier-type' : 'url-type';
122
+ return null;
123
+ }
124
+ /**
125
+ * 单条上行事件的形状守卫(批次 B):{kind, site?, subject, payload_json, clientTs?, idem_key?}。
126
+ * 返回 null = 该条拒绝(计入 rejected,不中断批次);返回对象 = 可落账输入。
127
+ * - payload_json 只约束 string,内容原样落账不二次解析(事件是活动上下文,消费方自鉴);
128
+ * - clientTs 仅约束有限数值(扩展侧时钟,不入列——账本唯一时间轴是服务端 ts);
129
+ * - site/idem_key 空字符串按缺省处理(NULL 不参与幂等去重)。
130
+ */
131
+ function validateBridgeEvent(clientId, ev) {
132
+ if (ev === null || typeof ev !== 'object' || Array.isArray(ev))
133
+ return null;
134
+ const rec = ev;
135
+ if (typeof rec.kind !== 'string' || !rec.kind)
136
+ return null;
137
+ if (rec.site !== undefined && typeof rec.site !== 'string')
138
+ return null;
139
+ if (typeof rec.subject !== 'string' || !rec.subject)
140
+ return null;
141
+ if (typeof rec.payload_json !== 'string')
142
+ return null;
143
+ if (rec.clientTs !== undefined && (typeof rec.clientTs !== 'number' || !Number.isFinite(rec.clientTs)))
144
+ return null;
145
+ if (rec.idem_key !== undefined && (typeof rec.idem_key !== 'string' || !rec.idem_key))
146
+ return null;
147
+ return {
148
+ client_id: clientId,
149
+ kind: rec.kind,
150
+ site: typeof rec.site === 'string' && rec.site ? rec.site : null,
151
+ subject: rec.subject,
152
+ payload_json: rec.payload_json,
153
+ idem_key: typeof rec.idem_key === 'string' && rec.idem_key ? rec.idem_key : null,
154
+ };
155
+ }
156
+ function readSearchQuery(obj) {
157
+ const q = obj.query;
158
+ if (q === undefined)
159
+ return { query: undefined };
160
+ if (q === null || typeof q !== 'object' || Array.isArray(q))
161
+ return { code: 'shape' };
162
+ const rec = q;
163
+ const entryUrl = rec.entryUrl;
164
+ const timeoutMs = rec.timeoutMs;
165
+ if (entryUrl !== undefined && typeof entryUrl !== 'string')
166
+ return { code: 'shape' };
167
+ if (timeoutMs !== undefined && (typeof timeoutMs !== 'number' || !Number.isFinite(timeoutMs)))
168
+ return { code: 'shape' };
169
+ const strField = (k) => {
170
+ const v = rec[k];
171
+ if (v === undefined)
172
+ return { ok: true };
173
+ if (typeof v !== 'string')
174
+ return { ok: false, code: 'shape' };
175
+ return { ok: true, value: v.trim() || undefined };
176
+ };
177
+ const numField = (k) => {
178
+ const v = rec[k];
179
+ if (v === undefined)
180
+ return { ok: true };
181
+ if (typeof v !== 'number' || !Number.isFinite(v) || v < 0)
182
+ return { ok: false, code: 'shape' };
183
+ return { ok: true, value: Math.floor(v) };
184
+ };
185
+ const city = strField('city');
186
+ if (!city.ok)
187
+ return { code: city.code };
188
+ const checkIn = strField('checkIn');
189
+ if (!checkIn.ok)
190
+ return { code: checkIn.code };
191
+ const checkOut = strField('checkOut');
192
+ if (!checkOut.ok)
193
+ return { code: checkOut.code };
194
+ const adults = numField('adults');
195
+ if (!adults.ok)
196
+ return { code: adults.code };
197
+ const children = numField('children');
198
+ if (!children.ok)
199
+ return { code: children.code };
200
+ return {
201
+ query: {
202
+ entryUrl,
203
+ timeoutMs,
204
+ ...(city.value ? { city: city.value } : {}),
205
+ ...(checkIn.value ? { checkIn: checkIn.value } : {}),
206
+ ...(checkOut.value ? { checkOut: checkOut.value } : {}),
207
+ ...(adults.value !== undefined ? { adults: adults.value } : {}),
208
+ ...(children.value !== undefined ? { children: children.value } : {}),
209
+ },
210
+ };
211
+ }
212
+ /**
213
+ * needs-extension 的安装入口必须随 HTTP 响应一起下发。
214
+ *
215
+ * 能力层在 verdict=needs-extension 时已经算好了 Chrome 商店链接与安装动作
216
+ * (dida 路径返回 EXTENSION_STORE_URL + 'add-to-chrome'),而这一层是**逐字段
217
+ * 组装**响应的——漏掉这两个键,该 verdict 唯一的行动项就消失在传输层,消费方
218
+ * 只能退化成"放弃实时价、切回目录价"(hotel-fe#3611)。
219
+ */
220
+ function extensionInstallFields(result) {
221
+ return {
222
+ ...(result.installUrl ? { installUrl: result.installUrl } : {}),
223
+ ...(result.installAction ? { installAction: result.installAction } : {}),
224
+ };
225
+ }
226
+ async function readBody(req, cap = 64 * 1024) {
227
+ return new Promise((resolve, reject) => {
228
+ const chunks = [];
229
+ let size = 0;
230
+ let rejected = false;
231
+ req.on('data', (c) => {
232
+ if (rejected)
233
+ return;
234
+ size += c.length;
235
+ if (size > cap) {
236
+ rejected = true;
237
+ reject(new Error(`body 超 ${cap} 字节上限`));
238
+ return;
239
+ }
240
+ chunks.push(c);
241
+ });
242
+ req.on('end', () => { if (!rejected)
243
+ resolve(Buffer.concat(chunks).toString('utf8')); });
244
+ req.on('error', (e) => { if (!rejected)
245
+ reject(e); });
246
+ });
247
+ }
248
+ const locks = new Map();
249
+ async function withLock(key, fn) {
250
+ const prev = locks.get(key) ?? Promise.resolve();
251
+ const next = prev.catch(() => undefined).then(fn);
252
+ locks.set(key, next);
253
+ try {
254
+ return await next;
255
+ }
256
+ finally {
257
+ if (locks.get(key) === next)
258
+ locks.delete(key);
259
+ }
260
+ }
261
+ export function startSessionSearchModule(options) {
262
+ const search = options.search ?? sessionDidaSearch;
263
+ // verdict 结构化日志通道(#272):缺省 stderr(服务运行时既见面),测试注入收集器
264
+ const verdictEmit = options.verdictLog ?? ((line) => { process.stderr.write(`${line}\n`); });
265
+ const verdictLog = (entry) => {
266
+ try {
267
+ verdictEmit(formatSessionVerdictLine(entry));
268
+ }
269
+ catch { /* 结算日志绝不反噬 HTTP 结算路径 */ }
270
+ };
271
+ // 桥队列形态(批次 A):注入 jobQueue(测试)→ 原样;给 stateRoot(挂载路径)→
272
+ // ledger-backed(store 注入 createBridgeJobQueue);两者皆缺 → 纯内存(现状)。
273
+ let ledger;
274
+ let queue;
275
+ if (options.jobQueue) {
276
+ queue = options.jobQueue;
277
+ }
278
+ else if (options.stateRoot !== undefined) {
279
+ try {
280
+ ledger = openBridgeLedgerStore(options.stateRoot);
281
+ }
282
+ catch (e) {
283
+ // 账本开不了不打断服务:退回纯内存(重启丢在飞的旧缺陷面),stderr 留痕
284
+ process.stderr.write(`[session-search] 桥账本打开失败,退回纯内存队列: ${e instanceof Error ? e.message : String(e)}\n`);
285
+ }
286
+ queue = createBridgeJobQueue(ledger ? { store: ledger } : {});
287
+ }
288
+ else {
289
+ queue = createBridgeJobQueue();
290
+ }
291
+ // 开机恢复(gotry-backend 会话模块启动路径):queued→重排;claimed 已超时→
292
+ // unresolved+节律记账;claimed 未超时→复活 inFlight(重启不再丢在飞作业)。
293
+ const recovery = queue.recoverOnBoot?.();
294
+ if (recovery && recovery.requeued + recovery.rehydratedInFlight + recovery.settledUnresolved + recovery.voidedStale > 0) {
295
+ process.stderr.write(`[session-search] 桥账本开机恢复:重排 ${recovery.requeued},复活在飞 ${recovery.rehydratedInFlight},超时结算 ${recovery.settledUnresolved},过期作废 ${recovery.voidedStale}\n`);
296
+ }
297
+ const authorized = (req, res) => {
298
+ const key = options.apiKey();
299
+ const auth = String(req.headers.authorization ?? '');
300
+ if (!key) {
301
+ sendJson(res, 503, { ok: false, error: 'GOTRY_BACKEND_SESSION_API_KEY 未配置(fail-closed)' });
302
+ return false;
303
+ }
304
+ if (auth !== `Bearer ${key}`) {
305
+ sendJson(res, 403, { ok: false, error: 'forbidden' });
306
+ return false;
307
+ }
308
+ return true;
309
+ };
310
+ /**
311
+ * 扩展 workspace 事件批量上行(批次 B,2026-10-01):bearer(路由前置 authorized)之上
312
+ * 再强制 Origin ∈ 扩展白名单——与 /jobs 同链(同一 EXTENSION_ORIGINS 常量,网页跨域
313
+ * 请求必带邪恶 Origin,双保险)。body ≤256KB 超限 400 整批拒绝;逐条形状校验后落
314
+ * bridge_events:合法落账 accepted++,形状非法/idem_key 重复 rejected++(重试幂等:
315
+ * 同 idem_key 重发不重复落行)。事件是活动上下文非权威事实,批次内单条账本写失败
316
+ * 降级为该条 rejected + stderr 留痕,不打断批次也不抛出(route 句柄 void 启动,
317
+ * 逃逸 reject 会变 unhandledRejection 终止进程)。无账本形态(未给 stateRoot)
318
+ * fail-closed 503:事件无处落账,不假成功。
319
+ */
320
+ const extensionOrigins = new Set(EXTENSION_ORIGINS);
321
+ async function handleBridgeEvents(req, res) {
322
+ const origin = req.headers.origin;
323
+ if (typeof origin !== 'string' || !extensionOrigins.has(origin)) {
324
+ sendJson(res, 403, { ok: false, error: 'origin 不在桥白名单' });
325
+ return;
326
+ }
327
+ if (!ledger) {
328
+ sendJson(res, 503, { ok: false, error: '事件账本未配置(缺 stateRoot 的纯内存形态不收事件,fail-closed)' });
329
+ return;
330
+ }
331
+ let raw;
332
+ try {
333
+ raw = await readBody(req, BRIDGE_EVENTS_BODY_LIMIT);
334
+ }
335
+ catch (e) {
336
+ sendJson(res, 400, { ok: false, error: e instanceof Error ? e.message : 'body 读取失败' });
337
+ return;
338
+ }
339
+ let parsed;
340
+ try {
341
+ parsed = JSON.parse(raw);
342
+ }
343
+ catch {
344
+ sendJson(res, 400, { ok: false, error: 'body 不是 JSON' });
345
+ return;
346
+ }
347
+ if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
348
+ sendJson(res, 400, { ok: false, error: 'body 必须是 JSON 对象' });
349
+ return;
350
+ }
351
+ const rec = parsed;
352
+ if (typeof rec.clientId !== 'string' || !CLIENT_ID_RE.test(rec.clientId)) {
353
+ sendJson(res, 400, { ok: false, error: 'clientId 必须是扩展客户端标识(UUID)' });
354
+ return;
355
+ }
356
+ if (!Array.isArray(rec.events)) {
357
+ sendJson(res, 400, { ok: false, error: 'events 必须是数组' });
358
+ return;
359
+ }
360
+ let accepted = 0;
361
+ let rejected = 0;
362
+ for (const ev of rec.events) {
363
+ const input = validateBridgeEvent(rec.clientId, ev);
364
+ if (!input) {
365
+ rejected += 1;
366
+ continue;
367
+ }
368
+ try {
369
+ if (ledger.insertEvent(input))
370
+ accepted += 1;
371
+ else
372
+ rejected += 1;
373
+ }
374
+ catch (e) {
375
+ rejected += 1;
376
+ process.stderr.write(`[session-search] 桥事件落账失败(计入 rejected): ${e instanceof Error ? e.message : String(e)}\n`);
377
+ }
378
+ }
379
+ sendJson(res, 200, { ok: true, accepted, rejected });
380
+ }
381
+ async function handleStatus(res) {
382
+ const startedAt = Date.now();
383
+ const checkedAt = new Date().toISOString();
384
+ if (!queue.extensionConnected()) {
385
+ sendJson(res, 200, {
386
+ ok: true,
387
+ suppliers: [{ supplier: 'dida-portal', loggedIn: false, reason: 'extension-not-connected', detail: '会话执行环境=管理员浏览器扩展(GoTry Session Bridge);扩展未连接桥——在管理员浏览器安装扩展并配置本服务桥地址' }],
388
+ bridge: queue.stats(),
389
+ checkedAt,
390
+ });
391
+ verdictLog({ surface: 'status', supplier: 'dida-portal', verdict: 'needs-extension', latencyMs: Date.now() - startedAt });
392
+ return;
393
+ }
394
+ const login = await extensionCookieNames({ site: 'dida-portal', domain: DIDA_SITE_DOMAIN, ticketNames: DIDA_LOGIN_COOKIE_NAMES, timeoutMs: 20_000 }, queue);
395
+ if (!login.ok) {
396
+ const verdict = classifyBridgeFailure(login.kind);
397
+ sendJson(res, 200, { ok: true, suppliers: [{ supplier: 'dida-portal', loggedIn: false, reason: verdict, detail: login.summary }], bridge: queue.stats(), checkedAt });
398
+ verdictLog({ surface: 'status', supplier: 'dida-portal', verdict, latencyMs: Date.now() - startedAt, error: login.summary });
399
+ return;
400
+ }
401
+ sendJson(res, 200, {
402
+ ok: true,
403
+ suppliers: [{ supplier: 'dida-portal', loggedIn: login.tickets.length > 0, tickets: login.tickets, ...(login.tickets.length === 0 ? { reason: 'needs-login' } : {}) }],
404
+ bridge: queue.stats(),
405
+ checkedAt,
406
+ });
407
+ // tickets 只有 cookie 名级(值零过手),verdict 行也只落登录态结论本身
408
+ verdictLog({ surface: 'status', supplier: 'dida-portal', verdict: login.tickets.length > 0 ? 'logged-in' : 'needs-login', latencyMs: Date.now() - startedAt });
409
+ }
410
+ async function handleSearch(req, res) {
411
+ const startedAt = Date.now();
412
+ const parsed = await readAndParseObjectBody(req);
413
+ if ('code' in parsed) {
414
+ sendJson(res, 400, { ok: false, error: validationMessage(parsed.code) });
415
+ return;
416
+ }
417
+ const supplierType = ensureStringField(parsed.obj, 'supplier');
418
+ if (supplierType) {
419
+ sendJson(res, 400, { ok: false, error: validationMessage(supplierType) });
420
+ return;
421
+ }
422
+ const queryCheck = readSearchQuery(parsed.obj);
423
+ if ('code' in queryCheck) {
424
+ sendJson(res, 400, { ok: false, error: validationMessage(queryCheck.code) });
425
+ return;
426
+ }
427
+ const supplier = (parsed.obj.supplier ?? '').trim();
428
+ if (supplier !== 'dida-portal') {
429
+ sendJson(res, 400, { ok: false, error: `未知供应商通道 ${supplier || '(空)'}(M0 仅 dida-portal)` });
430
+ return;
431
+ }
432
+ // 挂载路径节律读判定(批次 A):账本口径跨重启(超时结算/上一次提交都在库里),
433
+ // 与 sessionDidaSearch 的进程内节律闸双闸取严——内存闸挡本进程,账本闸挡重启前打过的站点。
434
+ const pacing = ledger?.pacingOf(supplier);
435
+ if (pacing && Date.now() < pacing.cooldownUntil) {
436
+ const retryAfterSec = Math.max(1, Math.ceil((pacing.cooldownUntil - Date.now()) / 1_000));
437
+ res.setHeader('retry-after', String(retryAfterSec));
438
+ sendJson(res, 429, {
439
+ ok: false,
440
+ verdict: 'cooldown',
441
+ error: `bridge ledger cooldown: site ${supplier} cooling down until ${new Date(pacing.cooldownUntil).toISOString()}(last ledger hit ${Date.now() - pacing.lastHitAt}ms ago)`,
442
+ });
443
+ verdictLog({ surface: 'search', supplier, verdict: 'cooldown', latencyMs: Date.now() - startedAt, error: `bridge ledger cooldown retry-after ${retryAfterSec}s` });
444
+ return;
445
+ }
446
+ try {
447
+ const q = queryCheck.query;
448
+ const result = await withLock(supplier, () => search({
449
+ entryUrl: q?.entryUrl,
450
+ timeoutMs: q?.timeoutMs,
451
+ // 查询态(城市+日期)交给能力层 → 扩展驱动门户目的地搜索
452
+ ...(q?.city
453
+ ? { query: { city: q.city, checkIn: q.checkIn, checkOut: q.checkOut, adults: q.adults, children: q.children } }
454
+ : {}),
455
+ auditPath: options.auditPath,
456
+ bridge: queue,
457
+ }));
458
+ if (result.verdict === 'cooldown') {
459
+ res.setHeader('retry-after', '30');
460
+ sendJson(res, 429, {
461
+ ok: false,
462
+ verdict: result.verdict,
463
+ error: result.error,
464
+ evidence: result.evidence,
465
+ ...extensionInstallFields(result),
466
+ });
467
+ verdictLog({ surface: 'search', supplier, verdict: result.verdict, latencyMs: result.latencyMs, error: result.error });
468
+ return;
469
+ }
470
+ sendJson(res, 200, {
471
+ ok: result.ok,
472
+ verdict: result.verdict,
473
+ supplier,
474
+ rates: result.rates ?? [],
475
+ evidence: result.evidence,
476
+ latencyMs: result.latencyMs,
477
+ fetchedAt: new Date().toISOString(),
478
+ ...(result.error ? { error: result.error } : {}),
479
+ // needs-extension 的安装入口必须跟着 verdict 一起下发。能力层已经算好了
480
+ // (dida 路径返回 EXTENSION_STORE_URL),这里是它在 HTTP 面唯一的出口——
481
+ // 逐字段组装时漏掉这两个键,消费方就只剩"放弃实时价、切回目录价"一条路
482
+ // (hotel-fe#3611)。
483
+ ...extensionInstallFields(result),
484
+ });
485
+ // 结算行只落 verdict/延迟/脱敏 error;rates 与 evidence(回包形状)永不进日志
486
+ verdictLog({ surface: 'search', supplier, verdict: result.verdict, latencyMs: result.latencyMs, error: result.error });
487
+ }
488
+ catch (e) {
489
+ sendJson(res, 500, { ok: false, error: `会话检索异常: ${e instanceof Error ? e.message.slice(0, 200) : String(e)}` });
490
+ verdictLog({ surface: 'search', supplier, verdict: 'error', latencyMs: Date.now() - startedAt, error: e instanceof Error ? e.message : String(e) });
491
+ }
492
+ }
493
+ async function handleLoginOpen(req, res) {
494
+ const parsed = await readAndParseObjectBody(req);
495
+ if ('code' in parsed) {
496
+ sendJson(res, 400, { ok: false, error: validationMessage(parsed.code) });
497
+ return;
498
+ }
499
+ const supplierType = ensureStringField(parsed.obj, 'supplier');
500
+ if (supplierType) {
501
+ sendJson(res, 400, { ok: false, error: validationMessage(supplierType) });
502
+ return;
503
+ }
504
+ const urlType = ensureStringField(parsed.obj, 'url');
505
+ if (urlType) {
506
+ sendJson(res, 400, { ok: false, error: validationMessage(urlType) });
507
+ return;
508
+ }
509
+ const supplier = (parsed.obj.supplier ?? '').trim();
510
+ if (supplier !== 'dida-portal') {
511
+ sendJson(res, 400, { ok: false, error: `未知供应商通道 ${supplier || '(空)'}` });
512
+ return;
513
+ }
514
+ const url = (parsed.obj.url ?? '').trim() || 'https://portal.dida.com/login';
515
+ if (!/^https:\/\/portal\.dida\.com\//.test(url)) {
516
+ sendJson(res, 400, { ok: false, error: '登录入口必须落在 https://portal.dida.com/ 域内(fail-closed)' });
517
+ return;
518
+ }
519
+ const outcome = await extensionOpenLogin({ site: supplier, url, timeoutMs: 20_000 }, queue);
520
+ if (!outcome.ok) {
521
+ const verdict = classifyBridgeFailure(outcome.kind);
522
+ sendJson(res, verdict === 'needs-extension' ? 503 : 502, { ok: false, verdict, error: outcome.summary });
523
+ return;
524
+ }
525
+ sendJson(res, 200, { ok: true, opened: true, url, note: '登录页已在会话所属浏览器置前台打开(验证码人过);gotry 永不经手密码/cookie 值' });
526
+ }
527
+ return {
528
+ name: 'session-search',
529
+ routes: [
530
+ { method: 'GET', path: '/v1/session/status', handle: (req, res) => { if (authorized(req, res))
531
+ void handleStatus(res); } },
532
+ { method: 'POST', path: '/v1/session/search', handle: (req, res) => { if (authorized(req, res))
533
+ void handleSearch(req, res); } },
534
+ { method: 'POST', path: '/v1/session/login/open', handle: (req, res) => { if (authorized(req, res))
535
+ void handleLoginOpen(req, res); } },
536
+ // 桥协议端点:远程扩展经 bearer 鉴权连入;Origin 白名单在队列处理器内再校验一道
537
+ { method: 'GET', path: '/v1/session/bridge/health', handle: (req, res) => { if (authorized(req, res))
538
+ queue.handleMountedRequest(req, res); } },
539
+ { method: 'GET', path: '/v1/session/bridge/status', handle: (req, res) => { if (authorized(req, res))
540
+ queue.handleMountedRequest(req, res); } },
541
+ { method: 'POST', path: '/v1/session/bridge/jobs', handle: (req, res) => { if (authorized(req, res))
542
+ queue.handleMountedRequest(req, res); } },
543
+ { method: 'POST', path: '/v1/session/bridge/results', handle: (req, res) => { if (authorized(req, res))
544
+ queue.handleMountedRequest(req, res); } },
545
+ // 事件上行(批次 B):bearer + Origin 白名单双校验与 /jobs 同链,处理器内落 bridge_events
546
+ { method: 'POST', path: BRIDGE_EVENTS_PATH, handle: (req, res) => { if (authorized(req, res))
547
+ void handleBridgeEvents(req, res); } },
548
+ ],
549
+ close: () => queue.close().then(() => { ledger?.close(); }),
550
+ };
551
+ }