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

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 (507) 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 +1744 -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 +135 -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 +546 -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 +509 -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/resilience.js +191 -0
  41. package/dist/capabilities/session/action-cache.js +50 -44
  42. package/dist/capabilities/session/adapters/ctrip-flight.js +120 -62
  43. package/dist/capabilities/session/adapters/ctrip-hotel.js +222 -0
  44. package/dist/capabilities/session/adapters/dida-portal.js +274 -0
  45. package/dist/capabilities/session/adapters/meituan-local.js +35 -54
  46. package/dist/capabilities/session/adapters/rail-12306.js +342 -0
  47. package/dist/capabilities/session/benchmark.js +189 -0
  48. package/dist/capabilities/session/bridge-ledger.js +224 -0
  49. package/dist/capabilities/session/extension-bridge.js +636 -0
  50. package/dist/capabilities/session/extension-channel.js +109 -0
  51. package/dist/capabilities/session/extension-distribution.js +230 -0
  52. package/dist/capabilities/session/extract.js +31 -21
  53. package/dist/capabilities/session/golden-score.js +114 -0
  54. package/dist/capabilities/session/health-watch.js +215 -0
  55. package/dist/capabilities/session/read-guard.js +75 -24
  56. package/dist/capabilities/session/static-flight-golden.js +150 -0
  57. package/dist/capabilities/session/transport.js +97 -83
  58. package/dist/capabilities/session/wizard.js +117 -0
  59. package/dist/capabilities/session-consent.js +178 -0
  60. package/dist/capabilities/session-login.js +170 -0
  61. package/dist/capabilities/session-search.js +635 -44
  62. package/dist/capabilities/spawn-bounded.js +203 -0
  63. package/dist/capabilities/sponsor-plugin.js +341 -0
  64. package/dist/capabilities/visa-policy.js +140 -0
  65. package/dist/capabilities/weather.js +243 -138
  66. package/dist/data/session-golden-20.json +25 -0
  67. package/dist/data/sf-golden-manifest.json +103 -0
  68. package/dist/data/sf-static-routes.json +91 -0
  69. package/dist/scripts/action-cache-tests.js +24 -59
  70. package/dist/scripts/agent-planning-turn-deadline-e2e.js +242 -0
  71. package/dist/scripts/agent-planning-turn-deadline-tests.js +185 -0
  72. package/dist/scripts/agent-reach-deep-tests.js +30 -40
  73. package/dist/scripts/agent-reach-error-tests.js +354 -0
  74. package/dist/scripts/agent-reach-tests.js +26 -18
  75. package/dist/scripts/agent-reach-wrapper-tests.js +50 -50
  76. package/dist/scripts/anything-tests.js +116 -60
  77. package/dist/scripts/artifact-client-contract-tests.js +220 -0
  78. package/dist/scripts/artifacts-capability-tests.js +727 -0
  79. package/dist/scripts/async-collect.js +50 -11
  80. package/dist/scripts/benchmark-environment-bridge-e2e.js +741 -0
  81. package/dist/scripts/benchmark-environment-bridge-tests.js +1452 -0
  82. package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +126 -0
  83. package/dist/scripts/booking-copilot-availability-policy-tests.js +265 -0
  84. package/dist/scripts/booking-copilot-bin-proof-tests.js +66 -0
  85. package/dist/scripts/booking-copilot-cleanup-proof-helper.js +76 -0
  86. package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +144 -0
  87. package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +424 -0
  88. package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +2839 -0
  89. package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +309 -0
  90. package/dist/scripts/booking-copilot-dsh-readiness-proof.js +238 -0
  91. package/dist/scripts/booking-copilot-dsh-warmer-proof.js +123 -0
  92. package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +156 -0
  93. package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +70 -0
  94. package/dist/scripts/booking-copilot-intent-proof-tests.js +422 -0
  95. package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +184 -0
  96. package/dist/scripts/booking-copilot-planner-live-probe.js +95 -0
  97. package/dist/scripts/booking-copilot-proof-runtime.js +42 -0
  98. package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +210 -0
  99. package/dist/scripts/booking-copilot-runtime-proof-tests.js +2349 -0
  100. package/dist/scripts/booking-copilot-server-proof-tests.js +784 -0
  101. package/dist/scripts/booking-copilot-startup-proof-tests.js +94 -0
  102. package/dist/scripts/booking-executor-tests.js +80 -0
  103. package/dist/scripts/booking-recovery-chain-tests.js +182 -0
  104. package/dist/scripts/booking-saga-tests.js +125 -0
  105. package/dist/scripts/booking-surface-contract-proof-tests.js +212 -0
  106. package/dist/scripts/bootstrap-tests.js +1479 -0
  107. package/dist/scripts/bridge-events-tests.js +239 -0
  108. package/dist/scripts/bridge-ledger-tests.js +428 -0
  109. package/dist/scripts/build-changelog.js +238 -0
  110. package/dist/scripts/build-metrics-report.js +331 -0
  111. package/dist/scripts/changelog-tests.js +118 -0
  112. package/dist/scripts/channel-probe-tests.js +103 -0
  113. package/dist/scripts/channel-probe.js +169 -0
  114. package/dist/scripts/channel-registry-tests.js +208 -0
  115. package/dist/scripts/companion-tests.js +25 -70
  116. package/dist/scripts/dida-cookie-probe.js +87 -0
  117. package/dist/scripts/dida-runner-stop-tests.js +311 -0
  118. package/dist/scripts/dida-sw-probe.js +114 -0
  119. package/dist/scripts/diff-test.js +17 -12
  120. package/dist/scripts/doctor-tests.js +564 -0
  121. package/dist/scripts/dsh-artifact-e2e.js +279 -0
  122. package/dist/scripts/dsh-artifact-web-e2e.js +675 -0
  123. package/dist/scripts/dsh-http-proxy-sse-proof.js +90 -0
  124. package/dist/scripts/dsh-runtime-closure-tests.js +182 -0
  125. package/dist/scripts/dsh-runtime-closure.js +162 -0
  126. package/dist/scripts/dsh-session-v3-migration-proof.js +109 -0
  127. package/dist/scripts/dsh-subprocess-local-proof.js +150 -0
  128. package/dist/scripts/dsh-target-closure-proof.js +178 -0
  129. package/dist/scripts/effect-tests.js +539 -0
  130. package/dist/scripts/engine-run.js +1 -3
  131. package/dist/scripts/engine-tests.js +16 -10
  132. package/dist/scripts/evaluation-cadence-tests.js +174 -0
  133. package/dist/scripts/evaluation-contract-tests.js +268 -0
  134. package/dist/scripts/extension-distribution-cli.js +39 -0
  135. package/dist/scripts/extension-distribution-tests.js +443 -0
  136. package/dist/scripts/extension-tests.js +988 -0
  137. package/dist/scripts/external-event-tests.js +350 -0
  138. package/dist/scripts/fact-gate-tests.js +869 -0
  139. package/dist/scripts/fixtures/extension-bridge-unref-child.mjs +21 -0
  140. package/dist/scripts/flight-hotel-anchor-363-registered-e2e.js +169 -0
  141. package/dist/scripts/flight-malformed-tests.js +159 -0
  142. package/dist/scripts/flyai-setup-tests.js +228 -0
  143. package/dist/scripts/flyai-setup-tool-tests.js +54 -0
  144. package/dist/scripts/flyai-tests.js +692 -0
  145. package/dist/scripts/flyai-tool-registration-contract-tests.js +91 -0
  146. package/dist/scripts/fx-contract-tests.js +201 -0
  147. package/dist/scripts/g5-guard-tests.js +131 -0
  148. package/dist/scripts/g5-guard.js +189 -0
  149. package/dist/scripts/gen-lunar-anchors.js +106 -0
  150. package/dist/scripts/geo-atlas-tests.js +283 -0
  151. package/dist/scripts/gotry-backend-kernel-tests.js +206 -0
  152. package/dist/scripts/gotry-try-demo-tests.js +79 -0
  153. package/dist/scripts/gotry-try-demo.js +49 -0
  154. package/dist/scripts/ground-transfer-tests.js +956 -0
  155. package/dist/scripts/hbcli-e2e-tests.js +159 -0
  156. package/dist/scripts/hbcli-live-optin-tests.js +96 -0
  157. package/dist/scripts/hbcli-release-contract-tests.js +122 -0
  158. package/dist/scripts/hbcli-tests.js +121 -69
  159. package/dist/scripts/health-watch-cli.js +73 -0
  160. package/dist/scripts/hotel-date-gate-tests.js +496 -0
  161. package/dist/scripts/hotelbyte-reconcile-tests.js +141 -0
  162. package/dist/scripts/hotelbyte-spawn-e2e-tests.js +373 -0
  163. package/dist/scripts/i18n-tests.js +41 -0
  164. package/dist/scripts/incident-tests.js +281 -87
  165. package/dist/scripts/issue-194-job-id-guard-tests.js +106 -0
  166. package/dist/scripts/issue-233-cancel-refund-commission-tests.js +392 -0
  167. package/dist/scripts/issue-271-liveness-tests.js +569 -0
  168. package/dist/scripts/issue-289-model-retry-real-tests.js +296 -0
  169. package/dist/scripts/issue-289-model-retry-tests.js +441 -0
  170. package/dist/scripts/issue-289-web-retry-e2e.js +630 -0
  171. package/dist/scripts/issue-338-home-city-e2e.js +577 -0
  172. package/dist/scripts/issue343-real-entry-e2e.js +160 -0
  173. package/dist/scripts/issue436-persisted-routing-e2e.js +247 -0
  174. package/dist/scripts/itinerary-artifact-tests.js +368 -0
  175. package/dist/scripts/itinerary-deck-artifact-tests.js +416 -0
  176. package/dist/scripts/itinerary-deck-export-tests.js +552 -0
  177. package/dist/scripts/itinerary-deck-tests.js +435 -0
  178. package/dist/scripts/itinerary-html-tests.js +426 -0
  179. package/dist/scripts/journey-tests.js +22 -27
  180. package/dist/scripts/kernel-manifest-evidence.js +109 -0
  181. package/dist/scripts/kernel-manifest-gate.js +126 -0
  182. package/dist/scripts/kernel-manifest-tests.js +212 -0
  183. package/dist/scripts/kernel-manifest-trace-entry.js +7 -0
  184. package/dist/scripts/kernel-manifest-trace-hook.mjs +28 -0
  185. package/dist/scripts/kernel-manifest.js +369 -0
  186. package/dist/scripts/lavish-local-tests.js +1226 -0
  187. package/dist/scripts/lavish-product-tools-tests.js +537 -0
  188. package/dist/scripts/ledger-repair-apply-tests.js +316 -0
  189. package/dist/scripts/ledger-repair-plan-tests.js +375 -0
  190. package/dist/scripts/ledger-tests.js +382 -246
  191. package/dist/scripts/ledger-workflow-crash.js +10 -20
  192. package/dist/scripts/managed-dsh-cleanup-diagnostic-proof.js +184 -0
  193. package/dist/scripts/managed-dsh-close-failure-proof.js +172 -0
  194. package/dist/scripts/managed-dsh-run-port-proof.js +153 -0
  195. package/dist/scripts/managed-dsh-terminal-proof.js +252 -0
  196. package/dist/scripts/map-tools-vendor-package-proof.js +365 -0
  197. package/dist/scripts/memory-capture-tests.js +242 -61
  198. package/dist/scripts/memory-decay-tests.js +18 -52
  199. package/dist/scripts/memory-lifecycle-tests.js +657 -0
  200. package/dist/scripts/memory-lifecycle.js +196 -0
  201. package/dist/scripts/memory-metrics.js +24 -12
  202. package/dist/scripts/memory-value-report.js +631 -0
  203. package/dist/scripts/memory-value-tests.js +328 -0
  204. package/dist/scripts/metrics-report-tests.js +151 -0
  205. package/dist/scripts/model-override-e2e.js +137 -0
  206. package/dist/scripts/nightly-evidence-tests.js +161 -0
  207. package/dist/scripts/nightly-evidence.js +286 -0
  208. package/dist/scripts/nudge-digest.js +39 -28
  209. package/dist/scripts/observability-tests.js +381 -0
  210. package/dist/scripts/onboarding-tests.js +161 -0
  211. package/dist/scripts/opensky-check.js +18 -13
  212. package/dist/scripts/opensky-tests.js +28 -28
  213. package/dist/scripts/persona-surface-guard-tests.js +49 -0
  214. package/dist/scripts/pnpm-dsh-closure-proof.js +17 -0
  215. package/dist/scripts/policy-anchor-359-registered-e2e.js +214 -0
  216. package/dist/scripts/price-drift-tests.js +340 -0
  217. package/dist/scripts/price-drift-watch.js +447 -0
  218. package/dist/scripts/probe-poi-tests.js +53 -45
  219. package/dist/scripts/product-metrics.js +483 -0
  220. package/dist/scripts/publish-preverify.js +110 -0
  221. package/dist/scripts/realtime-pricing-tests.js +76 -0
  222. package/dist/scripts/recall-tests.js +513 -0
  223. package/dist/scripts/replay-async.js +20 -18
  224. package/dist/scripts/replay-real.js +18 -18
  225. package/dist/scripts/replay.js +52 -82
  226. package/dist/scripts/session-attach-diagnose.js +20 -20
  227. package/dist/scripts/session-attach-poc.js +34 -37
  228. package/dist/scripts/session-benchmark.js +180 -0
  229. package/dist/scripts/session-dida-live-e2e.js +199 -0
  230. package/dist/scripts/session-extract-tests.js +14 -35
  231. package/dist/scripts/session-link-tests.js +478 -0
  232. package/dist/scripts/session-login.js +27 -46
  233. package/dist/scripts/session-tests.js +796 -96
  234. package/dist/scripts/session-zones-tests.js +358 -0
  235. package/dist/scripts/sf-live-benchmark.js +367 -0
  236. package/dist/scripts/sf-live-challenge-stop-tests.js +453 -0
  237. package/dist/scripts/sf-live-cli-tests.js +92 -0
  238. package/dist/scripts/sf-live-options.js +46 -0
  239. package/dist/scripts/sf-manifest-tests.js +30 -0
  240. package/dist/scripts/sf-manifest.js +33 -0
  241. package/dist/scripts/sf-soft-score-tests.js +67 -0
  242. package/dist/scripts/sf-summary-tests.js +324 -0
  243. package/dist/scripts/sf-summary.js +525 -0
  244. package/dist/scripts/share-tests.js +432 -0
  245. package/dist/scripts/skeleton-check.js +16 -14
  246. package/dist/scripts/skeleton-integration-test.js +28 -11
  247. package/dist/scripts/skills-contract-tests.js +51 -46
  248. package/dist/scripts/smoke-session-gate-tests.js +21 -0
  249. package/dist/scripts/smoke.js +690 -246
  250. package/dist/scripts/spawn-bounded-abort-tests.js +241 -0
  251. package/dist/scripts/sponsor-reuse-tests.js +262 -0
  252. package/dist/scripts/state-cli-tests.js +226 -101
  253. package/dist/scripts/state-cli.js +550 -199
  254. package/dist/scripts/state-repair-cli.js +66 -0
  255. package/dist/scripts/state-repair-tests.js +140 -0
  256. package/dist/scripts/static-golden-tests.js +165 -0
  257. package/dist/scripts/time-eval-tests.js +210 -192
  258. package/dist/scripts/travel-timeline-tests.js +29 -93
  259. package/dist/scripts/turn-handoff-collect-tests.js +169 -0
  260. package/dist/scripts/turn-handoff-collect.js +161 -0
  261. package/dist/scripts/turn-policy-tests.js +55 -0
  262. package/dist/scripts/typed-contract-canary.js +176 -0
  263. package/dist/scripts/tz-resolver-sanity.js +50 -0
  264. package/dist/scripts/tz-resolver-tests.js +584 -0
  265. package/dist/scripts/unified-tests.js +23 -19
  266. package/dist/scripts/visa-policy-tests.js +62 -0
  267. package/dist/scripts/weather-tests.js +276 -41
  268. package/dist/scripts/wish-channel-gate-tests.js +54 -0
  269. package/dist/scripts/write-gate-tests.js +522 -0
  270. package/dist/scripts/z3-lifecycle-fault-tests.js +188 -0
  271. package/dist/scripts/z3-lifecycle-tests.js +170 -0
  272. package/dist/scripts/z3-race-repeat-tests.js +39 -0
  273. package/dist/scripts/z3-race-tests.js +41 -0
  274. package/dist/src/artifact-gate.js +829 -0
  275. package/dist/src/backend/kernel.js +91 -0
  276. package/dist/src/backend/modules/booking-copilot.js +92 -0
  277. package/dist/src/backend/modules/booking-executor.js +124 -0
  278. package/dist/src/backend/modules/session-search.js +551 -0
  279. package/dist/src/benchmark-agent-conformance.js +578 -0
  280. package/dist/src/benchmark-environment-bridge.js +515 -0
  281. package/dist/src/benchmark-headless-child-diagnostics.js +166 -0
  282. package/dist/src/benchmark-tool-isolation.js +151 -0
  283. package/dist/src/bookable-facts.js +533 -0
  284. package/dist/src/booking-saga.js +97 -0
  285. package/dist/src/booking-surface/availability-policy.js +697 -0
  286. package/dist/src/booking-surface/booking-intent.js +43 -0
  287. package/dist/src/booking-surface/cancel-refund-commission.js +379 -0
  288. package/dist/src/booking-surface/canonical-schema.js +116 -0
  289. package/dist/src/booking-surface/contracts.js +75 -0
  290. package/dist/src/booking-surface/dsh-planner.js +1854 -0
  291. package/dist/src/booking-surface/dsh-plugin.js +378 -0
  292. package/dist/src/booking-surface/dsh-worker.js +98 -0
  293. package/dist/src/booking-surface/error-codes.js +231 -0
  294. package/dist/src/booking-surface/index.js +9 -0
  295. package/dist/src/booking-surface/managed-dsh-cleanup-diagnostic.js +97 -0
  296. package/dist/src/booking-surface/managed-dsh-run-port.js +244 -0
  297. package/dist/src/booking-surface/profile.js +24 -0
  298. package/dist/src/booking-surface/recovery-chain.js +367 -0
  299. package/dist/src/booking-surface/runtime.js +1968 -0
  300. package/dist/src/booking-surface/server.js +674 -0
  301. package/dist/src/booking-surface/startup.js +168 -0
  302. package/dist/src/booking-surface/validation.js +261 -0
  303. package/dist/src/bridge.js +20 -13
  304. package/dist/src/companions.js +48 -74
  305. package/dist/src/contracts.js +21 -43
  306. package/dist/src/dsh-llm.js +97 -111
  307. package/dist/src/engine.js +276 -193
  308. package/dist/src/evaluation-cadence.js +97 -0
  309. package/dist/src/evaluation-contracts.js +283 -0
  310. package/dist/src/flight-pack-adapter.js +54 -0
  311. package/dist/src/flight-pack-contract.js +2 -0
  312. package/dist/src/flyai-setup-tool.js +70 -0
  313. package/dist/src/gotry-backend.js +125 -0
  314. package/dist/src/hotel-date-gate.js +118 -0
  315. package/dist/src/i18n.js +88 -0
  316. package/dist/src/index.js +2227 -882
  317. package/dist/src/itinerary-deck.js +139 -0
  318. package/dist/src/itinerary-doc-shared.js +661 -0
  319. package/dist/src/itinerary-html.js +131 -0
  320. package/dist/src/journey.js +155 -108
  321. package/dist/src/lavish-tools.js +400 -0
  322. package/dist/src/ledger-repair-apply.js +538 -0
  323. package/dist/src/ledger-repair-plan.js +463 -0
  324. package/dist/src/loop.js +319 -160
  325. package/dist/src/memory-capture.js +180 -32
  326. package/dist/src/memory-decay.js +30 -14
  327. package/dist/src/memory-lifecycle.js +1310 -0
  328. package/dist/src/memory-utility.js +27 -40
  329. package/dist/src/mock-llm.js +36 -61
  330. package/dist/src/model.js +81 -36
  331. package/dist/src/realtime-pricing.js +103 -0
  332. package/dist/src/recall/card.js +74 -0
  333. package/dist/src/recall/evaluator.js +140 -0
  334. package/dist/src/recall/integration.js +17 -0
  335. package/dist/src/recall/tick.js +166 -0
  336. package/dist/src/session-link/plan-it-action.js +48 -0
  337. package/dist/src/session-link/session-link.js +248 -0
  338. package/dist/src/session-zones.js +507 -0
  339. package/dist/src/share/adapters.js +51 -0
  340. package/dist/src/share/share-consent.js +76 -0
  341. package/dist/src/share/share-deck.js +58 -0
  342. package/dist/src/share/share-token.js +146 -0
  343. package/dist/src/slot-spec.js +84 -106
  344. package/dist/src/state-ledger.js +435 -516
  345. package/dist/src/state-repair.js +299 -0
  346. package/dist/src/subagent-job-id-guard.js +58 -0
  347. package/dist/src/time-anchor.js +231 -33
  348. package/dist/src/tool-packet.js +20 -8
  349. package/dist/src/travel-slots.js +58 -35
  350. package/dist/src/travel-timeline.js +44 -63
  351. package/dist/src/turn-deadline.js +287 -0
  352. package/dist/src/turn-policy.js +118 -0
  353. package/dist/src/tz-resolver.js +143 -0
  354. package/dist/src/unified.js +535 -359
  355. package/dist/src/wish-pool.js +42 -12
  356. package/dist/src/write-gate.js +495 -0
  357. package/dist/src/z3-shared.js +284 -0
  358. package/extension/README.md +21 -0
  359. package/extension/README.zh-CN.md +21 -0
  360. package/extension/background.js +463 -0
  361. package/extension/content-bridge.js +270 -0
  362. package/extension/content-main.js +111 -0
  363. package/extension/manifest.json +60 -0
  364. package/package.json +407 -14
  365. package/schemas/booking.intent.schema.json +193 -0
  366. package/schemas/booking.surface.schema.json +2622 -0
  367. package/ts/capabilities/agent-reach-deep.ts +114 -0
  368. package/ts/capabilities/agent-reach.ts +198 -0
  369. package/ts/capabilities/anything.ts +255 -0
  370. package/ts/capabilities/artifacts.ts +428 -0
  371. package/ts/capabilities/fact-log.ts +54 -0
  372. package/ts/capabilities/flyai-config.ts +388 -0
  373. package/ts/capabilities/flyai.ts +1274 -0
  374. package/ts/capabilities/hbcli.ts +253 -71
  375. package/ts/capabilities/incident-log.ts +88 -59
  376. package/ts/capabilities/itinerary-artifact.ts +214 -0
  377. package/ts/capabilities/itinerary-deck-artifact.ts +218 -0
  378. package/ts/capabilities/itinerary-deck-export.ts +378 -0
  379. package/ts/capabilities/opensky.ts +121 -0
  380. package/ts/capabilities/session/action-cache.ts +148 -0
  381. package/ts/capabilities/session/adapters/ctrip-flight.ts +181 -0
  382. package/ts/capabilities/session/adapters/ctrip-hotel.ts +238 -0
  383. package/ts/capabilities/session/adapters/dida-portal.ts +338 -0
  384. package/ts/capabilities/session/adapters/meituan-local.ts +70 -0
  385. package/ts/capabilities/session/adapters/rail-12306.ts +392 -0
  386. package/ts/capabilities/session/benchmark.ts +276 -0
  387. package/ts/capabilities/session/bridge-ledger.ts +333 -0
  388. package/ts/capabilities/session/extension-bridge.ts +794 -0
  389. package/ts/capabilities/session/extension-channel.ts +144 -0
  390. package/ts/capabilities/session/extension-distribution.ts +266 -0
  391. package/ts/capabilities/session/extract.ts +54 -0
  392. package/ts/capabilities/session/golden-score.ts +139 -0
  393. package/ts/capabilities/session/health-watch.ts +264 -0
  394. package/ts/capabilities/session/read-guard.ts +141 -0
  395. package/ts/capabilities/session/static-flight-golden.ts +209 -0
  396. package/ts/capabilities/session/transport.ts +146 -0
  397. package/ts/capabilities/session/wizard.ts +140 -0
  398. package/ts/capabilities/session-consent.ts +211 -0
  399. package/ts/capabilities/session-login.ts +208 -0
  400. package/ts/capabilities/session-search.ts +893 -0
  401. package/ts/capabilities/weather.ts +330 -0
  402. package/ts/dsh-runtime/vendor/README.md +68 -0
  403. package/ts/dsh-runtime/vendor/dsh-map-tools/LICENSE +21 -0
  404. package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +405 -0
  405. package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +404 -0
  406. package/ts/dsh-runtime/vendor/dsh-map-tools/client/client.js +1584 -0
  407. package/ts/dsh-runtime/vendor/dsh-map-tools/cordis.patch.yml +5 -0
  408. package/ts/dsh-runtime/vendor/dsh-map-tools/icon.svg +5 -0
  409. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/amap.js +595 -0
  410. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/nominatim.js +63 -0
  411. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/osrm.js +58 -0
  412. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/photon.js +55 -0
  413. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-file.js +87 -0
  414. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-route.js +131 -0
  415. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config.js +16 -0
  416. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/geo.js +232 -0
  417. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/index.js +120 -0
  418. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +40 -0
  419. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/staticmap-route.js +115 -0
  420. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/geocode.js +127 -0
  421. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/poi.js +84 -0
  422. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/routes.js +267 -0
  423. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/amap.d.ts +90 -0
  424. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/nominatim.d.ts +17 -0
  425. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/osrm.d.ts +15 -0
  426. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/photon.d.ts +22 -0
  427. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-file.d.ts +33 -0
  428. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-route.d.ts +23 -0
  429. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config.d.ts +23 -0
  430. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/geo.d.ts +61 -0
  431. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/index.d.ts +18 -0
  432. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +14 -0
  433. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/staticmap-route.d.ts +31 -0
  434. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/geocode.d.ts +11 -0
  435. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/poi.d.ts +9 -0
  436. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/routes.d.ts +75 -0
  437. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/types.d.ts +68 -0
  438. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types.js +16 -0
  439. package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +97 -0
  440. package/ts/package.json +293 -3
  441. package/ts/scripts/async-collect.ts +91 -0
  442. package/ts/scripts/map-tools-vendor-package-proof.ts +404 -0
  443. package/ts/scripts/skeleton-check.ts +1 -1
  444. package/ts/scripts/skeleton-integration-test.ts +23 -1
  445. package/ts/scripts/state-cli.ts +568 -0
  446. package/ts/scripts/turn-handoff-collect.ts +178 -0
  447. package/ts/src/artifact-gate.ts +991 -0
  448. package/ts/src/benchmark-agent-conformance.ts +619 -0
  449. package/ts/src/benchmark-environment-bridge.ts +538 -0
  450. package/ts/src/benchmark-headless-child-diagnostics.ts +184 -0
  451. package/ts/src/benchmark-tool-isolation.ts +166 -0
  452. package/ts/src/bookable-facts.ts +837 -0
  453. package/ts/src/booking-saga.ts +133 -0
  454. package/ts/src/booking-surface/availability-policy.ts +522 -0
  455. package/ts/src/booking-surface/booking-intent.ts +86 -0
  456. package/ts/src/booking-surface/cancel-refund-commission.ts +488 -0
  457. package/ts/src/booking-surface/canonical-schema.js +116 -0
  458. package/ts/src/booking-surface/contracts.ts +475 -0
  459. package/ts/src/booking-surface/dsh-planner.ts +1949 -0
  460. package/ts/src/booking-surface/dsh-plugin.js +378 -0
  461. package/ts/src/booking-surface/dsh-worker.ts +110 -0
  462. package/ts/src/booking-surface/error-codes.ts +241 -0
  463. package/ts/src/booking-surface/index.ts +9 -0
  464. package/ts/src/booking-surface/managed-dsh-cleanup-diagnostic.ts +151 -0
  465. package/ts/src/booking-surface/managed-dsh-run-port.ts +273 -0
  466. package/ts/src/booking-surface/profile.ts +42 -0
  467. package/ts/src/booking-surface/recovery-chain.ts +409 -0
  468. package/ts/src/booking-surface/runtime.ts +1793 -0
  469. package/ts/src/booking-surface/server.ts +733 -0
  470. package/ts/src/booking-surface/startup.ts +201 -0
  471. package/ts/src/booking-surface/validation.ts +217 -0
  472. package/ts/src/companions.ts +113 -0
  473. package/ts/src/contracts.ts +13 -3
  474. package/ts/src/dsh-llm.ts +44 -11
  475. package/ts/src/flyai-setup-tool.ts +77 -0
  476. package/ts/src/index.ts +1948 -198
  477. package/ts/src/itinerary-deck.ts +189 -0
  478. package/ts/src/itinerary-doc-shared.ts +741 -0
  479. package/ts/src/itinerary-html.ts +171 -0
  480. package/ts/src/loop.ts +223 -25
  481. package/ts/src/memory-capture.ts +283 -0
  482. package/ts/src/memory-decay.ts +55 -0
  483. package/ts/src/memory-utility.ts +70 -0
  484. package/ts/src/mock-llm.ts +4 -8
  485. package/ts/src/model.ts +88 -2
  486. package/ts/src/recall/card.ts +106 -0
  487. package/ts/src/recall/evaluator.ts +170 -0
  488. package/ts/src/recall/integration.ts +35 -0
  489. package/ts/src/recall/tick.ts +213 -0
  490. package/ts/src/session-link/plan-it-action.ts +78 -0
  491. package/ts/src/session-link/session-link.ts +275 -0
  492. package/ts/src/share/adapters.ts +93 -0
  493. package/ts/src/share/share-consent.ts +105 -0
  494. package/ts/src/share/share-deck.ts +85 -0
  495. package/ts/src/share/share-token.ts +166 -0
  496. package/ts/src/slot-spec.ts +172 -0
  497. package/ts/src/state-ledger.ts +912 -0
  498. package/ts/src/subagent-job-id-guard.ts +72 -0
  499. package/ts/src/time-anchor.ts +338 -0
  500. package/ts/src/tool-packet.ts +32 -0
  501. package/ts/src/travel-slots.ts +219 -0
  502. package/ts/src/travel-timeline.ts +83 -0
  503. package/ts/src/turn-deadline.ts +366 -0
  504. package/ts/src/turn-policy.ts +154 -0
  505. package/ts/src/unified.ts +354 -88
  506. package/ts/src/wish-pool.ts +79 -0
  507. package/dist/scripts/session-attach-wait.js +0 -41
