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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (327) hide show
  1. package/README.md +102 -194
  2. package/README.zh-CN.md +115 -210
  3. package/bin/gotry-backend.js +53 -0
  4. package/bin/gotry-bootstrap.js +466 -35
  5. package/bin/gotry-inner.js +255 -36
  6. package/bin/gotry-process-liveness.d.ts +27 -0
  7. package/bin/gotry-process-liveness.js +97 -0
  8. package/bin/gotry-runtime-resolution.d.ts +1 -1
  9. package/bin/gotry-runtime-resolution.js +2 -2
  10. package/client/client.js +174 -0
  11. package/cordis.gotry-patch.yml +70 -93
  12. package/dist/capabilities/agent-reach-deep.js +45 -122
  13. package/dist/capabilities/agent-reach.js +63 -148
  14. package/dist/capabilities/anything.js +89 -75
  15. package/dist/capabilities/artifacts.js +123 -104
  16. package/dist/capabilities/channel-health.js +65 -45
  17. package/dist/capabilities/channel-registry.js +108 -87
  18. package/dist/capabilities/doctor.js +357 -235
  19. package/dist/capabilities/effect.js +223 -309
  20. package/dist/capabilities/fact-log.js +28 -14
  21. package/dist/capabilities/flyai.js +245 -156
  22. package/dist/capabilities/ground-transfer.js +509 -0
  23. package/dist/capabilities/hbcli.js +144 -148
  24. package/dist/capabilities/hotelbyte-transaction.js +194 -0
  25. package/dist/capabilities/incident-log.js +131 -61
  26. package/dist/capabilities/model-override.js +30 -10
  27. package/dist/capabilities/opensky.js +54 -43
  28. package/dist/capabilities/resilience.js +50 -32
  29. package/dist/capabilities/session/action-cache.js +50 -44
  30. package/dist/capabilities/session/adapters/ctrip-flight.js +119 -62
  31. package/dist/capabilities/session/adapters/ctrip-hotel.js +125 -110
  32. package/dist/capabilities/session/adapters/dida-portal.js +206 -0
  33. package/dist/capabilities/session/adapters/meituan-local.js +35 -54
  34. package/dist/capabilities/session/adapters/rail-12306.js +169 -112
  35. package/dist/capabilities/session/benchmark.js +85 -149
  36. package/dist/capabilities/session/extension-bridge.js +320 -259
  37. package/dist/capabilities/session/extension-channel.js +57 -76
  38. package/dist/capabilities/session/extension-distribution.js +115 -119
  39. package/dist/capabilities/session/extract.js +31 -21
  40. package/dist/capabilities/session/golden-score.js +55 -33
  41. package/dist/capabilities/session/health-watch.js +146 -154
  42. package/dist/capabilities/session/read-guard.js +55 -47
  43. package/dist/capabilities/session/static-flight-golden.js +49 -36
  44. package/dist/capabilities/session/transport.js +54 -61
  45. package/dist/capabilities/session/wizard.js +63 -93
  46. package/dist/capabilities/session-consent.js +143 -47
  47. package/dist/capabilities/session-login.js +95 -126
  48. package/dist/capabilities/session-search.js +391 -253
  49. package/dist/capabilities/sponsor-plugin.js +341 -0
  50. package/dist/capabilities/visa-policy.js +87 -73
  51. package/dist/capabilities/weather.js +163 -235
  52. package/dist/scripts/action-cache-tests.js +24 -59
  53. package/dist/scripts/agent-planning-turn-deadline-e2e.js +91 -142
  54. package/dist/scripts/agent-planning-turn-deadline-tests.js +80 -176
  55. package/dist/scripts/agent-reach-deep-tests.js +30 -40
  56. package/dist/scripts/agent-reach-tests.js +26 -18
  57. package/dist/scripts/agent-reach-wrapper-tests.js +46 -50
  58. package/dist/scripts/anything-tests.js +58 -62
  59. package/dist/scripts/artifact-client-contract-tests.js +69 -0
  60. package/dist/scripts/artifacts-capability-tests.js +235 -0
  61. package/dist/scripts/async-collect.js +26 -15
  62. package/dist/scripts/benchmark-environment-bridge-e2e.js +287 -684
  63. package/dist/scripts/benchmark-environment-bridge-tests.js +818 -3123
  64. package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +66 -279
  65. package/dist/scripts/booking-copilot-availability-policy-tests.js +153 -1257
  66. package/dist/scripts/booking-copilot-bin-proof-tests.js +22 -45
  67. package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +64 -76
  68. package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +69 -199
  69. package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +393 -759
  70. package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +33 -75
  71. package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +60 -110
  72. package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +28 -66
  73. package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +72 -271
  74. package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +73 -275
  75. package/dist/scripts/booking-copilot-runtime-proof-tests.js +784 -3398
  76. package/dist/scripts/booking-copilot-server-proof-tests.js +63 -168
  77. package/dist/scripts/booking-copilot-startup-proof-tests.js +38 -124
  78. package/dist/scripts/booking-executor-tests.js +80 -0
  79. package/dist/scripts/booking-recovery-chain-tests.js +182 -0
  80. package/dist/scripts/booking-saga-tests.js +61 -123
  81. package/dist/scripts/booking-surface-contract-proof-tests.js +152 -1167
  82. package/dist/scripts/bootstrap-tests.js +1383 -128
  83. package/dist/scripts/build-changelog.js +89 -130
  84. package/dist/scripts/build-metrics-report.js +135 -143
  85. package/dist/scripts/changelog-tests.js +35 -82
  86. package/dist/scripts/channel-probe-tests.js +44 -116
  87. package/dist/scripts/channel-probe.js +84 -167
  88. package/dist/scripts/channel-registry-tests.js +97 -185
  89. package/dist/scripts/companion-tests.js +25 -70
  90. package/dist/scripts/dida-cookie-probe.js +87 -0
  91. package/dist/scripts/dida-sw-probe.js +114 -0
  92. package/dist/scripts/diff-test.js +17 -12
  93. package/dist/scripts/doctor-tests.js +428 -120
  94. package/dist/scripts/dsh-artifact-e2e.js +150 -0
  95. package/dist/scripts/dsh-artifact-web-e2e.js +443 -0
  96. package/dist/scripts/dsh-http-proxy-sse-proof.js +90 -0
  97. package/dist/scripts/dsh-runtime-closure-tests.js +110 -153
  98. package/dist/scripts/dsh-runtime-closure.js +75 -63
  99. package/dist/scripts/dsh-session-v3-migration-proof.js +106 -0
  100. package/dist/scripts/dsh-subprocess-local-proof.js +149 -0
  101. package/dist/scripts/dsh-target-closure-proof.js +178 -0
  102. package/dist/scripts/effect-tests.js +165 -552
  103. package/dist/scripts/engine-run.js +1 -3
  104. package/dist/scripts/engine-tests.js +16 -10
  105. package/dist/scripts/evaluation-cadence-tests.js +69 -242
  106. package/dist/scripts/evaluation-contract-tests.js +193 -499
  107. package/dist/scripts/extension-distribution-cli.js +19 -15
  108. package/dist/scripts/extension-distribution-tests.js +98 -211
  109. package/dist/scripts/extension-tests.js +366 -389
  110. package/dist/scripts/fact-gate-tests.js +725 -263
  111. package/dist/scripts/fixtures/extension-bridge-unref-child.mjs +21 -0
  112. package/dist/scripts/flight-hotel-anchor-363-registered-e2e.js +169 -0
  113. package/dist/scripts/flight-malformed-tests.js +159 -0
  114. package/dist/scripts/flyai-tests.js +325 -68
  115. package/dist/scripts/g5-guard-tests.js +131 -0
  116. package/dist/scripts/g5-guard.js +189 -0
  117. package/dist/scripts/gen-lunar-anchors.js +106 -0
  118. package/dist/scripts/gotry-backend-kernel-tests.js +79 -0
  119. package/dist/scripts/ground-transfer-tests.js +956 -0
  120. package/dist/scripts/hbcli-e2e-tests.js +71 -90
  121. package/dist/scripts/hbcli-live-optin-tests.js +96 -0
  122. package/dist/scripts/hbcli-release-contract-tests.js +122 -0
  123. package/dist/scripts/hbcli-tests.js +41 -115
  124. package/dist/scripts/health-watch-cli.js +42 -28
  125. package/dist/scripts/hotel-date-gate-tests.js +496 -0
  126. package/dist/scripts/hotelbyte-reconcile-tests.js +141 -0
  127. package/dist/scripts/hotelbyte-spawn-e2e-tests.js +373 -0
  128. package/dist/scripts/i18n-tests.js +16 -9
  129. package/dist/scripts/incident-tests.js +281 -87
  130. package/dist/scripts/issue-194-job-id-guard-tests.js +106 -0
  131. package/dist/scripts/issue-233-cancel-refund-commission-tests.js +392 -0
  132. package/dist/scripts/issue-271-liveness-tests.js +547 -0
  133. package/dist/scripts/issue-289-model-retry-real-tests.js +296 -0
  134. package/dist/scripts/issue-289-model-retry-tests.js +441 -0
  135. package/dist/scripts/issue-289-web-retry-e2e.js +630 -0
  136. package/dist/scripts/issue-338-home-city-e2e.js +577 -0
  137. package/dist/scripts/issue343-real-entry-e2e.js +160 -0
  138. package/dist/scripts/journey-tests.js +22 -27
  139. package/dist/scripts/kernel-manifest-evidence.js +109 -0
  140. package/dist/scripts/kernel-manifest-gate.js +126 -0
  141. package/dist/scripts/kernel-manifest-tests.js +212 -0
  142. package/dist/scripts/kernel-manifest-trace-entry.js +7 -0
  143. package/dist/scripts/kernel-manifest-trace-hook.mjs +28 -0
  144. package/dist/scripts/kernel-manifest.js +369 -0
  145. package/dist/scripts/ledger-repair-apply-tests.js +316 -0
  146. package/dist/scripts/ledger-repair-plan-tests.js +375 -0
  147. package/dist/scripts/ledger-tests.js +325 -340
  148. package/dist/scripts/ledger-workflow-crash.js +10 -20
  149. package/dist/scripts/map-tools-vendor-package-proof.js +206 -134
  150. package/dist/scripts/memory-capture-tests.js +242 -61
  151. package/dist/scripts/memory-decay-tests.js +18 -52
  152. package/dist/scripts/memory-lifecycle-tests.js +657 -0
  153. package/dist/scripts/memory-lifecycle.js +196 -0
  154. package/dist/scripts/memory-metrics.js +24 -12
  155. package/dist/scripts/memory-value-report.js +474 -222
  156. package/dist/scripts/memory-value-tests.js +328 -0
  157. package/dist/scripts/metrics-report-tests.js +62 -199
  158. package/dist/scripts/model-override-e2e.js +66 -105
  159. package/dist/scripts/nightly-evidence-tests.js +64 -89
  160. package/dist/scripts/nightly-evidence.js +108 -111
  161. package/dist/scripts/nudge-digest.js +39 -28
  162. package/dist/scripts/onboarding-tests.js +63 -88
  163. package/dist/scripts/opensky-check.js +18 -13
  164. package/dist/scripts/opensky-tests.js +28 -28
  165. package/dist/scripts/persona-surface-guard-tests.js +37 -12
  166. package/dist/scripts/pnpm-dsh-closure-proof.js +2 -5
  167. package/dist/scripts/policy-anchor-359-registered-e2e.js +214 -0
  168. package/dist/scripts/price-drift-tests.js +126 -227
  169. package/dist/scripts/price-drift-watch.js +209 -253
  170. package/dist/scripts/probe-poi-tests.js +52 -45
  171. package/dist/scripts/product-metrics.js +187 -273
  172. package/dist/scripts/publish-preverify.js +47 -41
  173. package/dist/scripts/realtime-pricing-tests.js +37 -76
  174. package/dist/scripts/replay-async.js +20 -18
  175. package/dist/scripts/replay-real.js +16 -18
  176. package/dist/scripts/replay.js +52 -82
  177. package/dist/scripts/session-attach-diagnose.js +16 -12
  178. package/dist/scripts/session-attach-poc.js +34 -37
  179. package/dist/scripts/session-benchmark.js +66 -147
  180. package/dist/scripts/session-dida-live-e2e.js +151 -0
  181. package/dist/scripts/session-extract-tests.js +14 -35
  182. package/dist/scripts/session-login.js +14 -13
  183. package/dist/scripts/session-tests.js +545 -583
  184. package/dist/scripts/sf-live-benchmark.js +92 -110
  185. package/dist/scripts/sf-live-cli-tests.js +2 -9
  186. package/dist/scripts/sf-soft-score-tests.js +19 -60
  187. package/dist/scripts/sf-summary-tests.js +149 -0
  188. package/dist/scripts/sf-summary.js +466 -84
  189. package/dist/scripts/skeleton-check.js +16 -14
  190. package/dist/scripts/skeleton-integration-test.js +11 -10
  191. package/dist/scripts/skills-contract-tests.js +51 -46
  192. package/dist/scripts/smoke-session-gate-tests.js +12 -20
  193. package/dist/scripts/smoke.js +541 -422
  194. package/dist/scripts/sponsor-reuse-tests.js +262 -0
  195. package/dist/scripts/state-cli-tests.js +226 -101
  196. package/dist/scripts/state-cli.js +549 -212
  197. package/dist/scripts/static-golden-tests.js +46 -180
  198. package/dist/scripts/time-eval-tests.js +210 -192
  199. package/dist/scripts/travel-timeline-tests.js +29 -93
  200. package/dist/scripts/turn-handoff-collect-tests.js +46 -93
  201. package/dist/scripts/turn-handoff-collect.js +71 -99
  202. package/dist/scripts/turn-policy-tests.js +28 -29
  203. package/dist/scripts/typed-contract-canary.js +77 -162
  204. package/dist/scripts/tz-resolver-sanity.js +50 -0
  205. package/dist/scripts/tz-resolver-tests.js +584 -0
  206. package/dist/scripts/unified-tests.js +23 -19
  207. package/dist/scripts/visa-policy-tests.js +31 -44
  208. package/dist/scripts/weather-tests.js +121 -543
  209. package/dist/scripts/wish-channel-gate-tests.js +29 -86
  210. package/dist/scripts/write-gate-tests.js +522 -0
  211. package/dist/scripts/z3-lifecycle-fault-tests.js +188 -0
  212. package/dist/scripts/z3-lifecycle-tests.js +170 -0
  213. package/dist/scripts/z3-race-repeat-tests.js +39 -0
  214. package/dist/scripts/z3-race-tests.js +18 -12
  215. package/dist/src/artifact-gate.js +652 -221
  216. package/dist/src/backend/kernel.js +91 -0
  217. package/dist/src/backend/modules/booking-copilot.js +55 -0
  218. package/dist/src/backend/modules/booking-executor.js +124 -0
  219. package/dist/src/backend/modules/session-search.js +194 -0
  220. package/dist/src/benchmark-agent-conformance.js +296 -262
  221. package/dist/src/benchmark-environment-bridge.js +298 -413
  222. package/dist/src/benchmark-headless-child-diagnostics.js +93 -100
  223. package/dist/src/benchmark-tool-isolation.js +94 -67
  224. package/dist/src/bookable-facts.js +299 -174
  225. package/dist/src/booking-saga.js +64 -120
  226. package/dist/src/booking-surface/availability-policy.js +443 -576
  227. package/dist/src/booking-surface/cancel-refund-commission.js +379 -0
  228. package/dist/src/booking-surface/contracts.js +24 -80
  229. package/dist/src/booking-surface/dsh-planner.js +510 -281
  230. package/dist/src/booking-surface/dsh-plugin.js +17 -1
  231. package/dist/src/booking-surface/error-codes.js +82 -10
  232. package/dist/src/booking-surface/index.js +0 -3
  233. package/dist/src/booking-surface/profile.js +10 -54
  234. package/dist/src/booking-surface/recovery-chain.js +367 -0
  235. package/dist/src/booking-surface/runtime.js +765 -891
  236. package/dist/src/booking-surface/server.js +200 -251
  237. package/dist/src/booking-surface/startup.js +58 -54
  238. package/dist/src/booking-surface/validation.js +150 -218
  239. package/dist/src/bridge.js +20 -13
  240. package/dist/src/companions.js +48 -74
  241. package/dist/src/contracts.js +21 -43
  242. package/dist/src/dsh-llm.js +82 -120
  243. package/dist/src/engine.js +253 -239
  244. package/dist/src/evaluation-cadence.js +72 -209
  245. package/dist/src/evaluation-contracts.js +220 -843
  246. package/dist/src/flight-pack-adapter.js +54 -0
  247. package/dist/src/flight-pack-contract.js +2 -0
  248. package/dist/src/gotry-backend.js +70 -0
  249. package/dist/src/hotel-date-gate.js +118 -0
  250. package/dist/src/i18n.js +18 -7
  251. package/dist/src/index.js +1425 -1629
  252. package/dist/src/journey.js +132 -81
  253. package/dist/src/ledger-repair-apply.js +538 -0
  254. package/dist/src/ledger-repair-plan.js +463 -0
  255. package/dist/src/loop.js +257 -166
  256. package/dist/src/memory-capture.js +180 -32
  257. package/dist/src/memory-decay.js +30 -14
  258. package/dist/src/memory-lifecycle.js +1310 -0
  259. package/dist/src/memory-utility.js +27 -40
  260. package/dist/src/mock-llm.js +36 -61
  261. package/dist/src/model.js +81 -36
  262. package/dist/src/realtime-pricing.js +63 -72
  263. package/dist/src/slot-spec.js +84 -106
  264. package/dist/src/state-ledger.js +310 -471
  265. package/dist/src/subagent-job-id-guard.js +58 -0
  266. package/dist/src/time-anchor.js +231 -33
  267. package/dist/src/tool-packet.js +20 -8
  268. package/dist/src/travel-slots.js +58 -35
  269. package/dist/src/travel-timeline.js +44 -63
  270. package/dist/src/turn-deadline.js +121 -127
  271. package/dist/src/turn-policy.js +61 -89
  272. package/dist/src/tz-resolver.js +143 -0
  273. package/dist/src/unified.js +504 -381
  274. package/dist/src/wish-pool.js +39 -14
  275. package/dist/src/write-gate.js +495 -0
  276. package/dist/src/z3-shared.js +273 -7
  277. package/extension/README.md +4 -3
  278. package/extension/background.js +125 -14
  279. package/extension/content-bridge.js +23 -1
  280. package/extension/content-main.js +15 -4
  281. package/extension/manifest.json +16 -8
  282. package/package.json +251 -220
  283. package/ts/capabilities/agent-reach.ts +4 -4
  284. package/ts/capabilities/anything.ts +1 -1
  285. package/ts/capabilities/artifacts.ts +46 -9
  286. package/ts/capabilities/flyai.ts +156 -37
  287. package/ts/capabilities/hbcli.ts +1 -1
  288. package/ts/capabilities/incident-log.ts +88 -59
  289. package/ts/capabilities/session/adapters/ctrip-flight.ts +99 -36
  290. package/ts/capabilities/session/adapters/dida-portal.ts +250 -0
  291. package/ts/capabilities/session/adapters/rail-12306.ts +123 -24
  292. package/ts/capabilities/session/extension-bridge.ts +226 -101
  293. package/ts/capabilities/session/extension-channel.ts +22 -9
  294. package/ts/capabilities/session/wizard.ts +2 -2
  295. package/ts/capabilities/session-consent.ts +98 -14
  296. package/ts/capabilities/session-login.ts +1 -0
  297. package/ts/capabilities/session-search.ts +315 -31
  298. package/ts/dsh-runtime/vendor/README.md +8 -4
  299. package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +7 -1
  300. package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +5 -3
  301. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +1 -1
  302. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +1 -1
  303. package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +6 -6
  304. package/ts/package.json +236 -16
  305. package/ts/scripts/map-tools-vendor-package-proof.ts +152 -31
  306. package/ts/scripts/state-cli.ts +418 -51
  307. package/ts/src/artifact-gate.ts +561 -15
  308. package/ts/src/benchmark-environment-bridge.ts +37 -20
  309. package/ts/src/bookable-facts.ts +183 -7
  310. package/ts/src/booking-surface/cancel-refund-commission.ts +488 -0
  311. package/ts/src/booking-surface/dsh-planner.ts +240 -32
  312. package/ts/src/booking-surface/dsh-plugin.js +17 -1
  313. package/ts/src/booking-surface/error-codes.ts +75 -0
  314. package/ts/src/booking-surface/recovery-chain.ts +409 -0
  315. package/ts/src/booking-surface/server.ts +84 -51
  316. package/ts/src/booking-surface/validation.ts +2 -0
  317. package/ts/src/contracts.ts +12 -2
  318. package/ts/src/dsh-llm.ts +4 -8
  319. package/ts/src/index.ts +609 -90
  320. package/ts/src/loop.ts +116 -7
  321. package/ts/src/memory-capture.ts +227 -3
  322. package/ts/src/mock-llm.ts +4 -8
  323. package/ts/src/model.ts +88 -2
  324. package/ts/src/state-ledger.ts +47 -29
  325. package/ts/src/subagent-job-id-guard.ts +72 -0
  326. package/ts/src/time-anchor.ts +217 -13
  327. package/ts/src/unified.ts +316 -54
