@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.
Files changed (327) hide show
  1. package/README.md +102 -194
  2. package/README.zh-CN.md +115 -210
  3. package/bin/gotry-backend.js +53 -0
  4. package/bin/gotry-bootstrap.js +466 -35
  5. package/bin/gotry-inner.js +255 -36
  6. package/bin/gotry-process-liveness.d.ts +27 -0
  7. package/bin/gotry-process-liveness.js +97 -0
  8. package/bin/gotry-runtime-resolution.d.ts +1 -1
  9. package/bin/gotry-runtime-resolution.js +2 -2
  10. package/client/client.js +174 -0
  11. package/cordis.gotry-patch.yml +70 -93
  12. package/dist/capabilities/agent-reach-deep.js +45 -122
  13. package/dist/capabilities/agent-reach.js +63 -148
  14. package/dist/capabilities/anything.js +89 -75
  15. package/dist/capabilities/artifacts.js +123 -104
  16. package/dist/capabilities/channel-health.js +65 -45
  17. package/dist/capabilities/channel-registry.js +108 -87
  18. package/dist/capabilities/doctor.js +357 -235
  19. package/dist/capabilities/effect.js +223 -309
  20. package/dist/capabilities/fact-log.js +28 -14
  21. package/dist/capabilities/flyai.js +245 -156
  22. package/dist/capabilities/ground-transfer.js +509 -0
  23. package/dist/capabilities/hbcli.js +144 -148
  24. package/dist/capabilities/hotelbyte-transaction.js +194 -0
  25. package/dist/capabilities/incident-log.js +131 -61
  26. package/dist/capabilities/model-override.js +30 -10
  27. package/dist/capabilities/opensky.js +54 -43
  28. package/dist/capabilities/resilience.js +50 -32
  29. package/dist/capabilities/session/action-cache.js +50 -44
  30. package/dist/capabilities/session/adapters/ctrip-flight.js +119 -62
  31. package/dist/capabilities/session/adapters/ctrip-hotel.js +125 -110
  32. package/dist/capabilities/session/adapters/dida-portal.js +206 -0
  33. package/dist/capabilities/session/adapters/meituan-local.js +35 -54
  34. package/dist/capabilities/session/adapters/rail-12306.js +169 -112
  35. package/dist/capabilities/session/benchmark.js +85 -149
  36. package/dist/capabilities/session/extension-bridge.js +320 -259
  37. package/dist/capabilities/session/extension-channel.js +57 -76
  38. package/dist/capabilities/session/extension-distribution.js +115 -119
  39. package/dist/capabilities/session/extract.js +31 -21
  40. package/dist/capabilities/session/golden-score.js +55 -33
  41. package/dist/capabilities/session/health-watch.js +146 -154
  42. package/dist/capabilities/session/read-guard.js +55 -47
  43. package/dist/capabilities/session/static-flight-golden.js +49 -36
  44. package/dist/capabilities/session/transport.js +54 -61
  45. package/dist/capabilities/session/wizard.js +63 -93
  46. package/dist/capabilities/session-consent.js +143 -47
  47. package/dist/capabilities/session-login.js +95 -126
  48. package/dist/capabilities/session-search.js +391 -253
  49. package/dist/capabilities/sponsor-plugin.js +341 -0
  50. package/dist/capabilities/visa-policy.js +87 -73
  51. package/dist/capabilities/weather.js +163 -235
  52. package/dist/scripts/action-cache-tests.js +24 -59
  53. package/dist/scripts/agent-planning-turn-deadline-e2e.js +91 -142
  54. package/dist/scripts/agent-planning-turn-deadline-tests.js +80 -176
  55. package/dist/scripts/agent-reach-deep-tests.js +30 -40
  56. package/dist/scripts/agent-reach-tests.js +26 -18
  57. package/dist/scripts/agent-reach-wrapper-tests.js +46 -50
  58. package/dist/scripts/anything-tests.js +58 -62
  59. package/dist/scripts/artifact-client-contract-tests.js +69 -0
  60. package/dist/scripts/artifacts-capability-tests.js +235 -0
  61. package/dist/scripts/async-collect.js +26 -15
  62. package/dist/scripts/benchmark-environment-bridge-e2e.js +287 -684
  63. package/dist/scripts/benchmark-environment-bridge-tests.js +818 -3123
  64. package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +66 -279
  65. package/dist/scripts/booking-copilot-availability-policy-tests.js +153 -1257
  66. package/dist/scripts/booking-copilot-bin-proof-tests.js +22 -45
  67. package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +64 -76
  68. package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +69 -199
  69. package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +393 -759
  70. package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +33 -75
  71. package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +60 -110
  72. package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +28 -66
  73. package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +72 -271
  74. package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +73 -275
  75. package/dist/scripts/booking-copilot-runtime-proof-tests.js +784 -3398
  76. package/dist/scripts/booking-copilot-server-proof-tests.js +63 -168
  77. package/dist/scripts/booking-copilot-startup-proof-tests.js +38 -124
  78. package/dist/scripts/booking-executor-tests.js +80 -0
  79. package/dist/scripts/booking-recovery-chain-tests.js +182 -0
  80. package/dist/scripts/booking-saga-tests.js +61 -123
  81. package/dist/scripts/booking-surface-contract-proof-tests.js +152 -1167
  82. package/dist/scripts/bootstrap-tests.js +1383 -128
  83. package/dist/scripts/build-changelog.js +89 -130
  84. package/dist/scripts/build-metrics-report.js +135 -143
  85. package/dist/scripts/changelog-tests.js +35 -82
  86. package/dist/scripts/channel-probe-tests.js +44 -116
  87. package/dist/scripts/channel-probe.js +84 -167
  88. package/dist/scripts/channel-registry-tests.js +97 -185
  89. package/dist/scripts/companion-tests.js +25 -70
  90. package/dist/scripts/dida-cookie-probe.js +87 -0
  91. package/dist/scripts/dida-sw-probe.js +114 -0
  92. package/dist/scripts/diff-test.js +17 -12
  93. package/dist/scripts/doctor-tests.js +428 -120
  94. package/dist/scripts/dsh-artifact-e2e.js +150 -0
  95. package/dist/scripts/dsh-artifact-web-e2e.js +443 -0
  96. package/dist/scripts/dsh-http-proxy-sse-proof.js +90 -0
  97. package/dist/scripts/dsh-runtime-closure-tests.js +110 -153
  98. package/dist/scripts/dsh-runtime-closure.js +75 -63
  99. package/dist/scripts/dsh-session-v3-migration-proof.js +106 -0
  100. package/dist/scripts/dsh-subprocess-local-proof.js +149 -0
  101. package/dist/scripts/dsh-target-closure-proof.js +178 -0
  102. package/dist/scripts/effect-tests.js +165 -552
  103. package/dist/scripts/engine-run.js +1 -3
  104. package/dist/scripts/engine-tests.js +16 -10
  105. package/dist/scripts/evaluation-cadence-tests.js +69 -242
  106. package/dist/scripts/evaluation-contract-tests.js +193 -499
  107. package/dist/scripts/extension-distribution-cli.js +19 -15
  108. package/dist/scripts/extension-distribution-tests.js +98 -211
  109. package/dist/scripts/extension-tests.js +366 -389
  110. package/dist/scripts/fact-gate-tests.js +725 -263
  111. package/dist/scripts/fixtures/extension-bridge-unref-child.mjs +21 -0
  112. package/dist/scripts/flight-hotel-anchor-363-registered-e2e.js +169 -0
  113. package/dist/scripts/flight-malformed-tests.js +159 -0
  114. package/dist/scripts/flyai-tests.js +325 -68
  115. package/dist/scripts/g5-guard-tests.js +131 -0
  116. package/dist/scripts/g5-guard.js +189 -0
  117. package/dist/scripts/gen-lunar-anchors.js +106 -0
  118. package/dist/scripts/gotry-backend-kernel-tests.js +79 -0
  119. package/dist/scripts/ground-transfer-tests.js +956 -0
  120. package/dist/scripts/hbcli-e2e-tests.js +71 -90
  121. package/dist/scripts/hbcli-live-optin-tests.js +96 -0
  122. package/dist/scripts/hbcli-release-contract-tests.js +122 -0
  123. package/dist/scripts/hbcli-tests.js +41 -115
  124. package/dist/scripts/health-watch-cli.js +42 -28
  125. package/dist/scripts/hotel-date-gate-tests.js +496 -0
  126. package/dist/scripts/hotelbyte-reconcile-tests.js +141 -0
  127. package/dist/scripts/hotelbyte-spawn-e2e-tests.js +373 -0
  128. package/dist/scripts/i18n-tests.js +16 -9
  129. package/dist/scripts/incident-tests.js +281 -87
  130. package/dist/scripts/issue-194-job-id-guard-tests.js +106 -0
  131. package/dist/scripts/issue-233-cancel-refund-commission-tests.js +392 -0
  132. package/dist/scripts/issue-271-liveness-tests.js +547 -0
  133. package/dist/scripts/issue-289-model-retry-real-tests.js +296 -0
  134. package/dist/scripts/issue-289-model-retry-tests.js +441 -0
  135. package/dist/scripts/issue-289-web-retry-e2e.js +630 -0
  136. package/dist/scripts/issue-338-home-city-e2e.js +577 -0
  137. package/dist/scripts/issue343-real-entry-e2e.js +160 -0
  138. package/dist/scripts/journey-tests.js +22 -27
  139. package/dist/scripts/kernel-manifest-evidence.js +109 -0
  140. package/dist/scripts/kernel-manifest-gate.js +126 -0
  141. package/dist/scripts/kernel-manifest-tests.js +212 -0
  142. package/dist/scripts/kernel-manifest-trace-entry.js +7 -0
  143. package/dist/scripts/kernel-manifest-trace-hook.mjs +28 -0
  144. package/dist/scripts/kernel-manifest.js +369 -0
  145. package/dist/scripts/ledger-repair-apply-tests.js +316 -0
  146. package/dist/scripts/ledger-repair-plan-tests.js +375 -0
  147. package/dist/scripts/ledger-tests.js +325 -340
  148. package/dist/scripts/ledger-workflow-crash.js +10 -20
  149. package/dist/scripts/map-tools-vendor-package-proof.js +206 -134
  150. package/dist/scripts/memory-capture-tests.js +242 -61
  151. package/dist/scripts/memory-decay-tests.js +18 -52
  152. package/dist/scripts/memory-lifecycle-tests.js +657 -0
  153. package/dist/scripts/memory-lifecycle.js +196 -0
  154. package/dist/scripts/memory-metrics.js +24 -12
  155. package/dist/scripts/memory-value-report.js +474 -222
  156. package/dist/scripts/memory-value-tests.js +328 -0
  157. package/dist/scripts/metrics-report-tests.js +62 -199
  158. package/dist/scripts/model-override-e2e.js +66 -105
  159. package/dist/scripts/nightly-evidence-tests.js +64 -89
  160. package/dist/scripts/nightly-evidence.js +108 -111
  161. package/dist/scripts/nudge-digest.js +39 -28
  162. package/dist/scripts/onboarding-tests.js +63 -88
  163. package/dist/scripts/opensky-check.js +18 -13
  164. package/dist/scripts/opensky-tests.js +28 -28
  165. package/dist/scripts/persona-surface-guard-tests.js +37 -12
  166. package/dist/scripts/pnpm-dsh-closure-proof.js +2 -5
  167. package/dist/scripts/policy-anchor-359-registered-e2e.js +214 -0
  168. package/dist/scripts/price-drift-tests.js +126 -227
  169. package/dist/scripts/price-drift-watch.js +209 -253
  170. package/dist/scripts/probe-poi-tests.js +52 -45
  171. package/dist/scripts/product-metrics.js +187 -273
  172. package/dist/scripts/publish-preverify.js +47 -41
  173. package/dist/scripts/realtime-pricing-tests.js +37 -76
  174. package/dist/scripts/replay-async.js +20 -18
  175. package/dist/scripts/replay-real.js +16 -18
  176. package/dist/scripts/replay.js +52 -82
  177. package/dist/scripts/session-attach-diagnose.js +16 -12
  178. package/dist/scripts/session-attach-poc.js +34 -37
  179. package/dist/scripts/session-benchmark.js +66 -147
  180. package/dist/scripts/session-dida-live-e2e.js +151 -0
  181. package/dist/scripts/session-extract-tests.js +14 -35
  182. package/dist/scripts/session-login.js +14 -13
  183. package/dist/scripts/session-tests.js +545 -583
  184. package/dist/scripts/sf-live-benchmark.js +92 -110
  185. package/dist/scripts/sf-live-cli-tests.js +2 -9
  186. package/dist/scripts/sf-soft-score-tests.js +19 -60
  187. package/dist/scripts/sf-summary-tests.js +149 -0
  188. package/dist/scripts/sf-summary.js +466 -84
  189. package/dist/scripts/skeleton-check.js +16 -14
  190. package/dist/scripts/skeleton-integration-test.js +11 -10
  191. package/dist/scripts/skills-contract-tests.js +51 -46
  192. package/dist/scripts/smoke-session-gate-tests.js +12 -20
  193. package/dist/scripts/smoke.js +541 -422
  194. package/dist/scripts/sponsor-reuse-tests.js +262 -0
  195. package/dist/scripts/state-cli-tests.js +226 -101
  196. package/dist/scripts/state-cli.js +549 -212
  197. package/dist/scripts/static-golden-tests.js +46 -180
  198. package/dist/scripts/time-eval-tests.js +210 -192
  199. package/dist/scripts/travel-timeline-tests.js +29 -93
  200. package/dist/scripts/turn-handoff-collect-tests.js +46 -93
  201. package/dist/scripts/turn-handoff-collect.js +71 -99
  202. package/dist/scripts/turn-policy-tests.js +28 -29
  203. package/dist/scripts/typed-contract-canary.js +77 -162
  204. package/dist/scripts/tz-resolver-sanity.js +50 -0
  205. package/dist/scripts/tz-resolver-tests.js +584 -0
  206. package/dist/scripts/unified-tests.js +23 -19
  207. package/dist/scripts/visa-policy-tests.js +31 -44
  208. package/dist/scripts/weather-tests.js +121 -543
  209. package/dist/scripts/wish-channel-gate-tests.js +29 -86
  210. package/dist/scripts/write-gate-tests.js +522 -0
  211. package/dist/scripts/z3-lifecycle-fault-tests.js +188 -0
  212. package/dist/scripts/z3-lifecycle-tests.js +170 -0
  213. package/dist/scripts/z3-race-repeat-tests.js +39 -0
  214. package/dist/scripts/z3-race-tests.js +18 -12
  215. package/dist/src/artifact-gate.js +652 -221
  216. package/dist/src/backend/kernel.js +91 -0
  217. package/dist/src/backend/modules/booking-copilot.js +55 -0
  218. package/dist/src/backend/modules/booking-executor.js +124 -0
  219. package/dist/src/backend/modules/session-search.js +194 -0
  220. package/dist/src/benchmark-agent-conformance.js +296 -262
  221. package/dist/src/benchmark-environment-bridge.js +298 -413
  222. package/dist/src/benchmark-headless-child-diagnostics.js +93 -100
  223. package/dist/src/benchmark-tool-isolation.js +94 -67
  224. package/dist/src/bookable-facts.js +299 -174
  225. package/dist/src/booking-saga.js +64 -120
  226. package/dist/src/booking-surface/availability-policy.js +443 -576
  227. package/dist/src/booking-surface/cancel-refund-commission.js +379 -0
  228. package/dist/src/booking-surface/contracts.js +24 -80
  229. package/dist/src/booking-surface/dsh-planner.js +510 -281
  230. package/dist/src/booking-surface/dsh-plugin.js +17 -1
  231. package/dist/src/booking-surface/error-codes.js +82 -10
  232. package/dist/src/booking-surface/index.js +0 -3
  233. package/dist/src/booking-surface/profile.js +10 -54
  234. package/dist/src/booking-surface/recovery-chain.js +367 -0
  235. package/dist/src/booking-surface/runtime.js +765 -891
  236. package/dist/src/booking-surface/server.js +200 -251
  237. package/dist/src/booking-surface/startup.js +58 -54
  238. package/dist/src/booking-surface/validation.js +150 -218
  239. package/dist/src/bridge.js +20 -13
  240. package/dist/src/companions.js +48 -74
  241. package/dist/src/contracts.js +21 -43
  242. package/dist/src/dsh-llm.js +82 -120
  243. package/dist/src/engine.js +253 -239
  244. package/dist/src/evaluation-cadence.js +72 -209
  245. package/dist/src/evaluation-contracts.js +220 -843
  246. package/dist/src/flight-pack-adapter.js +54 -0
  247. package/dist/src/flight-pack-contract.js +2 -0
  248. package/dist/src/gotry-backend.js +70 -0
  249. package/dist/src/hotel-date-gate.js +118 -0
  250. package/dist/src/i18n.js +18 -7
  251. package/dist/src/index.js +1425 -1629
  252. package/dist/src/journey.js +132 -81
  253. package/dist/src/ledger-repair-apply.js +538 -0
  254. package/dist/src/ledger-repair-plan.js +463 -0
  255. package/dist/src/loop.js +257 -166
  256. package/dist/src/memory-capture.js +180 -32
  257. package/dist/src/memory-decay.js +30 -14
  258. package/dist/src/memory-lifecycle.js +1310 -0
  259. package/dist/src/memory-utility.js +27 -40
  260. package/dist/src/mock-llm.js +36 -61
  261. package/dist/src/model.js +81 -36
  262. package/dist/src/realtime-pricing.js +63 -72
  263. package/dist/src/slot-spec.js +84 -106
  264. package/dist/src/state-ledger.js +310 -471
  265. package/dist/src/subagent-job-id-guard.js +58 -0
  266. package/dist/src/time-anchor.js +231 -33
  267. package/dist/src/tool-packet.js +20 -8
  268. package/dist/src/travel-slots.js +58 -35
  269. package/dist/src/travel-timeline.js +44 -63
  270. package/dist/src/turn-deadline.js +121 -127
  271. package/dist/src/turn-policy.js +61 -89
  272. package/dist/src/tz-resolver.js +143 -0
  273. package/dist/src/unified.js +504 -381
  274. package/dist/src/wish-pool.js +39 -14
  275. package/dist/src/write-gate.js +495 -0
  276. package/dist/src/z3-shared.js +273 -7
  277. package/extension/README.md +4 -3
  278. package/extension/background.js +125 -14
  279. package/extension/content-bridge.js +23 -1
  280. package/extension/content-main.js +15 -4
  281. package/extension/manifest.json +16 -8
  282. package/package.json +251 -220
  283. package/ts/capabilities/agent-reach.ts +4 -4
  284. package/ts/capabilities/anything.ts +1 -1
  285. package/ts/capabilities/artifacts.ts +46 -9
  286. package/ts/capabilities/flyai.ts +156 -37
  287. package/ts/capabilities/hbcli.ts +1 -1
  288. package/ts/capabilities/incident-log.ts +88 -59
  289. package/ts/capabilities/session/adapters/ctrip-flight.ts +99 -36
  290. package/ts/capabilities/session/adapters/dida-portal.ts +250 -0
  291. package/ts/capabilities/session/adapters/rail-12306.ts +123 -24
  292. package/ts/capabilities/session/extension-bridge.ts +226 -101
  293. package/ts/capabilities/session/extension-channel.ts +22 -9
  294. package/ts/capabilities/session/wizard.ts +2 -2
  295. package/ts/capabilities/session-consent.ts +98 -14
  296. package/ts/capabilities/session-login.ts +1 -0
  297. package/ts/capabilities/session-search.ts +315 -31
  298. package/ts/dsh-runtime/vendor/README.md +8 -4
  299. package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +7 -1
  300. package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +5 -3
  301. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +1 -1
  302. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +1 -1
  303. package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +6 -6
  304. package/ts/package.json +236 -16
  305. package/ts/scripts/map-tools-vendor-package-proof.ts +152 -31
  306. package/ts/scripts/state-cli.ts +418 -51
  307. package/ts/src/artifact-gate.ts +561 -15
  308. package/ts/src/benchmark-environment-bridge.ts +37 -20
  309. package/ts/src/bookable-facts.ts +183 -7
  310. package/ts/src/booking-surface/cancel-refund-commission.ts +488 -0
  311. package/ts/src/booking-surface/dsh-planner.ts +240 -32
  312. package/ts/src/booking-surface/dsh-plugin.js +17 -1
  313. package/ts/src/booking-surface/error-codes.ts +75 -0
  314. package/ts/src/booking-surface/recovery-chain.ts +409 -0
  315. package/ts/src/booking-surface/server.ts +84 -51
  316. package/ts/src/booking-surface/validation.ts +2 -0
  317. package/ts/src/contracts.ts +12 -2
  318. package/ts/src/dsh-llm.ts +4 -8
  319. package/ts/src/index.ts +609 -90
  320. package/ts/src/loop.ts +116 -7
  321. package/ts/src/memory-capture.ts +227 -3
  322. package/ts/src/mock-llm.ts +4 -8
  323. package/ts/src/model.ts +88 -2
  324. package/ts/src/state-ledger.ts +47 -29
  325. package/ts/src/subagent-job-id-guard.ts +72 -0
  326. package/ts/src/time-anchor.ts +217 -13
  327. package/ts/src/unified.ts +316 -54
