@danceiny/gotry 0.0.1-rc.15 → 0.0.1-rc.16

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 (139) hide show
  1. package/README.md +10 -6
  2. package/README.zh-CN.md +10 -6
  3. package/bin/gotry-bootstrap.js +294 -5
  4. package/cordis.gotry-patch.yml +10 -0
  5. package/data/airline-airports.json +39 -0
  6. package/dist/capabilities/agent-reach-deep.js +1 -1
  7. package/dist/capabilities/agent-reach.js +1 -1
  8. package/dist/capabilities/anything.js +1 -1
  9. package/dist/capabilities/artifacts.js +1 -1
  10. package/dist/capabilities/effect.js +293 -0
  11. package/dist/capabilities/fact-log.js +41 -0
  12. package/dist/capabilities/flyai.js +1 -1
  13. package/dist/capabilities/hbcli.js +43 -1
  14. package/dist/capabilities/incident-log.js +1 -1
  15. package/dist/capabilities/opensky.js +1 -1
  16. package/dist/capabilities/resilience.js +90 -0
  17. package/dist/capabilities/session/action-cache.js +1 -1
  18. package/dist/capabilities/session/adapters/ctrip-flight.js +1 -1
  19. package/dist/capabilities/session/adapters/meituan-local.js +1 -1
  20. package/dist/capabilities/session/benchmark.js +2 -1
  21. package/dist/capabilities/session/extension-bridge.js +345 -0
  22. package/dist/capabilities/session/extension-channel.js +93 -0
  23. package/dist/capabilities/session/extract.js +1 -1
  24. package/dist/capabilities/session/health-watch.js +216 -0
  25. package/dist/capabilities/session/read-guard.js +1 -1
  26. package/dist/capabilities/session/transport.js +1 -1
  27. package/dist/capabilities/session/wizard.js +377 -0
  28. package/dist/capabilities/session-consent.js +1 -1
  29. package/dist/capabilities/session-login.js +77 -1
  30. package/dist/capabilities/session-search.js +69 -2
  31. package/dist/capabilities/weather.js +1 -1
  32. package/dist/scripts/action-cache-tests.js +1 -1
  33. package/dist/scripts/agent-reach-deep-tests.js +1 -1
  34. package/dist/scripts/agent-reach-tests.js +1 -1
  35. package/dist/scripts/agent-reach-wrapper-tests.js +1 -1
  36. package/dist/scripts/anything-tests.js +1 -1
  37. package/dist/scripts/async-collect.js +1 -1
  38. package/dist/scripts/booking-saga-tests.js +1 -1
  39. package/dist/scripts/bootstrap-tests.js +39 -3
  40. package/dist/scripts/build-changelog.js +279 -0
  41. package/dist/scripts/changelog-tests.js +165 -0
  42. package/dist/scripts/companion-tests.js +1 -1
  43. package/dist/scripts/diff-test.js +1 -1
  44. package/dist/scripts/effect-tests.js +474 -0
  45. package/dist/scripts/engine-run.js +1 -1
  46. package/dist/scripts/engine-tests.js +1 -1
  47. package/dist/scripts/extension-tests.js +468 -0
  48. package/dist/scripts/fact-gate-tests.js +318 -0
  49. package/dist/scripts/flyai-tests.js +1 -1
  50. package/dist/scripts/hbcli-e2e-tests.js +180 -0
  51. package/dist/scripts/hbcli-tests.js +1 -1
  52. package/dist/scripts/health-watch-cli.js +51 -0
  53. package/dist/scripts/i18n-tests.js +1 -1
  54. package/dist/scripts/incident-tests.js +1 -1
  55. package/dist/scripts/journey-tests.js +1 -1
  56. package/dist/scripts/ledger-tests.js +1 -1
  57. package/dist/scripts/ledger-workflow-crash.js +1 -1
  58. package/dist/scripts/memory-capture-tests.js +1 -1
  59. package/dist/scripts/memory-decay-tests.js +1 -1
  60. package/dist/scripts/memory-metrics.js +1 -1
  61. package/dist/scripts/memory-value-report.js +1 -1
  62. package/dist/scripts/nightly-evidence-tests.js +67 -4
  63. package/dist/scripts/nightly-evidence.js +59 -3
  64. package/dist/scripts/nudge-digest.js +1 -1
  65. package/dist/scripts/onboarding-tests.js +218 -0
  66. package/dist/scripts/opensky-check.js +1 -1
  67. package/dist/scripts/opensky-tests.js +1 -1
  68. package/dist/scripts/price-drift-tests.js +441 -0
  69. package/dist/scripts/price-drift-watch.js +491 -0
  70. package/dist/scripts/probe-poi-tests.js +1 -1
  71. package/dist/scripts/product-metrics.js +1 -1
  72. package/dist/scripts/publish-preverify.js +1 -1
  73. package/dist/scripts/realtime-pricing-tests.js +1 -1
  74. package/dist/scripts/replay-async.js +1 -1
  75. package/dist/scripts/replay-real.js +1 -1
  76. package/dist/scripts/replay.js +1 -1
  77. package/dist/scripts/session-attach-diagnose.js +1 -1
  78. package/dist/scripts/session-attach-poc.js +1 -1
  79. package/dist/scripts/session-benchmark.js +1 -1
  80. package/dist/scripts/session-extract-tests.js +1 -1
  81. package/dist/scripts/session-login.js +1 -1
  82. package/dist/scripts/session-tests.js +1 -1
  83. package/dist/scripts/skeleton-check.js +1 -1
  84. package/dist/scripts/skeleton-integration-test.js +1 -1
  85. package/dist/scripts/skills-contract-tests.js +1 -1
  86. package/dist/scripts/smoke.js +76 -1
  87. package/dist/scripts/state-cli-tests.js +1 -1
  88. package/dist/scripts/state-cli.js +1 -1
  89. package/dist/scripts/time-eval-tests.js +1 -1
  90. package/dist/scripts/travel-timeline-tests.js +1 -1
  91. package/dist/scripts/unified-tests.js +1 -1
  92. package/dist/scripts/weather-tests.js +1 -1
  93. package/dist/scripts/wizard-bootstrap.js +32 -0
  94. package/dist/scripts/z3-race-tests.js +1 -1
  95. package/dist/src/artifact-gate.js +310 -0
  96. package/dist/src/bookable-facts.js +349 -0
  97. package/dist/src/booking-saga.js +1 -1
  98. package/dist/src/bridge.js +1 -1
  99. package/dist/src/companions.js +1 -1
  100. package/dist/src/contracts.js +1 -1
  101. package/dist/src/dsh-llm.js +1 -1
  102. package/dist/src/engine.js +1 -1
  103. package/dist/src/i18n.js +1 -1
  104. package/dist/src/index.js +189 -46
  105. package/dist/src/journey.js +1 -1
  106. package/dist/src/loop.js +1 -1
  107. package/dist/src/memory-capture.js +1 -1
  108. package/dist/src/memory-decay.js +1 -1
  109. package/dist/src/memory-utility.js +1 -1
  110. package/dist/src/mock-llm.js +1 -1
  111. package/dist/src/model.js +1 -1
  112. package/dist/src/realtime-pricing.js +14 -7
  113. package/dist/src/slot-spec.js +1 -1
  114. package/dist/src/state-ledger.js +1 -1
  115. package/dist/src/time-anchor.js +1 -1
  116. package/dist/src/tool-packet.js +1 -1
  117. package/dist/src/travel-slots.js +1 -1
  118. package/dist/src/travel-timeline.js +1 -1
  119. package/dist/src/unified.js +1 -1
  120. package/dist/src/wish-pool.js +1 -1
  121. package/dist/src/z3-shared.js +1 -1
  122. package/extension/README.md +26 -0
  123. package/extension/background.js +160 -0
  124. package/extension/content-bridge.js +41 -0
  125. package/extension/content-main.js +62 -0
  126. package/extension/manifest.json +32 -0
  127. package/package.json +6 -2
  128. package/ts/capabilities/fact-log.ts +54 -0
  129. package/ts/capabilities/hbcli.ts +46 -0
  130. package/ts/capabilities/session/benchmark.ts +4 -1
  131. package/ts/capabilities/session/extension-bridge.ts +354 -0
  132. package/ts/capabilities/session/extension-channel.ts +92 -0
  133. package/ts/capabilities/session/health-watch.ts +257 -0
  134. package/ts/capabilities/session/wizard.ts +282 -0
  135. package/ts/capabilities/session-login.ts +53 -2
  136. package/ts/capabilities/session-search.ts +68 -3
  137. package/ts/src/artifact-gate.ts +365 -0
  138. package/ts/src/bookable-facts.ts +557 -0
  139. package/ts/src/index.ts +102 -8