@@ -1,23 +1,28 @@
1
+ /**
2
+ * action-cache 本地自愈层(RFC docs/rfc/user-session-data-rfc.md §3.2 / §2.3;Stagehand 云端缓存的本地化):
3
+ *
4
+ * 目的:会话检索的查询模式高度重复(同站点同类型搜索),首跑用 LLM/规则定位,后续走
5
+ * 缓存的确定性载荷零成本重放;站点改版 → DOM 指纹失配 → miss → 重新定位并回写。
6
+ *
7
+ * 设计原则(Stagehand「错误的缓存点击比慢更糟」的被动失效):
8
+ * - key = site + action + 参数模板(%from%/%to%/%date% 变量化,同型查询共享条目);
9
+ * - 每条目绑 domFingerprint(快照/接口形状的 sha256 指纹);lookup 时现场指纹与条目不符 = miss(即使 key 命中);
10
+ * - miss 即回写(记录新定位),过期(默认 48h)与容量(每 site 默认 50 条,LRU)被动淘汰;
11
+ * - 纯函数 + JSON 文件持久化(隔离 stateRoot;损坏文件按空缓存处理,永不抛错)。
12
+ *
13
+ * P2 切片:模块+确定性测试先行;消费方(P2 美团适配器/a11y 兜底)下一切片接线。
14
+ */
1
15
  import { createHash } from 'node:crypto';
