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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (507) hide show
  1. package/README.md +172 -219
  2. package/README.zh-CN.md +222 -0
  3. package/bin/gotry-backend.js +53 -0
  4. package/bin/gotry-booking-copilot.js +53 -0
  5. package/bin/gotry-bootstrap.js +1744 -0
  6. package/bin/gotry-inner.js +733 -83
  7. package/bin/gotry-process-liveness.d.ts +27 -0
  8. package/bin/gotry-process-liveness.js +97 -0
  9. package/bin/gotry-runtime-resolution.d.ts +27 -0
  10. package/bin/gotry-runtime-resolution.js +49 -0
  11. package/bin/gotry.js +1 -1
  12. package/client/client.js +203 -0
  13. package/cordis.gotry-patch.yml +80 -56
  14. package/data/airline-airports.json +39 -0
  15. package/data/stations-12306-verify.json +524 -0
  16. package/dist/capabilities/agent-reach-deep.js +45 -122
  17. package/dist/capabilities/agent-reach.js +101 -146
  18. package/dist/capabilities/anything.js +135 -94
  19. package/dist/capabilities/artifacts.js +370 -0
  20. package/dist/capabilities/channel-health.js +131 -0
  21. package/dist/capabilities/channel-registry.js +256 -0
  22. package/dist/capabilities/doctor.js +546 -0
  23. package/dist/capabilities/effect.js +394 -0
  24. package/dist/capabilities/external-event.js +149 -0
  25. package/dist/capabilities/fact-log.js +55 -0
  26. package/dist/capabilities/flyai-config.js +337 -0
  27. package/dist/capabilities/flyai.js +947 -110
  28. package/dist/capabilities/fx-contract.js +293 -0
  29. package/dist/capabilities/geo-atlas.js +246 -0
  30. package/dist/capabilities/ground-transfer.js +509 -0
  31. package/dist/capabilities/hbcli.js +260 -123
  32. package/dist/capabilities/hotelbyte-transaction.js +194 -0
  33. package/dist/capabilities/incident-log.js +131 -61
  34. package/dist/capabilities/itinerary-artifact.js +190 -0
  35. package/dist/capabilities/itinerary-deck-artifact.js +194 -0
  36. package/dist/capabilities/itinerary-deck-export.js +339 -0
  37. package/dist/capabilities/lavish-local.js +924 -0
  38. package/dist/capabilities/model-override.js +38 -0
  39. package/dist/capabilities/opensky.js +54 -43
  40. package/dist/capabilities/resilience.js +191 -0
  41. package/dist/capabilities/session/action-cache.js +50 -44
  42. package/dist/capabilities/session/adapters/ctrip-flight.js +120 -62
  43. package/dist/capabilities/session/adapters/ctrip-hotel.js +222 -0
  44. package/dist/capabilities/session/adapters/dida-portal.js +274 -0
  45. package/dist/capabilities/session/adapters/meituan-local.js +35 -54
  46. package/dist/capabilities/session/adapters/rail-12306.js +342 -0
  47. package/dist/capabilities/session/benchmark.js +189 -0
  48. package/dist/capabilities/session/bridge-ledger.js +224 -0
  49. package/dist/capabilities/session/extension-bridge.js +636 -0
  50. package/dist/capabilities/session/extension-channel.js +109 -0
  51. package/dist/capabilities/session/extension-distribution.js +230 -0
  52. package/dist/capabilities/session/extract.js +31 -21
  53. package/dist/capabilities/session/golden-score.js +114 -0
  54. package/dist/capabilities/session/health-watch.js +215 -0
  55. package/dist/capabilities/session/read-guard.js +75 -24
  56. package/dist/capabilities/session/static-flight-golden.js +150 -0
  57. package/dist/capabilities/session/transport.js +97 -83
  58. package/dist/capabilities/session/wizard.js +117 -0
  59. package/dist/capabilities/session-consent.js +178 -0
  60. package/dist/capabilities/session-login.js +170 -0
  61. package/dist/capabilities/session-search.js +635 -44
  62. package/dist/capabilities/spawn-bounded.js +203 -0
  63. package/dist/capabilities/sponsor-plugin.js +341 -0
  64. package/dist/capabilities/visa-policy.js +140 -0
  65. package/dist/capabilities/weather.js +243 -138
  66. package/dist/data/session-golden-20.json +25 -0
  67. package/dist/data/sf-golden-manifest.json +103 -0
  68. package/dist/data/sf-static-routes.json +91 -0
  69. package/dist/scripts/action-cache-tests.js +24 -59
  70. package/dist/scripts/agent-planning-turn-deadline-e2e.js +242 -0
  71. package/dist/scripts/agent-planning-turn-deadline-tests.js +185 -0
  72. package/dist/scripts/agent-reach-deep-tests.js +30 -40
  73. package/dist/scripts/agent-reach-error-tests.js +354 -0
  74. package/dist/scripts/agent-reach-tests.js +26 -18
  75. package/dist/scripts/agent-reach-wrapper-tests.js +50 -50
  76. package/dist/scripts/anything-tests.js +116 -60
  77. package/dist/scripts/artifact-client-contract-tests.js +220 -0
  78. package/dist/scripts/artifacts-capability-tests.js +727 -0
  79. package/dist/scripts/async-collect.js +50 -11
  80. package/dist/scripts/benchmark-environment-bridge-e2e.js +741 -0
  81. package/dist/scripts/benchmark-environment-bridge-tests.js +1452 -0
  82. package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +126 -0
  83. package/dist/scripts/booking-copilot-availability-policy-tests.js +265 -0
  84. package/dist/scripts/booking-copilot-bin-proof-tests.js +66 -0
  85. package/dist/scripts/booking-copilot-cleanup-proof-helper.js +76 -0
  86. package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +144 -0
  87. package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +424 -0
  88. package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +2839 -0
  89. package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +309 -0
  90. package/dist/scripts/booking-copilot-dsh-readiness-proof.js +238 -0
  91. package/dist/scripts/booking-copilot-dsh-warmer-proof.js +123 -0
  92. package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +156 -0
  93. package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +70 -0
  94. package/dist/scripts/booking-copilot-intent-proof-tests.js +422 -0
  95. package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +184 -0
  96. package/dist/scripts/booking-copilot-planner-live-probe.js +95 -0
  97. package/dist/scripts/booking-copilot-proof-runtime.js +42 -0
  98. package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +210 -0
  99. package/dist/scripts/booking-copilot-runtime-proof-tests.js +2349 -0
  100. package/dist/scripts/booking-copilot-server-proof-tests.js +784 -0
  101. package/dist/scripts/booking-copilot-startup-proof-tests.js +94 -0
  102. package/dist/scripts/booking-executor-tests.js +80 -0
  103. package/dist/scripts/booking-recovery-chain-tests.js +182 -0
  104. package/dist/scripts/booking-saga-tests.js +125 -0
  105. package/dist/scripts/booking-surface-contract-proof-tests.js +212 -0
  106. package/dist/scripts/bootstrap-tests.js +1479 -0
  107. package/dist/scripts/bridge-events-tests.js +239 -0
  108. package/dist/scripts/bridge-ledger-tests.js +428 -0
  109. package/dist/scripts/build-changelog.js +238 -0
  110. package/dist/scripts/build-metrics-report.js +331 -0
  111. package/dist/scripts/changelog-tests.js +118 -0
  112. package/dist/scripts/channel-probe-tests.js +103 -0
  113. package/dist/scripts/channel-probe.js +169 -0
  114. package/dist/scripts/channel-registry-tests.js +208 -0
  115. package/dist/scripts/companion-tests.js +25 -70
  116. package/dist/scripts/dida-cookie-probe.js +87 -0
  117. package/dist/scripts/dida-runner-stop-tests.js +311 -0
  118. package/dist/scripts/dida-sw-probe.js +114 -0
  119. package/dist/scripts/diff-test.js +17 -12
  120. package/dist/scripts/doctor-tests.js +564 -0
  121. package/dist/scripts/dsh-artifact-e2e.js +279 -0
  122. package/dist/scripts/dsh-artifact-web-e2e.js +675 -0
  123. package/dist/scripts/dsh-http-proxy-sse-proof.js +90 -0
  124. package/dist/scripts/dsh-runtime-closure-tests.js +182 -0
  125. package/dist/scripts/dsh-runtime-closure.js +162 -0
  126. package/dist/scripts/dsh-session-v3-migration-proof.js +109 -0
  127. package/dist/scripts/dsh-subprocess-local-proof.js +150 -0
  128. package/dist/scripts/dsh-target-closure-proof.js +178 -0
  129. package/dist/scripts/effect-tests.js +539 -0
  130. package/dist/scripts/engine-run.js +1 -3
  131. package/dist/scripts/engine-tests.js +16 -10
  132. package/dist/scripts/evaluation-cadence-tests.js +174 -0
  133. package/dist/scripts/evaluation-contract-tests.js +268 -0
  134. package/dist/scripts/extension-distribution-cli.js +39 -0
  135. package/dist/scripts/extension-distribution-tests.js +443 -0
  136. package/dist/scripts/extension-tests.js +988 -0
  137. package/dist/scripts/external-event-tests.js +350 -0
  138. package/dist/scripts/fact-gate-tests.js +869 -0
  139. package/dist/scripts/fixtures/extension-bridge-unref-child.mjs +21 -0
  140. package/dist/scripts/flight-hotel-anchor-363-registered-e2e.js +169 -0
  141. package/dist/scripts/flight-malformed-tests.js +159 -0
  142. package/dist/scripts/flyai-setup-tests.js +228 -0
  143. package/dist/scripts/flyai-setup-tool-tests.js +54 -0
  144. package/dist/scripts/flyai-tests.js +692 -0
  145. package/dist/scripts/flyai-tool-registration-contract-tests.js +91 -0
  146. package/dist/scripts/fx-contract-tests.js +201 -0
  147. package/dist/scripts/g5-guard-tests.js +131 -0
  148. package/dist/scripts/g5-guard.js +189 -0
  149. package/dist/scripts/gen-lunar-anchors.js +106 -0
  150. package/dist/scripts/geo-atlas-tests.js +283 -0
  151. package/dist/scripts/gotry-backend-kernel-tests.js +206 -0
  152. package/dist/scripts/gotry-try-demo-tests.js +79 -0
  153. package/dist/scripts/gotry-try-demo.js +49 -0
  154. package/dist/scripts/ground-transfer-tests.js +956 -0
  155. package/dist/scripts/hbcli-e2e-tests.js +159 -0
  156. package/dist/scripts/hbcli-live-optin-tests.js +96 -0
  157. package/dist/scripts/hbcli-release-contract-tests.js +122 -0
  158. package/dist/scripts/hbcli-tests.js +121 -69
  159. package/dist/scripts/health-watch-cli.js +73 -0
  160. package/dist/scripts/hotel-date-gate-tests.js +496 -0
  161. package/dist/scripts/hotelbyte-reconcile-tests.js +141 -0
  162. package/dist/scripts/hotelbyte-spawn-e2e-tests.js +373 -0
  163. package/dist/scripts/i18n-tests.js +41 -0
  164. package/dist/scripts/incident-tests.js +281 -87
  165. package/dist/scripts/issue-194-job-id-guard-tests.js +106 -0
  166. package/dist/scripts/issue-233-cancel-refund-commission-tests.js +392 -0
  167. package/dist/scripts/issue-271-liveness-tests.js +569 -0
  168. package/dist/scripts/issue-289-model-retry-real-tests.js +296 -0
  169. package/dist/scripts/issue-289-model-retry-tests.js +441 -0
  170. package/dist/scripts/issue-289-web-retry-e2e.js +630 -0
  171. package/dist/scripts/issue-338-home-city-e2e.js +577 -0
  172. package/dist/scripts/issue343-real-entry-e2e.js +160 -0
  173. package/dist/scripts/issue436-persisted-routing-e2e.js +247 -0
  174. package/dist/scripts/itinerary-artifact-tests.js +368 -0
  175. package/dist/scripts/itinerary-deck-artifact-tests.js +416 -0
  176. package/dist/scripts/itinerary-deck-export-tests.js +552 -0
  177. package/dist/scripts/itinerary-deck-tests.js +435 -0
  178. package/dist/scripts/itinerary-html-tests.js +426 -0
  179. package/dist/scripts/journey-tests.js +22 -27
  180. package/dist/scripts/kernel-manifest-evidence.js +109 -0
  181. package/dist/scripts/kernel-manifest-gate.js +126 -0
  182. package/dist/scripts/kernel-manifest-tests.js +212 -0
  183. package/dist/scripts/kernel-manifest-trace-entry.js +7 -0
  184. package/dist/scripts/kernel-manifest-trace-hook.mjs +28 -0
  185. package/dist/scripts/kernel-manifest.js +369 -0
  186. package/dist/scripts/lavish-local-tests.js +1226 -0
  187. package/dist/scripts/lavish-product-tools-tests.js +537 -0
  188. package/dist/scripts/ledger-repair-apply-tests.js +316 -0
  189. package/dist/scripts/ledger-repair-plan-tests.js +375 -0
  190. package/dist/scripts/ledger-tests.js +382 -246
  191. package/dist/scripts/ledger-workflow-crash.js +10 -20
  192. package/dist/scripts/managed-dsh-cleanup-diagnostic-proof.js +184 -0
  193. package/dist/scripts/managed-dsh-close-failure-proof.js +172 -0
  194. package/dist/scripts/managed-dsh-run-port-proof.js +153 -0
  195. package/dist/scripts/managed-dsh-terminal-proof.js +252 -0
  196. package/dist/scripts/map-tools-vendor-package-proof.js +365 -0
  197. package/dist/scripts/memory-capture-tests.js +242 -61
  198. package/dist/scripts/memory-decay-tests.js +18 -52
  199. package/dist/scripts/memory-lifecycle-tests.js +657 -0
  200. package/dist/scripts/memory-lifecycle.js +196 -0
  201. package/dist/scripts/memory-metrics.js +24 -12
  202. package/dist/scripts/memory-value-report.js +631 -0
  203. package/dist/scripts/memory-value-tests.js +328 -0
  204. package/dist/scripts/metrics-report-tests.js +151 -0
  205. package/dist/scripts/model-override-e2e.js +137 -0
  206. package/dist/scripts/nightly-evidence-tests.js +161 -0
  207. package/dist/scripts/nightly-evidence.js +286 -0
  208. package/dist/scripts/nudge-digest.js +39 -28
  209. package/dist/scripts/observability-tests.js +381 -0
  210. package/dist/scripts/onboarding-tests.js +161 -0
  211. package/dist/scripts/opensky-check.js +18 -13
  212. package/dist/scripts/opensky-tests.js +28 -28
  213. package/dist/scripts/persona-surface-guard-tests.js +49 -0
  214. package/dist/scripts/pnpm-dsh-closure-proof.js +17 -0
  215. package/dist/scripts/policy-anchor-359-registered-e2e.js +214 -0
  216. package/dist/scripts/price-drift-tests.js +340 -0
  217. package/dist/scripts/price-drift-watch.js +447 -0
  218. package/dist/scripts/probe-poi-tests.js +53 -45
  219. package/dist/scripts/product-metrics.js +483 -0
  220. package/dist/scripts/publish-preverify.js +110 -0
  221. package/dist/scripts/realtime-pricing-tests.js +76 -0
  222. package/dist/scripts/recall-tests.js +513 -0
  223. package/dist/scripts/replay-async.js +20 -18
  224. package/dist/scripts/replay-real.js +18 -18
  225. package/dist/scripts/replay.js +52 -82
  226. package/dist/scripts/session-attach-diagnose.js +20 -20
  227. package/dist/scripts/session-attach-poc.js +34 -37
  228. package/dist/scripts/session-benchmark.js +180 -0
  229. package/dist/scripts/session-dida-live-e2e.js +199 -0
  230. package/dist/scripts/session-extract-tests.js +14 -35
  231. package/dist/scripts/session-link-tests.js +478 -0
  232. package/dist/scripts/session-login.js +27 -46
  233. package/dist/scripts/session-tests.js +796 -96
  234. package/dist/scripts/session-zones-tests.js +358 -0
  235. package/dist/scripts/sf-live-benchmark.js +367 -0
  236. package/dist/scripts/sf-live-challenge-stop-tests.js +453 -0
  237. package/dist/scripts/sf-live-cli-tests.js +92 -0
  238. package/dist/scripts/sf-live-options.js +46 -0
  239. package/dist/scripts/sf-manifest-tests.js +30 -0
  240. package/dist/scripts/sf-manifest.js +33 -0
  241. package/dist/scripts/sf-soft-score-tests.js +67 -0
  242. package/dist/scripts/sf-summary-tests.js +324 -0
  243. package/dist/scripts/sf-summary.js +525 -0
  244. package/dist/scripts/share-tests.js +432 -0
  245. package/dist/scripts/skeleton-check.js +16 -14
  246. package/dist/scripts/skeleton-integration-test.js +28 -11
  247. package/dist/scripts/skills-contract-tests.js +51 -46
  248. package/dist/scripts/smoke-session-gate-tests.js +21 -0
  249. package/dist/scripts/smoke.js +690 -246
  250. package/dist/scripts/spawn-bounded-abort-tests.js +241 -0
  251. package/dist/scripts/sponsor-reuse-tests.js +262 -0
  252. package/dist/scripts/state-cli-tests.js +226 -101
  253. package/dist/scripts/state-cli.js +550 -199
  254. package/dist/scripts/state-repair-cli.js +66 -0
  255. package/dist/scripts/state-repair-tests.js +140 -0
  256. package/dist/scripts/static-golden-tests.js +165 -0
  257. package/dist/scripts/time-eval-tests.js +210 -192
  258. package/dist/scripts/travel-timeline-tests.js +29 -93
  259. package/dist/scripts/turn-handoff-collect-tests.js +169 -0
  260. package/dist/scripts/turn-handoff-collect.js +161 -0
  261. package/dist/scripts/turn-policy-tests.js +55 -0
  262. package/dist/scripts/typed-contract-canary.js +176 -0
  263. package/dist/scripts/tz-resolver-sanity.js +50 -0
  264. package/dist/scripts/tz-resolver-tests.js +584 -0
  265. package/dist/scripts/unified-tests.js +23 -19
  266. package/dist/scripts/visa-policy-tests.js +62 -0
  267. package/dist/scripts/weather-tests.js +276 -41
  268. package/dist/scripts/wish-channel-gate-tests.js +54 -0
  269. package/dist/scripts/write-gate-tests.js +522 -0
  270. package/dist/scripts/z3-lifecycle-fault-tests.js +188 -0
  271. package/dist/scripts/z3-lifecycle-tests.js +170 -0
  272. package/dist/scripts/z3-race-repeat-tests.js +39 -0
  273. package/dist/scripts/z3-race-tests.js +41 -0
  274. package/dist/src/artifact-gate.js +829 -0
  275. package/dist/src/backend/kernel.js +91 -0
  276. package/dist/src/backend/modules/booking-copilot.js +92 -0
  277. package/dist/src/backend/modules/booking-executor.js +124 -0
  278. package/dist/src/backend/modules/session-search.js +551 -0
  279. package/dist/src/benchmark-agent-conformance.js +578 -0
  280. package/dist/src/benchmark-environment-bridge.js +515 -0
  281. package/dist/src/benchmark-headless-child-diagnostics.js +166 -0
  282. package/dist/src/benchmark-tool-isolation.js +151 -0
  283. package/dist/src/bookable-facts.js +533 -0
  284. package/dist/src/booking-saga.js +97 -0
  285. package/dist/src/booking-surface/availability-policy.js +697 -0
  286. package/dist/src/booking-surface/booking-intent.js +43 -0
  287. package/dist/src/booking-surface/cancel-refund-commission.js +379 -0
  288. package/dist/src/booking-surface/canonical-schema.js +116 -0
  289. package/dist/src/booking-surface/contracts.js +75 -0
  290. package/dist/src/booking-surface/dsh-planner.js +1854 -0
  291. package/dist/src/booking-surface/dsh-plugin.js +378 -0
  292. package/dist/src/booking-surface/dsh-worker.js +98 -0
  293. package/dist/src/booking-surface/error-codes.js +231 -0
  294. package/dist/src/booking-surface/index.js +9 -0
  295. package/dist/src/booking-surface/managed-dsh-cleanup-diagnostic.js +97 -0
  296. package/dist/src/booking-surface/managed-dsh-run-port.js +244 -0
  297. package/dist/src/booking-surface/profile.js +24 -0
  298. package/dist/src/booking-surface/recovery-chain.js +367 -0
  299. package/dist/src/booking-surface/runtime.js +1968 -0
  300. package/dist/src/booking-surface/server.js +674 -0
  301. package/dist/src/booking-surface/startup.js +168 -0
  302. package/dist/src/booking-surface/validation.js +261 -0
  303. package/dist/src/bridge.js +20 -13
  304. package/dist/src/companions.js +48 -74
  305. package/dist/src/contracts.js +21 -43
  306. package/dist/src/dsh-llm.js +97 -111
  307. package/dist/src/engine.js +276 -193
  308. package/dist/src/evaluation-cadence.js +97 -0
  309. package/dist/src/evaluation-contracts.js +283 -0
  310. package/dist/src/flight-pack-adapter.js +54 -0
  311. package/dist/src/flight-pack-contract.js +2 -0
  312. package/dist/src/flyai-setup-tool.js +70 -0
  313. package/dist/src/gotry-backend.js +125 -0
  314. package/dist/src/hotel-date-gate.js +118 -0
  315. package/dist/src/i18n.js +88 -0
  316. package/dist/src/index.js +2227 -882
  317. package/dist/src/itinerary-deck.js +139 -0
  318. package/dist/src/itinerary-doc-shared.js +661 -0
  319. package/dist/src/itinerary-html.js +131 -0
  320. package/dist/src/journey.js +155 -108
  321. package/dist/src/lavish-tools.js +400 -0
  322. package/dist/src/ledger-repair-apply.js +538 -0
  323. package/dist/src/ledger-repair-plan.js +463 -0
  324. package/dist/src/loop.js +319 -160
  325. package/dist/src/memory-capture.js +180 -32
  326. package/dist/src/memory-decay.js +30 -14
  327. package/dist/src/memory-lifecycle.js +1310 -0
  328. package/dist/src/memory-utility.js +27 -40
  329. package/dist/src/mock-llm.js +36 -61
  330. package/dist/src/model.js +81 -36
  331. package/dist/src/realtime-pricing.js +103 -0
  332. package/dist/src/recall/card.js +74 -0
  333. package/dist/src/recall/evaluator.js +140 -0
  334. package/dist/src/recall/integration.js +17 -0
  335. package/dist/src/recall/tick.js +166 -0
  336. package/dist/src/session-link/plan-it-action.js +48 -0
  337. package/dist/src/session-link/session-link.js +248 -0
  338. package/dist/src/session-zones.js +507 -0
  339. package/dist/src/share/adapters.js +51 -0
  340. package/dist/src/share/share-consent.js +76 -0
  341. package/dist/src/share/share-deck.js +58 -0
  342. package/dist/src/share/share-token.js +146 -0
  343. package/dist/src/slot-spec.js +84 -106
  344. package/dist/src/state-ledger.js +435 -516
  345. package/dist/src/state-repair.js +299 -0
  346. package/dist/src/subagent-job-id-guard.js +58 -0
  347. package/dist/src/time-anchor.js +231 -33
  348. package/dist/src/tool-packet.js +20 -8
  349. package/dist/src/travel-slots.js +58 -35
  350. package/dist/src/travel-timeline.js +44 -63
  351. package/dist/src/turn-deadline.js +287 -0
  352. package/dist/src/turn-policy.js +118 -0
  353. package/dist/src/tz-resolver.js +143 -0
  354. package/dist/src/unified.js +535 -359
  355. package/dist/src/wish-pool.js +42 -12
  356. package/dist/src/write-gate.js +495 -0
  357. package/dist/src/z3-shared.js +284 -0
  358. package/extension/README.md +21 -0
  359. package/extension/README.zh-CN.md +21 -0
  360. package/extension/background.js +463 -0
  361. package/extension/content-bridge.js +270 -0
  362. package/extension/content-main.js +111 -0
  363. package/extension/manifest.json +60 -0
  364. package/package.json +407 -14
  365. package/schemas/booking.intent.schema.json +193 -0
  366. package/schemas/booking.surface.schema.json +2622 -0
  367. package/ts/capabilities/agent-reach-deep.ts +114 -0
  368. package/ts/capabilities/agent-reach.ts +198 -0
  369. package/ts/capabilities/anything.ts +255 -0
  370. package/ts/capabilities/artifacts.ts +428 -0
  371. package/ts/capabilities/fact-log.ts +54 -0
  372. package/ts/capabilities/flyai-config.ts +388 -0
  373. package/ts/capabilities/flyai.ts +1274 -0
  374. package/ts/capabilities/hbcli.ts +253 -71
  375. package/ts/capabilities/incident-log.ts +88 -59
  376. package/ts/capabilities/itinerary-artifact.ts +214 -0
  377. package/ts/capabilities/itinerary-deck-artifact.ts +218 -0
  378. package/ts/capabilities/itinerary-deck-export.ts +378 -0
  379. package/ts/capabilities/opensky.ts +121 -0
  380. package/ts/capabilities/session/action-cache.ts +148 -0
  381. package/ts/capabilities/session/adapters/ctrip-flight.ts +181 -0
  382. package/ts/capabilities/session/adapters/ctrip-hotel.ts +238 -0
  383. package/ts/capabilities/session/adapters/dida-portal.ts +338 -0
  384. package/ts/capabilities/session/adapters/meituan-local.ts +70 -0
  385. package/ts/capabilities/session/adapters/rail-12306.ts +392 -0
  386. package/ts/capabilities/session/benchmark.ts +276 -0
  387. package/ts/capabilities/session/bridge-ledger.ts +333 -0
  388. package/ts/capabilities/session/extension-bridge.ts +794 -0
  389. package/ts/capabilities/session/extension-channel.ts +144 -0
  390. package/ts/capabilities/session/extension-distribution.ts +266 -0
  391. package/ts/capabilities/session/extract.ts +54 -0
  392. package/ts/capabilities/session/golden-score.ts +139 -0
  393. package/ts/capabilities/session/health-watch.ts +264 -0
  394. package/ts/capabilities/session/read-guard.ts +141 -0
  395. package/ts/capabilities/session/static-flight-golden.ts +209 -0
  396. package/ts/capabilities/session/transport.ts +146 -0
  397. package/ts/capabilities/session/wizard.ts +140 -0
  398. package/ts/capabilities/session-consent.ts +211 -0
  399. package/ts/capabilities/session-login.ts +208 -0
  400. package/ts/capabilities/session-search.ts +893 -0
  401. package/ts/capabilities/weather.ts +330 -0
  402. package/ts/dsh-runtime/vendor/README.md +68 -0
  403. package/ts/dsh-runtime/vendor/dsh-map-tools/LICENSE +21 -0
  404. package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +405 -0
  405. package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +404 -0
  406. package/ts/dsh-runtime/vendor/dsh-map-tools/client/client.js +1584 -0
  407. package/ts/dsh-runtime/vendor/dsh-map-tools/cordis.patch.yml +5 -0
  408. package/ts/dsh-runtime/vendor/dsh-map-tools/icon.svg +5 -0
  409. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/amap.js +595 -0
  410. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/nominatim.js +63 -0
  411. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/osrm.js +58 -0
  412. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/photon.js +55 -0
  413. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-file.js +87 -0
  414. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-route.js +131 -0
  415. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config.js +16 -0
  416. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/geo.js +232 -0
  417. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/index.js +120 -0
  418. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +40 -0
  419. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/staticmap-route.js +115 -0
  420. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/geocode.js +127 -0
  421. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/poi.js +84 -0
  422. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/routes.js +267 -0
  423. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/amap.d.ts +90 -0
  424. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/nominatim.d.ts +17 -0
  425. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/osrm.d.ts +15 -0
  426. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/photon.d.ts +22 -0
  427. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-file.d.ts +33 -0
  428. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-route.d.ts +23 -0
  429. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config.d.ts +23 -0
  430. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/geo.d.ts +61 -0
  431. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/index.d.ts +18 -0
  432. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +14 -0
  433. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/staticmap-route.d.ts +31 -0
  434. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/geocode.d.ts +11 -0
  435. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/poi.d.ts +9 -0
  436. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/routes.d.ts +75 -0
  437. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/types.d.ts +68 -0
  438. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types.js +16 -0
  439. package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +97 -0
  440. package/ts/package.json +293 -3
  441. package/ts/scripts/async-collect.ts +91 -0
  442. package/ts/scripts/map-tools-vendor-package-proof.ts +404 -0
  443. package/ts/scripts/skeleton-check.ts +1 -1
  444. package/ts/scripts/skeleton-integration-test.ts +23 -1
  445. package/ts/scripts/state-cli.ts +568 -0
  446. package/ts/scripts/turn-handoff-collect.ts +178 -0
  447. package/ts/src/artifact-gate.ts +991 -0
  448. package/ts/src/benchmark-agent-conformance.ts +619 -0
  449. package/ts/src/benchmark-environment-bridge.ts +538 -0
  450. package/ts/src/benchmark-headless-child-diagnostics.ts +184 -0
  451. package/ts/src/benchmark-tool-isolation.ts +166 -0
  452. package/ts/src/bookable-facts.ts +837 -0
  453. package/ts/src/booking-saga.ts +133 -0
  454. package/ts/src/booking-surface/availability-policy.ts +522 -0
  455. package/ts/src/booking-surface/booking-intent.ts +86 -0
  456. package/ts/src/booking-surface/cancel-refund-commission.ts +488 -0
  457. package/ts/src/booking-surface/canonical-schema.js +116 -0
  458. package/ts/src/booking-surface/contracts.ts +475 -0
  459. package/ts/src/booking-surface/dsh-planner.ts +1949 -0
  460. package/ts/src/booking-surface/dsh-plugin.js +378 -0
  461. package/ts/src/booking-surface/dsh-worker.ts +110 -0
  462. package/ts/src/booking-surface/error-codes.ts +241 -0
  463. package/ts/src/booking-surface/index.ts +9 -0
  464. package/ts/src/booking-surface/managed-dsh-cleanup-diagnostic.ts +151 -0
  465. package/ts/src/booking-surface/managed-dsh-run-port.ts +273 -0
  466. package/ts/src/booking-surface/profile.ts +42 -0
  467. package/ts/src/booking-surface/recovery-chain.ts +409 -0
  468. package/ts/src/booking-surface/runtime.ts +1793 -0
  469. package/ts/src/booking-surface/server.ts +733 -0
  470. package/ts/src/booking-surface/startup.ts +201 -0
  471. package/ts/src/booking-surface/validation.ts +217 -0
  472. package/ts/src/companions.ts +113 -0
  473. package/ts/src/contracts.ts +13 -3
  474. package/ts/src/dsh-llm.ts +44 -11
  475. package/ts/src/flyai-setup-tool.ts +77 -0
  476. package/ts/src/index.ts +1948 -198
  477. package/ts/src/itinerary-deck.ts +189 -0
  478. package/ts/src/itinerary-doc-shared.ts +741 -0
  479. package/ts/src/itinerary-html.ts +171 -0
  480. package/ts/src/loop.ts +223 -25
  481. package/ts/src/memory-capture.ts +283 -0
  482. package/ts/src/memory-decay.ts +55 -0
  483. package/ts/src/memory-utility.ts +70 -0
  484. package/ts/src/mock-llm.ts +4 -8
  485. package/ts/src/model.ts +88 -2
  486. package/ts/src/recall/card.ts +106 -0
  487. package/ts/src/recall/evaluator.ts +170 -0
  488. package/ts/src/recall/integration.ts +35 -0
  489. package/ts/src/recall/tick.ts +213 -0
  490. package/ts/src/session-link/plan-it-action.ts +78 -0
  491. package/ts/src/session-link/session-link.ts +275 -0
  492. package/ts/src/share/adapters.ts +93 -0
  493. package/ts/src/share/share-consent.ts +105 -0
  494. package/ts/src/share/share-deck.ts +85 -0
  495. package/ts/src/share/share-token.ts +166 -0
  496. package/ts/src/slot-spec.ts +172 -0
  497. package/ts/src/state-ledger.ts +912 -0
  498. package/ts/src/subagent-job-id-guard.ts +72 -0
  499. package/ts/src/time-anchor.ts +338 -0
  500. package/ts/src/tool-packet.ts +32 -0
  501. package/ts/src/travel-slots.ts +219 -0
  502. package/ts/src/travel-timeline.ts +83 -0
  503. package/ts/src/turn-deadline.ts +366 -0
  504. package/ts/src/turn-policy.ts +154 -0
  505. package/ts/src/unified.ts +354 -88
  506. package/ts/src/wish-pool.ts +79 -0
  507. package/dist/scripts/session-attach-wait.js +0 -41
