@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,144 @@
1
+ /**
2
+ * 扩展车道客户端(RFC §2.2 通道 C,2026-08-29 PRIMARY;issue #21 传输层方案 B)。
3
+ *
4
+ * 三种 job 封装:search(被动嗅探 batchSearch)/ open-login(登录入口置前台)/
5
+ * cookie-names(票据 cookie **名字**,协议面不存在值字段)。verdict 映射纯函数
6
+ * `classifyBridgeFailure` 供回归覆盖:
7
+ * - extension-not-connected → 'needs-extension'(waiting no-spend,一次性安装指引;
8
+ * **不静默回退 CDP**——回退即重新引入逐连接权限框,正是本通道要消灭的摩擦);
9
+ * - bridge-unavailable(端口池全占等环境故障)→ 'error'(非用户门)。
10
+ * 检索页无回包不是车道失败:调用侧判为 sniff_timeout/error,页标题命挑战则判 challenged。
11
+ */
12
+
13
+ import { getOrCreateSessionBridge, needsExtensionSummary, type ExtensionJobResult, type SessionJobHandle, type SniffBodies } from './extension-bridge.ts'
14
+
15
+ /**
16
+ * needs-extension 用户门文案(D-24 自适应,issue #117):按本地通道是否落位自动跳过
17
+ * 开发者模式/本地通道指引——商店版用户只看到商店一键装与「已装即可」提示。
18
+ * 旧静态常量已退役:静态文案无法感知安装状态,正是 D-24 残量的病灶。
19
+ */
20
+ export function needsExtensionHint(): string {
21
+ return needsExtensionSummary()
22
+ }
23
+
24
+ export type BridgeFailureKind = 'bridge-unavailable' | 'extension-not-connected' | 'timeout' | 'job-error'
25
+
26
+ export interface BridgeFailure {
27
+ ok: false
28
+ kind: BridgeFailureKind
29
+ summary: string
30
+ }
31
+
32
+ /** 桥故障 → 用户门 verdict 纯函数(测试锚点):只有「扩展未连接」是用户门(waiting),其余降级 error */
33
+ export function classifyBridgeFailure(kind: BridgeFailureKind): 'needs-extension' | 'error' {
34
+ return kind === 'extension-not-connected' ? 'needs-extension' : 'error'
35
+ }
36
+
37
+ export interface SessionJobHandleRef {
38
+ ok: true
39
+ bridge: SessionJobHandle
40
+ }
41
+
42
+ function bridgeReady(b: { ok: true; bridge: SessionJobHandle } | { ok: false; summary: string }): b is SessionJobHandleRef {
43
+ return b.ok === true
44
+ }
45
+
46
+ function failedJob(result: ExtensionJobResult): BridgeFailure | null {
47
+ if (result.ok === true) return null
48
+ return {
49
+ ok: false,
50
+ kind: 'job-error',
51
+ summary: typeof result.error === 'string' && result.error.length > 0
52
+ ? result.error.slice(0, 200)
53
+ : '扩展作业失败且未提供原因',
54
+ }
55
+ }
56
+
57
+ /** 桥解析(2026-09-11):gotry-backend 服务形态注入进程内队列;桌面形态缺省走 loopback 懒单例 */
58
+ async function resolveBridge(injected?: SessionJobHandle): Promise<SessionJobHandleRef | { ok: false; summary: string }> {
59
+ if (injected) return { ok: true, bridge: injected }
60
+ return getOrCreateSessionBridge()
61
+ }
62
+
63
+ /** cookie-names job:票据 cookie 名存在性(名字级;协议不含值) */
64
+ export async function extensionCookieNames(q: { site: string; domain: string; ticketNames: string[]; timeoutMs?: number }, bridgeHandle?: SessionJobHandle): Promise<{ ok: true; tickets: string[]; origin?: string; clientId?: string } | BridgeFailure> {
65
+ const bridge = await resolveBridge(bridgeHandle)
66
+ if (!bridgeReady(bridge)) return { ok: false, kind: 'bridge-unavailable', summary: bridge.summary }
67
+ const outcome = await bridge.bridge.submit(
68
+ { kind: 'cookie-names', site: q.site, timeoutMs: q.timeoutMs ?? 8_000 },
69
+ { timeoutMs: q.timeoutMs ?? 8_000 },
70
+ )
71
+ if (!outcome.ok) return { ok: false, kind: outcome.reason, summary: outcome.summary }
72
+ const failure = failedJob(outcome.result)
73
+ if (failure) return failure
74
+ const names = Array.isArray(outcome.result.names) ? outcome.result.names.filter((n): n is string => typeof n === 'string') : []
75
+ // 红线自证:隧道面只有名字(extension-tests §红线断言协议面无值字段)
76
+ return { ok: true, tickets: names, ...(outcome.origin ? { origin: outcome.origin } : {}), ...(outcome.clientId ? { clientId: outcome.clientId } : {}) }
77
+ }
78
+
79
+ /** 登录入口置前台打开(#34 纪律:标签留给用户,扩展侧不 close) */
80
+ export async function extensionOpenLogin(q: { site: string; url: string; timeoutMs?: number }, bridgeHandle?: SessionJobHandle): Promise<{ ok: true; opened: boolean } | BridgeFailure> {
81
+ const bridge = await resolveBridge(bridgeHandle)
82
+ if (!bridgeReady(bridge)) return { ok: false, kind: 'bridge-unavailable', summary: bridge.summary }
83
+ const outcome = await bridge.bridge.submit({ kind: 'open-login', site: q.site, url: q.url }, { timeoutMs: q.timeoutMs ?? 15_000 })
84
+ if (!outcome.ok) return { ok: false, kind: outcome.reason, summary: outcome.summary }
85
+ const failure = failedJob(outcome.result)
86
+ if (failure) return failure
87
+ if (!outcome.result.opened) return { ok: false, kind: 'job-error', summary: outcome.result.error ?? '登录入口打开失败' }
88
+ return { ok: true, opened: true }
89
+ }
90
+
91
+ export interface ExtensionSearchOutcome {
92
+ ok: true
93
+ /** NETWORK_HINTS 命中的响应原文;未命中/超时为空 */
94
+ body: string
95
+ /** Exact NETWORK_HINTS response URL selected for body;未命中/超时为空 */
96
+ url: string
97
+ /** 页标题(challenged 判定素材) */
98
+ title: string
99
+ /** 到点未见 hints 命中(站点无回包/风控拦截页) */
100
+ timedOut: boolean
101
+ /** multiCollect(dida 推荐流):分桶回包体;旧扩展/非 multiCollect 缺省 */
102
+ bodies?: SniffBodies
103
+ /** 页面级挑战标记(content-bridge 按 DOM 判定;网关侧不得用供应商响应体扫「验证」——会把酒店名误判成风控) */
104
+ challenge?: boolean
105
+ }
106
+
107
+ /** 检索 job:后台标签打开 entry,等 content hook 的嗅探回包;页无响应=timedOut(非车道失败) */
108
+ export async function extensionSearchJob(
109
+ q: { site: string; url: string; timeoutMs?: number; multiCollect?: boolean; query?: Record<string, unknown>; preferredOrigin?: string; preferredClientId?: string },
110
+ bridgeHandle?: SessionJobHandle,
111
+ ): Promise<ExtensionSearchOutcome | BridgeFailure> {
112
+ const bridge = await resolveBridge(bridgeHandle)
113
+ if (!bridgeReady(bridge)) return { ok: false, kind: 'bridge-unavailable', summary: bridge.summary }
114
+ const timeoutMs = q.timeoutMs ?? 30_000
115
+ const outcome = await bridge.bridge.submit(
116
+ { kind: 'search', site: q.site, url: q.url, timeoutMs, ...(q.multiCollect ? { multiCollect: true } : {}), ...(q.query ? { query: q.query } : {}) },
117
+ { timeoutMs: timeoutMs + 10_000, ...(q.preferredOrigin ? { preferredOrigin: q.preferredOrigin } : {}), ...(q.preferredClientId ? { preferredClientId: q.preferredClientId } : {}) },
118
+ )
119
+ if (!outcome.ok) return { ok: false, kind: outcome.reason, summary: outcome.summary }
120
+ // An exhausted page sniff still carries the page title and challenge hint.
121
+ // Let the caller inspect them before classifying the empty body.
122
+ if (outcome.result.ok === false && outcome.result.timeout === true) {
123
+ return {
124
+ ok: true,
125
+ body: '',
126
+ url: '',
127
+ title: typeof outcome.result.title === 'string' ? outcome.result.title : '',
128
+ timedOut: true,
129
+ ...(outcome.result.challenge === true ? { challenge: true } : {}),
130
+ }
131
+ }
132
+ const failure = failedJob(outcome.result)
133
+ if (failure) return failure
134
+ const bodies = outcome.result.bodies
135
+ return {
136
+ ok: true,
137
+ ...(outcome.result.challenge === true ? { challenge: true } : {}),
138
+ body: typeof outcome.result.body === 'string' ? outcome.result.body : '',
139
+ url: typeof outcome.result.url === 'string' ? outcome.result.url : '',
140
+ title: typeof outcome.result.title === 'string' ? outcome.result.title : '',
141
+ timedOut: outcome.result.timeout === true,
142
+ ...(bodies && typeof bodies === 'object' ? { bodies } : {}),
143
+ }
144
+ }
@@ -0,0 +1,266 @@
1
+ /**
2
+ * 扩展产物分发(issue #21 分发通道,ADR-21;founder 2026-08-30「产物下载和安装也得做成更好的
3
+ * 用户体验,可以用 github 作为分发渠道」)。
4
+ *
5
+ * 平台硬约束(诚实前置):Chrome 禁止普通用户从任意 URL 安装打包 CRX——GitHub 只能改善
6
+ * 「下载」(版本化/回滚/与 npm 发版节奏解耦),改善不了「安装」;「开发者模式加载已解压」
7
+ * 那 3 次点击只有上架 Chrome Web Store 才能消掉(商店版自动更新,见 extension-webstore-submission.md)。
8
+ * manifest 固定 key ⇒ 双通道是同一个扩展 ID(olpgkofjhhiiiahdkkbcninhjmegghfe),端口池/
9
+ * host_permissions 不随通道漂移——本模块用 key 钉住这一不变量。
10
+ *
11
+ * 单一职责:① 产物源解析(bundled 默认离线确定性 | github 显式 opt-in);
12
+ * ② GitHub Releases 下载链:dist-manifest → tar.gz → SHA256 校验 → tar 解压 → key 钉扎校验
13
+ * → 版本比较 → 原子交换 ~/.gotry/extension;
14
+ * ③ 失败语义:github 源任何失败(无网/404/校验不过/key 漂移)→ 结构化 fallback bundled,
15
+ * 绝不挡 setup(安装外部产物永远不挡 gotry 本体——bootstrap 契约)。
16
+ *
17
+ * 信任边界(诚实声明):TLS 传输 + 同源 dist-manifest 哈希完整性——防截断/损坏/误传资产,
18
+ * 不防仓库本身被攻陷(无独立 pinning;独立 pin 需把哈希烘进 npm 包,与「扩展更新与 npm
19
+ * 发版解耦」目标冲突,明确不做)。
20
+ *
21
+ * 零新 npm 依赖:fetch 走 Node ≥22 全局;解压走平台原生 `tar -xzf`(macOS/Linux/Windows10+
22
+ * 自带);SHA256 走 node:crypto。spawn/fetch 可注入(离线测试)。
23
+ */
24
+
25
+ import { spawn } from 'node:child_process'
26
+ import { createHash } from 'node:crypto'
27
+ import { cpSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
28
+ import { join } from 'node:path'
29
+
30
+ /** Releases 稳定资产名(每版覆盖同名上传;latest/download 永久链只认稳定名)。
31
+ * 与 scripts/package-extension.mjs 的资产名必须逐字一致——extension-distribution-tests 防漂移。 */
32
+ export const DIST_ASSET_TARBALL = 'gotry-session-bridge.tar.gz'
33
+ export const DIST_ASSET_STORE_ZIP = 'gotry-session-bridge-store.zip'
34
+ export const DIST_ASSET_MANIFEST = 'extension-dist-manifest.json'
35
+
36
+ export const DEFAULT_RELEASE_BASE = 'https://github.com/Danceiny/gotry/releases'
37
+
38
+ export interface ExtensionDistManifest {
39
+ version: string
40
+ tarball: string
41
+ tarballSha256: string
42
+ zip: string
43
+ zipSha256: string
44
+ builtFromCommit?: string
45
+ }
46
+
47
+ export interface GithubSourceOptions {
48
+ /** Releases 基址(测试/镜像可指回环);默认 GitHub 官方 */
49
+ releaseBase?: string
50
+ /** 注入 fetch(离线测试);默认全局 fetch */
51
+ fetch?: typeof fetch
52
+ /** 注入 spawn(离线测试拦截 tar);默认 child_process.spawn */
53
+ spawnFn?: typeof spawn
54
+ /** 下载/解压超时(默认 60s,有界) */
55
+ timeoutMs?: number
56
+ }
57
+
58
+ export type ExtensionInstallAction = 'installed' | 'up-to-date' | 'fallback-bundled'
59
+
60
+ export interface ExtensionInstallResult {
61
+ ok: boolean
62
+ action: ExtensionInstallAction
63
+ /** 远端 dist-manifest 声明的版本(action=up-to-date 时也带回,供比较报告) */
64
+ version?: string
65
+ /** 交换前 dest 里已就位的版本(无则 undefined) */
66
+ previousVersion?: string
67
+ error?: string
68
+ }
69
+
70
+ /** 纯函数:三段数字版本比较(a<b 负 / 相等 0 / a>b 正;非数字段按 0 处理,长度差补 0) */
71
+ export function compareVersions(a: string, b: string): number {
72
+ const pa = String(a).split('.').map((s) => Number.parseInt(s, 10) || 0)
73
+ const pb = String(b).split('.').map((s) => Number.parseInt(s, 10) || 0)
74
+ const n = Math.max(pa.length, pb.length)
75
+ for (let i = 0; i < n; i += 1) {
76
+ const d = (pa[i] ?? 0) - (pb[i] ?? 0)
77
+ if (d !== 0) return d
78
+ }
79
+ return 0
80
+ }
81
+
82
+ /** 纯函数:Releases latest/download 永久链(稳定资产名) */
83
+ export function distAssetUrls(releaseBase: string = DEFAULT_RELEASE_BASE): { tarball: string; storeZip: string; manifest: string } {
84
+ const base = releaseBase.replace(/\/+$/, '')
85
+ return {
86
+ tarball: `${base}/latest/download/${DIST_ASSET_TARBALL}`,
87
+ storeZip: `${base}/latest/download/${DIST_ASSET_STORE_ZIP}`,
88
+ manifest: `${base}/latest/download/${DIST_ASSET_MANIFEST}`,
89
+ }
90
+ }
91
+
92
+ const SHA256_RE = /^[0-9a-f]{64}$/
93
+
94
+ /** 纯函数:dist-manifest 解析,fail-closed(坏 JSON/缺字段/资产名漂移/哈希非 64-hex 一律拒绝) */
95
+ export function parseDistManifest(raw: string): ExtensionDistManifest {
96
+ let obj: Record<string, unknown>
97
+ try {
98
+ obj = JSON.parse(raw) as Record<string, unknown>
99
+ } catch {
100
+ throw new Error('dist-manifest 不是合法 JSON')
101
+ }
102
+ const version = obj.version
103
+ const tarball = obj.tarball
104
+ const tarballSha256 = obj.tarballSha256
105
+ const zip = obj.zip
106
+ const zipSha256 = obj.zipSha256
107
+ // Chrome manifest version 形态:1-4 段点分整数(扩展版本跟随 gotry 主版本
108
+ // 0.0.1-rc.N → 四段投影 0.0.1.N,展示名走 version_name 原样)
109
+ if (typeof version !== 'string' || !/^\d+(\.\d+){1,3}$/.test(version)) throw new Error('dist-manifest.version 缺失或非 1-4 段点分整数')
110
+ if (tarball !== DIST_ASSET_TARBALL) throw new Error(`dist-manifest.tarball 资产名漂移(期望 ${DIST_ASSET_TARBALL})`)
111
+ if (zip !== DIST_ASSET_STORE_ZIP) throw new Error(`dist-manifest.zip 资产名漂移(期望 ${DIST_ASSET_STORE_ZIP})`)
112
+ if (typeof tarballSha256 !== 'string' || !SHA256_RE.test(tarballSha256)) throw new Error('dist-manifest.tarballSha256 非 64-hex')
113
+ if (typeof zipSha256 !== 'string' || !SHA256_RE.test(zipSha256)) throw new Error('dist-manifest.zipSha256 非 64-hex')
114
+ return {
115
+ version,
116
+ tarball,
117
+ tarballSha256,
118
+ zip,
119
+ zipSha256,
120
+ builtFromCommit: typeof obj.builtFromCommit === 'string' ? obj.builtFromCommit : undefined,
121
+ }
122
+ }
123
+
124
+ export function sha256Hex(bytes: Uint8Array | string): string {
125
+ return createHash('sha256').update(bytes).digest('hex')
126
+ }
127
+
128
+ /** 读取扩展 manifest 的 key(固定 key ⇒ 固定扩展 ID;分发通道 ID 不变量的锚点) */
129
+ export function readExtensionKey(extensionDir: string): string | undefined {
130
+ const p = join(extensionDir, 'manifest.json')
131
+ if (!existsSync(p)) return undefined
132
+ try {
133
+ const m = JSON.parse(readFileSync(p, 'utf8')) as { key?: unknown }
134
+ return typeof m.key === 'string' ? m.key : undefined
135
+ } catch {
136
+ return undefined
137
+ }
138
+ }
139
+
140
+ export function readExtensionVersion(extensionDir: string): string | undefined {
141
+ const p = join(extensionDir, 'manifest.json')
142
+ if (!existsSync(p)) return undefined
143
+ try {
144
+ const m = JSON.parse(readFileSync(p, 'utf8')) as { version?: unknown }
145
+ return typeof m.version === 'string' ? m.version : undefined
146
+ } catch {
147
+ return undefined
148
+ }
149
+ }
150
+
151
+ function runTar(args: string[], spawnFn: typeof spawn, timeoutMs: number): Promise<{ ok: boolean; error?: string }> {
152
+ return new Promise((resolve) => {
153
+ const child = spawnFn('tar', args, { stdio: 'ignore' })
154
+ let done = false
155
+ const timer = setTimeout(() => {
156
+ if (!done) {
157
+ done = true
158
+ try {
159
+ child.kill('SIGKILL')
160
+ } catch {
161
+ /* ignore */
162
+ }
163
+ resolve({ ok: false, error: `tar 超时(>${timeoutMs}ms)` })
164
+ }
165
+ }, timeoutMs)
166
+ child.on('error', (e) => {
167
+ if (!done) {
168
+ done = true
169
+ clearTimeout(timer)
170
+ resolve({ ok: false, error: `tar 不可用:${e.message}` })
171
+ }
172
+ })
173
+ child.on('close', (code) => {
174
+ if (!done) {
175
+ done = true
176
+ clearTimeout(timer)
177
+ resolve(code === 0 ? { ok: true } : { ok: false, error: `tar exit ${code}` })
178
+ }
179
+ })
180
+ })
181
+ }
182
+
183
+ async function fetchBytes(url: string, fetchFn: typeof fetch, timeoutMs: number): Promise<{ ok: true; bytes: Uint8Array } | { ok: false; error: string }> {
184
+ try {
185
+ const res = await fetchFn(url, { signal: AbortSignal.timeout(timeoutMs) })
186
+ if (!res.ok) return { ok: false, error: `HTTP ${res.status} ${url}` }
187
+ const buf = new Uint8Array(await res.arrayBuffer())
188
+ return { ok: true, bytes: buf }
189
+ } catch (e) {
190
+ return { ok: false, error: `下载失败 ${(e as Error).message}` }
191
+ }
192
+ }
193
+
194
+ export interface InstallFromGithubOptions extends GithubSourceOptions {
195
+ /** 落位目录(默认 ~/.gotry/extension 由调用方决定,本层不猜) */
196
+ destDir: string
197
+ /** 钉扎参照:bundled extension/ 目录(其 manifest key 是 ID 不变量的基准;缺省只做版本校验) */
198
+ pinnedSourceDir?: string
199
+ /** 只报告不落盘(up-to-date/将安装哪个版本;不下载 tarball 之外的任何东西) */
200
+ checkOnly?: boolean
201
+ }
202
+
203
+ /**
204
+ * GitHub Releases → ~/.gotry/extension 安装链。
205
+ * 任何失败都返回 { ok:false, action:'fallback-bundled' }——调用方显式降级 bundled,
206
+ * 本函数不抛出(bootstrap 契约:安装外部产物永远不挡 gotry 本体)。
207
+ */
208
+ export async function installExtensionFromGithub(opts: InstallFromGithubOptions): Promise<ExtensionInstallResult> {
209
+ const timeoutMs = opts.timeoutMs ?? 60_000
210
+ const fetchFn = opts.fetch ?? fetch
211
+ const spawnFn = opts.spawnFn ?? spawn
212
+ const urls = distAssetUrls(opts.releaseBase)
213
+ const fail = (error: string): ExtensionInstallResult => ({ ok: false, action: 'fallback-bundled', error })
214
+
215
+ const mRes = await fetchBytes(urls.manifest, fetchFn, timeoutMs)
216
+ if (!mRes.ok) return fail(mRes.error)
217
+ let manifest: ExtensionDistManifest
218
+ try {
219
+ manifest = parseDistManifest(new TextDecoder().decode(mRes.bytes))
220
+ } catch (e) {
221
+ return fail(`dist-manifest 校验失败:${(e as Error).message}`)
222
+ }
223
+
224
+ const previousVersion = readExtensionVersion(opts.destDir)
225
+ if (previousVersion != null && compareVersions(manifest.version, previousVersion) <= 0) {
226
+ return { ok: true, action: 'up-to-date', version: manifest.version, previousVersion }
227
+ }
228
+ if (opts.checkOnly) {
229
+ return { ok: true, action: 'up-to-date', version: manifest.version, previousVersion } // check-only 语义:报告远端版本,不落盘
230
+ }
231
+
232
+ const tRes = await fetchBytes(urls.tarball, fetchFn, timeoutMs)
233
+ if (!tRes.ok) return fail(tRes.error)
234
+ const actual = sha256Hex(tRes.bytes)
235
+ if (actual !== manifest.tarballSha256) return fail(`SHA256 不符(期望 ${manifest.tarballSha256.slice(0, 12)}… 实得 ${actual.slice(0, 12)}…)`)
236
+
237
+ // 落盘 → tar 解压 → key 钉扎 → 原子交换;incoming 目录同盘保证 rename 原子性
238
+ const incoming = `${opts.destDir}.incoming-${process.pid}-${Date.now()}`
239
+ const tarPath = `${incoming}.tar.gz`
240
+ try {
241
+ rmSync(incoming, { recursive: true, force: true })
242
+ mkdirSync(incoming, { recursive: true })
243
+ writeFileSync(tarPath, tRes.bytes)
244
+ // 包内含顶层目录 gotry-session-bridge/;--strip-components 落到 incoming 根
245
+ const ext = await runTar(['-xzf', tarPath, '-C', incoming, '--strip-components', '1'], spawnFn, timeoutMs)
246
+ if (!ext.ok) return fail(ext.error!)
247
+
248
+ const incomingKey = readExtensionKey(incoming)
249
+ if (incomingKey == null) return fail('解压产物缺 manifest.json/key(非法包)')
250
+ if (opts.pinnedSourceDir) {
251
+ const pinnedKey = readExtensionKey(opts.pinnedSourceDir)
252
+ if (pinnedKey != null && incomingKey !== pinnedKey) return fail('扩展 key 漂移(通道产物与 bundled 不同 ID——拒绝安装,防端口池/host 权限漂移)')
253
+ }
254
+ const incomingVersion = readExtensionVersion(incoming)
255
+ if (incomingVersion !== manifest.version) return fail(`解压产物版本(${incomingVersion})与 dist-manifest(${manifest.version})不符`)
256
+
257
+ rmSync(opts.destDir, { recursive: true, force: true })
258
+ cpSync(incoming, opts.destDir, { recursive: true })
259
+ return { ok: true, action: 'installed', version: manifest.version, previousVersion }
260
+ } catch (e) {
261
+ return fail(`落位失败 ${(e as Error).message}`)
262
+ } finally {
263
+ rmSync(incoming, { recursive: true, force: true })
264
+ rmSync(tarPath, { force: true })
265
+ }
266
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * a11y 快照兜底抽取器(RFC §2.3 第②层:站点无干净 XHR JSON 时,从可访问性树快照抽结构化条目)。
3
+ * 纯函数:输入 Playwright ariaSnapshot/domSnapshot 文本,输出归一化条目(role/name/ref),
4
+ * 供确定性规则或 LLM 按 schema 消费;不做任何页面交互。
5
+ *
6
+ * 辑律(ADR-12 同款边界):抽取只认结构(行首 role 与缩进),不做开放式语义猜测;
7
+ * 页面文本是不可信输入(RFC §3.5)——本层只归形状,语义判定在上游 schema 处。
8
+ */
9
+
10
+ export interface A11yEntry {
11
+ /** 行首 role,如 button / textbox / link / heading / listitem */
12
+ role: string
13
+ /** 括号内 accessible name(去引号,截断 200) */
14
+ name: string
15
+ /** 快照行号(0 基,回指原快照) */
16
+ line: number
17
+ }
18
+
19
+ /**
20
+ * Playwright aria snapshot 行形如:
21
+ * `- button "搜索" [ref=s1e5]`
22
+ * `- heading "上海到丽江" [level=1]`
23
+ * 提取 role/name;无 name 的行(name='')保留占位(计数/结构比对仍可用)。
24
+ */
25
+ export function extractA11yEntries(snapshotText: string, opts: { maxEntries?: number } = {}): A11yEntry[] {
26
+ const cap = opts.maxEntries ?? 500
27
+ const out: A11yEntry[] = []
28
+ const lines = snapshotText.split('\n')
29
+ for (let i = 0; i < lines.length && out.length < cap; i++) {
30
+ const m = /^[\s*-]*\s*([a-zA-Z][\w-]*)(?:\s+"((?:[^"\\]|\\.)*)")?/.exec(lines[i] ?? '')
31
+ if (!m) continue
32
+ const name = (m[2] ?? '').replace(/\\"/g, '"').slice(0, 200)
33
+ out.push({ role: m[1]!.toLowerCase(), name, line: i })
34
+ }
35
+ return out
36
+ }
37
+
38
+ /** DOM 提交件过滤入口(RFC §3.3-②):从条目集中剔除命中提交黑名单的可交互件,返回保留集 */
39
+ export function filterSubmitEntries<T extends { role: string; name: string }>(entries: T[], isSubmit: (name: string) => boolean): T[] {
40
+ const interactive = new Set(['button', 'link', 'menuitem', 'option'])
41
+ return entries.filter((e) => !(interactive.has(e.role) && isSubmit(e.name)))
42
+ }
43
+
44
+ /** 名称相似度粗筛(自愈定位的候选排序底座;0=不同串,1=包含) */
45
+ export function nameAffinity(a: string, b: string): number {
46
+ const x = a.trim(); const y = b.trim()
47
+ if (!x || !y) return 0
48
+ if (x === y) return 1
49
+ if (x.includes(y) || y.includes(x)) return 0.8
50
+ const sa = new Set(x); const sb = new Set(y)
51
+ let common = 0
52
+ for (const ch of sa) if (sb.has(ch)) common += 1
53
+ return common / Math.max(sa.size, sb.size)
54
+ }
@@ -0,0 +1,139 @@
1
+ import {
2
+ SESSION_FIELD_ACCURACY_THRESHOLD,
3
+ type SessionComparableRecord,
4
+ } from './benchmark.ts'
5
+
6
+ export interface GoldenBand {
7
+ query_id: string
8
+ from: string
9
+ to: string
10
+ date: string
11
+ window_dep_local: { earliest: string; latest: string }
12
+ window_arr_local: { earliest: string; latest: string }
13
+ duration_min: { min: number; max: number }
14
+ price_cny: { min: number; max: number }
15
+ transport_hint: string
16
+ known_flights: string[]
17
+ }
18
+
19
+ export interface GoldenSoftScore {
20
+ pass: boolean
21
+ total: number
22
+ correct: number
23
+ accuracy: number
24
+ missing: string[]
25
+ incorrect: string[]
26
+ golden_source: string
27
+ }
28
+
29
+ function parseHHmm(value: string): number {
30
+ const [hours, minutes] = value.split(':')
31
+ return parseInt(hours!, 10) * 60 + parseInt(minutes!, 10)
32
+ }
33
+
34
+ function parseLocalMinutes(value: string): number | null {
35
+ const match = value.match(/(\d{2}):(\d{2})/)
36
+ if (!match) return null
37
+ return parseInt(match[1]!, 10) * 60 + parseInt(match[2]!, 10)
38
+ }
39
+
40
+ function parseLocalDate(value: string): string | null {
41
+ return value.match(/^(\d{4}-\d{2}-\d{2})[T ]/)?.[1] ?? null
42
+ }
43
+
44
+ export function scoreSessionAgainstGoldenBand(
45
+ session: SessionComparableRecord,
46
+ band: GoldenBand,
47
+ goldenSource: string,
48
+ ): GoldenSoftScore {
49
+ const missing: string[] = []
50
+ const hardIncorrect: string[] = []
51
+ const segment = session.route_segments[0]
52
+
53
+ if (!session.query_id) missing.push('query_id')
54
+ else if (session.query_id !== band.query_id) hardIncorrect.push('query_id')
55
+ if (!session.currency) missing.push('currency')
56
+ else if (session.currency !== 'CNY') hardIncorrect.push('currency')
57
+ if (!session.source) missing.push('source')
58
+ else if (session.source !== 'ctrip-flight') hardIncorrect.push('source')
59
+ if (!session.verdict) missing.push('verdict')
60
+ else if (session.verdict !== 'hit') hardIncorrect.push('verdict')
61
+
62
+ if (!segment) {
63
+ missing.push(
64
+ 'route_segments[0].from',
65
+ 'route_segments[0].to',
66
+ 'route_segments[0].departure_at',
67
+ 'route_segments[0].arrival_at',
68
+ 'route_segments[0].transport_number',
69
+ )
70
+ } else {
71
+ if (!segment.from) missing.push('route_segments[0].from')
72
+ else if (segment.from !== band.from) hardIncorrect.push('route_segments[0].from')
73
+ if (!segment.to) missing.push('route_segments[0].to')
74
+ else if (segment.to !== band.to) hardIncorrect.push('route_segments[0].to')
75
+ if (!segment.departure_at) missing.push('route_segments[0].departure_at')
76
+ else if (parseLocalDate(segment.departure_at) !== band.date) {
77
+ hardIncorrect.push('route_segments[0].departure_at.date')
78
+ }
79
+ if (!segment.arrival_at) missing.push('route_segments[0].arrival_at')
80
+ else if (parseLocalDate(segment.arrival_at) !== band.date) {
81
+ hardIncorrect.push('route_segments[0].arrival_at.date')
82
+ }
83
+ if (!segment.transport_number) missing.push('route_segments[0].transport_number')
84
+ }
85
+
86
+ const softChecks: Array<{ path: string; ok: boolean }> = []
87
+ if (segment?.departure_at) {
88
+ const minutes = parseLocalMinutes(segment.departure_at)
89
+ softChecks.push({
90
+ path: 'route_segments[0].departure_at',
91
+ ok: minutes !== null
92
+ && minutes >= parseHHmm(band.window_dep_local.earliest)
93
+ && minutes <= parseHHmm(band.window_dep_local.latest),
94
+ })
95
+ }
96
+ if (segment?.arrival_at) {
97
+ const minutes = parseLocalMinutes(segment.arrival_at)
98
+ softChecks.push({
99
+ path: 'route_segments[0].arrival_at',
100
+ ok: minutes !== null
101
+ && minutes >= parseHHmm(band.window_arr_local.earliest)
102
+ && minutes <= parseHHmm(band.window_arr_local.latest),
103
+ })
104
+ }
105
+ if (segment?.transport_number) {
106
+ const actual = segment.transport_number.toUpperCase()
107
+ softChecks.push({
108
+ path: 'route_segments[0].transport_number',
109
+ ok: band.known_flights.some((flight) => actual.startsWith(flight.toUpperCase()))
110
+ || band.known_flights.some((flight) => actual.includes(flight.toUpperCase().slice(0, 2))),
111
+ })
112
+ }
113
+ if (Number.isFinite(session.price) && session.price > 0) {
114
+ const margin = band.price_cny.max * 0.15
115
+ softChecks.push({
116
+ path: 'price',
117
+ ok: session.price >= band.price_cny.min - margin
118
+ && session.price <= band.price_cny.max + margin,
119
+ })
120
+ } else missing.push('price')
121
+
122
+ const softIncorrect = softChecks.filter((check) => !check.ok).map((check) => check.path)
123
+ const incorrect = [...hardIncorrect, ...softIncorrect]
124
+ // 合同字段固定为 13,缺字段不能靠缩小分母抬高准确率。
125
+ const total = 13
126
+ const correct = Math.max(0, total - new Set(missing).size - incorrect.length)
127
+ const accuracy = total > 0 ? correct / total : 0
128
+ return {
129
+ pass: missing.length === 0
130
+ && hardIncorrect.length === 0
131
+ && accuracy >= SESSION_FIELD_ACCURACY_THRESHOLD,
132
+ total,
133
+ correct,
134
+ accuracy,
135
+ missing: Array.from(new Set(missing)),
136
+ incorrect,
137
+ golden_source: goldenSource,
138
+ }
139
+ }