@danceiny/gotry 0.0.1-rc.18 → 0.0.1-rc.20

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 (176) hide show
  1. package/README.md +42 -16
  2. package/README.zh-CN.md +37 -15
  3. package/bin/gotry-bootstrap.js +309 -30
  4. package/bin/gotry-inner.js +74 -23
  5. package/bin/gotry-runtime-resolution.d.ts +1 -1
  6. package/bin/gotry-runtime-resolution.js +7 -8
  7. package/cordis.gotry-patch.yml +22 -8
  8. package/data/stations-12306-verify.json +524 -0
  9. package/dist/capabilities/agent-reach.js +4 -4
  10. package/dist/capabilities/anything.js +62 -29
  11. package/dist/capabilities/channel-health.js +103 -0
  12. package/dist/capabilities/channel-registry.js +213 -0
  13. package/dist/capabilities/doctor.js +307 -0
  14. package/dist/capabilities/effect.js +178 -5
  15. package/dist/capabilities/flyai.js +13 -0
  16. package/dist/capabilities/hbcli.js +28 -2
  17. package/dist/capabilities/session/adapters/ctrip-hotel.js +207 -0
  18. package/dist/capabilities/session/adapters/rail-12306.js +285 -0
  19. package/dist/capabilities/session/extension-bridge.js +14 -1
  20. package/dist/capabilities/session/extension-channel.js +4 -2
  21. package/dist/capabilities/session/extension-distribution.js +1 -1
  22. package/dist/capabilities/session-search.js +311 -0
  23. package/dist/capabilities/visa-policy.js +126 -0
  24. package/dist/scripts/agent-planning-turn-deadline-e2e.js +305 -0
  25. package/dist/scripts/agent-planning-turn-deadline-tests.js +281 -0
  26. package/dist/scripts/anything-tests.js +70 -21
  27. package/dist/scripts/benchmark-environment-bridge-e2e.js +139 -37
  28. package/dist/scripts/benchmark-environment-bridge-tests.js +1099 -306
  29. package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +26 -26
  30. package/dist/scripts/{booking-copilot-availability-policy-v2-tests.js → booking-copilot-availability-policy-tests.js} +115 -115
  31. package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +41 -1
  32. package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +75 -120
  33. package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +370 -61
  34. package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +2 -2
  35. package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +7 -3
  36. package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +15 -9
  37. package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +19 -11
  38. package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +16 -52
  39. package/dist/scripts/booking-copilot-runtime-proof-tests.js +3953 -155
  40. package/dist/scripts/booking-copilot-server-proof-tests.js +58 -23
  41. package/dist/scripts/booking-copilot-startup-proof-tests.js +10 -119
  42. package/dist/scripts/booking-surface-contract-proof-tests.js +1154 -326
  43. package/dist/scripts/bootstrap-tests.js +113 -2
  44. package/dist/scripts/build-metrics-report.js +339 -0
  45. package/dist/scripts/channel-probe-tests.js +148 -0
  46. package/dist/scripts/channel-probe.js +252 -0
  47. package/dist/scripts/channel-registry-tests.js +262 -0
  48. package/dist/scripts/doctor-tests.js +175 -0
  49. package/dist/scripts/effect-tests.js +274 -1
  50. package/dist/scripts/extension-tests.js +129 -11
  51. package/dist/scripts/fact-gate-tests.js +91 -2
  52. package/dist/scripts/flyai-tests.js +17 -1
  53. package/dist/scripts/hbcli-e2e-tests.js +1 -3
  54. package/dist/scripts/hbcli-tests.js +38 -1
  55. package/dist/scripts/metrics-report-tests.js +288 -0
  56. package/dist/scripts/persona-surface-guard-tests.js +19 -0
  57. package/dist/scripts/session-tests.js +401 -1
  58. package/dist/scripts/smoke.js +100 -83
  59. package/dist/scripts/turn-handoff-collect-tests.js +216 -0
  60. package/dist/scripts/turn-handoff-collect.js +189 -0
  61. package/dist/scripts/turn-policy-tests.js +56 -0
  62. package/dist/scripts/typed-contract-canary.js +261 -0
  63. package/dist/scripts/visa-policy-tests.js +75 -0
  64. package/dist/scripts/wish-channel-gate-tests.js +111 -0
  65. package/dist/src/artifact-gate.js +91 -3
  66. package/dist/src/benchmark-agent-conformance.js +39 -16
  67. package/dist/src/benchmark-environment-bridge.js +316 -52
  68. package/dist/src/bookable-facts.js +62 -3
  69. package/dist/src/booking-surface/{availability-policy-v2.js → availability-policy.js} +89 -89
  70. package/dist/src/booking-surface/canonical-schema.js +8 -22
  71. package/dist/src/booking-surface/contracts.js +70 -19
  72. package/dist/src/booking-surface/dsh-planner.js +310 -177
  73. package/dist/src/booking-surface/dsh-plugin.js +3 -3
  74. package/dist/src/booking-surface/index.js +1 -5
  75. package/dist/src/booking-surface/profile.js +1 -1
  76. package/dist/src/booking-surface/runtime.js +1682 -247
  77. package/dist/src/booking-surface/server.js +371 -185
  78. package/dist/src/booking-surface/startup.js +17 -27
  79. package/dist/src/booking-surface/validation.js +270 -760
  80. package/dist/src/index.js +739 -150
  81. package/dist/src/turn-deadline.js +292 -0
  82. package/dist/src/turn-policy.js +146 -0
  83. package/dist/src/wish-pool.js +5 -0
  84. package/extension/background.js +23 -4
  85. package/extension/content-main.js +47 -9
  86. package/extension/manifest.json +27 -9
  87. package/package.json +7 -26
  88. package/schemas/booking.surface.schema.json +2593 -0
  89. package/ts/capabilities/agent-reach.ts +4 -4
  90. package/ts/capabilities/anything.ts +89 -38
  91. package/ts/capabilities/flyai.ts +21 -3
  92. package/ts/capabilities/hbcli.ts +53 -4
  93. package/ts/capabilities/session/action-cache.ts +1 -1
  94. package/ts/capabilities/session/adapters/ctrip-hotel.ts +238 -0
  95. package/ts/capabilities/session/adapters/rail-12306.ts +293 -0
  96. package/ts/capabilities/session/extension-bridge.ts +32 -2
  97. package/ts/capabilities/session/extension-channel.ts +9 -8
  98. package/ts/capabilities/session/extension-distribution.ts +3 -1
  99. package/ts/capabilities/session/health-watch.ts +1 -1
  100. package/ts/capabilities/session/read-guard.ts +1 -1
  101. package/ts/capabilities/session/wizard.ts +1 -1
  102. package/ts/capabilities/session-search.ts +323 -1
  103. package/ts/dsh-runtime/vendor/README.md +60 -0
  104. package/ts/dsh-runtime/vendor/dsh-map-tools/LICENSE +21 -0
  105. package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +200 -0
  106. package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +202 -0
  107. package/ts/dsh-runtime/vendor/dsh-map-tools/client/client.js +216 -0
  108. package/ts/dsh-runtime/vendor/dsh-map-tools/cordis.patch.yml +5 -0
  109. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/amap.js +371 -0
  110. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/nominatim.js +63 -0
  111. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/osrm.js +56 -0
  112. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/photon.js +55 -0
  113. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-file.js +87 -0
  114. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-route.js +126 -0
  115. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config.js +16 -0
  116. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/index.js +109 -0
  117. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +27 -0
  118. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/geocode.js +127 -0
  119. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/poi.js +84 -0
  120. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/routes.js +170 -0
  121. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/amap.d.ts +53 -0
  122. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/nominatim.d.ts +17 -0
  123. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/osrm.d.ts +15 -0
  124. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/photon.d.ts +22 -0
  125. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-file.d.ts +33 -0
  126. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-route.d.ts +20 -0
  127. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config.d.ts +23 -0
  128. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/index.d.ts +18 -0
  129. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +14 -0
  130. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/geocode.d.ts +11 -0
  131. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/poi.d.ts +9 -0
  132. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/routes.d.ts +16 -0
  133. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/types.d.ts +55 -0
  134. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types.js +16 -0
  135. package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +91 -0
  136. package/ts/package.json +9 -0
  137. package/ts/scripts/turn-handoff-collect.ts +178 -0
  138. package/ts/src/artifact-gate.ts +82 -2
  139. package/ts/src/benchmark-agent-conformance.ts +54 -15
  140. package/ts/src/benchmark-environment-bridge.ts +234 -46
  141. package/ts/src/bookable-facts.ts +109 -5
  142. package/ts/src/booking-saga.ts +1 -1
  143. package/ts/src/booking-surface/{availability-policy-v2.ts → availability-policy.ts} +124 -125
  144. package/ts/src/booking-surface/canonical-schema.js +8 -22
  145. package/ts/src/booking-surface/contracts.ts +278 -239
  146. package/ts/src/booking-surface/dsh-planner.ts +333 -194
  147. package/ts/src/booking-surface/dsh-plugin.js +3 -3
  148. package/ts/src/booking-surface/index.ts +1 -5
  149. package/ts/src/booking-surface/profile.ts +11 -11
  150. package/ts/src/booking-surface/runtime.ts +1351 -351
  151. package/ts/src/booking-surface/server.ts +282 -175
  152. package/ts/src/booking-surface/startup.ts +36 -48
  153. package/ts/src/booking-surface/validation.ts +194 -442
  154. package/ts/src/contracts.ts +1 -1
  155. package/ts/src/index.ts +492 -172
  156. package/ts/src/loop.ts +1 -1
  157. package/ts/src/state-ledger.ts +1 -1
  158. package/ts/src/turn-deadline.ts +365 -0
  159. package/ts/src/turn-policy.ts +154 -0
  160. package/ts/src/wish-pool.ts +17 -4
  161. package/dist/scripts/agent-planning-budget-e2e.js +0 -227
  162. package/dist/scripts/agent-planning-budget-tests.js +0 -173
  163. package/dist/scripts/booking-copilot-v2-runtime-proof-tests.js +0 -3935
  164. package/dist/scripts/booking-surface-v2-contract-proof-tests.js +0 -1174
  165. package/dist/src/booking-surface/contracts-v2.js +0 -89
  166. package/dist/src/booking-surface/runtime-v2.js +0 -1771
  167. package/dist/src/booking-surface/server-v2.js +0 -334
  168. package/dist/src/booking-surface/validation-v2.js +0 -319
  169. package/dist/src/tool-budget.js +0 -136
  170. package/schemas/booking.surface.v1.schema.json +0 -927
  171. package/schemas/booking.surface.v2.schema.json +0 -61
  172. package/ts/src/booking-surface/contracts-v2.ts +0 -118
  173. package/ts/src/booking-surface/runtime-v2.ts +0 -1466
  174. package/ts/src/booking-surface/server-v2.ts +0 -247
  175. package/ts/src/booking-surface/validation-v2.ts +0 -205
  176. package/ts/src/tool-budget.ts +0 -165
