@danceiny/gotry 0.0.1-rc.16 → 0.0.1-rc.18
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 +161 -116
- package/README.zh-CN.md +173 -144
- package/bin/gotry-booking-copilot.js +53 -0
- package/bin/gotry-bootstrap.js +113 -66
- package/bin/gotry-inner.js +436 -70
- 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 +45 -39
- 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,176 @@
|
|
|
1
|
+
import { createServer } from 'node:http';
|
|
2
|
+
import { existsSync, mkdtempSync, writeFileSync, rmSync } from 'node:fs';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { spawn } from 'node:child_process';
|
|
6
|
+
const BOOT_TIMEOUT_MS = 120_000;
|
|
7
|
+
async function startMockRelay() {
|
|
8
|
+
const bodies = [];
|
|
9
|
+
const server = createServer((req, res)=>{
|
|
10
|
+
if (req.method !== 'POST' || !req.url?.endsWith('/chat/completions')) {
|
|
11
|
+
res.writeHead(404).end('not found');
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const chunks = [];
|
|
15
|
+
req.on('data', (c)=>chunks.push(c));
|
|
16
|
+
req.on('end', ()=>{
|
|
17
|
+
try {
|
|
18
|
+
bodies.push(JSON.parse(Buffer.concat(chunks).toString('utf-8')));
|
|
19
|
+
} catch {
|
|
20
|
+
bodies.push({});
|
|
21
|
+
}
|
|
22
|
+
const chunk = (delta, finish)=>`data: ${JSON.stringify({
|
|
23
|
+
id: 'e2e',
|
|
24
|
+
object: 'chat.completion.chunk',
|
|
25
|
+
created: 1,
|
|
26
|
+
model: 'mock',
|
|
27
|
+
choices: [
|
|
28
|
+
{
|
|
29
|
+
index: 0,
|
|
30
|
+
delta,
|
|
31
|
+
finish_reason: finish
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
})}\n\n`;
|
|
35
|
+
res.writeHead(200, {
|
|
36
|
+
'content-type': 'text/event-stream',
|
|
37
|
+
'cache-control': 'no-cache'
|
|
38
|
+
});
|
|
39
|
+
res.write(chunk({
|
|
40
|
+
role: 'assistant',
|
|
41
|
+
content: 'ok'
|
|
42
|
+
}, null));
|
|
43
|
+
res.write(chunk({}, 'stop'));
|
|
44
|
+
res.write('data: [DONE]\n\n');
|
|
45
|
+
res.end();
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
await new Promise((resolve)=>server.listen(0, '127.0.0.1', resolve));
|
|
49
|
+
const port = server.address().port;
|
|
50
|
+
return {
|
|
51
|
+
port,
|
|
52
|
+
bodies,
|
|
53
|
+
close: ()=>new Promise((resolve)=>server.close(()=>resolve()))
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
async function runScenario(s, packageBin) {
|
|
57
|
+
const relay = await startMockRelay();
|
|
58
|
+
const dshHome = mkdtempSync(join(tmpdir(), 'gotry-77-dsh-home-'));
|
|
59
|
+
const childCwd = mkdtempSync(join(tmpdir(), 'gotry-77-cwd-'));
|
|
60
|
+
try {
|
|
61
|
+
if (s.userLayerModel) {
|
|
62
|
+
writeFileSync(join(dshHome, 'settings.yaml'), `agent-default-model:\n provider: deepseek-official\n model: ${s.userLayerModel}\n`);
|
|
63
|
+
}
|
|
64
|
+
const env = {
|
|
65
|
+
...process.env,
|
|
66
|
+
LLM_API_KEY: 'e2e-mock-key',
|
|
67
|
+
LLM_BASE_URL: `http://127.0.0.1:${relay.port}/v1`,
|
|
68
|
+
DSH_HOME: dshHome
|
|
69
|
+
};
|
|
70
|
+
delete env['GOTRY_LLM_MODEL'];
|
|
71
|
+
if (s.llmModel) env['LLM_MODEL'] = s.llmModel;
|
|
72
|
+
else delete env['LLM_MODEL'];
|
|
73
|
+
const child = spawn(packageBin, [
|
|
74
|
+
'reply with the word ok'
|
|
75
|
+
], {
|
|
76
|
+
env,
|
|
77
|
+
cwd: childCwd,
|
|
78
|
+
stdio: [
|
|
79
|
+
'ignore',
|
|
80
|
+
'pipe',
|
|
81
|
+
'pipe'
|
|
82
|
+
]
|
|
83
|
+
});
|
|
84
|
+
let logTail = '';
|
|
85
|
+
child.stdout.on('data', (d)=>{
|
|
86
|
+
logTail = (logTail + d).slice(-2000);
|
|
87
|
+
});
|
|
88
|
+
child.stderr.on('data', (d)=>{
|
|
89
|
+
logTail = (logTail + d).slice(-2000);
|
|
90
|
+
});
|
|
91
|
+
const exit = await new Promise((resolve)=>{
|
|
92
|
+
const timer = setTimeout(()=>{
|
|
93
|
+
child.kill('SIGKILL');
|
|
94
|
+
resolve(null);
|
|
95
|
+
}, BOOT_TIMEOUT_MS);
|
|
96
|
+
child.on('exit', (code)=>{
|
|
97
|
+
clearTimeout(timer);
|
|
98
|
+
resolve(code);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
if (relay.bodies.length === 0) {
|
|
102
|
+
return {
|
|
103
|
+
ok: false,
|
|
104
|
+
detail: `中转未收到任何请求(exit=${exit});尾部日志: ${logTail.slice(-400)}`
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
const models = relay.bodies.map((b)=>String(b.model));
|
|
108
|
+
const bad = models.filter((m)=>m !== s.expectModel);
|
|
109
|
+
return bad.length === 0 ? {
|
|
110
|
+
ok: true,
|
|
111
|
+
detail: `${models.length} 个请求体 model 全部 = ${s.expectModel}(exit=${exit})`
|
|
112
|
+
} : {
|
|
113
|
+
ok: false,
|
|
114
|
+
detail: `请求体 model 不符:期望 ${s.expectModel},实际 ${JSON.stringify(models)}`
|
|
115
|
+
};
|
|
116
|
+
} finally{
|
|
117
|
+
await relay.close();
|
|
118
|
+
rmSync(dshHome, {
|
|
119
|
+
recursive: true,
|
|
120
|
+
force: true
|
|
121
|
+
});
|
|
122
|
+
rmSync(childCwd, {
|
|
123
|
+
recursive: true,
|
|
124
|
+
force: true
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
async function main() {
|
|
129
|
+
const packageBin = process.env.GOTRY_MODEL_OVERRIDE_E2E_BIN;
|
|
130
|
+
if (!packageBin || !existsSync(packageBin)) {
|
|
131
|
+
console.error('GOTRY_MODEL_OVERRIDE_E2E_BIN 必须指向当前 tarball 的 clean installed-package bin');
|
|
132
|
+
process.exit(2);
|
|
133
|
+
}
|
|
134
|
+
await runAll(packageBin);
|
|
135
|
+
}
|
|
136
|
+
async function runAll(packageBin) {
|
|
137
|
+
const scenarios = [
|
|
138
|
+
{
|
|
139
|
+
name: '① 设 LLM_MODEL(干净 DSH_HOME)',
|
|
140
|
+
llmModel: 'gotry-e2e-model',
|
|
141
|
+
expectModel: 'gotry-e2e-model'
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
name: '② 设 LLM_MODEL + 用户层已选模型',
|
|
145
|
+
llmModel: 'gotry-e2e-model',
|
|
146
|
+
userLayerModel: 'user-picked-model',
|
|
147
|
+
expectModel: 'gotry-e2e-model'
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
name: '③ 不设 LLM_MODEL(干净 DSH_HOME)',
|
|
151
|
+
expectModel: 'deepseek-v4-flash'
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
name: '④ 不设 LLM_MODEL + 用户层已选模型',
|
|
155
|
+
userLayerModel: 'user-picked-model',
|
|
156
|
+
expectModel: 'user-picked-model'
|
|
157
|
+
}
|
|
158
|
+
];
|
|
159
|
+
let fail = 0;
|
|
160
|
+
for (const s of scenarios){
|
|
161
|
+
process.stdout.write(`${s.name} … `);
|
|
162
|
+
const t0 = Date.now();
|
|
163
|
+
const r = await runScenario(s, packageBin);
|
|
164
|
+
console.log(`${r.ok ? 'PASS' : 'FAIL'}(${((Date.now() - t0) / 1000).toFixed(1)}s)${r.detail}`);
|
|
165
|
+
if (!r.ok) fail = 1;
|
|
166
|
+
}
|
|
167
|
+
if (fail) {
|
|
168
|
+
console.error('\nMODEL OVERRIDE E2E FAIL');
|
|
169
|
+
process.exit(1);
|
|
170
|
+
}
|
|
171
|
+
console.log('\nMODEL OVERRIDE E2E OK');
|
|
172
|
+
}
|
|
173
|
+
await main();
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
//# sourceURL=ts/scripts/model-override-e2e.ts
|
|
@@ -183,4 +183,4 @@ ok('dry-run mock 全链演练 + real_llm=false + 零落盘');
|
|
|
183
183
|
console.log(`nightly-evidence tests: ${passed} 组断言全绿(offline,真跑不在 CI)`);
|
|
184
184
|
|
|
185
185
|
|
|
186
|
-
//# sourceURL
|
|
186
|
+
//# sourceURL=ts/scripts/nightly-evidence-tests.ts
|
|
@@ -37,27 +37,20 @@ async function asyncSleep(ms) {
|
|
|
37
37
|
await new Promise((resolve)=>setTimeout(resolve, ms));
|
|
38
38
|
}
|
|
39
39
|
console.log('ONBOARDING UX (§40)');
|
|
40
|
-
await check('1. wizard --dry-run
|
|
41
|
-
const { spawn } = captureSpawn();
|
|
40
|
+
await check('1. wizard --dry-run 零网络零浏览器零 GUI spawn,exit 0,2 步齐全', async ()=>{
|
|
42
41
|
const result = await runOnboardingWizard({
|
|
43
|
-
dryRun: true
|
|
44
|
-
forcePlatform: 'darwin',
|
|
45
|
-
spawn
|
|
42
|
+
dryRun: true
|
|
46
43
|
});
|
|
47
44
|
assert.equal(result.ok, true, `wizard ok 应 true,实际 ${JSON.stringify(result.steps)}`);
|
|
48
|
-
assert.equal(result.steps.length,
|
|
45
|
+
assert.equal(result.steps.length, 2, `应有 2 步,实际 ${result.steps.length}`);
|
|
49
46
|
const expected = [
|
|
50
47
|
'ensure-extension-files',
|
|
51
|
-
'open-chrome-extensions',
|
|
52
|
-
'clipboard-extension-path',
|
|
53
|
-
'panel-guide',
|
|
54
48
|
'watch-extension-ready'
|
|
55
49
|
];
|
|
56
50
|
for(let i = 0; i < expected.length; i++){
|
|
57
51
|
assert.equal(result.steps[i].step, expected[i]);
|
|
58
52
|
assert.equal(result.steps[i].status, 'skip', `dry-run 每步应为 skip,${result.steps[i].step} 实为 ${result.steps[i].status}`);
|
|
59
53
|
}
|
|
60
|
-
assert.equal(result.platform, 'darwin');
|
|
61
54
|
});
|
|
62
55
|
await check('2. health-watch 三时序:0ms / 中途 / 120s+1ms', async ()=>{
|
|
63
56
|
const w0 = startExtensionHealthWatch({
|
|
@@ -88,40 +81,21 @@ await check('2. health-watch 三时序:0ms / 中途 / 120s+1ms', async ()=>{
|
|
|
88
81
|
assert.equal(oTimeout.ready, false);
|
|
89
82
|
assert.equal(oTimeout.reason, 'timeout');
|
|
90
83
|
});
|
|
91
|
-
await check('3.
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
dryRun:
|
|
95
|
-
|
|
96
|
-
extensionDir: '/tmp/
|
|
97
|
-
spawn: darwin.spawn,
|
|
98
|
-
sourceDir: '/'
|
|
84
|
+
await check('3. wizard 完全不调 spawn(GUI 面板/剪贴板/直开浏览器均已退役)', async ()=>{
|
|
85
|
+
const dry = captureSpawn();
|
|
86
|
+
await runOnboardingWizard({
|
|
87
|
+
dryRun: true,
|
|
88
|
+
sourceDir: '/',
|
|
89
|
+
extensionDir: '/tmp/none'
|
|
99
90
|
});
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
assert.ok(darwinBins.includes('pbcopy'), 'darwin 应调 pbcopy');
|
|
103
|
-
assert.ok(darwinBins.includes('osascript'), 'darwin 应调 osascript');
|
|
104
|
-
const linux = captureSpawn();
|
|
91
|
+
assert.equal(dry.calls.length, 0, `dry-run 不应 spawn 任何命令(实调 ${dry.calls.length})`);
|
|
92
|
+
const fail = captureSpawn();
|
|
105
93
|
await runOnboardingWizard({
|
|
106
94
|
dryRun: false,
|
|
107
|
-
|
|
108
|
-
extensionDir: '/tmp/
|
|
109
|
-
spawn: linux.spawn,
|
|
110
|
-
sourceDir: '/'
|
|
111
|
-
});
|
|
112
|
-
const linuxBins = linux.calls.map((c)=>c.bin);
|
|
113
|
-
assert.ok(linuxBins.includes('xdg-open'), `linux 应调 xdg-open(实调 ${linuxBins.join(',')})`);
|
|
114
|
-
assert.ok(linuxBins.includes('xclip'), 'linux 应调 xclip');
|
|
115
|
-
assert.ok(linuxBins.includes('zenity'), 'linux 应调 zenity');
|
|
116
|
-
const headless = captureSpawn();
|
|
117
|
-
const rHeadless = await runOnboardingWizard({
|
|
118
|
-
dryRun: true,
|
|
119
|
-
forcePlatform: 'headless',
|
|
120
|
-
extensionDir: '/tmp/gotry-test-ext',
|
|
121
|
-
spawn: headless.spawn
|
|
95
|
+
sourceDir: '/nonexistent-source-dir-for-onboarding-tests',
|
|
96
|
+
extensionDir: '/tmp/none-fail'
|
|
122
97
|
});
|
|
123
|
-
assert.equal(
|
|
124
|
-
assert.equal(rHeadless.platform, 'headless');
|
|
98
|
+
assert.equal(fail.calls.length, 0, `fail 路径也不应 spawn(实调 ${fail.calls.length})`);
|
|
125
99
|
});
|
|
126
100
|
await check('4. retry-after-watch:needs-extension → watch ready → 自动重放同 query_id', async ()=>{
|
|
127
101
|
let fetchCalls = 0;
|
|
@@ -151,21 +125,15 @@ await check('4. retry-after-watch:needs-extension → watch ready → 自动重
|
|
|
151
125
|
assert.equal(retry.query_id, queryId, '同 query_id 必须保持');
|
|
152
126
|
assert.equal(fetchCalls, 2, `应调用 fetch 两次(首次 + 重放),实 ${fetchCalls}`);
|
|
153
127
|
});
|
|
154
|
-
await check('5. wizard
|
|
155
|
-
const headless = captureSpawn();
|
|
128
|
+
await check('5. wizard 不依赖 platform/panel 参数(GUI 跨平台降级退役)', async ()=>{
|
|
156
129
|
const result = await runOnboardingWizard({
|
|
157
130
|
dryRun: true,
|
|
158
|
-
|
|
159
|
-
extensionDir: '/tmp/gotry-test-ext',
|
|
160
|
-
spawn: headless.spawn
|
|
131
|
+
extensionDir: '/tmp/gotry-test-ext-2'
|
|
161
132
|
});
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
assert.equal(
|
|
166
|
-
assert.equal(panel?.status, 'skip', 'headless 面板应 skip(终端降级)');
|
|
167
|
-
assert.equal(watch?.status, 'skip', 'dry-run watch 应 skip');
|
|
168
|
-
assert.equal(headless.calls.length, 0, `headless 不应调任何 spawn(实调 ${headless.calls.length})`);
|
|
133
|
+
assert.equal(result.steps.length, 2, `应 2 步,实 ${result.steps.length}`);
|
|
134
|
+
assert.equal(result.steps[0].step, 'ensure-extension-files');
|
|
135
|
+
assert.equal(result.steps[1].step, 'watch-extension-ready');
|
|
136
|
+
assert.equal(result.platform, undefined, 'platform 字段应不再存在');
|
|
169
137
|
});
|
|
170
138
|
await check('6. withAutoRetryOnExtension 端到端:首次 needs-ext → 自动重放', async ()=>{
|
|
171
139
|
let callCount = 0;
|
|
@@ -215,4 +183,4 @@ await asyncSleep(0);
|
|
|
215
183
|
console.log(`ONBOARDING UX (§40): ${passed} pass`);
|
|
216
184
|
|
|
217
185
|
|
|
218
|
-
//# sourceURL
|
|
186
|
+
//# sourceURL=ts/scripts/onboarding-tests.ts
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
import { REQUIRED_BENCHMARK_DSH_VERSION } from '../../bin/gotry-runtime-resolution.js';
|
|
5
|
+
import { parsePnpmDshLock, REQUIRED_DSH_RUNTIME_PACKAGE_COUNT, validateDshRuntimeClosure } from './dsh-runtime-closure.js';
|
|
6
|
+
const consumerRoot = process.argv[2];
|
|
7
|
+
assert.ok(consumerRoot, 'usage: pnpm-dsh-closure-proof.ts <clean-consumer-root>');
|
|
8
|
+
const installedPackage = JSON.parse(readFileSync(resolve(consumerRoot, 'node_modules/@danceiny/gotry/package.json'), 'utf8'));
|
|
9
|
+
const lockPackages = parsePnpmDshLock(readFileSync(resolve(consumerRoot, 'pnpm-lock.yaml'), 'utf8'));
|
|
10
|
+
const closure = validateDshRuntimeClosure({
|
|
11
|
+
dependencies: installedPackage.dependencies ?? {},
|
|
12
|
+
lockPackages,
|
|
13
|
+
runtimeVersion: REQUIRED_BENCHMARK_DSH_VERSION,
|
|
14
|
+
expectedPackageCount: REQUIRED_DSH_RUNTIME_PACKAGE_COUNT
|
|
15
|
+
});
|
|
16
|
+
assert.equal(closure.names.length, REQUIRED_DSH_RUNTIME_PACKAGE_COUNT, 'clean pnpm consumer must resolve the complete Round 5 DSH closure');
|
|
17
|
+
console.log(`PNPM DSH CLOSURE PROOF: ${closure.names.length} packages at ${closure.version}`);
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
//# sourceURL=ts/scripts/pnpm-dsh-closure-proof.ts
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { execSync } from 'node:child_process';
|
|
2
|
-
import { mkdtempSync, rmSync, existsSync } from 'node:fs';
|
|
2
|
+
import { mkdtempSync, rmSync, existsSync, readFileSync } from 'node:fs';
|
|
3
3
|
import { tmpdir } from 'node:os';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
|
+
import { pathToFileURL } from 'node:url';
|
|
6
|
+
import { REQUIRED_BENCHMARK_DSH_VERSION } from '../../bin/gotry-runtime-resolution.js';
|
|
7
|
+
import { parsePnpmDshLock, parsePnpmRootDshImporter, REQUIRED_DSH_RUNTIME_PACKAGE_COUNT, validateDshRuntimeClosure, validatePnpmRootDshImporter } from './dsh-runtime-closure.js';
|
|
5
8
|
const repoRoot = join(import.meta.dirname, '..', '..');
|
|
6
9
|
process.chdir(repoRoot);
|
|
7
10
|
const pkg = JSON.parse(execSync('cat package.json', {
|
|
@@ -29,8 +32,30 @@ try {
|
|
|
29
32
|
encoding: 'utf-8'
|
|
30
33
|
}));
|
|
31
34
|
if (installedPkg.version !== version) throw new Error(`版本不符:${installedPkg.version}`);
|
|
35
|
+
const rootLock = JSON.parse(readFileSync(join(repoRoot, 'package-lock.json'), 'utf-8'));
|
|
36
|
+
const dshClosure = validateDshRuntimeClosure({
|
|
37
|
+
dependencies: installedPkg.dependencies ?? {},
|
|
38
|
+
lockPackages: rootLock.packages ?? {},
|
|
39
|
+
runtimeVersion: REQUIRED_BENCHMARK_DSH_VERSION,
|
|
40
|
+
expectedPackageCount: REQUIRED_DSH_RUNTIME_PACKAGE_COUNT
|
|
41
|
+
});
|
|
42
|
+
console.log(`dsh closure: ${dshClosure.names.length} packages pinned at ${dshClosure.version}`);
|
|
43
|
+
const pnpmLock = readFileSync(join(repoRoot, 'pnpm-lock.yaml'), 'utf-8');
|
|
44
|
+
const pnpmClosure = validateDshRuntimeClosure({
|
|
45
|
+
dependencies: installedPkg.dependencies ?? {},
|
|
46
|
+
lockPackages: parsePnpmDshLock(pnpmLock),
|
|
47
|
+
runtimeVersion: REQUIRED_BENCHMARK_DSH_VERSION,
|
|
48
|
+
expectedPackageCount: REQUIRED_DSH_RUNTIME_PACKAGE_COUNT
|
|
49
|
+
});
|
|
50
|
+
const pnpmImporter = validatePnpmRootDshImporter({
|
|
51
|
+
dependencies: installedPkg.dependencies ?? {},
|
|
52
|
+
importerEntries: parsePnpmRootDshImporter(pnpmLock),
|
|
53
|
+
runtimeVersion: REQUIRED_BENCHMARK_DSH_VERSION,
|
|
54
|
+
expectedPackageCount: REQUIRED_DSH_RUNTIME_PACKAGE_COUNT
|
|
55
|
+
});
|
|
56
|
+
console.log(`pnpm closure: ${pnpmClosure.names.length} packages, root importer ${pnpmImporter.names.length}`);
|
|
32
57
|
const deps = Object.keys(installedPkg.dependencies ?? {});
|
|
33
|
-
console.log(`dependencies: ${deps.
|
|
58
|
+
console.log(`dependencies: ${deps.length} declared`);
|
|
34
59
|
const runtimeImports = [
|
|
35
60
|
'better-sqlite3'
|
|
36
61
|
];
|
|
@@ -41,7 +66,13 @@ try {
|
|
|
41
66
|
for (const e of [
|
|
42
67
|
'dist/src/state-ledger.js',
|
|
43
68
|
'dist/src/index.js',
|
|
44
|
-
'bin/gotry-inner.js'
|
|
69
|
+
'bin/gotry-inner.js',
|
|
70
|
+
'dist/capabilities/session/static-flight-golden.js',
|
|
71
|
+
'dist/capabilities/session/golden-score.js',
|
|
72
|
+
'dist/scripts/sf-live-benchmark.js',
|
|
73
|
+
'dist/data/session-golden-20.json',
|
|
74
|
+
'dist/data/sf-golden-manifest.json',
|
|
75
|
+
'dist/data/sf-static-routes.json'
|
|
45
76
|
]){
|
|
46
77
|
if (!existsSync(join(pkgDir, e))) throw new Error(`发布缺文件: ${e}`);
|
|
47
78
|
}
|
|
@@ -50,6 +81,11 @@ try {
|
|
|
50
81
|
}).trim().match(/^[1-9]/)) {
|
|
51
82
|
throw new Error('dist/src/state-ledger.js 未引用 better-sqlite3(声明与实现不符)');
|
|
52
83
|
}
|
|
84
|
+
const staticProvider = await import(pathToFileURL(join(pkgDir, 'dist/capabilities/session/static-flight-golden.js')).href);
|
|
85
|
+
const staticSnapshot = staticProvider.loadStaticFlightSnapshot();
|
|
86
|
+
if (staticSnapshot.schema_version !== 'sf-static-routes.v1' || staticSnapshot.routes.length !== 8) {
|
|
87
|
+
throw new Error('发布 static golden 快照不可加载或覆盖不足 8 条');
|
|
88
|
+
}
|
|
53
89
|
console.log('PUBLISH PREVERIFY: OK');
|
|
54
90
|
} catch (e) {
|
|
55
91
|
console.error(`PREVERIFY FAILED: ${e.message}`);
|
|
@@ -65,4 +101,4 @@ try {
|
|
|
65
101
|
}
|
|
66
102
|
|
|
67
103
|
|
|
68
|
-
//# sourceURL
|
|
104
|
+
//# sourceURL=ts/scripts/publish-preverify.ts
|
|
@@ -112,4 +112,4 @@ assert.equal(bare.spec.segments[0].options[0].move.services[0].priceCny, 3400, '
|
|
|
112
112
|
console.log('\nREALTIME PRICING TESTS: 5/5 OK(hit 覆写+证据/error 降级/日期词表闸/求解集成/无段零触碰)');
|
|
113
113
|
|
|
114
114
|
|
|
115
|
-
//# sourceURL
|
|
115
|
+
//# sourceURL=ts/scripts/realtime-pricing-tests.ts
|
package/dist/scripts/replay.js
CHANGED
|
@@ -108,9 +108,9 @@ if (process.env.GOTRY_SESSION_LIVE === '0') {
|
|
|
108
108
|
destination: '丽江',
|
|
109
109
|
depDate: '2026-10-01'
|
|
110
110
|
});
|
|
111
|
-
const sentinelBlocked = fr.verdict === 'error' && /sentinel|block/i.test(fr.error ?? '');
|
|
111
|
+
const sentinelBlocked = fr.verdict === 'error' && /sentinel|block|trial limit/i.test(fr.error ?? '');
|
|
112
112
|
if (sentinelBlocked) {
|
|
113
|
-
console.log(' WARN -
|
|
113
|
+
console.log(' WARN - 飞猪上游限流(Sentinel 2026-08-28 / trial-limit 429 2026-08-31 实测,配额未文档化)——降级合同验证通过,跳过 hit 断言');
|
|
114
114
|
assert(fr.ok === false && /\[实时API:flyai@error@/.test(fr.evidence), '限流降级:结构化 error + 证据链错误形');
|
|
115
115
|
} else {
|
|
116
116
|
assert(fr.ok === true && fr.verdict === 'hit', '上海→丽江 hit', fr);
|
|
@@ -137,6 +137,48 @@ if (process.env.GOTRY_SESSION_LIVE === '0') {
|
|
|
137
137
|
recursive: true,
|
|
138
138
|
force: true
|
|
139
139
|
});
|
|
140
|
+
}{
|
|
141
|
+
const bigDir = mkdtempSync(join(tmpdir(), 'flyai-trunc-'));
|
|
142
|
+
const payloadJs = join(bigDir, 'payload.js');
|
|
143
|
+
const itemCount = 100;
|
|
144
|
+
writeFileSync(payloadJs, `
|
|
145
|
+
const items = []
|
|
146
|
+
for (let i = 0; i < ${itemCount}; i++) {
|
|
147
|
+
items.push({
|
|
148
|
+
journeys: [{ segments: [{
|
|
149
|
+
marketingTransportName: '吉祥航空', marketingTransportNo: 'HO' + (1000 + i),
|
|
150
|
+
depDateTime: '2026-09-15 08:30', arrDateTime: '2026-09-15 12:10',
|
|
151
|
+
depStationName: '浦东国际机场', arrStationName: '长水机场', duration: '220', seatClassName: '经济舱',
|
|
152
|
+
}] }],
|
|
153
|
+
ticketPrice: String(800 + i),
|
|
154
|
+
jumpUrl: 'https://fliggy.com/item/' + 'x'.repeat(800) + i,
|
|
155
|
+
})
|
|
156
|
+
}
|
|
157
|
+
const payload = JSON.stringify({ data: { itemList: items } })
|
|
158
|
+
const step = Math.ceil(payload.length / 100)
|
|
159
|
+
for (let i = 0; i < 100; i++) process.stdout.write(payload.slice(i * step, (i + 1) * step))
|
|
160
|
+
process.exit(0)
|
|
161
|
+
`);
|
|
162
|
+
const bigBin = join(bigDir, 'flyai-cli-big');
|
|
163
|
+
writeFileSync(bigBin, `#!/bin/sh\nexec node "${payloadJs}"\n`, {
|
|
164
|
+
mode: 0o755
|
|
165
|
+
});
|
|
166
|
+
const tr = await flyaiSearch({
|
|
167
|
+
kind: 'flight',
|
|
168
|
+
origin: '上海',
|
|
169
|
+
destination: '昆明',
|
|
170
|
+
depDate: '2026-09-15',
|
|
171
|
+
cliBin: bigBin
|
|
172
|
+
});
|
|
173
|
+
assert(tr.ok === true && tr.verdict === 'hit' && tr.options?.length === itemCount, `大载荷 ${itemCount} 条(>64KB)完整解析无截断(#84)`, {
|
|
174
|
+
verdict: tr.verdict,
|
|
175
|
+
options: tr.options?.length,
|
|
176
|
+
error: tr.error
|
|
177
|
+
});
|
|
178
|
+
rmSync(bigDir, {
|
|
179
|
+
recursive: true,
|
|
180
|
+
force: true
|
|
181
|
+
});
|
|
140
182
|
}console.log('G. sessionFlightSearch(live,Chrome+携程;默认跳过,GOTRY_SESSION_LIVE=1 显式开启)');
|
|
141
183
|
if (process.env.GOTRY_SESSION_LIVE !== '1') {
|
|
142
184
|
console.log(' SKIP - 会话 live 探针默认关(测试不再自动开浏览器窗口;GOTRY_SESSION_LIVE=1 显式开启)');
|
|
@@ -193,24 +235,28 @@ if (process.env.GOTRY_SESSION_LIVE !== '1') {
|
|
|
193
235
|
}
|
|
194
236
|
console.log('H. flyaiSearch hotel(飞猪官方 search-hotel)');
|
|
195
237
|
{
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
destName: '大理',
|
|
199
|
-
checkInDate: '2026-10-01',
|
|
200
|
-
checkOutDate: '2026-10-03'
|
|
201
|
-
});
|
|
202
|
-
const hSentinel = hr.verdict === 'error' && /sentinel|block/i.test(hr.error ?? '');
|
|
203
|
-
if (hSentinel) {
|
|
204
|
-
console.log(' WARN - 飞猪 Sentinel 限流——降级合同验证通过,跳过 hit 断言');
|
|
205
|
-
assert(hr.ok === false && /\[实时API:flyai@error@/.test(hr.evidence), '酒店限流降级:结构化 error + 证据链错误形');
|
|
206
|
-
} else if (hr.ok === false) {
|
|
207
|
-
console.log(` WARN - flyai hotel 端点降级(${String(hr.error).slice(0, 60)})——证据链合同通过,hit 断言跳过`);
|
|
208
|
-
assert(/\[实时API:flyai@error@/.test(hr.evidence), '端点降级仍带证据链错误形');
|
|
238
|
+
if (process.env.GOTRY_SESSION_LIVE === '0') {
|
|
239
|
+
console.log(' SKIP - GOTRY_SESSION_LIVE=0(离线门禁不调用 FlyAI 酒店实时端点)');
|
|
209
240
|
} else {
|
|
210
|
-
|
|
211
|
-
|
|
241
|
+
const hr = await flyaiSearch({
|
|
242
|
+
kind: 'hotel',
|
|
243
|
+
destName: '大理',
|
|
244
|
+
checkInDate: '2026-10-01',
|
|
245
|
+
checkOutDate: '2026-10-03'
|
|
246
|
+
});
|
|
247
|
+
const hSentinel = hr.verdict === 'error' && /sentinel|block/i.test(hr.error ?? '');
|
|
248
|
+
if (hSentinel) {
|
|
249
|
+
console.log(' WARN - 飞猪 Sentinel 限流——降级合同验证通过,跳过 hit 断言');
|
|
250
|
+
assert(hr.ok === false && /\[实时API:flyai@error@/.test(hr.evidence), '酒店限流降级:结构化 error + 证据链错误形');
|
|
251
|
+
} else if (hr.ok === false) {
|
|
252
|
+
console.log(` WARN - flyai hotel 端点降级(${String(hr.error).slice(0, 60)})——证据链合同通过,hit 断言跳过`);
|
|
253
|
+
assert(/\[实时API:flyai@error@/.test(hr.evidence), '端点降级仍带证据链错误形');
|
|
254
|
+
} else {
|
|
255
|
+
assert(hr.verdict === 'hit' && (hr.hotels?.length ?? 0) >= 1, '大理酒店 hit', hr.hotels?.[0]);
|
|
256
|
+
assert(hr.hotels?.every((h)=>!!h.name && !!h.jumpUrl) ?? false, '条目结构化(name + jumpUrl 透传)', hr.hotels?.[0]);
|
|
257
|
+
}
|
|
258
|
+
assert(/\[实时API:flyai/.test(hr.evidence), '证据链 [实时API:flyai@*]');
|
|
212
259
|
}
|
|
213
|
-
assert(/\[实时API:flyai/.test(hr.evidence), '证据链 [实时API:flyai@*]');
|
|
214
260
|
const fakeDir = mkdtempSync(join(tmpdir(), 'flyai-hotel-fake-'));
|
|
215
261
|
const fakeCliH = join(fakeDir, 'flyai-hotel-fake');
|
|
216
262
|
writeFileSync(fakeCliH, '#!/bin/sh\necho \'{"data":{"itemList":[{"name":"大理A 酒店","shId":"1","star":"高档型","rate":null,"price":"\\u00a57xx","address":"addr","interestsPoi":"近洱海","detailUrl":"https://router.feizhu.com/x"},{"star":"舒适型"}]}}\'\nexit 0\n', {
|
|
@@ -399,7 +445,11 @@ console.log('H. flyaiSearch hotel(飞猪官方 search-hotel)');
|
|
|
399
445
|
} else {
|
|
400
446
|
console.log(' SKIP - 登录 live 探针默认关(GOTRY_SESSION_LIVE=1 opt-in;工具面/桌面入口才真调)');
|
|
401
447
|
}
|
|
402
|
-
}
|
|
448
|
+
}if (process.env.GOTRY_SESSION_TEST_FORCE_FAILURE === '1') {
|
|
449
|
+
assert(false, 'forced session failure propagation proof');
|
|
450
|
+
}
|
|
451
|
+
console.log(`\nSESSION P1: ${pass} pass, ${fail} fail`);
|
|
452
|
+
if (fail > 0) process.exitCode = 1;
|
|
403
453
|
|
|
404
454
|
|
|
405
|
-
//# sourceURL
|
|
455
|
+
//# sourceURL=ts/scripts/session-tests.ts
|