2
- import { mkdirSync, readFileSync, writeFileSync, existsSync, rmSync } from 'node:fs';
16
+ import { mkdirSync, readFileSync, writeFileSync, existsSync } from 'node:fs';
3
17
  import { dirname, join } from 'node:path';
18
+ /** 把具体查询参数变量化为模板 key:日期→%date%,from/to 语义序在前,其余参数按字典序尾随 */
4
19
  export function templateKey(site, action, params) {
5
- const val = (k)=>k === 'date' ? '%date%' : (params[k] ?? '').trim();
6
- const head = [
7
- 'from',
8
- 'to',
9
- 'date'
10
- ].filter((k)=>k in params).map(val);
11
- const tail = Object.keys(params).filter((k)=>![
12
- 'from',
13
- 'to',
14
- 'date'
15
- ].includes(k)).sort().map(val);
16
- return `${site}:${action}:${[
17
- ...head,
18
- ...tail
19
- ].join('|')}`;
20
+ const val = (k) => (k === 'date' ? '%date%' : (params[k] ?? '').trim());
21
+ const head = ['from', 'to', 'date'].filter((k) => k in params).map(val);
22
+ const tail = Object.keys(params).filter((k) => !['from', 'to', 'date'].includes(k)).sort().map(val);
23
+ return `${site}:${action}:${[...head, ...tail].join('|')}`;
20
24
  }