@@ -1,3 +1,18 @@
1
+ /**
2
+ * extension-distribution CLI 入口(gotry setup --extension-from=github,ADR-21):
3
+ *
4
+ * bin/gotry-bootstrap.js setup 子命令 spawn `npx tsx scripts/extension-distribution-cli.ts`,
5
+ * 本脚本调 installExtensionFromGithub,把结果以单行 JSON stdout 打印(父进程解析后人话化)。
6
+ *
7
+ * 参数:
8
+ * --dest <dir> 落位目录(默认 ~/.gotry/extension)
9
+ * --source-dir <dir> bundled 钉扎参照(默认仓库 extension/,由 bootstrap 传入)
10
+ * --release-base <url> Releases 基址(默认 GitHub 官方;测试/镜像可覆盖)
11
+ * --check-only 只报告远端版本,不落盘
12
+ *
13
+ * 退出码:0 = installed/up-to-date;2 = fallback-bundled(JSON 字段区分原因,父进程据此降级);
14
+ * 非 0 且无 JSON = 脚本自身异常。
15
+ */
1
16
  import process from 'node:process';
2
17
  import { homedir } from 'node:os';
3
18
  import { join, dirname } from 'node:path';
@@ -14,22 +29,11 @@ const sourceDir = argValue(argv, '--source-dir') ?? join(repoRoot, 'extension');
14
29
  const releaseBase = argValue(argv, '--release-base') ?? DEFAULT_RELEASE_BASE;