@@ -0,0 +1,207 @@
1
+ const HOTEL_CITY_CODES = {
2
+ 上海: '2',
3
+ 北京: '1',
4
+ 广州: '32',
5
+ 深圳: '30',
6
+ 成都: '28',
7
+ 杭州: '17',
8
+ 南京: '12',
9
+ 苏州: '14',
10
+ 无锡: '13',
11
+ 扬州: '15',
12
+ 镇江: '16',
13
+ 青岛: '7',
14
+ 厦门: '25',
15
+ 珠海: '31',
16
+ 三亚: '43',
17
+ 海口: '42',
18
+ 桂林: '33',
19
+ 昆明: '34',
20
+ 大理: '36',
21
+ 丽江: '37',
22
+ 西双版纳: '35',
23
+ 贵阳: '38',
24
+ 拉萨: '41',
25
+ 乌鲁木齐: '39',
26
+ 太原: '105',
27
+ 长春: '158',
28
+ 南通: '82',
29
+ 敦煌: '11',
30
+ 舟山: '19',
31
+ 张家界: '27',
32
+ 黄山市: '23',
33
+ 九江: '24',
34
+ 武夷山: '26',
35
+ 迪拜: '220'
36
+ };
37
+ export function buildHotelEntryUrl(q) {
38
+ const unresolved = [];
39
+ const cityId = String(q.cityId ?? '').trim() || HOTEL_CITY_CODES[q.to.trim()];
40
+ if (!cityId) unresolved.push(q.to);
41
+ if (unresolved.length > 0) {
42
+ return {
43
+ ok: false,
44
+ unresolved
45
+ };
46
+ }
47
+ const params = new URLSearchParams({
48
+ city: cityId
49
+ });
50
+ if (q.checkIn) params.set('checkin', q.checkIn);
51
+ if (q.checkOut) params.set('checkout', q.checkOut);
52
+ if (q.adults && q.adults > 0) params.set('adult', String(q.adults));
53
+ return {
54
+ ok: true,
55
+ url: `https://hotels.ctrip.com/hotels/list?${params.toString()}`
56
+ };
57
+ }
58
+ export const HOTEL_NETWORK_HINTS = [
59
+ /hotels\.ctrip\.com\/(hotels\/api|domestic\/pc\/api)/i,
60
+ /GetHotelListBySOA|GetHotelListByCity|HotelSearch|hotelsearch/i,
61
+ /restapi\/soa2\/\d+\/fetchHotelList/i
62
+ ];
63
+ export function looksLikeHotelListBody(body) {
64
+ if (!body || body.length > 2_000_000) return false;
65
+ return /"hotelList"|"hotelMatchInfos"|"hotelName"/.test(body);
66
+ }
67
+ export const HOTEL_SITE_HOST = 'hotels.ctrip.com';
68
+ function hotelSignature(o) {
69
+ const name = o.hotelName ?? o.name ?? o.hotelNameEn;
70
+ if (typeof name !== 'string' || !name.trim()) return null;
71
+ let price;
72
+ let priceRaw;
73
+ if (typeof o.price === 'number' && o.price > 0) price = o.price;
74
+ else if (typeof o.price === 'string' && o.price.trim()) priceRaw = o.price.trim();
75
+ const probe = (v, seen = new Set())=>{
76
+ if (v == null || typeof v !== 'object') return;
77
+ if (seen.has(v)) return;
78
+ seen.add(v);
79
+ for (const [k, child] of Object.entries(v)){
80
+ if (/^(avgPrice|totalPrice|price|amount|total|startPrice)$/i.test(k) && typeof child === 'number' && child > 0 && price === undefined) price = child;
81
+ else if (/^(price|priceDisplay|amountText)$/i.test(k) && typeof child === 'string' && child.trim() && priceRaw === undefined) priceRaw = child.trim();
82
+ else probe(child, seen);
83
+ }
84
+ };
85
+ probe(o.priceInfo);
86
+ const flatPrice = o.totalPrice ?? o.avgPrice ?? o.minPrice;
87
+ if (typeof flatPrice === 'number' && flatPrice > 0 && price === undefined) price = flatPrice;
88
+ const flatRaw = o.priceText ?? o.priceDisplay;
89
+ if (typeof flatRaw === 'string' && flatRaw.trim() && priceRaw === undefined) priceRaw = flatRaw.trim();
90
+ if (price === undefined && priceRaw === undefined) return null;
91
+ const starRaw = o.star ?? o.level ?? o.hotelStar;
92
+ const star = typeof starRaw === 'number' && starRaw > 0 ? starRaw : Number.isFinite(Number(starRaw)) && Number(starRaw) > 0 ? Number(starRaw) : undefined;
93
+ const scoreRaw = o.score ?? o.commentScore ?? o.reviewScore;
94
+ const score = scoreRaw == null ? undefined : String(scoreRaw);
95
+ const pos = o.position;
96
+ const address = (typeof pos?.address === 'string' ? pos.address : undefined) ?? (typeof o.address === 'string' ? o.address : undefined);
97
+ const hotelId = (typeof o.hotelId === 'number' || typeof o.hotelId === 'string' ? String(o.hotelId) : undefined) ?? (typeof o.hotelIdStr === 'string' ? o.hotelIdStr : undefined);
98
+ return {
99
+ name: name.trim(),
100
+ price,
101
+ priceRaw,
102
+ star,
103
+ score,
104
+ address,
105
+ hotelId
106
+ };
107
+ }
108
+ function ctripStructuredCandidate(item) {
109
+ const info = item.hotelInfo;
110
+ const summary = info?.summary ?? item;
111
+ const nameInfo = summary.nameInfo;
112
+ const names = nameInfo?.names;
113
+ const nameRaw = nameInfo?.name ?? (Array.isArray(names) && names.length > 0 ? names[0] : undefined) ?? summary.hotelName ?? summary.name;
114
+ if (typeof nameRaw !== 'string' || !nameRaw.trim()) return null;
115
+ let price;
116
+ let priceRaw;
117
+ let encrypted = false;
118
+ const rooms = info?.roomInfo ?? item.roomInfo;
119
+ if (Array.isArray(rooms)) {
120
+ for (const room of rooms){
121
+ if (room == null || typeof room !== 'object') continue;
122
+ const pi = room.priceInfo;
123
+ if (!pi) continue;
124
+ if (typeof pi.price === 'number' && pi.price > 0) price = price === undefined ? pi.price : Math.min(price, pi.price);
125
+ if (typeof pi.price === 'string' && pi.price.trim() && !priceRaw) priceRaw = pi.price.trim();
126
+ if (typeof pi.displayPrice === 'string' && pi.displayPrice.trim() && !priceRaw) priceRaw = pi.displayPrice.trim();
127
+ if (pi.priceToken != null && pi.price === undefined) encrypted = true;
128
+ }
129
+ }
130
+ if (price === undefined && !priceRaw) {
131
+ const priceProbe = (v, depth, seen)=>{
132
+ if (price !== undefined || depth > 6 || v == null || typeof v !== 'object' || seen.has(v)) return;
133
+ seen.add(v);
134
+ for (const [k, child] of Object.entries(v)){
135
+ if (/^(price|avgPrice|totalPrice|minPrice|amount)$/i.test(k) && typeof child === 'number' && child > 0) {
136
+ price = child;
137
+ return;
138
+ }
139
+ if (/^(price|displayPrice|amountText)$/i.test(k) && typeof child === 'string' && child.trim()) {
140
+ priceRaw = priceRaw ?? child.trim();
141
+ continue;
142
+ }
143
+ priceProbe(child, depth + 1, seen);
144
+ }
145
+ };
146
+ priceProbe(item, 0, new Set());
147
+ }
148
+ if (price === undefined && !priceRaw && !encrypted) return null;
149
+ const starOf = summary.hotelStar;
150
+ const starRaw = starOf?.star ?? summary.star;
151
+ const star = typeof starRaw === 'number' && starRaw > 0 ? starRaw : undefined;
152
+ const scoreRaw = (info?.commentInfo ?? summary.commentInfo)?.commentScore;
153
+ const pos = summary.positionInfo;
154
+ const address = (typeof pos?.address === 'string' ? pos.address : undefined) ?? (typeof summary.address === 'string' ? summary.address : undefined);
155
+ const hotelId = summary.hotelId != null ? String(summary.hotelId) : undefined;
156
+ return {
157
+ name: nameRaw.trim(),
158
+ price,
159
+ priceRaw,
160
+ star,
161
+ score: scoreRaw == null ? undefined : String(scoreRaw),
162
+ address,
163
+ hotelId
164
+ };
165
+ }
166
+ export function parseCtripHotelList(body, opts = {}) {
167
+ let raw;
168
+ try {
169
+ raw = JSON.parse(body);
170
+ } catch {
171
+ return [];
172
+ }
173
+ const out = [];
174
+ const maxItems = opts.maxItems ?? 20;
175
+ const walk = (node, depth, seen)=>{
176
+ if (out.length >= maxItems || depth > 12 || node == null || typeof node !== 'object' || seen.has(node)) return;
177
+ if (Array.isArray(node)) {
178
+ for (const item of node){
179
+ if (out.length >= maxItems) return;
180
+ if (item == null || typeof item !== 'object' || Array.isArray(item)) continue;
181
+ const cand = hotelSignature(item) ?? ctripStructuredCandidate(item);
182
+ if (!cand) continue;
183
+ out.push({
184
+ name: cand.name,
185
+ price: cand.price ?? 0,
186
+ priceRaw: cand.priceRaw,
187
+ star: cand.star,
188
+ score: cand.score,
189
+ address: cand.address,
190
+ hotelId: cand.hotelId,
191
+ jumpUrl: cand.hotelId ? `https://hotels.ctrip.com/hotel/${cand.hotelId}` : undefined
192
+ });
193
+ }
194
+ return;
195
+ }
196
+ seen.add(node);
197
+ for (const child of Object.values(node)){
198
+ walk(child, depth + 1, seen);
199
+ if (out.length >= maxItems) return;
200
+ }
201
+ };
202
+ walk(raw, 0, new Set());
203
+ return out;
204
+ }
205
+
206
+
207
+ //# sourceURL=ts/capabilities/session/adapters/ctrip-hotel.ts
@@ -0,0 +1,285 @@
1
+ export const STATION_TELECODES = {
2
+ "三亚": 'SEQ',
3
+ "上海": 'SHH',
4
+ "上饶": 'SRG',
5
+ "东莞": 'RTQ',
6
+ "中卫": 'ZWJ',
7
+ "中山": 'ZSQ',
8
+ "丽江": 'LHM',
9
+ "乌鲁木齐": 'WAR',
10
+ "乐山": 'IVW',
11
+ "九江": 'JJG',
12
+ "伊宁": 'YMR',
13
+ "佛山": 'FSQ',
14
+ "保山": 'BAM',
15
+ "六盘水": 'UMW',
16
+ "兰州": 'LZJ',
17
+ "包头": 'BTC',
18
+ "北京": 'BJP',
19
+ "北海": 'BHZ',
20
+ "十堰": 'SNN',
21
+ "南京": 'NJH',
22
+ "南充": 'NCW',
23
+ "南宁": 'NNZ',
24
+ "南昌": 'NCG',
25
+ "南通": 'NUH',
26
+ "南阳": 'NFF',
27
+ "厦门": 'XMS',
28
+ "台州": 'TEU',
29
+ "合肥": 'HFH',
30
+ "吉林": 'JLL',
31
+ "吐鲁番": 'TFR',
32
+ "呼和浩特": 'HHC',
33
+ "咸阳": 'XYY',
34
+ "哈密": 'HMR',
35
+ "哈尔滨": 'HBB',
36
+ "喀什": 'KSR',
37
+ "嘉兴": 'JXH',
38
+ "嘉峪关": 'JGJ',
39
+ "大同": 'DTV',
40
+ "大庆": 'DZX',
41
+ "大理": 'DKM',
42
+ "大连": 'DLT',
43
+ "天水": 'TSJ',
44
+ "天津": 'TJP',
45
+ "太原": 'TYV',
46
+ "宁波": 'NGH',
47
+ "安顺": 'ASW',
48
+ "宜宾": 'YKE',
49
+ "宜昌": 'YCN',
50
+ "宝鸡": 'BJY',
51
+ "岳阳": 'YYQ',
52
+ "常州": 'CZH',
53
+ "常德": 'VGQ',
54
+ "广州": 'GZQ',
55
+ "库尔勒": 'KLR',
56
+ "延安": 'YWY',
57
+ "开封": 'KFF',
58
+ "张掖": 'ZYJ',
59
+ "徐州": 'XCH',
60
+ "德阳": 'DYW',
61
+ "惠州": 'HCQ',
62
+ "成都": 'CDW',
63
+ "扬州": 'YLH',
64
+ "承德": 'CDP',
65
+ "抚顺": 'FET',
66
+ "拉萨": 'LSO',
67
+ "揭阳": 'JYA',
68
+ "新乡": 'XXF',
69
+ "无锡": 'WGH',
70
+ "日喀则": 'RKO',
71
+ "昆明": 'KMM',
72
+ "普洱": 'PEM',
73
+ "景德镇": 'JCG',
74
+ "曲靖": 'QJM',
75
+ "杭州": 'HZH',
76
+ "林芝": 'LZO',
77
+ "柳州": 'LZZ',
78
+ "株洲": 'ZZQ',
79
+ "格尔木": 'GRO',
80
+ "桂林": 'GLZ',
81
+ "梧州": 'WZZ',
82
+ "武汉": 'WHN',
83
+ "汉中": 'HOY',
84
+ "汕头": 'OTQ',
85
+ "沈阳": 'SYT',
86
+ "泉州": 'QYS',
87
+ "泸州": 'LUE',
88
+ "洛阳": 'LYF',
89
+ "济南": 'JNK',
90
+ "深圳": 'SZQ',
91
+ "温州": 'RZH',
92
+ "湛江": 'ZJZ',
93
+ "漳州": 'ZUS',
94
+ "潮州": 'CKQ',
95
+ "牡丹江": 'MDB',
96
+ "珠海": 'ZHQ',
97
+ "盐城": 'AFH',
98
+ "石家庄": 'SJP',
99
+ "福州": 'FZS',
100
+ "秦皇岛": 'QTP',
101
+ "绍兴": 'SOH',
102
+ "绵阳": 'MYW',
103
+ "芜湖": 'WHH',
104
+ "苏州": 'SZH',
105
+ "茂名": 'MDQ',
106
+ "莆田": 'PTS',
107
+ "衡阳": 'HYQ',
108
+ "襄阳": 'XFN',
109
+ "西宁": 'XNO',
110
+ "西安": 'XAY',
111
+ "西昌": 'ECW',
112
+ "贵阳": 'GIW',
113
+ "赣州": 'GZG',
114
+ "达州": 'RXW',
115
+ "遵义": 'ZYE',
116
+ "郑州": 'ZZF',
117
+ "重庆": 'CUW',
118
+ "金华": 'JBH',
119
+ "银川": 'YIJ',
120
+ "镇江": 'ZJH',
121
+ "长春": 'CCT',
122
+ "长沙": 'CSQ',
123
+ "阜阳": 'FYH',
124
+ "青岛": 'QDK',
125
+ "鞍山": 'AST',
126
+ "韶关": 'SNQ',
127
+ "香格里拉": 'EUM',
128
+ "香港": 'XJA',
129
+ "齐齐哈尔": 'QHX',
130
+ "龙岩": 'LYS'
131
+ };
132
+ export function buildTrainEntryUrl(q) {
133
+ const unresolved = [];
134
+ const fromTc = (q.fromStationTelecode ?? '').trim().toUpperCase() || STATION_TELECODES[q.from.trim()];
135
+ const toTc = (q.toStationTelecode ?? '').trim().toUpperCase() || STATION_TELECODES[q.to.trim()];
136
+ if (!fromTc) unresolved.push(q.from);
137
+ if (!toTc) unresolved.push(q.to);
138
+ if (unresolved.length > 0 || !/^\d{4}-\d{2}-\d{2}$/.test(q.date)) {
139
+ return {
140
+ ok: false,
141
+ unresolved: unresolved.length > 0 ? unresolved : [
142
+ q.date
143
+ ]
144
+ };
145
+ }
146
+ const fs = encodeURIComponent(`${q.from.trim()},${fromTc}`);
147
+ const ts = encodeURIComponent(`${q.to.trim()},${toTc}`);
148
+ return {
149
+ ok: true,
150
+ url: `https://kyfw.12306.cn/otn/leftTicket/init?linktypeid=dc&fs=${fs}&ts=${ts}&date=${q.date}&flag=N,N,Y`
151
+ };
152
+ }
153
+ export const TRAIN_NETWORK_HINTS = [
154
+ /leftTicket\/query/i
155
+ ];
156
+ export const TRAIN_SITE_HOST = 'kyfw.12306.cn';
157
+ const SEAT_BUCKETS = [
158
+ {
159
+ index: 20,
160
+ field: 'gg_num',
161
+ label: '其他(通勤)'
162
+ },
163
+ {
164
+ index: 21,
165
+ field: 'gr_num',
166
+ label: '高级软卧'
167
+ },
168
+ {
169
+ index: 22,
170
+ field: 'qt_num',
171
+ label: '其他'
172
+ },
173
+ {
174
+ index: 23,
175
+ field: 'rw_num',
176
+ label: '软卧(一等卧)'
177
+ },
178
+ {
179
+ index: 24,
180
+ field: 'rz_num',
181
+ label: '软座'
182
+ },
183
+ {
184
+ index: 25,
185
+ field: 'tz_num',
186
+ label: '特等座'
187
+ },
188
+ {
189
+ index: 26,
190
+ field: 'wz_num',
191
+ label: '无座'
192
+ },
193
+ {
194
+ index: 27,
195
+ field: 'yb_num',
196
+ label: 'yp_b(上游席别)'
197
+ },
198
+ {
199
+ index: 28,
200
+ field: 'yw_num',
201
+ label: '硬卧(二等卧)'
202
+ },
203
+ {
204
+ index: 29,
205
+ field: 'yz_num',
206
+ label: '硬座'
207
+ },
208
+ {
209
+ index: 30,
210
+ field: 'ze_num',
211
+ label: '二等座'
212
+ },
213
+ {
214
+ index: 31,
215
+ field: 'zy_num',
216
+ label: '一等座'
217
+ },
218
+ {
219
+ index: 32,
220
+ field: 'swz_num',
221
+ label: '商务座'
222
+ },
223
+ {
224
+ index: 33,
225
+ field: 'srrb_num',
226
+ label: '动卧'
227
+ }
228
+ ];
229
+ const TRAIN_CODE_RE = /^[GDCZTKYLSF]\d{1,5}[A-Z]?$/i;
230
+ const HHMM_RE = /^\d{2}:\d{2}$/;
231
+ function lishiToMin(s) {
232
+ const m = /^(\d{1,3}):(\d{2})$/.exec((s ?? '').trim());
233
+ if (!m) return 0;
234
+ return Number(m[1]) * 60 + Number(m[2]);
235
+ }
236
+ function rowToOption(row, stationMap, entryUrl) {
237
+ const f = row.split('|');
238
+ if (f.length < 34) return null;
239
+ const trainCode = (f[3] ?? '').trim();
240
+ const depTime = (f[8] ?? '').trim();
241
+ const arrTime = (f[9] ?? '').trim();
242
+ if (!TRAIN_CODE_RE.test(trainCode) || !HHMM_RE.test(depTime) || !HHMM_RE.test(arrTime)) return null;
243
+ const fromStation = stationMap?.[f[6] ?? ''] ?? f[6] ?? '';
244
+ const toStation = stationMap?.[f[7] ?? ''] ?? f[7] ?? '';
245
+ const seats = {};
246
+ for (const b of SEAT_BUCKETS){
247
+ const v = (f[b.index] ?? '').trim();
248
+ if (v && v !== '--') seats[b.label] = v;
249
+ }
250
+ return {
251
+ trainCode,
252
+ fromStation,
253
+ toStation,
254
+ depTime,
255
+ arrTime,
256
+ durationMin: lishiToMin(f[10]),
257
+ canWebBuy: (f[11] ?? '').trim(),
258
+ seats,
259
+ jumpUrl: entryUrl
260
+ };
261
+ }
262
+ export function parseLeftTicketQuery(body, entryUrl, opts = {}) {
263
+ let raw;
264
+ try {
265
+ raw = JSON.parse(body);
266
+ } catch {
267
+ return [];
268
+ }
269
+ const rows = raw.data?.result;
270
+ if (!Array.isArray(rows)) return [];
271
+ const map = raw.data?.map && typeof raw.data.map === 'object' ? raw.data.map : undefined;
272
+ const out = [];
273
+ for (const r of rows){
274
+ if (typeof r !== 'string') continue;
275
+ const opt = rowToOption(r, map, entryUrl);
276
+ if (opt) {
277
+ out.push(opt);
278
+ if (out.length >= (opts.maxItems ?? 30)) break;
279
+ }
280
+ }
281
+ return out;
282
+ }
283
+
284
+
285
+ //# sourceURL=ts/capabilities/session/adapters/rail-12306.ts
@@ -1,4 +1,7 @@
1
1
  import { randomUUID } from 'node:crypto';
