@danceiny/gotry 0.0.1-rc.8 → 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 (506) hide show
  1. package/README.md +172 -217
  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 -49
  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 +968 -0
  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 +126 -0
  42. package/dist/capabilities/session/adapters/ctrip-flight.js +141 -0
  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 +54 -0
  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 +50 -0
  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 +107 -0
  56. package/dist/capabilities/session/static-flight-golden.js +150 -0
  57. package/dist/capabilities/session/transport.js +109 -0
  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 +686 -0
  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 +72 -0
  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 +68 -10
  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 +67 -0
  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 +480 -0
  191. package/dist/scripts/ledger-workflow-crash.js +32 -0
  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 +49 -0
  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 +29 -31
  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 +43 -42
  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 +31 -0
  227. package/dist/scripts/session-attach-poc.js +62 -0
  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 +60 -0
  231. package/dist/scripts/session-link-tests.js +478 -0
  232. package/dist/scripts/session-login.js +29 -0
  233. package/dist/scripts/session-tests.js +862 -0
  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 +703 -219
  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 +261 -0
  253. package/dist/scripts/state-cli.js +585 -0
  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 +59 -0
  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 +86 -0
  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 +2305 -731
  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 +358 -162
  325. package/dist/src/memory-capture.js +180 -32
  326. package/dist/src/memory-decay.js +47 -0
  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 +767 -0
  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 +59 -0
  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 +538 -360
  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 +296 -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 +2107 -224
  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 +278 -40
  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 +360 -89
  506. package/ts/src/wish-pool.ts +79 -0