15
30
  const checkOnly = argv.includes('--check-only');
16
31
  try {
17
- const r = await installExtensionFromGithub({
18
- destDir: dest,
19
- pinnedSourceDir: sourceDir,
20
- releaseBase,
21
- checkOnly
22
- });
32
+ const r = await installExtensionFromGithub({ destDir: dest, pinnedSourceDir: sourceDir, releaseBase, checkOnly });
23
33
  process.stdout.write(`${JSON.stringify(r)}\n`);
24
34
  process.exit(r.ok ? 0 : 2);
25
- } catch (e) {
26
- process.stdout.write(`${JSON.stringify({
27
- ok: false,
28
- action: 'fallback-bundled',
29
- error: `CLI 异常 ${e.message}`
30
- })}\n`);
35
+ }
36
+ catch (e) {
37
+ process.stdout.write(`${JSON.stringify({ ok: false, action: 'fallback-bundled', error: `CLI 异常 ${e.message}` })}\n`);
31
38
  process.exit(2);
32
39
  }
33
-
34
-
35
- //# sourceURL=ts/scripts/extension-distribution-cli.ts
@@ -1,20 +1,27 @@
1
- import assert from 'node:assert/strict';
1
+ /**
2
+ * 扩展分发通道合同测试(§43;ADR-21 分发 A,GitHub Releases 下载链)。
3
+ *
4
+ * 全离线确定性:回环 node:http 服务器(mkdtemp + 临时端口)serve dist-manifest 与
5
+ * 真 tar.gz 夹具(由平台 tar 从仓内 extension/ 打出);零外网、零浏览器、零共享状态。
6
+ *
7
+ * 断言面:
8
+ * ① 合同:稳定资产名/URL 形态;package-extension.mjs 资产名逐字防漂移(读源码比对);
9
+ * ② fail-closed:parseDistManifest 对坏 JSON/缺字段/资产名漂移/非 64-hex 哈希全部拒绝;
10
+ * ③ 版本比较:0.1.0<0.1.1<0.2.0<1.0.0,相等为 0;
11
+ * ④ 回环 e2e:installed(下载→SHA256→tar 解压→key 钉扎→原子交换)/ up-to-date(不下载 tarball)/
12
+ * check-only(只报告不落盘)/ 坏 SHA 拒绝 / 404 降级 fallback-bundled / key 漂移拒绝;
13
+ * ⑤ CLI 契约:extension-distribution-cli.ts 对回环基址单行 JSON + 退出码 0/2。
14
+ */
2
15
  import { execFileSync, spawn } from 'node:child_process';
