@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
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-http-proxy 本地 SSE + 中毒 HTTP 代理反例(issue #268):启动回环 SSE 服务器和
|
|
3
|
+
* 统计命中次数的中毒代理,用公共 installProxyFromEnvironment API 安装代理策略,
|
|
4
|
+
* 将 HTTP(S)_PROXY 指向中毒代理。在 127.0.0.1 上获取 SSE 端点,断言负载成功且
|
|
5
|
+
* 中毒命中计数保持为零;同时断言 proxyRouteFor(loopback) 是直接的,非回环 URL
|
|
6
|
+
* 被分类为代理,且 proxyEnvironmentForChild() 携带回环 NO_PROXY 以及 Node 24 下的
|
|
7
|
+
* NODE_USE_ENV_PROXY。始终 await 返回的 disposer 并在 finally 中关闭两个服务器;
|
|
8
|
+
* 证明全局路由返回到先前的直接状态。
|
|
9
|
+
*
|
|
10
|
+
* 运行:cd ts && npx tsx scripts/dsh-http-proxy-sse-proof.ts
|
|
11
|
+
*/
|
|
12
|
+
import assert from 'node:assert/strict';
|
|
13
|
+
import http from 'node:http';
|
|
14
|
+
import { installProxyFromEnvironment, proxyRouteFor, proxyEnvironmentForChild } from '@deepseek-ai/dsh-http-proxy';
|
|
15
|
+
// 1. 回环 SSE 服务器。
|
|
16
|
+
const sseServer = http.createServer((req, res) => {
|
|
17
|
+
res.writeHead(200, {
|
|
18
|
+
'Content-Type': 'text/event-stream',
|
|
19
|
+
'Cache-Control': 'no-cache',
|
|
20
|
+
Connection: 'keep-alive',
|
|
21
|
+
});
|
|
22
|
+
res.write('data: hello-sse\n\n');
|
|
23
|
+
res.end();
|
|
24
|
+
});
|
|
25
|
+
await new Promise((resolve) => sseServer.listen(0, '127.0.0.1', resolve));
|
|
26
|
+
const sseAddr = sseServer.address();
|
|
27
|
+
assert.ok(sseAddr !== null && typeof sseAddr === 'object', 'SSE 服务器必须已绑定地址');
|
|
28
|
+
const ssePort = sseAddr.port;
|
|
29
|
+
const sseUrl = `http://127.0.0.1:${ssePort}/`;
|
|
30
|
+
// 2. 中毒代理:统计命中次数,返回 502。
|
|
31
|
+
let poisonHits = 0;
|
|
32
|
+
const poisonServer = http.createServer((req, res) => {
|
|
33
|
+
poisonHits++;
|
|
34
|
+
res.writeHead(502);
|
|
35
|
+
res.end('poisoned');
|
|
36
|
+
});
|
|
37
|
+
await new Promise((resolve) => poisonServer.listen(0, '127.0.0.1', resolve));
|
|
38
|
+
const poisonAddr = poisonServer.address();
|
|
39
|
+
assert.ok(poisonAddr !== null && typeof poisonAddr === 'object', '中毒代理必须已绑定地址');
|
|
40
|
+
const poisonPort = poisonAddr.port;
|
|
41
|
+
let disposer;
|
|
42
|
+
try {
|
|
43
|
+
// 3. 用公共 installProxyFromEnvironment API 安装代理策略,指向中毒代理。
|
|
44
|
+
const envMap = new Map([
|
|
45
|
+
['HTTP_PROXY', `http://127.0.0.1:${poisonPort}`],
|
|
46
|
+
['HTTPS_PROXY', `http://127.0.0.1:${poisonPort}`],
|
|
47
|
+
]);
|
|
48
|
+
const envLookup = {
|
|
49
|
+
get(name) {
|
|
50
|
+
const v = envMap.get(name) ?? envMap.get(name.toLowerCase());
|
|
51
|
+
return v !== undefined ? { value: v } : undefined;
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
disposer = await installProxyFromEnvironment(envLookup, () => { });
|
|
55
|
+
// 4. proxyRouteFor(loopback) 是直接的;非回环 URL 被分类为代理。
|
|
56
|
+
const loopbackRoute = proxyRouteFor(new URL(sseUrl));
|
|
57
|
+
assert.equal(loopbackRoute.proxied, false, '回环 URL 必须路由为直接(proxyRouteFor)');
|
|
58
|
+
const externalRoute = proxyRouteFor(new URL('http://example.com/'));
|
|
59
|
+
assert.equal(externalRoute.proxied, true, '非回环 URL 必须被分类为代理(proxyRouteFor)');
|
|
60
|
+
// 5. proxyEnvironmentForChild() 携带回环 NO_PROXY 以及 Node 24 下的 NODE_USE_ENV_PROXY。
|
|
61
|
+
const childEnv = proxyEnvironmentForChild();
|
|
62
|
+
assert.equal(childEnv.NODE_USE_ENV_PROXY, '1', 'proxyEnvironmentForChild 必须携带 NODE_USE_ENV_PROXY=1(Node 24)');
|
|
63
|
+
assert.ok(typeof childEnv.NO_PROXY === 'string' && childEnv.NO_PROXY.includes('127.0.0.1'), `proxyEnvironmentForChild NO_PROXY 必须包含 127.0.0.1(当前 ${JSON.stringify(childEnv.NO_PROXY)})`);
|
|
64
|
+
// 6. 在 127.0.0.1 上获取 SSE 端点:负载成功且中毒命中计数保持为零。
|
|
65
|
+
const resp = await fetch(sseUrl);
|
|
66
|
+
assert.equal(resp.status, 200, `SSE fetch 必须成功(status=${resp.status})`);
|
|
67
|
+
const body = await resp.text();
|
|
68
|
+
assert.ok(body.includes('hello-sse'), `SSE 负载必须包含 hello-sse(当前 ${JSON.stringify(body)})`);
|
|
69
|
+
assert.equal(poisonHits, 0, `中毒代理命中计数必须为零(当前 ${poisonHits})——回环绕过代理`);
|
|
70
|
+
}
|
|
71
|
+
finally {
|
|
72
|
+
// 7. 始终 await 返回的 disposer 并在 finally 中 await 关闭两个服务器(包括失败路径)。
|
|
73
|
+
// 不依赖未 await 的 server.close() 让进程退出——显式 await 完成资源清理。
|
|
74
|
+
try {
|
|
75
|
+
if (disposer)
|
|
76
|
+
await disposer();
|
|
77
|
+
}
|
|
78
|
+
finally {
|
|
79
|
+
await Promise.all([
|
|
80
|
+
new Promise((resolve, reject) => sseServer.close((err) => (err ? reject(err) : resolve()))),
|
|
81
|
+
new Promise((resolve, reject) => poisonServer.close((err) => (err ? reject(err) : resolve()))),
|
|
82
|
+
]);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// 8. 证明全局路由返回到先前的直接状态。
|
|
86
|
+
const externalAfter = proxyRouteFor(new URL('http://example.com/'));
|
|
87
|
+
assert.equal(externalAfter.proxied, false, 'disposer 后全局路由必须返回直接状态');
|
|
88
|
+
console.log(`HTTP PROXY SSE PROOF: loopback SSE fetch=200 payload-has-hello-sse=true poison-hits=0, ` +
|
|
89
|
+
`loopback route=direct external route=proxied, NODE_USE_ENV_PROXY=1 NO_PROXY has 127.0.0.1, ` +
|
|
90
|
+
`routing restored to direct after dispose`);
|
|
@@ -1,225 +1,182 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
2
|
import test from 'node:test';
|
|
3
|
-
import { parsePnpmDshLock, parsePnpmRootDshImporter, REQUIRED_DSH_RUNTIME_PACKAGE_COUNT, validateDshRuntimeClosure, validatePnpmRootDshImporter } from './dsh-runtime-closure.js';
|
|
4
|
-
const VERSION = '0.1.
|
|
3
|
+
import { parsePnpmDshLock, parsePnpmRootDshImporter, REQUIRED_DSH_RUNTIME_PACKAGE_COUNT, validateDshRuntimeClosure, validatePnpmRootDshImporter, } from './dsh-runtime-closure.js';
|
|
4
|
+
const VERSION = '0.1.5-rc.1';
|
|
5
5
|
function validInput() {
|
|
6
6
|
return {
|
|
7
7
|
dependencies: {
|
|
8
8
|
'@deepseek-ai/dsh': VERSION,
|
|
9
|
-
'@deepseek-ai/dsh-session-title': VERSION
|
|
9
|
+
'@deepseek-ai/dsh-session-title': VERSION,
|
|
10
10
|
},
|
|
11
11
|
lockPackages: {
|
|
12
|
-
'node_modules/@deepseek-ai/dsh': {
|
|
13
|
-
|
|
14
|
-
},
|
|
15
|
-
'node_modules/@deepseek-ai/dsh-session-title': {
|
|
16
|
-
version: VERSION
|
|
17
|
-
}
|
|
12
|
+
'node_modules/@deepseek-ai/dsh': { version: VERSION },
|
|
13
|
+
'node_modules/@deepseek-ai/dsh-session-title': { version: VERSION },
|
|
18
14
|
},
|
|
19
|
-
runtimeVersion: VERSION
|
|
15
|
+
runtimeVersion: VERSION,
|
|
20
16
|
};
|
|
21
17
|
}
|
|
22
|
-
test('accepts an exact coherent DSH prerelease closure', ()=>{
|
|
18
|
+
test('accepts an exact coherent DSH prerelease closure', () => {
|
|
23
19
|
assert.deepEqual(validateDshRuntimeClosure(validInput()), {
|
|
24
|
-
names: [
|
|
25
|
-
|
|
26
|
-
'@deepseek-ai/dsh-session-title'
|
|
27
|
-
],
|
|
28
|
-
version: VERSION
|
|
20
|
+
names: ['@deepseek-ai/dsh', '@deepseek-ai/dsh-session-title'],
|
|
21
|
+
version: VERSION,
|
|
29
22
|
});
|
|
30
23
|
});
|
|
31
|
-
test('rejects a lock package missing from the published direct dependencies', ()=>{
|
|
24
|
+
test('rejects a lock package missing from the published direct dependencies', () => {
|
|
32
25
|
const input = validInput();
|
|
33
|
-
input.dependencies = {
|
|
34
|
-
|
|
35
|
-
};
|
|
36
|
-
assert.throws(()=>validateDshRuntimeClosure(input), /DSH closure 未精确声明/);
|
|
26
|
+
input.dependencies = { '@deepseek-ai/dsh': VERSION };
|
|
27
|
+
assert.throws(() => validateDshRuntimeClosure(input), /DSH closure 未精确声明/);
|
|
37
28
|
});
|
|
38
|
-
test('rejects an extra ranged DSH dependency absent from the tested lock closure', ()=>{
|
|
29
|
+
test('rejects an extra ranged DSH dependency absent from the tested lock closure', () => {
|
|
39
30
|
const input = validInput();
|
|
40
|
-
input.dependencies['@deepseek-ai/dsh-web'] = '^0.1.
|
|
41
|
-
assert.throws(()=>validateDshRuntimeClosure(input), /DSH manifest 与 lock 集合不一致/);
|
|
31
|
+
input.dependencies['@deepseek-ai/dsh-web'] = '^0.1.5-rc.1';
|
|
32
|
+
assert.throws(() => validateDshRuntimeClosure(input), /DSH manifest 与 lock 集合不一致/);
|
|
42
33
|
});
|
|
43
|
-
test('rejects a nested DSH package from another prerelease', ()=>{
|
|
34
|
+
test('rejects a nested DSH package from another prerelease', () => {
|
|
44
35
|
const input = validInput();
|
|
45
36
|
input.lockPackages['node_modules/@deepseek-ai/dsh/node_modules/@deepseek-ai/dsh-session-title'] = {
|
|
46
|
-
version: '0.1.
|
|
37
|
+
version: '0.1.5-alpha.2',
|
|
47
38
|
};
|
|
48
|
-
assert.throws(()=>validateDshRuntimeClosure(input), /DSH lock 版本漂移/);
|
|
39
|
+
assert.throws(() => validateDshRuntimeClosure(input), /DSH lock 版本漂移/);
|
|
49
40
|
});
|
|
50
|
-
test('rejects drift from the runtime spawn guard version', ()=>{
|
|
41
|
+
test('rejects drift from the runtime spawn guard version', () => {
|
|
51
42
|
const input = validInput();
|
|
52
|
-
input.runtimeVersion = '0.1.
|
|
53
|
-
assert.throws(()=>validateDshRuntimeClosure(input), /DSH runtime guard 版本漂移/);
|
|
43
|
+
input.runtimeVersion = '0.1.5-alpha.2';
|
|
44
|
+
assert.throws(() => validateDshRuntimeClosure(input), /DSH runtime guard 版本漂移/);
|
|
54
45
|
});
|
|
55
|
-
test('parses each pnpm DSH resolution once across packages and snapshots', ()=>{
|
|
46
|
+
test('parses each pnpm DSH resolution once across packages and snapshots', () => {
|
|
56
47
|
const lock = `
|
|
57
48
|
packages:
|
|
58
|
-
'@deepseek-ai/dsh@0.1.
|
|
59
|
-
'@deepseek-ai/dsh-session@0.1.
|
|
49
|
+
'@deepseek-ai/dsh@0.1.5-rc.1': {}
|
|
50
|
+
'@deepseek-ai/dsh-session@0.1.5-rc.1': {}
|
|
60
51
|
snapshots:
|
|
61
|
-
'@deepseek-ai/dsh@0.1.
|
|
52
|
+
'@deepseek-ai/dsh@0.1.5-rc.1': {}
|
|
62
53
|
`;
|
|
63
54
|
assert.deepEqual(parsePnpmDshLock(lock), {
|
|
64
|
-
'node_modules/@deepseek-ai/dsh': {
|
|
65
|
-
|
|
66
|
-
},
|
|
67
|
-
'node_modules/@deepseek-ai/dsh-session': {
|
|
68
|
-
version: VERSION
|
|
69
|
-
}
|
|
55
|
+
'node_modules/@deepseek-ai/dsh': { version: VERSION },
|
|
56
|
+
'node_modules/@deepseek-ai/dsh-session': { version: VERSION },
|
|
70
57
|
});
|
|
71
58
|
});
|
|
72
|
-
test('preserves two pnpm resolutions of the same DSH package for mixed-version rejection', ()=>{
|
|
59
|
+
test('preserves two pnpm resolutions of the same DSH package for mixed-version rejection', () => {
|
|
73
60
|
const lock = `
|
|
74
61
|
packages:
|
|
75
|
-
'@deepseek-ai/dsh@0.1.
|
|
76
|
-
'@deepseek-ai/dsh-session@0.1.
|
|
77
|
-
'@deepseek-ai/dsh-session@0.1.
|
|
62
|
+
'@deepseek-ai/dsh@0.1.5-rc.1': {}
|
|
63
|
+
'@deepseek-ai/dsh-session@0.1.5-rc.1': {}
|
|
64
|
+
'@deepseek-ai/dsh-session@0.1.5-alpha.2': {}
|
|
78
65
|
`;
|
|
79
66
|
const parsed = parsePnpmDshLock(lock);
|
|
80
67
|
assert.equal(Object.keys(parsed).length, 3);
|
|
81
|
-
assert.throws(()=>validateDshRuntimeClosure({
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
});
|
|
90
|
-
test('parses only the root pnpm importer DSH entries', ()=>{
|
|
68
|
+
assert.throws(() => validateDshRuntimeClosure({
|
|
69
|
+
dependencies: {
|
|
70
|
+
'@deepseek-ai/dsh': VERSION,
|
|
71
|
+
'@deepseek-ai/dsh-session': VERSION,
|
|
72
|
+
},
|
|
73
|
+
lockPackages: parsed,
|
|
74
|
+
runtimeVersion: VERSION,
|
|
75
|
+
}), /DSH lock 版本漂移/);
|
|
76
|
+
});
|
|
77
|
+
test('parses only the root pnpm importer DSH entries', () => {
|
|
91
78
|
const lock = `
|
|
92
79
|
lockfileVersion: '9.0'
|
|
93
80
|
importers:
|
|
94
81
|
.:
|
|
95
82
|
dependencies:
|
|
96
83
|
'@deepseek-ai/dsh':
|
|
97
|
-
specifier: 0.1.
|
|
98
|
-
version: 0.1.
|
|
84
|
+
specifier: 0.1.5-rc.1
|
|
85
|
+
version: 0.1.5-rc.1(peer@1.0.0)
|
|
99
86
|
'@deepseek-ai/dsh-session':
|
|
100
|
-
specifier: 0.1.
|
|
101
|
-
version: 0.1.
|
|
87
|
+
specifier: 0.1.5-rc.1
|
|
88
|
+
version: 0.1.5-rc.1
|
|
102
89
|
ts:
|
|
103
90
|
dependencies:
|
|
104
91
|
'@deepseek-ai/dsh-web':
|
|
105
|
-
specifier: 0.1.
|
|
106
|
-
version: 0.1.
|
|
92
|
+
specifier: 0.1.5-alpha.2
|
|
93
|
+
version: 0.1.5-alpha.2
|
|
107
94
|
packages: {}
|
|
108
95
|
`;
|
|
109
96
|
assert.deepEqual(parsePnpmRootDshImporter(lock), {
|
|
110
|
-
'@deepseek-ai/dsh': {
|
|
111
|
-
|
|
112
|
-
resolvedVersion: VERSION
|
|
113
|
-
},
|
|
114
|
-
'@deepseek-ai/dsh-session': {
|
|
115
|
-
specifier: VERSION,
|
|
116
|
-
resolvedVersion: VERSION
|
|
117
|
-
}
|
|
97
|
+
'@deepseek-ai/dsh': { specifier: VERSION, resolvedVersion: VERSION },
|
|
98
|
+
'@deepseek-ai/dsh-session': { specifier: VERSION, resolvedVersion: VERSION },
|
|
118
99
|
});
|
|
119
100
|
});
|
|
120
|
-
test('rejects a pnpm root importer missing a published DSH dependency', ()=>{
|
|
121
|
-
assert.throws(()=>validatePnpmRootDshImporter({
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
},
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
dependencies: validInput().dependencies,
|
|
151
|
-
importerEntries: {
|
|
152
|
-
'@deepseek-ai/dsh': {
|
|
153
|
-
specifier: VERSION,
|
|
154
|
-
resolvedVersion: '0.1.2-alpha.4'
|
|
155
|
-
},
|
|
156
|
-
'@deepseek-ai/dsh-session-title': {
|
|
157
|
-
specifier: VERSION,
|
|
158
|
-
resolvedVersion: VERSION
|
|
159
|
-
}
|
|
160
|
-
},
|
|
161
|
-
runtimeVersion: VERSION
|
|
162
|
-
}), /pnpm root importer resolved 版本漂移/);
|
|
163
|
-
});
|
|
164
|
-
test('rejects a missing resolved DSH version in the pnpm root importer', ()=>{
|
|
101
|
+
test('rejects a pnpm root importer missing a published DSH dependency', () => {
|
|
102
|
+
assert.throws(() => validatePnpmRootDshImporter({
|
|
103
|
+
dependencies: validInput().dependencies,
|
|
104
|
+
importerEntries: {
|
|
105
|
+
'@deepseek-ai/dsh': { specifier: VERSION, resolvedVersion: VERSION },
|
|
106
|
+
},
|
|
107
|
+
runtimeVersion: VERSION,
|
|
108
|
+
}), /pnpm root importer 与 manifest 集合不一致/);
|
|
109
|
+
});
|
|
110
|
+
test('rejects a ranged DSH specifier in the pnpm root importer', () => {
|
|
111
|
+
assert.throws(() => validatePnpmRootDshImporter({
|
|
112
|
+
dependencies: validInput().dependencies,
|
|
113
|
+
importerEntries: {
|
|
114
|
+
'@deepseek-ai/dsh': { specifier: VERSION, resolvedVersion: VERSION },
|
|
115
|
+
'@deepseek-ai/dsh-session-title': { specifier: '^0.1.5-rc.1', resolvedVersion: VERSION },
|
|
116
|
+
},
|
|
117
|
+
runtimeVersion: VERSION,
|
|
118
|
+
}), /pnpm root importer 未精确锁定/);
|
|
119
|
+
});
|
|
120
|
+
test('rejects a drifted resolved DSH version in the pnpm root importer', () => {
|
|
121
|
+
assert.throws(() => validatePnpmRootDshImporter({
|
|
122
|
+
dependencies: validInput().dependencies,
|
|
123
|
+
importerEntries: {
|
|
124
|
+
'@deepseek-ai/dsh': { specifier: VERSION, resolvedVersion: '0.1.5-alpha.2' },
|
|
125
|
+
'@deepseek-ai/dsh-session-title': { specifier: VERSION, resolvedVersion: VERSION },
|
|
126
|
+
},
|
|
127
|
+
runtimeVersion: VERSION,
|
|
128
|
+
}), /pnpm root importer resolved 版本漂移/);
|
|
129
|
+
});
|
|
130
|
+
test('rejects a missing resolved DSH version in the pnpm root importer', () => {
|
|
165
131
|
const lock = `
|
|
166
132
|
importers:
|
|
167
133
|
.:
|
|
168
134
|
dependencies:
|
|
169
135
|
'@deepseek-ai/dsh':
|
|
170
|
-
specifier: 0.1.
|
|
136
|
+
specifier: 0.1.5-rc.1
|
|
171
137
|
`;
|
|
172
|
-
assert.throws(()=>parsePnpmRootDshImporter(lock), /pnpm root importer version 不可用/);
|
|
138
|
+
assert.throws(() => parsePnpmRootDshImporter(lock), /pnpm root importer version 不可用/);
|
|
173
139
|
});
|
|
174
|
-
test('rejects duplicate resolved DSH versions in the pnpm root importer', ()=>{
|
|
140
|
+
test('rejects duplicate resolved DSH versions in the pnpm root importer', () => {
|
|
175
141
|
const lock = `
|
|
176
142
|
importers:
|
|
177
143
|
.:
|
|
178
144
|
dependencies:
|
|
179
145
|
'@deepseek-ai/dsh':
|
|
180
|
-
specifier: 0.1.
|
|
181
|
-
version: 0.1.
|
|
182
|
-
version: 0.1.
|
|
146
|
+
specifier: 0.1.5-rc.1
|
|
147
|
+
version: 0.1.5-rc.1
|
|
148
|
+
version: 0.1.5-alpha.2
|
|
183
149
|
`;
|
|
184
|
-
assert.throws(()=>parsePnpmRootDshImporter(lock), /pnpm root importer version 不可用/);
|
|
185
|
-
});
|
|
186
|
-
test('rejects a coherent closure below the required package count', ()=>{
|
|
187
|
-
assert.throws(()=>validateDshRuntimeClosure({
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
});
|
|
192
|
-
test('rejects a coherent root importer below the required package count', ()=>{
|
|
193
|
-
assert.throws(()=>validatePnpmRootDshImporter({
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
},
|
|
205
|
-
runtimeVersion: VERSION,
|
|
206
|
-
expectedPackageCount: REQUIRED_DSH_RUNTIME_PACKAGE_COUNT
|
|
207
|
-
}), /pnpm root importer 包数量不符/);
|
|
208
|
-
});
|
|
209
|
-
test('rejects duplicate DSH entries in the pnpm root importer', ()=>{
|
|
150
|
+
assert.throws(() => parsePnpmRootDshImporter(lock), /pnpm root importer version 不可用/);
|
|
151
|
+
});
|
|
152
|
+
test('rejects a coherent closure below the required package count', () => {
|
|
153
|
+
assert.throws(() => validateDshRuntimeClosure({
|
|
154
|
+
...validInput(),
|
|
155
|
+
expectedPackageCount: REQUIRED_DSH_RUNTIME_PACKAGE_COUNT,
|
|
156
|
+
}), /DSH closure 包数量不符/);
|
|
157
|
+
});
|
|
158
|
+
test('rejects a coherent root importer below the required package count', () => {
|
|
159
|
+
assert.throws(() => validatePnpmRootDshImporter({
|
|
160
|
+
dependencies: validInput().dependencies,
|
|
161
|
+
importerEntries: {
|
|
162
|
+
'@deepseek-ai/dsh': { specifier: VERSION, resolvedVersion: VERSION },
|
|
163
|
+
'@deepseek-ai/dsh-session-title': { specifier: VERSION, resolvedVersion: VERSION },
|
|
164
|
+
},
|
|
165
|
+
runtimeVersion: VERSION,
|
|
166
|
+
expectedPackageCount: REQUIRED_DSH_RUNTIME_PACKAGE_COUNT,
|
|
167
|
+
}), /pnpm root importer 包数量不符/);
|
|
168
|
+
});
|
|
169
|
+
test('rejects duplicate DSH entries in the pnpm root importer', () => {
|
|
210
170
|
const lock = `
|
|
211
171
|
importers:
|
|
212
172
|
.:
|
|
213
173
|
dependencies:
|
|
214
174
|
'@deepseek-ai/dsh':
|
|
215
|
-
specifier: 0.1.
|
|
216
|
-
version: 0.1.
|
|
175
|
+
specifier: 0.1.5-rc.1
|
|
176
|
+
version: 0.1.5-rc.1
|
|
217
177
|
'@deepseek-ai/dsh':
|
|
218
|
-
specifier: 0.1.
|
|
219
|
-
version: 0.1.
|
|
178
|
+
specifier: 0.1.5-rc.1
|
|
179
|
+
version: 0.1.5-rc.1
|
|
220
180
|
`;
|
|
221
|
-
assert.throws(()=>parsePnpmRootDshImporter(lock), /pnpm root importer DSH 依赖重复/);
|
|
181
|
+
assert.throws(() => parsePnpmRootDshImporter(lock), /pnpm root importer DSH 依赖重复/);
|
|
222
182
|
});
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
//# sourceURL=ts/scripts/dsh-runtime-closure-tests.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const REQUIRED_DSH_RUNTIME_PACKAGE_COUNT =
|
|
1
|
+
export const REQUIRED_DSH_RUNTIME_PACKAGE_COUNT = 232;
|
|
2
2
|
function yamlScalar(value) {
|
|
3
3
|
const trimmed = value.trim().replace(/\s+#.*$/, '');
|
|
4
4
|
const quoted = trimmed.match(/^(['"])(.*)\1$/);
|
|
@@ -12,55 +12,79 @@ function resolvedPnpmVersion(value) {
|
|
|
12
12
|
}
|
|
13
13
|
export function parsePnpmRootDshImporter(text) {
|
|
14
14
|
const lines = text.split(/\r?\n/);
|
|
15
|
-
const importers = lines
|
|
16
|
-
|
|
15
|
+
const importers = lines
|
|
16
|
+
.map((line, index) => line === 'importers:' ? index : -1)
|
|
17
|
+
.filter((index) => index >= 0);
|
|
18
|
+
if (importers.length !== 1)
|
|
19
|
+
throw new Error('pnpm lock importers 区块不可用');
|
|
17
20
|
const importersStart = importers[0];
|
|
18
|
-
const importersEnd = lines.findIndex((line, index)=>index > importersStart && line.trim() !== '' && indentation(line) === 0);
|
|
19
|
-
const rootCandidates = lines
|
|
20
|
-
|
|
21
|
+
const importersEnd = lines.findIndex((line, index) => index > importersStart && line.trim() !== '' && indentation(line) === 0);
|
|
22
|
+
const rootCandidates = lines
|
|
23
|
+
.map((line, index) => index > importersStart && (importersEnd < 0 || index < importersEnd)
|
|
24
|
+
&& /^ {2}(?:\.|'\.'|"\."):\s*$/.test(line) ? index : -1)
|
|
25
|
+
.filter((index) => index >= 0);
|
|
26
|
+
if (rootCandidates.length !== 1)
|
|
27
|
+
throw new Error('pnpm root importer 不唯一');
|
|
21
28
|
const rootStart = rootCandidates[0];
|
|
22
|
-
const rootEndRelative = lines.slice(rootStart + 1, importersEnd < 0 ? lines.length : importersEnd)
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
|
|
29
|
+
const rootEndRelative = lines.slice(rootStart + 1, importersEnd < 0 ? lines.length : importersEnd)
|
|
30
|
+
.findIndex((line) => line.trim() !== '' && indentation(line) <= 2);
|
|
31
|
+
const rootEnd = rootEndRelative < 0
|
|
32
|
+
? (importersEnd < 0 ? lines.length : importersEnd)
|
|
33
|
+
: rootStart + 1 + rootEndRelative;
|
|
34
|
+
const dependencyBlocks = lines
|
|
35
|
+
.map((line, index) => index > rootStart && index < rootEnd && /^ {4}dependencies:\s*$/.test(line) ? index : -1)
|
|
36
|
+
.filter((index) => index >= 0);
|
|
37
|
+
if (dependencyBlocks.length !== 1)
|
|
38
|
+
throw new Error('pnpm root importer dependencies 区块不可用');
|
|
26
39
|
const dependenciesStart = dependencyBlocks[0];
|
|
27
|
-
const dependenciesEndRelative = lines.slice(dependenciesStart + 1, rootEnd)
|
|
40
|
+
const dependenciesEndRelative = lines.slice(dependenciesStart + 1, rootEnd)
|
|
41
|
+
.findIndex((line) => line.trim() !== '' && indentation(line) <= 4);
|
|
28
42
|
const dependenciesEnd = dependenciesEndRelative < 0 ? rootEnd : dependenciesStart + 1 + dependenciesEndRelative;
|
|
29
|
-
const entries = lines
|
|
30
|
-
|
|
43
|
+
const entries = lines
|
|
44
|
+
.map((line, index) => {
|
|
45
|
+
if (index <= dependenciesStart || index >= dependenciesEnd)
|
|
46
|
+
return null;
|
|
31
47
|
const match = line.match(/^ {6}(['"]?)([^'":\s]+)\1:\s*$/);
|
|
32
|
-
return match ? {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
} : null;
|
|
36
|
-
}).filter((entry)=>entry !== null);
|
|
48
|
+
return match ? { index, name: match[2] } : null;
|
|
49
|
+
})
|
|
50
|
+
.filter((entry) => entry !== null);
|
|
37
51
|
const importerEntries = {};
|
|
38
|
-
for(let entryIndex = 0; entryIndex < entries.length; entryIndex += 1){
|
|
52
|
+
for (let entryIndex = 0; entryIndex < entries.length; entryIndex += 1) {
|
|
39
53
|
const entry = entries[entryIndex];
|
|
40
|
-
if (entry.name !== '@deepseek-ai/dsh' && !entry.name.startsWith('@deepseek-ai/dsh-'))
|
|
41
|
-
|
|
54
|
+
if (entry.name !== '@deepseek-ai/dsh' && !entry.name.startsWith('@deepseek-ai/dsh-'))
|
|
55
|
+
continue;
|
|
56
|
+
if (Object.hasOwn(importerEntries, entry.name))
|
|
57
|
+
throw new Error(`pnpm root importer DSH 依赖重复:${entry.name}`);
|
|
42
58
|
const end = entries[entryIndex + 1]?.index ?? dependenciesEnd;
|
|
43
59
|
const block = lines.slice(entry.index + 1, end);
|
|
44
|
-
const specifiers = block
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (
|
|
60
|
+
const specifiers = block
|
|
61
|
+
.map((line) => line.match(/^ {8}specifier:\s*(.+)$/)?.[1])
|
|
62
|
+
.filter((value) => value !== undefined);
|
|
63
|
+
if (specifiers.length !== 1)
|
|
64
|
+
throw new Error(`pnpm root importer specifier 不可用:${entry.name}`);
|
|
65
|
+
const versions = block
|
|
66
|
+
.map((line) => line.match(/^ {8}version:\s*(.+)$/)?.[1])
|
|
67
|
+
.filter((value) => value !== undefined);
|
|
68
|
+
if (versions.length !== 1)
|
|
69
|
+
throw new Error(`pnpm root importer version 不可用:${entry.name}`);
|
|
48
70
|
importerEntries[entry.name] = {
|
|
49
71
|
specifier: yamlScalar(specifiers[0]),
|
|
50
|
-
resolvedVersion: resolvedPnpmVersion(versions[0])
|
|
72
|
+
resolvedVersion: resolvedPnpmVersion(versions[0]),
|
|
51
73
|
};
|
|
52
74
|
}
|
|
53
75
|
return importerEntries;
|
|
54
76
|
}
|
|
55
77
|
export function validatePnpmRootDshImporter(input) {
|
|
56
|
-
const manifestNames = Object.keys(input.dependencies)
|
|
78
|
+
const manifestNames = Object.keys(input.dependencies)
|
|
79
|
+
.filter((name) => name === '@deepseek-ai/dsh' || name.startsWith('@deepseek-ai/dsh-'))
|
|
80
|
+
.sort();
|
|
57
81
|
const importerNames = Object.keys(input.importerEntries).sort();
|
|
58
|
-
const missing = manifestNames.filter((name)
|
|
59
|
-
const extra = importerNames.filter((name)
|
|
82
|
+
const missing = manifestNames.filter((name) => !importerNames.includes(name));
|
|
83
|
+
const extra = importerNames.filter((name) => !manifestNames.includes(name));
|
|
60
84
|
if (missing.length > 0 || extra.length > 0) {
|
|
61
85
|
throw new Error(`pnpm root importer 与 manifest 集合不一致:missing=${missing.join(',') || '-'};extra=${extra.join(',') || '-'}`);
|
|
62
86
|
}
|
|
63
|
-
for (const name of importerNames){
|
|
87
|
+
for (const name of importerNames) {
|
|
64
88
|
const importerEntry = input.importerEntries[name];
|
|
65
89
|
if (input.dependencies[name] !== input.runtimeVersion || importerEntry.specifier !== input.runtimeVersion) {
|
|
66
90
|
throw new Error(`pnpm root importer 未精确锁定:${name}@${input.runtimeVersion}`);
|
|
@@ -72,28 +96,24 @@ export function validatePnpmRootDshImporter(input) {
|
|
|
72
96
|
if (input.expectedPackageCount !== undefined && importerNames.length !== input.expectedPackageCount) {
|
|
73
97
|
throw new Error(`pnpm root importer 包数量不符:${importerNames.length}(expected ${input.expectedPackageCount})`);
|
|
74
98
|
}
|
|
75
|
-
return {
|
|
76
|
-
names: importerNames,
|
|
77
|
-
version: input.runtimeVersion
|
|
78
|
-
};
|
|
99
|
+
return { names: importerNames, version: input.runtimeVersion };
|
|
79
100
|
}
|
|
80
101
|
export function parsePnpmDshLock(text) {
|
|
81
102
|
const packages = {};
|
|
82
103
|
const seen = new Set();
|
|
83
104
|
const variants = new Map();
|
|
84
105
|
const entry = /^\s{2}['"]?(\@deepseek-ai\/dsh(?:-[^@'":\s]+)?)@([^'":\s(]+)(?:\([^'"]*\))?['"]?:/gm;
|
|
85
|
-
for (const match of text.matchAll(entry)){
|
|
106
|
+
for (const match of text.matchAll(entry)) {
|
|
86
107
|
const name = match[1];
|
|
87
108
|
const version = match[2];
|
|
88
109
|
const identity = `${name}@${version}`;
|
|
89
|
-
if (seen.has(identity))
|
|
110
|
+
if (seen.has(identity))
|
|
111
|
+
continue;
|
|
90
112
|
seen.add(identity);
|
|
91
113
|
const variant = variants.get(name) ?? 0;
|
|
92
114
|
variants.set(name, variant + 1);
|
|
93
115
|
const prefix = variant === 0 ? '' : `.pnpm-variant-${variant}/node_modules/`;
|
|
94
|
-
packages[`node_modules/${prefix}${name}`] = {
|
|
95
|
-
version
|
|
96
|
-
};
|
|
116
|
+
packages[`node_modules/${prefix}${name}`] = { version };
|
|
97
117
|
}
|
|
98
118
|
return packages;
|
|
99
119
|
}
|
|
@@ -105,34 +125,32 @@ export function validateDshRuntimeClosure(input) {
|
|
|
105
125
|
if (dshVersion !== input.runtimeVersion) {
|
|
106
126
|
throw new Error(`DSH runtime guard 版本漂移:${input.runtimeVersion}(manifest ${dshVersion})`);
|
|
107
127
|
}
|
|
108
|
-
const dshNodes = Object.entries(input.lockPackages)
|
|
128
|
+
const dshNodes = Object.entries(input.lockPackages)
|
|
129
|
+
.flatMap(([path, metadata]) => {
|
|
109
130
|
const match = path.match(/(?:^|\/)node_modules\/(\@deepseek-ai\/dsh(?:-[^/]+)?)$/);
|
|
110
|
-
return match ? [
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}).sort((left, right)=>left.name.localeCompare(right.name));
|
|
117
|
-
if (dshNodes.length === 0) throw new Error('package-lock 未解析到 DSH runtime closure');
|
|
118
|
-
for (const dependency of dshNodes){
|
|
131
|
+
return match ? [{ name: match[1], version: metadata.version }] : [];
|
|
132
|
+
})
|
|
133
|
+
.sort((left, right) => left.name.localeCompare(right.name));
|
|
134
|
+
if (dshNodes.length === 0)
|
|
135
|
+
throw new Error('package-lock 未解析到 DSH runtime closure');
|
|
136
|
+
for (const dependency of dshNodes) {
|
|
119
137
|
if (dependency.version !== dshVersion) {
|
|
120
138
|
throw new Error(`DSH lock 版本漂移:${dependency.name}@${dependency.version ?? 'missing'}(expected ${dshVersion})`);
|
|
121
139
|
}
|
|
122
140
|
}
|
|
123
|
-
const lockNames = [
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
const missing = lockNames.filter((name)
|
|
128
|
-
const extra = manifestNames.filter((name)
|
|
141
|
+
const lockNames = [...new Set(dshNodes.map((dependency) => dependency.name))].sort();
|
|
142
|
+
const manifestNames = Object.keys(input.dependencies)
|
|
143
|
+
.filter((name) => name === '@deepseek-ai/dsh' || name.startsWith('@deepseek-ai/dsh-'))
|
|
144
|
+
.sort();
|
|
145
|
+
const missing = lockNames.filter((name) => !manifestNames.includes(name));
|
|
146
|
+
const extra = manifestNames.filter((name) => !lockNames.includes(name));
|
|
129
147
|
if (missing.length > 0) {
|
|
130
148
|
throw new Error(`DSH closure 未精确声明:${missing[0]}@${dshVersion}`);
|
|
131
149
|
}
|
|
132
150
|
if (extra.length > 0) {
|
|
133
151
|
throw new Error(`DSH manifest 与 lock 集合不一致:missing=${missing.join(',') || '-'};extra=${extra.join(',') || '-'}`);
|
|
134
152
|
}
|
|
135
|
-
for (const name of manifestNames){
|
|
153
|
+
for (const name of manifestNames) {
|
|
136
154
|
if (input.dependencies[name] !== dshVersion) {
|
|
137
155
|
throw new Error(`DSH closure 未精确声明:${name}@${dshVersion}`);
|
|
138
156
|
}
|
|
@@ -140,11 +158,5 @@ export function validateDshRuntimeClosure(input) {
|
|
|
140
158
|
if (input.expectedPackageCount !== undefined && lockNames.length !== input.expectedPackageCount) {
|
|
141
159
|
throw new Error(`DSH closure 包数量不符:${lockNames.length}(expected ${input.expectedPackageCount})`);
|
|
142
160
|
}
|
|
143
|
-
return {
|
|
144
|
-
names: lockNames,
|
|
145
|
-
version: dshVersion
|
|
146
|
-
};
|
|
161
|
+
return { names: lockNames, version: dshVersion };
|
|
147
162
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
//# sourceURL=ts/scripts/dsh-runtime-closure.ts
|