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