@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,443 @@
1
+ /**
2
+ * 扩展分发通道合同测试(§43;ADR-21 分发 A,GitHub Releases 下载链 + 通道 B 发布链预检)。
3
+ *
4
+ * 全离线确定性:回环 node:http 服务器(mkdtemp + 临时端口)serve dist-manifest 与
5
+ * 真 tar.gz 夹具(由平台 tar 从仓内 extension/ 打出);零外网、零浏览器、零共享状态。
6
+ *
7
+ * 断言面:
8
+ * ① 合同:稳定资产名/URL 形态;package-extension.mjs 资产名逐字防漂移(读源码比对);
9
+ * ② fail-closed:parseDistManifest 对坏 JSON/缺字段/资产名漂移/非 64-hex 哈希全部拒绝;
10
+ * ③ 版本比较:0.1.0<0.1.1<0.2.0<1.0.0,相等为 0;
11
+ * ④ 回环 e2e:installed(下载→SHA256→tar 解压→key 钉扎→原子交换)/ up-to-date(不下载 tarball)/
12
+ * check-only(只报告不落盘)/ 坏 SHA 拒绝 / 404 降级 fallback-bundled / key 漂移拒绝;
13
+ * ⑤ CLI 契约:extension-distribution-cli.ts 对回环基址单行 JSON + 退出码 0/2;
14
+ * ⑥ CWS 发布链(scripts/cws-publish-validate.mjs,通道 B #346/#537):token/upload/publish
15
+ * 响应分类经子进程走同一条 CLI 路径(HTTP 2xx 不足为凭;invalid_grant/uploadState≠SUCCESS/
16
+ * status[] 无 OK 一律拒绝;仅 ITEM_PENDING_REVIEW = 已在审勿重复提审)+ artifact 预检
17
+ * (三件套/版本/SHA256 对账)+ upload→download 路径错位回归(artifact 根 = dist-extension,
18
+ * download 缺 path 解到 workspace 根 = 2026-09-24 事故形态)+ workflow/文档防漂移。
19
+ */
20
+ import { execFileSync, spawn } from 'node:child_process';
21
+ import { createServer } from 'node:http';
22
+ import { copyFileSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
23
+ import { tmpdir } from 'node:os';
24
+ import { join, dirname } from 'node:path';
25
+ import { fileURLToPath, pathToFileURL } from 'node:url';
26
+ import { DEFAULT_RELEASE_BASE, DIST_ASSET_MANIFEST, DIST_ASSET_STORE_ZIP, DIST_ASSET_TARBALL, compareVersions, distAssetUrls, installExtensionFromGithub, parseDistManifest, readExtensionKey, sha256Hex, } from '../capabilities/session/extension-distribution.js';
27
+ const repoRoot = join(dirname(fileURLToPath(import.meta.url)), '..', '..');
28
+ const EXT_SRC = join(repoRoot, 'extension');
29
+ const EXT_FILES = ['manifest.json', 'background.js', 'content-main.js', 'content-bridge.js', 'README.md'];
30
+ let passed = 0;
31
+ function ok(cond, label) {
32
+ if (!cond) {
33
+ console.error(` ✗ ${label}`);
34
+ process.exit(1);
35
+ }
36
+ passed += 1;
37
+ console.log(` ok - ${label}`);
38
+ }
39
+ // ─── ① 合同面 ───────────────────────────────────────────────────────────────
40
+ {
41
+ const urls = distAssetUrls();
42
+ ok(urls.tarball === `${DEFAULT_RELEASE_BASE}/latest/download/${DIST_ASSET_TARBALL}`, `tarball URL 形态(${urls.tarball})`);
43
+ ok(urls.manifest.endsWith(`/latest/download/${DIST_ASSET_MANIFEST}`), 'manifest URL 形态(latest/download 永久链)');
44
+ ok(distAssetUrls('https://x.example/releases/').tarball === 'https://x.example/releases/latest/download/gotry-session-bridge.tar.gz', 'releaseBase 尾斜杠归一');
45
+ // 打包脚本资产名逐字防漂移(读 mjs 源码;名字漂移 = latest/download 永久链断裂)
46
+ const pkgSrc = readFileSync(join(repoRoot, 'scripts', 'package-extension.mjs'), 'utf8');
47
+ ok(pkgSrc.includes(`const ASSET_TARBALL = '${DIST_ASSET_TARBALL}'`), 'package-extension.mjs tarball 资产名一致');
48
+ ok(pkgSrc.includes(`const ASSET_STORE_ZIP = '${DIST_ASSET_STORE_ZIP}'`), 'package-extension.mjs store zip 资产名一致');
49
+ ok(pkgSrc.includes(`const ASSET_MANIFEST = '${DIST_ASSET_MANIFEST}'`), 'package-extension.mjs dist-manifest 资产名一致');
50
+ ok(pkgSrc.includes("const STAGE = join(OUT, 'gotry-session-bridge')"), '打包根目录名固定 gotry-session-bridge/(下载端 strip-components 依赖)');
51
+ ok(pkgSrc.includes('delete m.key'), 'store zip 变体剥离 manifest key(2026-08-30 商店首传实测拒绝 key;tar.gz 保留 key 保通道 ID 不变量)');
52
+ }
53
+ // ─── ② parseDistManifest fail-closed ────────────────────────────────────────
54
+ {
55
+ const good = JSON.stringify({ version: '0.1.0', tarball: DIST_ASSET_TARBALL, tarballSha256: 'a'.repeat(64), zip: DIST_ASSET_STORE_ZIP, zipSha256: 'b'.repeat(64) });
56
+ ok(parseDistManifest(good).version === '0.1.0', '合法 dist-manifest 解析');
57
+ const rejects = [
58
+ ['{bad json', '坏 JSON'],
59
+ [JSON.stringify({ version: 'x', tarball: DIST_ASSET_TARBALL, tarballSha256: 'a'.repeat(64), zip: DIST_ASSET_STORE_ZIP, zipSha256: 'b'.repeat(64) }), 'version 非 x.y.z'],
60
+ [JSON.stringify({ tarball: DIST_ASSET_TARBALL, tarballSha256: 'a'.repeat(64), zip: DIST_ASSET_STORE_ZIP, zipSha256: 'b'.repeat(64) }), '缺 version'],
61
+ [JSON.stringify({ version: '0.1.0', tarball: 'other-name.tar.gz', tarballSha256: 'a'.repeat(64), zip: DIST_ASSET_STORE_ZIP, zipSha256: 'b'.repeat(64) }), 'tarball 资产名漂移'],
62
+ [JSON.stringify({ version: '0.1.0', tarball: DIST_ASSET_TARBALL, tarballSha256: 'zz', zip: DIST_ASSET_STORE_ZIP, zipSha256: 'b'.repeat(64) }), 'tarballSha256 非 64-hex'],
63
+ ];
64
+ for (const [raw, label] of rejects) {
65
+ let threw = false;
66
+ try {
67
+ parseDistManifest(raw);
68
+ }
69
+ catch {
70
+ threw = true;
71
+ }
72
+ ok(threw, `fail-closed:${label}`);
73
+ }
74
+ }
75
+ // ─── ③ 版本比较 ─────────────────────────────────────────────────────────────
76
+ {
77
+ ok(compareVersions('0.1.0', '0.1.1') < 0, '0.1.0 < 0.1.1');
78
+ ok(compareVersions('0.2.0', '0.1.9') > 0, '0.2.0 > 0.1.9');
79
+ ok(compareVersions('1.0.0', '0.9.9') > 0, '1.0.0 > 0.9.9');
80
+ ok(compareVersions('0.1.0', '0.1.0') === 0, '相等为 0');
81
+ ok(compareVersions('0.1', '0.1.0') === 0, '缺段按 0 补齐');
82
+ }
83
+ async function startLoopback(manifestJson, tarball) {
84
+ let hits = 0;
85
+ const server = createServer((req, res) => {
86
+ if (req.url?.endsWith(DIST_ASSET_MANIFEST)) {
87
+ res.writeHead(200, { 'content-type': 'application/json' });
88
+ res.end(manifestJson);
89
+ }
90
+ else if (req.url?.endsWith(DIST_ASSET_TARBALL)) {
91
+ hits += 1;
92
+ res.writeHead(200, { 'content-type': 'application/gzip' });
93
+ res.end(tarball);
94
+ }
95
+ else {
96
+ res.writeHead(404);
97
+ res.end('not found');
98
+ }
99
+ });
100
+ await new Promise((r) => server.listen(0, '127.0.0.1', r));
101
+ const addr = server.address();
102
+ const base = `http://127.0.0.1:${typeof addr === 'object' && addr ? addr.port : 0}/releases`;
103
+ return {
104
+ base,
105
+ manifestJson,
106
+ tarball,
107
+ tarballHits: () => hits,
108
+ close: () => new Promise((r) => server.close(() => r())),
109
+ };
110
+ }
111
+ /** 用平台 tar 从 sourceDir 打一个真 tar.gz 夹具(顶层目录 gotry-session-bridge/);
112
+ * versionOverride 把暂存副本的 manifest 版本改写为远端版本(保留真实 key——key 钉扎闸要在场) */
113
+ function buildTarball(sourceDir, versionOverride) {
114
+ const stage = mkdtempSync(join(tmpdir(), 'extdist-stage-'));
115
+ const root = join(stage, 'gotry-session-bridge');
116
+ mkdirSync(root);
117
+ for (const f of EXT_FILES)
118
+ copyFileSync(join(sourceDir, f), join(root, f));
119
+ if (versionOverride != null) {
120
+ const m = JSON.parse(readFileSync(join(root, 'manifest.json'), 'utf8'));
121
+ writeFileSync(join(root, 'manifest.json'), JSON.stringify({ ...m, version: versionOverride }));
122
+ }
123
+ const tarPath = join(stage, DIST_ASSET_TARBALL);
124
+ execFileSync('tar', ['-czf', tarPath, '-C', stage, 'gotry-session-bridge']);
125
+ const tarball = readFileSync(tarPath);
126
+ rmSync(stage, { recursive: true, force: true });
127
+ return { tarball, sha: sha256Hex(tarball) };
128
+ }
129
+ function distManifestJson(version, sha) {
130
+ return JSON.stringify({ version, tarball: DIST_ASSET_TARBALL, tarballSha256: sha, zip: DIST_ASSET_STORE_ZIP, zipSha256: 'c'.repeat(64), builtFromCommit: 'test' });
131
+ }
132
+ {
133
+ const work = mkdtempSync(join(tmpdir(), 'extdist-e2e-'));
134
+ const { tarball, sha } = buildTarball(EXT_SRC, '9.9.9');
135
+ const srcVersion = JSON.parse(readFileSync(join(EXT_SRC, 'manifest.json'), 'utf8'));
136
+ const remoteVersion = '9.9.9';
137
+ // (1) installed:下载→SHA256→解压→key 钉扎→原子交换
138
+ {
139
+ const dest = join(work, 'dest1');
140
+ const lb = await startLoopback(distManifestJson(remoteVersion, sha), tarball);
141
+ const r = await installExtensionFromGithub({ destDir: dest, pinnedSourceDir: EXT_SRC, releaseBase: lb.base });
142
+ lb.close();
143
+ ok(r.ok && r.action === 'installed' && r.version === remoteVersion, `installed 全链(action=${r.action},v=${r.version},err=${r.error ?? '无'})`);
144
+ ok(readExtensionKey(dest) === srcVersion.key, '落位产物 key 与 bundled 逐字一致(同扩展 ID)');
145
+ ok(JSON.parse(readFileSync(join(dest, 'manifest.json'), 'utf8')).version === remoteVersion, '落位产物为远端版本');
146
+ for (const f of EXT_FILES)
147
+ ok(existsSync(join(dest, f)), `文件就位:${f}`);
148
+ }
149
+ // (2) 坏 SHA 拒绝(截断/误传资产防住)
150
+ {
151
+ const dest = join(work, 'dest2');
152
+ const lb = await startLoopback(distManifestJson(remoteVersion, '0'.repeat(64)), tarball);
153
+ const r = await installExtensionFromGithub({ destDir: dest, pinnedSourceDir: EXT_SRC, releaseBase: lb.base });
154
+ lb.close();
155
+ ok(!r.ok && r.action === 'fallback-bundled' && /SHA256/.test(r.error ?? ''), `SHA256 不符拒绝(${r.error})`);
156
+ ok(!existsSync(dest), '失败路径零落盘');
157
+ }
158
+ // (3) 404 → fallback-bundled
159
+ {
160
+ const dest = join(work, 'dest3');
161
+ const lb = await startLoopback(distManifestJson(remoteVersion, sha), tarball);
162
+ lb.close(); // 关掉 = 连接拒绝,等价网络不可达
163
+ const r = await installExtensionFromGithub({ destDir: dest, releaseBase: lb.base });
164
+ ok(!r.ok && r.action === 'fallback-bundled', `无网降级 fallback-bundled(${(r.error ?? '').slice(0, 40)})`);
165
+ }
166
+ // (4) key 漂移拒绝(通道产物与 bundled 不同 ID → 防端口池/host 权限漂移)
167
+ {
168
+ const rogue = mkdtempSync(join(work, 'rogue-'));
169
+ const rogueManifest = { ...srcVersion, version: remoteVersion, key: `ROGUE-${srcVersion.key}` };
170
+ writeFileSync(join(rogue, 'manifest.json'), JSON.stringify(rogueManifest));
171
+ for (const f of EXT_FILES.filter((x) => x !== 'manifest.json'))
172
+ copyFileSync(join(EXT_SRC, f), join(rogue, f));
173
+ const { tarball: rTar, sha: rSha } = buildTarball(rogue);
174
+ const dest = join(work, 'dest4');
175
+ const lb = await startLoopback(distManifestJson(remoteVersion, rSha), rTar);
176
+ const r = await installExtensionFromGithub({ destDir: dest, pinnedSourceDir: EXT_SRC, releaseBase: lb.base });
177
+ lb.close();
178
+ ok(!r.ok && /key 漂移/.test(r.error ?? ''), `key 漂移拒绝(${r.error})`);
179
+ ok(!existsSync(dest), '漂移路径零落盘');
180
+ rmSync(rogue, { recursive: true, force: true });
181
+ }
182
+ // (5) up-to-date:本地已是远端版本 → 不下载 tarball
183
+ {
184
+ const dest = join(work, 'dest5');
185
+ mkdirSync(dest, { recursive: true });
186
+ writeFileSync(join(dest, 'manifest.json'), JSON.stringify({ ...srcVersion, version: remoteVersion }));
187
+ const lb = await startLoopback(distManifestJson(remoteVersion, sha), tarball);
188
+ const r = await installExtensionFromGithub({ destDir: dest, pinnedSourceDir: EXT_SRC, releaseBase: lb.base });
189
+ const hits = lb.tarballHits();
190
+ lb.close();
191
+ ok(r.ok && r.action === 'up-to-date' && hits === 0, `up-to-date 跳过(tarball 下载 ${hits} 次)`);
192
+ }
193
+ // (6) check-only:只报告远端版本,不落盘
194
+ {
195
+ const dest = join(work, 'dest6');
196
+ const lb = await startLoopback(distManifestJson(remoteVersion, sha), tarball);
197
+ const r = await installExtensionFromGithub({ destDir: dest, releaseBase: lb.base, checkOnly: true });
198
+ lb.close();
199
+ ok(r.ok && r.version === remoteVersion && !existsSync(dest), 'check-only 报告远端版本且零落盘');
200
+ }
201
+ rmSync(work, { recursive: true, force: true });
202
+ }
203
+ // ─── ⑤ CLI 契约(回环基址,单行 JSON + 退出码) ────────────────────────────────
204
+ {
205
+ const { tarball, sha } = buildTarball(EXT_SRC, '9.9.9');
206
+ const srcVersion = JSON.parse(readFileSync(join(EXT_SRC, 'manifest.json'), 'utf8'));
207
+ const lb = await startLoopback(distManifestJson('9.9.9', sha), tarball);
208
+ const dest = mkdtempSync(join(tmpdir(), 'extdist-cli-'));
209
+ const cli = join(repoRoot, 'ts', 'scripts', 'extension-distribution-cli.ts');
210
+ const run = (args) => new Promise((resolve) => {
211
+ const child = spawn('npx', ['--yes', 'tsx', cli, ...args], { cwd: join(repoRoot, 'ts'), stdio: ['ignore', 'pipe', 'inherit'] });
212
+ let buf = '';
213
+ child.stdout.on('data', (c) => { buf += c.toString('utf8'); });
214
+ child.on('close', (code) => {
215
+ const line = (buf.trim().split('\n').pop() ?? '');
216
+ let json = null;
217
+ if (line.startsWith('{')) {
218
+ try {
219
+ json = JSON.parse(line);
220
+ }
221
+ catch { /* null */ }
222
+ }
223
+ resolve({ code: code ?? -1, json });
224
+ });
225
+ });
226
+ const r1 = await run(['--dest', dest, '--source-dir', EXT_SRC, '--release-base', lb.base]);
227
+ ok(r1.code === 0 && r1.json?.ok === true && r1.json?.action === 'installed', `CLI installed 单行 JSON + exit 0(action=${String(r1.json?.action)})`);
228
+ const r2 = await run(['--dest', dest, '--source-dir', EXT_SRC, '--release-base', 'http://127.0.0.1:1/releases']);
229
+ ok(r2.code === 2 && r2.json?.ok === false && r2.json?.action === 'fallback-bundled', `CLI 失败 exit 2 + fallback-bundled JSON`);
230
+ lb.close();
231
+ rmSync(dest, { recursive: true, force: true });
232
+ }
233
+ // ─── ⑥ CWS 发布链:响应分类 + artifact 预检 + 路径错位回归(scripts/cws-publish-validate.mjs) ───
234
+ {
235
+ const VALIDATOR = join(repoRoot, 'scripts', 'cws-publish-validate.mjs');
236
+ const WORKFLOW_SRC = readFileSync(join(repoRoot, '.github/workflows/extension-publish.yml'), 'utf8');
237
+ const SENTINEL = 'FAKE_SECRET_SENTINEL';
238
+ let importWithoutArgv = false;
239
+ try {
240
+ execFileSync(process.execPath, ['--input-type=module', '-e', `await import(${JSON.stringify(pathToFileURL(VALIDATOR).href)})`], { cwd: repoRoot, stdio: 'pipe' });
241
+ importWithoutArgv = true;
242
+ }
243
+ catch { /* the pure module must not execute or crash its CLI entrypoint */ }
244
+ ok(importWithoutArgv, '校验器可作为纯模块导入,无 argv[1] 时不触发 CLI');
245
+ /** 子进程走与 workflow 逐字相同的 CLI 路径(stdin + --http-code + 退出码;成功 JSON 在 stdout,失败 JSON 在 stderr) */
246
+ const runValidator = (args, stdin) => new Promise((resolve) => {
247
+ const child = spawn('node', [VALIDATOR, ...args], { cwd: repoRoot, stdio: ['pipe', 'pipe', 'pipe'] });
248
+ let out = '';
249
+ let err = '';
250
+ child.stdout.on('data', (c) => { out += c.toString('utf8'); });
251
+ child.stderr.on('data', (c) => { err += c.toString('utf8'); });
252
+ if (stdin != null)
253
+ child.stdin.write(stdin);
254
+ child.stdin.end();
255
+ child.on('close', (code) => resolve({ code: code ?? -1, stdout: out, stderr: err }));
256
+ });
257
+ /** 机密纪律:任何失败路径的 stdout+stderr 都不得携带响应体/明细/凭据等 API 供应文本 */
258
+ const assertNoLeak = async (args, stdin, label) => {
259
+ const r = await runValidator(args, stdin);
260
+ ok(r.code === 1, `${label}:非零退出`);
261
+ ok(!`${r.stdout}${r.stderr}`.includes(SENTINEL), `${label}:stdout+stderr 无 sentinel 泄漏`);
262
+ const lastLine = r.stderr.trim().split('\n').pop() ?? '{}';
263
+ ok(JSON.parse(lastLine).ok === false, `${label}:失败 JSON 为固定分类(${JSON.parse(lastLine).reason})`);
264
+ };
265
+ // (1) token:合法 → exit 0;分类 JSON 不携带凭据;--field access_token 是唯一 token 出口
266
+ {
267
+ const r = await runValidator(['token', '--http-code', '200'], '{"access_token":"SECRET-TOKEN","expires_in":3599,"token_type":"Bearer"}');
268
+ ok(r.code === 0 && JSON.parse(r.stdout).ok === true, `token 合法响应接受(${r.stdout.trim()})`);
269
+ ok(!r.stdout.includes('SECRET-TOKEN'), 'token 分类 JSON 不回显 access_token(仅 --field 吐本值)');
270
+ const f = await runValidator(['token', '--http-code', '200', '--field', 'access_token'], '{"access_token":"SECRET-TOKEN"}');
271
+ ok(f.code === 0 && f.stdout.trim() === 'SECRET-TOKEN', 'token --field access_token 吐本值(workflow 捕获形态)');
272
+ }
273
+ // (2) token fail-closed:4xx/5xx、error 字段(任意类型含对象)、缺/空/纯空白/内嵌空白或控制字符的
274
+ // access_token、畸形 JSON——全部拒绝;每条都同时是 sentinel 泄漏探针(响应体不落日志)
275
+ {
276
+ const cases = [
277
+ ['401', `{"access_token":"${SENTINEL}"}`, 'http-status', 'HTTP 401(体含 sentinel)'],
278
+ ['200', `{"error":"invalid_grant","error_description":"expired ${SENTINEL}"}`, 'api-error', 'invalid_grant(描述含 sentinel)'],
279
+ ['200', `{"error":{"code":5,"message":"${SENTINEL}"}}`, 'api-error', '对象值 error 字段'],
280
+ ['200', `{"expires_in":3599,"note":"${SENTINEL}"}`, 'missing-access-token', '缺 access_token(体含 sentinel)'],
281
+ ['200', `{"access_token":"${SENTINEL}","error":null}`, 'api-error', 'null error 字段仍拒绝'],
282
+ ['200', '{"access_token":""}', 'missing-access-token', '空 access_token'],
283
+ ['200', '{"access_token":" "}', 'missing-access-token', '纯空白 access_token'],
284
+ ['200', '{"access_token":"ab\\ncd"}', 'missing-access-token', '合法 JSON 内嵌 \\n(转义形式)'],
285
+ ['200', '{"access_token":"a\\tb"}', 'missing-access-token', '内嵌制表符'],
286
+ ['200', 'not-json', 'malformed-json', '畸形 JSON'],
287
+ ];
288
+ for (const [code, body, reason, label] of cases) {
289
+ const r = await runValidator(['token', '--http-code', code], body);
290
+ ok(r.code === 1 && JSON.parse(r.stderr).reason === reason, `token fail-closed:${label}(${reason})`);
291
+ ok(!`${r.stdout}${r.stderr}`.includes(SENTINEL), `token 无泄漏:${label}`);
292
+ }
293
+ }
294
+ // (3) upload:SUCCESS 且 itemError 为空唯一放行;HTTP-success/application-rejection(200 + FAILURE、
295
+ // SUCCESS 带非空 itemError 的自相矛盾响应)拒绝;明细文本不落日志
296
+ {
297
+ const r = await runValidator(['upload', '--http-code', '200'], '{"kind":"chromewebstore#item","uploadState":"SUCCESS"}');
298
+ ok(r.code === 0 && JSON.parse(r.stdout).uploadState === 'SUCCESS', 'upload SUCCESS(空 itemError)接受');
299
+ const rejection = [
300
+ [`{"uploadState":"FAILURE","itemError":["${SENTINEL}"]}`, '200+FAILURE(明细含 sentinel)'],
301
+ [`{"uploadState":"SUCCESS","itemError":["${SENTINEL}"]}`, 'SUCCESS 带非空 itemError(自相矛盾,不前进了)'],
302
+ [`{"uploadState":"SUCCESS","itemError":"${SENTINEL}"}`, 'itemError 字符串拒绝'],
303
+ [`{"uploadState":"SUCCESS","itemError":{"message":"${SENTINEL}"}}`, 'itemError 对象拒绝'],
304
+ ['{"uploadState":"SUCCESS","itemError":null}', 'itemError null 拒绝'],
305
+ ['{"uploadState":"IN_PROGRESS"}', 'IN_PROGRESS 拒绝'],
306
+ ['{"uploadState":"NOT_FOUND"}', 'NOT_FOUND 拒绝'],
307
+ ['{"uploadState":"SOMETHING_NEW"}', '未知新值 fail-closed'],
308
+ ['{"kind":"chromewebstore#item"}', '缺 uploadState'],
309
+ ['<html>gateway error</html>', 'HTML 网关体按畸形 JSON 拒绝'],
310
+ ];
311
+ for (const [body, label] of rejection)
312
+ await assertNoLeak(['upload', '--http-code', '200'], body, `upload:${label}`);
313
+ const rMixed = await runValidator(['upload', '--http-code', '200'], rejection[1][0]);
314
+ ok(JSON.parse(rMixed.stderr).reason === 'upload-success-with-errors' && JSON.parse(rMixed.stderr).itemErrorCount === 1, 'SUCCESS+itemError 归类 upload-success-with-errors(计数为派生布尔/数值)');
315
+ const r500 = await runValidator(['upload', '--http-code', '500'], '{"uploadState":"SUCCESS"}');
316
+ ok(r500.code === 1 && JSON.parse(r500.stderr).reason === 'http-status' && JSON.parse(r500.stderr).httpCode === 500, '非 2xx 即使体面 SUCCESS 也拒绝(仅固定分类 + HTTP 码)');
317
+ }
318
+ // (4) publish:status[] 非空且每个元素都 === 'OK' 才算本次提审受理;混合 OK/拒绝、非字符串元素、
319
+ // 枚举外新值(IN_REVIEW 不存在于 v1)一律拒绝;仅 ITEM_PENDING_REVIEW = 独立拒绝原因
320
+ // (非零退出 + 读回指引,绝不是本版受理凭证);所有失败路径体文本不落日志
321
+ {
322
+ const rOk = await runValidator(['publish', '--http-code', '200'], '{"kind":"chromewebstore#item","item_id":"x","status":["OK"],"statusDetail":["OK"]}');
323
+ ok(rOk.code === 0 && JSON.parse(rOk.stdout).reviewState === 'submitted', 'publish status=[OK] 归类 submitted(HTTP 200 ≠ 提审受理,以响应体为准)');
324
+ const rOk2 = await runValidator(['publish', '--http-code', '200'], '{"status":["OK","OK"]}');
325
+ ok(rOk2.code === 0 && JSON.parse(rOk2.stdout).reviewState === 'submitted', '全 OK 多元素仍受理');
326
+ const rPending = await runValidator(['publish', '--http-code', '200'], '{"status":["ITEM_PENDING_REVIEW"]}');
327
+ const pendingJson = JSON.parse(rPending.stderr.trim().split('\n').pop() ?? '{}');
328
+ ok(rPending.code === 1 && pendingJson.reason === 'publish-already-pending-review', '仅 ITEM_PENDING_REVIEW = 独立拒绝原因,非零退出(读回后再决定,绝非本版受理凭证)');
329
+ ok(/read back the item state/.test(rPending.stderr) && !rPending.stderr.includes(SENTINEL), '读回指引为固定安全文本');
330
+ const rejections = [
331
+ [`{"status":["NOT_AUTHORIZED"],"statusDetail":["${SENTINEL}"]}`, 'NOT_AUTHORIZED(明细含 sentinel)'],
332
+ ['{"status":["OK","NOT_AUTHORIZED"]}', '混合 OK + 拒绝状态'],
333
+ ['{"status":["OK",123]}', '非字符串元素混入'],
334
+ ['{"status":["ITEM_NOT_FOUND"]}', 'ITEM_NOT_FOUND'],
335
+ ['{"status":["ITEM_TAKEN_DOWN"]}', 'ITEM_TAKEN_DOWN'],
336
+ ['{"status":["IN_REVIEW"]}', 'IN_REVIEW(v1 无此枚举值)'],
337
+ ['{"status":["ITEM_PENDING_REVIEW","NOT_AUTHORIZED"]}', '混合 pending + 拒绝'],
338
+ ['{"kind":"chromewebstore#item","item_id":"x"}', '缺 status[]'],
339
+ ['{"status":[]}', '空 status[]'],
340
+ ['{bad', '畸形 JSON'],
341
+ ];
342
+ for (const [body, label] of rejections)
343
+ await assertNoLeak(['publish', '--http-code', '200'], body, `publish:${label}`);
344
+ const rMix = await runValidator(['publish', '--http-code', '200'], rejections[1][0]);
345
+ ok(JSON.parse(rMix.stderr).reason === 'publish-rejected', '混合 OK/拒绝归 publish-rejected(绝不标 review-submitted)');
346
+ const rMixPending = await runValidator(['publish', '--http-code', '200'], rejections[6][0]);
347
+ const mixPendingJson = JSON.parse(rMixPending.stderr.trim().split('\n').pop() ?? '{}');
348
+ ok(mixPendingJson.reason === 'publish-already-pending-review' && mixPendingJson.hasRecognizedRejection === true, '混合 pending/拒绝也 fail(附 recognized-rejection 派生布尔)');
349
+ }
350
+ // (5) 用法错误 exit 2(--http-code 必填——workflow 逐字携带)
351
+ {
352
+ const r = await runValidator(['upload'], '{}');
353
+ ok(r.code === 2, '缺 --http-code 归用法错误 exit 2');
354
+ }
355
+ // (6) artifact 预检:三件套/版本/SHA256 对账 + pack→download→文件查找错位回归
356
+ // (upload-artifact 多路径 root 在公共祖先 dist-extension/;download 缺 path 解到
357
+ // workspace 根 = 2026-09-24 事故形态——旧 curl 引 dist-extension/ 必 ENOENT)
358
+ {
359
+ const work = mkdtempSync(join(tmpdir(), 'extdist-cws-'));
360
+ const zipBytes = Buffer.from(`store-zip-bytes-${Date.now()}`);
361
+ const tarBytes = Buffer.from(`tar-bytes-${Date.now()}`);
362
+ const zipSha = sha256Hex(zipBytes);
363
+ const tarSha = sha256Hex(tarBytes);
364
+ const distManifest = JSON.stringify({
365
+ version: '0.2.0.25',
366
+ tarball: DIST_ASSET_TARBALL,
367
+ tarballSha256: tarSha,
368
+ zip: DIST_ASSET_STORE_ZIP,
369
+ zipSha256: zipSha,
370
+ builtFromCommit: 'fb1cbf2',
371
+ });
372
+ // 事故形态(红):artifact 内容按 v4 根规则 = 三件文件在 archive 根;download 缺 path 落 workspace 根
373
+ const oldDownload = join(work, 'workspace-old');
374
+ mkdirSync(oldDownload);
375
+ writeFileSync(join(oldDownload, DIST_ASSET_STORE_ZIP), zipBytes);
376
+ writeFileSync(join(oldDownload, DIST_ASSET_TARBALL), tarBytes);
377
+ writeFileSync(join(oldDownload, DIST_ASSET_MANIFEST), distManifest);
378
+ const red = await runValidator(['artifact', '--dir', join(oldDownload, 'dist-extension'), '--expect-version', '0.2.0.25']);
379
+ ok(red.code === 1 && JSON.parse(red.stderr).reason === 'missing-manifest', '路径错位事故形态拒绝(download 缺 path → dist-extension/ 下无三件套,旧 curl 必 ENOENT)');
380
+ // 修复形态(绿):download 显式 path: dist-extension
381
+ const newDownload = join(work, 'workspace-new', 'dist-extension');
382
+ mkdirSync(newDownload, { recursive: true });
383
+ writeFileSync(join(newDownload, DIST_ASSET_STORE_ZIP), zipBytes);
384
+ writeFileSync(join(newDownload, DIST_ASSET_TARBALL), tarBytes);
385
+ writeFileSync(join(newDownload, DIST_ASSET_MANIFEST), distManifest);
386
+ const green = await runValidator(['artifact', '--dir', newDownload, '--expect-version', '0.2.0.25']);
387
+ ok(green.code === 0 && JSON.parse(green.stdout).zipSha256 === zipSha, '修复形态:显式 path 后预检全绿(版本+SHA256 对账)');
388
+ const mkFixture = () => {
389
+ const dir = join(work, `fixture-${Math.random().toString(36).slice(2)}`);
390
+ mkdirSync(dir, { recursive: true });
391
+ writeFileSync(join(dir, DIST_ASSET_STORE_ZIP), zipBytes);
392
+ writeFileSync(join(dir, DIST_ASSET_TARBALL), tarBytes);
393
+ writeFileSync(join(dir, DIST_ASSET_MANIFEST), distManifest);
394
+ return dir;
395
+ };
396
+ const tamper = [
397
+ (dir) => { writeFileSync(join(dir, DIST_ASSET_MANIFEST), JSON.stringify({ ...JSON.parse(distManifest), version: '0.0.1.1' })); return 'version-mismatch'; },
398
+ (dir) => { writeFileSync(join(dir, DIST_ASSET_STORE_ZIP), Buffer.from('tampered')); return 'checksum-mismatch'; },
399
+ (dir) => { rmSync(join(dir, DIST_ASSET_STORE_ZIP)); return 'missing-artifact'; },
400
+ (dir) => { rmSync(join(dir, DIST_ASSET_MANIFEST)); return 'missing-manifest'; },
401
+ (dir) => { writeFileSync(join(dir, DIST_ASSET_MANIFEST), '{bad'); return 'malformed-manifest'; },
402
+ (dir) => { writeFileSync(join(dir, DIST_ASSET_MANIFEST), JSON.stringify({ ...JSON.parse(distManifest), zipSha256: 'zz' })); return 'bad-hash-format'; },
403
+ (dir) => { writeFileSync(join(dir, DIST_ASSET_MANIFEST), JSON.stringify({ ...JSON.parse(distManifest), zip: 'other.zip' })); return 'asset-name-drift'; },
404
+ ];
405
+ for (const mutate of tamper) {
406
+ const dir = mkFixture();
407
+ const reason = mutate(dir);
408
+ const r = await runValidator(['artifact', '--dir', dir, '--expect-version', '0.2.0.25']);
409
+ ok(r.code === 1 && JSON.parse(r.stderr).reason === reason, `artifact 预检 fail-closed:${reason}`);
410
+ }
411
+ rmSync(work, { recursive: true, force: true });
412
+ }
413
+ // (7) 防漂移:validator 资产名与 package-extension.mjs 逐字一致;workflow 逐字携带
414
+ // path: dist-extension + 预检 + 校验器三步调用 + publishTarget + 有界超时 + UNCONFIRMED 读回
415
+ // + 机密纪律(-f 不回用);双语文档不再提 CHROME_PUBLISHER_ID(四 secret 口径)
416
+ {
417
+ const pkgSrc = readFileSync(join(repoRoot, 'scripts', 'package-extension.mjs'), 'utf8');
418
+ const validatorSrc = readFileSync(VALIDATOR, 'utf8');
419
+ ok(validatorSrc.includes(`export const STORE_ZIP_NAME = '${DIST_ASSET_STORE_ZIP}'`), 'validator store zip 资产名一致');
420
+ ok(validatorSrc.includes(`export const TARBALL_NAME = '${DIST_ASSET_TARBALL}'`), 'validator tarball 资产名一致');
421
+ ok(validatorSrc.includes(`export const DIST_MANIFEST_NAME = '${DIST_ASSET_MANIFEST}'`), 'validator dist-manifest 资产名一致');
422
+ for (const name of [DIST_ASSET_STORE_ZIP, DIST_ASSET_TARBALL, DIST_ASSET_MANIFEST]) {
423
+ ok(pkgSrc.includes(`'${name}'`), `package-extension.mjs 含 ${name}(validator 对账对象在场)`);
424
+ }
425
+ ok(/download-artifact@v4[\s\S]{0,400}path: dist-extension/.test(WORKFLOW_SRC), 'workflow download 显式 path: dist-extension(路径错位修复在位)');
426
+ ok(WORKFLOW_SRC.includes('cws-publish-validate.mjs artifact --dir dist-extension'), 'workflow 预检先于网络调用');
427
+ ok((WORKFLOW_SRC.match(/cws-publish-validate\.mjs (token|upload|publish)/g) ?? []).length === 3, 'token/upload/publish 三步都走校验器');
428
+ ok(!WORKFLOW_SRC.includes('CHROME_PUBLISHER_ID'), 'workflow 无 CHROME_PUBLISHER_ID(直连 API 四 secret)');
429
+ ok(WORKFLOW_SRC.includes('publishTarget=default'), 'publish query 用 v1 文档化参数 publishTarget=default');
430
+ ok(!/publish\?publishMode|&publishMode/.test(WORKFLOW_SRC), 'publishMode(v1 无此参数)不再出现在请求 URL');
431
+ const curlCalls = WORKFLOW_SRC.match(/curl -sS --connect-timeout \d+ --max-time \d+/g) ?? [];
432
+ ok(curlCalls.length === 3, `三步 curl 均带有界 --connect-timeout/--max-time(实得 ${curlCalls.length})`);
433
+ ok((WORKFLOW_SRC.match(/::error::[^\n]*UNCONFIRMED/g) ?? []).length === 3, '传输失败三步均记 UNCONFIRMED(读回后再决定,不自动重试)');
434
+ ok(!WORKFLOW_SRC.includes('curl -fsS'), '不再用 -f(吞错误响应体,无法分类)');
435
+ ok(WORKFLOW_SRC.includes('if-no-files-found: error'), 'workflow pack 侧 if-no-files-found: error 保留(缺件即红)');
436
+ for (const doc of ['docs/extension-store-publish.md', 'docs/extension-store-publish.zh-CN.md']) {
437
+ const src = readFileSync(join(repoRoot, doc), 'utf8');
438
+ ok(!src.includes('CHROME_PUBLISHER_ID'), `${doc} 无 CHROME_PUBLISHER_ID(四 secret 口径同步)`);
439
+ ok(src.includes('publishTarget'), `${doc} 载明 publishTarget(v1 文档化参数)`);
440
+ }
441
+ }
442
+ }
443
+ console.log(`EXTENSION DISTRIBUTION: ${passed} pass, 0 fail`);