@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,103 @@
1
+ /**
2
+ * 实时票价 overlay(README Known limitation「机票实时数据」清偿件):
3
+ * 静态包(data/flights_2026.json)仍是兜底,不再是唯一票价源——dated 航班链 spec
4
+ * (段带 date + route 词表内城市对)可经 FlyAI 官方只读通道(gotry_flyai_search 同源
5
+ * `capabilities/flyai.ts`)取实时价,按航班号精确匹配覆写 spec 价格后进求解,
6
+ * 证据链 `[实时API:flyai@ts]` 随行(data-sources §6)。
7
+ *
8
+ * 三值语义(永不抛错,与 hbcli/weather/opensky/anything 同构,L4 不变量):
9
+ * - hit 且价正 → 覆写 + 记 evidence(静态原价留档对账);
10
+ * - miss/error/打码价(如 "1xxx",非正数)/无匹配 → 段原样保留(静态价即降级);
11
+ * - 查询实现注入(测试离线确定性);默认关,`GOTRY_REALTIME_PRICING=1` 开启产品面。
12
+ */
13
+ import { interpretEffect } from '../capabilities/effect.js';
14
+ /** FlyAI CLI 收中文城市名;route 提示是 IATA 码(spec 层骨架词表,与 skeleton-check 同源) */
15
+ const IATA_TO_CITY = {
16
+ HKG: '香港', HKT: '普吉', BKK: '曼谷', KMG: '昆明', SZX: '深圳', DXB: '迪拜',
17
+ LJG: '丽江', DLU: '大理', SHA: '上海', PVG: '上海', PEK: '北京', CTU: '成都',
18
+ };
19
+ /**
20
+ * dated 航班链 spec 的实时票价覆写:
21
+ * - 只碰 `date`(YYYY-MM-DD)且 route 落在词表内的段;火车段(无 route 词表)原样;
22
+ * - 段内 option 按 service id(=航班号,大小写不敏感)与 FlyAI 条目精确匹配;
23
+ * - 任何失败(查询 error/miss、价格非正数、无匹配)→ 该段原样保留,绝不抛错。
24
+ */
25
+ export async function overlayRealtimeFlightPrices(spec, opts = {}) {
26
+ const out = { spec, matched: [], notes: [] };
27
+ const flights = [];
28
+ for (const seg of spec.segments) {
29
+ if (!seg.date || !/^\d{4}-\d{2}-\d{2}$/.test(seg.date))
30
+ continue;
31
+ const route = seg.route;
32
+ if (!route || !route.includes('->'))
33
+ continue;
34
+ const [a, b] = route.split('->').map(s => IATA_TO_CITY[s.trim()]);
35
+ if (!a || !b)
36
+ continue;
37
+ if (seg.options.some(o => !o.move))
38
+ continue;
39
+ flights.push({ seg, date: seg.date, origin: a, destination: b });
40
+ }
41
+ if (flights.length === 0)
42
+ return out;
43
+ const query = opts.query ?? defaultQuery;
44
+ for (const f of flights) {
45
+ let result;
46
+ try {
47
+ result = await query({ kind: 'flight', origin: f.origin, destination: f.destination, depDate: f.date });
48
+ }
49
+ catch (e) {
50
+ out.notes.push(`${f.seg.id}: 实时票价不可用(降级静态包):${e.message?.slice(0, 80)} [实时API:flyai@error]`);
51
+ continue;
52
+ }
53
+ if (!result.ok || result.verdict !== 'hit' || !result.options?.length) {
54
+ out.notes.push(`${f.seg.id}: 实时票价未取回(${result.verdict},降级静态包) ${result.evidence}`);
55
+ continue;
56
+ }
57
+ const ts = /@(\d{4}-\d{2}-\d{2}T[\d:.]+Z)\]/.exec(result.evidence)?.[1] ?? new Date().toISOString();
58
+ const byNo = new Map();
59
+ for (const o of result.options) {
60
+ if (Number.isFinite(o.price) && o.price > 0)
61
+ byNo.set(o.no.toUpperCase(), o);
62
+ }
63
+ for (const opt of f.seg.options) {
64
+ const svc = opt.move.services[0];
65
+ const rt = byNo.get(svc.id.toUpperCase());
66
+ if (!rt)
67
+ continue;
68
+ const evidence = `[实时API:flyai@${ts}] ${rt.no} ¥${rt.price}(静态包原价 ¥${svc.priceCny})`;
69
+ out.matched.push({ segment: f.seg.id, option: opt.id, staticCny: svc.priceCny, realtimeCny: rt.price, evidence });
70
+ out.notes.push(evidence);
71
+ svc.priceCny = rt.price;
72
+ }
73
+ }
74
+ return out;
75
+ }
76
+ /** 默认查询面走效应解译器(ADR-18):多段行程连查享有退避重试/断路器保护——
77
+ * 断路拒绝(上游连环失败)时抛错,一并落在「实时票价不可用(降级静态包)」既有兜底里 */
78
+ const defaultQuery = async (q) => {
79
+ const itp = await interpretEffect({ effect: 'FLYAI_SEARCH', params: { kind: q.kind, origin: q.origin, destination: q.destination, depDate: q.depDate } });
80
+ if (!itp.result)
81
+ throw new Error(itp.trace.evidence.join(';'));
82
+ return itp.result;
83
+ };
84
+ /** 求解端口包装(产品接缝):`GOTRY_REALTIME_PRICING=1`(或 opts.enabled)时 dated 航班链段
85
+ * 先经 FlyAI 实时价覆写,证据行并进结果 skeleton_notes;关闸/零覆写零改动,永不抛错。 */
86
+ export function realtimeSolvePort(base, opts = {}) {
87
+ return async (spec) => {
88
+ const enabled = opts.enabled ?? process.env['GOTRY_REALTIME_PRICING'] === '1';
89
+ if (!enabled)
90
+ return base(spec);
91
+ try {
92
+ const ov = await overlayRealtimeFlightPrices(spec, opts);
93
+ if (ov.matched.length === 0 && ov.notes.length === 0)
94
+ return base(ov.spec);
95
+ const res = await base(ov.spec);
96
+ res.skeleton_notes = [...(res.skeleton_notes ?? []), ...ov.notes];
97
+ return res;
98
+ }
99
+ catch {
100
+ return base(spec); // 覆写层任何异常 → 纯静态包原路求解
101
+ }
102
+ };
103
+ }
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Why-now card builder(issue #577,Phase D;研究决策 §3 Phase D;
3
+ * 自检 review 修复见 PR #578——边界校验让「无信源的卡构造上不可能」成为字面真)。
4
+ *
5
+ * 纯函数:RecallTrigger → WhyNowCard(中文文案:标题 + 触发原因 + 当前值/阈值 +
6
+ * 行动建议 + source tag)。
7
+ *
8
+ * 纪律:
9
+ * - **边界强制 provenance**:buildWhyNowCard 校验 signal.source 非空 + reason 在
10
+ * 闭集,不合法**直接抛错**——「source_tag 必现」不再是注释承诺而是构造保证;
11
+ * - 文案模板是封闭词汇(标题/建议的措辞改 = 契约变更,先 review);
12
+ * - 卡片是数据(不是渲染 HTML);渲染面(deck / 对话 / SMS)各自消费;
13
+ * - renderWhyNowCardLine 必须带证据边界标记(渲染契约:每个渲染面都要展示)。
14
+ */
15
+ import { RECALL_REASON_LABEL, RECALL_REASONS } from './evaluator.js';
16
+ const ACTION_HINT = {
17
+ holiday_proximity: '建议在假期前完成规划,锁定当前档期',
18
+ price_drop: '价格已降至阈值,建议尽快确认出发日期',
19
+ weather_window: '天气窗口已打开,适合按原计划出行',
20
+ route_new: '新班次已覆盖目标日期,可以重新评估可行性',
21
+ availability_recovered: '通道已恢复,此前不可行的方案现在可以重新查询',
22
+ };
23
+ /**
24
+ * 构造 why-now 卡:trigger → 人话卡片。
25
+ * **边界强制 provenance**:signal.source 非空 + reason 在闭集,否则抛错
26
+ * (「无信源的卡构造上不可能存在」的字面兑现——手工构造的 trigger 同样受检)。
27
+ * **证据诚实**:trigger.match_hits 是非空字符串数组时原样带上(all-or-nothing,
28
+ * 不部分裁剪、不发明);缺省/空/畸形 → 卡不带 match_evidence——手工构造的卡
29
+ * 宁可无证据,不虚构命中。
30
+ * title 格式:`现在可以去了:${wish_name}`(半角冒号)——封闭词汇,改措辞 = 契约变更。
31
+ */
32
+ export function buildWhyNowCard(trigger) {
33
+ const { wish_id, wish_name, signal, evaluated_at } = trigger;
34
+ if (signal === null || typeof signal !== 'object') {
35
+ throw new Error(`buildWhyNowCard:signal 必须是对象(实测 ${String(signal)})`);
36
+ }
37
+ if (typeof signal.source !== 'string' || signal.source.length === 0) {
38
+ throw new Error('buildWhyNowCard:signal.source 必须是非空字符串(无信源的卡构造上不可能存在)');
39
+ }
40
+ if (!RECALL_REASONS.includes(signal.reason)) {
41
+ throw new Error(`buildWhyNowCard:signal.reason 不在闭集(实测 ${String(signal.reason)};允许:${RECALL_REASONS.join(' / ')})`);
42
+ }
43
+ // 条件命中证据:all-or-nothing 校验(非空的非空字符串数组才带上;不发明、不裁剪)
44
+ const rawHits = trigger.match_hits;
45
+ const hasEvidence = Array.isArray(rawHits) && rawHits.length > 0
46
+ && rawHits.every(h => typeof h === 'string' && h.length > 0);
47
+ return {
48
+ title: `现在可以去了:${wish_name}`,
49
+ wish_id,
50
+ reason: signal.reason,
51
+ reason_label: RECALL_REASON_LABEL[signal.reason],
52
+ current_value: signal.current_value,
53
+ threshold: signal.threshold,
54
+ action_hint: ACTION_HINT[signal.reason],
55
+ source_tag: `[source:${signal.source}]`,
56
+ evaluated_at,
57
+ evidence_boundary: true,
58
+ ...(hasEvidence ? { match_evidence: [...rawHits] } : {}),
59
+ };
60
+ }
61
+ /** 渲染为单行中文摘要(对话/日志面用;卡片数据仍是权威)。
62
+ * 必须含证据边界标记(渲染契约:每个渲染面都要展示 evidence_boundary);
63
+ * 卡带 match_evidence 时逐项陈述命中条件,并显式声明**不主张全部出行条件已满足**
64
+ * (命中部分愿望条件只是召回资格,不是出行可行性证明)。 */
65
+ export function renderWhyNowCardLine(card) {
66
+ const evidence = Array.isArray(card.match_evidence) && card.match_evidence.length > 0
67
+ ? card.match_evidence
68
+ : null;
69
+ const conditionClause = evidence !== null ? `;命中条件:${evidence.join('+')}` : '';
70
+ const boundary = evidence !== null
71
+ ? '[证据边界:仅命中上述愿望条件,非全部出行条件已满足]'
72
+ : '[证据边界:仅证据驱动]';
73
+ return `${card.title}——${card.reason_label}(当前:${card.current_value};阈值:${card.threshold}${conditionClause})。${card.action_hint} ${card.source_tag} ${boundary}`;
74
+ }
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Recall condition evaluator(issue #577,Phase D;研究决策 §3 Phase D;
3
+ * 自检 review 修复见 PR #578 评论——两轮:广播升级/容器与时钟守卫/单表派生;
4
+ * #577 收口:条件资格门 + 命中证据,见 docs/design/recall-trigger.md §2)。
5
+ *
6
+ * 纯函数:给定 wish-pool 候选条目 + 当前上下文(时间 + 召回窗口 match_context +
7
+ * 各类简化信号),产出一组 RecallTrigger——每个含「为什么是现在」的具体原因
8
+ * (条件名 + 当前值 + 阈值)与实际命中的愿望条件(match_hits)与 source tag
9
+ * (**proactive with provenance**——研究文档红线)。
10
+ *
11
+ * 纪律:
12
+ * - 原因闭集 5 类,**单表派生**(RECALL_REASON_LABEL 为唯一事实源;union / 数组 /
13
+ * label 全部从它推导——新增原因 = 改一张表,编译器强制 card.ts 的 hint 表补全);
14
+ * - **条件资格门**:候选必须先过 scoreWishMatch(wish-pool.ts 原样复用,不复制
15
+ * 判定逻辑)——任一 days/budget/month 命中即有召回资格(既有语义:是召回资格,
16
+ * 不是「全部出行条件已满足」的证明);命名 down 通道否证。信号(含定向)不能
17
+ * 绕过资格门;match_context 缺省/畸形 → fail-closed 空返回,绝不降级为广播;
18
+ * - **职责边界**:信号是 producer 给的人话信号(current_value/threshold 是展示
19
+ * 字符串,不是类型化价格/日期事实),评估器不解析它们;资格事实只来自注入的
20
+ * match_context;
21
+ * - 畸形输入(信号/容器/时钟/条目)**跳过或空返回,不崩**——评估器是消费链一环,
22
+ * 一个坏 tick 不能杀掉调用方的 drain loop;
23
+ * - wish_ids 非数组(如字符串)= 畸形信号,**跳过**(绝不降级为广播匹配——
24
+ * 广播是最激进模式,降级等于扩权);
25
+ * - muted 过滤用 `muted === true` 严格判定(JSON 往返的 'false' 字符串不再误杀)。
26
+ */
27
+ import { scoreWishMatch } from '../wish-pool.js';
28
+ /** 唯一事实源:5 类原因 → 中文标签。新增原因 = 在此表加一行(union/数组自动派生;
29
+ * card.ts 的 ACTION_HINT 表由 Record<RecallReason,...> 编译强制补全)。 */
30
+ export const RECALL_REASON_LABEL = {
31
+ holiday_proximity: '假期临近',
32
+ price_drop: '价格降至阈值',
33
+ weather_window: '天气窗口打开',
34
+ route_new: '新航线/班次开通',
35
+ availability_recovered: '通道恢复可用',
36
+ };
37
+ /** 闭集数组从 label 表派生(单一事实源;不再手抄第二份) */
38
+ export const RECALL_REASONS = Object.keys(RECALL_REASON_LABEL);
39
+ /**
40
+ * 评估:候选 × 信号 → 触发列表。
41
+ * 两道门,先资格后匹配:
42
+ * 1. **资格门**:候选非 muted + 有稳定非空 wish_id + scoreWishMatch(entry,
43
+ * match_context) 非空(任一条件命中,且无命名 down 通道否证)——信号匹配只在
44
+ * 有资格的候选上进行;
45
+ * 2. **匹配门**:signal.wish_ids 是非空字符串数组时按 id 精确匹配(定向);
46
+ * 为空/缺省时匹配全部**有资格**候选(广播)。**wish_ids 为其它真值类型
47
+ * (字符串/对象等)视为畸形信号,整条跳过**——绝不降级为广播。
48
+ * 容器/时钟/上下文守卫:signals/pool 非数组、ctx.now 非法、match_context 缺省或
49
+ * 畸形 → 返回 [](不抛,不崩 drain loop,不广播扩权)。
50
+ */
51
+ export function evaluateRecallTriggers(pool, ctx) {
52
+ // 容器与时钟守卫:一个坏 tick 不能杀掉调用方(fail-closed 空返回)
53
+ if (!Array.isArray(pool) || !Array.isArray(ctx?.signals))
54
+ return [];
55
+ const nowMs = ctx.now instanceof Date ? ctx.now.getTime() : Number.NaN;
56
+ if (!Number.isFinite(nowMs))
57
+ return [];
58
+ // 条件上下文守卫:缺省/畸形 → fail-closed(绝不降级为「全部广播」——
59
+ // 没有窗口证据就广播「现在可以去」正是 #577 要堵住的扩权)
60
+ if (!isWishMatchContext(ctx.match_context))
61
+ return [];
62
+ const evaluatedAt = new Date(nowMs).toISOString();
63
+ // 资格门:scoreWishMatch 非空(≥1 项 days/budget/month 命中,且无命名通道 down 否证)
64
+ // 才进入候选;保持 pool 原序(广播/定向的输出顺序与既有行为一致)
65
+ const eligible = [];
66
+ for (const e of pool) {
67
+ if (e?.muted === true || typeof e?.wish_id !== 'string' || e.wish_id.length === 0)
68
+ continue;
69
+ const match = scoreCandidate(e, ctx.match_context);
70
+ if (match !== null)
71
+ eligible.push({ entry: e, match });
72
+ }
73
+ const triggers = [];
74
+ for (const signal of ctx.signals) {
75
+ if (!isRecallSignal(signal))
76
+ continue;
77
+ const targets = Array.isArray(signal.wish_ids) && signal.wish_ids.length > 0
78
+ ? eligible.filter(({ entry }) => signal.wish_ids.includes(entry.wish_id))
79
+ : eligible;
80
+ for (const { entry, match } of targets) {
81
+ triggers.push({
82
+ wish_id: String(entry.wish_id),
83
+ wish_name: typeof entry.name === 'string' && entry.name.length > 0 ? entry.name : String(entry.wish_id),
84
+ signal,
85
+ evaluated_at: evaluatedAt,
86
+ match_hits: [...match.hits],
87
+ });
88
+ }
89
+ }
90
+ return triggers;
91
+ }
92
+ /**
93
+ * 资格判定:scoreWishMatch 原样复用(唯一判定层,不复制判定/阈值逻辑)。
94
+ * 意外抛错(运行时畸形形态逃过静态与结构检查)→ 该条目无资格,不崩——
95
+ * 单个坏条目不能杀掉整轮评估。
96
+ */
97
+ function scoreCandidate(entry, ctx) {
98
+ try {
99
+ return scoreWishMatch(entry, ctx);
100
+ }
101
+ catch {
102
+ return null;
103
+ }
104
+ }
105
+ /** match_context 运行时校验(JSON 往返边界强制):非数组对象 + 数值字段(若给出)
106
+ * 必须是有限数字 + channelDown(若给出非 null)必须具备 has 方法(Set 形)。
107
+ * 与 scoreWishMatch 的缺省语义对齐:channelDown 缺省/null = 不启用通道否证。 */
108
+ function isWishMatchContext(value) {
109
+ if (typeof value !== 'object' || value === null || Array.isArray(value))
110
+ return false;
111
+ const c = value;
112
+ for (const k of ['days', 'budgetCny', 'month']) {
113
+ const v = c[k];
114
+ if (v !== undefined && (typeof v !== 'number' || !Number.isFinite(v)))
115
+ return false;
116
+ }
117
+ const down = c.channelDown;
118
+ if (down !== undefined && down !== null && typeof down.has !== 'function')
119
+ return false;
120
+ return true;
121
+ }
122
+ /** 信号校验(边界强制,不从输入信任):reason 在闭集 + source 非空字符串 +
123
+ * current_value/threshold 为字符串 + **wish_ids 一旦给出必须是字符串数组**
124
+ * (字符串等真值非数组 = 畸形,拒绝——绝不降级广播)。 */
125
+ function isRecallSignal(value) {
126
+ if (typeof value !== 'object' || value === null)
127
+ return false;
128
+ const s = value;
129
+ if (!RECALL_REASONS.includes(s.reason))
130
+ return false;
131
+ if (typeof s.source !== 'string' || s.source.length === 0)
132
+ return false;
133
+ if (typeof s.current_value !== 'string' || typeof s.threshold !== 'string')
134
+ return false;
135
+ if (s.wish_ids !== undefined && s.wish_ids !== null) {
136
+ if (!Array.isArray(s.wish_ids) || !s.wish_ids.every(id => typeof id === 'string'))
137
+ return false;
138
+ }
139
+ return true;
140
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Recall wish-pool integration(issue #577,Phase D)。
3
+ *
4
+ * 把 wish-pool 候选条目接到 evaluator:从 tick + signals 组装上下文 → 跑评估 →
5
+ * 产触发列表 + why-now 卡。**只读 wish-pool**(不调用 mutation;撤回/通知留 M4)。
6
+ *
7
+ * 本模块不接 IO——数据进出全靠参数(测试全离线;M4 由真实 tick source + sensor 喂数据)。
8
+ */
9
+ import { evaluateRecallTriggers } from './evaluator.js';
10
+ import { buildWhyNowCard } from './card.js';
11
+ /** 从 wish-pool + tick + signals + 召回窗口跑一轮评估并产卡(纯函数编排) */
12
+ export function evaluatePoolRecall(input) {
13
+ const ctx = { now: input.tick.at, signals: input.signals, match_context: input.match_context };
14
+ const triggers = evaluateRecallTriggers(input.pool, ctx);
15
+ const cards = triggers.map(buildWhyNowCard);
16
+ return { triggers, cards };
17
+ }
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Recall tick scheduler(issue #577,Phase D;研究决策见
3
+ * docs/research/karpo-deck-web-research.md §3 Phase D;
4
+ * seam 约束见 docs/design/external-event-seam.md §3.3/§4——**pull model,M5 前无 push**;
5
+ * 自检 review 两轮修复见 PR #578 评论)。
6
+ *
7
+ * 设计契约:
8
+ * - TickSource:`next()` **运行中阻塞到下一个 tick 可用**;**未运行(未启动或已
9
+ * stop)返回 null = 流终结**——drain-loop 调用方安全退出,永不悬挂;
10
+ * - PeriodicTickSource:**默认 enabled=false**(显式 opt-in);start() 三态
11
+ * ('started'|'disabled'|'already-running');timer.unref()(不拽住事件循环);
12
+ * pending 有界(maxPending 默认 100,溢出丢最旧);**stop() 清空 pending 并把
13
+ * 全部等待者以 null 唤醒**(终结核平——消费协程不泄漏,重启不吐陈旧 tick);
14
+ * - RecallTickScheduler:**永不抛错**——evaluate/toCard/deliver 全部容错:
15
+ * evaluate 抛错 → {delivered:0, failed:0, error};单卡 toCard/deliver 抛错 →
16
+ * 只弃该卡(failed++ 并记 errors),余下继续;返回 {delivered, failed, errors?};
17
+ * - **不推送**:sink 是注入的下游,不是 notification/push 通道(seam §4)。
18
+ */
19
+ /** 测试用 InMemory tick source:预排好的一组 tick,按序返回,耗尽返回 null。
20
+ * 构造与 next() 均防御式深拷贝(调用方改返回的 tick.at 不会污染队列快照)。 */
21
+ export class InMemoryTickSource {
22
+ queue;
23
+ constructor(ticks) {
24
+ this.queue = ticks.map(t => ({ at: new Date(t.at.getTime()), source: t.source }));
25
+ }
26
+ async next() {
27
+ const t = this.queue.shift();
28
+ if (t === undefined)
29
+ return null;
30
+ return { at: new Date(t.at.getTime()), source: t.source }; // 返回副本,调用方可安全改
31
+ }
32
+ }
33
+ /**
34
+ * 周期 tick source(默认关闭):封装 Node setInterval。
35
+ * - enabled=false 构造默认,显式 opt-in;start() 三态返回(不混同);
36
+ * - next() 语义:**运行中**阻塞到下个 tick;**未运行**(disabled/未 start/已 stop)
37
+ * 立即返回 null(流终结——drain-loop 安全退出,永不悬挂);
38
+ * - stop() 幂等:**清空 pending(重启不吐陈旧 tick)+ 把全部等待者以 null 唤醒**
39
+ * (消费协程不泄漏);
40
+ * - timer.unref():忘了 stop() 也不拽住进程事件循环;
41
+ * - pending 有界(maxPending,溢出丢最旧)。
42
+ */
43
+ export class PeriodicTickSource {
44
+ enabled;
45
+ intervalMs;
46
+ sourceLabel;
47
+ maxPending;
48
+ timer = null;
49
+ pending = [];
50
+ waiters = [];
51
+ constructor(opts) {
52
+ this.enabled = opts.enabled === true;
53
+ this.intervalMs = opts.intervalMs;
54
+ this.sourceLabel = opts.source ?? 'periodic';
55
+ this.maxPending = opts.maxPending ?? 100;
56
+ if (!Number.isFinite(this.intervalMs) || this.intervalMs <= 0) {
57
+ throw new Error(`PeriodicTickSource intervalMs 必须为正数(实测 ${this.intervalMs})`);
58
+ }
59
+ if (!Number.isInteger(this.maxPending) || this.maxPending < 1) {
60
+ throw new Error(`PeriodicTickSource maxPending 必须为 ≥1 整数(实测 ${this.maxPending})`);
61
+ }
62
+ }
63
+ /** 启动内部 setInterval;三态返回(见类注释)。已启动时幂等。 */
64
+ start() {
65
+ if (!this.enabled)
66
+ return 'disabled';
67
+ if (this.timer !== null)
68
+ return 'already-running';
69
+ this.timer = setInterval(() => {
70
+ const tick = { at: new Date(), source: this.sourceLabel };
71
+ // 优先唤醒等待者;无等待者入有界队列(溢出丢最旧)
72
+ const waiter = this.waiters.shift();
73
+ if (waiter !== undefined) {
74
+ waiter(tick);
75
+ return;
76
+ }
77
+ if (this.pending.length >= this.maxPending)
78
+ this.pending.shift();
79
+ this.pending.push(tick);
80
+ }, this.intervalMs);
81
+ this.timer.unref?.();
82
+ return 'started';
83
+ }
84
+ /** 停止(幂等):清 timer + **清空 pending(重启不吐陈旧 tick)+ 等待者全部以 null 唤醒**(终结核平) */
85
+ stop() {
86
+ if (this.timer !== null) {
87
+ clearInterval(this.timer);
88
+ this.timer = null;
89
+ }
90
+ this.pending = [];
91
+ const waiters = this.waiters;
92
+ this.waiters = [];
93
+ for (const w of waiters)
94
+ w(null);
95
+ }
96
+ /** 当前 pending 队列长度(只读;测试与诊断用) */
97
+ get pendingLength() {
98
+ return this.pending.length;
99
+ }
100
+ /** **运行中**阻塞到下一个 tick;**未运行**(disabled/未 start/已 stop)返回 null(流终结) */
101
+ async next() {
102
+ if (this.timer === null)
103
+ return null;
104
+ const queued = this.pending.shift();
105
+ if (queued !== undefined)
106
+ return queued;
107
+ return new Promise(resolve => {
108
+ this.waiters.push(resolve);
109
+ });
110
+ }
111
+ }
112
+ /** 数组收集 sink(测试用) */
113
+ export class ArrayRecallSink {
114
+ items = [];
115
+ deliver(card) {
116
+ this.items.push(card);
117
+ }
118
+ }
119
+ /**
120
+ * 编排器:拉 tick → 评估 → 转卡 → 送 sink。
121
+ * 每次 run 处理一个 tick(调用方决定循环;scheduler 自己不循环——不悄悄长驻)。
122
+ * **永不抛错**:evaluate 抛错 → {delivered:0, failed:0, error 记入 errors};
123
+ * 单卡 toCard/deliver 抛错 → 只弃该卡(failed++/errors 记一条),余下继续。
124
+ */
125
+ export class RecallTickScheduler {
126
+ deps;
127
+ constructor(deps) {
128
+ this.deps = deps;
129
+ }
130
+ async run(tick) {
131
+ const errors = [];
132
+ let evaluations;
133
+ try {
134
+ evaluations = this.deps.evaluate(tick);
135
+ if (!Array.isArray(evaluations))
136
+ evaluations = [];
137
+ }
138
+ catch (err) {
139
+ return { delivered: 0, failed: 0, errors: [`evaluate: ${err?.message ?? String(err)}`] };
140
+ }
141
+ let delivered = 0;
142
+ let failed = 0;
143
+ for (const evaluation of evaluations) {
144
+ let card;
145
+ try {
146
+ card = this.deps.toCard(evaluation, tick);
147
+ }
148
+ catch (err) {
149
+ failed++;
150
+ if (errors.length < 4)
151
+ errors.push(`toCard: ${err?.message ?? String(err)}`);
152
+ continue;
153
+ }
154
+ try {
155
+ await this.deps.sink.deliver(card);
156
+ delivered++;
157
+ }
158
+ catch (err) {
159
+ failed++;
160
+ if (errors.length < 4)
161
+ errors.push(`deliver: ${err?.message ?? String(err)}`);
162
+ }
163
+ }
164
+ return errors.length > 0 ? { delivered, failed, errors } : { delivered, failed };
165
+ }
166
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Plan-it 行动卡(issue #580,Phase E)——why-now 卡(Phase D)的一键行动
3
+ * 面:「好,规划它」深链回本地 session 继续规划该 wish。**只打开,不写**:
4
+ * 行动词位只有 plan_it(Continue planning),booking/payment 不在链接词位
5
+ * (session-link.ts 的 action 闭集),WriteGate 保持 sealed。
6
+ *
7
+ * 纪律:
8
+ * - 行动卡是数据(不是渲染 HTML);渲染面(deck / 对话 / 通知)各自消费;
9
+ * - `wish_id` 与 token payload **同源构造**(同一个值进两处),不可能漂移——
10
+ * 渲染面显示的 wish 与链接打开的 wish 是构造级同一个;
11
+ * - label 是封闭词汇(「好,规划它」改措辞 = 契约变更,先 review);
12
+ * - why-now 卡的「not_now」是渲染面本地消解(无链接、无状态写),
13
+ * 本契约不覆盖(文档声明)。
14
+ */
15
+ import { formatSessionLink, signSessionLink } from './session-link.js';
16
+ /** plan-it 行动文案(封闭词汇) */
17
+ export const PLAN_IT_LABEL = '好,规划它';
18
+ /**
19
+ * why-now 卡 → plan-it 行动卡。wish_id 取卡上的结构化字段(Phase E 起
20
+ * WhyNowCard 必含 wish_id——从 title 字符串反解不可接受)。
21
+ * 非法输入(wish_id 缺失/空、session_ref 路径化)抛错:行动卡构造层
22
+ * 即 fail-closed,不产「点了不知道开什么」的链接。
23
+ */
24
+ export function buildPlanItAction(card, deps) {
25
+ if (typeof card?.wish_id !== 'string' || card.wish_id.length === 0) {
26
+ throw new Error('buildPlanItAction:card.wish_id 必须是非空字符串(WhyNowCard 结构化自指其 wish 是 plan-it 行动的前提)');
27
+ }
28
+ if (typeof deps?.session_ref !== 'string' || deps.session_ref.length === 0) {
29
+ throw new Error(`buildPlanItAction:session_ref 必须是非空字符串(实测 ${String(deps?.session_ref)})`);
30
+ }
31
+ const now = deps.now ?? (() => new Date());
32
+ const payload = {
33
+ link_id: deps.link_id ?? `plan-${now().getTime().toString(36)}-${Math.random().toString(36).slice(2, 10)}`,
34
+ session_ref: deps.session_ref,
35
+ action: 'plan_it',
36
+ wish_id: card.wish_id,
37
+ created_at: now().toISOString(),
38
+ ttl_seconds: deps.ttl_seconds ?? 86_400,
39
+ };
40
+ // wish_id 同源:payload.wish_id 就是上面 card.wish_id 这一个值
41
+ const token = signSessionLink(payload, deps.secret);
42
+ return {
43
+ kind: 'plan_it',
44
+ label: PLAN_IT_LABEL,
45
+ deep_link: formatSessionLink(token, deps.base),
46
+ wish_id: card.wish_id,
47
+ };
48
+ }