25
+ /** 指纹:快照/接口形状文本 → sha256 前 16 位(微改版即失配——宁可 miss 不可错点) */
21
26
  export function fingerprint(shapeText) {
22
27
  return createHash('sha256').update(shapeText).digest('hex').slice(0, 16);
23
28
  }
@@ -28,76 +33,79 @@ export class ActionCache {
28
33
  ttlMs;
29
34
  maxPerSite;
30
35
  now;
31
- constructor(filePath, opts = {}){
36
+ constructor(filePath, opts = {}) {
32
37
  this.filePath = filePath;
33
38
  this.ttlMs = opts.ttlMs ?? 48 * 3600_000;
34
39
  this.maxPerSite = opts.maxEntriesPerSite ?? 50;
35
- this.now = opts.now ?? (()=>new Date());
40
+ this.now = opts.now ?? (() => new Date());
36
41
  }
37
42
  load() {
38
- if (this.loaded) return;
43
+ if (this.loaded)
44
+ return;
39
45
  this.loaded = true;
40
46
  try {
41
47
  if (existsSync(this.filePath)) {
42
48
  const raw = JSON.parse(readFileSync(this.filePath, 'utf8'));
43
- for (const e of raw){
44
- if (e?.key && e.domFingerprint && e.locator) this.entries.set(e.key, e);
49
+ for (const e of raw) {
50
+ if (e?.key && e.domFingerprint && e.locator)
51
+ this.entries.set(e.key, e);
45
52
  }
46
53
  }
47
- } catch {}
54
+ }
55
+ catch { /* 损坏文件按空缓存处理 */ }
48
56
  }
49
57
  persist() {
50
58
  try {
51
- mkdirSync(dirname(this.filePath), {
52
- recursive: true
53
- });
59
+ mkdirSync(dirname(this.filePath), { recursive: true });
54
60
  const tmp = this.filePath + '.tmp';
55
- writeFileSync(tmp, JSON.stringify([
56
- ...this.entries.values()
57
- ], null, 0), 'utf8');
61
+ writeFileSync(tmp, JSON.stringify([...this.entries.values()], null, 0), 'utf8');
58
62
  writeFileSync(this.filePath, readFileSync(tmp, 'utf8'), 'utf8');
59
63
  try {
60
64
  require('node:fs').rmSync(tmp);
61
- } catch {}
62
- } catch {}
65
+ }
66
+ catch { /* best effort */ }
67
+ }
68
+ catch { /* 持久化失败不阻塞内存路径 */ }
63
69
  }
