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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (507) hide show
  1. package/README.md +172 -219
  2. package/README.zh-CN.md +222 -0
  3. package/bin/gotry-backend.js +53 -0
  4. package/bin/gotry-booking-copilot.js +53 -0
  5. package/bin/gotry-bootstrap.js +1744 -0
  6. package/bin/gotry-inner.js +733 -83
  7. package/bin/gotry-process-liveness.d.ts +27 -0
  8. package/bin/gotry-process-liveness.js +97 -0
  9. package/bin/gotry-runtime-resolution.d.ts +27 -0
  10. package/bin/gotry-runtime-resolution.js +49 -0
  11. package/bin/gotry.js +1 -1
  12. package/client/client.js +203 -0
  13. package/cordis.gotry-patch.yml +80 -56
  14. package/data/airline-airports.json +39 -0
  15. package/data/stations-12306-verify.json +524 -0
  16. package/dist/capabilities/agent-reach-deep.js +45 -122
  17. package/dist/capabilities/agent-reach.js +101 -146
  18. package/dist/capabilities/anything.js +135 -94
  19. package/dist/capabilities/artifacts.js +370 -0
  20. package/dist/capabilities/channel-health.js +131 -0
  21. package/dist/capabilities/channel-registry.js +256 -0
  22. package/dist/capabilities/doctor.js +546 -0
  23. package/dist/capabilities/effect.js +394 -0
  24. package/dist/capabilities/external-event.js +149 -0
  25. package/dist/capabilities/fact-log.js +55 -0
  26. package/dist/capabilities/flyai-config.js +337 -0
  27. package/dist/capabilities/flyai.js +947 -110
  28. package/dist/capabilities/fx-contract.js +293 -0
  29. package/dist/capabilities/geo-atlas.js +246 -0
  30. package/dist/capabilities/ground-transfer.js +509 -0
  31. package/dist/capabilities/hbcli.js +260 -123
  32. package/dist/capabilities/hotelbyte-transaction.js +194 -0
  33. package/dist/capabilities/incident-log.js +131 -61
  34. package/dist/capabilities/itinerary-artifact.js +190 -0
  35. package/dist/capabilities/itinerary-deck-artifact.js +194 -0
  36. package/dist/capabilities/itinerary-deck-export.js +339 -0
  37. package/dist/capabilities/lavish-local.js +924 -0
  38. package/dist/capabilities/model-override.js +38 -0
  39. package/dist/capabilities/opensky.js +54 -43
  40. package/dist/capabilities/resilience.js +191 -0
  41. package/dist/capabilities/session/action-cache.js +50 -44
  42. package/dist/capabilities/session/adapters/ctrip-flight.js +120 -62
  43. package/dist/capabilities/session/adapters/ctrip-hotel.js +222 -0
  44. package/dist/capabilities/session/adapters/dida-portal.js +274 -0
  45. package/dist/capabilities/session/adapters/meituan-local.js +35 -54
  46. package/dist/capabilities/session/adapters/rail-12306.js +342 -0
  47. package/dist/capabilities/session/benchmark.js +189 -0
  48. package/dist/capabilities/session/bridge-ledger.js +224 -0
  49. package/dist/capabilities/session/extension-bridge.js +636 -0
  50. package/dist/capabilities/session/extension-channel.js +109 -0
  51. package/dist/capabilities/session/extension-distribution.js +230 -0
  52. package/dist/capabilities/session/extract.js +31 -21
  53. package/dist/capabilities/session/golden-score.js +114 -0
  54. package/dist/capabilities/session/health-watch.js +215 -0
  55. package/dist/capabilities/session/read-guard.js +75 -24
  56. package/dist/capabilities/session/static-flight-golden.js +150 -0
  57. package/dist/capabilities/session/transport.js +97 -83
  58. package/dist/capabilities/session/wizard.js +117 -0
  59. package/dist/capabilities/session-consent.js +178 -0
  60. package/dist/capabilities/session-login.js +170 -0
  61. package/dist/capabilities/session-search.js +635 -44
  62. package/dist/capabilities/spawn-bounded.js +203 -0
  63. package/dist/capabilities/sponsor-plugin.js +341 -0
  64. package/dist/capabilities/visa-policy.js +140 -0
  65. package/dist/capabilities/weather.js +243 -138
  66. package/dist/data/session-golden-20.json +25 -0
  67. package/dist/data/sf-golden-manifest.json +103 -0
  68. package/dist/data/sf-static-routes.json +91 -0
  69. package/dist/scripts/action-cache-tests.js +24 -59
  70. package/dist/scripts/agent-planning-turn-deadline-e2e.js +242 -0
  71. package/dist/scripts/agent-planning-turn-deadline-tests.js +185 -0
  72. package/dist/scripts/agent-reach-deep-tests.js +30 -40
  73. package/dist/scripts/agent-reach-error-tests.js +354 -0
  74. package/dist/scripts/agent-reach-tests.js +26 -18
  75. package/dist/scripts/agent-reach-wrapper-tests.js +50 -50
  76. package/dist/scripts/anything-tests.js +116 -60
  77. package/dist/scripts/artifact-client-contract-tests.js +220 -0
  78. package/dist/scripts/artifacts-capability-tests.js +727 -0
  79. package/dist/scripts/async-collect.js +50 -11
  80. package/dist/scripts/benchmark-environment-bridge-e2e.js +741 -0
  81. package/dist/scripts/benchmark-environment-bridge-tests.js +1452 -0
  82. package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +126 -0
  83. package/dist/scripts/booking-copilot-availability-policy-tests.js +265 -0
  84. package/dist/scripts/booking-copilot-bin-proof-tests.js +66 -0
  85. package/dist/scripts/booking-copilot-cleanup-proof-helper.js +76 -0
  86. package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +144 -0
  87. package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +424 -0
  88. package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +2839 -0
  89. package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +309 -0
  90. package/dist/scripts/booking-copilot-dsh-readiness-proof.js +238 -0
  91. package/dist/scripts/booking-copilot-dsh-warmer-proof.js +123 -0
  92. package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +156 -0
  93. package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +70 -0
  94. package/dist/scripts/booking-copilot-intent-proof-tests.js +422 -0
  95. package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +184 -0
  96. package/dist/scripts/booking-copilot-planner-live-probe.js +95 -0
  97. package/dist/scripts/booking-copilot-proof-runtime.js +42 -0
  98. package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +210 -0
  99. package/dist/scripts/booking-copilot-runtime-proof-tests.js +2349 -0
  100. package/dist/scripts/booking-copilot-server-proof-tests.js +784 -0
  101. package/dist/scripts/booking-copilot-startup-proof-tests.js +94 -0
  102. package/dist/scripts/booking-executor-tests.js +80 -0
  103. package/dist/scripts/booking-recovery-chain-tests.js +182 -0
  104. package/dist/scripts/booking-saga-tests.js +125 -0
  105. package/dist/scripts/booking-surface-contract-proof-tests.js +212 -0
  106. package/dist/scripts/bootstrap-tests.js +1479 -0
  107. package/dist/scripts/bridge-events-tests.js +239 -0
  108. package/dist/scripts/bridge-ledger-tests.js +428 -0
  109. package/dist/scripts/build-changelog.js +238 -0
  110. package/dist/scripts/build-metrics-report.js +331 -0
  111. package/dist/scripts/changelog-tests.js +118 -0
  112. package/dist/scripts/channel-probe-tests.js +103 -0
  113. package/dist/scripts/channel-probe.js +169 -0
  114. package/dist/scripts/channel-registry-tests.js +208 -0
  115. package/dist/scripts/companion-tests.js +25 -70
  116. package/dist/scripts/dida-cookie-probe.js +87 -0
  117. package/dist/scripts/dida-runner-stop-tests.js +311 -0
  118. package/dist/scripts/dida-sw-probe.js +114 -0
  119. package/dist/scripts/diff-test.js +17 -12
  120. package/dist/scripts/doctor-tests.js +564 -0
  121. package/dist/scripts/dsh-artifact-e2e.js +279 -0
  122. package/dist/scripts/dsh-artifact-web-e2e.js +675 -0
  123. package/dist/scripts/dsh-http-proxy-sse-proof.js +90 -0
  124. package/dist/scripts/dsh-runtime-closure-tests.js +182 -0
  125. package/dist/scripts/dsh-runtime-closure.js +162 -0
  126. package/dist/scripts/dsh-session-v3-migration-proof.js +109 -0
  127. package/dist/scripts/dsh-subprocess-local-proof.js +150 -0
  128. package/dist/scripts/dsh-target-closure-proof.js +178 -0
  129. package/dist/scripts/effect-tests.js +539 -0
  130. package/dist/scripts/engine-run.js +1 -3
  131. package/dist/scripts/engine-tests.js +16 -10
  132. package/dist/scripts/evaluation-cadence-tests.js +174 -0
  133. package/dist/scripts/evaluation-contract-tests.js +268 -0
  134. package/dist/scripts/extension-distribution-cli.js +39 -0
  135. package/dist/scripts/extension-distribution-tests.js +443 -0
  136. package/dist/scripts/extension-tests.js +988 -0
  137. package/dist/scripts/external-event-tests.js +350 -0
  138. package/dist/scripts/fact-gate-tests.js +869 -0
  139. package/dist/scripts/fixtures/extension-bridge-unref-child.mjs +21 -0
  140. package/dist/scripts/flight-hotel-anchor-363-registered-e2e.js +169 -0
  141. package/dist/scripts/flight-malformed-tests.js +159 -0
  142. package/dist/scripts/flyai-setup-tests.js +228 -0
  143. package/dist/scripts/flyai-setup-tool-tests.js +54 -0
  144. package/dist/scripts/flyai-tests.js +692 -0
  145. package/dist/scripts/flyai-tool-registration-contract-tests.js +91 -0
  146. package/dist/scripts/fx-contract-tests.js +201 -0
  147. package/dist/scripts/g5-guard-tests.js +131 -0
  148. package/dist/scripts/g5-guard.js +189 -0
  149. package/dist/scripts/gen-lunar-anchors.js +106 -0
  150. package/dist/scripts/geo-atlas-tests.js +283 -0
  151. package/dist/scripts/gotry-backend-kernel-tests.js +206 -0
  152. package/dist/scripts/gotry-try-demo-tests.js +79 -0
  153. package/dist/scripts/gotry-try-demo.js +49 -0
  154. package/dist/scripts/ground-transfer-tests.js +956 -0
  155. package/dist/scripts/hbcli-e2e-tests.js +159 -0
  156. package/dist/scripts/hbcli-live-optin-tests.js +96 -0
  157. package/dist/scripts/hbcli-release-contract-tests.js +122 -0
  158. package/dist/scripts/hbcli-tests.js +121 -69
  159. package/dist/scripts/health-watch-cli.js +73 -0
  160. package/dist/scripts/hotel-date-gate-tests.js +496 -0
  161. package/dist/scripts/hotelbyte-reconcile-tests.js +141 -0
  162. package/dist/scripts/hotelbyte-spawn-e2e-tests.js +373 -0
  163. package/dist/scripts/i18n-tests.js +41 -0
  164. package/dist/scripts/incident-tests.js +281 -87
  165. package/dist/scripts/issue-194-job-id-guard-tests.js +106 -0
  166. package/dist/scripts/issue-233-cancel-refund-commission-tests.js +392 -0
  167. package/dist/scripts/issue-271-liveness-tests.js +569 -0
  168. package/dist/scripts/issue-289-model-retry-real-tests.js +296 -0
  169. package/dist/scripts/issue-289-model-retry-tests.js +441 -0
  170. package/dist/scripts/issue-289-web-retry-e2e.js +630 -0
  171. package/dist/scripts/issue-338-home-city-e2e.js +577 -0
  172. package/dist/scripts/issue343-real-entry-e2e.js +160 -0
  173. package/dist/scripts/issue436-persisted-routing-e2e.js +247 -0
  174. package/dist/scripts/itinerary-artifact-tests.js +368 -0
  175. package/dist/scripts/itinerary-deck-artifact-tests.js +416 -0
  176. package/dist/scripts/itinerary-deck-export-tests.js +552 -0
  177. package/dist/scripts/itinerary-deck-tests.js +435 -0
  178. package/dist/scripts/itinerary-html-tests.js +426 -0
  179. package/dist/scripts/journey-tests.js +22 -27
  180. package/dist/scripts/kernel-manifest-evidence.js +109 -0
  181. package/dist/scripts/kernel-manifest-gate.js +126 -0
  182. package/dist/scripts/kernel-manifest-tests.js +212 -0
  183. package/dist/scripts/kernel-manifest-trace-entry.js +7 -0
  184. package/dist/scripts/kernel-manifest-trace-hook.mjs +28 -0
  185. package/dist/scripts/kernel-manifest.js +369 -0
  186. package/dist/scripts/lavish-local-tests.js +1226 -0
  187. package/dist/scripts/lavish-product-tools-tests.js +537 -0
  188. package/dist/scripts/ledger-repair-apply-tests.js +316 -0
  189. package/dist/scripts/ledger-repair-plan-tests.js +375 -0
  190. package/dist/scripts/ledger-tests.js +382 -246
  191. package/dist/scripts/ledger-workflow-crash.js +10 -20
  192. package/dist/scripts/managed-dsh-cleanup-diagnostic-proof.js +184 -0
  193. package/dist/scripts/managed-dsh-close-failure-proof.js +172 -0
  194. package/dist/scripts/managed-dsh-run-port-proof.js +153 -0
  195. package/dist/scripts/managed-dsh-terminal-proof.js +252 -0
  196. package/dist/scripts/map-tools-vendor-package-proof.js +365 -0
  197. package/dist/scripts/memory-capture-tests.js +242 -61
  198. package/dist/scripts/memory-decay-tests.js +18 -52
  199. package/dist/scripts/memory-lifecycle-tests.js +657 -0
  200. package/dist/scripts/memory-lifecycle.js +196 -0
  201. package/dist/scripts/memory-metrics.js +24 -12
  202. package/dist/scripts/memory-value-report.js +631 -0
  203. package/dist/scripts/memory-value-tests.js +328 -0
  204. package/dist/scripts/metrics-report-tests.js +151 -0
  205. package/dist/scripts/model-override-e2e.js +137 -0
  206. package/dist/scripts/nightly-evidence-tests.js +161 -0
  207. package/dist/scripts/nightly-evidence.js +286 -0
  208. package/dist/scripts/nudge-digest.js +39 -28
  209. package/dist/scripts/observability-tests.js +381 -0
  210. package/dist/scripts/onboarding-tests.js +161 -0
  211. package/dist/scripts/opensky-check.js +18 -13
  212. package/dist/scripts/opensky-tests.js +28 -28
  213. package/dist/scripts/persona-surface-guard-tests.js +49 -0
  214. package/dist/scripts/pnpm-dsh-closure-proof.js +17 -0
  215. package/dist/scripts/policy-anchor-359-registered-e2e.js +214 -0
  216. package/dist/scripts/price-drift-tests.js +340 -0
  217. package/dist/scripts/price-drift-watch.js +447 -0
  218. package/dist/scripts/probe-poi-tests.js +53 -45
  219. package/dist/scripts/product-metrics.js +483 -0
  220. package/dist/scripts/publish-preverify.js +110 -0
  221. package/dist/scripts/realtime-pricing-tests.js +76 -0
  222. package/dist/scripts/recall-tests.js +513 -0
  223. package/dist/scripts/replay-async.js +20 -18
  224. package/dist/scripts/replay-real.js +18 -18
  225. package/dist/scripts/replay.js +52 -82
  226. package/dist/scripts/session-attach-diagnose.js +20 -20
  227. package/dist/scripts/session-attach-poc.js +34 -37
  228. package/dist/scripts/session-benchmark.js +180 -0
  229. package/dist/scripts/session-dida-live-e2e.js +199 -0
  230. package/dist/scripts/session-extract-tests.js +14 -35
  231. package/dist/scripts/session-link-tests.js +478 -0
  232. package/dist/scripts/session-login.js +27 -46
  233. package/dist/scripts/session-tests.js +796 -96
  234. package/dist/scripts/session-zones-tests.js +358 -0
  235. package/dist/scripts/sf-live-benchmark.js +367 -0
  236. package/dist/scripts/sf-live-challenge-stop-tests.js +453 -0
  237. package/dist/scripts/sf-live-cli-tests.js +92 -0
  238. package/dist/scripts/sf-live-options.js +46 -0
  239. package/dist/scripts/sf-manifest-tests.js +30 -0
  240. package/dist/scripts/sf-manifest.js +33 -0
  241. package/dist/scripts/sf-soft-score-tests.js +67 -0
  242. package/dist/scripts/sf-summary-tests.js +324 -0
  243. package/dist/scripts/sf-summary.js +525 -0
  244. package/dist/scripts/share-tests.js +432 -0
  245. package/dist/scripts/skeleton-check.js +16 -14
  246. package/dist/scripts/skeleton-integration-test.js +28 -11
  247. package/dist/scripts/skills-contract-tests.js +51 -46
  248. package/dist/scripts/smoke-session-gate-tests.js +21 -0
  249. package/dist/scripts/smoke.js +690 -246
  250. package/dist/scripts/spawn-bounded-abort-tests.js +241 -0
  251. package/dist/scripts/sponsor-reuse-tests.js +262 -0
  252. package/dist/scripts/state-cli-tests.js +226 -101
  253. package/dist/scripts/state-cli.js +550 -199
  254. package/dist/scripts/state-repair-cli.js +66 -0
  255. package/dist/scripts/state-repair-tests.js +140 -0
  256. package/dist/scripts/static-golden-tests.js +165 -0
  257. package/dist/scripts/time-eval-tests.js +210 -192
  258. package/dist/scripts/travel-timeline-tests.js +29 -93
  259. package/dist/scripts/turn-handoff-collect-tests.js +169 -0
  260. package/dist/scripts/turn-handoff-collect.js +161 -0
  261. package/dist/scripts/turn-policy-tests.js +55 -0
  262. package/dist/scripts/typed-contract-canary.js +176 -0
  263. package/dist/scripts/tz-resolver-sanity.js +50 -0
  264. package/dist/scripts/tz-resolver-tests.js +584 -0
  265. package/dist/scripts/unified-tests.js +23 -19
  266. package/dist/scripts/visa-policy-tests.js +62 -0
  267. package/dist/scripts/weather-tests.js +276 -41
  268. package/dist/scripts/wish-channel-gate-tests.js +54 -0
  269. package/dist/scripts/write-gate-tests.js +522 -0
  270. package/dist/scripts/z3-lifecycle-fault-tests.js +188 -0
  271. package/dist/scripts/z3-lifecycle-tests.js +170 -0
  272. package/dist/scripts/z3-race-repeat-tests.js +39 -0
  273. package/dist/scripts/z3-race-tests.js +41 -0
  274. package/dist/src/artifact-gate.js +829 -0
  275. package/dist/src/backend/kernel.js +91 -0
  276. package/dist/src/backend/modules/booking-copilot.js +92 -0
  277. package/dist/src/backend/modules/booking-executor.js +124 -0
  278. package/dist/src/backend/modules/session-search.js +551 -0
  279. package/dist/src/benchmark-agent-conformance.js +578 -0
  280. package/dist/src/benchmark-environment-bridge.js +515 -0
  281. package/dist/src/benchmark-headless-child-diagnostics.js +166 -0
  282. package/dist/src/benchmark-tool-isolation.js +151 -0
  283. package/dist/src/bookable-facts.js +533 -0
  284. package/dist/src/booking-saga.js +97 -0
  285. package/dist/src/booking-surface/availability-policy.js +697 -0
  286. package/dist/src/booking-surface/booking-intent.js +43 -0
  287. package/dist/src/booking-surface/cancel-refund-commission.js +379 -0
  288. package/dist/src/booking-surface/canonical-schema.js +116 -0
  289. package/dist/src/booking-surface/contracts.js +75 -0
  290. package/dist/src/booking-surface/dsh-planner.js +1854 -0
  291. package/dist/src/booking-surface/dsh-plugin.js +378 -0
  292. package/dist/src/booking-surface/dsh-worker.js +98 -0
  293. package/dist/src/booking-surface/error-codes.js +231 -0
  294. package/dist/src/booking-surface/index.js +9 -0
  295. package/dist/src/booking-surface/managed-dsh-cleanup-diagnostic.js +97 -0
  296. package/dist/src/booking-surface/managed-dsh-run-port.js +244 -0
  297. package/dist/src/booking-surface/profile.js +24 -0
  298. package/dist/src/booking-surface/recovery-chain.js +367 -0
  299. package/dist/src/booking-surface/runtime.js +1968 -0
  300. package/dist/src/booking-surface/server.js +674 -0
  301. package/dist/src/booking-surface/startup.js +168 -0
  302. package/dist/src/booking-surface/validation.js +261 -0
  303. package/dist/src/bridge.js +20 -13
  304. package/dist/src/companions.js +48 -74
  305. package/dist/src/contracts.js +21 -43
  306. package/dist/src/dsh-llm.js +97 -111
  307. package/dist/src/engine.js +276 -193
  308. package/dist/src/evaluation-cadence.js +97 -0
  309. package/dist/src/evaluation-contracts.js +283 -0
  310. package/dist/src/flight-pack-adapter.js +54 -0
  311. package/dist/src/flight-pack-contract.js +2 -0
  312. package/dist/src/flyai-setup-tool.js +70 -0
  313. package/dist/src/gotry-backend.js +125 -0
  314. package/dist/src/hotel-date-gate.js +118 -0
  315. package/dist/src/i18n.js +88 -0
  316. package/dist/src/index.js +2227 -882
  317. package/dist/src/itinerary-deck.js +139 -0
  318. package/dist/src/itinerary-doc-shared.js +661 -0
  319. package/dist/src/itinerary-html.js +131 -0
  320. package/dist/src/journey.js +155 -108
  321. package/dist/src/lavish-tools.js +400 -0
  322. package/dist/src/ledger-repair-apply.js +538 -0
  323. package/dist/src/ledger-repair-plan.js +463 -0
  324. package/dist/src/loop.js +319 -160
  325. package/dist/src/memory-capture.js +180 -32
  326. package/dist/src/memory-decay.js +30 -14
  327. package/dist/src/memory-lifecycle.js +1310 -0
  328. package/dist/src/memory-utility.js +27 -40
  329. package/dist/src/mock-llm.js +36 -61
  330. package/dist/src/model.js +81 -36
  331. package/dist/src/realtime-pricing.js +103 -0
  332. package/dist/src/recall/card.js +74 -0
  333. package/dist/src/recall/evaluator.js +140 -0
  334. package/dist/src/recall/integration.js +17 -0
  335. package/dist/src/recall/tick.js +166 -0
  336. package/dist/src/session-link/plan-it-action.js +48 -0
  337. package/dist/src/session-link/session-link.js +248 -0
  338. package/dist/src/session-zones.js +507 -0
  339. package/dist/src/share/adapters.js +51 -0
  340. package/dist/src/share/share-consent.js +76 -0
  341. package/dist/src/share/share-deck.js +58 -0
  342. package/dist/src/share/share-token.js +146 -0
  343. package/dist/src/slot-spec.js +84 -106
  344. package/dist/src/state-ledger.js +435 -516
  345. package/dist/src/state-repair.js +299 -0
  346. package/dist/src/subagent-job-id-guard.js +58 -0
  347. package/dist/src/time-anchor.js +231 -33
  348. package/dist/src/tool-packet.js +20 -8
  349. package/dist/src/travel-slots.js +58 -35
  350. package/dist/src/travel-timeline.js +44 -63
  351. package/dist/src/turn-deadline.js +287 -0
  352. package/dist/src/turn-policy.js +118 -0
  353. package/dist/src/tz-resolver.js +143 -0
  354. package/dist/src/unified.js +535 -359
  355. package/dist/src/wish-pool.js +42 -12
  356. package/dist/src/write-gate.js +495 -0
  357. package/dist/src/z3-shared.js +284 -0
  358. package/extension/README.md +21 -0
  359. package/extension/README.zh-CN.md +21 -0
  360. package/extension/background.js +463 -0
  361. package/extension/content-bridge.js +270 -0
  362. package/extension/content-main.js +111 -0
  363. package/extension/manifest.json +60 -0
  364. package/package.json +407 -14
  365. package/schemas/booking.intent.schema.json +193 -0
  366. package/schemas/booking.surface.schema.json +2622 -0
  367. package/ts/capabilities/agent-reach-deep.ts +114 -0
  368. package/ts/capabilities/agent-reach.ts +198 -0
  369. package/ts/capabilities/anything.ts +255 -0
  370. package/ts/capabilities/artifacts.ts +428 -0
  371. package/ts/capabilities/fact-log.ts +54 -0
  372. package/ts/capabilities/flyai-config.ts +388 -0
  373. package/ts/capabilities/flyai.ts +1274 -0
  374. package/ts/capabilities/hbcli.ts +253 -71
  375. package/ts/capabilities/incident-log.ts +88 -59
  376. package/ts/capabilities/itinerary-artifact.ts +214 -0
  377. package/ts/capabilities/itinerary-deck-artifact.ts +218 -0
  378. package/ts/capabilities/itinerary-deck-export.ts +378 -0
  379. package/ts/capabilities/opensky.ts +121 -0
  380. package/ts/capabilities/session/action-cache.ts +148 -0
  381. package/ts/capabilities/session/adapters/ctrip-flight.ts +181 -0
  382. package/ts/capabilities/session/adapters/ctrip-hotel.ts +238 -0
  383. package/ts/capabilities/session/adapters/dida-portal.ts +338 -0
  384. package/ts/capabilities/session/adapters/meituan-local.ts +70 -0
  385. package/ts/capabilities/session/adapters/rail-12306.ts +392 -0
  386. package/ts/capabilities/session/benchmark.ts +276 -0
  387. package/ts/capabilities/session/bridge-ledger.ts +333 -0
  388. package/ts/capabilities/session/extension-bridge.ts +794 -0
  389. package/ts/capabilities/session/extension-channel.ts +144 -0
  390. package/ts/capabilities/session/extension-distribution.ts +266 -0
  391. package/ts/capabilities/session/extract.ts +54 -0
  392. package/ts/capabilities/session/golden-score.ts +139 -0
  393. package/ts/capabilities/session/health-watch.ts +264 -0
  394. package/ts/capabilities/session/read-guard.ts +141 -0
  395. package/ts/capabilities/session/static-flight-golden.ts +209 -0
  396. package/ts/capabilities/session/transport.ts +146 -0
  397. package/ts/capabilities/session/wizard.ts +140 -0
  398. package/ts/capabilities/session-consent.ts +211 -0
  399. package/ts/capabilities/session-login.ts +208 -0
  400. package/ts/capabilities/session-search.ts +893 -0
  401. package/ts/capabilities/weather.ts +330 -0
  402. package/ts/dsh-runtime/vendor/README.md +68 -0
  403. package/ts/dsh-runtime/vendor/dsh-map-tools/LICENSE +21 -0
  404. package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +405 -0
  405. package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +404 -0
  406. package/ts/dsh-runtime/vendor/dsh-map-tools/client/client.js +1584 -0
  407. package/ts/dsh-runtime/vendor/dsh-map-tools/cordis.patch.yml +5 -0
  408. package/ts/dsh-runtime/vendor/dsh-map-tools/icon.svg +5 -0
  409. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/amap.js +595 -0
  410. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/nominatim.js +63 -0
  411. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/osrm.js +58 -0
  412. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/photon.js +55 -0
  413. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-file.js +87 -0
  414. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-route.js +131 -0
  415. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config.js +16 -0
  416. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/geo.js +232 -0
  417. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/index.js +120 -0
  418. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +40 -0
  419. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/staticmap-route.js +115 -0
  420. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/geocode.js +127 -0
  421. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/poi.js +84 -0
  422. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/routes.js +267 -0
  423. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/amap.d.ts +90 -0
  424. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/nominatim.d.ts +17 -0
  425. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/osrm.d.ts +15 -0
  426. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/photon.d.ts +22 -0
  427. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-file.d.ts +33 -0
  428. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-route.d.ts +23 -0
  429. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config.d.ts +23 -0
  430. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/geo.d.ts +61 -0
  431. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/index.d.ts +18 -0
  432. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +14 -0
  433. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/staticmap-route.d.ts +31 -0
  434. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/geocode.d.ts +11 -0
  435. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/poi.d.ts +9 -0
  436. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/routes.d.ts +75 -0
  437. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/types.d.ts +68 -0
  438. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types.js +16 -0
  439. package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +97 -0
  440. package/ts/package.json +293 -3
  441. package/ts/scripts/async-collect.ts +91 -0
  442. package/ts/scripts/map-tools-vendor-package-proof.ts +404 -0
  443. package/ts/scripts/skeleton-check.ts +1 -1
  444. package/ts/scripts/skeleton-integration-test.ts +23 -1
  445. package/ts/scripts/state-cli.ts +568 -0
  446. package/ts/scripts/turn-handoff-collect.ts +178 -0
  447. package/ts/src/artifact-gate.ts +991 -0
  448. package/ts/src/benchmark-agent-conformance.ts +619 -0
  449. package/ts/src/benchmark-environment-bridge.ts +538 -0
  450. package/ts/src/benchmark-headless-child-diagnostics.ts +184 -0
  451. package/ts/src/benchmark-tool-isolation.ts +166 -0
  452. package/ts/src/bookable-facts.ts +837 -0
  453. package/ts/src/booking-saga.ts +133 -0
  454. package/ts/src/booking-surface/availability-policy.ts +522 -0
  455. package/ts/src/booking-surface/booking-intent.ts +86 -0
  456. package/ts/src/booking-surface/cancel-refund-commission.ts +488 -0
  457. package/ts/src/booking-surface/canonical-schema.js +116 -0
  458. package/ts/src/booking-surface/contracts.ts +475 -0
  459. package/ts/src/booking-surface/dsh-planner.ts +1949 -0
  460. package/ts/src/booking-surface/dsh-plugin.js +378 -0
  461. package/ts/src/booking-surface/dsh-worker.ts +110 -0
  462. package/ts/src/booking-surface/error-codes.ts +241 -0
  463. package/ts/src/booking-surface/index.ts +9 -0
  464. package/ts/src/booking-surface/managed-dsh-cleanup-diagnostic.ts +151 -0
  465. package/ts/src/booking-surface/managed-dsh-run-port.ts +273 -0
  466. package/ts/src/booking-surface/profile.ts +42 -0
  467. package/ts/src/booking-surface/recovery-chain.ts +409 -0
  468. package/ts/src/booking-surface/runtime.ts +1793 -0
  469. package/ts/src/booking-surface/server.ts +733 -0
  470. package/ts/src/booking-surface/startup.ts +201 -0
  471. package/ts/src/booking-surface/validation.ts +217 -0
  472. package/ts/src/companions.ts +113 -0
  473. package/ts/src/contracts.ts +13 -3
  474. package/ts/src/dsh-llm.ts +44 -11
  475. package/ts/src/flyai-setup-tool.ts +77 -0
  476. package/ts/src/index.ts +1948 -198
  477. package/ts/src/itinerary-deck.ts +189 -0
  478. package/ts/src/itinerary-doc-shared.ts +741 -0
  479. package/ts/src/itinerary-html.ts +171 -0
  480. package/ts/src/loop.ts +223 -25
  481. package/ts/src/memory-capture.ts +283 -0
  482. package/ts/src/memory-decay.ts +55 -0
  483. package/ts/src/memory-utility.ts +70 -0
  484. package/ts/src/mock-llm.ts +4 -8
  485. package/ts/src/model.ts +88 -2
  486. package/ts/src/recall/card.ts +106 -0
  487. package/ts/src/recall/evaluator.ts +170 -0
  488. package/ts/src/recall/integration.ts +35 -0
  489. package/ts/src/recall/tick.ts +213 -0
  490. package/ts/src/session-link/plan-it-action.ts +78 -0
  491. package/ts/src/session-link/session-link.ts +275 -0
  492. package/ts/src/share/adapters.ts +93 -0
  493. package/ts/src/share/share-consent.ts +105 -0
  494. package/ts/src/share/share-deck.ts +85 -0
  495. package/ts/src/share/share-token.ts +166 -0
  496. package/ts/src/slot-spec.ts +172 -0
  497. package/ts/src/state-ledger.ts +912 -0
  498. package/ts/src/subagent-job-id-guard.ts +72 -0
  499. package/ts/src/time-anchor.ts +338 -0
  500. package/ts/src/tool-packet.ts +32 -0
  501. package/ts/src/travel-slots.ts +219 -0
  502. package/ts/src/travel-timeline.ts +83 -0
  503. package/ts/src/turn-deadline.ts +366 -0
  504. package/ts/src/turn-policy.ts +154 -0
  505. package/ts/src/unified.ts +354 -88
  506. package/ts/src/wish-pool.ts +79 -0
  507. package/dist/scripts/session-attach-wait.js +0 -41