@@ -0,0 +1,293 @@
1
+ import { CircuitBreaker, withRetry } from './resilience.js';
2
+ import { flyaiSearch } from './flyai.js';
3
+ import { checkAvail, hotelRates, searchHotels } from './hbcli.js';
4
+ import { sessionFlightSearch } from './session-search.js';
5
+ import { geocodePlace, getClimate, getForecast } from './weather.js';
6
+ import { verifyFlight } from './opensky.js';
7
+ const DEFAULT_HANDLERS = {
8
+ FLYAI_SEARCH: (p)=>flyaiSearch(p),
9
+ HBCLI_HOTEL_SEARCH: (p)=>searchHotels({
10
+ destination: p.destination,
11
+ checkIn: p.checkIn,
12
+ checkOut: p.checkOut,
13
+ adults: p.adults
14
+ }, {
15
+ hbcliBin: p.hbcliBin,
16
+ timeoutMs: p.timeoutMs,
17
+ fallbackPath: p.fallbackPath
18
+ }),
19
+ HBCLI_HOTEL_RATES: (p)=>hotelRates({
20
+ hotelId: p.hotelId,
21
+ checkIn: p.checkIn,
22
+ checkOut: p.checkOut,
23
+ adults: p.adults,
24
+ countryCode: p.countryCode,
25
+ nationalityCode: p.nationalityCode,
26
+ residencyCode: p.residencyCode
27
+ }, {
28
+ hbcliBin: p.hbcliBin,
29
+ timeoutMs: p.timeoutMs
30
+ }),
31
+ HBCLI_CHECK_AVAIL: (p)=>checkAvail({
32
+ ratePkgId: p.ratePkgId
33
+ }, {
34
+ hbcliBin: p.hbcliBin,
35
+ timeoutMs: p.timeoutMs
36
+ }),
37
+ SESSION_FLIGHT_SEARCH: (p)=>sessionFlightSearch(p),
38
+ WEATHER_GEOCODE: (p)=>geocodePlace(p.name, {
39
+ count: p.count,
40
+ timeoutMs: p.timeoutMs
41
+ }),
42
+ WEATHER_FORECAST: (p)=>getForecast({
43
+ latitude: p.latitude,
44
+ longitude: p.longitude
45
+ }, {
46
+ days: p.days,
47
+ timeoutMs: p.timeoutMs
48
+ }),
49
+ WEATHER_CLIMATE: (p)=>getClimate({
50
+ latitude: p.latitude,
51
+ longitude: p.longitude
52
+ }, p.month, {
53
+ timeoutMs: p.timeoutMs
54
+ }),
55
+ OPENSKY_FLIGHT_VERIFY: (p)=>verifyFlight(p)
56
+ };
57
+ const defaultIsFailure = (r)=>r?.ok === false;
58
+ const flyaiTransient = (msg)=>msg.length > 0 && !/Sentinel/i.test(msg) && /timeout|timed out|ECONNRESET|ECONNREFUSED|ETIMEDOUT|socket|HTTP 5/i.test(msg);
59
+ const API_RETRY = {
60
+ maxAttempts: 2,
61
+ baseDelayMs: 400,
62
+ maxDelayMs: 1_600
63
+ };
64
+ const API_BREAKER = {
65
+ failureThreshold: 3,
66
+ openMs: 30_000
67
+ };
68
+ const SPECS = {
69
+ FLYAI_SEARCH: {
70
+ channel: 'cli',
71
+ retry: {
72
+ maxAttempts: 2,
73
+ baseDelayMs: 500,
74
+ maxDelayMs: 2_000
75
+ },
76
+ breaker: {
77
+ failureThreshold: 3,
78
+ openMs: 60_000
79
+ },
80
+ isRetryable: (_r, e)=>{
81
+ const msg = e != null ? String(e.message ?? e) : String((_r ?? {}).error ?? '');
82
+ return flyaiTransient(msg);
83
+ },
84
+ isFailure: defaultIsFailure
85
+ },
86
+ HBCLI_HOTEL_SEARCH: {
87
+ channel: 'cli',
88
+ retry: null,
89
+ breaker: {
90
+ failureThreshold: 3,
91
+ openMs: 60_000
92
+ },
93
+ isFailure: (r)=>r.via === 'hbcli-error'
94
+ },
95
+ HBCLI_HOTEL_RATES: {
96
+ channel: 'cli',
97
+ retry: null,
98
+ breaker: {
99
+ failureThreshold: 3,
100
+ openMs: 60_000
101
+ },
102
+ isFailure: (r)=>r.via === 'hbcli-error'
103
+ },
104
+ HBCLI_CHECK_AVAIL: {
105
+ channel: 'cli',
106
+ retry: null,
107
+ breaker: {
108
+ failureThreshold: 3,
109
+ openMs: 60_000
110
+ },
111
+ isFailure: (r)=>r.via === 'hbcli-error'
112
+ },
113
+ SESSION_FLIGHT_SEARCH: {
114
+ channel: 'browser',
115
+ retry: null,
116
+ breaker: null,
117
+ isFailure: defaultIsFailure
118
+ },
119
+ WEATHER_GEOCODE: {
120
+ channel: 'api',
121
+ retry: API_RETRY,
122
+ breaker: API_BREAKER,
123
+ isFailure: defaultIsFailure
124
+ },
125
+ WEATHER_FORECAST: {
126
+ channel: 'api',
127
+ retry: API_RETRY,
128
+ breaker: API_BREAKER,
129
+ isFailure: defaultIsFailure
130
+ },
131
+ WEATHER_CLIMATE: {
132
+ channel: 'api',
133
+ retry: API_RETRY,
134
+ breaker: API_BREAKER,
135
+ isFailure: defaultIsFailure
136
+ },
137
+ OPENSKY_FLIGHT_VERIFY: {
138
+ channel: 'api',
139
+ retry: API_RETRY,
140
+ breaker: API_BREAKER,
141
+ isRetryable: (_r, e)=>e != null || (_r ?? {}).verdict === 'unavailable',
142
+ isFailure: (r)=>r.via === 'opensky-error'
143
+ }
144
+ };
145
+ export function declinedObservation(effect, trace) {
146
+ return {
147
+ ok: false,
148
+ verdict: 'error',
149
+ summary: trace.declined === 'circuit-open' ? `${effect} 通道被断路器开启保护(连续失败达到阈值,冷却中)——不要立即重试,换其他工具或稍后再试;原因见 trace 证据链` : `${effect} 未登记效应(effect_interpreter.v1 注册表外,生产解译器拒绝)`,
150
+ evidence: trace.evidence.join(';')
151
+ };
152
+ }
153
+ const defaultBreakers = new Map();
154
+ const defaultSleep = (ms)=>new Promise((resolve)=>setTimeout(resolve, ms));
155
+ export function __resetEffectBreakersForTest() {
156
+ defaultBreakers.clear();
157
+ }
158
+ export function makeProductionInterpreter(opts = {}) {
159
+ const breakers = opts.breakers ?? defaultBreakers;
160
+ const sleep = opts.sleep ?? defaultSleep;
161
+ return async (fx)=>{
162
+ const ts = new Date().toISOString();
163
+ const name = fx.effect;
164
+ const spec = SPECS[name];
165
+ const handler = opts.handlers?.[fx.effect] ?? DEFAULT_HANDLERS[name];
166
+ if (!spec || !handler) {
167
+ return {
168
+ result: null,
169
+ trace: {
170
+ effect: fx.effect,
171
+ channel: 'api',
172
+ attempts: 0,
173
+ backoffMs: 0,
174
+ breaker: 'off',
175
+ declined: 'unknown-effect',
176
+ evidence: [
177
+ `[效应:${fx.effect}@${ts}] unknown effect`
178
+ ]
179
+ }
180
+ };
181
+ }
182
+ const br = (()=>{
183
+ if (!spec.breaker) return null;
184
+ const existing = breakers.get(fx.effect);
185
+ if (existing) return existing;
186
+ const created = new CircuitBreaker({
187
+ ...spec.breaker,
188
+ ...opts.now ? {
189
+ now: opts.now
190
+ } : {}
191
+ });
192
+ breakers.set(fx.effect, created);
193
+ return created;
194
+ })();
195
+ const gate = br?.canAttempt() ?? {
196
+ allowed: true,
197
+ state: 'closed'
198
+ };
199
+ if (!gate.allowed) {
200
+ const trace = {
201
+ effect: fx.effect,
202
+ channel: spec.channel,
203
+ attempts: 0,
204
+ backoffMs: 0,
205
+ breaker: gate.state,
206
+ declined: 'circuit-open',
207
+ evidence: [
208
+ `[效应:${fx.effect}@${ts}] breaker=${gate.state} 拒绝(冷却中,不重试)`
209
+ ]
210
+ };
211
+ return {
212
+ result: null,
213
+ trace
214
+ };
215
+ }
216
+ const policy = spec.retry ? {
217
+ maxAttempts: spec.retry.maxAttempts,
218
+ baseDelayMs: spec.retry.baseDelayMs,
219
+ maxDelayMs: spec.retry.maxDelayMs,
220
+ isRetryable: spec.isRetryable,
221
+ sleep
222
+ } : {
223
+ maxAttempts: 1,
224
+ baseDelayMs: 0,
225
+ maxDelayMs: 0,
226
+ sleep
227
+ };
228
+ const dispatch = handler;
229
+ const outcome = await withRetry(()=>dispatch(fx.params), policy);
230
+ const failed = outcome.error != null || spec.isFailure(outcome.result);
231
+ if (br) failed ? br.onFailure() : br.onSuccess();
232
+ const breakerState = br?.state() ?? 'off';
233
+ const evidence = [
234
+ `[效应:${fx.effect}@${ts}] attempts=${outcome.attempts} backoff=${outcome.backoffMs}ms breaker=${breakerState}`
235
+ ];
236
+ return {
237
+ result: outcome.error != null ? null : outcome.result,
238
+ trace: {
239
+ effect: fx.effect,
240
+ channel: spec.channel,
241
+ attempts: outcome.attempts,
242
+ backoffMs: outcome.backoffMs,
243
+ breaker: breakerState,
244
+ evidence
245
+ }
246
+ };
247
+ };
248
+ }
249
+ export const productionInterpreter = makeProductionInterpreter();
250
+ export async function interpretEffect(fx) {
251
+ return productionInterpreter(fx);
252
+ }
253
+ export function makeMockInterpreter(fixtures) {
254
+ return async (fx)=>{
255
+ const ts = new Date().toISOString();
256
+ const registered = Object.prototype.hasOwnProperty.call(fixtures, fx.effect);
257
+ if (!registered) {
258
+ return {
259
+ result: null,
260
+ trace: {
261
+ effect: fx.effect,
262
+ channel: 'mock',
263
+ attempts: 0,
264
+ backoffMs: 0,
265
+ breaker: 'off',
266
+ declined: 'unknown-effect',
267
+ evidence: [
268
+ `[效应:mock@${ts}] ${fx.effect} 未登记夹具`
269
+ ]
270
+ }
271
+ };
272
+ }
273
+ return {
274
+ result: fixtures[fx.effect],
275
+ trace: {
276
+ effect: fx.effect,
277
+ channel: 'mock',
278
+ attempts: 1,
279
+ backoffMs: 0,
280
+ breaker: 'off',
281
+ evidence: [
282
+ `[效应:mock@${ts}] ${fx.effect} 夹具回放(确定性,无网络)`
283
+ ]
284
+ }
285
+ };
286
+ };
287
+ }
288
+ export function selectInterpreter(env, opts = {}) {
289
+ return env === 'mock' ? makeMockInterpreter(opts.fixtures ?? {}) : makeProductionInterpreter(opts);
290
+ }
291
+
292
+
293
+ //# sourceURL=/Users/bytedance/work/gotry-publish/ts/capabilities/effect.ts
@@ -0,0 +1,41 @@
1
+ import { appendFile, mkdir, readFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { dedupeFacts } from '../src/bookable-facts.js';
4
+ export const FACT_LOG_NAME = 'bookable-facts.jsonl';
5
+ export function factLogPath(stateRoot) {
6
+ const root = stateRoot === '.' ? process.cwd() : stateRoot;
7
+ return join(root, 'gotry-state', FACT_LOG_NAME);
8
+ }
9
+ export async function appendFacts(stateRoot, facts) {
10
+ if (facts.length === 0) return true;
11
+ try {
12
+ const p = factLogPath(stateRoot);
13
+ await mkdir(join(p, '..'), {
14
+ recursive: true
15
+ });
16
+ await appendFile(p, facts.map((f)=>JSON.stringify(f)).join('\n') + '\n', 'utf-8');
17
+ return true;
18
+ } catch {
19
+ return false;
20
+ }
21
+ }
22
+ export async function loadFactRegistry(stateRoot) {
23
+ try {
24
+ const raw = await readFile(factLogPath(stateRoot), 'utf-8');
25
+ const facts = [];
26
+ for (const line of raw.split('\n')){
27
+ const t = line.trim();
28
+ if (!t) continue;
29
+ try {
30
+ const f = JSON.parse(t);
31
+ if (f.schema === 'gotry_bookable_fact.v1' && f.fact_id) facts.push(f);
32
+ } catch {}
33
+ }
34
+ return dedupeFacts(facts);
35
+ } catch {
36
+ return [];
37
+ }
38
+ }
39
+
40
+
41
+ //# sourceURL=/Users/bytedance/work/gotry-publish/ts/capabilities/fact-log.ts
@@ -233,4 +233,4 @@ function parseHotelItems(items) {
233
233
  }
234
234
 
235
235
 
236
- //# sourceURL=/Users/bytedance/work/gotry/ts/capabilities/flyai.ts
236
+ //# sourceURL=/Users/bytedance/work/gotry-publish/ts/capabilities/flyai.ts
@@ -177,6 +177,48 @@ export async function listDestinations(opts = {}) {
177
177
  destinations: r.result
178
178
  };
179
179
  }