70
+ /** 站点前缀条目数(LRU 淘汰用) */
64
71
  siteEntries(site) {
65
- return [
66
- ...this.entries.values()
67
- ].filter((e)=>e.key.startsWith(site + ':'));
72
+ return [...this.entries.values()].filter((e) => e.key.startsWith(site + ':'));
68
73
  }
74
+ /** 命中三条件:key 存在 + 未过期 + 指纹一致;命中计 hits 并惰性落盘 */
69
75
  lookup(key, domFingerprint, site) {
70
76
  this.load();
71
77
  const e = this.entries.get(key);
72
- if (!e) return null;
78
+ if (!e)
79
+ return null;
73
80
  if (this.now().getTime() - Date.parse(e.lastHitAt || e.createdAt) > this.ttlMs) {
74
81
  this.entries.delete(key);
75
82
  this.persist();
76
83
  return null;
77
84
  }
78
- if (e.domFingerprint !== domFingerprint) return null;
85
+ if (e.domFingerprint !== domFingerprint)
86
+ return null; // 改版:被动失效,等 record 回写
79
87
  e.hits += 1;
80
88
  e.lastHitAt = this.now().toISOString();
81
89
  this.persist();
82
90
  void site;
83
91
  return e;
84
92
  }
93
+ /** miss 后回写(重新定位的产物);同 key 覆盖;超容 LRU 淘汰最旧 */
85
94
  record(key, domFingerprint, locator, site) {
86
95
  this.load();
87
96
  const ts = this.now().toISOString();
88
97
  const prev = this.entries.get(key);
89
98
  this.entries.set(key, {
90
- key,
91
- domFingerprint,
92
- locator,
99
+ key, domFingerprint, locator,
93
100
  createdAt: prev?.createdAt ?? ts,
94
101
  lastHitAt: ts,
95
- hits: prev?.hits ?? 0
102
+ hits: prev?.hits ?? 0,
96
103
  });
97
104
  const siteList = this.siteEntries(site);
98
105
  if (siteList.length > this.maxPerSite) {
99
- const victim = siteList.sort((a, b)=>Date.parse(a.lastHitAt) - Date.parse(b.lastHitAt))[0];
100
- if (victim) this.entries.delete(victim.key);
106
+ const victim = siteList.sort((a, b) => Date.parse(a.lastHitAt) - Date.parse(b.lastHitAt))[0];
107
+ if (victim)
108
+ this.entries.delete(victim.key);
101
109
  }
102
110
  this.persist();
103
111
  return this.entries.get(key);
@@ -112,9 +120,7 @@ export class ActionCache {
112
120
  return site ? this.siteEntries(site).length : this.entries.size;
113
121
  }
114
122
  }