2
+ import { existsSync } from 'node:fs';
3
+ import { homedir } from 'node:os';
4
+ import { join } from 'node:path';
2
5
  import { createServer } from 'node:http';
3
6
  export const BRIDGE_PORTS = [
4
7
  8791,
@@ -17,6 +20,16 @@ export const EXTENSION_ORIGINS = [
17
20
  EXTENSION_ORIGIN,
18
21
  EXTENSION_ORIGIN_STORE
19
22
  ];
23
+ export function localExtensionInstalled(home = homedir()) {
24
+ return existsSync(join(home, '.gotry', 'extension', 'manifest.json'));
25
+ }
26
+ export function needsExtensionSummary(opts = {}) {
27
+ const local = opts.localInstalled ?? localExtensionInstalled(opts.home);
28
+ if (local) {
29
+ return 'GoTry Session Bridge 扩展未连接(未安装或已停用)。推荐 Chrome 应用商店一键装(自动更新) ' + `${EXTENSION_STORE_URL} ;或 npx gotry setup 落位后 chrome://extensions 开发者模式「加载已解压的扩展程序」指向 ~/.gotry/extension`;
30
+ }
31
+ return 'GoTry Session Bridge 扩展未连接。若你已从 Chrome 商店安装(自动更新):打开 Chrome 并确认扩展已启用即可自动连接,无需再装。' + `若尚未安装:应用商店一键装 ${EXTENSION_STORE_URL} (装完零弹窗,浏览器自己当安装器)`;
32
+ }
20
33
  export const EXTENSION_CONNECTED_WINDOW_MS = 45_000;
21
34
  export const JOBS_LONG_POLL_MS = 20_000;
22
35
  export const DEFAULT_EXTENSION_WAIT_MS = 6_000;
@@ -267,7 +280,7 @@ export async function createSessionBridge(opts = {}) {
267
280
  settle({
268
281
  ok: false,
269
282
  reason: 'extension-not-connected',
270
- summary: `GoTry Session Bridge 扩展未连接(未安装或已停用)。一次性安装(装完零弹窗):推荐 Chrome 应用商店一键装(自动更新) ${EXTENSION_STORE_URL} ;或 npx gotry setup 落位后 chrome://extensions 开发者模式「加载已解压的扩展程序」指向 ~/.gotry/extension`
283
+ summary: needsExtensionSummary()
271
284
  });
272
285
  }
273
286
  }, 250);