@@ -0,0 +1,463 @@
1
+ /**
2
+ * GoTry Session Bridge — MV3 Service Worker(RFC docs/rfc/user-session-data-rfc.md §2.2 通道 C,2026-08-29 定案为 PRIMARY 传输)。
3
+ *
4
+ * 职责(与 Node 侧 session/extension-bridge.ts 配对,零构建纯 JS):
5
+ * - 长轮询取活:POST /jobs(桥最多 hold 20s;每次响应/失败都重置 SW 30s 生命周期,任务秒级触达);
6
+ * 断线每 5s 重试,chrome.alarms(30s)兜底唤醒防 SW 悬挂。
7
+ * - 三种 job:
8
+ * search → 后台标签打开 job.url(per-site 白名单:flights/hotels.ctrip.com),等 content hook 嗅探回包,收尾关自己的标签;
9
+ * open-login → 置前台打开登录入口页(登录页纪律 #34),标签留给用户,绝不代关;
10
+ * cookie-names → chrome.cookies 只读票据 cookie **名字**(值即取即弃,永不离开扩展——红线)。
11
+ * - 检索回包经页面代码发出并被动观察;本 SW 的 fetch 只发往桥,不直接发往供应商站点。
12
+ * 员工门户另有获准的 Dida 搜索控件操作与一次性登录表单代填/提交,详见隐私政策。
13
+ *
14
+ * 桥地址(2026-09-11,founder 定案:执行环境=浏览器客户端,服务端零 Chrome):
15
+ * 扩展**完全不暴露任何配置**给员工。hotel-be portal 在员工已登录的页面里通过
16
+ * content-bridge.js 派发 `gotry-join` 消息({bridgeUrl, token}),SW 缓存到
17
+ * `joinTicket` 模块变量;员工从未看见 URL / token / API host 等技术字眼。
18
+ * SW 进程重启(约每 30s 节律)→ ticket 丢失 → 下次员工打开 portal 页面自动重发 → 静默恢复。
19
+ *
20
+ * 桌面形态(loopback 端口池)保留向后兼容:无 join ticket 时回退到 127.0.0.1 探测,
21
+ * 这是 gotry 桌面开发场景(gotry CLI 同机形态),与员工日常产品路径无关。
22
+ */
23
+
24
+ 'use strict'
25
+
26
+ const BRIDGE_PORTS = [8791, 8792, 8793, 8794, 8795]
27
+ const RETRY_MS = 5_000
28
+
29
+ /** 站点注册表(与 Node 侧 LOGIN_TARGETS/LOGIN_COOKIE_NAMES 对账,防漂移测试守住) */
30
+ const SITES = {
31
+ 'ctrip-flight': {
32
+ domain: 'ctrip.com',
33
+ ticketNames: ['cticket', 'uid', 'uname', 'passport'],
34
+ },
35
+ // 酒店(2026-09-03 实装):同一携程账号体系;检索走 hotels.ctrip.com 后台标签 + 被动嗅探
36
+ 'ctrip-hotel': {
37
+ domain: 'ctrip.com',
38
+ ticketNames: ['cticket', 'uid', 'uname', 'passport'],
39
+ },
40
+ // 火车(2026-09-03 实装):12306 余票查询是公开面(登录只关系下单),无票据名可检;
41
+ // search job 照常经 per-site 白名单,扩展只读被动嗅探
42
+ 'train-12306': {
43
+ domain: '12306.cn',
44
+ ticketNames: [],
45
+ },
46
+ // Dida 供应商门户(2026-09-09 实装;hotel-be portal integration 迁移线):
47
+ // 员工登录态(HttpOnly 会话 cookie 只读名字,值即取即弃);检索走 portal.dida.com
48
+ // 后台标签 + 被动嗅探 portal-webapi 实时价
49
+ 'dida-portal': {
50
+ domain: 'dida.com',
51
+ ticketNames: ['CN_M_DidaTravel'],
52
+ },
53
+ }
54
+
55
+ /** 检索 URL 白名单(per-site;search job 只允许开各自站点域,其余一律拒) */
56
+ const SITE_SEARCH_PREFIXES = {
57
+ 'ctrip-flight': 'https://flights.ctrip.com/',
58
+ 'ctrip-hotel': 'https://hotels.ctrip.com/',
59
+ 'train-12306': 'https://kyfw.12306.cn/',
60
+ 'dida-portal': 'https://portal.dida.com/',
61
+ }
62
+
63
+ /**
64
+ * join ticket:由 hotel-be portal 通过 content-bridge 派发,SW 缓存;
65
+ * 模块级变量,SW 重启即清空(下次 portal 页派发即恢复,无需持久化)。
66
+ * 形态:{ bridgeUrl, token, issuedAt, expiresAt }
67
+ */
68
+ let joinTicket = null
69
+ let activePort = null
70
+ let polling = false
71
+ // Each Chrome profile has its own service worker. A restart rotates this ID, so an
72
+ // in-flight search pinned to the old worker fails closed instead of switching profiles.
73
+ const clientId = crypto.randomUUID()
74
+
75
+ /**
76
+ * workspace 事件 buffer(批次 B,2026-10-01):content-bridge 转发的页面事件先进内存,
77
+ * 伴随每次 /jobs 长轮询批量上行(见 flushWorkspaceEvents)。模块变量,SW 重启即弃——
78
+ * 事件是活动上下文非权威事实,可接受;零 storage(扩展无该权限,红线)。
79
+ * 上界护栏:超出即丢最旧(页面风暴不得把 SW 内存或上行 body 顶爆 256KB 服务端限)。
80
+ */
81
+ const WORKSPACE_EVENT_BUFFER_CAP = 200
82
+ const workspaceEventBuffer = []
83
+
84
+ function isJoinFresh(t) {
85
+ if (!t || typeof t.bridgeUrl !== 'string' || !t.bridgeUrl) return false
86
+ if (t.expiresAt && Number.isFinite(Date.parse(t.expiresAt)) && Date.parse(t.expiresAt) < Date.now()) return false
87
+ return true
88
+ }
89
+
90
+ function sleep(ms) {
91
+ return new Promise((resolve) => setTimeout(resolve, ms))
92
+ }
93
+
94
+ async function detectBridge() {
95
+ // 远程 join ticket 优先:portal 派发则连远程
96
+ if (isJoinFresh(joinTicket)) {
97
+ try {
98
+ const r = await fetch(`${joinTicket.bridgeUrl.replace(/\/+$/, '')}/health`, {
99
+ headers: { authorization: `Bearer ${joinTicket.token ?? ''}`, 'x-gotry-bridge': 'v1' },
100
+ })
101
+ if (r.ok) return true
102
+ } catch { /* 远程暂不可达;若也无可用 loopback 则继续重试 */ }
103
+ }
104
+ // 桌面形态兜底:loopback 端口池扫描
105
+ for (const p of BRIDGE_PORTS) {
106
+ try {
107
+ const r = await fetch(`http://127.0.0.1:${p}/health`, { headers: { 'x-gotry-bridge': 'v1' } })
108
+ if (r.ok) { activePort = p; return true }
109
+ } catch { /* 无人监听,试下一个端口 */ }
110
+ }
111
+ return false
112
+ }
113
+
114
+ function bridgeBase() {
115
+ if (isJoinFresh(joinTicket)) return joinTicket.bridgeUrl.replace(/\/+$/, '')
116
+ return activePort != null ? `http://127.0.0.1:${activePort}` : null
117
+ }
118
+
119
+ function bridgeHeaders(withJson) {
120
+ const h = { 'x-gotry-bridge': 'v1', 'x-gotry-client-id': clientId }
121
+ if (withJson) h['content-type'] = 'application/json'
122
+ if (isJoinFresh(joinTicket) && joinTicket.token) h['authorization'] = `Bearer ${joinTicket.token}`
123
+ return h
124
+ }
125
+
126
+ async function postResult(jobId, result) {
127
+ const base = bridgeBase()
128
+ if (base == null || !jobId) return
129
+ // 远程桥挂载在 gotry-backend 精确路由内核上,jobId 走 query;loopback 独立桥保持路径式
130
+ const url = isJoinFresh(joinTicket)
131
+ ? `${base}/results?jobId=${encodeURIComponent(jobId)}`
132
+ : `${base}/results/${encodeURIComponent(jobId)}`
133
+ try {
134
+ await fetch(url, {
135
+ method: 'POST',
136
+ headers: bridgeHeaders(true),
137
+ body: JSON.stringify(result),
138
+ })
139
+ } catch { /* 桥可能已退场;Node 侧超时兜底 */ }
140
+ }
141
+
142
+ /**
143
+ * workspace 事件批量上行(批次 B):伴随每次 /jobs 长轮询,把 buffer 整批 POST
144
+ * /v1/session/bridge/events(带 x-gotry-client-id/content-type,bearer 随 bridgeHeaders,
145
+ * Origin 由扩展 fetch 上下文自带 chrome-extension:// 源)。失败(网络断/403/400/503)
146
+ * 静默丢弃——事件是活动上下文非权威事实,重试不增值;批已出 buffer,不回灌。
147
+ * loopback 桌面形态无该端点(404)同样静默丢弃,零影响。
148
+ */
149
+ async function flushWorkspaceEvents() {
150
+ if (workspaceEventBuffer.length === 0) return
151
+ const base = bridgeBase()
152
+ if (base == null) return
153
+ const batch = workspaceEventBuffer.splice(0, workspaceEventBuffer.length)
154
+ // 变量别名 url(与 postResult 同款):§38 fetch 审计只放行 bridgeBase()/joinTicket 派生或 url 别名
155
+ const url = `${base}/v1/session/bridge/events`
156
+ try {
157
+ await fetch(url, {
158
+ method: 'POST',
159
+ headers: bridgeHeaders(true),
160
+ body: JSON.stringify({ clientId, events: batch }),
161
+ })
162
+ } catch { /* 桥不可达:静默丢弃 */ }
163
+ }
164
+
165
+ /** 只读票据 cookie 名单(只上报名;chrome.cookies 的值就地丢弃,不进任何结果对象) */
166
+ async function ticketNames(site) {
167
+ const conf = SITES[site]
168
+ if (!conf) return []
169
+ const cookies = await chrome.cookies.getAll({ domain: conf.domain }).catch(() => [])
170
+ return (Array.isArray(cookies) ? cookies : [])
171
+ .map((c) => c.name)
172
+ .filter((n) => conf.ticketNames.includes(n))
173
+ }
174
+
175
+ /** dida 推荐流多回包分类(与 Node 侧 mergeDidaRatesBodies 对账,run-all §38 防漂移断言守住) */
176
+ function classifyDidaSniff(url) {
177
+ if (/SearchHomepageRecommendHotels/i.test(url)) return 'hotels'
178
+ if (/SearchHomepageRecommendPrices/i.test(url)) return 'recommendPrices'
179
+ if (/HotelPriceAPI\/SearchCache/i.test(url)) return 'searchCache'
180
+ if (/HotelPriceAPI\/SearchRealTime/i.test(url)) return 'realtime'
181
+ return null
182
+ }
183
+
184
+ /** multiCollect(dida):按城市+日期的检索以 **searchCache**(列表页价格面)结算;
185
+ * 旧口径(首页推荐流)仍等 hotels+recommendPrices 齐;超时带回已见分桶(诚实缺桶) */
186
+ function waitSniffMulti(tabId, timeoutMs) {
187
+ return new Promise((resolve) => {
188
+ const bodies = {}
189
+ let settled = false
190
+ let title = ''
191
+ let challenge = false
192
+ const finish = () => {
193
+ if (settled) return
194
+ settled = true
195
+ clearTimeout(timer)
196
+ chrome.runtime.onMessage.removeListener(handler)
197
+ resolve({ ok: true, kind: 'search', bodies, title, challenge, timeout: !(bodies.searchCache || (bodies.hotels && bodies.recommendPrices)) })
198
+ }
199
+ const handler = (msg, sender) => {
200
+ if (!sender || !sender.tab || sender.tab.id !== tabId) return
201
+ if (msg && msg.type === 'gotry-page') {
202
+ title = String(msg.title ?? title)
203
+ if (msg.challenge === true) challenge = true
204
+ return
205
+ }
206
+ if (msg && msg.type === 'gotry-sniff') {
207
+ const cls = classifyDidaSniff(String(msg.url ?? ''))
208
+ if (cls && !bodies[cls]) bodies[cls] = String(msg.body ?? '')
209
+ // searchCache = 查询态价格面,拿到即可结算(推荐流是首页口径,不参与查询态结算)
210
+ if (bodies.searchCache || (bodies.hotels && bodies.recommendPrices)) finish()
211
+ }
212
+ }
213
+ const timer = setTimeout(finish, Math.max(Number(timeoutMs) || 30_000, 5_000))
214
+ chrome.runtime.onMessage.addListener(handler)
215
+ })
216
+ }
217
+
218
+ /**
219
+ * 查询态等待器(2026-09-21):驱动门户目的地搜索后,**只认 searchCache**(列表页价格面)。
220
+ * 为什么不能复用 waitSniffMulti:驱动流程里标签先落在 find 页,推荐流 double 会立刻满足
221
+ * 「hotels && recommendPrices」把等待提前结算,导致永远等不到 /hotel/list 的 SearchCache。
222
+ */
223
+ function waitSniffSearchCache(tabId, timeoutMs) {
224
+ return new Promise((resolve) => {
225
+ let settled = false
226
+ let title = ''
227
+ let challenge = false
228
+ const finish = (timedOut) => {
229
+ if (settled) return
230
+ settled = true
231
+ clearTimeout(timer)
232
+ chrome.runtime.onMessage.removeListener(handler)
233
+ resolve({ ok: true, kind: 'search', bodies, title, challenge, timeout: timedOut })
234
+ }
235
+ const bodies = {}
236
+ const handler = (msg, sender) => {
237
+ if (!sender || !sender.tab || sender.tab.id !== tabId) return
238
+ if (msg && msg.type === 'gotry-page') {
239
+ title = String(msg.title ?? title)
240
+ if (msg.challenge === true) challenge = true
241
+ return
242
+ }
243
+ if (msg && msg.type === 'gotry-sniff') {
244
+ const cls = classifyDidaSniff(String(msg.url ?? ''))
245
+ if (cls && !bodies[cls]) bodies[cls] = String(msg.body ?? '')
246
+ if (bodies.searchCache) finish(false)
247
+ }
248
+ }
249
+ const timer = setTimeout(() => finish(true), Math.max(Number(timeoutMs) || 30_000, 5_000))
250
+ chrome.runtime.onMessage.addListener(handler)
251
+ })
252
+ }
253
+
254
+ /** 后台标签等嗅探回包;超时带回页标题(供 Node 侧 CHALLENGE_RE 判定),收尾关自己的标签 */
255
+ function waitSniff(tabId, timeoutMs) {
256
+ return new Promise((resolve) => {
257
+ let settled = false
258
+ let title = ''
259
+ let challenge = false
260
+ const handler = (msg, sender) => {
261
+ if (!sender || !sender.tab || sender.tab.id !== tabId) return
262
+ if (msg && msg.type === 'gotry-page') {
263
+ title = String(msg.title ?? title)
264
+ if (msg.challenge === true) challenge = true
265
+ return
266
+ }
267
+ if (msg && msg.type === 'gotry-sniff' && !settled) {
268
+ settled = true
269
+ clearTimeout(timer)
270
+ chrome.runtime.onMessage.removeListener(handler)
271
+ resolve({ ok: true, kind: 'search', body: String(msg.body ?? ''), url: String(msg.url ?? ''), title, challenge })
272
+ }
273
+ }
274
+ const timer = setTimeout(() => {
275
+ if (settled) return
276
+ settled = true
277
+ chrome.runtime.onMessage.removeListener(handler)
278
+ resolve({ ok: false, kind: 'search', timeout: true, url: '', title })
279
+ }, Math.max(Number(timeoutMs) || 30_000, 5_000))
280
+ chrome.runtime.onMessage.addListener(handler)
281
+ })
282
+ }
283
+
284
+ /**
285
+ * 代填登录(2026-09-21,hotel-fe#3713 形态 A「免密进入门户」):
286
+ * portal 页把一次性凭据载荷交给本 SW → 前台打开站点登录页 → 回派 content-bridge
287
+ * 按站点配方填表提交 → 员工零输入落在门户里。
288
+ *
289
+ * 红线:账密只在本函数栈内存活——不写 storage(扩展无该权限)、不进日志、不回传;
290
+ * 登录页必须落在该站点的白名单前缀内(拒绝任意 URL 载荷);sw 只管开页与转发,
291
+ * 不读页面、不碰 cookie 值。
292
+ */
293
+ async function openLoginAndFill(site, payload) {
294
+ const allowedPrefix = SITE_SEARCH_PREFIXES[site]
295
+ if (!allowedPrefix || typeof payload.loginUrl !== 'string' || !payload.loginUrl.startsWith(allowedPrefix)) {
296
+ return { ok: false, kind: 'open-login-fill', error: `login 只允许 ${allowedPrefix ?? '已注册站点域'}` }
297
+ }
298
+ if (typeof payload.username !== 'string' || !payload.username || typeof payload.password !== 'string' || !payload.password) {
299
+ return { ok: false, kind: 'open-login-fill', error: 'username/password required' }
300
+ }
301
+ const fill = {
302
+ username: payload.username,
303
+ password: payload.password,
304
+ usernameField: typeof payload.usernameField === 'string' ? payload.usernameField : undefined,
305
+ passwordField: typeof payload.passwordField === 'string' ? payload.passwordField : undefined,
306
+ }
307
+ const tab = await chrome.tabs.create({ url: payload.loginUrl, active: true })
308
+ // content-bridge 在 document_start 注入,但登录页多为 SPA:输入框常晚于脚本就绪。
309
+ // 因此「未就绪」必须继续重试——只在**填表成功**时收工(2026-09-21 E2E 实证:
310
+ // 首次即返回 ok:false 会让登录页一直空着)。
311
+ let lastError = 'login page not ready'
312
+ for (let i = 0; i < 30; i++) {
313
+ await sleep(500)
314
+ try {
315
+ const r = await chrome.tabs.sendMessage(tab.id, { type: 'gotry-fill-login', payload: fill })
316
+ if (r && r.ok) return { ok: true, kind: 'open-login-fill', tabId: tab.id, filled: true }
317
+ if (r && r.error) lastError = String(r.error).slice(0, 120)
318
+ } catch { /* 接收端未就绪,继续等 */ }
319
+ }
320
+ return { ok: false, kind: 'open-login-fill', tabId: tab.id, error: lastError }
321
+ }
322
+
323
+ async function handleJob(job) {
324
+ const jobId = job && job.jobId
325
+ if (typeof jobId !== 'string' || !jobId) return
326
+ const site = String((job && job.site) || '')
327
+ const conf = SITES[site]
328
+ try {
329
+ if (!conf) {
330
+ await postResult(jobId, { ok: false, error: `unknown site ${site}` })
331
+ return
332
+ }
333
+ if (job.kind === 'cookie-names') {
334
+ await postResult(jobId, { ok: true, kind: 'cookie-names', names: await ticketNames(site) })
335
+ return
336
+ }
337
+ if (job.kind === 'open-login') {
338
+ if (typeof job.url !== 'string' || !job.url.startsWith('https://')) {
339
+ await postResult(jobId, { ok: false, error: 'open-login 需要 https job.url' })
340
+ return
341
+ }
342
+ const tab = await chrome.tabs.create({ url: job.url, active: true })
343
+ await postResult(jobId, { ok: true, kind: 'open-login', opened: true, tabId: tab.id })
344
+ return
345
+ }
346
+ if (job.kind === 'search') {
347
+ const allowedPrefix = SITE_SEARCH_PREFIXES[site]
348
+ if (!allowedPrefix || typeof job.url !== 'string' || !job.url.startsWith(allowedPrefix)) {
349
+ await postResult(jobId, { ok: false, error: `search 只允许 ${allowedPrefix ?? '已注册站点域'}(收到 ${String(job.url).slice(0, 80)})` })
350
+ return
351
+ }
352
+ // 带 query 的 dida 检索 = 驱动门户目的地搜索(2026-09-21):门户无结果路由可直出,
353
+ // 必须先在城市联想里选定目的地。步骤:开 find 页 → 配方(选目的地+点查询) →
354
+ // 用**我们的日期**重写落地 URL(不驱动门户日期选择器) → 嗅探价格响应。
355
+ if (job.query && site === 'dida-portal') {
356
+ const tab = await chrome.tabs.create({ url: job.url, active: false })
357
+ try {
358
+ let recipe = null
359
+ for (let i = 0; i < 30; i++) {
360
+ await sleep(500)
361
+ try { recipe = await chrome.tabs.sendMessage(tab.id, { type: 'gotry-dida-search', params: job.query }); break } catch { /* 接收端未就绪 */ }
362
+ }
363
+ if (!recipe || !recipe.ok) {
364
+ await postResult(jobId, { ok: false, kind: 'search', error: `dida 目的地解析失败(${(recipe && (recipe.step || recipe.error)) || 'recipe-unavailable'})` })
365
+ return
366
+ }
367
+ let landing = recipe.url
368
+ try {
369
+ const u = new URL(recipe.url)
370
+ if (job.query.checkIn) u.searchParams.set('checkInDate', job.query.checkIn)
371
+ if (job.query.checkOut) u.searchParams.set('checkOutDate', job.query.checkOut)
372
+ landing = u.toString()
373
+ } catch { /* 解析失败则用门户落地 URL */ }
374
+ await chrome.tabs.update(tab.id, { url: landing })
375
+ // 查询态:等列表页的 searchCache(给足窗口——门列表页价格面到达约 10-20s)
376
+ const result = await waitSniffSearchCache(tab.id, Math.max(Number(job.timeoutMs) || 0, 45_000))
377
+ await postResult(jobId, { ok: true, kind: 'search', bodies: result.bodies, title: result.title, landingUrl: landing, picked: recipe.picked, timeout: result.timeout })
378
+ return
379
+ } finally {
380
+ await chrome.tabs.remove(tab.id).catch(() => { /* 用户先关了,无妨 */ })
381
+ }
382
+ }
383
+ const tab = await chrome.tabs.create({ url: job.url, active: false })
384
+ const result = job.multiCollect
385
+ ? await waitSniffMulti(tab.id, job.timeoutMs)
386
+ : await waitSniff(tab.id, job.timeoutMs)
387
+ await chrome.tabs.remove(tab.id).catch(() => { /* 用户先关了,无妨 */ })
388
+ await postResult(jobId, result)
389
+ return
390
+ }
391
+ await postResult(jobId, { ok: false, error: `unknown job kind ${String(job.kind)}` })
392
+ } catch (e) {
393
+ await postResult(jobId, { ok: false, error: String(e && e.message ? e.message : e).slice(0, 200) })
394
+ }
395
+ }
396
+
397
+ async function loop() {
398
+ if (polling) return
399
+ polling = true
400
+ try {
401
+ for (;;) {
402
+ if (bridgeBase() == null) {
403
+ const up = await detectBridge()
404
+ if (!up) { await sleep(RETRY_MS); continue }
405
+ }
406
+ try {
407
+ const r = await fetch(`${bridgeBase()}/jobs`, {
408
+ method: 'POST',
409
+ headers: bridgeHeaders(true),
410
+ body: JSON.stringify({
411
+ extensionVersion: chrome.runtime.getManifest().version,
412
+ capabilities: Object.keys(SITES),
413
+ clientId,
414
+ }),
415
+ })
416
+ const data = await r.json().catch(() => ({ job: null }))
417
+ if (data && data.job) await handleJob(data.job)
418
+ // 伴随每次 /jobs 长轮询的事件上行(批次 B):桥已确认可达,再发本批
419
+ await flushWorkspaceEvents()
420
+ } catch { activePort = null; await sleep(RETRY_MS) }
421
+ }
422
+ } finally {
423
+ polling = false
424
+ }
425
+ }
426
+
427
+ /**
428
+ * portal content-bridge 派发入口(2026-09-11):hotel-be portal 在员工已登录的
429
+ * 页面里通过 content-bridge.js 发 `gotry-join` 消息,SW 静默接收并缓存 ticket。
430
+ * 员工从未看见这些消息;任何外部源都可发,但 ticket 必须由 hotel-be 后端签发,
431
+ * Node 侧通过 Bearer 鉴权校验 ticket 内 token 才认账。
432
+ */
433
+ chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
434
+ if (msg && msg.type === 'gotry-join' && msg.ticket && typeof msg.ticket.bridgeUrl === 'string') {
435
+ joinTicket = msg.ticket
436
+ activePort = null
437
+ sendResponse && sendResponse({ ok: true })
438
+ return false
439
+ }
440
+ if (msg && msg.type === 'gotry-portal-login' && msg.payload && typeof msg.payload === 'object') {
441
+ // 凭据载荷只在本次调用内存活:不落 storage、不进日志、不回传账密。
442
+ const payload = msg.payload
443
+ const site = typeof payload.site === 'string' && payload.site ? payload.site : 'dida-portal'
444
+ openLoginAndFill(site, payload)
445
+ .then((result) => { sendResponse && sendResponse(result) })
446
+ .catch(() => { sendResponse && sendResponse({ ok: false, kind: 'open-login-fill', error: 'fill failed' }) })
447
+ return true // 异步响应
448
+ }
449
+ if (msg && msg.type === 'gotry-workspace-event' && msg.event && typeof msg.event === 'object') {
450
+ // 页面 workspace 事件进内存 buffer,随下一次 /jobs 长轮询批量上行(批次 B);
451
+ // 不回执(事件即发即弃),不落 storage。形状由服务端逐条校验,这里不解析内容。
452
+ if (workspaceEventBuffer.length >= WORKSPACE_EVENT_BUFFER_CAP) workspaceEventBuffer.shift()
453
+ workspaceEventBuffer.push(msg.event)
454
+ return false
455
+ }
456
+ return false
457
+ })
458
+
459
+ // SW 冷启动 + 闹钟兜底双保险;loop() 幂等
460
+ if (chrome.runtime.onStartup) chrome.runtime.onStartup.addListener(() => { void loop() })
461
+ chrome.alarms.create('gotry-bridge-poll', { periodInMinutes: 0.5 })
462
+ chrome.alarms.onAlarm.addListener((a) => { if (a.name === 'gotry-bridge-poll') void loop() })
463
+ void loop()