123
+ /** 便捷入口:隔离 stateRoot 下的缓存文件路径 */
115
124
  export function actionCachePath(stateRoot) {
116
125
  return join(stateRoot, 'session-action-cache.json');
117
126
  }
118
-
119
-
120
- //# sourceURL=ts/capabilities/session/action-cache.ts
@@ -1,83 +1,140 @@
1
+ /**
2
+ * 携程机票站点适配器(RFC §3.2 首个适配器;PoC 已识别接口面,data-sources.md §8):
3
+ * - entry:URL 参数直开(https://flights.ctrip.com/online/list/oneway-{from}-{to}?depdate=YYYY-MM-DD)
4
+ * - networkHints:主搜索接口 search/api/search/batchSearch(POST,~550KB,国内票同走)
5
+ * - 解析:flightItineraryList[].flightSegments[0].flightList[0] + priceList 最小 adultPrice
6
+ * (schema 实测 2026-08-28,见 data-sources.md §8)
7
+ * 只读:适配器不含任何提交/预订语义;URL 直开即零 DOM 交互。
8
+ */
9
+ /** 城市三字码表(小起步集;词表外 unresolved 逐字保留,不做开放式猜测——ADR-12 同款边界) */
1
10
  const CITY_CODES = {
2
- 上海: 'sha',
3
- 北京: 'bjs',
4
- 广州: 'can',
5
- 深圳: 'szx',
6
- 成都: 'ctu',
7
- 昆明: 'kmg',
8
- 大理: 'dlu',
9
- 丽江: 'ljg',
10
- 西安: 'sia',
11
- 杭州: 'hgh',
12
- 三亚: 'syx',
13
- 厦门: 'xmn',
14
- 重庆: 'cqg',
15
- 青岛: 'taa',
16
- 长沙: 'csx',
17
- 武汉: 'wuh',
18
- 南京: 'nkg',
19
- 郑州: 'cgo',
20
- 贵阳: 'kwe',
21
- 桂林: 'kwl',
22
- 西双版纳: 'jhg',
23
- 香格里拉: 'dig'
11
+ 上海: 'sha', 北京: 'bjs', 广州: 'can', 深圳: 'szx', 成都: 'ctu', 昆明: 'kmg',
12
+ 大理: 'dlu', 丽江: 'ljg', 西安: 'sia', 杭州: 'hgh', 三亚: 'syx', 厦门: 'xmn',
13
+ 重庆: 'cqg', 青岛: 'taa', 长沙: 'csx', 武汉: 'wuh', 南京: 'nkg', 郑州: 'cgo',
14
+ 贵阳: 'kwe', 桂林: 'kwl', 西双版纳: 'jhg', 香格里拉: 'dig',
24
15
  };