@@ -0,0 +1,381 @@
1
+ /**
2
+ * 服务运行时观测补齐测试(§73;#272/#511,2026-10-02 UAT 只读实查证实的两个
3
+ * 证据留存缺口)。
4
+ *
5
+ * 全离线确定性(零网络、零真实供应商、零真实模型调用;所有进程与目录隔离在
6
+ * /tmp 临时根,不写共享产品状态):
7
+ * ① #272 verdict 结构化日志:session-search 模块注入 fake search + verdictLog
8
+ * 收集器,经真 createBackendServer HTTP 面结算——形状断言(键封闭
9
+ * ts/surface/supplier/verdict/latencyMs[+error])/error 摘要 ≤200 字符/
10
+ * cookie·ticket·凭据哨兵脱敏为 [REDACTED]/rates·evidence 回包面永不入日志/
11
+ * 换行压平防日志注入/cooldown·异常路径也各落一行/status 结算面独立 verdict。
12
+ * ② #511 planner 子进程 boot 观测:临时 fixture worker 子进程走真
13
+ * ManagedDshRunPort JSON-lines 协议——boot 成功一行 HARNESS_BOOT_STAGE
14
+ * (initializeMs,mode=reused 不重复打)/worker 握手超时一行
15
+ * HARNESS_BOOT_TIMEOUT(闭集分类+elapsedMs+initializeMs 若可得)/
16
+ * 注入 runPort 的 planner turn 结算 PLANNER_BOOT_TIMEOUT 分类行。
17
+ * ③ #511 gotry-backend 启动阶段行:startGotryBackendFromEnvironment(离线假
18
+ * env,booking-copilot 只做惰性配置解析不 spawn planner)——每个模块挂载一行
19
+ * CORE_BOOT_STAGE(module_mounted)+ listening 一行(port 与句柄一致);
20
+ * 启动失败行 CORE_BOOT_FAILURE 形状与 200 字符有界。
21
+ */
22
+ import assert from 'node:assert/strict';
23
+ import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
24
+ import { tmpdir } from 'node:os';
25
+ import { join } from 'node:path';
26
+ import { startSessionSearchModule } from '../src/backend/modules/session-search.js';
27
+ import { closeBackend, createBackendServer } from '../src/backend/kernel.js';
28
+ import { formatBackendBootFailure, startGotryBackendFromEnvironment } from '../src/gotry-backend.js';
29
+ import { ManagedDshRunPort } from '../src/booking-surface/managed-dsh-run-port.js';
30
+ import { createDshEmbeddedBookingPlanner } from '../src/booking-surface/dsh-planner.js';
31
+ let passed = 0;
32
+ async function check(label, assertion) {
33
+ await assertion();
34
+ passed += 1;
35
+ console.log(` ok - ${label}`);
36
+ }
37
+ const VERDICT_PREFIX = '[session-search] verdict ';
38
+ async function jfetch(url, init = {}) {
39
+ const r = await fetch(url, init);
40
+ const text = await r.text();
41
+ let body;
42
+ try {
43
+ body = JSON.parse(text);
44
+ }
45
+ catch {
46
+ body = { raw: text };
47
+ }
48
+ return { status: r.status, body };
49
+ }
50
+ /** 解析一条 verdict 行:前缀剥离 + JSON 校验 */
51
+ function parseVerdictLine(line) {
52
+ assert.ok(line.startsWith(VERDICT_PREFIX), `verdict 行必须以 ${VERDICT_PREFIX} 开头:${line}`);
53
+ return JSON.parse(line.slice(VERDICT_PREFIX.length));
54
+ }
55
+ async function main() {
56
+ /* ================= ① #272 verdict 结构化日志 ================= */
57
+ console.log('① session-search verdict 结构化日志(#272)');
58
+ const verdictLines = [];
59
+ let fakeResult = {
60
+ ok: true, via: 'session-dida-portal', evidence: '[会话:dida-portal@fixture]', latencyMs: 42, verdict: 'hit', rates: [],
61
+ };
62
+ let fakeError;
63
+ const sessionModule = startSessionSearchModule({
64
+ apiKey: () => 'observability-key',
65
+ search: async () => {
66
+ if (fakeError)
67
+ throw fakeError;
68
+ return fakeResult;
69
+ },
70
+ verdictLog: (line) => verdictLines.push(line),
71
+ });
72
+ const sessionBackend = await createBackendServer({ modules: [sessionModule], port: 0 });
73
+ const base = `http://127.0.0.1:${sessionBackend.port}`;
74
+ const searchInit = {
75
+ method: 'POST',
76
+ headers: { 'content-type': 'application/json', authorization: 'Bearer observability-key' },
77
+ body: JSON.stringify({ supplier: 'dida-portal' }),
78
+ };
79
+ try {
80
+ await check('hit 结算:一行结构化 verdict,键封闭且值正确,回包内容不入日志', async () => {
81
+ // rates 形状对断言无关紧要(仅作为「回包内容」哨兵载体)
82
+ fakeResult = {
83
+ ok: true, via: 'session-dida-portal', evidence: '[会话:dida-portal@SECRET-EVIDENCE]', latencyMs: 42, verdict: 'hit',
84
+ rates: [{ hotelName: 'SECRET-HOTEL-RESPONSE-BODY', price: '100' }],
85
+ };
86
+ const before = verdictLines.length;
87
+ const r = await jfetch(`${base}/v1/session/search`, searchInit);
88
+ assert.equal(r.status, 200);
89
+ assert.equal(verdictLines.length - before, 1, 'hit 结算恰好一行');
90
+ const line = verdictLines.at(-1);
91
+ assert.ok(!line.includes('\n'), 'verdict 行内部不得有换行(日志注入面)');
92
+ assert.ok(!line.includes('SECRET-HOTEL-RESPONSE-BODY'), 'rates 回包内容不入日志');
93
+ assert.ok(!line.includes('SECRET-EVIDENCE'), 'evidence 字段不入日志');
94
+ const record = parseVerdictLine(line);
95
+ assert.deepEqual(Object.keys(record).sort(), ['latencyMs', 'supplier', 'surface', 'ts', 'verdict'], '键封闭:ts/surface/supplier/verdict/latencyMs');
96
+ assert.equal(record.verdict, 'hit');
97
+ assert.equal(record.supplier, 'dida-portal');
98
+ assert.equal(record.surface, 'search');
99
+ assert.equal(record.latencyMs, 42);
100
+ assert.ok(!Number.isNaN(Date.parse(String(record.ts))), 'ts 是可解析时刻');
101
+ assert.ok(/^\d{4}-\d{2}-\d{2}T/.test(String(record.ts)), 'ts 是 ISO 形状');
102
+ });
103
+ await check('error 结算:cookie/ticket/凭据哨兵脱敏为 [REDACTED],摘要 ≤200 字符,单行化', async () => {
104
+ fakeResult = {
105
+ ok: false, via: 'session-dida-portal-error', evidence: '[会话:dida-portal@fixture]', latencyMs: 7, verdict: 'error',
106
+ error: 'extension job failed; cookie SESSION_TICKET=SECRET-TICKET-9F3A; ticket=SECRET-TICKET-2;\nAuthorization: Bearer sk-SECRET-KEY-1; body fragment ignored',
107
+ };
108
+ const before = verdictLines.length;
109
+ const r = await jfetch(`${base}/v1/session/search`, searchInit);
110
+ assert.equal(r.status, 200);
111
+ assert.equal(verdictLines.length - before, 1);
112
+ const line = verdictLines.at(-1);
113
+ assert.ok(!line.includes('SECRET-TICKET-9F3A'), 'cookie 值不得入日志');
114
+ assert.ok(!line.includes('SECRET-TICKET-2'), 'ticket 值不得入日志');
115
+ assert.ok(!line.includes('sk-SECRET-KEY-1'), 'bearer 凭据值不得入日志');
116
+ assert.ok(line.includes('[REDACTED]'), '被脱敏的值以 [REDACTED] 占位');
117
+ assert.ok(!line.includes('\n'), '原始换行被压平(日志注入面)');
118
+ const record = parseVerdictLine(line);
119
+ assert.equal(record.verdict, 'error');
120
+ assert.ok(typeof record.error === 'string' && record.error.length <= 200, `error 摘要 ≤200 字符,实际 ${String(record.error).length}`);
121
+ });
122
+ await check('超长 error 摘要被截断到 ≤200 字符', async () => {
123
+ fakeResult = {
124
+ ok: false, via: 'session-dida-portal-error', evidence: '', latencyMs: 3, verdict: 'error',
125
+ error: `host copy prefix;${'x'.repeat(400)}`,
126
+ };
127
+ await jfetch(`${base}/v1/session/search`, searchInit);
128
+ const record = parseVerdictLine(verdictLines.at(-1));
129
+ assert.ok(typeof record.error === 'string' && record.error.length <= 200 && record.error.length >= 199, '截断后仍 ≤200 且保留信息量');
130
+ assert.ok(record.error.endsWith('…'), '截断以省略号标记');
131
+ });
132
+ await check('cooldown 结算:429 + verdict 行 verdict=cooldown', async () => {
133
+ fakeResult = {
134
+ ok: false, via: 'session-dida-portal-error', evidence: '', latencyMs: 5, verdict: 'cooldown', error: '节律冷却中,30s 后重试',
135
+ };
136
+ const r = await jfetch(`${base}/v1/session/search`, searchInit);
137
+ assert.equal(r.status, 429);
138
+ const record = parseVerdictLine(verdictLines.at(-1));
139
+ assert.equal(record.verdict, 'cooldown');
140
+ });
141
+ await check('异常结算:500 + verdict 行 verdict=error 且异常消息里的凭据脱敏', async () => {
142
+ fakeError = new Error('search crashed cookie=LEAK-COOKIE-77');
143
+ try {
144
+ const r = await jfetch(`${base}/v1/session/search`, searchInit);
145
+ assert.equal(r.status, 500);
146
+ }
147
+ finally {
148
+ fakeError = undefined;
149
+ }
150
+ const line = verdictLines.at(-1);
151
+ assert.ok(!line.includes('LEAK-COOKIE-77'), '异常消息里的 cookie 值不得入日志');
152
+ const record = parseVerdictLine(line);
153
+ assert.equal(record.verdict, 'error');
154
+ assert.ok(typeof record.latencyMs === 'number' && record.latencyMs >= 0, 'latencyMs 非负');
155
+ });
156
+ await check('status 结算:surface=status,扩展未连接时 verdict=needs-extension', async () => {
157
+ const before = verdictLines.length;
158
+ const r = await jfetch(`${base}/v1/session/status`, { headers: { authorization: 'Bearer observability-key' } });
159
+ assert.equal(r.status, 200);
160
+ assert.equal(verdictLines.length - before, 1);
161
+ const record = parseVerdictLine(verdictLines.at(-1));
162
+ assert.equal(record.surface, 'status');
163
+ assert.equal(record.verdict, 'needs-extension');
164
+ assert.equal(record.supplier, 'dida-portal');
165
+ assert.ok(typeof record.latencyMs === 'number' && record.latencyMs >= 0);
166
+ });
167
+ await check('非 verdict 结算(鉴权失败 403)不落 verdict 行', async () => {
168
+ const before = verdictLines.length;
169
+ const r = await jfetch(`${base}/v1/session/search`, {
170
+ method: 'POST', headers: { 'content-type': 'application/json', authorization: 'Bearer wrong' }, body: JSON.stringify({ supplier: 'dida-portal' }),
171
+ });
172
+ assert.equal(r.status, 403);
173
+ assert.equal(verdictLines.length - before, 0, '鉴权拒绝不是检索结算');
174
+ });
175
+ }
176
+ finally {
177
+ await closeBackend(sessionBackend, [sessionModule]);
178
+ }
179
+ /* ================= ② #511 planner 子进程 boot 观测 ================= */
180
+ console.log('② planner 子进程 boot 观测(#511)');
181
+ const bootScratch = mkdtempSync(join(tmpdir(), 'gotry-obs-boot-'));
182
+ try {
183
+ // fixture worker:真 ManagedDshRunPort JSON-lines 协议;首请求报 started 握手,
184
+ // 后续报 reused(拒绝 HARNESS_BOOT_TIMEOUT 的独立 fixture 在下方)。
185
+ const bootWorkerPath = join(bootScratch, 'boot-fixture-worker.mjs');
186
+ writeFileSync(bootWorkerPath, [
187
+ "import { createInterface } from 'node:readline'",
188
+ "process.stdout.write(JSON.stringify({ lifecycle: 'worker_started', workerPid: process.pid, parentPid: process.ppid }) + '\\n')",
189
+ "const input = createInterface({ input: process.stdin, crlfDelay: Infinity })",
190
+ "input.on('line', (line) => {",
191
+ ' const request = JSON.parse(line)',
192
+ ' const first = !globalThis.__booted',
193
+ ' globalThis.__booted = true',
194
+ " process.stdout.write(JSON.stringify({ id: request.id, boot: first ? { initializeMs: 531, mode: 'started' } : { initializeMs: 0, mode: 'reused' } }) + '\\n')",
195
+ " process.stdout.write(JSON.stringify({ id: request.id, ok: true, result: { finalResponse: '', events: [], notifications: [] } }) + '\\n')",
196
+ '})',
197
+ '',
198
+ ].join('\n'), { encoding: 'utf8' });
199
+ await check('boot 成功:每个子进程一行 HARNESS_BOOT_STAGE(role+initializeMs);reused 不重复打', async () => {
200
+ const bootLines = [];
201
+ const port = new ManagedDshRunPort({ workerPath: bootWorkerPath, cleanupRole: 'task', graceMs: 50, bootLog: (line) => bootLines.push(line) });
202
+ try {
203
+ await port.run('fixture', { sessionId: 'observability-boot' });
204
+ assert.deepEqual(bootLines, ['HARNESS_BOOT_STAGE {"role":"task","initializeMs":531,"mode":"started"}'], '首启动恰好一行,含 initializeMs');
205
+ assert.deepEqual(port.bootObservation(), { initializeMs: 531, mode: 'started' });
206
+ await port.run('fixture-two', { sessionId: 'observability-boot' });
207
+ assert.deepEqual(port.bootObservation(), { initializeMs: 0, mode: 'reused' });
208
+ assert.equal(bootLines.length, 1, 'reused 没有再 boot,不再打行');
209
+ }
210
+ finally {
211
+ await port.close();
212
+ }
213
+ });
214
+ const timeoutWorkerPath = join(bootScratch, 'boot-timeout-fixture-worker.mjs');
215
+ writeFileSync(timeoutWorkerPath, [
216
+ "import { createInterface } from 'node:readline'",
217
+ "process.stdout.write(JSON.stringify({ lifecycle: 'worker_started', workerPid: process.pid, parentPid: process.ppid }) + '\\n')",
218
+ "const input = createInterface({ input: process.stdin, crlfDelay: Infinity })",
219
+ "input.on('line', (line) => {",
220
+ ' const request = JSON.parse(line)',
221
+ ` process.stdout.write(JSON.stringify({ id: request.id, ok: false, error: 'HARNESS_BOOT_TIMEOUT' }) + '\\n')`,
222
+ '})',
223
+ '',
224
+ ].join('\n'), { encoding: 'utf8' });
225
+ await check('worker 握手超时:HARNESS_BOOT_TIMEOUT 行(闭集分类+elapsedMs+initializeMs=null)', async () => {
226
+ const bootLines = [];
227
+ const port = new ManagedDshRunPort({ workerPath: timeoutWorkerPath, cleanupRole: 'task', graceMs: 50, bootLog: (line) => bootLines.push(line) });
228
+ try {
229
+ await assert.rejects(() => port.run('fixture', { sessionId: 'observability-boot-timeout' }), /HARNESS_BOOT_TIMEOUT/);
230
+ assert.equal(bootLines.length, 1);
231
+ const line = bootLines[0];
232
+ assert.ok(line.startsWith('HARNESS_BOOT_TIMEOUT '), `行前缀必须是 HARNESS_BOOT_TIMEOUT:${line}`);
233
+ const record = JSON.parse(line.slice('HARNESS_BOOT_TIMEOUT '.length));
234
+ assert.equal(record.role, 'task');
235
+ assert.equal(record.initializeMs, null, '握手从未完成,initializeMs 不可得即为 null');
236
+ assert.ok(typeof record.elapsedMs === 'number' && record.elapsedMs >= 0, 'elapsedMs 时刻差非负');
237
+ }
238
+ finally {
239
+ await port.close();
240
+ }
241
+ });
242
+ await check('planner 结算:boot 超时分类 PLANNER_BOOT_TIMEOUT 行(initializeMs/mode 不可得即 null)', async () => {
243
+ const availability = {
244
+ initialized: true, recoveryStarted: false, availabilityPhase: 'need_offers', activeHotelOrdinal: 0,
245
+ hotelRefs: [], hotels: {}, attempts: [], queryReservations: [],
246
+ };
247
+ const task = {
248
+ schemaVersion: 'booking.surface',
249
+ taskId: 'task-observability-boot-1',
250
+ contextRef: 'ctx-observability-boot-1',
251
+ surface: 'tenant',
252
+ revision: 0,
253
+ allowedActions: ['search.patch', 'search.run'],
254
+ userTurnCount: 1,
255
+ lastTurnId: 'turn-observability-boot-1',
256
+ operationCount: 0,
257
+ phase: 'planning',
258
+ lastSequence: 0,
259
+ availability,
260
+ };
261
+ const workspace = {
262
+ schemaVersion: 'booking.surface',
263
+ contextRef: task.contextRef,
264
+ surface: 'tenant',
265
+ revision: 0,
266
+ locale: 'zh-CN',
267
+ currency: 'CNY',
268
+ searchDraft: {},
269
+ results: { status: 'idle' },
270
+ visibleHotels: [],
271
+ loadedOffers: [],
272
+ shortlistedOfferRefs: [],
273
+ capabilities: { surface: 'tenant', allowedActions: ['search.patch', 'search.run'] },
274
+ };
275
+ task.workspaceSnapshot = workspace;
276
+ const turn = {
277
+ schemaVersion: 'booking.surface',
278
+ kind: 'user.turn',
279
+ taskId: task.taskId,
280
+ turnId: task.lastTurnId,
281
+ workspace,
282
+ request: { text: 'Find hotels' },
283
+ };
284
+ const captured = [];
285
+ const originalStderrWrite = process.stderr.write.bind(process.stderr);
286
+ process.stderr.write = ((chunk) => {
287
+ captured.push(typeof chunk === 'string' ? chunk : Buffer.from(chunk).toString('utf8'));
288
+ return true;
289
+ });
290
+ let planner;
291
+ try {
292
+ const factoryPort = {
293
+ run: () => Promise.reject(new Error('HARNESS_BOOT_TIMEOUT')),
294
+ async close() { },
295
+ bootObservation: () => undefined,
296
+ };
297
+ planner = await createDshEmbeddedBookingPlanner({ runPortFactory: () => factoryPort, turnTimeoutMs: 1_000 });
298
+ const decisions = await planner.plannerFactory(task).next({ task, turn });
299
+ assert.equal(decisions[0]?.kind, 'error');
300
+ assert.equal(decisions[0].error?.code, 'PLANNER_BOOT_TIMEOUT');
301
+ await planner.close();
302
+ planner = undefined;
303
+ const line = captured.find((value) => value.startsWith('PLANNER_BOOT_TIMEOUT '));
304
+ assert.ok(line, '服务进程 stderr 必须出现 PLANNER_BOOT_TIMEOUT 行');
305
+ const record = JSON.parse(line.slice('PLANNER_BOOT_TIMEOUT '.length).trim());
306
+ assert.deepEqual(record, { initializeMs: null, mode: null });
307
+ }
308
+ finally {
309
+ process.stderr.write = originalStderrWrite;
310
+ await planner?.close().catch(() => undefined);
311
+ }
312
+ });
313
+ }
314
+ finally {
315
+ rmSync(bootScratch, { recursive: true, force: true });
316
+ }
317
+ /* ================= ③ #511 gotry-backend 启动阶段行 ================= */
318
+ console.log('③ gotry-backend 启动阶段行(#511)');
319
+ const backendScratch = mkdtempSync(join(tmpdir(), 'gotry-obs-backend-'));
320
+ let backendHandle;
321
+ try {
322
+ await check('启动:每模块一行 module_mounted + 一行 listening(port 与句柄一致)', async () => {
323
+ const stageLines = [];
324
+ backendHandle = await startGotryBackendFromEnvironment({
325
+ GOTRY_BACKEND_PORT: '0',
326
+ GOTRY_BACKEND_SESSION_API_KEY: 'observability-session-key',
327
+ GOTRY_BACKEND_STATE_ROOT: backendScratch,
328
+ GOTRY_BOOKING_COPILOT_API_KEY: 'observability-copilot-key',
329
+ GOTRY_BOOKING_COPILOT_STATE_ROOT: backendScratch,
330
+ DEEPSEEK_API_KEY: 'offline-fake-key-planner-not-spawned-at-boot',
331
+ }, (line) => stageLines.push(line));
332
+ const records = stageLines.map((line) => {
333
+ assert.ok(line.startsWith('CORE_BOOT_STAGE '), `启动阶段行前缀必须是 CORE_BOOT_STAGE:${line}`);
334
+ return JSON.parse(line.slice('CORE_BOOT_STAGE '.length));
335
+ });
336
+ const mounted = records.filter((record) => record.phase === 'module_mounted');
337
+ assert.deepEqual(mounted.map((record) => record.module), ['booking-copilot', 'session-search', 'booking-executor'], '每个模块挂载一行,按挂载顺序');
338
+ for (const record of mounted) {
339
+ assert.ok(typeof record.elapsedMs === 'number' && record.elapsedMs >= 0, 'module_mounted 携带非负 elapsedMs');
340
+ }
341
+ const listening = records.at(-1);
342
+ assert.equal(listening.phase, 'listening');
343
+ assert.equal(listening.port, backendHandle.port, 'listening 行端口与句柄一致');
344
+ assert.equal(listening.modules, 'booking-copilot,session-search,booking-executor');
345
+ });
346
+ await check('启动失败行:CORE_BOOT_FAILURE 数组形状,error 摘要 ≤200 字符', () => {
347
+ const line = formatBackendBootFailure(new Error('x'.repeat(500)));
348
+ assert.ok(line.startsWith('CORE_BOOT_FAILURE '), '启动失败行前缀必须是 CORE_BOOT_FAILURE');
349
+ const [record] = JSON.parse(line.slice('CORE_BOOT_FAILURE '.length));
350
+ assert.equal(record.phase, 'startup');
351
+ assert.ok(record.error.length <= 200 && record.error.length === 200, '500 字符消息被截到 200');
352
+ assert.ok(!line.includes('\n'), '失败行单行');
353
+ });
354
+ await check('启动失败(缺 booking-copilot key):同一函数落 CORE_BOOT_FAILURE 后原样抛出', async () => {
355
+ const failureLines = [];
356
+ await assert.rejects(() => startGotryBackendFromEnvironment({
357
+ GOTRY_BACKEND_PORT: '0',
358
+ GOTRY_BACKEND_SESSION_API_KEY: 'observability-session-key',
359
+ // GOTRY_BOOKING_COPILOT_API_KEY 缺失 → booking_copilot_api_key_required
360
+ }, (line) => failureLines.push(line)), /booking_copilot_api_key_required/);
361
+ const line = failureLines.find((value) => value.startsWith('CORE_BOOT_FAILURE '));
362
+ assert.ok(line, '模块挂载失败必须经启动函数落 CORE_BOOT_FAILURE(bin 包装层直接调本函数)');
363
+ const [record] = JSON.parse(line.slice('CORE_BOOT_FAILURE '.length));
364
+ assert.equal(record.phase, 'startup');
365
+ assert.ok(!line.includes('offline-fake-key'), '失败行不含密钥材料');
366
+ });
367
+ await check('健康面可达后干净关闭', async () => {
368
+ const r = await jfetch(`http://127.0.0.1:${backendHandle.port}/healthz`, { headers: { authorization: 'Bearer observability-copilot-key' } });
369
+ assert.ok(r.status === 200 || r.status === 503, `healthz 探活可达(实际 ${r.status})`);
370
+ });
371
+ }
372
+ finally {
373
+ await backendHandle?.close().catch(() => undefined);
374
+ rmSync(backendScratch, { recursive: true, force: true });
375
+ }
376
+ console.log(`\n§73 observability: ${passed} 段全绿`);
377
+ }
378
+ main().catch((error) => {
379
+ console.error('FAIL:', error);
380
+ process.exit(1);
381
+ });
@@ -0,0 +1,161 @@
1
+ /**
2
+ * onboarding UX 测试(issue #21 onboarding UX,§3.3 ADR-21 上架后重设,run-all §40)。
3
+ *
4
+ * 4 段全离线断言(wizard 2026-09-02 缩为 2 步纯 Node 端:扩展落位 + watch precheck):
5
+ * 1. wizard --dry-run:零网络零浏览器零 GUI spawn,exit 0,2 步齐全
6
+ * 2. health-watch 三时序:0ms ready(立即 timeout)/ 5s ready(中途 ready)/ 120s+1ms 超时
7
+ * 3. retry-after-watch:needs-extension → watch ready → 自动重放同 query_id 同参数
8
+ * 4. wizard 无强制 spawn:forcePlatform 参数彻底消失(GUI 跨平台降级退役)
9
+ *
10
+ * 离线纪律:不打真 Chrome、不发真请求;wizard 不需要 spawn 注入(stub 注入路径仍在但 dry-run 路径不调)。
11
+ */
12
+ import assert from 'node:assert/strict';
13
+ import { runOnboardingWizard, defaultExtensionDir, describeExtensionDir, } from '../capabilities/session/wizard.js';
14
+ import { startExtensionHealthWatch, withAutoRetryOnExtension, HEALTH_WATCH_INTERVAL_FLOOR_MS, HEALTH_WATCH_INTERVAL_CEIL_MS, } from '../capabilities/session/health-watch.js';
15
+ let passed = 0;
16
+ function check(label, fn) {
17
+ return Promise.resolve()
18
+ .then(fn)
19
+ .then(() => { passed += 1; console.log(` ok - ${label}`); });
20
+ }
21
+ function noopSpawn() {
22
+ const { EventEmitter } = require('node:events');
23
+ const child = new EventEmitter();
24
+ // 流对象 stub
25
+ const stream = new EventEmitter();
26
+ child.stdin = stream;
27
+ child.stdout = null;
28
+ child.stderr = null;
29
+ child.unref = () => undefined;
30
+ return child;
31
+ }
32
+ function captureSpawn() {
33
+ const calls = [];
34
+ const spawn = ((bin, args = []) => {
35
+ calls.push({ bin, args });
36
+ return noopSpawn();
37
+ });
38
+ return { spawn, calls };
39
+ }
40
+ async function asyncSleep(ms) {
41
+ if (ms <= 0)
42
+ return;
43
+ await new Promise((resolve) => setTimeout(resolve, ms));
44
+ }
45
+ console.log('ONBOARDING UX (§40)');
46
+ await check('1. wizard --dry-run 零网络零浏览器零 GUI spawn,exit 0,2 步齐全', async () => {
47
+ const result = await runOnboardingWizard({ dryRun: true });
48
+ assert.equal(result.ok, true, `wizard ok 应 true,实际 ${JSON.stringify(result.steps)}`);
49
+ assert.equal(result.steps.length, 2, `应有 2 步,实际 ${result.steps.length}`);
50
+ const expected = ['ensure-extension-files', 'watch-extension-ready'];
51
+ for (let i = 0; i < expected.length; i++) {
52
+ assert.equal(result.steps[i].step, expected[i]);
53
+ assert.equal(result.steps[i].status, 'skip', `dry-run 每步应为 skip,${result.steps[i].step} 实为 ${result.steps[i].status}`);
54
+ }
55
+ });
56
+ await check('2. health-watch 三时序:0ms / 中途 / 120s+1ms', async () => {
57
+ // (a) timeoutMs=0 → 立即 timeout
58
+ const w0 = startExtensionHealthWatch({ timeoutMs: 0, intervalMs: 10 });
59
+ const o0 = await w0.waitReady();
60
+ assert.equal(o0.ready, false);
61
+ assert.equal(o0.reason, 'timeout');
62
+ // (b) 中途 ready:第一次 probe false,第二次 true(30ms 后)
63
+ let probeCalls = 0;
64
+ const wMid = startExtensionHealthWatch({
65
+ timeoutMs: 500,
66
+ intervalMs: 30,
67
+ probe: async () => { probeCalls += 1; return probeCalls >= 2; },
68
+ });
69
+ const oMid = await wMid.waitReady();
70
+ assert.equal(oMid.ready, true, `中途 ready 实为 ${JSON.stringify(oMid)}`);
71
+ assert.ok(oMid.attempts >= 2);
72
+ // (c) 永不 ready → timeout(用极小 timeoutMs+全 false probe 模拟)
73
+ const wTimeout = startExtensionHealthWatch({
74
+ timeoutMs: 60,
75
+ intervalMs: 20,
76
+ probe: async () => false,
77
+ });
78
+ const oTimeout = await wTimeout.waitReady();
79
+ assert.equal(oTimeout.ready, false);
80
+ assert.equal(oTimeout.reason, 'timeout');
81
+ });
82
+ await check('3. wizard 完全不调 spawn(GUI 面板/剪贴板/直开浏览器均已退役)', async () => {
83
+ // 2026-09-02 上架后:wizard 缩为 2 步纯 Node 端职责(扩展落位 + watch precheck),
84
+ // 不弹 osascript/zenity、不动 pbcopy/xclip/clip、不 open 浏览器。
85
+ // 这里只校验 dry-run 与无源目录 fail 路径都不产生 spawn 调用。
86
+ const dry = captureSpawn();
87
+ await runOnboardingWizard({ dryRun: true, sourceDir: '/', extensionDir: '/tmp/none' });
88
+ assert.equal(dry.calls.length, 0, `dry-run 不应 spawn 任何命令(实调 ${dry.calls.length})`);
89
+ const fail = captureSpawn();
90
+ // dryRun=false + 不存在的源目录 → ensure 会 fail,但应仍不产生 spawn 调用
91
+ await runOnboardingWizard({ dryRun: false, sourceDir: '/nonexistent-source-dir-for-onboarding-tests', extensionDir: '/tmp/none-fail' });
92
+ assert.equal(fail.calls.length, 0, `fail 路径也不应 spawn(实调 ${fail.calls.length})`);
93
+ });
94
+ await check('4. retry-after-watch:needs-extension → watch ready → 自动重放同 query_id', async () => {
95
+ let fetchCalls = 0;
96
+ const queryId = 'sf-01';
97
+ const fetch = async () => {
98
+ fetchCalls += 1;
99
+ return { query_id: queryId, verdict: 'needs-extension', needsExt: fetchCalls === 1 };
100
+ };
101
+ // 第一次 → needs-extension,启 watch
102
+ const first = await fetch();
103
+ assert.equal(first.verdict, 'needs-extension');
104
+ let probeCount = 0;
105
+ const watch = startExtensionHealthWatch({
106
+ timeoutMs: 1_000,
107
+ intervalMs: 20,
108
+ probe: async () => { probeCount += 1; return probeCount >= 2; },
109
+ });
110
+ const outcome = await watch.waitReady();
111
+ assert.equal(outcome.ready, true);
112
+ // watch ready → 自动重放同 query_id
113
+ const retry = await fetch();
114
+ assert.equal(retry.query_id, queryId, '同 query_id 必须保持');
115
+ assert.equal(fetchCalls, 2, `应调用 fetch 两次(首次 + 重放),实 ${fetchCalls}`);
116
+ });
117
+ await check('5. wizard 不依赖 platform/panel 参数(GUI 跨平台降级退役)', async () => {
118
+ // 2026-09-02 上架后:wizard 不再接 forcePlatform/spawn panel 参数,
119
+ // 任何对 wizard 的调用都是 2 步(ensure + watch precheck)。
120
+ const result = await runOnboardingWizard({ dryRun: true, extensionDir: '/tmp/gotry-test-ext-2' });
121
+ assert.equal(result.steps.length, 2, `应 2 步,实 ${result.steps.length}`);
122
+ assert.equal(result.steps[0].step, 'ensure-extension-files');
123
+ assert.equal(result.steps[1].step, 'watch-extension-ready');
124
+ assert.equal(result.platform, undefined, 'platform 字段应不再存在');
125
+ });
126
+ await check('6. withAutoRetryOnExtension 端到端:首次 needs-ext → 自动重放', async () => {
127
+ let callCount = 0;
128
+ let ready = false;
129
+ // watch 第一次 probe 后 30ms 标记 ready(模拟用户装完扩展)
130
+ setTimeout(() => { ready = true; }, 30);
131
+ const args = {
132
+ fetch: async () => {
133
+ callCount += 1;
134
+ return callCount === 1 ? { needsExt: true } : { needsExt: false, hit: true };
135
+ },
136
+ isExtensionNeeded: (r) => r.needsExt === true,
137
+ watch: { timeoutMs: 1_000, intervalMs: 20, probe: async () => ready },
138
+ };
139
+ const out = await withAutoRetryOnExtension(args);
140
+ assert.equal(out.retried, true, `应触发重放,实 retried=${out.retried}`);
141
+ assert.equal(out.attempts, 2);
142
+ assert.equal(out.result.needsExt, false);
143
+ assert.equal(out.result.hit, true);
144
+ assert.equal(callCount, 2, `withAutoRetry 应调 2 次 fetch,实 ${callCount}`);
145
+ });
146
+ await check('7. health-watch interval 边界常量与 watch 契约对齐', () => {
147
+ assert.ok(HEALTH_WATCH_INTERVAL_FLOOR_MS >= 1_000, '下界不应让 watch 风暴');
148
+ assert.ok(HEALTH_WATCH_INTERVAL_CEIL_MS <= 44_000, '上界应 < EXTENSION_CONNECTED_WINDOW_MS');
149
+ });
150
+ await check('8. defaultExtensionDir = ~/.gotry/extension(契约对齐 bootstrap 节)', () => {
151
+ const dir = defaultExtensionDir();
152
+ assert.match(dir, /\.gotry[\\/]extension$/, `扩展目录形态应是 ~/.gotry/extension,实 ${dir}`);
153
+ });
154
+ await check('9. describeExtensionDir:不存在的目录不抛错,返回 exists:false', () => {
155
+ const desc = describeExtensionDir('/nonexistent/zzz');
156
+ assert.equal(desc.exists, false);
157
+ assert.equal(desc.fileCount, 0);
158
+ assert.equal(desc.hasManifest, false);
159
+ });
160
+ await asyncSleep(0);
161
+ console.log(`ONBOARDING UX (§40): ${passed} pass`);
@@ -1,20 +1,25 @@
1
+ /**
2
+ * OpenSky 校验桥(M2 段 3 第一件,§7-1 免费路线的校验层):验证某航班真实执飞。
3
+ * 零新依赖:匿名 REST(400 credits/天),失败降级为「校验不可用」而非阻塞规划。
4
+ * 证据链:[实时API:opensky] + 抓取时间;查不到≠不存在(ADS-B 覆盖有限),只作正向印证。
5
+ * 运行:cd ts && npx tsx scripts/opensky-check.ts EK329
6
+ */
1
7
  const BASE = 'https://opensky-network.org/api';
