@reconcrap/boss-recommend-mcp 1.3.38 → 1.3.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -83,8 +83,11 @@ const PAGE_SCOPE_TAB_STATUS = {
|
|
|
83
83
|
latest: "1",
|
|
84
84
|
featured: "3"
|
|
85
85
|
};
|
|
86
|
-
const BOTTOM_HINT_KEYWORDS = ["没有更多", "已显示全部", "已经到底", "暂无更多", "推荐完了", "没有更多人选"];
|
|
87
|
-
const LOAD_MORE_HINT_KEYWORDS = ["滚动加载更多", "下滑加载更多", "继续下滑", "继续滑动", "滑动加载", "正在加载", "加载中"];
|
|
86
|
+
const BOTTOM_HINT_KEYWORDS = ["没有更多", "已显示全部", "已经到底", "暂无更多", "推荐完了", "没有更多人选"];
|
|
87
|
+
const LOAD_MORE_HINT_KEYWORDS = ["滚动加载更多", "下滑加载更多", "继续下滑", "继续滑动", "滑动加载", "正在加载", "加载中"];
|
|
88
|
+
const VIEWPORT_COLLAPSE_RATIO_THRESHOLD = 0.6;
|
|
89
|
+
const VIEWPORT_COLLAPSE_MIN_EXPECTED_WIDTH = 1000;
|
|
90
|
+
const VIEWPORT_COLLAPSE_NEAR_FULLSCREEN_RATIO = 0.85;
|
|
88
91
|
|
|
89
92
|
function getHealingRulesPath() {
|
|
90
93
|
const fromEnv = normalizeText(process.env.BOSS_RECOMMEND_HEALING_RULES_FILE || "");
|
|
@@ -2465,17 +2468,28 @@ const jsGetListState = `(() => {
|
|
|
2465
2468
|
scrollHeight: body ? body.scrollHeight : 0,
|
|
2466
2469
|
clientHeight: body ? body.clientHeight : 0,
|
|
2467
2470
|
clientWidth: body ? body.clientWidth : 0,
|
|
2468
|
-
frameRect: {
|
|
2469
|
-
width: frameRect.width,
|
|
2470
|
-
height: frameRect.height
|
|
2471
|
-
},
|
|
2472
|
-
viewport: {
|
|
2473
|
-
width: (doc.defaultView && Number.isFinite(doc.defaultView.innerWidth)) ? doc.defaultView.innerWidth : 0,
|
|
2474
|
-
height: (doc.defaultView && Number.isFinite(doc.defaultView.innerHeight)) ? doc.defaultView.innerHeight : 0
|
|
2475
|
-
},
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2471
|
+
frameRect: {
|
|
2472
|
+
width: frameRect.width,
|
|
2473
|
+
height: frameRect.height
|
|
2474
|
+
},
|
|
2475
|
+
viewport: {
|
|
2476
|
+
width: (doc.defaultView && Number.isFinite(doc.defaultView.innerWidth)) ? doc.defaultView.innerWidth : 0,
|
|
2477
|
+
height: (doc.defaultView && Number.isFinite(doc.defaultView.innerHeight)) ? doc.defaultView.innerHeight : 0
|
|
2478
|
+
},
|
|
2479
|
+
topViewport: {
|
|
2480
|
+
innerWidth: Number.isFinite(window.innerWidth) ? window.innerWidth : 0,
|
|
2481
|
+
innerHeight: Number.isFinite(window.innerHeight) ? window.innerHeight : 0,
|
|
2482
|
+
outerWidth: Number.isFinite(window.outerWidth) ? window.outerWidth : 0,
|
|
2483
|
+
outerHeight: Number.isFinite(window.outerHeight) ? window.outerHeight : 0,
|
|
2484
|
+
visualWidth: (window.visualViewport && Number.isFinite(window.visualViewport.width)) ? window.visualViewport.width : 0,
|
|
2485
|
+
visualHeight: (window.visualViewport && Number.isFinite(window.visualViewport.height)) ? window.visualViewport.height : 0,
|
|
2486
|
+
screenAvailWidth: (window.screen && Number.isFinite(window.screen.availWidth)) ? window.screen.availWidth : 0,
|
|
2487
|
+
screenAvailHeight: (window.screen && Number.isFinite(window.screen.availHeight)) ? window.screen.availHeight : 0,
|
|
2488
|
+
devicePixelRatio: Number.isFinite(window.devicePixelRatio) ? window.devicePixelRatio : 0
|
|
2489
|
+
},
|
|
2490
|
+
candidateCount: effectiveCount,
|
|
2491
|
+
recommendCandidateCount: candidateCards.length,
|
|
2492
|
+
featuredCandidateCount: featuredCandidates.length,
|
|
2479
2493
|
latestCandidateCount: latestCandidates.length,
|
|
2480
2494
|
totalCards: Math.max(cards.length, featuredCards.length, latestCards.length),
|
|
2481
2495
|
activeTabStatus: inferredStatus || null
|
|
@@ -4650,23 +4664,25 @@ class RecommendScreenCli {
|
|
|
4650
4664
|
return state?.closed === false;
|
|
4651
4665
|
}
|
|
4652
4666
|
|
|
4653
|
-
async getListState() {
|
|
4654
|
-
const state = await this.evaluate(jsGetListState);
|
|
4655
|
-
if (state && typeof state === "object") {
|
|
4656
|
-
const activeStatus = normalizeText(state.activeTabStatus || "");
|
|
4657
|
-
if (activeStatus) {
|
|
4658
|
-
this.lastActiveTabStatus = activeStatus;
|
|
4659
|
-
}
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
|
|
4665
|
-
|
|
4666
|
-
|
|
4667
|
-
|
|
4668
|
-
|
|
4669
|
-
const
|
|
4667
|
+
async getListState() {
|
|
4668
|
+
const state = await this.evaluate(jsGetListState);
|
|
4669
|
+
if (state && typeof state === "object") {
|
|
4670
|
+
const activeStatus = normalizeText(state.activeTabStatus || "");
|
|
4671
|
+
if (activeStatus) {
|
|
4672
|
+
this.lastActiveTabStatus = activeStatus;
|
|
4673
|
+
}
|
|
4674
|
+
state.viewportDiagnostics = await this.getViewportHealthDiagnostics(state);
|
|
4675
|
+
return state;
|
|
4676
|
+
}
|
|
4677
|
+
return { ok: false, error: "INVALID_LIST_STATE" };
|
|
4678
|
+
}
|
|
4679
|
+
|
|
4680
|
+
isListViewportCollapsed(state) {
|
|
4681
|
+
if (!state?.ok) return false;
|
|
4682
|
+
if (state.viewportDiagnostics?.relativeCollapsed === true) return true;
|
|
4683
|
+
const clientHeight = Number(state.clientHeight || 0);
|
|
4684
|
+
const clientWidth = Number(state.clientWidth || 0);
|
|
4685
|
+
const frameWidth = Number(state.frameRect?.width || 0);
|
|
4670
4686
|
const frameHeight = Number(state.frameRect?.height || 0);
|
|
4671
4687
|
const viewportWidth = Number(state.viewport?.width || 0);
|
|
4672
4688
|
const viewportHeight = Number(state.viewport?.height || 0);
|
|
@@ -4676,23 +4692,147 @@ class RecommendScreenCli {
|
|
|
4676
4692
|
|| (clientWidth > 0 && clientWidth < 280)
|
|
4677
4693
|
|| (frameHeight > 0 && frameHeight < 320)
|
|
4678
4694
|
|| (frameWidth > 0 && frameWidth < 460)
|
|
4679
|
-
|| (viewportHeight > 0 && viewportHeight < 260)
|
|
4680
|
-
|| (viewportWidth > 0 && viewportWidth < 360)
|
|
4681
|
-
);
|
|
4682
|
-
}
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4695
|
+
|| (viewportHeight > 0 && viewportHeight < 260)
|
|
4696
|
+
|| (viewportWidth > 0 && viewportWidth < 360)
|
|
4697
|
+
);
|
|
4698
|
+
}
|
|
4699
|
+
|
|
4700
|
+
getPositiveNumber(...values) {
|
|
4701
|
+
for (const value of values) {
|
|
4702
|
+
const number = Number(value);
|
|
4703
|
+
if (Number.isFinite(number) && number > 0) return number;
|
|
4704
|
+
}
|
|
4705
|
+
return 0;
|
|
4706
|
+
}
|
|
4707
|
+
|
|
4708
|
+
async getWindowBoundsInfo() {
|
|
4709
|
+
if (!this.Browser || !this.windowId || typeof this.Browser.getWindowBounds !== "function") {
|
|
4710
|
+
return null;
|
|
4711
|
+
}
|
|
4712
|
+
try {
|
|
4713
|
+
const info = await this.Browser.getWindowBounds({ windowId: this.windowId });
|
|
4714
|
+
return info && typeof info === "object" ? info : null;
|
|
4715
|
+
} catch {
|
|
4716
|
+
return null;
|
|
4717
|
+
}
|
|
4718
|
+
}
|
|
4719
|
+
|
|
4720
|
+
async getPageLayoutMetrics() {
|
|
4721
|
+
if (!this.Page || typeof this.Page.getLayoutMetrics !== "function") {
|
|
4722
|
+
return null;
|
|
4723
|
+
}
|
|
4724
|
+
try {
|
|
4725
|
+
const metrics = await this.Page.getLayoutMetrics();
|
|
4726
|
+
return metrics && typeof metrics === "object" ? metrics : null;
|
|
4727
|
+
} catch {
|
|
4728
|
+
return null;
|
|
4729
|
+
}
|
|
4730
|
+
}
|
|
4731
|
+
|
|
4732
|
+
buildViewportHealthDiagnostics(state, windowInfo = null, layoutMetrics = null) {
|
|
4733
|
+
const topViewport = state?.topViewport || {};
|
|
4734
|
+
const bounds = windowInfo?.bounds || null;
|
|
4735
|
+
const windowState = normalizeText(bounds?.windowState || "").toLowerCase() || null;
|
|
4736
|
+
const windowWidth = this.getPositiveNumber(bounds?.width);
|
|
4737
|
+
const screenAvailWidth = this.getPositiveNumber(topViewport.screenAvailWidth);
|
|
4738
|
+
const topOuterWidth = this.getPositiveNumber(topViewport.outerWidth);
|
|
4739
|
+
const actualWidth = this.getPositiveNumber(
|
|
4740
|
+
layoutMetrics?.cssVisualViewport?.clientWidth,
|
|
4741
|
+
layoutMetrics?.cssLayoutViewport?.clientWidth,
|
|
4742
|
+
topViewport.visualWidth,
|
|
4743
|
+
topViewport.innerWidth,
|
|
4744
|
+
state?.viewport?.width,
|
|
4745
|
+
state?.clientWidth,
|
|
4746
|
+
state?.frameRect?.width
|
|
4747
|
+
);
|
|
4748
|
+
const actualHeight = this.getPositiveNumber(
|
|
4749
|
+
layoutMetrics?.cssVisualViewport?.clientHeight,
|
|
4750
|
+
layoutMetrics?.cssLayoutViewport?.clientHeight,
|
|
4751
|
+
topViewport.visualHeight,
|
|
4752
|
+
topViewport.innerHeight,
|
|
4753
|
+
state?.viewport?.height,
|
|
4754
|
+
state?.clientHeight,
|
|
4755
|
+
state?.frameRect?.height
|
|
4756
|
+
);
|
|
4757
|
+
const nearFullscreen = (
|
|
4758
|
+
windowState === "maximized"
|
|
4759
|
+
|| (
|
|
4760
|
+
windowWidth > 0
|
|
4761
|
+
&& screenAvailWidth > 0
|
|
4762
|
+
&& windowWidth >= screenAvailWidth * VIEWPORT_COLLAPSE_NEAR_FULLSCREEN_RATIO
|
|
4763
|
+
)
|
|
4764
|
+
|| (
|
|
4765
|
+
topOuterWidth > 0
|
|
4766
|
+
&& screenAvailWidth > 0
|
|
4767
|
+
&& topOuterWidth >= screenAvailWidth * VIEWPORT_COLLAPSE_NEAR_FULLSCREEN_RATIO
|
|
4768
|
+
)
|
|
4769
|
+
);
|
|
4770
|
+
let expectedWidth = 0;
|
|
4771
|
+
if (windowState === "maximized" && screenAvailWidth > 0) {
|
|
4772
|
+
expectedWidth = screenAvailWidth;
|
|
4773
|
+
} else if (windowWidth > 0) {
|
|
4774
|
+
expectedWidth = screenAvailWidth > 0 && windowWidth >= screenAvailWidth * VIEWPORT_COLLAPSE_NEAR_FULLSCREEN_RATIO
|
|
4775
|
+
? Math.min(windowWidth, screenAvailWidth)
|
|
4776
|
+
: windowWidth;
|
|
4777
|
+
} else if (topOuterWidth > 0) {
|
|
4778
|
+
expectedWidth = screenAvailWidth > 0 && topOuterWidth >= screenAvailWidth * VIEWPORT_COLLAPSE_NEAR_FULLSCREEN_RATIO
|
|
4779
|
+
? Math.min(topOuterWidth, screenAvailWidth)
|
|
4780
|
+
: topOuterWidth;
|
|
4781
|
+
}
|
|
4782
|
+
const widthRatio = actualWidth > 0 && expectedWidth > 0 ? actualWidth / expectedWidth : null;
|
|
4783
|
+
const relativeCollapsed = Boolean(
|
|
4784
|
+
nearFullscreen
|
|
4785
|
+
&& expectedWidth >= VIEWPORT_COLLAPSE_MIN_EXPECTED_WIDTH
|
|
4786
|
+
&& actualWidth > 0
|
|
4787
|
+
&& widthRatio !== null
|
|
4788
|
+
&& widthRatio <= VIEWPORT_COLLAPSE_RATIO_THRESHOLD
|
|
4789
|
+
);
|
|
4790
|
+
return {
|
|
4791
|
+
relativeCollapsed,
|
|
4792
|
+
threshold: VIEWPORT_COLLAPSE_RATIO_THRESHOLD,
|
|
4793
|
+
minExpectedWidth: VIEWPORT_COLLAPSE_MIN_EXPECTED_WIDTH,
|
|
4794
|
+
nearFullscreen,
|
|
4795
|
+
windowState,
|
|
4796
|
+
actualWidth,
|
|
4797
|
+
actualHeight,
|
|
4798
|
+
expectedWidth,
|
|
4799
|
+
widthRatio,
|
|
4800
|
+
windowBounds: bounds ? {
|
|
4801
|
+
left: bounds.left ?? null,
|
|
4802
|
+
top: bounds.top ?? null,
|
|
4803
|
+
width: bounds.width ?? null,
|
|
4804
|
+
height: bounds.height ?? null,
|
|
4805
|
+
windowState: bounds.windowState ?? null
|
|
4806
|
+
} : null,
|
|
4807
|
+
cssLayoutViewport: layoutMetrics?.cssLayoutViewport || null,
|
|
4808
|
+
cssVisualViewport: layoutMetrics?.cssVisualViewport || null,
|
|
4809
|
+
topViewport: {
|
|
4810
|
+
innerWidth: topViewport.innerWidth || 0,
|
|
4811
|
+
innerHeight: topViewport.innerHeight || 0,
|
|
4812
|
+
outerWidth: topViewport.outerWidth || 0,
|
|
4813
|
+
outerHeight: topViewport.outerHeight || 0,
|
|
4814
|
+
visualWidth: topViewport.visualWidth || 0,
|
|
4815
|
+
visualHeight: topViewport.visualHeight || 0,
|
|
4816
|
+
screenAvailWidth: topViewport.screenAvailWidth || 0,
|
|
4817
|
+
screenAvailHeight: topViewport.screenAvailHeight || 0,
|
|
4818
|
+
devicePixelRatio: topViewport.devicePixelRatio || 0
|
|
4819
|
+
}
|
|
4820
|
+
};
|
|
4821
|
+
}
|
|
4822
|
+
|
|
4823
|
+
async getViewportHealthDiagnostics(state) {
|
|
4824
|
+
const [windowInfo, layoutMetrics] = await Promise.all([
|
|
4825
|
+
this.getWindowBoundsInfo(),
|
|
4826
|
+
this.getPageLayoutMetrics()
|
|
4827
|
+
]);
|
|
4828
|
+
return this.buildViewportHealthDiagnostics(state, windowInfo, layoutMetrics);
|
|
4829
|
+
}
|
|
4830
|
+
|
|
4831
|
+
async getCurrentWindowState() {
|
|
4832
|
+
const info = await this.getWindowBoundsInfo();
|
|
4833
|
+
const state = String(info?.bounds?.windowState || "").toLowerCase();
|
|
4834
|
+
return state || null;
|
|
4835
|
+
}
|
|
4696
4836
|
|
|
4697
4837
|
async setWindowStateIfPossible(windowState, reason = "unknown") {
|
|
4698
4838
|
if (!this.Browser || !this.windowId || typeof this.Browser.setWindowBounds !== "function") {
|
|
@@ -4734,26 +4874,31 @@ class RecommendScreenCli {
|
|
|
4734
4874
|
return applied;
|
|
4735
4875
|
}
|
|
4736
4876
|
|
|
4737
|
-
async ensureHealthyListViewport(reason = "unknown") {
|
|
4738
|
-
let state = await this.getListState();
|
|
4739
|
-
if (!this.isListViewportCollapsed(state)) {
|
|
4740
|
-
return { ok: true, recovered: false, state };
|
|
4741
|
-
}
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4877
|
+
async ensureHealthyListViewport(reason = "unknown") {
|
|
4878
|
+
let state = await this.getListState();
|
|
4879
|
+
if (!this.isListViewportCollapsed(state)) {
|
|
4880
|
+
return { ok: true, recovered: false, state };
|
|
4881
|
+
}
|
|
4882
|
+
|
|
4883
|
+
const diagnostics = state?.viewportDiagnostics || null;
|
|
4884
|
+
const ratioText = Number.isFinite(diagnostics?.widthRatio)
|
|
4885
|
+
? `,宽度比例: ${diagnostics.widthRatio.toFixed(3)}`
|
|
4886
|
+
: "";
|
|
4887
|
+
log(`[视口恢复] 检测到推荐列表视口异常缩小,尝试自动恢复。原因: ${reason}${ratioText}`);
|
|
4888
|
+
await this.toggleWindowStateForViewportRecovery(reason);
|
|
4889
|
+
await sleep(humanDelay(900, 130));
|
|
4890
|
+
state = await this.getListState();
|
|
4747
4891
|
if (!this.isListViewportCollapsed(state)) {
|
|
4748
4892
|
return { ok: true, recovered: true, state };
|
|
4749
4893
|
}
|
|
4750
4894
|
|
|
4751
|
-
return {
|
|
4752
|
-
ok: false,
|
|
4753
|
-
recovered: false,
|
|
4754
|
-
state
|
|
4755
|
-
|
|
4756
|
-
|
|
4895
|
+
return {
|
|
4896
|
+
ok: false,
|
|
4897
|
+
recovered: false,
|
|
4898
|
+
state,
|
|
4899
|
+
diagnostics: state?.viewportDiagnostics || diagnostics || null
|
|
4900
|
+
};
|
|
4901
|
+
}
|
|
4757
4902
|
|
|
4758
4903
|
async discoverCandidates() {
|
|
4759
4904
|
const health = await this.ensureHealthyListViewport("discover_candidates");
|
|
@@ -185,6 +185,62 @@ function createResumeCaptureError(message = "Resume canvas not found") {
|
|
|
185
185
|
return error;
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
+
function createViewportState(cli, {
|
|
189
|
+
actualWidth,
|
|
190
|
+
actualHeight = 585,
|
|
191
|
+
screenAvailWidth = 1440,
|
|
192
|
+
windowState = "maximized",
|
|
193
|
+
windowWidth = 1454
|
|
194
|
+
}) {
|
|
195
|
+
const state = {
|
|
196
|
+
ok: true,
|
|
197
|
+
clientWidth: actualWidth,
|
|
198
|
+
clientHeight: actualHeight,
|
|
199
|
+
frameRect: {
|
|
200
|
+
width: actualWidth,
|
|
201
|
+
height: actualHeight
|
|
202
|
+
},
|
|
203
|
+
viewport: {
|
|
204
|
+
width: actualWidth,
|
|
205
|
+
height: actualHeight
|
|
206
|
+
},
|
|
207
|
+
topViewport: {
|
|
208
|
+
innerWidth: actualWidth,
|
|
209
|
+
innerHeight: actualHeight,
|
|
210
|
+
outerWidth: actualWidth,
|
|
211
|
+
outerHeight: actualHeight,
|
|
212
|
+
visualWidth: actualWidth,
|
|
213
|
+
visualHeight: actualHeight,
|
|
214
|
+
screenAvailWidth,
|
|
215
|
+
screenAvailHeight: 860,
|
|
216
|
+
devicePixelRatio: 2
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
state.viewportDiagnostics = cli.buildViewportHealthDiagnostics(
|
|
220
|
+
state,
|
|
221
|
+
{
|
|
222
|
+
bounds: {
|
|
223
|
+
left: -7,
|
|
224
|
+
top: -7,
|
|
225
|
+
width: windowWidth,
|
|
226
|
+
height: 874,
|
|
227
|
+
windowState
|
|
228
|
+
}
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
cssVisualViewport: {
|
|
232
|
+
clientWidth: actualWidth,
|
|
233
|
+
clientHeight: actualHeight
|
|
234
|
+
},
|
|
235
|
+
cssLayoutViewport: {
|
|
236
|
+
clientWidth: actualWidth,
|
|
237
|
+
clientHeight: actualHeight
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
);
|
|
241
|
+
return state;
|
|
242
|
+
}
|
|
243
|
+
|
|
188
244
|
function createArgs(tempDir) {
|
|
189
245
|
return {
|
|
190
246
|
baseUrl: "https://example.invalid/v1",
|
|
@@ -219,6 +275,75 @@ function createArgs(tempDir) {
|
|
|
219
275
|
};
|
|
220
276
|
}
|
|
221
277
|
|
|
278
|
+
function testViewportCollapseRiskShouldUseRelativeWidth() {
|
|
279
|
+
const cli = new RecommendScreenCli(createArgs(os.tmpdir()));
|
|
280
|
+
const state = createViewportState(cli, {
|
|
281
|
+
actualWidth: 785,
|
|
282
|
+
screenAvailWidth: 1440,
|
|
283
|
+
windowState: "maximized",
|
|
284
|
+
windowWidth: 1454
|
|
285
|
+
});
|
|
286
|
+
assert.equal(state.viewportDiagnostics.relativeCollapsed, true);
|
|
287
|
+
assert.equal(cli.isListViewportCollapsed(state), true);
|
|
288
|
+
assert.equal(Math.round(state.viewportDiagnostics.widthRatio * 1000), 545);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function testNormalMaximizedViewportShouldNotCollapse() {
|
|
292
|
+
const cli = new RecommendScreenCli(createArgs(os.tmpdir()));
|
|
293
|
+
const state = createViewportState(cli, {
|
|
294
|
+
actualWidth: 1280,
|
|
295
|
+
screenAvailWidth: 1440,
|
|
296
|
+
windowState: "maximized",
|
|
297
|
+
windowWidth: 1454
|
|
298
|
+
});
|
|
299
|
+
assert.equal(state.viewportDiagnostics.relativeCollapsed, false);
|
|
300
|
+
assert.equal(cli.isListViewportCollapsed(state), false);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function testSmallNormalWindowShouldNotUseScreenWidthRatio() {
|
|
304
|
+
const cli = new RecommendScreenCli(createArgs(os.tmpdir()));
|
|
305
|
+
const state = createViewportState(cli, {
|
|
306
|
+
actualWidth: 785,
|
|
307
|
+
screenAvailWidth: 1440,
|
|
308
|
+
windowState: "normal",
|
|
309
|
+
windowWidth: 800
|
|
310
|
+
});
|
|
311
|
+
assert.equal(state.viewportDiagnostics.nearFullscreen, false);
|
|
312
|
+
assert.equal(state.viewportDiagnostics.relativeCollapsed, false);
|
|
313
|
+
assert.equal(cli.isListViewportCollapsed(state), false);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
async function testViewportCollapseRiskShouldTriggerRecovery() {
|
|
317
|
+
const cli = new RecommendScreenCli(createArgs(os.tmpdir()));
|
|
318
|
+
const collapsedState = createViewportState(cli, {
|
|
319
|
+
actualWidth: 785,
|
|
320
|
+
screenAvailWidth: 1440,
|
|
321
|
+
windowState: "maximized",
|
|
322
|
+
windowWidth: 1454
|
|
323
|
+
});
|
|
324
|
+
const healthyState = createViewportState(cli, {
|
|
325
|
+
actualWidth: 1280,
|
|
326
|
+
screenAvailWidth: 1440,
|
|
327
|
+
windowState: "maximized",
|
|
328
|
+
windowWidth: 1454
|
|
329
|
+
});
|
|
330
|
+
let listStateCalls = 0;
|
|
331
|
+
let recoveryCalled = false;
|
|
332
|
+
cli.getListState = async () => {
|
|
333
|
+
listStateCalls += 1;
|
|
334
|
+
return listStateCalls === 1 ? collapsedState : healthyState;
|
|
335
|
+
};
|
|
336
|
+
cli.toggleWindowStateForViewportRecovery = async () => {
|
|
337
|
+
recoveryCalled = true;
|
|
338
|
+
return true;
|
|
339
|
+
};
|
|
340
|
+
const result = await cli.ensureHealthyListViewport("test_relative_viewport");
|
|
341
|
+
assert.equal(recoveryCalled, true);
|
|
342
|
+
assert.equal(result.ok, true);
|
|
343
|
+
assert.equal(result.recovered, true);
|
|
344
|
+
assert.equal(result.state, healthyState);
|
|
345
|
+
}
|
|
346
|
+
|
|
222
347
|
async function withLongResumeChunkEnv(overrides, fn) {
|
|
223
348
|
const envKeys = [
|
|
224
349
|
"BOSS_RECOMMEND_TEXT_CHUNK_SIZE_CHARS",
|
|
@@ -2225,6 +2350,10 @@ async function testVisionModelShouldSendAllOrderedChunks() {
|
|
|
2225
2350
|
async function main() {
|
|
2226
2351
|
testShouldAbortResumeProbeEarly();
|
|
2227
2352
|
testResumeViewportStabilityRequiresSettledScrollAndClip();
|
|
2353
|
+
testViewportCollapseRiskShouldUseRelativeWidth();
|
|
2354
|
+
testNormalMaximizedViewportShouldNotCollapse();
|
|
2355
|
+
testSmallNormalWindowShouldNotUseScreenWidthRatio();
|
|
2356
|
+
await testViewportCollapseRiskShouldTriggerRecovery();
|
|
2228
2357
|
await testSingleResumeCaptureFailureIsSkipped();
|
|
2229
2358
|
await testConsecutiveResumeCaptureFailuresStillAbort();
|
|
2230
2359
|
await testPageExhaustedBeforeTargetShouldRaiseRecoverableError();
|