3
16
  import { createServer } from 'node:http';
4
17
  import { copyFileSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
5
18
  import { tmpdir } from 'node:os';
6
19
  import { join, dirname } from 'node:path';
7
20
  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';
21
+ 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
22
  const repoRoot = join(dirname(fileURLToPath(import.meta.url)), '..', '..');
10
23
  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
- ];
24
+ const EXT_FILES = ['manifest.json', 'background.js', 'content-main.js', 'content-bridge.js', 'README.md'];
18
25
  let passed = 0;
19
26
  function ok(cond, label) {
20
27
  if (!cond) {
@@ -24,318 +31,198 @@ function ok(cond, label) {
24
31
  passed += 1;
25
32
  console.log(` ok - ${label}`);
26
33
  }
34
+ // ─── ① 合同面 ───────────────────────────────────────────────────────────────
27
35
  {
28
36
  const urls = distAssetUrls();
29
37
  ok(urls.tarball === `${DEFAULT_RELEASE_BASE}/latest/download/${DIST_ASSET_TARBALL}`, `tarball URL 形态(${urls.tarball})`);
30
38
  ok(urls.manifest.endsWith(`/latest/download/${DIST_ASSET_MANIFEST}`), 'manifest URL 形态(latest/download 永久链)');
31
39
  ok(distAssetUrls('https://x.example/releases/').tarball === 'https://x.example/releases/latest/download/gotry-session-bridge.tar.gz', 'releaseBase 尾斜杠归一');
40
+ // 打包脚本资产名逐字防漂移(读 mjs 源码;名字漂移 = latest/download 永久链断裂)
32
41
  const pkgSrc = readFileSync(join(repoRoot, 'scripts', 'package-extension.mjs'), 'utf8');
33
42
  ok(pkgSrc.includes(`const ASSET_TARBALL = '${DIST_ASSET_TARBALL}'`), 'package-extension.mjs tarball 资产名一致');
34
43
  ok(pkgSrc.includes(`const ASSET_STORE_ZIP = '${DIST_ASSET_STORE_ZIP}'`), 'package-extension.mjs store zip 资产名一致');
35
44
  ok(pkgSrc.includes(`const ASSET_MANIFEST = '${DIST_ASSET_MANIFEST}'`), 'package-extension.mjs dist-manifest 资产名一致');
36
45
  ok(pkgSrc.includes("const STAGE = join(OUT, 'gotry-session-bridge')"), '打包根目录名固定 gotry-session-bridge/(下载端 strip-components 依赖)');
37
46
  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
- });
47
+ }
48
+ // ─── parseDistManifest fail-closed ────────────────────────────────────────
49
+ {
50
+ const good = JSON.stringify({ version: '0.1.0', tarball: DIST_ASSET_TARBALL, tarballSha256: 'a'.repeat(64), zip: DIST_ASSET_STORE_ZIP, zipSha256: 'b'.repeat(64) });
46
51
  ok(parseDistManifest(good).version === '0.1.0', '合法 dist-manifest 解析');
47
52
  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
- ]
53
+ ['{bad json', '坏 JSON'],
54
+ [JSON.stringify({ version: 'x', tarball: DIST_ASSET_TARBALL, tarballSha256: 'a'.repeat(64), zip: DIST_ASSET_STORE_ZIP, zipSha256: 'b'.repeat(64) }), 'version 非 x.y.z'],
55
+ [JSON.stringify({ tarball: DIST_ASSET_TARBALL, tarballSha256: 'a'.repeat(64), zip: DIST_ASSET_STORE_ZIP, zipSha256: 'b'.repeat(64) }), '缺 version'],
56
+ [JSON.stringify({ version: '0.1.0', tarball: 'other-name.tar.gz', tarballSha256: 'a'.repeat(64), zip: DIST_ASSET_STORE_ZIP, zipSha256: 'b'.repeat(64) }), 'tarball 资产名漂移'],
57
+ [JSON.stringify({ version: '0.1.0', tarball: DIST_ASSET_TARBALL, tarballSha256: 'zz', zip: DIST_ASSET_STORE_ZIP, zipSha256: 'b'.repeat(64) }), 'tarballSha256 非 64-hex'],
91
58
  ];