180
+ export async function hotelRates(query, opts = {}) {
181
+ const hbArgs = [
182
+ 'search',
183
+ 'hotel-rates',
184
+ '--json',
185
+ '--hotel-id',
186
+ query.hotelId
187
+ ];
188
+ if (query.checkIn) hbArgs.push('--check-in', query.checkIn);
189
+ if (query.checkOut) hbArgs.push('--check-out', query.checkOut);
190
+ if (query.countryCode) hbArgs.push('--country-code', query.countryCode);
191
+ if (query.nationalityCode) hbArgs.push('--nationality-code', query.nationalityCode);
192
+ if (query.residencyCode) hbArgs.push('--residency-code', query.residencyCode);
193
+ if (query.adults) hbArgs.push('--room-occupancies', JSON.stringify([
194
+ {
195
+ adultCount: query.adults,
196
+ childrenAges: []
197
+ }
198
+ ]));
199
+ const live = await callHbcliJson(hbArgs, opts);
200
+ const summary = live.via === 'hbcli-realtime' ? `hotel ${query.hotelId}:hbcli 实时报价${query.checkIn ? `(${query.checkIn} → ${query.checkOut ?? '?'})` : ''}` : `hotel ${query.hotelId}:hbcli 实时报价不可用(${live.error ?? live.via});价格面无静态降级,fail-closed 不估算`;
201
+ return {
202
+ ...live,
203
+ rates: live.result,
204
+ summary
205
+ };
206
+ }
207
+ export async function checkAvail(query, opts = {}) {
208
+ const live = await callHbcliJson([
209
+ 'search',
210
+ 'check-avail',
211
+ '--json',
212
+ '--rate-pkg-id',
213
+ query.ratePkgId
214
+ ], opts);
215
+ const summary = live.via === 'hbcli-realtime' ? `ratePkg ${query.ratePkgId}:hbcli 实时验价(库存与价格以后端为准)` : `ratePkg ${query.ratePkgId}:hbcli 实时验价不可用(${live.error ?? live.via});价格面无静态降级,fail-closed`;
216
+ return {
217
+ ...live,
218
+ avail: live.result,
219
+ summary
220
+ };
221
+ }
180
222
 
