@danceiny/gotry 0.0.1-rc.16 → 0.0.1-rc.17
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 +47 -13
- package/README.zh-CN.md +20 -10
- package/bin/gotry-booking-copilot.js +53 -0
- package/bin/gotry-bootstrap.js +111 -51
- package/bin/gotry-inner.js +442 -60
- package/bin/gotry-runtime-resolution.d.ts +27 -0
- package/bin/gotry-runtime-resolution.js +50 -0
- package/bin/gotry.js +1 -1
- package/cordis.gotry-patch.yml +5 -1
- package/dist/capabilities/agent-reach-deep.js +1 -1
- package/dist/capabilities/agent-reach.js +1 -1
- package/dist/capabilities/anything.js +1 -1
- package/dist/capabilities/artifacts.js +1 -1
- package/dist/capabilities/effect.js +1 -1
- package/dist/capabilities/fact-log.js +1 -1
- package/dist/capabilities/flyai.js +20 -6
- package/dist/capabilities/hbcli.js +1 -1
- package/dist/capabilities/incident-log.js +1 -1
- package/dist/capabilities/model-override.js +18 -0
- package/dist/capabilities/opensky.js +1 -1
- package/dist/capabilities/resilience.js +1 -1
- package/dist/capabilities/session/action-cache.js +1 -1
- package/dist/capabilities/session/adapters/ctrip-flight.js +1 -1
- package/dist/capabilities/session/adapters/meituan-local.js +1 -1
- package/dist/capabilities/session/benchmark.js +1 -1
- package/dist/capabilities/session/extension-bridge.js +19 -6
- package/dist/capabilities/session/extension-channel.js +3 -3
- package/dist/capabilities/session/extension-distribution.js +234 -0
- package/dist/capabilities/session/extract.js +1 -1
- package/dist/capabilities/session/golden-score.js +92 -0
- package/dist/capabilities/session/health-watch.js +1 -1
- package/dist/capabilities/session/read-guard.js +1 -1
- package/dist/capabilities/session/static-flight-golden.js +137 -0
- package/dist/capabilities/session/transport.js +1 -1
- package/dist/capabilities/session/wizard.js +21 -251
- package/dist/capabilities/session-consent.js +1 -1
- package/dist/capabilities/session-login.js +11 -5
- package/dist/capabilities/session-search.js +46 -4
- package/dist/capabilities/weather.js +168 -46
- package/dist/data/session-golden-20.json +25 -0
- package/dist/data/sf-golden-manifest.json +102 -0
- package/dist/data/sf-static-routes.json +91 -0
- package/dist/scripts/action-cache-tests.js +1 -1
- package/dist/scripts/agent-planning-budget-e2e.js +227 -0
- package/dist/scripts/agent-planning-budget-tests.js +173 -0
- package/dist/scripts/agent-reach-deep-tests.js +1 -1
- package/dist/scripts/agent-reach-tests.js +1 -1
- package/dist/scripts/agent-reach-wrapper-tests.js +1 -1
- package/dist/scripts/anything-tests.js +1 -1
- package/dist/scripts/async-collect.js +1 -1
- package/dist/scripts/benchmark-environment-bridge-e2e.js +981 -0
- package/dist/scripts/benchmark-environment-bridge-tests.js +2544 -0
- package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +335 -0
- package/dist/scripts/booking-copilot-availability-policy-v2-tests.js +1355 -0
- package/dist/scripts/booking-copilot-bin-proof-tests.js +89 -0
- package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +113 -0
- package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +356 -0
- package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +557 -0
- package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +140 -0
- package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +202 -0
- package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +102 -0
- package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +374 -0
- package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +447 -0
- package/dist/scripts/booking-copilot-runtime-proof-tests.js +205 -0
- package/dist/scripts/booking-copilot-server-proof-tests.js +317 -0
- package/dist/scripts/booking-copilot-startup-proof-tests.js +283 -0
- package/dist/scripts/booking-copilot-v2-runtime-proof-tests.js +3935 -0
- package/dist/scripts/booking-saga-tests.js +1 -1
- package/dist/scripts/booking-surface-contract-proof-tests.js +393 -0
- package/dist/scripts/booking-surface-v2-contract-proof-tests.js +1174 -0
- package/dist/scripts/bootstrap-tests.js +30 -10
- package/dist/scripts/build-changelog.js +1 -1
- package/dist/scripts/changelog-tests.js +1 -1
- package/dist/scripts/companion-tests.js +1 -1
- package/dist/scripts/diff-test.js +1 -1
- package/dist/scripts/dsh-runtime-closure-tests.js +225 -0
- package/dist/scripts/dsh-runtime-closure.js +150 -0
- package/dist/scripts/effect-tests.js +1 -1
- package/dist/scripts/engine-run.js +1 -1
- package/dist/scripts/engine-tests.js +1 -1
- package/dist/scripts/evaluation-cadence-tests.js +347 -0
- package/dist/scripts/evaluation-contract-tests.js +574 -0
- package/dist/scripts/extension-distribution-cli.js +35 -0
- package/dist/scripts/extension-distribution-tests.js +341 -0
- package/dist/scripts/extension-tests.js +128 -23
- package/dist/scripts/fact-gate-tests.js +1 -1
- package/dist/scripts/flyai-tests.js +1 -1
- package/dist/scripts/hbcli-e2e-tests.js +1 -1
- package/dist/scripts/hbcli-tests.js +1 -1
- package/dist/scripts/health-watch-cli.js +1 -1
- package/dist/scripts/i18n-tests.js +1 -1
- package/dist/scripts/incident-tests.js +1 -1
- package/dist/scripts/journey-tests.js +1 -1
- package/dist/scripts/ledger-tests.js +1 -1
- package/dist/scripts/ledger-workflow-crash.js +1 -1
- package/dist/scripts/memory-capture-tests.js +1 -1
- package/dist/scripts/memory-decay-tests.js +1 -1
- package/dist/scripts/memory-metrics.js +1 -1
- package/dist/scripts/memory-value-report.js +1 -1
- package/dist/scripts/model-override-e2e.js +176 -0
- package/dist/scripts/nightly-evidence-tests.js +1 -1
- package/dist/scripts/nightly-evidence.js +1 -1
- package/dist/scripts/nudge-digest.js +1 -1
- package/dist/scripts/onboarding-tests.js +21 -53
- package/dist/scripts/opensky-check.js +1 -1
- package/dist/scripts/opensky-tests.js +1 -1
- package/dist/scripts/pnpm-dsh-closure-proof.js +20 -0
- package/dist/scripts/price-drift-tests.js +1 -1
- package/dist/scripts/price-drift-watch.js +1 -1
- package/dist/scripts/probe-poi-tests.js +1 -1
- package/dist/scripts/product-metrics.js +1 -1
- package/dist/scripts/publish-preverify.js +40 -4
- package/dist/scripts/realtime-pricing-tests.js +1 -1
- package/dist/scripts/replay-async.js +1 -1
- package/dist/scripts/replay-real.js +1 -1
- package/dist/scripts/replay.js +1 -1
- package/dist/scripts/session-attach-diagnose.js +1 -1
- package/dist/scripts/session-attach-poc.js +1 -1
- package/dist/scripts/session-benchmark.js +1 -1
- package/dist/scripts/session-extract-tests.js +1 -1
- package/dist/scripts/session-login.js +1 -1
- package/dist/scripts/session-tests.js +70 -20
- package/dist/scripts/sf-live-benchmark.js +338 -0
- package/dist/scripts/sf-live-cli-tests.js +21 -0
- package/dist/scripts/sf-soft-score-tests.js +108 -0
- package/dist/scripts/sf-summary.js +93 -0
- package/dist/scripts/skeleton-check.js +1 -1
- package/dist/scripts/skeleton-integration-test.js +1 -1
- package/dist/scripts/skills-contract-tests.js +1 -1
- package/dist/scripts/smoke-session-gate-tests.js +29 -0
- package/dist/scripts/smoke.js +79 -33
- package/dist/scripts/state-cli-tests.js +1 -1
- package/dist/scripts/state-cli.js +1 -1
- package/dist/scripts/static-golden-tests.js +299 -0
- package/dist/scripts/time-eval-tests.js +1 -1
- package/dist/scripts/travel-timeline-tests.js +1 -1
- package/dist/scripts/unified-tests.js +1 -1
- package/dist/scripts/weather-tests.js +694 -44
- package/dist/scripts/z3-race-tests.js +1 -1
- package/dist/src/artifact-gate.js +1 -1
- package/dist/src/benchmark-agent-conformance.js +370 -0
- package/dist/src/benchmark-environment-bridge.js +384 -0
- package/dist/src/benchmark-headless-child-diagnostics.js +173 -0
- package/dist/src/benchmark-tool-isolation.js +124 -0
- package/dist/src/bookable-facts.js +1 -1
- package/dist/src/booking-saga.js +1 -1
- package/dist/src/booking-surface/availability-policy-v2.js +830 -0
- package/dist/src/booking-surface/canonical-schema.js +113 -0
- package/dist/src/booking-surface/contracts-v2.js +89 -0
- package/dist/src/booking-surface/contracts.js +46 -0
- package/dist/src/booking-surface/dsh-planner.js +453 -0
- package/dist/src/booking-surface/dsh-plugin.js +93 -0
- package/dist/src/booking-surface/error-codes.js +94 -0
- package/dist/src/booking-surface/index.js +15 -0
- package/dist/src/booking-surface/profile.js +68 -0
- package/dist/src/booking-surface/runtime-v2.js +1771 -0
- package/dist/src/booking-surface/runtime.js +351 -0
- package/dist/src/booking-surface/server-v2.js +334 -0
- package/dist/src/booking-surface/server.js +302 -0
- package/dist/src/booking-surface/startup.js +159 -0
- package/dist/src/booking-surface/validation-v2.js +319 -0
- package/dist/src/booking-surface/validation.js +809 -0
- package/dist/src/bridge.js +1 -1
- package/dist/src/companions.js +1 -1
- package/dist/src/contracts.js +1 -1
- package/dist/src/dsh-llm.js +1 -1
- package/dist/src/engine.js +1 -1
- package/dist/src/evaluation-cadence.js +234 -0
- package/dist/src/evaluation-contracts.js +906 -0
- package/dist/src/i18n.js +1 -1
- package/dist/src/index.js +50 -19
- package/dist/src/journey.js +1 -1
- package/dist/src/loop.js +1 -1
- package/dist/src/memory-capture.js +1 -1
- package/dist/src/memory-decay.js +1 -1
- package/dist/src/memory-utility.js +1 -1
- package/dist/src/mock-llm.js +1 -1
- package/dist/src/model.js +1 -1
- package/dist/src/realtime-pricing.js +1 -1
- package/dist/src/slot-spec.js +1 -1
- package/dist/src/state-ledger.js +2 -1
- package/dist/src/time-anchor.js +1 -1
- package/dist/src/tool-budget.js +136 -0
- package/dist/src/tool-packet.js +1 -1
- package/dist/src/travel-slots.js +1 -1
- package/dist/src/travel-timeline.js +1 -1
- package/dist/src/unified.js +1 -1
- package/dist/src/wish-pool.js +1 -1
- package/dist/src/z3-shared.js +1 -1
- package/extension/README.md +31 -7
- package/package.json +286 -11
- package/schemas/booking.surface.v1.schema.json +927 -0
- package/schemas/booking.surface.v2.schema.json +61 -0
- package/ts/capabilities/flyai.ts +16 -3
- package/ts/capabilities/session/extension-bridge.ts +37 -14
- package/ts/capabilities/session/extension-channel.ts +6 -3
- package/ts/capabilities/session/extension-distribution.ts +264 -0
- package/ts/capabilities/session/golden-score.ts +139 -0
- package/ts/capabilities/session/health-watch.ts +1 -1
- package/ts/capabilities/session/static-flight-golden.ts +209 -0
- package/ts/capabilities/session/wizard.ts +34 -176
- package/ts/capabilities/session-login.ts +15 -5
- package/ts/capabilities/session-search.ts +40 -3
- package/ts/capabilities/weather.ts +141 -52
- package/ts/package.json +3 -3
- package/ts/src/benchmark-agent-conformance.ts +448 -0
- package/ts/src/benchmark-environment-bridge.ts +348 -0
- package/ts/src/benchmark-headless-child-diagnostics.ts +184 -0
- package/ts/src/benchmark-tool-isolation.ts +166 -0
- package/ts/src/booking-surface/availability-policy-v2.ts +523 -0
- package/ts/src/booking-surface/canonical-schema.js +113 -0
- package/ts/src/booking-surface/contracts-v2.ts +118 -0
- package/ts/src/booking-surface/contracts.ts +380 -0
- package/ts/src/booking-surface/dsh-planner.ts +452 -0
- package/ts/src/booking-surface/dsh-plugin.js +93 -0
- package/ts/src/booking-surface/error-codes.ts +101 -0
- package/ts/src/booking-surface/index.ts +12 -0
- package/ts/src/booking-surface/profile.ts +42 -0
- package/ts/src/booking-surface/runtime-v2.ts +1466 -0
- package/ts/src/booking-surface/runtime.ts +483 -0
- package/ts/src/booking-surface/server-v2.ts +247 -0
- package/ts/src/booking-surface/server.ts +324 -0
- package/ts/src/booking-surface/startup.ts +196 -0
- package/ts/src/booking-surface/validation-v2.ts +205 -0
- package/ts/src/booking-surface/validation.ts +453 -0
- package/ts/src/index.ts +64 -11
- package/ts/src/state-ledger.ts +1 -0
- package/ts/src/tool-budget.ts +165 -0
- package/dist/scripts/wizard-bootstrap.js +0 -32
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { SESSION_FIELD_ACCURACY_THRESHOLD } from './benchmark.js';
|
|
2
|
+
function parseHHmm(value) {
|
|
3
|
+
const [hours, minutes] = value.split(':');
|
|
4
|
+
return parseInt(hours, 10) * 60 + parseInt(minutes, 10);
|
|
5
|
+
}
|
|
6
|
+
function parseLocalMinutes(value) {
|
|
7
|
+
const match = value.match(/(\d{2}):(\d{2})/);
|
|
8
|
+
if (!match) return null;
|
|
9
|
+
return parseInt(match[1], 10) * 60 + parseInt(match[2], 10);
|
|
10
|
+
}
|
|
11
|
+
function parseLocalDate(value) {
|
|
12
|
+
return value.match(/^(\d{4}-\d{2}-\d{2})[T ]/)?.[1] ?? null;
|
|
13
|
+
}
|
|
14
|
+
export function scoreSessionAgainstGoldenBand(session, band, goldenSource) {
|
|
15
|
+
const missing = [];
|
|
16
|
+
const hardIncorrect = [];
|
|
17
|
+
const segment = session.route_segments[0];
|
|
18
|
+
if (!session.query_id) missing.push('query_id');
|
|
19
|
+
else if (session.query_id !== band.query_id) hardIncorrect.push('query_id');
|
|
20
|
+
if (!session.currency) missing.push('currency');
|
|
21
|
+
else if (session.currency !== 'CNY') hardIncorrect.push('currency');
|
|
22
|
+
if (!session.source) missing.push('source');
|
|
23
|
+
else if (session.source !== 'ctrip-flight') hardIncorrect.push('source');
|
|
24
|
+
if (!session.verdict) missing.push('verdict');
|
|
25
|
+
else if (session.verdict !== 'hit') hardIncorrect.push('verdict');
|
|
26
|
+
if (!segment) {
|
|
27
|
+
missing.push('route_segments[0].from', 'route_segments[0].to', 'route_segments[0].departure_at', 'route_segments[0].arrival_at', 'route_segments[0].transport_number');
|
|
28
|
+
} else {
|
|
29
|
+
if (!segment.from) missing.push('route_segments[0].from');
|
|
30
|
+
else if (segment.from !== band.from) hardIncorrect.push('route_segments[0].from');
|
|
31
|
+
if (!segment.to) missing.push('route_segments[0].to');
|
|
32
|
+
else if (segment.to !== band.to) hardIncorrect.push('route_segments[0].to');
|
|
33
|
+
if (!segment.departure_at) missing.push('route_segments[0].departure_at');
|
|
34
|
+
else if (parseLocalDate(segment.departure_at) !== band.date) {
|
|
35
|
+
hardIncorrect.push('route_segments[0].departure_at.date');
|
|
36
|
+
}
|
|
37
|
+
if (!segment.arrival_at) missing.push('route_segments[0].arrival_at');
|
|
38
|
+
else if (parseLocalDate(segment.arrival_at) !== band.date) {
|
|
39
|
+
hardIncorrect.push('route_segments[0].arrival_at.date');
|
|
40
|
+
}
|
|
41
|
+
if (!segment.transport_number) missing.push('route_segments[0].transport_number');
|
|
42
|
+
}
|
|
43
|
+
const softChecks = [];
|
|
44
|
+
if (segment?.departure_at) {
|
|
45
|
+
const minutes = parseLocalMinutes(segment.departure_at);
|
|
46
|
+
softChecks.push({
|
|
47
|
+
path: 'route_segments[0].departure_at',
|
|
48
|
+
ok: minutes !== null && minutes >= parseHHmm(band.window_dep_local.earliest) && minutes <= parseHHmm(band.window_dep_local.latest)
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
if (segment?.arrival_at) {
|
|
52
|
+
const minutes = parseLocalMinutes(segment.arrival_at);
|
|
53
|
+
softChecks.push({
|
|
54
|
+
path: 'route_segments[0].arrival_at',
|
|
55
|
+
ok: minutes !== null && minutes >= parseHHmm(band.window_arr_local.earliest) && minutes <= parseHHmm(band.window_arr_local.latest)
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
if (segment?.transport_number) {
|
|
59
|
+
const actual = segment.transport_number.toUpperCase();
|
|
60
|
+
softChecks.push({
|
|
61
|
+
path: 'route_segments[0].transport_number',
|
|
62
|
+
ok: band.known_flights.some((flight)=>actual.startsWith(flight.toUpperCase())) || band.known_flights.some((flight)=>actual.includes(flight.toUpperCase().slice(0, 2)))
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
if (Number.isFinite(session.price) && session.price > 0) {
|
|
66
|
+
const margin = band.price_cny.max * 0.15;
|
|
67
|
+
softChecks.push({
|
|
68
|
+
path: 'price',
|
|
69
|
+
ok: session.price >= band.price_cny.min - margin && session.price <= band.price_cny.max + margin
|
|
70
|
+
});
|
|
71
|
+
} else missing.push('price');
|
|
72
|
+
const softIncorrect = softChecks.filter((check)=>!check.ok).map((check)=>check.path);
|
|
73
|
+
const incorrect = [
|
|
74
|
+
...hardIncorrect,
|
|
75
|
+
...softIncorrect
|
|
76
|
+
];
|
|
77
|
+
const total = 13;
|
|
78
|
+
const correct = Math.max(0, total - new Set(missing).size - incorrect.length);
|
|
79
|
+
const accuracy = total > 0 ? correct / total : 0;
|
|
80
|
+
return {
|
|
81
|
+
pass: missing.length === 0 && hardIncorrect.length === 0 && accuracy >= SESSION_FIELD_ACCURACY_THRESHOLD,
|
|
82
|
+
total,
|
|
83
|
+
correct,
|
|
84
|
+
accuracy,
|
|
85
|
+
missing: Array.from(new Set(missing)),
|
|
86
|
+
incorrect,
|
|
87
|
+
golden_source: goldenSource
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
//# sourceURL=ts/capabilities/session/golden-score.ts
|
|
@@ -213,4 +213,4 @@ export const HEALTH_WATCH_INTERVAL_FLOOR_MS = 1_000;
|
|
|
213
213
|
export const HEALTH_WATCH_INTERVAL_CEIL_MS = EXTENSION_CONNECTED_WINDOW_MS - 1_000;
|
|
214
214
|
|
|
215
215
|
|
|
216
|
-
//# sourceURL
|
|
216
|
+
//# sourceURL=ts/capabilities/session/health-watch.ts
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
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') return raw;
|
|
6
|
+
throw new Error(`不支持的 golden vendor: ${raw}`);
|
|
7
|
+
}
|
|
8
|
+
export function loadStaticFlightSnapshot(path = join(import.meta.dirname, '..', '..', 'data', 'sf-static-routes.json')) {
|
|
9
|
+
const parsed = JSON.parse(readFileSync(path, 'utf8'));
|
|
10
|
+
if (!isRecord(parsed) || parsed.schema_version !== 'sf-static-routes.v1') {
|
|
11
|
+
throw new Error(`invalid static snapshot schema_version: ${String(isRecord(parsed) ? parsed.schema_version : undefined)}`);
|
|
12
|
+
}
|
|
13
|
+
const source = parsed.source;
|
|
14
|
+
if (!isRecord(source) || ![
|
|
15
|
+
'name',
|
|
16
|
+
'url',
|
|
17
|
+
'revision',
|
|
18
|
+
'license',
|
|
19
|
+
'retrieved_at'
|
|
20
|
+
].every((key)=>typeof source[key] === 'string') || !Array.isArray(source.limitations) || !source.limitations.every((item)=>typeof item === 'string')) {
|
|
21
|
+
throw new Error('invalid static snapshot source');
|
|
22
|
+
}
|
|
23
|
+
if (!Array.isArray(parsed.routes) || !parsed.routes.every(isStaticFlightRoute)) {
|
|
24
|
+
throw new Error('invalid static snapshot routes');
|
|
25
|
+
}
|
|
26
|
+
return parsed;
|
|
27
|
+
}
|
|
28
|
+
function isRecord(value) {
|
|
29
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
30
|
+
}
|
|
31
|
+
function isStaticFlightRoute(value) {
|
|
32
|
+
if (!isRecord(value) || typeof value.query_id !== 'string' || typeof value.from_city !== 'string' || typeof value.to_city !== 'string' || value.route_kind !== 'direct' && value.route_kind !== 'transfer' || !Array.isArray(value.legs) || value.legs.length === 0) return false;
|
|
33
|
+
return value.legs.every((leg)=>isRecord(leg) && typeof leg.from_iata === 'string' && typeof leg.to_iata === 'string' && Array.isArray(leg.carrier_codes) && leg.carrier_codes.every((carrier)=>typeof carrier === 'string'));
|
|
34
|
+
}
|
|
35
|
+
function provenance(snapshot) {
|
|
36
|
+
return {
|
|
37
|
+
route_source: snapshot?.source.url ?? '',
|
|
38
|
+
route_revision: snapshot?.source.revision ?? '',
|
|
39
|
+
route_license: snapshot?.source.license ?? '',
|
|
40
|
+
band_source: 'sf-golden-manifest.json'
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function formatWithOffset(timestampMs, offset) {
|
|
44
|
+
const sign = offset.startsWith('-') ? -1 : 1;
|
|
45
|
+
const [hours, minutes] = offset.slice(1).split(':').map(Number);
|
|
46
|
+
const offsetMinutes = sign * ((hours ?? 0) * 60 + (minutes ?? 0));
|
|
47
|
+
const local = new Date(timestampMs + offsetMinutes * 60_000).toISOString().slice(0, 19);
|
|
48
|
+
return `${local}${offset}`;
|
|
49
|
+
}
|
|
50
|
+
function buildSegments(query, route, manualSegment) {
|
|
51
|
+
if (route.route_kind === 'direct' && route.legs.length === 1) {
|
|
52
|
+
return [
|
|
53
|
+
{
|
|
54
|
+
from: query.from,
|
|
55
|
+
to: query.to,
|
|
56
|
+
departure_at: manualSegment.departure_at,
|
|
57
|
+
arrival_at: manualSegment.arrival_at,
|
|
58
|
+
transport_number: `${route.legs[0].carrier_codes[0]}-STATIC`
|
|
59
|
+
}
|
|
60
|
+
];
|
|
61
|
+
}
|
|
62
|
+
if (route.route_kind !== 'transfer' || route.legs.length !== 2) return null;
|
|
63
|
+
const departureMs = Date.parse(manualSegment.departure_at);
|
|
64
|
+
const arrivalMs = Date.parse(manualSegment.arrival_at);
|
|
65
|
+
if (!Number.isFinite(departureMs) || !Number.isFinite(arrivalMs) || arrivalMs <= departureMs) return null;
|
|
66
|
+
const offset = manualSegment.departure_at.match(/([+-]\d{2}:\d{2})$/)?.[1] ?? '+08:00';
|
|
67
|
+
const totalMinutes = Math.floor((arrivalMs - departureMs) / 60_000);
|
|
68
|
+
if (totalMinutes < 90) return null;
|
|
69
|
+
const layoverMinutes = Math.min(60, Math.floor(totalMinutes / 3));
|
|
70
|
+
const travelMinutes = totalMinutes - layoverMinutes;
|
|
71
|
+
const firstTravelMinutes = Math.floor(travelMinutes / 2);
|
|
72
|
+
const secondDepartureMs = arrivalMs - (travelMinutes - firstTravelMinutes) * 60_000;
|
|
73
|
+
const middle = route.legs[0].to_iata;
|
|
74
|
+
return [
|
|
75
|
+
{
|
|
76
|
+
from: query.from,
|
|
77
|
+
to: middle,
|
|
78
|
+
departure_at: manualSegment.departure_at,
|
|
79
|
+
arrival_at: formatWithOffset(departureMs + firstTravelMinutes * 60_000, offset),
|
|
80
|
+
transport_number: `${route.legs[0].carrier_codes[0]}-STATIC`
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
from: middle,
|
|
84
|
+
to: query.to,
|
|
85
|
+
departure_at: formatWithOffset(secondDepartureMs, offset),
|
|
86
|
+
arrival_at: manualSegment.arrival_at,
|
|
87
|
+
transport_number: `${route.legs[1].carrier_codes[0]}-STATIC`
|
|
88
|
+
}
|
|
89
|
+
];
|
|
90
|
+
}
|
|
91
|
+
export function resolveStaticGolden(input) {
|
|
92
|
+
const route = input.snapshot?.routes.find((candidate)=>candidate.query_id === input.query.id);
|
|
93
|
+
let fallbackReason;
|
|
94
|
+
if (input.snapshotError) {
|
|
95
|
+
fallbackReason = `static snapshot unavailable: ${input.snapshotError}`;
|
|
96
|
+
} else if (!route) {
|
|
97
|
+
fallbackReason = `static route missing for ${input.query.id}`;
|
|
98
|
+
} else if (route.from_city !== input.query.from || route.to_city !== input.query.to) {
|
|
99
|
+
fallbackReason = `static route mismatch for ${input.query.id}`;
|
|
100
|
+
} else if (route.legs.some((leg)=>leg.carrier_codes.length === 0)) {
|
|
101
|
+
fallbackReason = `static carrier coverage missing for ${input.query.id}`;
|
|
102
|
+
}
|
|
103
|
+
const manualSegment = input.manualRecord.route_segments[0];
|
|
104
|
+
const segments = !fallbackReason && route && manualSegment ? buildSegments(input.query, route, manualSegment) : null;
|
|
105
|
+
if (!fallbackReason && !segments) fallbackReason = `static route cannot form comparable record for ${input.query.id}`;
|
|
106
|
+
if (fallbackReason) {
|
|
107
|
+
input.warn?.(`[sf-live-benchmark] static vendor failed for ${input.query.id}: ${fallbackReason}; fallback=manual-golden`);
|
|
108
|
+
return {
|
|
109
|
+
requested_source: 'static',
|
|
110
|
+
effective_source: 'manual-golden',
|
|
111
|
+
record: input.manualRecord,
|
|
112
|
+
fallback_reason: fallbackReason,
|
|
113
|
+
estimated_fields: [],
|
|
114
|
+
provenance: provenance(input.snapshot)
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
requested_source: 'static',
|
|
119
|
+
effective_source: 'static-openflights+manual-band',
|
|
120
|
+
record: {
|
|
121
|
+
...input.manualRecord,
|
|
122
|
+
route_segments: segments,
|
|
123
|
+
journey_type: route.route_kind,
|
|
124
|
+
source: 'static-openflights+manual-band'
|
|
125
|
+
},
|
|
126
|
+
estimated_fields: [
|
|
127
|
+
'route_segments[].departure_at',
|
|
128
|
+
'route_segments[].arrival_at',
|
|
129
|
+
'route_segments[].transport_number',
|
|
130
|
+
'price'
|
|
131
|
+
],
|
|
132
|
+
provenance: provenance(input.snapshot)
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
//# sourceURL=ts/capabilities/session/static-flight-golden.ts
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { spawn } from 'node:child_process';
|
|
2
1
|
import { copyFileSync, existsSync, mkdirSync, readdirSync, statSync } from 'node:fs';
|
|
3
|
-
import { homedir
|
|
2
|
+
import { homedir } from 'node:os';
|
|
4
3
|
import { join } from 'node:path';
|
|
5
4
|
const DEFAULT_SOURCE_DIR_CANDIDATES = [
|
|
6
5
|
join(process.cwd(), 'extension'),
|
|
@@ -16,16 +15,6 @@ function resolveExtensionSourceDir() {
|
|
|
16
15
|
export function defaultExtensionDir() {
|
|
17
16
|
return join(homedir(), '.gotry', 'extension');
|
|
18
17
|
}
|
|
19
|
-
function detectPlatform(force) {
|
|
20
|
-
if (force) return force;
|
|
21
|
-
if (process.env.GOTRY_ONBOARDING_HEADLESS === '1') return 'headless';
|
|
22
|
-
const p = platform();
|
|
23
|
-
if (p === 'darwin' || p === 'linux' || p === 'win32') {
|
|
24
|
-
if (p !== 'darwin' && !process.env.DISPLAY) return 'headless';
|
|
25
|
-
return p;
|
|
26
|
-
}
|
|
27
|
-
return 'headless';
|
|
28
|
-
}
|
|
29
18
|
function ensureExtensionFiles(source, target, dryRun) {
|
|
30
19
|
if (dryRun) return {
|
|
31
20
|
step: 'ensure-extension-files',
|
|
@@ -71,246 +60,42 @@ function ensureExtensionFiles(source, target, dryRun) {
|
|
|
71
60
|
};
|
|
72
61
|
}
|
|
73
62
|
}
|
|
74
|
-
function
|
|
63
|
+
async function watchExtensionReady(dryRun, sourceDir, extensionDir) {
|
|
75
64
|
if (dryRun) return {
|
|
76
|
-
step: '
|
|
77
|
-
status: 'skip',
|
|
78
|
-
summary: '[dry-run] skip 打开 chrome://extensions'
|
|
79
|
-
};
|
|
80
|
-
if (plat === 'headless') return {
|
|
81
|
-
step: 'open-chrome-extensions',
|
|
65
|
+
step: 'watch-extension-ready',
|
|
82
66
|
status: 'skip',
|
|
83
|
-
summary: '
|
|
67
|
+
summary: '[dry-run] skip health-watch precheck'
|
|
84
68
|
};
|
|
85
|
-
|
|
86
|
-
if (plat === 'darwin') return {
|
|
87
|
-
bin: 'open',
|
|
88
|
-
args: [
|
|
89
|
-
'-a',
|
|
90
|
-
'Google Chrome',
|
|
91
|
-
'chrome://extensions'
|
|
92
|
-
]
|
|
93
|
-
};
|
|
94
|
-
if (plat === 'linux') return {
|
|
95
|
-
bin: 'xdg-open',
|
|
96
|
-
args: [
|
|
97
|
-
'chrome://extensions'
|
|
98
|
-
]
|
|
99
|
-
};
|
|
100
|
-
return {
|
|
101
|
-
bin: 'cmd',
|
|
102
|
-
args: [
|
|
103
|
-
'/c',
|
|
104
|
-
'start',
|
|
105
|
-
'chrome',
|
|
106
|
-
'chrome://extensions'
|
|
107
|
-
]
|
|
108
|
-
};
|
|
109
|
-
})();
|
|
110
|
-
try {
|
|
111
|
-
const child = sp(cmd.bin, cmd.args, {
|
|
112
|
-
detached: true,
|
|
113
|
-
stdio: 'ignore'
|
|
114
|
-
});
|
|
115
|
-
child.unref?.();
|
|
116
|
-
return {
|
|
117
|
-
step: 'open-chrome-extensions',
|
|
118
|
-
status: 'ok',
|
|
119
|
-
summary: `已打开 chrome://extensions(${plat})`
|
|
120
|
-
};
|
|
121
|
-
} catch (e) {
|
|
69
|
+
if (!existsSync(extensionDir) || !existsSync(join(extensionDir, 'manifest.json'))) {
|
|
122
70
|
return {
|
|
123
|
-
step: '
|
|
71
|
+
step: 'watch-extension-ready',
|
|
124
72
|
status: 'fail',
|
|
125
|
-
summary:
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
async function clipboardExtensionPath(sp, plat, path, dryRun) {
|
|
130
|
-
if (dryRun) return {
|
|
131
|
-
step: 'clipboard-extension-path',
|
|
132
|
-
status: 'skip',
|
|
133
|
-
summary: '[dry-run] skip 剪贴板复制'
|
|
134
|
-
};
|
|
135
|
-
if (plat === 'headless') return {
|
|
136
|
-
step: 'clipboard-extension-path',
|
|
137
|
-
status: 'skip',
|
|
138
|
-
summary: `headless 无剪贴板;扩展目录路径:${path}`
|
|
139
|
-
};
|
|
140
|
-
const cmd = (()=>{
|
|
141
|
-
if (plat === 'darwin') return {
|
|
142
|
-
bin: 'pbcopy',
|
|
143
|
-
args: []
|
|
144
|
-
};
|
|
145
|
-
if (plat === 'linux') return {
|
|
146
|
-
bin: 'xclip',
|
|
147
|
-
args: [
|
|
148
|
-
'-selection',
|
|
149
|
-
'clipboard'
|
|
150
|
-
]
|
|
151
|
-
};
|
|
152
|
-
return {
|
|
153
|
-
bin: 'clip',
|
|
154
|
-
args: []
|
|
155
|
-
};
|
|
156
|
-
})();
|
|
157
|
-
return new Promise((resolveStep)=>{
|
|
158
|
-
let child;
|
|
159
|
-
try {
|
|
160
|
-
child = sp(cmd.bin, cmd.args, {
|
|
161
|
-
stdio: [
|
|
162
|
-
'pipe',
|
|
163
|
-
'ignore',
|
|
164
|
-
'ignore'
|
|
165
|
-
]
|
|
166
|
-
});
|
|
167
|
-
} catch {
|
|
168
|
-
resolveStep({
|
|
169
|
-
step: 'clipboard-extension-path',
|
|
170
|
-
status: 'skip',
|
|
171
|
-
summary: `剪贴板工具不可用(${cmd.bin});扩展目录路径手动复制: ${path}`
|
|
172
|
-
});
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
let settled = false;
|
|
176
|
-
const settle = (s)=>{
|
|
177
|
-
if (settled) return;
|
|
178
|
-
settled = true;
|
|
179
|
-
resolveStep(s);
|
|
180
|
-
};
|
|
181
|
-
child.on('error', ()=>settle({
|
|
182
|
-
step: 'clipboard-extension-path',
|
|
183
|
-
status: 'skip',
|
|
184
|
-
summary: `剪贴板工具启动失败(${cmd.bin});扩展目录路径手动复制: ${path}`
|
|
185
|
-
}));
|
|
186
|
-
child.on('exit', (code)=>{
|
|
187
|
-
if (code === 0) settle({
|
|
188
|
-
step: 'clipboard-extension-path',
|
|
189
|
-
status: 'ok',
|
|
190
|
-
summary: `已复制扩展目录到剪贴板: ${path}`
|
|
191
|
-
});
|
|
192
|
-
else settle({
|
|
193
|
-
step: 'clipboard-extension-path',
|
|
194
|
-
status: 'fail',
|
|
195
|
-
summary: `剪贴板工具退出码 ${code}(${cmd.bin});扩展目录路径手动复制: ${path}`
|
|
196
|
-
});
|
|
197
|
-
});
|
|
198
|
-
try {
|
|
199
|
-
child.stdin?.write(path);
|
|
200
|
-
child.stdin?.end();
|
|
201
|
-
} catch {
|
|
202
|
-
settle({
|
|
203
|
-
step: 'clipboard-extension-path',
|
|
204
|
-
status: 'skip',
|
|
205
|
-
summary: `剪贴板工具 stdin 不可写(${cmd.bin});扩展目录路径手动复制: ${path}`
|
|
206
|
-
});
|
|
207
|
-
}
|
|
208
|
-
});
|
|
209
|
-
}
|
|
210
|
-
function panelGuideTerminal(plat, extensionDir, watchMs) {
|
|
211
|
-
const lines = [
|
|
212
|
-
'┌─ GoTry 扩展安装 ─────────────────────────────────┐',
|
|
213
|
-
'│ 共 3 步,约 30 秒,装完零弹窗 │',
|
|
214
|
-
'│ │',
|
|
215
|
-
'│ ① 在 Chrome 右上角开启「开发者模式」 │',
|
|
216
|
-
`│ ② 点「加载已解压的扩展程序」选这个目录(已复制): │`,
|
|
217
|
-
`│ ${extensionDir}`,
|
|
218
|
-
'│ ③ 弹窗「添加扩展」点「添加」 │',
|
|
219
|
-
`│ │`,
|
|
220
|
-
`│ 后台探活中(最长 ${Math.round(watchMs / 1000)}s)… │`,
|
|
221
|
-
'└───────────────────────────────────────────────────┘'
|
|
222
|
-
];
|
|
223
|
-
if (plat === 'headless') {
|
|
224
|
-
process.stdout.write(lines.join('\n') + '\n');
|
|
225
|
-
return {
|
|
226
|
-
step: 'panel-guide',
|
|
227
|
-
status: 'skip',
|
|
228
|
-
summary: 'headless 终端面板已打印'
|
|
73
|
+
summary: `落位缺失 manifest.json:${extensionDir}`
|
|
229
74
|
};
|
|
230
75
|
}
|
|
231
|
-
process.stdout.write(lines.join('\n') + '\n');
|
|
232
|
-
return {
|
|
233
|
-
step: 'panel-guide',
|
|
234
|
-
status: 'skip',
|
|
235
|
-
summary: '终端面板已打印(GUI 面板降级)'
|
|
236
|
-
};
|
|
237
|
-
}
|
|
238
|
-
function panelGuideGui(sp, plat, extensionDir, dryRun) {
|
|
239
|
-
if (dryRun) return {
|
|
240
|
-
step: 'panel-guide',
|
|
241
|
-
status: 'skip',
|
|
242
|
-
summary: '[dry-run] skip GUI 面板'
|
|
243
|
-
};
|
|
244
|
-
if (plat === 'headless') return panelGuideTerminal(plat, extensionDir, 120_000);
|
|
245
|
-
const message = `在 Chrome 右上角开启「开发者模式」 → 点「加载已解压的扩展程序」 → 选择(已复制):${extensionDir} → 弹窗点「添加扩展」`;
|
|
246
76
|
try {
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
'-e',
|
|
251
|
-
script
|
|
252
|
-
], {
|
|
253
|
-
stdio: 'ignore',
|
|
254
|
-
detached: true
|
|
255
|
-
}).unref?.();
|
|
77
|
+
const srcStat = statSync(sourceDir);
|
|
78
|
+
const dstStat = statSync(extensionDir);
|
|
79
|
+
if (srcStat.mtimeMs > dstStat.mtimeMs) {
|
|
256
80
|
return {
|
|
257
|
-
step: '
|
|
258
|
-
status: '
|
|
259
|
-
summary:
|
|
81
|
+
step: 'watch-extension-ready',
|
|
82
|
+
status: 'fail',
|
|
83
|
+
summary: `扩展文件可能过期(源比落位新);重跑 npx gotry setup`
|
|
260
84
|
};
|
|
261
85
|
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
'--info',
|
|
265
|
-
'--title=GoTry 扩展安装',
|
|
266
|
-
`--text=${message}`
|
|
267
|
-
], {
|
|
268
|
-
stdio: 'ignore',
|
|
269
|
-
detached: true
|
|
270
|
-
});
|
|
271
|
-
child.unref?.();
|
|
272
|
-
child.on('error', ()=>{
|
|
273
|
-
process.stdout.write(`(zenity 不可用,走终端面板)扩展目录: ${extensionDir}\n`);
|
|
274
|
-
});
|
|
86
|
+
const manifest = JSON.parse(await (await import('node:fs/promises')).readFile(join(extensionDir, 'manifest.json'), 'utf8'));
|
|
87
|
+
if (typeof manifest.key !== 'string' || manifest.key.length < 100) {
|
|
275
88
|
return {
|
|
276
|
-
step: '
|
|
277
|
-
status: '
|
|
278
|
-
summary: '
|
|
89
|
+
step: 'watch-extension-ready',
|
|
90
|
+
status: 'fail',
|
|
91
|
+
summary: 'manifest.key 缺失或过短,扩展 ID 不能稳定'
|
|
279
92
|
};
|
|
280
93
|
}
|
|
281
|
-
return panelGuideTerminal(plat, extensionDir, 120_000);
|
|
282
94
|
} catch (e) {
|
|
283
|
-
return panelGuideTerminal(plat, extensionDir, 120_000);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
async function watchExtensionReady(dryRun, sourceDir, extensionDir) {
|
|
287
|
-
if (dryRun) return {
|
|
288
|
-
step: 'watch-extension-ready',
|
|
289
|
-
status: 'skip',
|
|
290
|
-
summary: '[dry-run] skip health-watch'
|
|
291
|
-
};
|
|
292
|
-
if (!existsSync(extensionDir) || !existsSync(join(extensionDir, 'manifest.json'))) {
|
|
293
95
|
return {
|
|
294
96
|
step: 'watch-extension-ready',
|
|
295
97
|
status: 'fail',
|
|
296
|
-
summary:
|
|
297
|
-
};
|
|
298
|
-
}
|
|
299
|
-
const srcStat = statSync(sourceDir);
|
|
300
|
-
const dstStat = statSync(extensionDir);
|
|
301
|
-
if (srcStat.mtimeMs > dstStat.mtimeMs) {
|
|
302
|
-
return {
|
|
303
|
-
step: 'watch-extension-ready',
|
|
304
|
-
status: 'fail',
|
|
305
|
-
summary: `扩展文件可能过期(源比落位新);重跑 npx gotry setup`
|
|
306
|
-
};
|
|
307
|
-
}
|
|
308
|
-
const manifest = JSON.parse(await (await import('node:fs/promises')).readFile(join(extensionDir, 'manifest.json'), 'utf8'));
|
|
309
|
-
if (typeof manifest.key !== 'string' || manifest.key.length < 100) {
|
|
310
|
-
return {
|
|
311
|
-
step: 'watch-extension-ready',
|
|
312
|
-
status: 'fail',
|
|
313
|
-
summary: 'manifest.key 缺失或过短,扩展 ID 不能稳定'
|
|
98
|
+
summary: `静态预检失败: ${e instanceof Error ? e.message.slice(0, 120) : String(e)}`
|
|
314
99
|
};
|
|
315
100
|
}
|
|
316
101
|
return {
|
|
@@ -320,31 +105,16 @@ async function watchExtensionReady(dryRun, sourceDir, extensionDir) {
|
|
|
320
105
|
};
|
|
321
106
|
}
|
|
322
107
|
export async function runOnboardingWizard(opts = {}) {
|
|
323
|
-
const sp = opts.spawn ?? spawn;
|
|
324
108
|
const dryRun = opts.dryRun ?? false;
|
|
325
|
-
const plat = detectPlatform(opts.forcePlatform);
|
|
326
109
|
const extensionDir = opts.extensionDir ?? defaultExtensionDir();
|
|
327
110
|
const sourceDir = opts.sourceDir ?? resolveExtensionSourceDir();
|
|
328
111
|
const steps = [];
|
|
329
112
|
steps.push(ensureExtensionFiles(sourceDir, extensionDir, dryRun));
|
|
330
|
-
steps.push(openChromeExtensions(sp, plat, dryRun));
|
|
331
|
-
if (plat !== 'headless') {
|
|
332
|
-
steps.push(await clipboardExtensionPath(sp, plat, extensionDir, dryRun));
|
|
333
|
-
steps.push(panelGuideGui(sp, plat, extensionDir, dryRun));
|
|
334
|
-
} else {
|
|
335
|
-
steps.push({
|
|
336
|
-
step: 'clipboard-extension-path',
|
|
337
|
-
status: 'skip',
|
|
338
|
-
summary: 'headless 跳过剪贴板'
|
|
339
|
-
});
|
|
340
|
-
steps.push(panelGuideTerminal(plat, extensionDir, 120_000));
|
|
341
|
-
}
|
|
342
113
|
steps.push(await watchExtensionReady(dryRun, sourceDir, extensionDir));
|
|
343
114
|
const ok = steps.every((s)=>s.status !== 'fail');
|
|
344
115
|
return {
|
|
345
116
|
ok,
|
|
346
117
|
steps,
|
|
347
|
-
platform: plat,
|
|
348
118
|
extensionDir
|
|
349
119
|
};
|
|
350
120
|
}
|
|
@@ -357,7 +127,7 @@ export function printWizardResult(result, destination = process.stdout) {
|
|
|
357
127
|
for (const s of result.steps){
|
|
358
128
|
destination.write(`${tag(s)} ${s.step}: ${s.summary}\n`);
|
|
359
129
|
}
|
|
360
|
-
destination.write(`
|
|
130
|
+
destination.write(`extensionDir=${result.extensionDir}; overall=${result.ok ? 'ok' : 'has-failures'}\n`);
|
|
361
131
|
}
|
|
362
132
|
export function describeExtensionDir(extensionDir) {
|
|
363
133
|
if (!existsSync(extensionDir)) return {
|
|
@@ -374,4 +144,4 @@ export function describeExtensionDir(extensionDir) {
|
|
|
374
144
|
}
|
|
375
145
|
|
|
376
146
|
|
|
377
|
-
//# sourceURL
|
|
147
|
+
//# sourceURL=ts/capabilities/session/wizard.ts
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { openSession } from './session/transport.js';
|
|
2
|
-
import { extensionCookieNames, extensionOpenLogin, classifyBridgeFailure
|
|
2
|
+
import { extensionCookieNames, extensionOpenLogin, classifyBridgeFailure } from './session/extension-channel.js';
|
|
3
|
+
import { EXTENSION_STORE_URL } from './session/extension-bridge.js';
|
|
3
4
|
import { resolveTransportMode } from './session-search.js';
|
|
4
5
|
export const LOGIN_TARGETS = {
|
|
5
6
|
'ctrip-flight': {
|
|
@@ -121,15 +122,20 @@ export async function sessionLogin(q = {}) {
|
|
|
121
122
|
}
|
|
122
123
|
async function sessionLoginViaExtension(site, target, q, started, ts) {
|
|
123
124
|
const evidenceTag = `[会话:${site}-login@${ts}]`;
|
|
124
|
-
const quick = (verdict, error)=>
|
|
125
|
+
const quick = (verdict, error)=>{
|
|
126
|
+
const base = {
|
|
125
127
|
ok: false,
|
|
126
128
|
via: 'session-login-error',
|
|
127
129
|
evidence: `[会话:login-error@${ts}] ${error.slice(0, 200)}`,
|
|
128
130
|
latencyMs: Date.now() - started,
|
|
129
131
|
verdict,
|
|
130
132
|
site,
|
|
131
|
-
error:
|
|
132
|
-
}
|
|
133
|
+
error: error.slice(0, 400)
|
|
134
|
+
};
|
|
135
|
+
if (verdict === 'needs-extension') base.installUrl = EXTENSION_STORE_URL;
|
|
136
|
+
if (verdict === 'needs-extension') base.installAction = 'add-to-chrome';
|
|
137
|
+
return base;
|
|
138
|
+
};
|
|
133
139
|
const pre = await extensionCookieNames({
|
|
134
140
|
site,
|
|
135
141
|
domain: target.domain,
|
|
@@ -192,4 +198,4 @@ async function sessionLoginViaExtension(site, target, q, started, ts) {
|
|
|
192
198
|
}
|
|
193
199
|
|
|
194
200
|
|
|
195
|
-
//# sourceURL
|
|
201
|
+
//# sourceURL=ts/capabilities/session-login.ts
|