92
- for (const [raw, label] of rejects){
59
+ for (const [raw, label] of rejects) {
93
60
  let threw = false;
94
61
  try {
95
62
  parseDistManifest(raw);
96
- } catch {
63
+ }
64
+ catch {
97
65
  threw = true;
98
66
  }
99
67
  ok(threw, `fail-closed:${label}`);
100
68
  }
101
- }{
69
+ }
70
+ // ─── ③ 版本比较 ─────────────────────────────────────────────────────────────
71
+ {
102
72
  ok(compareVersions('0.1.0', '0.1.1') < 0, '0.1.0 < 0.1.1');
103
73
  ok(compareVersions('0.2.0', '0.1.9') > 0, '0.2.0 > 0.1.9');
104
74
  ok(compareVersions('1.0.0', '0.9.9') > 0, '1.0.0 > 0.9.9');
105
75
  ok(compareVersions('0.1.0', '0.1.0') === 0, '相等为 0');
106
76
  ok(compareVersions('0.1', '0.1.0') === 0, '缺段按 0 补齐');
107
- }async function startLoopback(manifestJson, tarball) {
77
+ }
78
+ async function startLoopback(manifestJson, tarball) {
108
79
  let hits = 0;
109
- const server = createServer((req, res)=>{
80
+ const server = createServer((req, res) => {
110
81
  if (req.url?.endsWith(DIST_ASSET_MANIFEST)) {
111
- res.writeHead(200, {
112
- 'content-type': 'application/json'
113
- });
82
+ res.writeHead(200, { 'content-type': 'application/json' });
114
83
  res.end(manifestJson);
115
- } else if (req.url?.endsWith(DIST_ASSET_TARBALL)) {
84
+ }
85
+ else if (req.url?.endsWith(DIST_ASSET_TARBALL)) {
116
86
  hits += 1;
117
- res.writeHead(200, {
118
- 'content-type': 'application/gzip'
119
- });
87
+ res.writeHead(200, { 'content-type': 'application/gzip' });
120
88
  res.end(tarball);
121
- } else {
89
+ }
90
+ else {
122
91
  res.writeHead(404);
123
92
  res.end('not found');
124
93
  }
125
94
  });
126
- await new Promise((r)=>server.listen(0, '127.0.0.1', r));
95
+ await new Promise((r) => server.listen(0, '127.0.0.1', r));
127
96
  const addr = server.address();
128
97
  const base = `http://127.0.0.1:${typeof addr === 'object' && addr ? addr.port : 0}/releases`;
129
98
  return {
130
99
  base,
131
100
  manifestJson,
132
101
  tarball,
133
- tarballHits: ()=>hits,
134
- close: ()=>new Promise((r)=>server.close(()=>r()))
102
+ tarballHits: () => hits,
103
+ close: () => new Promise((r) => server.close(() => r())),
135
104
  };
136
105
  }
106
+ /** 用平台 tar 从 sourceDir 打一个真 tar.gz 夹具(顶层目录 gotry-session-bridge/);
107
+ * versionOverride 把暂存副本的 manifest 版本改写为远端版本(保留真实 key——key 钉扎闸要在场) */
137
108
  function buildTarball(sourceDir, versionOverride) {
138
109
  const stage = mkdtempSync(join(tmpdir(), 'extdist-stage-'));
139
110
  const root = join(stage, 'gotry-session-bridge');
140
111
  mkdirSync(root);
141
- for (const f of EXT_FILES)copyFileSync(join(sourceDir, f), join(root, f));
112
+ for (const f of EXT_FILES)
113
+ copyFileSync(join(sourceDir, f), join(root, f));
142
114
  if (versionOverride != null) {
143
115
  const m = JSON.parse(readFileSync(join(root, 'manifest.json'), 'utf8'));
144
- writeFileSync(join(root, 'manifest.json'), JSON.stringify({
145
- ...m,
146
- version: versionOverride
147
- }));
116
+ writeFileSync(join(root, 'manifest.json'), JSON.stringify({ ...m, version: versionOverride }));
148
117
  }
149
118
  const tarPath = join(stage, DIST_ASSET_TARBALL);
150
- execFileSync('tar', [
151
- '-czf',
152
- tarPath,
153
- '-C',
154
- stage,
155
- 'gotry-session-bridge'
156
- ]);
119
+ execFileSync('tar', ['-czf', tarPath, '-C', stage, 'gotry-session-bridge']);
157
120
  const tarball = readFileSync(tarPath);
158
- rmSync(stage, {
159
- recursive: true,
160
- force: true
161
- });
162
- return {
163
- tarball,
164
- sha: sha256Hex(tarball)
165
- };
121
+ rmSync(stage, { recursive: true, force: true });
122
+ return { tarball, sha: sha256Hex(tarball) };
166
123
  }
167
124
  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
- });
125
+ return JSON.stringify({ version, tarball: DIST_ASSET_TARBALL, tarballSha256: sha, zip: DIST_ASSET_STORE_ZIP, zipSha256: 'c'.repeat(64), builtFromCommit: 'test' });
176
126
  }
