@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,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-http-proxy 本地 SSE + 中毒 HTTP 代理反例(issue #268):启动回环 SSE 服务器和
|
|
3
|
+
* 统计命中次数的中毒代理,用公共 installProxyFromEnvironment API 安装代理策略,
|
|
4
|
+
* 将 HTTP(S)_PROXY 指向中毒代理。在 127.0.0.1 上获取 SSE 端点,断言负载成功且
|
|
5
|
+
* 中毒命中计数保持为零;同时断言 proxyRouteFor(loopback) 是直接的,非回环 URL
|
|
6
|
+
* 被分类为代理,且 proxyEnvironmentForChild() 携带回环 NO_PROXY 以及 Node 24 下的
|
|
7
|
+
* NODE_USE_ENV_PROXY。始终 await 返回的 disposer 并在 finally 中关闭两个服务器;
|
|
8
|
+
* 证明全局路由返回到先前的直接状态。
|
|
9
|
+
*
|
|
10
|
+
* 运行:cd ts && npx tsx scripts/dsh-http-proxy-sse-proof.ts
|
|
11
|
+
*/
|
|
12
|
+
import assert from 'node:assert/strict';
|
|
13
|
+
import http from 'node:http';
|
|
14
|
+
import { installProxyFromEnvironment, proxyRouteFor, proxyEnvironmentForChild } from '@deepseek-ai/dsh-http-proxy';
|
|
15
|
+
// 1. 回环 SSE 服务器。
|
|
16
|
+
const sseServer = http.createServer((req, res) => {
|
|
17
|
+
res.writeHead(200, {
|
|
18
|
+
'Content-Type': 'text/event-stream',
|
|
19
|
+
'Cache-Control': 'no-cache',
|
|
20
|
+
Connection: 'keep-alive',
|
|
21
|
+
});
|
|
22
|
+
res.write('data: hello-sse\n\n');
|
|
23
|
+
res.end();
|
|
24
|
+
});
|
|
25
|
+
await new Promise((resolve) => sseServer.listen(0, '127.0.0.1', resolve));
|
|
26
|
+
const sseAddr = sseServer.address();
|
|
27
|
+
assert.ok(sseAddr !== null && typeof sseAddr === 'object', 'SSE 服务器必须已绑定地址');
|
|
28
|
+
const ssePort = sseAddr.port;
|
|
29
|
+
const sseUrl = `http://127.0.0.1:${ssePort}/`;
|
|
30
|
+
// 2. 中毒代理:统计命中次数,返回 502。
|
|
31
|
+
let poisonHits = 0;
|
|
32
|
+
const poisonServer = http.createServer((req, res) => {
|
|
33
|
+
poisonHits++;
|
|
34
|
+
res.writeHead(502);
|
|
35
|
+
res.end('poisoned');
|
|
36
|
+
});
|
|
37
|
+
await new Promise((resolve) => poisonServer.listen(0, '127.0.0.1', resolve));
|
|
38
|
+
const poisonAddr = poisonServer.address();
|
|
39
|
+
assert.ok(poisonAddr !== null && typeof poisonAddr === 'object', '中毒代理必须已绑定地址');
|
|
40
|
+
const poisonPort = poisonAddr.port;
|
|
41
|
+
let disposer;
|
|
42
|
+
try {
|
|
43
|
+
// 3. 用公共 installProxyFromEnvironment API 安装代理策略,指向中毒代理。
|
|
44
|
+
const envMap = new Map([
|
|
45
|
+
['HTTP_PROXY', `http://127.0.0.1:${poisonPort}`],
|
|
46
|
+
['HTTPS_PROXY', `http://127.0.0.1:${poisonPort}`],
|
|
47
|
+
]);
|
|
48
|
+
const envLookup = {
|
|
49
|
+
get(name) {
|
|
50
|
+
const v = envMap.get(name) ?? envMap.get(name.toLowerCase());
|
|
51
|
+
return v !== undefined ? { value: v } : undefined;
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
disposer = await installProxyFromEnvironment(envLookup, () => { });
|
|
55
|
+
// 4. proxyRouteFor(loopback) 是直接的;非回环 URL 被分类为代理。
|
|
56
|
+
const loopbackRoute = proxyRouteFor(new URL(sseUrl));
|
|
57
|
+
assert.equal(loopbackRoute.proxied, false, '回环 URL 必须路由为直接(proxyRouteFor)');
|
|
58
|
+
const externalRoute = proxyRouteFor(new URL('http://example.com/'));
|
|
59
|
+
assert.equal(externalRoute.proxied, true, '非回环 URL 必须被分类为代理(proxyRouteFor)');
|
|
60
|
+
// 5. proxyEnvironmentForChild() 携带回环 NO_PROXY 以及 Node 24 下的 NODE_USE_ENV_PROXY。
|
|
61
|
+
const childEnv = proxyEnvironmentForChild();
|
|
62
|
+
assert.equal(childEnv.NODE_USE_ENV_PROXY, '1', 'proxyEnvironmentForChild 必须携带 NODE_USE_ENV_PROXY=1(Node 24)');
|
|
63
|
+
assert.ok(typeof childEnv.NO_PROXY === 'string' && childEnv.NO_PROXY.includes('127.0.0.1'), `proxyEnvironmentForChild NO_PROXY 必须包含 127.0.0.1(当前 ${JSON.stringify(childEnv.NO_PROXY)})`);
|
|
64
|
+
// 6. 在 127.0.0.1 上获取 SSE 端点:负载成功且中毒命中计数保持为零。
|
|
65
|
+
const resp = await fetch(sseUrl);
|
|
66
|
+
assert.equal(resp.status, 200, `SSE fetch 必须成功(status=${resp.status})`);
|
|
67
|
+
const body = await resp.text();
|
|
68
|
+
assert.ok(body.includes('hello-sse'), `SSE 负载必须包含 hello-sse(当前 ${JSON.stringify(body)})`);
|
|
69
|
+
assert.equal(poisonHits, 0, `中毒代理命中计数必须为零(当前 ${poisonHits})——回环绕过代理`);
|
|
70
|
+
}
|
|
71
|
+
finally {
|
|
72
|
+
// 7. 始终 await 返回的 disposer 并在 finally 中 await 关闭两个服务器(包括失败路径)。
|
|
73
|
+
// 不依赖未 await 的 server.close() 让进程退出——显式 await 完成资源清理。
|
|
74
|
+
try {
|
|
75
|
+
if (disposer)
|
|
76
|
+
await disposer();
|
|
77
|
+
}
|
|
78
|
+
finally {
|
|
79
|
+
await Promise.all([
|
|
80
|
+
new Promise((resolve, reject) => sseServer.close((err) => (err ? reject(err) : resolve()))),
|
|
81
|
+
new Promise((resolve, reject) => poisonServer.close((err) => (err ? reject(err) : resolve()))),
|
|
82
|
+
]);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// 8. 证明全局路由返回到先前的直接状态。
|
|
86
|
+
const externalAfter = proxyRouteFor(new URL('http://example.com/'));
|
|
87
|
+
assert.equal(externalAfter.proxied, false, 'disposer 后全局路由必须返回直接状态');
|
|
88
|
+
console.log(`HTTP PROXY SSE PROOF: loopback SSE fetch=200 payload-has-hello-sse=true poison-hits=0, ` +
|
|
89
|
+
`loopback route=direct external route=proxied, NODE_USE_ENV_PROXY=1 NO_PROXY has 127.0.0.1, ` +
|
|
90
|
+
`routing restored to direct after dispose`);
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import test from 'node:test';
|
|
3
|
+
import { parsePnpmDshLock, parsePnpmRootDshImporter, REQUIRED_DSH_RUNTIME_PACKAGE_COUNT, validateDshRuntimeClosure, validatePnpmRootDshImporter, } from './dsh-runtime-closure.js';
|
|
4
|
+
const VERSION = '0.2.0-rc.2';
|
|
5
|
+
function validInput() {
|
|
6
|
+
return {
|
|
7
|
+
dependencies: {
|
|
8
|
+
'@deepseek-ai/dsh': VERSION,
|
|
9
|
+
'@deepseek-ai/dsh-session-title': VERSION,
|
|
10
|
+
},
|
|
11
|
+
lockPackages: {
|
|
12
|
+
'node_modules/@deepseek-ai/dsh': { version: VERSION },
|
|
13
|
+
'node_modules/@deepseek-ai/dsh-session-title': { version: VERSION },
|
|
14
|
+
},
|
|
15
|
+
runtimeVersion: VERSION,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
test('accepts an exact coherent DSH prerelease closure', () => {
|
|
19
|
+
assert.deepEqual(validateDshRuntimeClosure(validInput()), {
|
|
20
|
+
names: ['@deepseek-ai/dsh', '@deepseek-ai/dsh-session-title'],
|
|
21
|
+
version: VERSION,
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
test('rejects a lock package missing from the published direct dependencies', () => {
|
|
25
|
+
const input = validInput();
|
|
26
|
+
input.dependencies = { '@deepseek-ai/dsh': VERSION };
|
|
27
|
+
assert.throws(() => validateDshRuntimeClosure(input), /DSH closure 未精确声明/);
|
|
28
|
+
});
|
|
29
|
+
test('rejects an extra ranged DSH dependency absent from the tested lock closure', () => {
|
|
30
|
+
const input = validInput();
|
|
31
|
+
input.dependencies['@deepseek-ai/dsh-web'] = '^0.2.0-rc.2';
|
|
32
|
+
assert.throws(() => validateDshRuntimeClosure(input), /DSH manifest 与 lock 集合不一致/);
|
|
33
|
+
});
|
|
34
|
+
test('rejects a nested DSH package from another prerelease', () => {
|
|
35
|
+
const input = validInput();
|
|
36
|
+
input.lockPackages['node_modules/@deepseek-ai/dsh/node_modules/@deepseek-ai/dsh-session-title'] = {
|
|
37
|
+
version: '0.1.5-alpha.2',
|
|
38
|
+
};
|
|
39
|
+
assert.throws(() => validateDshRuntimeClosure(input), /DSH lock 版本漂移/);
|
|
40
|
+
});
|
|
41
|
+
test('rejects drift from the runtime spawn guard version', () => {
|
|
42
|
+
const input = validInput();
|
|
43
|
+
input.runtimeVersion = '0.1.5-alpha.2';
|
|
44
|
+
assert.throws(() => validateDshRuntimeClosure(input), /DSH runtime guard 版本漂移/);
|
|
45
|
+
});
|
|
46
|
+
test('parses each pnpm DSH resolution once across packages and snapshots', () => {
|
|
47
|
+
const lock = `
|
|
48
|
+
packages:
|
|
49
|
+
'@deepseek-ai/dsh@0.2.0-rc.2': {}
|
|
50
|
+
'@deepseek-ai/dsh-session@0.2.0-rc.2': {}
|
|
51
|
+
snapshots:
|
|
52
|
+
'@deepseek-ai/dsh@0.2.0-rc.2': {}
|
|
53
|
+
`;
|
|
54
|
+
assert.deepEqual(parsePnpmDshLock(lock), {
|
|
55
|
+
'node_modules/@deepseek-ai/dsh': { version: VERSION },
|
|
56
|
+
'node_modules/@deepseek-ai/dsh-session': { version: VERSION },
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
test('preserves two pnpm resolutions of the same DSH package for mixed-version rejection', () => {
|
|
60
|
+
const lock = `
|
|
61
|
+
packages:
|
|
62
|
+
'@deepseek-ai/dsh@0.2.0-rc.2': {}
|
|
63
|
+
'@deepseek-ai/dsh-session@0.2.0-rc.2': {}
|
|
64
|
+
'@deepseek-ai/dsh-session@0.1.5-alpha.2': {}
|
|
65
|
+
`;
|
|
66
|
+
const parsed = parsePnpmDshLock(lock);
|
|
67
|
+
assert.equal(Object.keys(parsed).length, 3);
|
|
68
|
+
assert.throws(() => validateDshRuntimeClosure({
|
|
69
|
+
dependencies: {
|
|
70
|
+
'@deepseek-ai/dsh': VERSION,
|
|
71
|
+
'@deepseek-ai/dsh-session': VERSION,
|
|
72
|
+
},
|
|
73
|
+
lockPackages: parsed,
|
|
74
|
+
runtimeVersion: VERSION,
|
|
75
|
+
}), /DSH lock 版本漂移/);
|
|
76
|
+
});
|
|
77
|
+
test('parses only the root pnpm importer DSH entries', () => {
|
|
78
|
+
const lock = `
|
|
79
|
+
lockfileVersion: '9.0'
|
|
80
|
+
importers:
|
|
81
|
+
.:
|
|
82
|
+
dependencies:
|
|
83
|
+
'@deepseek-ai/dsh':
|
|
84
|
+
specifier: 0.2.0-rc.2
|
|
85
|
+
version: 0.2.0-rc.2(peer@1.0.0)
|
|
86
|
+
'@deepseek-ai/dsh-session':
|
|
87
|
+
specifier: 0.2.0-rc.2
|
|
88
|
+
version: 0.2.0-rc.2
|
|
89
|
+
ts:
|
|
90
|
+
dependencies:
|
|
91
|
+
'@deepseek-ai/dsh-web':
|
|
92
|
+
specifier: 0.1.5-alpha.2
|
|
93
|
+
version: 0.1.5-alpha.2
|
|
94
|
+
packages: {}
|
|
95
|
+
`;
|
|
96
|
+
assert.deepEqual(parsePnpmRootDshImporter(lock), {
|
|
97
|
+
'@deepseek-ai/dsh': { specifier: VERSION, resolvedVersion: VERSION },
|
|
98
|
+
'@deepseek-ai/dsh-session': { specifier: VERSION, resolvedVersion: VERSION },
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
test('rejects a pnpm root importer missing a published DSH dependency', () => {
|
|
102
|
+
assert.throws(() => validatePnpmRootDshImporter({
|
|
103
|
+
dependencies: validInput().dependencies,
|
|
104
|
+
importerEntries: {
|
|
105
|
+
'@deepseek-ai/dsh': { specifier: VERSION, resolvedVersion: VERSION },
|
|
106
|
+
},
|
|
107
|
+
runtimeVersion: VERSION,
|
|
108
|
+
}), /pnpm root importer 与 manifest 集合不一致/);
|
|
109
|
+
});
|
|
110
|
+
test('rejects a ranged DSH specifier in the pnpm root importer', () => {
|
|
111
|
+
assert.throws(() => validatePnpmRootDshImporter({
|
|
112
|
+
dependencies: validInput().dependencies,
|
|
113
|
+
importerEntries: {
|
|
114
|
+
'@deepseek-ai/dsh': { specifier: VERSION, resolvedVersion: VERSION },
|
|
115
|
+
'@deepseek-ai/dsh-session-title': { specifier: '^0.2.0-rc.2', resolvedVersion: VERSION },
|
|
116
|
+
},
|
|
117
|
+
runtimeVersion: VERSION,
|
|
118
|
+
}), /pnpm root importer 未精确锁定/);
|
|
119
|
+
});
|
|
120
|
+
test('rejects a drifted resolved DSH version in the pnpm root importer', () => {
|
|
121
|
+
assert.throws(() => validatePnpmRootDshImporter({
|
|
122
|
+
dependencies: validInput().dependencies,
|
|
123
|
+
importerEntries: {
|
|
124
|
+
'@deepseek-ai/dsh': { specifier: VERSION, resolvedVersion: '0.1.5-alpha.2' },
|
|
125
|
+
'@deepseek-ai/dsh-session-title': { specifier: VERSION, resolvedVersion: VERSION },
|
|
126
|
+
},
|
|
127
|
+
runtimeVersion: VERSION,
|
|
128
|
+
}), /pnpm root importer resolved 版本漂移/);
|
|
129
|
+
});
|
|
130
|
+
test('rejects a missing resolved DSH version in the pnpm root importer', () => {
|
|
131
|
+
const lock = `
|
|
132
|
+
importers:
|
|
133
|
+
.:
|
|
134
|
+
dependencies:
|
|
135
|
+
'@deepseek-ai/dsh':
|
|
136
|
+
specifier: 0.2.0-rc.2
|
|
137
|
+
`;
|
|
138
|
+
assert.throws(() => parsePnpmRootDshImporter(lock), /pnpm root importer version 不可用/);
|
|
139
|
+
});
|
|
140
|
+
test('rejects duplicate resolved DSH versions in the pnpm root importer', () => {
|
|
141
|
+
const lock = `
|
|
142
|
+
importers:
|
|
143
|
+
.:
|
|
144
|
+
dependencies:
|
|
145
|
+
'@deepseek-ai/dsh':
|
|
146
|
+
specifier: 0.2.0-rc.2
|
|
147
|
+
version: 0.2.0-rc.2
|
|
148
|
+
version: 0.1.5-alpha.2
|
|
149
|
+
`;
|
|
150
|
+
assert.throws(() => parsePnpmRootDshImporter(lock), /pnpm root importer version 不可用/);
|
|
151
|
+
});
|
|
152
|
+
test('rejects a coherent closure below the required package count', () => {
|
|
153
|
+
assert.throws(() => validateDshRuntimeClosure({
|
|
154
|
+
...validInput(),
|
|
155
|
+
expectedPackageCount: REQUIRED_DSH_RUNTIME_PACKAGE_COUNT,
|
|
156
|
+
}), /DSH closure 包数量不符/);
|
|
157
|
+
});
|
|
158
|
+
test('rejects a coherent root importer below the required package count', () => {
|
|
159
|
+
assert.throws(() => validatePnpmRootDshImporter({
|
|
160
|
+
dependencies: validInput().dependencies,
|
|
161
|
+
importerEntries: {
|
|
162
|
+
'@deepseek-ai/dsh': { specifier: VERSION, resolvedVersion: VERSION },
|
|
163
|
+
'@deepseek-ai/dsh-session-title': { specifier: VERSION, resolvedVersion: VERSION },
|
|
164
|
+
},
|
|
165
|
+
runtimeVersion: VERSION,
|
|
166
|
+
expectedPackageCount: REQUIRED_DSH_RUNTIME_PACKAGE_COUNT,
|
|
167
|
+
}), /pnpm root importer 包数量不符/);
|
|
168
|
+
});
|
|
169
|
+
test('rejects duplicate DSH entries in the pnpm root importer', () => {
|
|
170
|
+
const lock = `
|
|
171
|
+
importers:
|
|
172
|
+
.:
|
|
173
|
+
dependencies:
|
|
174
|
+
'@deepseek-ai/dsh':
|
|
175
|
+
specifier: 0.2.0-rc.2
|
|
176
|
+
version: 0.2.0-rc.2
|
|
177
|
+
'@deepseek-ai/dsh':
|
|
178
|
+
specifier: 0.2.0-rc.2
|
|
179
|
+
version: 0.2.0-rc.2
|
|
180
|
+
`;
|
|
181
|
+
assert.throws(() => parsePnpmRootDshImporter(lock), /pnpm root importer DSH 依赖重复/);
|
|
182
|
+
});
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
export const REQUIRED_DSH_RUNTIME_PACKAGE_COUNT = 279;
|
|
2
|
+
function yamlScalar(value) {
|
|
3
|
+
const trimmed = value.trim().replace(/\s+#.*$/, '');
|
|
4
|
+
const quoted = trimmed.match(/^(['"])(.*)\1$/);
|
|
5
|
+
return quoted?.[2] ?? trimmed;
|
|
6
|
+
}
|
|
7
|
+
function indentation(line) {
|
|
8
|
+
return line.match(/^ */)?.[0].length ?? 0;
|
|
9
|
+
}
|
|
10
|
+
function resolvedPnpmVersion(value) {
|
|
11
|
+
return yamlScalar(value).replace(/\(.+$/, '');
|
|
12
|
+
}
|
|
13
|
+
export function parsePnpmRootDshImporter(text) {
|
|
14
|
+
const lines = text.split(/\r?\n/);
|
|
15
|
+
const importers = lines
|
|
16
|
+
.map((line, index) => line === 'importers:' ? index : -1)
|
|
17
|
+
.filter((index) => index >= 0);
|
|
18
|
+
if (importers.length !== 1)
|
|
19
|
+
throw new Error('pnpm lock importers 区块不可用');
|
|
20
|
+
const importersStart = importers[0];
|
|
21
|
+
const importersEnd = lines.findIndex((line, index) => index > importersStart && line.trim() !== '' && indentation(line) === 0);
|
|
22
|
+
const rootCandidates = lines
|
|
23
|
+
.map((line, index) => index > importersStart && (importersEnd < 0 || index < importersEnd)
|
|
24
|
+
&& /^ {2}(?:\.|'\.'|"\."):\s*$/.test(line) ? index : -1)
|
|
25
|
+
.filter((index) => index >= 0);
|
|
26
|
+
if (rootCandidates.length !== 1)
|
|
27
|
+
throw new Error('pnpm root importer 不唯一');
|
|
28
|
+
const rootStart = rootCandidates[0];
|
|
29
|
+
const rootEndRelative = lines.slice(rootStart + 1, importersEnd < 0 ? lines.length : importersEnd)
|
|
30
|
+
.findIndex((line) => line.trim() !== '' && indentation(line) <= 2);
|
|
31
|
+
const rootEnd = rootEndRelative < 0
|
|
32
|
+
? (importersEnd < 0 ? lines.length : importersEnd)
|
|
33
|
+
: rootStart + 1 + rootEndRelative;
|
|
34
|
+
const dependencyBlocks = lines
|
|
35
|
+
.map((line, index) => index > rootStart && index < rootEnd && /^ {4}dependencies:\s*$/.test(line) ? index : -1)
|
|
36
|
+
.filter((index) => index >= 0);
|
|
37
|
+
if (dependencyBlocks.length !== 1)
|
|
38
|
+
throw new Error('pnpm root importer dependencies 区块不可用');
|
|
39
|
+
const dependenciesStart = dependencyBlocks[0];
|
|
40
|
+
const dependenciesEndRelative = lines.slice(dependenciesStart + 1, rootEnd)
|
|
41
|
+
.findIndex((line) => line.trim() !== '' && indentation(line) <= 4);
|
|
42
|
+
const dependenciesEnd = dependenciesEndRelative < 0 ? rootEnd : dependenciesStart + 1 + dependenciesEndRelative;
|
|
43
|
+
const entries = lines
|
|
44
|
+
.map((line, index) => {
|
|
45
|
+
if (index <= dependenciesStart || index >= dependenciesEnd)
|
|
46
|
+
return null;
|
|
47
|
+
const match = line.match(/^ {6}(['"]?)([^'":\s]+)\1:\s*$/);
|
|
48
|
+
return match ? { index, name: match[2] } : null;
|
|
49
|
+
})
|
|
50
|
+
.filter((entry) => entry !== null);
|
|
51
|
+
const importerEntries = {};
|
|
52
|
+
for (let entryIndex = 0; entryIndex < entries.length; entryIndex += 1) {
|
|
53
|
+
const entry = entries[entryIndex];
|
|
54
|
+
if (entry.name !== '@deepseek-ai/dsh' && !entry.name.startsWith('@deepseek-ai/dsh-'))
|
|
55
|
+
continue;
|
|
56
|
+
if (Object.hasOwn(importerEntries, entry.name))
|
|
57
|
+
throw new Error(`pnpm root importer DSH 依赖重复:${entry.name}`);
|
|
58
|
+
const end = entries[entryIndex + 1]?.index ?? dependenciesEnd;
|
|
59
|
+
const block = lines.slice(entry.index + 1, end);
|
|
60
|
+
const specifiers = block
|
|
61
|
+
.map((line) => line.match(/^ {8}specifier:\s*(.+)$/)?.[1])
|
|
62
|
+
.filter((value) => value !== undefined);
|
|
63
|
+
if (specifiers.length !== 1)
|
|
64
|
+
throw new Error(`pnpm root importer specifier 不可用:${entry.name}`);
|
|
65
|
+
const versions = block
|
|
66
|
+
.map((line) => line.match(/^ {8}version:\s*(.+)$/)?.[1])
|
|
67
|
+
.filter((value) => value !== undefined);
|
|
68
|
+
if (versions.length !== 1)
|
|
69
|
+
throw new Error(`pnpm root importer version 不可用:${entry.name}`);
|
|
70
|
+
importerEntries[entry.name] = {
|
|
71
|
+
specifier: yamlScalar(specifiers[0]),
|
|
72
|
+
resolvedVersion: resolvedPnpmVersion(versions[0]),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
return importerEntries;
|
|
76
|
+
}
|
|
77
|
+
export function validatePnpmRootDshImporter(input) {
|
|
78
|
+
const manifestNames = Object.keys(input.dependencies)
|
|
79
|
+
.filter((name) => name === '@deepseek-ai/dsh' || name.startsWith('@deepseek-ai/dsh-'))
|
|
80
|
+
.sort();
|
|
81
|
+
const importerNames = Object.keys(input.importerEntries).sort();
|
|
82
|
+
const missing = manifestNames.filter((name) => !importerNames.includes(name));
|
|
83
|
+
const extra = importerNames.filter((name) => !manifestNames.includes(name));
|
|
84
|
+
if (missing.length > 0 || extra.length > 0) {
|
|
85
|
+
throw new Error(`pnpm root importer 与 manifest 集合不一致:missing=${missing.join(',') || '-'};extra=${extra.join(',') || '-'}`);
|
|
86
|
+
}
|
|
87
|
+
for (const name of importerNames) {
|
|
88
|
+
const importerEntry = input.importerEntries[name];
|
|
89
|
+
if (input.dependencies[name] !== input.runtimeVersion || importerEntry.specifier !== input.runtimeVersion) {
|
|
90
|
+
throw new Error(`pnpm root importer 未精确锁定:${name}@${input.runtimeVersion}`);
|
|
91
|
+
}
|
|
92
|
+
if (importerEntry.resolvedVersion !== input.runtimeVersion) {
|
|
93
|
+
throw new Error(`pnpm root importer resolved 版本漂移:${name}@${importerEntry.resolvedVersion}(expected ${input.runtimeVersion})`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (input.expectedPackageCount !== undefined && importerNames.length !== input.expectedPackageCount) {
|
|
97
|
+
throw new Error(`pnpm root importer 包数量不符:${importerNames.length}(expected ${input.expectedPackageCount})`);
|
|
98
|
+
}
|
|
99
|
+
return { names: importerNames, version: input.runtimeVersion };
|
|
100
|
+
}
|
|
101
|
+
export function parsePnpmDshLock(text) {
|
|
102
|
+
const packages = {};
|
|
103
|
+
const seen = new Set();
|
|
104
|
+
const variants = new Map();
|
|
105
|
+
const entry = /^\s{2}['"]?(\@deepseek-ai\/dsh(?:-[^@'":\s]+)?)@([^'":\s(]+)(?:\([^'"]*\))?['"]?:/gm;
|
|
106
|
+
for (const match of text.matchAll(entry)) {
|
|
107
|
+
const name = match[1];
|
|
108
|
+
const version = match[2];
|
|
109
|
+
const identity = `${name}@${version}`;
|
|
110
|
+
if (seen.has(identity))
|
|
111
|
+
continue;
|
|
112
|
+
seen.add(identity);
|
|
113
|
+
const variant = variants.get(name) ?? 0;
|
|
114
|
+
variants.set(name, variant + 1);
|
|
115
|
+
const prefix = variant === 0 ? '' : `.pnpm-variant-${variant}/node_modules/`;
|
|
116
|
+
packages[`node_modules/${prefix}${name}`] = { version };
|
|
117
|
+
}
|
|
118
|
+
return packages;
|
|
119
|
+
}
|
|
120
|
+
export function validateDshRuntimeClosure(input) {
|
|
121
|
+
const dshVersion = input.dependencies['@deepseek-ai/dsh'];
|
|
122
|
+
if (typeof dshVersion !== 'string' || !/^\d+\.\d+\.\d+-[0-9A-Za-z.-]+$/.test(dshVersion)) {
|
|
123
|
+
throw new Error('@deepseek-ai/dsh 必须以精确 prerelease 版本声明');
|
|
124
|
+
}
|
|
125
|
+
if (dshVersion !== input.runtimeVersion) {
|
|
126
|
+
throw new Error(`DSH runtime guard 版本漂移:${input.runtimeVersion}(manifest ${dshVersion})`);
|
|
127
|
+
}
|
|
128
|
+
const dshNodes = Object.entries(input.lockPackages)
|
|
129
|
+
.flatMap(([path, metadata]) => {
|
|
130
|
+
const match = path.match(/(?:^|\/)node_modules\/(\@deepseek-ai\/dsh(?:-[^/]+)?)$/);
|
|
131
|
+
return match ? [{ name: match[1], version: metadata.version }] : [];
|
|
132
|
+
})
|
|
133
|
+
.sort((left, right) => left.name.localeCompare(right.name));
|
|
134
|
+
if (dshNodes.length === 0)
|
|
135
|
+
throw new Error('package-lock 未解析到 DSH runtime closure');
|
|
136
|
+
for (const dependency of dshNodes) {
|
|
137
|
+
if (dependency.version !== dshVersion) {
|
|
138
|
+
throw new Error(`DSH lock 版本漂移:${dependency.name}@${dependency.version ?? 'missing'}(expected ${dshVersion})`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const lockNames = [...new Set(dshNodes.map((dependency) => dependency.name))].sort();
|
|
142
|
+
const manifestNames = Object.keys(input.dependencies)
|
|
143
|
+
.filter((name) => name === '@deepseek-ai/dsh' || name.startsWith('@deepseek-ai/dsh-'))
|
|
144
|
+
.sort();
|
|
145
|
+
const missing = lockNames.filter((name) => !manifestNames.includes(name));
|
|
146
|
+
const extra = manifestNames.filter((name) => !lockNames.includes(name));
|
|
147
|
+
if (missing.length > 0) {
|
|
148
|
+
throw new Error(`DSH closure 未精确声明:${missing[0]}@${dshVersion}`);
|
|
149
|
+
}
|
|
150
|
+
if (extra.length > 0) {
|
|
151
|
+
throw new Error(`DSH manifest 与 lock 集合不一致:missing=${missing.join(',') || '-'};extra=${extra.join(',') || '-'}`);
|
|
152
|
+
}
|
|
153
|
+
for (const name of manifestNames) {
|
|
154
|
+
if (input.dependencies[name] !== dshVersion) {
|
|
155
|
+
throw new Error(`DSH closure 未精确声明:${name}@${dshVersion}`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (input.expectedPackageCount !== undefined && lockNames.length !== input.expectedPackageCount) {
|
|
159
|
+
throw new Error(`DSH closure 包数量不符:${lockNames.length}(expected ${input.expectedPackageCount})`);
|
|
160
|
+
}
|
|
161
|
+
return { names: lockNames, version: dshVersion };
|
|
162
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session V3 确定性迁移契约(issue #268):在隔离临时目录下用真实发布的 V2 编解码器
|
|
3
|
+
* 生成 V2 header/events,序列化为 JSONL 字节写入磁盘,保存确切源字节快照;通过
|
|
4
|
+
* sessionFormatCatalog 从磁盘读取并解析这些字节,分类为 migration-required,迁移为
|
|
5
|
+
* V3,编码独立 V3 继任者写入磁盘;然后用 catalog validation:current 完全解码 V3
|
|
6
|
+
* 继任者;迁移后重新读取 V2 源文件做字节比较,证明迁移不修改源工件字节。
|
|
7
|
+
*
|
|
8
|
+
* 这是确定性格式兼容性证据(隔离文件字节,非内存 structuredClone),不是创始人状态
|
|
9
|
+
* 迁移,也不是 M5/M6 准入。
|
|
10
|
+
*
|
|
11
|
+
* 运行:cd ts && npx tsx scripts/dsh-session-v3-migration-proof.ts
|
|
12
|
+
*/
|
|
13
|
+
import assert from 'node:assert/strict';
|
|
14
|
+
import { writeFileSync, readFileSync, mkdtempSync, rmSync } from 'node:fs';
|
|
15
|
+
import { join } from 'node:path';
|
|
16
|
+
import { tmpdir } from 'node:os';
|
|
17
|
+
import { createSessionFormatCatalogWithChildren } from '@deepseek-ai/dsh-session-format-catalog';
|
|
18
|
+
import { releasedV2SessionFormatCodec } from '@deepseek-ai/dsh-session-format-v1-to-v2';
|
|
19
|
+
// 最小有效 V2 工件:一个 turn 包含一个 step,turn 正常完成。
|
|
20
|
+
// V2 事件处置要求 turn/start 需 ["turn"],step/start|step/end 需 ["turn","step"],
|
|
21
|
+
// turn/end 需 ["turn","reason"],reason.kind="completed" 是最简有效种类。
|
|
22
|
+
const v2Header = {
|
|
23
|
+
version: 2,
|
|
24
|
+
id: 's-min-v2',
|
|
25
|
+
createdAt: 1700000000000,
|
|
26
|
+
isSeeded: false,
|
|
27
|
+
delegationDepth: 0,
|
|
28
|
+
};
|
|
29
|
+
const v2Events = [
|
|
30
|
+
{ type: 'turn/start', seq: 0, time: 1700000000000, data: { turn: 1 } },
|
|
31
|
+
{ type: 'step/start', seq: 1, time: 1700000000001, data: { turn: 1, step: 1 } },
|
|
32
|
+
{ type: 'step/end', seq: 2, time: 1700000000002, data: { turn: 1, step: 1 } },
|
|
33
|
+
{ type: 'turn/end', seq: 3, time: 1700000000003, data: { turn: 1, reason: { kind: 'completed' } } },
|
|
34
|
+
];
|
|
35
|
+
// 1. 用真实发布的 V2 编解码器编码 header + 事件行为 JSON 对象,序列化为 JSONL 字节。
|
|
36
|
+
const encodedHeader = releasedV2SessionFormatCodec.encodeHeader(v2Header, 0);
|
|
37
|
+
const encodedRows = v2Events.map((e) => releasedV2SessionFormatCodec.encodeEvent(e));
|
|
38
|
+
function toLine(obj) {
|
|
39
|
+
return JSON.stringify(obj);
|
|
40
|
+
}
|
|
41
|
+
const sourceLines = [toLine(encodedHeader), ...encodedRows.map(toLine)];
|
|
42
|
+
const sourceJsonl = sourceLines.join('\n') + '\n';
|
|
43
|
+
const tmp = mkdtempSync(join(tmpdir(), 'session-v3-migration-proof-'));
|
|
44
|
+
const sourcePath = join(tmp, 'source.v2.jsonl');
|
|
45
|
+
const successorPath = join(tmp, 'successor.current.jsonl');
|
|
46
|
+
// 0.2.0-rc.2 起 catalog current = V4;V3→V4 边要求显式历史子代理证据,
|
|
47
|
+
// 本 fixture 是无父会话,声明空数组(createSessionFormatCatalogWithChildren)。
|
|
48
|
+
const catalog = createSessionFormatCatalogWithChildren([]);
|
|
49
|
+
try {
|
|
50
|
+
// 2. 写 V2 源字节到磁盘,保存确切源字节快照。
|
|
51
|
+
writeFileSync(sourcePath, sourceJsonl, 'utf8');
|
|
52
|
+
const sourceBytes = readFileSync(sourcePath);
|
|
53
|
+
// 3. 从磁盘读取并解析 V2 源字节:首行 = header,其余 = 事件行。
|
|
54
|
+
const parsedLines = readFileSync(sourcePath, 'utf8').split('\n').filter((l) => l.length > 0);
|
|
55
|
+
assert.ok(parsedLines.length === sourceLines.length, `磁盘行数必须等于源行数(${parsedLines.length} vs ${sourceLines.length})`);
|
|
56
|
+
const headerValue = JSON.parse(parsedLines[0]);
|
|
57
|
+
const rowValues = parsedLines.slice(1).map((l) => JSON.parse(l));
|
|
58
|
+
// 4. catalog 当前版本 = 4(0.2.0-rc.2 起);V2 header 分类为 migration-required。
|
|
59
|
+
assert.equal(catalog.currentVersion, 4, 'catalog 当前版本必须为 4(0.2.0-rc.2 起 V4 为 current)');
|
|
60
|
+
const headerRead = catalog.readHeader(headerValue);
|
|
61
|
+
assert.equal(headerRead.status, 'migration-required', `V2 header 必须分类为 migration-required(当前 ${headerRead.status})`);
|
|
62
|
+
// 5. 创建恢复器,逐行解码,完成恢复为 V3 工件(validation:transformed,迁移后校验)。
|
|
63
|
+
const restore = catalog.createRestore(headerValue, {
|
|
64
|
+
recovery: 'recoverable',
|
|
65
|
+
validation: 'transformed',
|
|
66
|
+
});
|
|
67
|
+
for (const row of rowValues) {
|
|
68
|
+
restore.decodeRow(row);
|
|
69
|
+
}
|
|
70
|
+
const artifact = restore.finish();
|
|
71
|
+
// 6. 迁移链工件版本 = 4(V2→V3 插入 system head 后,V3→V4 不减事件)。
|
|
72
|
+
assert.equal(artifact.header.version, 4, '恢复后工件版本必须为 4');
|
|
73
|
+
assert.ok(artifact.events.length >= v2Events.length + 1, `迁移链事件数必须 ≥ V2 + 1(插入 system head),当前 ${artifact.events.length}`);
|
|
74
|
+
// 插入的 system head(原 step/start 后)必须是 system/message。
|
|
75
|
+
const inserted = artifact.events.find((event) => event.type === 'system/message');
|
|
76
|
+
assert.ok(inserted, '迁移链必须包含插入的 system/message head');
|
|
77
|
+
// 7. 编码 current(V4)继任者为 JSONL 字节,写入独立磁盘文件。
|
|
78
|
+
const currentHeaderRecord = catalog.encodeCurrentHeader(artifact.header, artifact.inheritedEventCount);
|
|
79
|
+
const currentRowRecords = artifact.events.map((e) => catalog.encodeCurrentEvent(e));
|
|
80
|
+
const successorLines = [toLine(currentHeaderRecord), ...currentRowRecords.map(toLine)];
|
|
81
|
+
const successorJsonl = successorLines.join('\n') + '\n';
|
|
82
|
+
writeFileSync(successorPath, successorJsonl, 'utf8');
|
|
83
|
+
// 8. 从磁盘读取 V3 继任者,用 catalog validation:current 完全解码。
|
|
84
|
+
const successorParsed = readFileSync(successorPath, 'utf8').split('\n').filter((l) => l.length > 0);
|
|
85
|
+
assert.ok(successorParsed.length === successorLines.length, `V3 磁盘行数必须等于继任者行数`);
|
|
86
|
+
const successorHeaderValue = JSON.parse(successorParsed[0]);
|
|
87
|
+
const successorRowValues = successorParsed.slice(1).map((l) => JSON.parse(l));
|
|
88
|
+
const successorRead = catalog.readHeader(successorHeaderValue);
|
|
89
|
+
assert.equal(successorRead.status, 'current', `V3 继任者必须重新打开为 current(当前 ${successorRead.status})`);
|
|
90
|
+
const successorRestore = catalog.createRestore(successorHeaderValue, {
|
|
91
|
+
recovery: 'recoverable',
|
|
92
|
+
validation: 'current',
|
|
93
|
+
});
|
|
94
|
+
for (const row of successorRowValues) {
|
|
95
|
+
successorRestore.decodeRow(row);
|
|
96
|
+
}
|
|
97
|
+
const successorArtifact = successorRestore.finish();
|
|
98
|
+
assert.equal(successorArtifact.header.version, 4, 'current 继任者完全解码后版本必须为 4');
|
|
99
|
+
assert.equal(successorArtifact.events.length, artifact.events.length, 'V3 继任者完全解码后事件数必须与迁移工件一致');
|
|
100
|
+
// 9. 迁移后重新读取 V2 源文件字节,与快照字节比较——证明迁移不修改源工件字节。
|
|
101
|
+
const sourceBytesAfter = readFileSync(sourcePath);
|
|
102
|
+
assert.ok(Buffer.compare(sourceBytes, sourceBytesAfter) === 0, '迁移后 V2 源文件字节必须与快照完全一致——迁移不修改源工件字节');
|
|
103
|
+
console.log(`SESSION V3 MIGRATION PROOF: V2 source ${sourceBytes.length}B (${v2Events.length} events) on disk → ` +
|
|
104
|
+
`current V4(${artifact.events.length} events, +system/message), successor ${successorJsonl.length}B reopens as current ` +
|
|
105
|
+
`and fully decodes (${successorArtifact.events.length} events), source bytes unchanged after migration`);
|
|
106
|
+
}
|
|
107
|
+
finally {
|
|
108
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
109
|
+
}
|