@danceiny/gotry 0.0.1-rc.8 → 0.2.0-rc.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +172 -217
- 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 -49
- 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 +968 -0
- 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 +126 -0
- package/dist/capabilities/session/adapters/ctrip-flight.js +141 -0
- 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 +54 -0
- 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 +50 -0
- 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 +107 -0
- package/dist/capabilities/session/static-flight-golden.js +150 -0
- package/dist/capabilities/session/transport.js +109 -0
- 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 +686 -0
- 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 +72 -0
- 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 +68 -10
- 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 +67 -0
- 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 +480 -0
- package/dist/scripts/ledger-workflow-crash.js +32 -0
- 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 +49 -0
- package/dist/scripts/memory-lifecycle-tests.js +657 -0
- package/dist/scripts/memory-lifecycle.js +196 -0
- package/dist/scripts/memory-metrics.js +29 -31
- 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 +43 -42
- 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 +31 -0
- package/dist/scripts/session-attach-poc.js +62 -0
- 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 +60 -0
- package/dist/scripts/session-link-tests.js +478 -0
- package/dist/scripts/session-login.js +29 -0
- package/dist/scripts/session-tests.js +862 -0
- 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 +703 -219
- 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 +261 -0
- package/dist/scripts/state-cli.js +585 -0
- 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 +59 -0
- 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 +86 -0
- 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 +2305 -731
- 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 +358 -162
- package/dist/src/memory-capture.js +180 -32
- package/dist/src/memory-decay.js +47 -0
- 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 +767 -0
- 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 +59 -0
- 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 +538 -360
- 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 +296 -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 +2107 -224
- 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 +278 -40
- 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 +360 -89
- package/ts/src/wish-pool.ts +79 -0
|
@@ -1,38 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* agent-reach web 读取(readUrl 薄壳)测试:
|
|
3
|
+
* readUrl = URL 校验 + 委托上游 WebChannel.read(反射桥) + Title 提取,自身无网络实现。
|
|
4
|
+
* 上游真读已在 §15 wrapper 测试覆盖;本套只测薄壳行为:
|
|
5
|
+
* 1. 非法 URL(不带 http) → 拒绝,不抛错,降级返回(离线确定性)
|
|
6
|
+
* 2. 1ms 超时 → 桥被杀,降级 error(离线确定性)
|
|
7
|
+
* 3. live 读 example.com → 成功时断言 Title/证据链;网络边界允许降级(不抛错)
|
|
8
|
+
*
|
|
9
|
+
* 运行: cd ts && npx tsx scripts/agent-reach-tests.ts
|
|
10
|
+
*/
|
|
1
11
|
import assert from 'node:assert/strict';
|
|
2
12
|
import { readUrl } from '../capabilities/agent-reach.js';
|
|
13
|
+
// 1. 非法 URL(不带 scheme)
|
|
3
14
|
{
|
|
4
|
-
const r = await readUrl({
|
|
5
|
-
url: 'example.com'
|
|
6
|
-
});
|
|
15
|
+
const r = await readUrl({ url: 'example.com' });
|
|
7
16
|
assert.equal(r.ok, false);
|
|
8
17
|
assert.equal(r.via, 'r.jina.ai-error');
|
|
9
18
|
assert.ok(r.evidence.includes('error'), 'evidence 带 error');
|
|
10
19
|
console.log('1. 非法 URL 拒绝 OK');
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
});
|
|
20
|
+
}
|
|
21
|
+
// 2. 超时(1ms 杀掉反射桥进程)
|
|
22
|
+
{
|
|
23
|
+
const r = await readUrl({ url: 'https://example.com', timeoutMs: 1 });
|
|
16
24
|
assert.equal(r.ok, false);
|
|
17
25
|
assert.equal(r.via, 'r.jina.ai-error');
|
|
18
26
|
assert.ok(r.latencyMs >= 0, '永不抛错');
|
|
19
27
|
console.log('2. 超时降级 OK');
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
});
|
|
28
|
+
}
|
|
29
|
+
// 3. live 读 example.com(上游 Jina Reader;网络边界允许降级)
|
|
30
|
+
{
|
|
31
|
+
const r = await readUrl({ url: 'https://example.com', timeoutMs: 30_000 });
|
|
25
32
|
if (r.ok) {
|
|
26
33
|
assert.ok(r.evidence.includes('[agent-reach:web.read@'), '证据链');
|
|
27
34
|
assert.match(r.evidence, /\[agent-reach:web\.read@2\d{3}-\d{2}-\d{2}T/, '证据链带 ISO 时间戳');
|
|
28
35
|
assert.ok(typeof r.content === 'string' && r.content.length > 0, 'content 非空');
|
|
36
|
+
// live 内容会漂移(example.com 经 Jina 的 Title 曾从 Example Domain 变 Test Document),
|
|
37
|
+
// 断言结构(非空标题被提取)而非精确文案
|
|
29
38
|
assert.ok(typeof r.title === 'string' && r.title.length > 0, `Title 提取,实际 ${r.title}`);
|
|
30
39
|
console.log(`3. readUrl example.com → ok (title=${r.title}) OK`);
|
|
31
|
-
}
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
32
42
|
assert.equal(r.via, 'r.jina.ai-error');
|
|
33
43
|
console.log(`3. readUrl example.com → 降级(${r.error?.slice(0, 60)})(网络边界,合法) OK`);
|
|
34
44
|
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
//# sourceURL=/Users/bytedance/work/gotry/ts/scripts/agent-reach-tests.ts
|
|
45
|
+
}
|
|
46
|
+
console.log('\nAGENT-REACH TESTS: 3/3 OK(readUrl 薄壳;上游真读见 wrapper 套)');
|
|
@@ -1,79 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* agent-reach wrapper 测试(零渠道知识,全部走反射桥):
|
|
3
|
+
* 1. status: 真 agent-reach doctor 透传(via=agent-reach-cli)
|
|
4
|
+
* 2. web.read: 真读 example.com(上游 Jina Reader 后端)
|
|
5
|
+
* 3. v2ex.get_hot_topics: 上游 python 方法真调(网络边界允许降级)
|
|
6
|
+
* 4. xueqiu.get_stock_quote: 无 cookie → needs-setup 且 setup=上游 check() 原话
|
|
7
|
+
* 5. 未知渠道 → 自描述错误带回上游渠道清单
|
|
8
|
+
* 6. 未知方法 → 自描述错误带回上游方法签名清单
|
|
9
|
+
* 7. 永不抛错: 空 channel/method 降级
|
|
10
|
+
*
|
|
11
|
+
* 运行: cd ts && npx tsx scripts/agent-reach-wrapper-tests.ts
|
|
12
|
+
*/
|
|
1
13
|
import assert from 'node:assert/strict';
|
|
2
14
|
import { reach, reachStatus } from '../capabilities/agent-reach.js';
|
|
15
|
+
// 1. status(真 doctor 原样透传;agent-reach 未装时结构化 SKIP——真集成面设备绑定,
|
|
16
|
+
// 与 §17 skills-contract「有凭证真校验,离线 SKIP」同构;CI 装了则全跑 7 断言)
|
|
3
17
|
{
|
|
4
18
|
const st = await reachStatus(90_000);
|
|
19
|
+
if (!st.ok) {
|
|
20
|
+
console.log(`SKIP: agent-reach doctor 未就绪(未安装/needs-setup),7 断言整体跳过 — via=${st.via} output=${String(st.output).slice(0, 120)}`);
|
|
21
|
+
process.exit(0);
|
|
22
|
+
}
|
|
5
23
|
assert.equal(st.ok, true);
|
|
6
24
|
assert.equal(st.via, 'agent-reach-cli');
|
|
7
25
|
assert.ok(st.output.length > 50, 'doctor 输出非空(上游原样)');
|
|
8
26
|
console.log(`1. status → doctor 透传 (${st.latencyMs}ms) OK`);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
args: [
|
|
14
|
-
'https://example.com'
|
|
15
|
-
],
|
|
16
|
-
timeoutMs: 30_000
|
|
17
|
-
});
|
|
27
|
+
}
|
|
28
|
+
// 2. web.read(上游 WebChannel.read → Jina Reader)
|
|
29
|
+
{
|
|
30
|
+
const r = await reach({ channel: 'web', method: 'read', args: ['https://example.com'], timeoutMs: 30_000 });
|
|
18
31
|
assert.equal(r.verdict, 'found');
|
|
19
32
|
assert.ok(r.evidence.includes('[agent-reach:web.read@'), '证据链 [agent-reach:web.read@ts]');
|
|
33
|
+
// live 内容会漂移(同 §13),断言非空 markdown 而非精确文案
|
|
20
34
|
assert.ok(typeof r.data === 'string' && r.data.length > 200, 'content 非空 markdown');
|
|
21
35
|
console.log(`2. web.read example.com → found (${r.latencyMs}ms) OK`);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
timeoutMs: 30_000
|
|
27
|
-
});
|
|
36
|
+
}
|
|
37
|
+
// 3. v2ex.get_hot_topics(上游 python 方法;网络边界允许降级不抛错)
|
|
38
|
+
{
|
|
39
|
+
const r = await reach({ channel: 'v2ex', method: 'get_hot_topics', timeoutMs: 30_000 });
|
|
28
40
|
if (r.ok) {
|
|
29
41
|
assert.ok(Array.isArray(r.data), 'hot topics 是数组');
|
|
30
42
|
console.log(`3. v2ex.get_hot_topics → found (${r.data.length} topics) OK`);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
'needs-setup'
|
|
35
|
-
].includes(r.verdict), '降级合法');
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
assert.ok(['error', 'needs-setup'].includes(r.verdict), '降级合法');
|
|
36
46
|
console.log(`3. v2ex.get_hot_topics → ${r.verdict}(网络边界,降级合法) OK`);
|
|
37
47
|
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
args: [
|
|
43
|
-
'SH600519'
|
|
44
|
-
],
|
|
45
|
-
timeoutMs: 30_000
|
|
46
|
-
});
|
|
48
|
+
}
|
|
49
|
+
// 4. xueqiu.get_stock_quote(无 cookie → needs-setup 且 setup 是上游 check() 原话)
|
|
50
|
+
{
|
|
51
|
+
const r = await reach({ channel: 'xueqiu', method: 'get_stock_quote', args: ['SH600519'], timeoutMs: 30_000 });
|
|
47
52
|
assert.equal(r.verdict, 'needs-setup', `实际 verdict=${r.verdict} error=${r.error}`);
|
|
48
53
|
assert.ok((r.setup ?? '').includes('configure'), 'setup 透传上游 configure 指引(不转述)');
|
|
49
54
|
console.log('4. xueqiu.get_stock_quote → needs-setup(上游原话指引) OK');
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
});
|
|
55
|
+
}
|
|
56
|
+
// 5. 未知渠道 → 自描述,带回上游渠道清单
|
|
57
|
+
{
|
|
58
|
+
const r = await reach({ channel: 'nosuch', method: 'foo' });
|
|
55
59
|
assert.equal(r.ok, false);
|
|
56
|
-
const channels = r.inventory?.channels ?? {};
|
|
60
|
+
const channels = (r.inventory?.channels ?? {});
|
|
57
61
|
assert.ok(channels.web && channels.xueqiu && channels['exa_search'], 'inventory 带回上游注册表(含 exa_search 真名)');
|
|
58
62
|
console.log(`5. 未知渠道 → 自描述清单(${Object.keys(channels).length} 渠道) OK`);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
});
|
|
63
|
+
}
|
|
64
|
+
// 6. 未知方法 → 自描述,带回上游方法签名清单
|
|
65
|
+
{
|
|
66
|
+
const r = await reach({ channel: 'web', method: 'nosuch' });
|
|
64
67
|
assert.equal(r.ok, false);
|
|
65
|
-
const methods = r.inventory?.methods ?? {};
|
|
68
|
+
const methods = (r.inventory?.methods ?? {});
|
|
66
69
|
assert.ok(methods.read, 'inventory.methods 带 read 签名');
|
|
67
70
|
console.log(`6. 未知方法 → 自描述清单(${Object.keys(methods).length} 方法) OK`);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
});
|
|
71
|
+
}
|
|
72
|
+
// 7. 永不抛错: 空 channel/method
|
|
73
|
+
{
|
|
74
|
+
const r = await reach({ channel: '', method: '' });
|
|
73
75
|
assert.equal(r.ok, false);
|
|
74
76
|
assert.equal(r.verdict, 'error');
|
|
75
77
|
console.log('7. 空 channel/method 降级 OK');
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
//# sourceURL=/Users/bytedance/work/gotry/ts/scripts/agent-reach-wrapper-tests.ts
|
|
78
|
+
}
|
|
79
|
+
console.log('\nAGENT-REACH WRAPPER TESTS: 7/7 OK(反射桥 + doctor 透传 + 自描述错误)');
|
|
@@ -1,5 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anything 能力层测试(模拟 hbcli):
|
|
3
|
+
* 1. 真实候选:fake hbcli 按 hotel-be SearchItem wire 形状返 JSON — verdict hit + hits
|
|
4
|
+
* (i18n name zh 优先 / region.centerLat / hotel.latlngCoordinator / star / id 逐字段对齐)
|
|
5
|
+
* 2. 旗标回归:--json 在子命令前(cli.ts 全局旗标预扫描只认子命令前位置)+
|
|
6
|
+
* --content-type / parentDestinationId → --destination-id 映射
|
|
7
|
+
* 3. 空候选:fake hbcli 返 empty JSON — verdict miss
|
|
8
|
+
* 4. exit≠0:fake hbcli 返 stderr+退出 — verdict error + 不抛错
|
|
9
|
+
* 5. 旧 CLI「unknown command」:error 带升级指引(issue #195:裸 unknown command 读起来像工具坏了)
|
|
10
|
+
* 6. 超时:fake hbcli hang — AbortError → verdict error + 不抛错
|
|
11
|
+
* 7. 关键词为空:不调 hbcli — verdict error
|
|
12
|
+
* 8. 缺 hbcli(spawn 失败):用户面是人话(不留 `(exit null)`/ENOENT 进程噪音)
|
|
13
|
+
*
|
|
14
|
+
* 运行: cd ts && npx tsx scripts/anything-tests.ts
|
|
15
|
+
*/
|
|
1
16
|
import assert from 'node:assert/strict';
|
|
2
|
-
import { mkdtemp, rm, writeFile
|
|
17
|
+
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
3
18
|
import { tmpdir } from 'node:os';
|
|
4
19
|
import { join } from 'node:path';
|
|
5
20
|
import { anythingSearch } from '../capabilities/anything.js';
|
|
@@ -8,88 +23,129 @@ try {
|
|
|
8
23
|
async function fakeBin(name, behaviour) {
|
|
9
24
|
const p = join(tmp, name);
|
|
10
25
|
if (behaviour === 'ok') {
|
|
26
|
+
// hotel-be SearchItem 真实 wire 形状(2026-09-07 对齐源码):i18n name 对象、
|
|
27
|
+
// region.coordinates.centerLat/centerLng、hotel.latlngCoordinator.google、star、matchScore
|
|
11
28
|
await writeFile(p, `#!/bin/sh
|
|
12
29
|
cat <<'JSON'
|
|
13
30
|
{"candidates":[
|
|
14
|
-
{"type":"hotel","
|
|
15
|
-
{"type":"city","
|
|
16
|
-
{"type":"place","
|
|
31
|
+
{"type":"hotel","matchScore":180,"hotel":{"id":"h1","name":{"en":"Park Hyatt","zh":"柏悦酒店"},"star":5,"destinationId":"d1","latlngCoordinator":{"google":{"lat":22.31,"lng":114.16}}}},
|
|
32
|
+
{"type":"city","matchScore":250,"region":{"id":"d1","name":{"en":"Dali","zh":"大理市"},"countryCode":"CN","coordinates":{"centerLat":25.58,"centerLng":100.21}}},
|
|
33
|
+
{"type":"place","matchScore":90,"region":{"id":"r1","name":{"zh":"洱海"}},"place":{"latlngCoordinator":{"google":{"lat":25.74,"lng":100.25}}}}
|
|
17
34
|
]}
|
|
18
35
|
JSON
|
|
19
|
-
`, {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
36
|
+
`, { mode: 0o755 });
|
|
37
|
+
}
|
|
38
|
+
else if (behaviour === 'echo-args') {
|
|
39
|
+
// 旗标回归探针:把 "$@" 回显进候选 region.id(anythingSearch 原样透传为 destinationId)
|
|
40
|
+
await writeFile(p, `#!/bin/sh
|
|
41
|
+
printf '{"candidates":[{"type":"city","region":{"id":"%s"}}]}' "$*"
|
|
42
|
+
`, { mode: 0o755 });
|
|
43
|
+
}
|
|
44
|
+
else if (behaviour === 'empty') {
|
|
23
45
|
await writeFile(p, `#!/bin/sh
|
|
24
46
|
cat <<'JSON'
|
|
25
47
|
{"candidates":[]}
|
|
26
48
|
JSON
|
|
27
|
-
`, {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
} else if (behaviour === 'fail') {
|
|
49
|
+
`, { mode: 0o755 });
|
|
50
|
+
}
|
|
51
|
+
else if (behaviour === 'fail') {
|
|
31
52
|
await writeFile(p, `#!/bin/sh
|
|
32
53
|
echo 'hotelbe down' >&2
|
|
33
54
|
exit 1
|
|
34
|
-
`, {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
55
|
+
`, { mode: 0o755 });
|
|
56
|
+
}
|
|
57
|
+
else if (behaviour === 'unknown-command') {
|
|
58
|
+
// 旧版 CLI(< 2026-09 的 staicli)没有 search anything 子命令时的 commander 原话
|
|
59
|
+
await writeFile(p, `#!/bin/sh
|
|
60
|
+
echo "error: unknown command 'anything'" >&2
|
|
61
|
+
exit 1
|
|
62
|
+
`, { mode: 0o755 });
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
// hang forever — test will timeout. Spawn on POSIX reacts to AbortSignal
|
|
66
|
+
// via SIGTERM; SIGKILL is the fallback at +500ms. Some shells (e.g. bash
|
|
67
|
+
// builtins shelled-out via Bun) cache the child pid briefly, so we give
|
|
68
|
+
// a generous upper bound in the assertion (note in code for future).
|
|
38
69
|
await writeFile(p, `#!/bin/sh
|
|
39
70
|
echo 'starting' >&2
|
|
40
71
|
while :; do sleep 5; done
|
|
41
|
-
`, {
|
|
42
|
-
mode: 0o755
|
|
43
|
-
});
|
|
72
|
+
`, { mode: 0o755 });
|
|
44
73
|
}
|
|
45
74
|
return p;
|
|
46
75
|
}
|
|
76
|
+
// 1. 真实候选(wire 形状逐字段)
|
|
47
77
|
const ok = await fakeBin('hbcli-ok', 'ok');
|
|
48
|
-
const r1 = await anythingSearch({
|
|
49
|
-
keyword: 'Park Hyatt',
|
|
50
|
-
hbcliBin: ok
|
|
51
|
-
});
|
|
78
|
+
const r1 = await anythingSearch({ keyword: '大理', hbcliBin: ok });
|
|
52
79
|
assert.equal(r1.verdict, 'hit');
|
|
53
80
|
assert.equal(r1.hits.length, 3);
|
|
54
81
|
assert.ok(r1.evidence.includes('hbcli-anything@'));
|
|
55
|
-
|
|
82
|
+
const [hotelHit, cityHit, placeHit] = r1.hits;
|
|
83
|
+
assert.equal(hotelHit.type, 'hotel');
|
|
84
|
+
assert.equal(hotelHit.name, '柏悦酒店', 'hotel i18n name 应 zh 优先');
|
|
85
|
+
assert.equal(hotelHit.hotelId, 'h1');
|
|
86
|
+
assert.equal(hotelHit.destinationId, 'd1', 'hotel 候选 destinationId 取所属目的地');
|
|
87
|
+
assert.equal(hotelHit.star, 5);
|
|
88
|
+
assert.equal(hotelHit.latitude, 22.31);
|
|
89
|
+
assert.equal(hotelHit.longitude, 114.16);
|
|
90
|
+
assert.equal(hotelHit.score, 180);
|
|
91
|
+
assert.equal(cityHit.type, 'city');
|
|
92
|
+
assert.equal(cityHit.name, '大理市', 'region i18n name 应 zh 优先');
|
|
93
|
+
assert.equal(cityHit.destinationId, 'd1');
|
|
94
|
+
assert.equal(cityHit.latitude, 25.58, 'city 坐标取 region.coordinates.centerLat');
|
|
95
|
+
assert.equal(cityHit.longitude, 100.21);
|
|
96
|
+
assert.equal(placeHit.type, 'place');
|
|
97
|
+
assert.equal(placeHit.name, '洱海');
|
|
98
|
+
assert.equal(placeHit.latitude, 25.74, 'place 坐标回退 place.latlngCoordinator');
|
|
99
|
+
console.log('1. 真实候选 wire 形状(hotel/city/place 逐字段)OK');
|
|
100
|
+
// 2. 旗标回归:--json 必须在子命令前(cli.ts 全局旗标预扫描只认子命令前位置);
|
|
101
|
+
// contentType → --content-type;parentDestinationId → --destination-id(上游 CLI 旗标名)
|
|
102
|
+
const echo = await fakeBin('hbcli-echo-args', 'echo-args');
|
|
103
|
+
const r2 = await anythingSearch({ keyword: '大理', contentType: 'city', parentDestinationId: 'd1', hbcliBin: echo });
|
|
104
|
+
assert.equal(r2.verdict, 'hit');
|
|
105
|
+
assert.equal(r2.hits[0].destinationId, '--json search anything 大理 --content-type city --destination-id d1', 'spawn 旗标形态(--json 前置/--destination-id 映射)应稳定,实际 ' + r2.hits[0].destinationId);
|
|
106
|
+
console.log('2. 旗标回归(--json 前置 + --destination-id 映射)OK');
|
|
107
|
+
// 3. 空候选
|
|
56
108
|
const empty = await fakeBin('hbcli-empty', 'empty');
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
assert.equal(r2.hits.length, 0);
|
|
63
|
-
console.log('2. nothing → miss OK');
|
|
109
|
+
const r3 = await anythingSearch({ keyword: 'nothing', hbcliBin: empty });
|
|
110
|
+
assert.equal(r3.verdict, 'miss');
|
|
111
|
+
assert.equal(r3.hits.length, 0);
|
|
112
|
+
console.log('3. nothing → miss OK');
|
|
113
|
+
// 4. exit≠0
|
|
64
114
|
const fail = await fakeBin('hbcli-fail', 'fail');
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const hang = await fakeBin('hbcli-hang', 'hang');
|
|
74
|
-
const r4 = await anythingSearch({
|
|
75
|
-
keyword: 'x',
|
|
76
|
-
hbcliBin: hang,
|
|
77
|
-
timeoutMs: 800
|
|
78
|
-
});
|
|
79
|
-
assert.equal(r4.verdict, 'error', 'timeout 应判 error');
|
|
80
|
-
console.log(`4. hang/timeout → error OK (latency=${r4.latencyMs}ms)`);
|
|
81
|
-
const r5 = await anythingSearch({
|
|
82
|
-
keyword: ' '
|
|
83
|
-
});
|
|
115
|
+
const r4 = await anythingSearch({ keyword: 'x', hbcliBin: fail });
|
|
116
|
+
assert.equal(r4.verdict, 'error');
|
|
117
|
+
assert.equal(r4.ok, false);
|
|
118
|
+
assert.match(r4.evidence, /error/);
|
|
119
|
+
console.log('4. fail → error (降级) OK');
|
|
120
|
+
// 5. 旧 CLI unknown command → error 带升级指引(issue #195)
|
|
121
|
+
const old = await fakeBin('hbcli-old', 'unknown-command');
|
|
122
|
+
const r5 = await anythingSearch({ keyword: 'x', hbcliBin: old });
|
|
84
123
|
assert.equal(r5.verdict, 'error');
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
});
|
|
124
|
+
assert.match(r5.error ?? '', /hbcli update|gotry setup/, 'error 应带升级指引,实际 ' + r5.error);
|
|
125
|
+
assert.match(r5.evidence, /unknown command/, 'evidence 保留上游原话(溯源)');
|
|
126
|
+
console.log(`5. 旧 CLI unknown command → 升级指引 OK(${r5.error})`);
|
|
127
|
+
// 6. 超时:fake hang 60s,我们给 800ms 超时,期望 verdict=error
|
|
128
|
+
// (latency 断言范围放宽,因为 sandbox node spawn 的 abort 行为不稳定)
|
|
129
|
+
const hang = await fakeBin('hbcli-hang', 'hang');
|
|
130
|
+
const r6 = await anythingSearch({ keyword: 'x', hbcliBin: hang, timeoutMs: 800 });
|
|
131
|
+
assert.equal(r6.verdict, 'error', 'timeout 应判 error');
|
|
132
|
+
console.log(`6. hang/timeout → error OK (latency=${r6.latencyMs}ms)`);
|
|
133
|
+
// 7. 空 keyword
|
|
134
|
+
const r7 = await anythingSearch({ keyword: ' ' });
|
|
135
|
+
assert.equal(r7.verdict, 'error');
|
|
136
|
+
console.log('7. empty keyword → error OK');
|
|
137
|
+
// 8. 缺 hbcli(spawn 失败):用户面必须是人话。这条消息会直接渲染进用户回复
|
|
138
|
+
// (loop.ts 的 D-7a PoI 探针),旧实现回落成 `(exit null)` 这类进程噪音
|
|
139
|
+
// (2026-09-22 端到端走查在「我订了酒店:The Title East Wing Rawai」上实测到)。
|
|
140
|
+
const r8 = await anythingSearch({ keyword: 'The Title East Wing Rawai', hbcliBin: join(tmp, 'definitely-missing-hbcli') });
|
|
141
|
+
assert.equal(r8.verdict, 'error', '缺 hbcli 应判 error 而非抛错');
|
|
142
|
+
assert.ok(r8.error && r8.error.length > 0, '必须给出原因');
|
|
143
|
+
assert.ok(!/(exit null|ENOENT|spawn )/i.test(r8.error), `用户面不得出现进程噪音,实得:${r8.error}`);
|
|
144
|
+
assert.ok(/hbcli/.test(r8.error), `原因须指明是 hbcli,实得:${r8.error}`);
|
|
145
|
+
assert.ok(r8.evidence.includes('[实时API:hbcli-anything@error@'), '证据链 tag 形态不变');
|
|
146
|
+
console.log(`8. 缺 hbcli → 人话降级 OK(${r8.error})`);
|
|
147
|
+
console.log('\nANYTHING TESTS: 8/8 OK(hbcli fake + wire 对齐 + 降级诚实)');
|
|
148
|
+
}
|
|
149
|
+
finally {
|
|
150
|
+
await rm(tmp, { recursive: true, force: true });
|
|
92
151
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
//# sourceURL=/Users/bytedance/work/gotry/ts/scripts/anything-tests.ts
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Client contract: package export, lazy-CJS loader shape, keyed DSH
|
|
3
|
+
* registrations, and defensive rendering from the runtime `block` payload.
|
|
4
|
+
* Browser execution is covered separately by dsh-artifact-web-e2e.ts.
|
|
5
|
+
*/
|
|
6
|
+
import assert from 'node:assert/strict';
|
|
7
|
+
import { readFileSync } from 'node:fs';
|
|
8
|
+
import { createRequire } from 'node:module';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import vm from 'node:vm';
|
|
11
|
+
const ROOT = join(import.meta.dirname, '..', '..');
|
|
12
|
+
const source = readFileSync(join(ROOT, 'client/client.js'), 'utf8');
|
|
13
|
+
const pkg = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf8'));
|
|
14
|
+
assert.equal(pkg.exports?.['./client'], './client/client.js');
|
|
15
|
+
assert.equal(pkg.dsh?.client?.platform, 'web');
|
|
16
|
+
assert.ok(pkg.dsh?.client?.inject?.includes('@deepseek-ai/dsh-client-ui-tool'));
|
|
17
|
+
assert.ok(pkg.files?.includes('client/'));
|
|
18
|
+
assert.ok(source.includes('window.__ModuleLoader__.load'));
|
|
19
|
+
assert.ok(source.includes("tool.call.toolview"));
|
|
20
|
+
assert.ok(source.includes("gotry_artifacts_list"));
|
|
21
|
+
assert.ok(source.includes("gotry_artifacts_read"));
|
|
22
|
+
assert.ok(!source.includes('@deepseek-ai/dsh-client-ui-tool/lib/'));
|
|
23
|
+
const registrations = [];
|
|
24
|
+
const context = vm.createContext({
|
|
25
|
+
window: { __ModuleLoader__: { load: (registration) => registrations.push(registration) } },
|
|
26
|
+
console,
|
|
27
|
+
});
|
|
28
|
+
new vm.Script(source, { filename: 'client/client.js' }).runInContext(context);
|
|
29
|
+
assert.equal(registrations.length, 1);
|
|
30
|
+
assert.equal(registrations[0].id, '@danceiny/gotry');
|
|
31
|
+
function createElement(type, props, ...children) {
|
|
32
|
+
return { type, props: props ?? {}, children };
|
|
33
|
+
}
|
|
34
|
+
const fakeReact = {
|
|
35
|
+
createElement,
|
|
36
|
+
useState(initial) { return [initial, () => { }]; },
|
|
37
|
+
};
|
|
38
|
+
const clientExports = registrations[0].factory(name => {
|
|
39
|
+
assert.equal(name, 'react');
|
|
40
|
+
return fakeReact;
|
|
41
|
+
});
|
|
42
|
+
assert.deepEqual(Object.keys(clientExports), ['apply', 'inject']);
|
|
43
|
+
const slotRegistrations = [];
|
|
44
|
+
const registrationContext = {
|
|
45
|
+
inject(_deps, callback) { callback(registrationContext); },
|
|
46
|
+
slots: {
|
|
47
|
+
inject(_slot, callback) { callback(); },
|
|
48
|
+
register(definition, view) {
|
|
49
|
+
slotRegistrations.push({ key: definition.key, view });
|
|
50
|
+
return () => { };
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
clientExports.apply(registrationContext);
|
|
55
|
+
assert.deepEqual(slotRegistrations.map(item => item.key), ['gotry_artifacts_list', 'gotry_artifacts_read']);
|
|
56
|
+
assert.equal(slotRegistrations[0].view, slotRegistrations[1].view);
|
|
57
|
+
const view = slotRegistrations[0].view;
|
|
58
|
+
const listTree = view({
|
|
59
|
+
toolName: 'gotry_artifacts_list',
|
|
60
|
+
block: { kind: 'tool-result', isError: false, meta: { shape: 'paths', paths: ['/tmp/trip-2027.md'], total: 1, truncated: false }, content: [] },
|
|
61
|
+
});
|
|
62
|
+
assert.equal(listTree.props['data-gotry-artifact-card'], 'list');
|
|
63
|
+
assert.equal(listTree.props['data-gotry-artifact-state'], 'ok');
|
|
64
|
+
const malformedTree = view({ toolName: 'gotry_artifacts_read', block: { kind: 'tool-result', isError: false, meta: { shape: 'bad' }, content: [{ type: 'text', text: 'raw fallback' }] } });
|
|
65
|
+
assert.equal(malformedTree.props['data-gotry-artifact-card'], 'read');
|
|
66
|
+
assert.equal(malformedTree.props['data-gotry-artifact-state'], 'ok');
|
|
67
|
+
const requireRoot = createRequire(join(ROOT, 'package.json'));
|
|
68
|
+
assert.ok(requireRoot.resolve('./client/client.js'));
|
|
69
|
+
// issue #441: an HTML artifact is previewed as source text only. The client half
|
|
70
|
+
// must not gain a raw-HTML injection API or an embedded browsing context.
|
|
71
|
+
for (const banned of ['dangerouslySetInnerHTML', 'innerHTML', 'outerHTML', 'insertAdjacentHTML', 'srcdoc', 'iframe', 'document.write', 'eval(']) {
|
|
72
|
+
assert.ok(!source.includes(banned), `client bundle must not use ${banned}`);
|
|
73
|
+
}
|
|
74
|
+
const textNodes = [];
|
|
75
|
+
const elementTypes = [];
|
|
76
|
+
const forbiddenProps = [];
|
|
77
|
+
function walkTree(node) {
|
|
78
|
+
if (typeof node === 'string') {
|
|
79
|
+
textNodes.push(node);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (Array.isArray(node)) {
|
|
83
|
+
for (const child of node)
|
|
84
|
+
walkTree(child);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const item = node;
|
|
88
|
+
if (!item || typeof item !== 'object')
|
|
89
|
+
return;
|
|
90
|
+
elementTypes.push(item.type);
|
|
91
|
+
for (const key of ['dangerouslySetInnerHTML', 'innerHTML', 'outerHTML', 'srcdoc']) {
|
|
92
|
+
if (key in (item.props ?? {}))
|
|
93
|
+
forbiddenProps.push(key);
|
|
94
|
+
}
|
|
95
|
+
for (const child of item.children ?? [])
|
|
96
|
+
walkTree(child);
|
|
97
|
+
}
|
|
98
|
+
const hostileLines = [
|
|
99
|
+
'<script>globalThis.__gotry441Pwned = true</script>',
|
|
100
|
+
'<img src=x onerror="globalThis.__gotry441Pwned = true">',
|
|
101
|
+
'<iframe src="https://example.invalid/track"></iframe>',
|
|
102
|
+
'<a href="javascript:globalThis.__gotry441Pwned=true">点击</a>',
|
|
103
|
+
];
|
|
104
|
+
const hostileTree = view({
|
|
105
|
+
toolName: 'gotry_artifacts_read',
|
|
106
|
+
block: {
|
|
107
|
+
kind: 'tool-result',
|
|
108
|
+
isError: false,
|
|
109
|
+
meta: {
|
|
110
|
+
path: '/tmp/trip-2027.html', offset: 1, totalLines: hostileLines.length, lang: 'html',
|
|
111
|
+
source: 'cwd', version: 'a1b2c3d4e5f6',
|
|
112
|
+
lines: hostileLines.map((text, index) => ({ number: index + 1, text })),
|
|
113
|
+
},
|
|
114
|
+
content: [],
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
assert.equal(hostileTree.props['data-gotry-artifact-card'], 'read');
|
|
118
|
+
assert.equal(hostileTree.props['data-gotry-artifact-state'], 'ok');
|
|
119
|
+
walkTree(hostileTree);
|
|
120
|
+
assert.deepEqual(forbiddenProps, [], `预览树不得出现 raw HTML 注入 props,实际 ${forbiddenProps.join(',')}`);
|
|
121
|
+
assert.ok(!elementTypes.includes('iframe'), '预览树不得创建 iframe');
|
|
122
|
+
for (const line of hostileLines) {
|
|
123
|
+
assert.ok(textNodes.includes(line), `HTML 源码行必须以文本节点原样呈现:${line}`);
|
|
124
|
+
}
|
|
125
|
+
function collect(node, out = []) {
|
|
126
|
+
if (Array.isArray(node)) {
|
|
127
|
+
for (const child of node)
|
|
128
|
+
collect(child, out);
|
|
129
|
+
return out;
|
|
130
|
+
}
|
|
131
|
+
const item = node;
|
|
132
|
+
if (!item || typeof item !== 'object')
|
|
133
|
+
return out;
|
|
134
|
+
out.push({ type: item.type, props: item.props ?? {}, children: item.children ?? [] });
|
|
135
|
+
for (const child of item.children ?? [])
|
|
136
|
+
collect(child, out);
|
|
137
|
+
return out;
|
|
138
|
+
}
|
|
139
|
+
function textsOf(node) {
|
|
140
|
+
const out = [];
|
|
141
|
+
const visit = (value) => {
|
|
142
|
+
if (typeof value === 'string') {
|
|
143
|
+
out.push(value);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
if (Array.isArray(value)) {
|
|
147
|
+
for (const child of value)
|
|
148
|
+
visit(child);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const item = value;
|
|
152
|
+
if (!item || typeof item !== 'object')
|
|
153
|
+
return;
|
|
154
|
+
for (const child of item.children ?? [])
|
|
155
|
+
visit(child);
|
|
156
|
+
};
|
|
157
|
+
visit(node.children);
|
|
158
|
+
return out;
|
|
159
|
+
}
|
|
160
|
+
// HTML list entries are opened through the host's native HTML preview, which is a
|
|
161
|
+
// different action from reading source text: it must be labelled and explained.
|
|
162
|
+
const mixedTree = view({
|
|
163
|
+
toolName: 'gotry_artifacts_list',
|
|
164
|
+
block: {
|
|
165
|
+
kind: 'tool-result', isError: false,
|
|
166
|
+
meta: { shape: 'paths', paths: ['/tmp/trip-2027.md', '/tmp/trip-2027.html', '/tmp/Trip-2027.HTM'], total: 3, truncated: false },
|
|
167
|
+
content: [],
|
|
168
|
+
},
|
|
169
|
+
});
|
|
170
|
+
const buttons = collect(mixedTree).filter(node => node.type === 'button');
|
|
171
|
+
assert.equal(buttons.length, 3, `3 条路径应有 3 个按钮,实际 ${buttons.length}`);
|
|
172
|
+
const mdButton = buttons.find(node => node.props['data-gotry-artifact-path'] === '/tmp/trip-2027.md');
|
|
173
|
+
const htmlButtons = buttons.filter(node => String(node.props['data-gotry-artifact-path']).toLowerCase().endsWith('.htm') ||
|
|
174
|
+
String(node.props['data-gotry-artifact-path']).toLowerCase().endsWith('.html'));
|
|
175
|
+
assert.equal(htmlButtons.length, 2, `.html 与 .HTM 都应识别为 HTML 预览,实际 ${htmlButtons.length}`);
|
|
176
|
+
assert.equal(mdButton?.props['data-gotry-artifact-open'], 'artifact', 'markdown 打开动作保持原文');
|
|
177
|
+
assert.equal(mdButton?.props['aria-label'], 'Open artifact /tmp/trip-2027.md', 'markdown 可访问标签不变');
|
|
178
|
+
assert.equal(mdButton?.props.title, undefined, 'markdown 不新增提示(行为不变)');
|
|
179
|
+
assert.ok(!textsOf(mdButton).includes('HTML 预览'), 'markdown 条目不显示 HTML 预览徽标');
|
|
180
|
+
for (const button of htmlButtons) {
|
|
181
|
+
const path = String(button.props['data-gotry-artifact-path']);
|
|
182
|
+
assert.equal(button.props['data-gotry-artifact-open'], 'html-preview', `HTML 条目应标记为原生预览动作:${path}`);
|
|
183
|
+
assert.equal(button.props['aria-label'], `Open HTML preview ${path}`, `HTML 条目可访问标签应显式声明 HTML 预览:${path}`);
|
|
184
|
+
const title = String(button.props.title ?? '');
|
|
185
|
+
assert.ok(title.includes('脚本') && title.includes('可能'), `提示应说明脚本可能运行:${title}`);
|
|
186
|
+
assert.ok(!/sandbox|renderer|iframe|宿主|DSH|dsh/i.test(title), `提示不得使用基础设施术语:${title}`);
|
|
187
|
+
assert.ok(textsOf(button).includes('HTML 预览'), `HTML 条目应有可见的 HTML 预览指示:${path}`);
|
|
188
|
+
}
|
|
189
|
+
// Source read card: HTML is identified as source text, still plain text nodes.
|
|
190
|
+
const htmlSourceTree = view({
|
|
191
|
+
toolName: 'gotry_artifacts_read',
|
|
192
|
+
block: {
|
|
193
|
+
kind: 'tool-result', isError: false,
|
|
194
|
+
meta: {
|
|
195
|
+
path: '/tmp/trip-2027.html', offset: 1, totalLines: hostileLines.length, lang: 'html',
|
|
196
|
+
source: 'cwd', version: 'a1b2c3d4e5f6',
|
|
197
|
+
lines: hostileLines.map((text, index) => ({ number: index + 1, text })),
|
|
198
|
+
},
|
|
199
|
+
content: [],
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
assert.equal(htmlSourceTree.props['data-gotry-artifact-source'], 'html', 'HTML 读卡应显式标注源码来源');
|
|
203
|
+
assert.ok(textsOf(htmlSourceTree).includes('HTML 源码预览(只读文本)'), 'HTML 读卡标题应明确是源码文本');
|
|
204
|
+
const htmlSourceNodes = collect(htmlSourceTree);
|
|
205
|
+
assert.ok(!htmlSourceNodes.some(node => 'dangerouslySetInnerHTML' in node.props || 'innerHTML' in node.props), 'HTML 读卡不得注入原始 HTML');
|
|
206
|
+
assert.ok(htmlSourceNodes.every(node => node.type !== 'iframe'), 'HTML 读卡不得内嵌浏览上下文');
|
|
207
|
+
for (const line of hostileLines) {
|
|
208
|
+
assert.ok(textsOf({ children: [htmlSourceTree] }).includes(line), `HTML 读卡仍以文本节点逐字呈现:${line}`);
|
|
209
|
+
}
|
|
210
|
+
const mdSourceTree = view({
|
|
211
|
+
toolName: 'gotry_artifacts_read',
|
|
212
|
+
block: {
|
|
213
|
+
kind: 'tool-result', isError: false,
|
|
214
|
+
meta: { path: '/tmp/trip-2027.md', offset: 1, totalLines: 1, lang: 'markdown', source: 'cwd', version: 'f6e5d4c3b2a1', lines: [{ number: 1, text: '# 行程' }] },
|
|
215
|
+
content: [],
|
|
216
|
+
},
|
|
217
|
+
});
|
|
218
|
+
assert.equal(mdSourceTree.props['data-gotry-artifact-source'], undefined, 'markdown 读卡不得被标注为 HTML 源码');
|
|
219
|
+
assert.ok(textsOf(mdSourceTree).includes('产物预览'), 'markdown 读卡标题保持原样');
|
|
220
|
+
console.log('ARTIFACT CLIENT CONTRACT: package export + web manifest + lazy loader + 2 keyed views + malformed fallback + HTML source-as-text + explicit HTML preview action OK');
|