From 8e34c8762a6003d5ec487a6ed749649c67cca9bc Mon Sep 17 00:00:00 2001 From: npc0-hue Date: Wed, 22 Jul 2026 15:27:26 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=B9=B3=E5=8F=B0=E6=9E=84=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 10 ++ platform_web/AGENTS.md | 3 +- .../components/AIConfigDiffReviewPanel.tsx | 14 +- .../components/PluginLifecycleWorkbench.tsx | 8 +- .../components/ProductionGovernancePanel.tsx | 20 +-- platform_web/pages/HomePage.tsx | 22 +-- platform_web/pages/MaintenancePage.tsx | 22 +-- platform_web/pages/ServerDetailPage.tsx | 46 ++--- platform_web/pages/UsersPage.tsx | 6 +- platform_web/theme/README.md | 21 ++- platform_web/theme/base.css | 157 +++++++++--------- platform_web/theme/tokens.ts | 14 ++ 12 files changed, 188 insertions(+), 155 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 67c0690..63db68f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -20,6 +20,10 @@ The machine-side run executor lives in the independent repository `git@git.npc0. Do not place implementation code outside the matching root. Shared contracts must be generated or copied through explicit contract packages, not imported by reaching across ownership boundaries casually. +## CSS Authoring Rules + +Any task that touches CSS must keep CSS declarations compressed and compact. Do not expand a single selector's style block across many lines when it can be written as a concise one-line rule. + ## OpenSpec Rules - Use judgment before creating an OpenSpec change. Create one when the work changes behavior, architecture, public/API contracts, validation rules, persistence, security boundaries, cross-root workflows, or the required product/visual direction. @@ -35,6 +39,12 @@ When creating a task, include the following prompt boundaries before implementat - Directional prompt (方向提示词): state the expected implementation direction, affected project root, relevant existing patterns to preserve, and verification command or evidence expected. - Boundary prompt (任务边界): explicitly list out-of-scope areas, forbidden product expansions, and files or roots that must not be touched unless the task explicitly requires them. +## Git Completion Rules + +For every substantial session task that modifies repository files, automatically stage only the files changed for that task, create a concise git commit after verification succeeds, and push the current branch to its configured git remote before sending the final response. + +Do not include unrelated pre-existing worktree changes in the commit. If commit or push is blocked by missing credentials, a missing remote, conflicts, or a failing required verification step, report the blocker clearly instead of broadening the commit scope. + ## Structure Rules Backend roots must keep these concerns in fixed directories: diff --git a/platform_web/AGENTS.md b/platform_web/AGENTS.md index ad0bec1..154185b 100644 --- a/platform_web/AGENTS.md +++ b/platform_web/AGENTS.md @@ -29,10 +29,11 @@ Dropdown and contextual action menus must follow these rules: The platform_web visual system is a game operations console, not a generic SaaS dashboard. The default theme is black mecha; the selectable alternate theme is magical-girl. Future UI work must preserve the current style contract: - Use the shared theme tokens in `theme/tokens.ts` and shared styles in `theme/base.css`; do not add page-local opaque card systems, one-off dark dashboards, or unrelated visual languages. +- Repeated console modules, record lists, compact status rows, metric strips, action rows, and access lists should use the shared `console-module`, `console-record-list`, `console-record`, `console-row-list`, `console-row`, `console-stat-strip`, `console-row-actions`, and `access-list` classes. Treat older page-specific operation/user/maintenance class names as compatibility aliases, not new style ownership. - Keep major surfaces translucent enough for the selected desktop/background to remain visible: side navigation, account/profile controls, metric cards, console panels, server cards, server detail headers, tables, drawers, dialogs, plugin groups, and operation history. - Preserve theme-specific materials: black mecha uses dark cockpit panels, angular clipped frames, cyan scanner lines, and amber energy accents; magical-girl uses pink jelly glass, gold star frames, ribbon glow, and visible magic-circle motifs. - Theme changes must be isolated and complete. Switching from magical-girl to black mecha must clear previous magical variables and update root theme marker, sidebar subtitle, active navigation frame, swatch strip, and shared surface accessories together. -- Do not double-frame nested content. A `.state-view` inside an already framed shared parent such as a console panel, card, table wrapper, plugin group, or operation item is content only; the parent owns the visible border and accessory layer. +- Do not double-frame nested content. A `.state-view` inside an already framed shared parent such as a console panel, card, table wrapper, plugin group, `console-record`, or compatibility operation item is content only; the parent owns the visible border and accessory layer. - Keep the primary menu as a compact admin sidebar with two states: expanded text menu and collapsed icon rail. Do not reintroduce the single-column / double-column menu toggle. The same route order should render as a restrained dark mecha operations rail in black mecha and as a semi-transparent pink frosted-glass rail with star-framed active states in magical-girl. - Use `components/MagicalParticleLayer.tsx` for full-workspace theme-aware ultimate effects. Each theme should have a distinct low-cost “大招” scene, not a dense field of tiny rotating particles. Do not reintroduce hardcoded fixed decorative DOM/CSS elements such as page-local sparkles, hearts, moons, snowflakes, or sigils. - Built-in backgrounds must stay original CSS/generated motif desktops. Do not bundle recognizable third-party character art. User-uploaded backgrounds are allowed and must render behind readable contrast overlays. diff --git a/platform_web/components/AIConfigDiffReviewPanel.tsx b/platform_web/components/AIConfigDiffReviewPanel.tsx index 005719d..27e9b6b 100644 --- a/platform_web/components/AIConfigDiffReviewPanel.tsx +++ b/platform_web/components/AIConfigDiffReviewPanel.tsx @@ -49,7 +49,7 @@ export function AIConfigDiffReviewPanel() { } return ( -
+

AI 配置审查

@@ -58,15 +58,15 @@ export function AIConfigDiffReviewPanel() { {loading && } {!loading && error && void refresh()} compact />} {!loading && !error && ( -
- {items.length === 0 &&

当前没有 AI 配置差异。

} +
+ {items.length === 0 &&

当前没有 AI 配置差异。

} {items.slice(0, 12).map((item) => ( -
-
{item.serverInstanceId} · {item.key}{item.state}
-
请求 {item.requestId}版本 {item.configVersion}{item.model || "Platform model"}到期 {new Date(item.expiresAt).toLocaleString()}{item.jobId && 任务 {item.jobId}}
+
+
{item.serverInstanceId} · {item.key}{item.state}
+
请求 {item.requestId}版本 {item.configVersion}{item.model || "Platform model"}到期 {new Date(item.expiresAt).toLocaleString()}{item.jobId && 任务 {item.jobId}}

{item.diffSummary}

{item.proposedConfig &&
{item.proposedConfig}
} - {item.state === "pending" &&
} + {item.state === "pending" &&
}
))}
diff --git a/platform_web/components/PluginLifecycleWorkbench.tsx b/platform_web/components/PluginLifecycleWorkbench.tsx index 548335d..63cddd5 100644 --- a/platform_web/components/PluginLifecycleWorkbench.tsx +++ b/platform_web/components/PluginLifecycleWorkbench.tsx @@ -98,15 +98,15 @@ export function PluginLifecycleWorkbench({ pluginId, pluginName, operations = li
{installation ? ( -
-
{installation.currentState} → {installation.desiredState}{installation.compatibility || "pending"}
-
+
+
{installation.currentState} → {installation.desiredState}{installation.compatibility || "pending"}
+
当前 {installation.currentVersion || "--"}目标 {installation.targetVersion || "--"}依赖 {installation.dependencyState || "unknown"} {installation.jobId && 任务 {installation.jobId}}{installation.auditEventId && 审计 {installation.auditEventId}}{installation.alertId && 告警 {installation.alertId}}
{installation.failureReason &&

{installation.failureReason}

}
- ) :

该服务器尚无插件生命周期记录。

} + ) :

该服务器尚无插件生命周期记录。

} )} { if (!busy) setConfirming(false); }} onConfirm={() => void submit()} /> diff --git a/platform_web/components/ProductionGovernancePanel.tsx b/platform_web/components/ProductionGovernancePanel.tsx index 0ab0c8c..5e2b3da 100644 --- a/platform_web/components/ProductionGovernancePanel.tsx +++ b/platform_web/components/ProductionGovernancePanel.tsx @@ -69,7 +69,7 @@ export function ProductionGovernancePanel({ compact = false, title = "容量与 const visibleEndpoints = compact ? capacity?.endpoints.slice(0, 3) ?? [] : capacity?.endpoints ?? []; return ( -
+

{title}

} {alert.retryable && } diff --git a/platform_web/pages/HomePage.tsx b/platform_web/pages/HomePage.tsx index 3e48ccc..1074f6d 100644 --- a/platform_web/pages/HomePage.tsx +++ b/platform_web/pages/HomePage.tsx @@ -224,7 +224,7 @@ export function HomePage({ session, onNavigate, initialState }: HomePageProps) { )}
-
+

任务脉冲

{moduleFreshnessLabel(core.status === "ready" ? core.refreshedAt : core.refreshedAt)} @@ -233,20 +233,20 @@ export function HomePage({ session, onNavigate, initialState }: HomePageProps) { {core.status === "error" && void refreshCore()} compact />} {core.status === "ready" && jobs && ( <> -
+
执行中
{jobs.active.length}
等待重试
{jobs.retrying.length}
近期失败
{jobs.failed.length}
{jobs.active.length === 0 && jobs.failed.length === 0 ? ( -

当前没有执行中或失败任务。

+

当前没有执行中或失败任务。

) : ( -
+
{[...jobs.active.slice(0, 3), ...jobs.failed.slice(0, 2)].map((job) => (
-
+

运行节点

@@ -269,17 +269,17 @@ export function HomePage({ session, onNavigate, initialState }: HomePageProps) { {core.status === "error" && void refreshCore()} compact />} {core.status === "ready" && endpointSummary && ( <> -
+
在线
{endpointSummary.online}
活跃任务
{endpointSummary.activeJobs}
排队
{endpointSummary.queuedJobs}
{core.data.endpoints.length === 0 ? ( -

Platform 未返回运行节点。

+

Platform 未返回运行节点。

) : ( -
+
{core.data.endpoints.slice(0, 4).map((endpoint) => ( -
+
{endpoint.displayName}{endpoint.version} {endpointStatusLabel(endpoint.status)} {endpoint.capacity.runningJobs}/{endpoint.capacity.maxJobs} 运行 @@ -311,7 +311,7 @@ export function HomePage({ session, onNavigate, initialState }: HomePageProps) {
- {moduleFreshnessLabel(metricAverages.refreshedAt)} + {moduleFreshnessLabel(metricAverages.refreshedAt)} {(usage.status === "error" || metrics.status === "error") && ( @@ -220,17 +220,17 @@ export function MaintenancePage({ session, operations, onNavigate }: PageCompone void refreshJobs()} /> )} {jobs.status === "ready" && failedJobs.length > 0 && ( -
+
{failedJobs.map((job) => { const server = job.serverInstanceId ? serverById.get(job.serverInstanceId) : undefined; const endpoint = endpointById.get(job.runEndpointId); return ( -
-
+
+
{job.capability} {jobStateLabel(job.state)}
-
+
任务 {job.id} @@ -242,7 +242,7 @@ export function MaintenancePage({ session, operations, onNavigate }: PageCompone {formatTimestamp(job.updatedAt)}
-
+
diff --git a/platform_web/pages/ServerDetailPage.tsx b/platform_web/pages/ServerDetailPage.tsx index b2b1741..afd504b 100644 --- a/platform_web/pages/ServerDetailPage.tsx +++ b/platform_web/pages/ServerDetailPage.tsx @@ -1783,7 +1783,7 @@ function PluginControlsSection({ serverId, instance, plugins, artifacts, session } return ( -
+
{groups.length === 0 && ( )} @@ -2206,17 +2206,17 @@ function HistorySection({ serverId, serverOperations, jobs, artifacts, metricHis {serverOperations.length === 0 ? ( ) : ( -
+
{serverOperations.map((operation) => ( -
-
+
+
{operation.intent}
-
+
操作 {operation.id} @@ -2249,16 +2249,16 @@ function HistorySection({ serverId, serverOperations, jobs, artifacts, metricHis {jobs.length === 0 ? ( ) : ( -
+
{jobs.slice(0, 20).map((job) => ( -
-
+
+
{job.capability} {job.state}
-
+
任务 {job.id} @@ -2291,18 +2291,18 @@ function HistorySection({ serverId, serverOperations, jobs, artifacts, metricHis

持久化观测

-
-
-
指标样本{metricHistory.length} 条
-
最新采集 {metricHistory.length > 0 ? new Date(metricHistory[metricHistory.length - 1].collectedAt).toLocaleString() : "暂无"}
+
+
+
指标样本{metricHistory.length} 条
+
最新采集 {metricHistory.length > 0 ? new Date(metricHistory[metricHistory.length - 1].collectedAt).toLocaleString() : "暂无"}
-
-
备份记录{backups.length} 条
-
{backups.slice(0, 4).map((backup) => {backup.id} · {backup.state} · {backup.checksum.slice(0, 18)})}
+
+
备份记录{backups.length} 条
+
{backups.slice(0, 4).map((backup) => {backup.id} · {backup.state} · {backup.checksum.slice(0, 18)})}
-
-
远端适配器声明{remoteAdapters.length} 个
-
{remoteAdapters.slice(0, 4).map((adapter) => {adapter.key} · {adapter.kind} · {adapter.targetKeys.join(", ")})}
+
+
远端适配器声明{remoteAdapters.length} 个
+
{remoteAdapters.slice(0, 4).map((adapter) => {adapter.key} · {adapter.kind} · {adapter.targetKeys.join(", ")})}
@@ -2347,16 +2347,16 @@ function ArtifactDownloadPanel({ serverId, artifacts }: ArtifactDownloadPanelPro {artifacts.length === 0 ? ( ) : ( -
+
{artifacts.slice(0, 12).map((artifact) => { const itemResult = result[artifact.id]; return ( -
-
+
+
{artifact.id}
-
+
服务器 {serverId} {formatBytes(artifact.sizeBytes)} {artifact.checksum} diff --git a/platform_web/pages/UsersPage.tsx b/platform_web/pages/UsersPage.tsx index 34d9e9e..f42e3b9 100644 --- a/platform_web/pages/UsersPage.tsx +++ b/platform_web/pages/UsersPage.tsx @@ -301,9 +301,9 @@ export function UsersPage({ session, operations, initialState }: UsersPageProps) ) : !loading && !loadError && filteredUsers.length === 0 ? ( { setKeyword(""); setRoleFilter(""); setStatusFilter("all"); }} /> ) : ( -
+
{filteredUsers.map((user) => ( -
+
{user.displayName} {user.email ?? user.id} @@ -314,7 +314,7 @@ export function UsersPage({ session, operations, initialState }: UsersPageProps) {user.roles.map(roleLabel).join(" / ")} {profileSummary(user)} -
+