25
16
  export function buildEntryUrl(from, to, depDate) {
26
17
  const unresolved = [];
27
18
  const fromCode = CITY_CODES[from];
28
19
  const toCode = CITY_CODES[to];
29
- if (!fromCode) unresolved.push(from);
30
- if (!toCode) unresolved.push(to);
20
+ if (!fromCode)
21
+ unresolved.push(from);
22
+ if (!toCode)
23
+ unresolved.push(to);
31
24
  if (unresolved.length > 0 || !/^\d{4}-\d{2}-\d{2}$/.test(depDate)) {
32
- return {
33
- ok: false,
34
- unresolved: unresolved.length > 0 ? unresolved : [
35
- depDate
36
- ]
37
- };
25
+ return { ok: false, unresolved: unresolved.length > 0 ? unresolved : [depDate] };
38
26
  }
39
- return {
40
- ok: true,
41
- url: `https://flights.ctrip.com/online/list/oneway-${fromCode}-${toCode}?depdate=${depDate}`
42
- };
27
+ return { ok: true, url: `https://flights.ctrip.com/online/list/oneway-${fromCode}-${toCode}?depdate=${depDate}` };
43
28
  }
44
- export const NETWORK_HINTS = [
45
- /search\/api\/search\/batchSearch/
46
- ];
47
- export const LOGIN_COOKIE_NAMES = [
48
- 'cticket',
49
- 'uid',
50
- 'uname',
51
- 'passport'
52
- ];
29
+ /** networkHints:响应 URL 命中即视为搜索回包(对 UI 改版免疫,只怕接口改版) */
30
+ export const NETWORK_HINTS = [/search\/api\/search\/batchSearch/];
31
+ /**
32
+ * 登录态检测(用户自己的账号,不是匿名实例——founder 2026-08-28 纠偏):
33
+ * 任一登录票据 cookie 存在即视为已登录;名单基于公开常识,首个真登录后校准(D-13)。
34
+ */
35
+ export const LOGIN_COOKIE_NAMES = ['cticket', 'uid', 'uname', 'passport'];
53
36
  export const SITE_DOMAIN = '.ctrip.com';
