@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,416 @@
1
+ /**
2
+ * 行程 deck 产物生成入口的注册工具 E2E(issue #566,Phase B 切片 2;
3
+ * 与 issue #442 单页入口镜像)。
4
+ *
5
+ * 真实执行面:在隔离临时 stateRoot 下 `apply(ctx, config)` 装载 gotry-tools 插件,
6
+ * 取**注册定义** `gotry_itinerary_deck_render` 的 execute 直调(与本仓库既有
7
+ * registered-e2e 同构),exec 上下文给出真实会话 cwd。事实经 `appendFacts` 写入
8
+ * 隔离注册表(<stateRoot>/gotry-state/bookable-facts.jsonl),生成入口只能从那里取。
9
+ *
10
+ * 覆盖(对照单页 itinerary-artifact-tests.ts 同一份验收面;deck 差异在 §3/§4
11
+ * 增补的形态契约:scroll-snap 零脚本翻页 / 11 张幻灯确定性派生 / 命名契约前缀):
12
+ * 1. 空 fact_ids = 明确未核验计划:落盘成功、无整体「已验证」徽章、无写入 stateRoot;
13
+ * 2. 选中 3 条事实:落盘字节 == 同输入 deck 渲染器输出(事实顺序/内容均由注册表决定);
14
+ * 3. 未知 id / 重复 id / 超量 id 一律拒绝且零写入;
15
+ * 4. 登记行畸形 → 渲染器显式拒绝,零写入;
16
+ * 5. 调用方自带 facts 对象不被接受(空列表不投影、伪造 id 走未知 id 拒绝);
17
+ * 6. 显式 basename 撞车不覆盖(字节不变);
18
+ * 7. 符号链接目标不被改写(排除链接逃逸);
19
+ * 8. basename 路径分隔符 / 越级 / 错误前缀 / 超长 / 绝对路径全部拒绝,仓外零文件;
20
+ * 9. 会话 cwd 位于 .git/node_modules 段或不存在 → 拒绝;
21
+ * 10. 随机默认名符合 `gotry-deck-` 契约且两次不同;同一输入两次生成字节一致(确定性);
22
+ * 11. 畸形 title/itinerary/fact_ids 类型 → 拒绝且零写入;
23
+ * 12. 缺失/空对象/空串/纯空白/非字符串/相对的会话 cwd → 工具层与能力层都 fail closed,
24
+ * 进程 cwd 零新增文件(绝不回落 process.cwd());
25
+ * 13. 真实产出链路(注册工具):生成 → gotry_artifacts_list 在册同一路径 → gotry_artifacts_read
26
+ * 以 html 源码文本读回,内容与落盘字节逐字一致、version 与磁盘 sha256 一致;
27
+ * 14. 路径保真:宿主 cwd 的尾随空格属于路径本身——同时存在 `session` 与 `session ` 时,
28
+ * 工具层与能力层都只写进宿主给出的那一个,绝不 trim 归一化到同名兄弟目录;
29
+ * 只有兄弟存在时带空格路径按不存在拒绝;
30
+ * 15. deck 形态契约:零脚本 / 无远端依赖 / 纯 CSS scroll-snap 翻页 / 11 张幻灯确定性派生 /
31
+ * 共享 evidence 边界声明。
32
+ * 全部合成事实,无用户真实行程;不启动 dsh 宿主、无网络、无供应商调用。
33
+ *
34
+ * 运行(在 ts/ 下):
35
+ * PATH=/opt/homebrew/opt/node@24/bin:$PATH npx tsx scripts/itinerary-deck-artifact-tests.ts
36
+ */
37
+ import assert from 'node:assert/strict';
38
+ import { createHash } from 'node:crypto';
39
+ import { mkdirSync, mkdtempSync, readdirSync, readFileSync, realpathSync, rmSync, symlinkSync, lstatSync, writeFileSync } from 'node:fs';
40
+ import { tmpdir } from 'node:os';
41
+ import { join } from 'node:path';
42
+ import { apply } from '../src/index.js';
43
+ import { BOOKABLE_FACT_SCHEMA, } from '../src/bookable-facts.js';
44
+ import { appendFacts, loadFactRegistry } from '../capabilities/fact-log.js';
45
+ import { generateItineraryDeckArtifact } from '../capabilities/itinerary-deck-artifact.js';
46
+ import { renderItineraryDeck } from '../src/itinerary-deck.js';
47
+ import { ITINERARY_DECK_ARTIFACT_BASENAME_RE } from '../capabilities/itinerary-deck-artifact.js';
48
+ let pass = 0;
49
+ let fail = 0;
50
+ const failures = [];
51
+ function ok(cond, msg) {
52
+ if (cond) {
53
+ pass++;
54
+ return;
55
+ }
56
+ fail++;
57
+ failures.push(msg);
58
+ }
59
+ const TITLE = '合成行程:深圳 → 普吉(内部切片夹具)';
60
+ const ITINERARY = {
61
+ trip_start: '2027-07-16',
62
+ trip_end: '2027-07-24',
63
+ stays: [
64
+ { place: '普吉岛', check_in: '2027-07-17', check_out: '2027-07-21' },
65
+ { place: '甲米', check_in: '2027-07-21', check_out: '2027-07-23' },
66
+ ],
67
+ od_segments: [
68
+ { from: '广州南', to: '深圳北', date: '2027-07-16', mode: 'rail', legs: 1 },
69
+ { from: 'SZX', to: 'HKT', date: '2027-07-17', mode: 'flight', legs: 1 },
70
+ { from: 'HKT', to: 'BKK', date: '2027-07-21', mode: 'flight', legs: 2 },
71
+ ],
72
+ };
73
+ const FLIGHT_ID = 'i566flight0001';
74
+ const HOTEL_ID = 'i566hotel0001';
75
+ const POLICY_ID = 'i566policy0001';
76
+ const TRAIN_ID = 'i566train00001';
77
+ const FLIGHT = {
78
+ schema: BOOKABLE_FACT_SCHEMA,
79
+ fact_id: FLIGHT_ID,
80
+ kind: 'flight',
81
+ route: { origin: 'SZX', destination: 'HKT', origin_airport: 'SZX', dest_airport: 'HKT' },
82
+ date: '2027-07-17',
83
+ flight_no: 'CZ6061',
84
+ marketing_carrier: '南方航空',
85
+ dep_local: '09:20',
86
+ arr_local: '12:05',
87
+ nonstop: true,
88
+ price: 1680,
89
+ currency: 'CNY',
90
+ tier: 'live_inventory',
91
+ bookability: 'bookable_exact_date',
92
+ source: 'session:ctrip-flight',
93
+ query_id: 'session:ctrip-flight:flight:SZX-HKT:2027-07-17',
94
+ fetched_at: '2026-09-12T02:10:03.000Z',
95
+ as_of: '2026-09-12',
96
+ };
97
+ const TRAIN = {
98
+ schema: BOOKABLE_FACT_SCHEMA,
99
+ fact_id: TRAIN_ID,
100
+ kind: 'train',
101
+ route: { origin: '广州南', destination: '深圳北' },
102
+ date: '2027-07-16',
103
+ flight_no: 'G6011',
104
+ dep_local: '07:12',
105
+ arr_local: '07:48',
106
+ tier: 'historical_schedule',
107
+ bookability: 'unverified',
108
+ source: 'flyai',
109
+ query_id: 'flyai:train:广州南-深圳北:2027-07-16',
110
+ fetched_at: '2026-09-12T02:00:00.000Z',
111
+ as_of: '2026-08-01',
112
+ };
113
+ const HOTEL = {
114
+ schema: BOOKABLE_FACT_SCHEMA,
115
+ fact_id: HOTEL_ID,
116
+ kind: 'hotel',
117
+ destination: '普吉岛',
118
+ check_in: '2027-07-17',
119
+ check_out: '2027-07-21',
120
+ verdict: 'hit',
121
+ bookability: 'bookable_exact_date',
122
+ options_masked: 37,
123
+ source: 'flyai-hotel',
124
+ query_id: 'hotel:flyai-hotel:普吉岛:2027-07-17_2027-07-21',
125
+ fetched_at: '2026-09-12T02:20:00.000Z',
126
+ as_of: '2026-09-12',
127
+ tier: 'live_inventory',
128
+ };
129
+ const POLICY = {
130
+ schema: BOOKABLE_FACT_SCHEMA,
131
+ fact_id: POLICY_ID,
132
+ kind: 'policy',
133
+ subject: '泰国免签',
134
+ statement: '中国护照可免签入境停留不超过 30 天(以落地执行口径为准)',
135
+ source: 'flyai',
136
+ query_id: 'flyai:policy:泰国免签',
137
+ fetched_at: '2026-09-12T02:30:00.000Z',
138
+ as_of: '2026-09-12',
139
+ review_by: '2027-06-17',
140
+ };
141
+ function loadTools(stateRoot) {
142
+ assert.ok(stateRoot.startsWith(tmpdir()), 'stateRoot 必须是隔离临时根(绝不触真实 stateRoot)');
143
+ const registered = [];
144
+ const ctx = {
145
+ tools: { register: (t) => { registered.push(t); } },
146
+ systemPrompt: { variable: () => { } },
147
+ on: () => () => { },
148
+ };
149
+ apply(ctx, { stateRoot, timeoutMs: 30_000, hbcliBin: 'hbcli-not-on-path', sessionAccess: 'ask' });
150
+ return new Map(registered.map(t => [t.name, t]));
151
+ }
152
+ function htmlFiles(dir) {
153
+ return readdirSync(dir).filter(n => n.endsWith('.html')).sort();
154
+ }
155
+ function deckFiles(dir) {
156
+ return readdirSync(dir).filter(n => n.startsWith('gotry-deck-') && n.endsWith('.html')).sort();
157
+ }
158
+ function renderDeck(facts) {
159
+ const r = renderItineraryDeck({ title: TITLE, itinerary: ITINERARY, facts });
160
+ assert.ok(r.ok, `对照渲染必须成功:${r.ok ? '' : JSON.stringify(r.errors)}`);
161
+ return r.ok ? r.html : '';
162
+ }
163
+ function countOf(haystack, needle) {
164
+ return haystack.split(needle).length - 1;
165
+ }
166
+ async function main() {
167
+ const home = mkdtempSync(join(tmpdir(), 'gotry-566-artifact-'));
168
+ const stateRoot = join(home, 'state');
169
+ const cwd = join(home, 'workspace');
170
+ const outside = join(home, 'outside');
171
+ for (const d of [stateRoot, cwd, outside])
172
+ mkdirSync(d, { recursive: true });
173
+ const outsideFile = join(outside, 'target.html');
174
+ writeFileSync(outsideFile, 'DO NOT TOUCH', 'utf-8');
175
+ const tools = loadTools(stateRoot);
176
+ const tool = tools.get('gotry_itinerary_deck_render');
177
+ assert.ok(tool, 'gotry_itinerary_deck_render 必须已注册');
178
+ // deck 工具与单页工具并存:注册定义同名检查
179
+ ok(Boolean(tools.get('gotry_itinerary_render')), '§0a 单页入口(issue #442)仍注册');
180
+ if (!tool) {
181
+ console.log('\nITINERARY DECK ARTIFACT TESTS: 0 pass, 1 fail');
182
+ console.log(' - 工具未注册');
183
+ process.exit(1);
184
+ }
185
+ const exec = { agent: { session: { header: { cwd } } } };
186
+ const run = async (args, execCtx = exec) => await tool.execute(args, execCtx);
187
+ // ---- §1 模型可见契约(fact_ids 必填、空数组合法) ----
188
+ const params = tool.parameters;
189
+ ok(params.required?.includes('fact_ids') === true, '§1a fact_ids 是必填参数');
190
+ ok(params.properties?.fact_ids?.type === 'array' && params.properties?.fact_ids?.items?.type === 'string', '§1b fact_ids 是字符串数组参数');
191
+ ok(params.required?.includes('title') === true, '§1c title 必填');
192
+ ok(params.required?.includes('itinerary') === true, '§1d itinerary 必填');
193
+ ok(params.required?.includes('basename') !== true, '§1e basename 可选');
194
+ ok(/registry/i.test(tool.description), '§1f 描述声明事实只从注册表取');
195
+ ok(/never overwrites/i.test(tool.description), '§1g 描述声明绝不覆盖');
196
+ ok(/DECK|deck/i.test(tool.description), '§1h 描述声明 deck 形态');
197
+ ok(/gotry-deck-/.test(tool.description), '§1i 描述声明 deck 命名前缀');
198
+ // ---- §2 事实登记进隔离注册表 ----
199
+ ok(await appendFacts(stateRoot, [FLIGHT, TRAIN, HOTEL, POLICY]), '§2a 合成事实写入隔离注册表');
200
+ const registry = await loadFactRegistry(stateRoot);
201
+ ok(registry.length === 4, `§2b 注册表读回 4 条(实测 ${registry.length})`);
202
+ ok(deckFiles(cwd).length === 0, '§2c 生成前工作目录无 deck html');
203
+ // ---- §3 空 fact_ids = 明确未核验计划 + deck 形态契约 ----
204
+ const empty = await run({ title: TITLE, itinerary: ITINERARY, fact_ids: [] });
205
+ ok(empty.ok === true, `§3a 空 fact_ids 合法(实际:${JSON.stringify(empty.error ?? '')})`);
206
+ ok(empty.overall_verified === false, '§3b 结果显式声明无整体「已验证」结论');
207
+ ok(deckFiles(cwd).length === 1, `§3c 落盘 1 个 deck html(实测 ${deckFiles(cwd).length})`);
208
+ const emptyPath = String(empty.path ?? '');
209
+ ok(emptyPath.endsWith(String(empty.basename)), '§3d 返回最终真实路径');
210
+ const emptyDisk = readFileSync(emptyPath, 'utf-8');
211
+ ok(emptyDisk === renderDeck([]), '§3e 落盘字节 == 同输入 deck 渲染器输出');
212
+ ok(empty.bytes === Buffer.byteLength(emptyDisk, 'utf8'), '§3f bytes 与磁盘字节一致');
213
+ ok(emptyDisk.split('class="badge ok"').length - 1 === 0, '§3g 空事实文档没有任何 ok 徽章');
214
+ ok(emptyDisk.includes('共 0 条事实'), '§3h 文档显式陈述 0 条事实');
215
+ ok(emptyDisk.includes('该段没有匹配的已注册事实'), '§3i 计划段显式标注未核验');
216
+ ok(!emptyDisk.includes('<script'), '§3j 产物无 script(零脚本翻页)');
217
+ ok(!emptyDisk.includes('http://') && !emptyDisk.includes('https://'), '§3k 产物无远端资源');
218
+ // deck 形态契约(issue #564):纯 CSS scroll-snap / 11 张幻灯 / 共享 evidence 边界
219
+ ok(emptyDisk.includes('html{scroll-snap-type:y proximity}') && emptyDisk.includes('scroll-snap-align:start'), '§3l 纯 CSS scroll-snap 翻页');
220
+ // 空事实输入:政策幻灯(仅当有政策事实时存在)被跳过,余 10 张
221
+ ok(countOf(emptyDisk, '<section class="slide') === 10, `§3m 空事实输入 10 张幻灯确定性派生(实测 ${countOf(emptyDisk, '<section class="slide')})`);
222
+ ok(emptyDisk.includes('本文档只投影调用方给出的显式行程与已注册事实'), '§3n 共享 evidence 边界声明(单面文案逐字一致)');
223
+ ok(readdirSync(stateRoot).filter(n => n.endsWith('.html')).length === 0, '§3o stateRoot 下不写 html(只写会话工作目录)');
224
+ // ---- §4 选中注册表事实:字节与 deck 渲染器一致,按调用方顺序选中 ----
225
+ const selected = await run({ title: TITLE, itinerary: ITINERARY, fact_ids: [FLIGHT_ID, HOTEL_ID, POLICY_ID] });
226
+ ok(selected.ok === true, `§4a 已注册 id 选中成功(实际:${JSON.stringify(selected.error ?? '')})`);
227
+ const selectedDisk = readFileSync(String(selected.path), 'utf-8');
228
+ ok(selectedDisk === renderDeck([FLIGHT, HOTEL, POLICY]), '§4b 落盘字节 == 注册表选出的 3 条事实的 deck 输出');
229
+ ok(selectedDisk.split('class="badge ok"').length - 1 > 0, '§4c 逐条事实带可下单徽章(非整体徽章)');
230
+ for (const id of [FLIGHT_ID, HOTEL_ID, POLICY_ID])
231
+ ok(selectedDisk.includes(id), `§4d 事实 ${id} 在产物中可见`);
232
+ ok(selectedDisk.includes('独立记录:目的地级酒店事实'), '§4e 酒店证据独立成区(不冒充某家酒店可订)');
233
+ ok(selectedDisk.includes('slide-hotel-evidence') && selectedDisk.includes('slide-policy') && selectedDisk.includes('slide-leftovers') && selectedDisk.includes('slide-flights'), '§4f deck 证据幻灯齐全');
234
+ ok(Array.isArray(selected.fact_ids) && selected.fact_ids.join(',') === [FLIGHT_ID, HOTEL_ID, POLICY_ID].join(','), '§4g 结果回显选中顺序');
235
+ const reversed = await run({ title: TITLE, itinerary: ITINERARY, fact_ids: [POLICY_ID, FLIGHT_ID, HOTEL_ID] });
236
+ ok(reversed.ok === true && reversed.bytes === selected.bytes, '§4h 顺序变化不改变 deck 文档字节(确定性投影)');
237
+ // ---- §5 未知 id 拒绝,零写入 ----
238
+ const before5 = deckFiles(cwd).length;
239
+ const unknown = await run({ title: TITLE, itinerary: ITINERARY, fact_ids: ['i566notthere'] });
240
+ ok(unknown.ok === false && String(unknown.error).includes('i566notthere'), '§5a 未知 id 显式拒绝并回显 id');
241
+ ok(deckFiles(cwd).length === before5, '§5b 未知 id 零写入');
242
+ // ---- §6 重复 id 拒绝,零写入 ----
243
+ const dup = await run({ title: TITLE, itinerary: ITINERARY, fact_ids: [FLIGHT_ID, FLIGHT_ID] });
244
+ ok(dup.ok === false && /重复/.test(String(dup.error)), '§6a 重复 id 拒绝');
245
+ ok(deckFiles(cwd).length === before5, '§6b 重复 id 零写入');
246
+ // ---- §7 超量 id 拒绝,零写入 ----
247
+ const many = Array.from({ length: 201 }, (_, i) => `i566bulk${i}`);
248
+ const over = await run({ title: TITLE, itinerary: ITINERARY, fact_ids: many });
249
+ ok(over.ok === false && /容量上限/.test(String(over.error)), '§7a 超量 id 拒绝');
250
+ ok(deckFiles(cwd).length === before5, '§7b 超量 id 零写入');
251
+ // ---- §8 登记行畸形 → deck 渲染器拒绝,零写入 ----
252
+ const malformed = { ...HOTEL, fact_id: 'i566malformed01', verdict: 'hit', options_masked: 'many' };
253
+ ok(await appendFacts(stateRoot, [malformed]), '§8a 畸形登记行写入注册表');
254
+ const malformedRun = await run({ title: TITLE, itinerary: ITINERARY, fact_ids: ['i566malformed01'] });
255
+ ok(malformedRun.ok === false, '§8b 畸形登记行不渲染成功');
256
+ ok(Array.isArray(malformedRun.errors) && malformedRun.errors.length > 0, '§8c 畸形行给出结构化 errors(渲染器校验)');
257
+ ok(deckFiles(cwd).length === before5, '§8d 畸形行零写入');
258
+ // ---- §9 调用方自带 facts 不被接受 ----
259
+ const forgedId = 'i566forged0001';
260
+ const callerFacts = await run({
261
+ title: TITLE,
262
+ itinerary: ITINERARY,
263
+ fact_ids: [],
264
+ facts: [{ schema: BOOKABLE_FACT_SCHEMA, fact_id: forgedId, kind: 'flight' }],
265
+ });
266
+ ok(callerFacts.ok === true, '§9a 额外的 facts 字段不影响空列表生成');
267
+ ok(!readFileSync(String(callerFacts.path), 'utf-8').includes(forgedId), '§9b 调用方自带事实对象不被投影');
268
+ const forged = await run({ title: TITLE, itinerary: ITINERARY, fact_ids: [forgedId] });
269
+ ok(forged.ok === false, '§9c 伪造 id(只存在于调用方入参)按未知 id 拒绝');
270
+ ok(deckFiles(cwd).length === before5 + 1, '§9d 仅 §9a 新增一个文件');
271
+ // ---- §10 显式 basename 撞车不覆盖(deck 命名契约) ----
272
+ const named = 'gotry-deck-2027-phuket.html';
273
+ const first = await run({ title: TITLE, itinerary: ITINERARY, fact_ids: [FLIGHT_ID], basename: named });
274
+ ok(first.ok === true && first.basename === named, '§10a 合法 deck basename 生成成功');
275
+ const namedPath = join(cwd, named);
276
+ const namedBytes = readFileSync(namedPath, 'utf-8');
277
+ const second = await run({ title: '合成行程:第二次(不应覆盖)', itinerary: ITINERARY, fact_ids: [FLIGHT_ID], basename: named });
278
+ ok(second.ok === false && /拒绝覆盖/.test(String(second.error)), '§10b 同名第二次拒绝覆盖');
279
+ ok(readFileSync(namedPath, 'utf-8') === namedBytes, '§10c 既有产物字节未被改写');
280
+ // ---- §11 符号链接目标不被改写 ----
281
+ const linkName = 'gotry-deck-link.html';
282
+ symlinkSync(outsideFile, join(cwd, linkName));
283
+ const linked = await run({ title: TITLE, itinerary: ITINERARY, fact_ids: [FLIGHT_ID], basename: linkName });
284
+ ok(linked.ok === false, '§11a 指向别处的符号链接不被跟随写入');
285
+ ok(readFileSync(outsideFile, 'utf-8') === 'DO NOT TOUCH', '§11b 链接目标字节未被改写');
286
+ ok(lstatSync(join(cwd, linkName)).isSymbolicLink(), '§11c 链接本身未被替换');
287
+ // ---- §12 deck basename 路径与命名契约(前缀不同 + 与单页契约互不兼容) ----
288
+ const before12 = deckFiles(cwd).length;
289
+ const rejectNames = [
290
+ '../../evil.html',
291
+ 'sub/evil.html',
292
+ 'sub\\evil.html',
293
+ join(outside, 'evil.html'),
294
+ 'evil.html',
295
+ 'gotry-deck-.html',
296
+ 'gotry-deck-2027-phuket.HTML',
297
+ `gotry-deck-${'a'.repeat(70)}.html`,
298
+ 'gotry-deck-2027 phuket.html',
299
+ // 单页前缀不应被 deck 工具接受(契约互不兼容,避免文件名撞车归责混乱)
300
+ 'gotry-itinerary-2027-phuket.html',
301
+ ];
302
+ for (const name of rejectNames) {
303
+ const r = await run({ title: TITLE, itinerary: ITINERARY, fact_ids: [], basename: name });
304
+ ok(r.ok === false, `§12a basename 拒绝:${name}`);
305
+ }
306
+ ok(deckFiles(cwd).length === before12, `§12b 拒绝的 basename 未产生 deck 文件(实测 ${deckFiles(cwd).length})`);
307
+ ok(!readdirSync(outside).includes('evil.html'), '§12c 仓外无越级文件');
308
+ // 单页契约仍由 gotry_itinerary_render 单独负责(两个工具并存、契约不互串)
309
+ ok(ITINERARY_DECK_ARTIFACT_BASENAME_RE.source.startsWith('^gotry-deck-'), '§12d 契约 regex 锁定 gotry-deck- 前缀');
310
+ // ---- §13 会话 cwd 边界 ----
311
+ for (const bad of [join(stateRoot, 'node_modules'), join(home, '.git'), join(home, 'nope')]) {
312
+ mkdirSync(join(stateRoot, 'node_modules'), { recursive: true });
313
+ mkdirSync(join(home, '.git'), { recursive: true });
314
+ const r = await run({ title: TITLE, itinerary: ITINERARY, fact_ids: [] }, { agent: { session: { header: { cwd: bad } } } });
315
+ ok(r.ok === false, `§13a 受限/不存在的 cwd 拒绝:${bad}`);
316
+ }
317
+ ok(readdirSync(join(home, '.git')).length === 0, '§13b .git 段零写入');
318
+ ok(readdirSync(join(stateRoot, 'node_modules')).length === 0, '§13c node_modules 段零写入');
319
+ // ---- §14 随机默认名 + 真实路径 ----
320
+ const r1 = await run({ title: TITLE, itinerary: ITINERARY, fact_ids: [] });
321
+ const r2 = await run({ title: TITLE, itinerary: ITINERARY, fact_ids: [] });
322
+ ok(r1.ok === true && r2.ok === true, '§14a 默认随机名连续生成成功');
323
+ ok(ITINERARY_DECK_ARTIFACT_BASENAME_RE.test(String(r1.basename)), '§14b 随机名符合 deck 命名契约');
324
+ ok(r1.basename !== r2.basename, '§14c 连续两次随机名不同');
325
+ ok(String(r1.path) === join(realpathSync(cwd), String(r1.basename)), '§14d 返回路径 = 会话工作目录(realpath)+ basename');
326
+ // ---- §15 畸形输入拒绝,零写入 ----
327
+ const before15 = deckFiles(cwd).length;
328
+ const invalid = [
329
+ { title: TITLE, itinerary: ITINERARY },
330
+ { title: TITLE, itinerary: ITINERARY, fact_ids: 'not-an-array' },
331
+ { title: TITLE, itinerary: ITINERARY, fact_ids: [42] },
332
+ { title: TITLE, itinerary: ITINERARY, fact_ids: [''] },
333
+ { itinerary: ITINERARY, fact_ids: [] },
334
+ { title: TITLE, fact_ids: [] },
335
+ { title: TITLE, itinerary: { ...ITINERARY, trip_start: '2027-02-30' }, fact_ids: [] },
336
+ { title: TITLE, itinerary: { ...ITINERARY, od_segments: [{ from: 'SZX', to: 'HKT', date: '2027-07-17', mode: 'teleport', legs: 1 }] }, fact_ids: [] },
337
+ ];
338
+ for (const [i, args] of invalid.entries()) {
339
+ const r = await run(args);
340
+ ok(r.ok === false, `§15a 畸形输入 ${i} 拒绝`);
341
+ }
342
+ ok(deckFiles(cwd).length === before15, `§15b 畸形输入零写入(实测 ${deckFiles(cwd).length})`);
343
+ // ---- §16 会话 cwd 非法一律 fail closed(零写入,绝不回落进程 cwd) ----
344
+ const procCwdBefore = readdirSync(process.cwd()).sort().join(',');
345
+ const badExecs = [
346
+ ['缺 exec', undefined],
347
+ ['空对象 exec', {}],
348
+ ['无 session', { agent: {} }],
349
+ ['无 header', { agent: { session: {} } }],
350
+ ['header 无 cwd', { agent: { session: { header: {} } } }],
351
+ ['cwd 空串', { agent: { session: { header: { cwd: '' } } } }],
352
+ ['cwd 纯空白', { agent: { session: { header: { cwd: ' ' } } } }],
353
+ ['cwd 非字符串', { agent: { session: { header: { cwd: 42 } } } }],
354
+ ['cwd 相对路径', { agent: { session: { header: { cwd: 'relative/workspace' } } } }],
355
+ ];
356
+ for (const [label, badExec] of badExecs) {
357
+ const r = await tool.execute({ title: TITLE, itinerary: ITINERARY, fact_ids: [] }, badExec);
358
+ ok(r.ok === false, `§16a 非法会话 cwd 拒绝:${label}`);
359
+ ok(/会话工作目录/.test(String(r.error)), `§16b 拒绝原因是会话工作目录缺失/非法:${label}`);
360
+ }
361
+ ok(readdirSync(process.cwd()).sort().join(',') === procCwdBefore, '§16c 进程 cwd 零新增文件');
362
+ // ---- §16d 直接调用能力层同样 fail closed(不依赖工具层守卫) ----
363
+ for (const bad of ['', ' ', undefined]) {
364
+ const r = await generateItineraryDeckArtifact({ title: TITLE, itinerary: ITINERARY, fact_ids: [] }, { stateRoot, cwd: bad });
365
+ ok(r.ok === false && /会话工作目录/.test(String(r.error)), `§16e 能力层拒绝 cwd=${JSON.stringify(bad)}`);
366
+ }
367
+ ok(readdirSync(process.cwd()).sort().join(',') === procCwdBefore, '§16f 能力层非法 cwd 零写入进程 cwd');
368
+ // ---- §17 真实产出链路:注册工具生成 → gotry_artifacts_list → gotry_artifacts_read ----
369
+ const listTool = tools.get('gotry_artifacts_list');
370
+ const readTool = tools.get('gotry_artifacts_read');
371
+ ok(Boolean(listTool && readTool), '§17a 产物 list/read 注册工具可用');
372
+ const chainName = 'gotry-deck-e2e-chain.html';
373
+ const chain = await run({ title: TITLE, itinerary: ITINERARY, fact_ids: [FLIGHT_ID, HOTEL_ID, TRAIN_ID], basename: chainName });
374
+ ok(chain.ok === true, `§17b 生成成功(实际:${JSON.stringify(chain.error ?? '')})`);
375
+ const chainDisk = readFileSync(String(chain.path), 'utf-8');
376
+ const listed = await listTool.execute({ limit: 50 }, exec);
377
+ const entry = (listed.artifacts ?? []).find(a => a.id === chainName);
378
+ ok(Boolean(entry), '§17c list 在册发现生成的 deck HTML(同一文件)');
379
+ ok(entry?.source === 'cwd-file', '§17d 来源为会话工作目录文件');
380
+ ok(realpathSync(String(entry?.path)) === String(chain.path), '§17e list 路径解析到生成返回的同一真实路径');
381
+ ok(entry?.bytes === Buffer.byteLength(chainDisk, 'utf8'), '§17f list 字节数与磁盘一致');
382
+ const read = await readTool.execute({ path: String(entry?.path) }, exec);
383
+ ok(read.ok === true, `§17g read 成功(实际:${JSON.stringify(read.error ?? '')})`);
384
+ ok(read.lang === 'html', '§17h read 以 html 源码文本读出');
385
+ ok(read.content === chainDisk, '§17i read 内容与落盘字节逐字一致');
386
+ ok(read.version === createHash('sha256').update(chainDisk).digest('hex').slice(0, 12), '§17j content version 与磁盘 sha256 指纹一致');
387
+ ok(read.content === renderDeck([FLIGHT, HOTEL, TRAIN]), '§17k 读回内容 == 注册表选中事实的 deck 输出');
388
+ // ---- §18 路径保真:宿主 cwd 的尾随空格是路径的一部分,绝不 trim 归一化到同名兄弟目录 ----
389
+ const plainDir = join(home, 'session');
390
+ const spacedDir = join(home, 'session ');
391
+ mkdirSync(plainDir, { recursive: true });
392
+ mkdirSync(spacedDir, { recursive: true });
393
+ const spacedExec = { agent: { session: { header: { cwd: spacedDir } } } };
394
+ const viaTool = await run({ title: TITLE, itinerary: ITINERARY, fact_ids: [], basename: 'gotry-deck-spaced.html' }, spacedExec);
395
+ ok(viaTool.ok === true, `§18a 带尾随空格的会话 cwd 生成成功(实际:${JSON.stringify(viaTool.error ?? '')})`);
396
+ ok(String(viaTool.path) === join(realpathSync(spacedDir), 'gotry-deck-spaced.html'), '§18b 落点 = 宿主给出的带空格目录');
397
+ ok(readdirSync(spacedDir).includes('gotry-deck-spaced.html'), '§18c 文件确实写在带空格目录内');
398
+ ok(deckFiles(plainDir).length === 0, '§18d 同名兄弟目录零写入(工具层未归一化)');
399
+ const viaCap = await generateItineraryDeckArtifact({ title: TITLE, itinerary: ITINERARY, fact_ids: [], basename: 'gotry-deck-spaced2.html' }, { stateRoot, cwd: spacedDir });
400
+ ok(viaCap.ok === true && readdirSync(spacedDir).includes('gotry-deck-spaced2.html'), '§18e 能力层写进带空格目录');
401
+ ok(deckFiles(plainDir).length === 0, '§18f 能力层不落到同名兄弟目录');
402
+ const plainOnly = join(home, 'plainonly');
403
+ mkdirSync(plainOnly, { recursive: true });
404
+ const ghost = await generateItineraryDeckArtifact({ title: TITLE, itinerary: ITINERARY, fact_ids: [] }, { stateRoot, cwd: `${plainOnly} ` });
405
+ ok(ghost.ok === false, '§18g 带空格路径不存在时拒绝(绝不回落 trim 后的兄弟)');
406
+ ok(readdirSync(plainOnly).length === 0, '§18h trim 后的兄弟目录零写入');
407
+ rmSync(home, { recursive: true, force: true });
408
+ console.log(`\nITINERARY DECK ARTIFACT TESTS: ${pass} pass, ${fail} fail`);
409
+ if (fail > 0) {
410
+ console.log('\nFAILURES:');
411
+ for (const f of failures)
412
+ console.log(` - ${f}`);
413
+ process.exit(1);
414
+ }
415
+ }
416
+ await main();