@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.
- package/README.md +172 -219
- package/README.zh-CN.md +222 -0
- package/bin/gotry-backend.js +53 -0
- package/bin/gotry-booking-copilot.js +53 -0
- package/bin/gotry-bootstrap.js +1744 -0
- package/bin/gotry-inner.js +733 -83
- package/bin/gotry-process-liveness.d.ts +27 -0
- package/bin/gotry-process-liveness.js +97 -0
- package/bin/gotry-runtime-resolution.d.ts +27 -0
- package/bin/gotry-runtime-resolution.js +49 -0
- package/bin/gotry.js +1 -1
- package/client/client.js +203 -0
- package/cordis.gotry-patch.yml +80 -56
- package/data/airline-airports.json +39 -0
- package/data/stations-12306-verify.json +524 -0
- package/dist/capabilities/agent-reach-deep.js +45 -122
- package/dist/capabilities/agent-reach.js +101 -146
- package/dist/capabilities/anything.js +135 -94
- package/dist/capabilities/artifacts.js +370 -0
- package/dist/capabilities/channel-health.js +131 -0
- package/dist/capabilities/channel-registry.js +256 -0
- package/dist/capabilities/doctor.js +546 -0
- package/dist/capabilities/effect.js +394 -0
- package/dist/capabilities/external-event.js +149 -0
- package/dist/capabilities/fact-log.js +55 -0
- package/dist/capabilities/flyai-config.js +337 -0
- package/dist/capabilities/flyai.js +947 -110
- package/dist/capabilities/fx-contract.js +293 -0
- package/dist/capabilities/geo-atlas.js +246 -0
- package/dist/capabilities/ground-transfer.js +509 -0
- package/dist/capabilities/hbcli.js +260 -123
- package/dist/capabilities/hotelbyte-transaction.js +194 -0
- package/dist/capabilities/incident-log.js +131 -61
- package/dist/capabilities/itinerary-artifact.js +190 -0
- package/dist/capabilities/itinerary-deck-artifact.js +194 -0
- package/dist/capabilities/itinerary-deck-export.js +339 -0
- package/dist/capabilities/lavish-local.js +924 -0
- package/dist/capabilities/model-override.js +38 -0
- package/dist/capabilities/opensky.js +54 -43
- package/dist/capabilities/resilience.js +191 -0
- package/dist/capabilities/session/action-cache.js +50 -44
- package/dist/capabilities/session/adapters/ctrip-flight.js +120 -62
- package/dist/capabilities/session/adapters/ctrip-hotel.js +222 -0
- package/dist/capabilities/session/adapters/dida-portal.js +274 -0
- package/dist/capabilities/session/adapters/meituan-local.js +35 -54
- package/dist/capabilities/session/adapters/rail-12306.js +342 -0
- package/dist/capabilities/session/benchmark.js +189 -0
- package/dist/capabilities/session/bridge-ledger.js +224 -0
- package/dist/capabilities/session/extension-bridge.js +636 -0
- package/dist/capabilities/session/extension-channel.js +109 -0
- package/dist/capabilities/session/extension-distribution.js +230 -0
- package/dist/capabilities/session/extract.js +31 -21
- package/dist/capabilities/session/golden-score.js +114 -0
- package/dist/capabilities/session/health-watch.js +215 -0
- package/dist/capabilities/session/read-guard.js +75 -24
- package/dist/capabilities/session/static-flight-golden.js +150 -0
- package/dist/capabilities/session/transport.js +97 -83
- package/dist/capabilities/session/wizard.js +117 -0
- package/dist/capabilities/session-consent.js +178 -0
- package/dist/capabilities/session-login.js +170 -0
- package/dist/capabilities/session-search.js +635 -44
- package/dist/capabilities/spawn-bounded.js +203 -0
- package/dist/capabilities/sponsor-plugin.js +341 -0
- package/dist/capabilities/visa-policy.js +140 -0
- package/dist/capabilities/weather.js +243 -138
- package/dist/data/session-golden-20.json +25 -0
- package/dist/data/sf-golden-manifest.json +103 -0
- package/dist/data/sf-static-routes.json +91 -0
- package/dist/scripts/action-cache-tests.js +24 -59
- package/dist/scripts/agent-planning-turn-deadline-e2e.js +242 -0
- package/dist/scripts/agent-planning-turn-deadline-tests.js +185 -0
- package/dist/scripts/agent-reach-deep-tests.js +30 -40
- package/dist/scripts/agent-reach-error-tests.js +354 -0
- package/dist/scripts/agent-reach-tests.js +26 -18
- package/dist/scripts/agent-reach-wrapper-tests.js +50 -50
- package/dist/scripts/anything-tests.js +116 -60
- package/dist/scripts/artifact-client-contract-tests.js +220 -0
- package/dist/scripts/artifacts-capability-tests.js +727 -0
- package/dist/scripts/async-collect.js +50 -11
- package/dist/scripts/benchmark-environment-bridge-e2e.js +741 -0
- package/dist/scripts/benchmark-environment-bridge-tests.js +1452 -0
- package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +126 -0
- package/dist/scripts/booking-copilot-availability-policy-tests.js +265 -0
- package/dist/scripts/booking-copilot-bin-proof-tests.js +66 -0
- package/dist/scripts/booking-copilot-cleanup-proof-helper.js +76 -0
- package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +144 -0
- package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +424 -0
- package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +2839 -0
- package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +309 -0
- package/dist/scripts/booking-copilot-dsh-readiness-proof.js +238 -0
- package/dist/scripts/booking-copilot-dsh-warmer-proof.js +123 -0
- package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +156 -0
- package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +70 -0
- package/dist/scripts/booking-copilot-intent-proof-tests.js +422 -0
- package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +184 -0
- package/dist/scripts/booking-copilot-planner-live-probe.js +95 -0
- package/dist/scripts/booking-copilot-proof-runtime.js +42 -0
- package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +210 -0
- package/dist/scripts/booking-copilot-runtime-proof-tests.js +2349 -0
- package/dist/scripts/booking-copilot-server-proof-tests.js +784 -0
- package/dist/scripts/booking-copilot-startup-proof-tests.js +94 -0
- package/dist/scripts/booking-executor-tests.js +80 -0
- package/dist/scripts/booking-recovery-chain-tests.js +182 -0
- package/dist/scripts/booking-saga-tests.js +125 -0
- package/dist/scripts/booking-surface-contract-proof-tests.js +212 -0
- package/dist/scripts/bootstrap-tests.js +1479 -0
- package/dist/scripts/bridge-events-tests.js +239 -0
- package/dist/scripts/bridge-ledger-tests.js +428 -0
- package/dist/scripts/build-changelog.js +238 -0
- package/dist/scripts/build-metrics-report.js +331 -0
- package/dist/scripts/changelog-tests.js +118 -0
- package/dist/scripts/channel-probe-tests.js +103 -0
- package/dist/scripts/channel-probe.js +169 -0
- package/dist/scripts/channel-registry-tests.js +208 -0
- package/dist/scripts/companion-tests.js +25 -70
- package/dist/scripts/dida-cookie-probe.js +87 -0
- package/dist/scripts/dida-runner-stop-tests.js +311 -0
- package/dist/scripts/dida-sw-probe.js +114 -0
- package/dist/scripts/diff-test.js +17 -12
- package/dist/scripts/doctor-tests.js +564 -0
- package/dist/scripts/dsh-artifact-e2e.js +279 -0
- package/dist/scripts/dsh-artifact-web-e2e.js +675 -0
- package/dist/scripts/dsh-http-proxy-sse-proof.js +90 -0
- package/dist/scripts/dsh-runtime-closure-tests.js +182 -0
- package/dist/scripts/dsh-runtime-closure.js +162 -0
- package/dist/scripts/dsh-session-v3-migration-proof.js +109 -0
- package/dist/scripts/dsh-subprocess-local-proof.js +150 -0
- package/dist/scripts/dsh-target-closure-proof.js +178 -0
- package/dist/scripts/effect-tests.js +539 -0
- package/dist/scripts/engine-run.js +1 -3
- package/dist/scripts/engine-tests.js +16 -10
- package/dist/scripts/evaluation-cadence-tests.js +174 -0
- package/dist/scripts/evaluation-contract-tests.js +268 -0
- package/dist/scripts/extension-distribution-cli.js +39 -0
- package/dist/scripts/extension-distribution-tests.js +443 -0
- package/dist/scripts/extension-tests.js +988 -0
- package/dist/scripts/external-event-tests.js +350 -0
- package/dist/scripts/fact-gate-tests.js +869 -0
- package/dist/scripts/fixtures/extension-bridge-unref-child.mjs +21 -0
- package/dist/scripts/flight-hotel-anchor-363-registered-e2e.js +169 -0
- package/dist/scripts/flight-malformed-tests.js +159 -0
- package/dist/scripts/flyai-setup-tests.js +228 -0
- package/dist/scripts/flyai-setup-tool-tests.js +54 -0
- package/dist/scripts/flyai-tests.js +692 -0
- package/dist/scripts/flyai-tool-registration-contract-tests.js +91 -0
- package/dist/scripts/fx-contract-tests.js +201 -0
- package/dist/scripts/g5-guard-tests.js +131 -0
- package/dist/scripts/g5-guard.js +189 -0
- package/dist/scripts/gen-lunar-anchors.js +106 -0
- package/dist/scripts/geo-atlas-tests.js +283 -0
- package/dist/scripts/gotry-backend-kernel-tests.js +206 -0
- package/dist/scripts/gotry-try-demo-tests.js +79 -0
- package/dist/scripts/gotry-try-demo.js +49 -0
- package/dist/scripts/ground-transfer-tests.js +956 -0
- package/dist/scripts/hbcli-e2e-tests.js +159 -0
- package/dist/scripts/hbcli-live-optin-tests.js +96 -0
- package/dist/scripts/hbcli-release-contract-tests.js +122 -0
- package/dist/scripts/hbcli-tests.js +121 -69
- package/dist/scripts/health-watch-cli.js +73 -0
- package/dist/scripts/hotel-date-gate-tests.js +496 -0
- package/dist/scripts/hotelbyte-reconcile-tests.js +141 -0
- package/dist/scripts/hotelbyte-spawn-e2e-tests.js +373 -0
- package/dist/scripts/i18n-tests.js +41 -0
- package/dist/scripts/incident-tests.js +281 -87
- package/dist/scripts/issue-194-job-id-guard-tests.js +106 -0
- package/dist/scripts/issue-233-cancel-refund-commission-tests.js +392 -0
- package/dist/scripts/issue-271-liveness-tests.js +569 -0
- package/dist/scripts/issue-289-model-retry-real-tests.js +296 -0
- package/dist/scripts/issue-289-model-retry-tests.js +441 -0
- package/dist/scripts/issue-289-web-retry-e2e.js +630 -0
- package/dist/scripts/issue-338-home-city-e2e.js +577 -0
- package/dist/scripts/issue343-real-entry-e2e.js +160 -0
- package/dist/scripts/issue436-persisted-routing-e2e.js +247 -0
- package/dist/scripts/itinerary-artifact-tests.js +368 -0
- package/dist/scripts/itinerary-deck-artifact-tests.js +416 -0
- package/dist/scripts/itinerary-deck-export-tests.js +552 -0
- package/dist/scripts/itinerary-deck-tests.js +435 -0
- package/dist/scripts/itinerary-html-tests.js +426 -0
- package/dist/scripts/journey-tests.js +22 -27
- package/dist/scripts/kernel-manifest-evidence.js +109 -0
- package/dist/scripts/kernel-manifest-gate.js +126 -0
- package/dist/scripts/kernel-manifest-tests.js +212 -0
- package/dist/scripts/kernel-manifest-trace-entry.js +7 -0
- package/dist/scripts/kernel-manifest-trace-hook.mjs +28 -0
- package/dist/scripts/kernel-manifest.js +369 -0
- package/dist/scripts/lavish-local-tests.js +1226 -0
- package/dist/scripts/lavish-product-tools-tests.js +537 -0
- package/dist/scripts/ledger-repair-apply-tests.js +316 -0
- package/dist/scripts/ledger-repair-plan-tests.js +375 -0
- package/dist/scripts/ledger-tests.js +382 -246
- package/dist/scripts/ledger-workflow-crash.js +10 -20
- package/dist/scripts/managed-dsh-cleanup-diagnostic-proof.js +184 -0
- package/dist/scripts/managed-dsh-close-failure-proof.js +172 -0
- package/dist/scripts/managed-dsh-run-port-proof.js +153 -0
- package/dist/scripts/managed-dsh-terminal-proof.js +252 -0
- package/dist/scripts/map-tools-vendor-package-proof.js +365 -0
- package/dist/scripts/memory-capture-tests.js +242 -61
- package/dist/scripts/memory-decay-tests.js +18 -52
- package/dist/scripts/memory-lifecycle-tests.js +657 -0
- package/dist/scripts/memory-lifecycle.js +196 -0
- package/dist/scripts/memory-metrics.js +24 -12
- package/dist/scripts/memory-value-report.js +631 -0
- package/dist/scripts/memory-value-tests.js +328 -0
- package/dist/scripts/metrics-report-tests.js +151 -0
- package/dist/scripts/model-override-e2e.js +137 -0
- package/dist/scripts/nightly-evidence-tests.js +161 -0
- package/dist/scripts/nightly-evidence.js +286 -0
- package/dist/scripts/nudge-digest.js +39 -28
- package/dist/scripts/observability-tests.js +381 -0
- package/dist/scripts/onboarding-tests.js +161 -0
- package/dist/scripts/opensky-check.js +18 -13
- package/dist/scripts/opensky-tests.js +28 -28
- package/dist/scripts/persona-surface-guard-tests.js +49 -0
- package/dist/scripts/pnpm-dsh-closure-proof.js +17 -0
- package/dist/scripts/policy-anchor-359-registered-e2e.js +214 -0
- package/dist/scripts/price-drift-tests.js +340 -0
- package/dist/scripts/price-drift-watch.js +447 -0
- package/dist/scripts/probe-poi-tests.js +53 -45
- package/dist/scripts/product-metrics.js +483 -0
- package/dist/scripts/publish-preverify.js +110 -0
- package/dist/scripts/realtime-pricing-tests.js +76 -0
- package/dist/scripts/recall-tests.js +513 -0
- package/dist/scripts/replay-async.js +20 -18
- package/dist/scripts/replay-real.js +18 -18
- package/dist/scripts/replay.js +52 -82
- package/dist/scripts/session-attach-diagnose.js +20 -20
- package/dist/scripts/session-attach-poc.js +34 -37
- package/dist/scripts/session-benchmark.js +180 -0
- package/dist/scripts/session-dida-live-e2e.js +199 -0
- package/dist/scripts/session-extract-tests.js +14 -35
- package/dist/scripts/session-link-tests.js +478 -0
- package/dist/scripts/session-login.js +27 -46
- package/dist/scripts/session-tests.js +796 -96
- package/dist/scripts/session-zones-tests.js +358 -0
- package/dist/scripts/sf-live-benchmark.js +367 -0
- package/dist/scripts/sf-live-challenge-stop-tests.js +453 -0
- package/dist/scripts/sf-live-cli-tests.js +92 -0
- package/dist/scripts/sf-live-options.js +46 -0
- package/dist/scripts/sf-manifest-tests.js +30 -0
- package/dist/scripts/sf-manifest.js +33 -0
- package/dist/scripts/sf-soft-score-tests.js +67 -0
- package/dist/scripts/sf-summary-tests.js +324 -0
- package/dist/scripts/sf-summary.js +525 -0
- package/dist/scripts/share-tests.js +432 -0
- package/dist/scripts/skeleton-check.js +16 -14
- package/dist/scripts/skeleton-integration-test.js +28 -11
- package/dist/scripts/skills-contract-tests.js +51 -46
- package/dist/scripts/smoke-session-gate-tests.js +21 -0
- package/dist/scripts/smoke.js +690 -246
- package/dist/scripts/spawn-bounded-abort-tests.js +241 -0
- package/dist/scripts/sponsor-reuse-tests.js +262 -0
- package/dist/scripts/state-cli-tests.js +226 -101
- package/dist/scripts/state-cli.js +550 -199
- package/dist/scripts/state-repair-cli.js +66 -0
- package/dist/scripts/state-repair-tests.js +140 -0
- package/dist/scripts/static-golden-tests.js +165 -0
- package/dist/scripts/time-eval-tests.js +210 -192
- package/dist/scripts/travel-timeline-tests.js +29 -93
- package/dist/scripts/turn-handoff-collect-tests.js +169 -0
- package/dist/scripts/turn-handoff-collect.js +161 -0
- package/dist/scripts/turn-policy-tests.js +55 -0
- package/dist/scripts/typed-contract-canary.js +176 -0
- package/dist/scripts/tz-resolver-sanity.js +50 -0
- package/dist/scripts/tz-resolver-tests.js +584 -0
- package/dist/scripts/unified-tests.js +23 -19
- package/dist/scripts/visa-policy-tests.js +62 -0
- package/dist/scripts/weather-tests.js +276 -41
- package/dist/scripts/wish-channel-gate-tests.js +54 -0
- package/dist/scripts/write-gate-tests.js +522 -0
- package/dist/scripts/z3-lifecycle-fault-tests.js +188 -0
- package/dist/scripts/z3-lifecycle-tests.js +170 -0
- package/dist/scripts/z3-race-repeat-tests.js +39 -0
- package/dist/scripts/z3-race-tests.js +41 -0
- package/dist/src/artifact-gate.js +829 -0
- package/dist/src/backend/kernel.js +91 -0
- package/dist/src/backend/modules/booking-copilot.js +92 -0
- package/dist/src/backend/modules/booking-executor.js +124 -0
- package/dist/src/backend/modules/session-search.js +551 -0
- package/dist/src/benchmark-agent-conformance.js +578 -0
- package/dist/src/benchmark-environment-bridge.js +515 -0
- package/dist/src/benchmark-headless-child-diagnostics.js +166 -0
- package/dist/src/benchmark-tool-isolation.js +151 -0
- package/dist/src/bookable-facts.js +533 -0
- package/dist/src/booking-saga.js +97 -0
- package/dist/src/booking-surface/availability-policy.js +697 -0
- package/dist/src/booking-surface/booking-intent.js +43 -0
- package/dist/src/booking-surface/cancel-refund-commission.js +379 -0
- package/dist/src/booking-surface/canonical-schema.js +116 -0
- package/dist/src/booking-surface/contracts.js +75 -0
- package/dist/src/booking-surface/dsh-planner.js +1854 -0
- package/dist/src/booking-surface/dsh-plugin.js +378 -0
- package/dist/src/booking-surface/dsh-worker.js +98 -0
- package/dist/src/booking-surface/error-codes.js +231 -0
- package/dist/src/booking-surface/index.js +9 -0
- package/dist/src/booking-surface/managed-dsh-cleanup-diagnostic.js +97 -0
- package/dist/src/booking-surface/managed-dsh-run-port.js +244 -0
- package/dist/src/booking-surface/profile.js +24 -0
- package/dist/src/booking-surface/recovery-chain.js +367 -0
- package/dist/src/booking-surface/runtime.js +1968 -0
- package/dist/src/booking-surface/server.js +674 -0
- package/dist/src/booking-surface/startup.js +168 -0
- package/dist/src/booking-surface/validation.js +261 -0
- package/dist/src/bridge.js +20 -13
- package/dist/src/companions.js +48 -74
- package/dist/src/contracts.js +21 -43
- package/dist/src/dsh-llm.js +97 -111
- package/dist/src/engine.js +276 -193
- package/dist/src/evaluation-cadence.js +97 -0
- package/dist/src/evaluation-contracts.js +283 -0
- package/dist/src/flight-pack-adapter.js +54 -0
- package/dist/src/flight-pack-contract.js +2 -0
- package/dist/src/flyai-setup-tool.js +70 -0
- package/dist/src/gotry-backend.js +125 -0
- package/dist/src/hotel-date-gate.js +118 -0
- package/dist/src/i18n.js +88 -0
- package/dist/src/index.js +2227 -882
- package/dist/src/itinerary-deck.js +139 -0
- package/dist/src/itinerary-doc-shared.js +661 -0
- package/dist/src/itinerary-html.js +131 -0
- package/dist/src/journey.js +155 -108
- package/dist/src/lavish-tools.js +400 -0
- package/dist/src/ledger-repair-apply.js +538 -0
- package/dist/src/ledger-repair-plan.js +463 -0
- package/dist/src/loop.js +319 -160
- package/dist/src/memory-capture.js +180 -32
- package/dist/src/memory-decay.js +30 -14
- package/dist/src/memory-lifecycle.js +1310 -0
- package/dist/src/memory-utility.js +27 -40
- package/dist/src/mock-llm.js +36 -61
- package/dist/src/model.js +81 -36
- package/dist/src/realtime-pricing.js +103 -0
- package/dist/src/recall/card.js +74 -0
- package/dist/src/recall/evaluator.js +140 -0
- package/dist/src/recall/integration.js +17 -0
- package/dist/src/recall/tick.js +166 -0
- package/dist/src/session-link/plan-it-action.js +48 -0
- package/dist/src/session-link/session-link.js +248 -0
- package/dist/src/session-zones.js +507 -0
- package/dist/src/share/adapters.js +51 -0
- package/dist/src/share/share-consent.js +76 -0
- package/dist/src/share/share-deck.js +58 -0
- package/dist/src/share/share-token.js +146 -0
- package/dist/src/slot-spec.js +84 -106
- package/dist/src/state-ledger.js +435 -516
- package/dist/src/state-repair.js +299 -0
- package/dist/src/subagent-job-id-guard.js +58 -0
- package/dist/src/time-anchor.js +231 -33
- package/dist/src/tool-packet.js +20 -8
- package/dist/src/travel-slots.js +58 -35
- package/dist/src/travel-timeline.js +44 -63
- package/dist/src/turn-deadline.js +287 -0
- package/dist/src/turn-policy.js +118 -0
- package/dist/src/tz-resolver.js +143 -0
- package/dist/src/unified.js +535 -359
- package/dist/src/wish-pool.js +42 -12
- package/dist/src/write-gate.js +495 -0
- package/dist/src/z3-shared.js +284 -0
- package/extension/README.md +21 -0
- package/extension/README.zh-CN.md +21 -0
- package/extension/background.js +463 -0
- package/extension/content-bridge.js +270 -0
- package/extension/content-main.js +111 -0
- package/extension/manifest.json +60 -0
- package/package.json +407 -14
- package/schemas/booking.intent.schema.json +193 -0
- package/schemas/booking.surface.schema.json +2622 -0
- package/ts/capabilities/agent-reach-deep.ts +114 -0
- package/ts/capabilities/agent-reach.ts +198 -0
- package/ts/capabilities/anything.ts +255 -0
- package/ts/capabilities/artifacts.ts +428 -0
- package/ts/capabilities/fact-log.ts +54 -0
- package/ts/capabilities/flyai-config.ts +388 -0
- package/ts/capabilities/flyai.ts +1274 -0
- package/ts/capabilities/hbcli.ts +253 -71
- package/ts/capabilities/incident-log.ts +88 -59
- package/ts/capabilities/itinerary-artifact.ts +214 -0
- package/ts/capabilities/itinerary-deck-artifact.ts +218 -0
- package/ts/capabilities/itinerary-deck-export.ts +378 -0
- package/ts/capabilities/opensky.ts +121 -0
- package/ts/capabilities/session/action-cache.ts +148 -0
- package/ts/capabilities/session/adapters/ctrip-flight.ts +181 -0
- package/ts/capabilities/session/adapters/ctrip-hotel.ts +238 -0
- package/ts/capabilities/session/adapters/dida-portal.ts +338 -0
- package/ts/capabilities/session/adapters/meituan-local.ts +70 -0
- package/ts/capabilities/session/adapters/rail-12306.ts +392 -0
- package/ts/capabilities/session/benchmark.ts +276 -0
- package/ts/capabilities/session/bridge-ledger.ts +333 -0
- package/ts/capabilities/session/extension-bridge.ts +794 -0
- package/ts/capabilities/session/extension-channel.ts +144 -0
- package/ts/capabilities/session/extension-distribution.ts +266 -0
- package/ts/capabilities/session/extract.ts +54 -0
- package/ts/capabilities/session/golden-score.ts +139 -0
- package/ts/capabilities/session/health-watch.ts +264 -0
- package/ts/capabilities/session/read-guard.ts +141 -0
- package/ts/capabilities/session/static-flight-golden.ts +209 -0
- package/ts/capabilities/session/transport.ts +146 -0
- package/ts/capabilities/session/wizard.ts +140 -0
- package/ts/capabilities/session-consent.ts +211 -0
- package/ts/capabilities/session-login.ts +208 -0
- package/ts/capabilities/session-search.ts +893 -0
- package/ts/capabilities/weather.ts +330 -0
- package/ts/dsh-runtime/vendor/README.md +68 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/LICENSE +21 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +405 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +404 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/client/client.js +1584 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/cordis.patch.yml +5 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/icon.svg +5 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/amap.js +595 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/nominatim.js +63 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/osrm.js +58 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/photon.js +55 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-file.js +87 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-route.js +131 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config.js +16 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/geo.js +232 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/index.js +120 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +40 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/staticmap-route.js +115 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/geocode.js +127 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/poi.js +84 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/routes.js +267 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/amap.d.ts +90 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/nominatim.d.ts +17 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/osrm.d.ts +15 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/photon.d.ts +22 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-file.d.ts +33 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-route.d.ts +23 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config.d.ts +23 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/geo.d.ts +61 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/index.d.ts +18 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +14 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/staticmap-route.d.ts +31 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/geocode.d.ts +11 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/poi.d.ts +9 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/routes.d.ts +75 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/types.d.ts +68 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types.js +16 -0
- package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +97 -0
- package/ts/package.json +293 -3
- package/ts/scripts/async-collect.ts +91 -0
- package/ts/scripts/map-tools-vendor-package-proof.ts +404 -0
- package/ts/scripts/skeleton-check.ts +1 -1
- package/ts/scripts/skeleton-integration-test.ts +23 -1
- package/ts/scripts/state-cli.ts +568 -0
- package/ts/scripts/turn-handoff-collect.ts +178 -0
- package/ts/src/artifact-gate.ts +991 -0
- package/ts/src/benchmark-agent-conformance.ts +619 -0
- package/ts/src/benchmark-environment-bridge.ts +538 -0
- package/ts/src/benchmark-headless-child-diagnostics.ts +184 -0
- package/ts/src/benchmark-tool-isolation.ts +166 -0
- package/ts/src/bookable-facts.ts +837 -0
- package/ts/src/booking-saga.ts +133 -0
- package/ts/src/booking-surface/availability-policy.ts +522 -0
- package/ts/src/booking-surface/booking-intent.ts +86 -0
- package/ts/src/booking-surface/cancel-refund-commission.ts +488 -0
- package/ts/src/booking-surface/canonical-schema.js +116 -0
- package/ts/src/booking-surface/contracts.ts +475 -0
- package/ts/src/booking-surface/dsh-planner.ts +1949 -0
- package/ts/src/booking-surface/dsh-plugin.js +378 -0
- package/ts/src/booking-surface/dsh-worker.ts +110 -0
- package/ts/src/booking-surface/error-codes.ts +241 -0
- package/ts/src/booking-surface/index.ts +9 -0
- package/ts/src/booking-surface/managed-dsh-cleanup-diagnostic.ts +151 -0
- package/ts/src/booking-surface/managed-dsh-run-port.ts +273 -0
- package/ts/src/booking-surface/profile.ts +42 -0
- package/ts/src/booking-surface/recovery-chain.ts +409 -0
- package/ts/src/booking-surface/runtime.ts +1793 -0
- package/ts/src/booking-surface/server.ts +733 -0
- package/ts/src/booking-surface/startup.ts +201 -0
- package/ts/src/booking-surface/validation.ts +217 -0
- package/ts/src/companions.ts +113 -0
- package/ts/src/contracts.ts +13 -3
- package/ts/src/dsh-llm.ts +44 -11
- package/ts/src/flyai-setup-tool.ts +77 -0
- package/ts/src/index.ts +1948 -198
- package/ts/src/itinerary-deck.ts +189 -0
- package/ts/src/itinerary-doc-shared.ts +741 -0
- package/ts/src/itinerary-html.ts +171 -0
- package/ts/src/loop.ts +223 -25
- package/ts/src/memory-capture.ts +283 -0
- package/ts/src/memory-decay.ts +55 -0
- package/ts/src/memory-utility.ts +70 -0
- package/ts/src/mock-llm.ts +4 -8
- package/ts/src/model.ts +88 -2
- package/ts/src/recall/card.ts +106 -0
- package/ts/src/recall/evaluator.ts +170 -0
- package/ts/src/recall/integration.ts +35 -0
- package/ts/src/recall/tick.ts +213 -0
- package/ts/src/session-link/plan-it-action.ts +78 -0
- package/ts/src/session-link/session-link.ts +275 -0
- package/ts/src/share/adapters.ts +93 -0
- package/ts/src/share/share-consent.ts +105 -0
- package/ts/src/share/share-deck.ts +85 -0
- package/ts/src/share/share-token.ts +166 -0
- package/ts/src/slot-spec.ts +172 -0
- package/ts/src/state-ledger.ts +912 -0
- package/ts/src/subagent-job-id-guard.ts +72 -0
- package/ts/src/time-anchor.ts +338 -0
- package/ts/src/tool-packet.ts +32 -0
- package/ts/src/travel-slots.ts +219 -0
- package/ts/src/travel-timeline.ts +83 -0
- package/ts/src/turn-deadline.ts +366 -0
- package/ts/src/turn-policy.ts +154 -0
- package/ts/src/unified.ts +354 -88
- package/ts/src/wish-pool.ts +79 -0
- package/dist/scripts/session-attach-wait.js +0 -41
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 行程 deck 静态导出 bundle(issue #568,Phase B 切片 3a;研究决策见
|
|
3
|
+
* docs/research/karpo-deck-web-research.md 决策 #1 与
|
|
4
|
+
* docs/design/itinerary-deck-renderer.md;QR 真矩阵编码独立为 issue #569 切片 3b)。
|
|
5
|
+
*
|
|
6
|
+
* 与切片 2 单页入口(`gotry_itinerary_render`)/切片 2 deck 入口
|
|
7
|
+
* (`gotry_itinerary_deck_render`)的产品分工:那两个入口把产物写到 dsh 会话
|
|
8
|
+
* 工作目录顶层(用于 chat 内嵌);本入口把 deck 写到**宿主显式给出的
|
|
9
|
+
* target_dir** 下的一个「分享 bundle」——`basename.html` + `manifest.json` +
|
|
10
|
+
* `qr.svg`(qrcode 库真矩阵,#569),ready for 任意静态托管。
|
|
11
|
+
*
|
|
12
|
+
* 三条硬纪律(继承自单页入口 + deck 入口,verbatim):
|
|
13
|
+
* 1. 事实只从 <stateRoot>/gotry-state/bookable-facts.jsonl 注册表取;
|
|
14
|
+
* 2. target_dir 必须是宿主显式给出的**绝对**目录,realpath 化并排除
|
|
15
|
+
* .git/node_modules 后,以 `O_CREAT|O_EXCL` 独占创建 bundle 三件——
|
|
16
|
+
* 既有 bundle 文件任何一件存在都拒绝覆盖;
|
|
17
|
+
* 3. 失败即拒绝、零写入:输入非法/事实未注册/渲染被拒/basename 非法/
|
|
18
|
+
* bundle 任一文件已被占用都返回结构化错误,不开文件、不落字节。
|
|
19
|
+
*/
|
|
20
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
21
|
+
import { lstat, open, realpath, stat } from 'node:fs/promises';
|
|
22
|
+
import { isAbsolute, join, sep } from 'node:path';
|
|
23
|
+
import QRCode from 'qrcode';
|
|
24
|
+
import { loadFactRegistry } from './fact-log.js';
|
|
25
|
+
import { ITINERARY_DOC_LIMITS } from '../src/itinerary-doc-shared.js';
|
|
26
|
+
import { renderItineraryDeck } from '../src/itinerary-deck.js';
|
|
27
|
+
/** 产物 basename 契约:固定前缀 + ASCII 安全 token(后缀固定 .html/.manifest.json/.qr.svg,basename 不含 .) */
|
|
28
|
+
export const ITINERARY_DECK_EXPORT_BASENAME_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/;
|
|
29
|
+
/** bundle 三件文件名 — 三件都带 basename 前缀(同一 target_dir 下多 bundle 不互撞) */
|
|
30
|
+
export const ITINERARY_DECK_EXPORT_HTML_SUFFIX = '.html';
|
|
31
|
+
export const ITINERARY_DECK_EXPORT_MANIFEST_SUFFIX = '.manifest.json';
|
|
32
|
+
export const ITINERARY_DECK_EXPORT_QR_SUFFIX = '.qr.svg';
|
|
33
|
+
/** 保留未带后缀的别名(向后兼容:导出 manifest.json / qr.svg 单件名给老消费者) */
|
|
34
|
+
export const ITINERARY_DECK_EXPORT_MANIFEST_NAME = 'manifest.json';
|
|
35
|
+
export const ITINERARY_DECK_EXPORT_QR_NAME = 'qr.svg';
|
|
36
|
+
/** 随机默认 bundle basename(仅 crypto 十六进制;显式 basename 优先) */
|
|
37
|
+
export const ITINERARY_DECK_EXPORT_RANDOM_BYTES = 8;
|
|
38
|
+
/** 无 target_url 时 QR 编码的字面本地占位串(扫码得到说明文本而非死链;#569) */
|
|
39
|
+
export const ITINERARY_DECK_EXPORT_LOCAL_MARKER = '<local bundle; not yet hosted>';
|
|
40
|
+
const RANDOM_ATTEMPTS = 3;
|
|
41
|
+
const DIR_DENY = ['.git', 'node_modules'];
|
|
42
|
+
const ID_SAMPLE = 3;
|
|
43
|
+
const SOURCE_TAG_SAMPLE = 12;
|
|
44
|
+
const TARGET_URL_MAX = 2048;
|
|
45
|
+
function isRecord(value) {
|
|
46
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
47
|
+
}
|
|
48
|
+
function hasDeniedSegment(p) {
|
|
49
|
+
return p.split(sep).some(seg => DIR_DENY.includes(seg));
|
|
50
|
+
}
|
|
51
|
+
function fsErrorText(err) {
|
|
52
|
+
const code = err?.code;
|
|
53
|
+
switch (code) {
|
|
54
|
+
case 'EACCES':
|
|
55
|
+
case 'EPERM': return '无写入权限';
|
|
56
|
+
case 'ENOSPC': return '磁盘空间不足';
|
|
57
|
+
case 'EROFS': return '只读文件系统';
|
|
58
|
+
case 'ENOTDIR': return '路径中某段不是目录';
|
|
59
|
+
case 'ENOENT': return '目录不存在';
|
|
60
|
+
case 'ENAMETOOLONG': return '文件名过长';
|
|
61
|
+
default: return typeof code === 'string' ? `文件系统错误 ${code}` : '文件系统错误';
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/** fact_ids 输入收窄:必填数组、逐条非空短字符串、无重复、不超渲染器容量 */
|
|
65
|
+
function takeFactIds(value) {
|
|
66
|
+
if (value === undefined || value === null) {
|
|
67
|
+
return { error: 'fact_ids 必填(字符串数组,可为空数组)', hint: 'id 来自本次会话 exact-date 工具结果记录的注册表;不接受调用方自带事实' };
|
|
68
|
+
}
|
|
69
|
+
if (!Array.isArray(value))
|
|
70
|
+
return { error: 'fact_ids 必须是字符串数组' };
|
|
71
|
+
if (value.length > ITINERARY_DOC_LIMITS.facts) {
|
|
72
|
+
return { error: `fact_ids 超出容量上限(${ITINERARY_DOC_LIMITS.facts} 条,实测 ${value.length} 条)` };
|
|
73
|
+
}
|
|
74
|
+
const ids = [];
|
|
75
|
+
const seen = new Set();
|
|
76
|
+
const duplicates = [];
|
|
77
|
+
for (const [i, raw] of value.entries()) {
|
|
78
|
+
if (typeof raw !== 'string' || raw.length === 0)
|
|
79
|
+
return { error: `fact_ids[${i}] 必须是非空字符串` };
|
|
80
|
+
if (raw.length > ITINERARY_DOC_LIMITS.factIdChars) {
|
|
81
|
+
return { error: `fact_ids[${i}] 超出 id 长度上限(${ITINERARY_DOC_LIMITS.factIdChars} 字符)` };
|
|
82
|
+
}
|
|
83
|
+
if (seen.has(raw)) {
|
|
84
|
+
duplicates.push(raw);
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
seen.add(raw);
|
|
88
|
+
ids.push(raw);
|
|
89
|
+
}
|
|
90
|
+
if (duplicates.length > 0) {
|
|
91
|
+
return { error: `fact_ids 有重复 id:${duplicates.slice(0, ID_SAMPLE).join('、')}${duplicates.length > ID_SAMPLE ? ` 等 ${duplicates.length} 条` : ''}`, hint: '同一条事实只能选一次;重复选择说明调用方对证据面不确定' };
|
|
92
|
+
}
|
|
93
|
+
return { ids };
|
|
94
|
+
}
|
|
95
|
+
function takeBasename(value) {
|
|
96
|
+
if (value === undefined || value === null)
|
|
97
|
+
return { basename: `export-${randomBytes(ITINERARY_DECK_EXPORT_RANDOM_BYTES).toString('hex')}` };
|
|
98
|
+
if (typeof value !== 'string' || value.length === 0)
|
|
99
|
+
return { error: 'basename 必须是字符串' };
|
|
100
|
+
if (value.includes('/') || value.includes('\\') || value.includes('..')) {
|
|
101
|
+
return { error: 'basename 只能是文件 stem,不能含路径分隔符或 ..', hint: '形如 2027-thailand-phuket(用于生成 2027-thailand-phuket.html + manifest.json + qr.svg)' };
|
|
102
|
+
}
|
|
103
|
+
if (!ITINERARY_DECK_EXPORT_BASENAME_RE.test(value)) {
|
|
104
|
+
return { error: 'basename 不符合命名契约', hint: '必须是字母/数字开头,后接字母/数字/._-(1-64 字符)' };
|
|
105
|
+
}
|
|
106
|
+
return { basename: value };
|
|
107
|
+
}
|
|
108
|
+
function takeTargetUrl(value) {
|
|
109
|
+
if (value === undefined || value === null)
|
|
110
|
+
return { targetUrl: undefined };
|
|
111
|
+
if (typeof value !== 'string' || value.length === 0)
|
|
112
|
+
return { error: 'target_url 必须是字符串(可省略)' };
|
|
113
|
+
if (value.length > TARGET_URL_MAX) {
|
|
114
|
+
return { error: `target_url 超出长度上限(${TARGET_URL_MAX} 字符)` };
|
|
115
|
+
}
|
|
116
|
+
return { targetUrl: value };
|
|
117
|
+
}
|
|
118
|
+
/** target_dir:必须显式且为绝对路径(缺失/空白/相对一律拒绝,绝不回落 '.' 或 process.cwd()),
|
|
119
|
+
* 按宿主原值解析(trim 只判全空白、绝不归一化路径),已存在、可 realpath、是目录,且不含 .git/node_modules 段;
|
|
120
|
+
* **拒绝符号链接**(防止「跟随 symlink 写到 host 未授权目录」——realpath 会解析 symlink,所以必须在 realpath 之前用 lstat 显式拒) */
|
|
121
|
+
async function resolveWritableDir(targetDir) {
|
|
122
|
+
if (typeof targetDir !== 'string' || targetDir.trim() === '') {
|
|
123
|
+
return { error: 'target_dir 缺失:拒绝在未知目录写产物', hint: '本工具必须有宿主显式给出的绝对目录,不做任何猜测性回落' };
|
|
124
|
+
}
|
|
125
|
+
if (!isAbsolute(targetDir)) {
|
|
126
|
+
return { error: `target_dir 必须是绝对路径:${targetDir}`, hint: '相对路径会随进程工作目录漂移,拒绝写入' };
|
|
127
|
+
}
|
|
128
|
+
// lstat 在 symlink 上返回 isSymbolicLink()=true 而非跟随;realpath 之前的这层检查是关键:
|
|
129
|
+
// 允许存在目录,但拒绝把 symlink 静默重定向到别处
|
|
130
|
+
const lst = await lstat(targetDir).catch(() => null);
|
|
131
|
+
if (!lst)
|
|
132
|
+
return { error: `target_dir 不存在或无法访问:${targetDir}`, hint: '本工具只在真实存在的目录里写 bundle' };
|
|
133
|
+
if (lst.isSymbolicLink()) {
|
|
134
|
+
return { error: `target_dir 是符号链接,拒绝跟随写入:${targetDir}`, hint: '宿主给出真实目录路径,不要用 symlink 指向其他目录(本工具拒绝跟随)' };
|
|
135
|
+
}
|
|
136
|
+
const canonical = await realpath(targetDir).catch(() => null);
|
|
137
|
+
if (!canonical)
|
|
138
|
+
return { error: `target_dir 无法解析:${targetDir}` };
|
|
139
|
+
if (hasDeniedSegment(canonical)) {
|
|
140
|
+
return { error: 'target_dir 位于受限段(.git/node_modules)内,拒绝写入', hint: `解析后:${canonical}` };
|
|
141
|
+
}
|
|
142
|
+
const st = await stat(canonical).catch(() => null);
|
|
143
|
+
if (!st?.isDirectory())
|
|
144
|
+
return { error: `target_dir 不是目录:${canonical}` };
|
|
145
|
+
return { dir: canonical };
|
|
146
|
+
}
|
|
147
|
+
/** bundle 命名规则:basename → 三件文件名(<basename>.html / <basename>.manifest.json / <basename>.qr.svg) */
|
|
148
|
+
function bundleFileNames(basename) {
|
|
149
|
+
return {
|
|
150
|
+
html: `${basename}${ITINERARY_DECK_EXPORT_HTML_SUFFIX}`,
|
|
151
|
+
manifest: `${basename}${ITINERARY_DECK_EXPORT_MANIFEST_SUFFIX}`,
|
|
152
|
+
qr: `${basename}${ITINERARY_DECK_EXPORT_QR_SUFFIX}`,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
/** 预检:bundle 三件文件必须全部尚未存在 —— 任一存在则整体拒绝(零字节) */
|
|
156
|
+
async function assertBundleSlot(dir, names) {
|
|
157
|
+
for (const n of [names.html, names.manifest, names.qr]) {
|
|
158
|
+
try {
|
|
159
|
+
const st = await stat(join(dir, n));
|
|
160
|
+
if (st.isFile())
|
|
161
|
+
return { error: `bundle 文件已存在,拒绝覆盖:${n}`, hint: '换一个 basename 或清空目标目录;本工具永不覆盖既有 bundle' };
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
if (err?.code !== 'ENOENT') {
|
|
165
|
+
return { error: `无法访问 bundle 文件:${fsErrorText(err)}`, hint: `目标目录:${dir}` };
|
|
166
|
+
}
|
|
167
|
+
// ENOENT 是预期的(slot 干净)
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return { ok: true };
|
|
171
|
+
}
|
|
172
|
+
/** 独占创建:wx(O_CREAT|O_EXCL)既拒绝覆盖既有文件,也拒绝落在指向别处的符号链接上 */
|
|
173
|
+
async function writeExclusive(path, body) {
|
|
174
|
+
const bytes = Buffer.byteLength(body, 'utf8');
|
|
175
|
+
let handle;
|
|
176
|
+
try {
|
|
177
|
+
handle = await open(path, 'wx', 0o644);
|
|
178
|
+
}
|
|
179
|
+
catch (err) {
|
|
180
|
+
if (err?.code === 'EEXIST') {
|
|
181
|
+
return { error: `bundle 文件已存在,拒绝覆盖:${path}` };
|
|
182
|
+
}
|
|
183
|
+
return { error: `无法在 target_dir 新建 bundle 文件:${fsErrorText(err)}`, hint: `目标路径:${path}` };
|
|
184
|
+
}
|
|
185
|
+
try {
|
|
186
|
+
await handle.writeFile(body, 'utf-8');
|
|
187
|
+
}
|
|
188
|
+
catch (err) {
|
|
189
|
+
await handle.close().catch(() => { });
|
|
190
|
+
return { error: `写入 bundle 文件失败:${fsErrorText(err)}`, hint: `目标文件:${path}` };
|
|
191
|
+
}
|
|
192
|
+
await handle.close();
|
|
193
|
+
return { bytes };
|
|
194
|
+
}
|
|
195
|
+
/** 构造 manifest:v1 schema,记录 deck 字节/sha256、事实计数 + 来源标签、证据链分布、target_url、local_only、share_intent。
|
|
196
|
+
* local_only 是 #569 的显式指示字段(v1 兼容附加字段,不改 schema 名):无 target_url 时为 true——
|
|
197
|
+
* 消费方据此读出「本地 bundle,无线上目的地」,绝不靠 target_url 字段缺失来暗示。 */
|
|
198
|
+
function buildManifest(basename, facts, exportedAt, targetUrl) {
|
|
199
|
+
const byKind = { flight: 0, train: 0, hotel: 0, policy: 0 };
|
|
200
|
+
const sourceTags = [];
|
|
201
|
+
const byTier = {};
|
|
202
|
+
const byBookability = {};
|
|
203
|
+
let unverified = 0;
|
|
204
|
+
const seenTags = new Set();
|
|
205
|
+
for (const f of facts) {
|
|
206
|
+
byKind[f.kind] = (byKind[f.kind] ?? 0) + 1;
|
|
207
|
+
const tag = `[${f.source}]`;
|
|
208
|
+
if (!seenTags.has(tag)) {
|
|
209
|
+
seenTags.add(tag);
|
|
210
|
+
sourceTags.push(tag);
|
|
211
|
+
}
|
|
212
|
+
// policy 事实无 tier/bookability(tier/bookability 只描述「可下单」语义);按 kind 区分聚合
|
|
213
|
+
if (f.kind !== 'policy') {
|
|
214
|
+
byTier[f.tier] = (byTier[f.tier] ?? 0) + 1;
|
|
215
|
+
byBookability[f.bookability] = (byBookability[f.bookability] ?? 0) + 1;
|
|
216
|
+
if (f.bookability === 'unverified')
|
|
217
|
+
unverified += 1;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return {
|
|
221
|
+
schema: 'gotry_deck_manifest.v1',
|
|
222
|
+
exported_at: exportedAt.toISOString(),
|
|
223
|
+
deck: { basename: `${basename}${ITINERARY_DECK_EXPORT_HTML_SUFFIX}`, sha256: '', bytes: 0 },
|
|
224
|
+
facts: { total: facts.length, by_kind: byKind, source_tags: sourceTags.slice(0, SOURCE_TAG_SAMPLE) },
|
|
225
|
+
evidence_chain: { unverified, by_tier: byTier, by_bookability: byBookability },
|
|
226
|
+
target_url: targetUrl,
|
|
227
|
+
local_only: targetUrl === undefined,
|
|
228
|
+
share_intent: { qr: 'generated', qr_path: `${basename}${ITINERARY_DECK_EXPORT_QR_SUFFIX}` },
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
/** sha256 + bytes 在 manifest 写盘前用真实 html 填回,避免 hash of empty buffer 的占位 */
|
|
232
|
+
function stampManifest(manifest, html) {
|
|
233
|
+
const sha256 = createHash('sha256').update(Buffer.from(html, 'utf8')).digest('hex');
|
|
234
|
+
const bytes = Buffer.byteLength(html, 'utf8');
|
|
235
|
+
const deck = manifest.deck;
|
|
236
|
+
return { ...manifest, deck: { ...deck, sha256, bytes } };
|
|
237
|
+
}
|
|
238
|
+
/** qr.svg 真矩阵编码(issue #569,Phase B 切片 3b):用 npm `qrcode` 库直接渲染 SVG,
|
|
239
|
+
* 编码 target_url;无 target_url 时编码字面标记 ITINERARY_DECK_EXPORT_LOCAL_MARKER
|
|
240
|
+
* (扫码得到一段说明文本而非死链;manifest.target_url 同时缺省、manifest.local_only=true,
|
|
241
|
+
* 消费方据 manifest 字段判断是否 hosted,不靠扫码内容)。
|
|
242
|
+
* error correction level 默认 M(15% 冗余,适合带 logo / 抗打印 / 二维码扫描容错);
|
|
243
|
+
* margin=2(ISO 标准 4 模块静默区中的 2——可扫描 + 视觉紧凑;#569 T2 验收:payload ×
|
|
244
|
+
* 128/240/480px 全矩阵经独立解码链还原精确 payload,无证据要求调整)。
|
|
245
|
+
* SVG 是自包含 XML,可在任意现代浏览器/扫码 app 直接渲染。 */
|
|
246
|
+
async function qrSvgFor(payload) {
|
|
247
|
+
return QRCode.toString(payload, {
|
|
248
|
+
type: 'svg',
|
|
249
|
+
errorCorrectionLevel: 'M',
|
|
250
|
+
margin: 2,
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* 生成一份 deck 静态导出 bundle。写入唯一目标 = target_dir 顶层三个文件;
|
|
255
|
+
* 事实唯一来源 = deps.stateRoot 的事实注册表;basename 走 ASCII 契约。
|
|
256
|
+
*/
|
|
257
|
+
export async function generateItineraryDeckExport(input, deps) {
|
|
258
|
+
if (!isRecord(input))
|
|
259
|
+
return { ok: false, error: 'input 必须是对象 {title, itinerary, fact_ids, target_dir?, target_url?, basename?}' };
|
|
260
|
+
const ids = takeFactIds(input.fact_ids);
|
|
261
|
+
if ('error' in ids)
|
|
262
|
+
return { ok: false, error: ids.error, hint: ids.hint };
|
|
263
|
+
const named = takeBasename(input.basename);
|
|
264
|
+
if ('error' in named)
|
|
265
|
+
return { ok: false, error: named.error, hint: named.hint };
|
|
266
|
+
const url = takeTargetUrl(input.target_url);
|
|
267
|
+
if ('error' in url)
|
|
268
|
+
return { ok: false, error: url.error };
|
|
269
|
+
const registry = await loadFactRegistry(deps.stateRoot);
|
|
270
|
+
const byId = new Map(registry.map(f => [f.fact_id, f]));
|
|
271
|
+
const missing = ids.ids.filter(id => !byId.has(id));
|
|
272
|
+
if (missing.length > 0) {
|
|
273
|
+
return {
|
|
274
|
+
ok: false,
|
|
275
|
+
error: `事实 id 未在当前注册表:${missing.slice(0, ID_SAMPLE).join('、')}${missing.length > ID_SAMPLE ? ` 等 ${missing.length} 条` : ''}`,
|
|
276
|
+
hint: 'fact_ids 只能取自本会话 exact-date 工具结果的注册表;不接受调用方自带事实对象,也不从 Markdown 猜事实',
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
// 顺序保留调用方选择;登记行畸形不在选择阶段放宽——交给 deck 渲染器运行时校验显式拒绝
|
|
280
|
+
const selected = ids.ids.map(id => byId.get(id));
|
|
281
|
+
const rendered = renderItineraryDeck({ title: input.title, itinerary: input.itinerary, facts: selected });
|
|
282
|
+
if (!rendered.ok) {
|
|
283
|
+
return {
|
|
284
|
+
ok: false,
|
|
285
|
+
error: '渲染被拒:行程或事实不满足渲染契约,未写入任何文件',
|
|
286
|
+
errors: rendered.errors,
|
|
287
|
+
hint: '按 errors 修正显式行程结构或换用合法登记的事实;本工具不会静默截断核心行程',
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
const dir = await resolveWritableDir(deps.targetDir);
|
|
291
|
+
if ('error' in dir)
|
|
292
|
+
return { ok: false, error: dir.error, hint: dir.hint };
|
|
293
|
+
const files = bundleFileNames(named.basename);
|
|
294
|
+
const slot = await assertBundleSlot(dir.dir, files);
|
|
295
|
+
if ('error' in slot)
|
|
296
|
+
return { ok: false, error: slot.error, hint: slot.hint };
|
|
297
|
+
const exportedAt = (deps.now ?? (() => new Date()))();
|
|
298
|
+
const manifest = stampManifest(buildManifest(named.basename, selected, exportedAt, url.targetUrl), rendered.html);
|
|
299
|
+
// QR **先于任何写盘**生成(fail-fast 零写入):qrcode 库对超容量输入会 reject
|
|
300
|
+
// (QR v40-M 字节模式上限 2331 字节;2048 个 CJK 字符约 2409 字节即超),
|
|
301
|
+
// 若先生成 HTML/manifest 再遇 QR reject 会留下半成品 bundle 且重试撞 EEXIST。
|
|
302
|
+
const qrTarget = url.targetUrl && url.targetUrl.length > 0
|
|
303
|
+
? url.targetUrl
|
|
304
|
+
: ITINERARY_DECK_EXPORT_LOCAL_MARKER;
|
|
305
|
+
let qrSvg;
|
|
306
|
+
try {
|
|
307
|
+
qrSvg = await qrSvgFor(qrTarget);
|
|
308
|
+
}
|
|
309
|
+
catch (err) {
|
|
310
|
+
return {
|
|
311
|
+
ok: false,
|
|
312
|
+
error: `QR 编码失败(未写入任何文件):${err?.message ?? String(err)}`,
|
|
313
|
+
hint: `target_url 过长(QR v40-M 字节模式上限约 2331 字节;实测 UTF-8 ${Buffer.byteLength(qrTarget, 'utf8')} 字节)——缩短 target_url 后重试`,
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
// 写盘顺序:HTML → manifest(含 sha256 已填)→ qr.svg(已在上方预生成)
|
|
317
|
+
const htmlPath = join(dir.dir, files.html);
|
|
318
|
+
const manifestPath = join(dir.dir, files.manifest);
|
|
319
|
+
const qrPath = join(dir.dir, files.qr);
|
|
320
|
+
const writtenHtml = await writeExclusive(htmlPath, rendered.html);
|
|
321
|
+
if ('error' in writtenHtml)
|
|
322
|
+
return { ok: false, error: writtenHtml.error, hint: writtenHtml.hint };
|
|
323
|
+
const writtenManifest = await writeExclusive(manifestPath, JSON.stringify(manifest, null, 2));
|
|
324
|
+
if ('error' in writtenManifest)
|
|
325
|
+
return { ok: false, error: writtenManifest.error, hint: writtenManifest.hint };
|
|
326
|
+
const writtenQr = await writeExclusive(qrPath, qrSvg);
|
|
327
|
+
if ('error' in writtenQr)
|
|
328
|
+
return { ok: false, error: writtenQr.error, hint: writtenQr.hint };
|
|
329
|
+
const totalBytes = writtenHtml.bytes + writtenManifest.bytes + writtenQr.bytes;
|
|
330
|
+
return {
|
|
331
|
+
ok: true,
|
|
332
|
+
target_dir: dir.dir,
|
|
333
|
+
basename: named.basename,
|
|
334
|
+
files: { html: htmlPath, manifest: manifestPath, qr: qrPath },
|
|
335
|
+
bytes: totalBytes,
|
|
336
|
+
fact_ids: ids.ids,
|
|
337
|
+
overall_verified: false,
|
|
338
|
+
};
|
|
339
|
+
}
|