181
223
 
182
- //# sourceURL=/Users/bytedance/work/gotry/ts/capabilities/hbcli.ts
224
+ //# sourceURL=/Users/bytedance/work/gotry-publish/ts/capabilities/hbcli.ts
@@ -97,4 +97,4 @@ if (import.meta.url === `file://${fileURLToPath(import.meta.url)}` && process.ar
97
97
  }
98
98
 
99
99
 
100
- //# sourceURL=/Users/bytedance/work/gotry/ts/capabilities/incident-log.ts
100
+ //# sourceURL=/Users/bytedance/work/gotry-publish/ts/capabilities/incident-log.ts
@@ -71,4 +71,4 @@ export async function verifyFlight(query) {
71
71
  }
72
72
 
73
73
 
74
- //# sourceURL=/Users/bytedance/work/gotry/ts/capabilities/opensky.ts
74
+ //# sourceURL=/Users/bytedance/work/gotry-publish/ts/capabilities/opensky.ts
@@ -0,0 +1,90 @@
1
+ export function backoffDelayMs(policy, failedAttempt) {
2
+ const raw = policy.baseDelayMs * 2 ** (Math.max(1, failedAttempt) - 1);
3
+ return Math.min(raw, policy.maxDelayMs);
4
+ }
5
+ const defaultSleep = (ms)=>new Promise((resolve)=>setTimeout(resolve, ms));
6
+ export async function withRetry(fn, policy, onBackoff) {
7
+ const sleep = policy.sleep ?? defaultSleep;
8
+ const maxAttempts = Math.max(1, policy.maxAttempts);
9
+ let attempts = 0;
10
+ let backoffMs = 0;
11
+ for(;;){
12
+ attempts += 1;
13
+ let result = null;
14
+ let error = null;
15
+ try {
16
+ result = await fn();
17
+ } catch (e) {
18
+ error = e;
19
+ }
20
+ const retryable = policy.isRetryable?.(result, error) ?? (error != null || result?.ok === false);
21
+ if (attempts < maxAttempts && retryable) {
22
+ const delay = backoffDelayMs(policy, attempts);
23
+ onBackoff?.(attempts, delay);
24
+ backoffMs += delay;
25
+ await sleep(delay);
26
+ continue;
27
+ }
28
+ return {
29
+ result,
30
+ error,
31
+ attempts,
32
+ backoffMs
33
+ };
34
+ }
35
+ }
36
+ export class CircuitBreaker {
37
+ o;
38
+ consecutiveFailures = 0;
39
+ openedAt = 0;
40
+ probeInFlight = false;
41
+ constructor(o){
42
+ this.o = o;
43
+ }
44
+ threshold() {
45
+ return Math.max(1, this.o.failureThreshold);
46
+ }
47
+ now() {
48
+ return (this.o.now ?? Date.now)();
49
+ }
50
+ state() {
51
+ if (this.openedAt > 0 && this.now() - this.openedAt >= this.o.openMs) return 'half-open';
52
+ if (this.openedAt > 0) return 'open';
53
+ return 'closed';
54
+ }
55
+ canAttempt() {
56
+ const s = this.state();
57
+ if (s === 'closed') return {
58
+ allowed: true,
59
+ state: s
60
+ };
61
+ if (s === 'open') return {
62
+ allowed: false,
63
+ state: s
64
+ };
65
+ if (this.probeInFlight) return {
66
+ allowed: false,
67
+ state: s
68
+ };
69
+ this.probeInFlight = true;
70
+ return {
71
+ allowed: true,
72
+ state: s
73
+ };
74
+ }
75
+ onSuccess() {
76
+ this.consecutiveFailures = 0;
77
+ this.openedAt = 0;
78
+ this.probeInFlight = false;
79
+ }
80
+ onFailure() {
81
+ this.probeInFlight = false;
82
+ this.consecutiveFailures += 1;
83
+ if (this.openedAt > 0 || this.consecutiveFailures >= this.threshold()) {
84
+ this.openedAt = this.now();
85
+ }
86
+ }
87
+ }
88
+
89
+
90
+ //# sourceURL=/Users/bytedance/work/gotry-publish/ts/capabilities/resilience.ts
@@ -117,4 +117,4 @@ export function actionCachePath(stateRoot) {
117
117
  }
