@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,161 @@
1
+ /**
2
+ * M3 nightly 证据生产器合同测试(run-all §35,issue #22 验收⑥「nightly real-LLM 与成本质量证据可复跑」)。
3
+ * 全确定性、零网络、零 API 花费:
4
+ * - 封存价表仅可审计换算(peak 保守上界),未知模型 fail-closed,usage 缺失 fail-closed;
5
+ * - run_key 确定性 + 记录必须过消费方 parseNightlyRun(生产器写的就是评分器读的);
6
+ * - 无凭证 = waiting_external_evidence,不写任何文件(issue #22 停机纪律);
7
+ * - --dry-run mock 全链演练可跑通且绝不落盘。
8
+ * 真跑(花钱)不在 CI:heartbeat/founder 手动 `npx tsx scripts/nightly-evidence.ts`。
9
+ *
10
+ * 价表 schema 演进(issue #49):v1 (legacy DeepSeek only) / v2 (provider-aware;DeepSeek+MiniMax);
11
+ * 本测试在 v2 形态下覆盖:DeepSeek alias、裸模型名、MiniMax 跨 provider 命中、跨 provider 守门、
12
+ * MiniMax flat_no_offpeak 纪律同价守门、未声明 schema_version 拒绝、unknown model fail-closed、
13
+ * usage 缺失 fail-closed、run_key 确定性 + 消费方 parseNightlyRun、无凭证 waiting、dry-run 零落盘。
14
+ */
15
+ import assert from 'node:assert/strict';
16
+ import { existsSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
17
+ import { join } from 'node:path';
18
+ import { tmpdir } from 'node:os';
19
+ import { buildNightlyRunRecord, loadPriceTable, loadPromptSet, priceRunCost, runNightlyEvidence, } from './nightly-evidence.js';
20
+ import { parseNightlyRun } from './product-metrics.js';
21
+ let passed = 0;
22
+ function ok(label) {
23
+ passed += 1;
24
+ console.log(` ok ${label}`);
25
+ }
26
+ // ---- 1. 封存文件可加载,schema v2 + provider-aware alias/裸模型双查找(以仓库内真正随发的数据文件为夹具) ----
27
+ const priceTable = loadPriceTable('data/llm-price-table.json');
28
+ const promptSet = loadPromptSet('data/m3-nightly-prompts.json');
29
+ assert.equal(priceTable.schema_version, 'gotry_llm_price_table_v2');
30
+ assert.equal(promptSet.schema_version, 'gotry_m3_nightly_prompt_set_v1');
31
+ assert.ok(promptSet.turns.length >= 1);
32
+ assert.ok(priceTable.prices['deepseek-v4-flash'], '裸键 deepseek-v4-flash 必须可查');
33
+ assert.ok(priceTable.prices['MiniMax-M3'], '裸键 MiniMax-M3 必须可查(provider 为单一时透明)');
34
+ assert.ok(priceTable.prices['minimax:MiniMax-M3'], 'qualified 键 minimax:MiniMax-M3 必须可查');
35
+ assert.ok(priceTable.aliases['deepseek-chat'], 'deepseek-chat 必须在 aliases 表');
36
+ assert.equal(priceTable.aliases['deepseek-chat'], 'deepseek-v4-flash');
37
+ ok('v2 schema 载入 + 裸键 + qualified 键 + alias 双查找');
38
+ // ---- 2. 保守上界不变量:每个价目 hit<=miss 且 offpeak<=peak(只高不低) ----
39
+ for (const [name, entry] of Object.entries(priceTable.prices)) {
40
+ assert.ok(entry.input_cache_hit_usd_per_1m_peak <= entry.input_cache_miss_usd_per_1m_peak, `${name} hit<=miss`);
41
+ assert.ok(entry.output_usd_per_1m_offpeak <= entry.output_usd_per_1m_peak, `${name} offpeak<=peak`);
42
+ }
43
+ ok('价目保守上界不变量(hit<=miss, offpeak<=peak)');
44
+ // ---- 3. 换算数学:deepseek-chat -> v4-flash peak(miss 1M + 1M out = 1.76) ----
45
+ const baseUsage = {
46
+ calls: 3,
47
+ inputTokens: 1_000_000,
48
+ outputTokens: 1_000_000,
49
+ inputCacheHitTokens: 0,
50
+ inputCacheMissTokens: 1_000_000,
51
+ responsesMissingUsage: 0,
52
+ };
53
+ const cost = priceRunCost('deepseek-chat', baseUsage, priceTable);
54
+ assert.equal(cost, 1.76); // 0.44 + 1.32
55
+ ok('peak miss 换算 0.44+1.32=1.76(经 alias)');
56
+ const hitUsage = { ...baseUsage, inputCacheHitTokens: 1_000_000, inputCacheMissTokens: 0 };
57
+ assert.equal(priceRunCost('deepseek-chat', hitUsage, priceTable), 1.334); // 0.014+1.32
58
+ ok('peak hit 换算 0.014+1.32=1.334');
59
+ // ---- 3b. MiniMax-M3 peak 换算(issue #49 验收):miss 1M + 1M out = 3.00(0.60+2.40,ADR-11 保守上界) ----
60
+ const m3cost = priceRunCost('MiniMax-M3', baseUsage, priceTable);
61
+ assert.equal(m3cost, 3.00); // 0.60 + 2.40
62
+ ok('MiniMax-M3 peak miss 换算 0.60+2.40=3.00');
63
+ const m3hit = priceRunCost('MiniMax-M3', hitUsage, priceTable);
64
+ assert.equal(m3hit, 2.52); // 0.12+2.40
65
+ ok('MiniMax-M3 peak hit 换算 0.12+2.40=2.52');
66
+ // ---- 3c. MiniMax flat_no_offpeak 纪律:peak 与 offpeak 列同价 —— 给定用量下两种策略产出同一价格 ----
67
+ const m3prov = priceTable.prices['minimax:MiniMax-M3'];
68
+ assert.equal(m3prov.input_cache_miss_usd_per_1m_peak, m3prov.input_cache_miss_usd_per_1m_offpeak, 'MiniMax-M3 flat 纪律:peak==offpeak miss');
69
+ assert.equal(m3prov.input_cache_hit_usd_per_1m_peak, m3prov.input_cache_hit_usd_per_1m_offpeak, 'MiniMax-M3 flat 纪律:peak==offpeak hit');
70
+ assert.equal(m3prov.output_usd_per_1m_peak, m3prov.output_usd_per_1m_offpeak, 'MiniMax-M3 flat 纪律:peak==offpeak output');
71
+ ok('MiniMax flat_no_offpeak 纪律同价守门');
72
+ // ---- 3d. issue #49 验收:人为改一个不存在的模型名 → 仍 fail-closed(waiting/error,不猜价) ----
73
+ assert.throws(() => priceRunCost('unknown-model-xyz', baseUsage, priceTable), /no entry for model/);
74
+ ok('未知模型名 → fail-closed');
75
+ // ---- 4. fail-closed:未知模型 / alias 悬空 / usage 缺失 / 非法 schema_version 都不许出现价格 ----
76
+ const dangling = { ...priceTable, aliases: { 'deepseek-chat': 'not-a-model' } };
77
+ assert.throws(() => priceRunCost('deepseek-chat', baseUsage, dangling), /has no entry/);
78
+ assert.throws(() => priceRunCost('deepseek-chat', { ...baseUsage, responsesMissingUsage: 1 }, priceTable), /cost unprovable/);
79
+ // 非法 schema_version 守门(写入 tmp 后用 loadPriceTable 加载应抛错)
80
+ const tmpSchemaDir = mkdtempSync(join(tmpdir(), 'nightly-bad-schema-'));
81
+ const badSchemaPath = join(tmpSchemaDir, 'bad.json');
82
+ try {
83
+ writeFileSync(badSchemaPath, JSON.stringify({ schema_version: 'gotry_llm_price_table_v99', prices: {} }));
84
+ assert.throws(() => loadPriceTable(badSchemaPath), /schema_version must be/);
85
+ ok('非法 schema_version 拒绝');
86
+ }
87
+ finally {
88
+ rmSync(tmpSchemaDir, { recursive: true, force: true });
89
+ }
90
+ // 非法 provider price_strategy 守门(在 v2 表写入非法策略应抛错)
91
+ const tmpStrategyDir = mkdtempSync(join(tmpdir(), 'nightly-bad-strategy-'));
92
+ const badStrategyPath = join(tmpStrategyDir, 'bad.json');
93
+ try {
94
+ writeFileSync(badStrategyPath, JSON.stringify({
95
+ schema_version: 'gotry_llm_price_table_v2',
96
+ providers: {
97
+ bad: { family: 'x', price_strategy: 'mystery_strategy', aliases: {}, models: { 'm': { input_cache_miss_usd_per_1m_peak: 0.1, input_cache_hit_usd_per_1m_peak: 0.01, output_usd_per_1m_peak: 0.5, input_cache_miss_usd_per_1m_offpeak: 0.1, input_cache_hit_usd_per_1m_offpeak: 0.01, output_usd_per_1m_offpeak: 0.5 } } },
98
+ },
99
+ }));
100
+ assert.throws(() => loadPriceTable(badStrategyPath), /price_strategy must be/);
101
+ ok('v2 非法 price_strategy 拒绝');
102
+ }
103
+ finally {
104
+ rmSync(tmpStrategyDir, { recursive: true, force: true });
105
+ }
106
+ ok('未知模型/悬空alias/usage缺失 fail-closed');
107
+ // ---- 5. run_key 确定性 + 消费方合同 ----
108
+ const executeAt = '2026-08-29T12:00:00.000Z';
109
+ const recordInput = {
110
+ schema_version: 'gotry_m3_nightly_run_v1',
111
+ executed_at: executeAt,
112
+ real_llm: true,
113
+ prompt_set_sha256: 'a'.repeat(64),
114
+ output_sha256: 'b'.repeat(64),
115
+ cost_usd: 0.25,
116
+ };
117
+ const rec1 = buildNightlyRunRecord(recordInput);
118
+ const rec2 = buildNightlyRunRecord({ ...recordInput });
119
+ assert.equal(rec1.run_key, rec2.run_key);
120
+ assert.match(rec1.run_key, /^hmac-sha256:[0-9a-f]{64}$/);
121
+ parseNightlyRun(JSON.parse(JSON.stringify(rec1)), 0);
122
+ const rec3 = buildNightlyRunRecord({ ...recordInput, cost_usd: 0.26 });
123
+ assert.notEqual(rec3.run_key, rec1.run_key);
124
+ ok('run_key 确定性 + 已过消费方 parseNightlyRun');
125
+ // ---- 6. 无凭证 = waiting_external_evidence,零写入(evidence root 自身也不得被创建) ----
126
+ const prevKey = process.env['LLM_API_KEY'];
127
+ const prevDeepseekKey = process.env['DEEPSEEK_API_KEY'];
128
+ const waitParent = mkdtempSync(join(tmpdir(), 'nightly-wait-'));
129
+ const waitRoot = join(waitParent, 'evidence', 'm3');
130
+ try {
131
+ delete process.env['LLM_API_KEY'];
132
+ delete process.env['DEEPSEEK_API_KEY'];
133
+ const waiting = await runNightlyEvidence({ evidenceRoot: waitRoot, dryRun: false, clock: () => new Date(executeAt) });
134
+ assert.equal(waiting.state, 'waiting_external_evidence');
135
+ assert.equal(waiting.record, null);
136
+ assert.ok(waiting.reason?.includes('backoff'));
137
+ assert.equal(existsSync(waitRoot), false, 'waiting 不得创建任何证据目录');
138
+ }
139
+ finally {
140
+ if (prevKey !== undefined)
141
+ process.env['LLM_API_KEY'] = prevKey;
142
+ if (prevDeepseekKey !== undefined)
143
+ process.env['DEEPSEEK_API_KEY'] = prevDeepseekKey;
144
+ rmSync(waitParent, { recursive: true, force: true });
145
+ }
146
+ ok('无凭证 → waiting_external_evidence 且零写入');
147
+ // ---- 7. dry-run:mock 全链演练,记录为 real_llm=false 且绝不落盘 ----
148
+ const dryParent = mkdtempSync(join(tmpdir(), 'nightly-dry-'));
149
+ const dryRoot = join(dryParent, 'evidence', 'm3');
150
+ try {
151
+ const dry = await runNightlyEvidence({ evidenceRoot: dryRoot, dryRun: true, clock: () => new Date(executeAt) });
152
+ assert.equal(dry.state, 'dry_run');
153
+ assert.equal(dry.record?.real_llm, false);
154
+ parseNightlyRun(JSON.parse(JSON.stringify(dry.record)), 0);
155
+ assert.equal(existsSync(dryRoot), false, 'dry-run 不得写任何证据文件');
156
+ }
157
+ finally {
158
+ rmSync(dryParent, { recursive: true, force: true });
159
+ }
160
+ ok('dry-run mock 全链演练 + real_llm=false + 零落盘');
161
+ console.log(`nightly-evidence tests: ${passed} 组断言全绿(offline,真跑不在 CI)`);
@@ -0,0 +1,286 @@
1
+ /**
2
+ * M3 nightly real-LLM 证据生产器(issue #22 验收「nightly real-LLM 与成本质量证据可复跑」)。
3
+ * ADR-11 巡检层的 nightly 形态:固定 prompt 集 × 真实 LLM,产出被 product-metrics.ts
4
+ * 消费的 `gotry_m3_nightly_run_v1` 记录,追加进私有证据账本 gotry-state/evidence/m3/cohort.jsonl
5
+ * (gitignored;绝不写真实产品状态 ts/dsh-runtime/gotry-state/)。
6
+ *
7
+ * 运行(在 ts/ 下):
8
+ * npx tsx scripts/nightly-evidence.ts # 真跑:需 LLM_API_KEY,追加证据记录
9
+ * npx tsx scripts/nightly-evidence.ts --dry-run # mock 全链演练,绝不写证据
10
+ * npx tsx scripts/nightly-evidence.ts --format json # 机器可读状态(heartbeat 消费)
11
+ * npx tsx scripts/nightly-evidence.ts --no-env-file # 不读仓根 .env(等待态测试用)
12
+ *
13
+ * 纪律:
14
+ * - 无凭证 = waiting_external_evidence + backoff/no-spend:退出码 0,状态 JSON 明示,不写任何文件。
15
+ * - cost_usd 只能来自 dsh-llm 实测 usage × `data/llm-price-table.json` 封存价(peak 保守上界);
16
+ * usage 缺失/模型无价目 = fail-closed,不写记录、不猜价格;价目调整走 PR 改封存文件。
17
+ * - prompt_set_sha256 锚定 `data/m3-nightly-prompts.json` 内容;output_sha256 锚定本轮对话全文。
18
+ * - 预算闸 GOTRY_NIGHTLY_BUDGET_USD(默认 1.00 美元):超闸时记录照写(已发生的花费是事实),
19
+ * 但退出码 3,heartbeat 应 backoff。
20
+ * - 写入前先过消费方 parseNightlyRun 校验——生产器自己写出的必须是评分器读得懂的记录。
21
+ *
22
+ * 价表 schema 演进(issue #49 落地):
23
+ * - `gotry_llm_price_table_v1`:仅 DeepSeek,flat 字段直接挂在 prices.<model> 下,本 loader 兼容读取。
24
+ * - `gotry_llm_price_table_v2`(本仓现状):providers.<id>.models.<model>,provider-aware。
25
+ * v2 引入 provider 别名/价格策略(tiered_peak_offpeak vs flat_no_offpeak),允许 MiniMax/等
26
+ * 没有 off-peak 列的 provider 以同价占位填入 _offpeak 列(peak_conservative_upper_bound 纪律)。
27
+ * - reader 兼容 v1/v2:loadPriceTable 检测 schema_version;v1 走旧 PriceEntry 形态,v2 走
28
+ * ProviderEntry 形态;priceRunCost 与外暴露 API 不变。
29
+ */
30
+ import { createHash } from 'node:crypto';
31
+ import { appendFileSync, mkdirSync, readFileSync } from 'node:fs';
32
+ import { join } from 'node:path';
33
+ import { createMockLlm } from '../src/mock-llm.js';
34
+ import { createOpenAICompatLlm } from '../src/dsh-llm.js';
35
+ import { newState, runTurn } from '../src/loop.js';
36
+ import { solveUnified } from '../src/unified.js';
37
+ import { realtimeSolvePort } from '../src/realtime-pricing.js';
38
+ import { parseNightlyRun } from './product-metrics.js';
39
+ const SHA256 = /^[0-9a-f]{64}$/;
40
+ const DEFAULT_BUDGET_USD = 1;
41
+ function canonical(value) {
42
+ if (Array.isArray(value))
43
+ return `[${value.map(canonical).join(',')}]`;
44
+ if (typeof value === 'object' && value !== null) {
45
+ const record = value;
46
+ return `{${Object.keys(record).sort().map(key => `${JSON.stringify(key)}:${canonical(record[key])}`).join(',')}}`;
47
+ }
48
+ return JSON.stringify(value);
49
+ }
50
+ function sha256Of(value) {
51
+ return createHash('sha256').update(canonical(value)).digest('hex');
52
+ }
53
+ function round6(value) {
54
+ return Number(value.toFixed(6));
55
+ }
56
+ export function loadPromptSet(path) {
57
+ const raw = JSON.parse(readFileSync(path, 'utf8'));
58
+ if (raw['schema_version'] !== 'gotry_m3_nightly_prompt_set_v1') {
59
+ throw new Error(`prompt set schema_version must be gotry_m3_nightly_prompt_set_v1, got: ${String(raw['schema_version'])}`);
60
+ }
61
+ const turns = raw['turns'];
62
+ if (!Array.isArray(turns) || turns.length === 0 || turns.some(t => typeof t !== 'string' || t.length === 0)) {
63
+ throw new Error('prompt set turns must be a non-empty array of non-empty strings');
64
+ }
65
+ return { schema_version: 'gotry_m3_nightly_prompt_set_v1', description: raw['description'], turns: turns };
66
+ }
67
+ function assertPriceEntry(label, value) {
68
+ const entry = typeof value === 'object' && value !== null ? value : null;
69
+ if (!entry)
70
+ throw new Error(`${label} must be an object`);
71
+ for (const field of ['input_cache_miss_usd_per_1m_peak', 'input_cache_hit_usd_per_1m_peak', 'output_usd_per_1m_peak']) {
72
+ const num = entry[field];
73
+ if (typeof num !== 'number' || !Number.isFinite(num) || num < 0) {
74
+ throw new Error(`${label}.${field} must be a non-negative finite number`);
75
+ }
76
+ }
77
+ return value;
78
+ }
79
+ export function loadPriceTable(path) {
80
+ const raw = JSON.parse(readFileSync(path, 'utf8'));
81
+ const schemaVersion = raw['schema_version'];
82
+ if (schemaVersion === 'gotry_llm_price_table_v2') {
83
+ return loadPriceTableV2(raw);
84
+ }
85
+ if (schemaVersion === 'gotry_llm_price_table_v1') {
86
+ return loadPriceTableV1(raw);
87
+ }
88
+ throw new Error(`price table schema_version must be gotry_llm_price_table_v1 or _v2, got: ${String(schemaVersion)}`);
89
+ }
90
+ function loadPriceTableV1(raw) {
91
+ const aliases = typeof raw['aliases'] === 'object' && raw['aliases'] !== null ? raw['aliases'] : {};
92
+ for (const [from, to] of Object.entries(aliases)) {
93
+ if (typeof to !== 'string')
94
+ throw new Error(`price table alias ${from} must map to a model name`);
95
+ }
96
+ const prices = {};
97
+ for (const [name, entry] of Object.entries(typeof raw['prices'] === 'object' && raw['prices'] !== null ? raw['prices'] : {})) {
98
+ prices[name] = assertPriceEntry(`price table entry ${name}`, entry);
99
+ }
100
+ return { schema_version: 'gotry_llm_price_table_v1', aliases, prices };
101
+ }
102
+ /** v2 reader:providers.<id>.models.<model> 平铺为统一的 aliases/prices 双表,外暴露 API 不变。
103
+ * lookup 规则:给定 model 名 →
104
+ * 1. 若在 aliases 表中,跳到别名目标(qualified `providerId:model`);
105
+ * 2. 否则直接以 qualified `providerId:model` 在 prices 中查找;
106
+ * 3. 否则尝试裸 `model` 键(单 provider 时透明,如 MiniMax-M3 在 minimax:models 下唯一);
107
+ * 4. 仍找不到 → fail-closed。 */
108
+ function loadPriceTableV2(raw) {
109
+ const providersObj = typeof raw['providers'] === 'object' && raw['providers'] !== null ? raw['providers'] : null;
110
+ if (!providersObj)
111
+ throw new Error('price table v2 requires providers object');
112
+ const aliases = {};
113
+ const prices = {};
114
+ for (const [providerId, rawProvider] of Object.entries(providersObj)) {
115
+ const provider = assertProviderEntry(`price table provider ${providerId}`, rawProvider);
116
+ for (const [aliasName, target] of Object.entries(provider.aliases)) {
117
+ if (typeof target !== 'string')
118
+ throw new Error(`provider ${providerId} alias ${aliasName} must map to a model name`);
119
+ if (!provider.models[target]) {
120
+ throw new Error(`provider ${providerId} alias ${aliasName} -> ${target} has no entry; update data/llm-price-table.json via PR`);
121
+ }
122
+ aliases[aliasName] = target;
123
+ }
124
+ for (const [modelName, entry] of Object.entries(provider.models)) {
125
+ const qualified = `${providerId}:${modelName}`;
126
+ const validated = assertPriceEntry(`price table provider ${providerId} model ${modelName}`, entry);
127
+ if (prices[qualified])
128
+ throw new Error(`duplicate price table key ${qualified}`);
129
+ prices[qualified] = validated;
130
+ if (prices[modelName])
131
+ throw new Error(`duplicate price table key ${modelName} (across providers, disambiguate via aliases or qualified lookup)`);
132
+ prices[modelName] = validated;
133
+ }
134
+ }
135
+ return { schema_version: 'gotry_llm_price_table_v2', aliases, prices };
136
+ }
137
+ function assertProviderEntry(label, value) {
138
+ const entry = typeof value === 'object' && value !== null ? value : null;
139
+ if (!entry)
140
+ throw new Error(`${label} must be an object`);
141
+ const family = entry['family'];
142
+ if (typeof family !== 'string' || family.length === 0)
143
+ throw new Error(`${label}.family must be a non-empty string`);
144
+ const strategy = entry['price_strategy'];
145
+ if (strategy !== 'tiered_peak_offpeak' && strategy !== 'flat_no_offpeak') {
146
+ throw new Error(`${label}.price_strategy must be 'tiered_peak_offpeak' or 'flat_no_offpeak', got: ${String(strategy)}`);
147
+ }
148
+ const aliases = typeof entry['aliases'] === 'object' && entry['aliases'] !== null ? entry['aliases'] : {};
149
+ const models = typeof entry['models'] === 'object' && entry['models'] !== null ? entry['models'] : {};
150
+ return {
151
+ family,
152
+ price_strategy: strategy,
153
+ api_base: typeof entry['api_base'] === 'string' ? entry['api_base'] : undefined,
154
+ source_url: typeof entry['source_url'] === 'string' ? entry['source_url'] : undefined,
155
+ aliases,
156
+ models,
157
+ };
158
+ }
159
+ /** 换算单次运行成本(peak 保守上界:全部输入按 cache miss 峰价计,只高不低)。 */
160
+ export function priceRunCost(model, usage, table) {
161
+ if (usage.responsesMissingUsage > 0) {
162
+ throw new Error(`usage provider omitted usage on ${usage.responsesMissingUsage} response(s) — cost unprovable, refusing to price (fail-closed)`);
163
+ }
164
+ const alias = table.aliases[model];
165
+ if (alias && !table.prices[alias])
166
+ throw new Error(`price table alias ${model} -> ${alias} has no entry; update data/llm-price-table.json via PR`);
167
+ const entry = table.prices[alias ?? model];
168
+ if (!entry)
169
+ throw new Error(`price table has no entry for model ${model}; update data/llm-price-table.json via PR (fail-closed, no guessed price)`);
170
+ const cost = (usage.inputCacheMissTokens * entry.input_cache_miss_usd_per_1m_peak
171
+ + usage.inputCacheHitTokens * entry.input_cache_hit_usd_per_1m_peak
172
+ + usage.outputTokens * entry.output_usd_per_1m_peak) / 1_000_000;
173
+ return round6(cost);
174
+ }
175
+ /** 记录构建(确定性:同内容同 executed_at => 同 run_key)。写入前由消费方 parseNightlyRun 校验。 */
176
+ export function buildNightlyRunRecord(input) {
177
+ const { schema_version, executed_at, real_llm, prompt_set_sha256, output_sha256, cost_usd } = input;
178
+ const core = { schema_version, executed_at, real_llm, prompt_set_sha256, output_sha256, cost_usd };
179
+ if (!SHA256.test(prompt_set_sha256) || !SHA256.test(output_sha256)) {
180
+ throw new Error('nightly record hashes must be lowercase SHA-256 digests');
181
+ }
182
+ const record = { ...core, run_key: `hmac-sha256:${createHash('sha256').update(canonical(core)).digest('hex')}` };
183
+ parseNightlyRun(JSON.parse(JSON.stringify(record)), 0);
184
+ return record;
185
+ }
186
+ function activeModel() {
187
+ return process.env['LLM_MODEL'] ?? process.env['DEEPSEEK_MODEL'] ?? 'MiniMax-M2';
188
+ }
189
+ function arg(name) {
190
+ const index = process.argv.indexOf(name);
191
+ return index >= 0 ? process.argv[index + 1] : undefined;
192
+ }
193
+ export async function runNightlyEvidence(options) {
194
+ const clock = options.clock ?? (() => new Date());
195
+ const llmKey = process.env['LLM_API_KEY'] ?? process.env['DEEPSEEK_API_KEY'];
196
+ if (!options.dryRun && !llmKey) {
197
+ return { state: 'waiting_external_evidence', record: null, reason: 'no real LLM credential (LLM_API_KEY/DEEPSEEK_API_KEY); waiting & backoff & no-spend per issue #22 停机纪律' };
198
+ }
199
+ const promptSet = loadPromptSet('data/m3-nightly-prompts.json');
200
+ const priceTable = loadPriceTable('data/llm-price-table.json');
201
+ const packPath = join('..', 'data', 'flights_2026.json');
202
+ const solvePort = realtimeSolvePort(solveUnified);
203
+ const port = options.dryRun ? createMockLlm(packPath) : createOpenAICompatLlm(packPath);
204
+ const state = newState();
205
+ const history = [];
206
+ for (const turn of promptSet.turns) {
207
+ const { reply } = await runTurn(state, turn, port, [...history], solvePort);
208
+ history.push({ role: 'user', text: turn }, { role: 'assistant', text: reply });
209
+ }
210
+ const promptSetSha = sha256Of(promptSet);
211
+ // history 是 user/assistant 交错序列;assistant 回复落在每个 user 之后(index*2+1)
212
+ const turnsTranscript = promptSet.turns.map((turn, index) => ({ turn_index: index, user: turn, reply: history[index * 2 + 1]?.text ?? '' }));
213
+ const outputSha = sha256Of(turnsTranscript);
214
+ let record;
215
+ if (options.dryRun) {
216
+ record = buildNightlyRunRecord({
217
+ schema_version: 'gotry_m3_nightly_run_v1',
218
+ executed_at: clock().toISOString(),
219
+ real_llm: false,
220
+ prompt_set_sha256: promptSetSha,
221
+ output_sha256: outputSha,
222
+ cost_usd: 0,
223
+ });
224
+ return { state: 'dry_run', record, reason: 'dry-run exercises the pipeline against mock LLM; no evidence written' };
225
+ }
226
+ const usage = port.usage;
227
+ if (!usage)
228
+ throw new Error('real LLM port did not expose usage tracker (dsh-llm regression) — refusing to write cost evidence');
229
+ if (usage.calls !== promptSet.turns.length) {
230
+ throw new Error(`usage calls ${usage.calls} != expected turns ${promptSet.turns.length} — fail-closed, no evidence written`);
231
+ }
232
+ const costUsd = priceRunCost(activeModel(), usage, priceTable);
233
+ record = buildNightlyRunRecord({
234
+ schema_version: 'gotry_m3_nightly_run_v1',
235
+ executed_at: clock().toISOString(),
236
+ real_llm: true,
237
+ prompt_set_sha256: promptSetSha,
238
+ output_sha256: outputSha,
239
+ cost_usd: costUsd,
240
+ });
241
+ mkdirSync(options.evidenceRoot, { recursive: true });
242
+ appendFileSync(join(options.evidenceRoot, 'cohort.jsonl'), `${JSON.stringify(record)}\n`, 'utf8');
243
+ const budget = Number(process.env['GOTRY_NIGHTLY_BUDGET_USD'] ?? DEFAULT_BUDGET_USD);
244
+ const overBudget = Number.isFinite(budget) && budget > 0 ? costUsd > budget : false;
245
+ return { state: 'evidence_written', record, cost_over_budget: overBudget, reason: overBudget ? `cost_usd ${costUsd} exceeds GOTRY_NIGHTLY_BUDGET_USD ${budget} — backoff suggested` : undefined };
246
+ }
247
+ function output(payload, asJson) {
248
+ if (asJson)
249
+ console.log(JSON.stringify(payload));
250
+ else {
251
+ console.log(`nightly-evidence state: ${payload.state}${payload.error ? ` — ${payload.error}` : ''}`);
252
+ if (payload.record)
253
+ console.log(JSON.stringify(payload.record, null, 2));
254
+ if (payload.reason)
255
+ console.log(payload.reason);
256
+ }
257
+ }
258
+ async function main() {
259
+ // 仓根 .env(gitignored):每行 KEY=VALUE,不覆盖已有环境变量;--no-env-file 供等待态测试绕过
260
+ if (!process.argv.includes('--no-env-file')) {
261
+ try {
262
+ for (const line of readFileSync(join('..', '.env'), 'utf-8').split('\n')) {
263
+ const m = line.match(/^([A-Z_]+)=(.*)$/);
264
+ if (m && !process.env[m[1]])
265
+ process.env[m[1]] = m[2].trim();
266
+ }
267
+ }
268
+ catch { /* .env 可选 */ }
269
+ }
270
+ const asJson = (arg('--format') ?? 'markdown') === 'json';
271
+ const evidenceRoot = arg('--evidence-root') ?? 'gotry-state/evidence/m3';
272
+ const dryRun = process.argv.includes('--dry-run');
273
+ try {
274
+ const result = await runNightlyEvidence({ evidenceRoot, dryRun });
275
+ output(result, asJson);
276
+ if (result.cost_over_budget)
277
+ process.exitCode = 3;
278
+ }
279
+ catch (error) {
280
+ output({ state: 'error', record: null, error: error.message }, asJson);
281
+ process.exitCode = 1;
282
+ }
283
+ }
284
+ if (process.argv[1]?.endsWith('nightly-evidence.ts')) {
285
+ await main();
286
+ }
@@ -1,3 +1,20 @@
1
+ /**
2
+ * 「下一次出发」回访摘要(roadmap M4 交付「主动回访(可关闭)」的骨架):
3
+ * 读 wish pool + 效用 sidecar,按当前窗口条件匹配 0..1 条建议,渲染成摘要,
4
+ * 经可插拔通道送出——通道 key 未配时骨架降级为 stdout/file,即插即用。
5
+ *
6
+ * 通道(环境变量,无新依赖,fetch 为 Node 18+ 全局):
7
+ * GOTRY_NUDGE_ENABLED=false 全局关闭(契约:可关闭;其余配置再对也直接退出)
8
+ * GOTRY_NUDGE_CHANNEL=stdout|file|lark 默认 stdout
9
+ * GOTRY_NUDGE_FILE=<path> file 通道输出位置,默认 <stateRoot>/gotry-state/nudge-digest.md
10
+ * GOTRY_LARK_WEBHOOK=<url> lark 通道 webhook(founder 侧配置即生效)
11
+ *
12
+ * 纪律:0..1(muted 永不召回,无命中不硬推);lark 投递失败降级 stdout 不抛
13
+ * (回访是 sidecar 性质,永不阻塞主路径);本脚本只读状态文件。
14
+ *
15
+ * 运行:cd ts && npx tsx scripts/nudge-digest.ts [--days N] [--budget N] [--month M] [--state-root DIR]
16
+ * 无参数时 days/budget 不参与评分,month 取系统当月。
17
+ */
1
18
  import { writeFileSync, mkdirSync } from 'node:fs';
2
19
  import { join, dirname } from 'node:path';
3
20
  import { pickNudgeWish } from '../src/wish-pool.js';
@@ -11,6 +28,7 @@ function arg(name) {
11
28
  const stateRoot = arg('--state-root') ?? '.';
12
29
  const stateDir = join(stateRoot, 'gotry-state');
13
30
  function readEvents() {
31
+ // ADR-15:账本优先,未迁移 root 回退旧文件(只读)
14
32
  return readUtilityEventsWithFallback(stateRoot);
15
33
  }
16
34
  if (process.env['GOTRY_NUDGE_ENABLED'] === 'false') {
@@ -22,20 +40,20 @@ const anchor = buildTimeAnchor(new Date());
22
40
  const ctx = {
23
41
  days: arg('--days') ? Number(arg('--days')) : undefined,
24
42
  budgetCny: arg('--budget') ? Number(arg('--budget')) : undefined,
25
- month: arg('--month') ? Number(arg('--month')) : new Date().getMonth() + 1
43
+ month: arg('--month') ? Number(arg('--month')) : new Date().getMonth() + 1,
26
44
  };
27
45
  const match = pickNudgeWish(pool, ctx);
28
- const lines = [
29
- `# 「下一次出发」回访摘要(${anchor.today} ${anchor.todayWeekdayZh})`
30
- ];
46
+ const lines = [`# 「下一次出发」回访摘要(${anchor.today} ${anchor.todayWeekdayZh})`];
31
47
  if (!match) {
32
- lines.push(`在册 ${pool.filter((p)=>!p.muted).length} 条憧憬,当前窗口无可成行匹配——不打扰(0..1 纪律:不硬推)。`);
33
- } else {
34
- const c = match.entry.conditions ?? {};
48
+ lines.push(`在册 ${pool.filter(p => !p.muted).length} 条憧憬,当前窗口无可成行匹配——不打扰(0..1 纪律:不硬推)。`);
49
+ }
50
+ else {
51
+ const c = (match.entry.conditions ?? {});
35
52
  const u = projectUtility(readEvents())[match.wishId];
36
53
  lines.push(`**${String(match.entry.name ?? match.wishId)}**(${match.hits.join(' + ')},命中 ${match.score}/3 项)`);
37
54
  lines.push(`- 成行条件: ${JSON.stringify(c)}`);
38
- if (match.entry.reason) lines.push(`- 当初为什么: ${String(match.entry.reason).slice(0, 160)}`);
55
+ if (match.entry.reason)
56
+ lines.push(`- 当初为什么: ${String(match.entry.reason).slice(0, 160)}`);
39
57
  lines.push(`- 效用状态: ${u?.status ?? 'unknown'}(被召回 ${u?.recalled ?? 0} 次)`);
40
58
  lines.push('');
41
59
  lines.push('_想安排就说一声;不想被打扰说「mute <名字>」即可休眠,憧憬不被拒绝。_');
@@ -44,40 +62,33 @@ const digest = lines.join('\n');
44
62
  const channel = process.env['GOTRY_NUDGE_CHANNEL'] ?? 'stdout';
45
63
  if (channel === 'file') {
46
64
  const out = process.env['GOTRY_NUDGE_FILE'] ?? join(stateDir, 'nudge-digest.md');
47
- mkdirSync(dirname(out), {
48
- recursive: true
49
- });
65
+ mkdirSync(dirname(out), { recursive: true });
50
66
  writeFileSync(out, digest + '\n', 'utf-8');
51
67
  console.log(`摘要已写入 ${out}`);
52
- } else if (channel === 'lark') {
68
+ }
69
+ else if (channel === 'lark') {
53
70
  const webhook = process.env['GOTRY_LARK_WEBHOOK'];
54
71
  if (!webhook) {
55
72
  console.log('lark 通道未配置(GOTRY_LARK_WEBHOOK 缺失)——降级 stdout,即插即用等 key:');
56
73
  console.log(digest);
57
- } else {
74
+ }
75
+ else {
58
76
  try {
59
77
  const resp = await fetch(webhook, {
60
78
  method: 'POST',
61
- headers: {
62
- 'Content-Type': 'application/json'
63
- },
64
- body: JSON.stringify({
65
- msg_type: 'text',
66
- content: {
67
- text: digest
68
- }
69
- })
79
+ headers: { 'Content-Type': 'application/json' },
80
+ body: JSON.stringify({ msg_type: 'text', content: { text: digest } }),
70
81
  });
71
82
  console.log(`lark 投递 HTTP ${resp.status}`);
72
- if (!resp.ok) console.log(digest);
73
- } catch (e) {
83
+ if (!resp.ok)
84
+ console.log(digest); // 失败降级 stdout,不丢摘要
85
+ }
86
+ catch (e) {
74
87
  console.log(`lark 投递失败(${e.message})——降级 stdout:`);
75
88
  console.log(digest);
76
89
  }
77
90
  }
78
- } else {
91
+ }
92
+ else {
79
93
  console.log(digest);
80
94
  }
81
-
82
-
83
- //# sourceURL=/Users/bytedance/work/gotry/ts/scripts/nudge-digest.ts