@@ -0,0 +1,331 @@
1
+ /**
2
+ * #138 指标面板第一切片:只读聚合呈现面 v1(ADR-11 质量层,工程面交付)。
3
+ *
4
+ * 聚合既有落盘侧车(不新增任何数据源)→ 单一 markdown 报告:
5
+ * - 事实闸 verdict 分布 + blocked 牊(<stateRoot>/gotry-state/bookable-facts.jsonl)
6
+ * - 通道健康 down/cooldown('ok' 恢复事件 latest-wins 超越;<stateRoot>/gotry-state/channel-health.jsonl,30 天窗,
7
+ * 与 doctor 持久面 readLatestChannelEvents 同口径)
8
+ * - 事故面(<stateRoot>/gotry-state/incidents.jsonl,--days 窗,默认 7)
9
+ * - 桥延迟 p50/p95/max + >500ms 违约计数(<stateRoot>/gotry-state/bridge-latency.jsonl;
10
+ * >500ms 是架构 §11 复审节奏的触发锚点,这里给出可见性)
11
+ * - 账本存在性(gotry-state.db 只 stat:openDb 建连即可能写 kv,指标面不打开 SQLite)
12
+ * - doctor 报告存在性 + 评测三层入口指针(运行结果由 run-all-tests.sh/CI 承载,v1 不重跑评测)
13
+ *
14
+ * 纪律:全程只读(缺文件=空节;坏行跳过,与 incidents/fact-log 同纪律);
15
+ * 默认写 stdout,仅 --out 指定路径时落盘;零新依赖零 LLM;
16
+ * 工程面交付,不构成 M3 Exit 证据(#138 口径,Exit 证据归 #22)。
17
+ *
18
+ * 运行:npx tsx ts/scripts/build-metrics-report.ts [--state-root <dir>] [--out <file>] [--days <N>]
19
+ */
20
+ import { existsSync, readFileSync, statSync, writeFileSync } from 'node:fs';
21
+ import { isAbsolute, join, resolve } from 'node:path';
22
+ const BRIDGE_LATENCY_BUDGET_MS = 500;
23
+ const CHANNEL_WINDOW_DAYS = 30;
24
+ function stateFile(stateRoot, name) {
25
+ const root = stateRoot === '.' ? process.cwd() : stateRoot;
26
+ return join(root, 'gotry-state', name);
27
+ }
28
+ /** 坏行跳过的 JSONL 读取(与 incidents/fact-log/channel-health 同纪律) */
29
+ function readJsonl(path) {
30
+ if (!existsSync(path))
31
+ return [];
32
+ try {
33
+ const rows = [];
34
+ for (const line of readFileSync(path, 'utf-8').split('\n')) {
35
+ const t = line.trim();
36
+ if (!t)
37
+ continue;
38
+ try {
39
+ rows.push(JSON.parse(t));
40
+ }
41
+ catch { /* 单行损坏不拖垮聚合 */ }
42
+ }
43
+ return rows;
44
+ }
45
+ catch {
46
+ return [];
47
+ }
48
+ }
49
+ function bounded(value, max = 120) {
50
+ if (!value)
51
+ return undefined;
52
+ return value.length <= max ? value : `${value.slice(0, max - 1)}…`;
53
+ }
54
+ const BLOCKED_VERDICTS = new Set(['error', 'needs-setup']);
55
+ /** 同 fact_id 取最新(与 loadFactRegistry 的 dedupe 同语义;行序后者胜) */
56
+ export function aggregateFacts(rows) {
57
+ const latest = new Map();
58
+ let lines = 0;
59
+ for (const raw of rows) {
60
+ const row = (typeof raw === 'object' && raw !== null ? raw : {});
61
+ lines += 1;
62
+ const id = typeof row.fact_id === 'string' ? row.fact_id : '';
63
+ if (!id)
64
+ continue;
65
+ latest.set(id, row);
66
+ }
67
+ const byKind = {};
68
+ for (const row of latest.values()) {
69
+ const kind = typeof row.kind === 'string' && row.kind ? row.kind : 'unknown';
70
+ const verdict = typeof row.verdict === 'string' && row.verdict ? row.verdict : 'n/a';
71
+ const slot = (byKind[kind] ??= { total: 0, verdicts: {}, blocked: 0 });
72
+ slot.total += 1;
73
+ slot.verdicts[verdict] = (slot.verdicts[verdict] ?? 0) + 1;
74
+ if (BLOCKED_VERDICTS.has(verdict))
75
+ slot.blocked += 1;
76
+ }
77
+ return { lines, deduped: latest.size, byKind };
78
+ }
79
+ export function aggregateChannels(rows, opts = {}) {
80
+ const nowMs = (opts.now ?? new Date()).getTime();
81
+ const cutoff = nowMs - (opts.windowDays ?? CHANNEL_WINDOW_DAYS) * 86_400_000;
82
+ const counts = new Map();
83
+ const newest = new Map();
84
+ // ok 超越(外部事件接缝第 1 段):通道最新事件若为 'ok'(本地探针恢复),
85
+ // 该通道从「当前 down/cooldown」展示面退出——down 计数(历史频率)保留。
86
+ const lastState = new Map();
87
+ for (const raw of rows) {
88
+ const row = (typeof raw === 'object' && raw !== null ? raw : {});
89
+ if (typeof row.channel !== 'string' || !row.channel)
90
+ continue;
91
+ if (typeof row.state === 'string' && ['down', 'cooldown', 'ok'].includes(row.state)) {
92
+ lastState.set(row.channel, row.state);
93
+ }
94
+ }
95
+ for (const raw of rows) {
96
+ const row = (typeof raw === 'object' && raw !== null ? raw : {});
97
+ if (typeof row.channel !== 'string' || !row.channel)
98
+ continue;
99
+ if (row.state !== 'down' && row.state !== 'cooldown')
100
+ continue;
101
+ if (lastState.get(row.channel) === 'ok')
102
+ continue;
103
+ const at = typeof row.at === 'string' ? row.at : '';
104
+ const atMs = Date.parse(at);
105
+ if (Number.isFinite(atMs) && atMs < cutoff)
106
+ continue;
107
+ counts.set(row.channel, (counts.get(row.channel) ?? 0) + 1);
108
+ const atMsSafe = Number.isFinite(atMs) ? atMs : 0;
109
+ const prev = newest.get(row.channel);
110
+ if (prev && prev.atMs >= atMsSafe)
111
+ continue;
112
+ newest.set(row.channel, {
113
+ channel: row.channel,
114
+ state: row.state,
115
+ reason: typeof row.reason === 'string' ? row.reason : undefined,
116
+ at: at || undefined,
117
+ events: 0,
118
+ atMs: atMsSafe,
119
+ });
120
+ }
121
+ const latest = [...newest.values()].map(({ atMs: _atMs, ...row }) => ({
122
+ ...row,
123
+ events: counts.get(row.channel) ?? 0,
124
+ }));
125
+ return { windowDays: opts.windowDays ?? CHANNEL_WINDOW_DAYS, latest };
126
+ }
127
+ export function aggregateIncidents(rows, opts = {}) {
128
+ const nowMs = (opts.now ?? new Date()).getTime();
129
+ const windowDays = opts.windowDays ?? 7;
130
+ const cutoff = nowMs - windowDays * 86_400_000;
131
+ const byKind = {};
132
+ const sources = new Map();
133
+ let total = 0;
134
+ for (const raw of rows) {
135
+ const row = (typeof raw === 'object' && raw !== null ? raw : {});
136
+ const ts = typeof row.ts === 'string' ? row.ts : '';
137
+ const atMs = Date.parse(ts);
138
+ if (Number.isFinite(atMs) && atMs < cutoff)
139
+ continue;
140
+ const kind = typeof row.kind === 'string' && row.kind ? row.kind : 'unknown';
141
+ const slot = (byKind[kind] ??= { count: 0 });
142
+ slot.count += 1;
143
+ if (!slot.lastTs || (Number.isFinite(atMs) && atMs > Date.parse(slot.lastTs))) {
144
+ slot.lastTs = ts || slot.lastTs;
145
+ slot.lastMessage = bounded(typeof row.message === 'string' ? row.message : undefined);
146
+ }
147
+ const source = typeof row.source === 'string' && row.source ? row.source : '(unknown)';
148
+ sources.set(source, (sources.get(source) ?? 0) + 1);
149
+ total += 1;
150
+ }
151
+ const topSources = [...sources.entries()]
152
+ .sort((a, b) => b[1] - a[1])
153
+ .slice(0, 5)
154
+ .map(([source, count]) => ({ source, count }));
155
+ return { windowDays, totalInWindow: total, byKind, topSources };
156
+ }
157
+ export function aggregateLatency(rows, opts = {}) {
158
+ const nowMs = (opts.now ?? new Date()).getTime();
159
+ const cutoff = nowMs - (opts.windowDays ?? 7) * 86_400_000;
160
+ const values = [];
161
+ const kinds = new Map();
162
+ for (const raw of rows) {
163
+ const row = (typeof raw === 'object' && raw !== null ? raw : {});
164
+ const ts = typeof row.ts === 'string' ? row.ts : '';
165
+ const atMs = Date.parse(ts);
166
+ if (Number.isFinite(atMs) && atMs < cutoff)
167
+ continue;
168
+ const ms = typeof row.latencyMs === 'number' ? row.latencyMs : Number.NaN;
169
+ if (!Number.isFinite(ms))
170
+ continue;
171
+ values.push(ms);
172
+ const kind = typeof row.kind === 'string' && row.kind ? row.kind : 'unknown';
173
+ kinds.set(kind, (kinds.get(kind) ?? 0) + 1);
174
+ }
175
+ const sorted = [...values].sort((a, b) => a - b);
176
+ const pick = (q) => (sorted.length === 0 ? 0 : sorted[Math.min(sorted.length - 1, Math.ceil(q * sorted.length) - 1)]);
177
+ return {
178
+ count: sorted.length,
179
+ p50: pick(0.5),
180
+ p95: pick(0.95),
181
+ max: sorted.length === 0 ? 0 : sorted[sorted.length - 1],
182
+ overBudget: sorted.filter((ms) => ms > BRIDGE_LATENCY_BUDGET_MS).length,
183
+ budgetMs: BRIDGE_LATENCY_BUDGET_MS,
184
+ topKinds: [...kinds.entries()].sort((a, b) => b[1] - a[1]).slice(0, 5).map(([kind, count]) => ({ kind, count })),
185
+ };
186
+ }
187
+ function presenceOf(path) {
188
+ try {
189
+ if (!existsSync(path))
190
+ return { exists: false };
191
+ const st = statSync(path);
192
+ return { exists: true, bytes: st.size, mtime: st.mtime.toISOString() };
193
+ }
194
+ catch {
195
+ return { exists: false };
196
+ }
197
+ }
198
+ export async function collectMetrics(stateRoot, opts = {}) {
199
+ const root = resolve(stateRoot === '.' ? process.cwd() : stateRoot);
200
+ return {
201
+ generatedAt: (opts.now ?? new Date()).toISOString(),
202
+ stateRoot: root,
203
+ facts: aggregateFacts(readJsonl(stateFile(stateRoot, 'bookable-facts.jsonl'))),
204
+ channels: aggregateChannels(readJsonl(stateFile(stateRoot, 'channel-health.jsonl')), { now: opts.now, windowDays: CHANNEL_WINDOW_DAYS }),
205
+ incidents: aggregateIncidents(readJsonl(stateFile(stateRoot, 'incidents.jsonl')), { now: opts.now, windowDays: opts.days ?? 7 }),
206
+ latency: aggregateLatency(readJsonl(stateFile(stateRoot, 'bridge-latency.jsonl')), { now: opts.now, windowDays: opts.days ?? 7 }),
207
+ ledger: presenceOf(stateFile(stateRoot, 'gotry-state.db')),
208
+ doctorReport: presenceOf(stateFile(stateRoot, 'doctor-report.md')),
209
+ };
210
+ }
211
+ function fmtRate(blocked, total) {
212
+ return total === 0 ? '—' : `${blocked}/${total}(${((blocked / total) * 100).toFixed(0)}%)`;
213
+ }
214
+ function fmtBytes(bytes) {
215
+ if (bytes === undefined)
216
+ return '—';
217
+ return bytes >= 1_048_576 ? `${(bytes / 1_048_576).toFixed(1)}MB` : `${bytes}B`;
218
+ }
219
+ export function renderMetricsReport(s) {
220
+ const L = [];
221
+ L.push(`# GoTry 质量指标报告(只读聚合,#138 第一切片)`);
222
+ L.push('');
223
+ L.push(`- 生成时间:${s.generatedAt}`);
224
+ L.push(`- stateRoot:\`${s.stateRoot}\`(全程只读,零 SQLite 打开)`);
225
+ L.push(`- 口径:工程面交付,不构成 M3 Exit 证据(Exit 证据归 issue #22)`);
226
+ L.push('');
227
+ L.push('## 事实闸 verdict 分布(bookable-facts.jsonl,同 fact_id 取最新)');
228
+ L.push('');
229
+ const kinds = Object.entries(s.facts.byKind);
230
+ if (kinds.length === 0) {
231
+ L.push('(空:无事实落盘)');
232
+ }
233
+ else {
234
+ L.push('| kind | 去重后 | verdict 分布 | blocked(error+needs-setup) |');
235
+ L.push('|---|---|---|---|');
236
+ for (const [kind, st] of kinds) {
237
+ const dist = Object.entries(st.verdicts).map(([v, n]) => `${v}:${n}`).join(' / ');
238
+ L.push(`| ${kind} | ${st.total} | ${dist} | ${fmtRate(st.blocked, st.total)} |`);
239
+ }
240
+ L.push('');
241
+ L.push(`原始行 ${s.facts.lines},去重后 ${s.facts.deduped}(重查重放幂等)。`);
242
+ }
243
+ L.push('');
244
+ L.push(`## 通道健康(channel-health.jsonl,${s.channels.windowDays} 天窗;hit 即清除,此处只见当前处于 down/cooldown 的通道;'ok' 恢复事件已超越)`);
245
+ L.push('');
246
+ if (s.channels.latest.length === 0) {
247
+ L.push('(空:窗口内无 down/cooldown 事件)');
248
+ }
249
+ else {
250
+ L.push('| 通道 | 最新状态 | 原因 | 时间 | 窗口事件 |');
251
+ L.push('|---|---|---|---|---|');
252
+ for (const c of s.channels.latest) {
253
+ L.push(`| ${c.channel} | ${c.state} | ${bounded(c.reason ?? '', 60) ?? '—'} | ${c.at ?? '—'} | ${c.events} |`);
254
+ }
255
+ }
256
+ L.push('');
257
+ L.push(`## 事故面(incidents.jsonl,${s.incidents.windowDays} 天窗)`);
258
+ L.push('');
259
+ const incidentKinds = Object.entries(s.incidents.byKind);
260
+ if (incidentKinds.length === 0) {
261
+ L.push('(空:窗口内无事故)');
262
+ }
263
+ else {
264
+ L.push('| kind | 次数 | 最近一次 |');
265
+ L.push('|---|---|---|');
266
+ for (const [kind, st] of incidentKinds) {
267
+ L.push(`| ${kind} | ${st.count} | ${st.lastTs ?? '—'}${st.lastMessage ? ` · ${st.lastMessage}` : ''} |`);
268
+ }
269
+ const src = s.incidents.topSources.map((t) => `${t.source}×${t.count}`).join(', ');
270
+ if (src) {
271
+ L.push('');
272
+ L.push(`Top 来源:${src}`);
273
+ }
274
+ }
275
+ L.push('');
276
+ L.push(`## 桥延迟(bridge-latency.jsonl,${s.incidents.windowDays} 天窗;预算 ${s.latency.budgetMs}ms,超限即复审锚点)`);
277
+ L.push('');
278
+ if (s.latency.count === 0) {
279
+ L.push('(空:窗口内无延迟记录)');
280
+ }
281
+ else {
282
+ const kinds = s.latency.topKinds.map((t) => `${t.kind}×${t.count}`).join(', ');
283
+ L.push(`样本 ${s.latency.count}:p50=${s.latency.p50}ms · p95=${s.latency.p95}ms · max=${s.latency.max}ms · 超预算(>${s.latency.budgetMs}ms)= **${s.latency.overBudget}**`);
284
+ if (kinds)
285
+ L.push(`按 kind:${kinds}`);
286
+ }
287
+ L.push('');
288
+ L.push('## 账本与体检报告');
289
+ L.push('');
290
+ L.push(`- 账本 gotry-state.db:${s.ledger.exists ? `存在(${fmtBytes(s.ledger.bytes)},更新 ${s.ledger.mtime};明细经 \`npx @danceiny/gotry state\` 查看,指标面不打开 SQLite)` : '不存在(该 stateRoot 无账本)'}`);
291
+ L.push(`- doctor 报告 doctor-report.md:${s.doctorReport.exists ? `存在(更新 ${s.doctorReport.mtime})` : '不存在(跑 `npx @danceiny/gotry doctor` 生成)'}`);
292
+ L.push('');
293
+ L.push('## 评测三层入口(ADR-11;运行结果由 run-all-tests.sh / CI 承载,v1 不在此重跑)');
294
+ L.push('');
295
+ L.push('- 单元/合同/golden E2E:`./scripts/run-all-tests.sh`(全绿是任何提交前闸)');
296
+ L.push('- 合同层样例:`evaluation-contract-tests.ts`;golden E2E:`benchmark-environment-bridge-e2e.ts`;typed 契约 canary:`typed-contract-canary.ts`');
297
+ L.push('');
298
+ return L.join('\n');
299
+ }
300
+ // ---- CLI ---------------------------------------------------------------------
301
+ export function parseArgs(argv) {
302
+ let stateRoot = '.';
303
+ let out;
304
+ let days = 7;
305
+ for (let i = 0; i < argv.length; i += 1) {
306
+ const a = argv[i];
307
+ if (a === '--state-root')
308
+ stateRoot = argv[++i] ?? stateRoot;
309
+ else if (a === '--out')
310
+ out = argv[++i];
311
+ else if (a === '--days')
312
+ days = Math.max(1, Number.parseInt(argv[++i] ?? '7', 10) || 7);
313
+ }
314
+ return { stateRoot: isAbsolute(stateRoot) ? stateRoot : resolve(stateRoot), out, days };
315
+ }
316
+ export async function main(argv, injectedNow) {
317
+ const { stateRoot, out, days } = parseArgs(argv);
318
+ const now = injectedNow ?? new Date();
319
+ const snapshot = await collectMetrics(stateRoot, { days, now });
320
+ const markdown = renderMetricsReport(snapshot);
321
+ if (out) {
322
+ writeFileSync(out, markdown + '\n', 'utf-8');
323
+ process.stdout.write(`指标报告已写 ${out}(stateRoot 只读未动)\n`);
324
+ }
325
+ else {
326
+ process.stdout.write(markdown + '\n');
327
+ }
328
+ }
329
+ const invokedDirectly = process.argv[1] && import.meta.url === new URL(`file://${resolve(process.argv[1])}`).href;
330
+ if (invokedDirectly)
331
+ await main(process.argv.slice(2));
@@ -0,0 +1,118 @@
1
+ /**
2
+ * CHANGELOG 生成器合同测试(run-all §42;2026-08-30 owner 拍板补 changelog 机制)。
3
+ * 纯函数、零网络、零 git 调用:
4
+ * - Conventional Commits 解析:feat/fix/perf/refactor/docs/test/build/ci/chore/revert + scope + ! + PR 引用
5
+ * - 不符合 Conventional 的 commit → other 桶(不丢历史)
6
+ * - groupCommits 按 Keep a Changelog 显示顺序输出
7
+ * - renderMarkdownEntry 节结构(Added/Changed/Fixed/...)
8
+ * - prependEntry:不覆盖 CHANGELOG.md 历史段,只在顶部插入新版本段
9
+ * - splitChangelog:preamble/history 分隔正确
10
+ */
11
+ import assert from 'node:assert/strict';
12
+ import { buildEntry, groupCommits, parseCommit, prependEntry, renderMarkdownEntry, splitChangelog, } from './build-changelog.js';
13
+ let passed = 0;
14
+ function ok(label) {
15
+ passed += 1;
16
+ console.log(` ok ${label}`);
17
+ }
18
+ // ---- 1. parseCommit:Conventional 完整形态 ----
19
+ const sample = parseCommit('feat(cost): 价表 provider-aware v2 + 价格漂移监测 (#68)');
20
+ assert.ok(sample);
21
+ assert.equal(sample.type, 'feat');
22
+ assert.equal(sample.scope, 'cost');
23
+ assert.equal(sample.subject, '价表 provider-aware v2 + 价格漂移监测');
24
+ assert.equal(sample.prRef, '68');
25
+ ok('parseCommit feat(scope)! + #PR');
26
+ // ---- 2. parseCommit:不带 scope ----
27
+ const noScope = parseCommit('fix: 修复登录页可见性');
28
+ assert.equal(noScope.type, 'fix');
29
+ assert.equal(noScope.scope, null);
30
+ assert.equal(noScope.subject, '修复登录页可见性');
31
+ assert.equal(noScope.prRef, null);
32
+ ok('parseCommit fix 无 scope');
33
+ // ---- 3. parseCommit:不符合 Conventional → other 桶,保留原文 ----
34
+ const other = parseCommit('docs: README 更新');
35
+ assert.equal(other.type, 'docs');
36
+ const legacy = parseCommit('feat(issue #21 P3.6): 会话扩展 onboarding UX 闭环(点点点 + 装完零重跑)');
37
+ assert.equal(legacy.type, 'feat');
38
+ assert.equal(legacy.scope, 'issue #21 P3.6');
39
+ const historical = parseCommit('Merge branch main into feat/x');
40
+ assert.equal(historical.type, 'other');
41
+ assert.equal(historical.subject, 'Merge branch main into feat/x');
42
+ ok('parseCommit 历史 commit + 中文 subject + 无 #PR 兼容');
43
+ // ---- 4. parseCommit:perf/refactor/docs/test/build/ci/chore/revert 全覆盖 ----
44
+ for (const t of ['perf', 'refactor', 'docs', 'test', 'build', 'ci', 'chore', 'revert']) {
45
+ const p = parseCommit(`${t}: 一些改动`);
46
+ assert.equal(p.type, t);
47
+ }
48
+ ok('parseCommit 全 9 类型支持');
49
+ // ---- 5. groupCommits:Keep a Changelog 显示顺序 ----
50
+ const commits = [
51
+ { sha: 'aaa', type: 'fix', scope: null, subject: 'fix bug', prRef: '1', raw: '' },
52
+ { sha: 'bbb', type: 'feat', scope: null, subject: 'add feature', prRef: '2', raw: '' },
53
+ { sha: 'ccc', type: 'docs', scope: null, subject: 'update docs', prRef: null, raw: '' },
54
+ { sha: 'ddd', type: 'other', scope: null, subject: 'random commit', prRef: null, raw: '' },
55
+ ];
56
+ const grouped = groupCommits(commits);
57
+ assert.equal(grouped.length, 4);
58
+ assert.equal(grouped[0].type, 'feat');
59
+ assert.equal(grouped[1].type, 'fix');
60
+ assert.equal(grouped[2].type, 'docs');
61
+ assert.equal(grouped[3].type, 'other');
62
+ ok('groupCommits Keep a Changelog 显示顺序(Added → Fixed → Documentation → Other)');
63
+ // ---- 6. renderMarkdownEntry:节结构 + PR 引用 + sha 后缀 ----
64
+ // 用较长 subject 避开 truncate 逻辑(短 subject 仍可能触发 breaker,断言用「包含」而非「完全等」)
65
+ const entry = buildEntry({ version: '0.0.1-rc.16', date: '2026-08-30', commits: [
66
+ { sha: 'aaa', type: 'feat', scope: null, subject: 'add a brand new feature with substantial description text', prRef: '2', raw: '' },
67
+ { sha: 'bbb', type: 'fix', scope: null, subject: 'fix a critical bug in the rendering path of the parser', prRef: '1', raw: '' },
68
+ { sha: 'ccc', type: 'docs', scope: null, subject: 'update the documentation for the new auth module', prRef: null, raw: '' },
69
+ ] });
70
+ const md = renderMarkdownEntry(entry);
71
+ assert.match(md, /^## \[0\.0\.1-rc\.16\] - 2026-08-30/);
72
+ assert.match(md, /### Added/);
73
+ assert.match(md, /### Fixed/);
74
+ assert.match(md, /### Documentation/);
75
+ assert.match(md, /- add a brand new feature[^()]*\(#2\)/);
76
+ assert.match(md, /- fix a critical bug[^()]*\(#1\)/);
77
+ assert.match(md, /- update the documentation[^()]*\(ccc\)/); // sha 后缀(无 PR)
78
+ ok('renderMarkdownEntry 节结构 + PR/sha 后缀');
79
+ // ---- 7. prependEntry:不覆盖 CHANGELOG.md 历史段 ----
80
+ const existing = `# Changelog
81
+
82
+ All notable changes to this project will be documented in this file.
83
+
84
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
85
+
86
+ ## [0.0.1-rc.15] - 2026-08-29
87
+
88
+ ### Added
89
+ - 预订 saga 状态机
90
+ `;
91
+ const newMd = renderMarkdownEntry(entry);
92
+ const next = prependEntry(existing, newMd);
93
+ assert.match(next, /## \[0\.0\.1-rc\.16\] - 2026-08-30/);
94
+ assert.match(next, /## \[0\.0\.1-rc\.15\] - 2026-08-29/);
95
+ assert.match(next, /预订 saga 状态机/);
96
+ ok('prependEntry:新版本段在顶部,历史段原样保留');
97
+ // ---- 8. prependEntry:空文件 → 仅生成 CHANGELOG header + 新段 ----
98
+ const fromEmpty = prependEntry('', newMd);
99
+ assert.match(fromEmpty, /Keep a Changelog/);
100
+ assert.match(fromEmpty, /## \[0\.0\.1-rc\.16\]/);
101
+ ok('prependEntry:空文件首次生成');
102
+ // ---- 9. splitChangelog:preamble 与 history 分割 ----
103
+ const split = splitChangelog(existing);
104
+ assert.ok(split.preamble.includes('All notable changes'));
105
+ assert.ok(split.history[0].includes('## [0.0.1-rc.15]'));
106
+ ok('splitChangelog preamble/history 分隔正确');
107
+ // ---- 10. buildEntry 空 sections 不崩(空 commit 列表)----
108
+ const emptyEntry = buildEntry({ version: '0.0.1-rc.16', date: '2026-08-30', commits: [] });
109
+ const emptyMd = renderMarkdownEntry(emptyEntry);
110
+ assert.match(emptyMd, /## \[0\.0\.1-rc\.16\]/);
111
+ ok('buildEntry 空 commit 列表 → 仍输出版本头(0 section,合规)');
112
+ // ---- 11. parseCommit:! 标记(breaking change)----
113
+ const breaking = parseCommit('feat(api)!: 重命名端点 /v1/users → /v2/users (#99)');
114
+ assert.equal(breaking.type, 'feat');
115
+ assert.equal(breaking.subject, '重命名端点 /v1/users → /v2/users');
116
+ assert.equal(breaking.prRef, '99');
117
+ ok('parseCommit feat(scope)!: breaking change marker 容错');
118
+ console.log(`changelog tests: ${passed} 组断言全绿(纯函数)`);
@@ -0,0 +1,103 @@
1
+ /**
2
+ * 通道探针 tick 测试(外部事件接缝第 1 段,issue #82 兼容方向;全离线):
3
+ * 1. evaluateProbeResults 纯函数:fail→down / ok+此前down→'ok'恢复 / ok+健康→零写 / skip→不产事件
4
+ * 2. readLatestChannelEvents latest-wins:'ok' 事件超越同通道更早的 down(恢复语义落地)
5
+ * 3. doctor 消费口径:恢复后 `state === 'down'` 判定不再命中(飞行可达性注释消失)
6
+ * 4. metrics aggregateChannels:'ok' 超越后 newest 不含该通道,down 事件计数保留(历史频率面)
7
+ * 5. CLI:--list 列探测面(session 系与 flyai 显式 skip);--only 未匹配 exit 2
8
+ * 6. requireValidTimestamp opt-in(#436):坏时间戳行(未来/缺/坏)不得在 latest-wins
9
+ * 覆盖前顶掉同通道更早的有效 down;默认口径(doctor/metrics/探针)不变
10
+ *
11
+ * 运行: cd ts && npx tsx scripts/channel-probe-tests.ts
12
+ */
13
+ import assert from 'node:assert/strict';
14
+ import { mkdtemp, writeFile, mkdir, readFile } from 'node:fs/promises';
15
+ import { tmpdir } from 'node:os';
16
+ import { join } from 'node:path';
17
+ import { evaluateProbeResults, defaultProbes, parseArgs, main } from './channel-probe.js';
18
+ import { readLatestChannelEvents } from '../capabilities/channel-health.js';
19
+ import { aggregateChannels } from './build-metrics-report.js';
20
+ const tmp = await mkdtemp(join(tmpdir(), 'gotry-probe-test-'));
21
+ // ── 1. evaluateProbeResults 纯函数 ───────────────────────────────────────────
22
+ const probes = defaultProbes();
23
+ const hb = probes.find((p) => p.channel === 'hbcli-hotel');
24
+ const om = probes.find((p) => p.channel === 'open-meteo');
25
+ const fly = probes.find((p) => p.channel === 'flyai');
26
+ const now = new Date('2026-09-07T12:00:00Z');
27
+ const evs = evaluateProbeResults([
28
+ { probe: hb, result: { ok: false, reason: 'auth-denied', ms: 5 } },
29
+ { probe: om, result: { ok: true, ms: 100 } },
30
+ { probe: fly, result: { ok: true, ms: 0 } },
31
+ ], new Set(['open-meteo']), now);
32
+ assert.equal(evs.length, 2, `fail→down + ok恢复→'ok' 共 2 条,实际 ${evs.length}`);
33
+ assert.deepEqual({ channel: evs[0].channel, state: evs[0].state, reason: evs[0].reason }, { channel: 'hbcli-hotel', state: 'down', reason: 'auth-denied' }, 'fail 应产 down 事件带 reason');
34
+ assert.deepEqual({ channel: evs[1].channel, state: evs[1].state }, { channel: 'open-meteo', state: 'ok' }, 'ok 且此前 down 应产 ok 恢复事件');
35
+ const noWrites = evaluateProbeResults([{ probe: om, result: { ok: true, ms: 90 } }], new Set(), now);
36
+ assert.equal(noWrites.length, 0, 'ok 且此前健康 → 零写放大');
37
+ // ── 2. latest-wins:'ok' 超越更早的 down ──────────────────────────────────────
38
+ const stateRoot = join(tmp, 'state');
39
+ await mkdir(join(stateRoot, 'gotry-state'), { recursive: true });
40
+ const jsonl = join(stateRoot, 'gotry-state', 'channel-health.jsonl');
41
+ await writeFile(jsonl, [
42
+ JSON.stringify({ channel: 'opensky', state: 'down', reason: 'http-503', at: '2026-09-07T10:00:00.000Z' }),
43
+ JSON.stringify({ channel: 'opensky', state: 'ok', at: '2026-09-07T11:00:00.000Z' }),
44
+ JSON.stringify({ channel: 'hbcli-hotel', state: 'down', reason: 'auth-denied', at: '2026-09-07T10:30:00.000Z' }),
45
+ 'not-json-garbage',
46
+ '',
47
+ ].join('\n'), 'utf-8');
48
+ const latest = await readLatestChannelEvents(stateRoot, { now: Date.parse('2026-09-07T12:00:00Z') });
49
+ assert.equal(latest.get('opensky')?.state, 'ok', "'ok' 应超越同通道更早的 down");
50
+ assert.equal(latest.get('hbcli-hotel')?.state, 'down', '未恢复通道保持 down');
51
+ assert.equal(latest.size, 2, '坏行跳过,latest 只含两通道');
52
+ // ── 3. doctor 消费口径:恢复后 '=== down' 不命中 ─────────────────────────────
53
+ const openskyEv = latest.get('opensky');
54
+ assert.ok(openskyEv && openskyEv.state !== 'down', 'doctor 的 down 判定应不再命中已恢复通道');
55
+ // ── 4. metrics:ok 超越后 newest 不含该通道,计数保留 ─────────────────────────
56
+ const rows = (await readFile(jsonl, 'utf-8')).split('\n').filter((l) => l.trim()).flatMap((l) => {
57
+ try {
58
+ return [JSON.parse(l)];
59
+ }
60
+ catch {
61
+ return [];
62
+ }
63
+ });
64
+ const stats = aggregateChannels(rows, { now: new Date('2026-09-07T12:00:00Z'), windowDays: 30 });
65
+ const openskyStat = stats.latest.find((c) => c.channel === 'opensky');
66
+ assert.equal(openskyStat, undefined, 'ok 超越的通道不应出现在当前 down/cooldown newest 面');
67
+ const hbStat = stats.latest.find((c) => c.channel === 'hbcli-hotel');
68
+ assert.ok(hbStat && hbStat.state === 'down', '未恢复通道仍在 newest 面');
69
+ // ── 5. CLI 面 ────────────────────────────────────────────────────────────────
70
+ const listed = defaultProbes();
71
+ assert.ok(listed.find((p) => p.channel === 'flyai')?.probeable === false, 'flyai 默认不探(共享额度)');
72
+ assert.ok(listed.filter((p) => p.channel.startsWith('session:')).every((p) => !p.probeable), 'session:* 全部 skip');
73
+ assert.deepEqual(parseArgs(['--state-root', '/tmp/x', '--only', 'a, b', '--dry-run']), { stateRoot: '/tmp/x', only: ['a', 'b'], dryRun: true, list: false }, 'parseArgs 解析');
74
+ const rcList = await main(['--list']);
75
+ assert.equal(rcList, 0, '--list exit 0');
76
+ const rcBad = await main(['--only', 'no-such-channel']);
77
+ assert.equal(rcBad, 2, '--only 未匹配 exit 2');
78
+ // ── 6. requireValidTimestamp opt-in(#436):坏时间戳不得顶掉更早的有效 down ────
79
+ const strictRoot = join(tmp, 'strict');
80
+ await mkdir(join(strictRoot, 'gotry-state'), { recursive: true });
81
+ const strictJsonl = join(strictRoot, 'gotry-state', 'channel-health.jsonl');
82
+ const strictNow = Date.parse('2026-09-07T12:00:00Z');
83
+ const validDownRow = JSON.stringify({ channel: 'session:ctrip-flight', state: 'down', reason: 'challenged', at: '2026-09-07T10:00:00.000Z' });
84
+ const unusableRows = [
85
+ ['未来 down', JSON.stringify({ channel: 'session:ctrip-flight', state: 'down', reason: 'clock-skew', at: '2026-09-08T10:00:00.000Z' })],
86
+ ['未来 ok', JSON.stringify({ channel: 'session:ctrip-flight', state: 'ok', at: '2026-09-08T10:00:00.000Z' })],
87
+ ['缺时间戳 ok', JSON.stringify({ channel: 'session:ctrip-flight', state: 'ok' })],
88
+ ['坏时间戳 down', JSON.stringify({ channel: 'session:ctrip-flight', state: 'down', reason: 'bad-at', at: 'not-a-date' })],
89
+ ['过期 down', JSON.stringify({ channel: 'session:ctrip-flight', state: 'down', reason: 'stale', at: '2026-08-01T10:00:00.000Z' })],
90
+ ];
91
+ for (const [label, badRow] of unusableRows) {
92
+ await writeFile(strictJsonl, `${validDownRow}\n${badRow}\n`, 'utf-8');
93
+ const strict = await readLatestChannelEvents(strictRoot, { now: strictNow, requireValidTimestamp: true });
94
+ assert.equal(strict.get('session:ctrip-flight')?.state, 'down', `有效 down 之后的${label}行不得顶掉它(严格模式)`);
95
+ const legacy = await readLatestChannelEvents(strictRoot, { now: strictNow });
96
+ assert.ok(legacy.has('session:ctrip-flight'), '默认口径仍读得到该通道(未改老消费者)');
97
+ }
98
+ await writeFile(strictJsonl, `${validDownRow}\n${JSON.stringify({ channel: 'session:ctrip-flight', state: 'ok', at: '2026-09-07T11:30:00.000Z' })}\n`, 'utf-8');
99
+ assert.equal((await readLatestChannelEvents(strictRoot, { now: strictNow, requireValidTimestamp: true })).get('session:ctrip-flight')?.state, 'ok', '保留期内的有效 ok 仍能恢复(latest-wins 不变)');
100
+ await writeFile(strictJsonl, `${JSON.stringify({ channel: 'session:ctrip-flight', state: 'down', at: '2026-09-08T10:00:00.000Z' })}\n`, 'utf-8');
101
+ assert.ok(!(await readLatestChannelEvents(strictRoot, { now: strictNow, requireValidTimestamp: true })).has('session:ctrip-flight'), '全坏行文件在严格模式下不产生该通道的行(不压制)');
102
+ assert.ok((await readLatestChannelEvents(strictRoot, { now: strictNow })).get('session:ctrip-flight')?.state === 'down', '默认口径保持旧行为:未来 down 仍被读出(opt-in 才改)');
103
+ console.log('CHANNEL PROBE TESTS: 6/6 OK(evaluate 纯函数 / latest-wins 恢复 / doctor 口径 / metrics 超越 / CLI 面 / 严格时间戳 opt-in #436)');