118
118
 
119
119
 
120
- //# sourceURL=/Users/bytedance/work/gotry/ts/capabilities/session/action-cache.ts
120
+ //# sourceURL=/Users/bytedance/work/gotry-publish/ts/capabilities/session/action-cache.ts
@@ -80,4 +80,4 @@ export function parseBatchSearch(body) {
80
80
  }
81
81
 
82
82
 
83
- //# sourceURL=/Users/bytedance/work/gotry/ts/capabilities/session/adapters/ctrip-flight.ts
83
+ //# sourceURL=/Users/bytedance/work/gotry-publish/ts/capabilities/session/adapters/ctrip-flight.ts
@@ -70,4 +70,4 @@ export function extractListings(entries, opts = {}) {
70
70
  }
71
71
 
72
72
 
73
- //# sourceURL=/Users/bytedance/work/gotry/ts/capabilities/session/adapters/meituan-local.ts
73
+ //# sourceURL=/Users/bytedance/work/gotry-publish/ts/capabilities/session/adapters/meituan-local.ts
@@ -228,6 +228,7 @@ export function evaluateDoubleSource(input) {
228
228
  }
229
229
  if (!session) return baseEvaluation('source_unavailable', 'no_spend_stop');
230
230
  if (session.verdict === 'needs-attach') return baseEvaluation('waiting_attach', 'no_spend_waiting_user');
231
+ if (session.verdict === 'needs-extension') return baseEvaluation('waiting_extension', 'no_spend_waiting_user');
231
232
  if (session.verdict === 'needs-login') return baseEvaluation('waiting_login', 'no_spend_waiting_user');
232
233
  if (!official || official.verdict !== 'hit' || session.verdict !== 'hit') {
233
234
  return baseEvaluation('source_unavailable', 'no_spend_stop');
@@ -249,4 +250,4 @@ export function evaluateDoubleSource(input) {
249
250
  }
250
251
 
251
252
 
252
- //# sourceURL=/Users/bytedance/work/gotry/ts/capabilities/session/benchmark.ts
253
+ //# sourceURL=/Users/bytedance/work/gotry-publish/ts/capabilities/session/benchmark.ts