37
+ /** 安全取字符串字段(任意来源字段都可能是 null/undefined/数字/对象) */
38
+ function asString(v) {
39
+ return typeof v === 'string' ? v : '';
40
+ }
41
+ /** 安全取正数(无法解析按 0 返,绝不伪造价格) */
42
+ function asPositiveNumber(v) {
43
+ return typeof v === 'number' && Number.isFinite(v) && v > 0 ? v : 0;
44
+ }
45
+ /** 解析 batchSearch 响应(纯函数,fixture 测试锚点);malformed 一律返空,不抛错 */
54
46
  export function parseBatchSearch(body) {
47
+ return parseBatchSearchResult(body).options;
48
+ }
49
+ /**
50
+ * 结构化解析(issue #279):返回选项 + 三态判语。
51
+ * - `hit` = 已识别合法结构 + 至少一个有效行程
52
+ * - `miss` = 已识别合法空(data.flightItineraryList 是空数组)
53
+ * - `error`= 形状未识别(JSON 解析失败 / 非对象根 / data 缺失或非对象 /
54
+ * flightItineraryList 不是数组 / 非空数组没有可用行程)——未知响应
55
+ * 不可静默收敛为 miss
56
+ * 绝不发明价格、航班号、机场、时刻;混合数组保留有效项,全畸形数组报 error。
57
+ */
58
+ export function parseBatchSearchResult(body) {
55
59
  let raw;
56
60
  try {
57
61
  raw = JSON.parse(body);
58
- } catch {
59
- return [];
62
+ }
63
+ catch {
64
+ return { options: [], verdict: 'error' };
65
+ }
66
+ if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) {
67
+ return { options: [], verdict: 'error' };
68
+ }
69
+ const data = raw.data;
70
+ if (data === null || typeof data !== 'object' || Array.isArray(data)) {
71
+ return { options: [], verdict: 'error' };
72
+ }
73
+ const list = raw.data.flightItineraryList;
74
+ if (!Array.isArray(list)) {
75
+ return { options: [], verdict: 'error' };
60
76
  }
61
77
  const out = [];
62
- for (const it of raw.data?.flightItineraryList ?? []){
63
- const seg = it.flightSegments?.[0];
64
- const fl = seg?.flightList?.[0];
65
- if (!fl?.flightNo || !fl.departureDateTime) continue;
66
- const prices = (it.priceList ?? []).map((p)=>Number(p.adultPrice ?? 0)).filter((n)=>n > 0);
78
+ for (const it of list) {
79
+ if (it === null || typeof it !== 'object' || Array.isArray(it))
80
+ continue;
81
+ const item = it;
82
+ const segs = item.flightSegments;
83
+ if (!Array.isArray(segs) || segs.length === 0)
84
+ continue;
85
+ const seg = segs[0];
86
+ if (seg === null || typeof seg !== 'object' || Array.isArray(seg))
87
+ continue;
88
+ const segObj = seg;
89
+ const fl = segObj.flightList;
90
+ if (!Array.isArray(fl) || fl.length === 0)
91
+ continue;
92
+ const flight = fl[0];
93
+ if (flight === null || typeof flight !== 'object' || Array.isArray(flight))
94
+ continue;
95
+ const f = flight;
96
+ if (typeof f.flightNo !== 'string' || !f.flightNo)
97
+ continue;
98
+ if (typeof f.departureDateTime !== 'string' || !f.departureDateTime)
99
+ continue;
100
+ // 缺 priceList 延续旧合同为「有航班、价格未知」;显式非数组与畸形价项
101
+ // 属未知响应,整项跳过。若响应里没有其他有效项,最终判 error 而非 miss。
102
+ if (item.priceList !== undefined && !Array.isArray(item.priceList))
103
+ continue;
104
+ const priceList = item.priceList ?? [];
105
+ const prices = [];
106
+ let malformedPrice = false;
107
+ for (const p of priceList) {
108
+ if (p === null || typeof p !== 'object' || Array.isArray(p)) {
109
+ malformedPrice = true;
110
+ break;
111
+ }
112
+ const adultPrice = p.adultPrice;
113
+ if (adultPrice === undefined)
114
+ continue;
115
+ if (typeof adultPrice !== 'number' || !Number.isFinite(adultPrice)) {
116
+ malformedPrice = true;
117
+ break;
118
+ }
119
+ if (adultPrice > 0)
120
+ prices.push(adultPrice);
121
+ }
122
+ if (malformedPrice)
123
+ continue;
67
124
  out.push({
68
- flightNo: fl.flightNo,
69
- airline: seg?.airlineName ?? '',
70
- depDateTime: fl.departureDateTime ?? '',
71
- arrDateTime: fl.arrivalDateTime ?? '',
72
- depAirport: fl.departureAirportName ?? '',
73
- arrAirport: fl.arrivalAirportName ?? '',
74
- durationMin: Number(seg?.duration ?? 0) || 0,
125
+ flightNo: f.flightNo,
126
+ airline: asString(segObj.airlineName),
127
+ depDateTime: asString(f.departureDateTime),
128
+ arrDateTime: asString(f.arrivalDateTime),
129
+ depAirport: asString(f.departureAirportName),
130
+ arrAirport: asString(f.arrivalAirportName),
131
+ durationMin: asPositiveNumber(segObj.duration),
75
132
  price: prices.length > 0 ? Math.min(...prices) : 0,
76
- aircraft: fl.aircraftName
133
+ aircraft: typeof f.aircraftName === 'string' ? f.aircraftName : undefined,
77
134
  });
78
135
  }
79
- return out;
136
+ return {
137
+ options: out,
138
+ verdict: out.length > 0 ? 'hit' : list.length === 0 ? 'miss' : 'error',
139
+ };
80
140
  }
81
-
82
-
83
- //# sourceURL=ts/capabilities/session/adapters/ctrip-flight.ts