@danceiny/gotry 0.0.1-rc.21 → 0.0.1-rc.24
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 +102 -194
- package/README.zh-CN.md +115 -210
- package/bin/gotry-backend.js +53 -0
- package/bin/gotry-bootstrap.js +466 -35
- package/bin/gotry-inner.js +255 -36
- package/bin/gotry-process-liveness.d.ts +27 -0
- package/bin/gotry-process-liveness.js +97 -0
- package/bin/gotry-runtime-resolution.d.ts +1 -1
- package/bin/gotry-runtime-resolution.js +2 -2
- package/client/client.js +174 -0
- package/cordis.gotry-patch.yml +70 -93
- package/dist/capabilities/agent-reach-deep.js +45 -122
- package/dist/capabilities/agent-reach.js +63 -148
- package/dist/capabilities/anything.js +89 -75
- package/dist/capabilities/artifacts.js +123 -104
- package/dist/capabilities/channel-health.js +65 -45
- package/dist/capabilities/channel-registry.js +108 -87
- package/dist/capabilities/doctor.js +357 -235
- package/dist/capabilities/effect.js +223 -309
- package/dist/capabilities/fact-log.js +28 -14
- package/dist/capabilities/flyai.js +245 -156
- package/dist/capabilities/ground-transfer.js +509 -0
- package/dist/capabilities/hbcli.js +144 -148
- package/dist/capabilities/hotelbyte-transaction.js +194 -0
- package/dist/capabilities/incident-log.js +131 -61
- package/dist/capabilities/model-override.js +30 -10
- package/dist/capabilities/opensky.js +54 -43
- package/dist/capabilities/resilience.js +50 -32
- package/dist/capabilities/session/action-cache.js +50 -44
- package/dist/capabilities/session/adapters/ctrip-flight.js +119 -62
- package/dist/capabilities/session/adapters/ctrip-hotel.js +125 -110
- package/dist/capabilities/session/adapters/dida-portal.js +206 -0
- package/dist/capabilities/session/adapters/meituan-local.js +35 -54
- package/dist/capabilities/session/adapters/rail-12306.js +169 -112
- package/dist/capabilities/session/benchmark.js +85 -149
- package/dist/capabilities/session/extension-bridge.js +320 -259
- package/dist/capabilities/session/extension-channel.js +57 -76
- package/dist/capabilities/session/extension-distribution.js +115 -119
- package/dist/capabilities/session/extract.js +31 -21
- package/dist/capabilities/session/golden-score.js +55 -33
- package/dist/capabilities/session/health-watch.js +146 -154
- package/dist/capabilities/session/read-guard.js +55 -47
- package/dist/capabilities/session/static-flight-golden.js +49 -36
- package/dist/capabilities/session/transport.js +54 -61
- package/dist/capabilities/session/wizard.js +63 -93
- package/dist/capabilities/session-consent.js +143 -47
- package/dist/capabilities/session-login.js +95 -126
- package/dist/capabilities/session-search.js +391 -253
- package/dist/capabilities/sponsor-plugin.js +341 -0
- package/dist/capabilities/visa-policy.js +87 -73
- package/dist/capabilities/weather.js +163 -235
- package/dist/scripts/action-cache-tests.js +24 -59
- package/dist/scripts/agent-planning-turn-deadline-e2e.js +91 -142
- package/dist/scripts/agent-planning-turn-deadline-tests.js +80 -176
- package/dist/scripts/agent-reach-deep-tests.js +30 -40
- package/dist/scripts/agent-reach-tests.js +26 -18
- package/dist/scripts/agent-reach-wrapper-tests.js +46 -50
- package/dist/scripts/anything-tests.js +58 -62
- package/dist/scripts/artifact-client-contract-tests.js +69 -0
- package/dist/scripts/artifacts-capability-tests.js +235 -0
- package/dist/scripts/async-collect.js +26 -15
- package/dist/scripts/benchmark-environment-bridge-e2e.js +287 -684
- package/dist/scripts/benchmark-environment-bridge-tests.js +818 -3123
- package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +66 -279
- package/dist/scripts/booking-copilot-availability-policy-tests.js +153 -1257
- package/dist/scripts/booking-copilot-bin-proof-tests.js +22 -45
- package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +64 -76
- package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +69 -199
- package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +393 -759
- package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +33 -75
- package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +60 -110
- package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +28 -66
- package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +72 -271
- package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +73 -275
- package/dist/scripts/booking-copilot-runtime-proof-tests.js +784 -3398
- package/dist/scripts/booking-copilot-server-proof-tests.js +63 -168
- package/dist/scripts/booking-copilot-startup-proof-tests.js +38 -124
- 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 +61 -123
- package/dist/scripts/booking-surface-contract-proof-tests.js +152 -1167
- package/dist/scripts/bootstrap-tests.js +1383 -128
- package/dist/scripts/build-changelog.js +89 -130
- package/dist/scripts/build-metrics-report.js +135 -143
- package/dist/scripts/changelog-tests.js +35 -82
- package/dist/scripts/channel-probe-tests.js +44 -116
- package/dist/scripts/channel-probe.js +84 -167
- package/dist/scripts/channel-registry-tests.js +97 -185
- package/dist/scripts/companion-tests.js +25 -70
- package/dist/scripts/dida-cookie-probe.js +87 -0
- package/dist/scripts/dida-sw-probe.js +114 -0
- package/dist/scripts/diff-test.js +17 -12
- package/dist/scripts/doctor-tests.js +428 -120
- package/dist/scripts/dsh-artifact-e2e.js +150 -0
- package/dist/scripts/dsh-artifact-web-e2e.js +443 -0
- package/dist/scripts/dsh-http-proxy-sse-proof.js +90 -0
- package/dist/scripts/dsh-runtime-closure-tests.js +110 -153
- package/dist/scripts/dsh-runtime-closure.js +75 -63
- package/dist/scripts/dsh-session-v3-migration-proof.js +106 -0
- package/dist/scripts/dsh-subprocess-local-proof.js +149 -0
- package/dist/scripts/dsh-target-closure-proof.js +178 -0
- package/dist/scripts/effect-tests.js +165 -552
- package/dist/scripts/engine-run.js +1 -3
- package/dist/scripts/engine-tests.js +16 -10
- package/dist/scripts/evaluation-cadence-tests.js +69 -242
- package/dist/scripts/evaluation-contract-tests.js +193 -499
- package/dist/scripts/extension-distribution-cli.js +19 -15
- package/dist/scripts/extension-distribution-tests.js +98 -211
- package/dist/scripts/extension-tests.js +366 -389
- package/dist/scripts/fact-gate-tests.js +725 -263
- 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-tests.js +325 -68
- 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/gotry-backend-kernel-tests.js +79 -0
- package/dist/scripts/ground-transfer-tests.js +956 -0
- package/dist/scripts/hbcli-e2e-tests.js +71 -90
- 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 +41 -115
- package/dist/scripts/health-watch-cli.js +42 -28
- 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 +16 -9
- 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 +547 -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/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/ledger-repair-apply-tests.js +316 -0
- package/dist/scripts/ledger-repair-plan-tests.js +375 -0
- package/dist/scripts/ledger-tests.js +325 -340
- package/dist/scripts/ledger-workflow-crash.js +10 -20
- package/dist/scripts/map-tools-vendor-package-proof.js +206 -134
- 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 +474 -222
- package/dist/scripts/memory-value-tests.js +328 -0
- package/dist/scripts/metrics-report-tests.js +62 -199
- package/dist/scripts/model-override-e2e.js +66 -105
- package/dist/scripts/nightly-evidence-tests.js +64 -89
- package/dist/scripts/nightly-evidence.js +108 -111
- package/dist/scripts/nudge-digest.js +39 -28
- package/dist/scripts/onboarding-tests.js +63 -88
- package/dist/scripts/opensky-check.js +18 -13
- package/dist/scripts/opensky-tests.js +28 -28
- package/dist/scripts/persona-surface-guard-tests.js +37 -12
- package/dist/scripts/pnpm-dsh-closure-proof.js +2 -5
- package/dist/scripts/policy-anchor-359-registered-e2e.js +214 -0
- package/dist/scripts/price-drift-tests.js +126 -227
- package/dist/scripts/price-drift-watch.js +209 -253
- package/dist/scripts/probe-poi-tests.js +52 -45
- package/dist/scripts/product-metrics.js +187 -273
- package/dist/scripts/publish-preverify.js +47 -41
- package/dist/scripts/realtime-pricing-tests.js +37 -76
- package/dist/scripts/replay-async.js +20 -18
- package/dist/scripts/replay-real.js +16 -18
- package/dist/scripts/replay.js +52 -82
- package/dist/scripts/session-attach-diagnose.js +16 -12
- package/dist/scripts/session-attach-poc.js +34 -37
- package/dist/scripts/session-benchmark.js +66 -147
- package/dist/scripts/session-dida-live-e2e.js +151 -0
- package/dist/scripts/session-extract-tests.js +14 -35
- package/dist/scripts/session-login.js +14 -13
- package/dist/scripts/session-tests.js +545 -583
- package/dist/scripts/sf-live-benchmark.js +92 -110
- package/dist/scripts/sf-live-cli-tests.js +2 -9
- package/dist/scripts/sf-soft-score-tests.js +19 -60
- package/dist/scripts/sf-summary-tests.js +149 -0
- package/dist/scripts/sf-summary.js +466 -84
- package/dist/scripts/skeleton-check.js +16 -14
- package/dist/scripts/skeleton-integration-test.js +11 -10
- package/dist/scripts/skills-contract-tests.js +51 -46
- package/dist/scripts/smoke-session-gate-tests.js +12 -20
- package/dist/scripts/smoke.js +541 -422
- package/dist/scripts/sponsor-reuse-tests.js +262 -0
- package/dist/scripts/state-cli-tests.js +226 -101
- package/dist/scripts/state-cli.js +549 -212
- package/dist/scripts/static-golden-tests.js +46 -180
- 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 +46 -93
- package/dist/scripts/turn-handoff-collect.js +71 -99
- package/dist/scripts/turn-policy-tests.js +28 -29
- package/dist/scripts/typed-contract-canary.js +77 -162
- 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 +31 -44
- package/dist/scripts/weather-tests.js +121 -543
- package/dist/scripts/wish-channel-gate-tests.js +29 -86
- 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 +18 -12
- package/dist/src/artifact-gate.js +652 -221
- package/dist/src/backend/kernel.js +91 -0
- package/dist/src/backend/modules/booking-copilot.js +55 -0
- package/dist/src/backend/modules/booking-executor.js +124 -0
- package/dist/src/backend/modules/session-search.js +194 -0
- package/dist/src/benchmark-agent-conformance.js +296 -262
- package/dist/src/benchmark-environment-bridge.js +298 -413
- package/dist/src/benchmark-headless-child-diagnostics.js +93 -100
- package/dist/src/benchmark-tool-isolation.js +94 -67
- package/dist/src/bookable-facts.js +299 -174
- package/dist/src/booking-saga.js +64 -120
- package/dist/src/booking-surface/availability-policy.js +443 -576
- package/dist/src/booking-surface/cancel-refund-commission.js +379 -0
- package/dist/src/booking-surface/contracts.js +24 -80
- package/dist/src/booking-surface/dsh-planner.js +510 -281
- package/dist/src/booking-surface/dsh-plugin.js +17 -1
- package/dist/src/booking-surface/error-codes.js +82 -10
- package/dist/src/booking-surface/index.js +0 -3
- package/dist/src/booking-surface/profile.js +10 -54
- package/dist/src/booking-surface/recovery-chain.js +367 -0
- package/dist/src/booking-surface/runtime.js +765 -891
- package/dist/src/booking-surface/server.js +200 -251
- package/dist/src/booking-surface/startup.js +58 -54
- package/dist/src/booking-surface/validation.js +150 -218
- 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 +82 -120
- package/dist/src/engine.js +253 -239
- package/dist/src/evaluation-cadence.js +72 -209
- package/dist/src/evaluation-contracts.js +220 -843
- package/dist/src/flight-pack-adapter.js +54 -0
- package/dist/src/flight-pack-contract.js +2 -0
- package/dist/src/gotry-backend.js +70 -0
- package/dist/src/hotel-date-gate.js +118 -0
- package/dist/src/i18n.js +18 -7
- package/dist/src/index.js +1425 -1629
- package/dist/src/journey.js +132 -81
- package/dist/src/ledger-repair-apply.js +538 -0
- package/dist/src/ledger-repair-plan.js +463 -0
- package/dist/src/loop.js +257 -166
- 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 +63 -72
- package/dist/src/slot-spec.js +84 -106
- package/dist/src/state-ledger.js +310 -471
- 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 +121 -127
- package/dist/src/turn-policy.js +61 -89
- package/dist/src/tz-resolver.js +143 -0
- package/dist/src/unified.js +504 -381
- package/dist/src/wish-pool.js +39 -14
- package/dist/src/write-gate.js +495 -0
- package/dist/src/z3-shared.js +273 -7
- package/extension/README.md +4 -3
- package/extension/background.js +125 -14
- package/extension/content-bridge.js +23 -1
- package/extension/content-main.js +15 -4
- package/extension/manifest.json +16 -8
- package/package.json +251 -220
- package/ts/capabilities/agent-reach.ts +4 -4
- package/ts/capabilities/anything.ts +1 -1
- package/ts/capabilities/artifacts.ts +46 -9
- package/ts/capabilities/flyai.ts +156 -37
- package/ts/capabilities/hbcli.ts +1 -1
- package/ts/capabilities/incident-log.ts +88 -59
- package/ts/capabilities/session/adapters/ctrip-flight.ts +99 -36
- package/ts/capabilities/session/adapters/dida-portal.ts +250 -0
- package/ts/capabilities/session/adapters/rail-12306.ts +123 -24
- package/ts/capabilities/session/extension-bridge.ts +226 -101
- package/ts/capabilities/session/extension-channel.ts +22 -9
- package/ts/capabilities/session/wizard.ts +2 -2
- package/ts/capabilities/session-consent.ts +98 -14
- package/ts/capabilities/session-login.ts +1 -0
- package/ts/capabilities/session-search.ts +315 -31
- package/ts/dsh-runtime/vendor/README.md +8 -4
- package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +7 -1
- package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +5 -3
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +1 -1
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +1 -1
- package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +6 -6
- package/ts/package.json +236 -16
- package/ts/scripts/map-tools-vendor-package-proof.ts +152 -31
- package/ts/scripts/state-cli.ts +418 -51
- package/ts/src/artifact-gate.ts +561 -15
- package/ts/src/benchmark-environment-bridge.ts +37 -20
- package/ts/src/bookable-facts.ts +183 -7
- package/ts/src/booking-surface/cancel-refund-commission.ts +488 -0
- package/ts/src/booking-surface/dsh-planner.ts +240 -32
- package/ts/src/booking-surface/dsh-plugin.js +17 -1
- package/ts/src/booking-surface/error-codes.ts +75 -0
- package/ts/src/booking-surface/recovery-chain.ts +409 -0
- package/ts/src/booking-surface/server.ts +84 -51
- package/ts/src/booking-surface/validation.ts +2 -0
- package/ts/src/contracts.ts +12 -2
- package/ts/src/dsh-llm.ts +4 -8
- package/ts/src/index.ts +609 -90
- package/ts/src/loop.ts +116 -7
- package/ts/src/memory-capture.ts +227 -3
- package/ts/src/mock-llm.ts +4 -8
- package/ts/src/model.ts +88 -2
- package/ts/src/state-ledger.ts +47 -29
- package/ts/src/subagent-job-id-guard.ts +72 -0
- package/ts/src/time-anchor.ts +217 -13
- package/ts/src/unified.ts +316 -54
|
@@ -1,45 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ReadGuard:会话检索面的只读物理隔离(RFC docs/rfc/user-session-data-rfc.md §3.3)。
|
|
3
|
+
*
|
|
4
|
+
* 写不是「被禁止的行为」,是「不存在的原语」——WriteGate(L0-L4)的检索态前置:
|
|
5
|
+
* ① 网络层:route 拦截——命中硬支付模式(任意方法)或写方法+写URL模式 → abort + 审计落盘;
|
|
6
|
+
* ② DOM 层:提交类按钮文本黑名单,从快照/断言文本中剔除(模型看不到可点的提交件);
|
|
7
|
+
* ③ fail-closed:guard 未装上,session transport 不允许导航(openSession 装不上即整会话失败)。
|
|
8
|
+
*
|
|
9
|
+
* 审计:append-only JSONL(session-incidents.jsonl,对齐 incident-log 惯例),隔离 stateRoot。
|
|
10
|
+
* 注意:搜索接口多为 POST(如携程 batchSearch),因此写判定必须「方法 × URL 模式」双因子,
|
|
11
|
+
* 不能一刀切禁 POST——batchSearch 不含写词,放行。
|
|
12
|
+
*/
|
|
1
13
|
import { mkdirSync, appendFileSync } from 'node:fs';
|
|
2
14
|
import { dirname } from 'node:path';
|
|
15
|
+
/** 硬支付模式:任意方法(含 GET)都视为写——进支付/收银面本身就是风险 */
|
|
3
16
|
const HARD_PAY_RE = /\/(pay|payment|cashier)(\/|\?|$)/i;
|
|
17
|
+
/** 驼峰复合写词(OTA 常见 /submitOrder、/createOrder):段式正则漏接,单列 */
|
|
4
18
|
const WRITE_COMPOUND_RE = /(submitorder|createorder|placeorder|cancelorder|refundorder|orderconfirm|orderpay|confirmpay)/i;
|
|
19
|
+
/** 写词 URL 模式:仅在写方法(POST/PUT/DELETE/PATCH)下触发 */
|
|
5
20
|
const WRITE_URL_RE = /\/(order|orders|submit|trade|booking|book|purchase|buy|create|cancel|refund)(\/|\?|$)/i;
|
|
6
|
-
const WRITE_METHODS = new Set([
|
|
7
|
-
|
|
8
|
-
'PUT',
|
|
9
|
-
'DELETE',
|
|
10
|
-
'PATCH'
|
|
11
|
-
]);
|
|
21
|
+
const WRITE_METHODS = new Set(['POST', 'PUT', 'DELETE', 'PATCH']);
|
|
22
|
+
/** DOM 提交件文本黑名单(§3.3-②):命中即从可交互面剔除 */
|
|
12
23
|
export const SUBMIT_TEXT_RE = /下单|去支付|支付|预订|订票|购买|提交订单|确认订单/;
|
|
24
|
+
/** 网络层写判定(纯函数,测试锚点) */
|
|
13
25
|
export function classifyRequest(method, url) {
|
|
14
|
-
if (HARD_PAY_RE.test(url) || WRITE_COMPOUND_RE.test(url))
|
|
15
|
-
|
|
26
|
+
if (HARD_PAY_RE.test(url) || WRITE_COMPOUND_RE.test(url))
|
|
27
|
+
return 'block';
|
|
28
|
+
if (WRITE_METHODS.has(method.toUpperCase()) && WRITE_URL_RE.test(url))
|
|
29
|
+
return 'block';
|
|
16
30
|
return 'allow';
|
|
17
31
|
}
|
|
32
|
+
/** DOM 层提交件过滤(纯函数,测试锚点):true=剔除 */
|
|
18
33
|
export function isSubmitText(text) {
|
|
19
34
|
return SUBMIT_TEXT_RE.test(text ?? '');
|
|
20
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* 装上网络层守卫(fail-closed 的「closed」在调用方:openSession 装不上 guard 即失败,不给无 guard 的会话)。
|
|
38
|
+
* 审计落 auditPath(JSONL append);auditPath 缺省不落盘(仅内存计数)。
|
|
39
|
+
*/
|
|
21
40
|
export async function attachReadGuard(ctx, auditPath) {
|
|
22
41
|
let blocked = 0;
|
|
23
42
|
let total = 0;
|
|
24
|
-
await ctx.route('**/*', async (route)=>{
|
|
43
|
+
await ctx.route('**/*', async (route) => {
|
|
25
44
|
const req = route.request();
|
|
26
45
|
total += 1;
|
|
27
46
|
const verdict = classifyRequest(req.method(), req.url());
|
|
28
47
|
if (verdict === 'block') {
|
|
29
48
|
blocked += 1;
|
|
30
49
|
if (auditPath) {
|
|
31
|
-
const entry = {
|
|
32
|
-
ts: new Date().toISOString(),
|
|
33
|
-
kind: 'blocked-write-request',
|
|
34
|
-
method: req.method(),
|
|
35
|
-
url: req.url().slice(0, 400)
|
|
36
|
-
};
|
|
50
|
+
const entry = { ts: new Date().toISOString(), kind: 'blocked-write-request', method: req.method(), url: req.url().slice(0, 400) };
|
|
37
51
|
try {
|
|
38
|
-
mkdirSync(dirname(auditPath), {
|
|
39
|
-
recursive: true
|
|
40
|
-
});
|
|
52
|
+
mkdirSync(dirname(auditPath), { recursive: true });
|
|
41
53
|
appendFileSync(auditPath, JSON.stringify(entry) + '\n');
|
|
42
|
-
}
|
|
54
|
+
}
|
|
55
|
+
catch { /* 审计失败不阻塞拦截本身 */ }
|
|
43
56
|
}
|
|
44
57
|
await route.abort('blockedbyclient');
|
|
45
58
|
return;
|
|
@@ -47,53 +60,48 @@ export async function attachReadGuard(ctx, auditPath) {
|
|
|
47
60
|
await route.continue();
|
|
48
61
|
});
|
|
49
62
|
return {
|
|
50
|
-
blockedCount: ()=>blocked,
|
|
51
|
-
requestCount: ()=>total
|
|
63
|
+
blockedCount: () => blocked,
|
|
64
|
+
requestCount: () => total,
|
|
52
65
|
};
|
|
53
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* puppeteer 版守卫:对既有页面与新建页面全部开启请求拦截,写请求 abort + 审计。
|
|
69
|
+
* 与 playwright 版共用 classifyRequest 判定与审计条目(单一事实源)。
|
|
70
|
+
*/
|
|
54
71
|
export async function attachReadGuardPuppeteer(browser, auditPath) {
|
|
55
72
|
let blocked = 0;
|
|
56
73
|
let total = 0;
|
|
57
|
-
const wire = (page)=>{
|
|
58
|
-
void (async ()=>{
|
|
74
|
+
const wire = (page) => {
|
|
75
|
+
void (async () => {
|
|
59
76
|
try {
|
|
60
77
|
await page.setRequestInterception(true);
|
|
61
|
-
page.on('request', async (req)=>{
|
|
78
|
+
page.on('request', async (req) => {
|
|
62
79
|
total += 1;
|
|
63
80
|
const verdict = classifyRequest(req.method(), req.url());
|
|
64
81
|
if (verdict === 'block') {
|
|
65
82
|
blocked += 1;
|
|
66
83
|
if (auditPath) {
|
|
67
|
-
const entry = {
|
|
68
|
-
ts: new Date().toISOString(),
|
|
69
|
-
kind: 'blocked-write-request',
|
|
70
|
-
method: req.method(),
|
|
71
|
-
url: req.url().slice(0, 400)
|
|
72
|
-
};
|
|
84
|
+
const entry = { ts: new Date().toISOString(), kind: 'blocked-write-request', method: req.method(), url: req.url().slice(0, 400) };
|
|
73
85
|
try {
|
|
74
|
-
mkdirSync(dirname(auditPath), {
|
|
75
|
-
recursive: true
|
|
76
|
-
});
|
|
86
|
+
mkdirSync(dirname(auditPath), { recursive: true });
|
|
77
87
|
appendFileSync(auditPath, JSON.stringify(entry) + '\n');
|
|
78
|
-
}
|
|
88
|
+
}
|
|
89
|
+
catch { /* 审计失败不阻塞拦截本身 */ }
|
|
79
90
|
}
|
|
80
|
-
await req.abort('blockedbyclient').catch(()=>{});
|
|
91
|
+
await req.abort('blockedbyclient').catch(() => { });
|
|
81
92
|
return;
|
|
82
93
|
}
|
|
83
|
-
await req.continue().catch(()=>{});
|
|
94
|
+
await req.continue().catch(() => { });
|
|
84
95
|
});
|
|
85
|
-
}
|
|
96
|
+
}
|
|
97
|
+
catch { /* 已关闭的 target 容忍 */ }
|
|
86
98
|
})();
|
|
87
99
|
};
|
|
88
|
-
for (const p of
|
|
89
|
-
|
|
90
|
-
|
|
100
|
+
for (const p of await browser.pages())
|
|
101
|
+
wire(p);
|
|
102
|
+
browser.on('targetcreated', (t) => {
|
|
103
|
+
if (t.type() === 'page')
|
|
104
|
+
void t.page().then(wire).catch(() => { });
|
|
91
105
|
});
|
|
92
|
-
return {
|
|
93
|
-
blockedCount: ()=>blocked,
|
|
94
|
-
requestCount: ()=>total
|
|
95
|
-
};
|
|
106
|
+
return { blockedCount: () => blocked, requestCount: () => total };
|
|
96
107
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
//# sourceURL=ts/capabilities/session/read-guard.ts
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { readFileSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
export function parseGoldenSource(args) {
|
|
4
|
-
const raw = args.find((arg)=>arg.startsWith('--golden='))?.slice('--golden='.length) ?? 'manual';
|
|
5
|
-
if (raw === 'manual' || raw === 'flyai' || raw === 'static')
|
|
4
|
+
const raw = args.find((arg) => arg.startsWith('--golden='))?.slice('--golden='.length) ?? 'manual';
|
|
5
|
+
if (raw === 'manual' || raw === 'flyai' || raw === 'static')
|
|
6
|
+
return raw;
|
|
6
7
|
throw new Error(`不支持的 golden vendor: ${raw}`);
|
|
7
8
|
}
|
|
8
9
|
export function loadStaticFlightSnapshot(path = join(import.meta.dirname, '..', '..', 'data', 'sf-static-routes.json')) {
|
|
@@ -11,13 +12,10 @@ export function loadStaticFlightSnapshot(path = join(import.meta.dirname, '..',
|
|
|
11
12
|
throw new Error(`invalid static snapshot schema_version: ${String(isRecord(parsed) ? parsed.schema_version : undefined)}`);
|
|
12
13
|
}
|
|
13
14
|
const source = parsed.source;
|
|
14
|
-
if (!isRecord(source)
|
|
15
|
-
'name',
|
|
16
|
-
|
|
17
|
-
'
|
|
18
|
-
'license',
|
|
19
|
-
'retrieved_at'
|
|
20
|
-
].every((key)=>typeof source[key] === 'string') || !Array.isArray(source.limitations) || !source.limitations.every((item)=>typeof item === 'string')) {
|
|
15
|
+
if (!isRecord(source)
|
|
16
|
+
|| !['name', 'url', 'revision', 'license', 'retrieved_at'].every((key) => typeof source[key] === 'string')
|
|
17
|
+
|| !Array.isArray(source.limitations)
|
|
18
|
+
|| !source.limitations.every((item) => typeof item === 'string')) {
|
|
21
19
|
throw new Error('invalid static snapshot source');
|
|
22
20
|
}
|
|
23
21
|
if (!Array.isArray(parsed.routes) || !parsed.routes.every(isStaticFlightRoute)) {
|
|
@@ -29,15 +27,26 @@ function isRecord(value) {
|
|
|
29
27
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
30
28
|
}
|
|
31
29
|
function isStaticFlightRoute(value) {
|
|
32
|
-
if (!isRecord(value)
|
|
33
|
-
|
|
30
|
+
if (!isRecord(value)
|
|
31
|
+
|| typeof value.query_id !== 'string'
|
|
32
|
+
|| typeof value.from_city !== 'string'
|
|
33
|
+
|| typeof value.to_city !== 'string'
|
|
34
|
+
|| (value.route_kind !== 'direct' && value.route_kind !== 'transfer')
|
|
35
|
+
|| !Array.isArray(value.legs)
|
|
36
|
+
|| value.legs.length === 0)
|
|
37
|
+
return false;
|
|
38
|
+
return value.legs.every((leg) => isRecord(leg)
|
|
39
|
+
&& typeof leg.from_iata === 'string'
|
|
40
|
+
&& typeof leg.to_iata === 'string'
|
|
41
|
+
&& Array.isArray(leg.carrier_codes)
|
|
42
|
+
&& leg.carrier_codes.every((carrier) => typeof carrier === 'string'));
|
|
34
43
|
}
|
|
35
44
|
function provenance(snapshot) {
|
|
36
45
|
return {
|
|
37
46
|
route_source: snapshot?.source.url ?? '',
|
|
38
47
|
route_revision: snapshot?.source.revision ?? '',
|
|
39
48
|
route_license: snapshot?.source.license ?? '',
|
|
40
|
-
band_source: 'sf-golden-manifest.json'
|
|
49
|
+
band_source: 'sf-golden-manifest.json',
|
|
41
50
|
};
|
|
42
51
|
}
|
|
43
52
|
function formatWithOffset(timestampMs, offset) {
|
|
@@ -49,23 +58,24 @@ function formatWithOffset(timestampMs, offset) {
|
|
|
49
58
|
}
|
|
50
59
|
function buildSegments(query, route, manualSegment) {
|
|
51
60
|
if (route.route_kind === 'direct' && route.legs.length === 1) {
|
|
52
|
-
return [
|
|
53
|
-
{
|
|
61
|
+
return [{
|
|
54
62
|
from: query.from,
|
|
55
63
|
to: query.to,
|
|
56
64
|
departure_at: manualSegment.departure_at,
|
|
57
65
|
arrival_at: manualSegment.arrival_at,
|
|
58
|
-
transport_number: `${route.legs[0].carrier_codes[0]}-STATIC
|
|
59
|
-
}
|
|
60
|
-
];
|
|
66
|
+
transport_number: `${route.legs[0].carrier_codes[0]}-STATIC`,
|
|
67
|
+
}];
|
|
61
68
|
}
|
|
62
|
-
if (route.route_kind !== 'transfer' || route.legs.length !== 2)
|
|
69
|
+
if (route.route_kind !== 'transfer' || route.legs.length !== 2)
|
|
70
|
+
return null;
|
|
63
71
|
const departureMs = Date.parse(manualSegment.departure_at);
|
|
64
72
|
const arrivalMs = Date.parse(manualSegment.arrival_at);
|
|
65
|
-
if (!Number.isFinite(departureMs) || !Number.isFinite(arrivalMs) || arrivalMs <= departureMs)
|
|
73
|
+
if (!Number.isFinite(departureMs) || !Number.isFinite(arrivalMs) || arrivalMs <= departureMs)
|
|
74
|
+
return null;
|
|
66
75
|
const offset = manualSegment.departure_at.match(/([+-]\d{2}:\d{2})$/)?.[1] ?? '+08:00';
|
|
67
76
|
const totalMinutes = Math.floor((arrivalMs - departureMs) / 60_000);
|
|
68
|
-
if (totalMinutes < 90)
|
|
77
|
+
if (totalMinutes < 90)
|
|
78
|
+
return null;
|
|
69
79
|
const layoverMinutes = Math.min(60, Math.floor(totalMinutes / 3));
|
|
70
80
|
const travelMinutes = totalMinutes - layoverMinutes;
|
|
71
81
|
const firstTravelMinutes = Math.floor(travelMinutes / 2);
|
|
@@ -77,32 +87,38 @@ function buildSegments(query, route, manualSegment) {
|
|
|
77
87
|
to: middle,
|
|
78
88
|
departure_at: manualSegment.departure_at,
|
|
79
89
|
arrival_at: formatWithOffset(departureMs + firstTravelMinutes * 60_000, offset),
|
|
80
|
-
transport_number: `${route.legs[0].carrier_codes[0]}-STATIC
|
|
90
|
+
transport_number: `${route.legs[0].carrier_codes[0]}-STATIC`,
|
|
81
91
|
},
|
|
82
92
|
{
|
|
83
93
|
from: middle,
|
|
84
94
|
to: query.to,
|
|
85
95
|
departure_at: formatWithOffset(secondDepartureMs, offset),
|
|
86
96
|
arrival_at: manualSegment.arrival_at,
|
|
87
|
-
transport_number: `${route.legs[1].carrier_codes[0]}-STATIC
|
|
88
|
-
}
|
|
97
|
+
transport_number: `${route.legs[1].carrier_codes[0]}-STATIC`,
|
|
98
|
+
},
|
|
89
99
|
];
|
|
90
100
|
}
|
|
91
101
|
export function resolveStaticGolden(input) {
|
|
92
|
-
const route = input.snapshot?.routes.find((candidate)=>candidate.query_id === input.query.id);
|
|
102
|
+
const route = input.snapshot?.routes.find((candidate) => candidate.query_id === input.query.id);
|
|
93
103
|
let fallbackReason;
|
|
94
104
|
if (input.snapshotError) {
|
|
95
105
|
fallbackReason = `static snapshot unavailable: ${input.snapshotError}`;
|
|
96
|
-
}
|
|
106
|
+
}
|
|
107
|
+
else if (!route) {
|
|
97
108
|
fallbackReason = `static route missing for ${input.query.id}`;
|
|
98
|
-
}
|
|
109
|
+
}
|
|
110
|
+
else if (route.from_city !== input.query.from || route.to_city !== input.query.to) {
|
|
99
111
|
fallbackReason = `static route mismatch for ${input.query.id}`;
|
|
100
|
-
}
|
|
112
|
+
}
|
|
113
|
+
else if (route.legs.some((leg) => leg.carrier_codes.length === 0)) {
|
|
101
114
|
fallbackReason = `static carrier coverage missing for ${input.query.id}`;
|
|
102
115
|
}
|
|
103
116
|
const manualSegment = input.manualRecord.route_segments[0];
|
|
104
|
-
const segments = !fallbackReason && route && manualSegment
|
|
105
|
-
|
|
117
|
+
const segments = !fallbackReason && route && manualSegment
|
|
118
|
+
? buildSegments(input.query, route, manualSegment)
|
|
119
|
+
: null;
|
|
120
|
+
if (!fallbackReason && !segments)
|
|
121
|
+
fallbackReason = `static route cannot form comparable record for ${input.query.id}`;
|
|
106
122
|
if (fallbackReason) {
|
|
107
123
|
input.warn?.(`[sf-live-benchmark] static vendor failed for ${input.query.id}: ${fallbackReason}; fallback=manual-golden`);
|
|
108
124
|
return {
|
|
@@ -111,7 +127,7 @@ export function resolveStaticGolden(input) {
|
|
|
111
127
|
record: input.manualRecord,
|
|
112
128
|
fallback_reason: fallbackReason,
|
|
113
129
|
estimated_fields: [],
|
|
114
|
-
provenance: provenance(input.snapshot)
|
|
130
|
+
provenance: provenance(input.snapshot),
|
|
115
131
|
};
|
|
116
132
|
}
|
|
117
133
|
return {
|
|
@@ -121,17 +137,14 @@ export function resolveStaticGolden(input) {
|
|
|
121
137
|
...input.manualRecord,
|
|
122
138
|
route_segments: segments,
|
|
123
139
|
journey_type: route.route_kind,
|
|
124
|
-
source: 'static-openflights+manual-band'
|
|
140
|
+
source: 'static-openflights+manual-band',
|
|
125
141
|
},
|
|
126
142
|
estimated_fields: [
|
|
127
143
|
'route_segments[].departure_at',
|
|
128
144
|
'route_segments[].arrival_at',
|
|
129
145
|
'route_segments[].transport_number',
|
|
130
|
-
'price'
|
|
146
|
+
'price',
|
|
131
147
|
],
|
|
132
|
-
provenance: provenance(input.snapshot)
|
|
148
|
+
provenance: provenance(input.snapshot),
|
|
133
149
|
};
|
|
134
150
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
//# sourceURL=ts/capabilities/session/static-flight-golden.ts
|
|
@@ -1,13 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SessionTransport(会话检索传输层,RFC §3.2;2026-08-28 定案 puppeteer-core):
|
|
3
|
+
* - mode=cdp(默认):attach 用户日常 Chrome——Chrome 144+ 调试服务(chrome://inspect 开关)
|
|
4
|
+
* 与 playwright 不兼容(握手后 CDP 初始化悬挂,实测三轮),与 puppeteer 完全兼容(实测 2256 cookies)。
|
|
5
|
+
* 发现走 user-data-dir 的 DevToolsActivePort 文件(HTTP 发现面已硬化 404;Origin 头=403,安全设计)。
|
|
6
|
+
* close() 只 disconnect,绝不关用户浏览器。
|
|
7
|
+
* - mode=persistent(测试/后备):puppeteer.launch 专用 profile(测试用 mktemp 隔离匿名态)。
|
|
8
|
+
* fail-closed(RFC §3.3-④):guard 装不上 = 整个会话打不开——不存在「无守卫的会话」这一形态。
|
|
9
|
+
* 永不抛错:任何启动失败降级为 TransportFailure,由 session-search 编排层消费。
|
|
10
|
+
*/
|
|
1
11
|
import { readFileSync } from 'node:fs';
|
|
2
12
|
import { homedir } from 'node:os';
|
|
3
13
|
import { attachReadGuardPuppeteer } from './read-guard.js';
|
|
14
|
+
/**
|
|
15
|
+
* puppeteer-core 为可选依赖(D-14:产品运行时零硬依赖,缺则优雅降级)。
|
|
16
|
+
* 顶层动态 import——npm 形态若未装 puppeteer-core,openSession 返回 TransportFailure
|
|
17
|
+
* 而非在模块加载期炸掉整个插件(2026-08-28 发布面实测:静态 import 会拖垮 index.ts 加载链)。
|
|
18
|
+
*/
|
|
4
19
|
async function loadPuppeteer() {
|
|
5
20
|
try {
|
|
6
21
|
return await import('puppeteer-core');
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
};
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return { missing: true };
|
|
11
25
|
}
|
|
12
26
|
}
|
|
13
27
|
function devtoolsWsEndpoint() {
|
|
@@ -15,102 +29,81 @@ function devtoolsWsEndpoint() {
|
|
|
15
29
|
const udd = process.env.CHROME_USER_DATA_DIR ?? `${homedir()}/Library/Application Support/Google/Chrome`;
|
|
16
30
|
const [port, wsPath] = readFileSync(`${udd}/DevToolsActivePort`, 'utf8').trim().split('\n');
|
|
17
31
|
if (!port || !wsPath?.startsWith('/devtools/browser/')) {
|
|
18
|
-
return {
|
|
19
|
-
err: `DevToolsActivePort 内容异常: ${String(port)}/${String(wsPath)}`
|
|
20
|
-
};
|
|
32
|
+
return { err: `DevToolsActivePort 内容异常: ${String(port)}/${String(wsPath)}` };
|
|
21
33
|
}
|
|
22
|
-
return {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
return {
|
|
27
|
-
err: '日常 Chrome 未开调试端口。开启方法:Chrome 打开 chrome://inspect/#remote-debugging → 打开开关(Chrome 144+)'
|
|
28
|
-
};
|
|
34
|
+
return { ws: `ws://127.0.0.1:${port.trim()}${wsPath.trim()}` };
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return { err: '日常 Chrome 未开调试端口。开启方法:Chrome 打开 chrome://inspect/#remote-debugging → 打开开关(Chrome 144+)' };
|
|
29
38
|
}
|
|
30
39
|
}
|
|
31
40
|
export async function openSession(opts = {}) {
|
|
32
41
|
const pp = await loadPuppeteer();
|
|
33
42
|
if ('missing' in pp) {
|
|
34
|
-
return {
|
|
35
|
-
ok: false,
|
|
36
|
-
summary: 'puppeteer-core 未安装(可选依赖):会话检索不可用,官方通道 gotry_flyai_search 仍可用。安装:npm i -D puppeteer-core'
|
|
37
|
-
};
|
|
43
|
+
return { ok: false, summary: 'puppeteer-core 未安装(可选依赖):会话检索不可用,官方通道 gotry_flyai_search 仍可用。安装:npm i -D puppeteer-core' };
|
|
38
44
|
}
|
|
39
45
|
const puppeteer = pp.default;
|
|
40
|
-
const useCdp = opts.mode === 'cdp' || opts.mode !== 'persistent' && !opts.profileDir;
|
|
46
|
+
const useCdp = opts.mode === 'cdp' || (opts.mode !== 'persistent' && !opts.profileDir);
|
|
41
47
|
let browser;
|
|
42
48
|
let isCdp = false;
|
|
43
49
|
if (useCdp) {
|
|
44
50
|
const d = devtoolsWsEndpoint();
|
|
45
|
-
if ('err' in d)
|
|
46
|
-
ok: false,
|
|
47
|
-
summary: d.err
|
|
48
|
-
};
|
|
51
|
+
if ('err' in d)
|
|
52
|
+
return { ok: false, summary: d.err };
|
|
49
53
|
try {
|
|
50
|
-
browser = await puppeteer.connect({
|
|
51
|
-
browserWSEndpoint: d.ws,
|
|
52
|
-
defaultViewport: null
|
|
53
|
-
});
|
|
54
|
+
browser = await puppeteer.connect({ browserWSEndpoint: d.ws, defaultViewport: null });
|
|
54
55
|
isCdp = true;
|
|
55
|
-
}
|
|
56
|
+
}
|
|
57
|
+
catch (e) {
|
|
56
58
|
const msg = e instanceof Error ? e.message : e?.message ?? JSON.stringify(e).slice(0, 200);
|
|
57
|
-
return {
|
|
58
|
-
ok: false,
|
|
59
|
-
summary: `cdp attach 失败:${String(msg).split('\n')[0]}`
|
|
60
|
-
};
|
|
59
|
+
return { ok: false, summary: `cdp attach 失败:${String(msg).split('\n')[0]}` };
|
|
61
60
|
}
|
|
62
|
-
}
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
63
|
const { tmpdir } = await import('node:os');
|
|
64
64
|
const profileDir = opts.profileDir ?? `${tmpdir()}/gotry-session-profile`;
|
|
65
65
|
try {
|
|
66
|
-
browser = await puppeteer.launch({
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
});
|
|
71
|
-
} catch (e) {
|
|
72
|
-
return {
|
|
73
|
-
ok: false,
|
|
74
|
-
summary: `chrome launch failed: ${e instanceof Error ? e.message.split('\n')[0] : String(e)}`
|
|
75
|
-
};
|
|
66
|
+
browser = await puppeteer.launch({ channel: 'chrome', headless: opts.headless ?? true, userDataDir: profileDir });
|
|
67
|
+
}
|
|
68
|
+
catch (e) {
|
|
69
|
+
return { ok: false, summary: `chrome launch failed: ${e instanceof Error ? e.message.split('\n')[0] : String(e)}` };
|
|
76
70
|
}
|
|
77
71
|
}
|
|
72
|
+
// fail-closed:guard 装不上即断开返回失败——不给无守卫的检索会话形态
|
|
73
|
+
// (唯一豁免:登录 bootstrap 显式 guard:false,见 TransportOptions 注释)
|
|
78
74
|
let guard;
|
|
79
75
|
if (opts.guard !== false) {
|
|
80
76
|
try {
|
|
81
77
|
guard = await attachReadGuardPuppeteer(browser, opts.auditPath);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
summary: `read-guard attach failed: ${e instanceof Error ? e.message.split('\n')[0] : String(e)}`
|
|
87
|
-
};
|
|
78
|
+
}
|
|
79
|
+
catch (e) {
|
|
80
|
+
await (isCdp ? browser.disconnect() : browser.close()).catch(() => { });
|
|
81
|
+
return { ok: false, summary: `read-guard attach failed: ${e instanceof Error ? e.message.split('\n')[0] : String(e)}` };
|
|
88
82
|
}
|
|
89
83
|
}
|
|
84
|
+
// 标签页纪律:ownPage=自己开的新页(newPage:true)——用它,收尾按 closeOwnPage 关;
|
|
85
|
+
// 否则沿用既有首页(仅 persistent 兼容形态;cdp 检索/登录一律 newPage)
|
|
90
86
|
let ownPage = false;
|
|
91
87
|
let page;
|
|
92
88
|
if (opts.newPage) {
|
|
93
89
|
page = await browser.newPage();
|
|
94
90
|
ownPage = true;
|
|
95
|
-
}
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
96
93
|
page = (await browser.pages())[0] ?? await browser.newPage();
|
|
97
94
|
}
|
|
98
95
|
return {
|
|
99
96
|
ok: true,
|
|
100
97
|
browser,
|
|
101
98
|
page,
|
|
102
|
-
guard: guard ?? {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
close: async ()=>{
|
|
99
|
+
guard: guard ?? { blockedCount: () => 0, requestCount: () => 0 },
|
|
100
|
+
close: async () => {
|
|
101
|
+
// 自己开的标签页按 closeOwnPage 收尾(登录引导保持 false——登录页留给用户);
|
|
102
|
+
// cdp:只断开连接,绝不关用户浏览器;persistent:关自己拉起的实例
|
|
107
103
|
if (ownPage && (opts.closeOwnPage ?? true)) {
|
|
108
|
-
await page.close().catch(()=>{});
|
|
104
|
+
await page.close().catch(() => { });
|
|
109
105
|
}
|
|
110
|
-
await (isCdp ? browser.disconnect() : browser.close()).catch(()=>{});
|
|
111
|
-
}
|
|
106
|
+
await (isCdp ? browser.disconnect() : browser.close()).catch(() => { });
|
|
107
|
+
},
|
|
112
108
|
};
|
|
113
109
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
//# sourceURL=ts/capabilities/session/transport.ts
|