@danceiny/gotry 0.0.1-rc.15 → 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.
Files changed (238) hide show
  1. package/README.md +51 -13
  2. package/README.zh-CN.md +26 -12
  3. package/bin/gotry-booking-copilot.js +53 -0
  4. package/bin/gotry-bootstrap.js +357 -8
  5. package/bin/gotry-inner.js +442 -60
  6. package/bin/gotry-runtime-resolution.d.ts +27 -0
  7. package/bin/gotry-runtime-resolution.js +50 -0
  8. package/bin/gotry.js +1 -1
  9. package/cordis.gotry-patch.yml +15 -1
  10. package/data/airline-airports.json +39 -0
  11. package/dist/capabilities/agent-reach-deep.js +1 -1
  12. package/dist/capabilities/agent-reach.js +1 -1
  13. package/dist/capabilities/anything.js +1 -1
  14. package/dist/capabilities/artifacts.js +1 -1
  15. package/dist/capabilities/effect.js +293 -0
  16. package/dist/capabilities/fact-log.js +41 -0
  17. package/dist/capabilities/flyai.js +20 -6
  18. package/dist/capabilities/hbcli.js +43 -1
  19. package/dist/capabilities/incident-log.js +1 -1
  20. package/dist/capabilities/model-override.js +18 -0
  21. package/dist/capabilities/opensky.js +1 -1
  22. package/dist/capabilities/resilience.js +90 -0
  23. package/dist/capabilities/session/action-cache.js +1 -1
  24. package/dist/capabilities/session/adapters/ctrip-flight.js +1 -1
  25. package/dist/capabilities/session/adapters/meituan-local.js +1 -1
  26. package/dist/capabilities/session/benchmark.js +2 -1
  27. package/dist/capabilities/session/extension-bridge.js +358 -0
  28. package/dist/capabilities/session/extension-channel.js +93 -0
  29. package/dist/capabilities/session/extension-distribution.js +234 -0
  30. package/dist/capabilities/session/extract.js +1 -1
  31. package/dist/capabilities/session/golden-score.js +92 -0
  32. package/dist/capabilities/session/health-watch.js +216 -0
  33. package/dist/capabilities/session/read-guard.js +1 -1
  34. package/dist/capabilities/session/static-flight-golden.js +137 -0
  35. package/dist/capabilities/session/transport.js +1 -1
  36. package/dist/capabilities/session/wizard.js +147 -0
  37. package/dist/capabilities/session-consent.js +1 -1
  38. package/dist/capabilities/session-login.js +83 -1
  39. package/dist/capabilities/session-search.js +111 -2
  40. package/dist/capabilities/weather.js +168 -46
  41. package/dist/data/session-golden-20.json +25 -0
  42. package/dist/data/sf-golden-manifest.json +102 -0
  43. package/dist/data/sf-static-routes.json +91 -0
  44. package/dist/scripts/action-cache-tests.js +1 -1
  45. package/dist/scripts/agent-planning-budget-e2e.js +227 -0
  46. package/dist/scripts/agent-planning-budget-tests.js +173 -0
  47. package/dist/scripts/agent-reach-deep-tests.js +1 -1
  48. package/dist/scripts/agent-reach-tests.js +1 -1
  49. package/dist/scripts/agent-reach-wrapper-tests.js +1 -1
  50. package/dist/scripts/anything-tests.js +1 -1
  51. package/dist/scripts/async-collect.js +1 -1
  52. package/dist/scripts/benchmark-environment-bridge-e2e.js +981 -0
  53. package/dist/scripts/benchmark-environment-bridge-tests.js +2544 -0
  54. package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +335 -0
  55. package/dist/scripts/booking-copilot-availability-policy-v2-tests.js +1355 -0
  56. package/dist/scripts/booking-copilot-bin-proof-tests.js +89 -0
  57. package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +113 -0
  58. package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +356 -0
  59. package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +557 -0
  60. package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +140 -0
  61. package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +202 -0
  62. package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +102 -0
  63. package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +374 -0
  64. package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +447 -0
  65. package/dist/scripts/booking-copilot-runtime-proof-tests.js +205 -0
  66. package/dist/scripts/booking-copilot-server-proof-tests.js +317 -0
  67. package/dist/scripts/booking-copilot-startup-proof-tests.js +283 -0
  68. package/dist/scripts/booking-copilot-v2-runtime-proof-tests.js +3935 -0
  69. package/dist/scripts/booking-saga-tests.js +1 -1
  70. package/dist/scripts/booking-surface-contract-proof-tests.js +393 -0
  71. package/dist/scripts/booking-surface-v2-contract-proof-tests.js +1174 -0
  72. package/dist/scripts/bootstrap-tests.js +59 -3
  73. package/dist/scripts/build-changelog.js +279 -0
  74. package/dist/scripts/changelog-tests.js +165 -0
  75. package/dist/scripts/companion-tests.js +1 -1
  76. package/dist/scripts/diff-test.js +1 -1
  77. package/dist/scripts/dsh-runtime-closure-tests.js +225 -0
  78. package/dist/scripts/dsh-runtime-closure.js +150 -0
  79. package/dist/scripts/effect-tests.js +474 -0
  80. package/dist/scripts/engine-run.js +1 -1
  81. package/dist/scripts/engine-tests.js +1 -1
  82. package/dist/scripts/evaluation-cadence-tests.js +347 -0
  83. package/dist/scripts/evaluation-contract-tests.js +574 -0
  84. package/dist/scripts/extension-distribution-cli.js +35 -0
  85. package/dist/scripts/extension-distribution-tests.js +341 -0
  86. package/dist/scripts/extension-tests.js +573 -0
  87. package/dist/scripts/fact-gate-tests.js +318 -0
  88. package/dist/scripts/flyai-tests.js +1 -1
  89. package/dist/scripts/hbcli-e2e-tests.js +180 -0
  90. package/dist/scripts/hbcli-tests.js +1 -1
  91. package/dist/scripts/health-watch-cli.js +51 -0
  92. package/dist/scripts/i18n-tests.js +1 -1
  93. package/dist/scripts/incident-tests.js +1 -1
  94. package/dist/scripts/journey-tests.js +1 -1
  95. package/dist/scripts/ledger-tests.js +1 -1
  96. package/dist/scripts/ledger-workflow-crash.js +1 -1
  97. package/dist/scripts/memory-capture-tests.js +1 -1
  98. package/dist/scripts/memory-decay-tests.js +1 -1
  99. package/dist/scripts/memory-metrics.js +1 -1
  100. package/dist/scripts/memory-value-report.js +1 -1
  101. package/dist/scripts/model-override-e2e.js +176 -0
  102. package/dist/scripts/nightly-evidence-tests.js +67 -4
  103. package/dist/scripts/nightly-evidence.js +59 -3
  104. package/dist/scripts/nudge-digest.js +1 -1
  105. package/dist/scripts/onboarding-tests.js +186 -0
  106. package/dist/scripts/opensky-check.js +1 -1
  107. package/dist/scripts/opensky-tests.js +1 -1
  108. package/dist/scripts/pnpm-dsh-closure-proof.js +20 -0
  109. package/dist/scripts/price-drift-tests.js +441 -0
  110. package/dist/scripts/price-drift-watch.js +491 -0
  111. package/dist/scripts/probe-poi-tests.js +1 -1
  112. package/dist/scripts/product-metrics.js +1 -1
  113. package/dist/scripts/publish-preverify.js +40 -4
  114. package/dist/scripts/realtime-pricing-tests.js +1 -1
  115. package/dist/scripts/replay-async.js +1 -1
  116. package/dist/scripts/replay-real.js +1 -1
  117. package/dist/scripts/replay.js +1 -1
  118. package/dist/scripts/session-attach-diagnose.js +1 -1
  119. package/dist/scripts/session-attach-poc.js +1 -1
  120. package/dist/scripts/session-benchmark.js +1 -1
  121. package/dist/scripts/session-extract-tests.js +1 -1
  122. package/dist/scripts/session-login.js +1 -1
  123. package/dist/scripts/session-tests.js +70 -20
  124. package/dist/scripts/sf-live-benchmark.js +338 -0
  125. package/dist/scripts/sf-live-cli-tests.js +21 -0
  126. package/dist/scripts/sf-soft-score-tests.js +108 -0
  127. package/dist/scripts/sf-summary.js +93 -0
  128. package/dist/scripts/skeleton-check.js +1 -1
  129. package/dist/scripts/skeleton-integration-test.js +1 -1
  130. package/dist/scripts/skills-contract-tests.js +1 -1
  131. package/dist/scripts/smoke-session-gate-tests.js +29 -0
  132. package/dist/scripts/smoke.js +154 -33
  133. package/dist/scripts/state-cli-tests.js +1 -1
  134. package/dist/scripts/state-cli.js +1 -1
  135. package/dist/scripts/static-golden-tests.js +299 -0
  136. package/dist/scripts/time-eval-tests.js +1 -1
  137. package/dist/scripts/travel-timeline-tests.js +1 -1
  138. package/dist/scripts/unified-tests.js +1 -1
  139. package/dist/scripts/weather-tests.js +694 -44
  140. package/dist/scripts/z3-race-tests.js +1 -1
  141. package/dist/src/artifact-gate.js +310 -0
  142. package/dist/src/benchmark-agent-conformance.js +370 -0
  143. package/dist/src/benchmark-environment-bridge.js +384 -0
  144. package/dist/src/benchmark-headless-child-diagnostics.js +173 -0
  145. package/dist/src/benchmark-tool-isolation.js +124 -0
  146. package/dist/src/bookable-facts.js +349 -0
  147. package/dist/src/booking-saga.js +1 -1
  148. package/dist/src/booking-surface/availability-policy-v2.js +830 -0
  149. package/dist/src/booking-surface/canonical-schema.js +113 -0
  150. package/dist/src/booking-surface/contracts-v2.js +89 -0
  151. package/dist/src/booking-surface/contracts.js +46 -0
  152. package/dist/src/booking-surface/dsh-planner.js +453 -0
  153. package/dist/src/booking-surface/dsh-plugin.js +93 -0
  154. package/dist/src/booking-surface/error-codes.js +94 -0
  155. package/dist/src/booking-surface/index.js +15 -0
  156. package/dist/src/booking-surface/profile.js +68 -0
  157. package/dist/src/booking-surface/runtime-v2.js +1771 -0
  158. package/dist/src/booking-surface/runtime.js +351 -0
  159. package/dist/src/booking-surface/server-v2.js +334 -0
  160. package/dist/src/booking-surface/server.js +302 -0
  161. package/dist/src/booking-surface/startup.js +159 -0
  162. package/dist/src/booking-surface/validation-v2.js +319 -0
  163. package/dist/src/booking-surface/validation.js +809 -0
  164. package/dist/src/bridge.js +1 -1
  165. package/dist/src/companions.js +1 -1
  166. package/dist/src/contracts.js +1 -1
  167. package/dist/src/dsh-llm.js +1 -1
  168. package/dist/src/engine.js +1 -1
  169. package/dist/src/evaluation-cadence.js +234 -0
  170. package/dist/src/evaluation-contracts.js +906 -0
  171. package/dist/src/i18n.js +1 -1
  172. package/dist/src/index.js +234 -60
  173. package/dist/src/journey.js +1 -1
  174. package/dist/src/loop.js +1 -1
  175. package/dist/src/memory-capture.js +1 -1
  176. package/dist/src/memory-decay.js +1 -1
  177. package/dist/src/memory-utility.js +1 -1
  178. package/dist/src/mock-llm.js +1 -1
  179. package/dist/src/model.js +1 -1
  180. package/dist/src/realtime-pricing.js +14 -7
  181. package/dist/src/slot-spec.js +1 -1
  182. package/dist/src/state-ledger.js +2 -1
  183. package/dist/src/time-anchor.js +1 -1
  184. package/dist/src/tool-budget.js +136 -0
  185. package/dist/src/tool-packet.js +1 -1
  186. package/dist/src/travel-slots.js +1 -1
  187. package/dist/src/travel-timeline.js +1 -1
  188. package/dist/src/unified.js +1 -1
  189. package/dist/src/wish-pool.js +1 -1
  190. package/dist/src/z3-shared.js +1 -1
  191. package/extension/README.md +50 -0
  192. package/extension/background.js +160 -0
  193. package/extension/content-bridge.js +41 -0
  194. package/extension/content-main.js +62 -0
  195. package/extension/manifest.json +32 -0
  196. package/package.json +291 -12
  197. package/schemas/booking.surface.v1.schema.json +927 -0
  198. package/schemas/booking.surface.v2.schema.json +61 -0
  199. package/ts/capabilities/fact-log.ts +54 -0
  200. package/ts/capabilities/flyai.ts +16 -3
  201. package/ts/capabilities/hbcli.ts +46 -0
  202. package/ts/capabilities/session/benchmark.ts +4 -1
  203. package/ts/capabilities/session/extension-bridge.ts +377 -0
  204. package/ts/capabilities/session/extension-channel.ts +95 -0
  205. package/ts/capabilities/session/extension-distribution.ts +264 -0
  206. package/ts/capabilities/session/golden-score.ts +139 -0
  207. package/ts/capabilities/session/health-watch.ts +257 -0
  208. package/ts/capabilities/session/static-flight-golden.ts +209 -0
  209. package/ts/capabilities/session/wizard.ts +140 -0
  210. package/ts/capabilities/session-login.ts +63 -2
  211. package/ts/capabilities/session-search.ts +105 -3
  212. package/ts/capabilities/weather.ts +141 -52
  213. package/ts/package.json +3 -3
  214. package/ts/src/artifact-gate.ts +365 -0
  215. package/ts/src/benchmark-agent-conformance.ts +448 -0
  216. package/ts/src/benchmark-environment-bridge.ts +348 -0
  217. package/ts/src/benchmark-headless-child-diagnostics.ts +184 -0
  218. package/ts/src/benchmark-tool-isolation.ts +166 -0
  219. package/ts/src/bookable-facts.ts +557 -0
  220. package/ts/src/booking-surface/availability-policy-v2.ts +523 -0
  221. package/ts/src/booking-surface/canonical-schema.js +113 -0
  222. package/ts/src/booking-surface/contracts-v2.ts +118 -0
  223. package/ts/src/booking-surface/contracts.ts +380 -0
  224. package/ts/src/booking-surface/dsh-planner.ts +452 -0
  225. package/ts/src/booking-surface/dsh-plugin.js +93 -0
  226. package/ts/src/booking-surface/error-codes.ts +101 -0
  227. package/ts/src/booking-surface/index.ts +12 -0
  228. package/ts/src/booking-surface/profile.ts +42 -0
  229. package/ts/src/booking-surface/runtime-v2.ts +1466 -0
  230. package/ts/src/booking-surface/runtime.ts +483 -0
  231. package/ts/src/booking-surface/server-v2.ts +247 -0
  232. package/ts/src/booking-surface/server.ts +324 -0
  233. package/ts/src/booking-surface/startup.ts +196 -0
  234. package/ts/src/booking-surface/validation-v2.ts +205 -0
  235. package/ts/src/booking-surface/validation.ts +453 -0
  236. package/ts/src/index.ts +161 -14
  237. package/ts/src/state-ledger.ts +1 -0
  238. package/ts/src/tool-budget.ts +165 -0