2
8
  async function checkArrival(callsign, airport) {
9
+ // 匿名窗口只支持近 7 天;演示用最近的到达查询验证桥通不通
3
10
  const now = Math.floor(Date.now() / 1000);
4
- const url = airport ? `${BASE}/arrivals?airport=${airport}&begin=${now - 7 * 86400}&end=${now}` : `${BASE}/arrivals?airport=OMDB&begin=${now - 7 * 86400}&end=${now}`;
5
- const res = await fetch(url, {
6
- headers: {
7
- Accept: 'application/json'
8
- }
9
- });
10
- if (!res.ok) return `[校验不可用:opensky ${res.status}]`;
11
- const data = await res.json();
12
- const hit = data.find((a)=>(a.callsign ?? '').trim().toUpperCase().includes(callsign.toUpperCase()));
11
+ const url = airport
12
+ ? `${BASE}/arrivals?airport=${airport}&begin=${now - 7 * 86400}&end=${now}`
13
+ : `${BASE}/arrivals?airport=OMDB&begin=${now - 7 * 86400}&end=${now}`;
14
+ const res = await fetch(url, { headers: { Accept: 'application/json' } });
15
+ if (!res.ok)
16
+ return `[校验不可用:opensky ${res.status}]`;
17
+ const data = (await res.json());
18
+ const hit = data.find(a => (a.callsign ?? '').trim().toUpperCase().includes(callsign.toUpperCase()));
13
19
  const ts = new Date().toISOString();
14
- return hit ? `[实时API:opensky@${ts}] ✅ ${callsign} 近 7 天执飞记录:到达 ${hit.arrivalAirport ?? '?'}(callsign ${hit.callsign?.trim()})` : `[实时API:opensky@${ts}] ○ 近 7 天 ${airport ?? 'OMDB'} 到达列表未见 ${callsign}(ADS-B 覆盖有限,不作否定结论)`;
20
+ return hit
21
+ ? `[实时API:opensky@${ts}] ✅ ${callsign} 近 7 天执飞记录:到达 ${hit.arrivalAirport ?? '?'}(callsign ${hit.callsign?.trim()})`
22
+ : `[实时API:opensky@${ts}] ○ 近 7 天 ${airport ?? 'OMDB'} 到达列表未见 ${callsign}(ADS-B 覆盖有限,不作否定结论)`;
15
23
  }
16
24
  const target = process.argv[2] ?? 'EK329';
17
25
  console.log(await checkArrival(target, process.argv[3] ?? null));
18
-
19
-
20
- //# sourceURL=/Users/bytedance/work/gotry/ts/scripts/opensky-check.ts