177
127
  {
178
128
  const work = mkdtempSync(join(tmpdir(), 'extdist-e2e-'));
179
129
  const { tarball, sha } = buildTarball(EXT_SRC, '9.9.9');
180
130
  const srcVersion = JSON.parse(readFileSync(join(EXT_SRC, 'manifest.json'), 'utf8'));
181
131
  const remoteVersion = '9.9.9';
132
+ // (1) installed:下载→SHA256→解压→key 钉扎→原子交换
182
133
  {
183
134
  const dest = join(work, 'dest1');
184
135
  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
- });
136
+ const r = await installExtensionFromGithub({ destDir: dest, pinnedSourceDir: EXT_SRC, releaseBase: lb.base });
190
137
  lb.close();
191
138
  ok(r.ok && r.action === 'installed' && r.version === remoteVersion, `installed 全链(action=${r.action},v=${r.version},err=${r.error ?? '无'})`);
192
139
  ok(readExtensionKey(dest) === srcVersion.key, '落位产物 key 与 bundled 逐字一致(同扩展 ID)');
193
140
  ok(JSON.parse(readFileSync(join(dest, 'manifest.json'), 'utf8')).version === remoteVersion, '落位产物为远端版本');
194
- for (const f of EXT_FILES)ok(existsSync(join(dest, f)), `文件就位:${f}`);
141
+ for (const f of EXT_FILES)
142
+ ok(existsSync(join(dest, f)), `文件就位:${f}`);
195
143
  }