@@ -0,0 +1,507 @@
1
+ /**
2
+ * 会话双区记忆分区契约纯核(P4-1,docs/design/session-dual-zone-memory-design.md):
3
+ * 一个账本上的两个分区——会话工作区(hot_context:随会话生灭,30min/24h 分层快过期,
4
+ * 永不 owner 确认)与持久笔记本(trip_notebook:跨会话存活,唯一入口是 owner 确认晋升,
5
+ * 模型只可提议,永不自晋升)。
6
+ *
7
+ * 本模块只交契约核,纯函数、零 IO、零定时器、零网络、零 import:
8
+ * - 闭集:zone(hot_context|trip_notebook)/tier/kind/确认表面/事件 kind,未知拒收;
9
+ * - 写侧负面清单(设计 §4 双重负面清单的写侧,companions 守卫同族):
10
+ * 证件号/手机号/URL/凭证形态零入区;证据只走指针(session_ref+turn)与有界引用;
11
+ * - owner 确认引用闸:缺引用或引用超界拒收(ADR-14「归因只认 owner 确认」落到存储面);
12
+ * - rev CAS:同 rev 同内容的重放是幂等 no-op;父 rev ≠ 当前 fold rev → stale_rev
13
+ * fail-closed(类型化错误词表,乐观修订在插入前被拒);
14
+ * - 注入时钟的分层 TTL:resource 30min / intent 24h,自**写入**起算(读不续命);
15
+ * 过期不是事件,是读时纯函数视图(墙钟动作不进 append-only 账本,fold 才可确定);
16
+ * - 确定性 fold:事件序列 → 分区状态,重建 == 直读(state-ledger 投影纪律的纯核版)。
17
+ *
18
+ * 边界(P4-2/P4-3 的事,本 PR 不做):不接账本(state-ledger.ts 零改动,内核 manifest
19
+ * 零漂移);不接会话捕获缝/persona 读回;导出侧负面清单属 P4-4 观测面。
20
+ * 期限语义:live ⇔ now < ttl_expires_at(到期瞬间即过期);坏时钟/坏时间戳 fail-closed。
21
+ */
22
+ // ---- 闭集(类型化;未知值在守门处拒收,fold 对伪造文档拒投影) ---------------------
23
+ export const SESSION_ZONES = ['hot_context', 'trip_notebook'];
24
+ /** 工作区分层:resource=搜索结果/可售形态/价格带指针;intent=目的地/日期/人数/预算立场 */
25
+ export const HOT_TIERS = ['resource', 'intent'];
26
+ /** 工作区笔记 kind 闭集(设计 §1.1「kind (closed set)」的 v1 词表;载荷为 slot-spec 族结构片段) */
27
+ export const HOT_NOTE_KINDS = [
28
+ 'availability',
29
+ 'price_band',
30
+ 'destination',
31
+ 'date_window',
32
+ 'party_size',
33
+ 'budget_stance',
34
+ ];
35
+ /** 笔记本条目 kind 闭集(设计 §1.2 明文) */
36
+ export const NOTEBOOK_KINDS = ['trip_fact', 'preference', 'constraint', 'lesson'];
37
+ /** owner 确认表面闭集(设计 §1.2 owner_confirm.surface) */
38
+ export const CONFIRM_SURFACES = ['user_reply', 'approval_card'];
39
+ /** 六个边界事件 kind(设计 §1.3/§2;P4-2 以日志类事件落在既有 events 表) */
40
+ export const ZONE_EVENT_KINDS = [
41
+ 'hotctx.note.captured',
42
+ 'hotctx.note.revised',
43
+ 'hotctx.note.dropped',
44
+ 'notebook.entry.promoted',
45
+ 'notebook.entry.revised',
46
+ 'notebook.entry.dropped',
47
+ ];
48
+ export function isSessionZone(v) {
49
+ return typeof v === 'string' && SESSION_ZONES.includes(v);
50
+ }
51
+ export function isHotTier(v) {
52
+ return typeof v === 'string' && HOT_TIERS.includes(v);
53
+ }
54
+ export function isHotNoteKind(v) {
55
+ return typeof v === 'string' && HOT_NOTE_KINDS.includes(v);
56
+ }
57
+ export function isNotebookKind(v) {
58
+ return typeof v === 'string' && NOTEBOOK_KINDS.includes(v);
59
+ }
60
+ export function isConfirmSurface(v) {
61
+ return typeof v === 'string' && CONFIRM_SURFACES.includes(v);
62
+ }
63
+ export function isZoneEventKind(v) {
64
+ return typeof v === 'string' && ZONE_EVENT_KINDS.includes(v);
65
+ }
66
+ /**
67
+ * 幂等键(设计 §2 钉死的 rev 写键:P4-2 落账本直接复用):
68
+ * rev 写 `hotctx:<note_id>:<rev>` / `notebook:<entry_id>:<rev>`——同 rev 重放物理 no-op;
69
+ * drop 键带 ts:同一事件重放仍去重,且不跨生命周期碰撞(drop→再捕获循环不误伤)。
70
+ */
71
+ export function zoneIdemKey(ev) {
72
+ switch (ev.kind) {
73
+ case 'hotctx.note.captured':
74
+ case 'hotctx.note.revised':
75
+ return `hotctx:${ev.note.note_id}:${ev.note.rev}`;
76
+ case 'notebook.entry.promoted':
77
+ case 'notebook.entry.revised':
78
+ return `notebook:${ev.entry.entry_id}:${ev.entry.rev}`;
79
+ case 'hotctx.note.dropped':
80
+ return `hotctx:${ev.note_id}:drop:${ev.ts}`;
81
+ case 'notebook.entry.dropped':
82
+ return `notebook:${ev.entry_id}:drop:${ev.ts}`;
83
+ }
84
+ }
85
+ /** 单事件应用(fold 内部件;结构性守卫让重放/悬空/越级事件天然 no-op,fold 全且确定) */
86
+ function applyZoneEvent(state, ev) {
87
+ switch (ev.kind) {
88
+ case 'hotctx.note.captured': {
89
+ const n = ev.note;
90
+ // 未知分区/tier/kind 拒投影;已存在 → 首写胜(同 rev 重放 no-op)
91
+ if (!validHotDoc(n) || state.hot[n.note_id])
92
+ return;
93
+ state.hot[n.note_id] = n;
94
+ return;
95
+ }
96
+ case 'hotctx.note.revised': {
97
+ const n = ev.note;
98
+ const cur = state.hot[n.note_id];
99
+ // CAS 链断裂(悬空/重放/越级)跳过:写时 CAS 已拒,这里保持确定性
100
+ if (!validHotDoc(n) || !cur || n.rev !== cur.rev + 1)
101
+ return;
102
+ state.hot[n.note_id] = n;
103
+ return;
104
+ }
105
+ case 'hotctx.note.dropped':
106
+ delete state.hot[ev.note_id];
107
+ return;
108
+ case 'notebook.entry.promoted': {
109
+ const e = ev.entry;
110
+ if (!validNotebookDoc(e) || state.notebook[e.entry_id])
111
+ return;
112
+ state.notebook[e.entry_id] = e;
113
+ return;
114
+ }
115
+ case 'notebook.entry.revised': {
116
+ const e = ev.entry;
117
+ const cur = state.notebook[e.entry_id];
118
+ if (!validNotebookDoc(e) || !cur || e.rev !== cur.rev + 1)
119
+ return;
120
+ state.notebook[e.entry_id] = e;
121
+ return;
122
+ }
123
+ case 'notebook.entry.dropped':
124
+ delete state.notebook[ev.entry_id];
125
+ return;
126
+ }
127
+ }
128
+ /** 确定性 fold:事件序列 → 分区状态(纯函数,不改入参;重建==直读的可验证性来源) */
129
+ export function foldZoneEvents(events) {
130
+ const state = { hot: {}, notebook: {} };
131
+ for (const ev of events) {
132
+ if (!isZoneEventKind(ev?.kind))
133
+ continue; // 未知事件 kind 拒投影
134
+ applyZoneEvent(state, ev);
135
+ }
136
+ return state;
137
+ }
138
+ /** 文档级闭集守卫(fold 对伪造文档 fail-closed;守门与 fold 共用同一词表) */
139
+ function validHotDoc(n) {
140
+ const d = n;
141
+ return (!!d && d.zone === 'hot_context' && isHotTier(d.tier) && isHotNoteKind(d.kind) &&
142
+ typeof d.note_id === 'string' && d.note_id.length > 0 &&
143
+ typeof d.rev === 'number' && Number.isInteger(d.rev) && d.rev >= 1);
144
+ }
145
+ function validNotebookDoc(e) {
146
+ const d = e;
147
+ return (!!d && d.zone === 'trip_notebook' && isNotebookKind(d.kind) &&
148
+ isConfirmSurface(d.owner_confirm?.surface) &&
149
+ typeof d.entry_id === 'string' && d.entry_id.length > 0 &&
150
+ typeof d.rev === 'number' && Number.isInteger(d.rev) && d.rev >= 1);
151
+ }
152
+ // ---- 写侧负面清单(设计 §4 双重负面清单的写侧;companions 守卫同族) ----------------
153
+ const WRITE_NEGATIVE_PATTERNS = [
154
+ { re: /\d{15,17}[Xx]?/, label: '疑似证件号/卡号' },
155
+ { re: /1[3-9]\d{9}/, label: '疑似手机号' },
156
+ { re: /(护照|身份证|证件号|通行证)\s*号?\s*[::]?\s*\w+/i, label: '证件信息' },
157
+ { re: /https?:\/\/\S+/i, label: 'URL' },
158
+ { re: /\bwww\.[\w-]+(?:\.[\w-]+)+/i, label: 'URL' },
159
+ { re: /\b[\w-]+\.(?:com|cn|net|org|io|dev|app|co|xyz|info|biz|edu|gov)\b(?:\/\S*)?/i, label: 'URL' },
160
+ { re: /(?:api[_-]?key|secret|token|password|passwd)\s*[:=]\s*\S+/i, label: '凭证形态' },
161
+ { re: /\bbearer\s+[A-Za-z0-9._-]{8,}/i, label: '凭证形态' },
162
+ { re: /\bsk-[A-Za-z0-9]{12,}/, label: '凭证形态' },
163
+ ];
164
+ /** 写闸:内容命中负面清单 → 返回拒收理由;否则 null(分区永不承载转写原文/凭证/URL/敏感身份) */
165
+ export function zoneWriteViolation(text) {
166
+ for (const { re, label } of WRITE_NEGATIVE_PATTERNS) {
167
+ if (re.test(text))
168
+ return `负面清单拒收:${label}不入分区(证据走指针与有界引用)`;
169
+ }
170
+ return null;
171
+ }
172
+ // ---- 有界与形状常量 ---------------------------------------------------------------
173
+ export const OWNER_QUOTE_MAX = 200;
174
+ export const HOT_PAYLOAD_MAX_JSON = 2048;
175
+ export const SESSION_REF_MAX = 64;
176
+ const CANONICAL_MAX_DEPTH = 6;
177
+ /** 不透明会话引用形状(session-link 契约同族:无路径字符/无空白/有界) */
178
+ export function validSessionRef(ref) {
179
+ return (typeof ref === 'string' && ref.length > 0 && ref.length <= SESSION_REF_MAX &&
180
+ !/[\/\\\s\u0000-\u001f]/.test(ref) && !ref.includes('..'));
181
+ }
182
+ /**
183
+ * 规范 JSON(键排序,确定性):载荷规范化/id 派生/负面清单扫描的单一事实源。
184
+ * 环/超深/undefined → null(不猜,fail-closed)。注意:载荷承载 slot-spec 族类型
185
+ * (YYYY-MM-DD 日期/字符串/常规数值),不承载毫秒纪元戳等长数字串。
186
+ */
187
+ export function canonicalJson(v, depth = 0, seen = new Set()) {
188
+ if (v === undefined || typeof v === 'function')
189
+ return null;
190
+ if (v === null || typeof v !== 'object')
191
+ return JSON.stringify(v) ?? 'null';
192
+ if (depth > CANONICAL_MAX_DEPTH || seen.has(v))
193
+ return null;
194
+ seen.add(v);
195
+ if (Array.isArray(v)) {
196
+ const parts = [];
197
+ for (const x of v) {
198
+ const p = canonicalJson(x, depth + 1, seen);
199
+ if (p === null)
200
+ return null;
201
+ parts.push(p);
202
+ }
203
+ return '[' + parts.join(',') + ']';
204
+ }
205
+ const obj = v;
206
+ const keys = Object.keys(obj).sort();
207
+ const parts = [];
208
+ for (const k of keys) {
209
+ const p = canonicalJson(obj[k], depth + 1, seen);
210
+ if (p === null)
211
+ return null;
212
+ parts.push(JSON.stringify(k) + ':' + p);
213
+ }
214
+ return '{' + parts.join(',') + '}';
215
+ }
216
+ // ---- 注入时钟的分层 TTL(读时纯函数视图;读不 mutate、不续命) ----------------------
217
+ /** master outline §3.5 layer 5:resource 30min / intent 24h;自最后一次**写入**起算 */
218
+ export const HOT_TTL_MS = {
219
+ resource: 30 * 60_000,
220
+ intent: 24 * 60 * 60_000,
221
+ };
222
+ /** 到期时刻 = 最后写入 + 分层窗(确定性派生;坏时间戳 → null 不猜) */
223
+ export function expiresAtOf(tier, lastWriteIso) {
224
+ const t = Date.parse(lastWriteIso);
225
+ if (Number.isNaN(t))
226
+ return null;
227
+ return new Date(t + HOT_TTL_MS[tier]).toISOString();
228
+ }
229
+ /** 过期判定(读时视图):live ⇔ now < ttl_expires_at;坏时钟/坏时间戳 fail-closed */
230
+ export function isHotNoteLive(note, nowIso) {
231
+ const now = Date.parse(nowIso);
232
+ const exp = Date.parse(note.ttl_expires_at);
233
+ if (Number.isNaN(now) || Number.isNaN(exp))
234
+ return false;
235
+ return now < exp;
236
+ }
237
+ /** 读视图:工作区活笔记(resource 只在本会话可读;intent 跨会话可读到过期;note_id 确定序) */
238
+ export function readWorkingZone(state, q) {
239
+ return Object.values(state.hot)
240
+ .filter(n => n.tier === 'intent' || n.session_ref === q.session_ref)
241
+ .filter(n => isHotNoteLive(n, q.now))
242
+ .sort((a, b) => (a.note_id < b.note_id ? -1 : 1));
243
+ }
244
+ /** 读视图:笔记本全量(持久区无 TTL、无会话域;entry_id 确定序) */
245
+ export function readNotebook(state) {
246
+ return Object.values(state.notebook).sort((a, b) => (a.entry_id < b.entry_id ? -1 : 1));
247
+ }
248
+ function rejected(code, detail) {
249
+ return { ok: false, code, detail };
250
+ }
251
+ function deepEqual(a, b) {
252
+ if (a === b)
253
+ return true;
254
+ if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null)
255
+ return false;
256
+ if (Array.isArray(a) !== Array.isArray(b))
257
+ return false;
258
+ const ka = Object.keys(a).sort();
259
+ const kb = Object.keys(b).sort();
260
+ if (ka.length !== kb.length || ka.some((k, i) => k !== kb[i]))
261
+ return false;
262
+ return ka.every(k => deepEqual(a[k], b[k]));
263
+ }
264
+ /** 载荷闸:必须是纯结构化对象、可规范化、有界(结构片段,不是自由文本) */
265
+ function checkedPayload(payload) {
266
+ if (typeof payload !== 'object' || payload === null || Array.isArray(payload)) {
267
+ return { ok: false, detail: 'payload 必须为结构化对象(slot-spec 族类型,不接受数组/自由文本)' };
268
+ }
269
+ const canonical = canonicalJson(payload);
270
+ if (canonical === null)
271
+ return { ok: false, detail: 'payload 不可规范化(超深/含环/含 undefined)' };
272
+ if (canonical.length > HOT_PAYLOAD_MAX_JSON) {
273
+ return { ok: false, detail: `payload 超界(${canonical.length}>${HOT_PAYLOAD_MAX_JSON})` };
274
+ }
275
+ return { ok: true, canonical };
276
+ }
277
+ /** 稳定诞生 id:同会话同 tier 同 kind 同诞生载荷 = 同一笔记(重放天然幂等) */
278
+ export function makeHotNoteId(input) {
279
+ const canonical = canonicalJson(input.payload);
280
+ if (canonical === null)
281
+ return null;
282
+ return `hn|${input.session_ref}|${input.tier}|${input.kind}|${canonical}`;
283
+ }
284
+ /** 稳定条目 id:自晋升血缘+kind 派生(修订不漂移;同源同 kind 重晋升天然幂等) */
285
+ export function makeNotebookEntryId(input) {
286
+ return `nb|${input.session_ref}|${input.note_id}|${input.kind}`;
287
+ }
288
+ /** owner 确认引用闸:表面闭集 + 引用非空且有界(设计 §1.2「the gate rejects a missing or oversized quote」) */
289
+ function checkedOwnerConfirm(confirm) {
290
+ if (typeof confirm !== 'object' || confirm === null) {
291
+ return { ok: false, code: 'owner_confirm', detail: 'owner_confirm 缺失(晋升/修订必须携带 owner 确认引用)' };
292
+ }
293
+ const c = confirm;
294
+ if (!isConfirmSurface(c.surface)) {
295
+ return { ok: false, code: 'closed_set', detail: `未知确认表面:${String(c.surface)}(闭集 ${CONFIRM_SURFACES.join('|')})` };
296
+ }
297
+ if (typeof c.quote !== 'string' || c.quote.trim().length === 0) {
298
+ return { ok: false, code: 'owner_confirm', detail: 'owner 确认引用缺失或为空(模型自述不是确认)' };
299
+ }
300
+ if (c.quote.length > OWNER_QUOTE_MAX) {
301
+ return { ok: false, code: 'owner_confirm', detail: `owner 确认引用超界(${c.quote.length}>${OWNER_QUOTE_MAX})` };
302
+ }
303
+ return { ok: true, confirm: { surface: c.surface, quote: c.quote } };
304
+ }
305
+ /** 全文档负面清单扫描(id 内嵌规范载荷,扫全文档即覆盖载荷/引用/指针) */
306
+ function docViolation(canonical) {
307
+ const v = zoneWriteViolation(canonical);
308
+ return v ? rejected('negative_list', v) : null;
309
+ }
310
+ /**
311
+ * 捕获笔记(隐含父 rev 0):
312
+ * - 闭集/形状/有界/负面清单逐闸;
313
+ * - 同 note_id 已存在且全文档相等 → 幂等 no-op(重放);
314
+ * - 已存在且不相等 → stale_rev fail-closed(活笔记再断言走 revise;capture 只诞生)。
315
+ */
316
+ export function captureHotNote(state, input) {
317
+ if (!isHotTier(input.tier)) {
318
+ return rejected('closed_set', `未知 tier:${String(input.tier)}(闭集 ${HOT_TIERS.join('|')})`);
319
+ }
320
+ if (!isHotNoteKind(input.kind)) {
321
+ return rejected('closed_set', `未知 kind:${String(input.kind)}(闭集 ${HOT_NOTE_KINDS.join('|')})`);
322
+ }
323
+ if (!validSessionRef(input.session_ref) || !validSessionRef(input.evidence_ref?.session_ref)) {
324
+ return rejected('bad_session_ref', `session_ref 形状不合法(不透明引用:无路径字符/无空白/≤${SESSION_REF_MAX})`);
325
+ }
326
+ if (!Number.isInteger(input.evidence_ref?.turn) || input.evidence_ref.turn < 0) {
327
+ return rejected('bad_evidence_ref', 'evidence_ref.turn 必须为 ≥0 整数(转写指针,不是内容)');
328
+ }
329
+ const payloadCheck = checkedPayload(input.payload);
330
+ if (!payloadCheck.ok)
331
+ return rejected('payload_bound', payloadCheck.detail);
332
+ const expires = expiresAtOf(input.tier, input.ts);
333
+ if (expires === null)
334
+ return rejected('bad_ts', `ts 不是合法 ISO 时间戳:${input.ts}`);
335
+ const note = {
336
+ schema: 'session_zone_hot_note.v1',
337
+ note_id: `hn|${input.session_ref}|${input.tier}|${input.kind}|${payloadCheck.canonical}`,
338
+ zone: 'hot_context',
339
+ tier: input.tier,
340
+ kind: input.kind,
341
+ payload: input.payload,
342
+ evidence_ref: { session_ref: input.evidence_ref.session_ref, turn: input.evidence_ref.turn },
343
+ session_ref: input.session_ref,
344
+ created_at: input.ts,
345
+ last_touched_at: input.ts,
346
+ ttl_expires_at: expires,
347
+ rev: 1,
348
+ };
349
+ const violation = docViolation(canonicalJson(note) ?? '');
350
+ if (violation)
351
+ return violation;
352
+ const existing = state.hot[note.note_id];
353
+ if (existing) {
354
+ if (deepEqual(existing, note)) {
355
+ return { ok: true, appended: false, idemKey: zoneIdemKey({ kind: 'hotctx.note.captured', ts: input.ts, note }), detail: '同 rev 同内容重放:幂等 no-op' };
356
+ }
357
+ return rejected('stale_rev', `capture 隐含父 rev 0,当前 fold rev ${existing.rev}(活笔记再断言走 revise)`);
358
+ }
359
+ const event = { kind: 'hotctx.note.captured', ts: input.ts, note };
360
+ return { ok: true, appended: true, event, idemKey: zoneIdemKey(event) };
361
+ }
362
+ /**
363
+ * CAS 修订(rev+1;每写续 TTL——「时钟自最后一次写入起算」):
364
+ * - 同内容同时戳的父 rev 重放(即产生当前 rev 的那次写)→ 幂等 no-op;
365
+ * - expected_rev ≠ 当前 fold rev(旧/未来)→ stale_rev fail-closed;
366
+ * - 仅不传 payload/kind 的纯 touch 也合法(续 TTL 是写入,不是读)。
367
+ */
368
+ export function reviseHotNote(state, input) {
369
+ const cur = state.hot[input.note_id];
370
+ if (!cur)
371
+ return rejected('unknown_subject', `工作区笔记不存在:${input.note_id}(已 drop 或未捕获)`);
372
+ if (input.kind !== undefined && !isHotNoteKind(input.kind)) {
373
+ return rejected('closed_set', `未知 kind:${String(input.kind)}(闭集 ${HOT_NOTE_KINDS.join('|')})`);
374
+ }
375
+ let canonicalPayload = null;
376
+ if (input.payload !== undefined) {
377
+ const payloadCheck = checkedPayload(input.payload);
378
+ if (!payloadCheck.ok)
379
+ return rejected('payload_bound', payloadCheck.detail);
380
+ canonicalPayload = payloadCheck.canonical;
381
+ }
382
+ const expires = expiresAtOf(cur.tier, input.ts);
383
+ if (expires === null)
384
+ return rejected('bad_ts', `ts 不是合法 ISO 时间戳:${input.ts}`);
385
+ const next = {
386
+ ...cur,
387
+ kind: input.kind ?? cur.kind,
388
+ payload: input.payload ?? cur.payload,
389
+ last_touched_at: input.ts,
390
+ ttl_expires_at: expires,
391
+ rev: input.expected_rev + 1,
392
+ };
393
+ const violation = docViolation(canonicalJson(next) ?? '');
394
+ if (violation)
395
+ return violation;
396
+ if (deepEqual(cur, next)) {
397
+ return { ok: true, appended: false, idemKey: zoneIdemKey({ kind: 'hotctx.note.revised', ts: input.ts, note: next }), detail: '同 rev 同内容重放:幂等 no-op' };
398
+ }
399
+ if (input.expected_rev !== cur.rev) {
400
+ return rejected('stale_rev', `父 rev ${input.expected_rev} ≠ 当前 fold rev ${cur.rev}(fail-closed,插入前拒绝)`);
401
+ }
402
+ const event = { kind: 'hotctx.note.revised', ts: input.ts, note: next };
403
+ return { ok: true, appended: true, event, idemKey: zoneIdemKey(event) };
404
+ }
405
+ /** 更正/矛盾即弃(drop 后仍真可重捕获;审计行随事件日志存活) */
406
+ export function dropHotNote(state, note_id, ts) {
407
+ if (!state.hot[note_id])
408
+ return rejected('unknown_subject', `工作区笔记不存在:${note_id}`);
409
+ const event = { kind: 'hotctx.note.dropped', ts, note_id };
410
+ return { ok: true, appended: true, event, idemKey: zoneIdemKey(event) };
411
+ }
412
+ /**
413
+ * owner 确认晋升(hot → durable;隐含条目父 rev 0):
414
+ * - 源笔记必须活在同一过期函数下(过期源 fail-closed:source_expired);
415
+ * - owner_confirm 闸(表面闭集/引用非空有界);
416
+ * - 同 entry_id 已存在且全文档相等 → 幂等 no-op;不相等 → stale_rev(改条目走 notebook 修订);
417
+ * - 晋升不移除工作区笔记(它仍服务本会话直到过期/drop);lineage 进 origin。
418
+ */
419
+ export function promoteHotNote(state, input) {
420
+ const cur = state.hot[input.note_id];
421
+ if (!cur)
422
+ return rejected('unknown_subject', `工作区笔记不存在:${input.note_id}(已 drop/未捕获/已过期出视图)`);
423
+ if (!isNotebookKind(input.kind)) {
424
+ return rejected('closed_set', `未知笔记本 kind:${String(input.kind)}(闭集 ${NOTEBOOK_KINDS.join('|')})`);
425
+ }
426
+ const confirmCheck = checkedOwnerConfirm(input.owner_confirm);
427
+ if (!confirmCheck.ok)
428
+ return rejected(confirmCheck.code, confirmCheck.detail);
429
+ if (!isHotNoteLive(cur, input.ts)) {
430
+ return rejected('source_expired', `晋升源已过期(到期 ${cur.ttl_expires_at},时钟 ${input.ts};过期不是事件,读时判定)`);
431
+ }
432
+ const payload = input.payload ?? cur.payload;
433
+ const payloadCheck = checkedPayload(payload);
434
+ if (!payloadCheck.ok)
435
+ return rejected('payload_bound', payloadCheck.detail);
436
+ const entry = {
437
+ schema: 'session_zone_notebook_entry.v1',
438
+ entry_id: makeNotebookEntryId({ session_ref: cur.session_ref, note_id: cur.note_id, kind: input.kind }),
439
+ zone: 'trip_notebook',
440
+ kind: input.kind,
441
+ payload,
442
+ evidence: confirmCheck.confirm.quote,
443
+ origin: { session_ref: cur.session_ref, note_id: cur.note_id },
444
+ owner_confirm: confirmCheck.confirm,
445
+ created_at: input.ts,
446
+ updated_at: input.ts,
447
+ rev: 1,
448
+ };
449
+ const violation = docViolation(canonicalJson(entry) ?? '');
450
+ if (violation)
451
+ return violation;
452
+ const existing = state.notebook[entry.entry_id];
453
+ if (existing) {
454
+ if (deepEqual(existing, entry)) {
455
+ return { ok: true, appended: false, idemKey: zoneIdemKey({ kind: 'notebook.entry.promoted', ts: input.ts, entry }), detail: '同 rev 同内容重放:幂等 no-op' };
456
+ }
457
+ return rejected('stale_rev', `晋升隐含父 rev 0,当前 fold rev ${existing.rev}(改条目走 notebook 修订)`);
458
+ }
459
+ const event = { kind: 'notebook.entry.promoted', ts: input.ts, entry };
460
+ return { ok: true, appended: true, event, idemKey: zoneIdemKey(event) };
461
+ }
462
+ /** owner 修订笔记本条目(CAS rev+1;幂等重放 no-op;stale_rev fail-closed;持久区无 TTL) */
463
+ export function reviseNotebookEntry(state, input) {
464
+ const cur = state.notebook[input.entry_id];
465
+ if (!cur)
466
+ return rejected('unknown_subject', `笔记本条目不存在:${input.entry_id}`);
467
+ if (input.kind !== undefined && !isNotebookKind(input.kind)) {
468
+ return rejected('closed_set', `未知笔记本 kind:${String(input.kind)}(闭集 ${NOTEBOOK_KINDS.join('|')})`);
469
+ }
470
+ const confirmCheck = checkedOwnerConfirm(input.owner_confirm);
471
+ if (!confirmCheck.ok)
472
+ return rejected(confirmCheck.code, confirmCheck.detail);
473
+ const payload = input.payload ?? cur.payload;
474
+ const payloadCheck = checkedPayload(payload);
475
+ if (!payloadCheck.ok)
476
+ return rejected('payload_bound', payloadCheck.detail);
477
+ if (input.evidence !== undefined && (input.evidence.trim().length === 0 || input.evidence.length > OWNER_QUOTE_MAX)) {
478
+ return rejected('owner_confirm', `evidence 引用为空或超界(> ${OWNER_QUOTE_MAX})`);
479
+ }
480
+ const next = {
481
+ ...cur,
482
+ kind: input.kind ?? cur.kind,
483
+ payload,
484
+ evidence: input.evidence ?? cur.evidence,
485
+ owner_confirm: confirmCheck.confirm,
486
+ updated_at: input.ts,
487
+ rev: input.expected_rev + 1,
488
+ };
489
+ const violation = docViolation(canonicalJson(next) ?? '');
490
+ if (violation)
491
+ return violation;
492
+ if (deepEqual(cur, next)) {
493
+ return { ok: true, appended: false, idemKey: zoneIdemKey({ kind: 'notebook.entry.revised', ts: input.ts, entry: next }), detail: '同 rev 同内容重放:幂等 no-op' };
494
+ }
495
+ if (input.expected_rev !== cur.rev) {
496
+ return rejected('stale_rev', `父 rev ${input.expected_rev} ≠ 当前 fold rev ${cur.rev}(fail-closed,插入前拒绝)`);
497
+ }
498
+ const event = { kind: 'notebook.entry.revised', ts: input.ts, entry: next };
499
+ return { ok: true, appended: true, event, idemKey: zoneIdemKey(event) };
500
+ }
501
+ /** owner 移除条目(物理删除=遗忘;审计行随事件日志存活——设计 §1.3) */
502
+ export function dropNotebookEntry(state, entry_id, ts) {
503
+ if (!state.notebook[entry_id])
504
+ return rejected('unknown_subject', `笔记本条目不存在:${entry_id}`);
505
+ const event = { kind: 'notebook.entry.dropped', ts, entry_id };
506
+ return { ok: true, appended: true, event, idemKey: zoneIdemKey(event) };
507
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Share outbound adapter 契约层(issue #573,Phase C 切片;研究决策见
3
+ * docs/research/karpo-deck-web-research.md 决策 §3 Phase C;自检 review 修复见 PR #574 评论)。
4
+ *
5
+ * 设计契约:**所有 outbound 外发必经同意卡 + 签名 token**,且必经这个接口。
6
+ * 4 个内置适配器(iMessage / SMS / Slack / webhook)只实现契约形状、**不接
7
+ * 真实 SDK、不发网络**——统一返回 `{ delivered: false, reason: 'not_activated' }`,
8
+ * 由 share-deck.ts 主流程在 M4 阶段才决定哪些 adapter 真正激活。
9
+ *
10
+ * 三条硬纪律(继承自单页入口 + deck 入口):
11
+ * 1. payload 是**显式结构**(token 绑定 target/body)——调用方不传 raw HTML,
12
+ * 只传路径(产物可被 list/read 单独审计);
13
+ * 2. token 校验(含 target 绑定)由 share-deck 在选 adapter 之前完成——未通过
14
+ * 校验的 adapter.send 永远不会被调用;
15
+ * 3. adapter.send 返回 `delivered:false` 或抛错都算合法完成(抛错被主流程
16
+ * 收敛为 `adapter_error`);调用方据此决定 UI 反馈与重试策略。
17
+ */
18
+ // ---- 4 个 stub 适配器(issue #573 Phase C):契约形状 + no-op;不接 SDK、不发网络 ----
19
+ export const iMessageAdapter = {
20
+ id: 'imessage',
21
+ send: async () => ({ delivered: false, reason: 'not_activated' }),
22
+ };
23
+ export const smsAdapter = {
24
+ id: 'sms',
25
+ send: async () => ({ delivered: false, reason: 'not_activated' }),
26
+ };
27
+ export const slackAdapter = {
28
+ id: 'slack',
29
+ send: async () => ({ delivered: false, reason: 'not_activated' }),
30
+ };
31
+ export const webhookAdapter = {
32
+ id: 'webhook',
33
+ send: async () => ({ delivered: false, reason: 'not_activated' }),
34
+ };
35
+ /** 通道 → adapter 表(主流程 share-deck 用此表分发)。
36
+ * 运行时 Object.freeze(设计文档「冻结 record」的字面兑现——编译期 Readonly 只挡 TS)。
37
+ * 扩通道须同时扩 ShareChannel 联合与这个表;SHARE_CHANNELS 由表键派生(单一事实源)。 */
38
+ export const ADAPTERS = Object.freeze({
39
+ imessage: iMessageAdapter,
40
+ sms: smsAdapter,
41
+ slack: slackAdapter,
42
+ webhook: webhookAdapter,
43
+ });
44
+ /** 通道闭集:从 ADAPTERS 键派生(自检 review:手列第二份清单必然漂移) */
45
+ export const SHARE_CHANNELS = Object.freeze(Object.keys(ADAPTERS));
46
+ /** 自有键判定:分发守卫用它挡原型键('__proto__'/'constructor'/'toString' 经
47
+ * Record 索引会命中 Object.prototype 继承成员,直接 lookup 会拿到真值绕过
48
+ * unknown_channel 检查然后 adapter.send undefined 崩溃)。 */
49
+ export function hasAdapterChannel(table, channel) {
50
+ return typeof channel === 'string' && Object.prototype.hasOwnProperty.call(table, channel);
51
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Share consent state machine(issue #573,Phase C 切片;自检 review 修复见 PR #574)。
3
+ *
4
+ * 模式:`mode: 'ask' | 'allow' | 'off'` 三态总开关 + 每 share_id 一次性同意卡。
5
+ * 借鉴 `session-consent.ts` 的「一次一卡 + 拒绝即撤回 + 总开关 off」范式,
6
+ * 但与 session 授权**完全独立**(不合并——session 是「我能不能读你的浏览器」,
7
+ * share 是「我能不能替你外发到第三方」,两类授权的语义与撤销粒度都不同)。
8
+ *
9
+ * 三条硬纪律:
10
+ * 1. **默认 deny**:off 一律拒;ask/allow 下该 share_id 无存活卡 → consent_required;
11
+ * 2. **拒绝即撤回**:card_id 进 revoked 后,该卡即死;调用方出示的 card_id 必须
12
+ * 本身存活(在哪张卡上匹配就以哪张为准——不是「第一张活卡」);
13
+ * 3. **状态纯函数**:grant/revoke/setMode 返回新 state,不原地改;grant 幂等
14
+ * (同 share 已有存活卡则复用该卡,不再追加——防多卡漂移破坏撤销全量性)。
15
+ */
16
+ import { randomUUID } from 'node:crypto';
17
+ export function defaultShareConsentState() {
18
+ return { mode: 'ask', granted: [], revoked: [] };
19
+ }
20
+ /** 校验:off 一律拒;该 share_id 无任何卡 → consent_required(从未发卡);
21
+ * 有卡但全部被撤 → consent_revoked(曾发卡已撤);调用方出示 card_id 时,
22
+ * 该卡必须属于此 share 且自身未撤销(按卡匹配,不按第一张活卡——防多卡下
23
+ * 合法卡被误判 revoked、被撤卡被其它活卡顶替)。 */
24
+ export function checkShareConsent(state, share_id, card_id) {
25
+ if (state.mode === 'off')
26
+ return { ok: false, reason: 'share_consent_off' };
27
+ // 边界守卫:畸形持久化 state(字段非数组)fail closed 视为空——绝不抛错
28
+ const grantedList = Array.isArray(state?.granted) ? state.granted : [];
29
+ const revokedList = Array.isArray(state?.revoked) ? state.revoked : [];
30
+ const allForShare = grantedList.filter(c => c.share_id === share_id);
31
+ if (allForShare.length === 0) {
32
+ return { ok: false, reason: 'consent_required' };
33
+ }
34
+ if (card_id !== undefined) {
35
+ const given = allForShare.find(c => c.card_id === card_id);
36
+ if (!given || revokedList.includes(card_id)) {
37
+ return { ok: false, reason: 'consent_revoked' };
38
+ }
39
+ return { ok: true };
40
+ }
41
+ const anyLive = allForShare.some(c => !revokedList.includes(c.card_id));
42
+ if (!anyLive) {
43
+ return { ok: false, reason: 'consent_revoked' };
44
+ }
45
+ return { ok: true };
46
+ }
47
+ /** 发卡:幂等——同 share_id 已有存活卡则复用(不再追加,防多卡漂移);
48
+ * 否则追加新卡。返回 state 与卡本身(调用方持有 card_id 用于后续校验)。 */
49
+ export function grantShareConsent(state, share_id, now = () => new Date(), randomCardId = defaultCardId) {
50
+ const existing = state.granted.find(c => c.share_id === share_id && !state.revoked.includes(c.card_id));
51
+ if (existing)
52
+ return { state, card: existing };
53
+ const card = {
54
+ card_id: randomCardId(),
55
+ share_id,
56
+ granted_at: now().toISOString(),
57
+ };
58
+ return {
59
+ state: { mode: state.mode, granted: [...state.granted, card], revoked: state.revoked },
60
+ card,
61
+ };
62
+ }
63
+ /** 撤回:把 card_id 加入 revoked(幂等——重复 revoke 不变) */
64
+ export function revokeShareConsent(state, card_id) {
65
+ if (state.revoked.includes(card_id))
66
+ return state;
67
+ return { mode: state.mode, granted: state.granted, revoked: [...state.revoked, card_id] };
68
+ }
69
+ /** 切总开关:返回新 state(不原地改) */
70
+ export function setShareConsentMode(state, mode) {
71
+ return { mode, granted: state.granted, revoked: state.revoked };
72
+ }
73
+ /** 默认 card_id 生成器(测试可注入);Node 原生 crypto.randomUUID */
74
+ export function defaultCardId() {
75
+ return randomUUID();
76
+ }