feat: tune scan dashboard and telegram monitor

This commit is contained in:
2569718930@qq.com
2026-05-15 14:36:43 +08:00
parent e7fc3c97cb
commit 747c8aa401
11 changed files with 406 additions and 22 deletions
@@ -0,0 +1,33 @@
import fs from "node:fs";
import path from "node:path";
function assert(condition: unknown, message: string) {
if (!condition) throw new Error(message);
}
export function runTests() {
const projectRoot = process.cwd();
const hookPath = path.join(
projectRoot,
"components",
"dashboard",
"scan-terminal",
"use-ai-city-forecast.ts",
);
const source = fs.readFileSync(hookPath, "utf8");
assert(
source.includes("AI_CITY_READ_SOFT_TIMEOUT_MS") &&
source.includes("softTimeoutId"),
"AI city read hook must use a soft timeout so airport-read loading does not linger",
);
assert(
source.includes("ai_soft_timeout_fallback") &&
source.includes("buildAiCityErrorForecastState"),
"AI city read soft timeout must switch to the fast fallback state while allowing later merge",
);
assert(
!source.includes("controller.abort()"),
"AI city read soft timeout should not abort the stream; late AI results should still merge",
);
}
@@ -0,0 +1,24 @@
import fs from "node:fs";
import path from "node:path";
function assert(condition: unknown, message: string) {
if (!condition) throw new Error(message);
}
export function runTests() {
const source = fs.readFileSync(
path.join(process.cwd(), "hooks", "useDashboardStore.tsx"),
"utf8",
);
assert(
source.includes("function pickRicherHourly"),
"city detail merge should have an explicit hourly-series preservation helper",
);
assert(
/hourly:\s*pickRicherHourly\(\s*current\.hourly,\s*incoming\.hourly\s*\)/.test(
source,
),
"deep-analysis refresh must not let sparse incoming hourly data overwrite chart-capable cached hourly data",
);
}
@@ -0,0 +1,25 @@
import fs from "node:fs";
import path from "node:path";
function assert(condition: unknown, message: string) {
if (!condition) throw new Error(message);
}
export function runTests() {
const projectRoot = process.cwd();
const bannerPath = path.join(
projectRoot,
"components",
"dashboard",
"scan-terminal",
"MarketOverviewBanner.tsx",
);
const source = fs.readFileSync(bannerPath, "utf8");
assert(
!source.includes("AI Overview") &&
!source.includes("AI 概览") &&
!source.includes("styles.badge"),
"market overview banner should not render the AI overview badge",
);
}