144
+ // (2) 坏 SHA 拒绝(截断/误传资产防住)
196
145
  {
197
146
  const dest = join(work, 'dest2');
198
147
  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
- });
148
+ const r = await installExtensionFromGithub({ destDir: dest, pinnedSourceDir: EXT_SRC, releaseBase: lb.base });
204
149
  lb.close();
205
150
  ok(!r.ok && r.action === 'fallback-bundled' && /SHA256/.test(r.error ?? ''), `SHA256 不符拒绝(${r.error})`);
206
151
  ok(!existsSync(dest), '失败路径零落盘');
207
152
  }
153
+ // (3) 404 → fallback-bundled
208
154
  {
209
155
  const dest = join(work, 'dest3');
210
156
  const lb = await startLoopback(distManifestJson(remoteVersion, sha), tarball);
211
- lb.close();
212
- const r = await installExtensionFromGithub({
213
- destDir: dest,
214
- releaseBase: lb.base
215
- });
157
+ lb.close(); // 关掉 = 连接拒绝,等价网络不可达
158
+ const r = await installExtensionFromGithub({ destDir: dest, releaseBase: lb.base });
216
159
  ok(!r.ok && r.action === 'fallback-bundled', `无网降级 fallback-bundled(${(r.error ?? '').slice(0, 40)})`);
217
160
  }