@@ -1,5 +1,7 @@
1
- import { getOrCreateSessionBridge, EXTENSION_STORE_URL } from './extension-bridge.js';
2
- export const NEEDS_EXTENSION_HINT = '需要一次性安装 GoTry Session Bridge 浏览器扩展(装完零弹窗):' + `推荐 Chrome 应用商店一键安装(自动更新) ${EXTENSION_STORE_URL} ;` + '免审核、版本更新更快的 GitHub 通道:npx gotry setup --extension-from=github(自动下载落位 ~/.gotry/extension;' + '手动下载 github.com/Danceiny/gotry/releases 标签 ext-* 的 gotry-session-bridge.tar.gz),' + '再在 chrome://extensions 开发者模式「加载已解压的扩展程序」指向解压目录';
1
+ import { getOrCreateSessionBridge, needsExtensionSummary } from './extension-bridge.js';
2
+ export function needsExtensionHint() {
3
+ return needsExtensionSummary();
4
+ }
3
5
  export function classifyBridgeFailure(kind) {
4
6
  return kind === 'extension-not-connected' ? 'needs-extension' : 'error';
5
7
  }
@@ -37,7 +37,7 @@ export function parseDistManifest(raw) {
37
37
  const tarballSha256 = obj.tarballSha256;
38
38
  const zip = obj.zip;
39
39
  const zipSha256 = obj.zipSha256;
40
- if (typeof version !== 'string' || !/^\d+\.\d+\.\d+$/.test(version)) throw new Error('dist-manifest.version 缺失或非 x.y.z');
40
+ if (typeof version !== 'string' || !/^\d+(\.\d+){1,3}$/.test(version)) throw new Error('dist-manifest.version 缺失或非 1-4 段点分整数');
41
41
  if (tarball !== DIST_ASSET_TARBALL) throw new Error(`dist-manifest.tarball 资产名漂移(期望 ${DIST_ASSET_TARBALL})`);
42
42
  if (zip !== DIST_ASSET_STORE_ZIP) throw new Error(`dist-manifest.zip 资产名漂移(期望 ${DIST_ASSET_STORE_ZIP})`);
43
43
  if (typeof tarballSha256 !== 'string' || !SHA256_RE.test(tarballSha256)) throw new Error('dist-manifest.tarballSha256 非 64-hex');