@@ -0,0 +1,341 @@
1
+ import assert from 'node:assert/strict';
2
+ import { execFileSync, spawn } from 'node:child_process';
3
+ import { createServer } from 'node:http';
4
+ import { copyFileSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
5
+ import { tmpdir } from 'node:os';
6
+ import { join, dirname } from 'node:path';
7
+ import { fileURLToPath } from 'node:url';
8
+ import { DEFAULT_RELEASE_BASE, DIST_ASSET_MANIFEST, DIST_ASSET_STORE_ZIP, DIST_ASSET_TARBALL, compareVersions, distAssetUrls, installExtensionFromGithub, parseDistManifest, readExtensionKey, sha256Hex } from '../capabilities/session/extension-distribution.js';
9
+ const repoRoot = join(dirname(fileURLToPath(import.meta.url)), '..', '..');
10
+ const EXT_SRC = join(repoRoot, 'extension');
11
+ const EXT_FILES = [
12
+ 'manifest.json',
13
+ 'background.js',
14
+ 'content-main.js',
15
+ 'content-bridge.js',
16
+ 'README.md'
17
+ ];
18
+ let passed = 0;
19
+ function ok(cond, label) {
20
+ if (!cond) {
21
+ console.error(` ✗ ${label}`);
22
+ process.exit(1);
23
+ }
24
+ passed += 1;
25
+ console.log(` ok - ${label}`);
26
+ }
27
+ {
28
+ const urls = distAssetUrls();
29
+ ok(urls.tarball === `${DEFAULT_RELEASE_BASE}/latest/download/${DIST_ASSET_TARBALL}`, `tarball URL 形态(${urls.tarball})`);
30
+ ok(urls.manifest.endsWith(`/latest/download/${DIST_ASSET_MANIFEST}`), 'manifest URL 形态(latest/download 永久链)');
31
+ ok(distAssetUrls('https://x.example/releases/').tarball === 'https://x.example/releases/latest/download/gotry-session-bridge.tar.gz', 'releaseBase 尾斜杠归一');
32
+ const pkgSrc = readFileSync(join(repoRoot, 'scripts', 'package-extension.mjs'), 'utf8');
33
+ ok(pkgSrc.includes(`const ASSET_TARBALL = '${DIST_ASSET_TARBALL}'`), 'package-extension.mjs tarball 资产名一致');
34
+ ok(pkgSrc.includes(`const ASSET_STORE_ZIP = '${DIST_ASSET_STORE_ZIP}'`), 'package-extension.mjs store zip 资产名一致');
35
+ ok(pkgSrc.includes(`const ASSET_MANIFEST = '${DIST_ASSET_MANIFEST}'`), 'package-extension.mjs dist-manifest 资产名一致');
36
+ ok(pkgSrc.includes("const STAGE = join(OUT, 'gotry-session-bridge')"), '打包根目录名固定 gotry-session-bridge/(下载端 strip-components 依赖)');
37
+ ok(pkgSrc.includes('delete m.key'), 'store zip 变体剥离 manifest key(2026-08-30 商店首传实测拒绝 key;tar.gz 保留 key 保通道 ID 不变量)');
38
+ }{
39
+ const good = JSON.stringify({
40
+ version: '0.1.0',
41
+ tarball: DIST_ASSET_TARBALL,
42
+ tarballSha256: 'a'.repeat(64),
43
+ zip: DIST_ASSET_STORE_ZIP,
44
+ zipSha256: 'b'.repeat(64)
45
+ });
46
+ ok(parseDistManifest(good).version === '0.1.0', '合法 dist-manifest 解析');
47
+ const rejects = [
48
+ [
49
+ '{bad json',
50
+ '坏 JSON'
51
+ ],
52
+ [
53
+ JSON.stringify({
54
+ version: 'x',
55
+ tarball: DIST_ASSET_TARBALL,
56
+ tarballSha256: 'a'.repeat(64),
57
+ zip: DIST_ASSET_STORE_ZIP,
58
+ zipSha256: 'b'.repeat(64)
59
+ }),
60
+ 'version 非 x.y.z'
61
+ ],
62
+ [
63
+ JSON.stringify({
64
+ tarball: DIST_ASSET_TARBALL,
65
+ tarballSha256: 'a'.repeat(64),
66
+ zip: DIST_ASSET_STORE_ZIP,
67
+ zipSha256: 'b'.repeat(64)
68
+ }),
69
+ '缺 version'
70
+ ],
71
+ [
72
+ JSON.stringify({
73
+ version: '0.1.0',
74
+ tarball: 'other-name.tar.gz',
75
+ tarballSha256: 'a'.repeat(64),
76
+ zip: DIST_ASSET_STORE_ZIP,
77
+ zipSha256: 'b'.repeat(64)
78
+ }),
79
+ 'tarball 资产名漂移'
80
+ ],
81
+ [
82
+ JSON.stringify({
83
+ version: '0.1.0',
84
+ tarball: DIST_ASSET_TARBALL,
85
+ tarballSha256: 'zz',
86
+ zip: DIST_ASSET_STORE_ZIP,
87
+ zipSha256: 'b'.repeat(64)
88
+ }),
89
+ 'tarballSha256 非 64-hex'
90
+ ]
91
+ ];
92
+ for (const [raw, label] of rejects){
93
+ let threw = false;
94
+ try {
95
+ parseDistManifest(raw);
96
+ } catch {
97
+ threw = true;
98
+ }
99
+ ok(threw, `fail-closed:${label}`);
100
+ }
101
+ }{
102
+ ok(compareVersions('0.1.0', '0.1.1') < 0, '0.1.0 < 0.1.1');
103
+ ok(compareVersions('0.2.0', '0.1.9') > 0, '0.2.0 > 0.1.9');
104
+ ok(compareVersions('1.0.0', '0.9.9') > 0, '1.0.0 > 0.9.9');
105
+ ok(compareVersions('0.1.0', '0.1.0') === 0, '相等为 0');
106
+ ok(compareVersions('0.1', '0.1.0') === 0, '缺段按 0 补齐');
107
+ }async function startLoopback(manifestJson, tarball) {
108
+ let hits = 0;
109
+ const server = createServer((req, res)=>{
110
+ if (req.url?.endsWith(DIST_ASSET_MANIFEST)) {
111
+ res.writeHead(200, {
112
+ 'content-type': 'application/json'
113
+ });
114
+ res.end(manifestJson);
115
+ } else if (req.url?.endsWith(DIST_ASSET_TARBALL)) {
116
+ hits += 1;
117
+ res.writeHead(200, {
118
+ 'content-type': 'application/gzip'
119
+ });
120
+ res.end(tarball);
121
+ } else {
122
+ res.writeHead(404);
123
+ res.end('not found');
124
+ }
125
+ });
126
+ await new Promise((r)=>server.listen(0, '127.0.0.1', r));
127
+ const addr = server.address();
128
+ const base = `http://127.0.0.1:${typeof addr === 'object' && addr ? addr.port : 0}/releases`;
129
+ return {
130
+ base,
131
+ manifestJson,
132
+ tarball,
133
+ tarballHits: ()=>hits,
134
+ close: ()=>new Promise((r)=>server.close(()=>r()))
135
+ };
136
+ }
137
+ function buildTarball(sourceDir, versionOverride) {
138
+ const stage = mkdtempSync(join(tmpdir(), 'extdist-stage-'));
139
+ const root = join(stage, 'gotry-session-bridge');
140
+ mkdirSync(root);
141
+ for (const f of EXT_FILES)copyFileSync(join(sourceDir, f), join(root, f));
142
+ if (versionOverride != null) {
143
+ const m = JSON.parse(readFileSync(join(root, 'manifest.json'), 'utf8'));
144
+ writeFileSync(join(root, 'manifest.json'), JSON.stringify({
145
+ ...m,
146
+ version: versionOverride
147
+ }));
148
+ }
149
+ const tarPath = join(stage, DIST_ASSET_TARBALL);
150
+ execFileSync('tar', [
151
+ '-czf',
152
+ tarPath,
153
+ '-C',
154
+ stage,
155
+ 'gotry-session-bridge'
156
+ ]);
157
+ const tarball = readFileSync(tarPath);
158
+ rmSync(stage, {
159
+ recursive: true,
160
+ force: true
161
+ });
162
+ return {
163
+ tarball,
164
+ sha: sha256Hex(tarball)
165
+ };
166
+ }
167
+ function distManifestJson(version, sha) {
168
+ return JSON.stringify({
169
+ version,
170
+ tarball: DIST_ASSET_TARBALL,
171
+ tarballSha256: sha,
172
+ zip: DIST_ASSET_STORE_ZIP,
173
+ zipSha256: 'c'.repeat(64),
174
+ builtFromCommit: 'test'
175
+ });
176
+ }
177
+ {
178
+ const work = mkdtempSync(join(tmpdir(), 'extdist-e2e-'));
179
+ const { tarball, sha } = buildTarball(EXT_SRC, '9.9.9');
180
+ const srcVersion = JSON.parse(readFileSync(join(EXT_SRC, 'manifest.json'), 'utf8'));
181
+ const remoteVersion = '9.9.9';
182
+ {
183
+ const dest = join(work, 'dest1');
184
+ const lb = await startLoopback(distManifestJson(remoteVersion, sha), tarball);
185
+ const r = await installExtensionFromGithub({
186
+ destDir: dest,
187
+ pinnedSourceDir: EXT_SRC,
188
+ releaseBase: lb.base
189
+ });
190
+ lb.close();
191
+ ok(r.ok && r.action === 'installed' && r.version === remoteVersion, `installed 全链(action=${r.action},v=${r.version},err=${r.error ?? '无'})`);
192
+ ok(readExtensionKey(dest) === srcVersion.key, '落位产物 key 与 bundled 逐字一致(同扩展 ID)');
193
+ ok(JSON.parse(readFileSync(join(dest, 'manifest.json'), 'utf8')).version === remoteVersion, '落位产物为远端版本');
194
+ for (const f of EXT_FILES)ok(existsSync(join(dest, f)), `文件就位:${f}`);
195
+ }
196
+ {
197
+ const dest = join(work, 'dest2');
198
+ const lb = await startLoopback(distManifestJson(remoteVersion, '0'.repeat(64)), tarball);
199
+ const r = await installExtensionFromGithub({
200
+ destDir: dest,
201
+ pinnedSourceDir: EXT_SRC,
202
+ releaseBase: lb.base
203
+ });
204
+ lb.close();
205
+ ok(!r.ok && r.action === 'fallback-bundled' && /SHA256/.test(r.error ?? ''), `SHA256 不符拒绝(${r.error})`);
206
+ ok(!existsSync(dest), '失败路径零落盘');
207
+ }
208
+ {
209
+ const dest = join(work, 'dest3');
210
+ const lb = await startLoopback(distManifestJson(remoteVersion, sha), tarball);
211
+ lb.close();
212
+ const r = await installExtensionFromGithub({
213
+ destDir: dest,
214
+ releaseBase: lb.base
215
+ });
216
+ ok(!r.ok && r.action === 'fallback-bundled', `无网降级 fallback-bundled(${(r.error ?? '').slice(0, 40)})`);
217
+ }
218
+ {
219
+ const rogue = mkdtempSync(join(work, 'rogue-'));
220
+ const rogueManifest = {
221
+ ...srcVersion,
222
+ version: remoteVersion,
223
+ key: `ROGUE-${srcVersion.key}`
224
+ };
225
+ writeFileSync(join(rogue, 'manifest.json'), JSON.stringify(rogueManifest));
226
+ for (const f of EXT_FILES.filter((x)=>x !== 'manifest.json'))copyFileSync(join(EXT_SRC, f), join(rogue, f));
227
+ const { tarball: rTar, sha: rSha } = buildTarball(rogue);
228
+ const dest = join(work, 'dest4');
229
+ const lb = await startLoopback(distManifestJson(remoteVersion, rSha), rTar);
230
+ const r = await installExtensionFromGithub({
231
+ destDir: dest,
232
+ pinnedSourceDir: EXT_SRC,
233
+ releaseBase: lb.base
234
+ });
235
+ lb.close();
236
+ ok(!r.ok && /key 漂移/.test(r.error ?? ''), `key 漂移拒绝(${r.error})`);
237
+ ok(!existsSync(dest), '漂移路径零落盘');
238
+ rmSync(rogue, {
239
+ recursive: true,
240
+ force: true
241
+ });
242
+ }
243
+ {
244
+ const dest = join(work, 'dest5');
245
+ mkdirSync(dest, {
246
+ recursive: true
247
+ });
248
+ writeFileSync(join(dest, 'manifest.json'), JSON.stringify({
249
+ ...srcVersion,
250
+ version: remoteVersion
251
+ }));
252
+ const lb = await startLoopback(distManifestJson(remoteVersion, sha), tarball);
253
+ const r = await installExtensionFromGithub({
254
+ destDir: dest,
255
+ pinnedSourceDir: EXT_SRC,
256
+ releaseBase: lb.base
257
+ });
258
+ const hits = lb.tarballHits();
259
+ lb.close();
260
+ ok(r.ok && r.action === 'up-to-date' && hits === 0, `up-to-date 跳过(tarball 下载 ${hits} 次)`);
261
+ }
262
+ {
263
+ const dest = join(work, 'dest6');
264
+ const lb = await startLoopback(distManifestJson(remoteVersion, sha), tarball);
265
+ const r = await installExtensionFromGithub({
266
+ destDir: dest,
267
+ releaseBase: lb.base,
268
+ checkOnly: true
269
+ });
270
+ lb.close();
271
+ ok(r.ok && r.version === remoteVersion && !existsSync(dest), 'check-only 报告远端版本且零落盘');
272
+ }
273
+ rmSync(work, {
274
+ recursive: true,
275
+ force: true
276
+ });
277
+ }{
278
+ const { tarball, sha } = buildTarball(EXT_SRC, '9.9.9');
279
+ const srcVersion = JSON.parse(readFileSync(join(EXT_SRC, 'manifest.json'), 'utf8'));
280
+ const lb = await startLoopback(distManifestJson('9.9.9', sha), tarball);
281
+ const dest = mkdtempSync(join(tmpdir(), 'extdist-cli-'));
282
+ const cli = join(repoRoot, 'ts', 'scripts', 'extension-distribution-cli.ts');
283
+ const run = (args)=>new Promise((resolve)=>{
284
+ const child = spawn('npx', [
285
+ '--yes',
286
+ 'tsx',
287
+ cli,
288
+ ...args
289
+ ], {
290
+ cwd: join(repoRoot, 'ts'),
291
+ stdio: [
292
+ 'ignore',
293
+ 'pipe',
294
+ 'inherit'
295
+ ]
296
+ });
297
+ let buf = '';
298
+ child.stdout.on('data', (c)=>{
299
+ buf += c.toString('utf8');
300
+ });
301
+ child.on('close', (code)=>{
302
+ const line = buf.trim().split('\n').pop() ?? '';
303
+ let json = null;
304
+ if (line.startsWith('{')) {
305
+ try {
306
+ json = JSON.parse(line);
307
+ } catch {}
308
+ }
309
+ resolve({
310
+ code: code ?? -1,
311
+ json
312
+ });
313
+ });
314
+ });
315
+ const r1 = await run([
316
+ '--dest',
317
+ dest,
318
+ '--source-dir',
319
+ EXT_SRC,
320
+ '--release-base',
321
+ lb.base
322
+ ]);
323
+ ok(r1.code === 0 && r1.json?.ok === true && r1.json?.action === 'installed', `CLI installed 单行 JSON + exit 0(action=${String(r1.json?.action)})`);
324
+ const r2 = await run([
325
+ '--dest',
326
+ dest,
327
+ '--source-dir',
328
+ EXT_SRC,
329
+ '--release-base',
330
+ 'http://127.0.0.1:1/releases'
331
+ ]);
332
+ ok(r2.code === 2 && r2.json?.ok === false && r2.json?.action === 'fallback-bundled', `CLI 失败 exit 2 + fallback-bundled JSON`);
333
+ lb.close();
334
+ rmSync(dest, {
335
+ recursive: true,
336
+ force: true
337
+ });
338
+ }console.log(`EXTENSION DISTRIBUTION: ${passed} pass, 0 fail`);
339
+
340
+
341
+ //# sourceURL=ts/scripts/extension-distribution-tests.ts