161
+ // (4) key 漂移拒绝(通道产物与 bundled 不同 ID → 防端口池/host 权限漂移)
218
162
  {
219
163
  const rogue = mkdtempSync(join(work, 'rogue-'));
220
- const rogueManifest = {
221
- ...srcVersion,
222
- version: remoteVersion,
223
- key: `ROGUE-${srcVersion.key}`
224
- };
164
+ const rogueManifest = { ...srcVersion, version: remoteVersion, key: `ROGUE-${srcVersion.key}` };
225
165
  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));
166
+ for (const f of EXT_FILES.filter((x) => x !== 'manifest.json'))
167
+ copyFileSync(join(EXT_SRC, f), join(rogue, f));
227
168
  const { tarball: rTar, sha: rSha } = buildTarball(rogue);
228
169
  const dest = join(work, 'dest4');
229
170
  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
- });
171
+ const r = await installExtensionFromGithub({ destDir: dest, pinnedSourceDir: EXT_SRC, releaseBase: lb.base });
235
172
  lb.close();
236
173
  ok(!r.ok && /key 漂移/.test(r.error ?? ''), `key 漂移拒绝(${r.error})`);
237
174
  ok(!existsSync(dest), '漂移路径零落盘');
238
- rmSync(rogue, {
239
- recursive: true,
240
- force: true
241
- });
175
+ rmSync(rogue, { recursive: true, force: true });
242
176
  }
177
+ // (5) up-to-date:本地已是远端版本 → 不下载 tarball
243
178
  {
244
179
  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
- }));
180
+ mkdirSync(dest, { recursive: true });
181
+ writeFileSync(join(dest, 'manifest.json'), JSON.stringify({ ...srcVersion, version: remoteVersion }));
252
182
  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
- });
183
+ const r = await installExtensionFromGithub({ destDir: dest, pinnedSourceDir: EXT_SRC, releaseBase: lb.base });
258
184
  const hits = lb.tarballHits();
259
185
  lb.close();
260
186
  ok(r.ok && r.action === 'up-to-date' && hits === 0, `up-to-date 跳过(tarball 下载 ${hits} 次)`);
261
187
  }
188
+ // (6) check-only:只报告远端版本,不落盘
262
189
  {
263
190
  const dest = join(work, 'dest6');
264
191
  const lb = await startLoopback(distManifestJson(remoteVersion, sha), tarball);
265
- const r = await installExtensionFromGithub({
266
- destDir: dest,
267
- releaseBase: lb.base,
268
- checkOnly: true
269
- });
192
+ const r = await installExtensionFromGithub({ destDir: dest, releaseBase: lb.base, checkOnly: true });
270
193
  lb.close();
271
194
  ok(r.ok && r.version === remoteVersion && !existsSync(dest), 'check-only 报告远端版本且零落盘');
272
195
  }
273
- rmSync(work, {
274
- recursive: true,
275
- force: true
276
- });
277
- }{
196
+ rmSync(work, { recursive: true, force: true });
197
+ }
198
+ // ─── ⑤ CLI 契约(回环基址,单行 JSON + 退出码) ────────────────────────────────
199
+ {
278
200
  const { tarball, sha } = buildTarball(EXT_SRC, '9.9.9');
279
201
  const srcVersion = JSON.parse(readFileSync(join(EXT_SRC, 'manifest.json'), 'utf8'));
280
202
  const lb = await startLoopback(distManifestJson('9.9.9', sha), tarball);
281
203
  const dest = mkdtempSync(join(tmpdir(), 'extdist-cli-'));
282
204
  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 {}
205
+ const run = (args) => new Promise((resolve) => {
206
+ const child = spawn('npx', ['--yes', 'tsx', cli, ...args], { cwd: join(repoRoot, 'ts'), stdio: ['ignore', 'pipe', 'inherit'] });
207
+ let buf = '';
208
+ child.stdout.on('data', (c) => { buf += c.toString('utf8'); });
209
+ child.on('close', (code) => {
210
+ const line = (buf.trim().split('\n').pop() ?? '');
211
+ let json = null;
212
+ if (line.startsWith('{')) {
213
+ try {
214
+ json = JSON.parse(line);
308
215
  }
309
- resolve({
310
- code: code ?? -1,
311
- json
312
- });
313
- });
216
+ catch { /* null */ }
217
+ }
218
+ resolve({ code: code ?? -1, json });
314
219
  });
315
- const r1 = await run([
316
- '--dest',
317
- dest,
318
- '--source-dir',
319
- EXT_SRC,
320
- '--release-base',
321
- lb.base
322
- ]);
220
+ });
221
+ const r1 = await run(['--dest', dest, '--source-dir', EXT_SRC, '--release-base', lb.base]);
323
222
  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
- ]);
223
+ const r2 = await run(['--dest', dest, '--source-dir', EXT_SRC, '--release-base', 'http://127.0.0.1:1/releases']);
332
224
  ok(r2.code === 2 && r2.json?.ok === false && r2.json?.action === 'fallback-bundled', `CLI 失败 exit 2 + fallback-bundled JSON`);
333
225
  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
226
+ rmSync(dest, { recursive: true, force: true });
227
+ }
228
+ console.log(`EXTENSION DISTRIBUTION: ${passed} pass, 0 fail`);