fix: polish degraded workbench mobile UX
This commit is contained in:
@@ -58,7 +58,14 @@ const defaultHomepageForbiddenTerms = Object.freeze([
|
||||
"BLOCKED",
|
||||
"db-live",
|
||||
"m3-hardware-loop-runtime",
|
||||
"执行轨迹"
|
||||
"执行轨迹",
|
||||
"runtime_durable_adapter_query_blocked",
|
||||
"OPENAI_API_KEY",
|
||||
"Secret",
|
||||
"secretRef",
|
||||
"hwlab-code-agent-provider",
|
||||
"m3-route-required",
|
||||
"waiting-for-dev-live"
|
||||
]);
|
||||
|
||||
const diagnosticsRequiredTerms = Object.freeze([
|
||||
@@ -367,9 +374,19 @@ function runStaticSmoke() {
|
||||
evidence: ["command-send", "agent-chat-status", "/v1/agent/chat", "conversationId/messageId/status/timestamps/error.message"]
|
||||
});
|
||||
|
||||
addCheck(checks, blockers, "code-agent-provider-readiness-visibility", hasCodeAgentReadinessVisibility(files), "Workbench shows provider credential blockers and only real completed replies can become DEV-LIVE.", {
|
||||
addCheck(checks, blockers, "code-agent-provider-readiness-visibility", hasCodeAgentReadinessVisibility(files), "Workbench shows provider blockers without exposing credential internals and only real completed replies can become DEV-LIVE.", {
|
||||
blocker: "observability_blocker",
|
||||
evidence: ["服务受阻 or legacy BLOCKED 凭证缺口", "provider_unavailable classifier", "completed -> dev-live guard"]
|
||||
evidence: ["服务受阻 or legacy BLOCKED 凭证缺口", "provider_unavailable classifier", "completed -> dev-live guard", "default workspace hides credential internals"]
|
||||
});
|
||||
|
||||
addCheck(checks, blockers, "default-workspace-sanitized", defaultWorkspaceIsSanitized(files), "Default user workspace hides raw blocker codes, internal route markers, and credential reference material.", {
|
||||
blocker: "observability_blocker",
|
||||
evidence: defaultHomepageForbiddenTerms
|
||||
});
|
||||
|
||||
addCheck(checks, blockers, "route-control-stable-dimensions", hasStableRouteControls(files), "Route controls and status tags have stable dimensions, readable wrapping, and usable labels on small screens.", {
|
||||
blocker: "runtime_blocker",
|
||||
evidence: ["rail-button min-width/min-height", "state-tag wrapping", "side-tab stable labels", "mobile message evidence column"]
|
||||
});
|
||||
|
||||
addCheck(checks, blockers, "code-agent-completed-evidence-visible", hasCodeAgentCompletedEvidenceVisibility(files), "Completed Code Agent replies expose provider/model/trace/conversation evidence and reject echo/mock/stub completions.", {
|
||||
@@ -377,7 +394,7 @@ function runStaticSmoke() {
|
||||
evidence: requiredCodeAgentEvidenceTerms
|
||||
});
|
||||
|
||||
addCheck(checks, blockers, "code-agent-conversation-ux-states", hasCodeAgentConversationUxStates(files), "Code Agent thread renders trusted completed, SOURCE fixture, failed, and provider_unavailable states as distinct conversation replies with bounded evidence.", {
|
||||
addCheck(checks, blockers, "code-agent-conversation-ux-states", hasCodeAgentConversationUxStates(files), "Code Agent thread renders trusted completed, SOURCE fixture, failed, and blocked provider states as distinct conversation replies with bounded evidence.", {
|
||||
blocker: "observability_blocker",
|
||||
evidence: [
|
||||
"DEV-LIVE 回复",
|
||||
@@ -1053,6 +1070,27 @@ function defaultHomepageHidesBackstage({ html }) {
|
||||
return defaultHomepageForbiddenTerms.every((term) => !visibleShellHtml.includes(term));
|
||||
}
|
||||
|
||||
function defaultWorkspaceIsSanitized({ html, app }) {
|
||||
const workspaceHtml = sectionSource(html, "workspace");
|
||||
const defaultShell = `${beforeSection(html, "help")}\n${workspaceHtml}`;
|
||||
const userFacingBodies = [
|
||||
functionBody(app, "codeAgentStatusMessage"),
|
||||
functionBody(app, "codeAgentPromptText"),
|
||||
functionBody(app, "codeAgentControlSummary"),
|
||||
functionBody(app, "codeAgentBlockedSummary"),
|
||||
functionBody(app, "codeAgentAvailabilitySummary"),
|
||||
functionBody(app, "failureMessage"),
|
||||
functionBody(app, "renderWiringList")
|
||||
].join("\n");
|
||||
return (
|
||||
!/OPENAI_API_KEY|hwlab-code-agent-provider|Secret|secretRef|m3-route-required|waiting-for-dev-live/u.test(defaultShell) &&
|
||||
!/OPENAI_API_KEY|hwlab-code-agent-provider|Secret|secretRef|m3-route-required|waiting-for-dev-live|BLOCKED 凭证缺口/u.test(userFacingBodies) &&
|
||||
/服务受阻/u.test(functionBody(app, "renderAgentChatStatus")) &&
|
||||
/Code Agent 服务暂不可用/u.test(functionBody(app, "codeAgentBlockedSummary")) &&
|
||||
/等待可信记录/u.test(functionBody(app, "renderWiringList"))
|
||||
);
|
||||
}
|
||||
|
||||
function hasCompletePrimaryNavigation(html) {
|
||||
const navLabelsPresent = ["工作台", "内部复核", "使用说明", "资源树"].every((label) => html.includes(`>${label}<`));
|
||||
const legacyLabelsAbsent = incompletePrimaryNavLabels.every((label) => !html.includes(`>${label}<`));
|
||||
@@ -1142,6 +1180,7 @@ function trustedRecordGroups({ html, app, styles }) {
|
||||
/function\s+evidenceCard\s*\(/u.test(app) &&
|
||||
/function\s+recordGroup\s*\(/u.test(app) &&
|
||||
/function\s+recordField\s*\(/u.test(app) &&
|
||||
/function\s+safeFailureReason\s*\(/u.test(app) &&
|
||||
/function\s+sourceKindLabel\s*\(/u.test(app) &&
|
||||
/function\s+liveFailureCard\s*\(/u.test(app) &&
|
||||
/state\.liveSurface/u.test(app) &&
|
||||
@@ -1156,6 +1195,7 @@ function trustedRecordGroups({ html, app, styles }) {
|
||||
/gateSummary\.operations\.map/u.test(app) &&
|
||||
/gateSummary\.auditEvents\.slice\(0,\s*4\)\.map/u.test(app) &&
|
||||
/gateSummary\.evidenceRecords\.map/u.test(app) &&
|
||||
/safeFailureReason\(message\.error\.message\)/u.test(app) &&
|
||||
/message\.status === "failed" \? "blocked" : "source"/u.test(app) &&
|
||||
!/message\.status === "completed"\s*\?\s*"dev-live"/u.test(app)
|
||||
);
|
||||
@@ -1201,6 +1241,19 @@ function hasMobileWorkbenchLayoutContract({ html, app, styles }) {
|
||||
);
|
||||
}
|
||||
|
||||
function hasStableRouteControls({ html, styles }) {
|
||||
return (
|
||||
["工作台", "内部复核", "使用说明", "资源树", "控制", "接线", "可信记录"].every((label) => html.includes(`>${label}<`)) &&
|
||||
/\.rail-button\s*\{[^}]*min-width:\s*0;[^}]*min-height:\s*36px;[^}]*text-align:\s*center;[^}]*word-break:\s*keep-all;/su.test(styles) &&
|
||||
/@media\s*\(max-width:\s*860px\)[\s\S]*?\.rail-button\s*\{[\s\S]*?min-height:\s*42px;/u.test(styles) &&
|
||||
/\.side-tab\s*\{[^}]*min-width:\s*0;[^}]*min-height:\s*34px;[^}]*overflow-wrap:\s*anywhere;[^}]*word-break:\s*keep-all;/su.test(styles) &&
|
||||
/\.(?:status-dot|state-tag|badge)[^{]*\{[^}]*max-width:\s*100%;[^}]*line-height:\s*1\.25;[^}]*white-space:\s*normal;[^}]*overflow-wrap:\s*anywhere;/su.test(styles) &&
|
||||
/\.probe-card\s*\{[^}]*min-width:\s*0;/su.test(styles) &&
|
||||
/\.probe-card strong\s*\{[^}]*line-height:\s*1\.2;[^}]*overflow-wrap:\s*anywhere;/su.test(styles) &&
|
||||
/@media\s*\(max-width:\s*860px\)[\s\S]*?\.message-evidence\s*\{[\s\S]*?grid-column:\s*1;/u.test(styles)
|
||||
);
|
||||
}
|
||||
|
||||
function hasSameOriginReadOnlyBoundary(app) {
|
||||
const rpcCalls = [...app.matchAll(/callRpc\(\s*["']([^"']+)["']/gu)].map((match) => match[1]).sort();
|
||||
return (
|
||||
@@ -1257,9 +1310,18 @@ function hasCodeAgentChatContract({ html, app }) {
|
||||
|
||||
function hasCodeAgentReadinessVisibility({ html, app }) {
|
||||
const source = `${html}\n${app}`;
|
||||
const userFacingBodies = [
|
||||
functionBody(app, "codeAgentStatusMessage"),
|
||||
functionBody(app, "codeAgentPromptText"),
|
||||
functionBody(app, "codeAgentControlSummary"),
|
||||
functionBody(app, "codeAgentBlockedSummary"),
|
||||
functionBody(app, "codeAgentAvailabilitySummary"),
|
||||
functionBody(app, "failureMessage")
|
||||
].join("\n");
|
||||
return (
|
||||
/codeAgentAvailability/u.test(app) &&
|
||||
/codeAgentAvailabilityFrom/u.test(app) &&
|
||||
/sanitizeCodeAgentAvailability/u.test(app) &&
|
||||
/latestCompletedAgentMessage/u.test(app) &&
|
||||
blockedCodeAgentUiLabels.some((label) => app.includes(label)) &&
|
||||
/provider_unavailable/u.test(app) &&
|
||||
@@ -1277,6 +1339,7 @@ function hasCodeAgentReadinessVisibility({ html, app }) {
|
||||
!/status === "failed" \? "dev-live"/u.test(app) &&
|
||||
!/tone:\s*state\.conversationId\s*\?\s*"dev-live"/u.test(app) &&
|
||||
!/provider_unavailable[\s\S]{0,120}tone-[\w-]*dev-live/iu.test(source) &&
|
||||
!/OPENAI_API_KEY|hwlab-code-agent-provider|Secret|secretRef/u.test(userFacingBodies) &&
|
||||
!/sk-[A-Za-z0-9._-]{8,}/u.test(source)
|
||||
);
|
||||
}
|
||||
|
||||
+34
-13
@@ -1320,7 +1320,7 @@ function renderWiringList(summary = null) {
|
||||
const m3Live = hasTrustedM3LiveEvidence(liveM3Evidence);
|
||||
const traceEvidence = m3Live
|
||||
? [liveM3Evidence.operationId, liveM3Evidence.traceId, liveM3Evidence.auditId, liveM3Evidence.evidenceId].join(" / ")
|
||||
: "m3-route-required / waiting-for-dev-live";
|
||||
: "等待可信记录";
|
||||
const tr = document.createElement("tr");
|
||||
tr.append(cell(M3_TRUSTED_ROUTE.fromResourceId, "mono wrap"));
|
||||
tr.append(cell(M3_TRUSTED_ROUTE.fromPort, "mono"));
|
||||
@@ -1330,7 +1330,7 @@ function renderWiringList(summary = null) {
|
||||
const status = document.createElement("td");
|
||||
status.append(badge(m3Live ? "开发实况 DEV-LIVE" : "阻塞 BLOCKED", m3Live ? "dev-live" : "blocked"));
|
||||
tr.append(status);
|
||||
tr.append(cell(m3Live ? "DEV-LIVE" : "SOURCE / required M3 route", "wrap"));
|
||||
tr.append(cell(m3Live ? "DEV-LIVE" : "来源拓扑", "wrap"));
|
||||
tr.append(cell(traceEvidence, "mono wrap"));
|
||||
|
||||
replaceChildren(el.wiringBody, tr);
|
||||
@@ -1383,7 +1383,7 @@ function codeAgentRecordCards() {
|
||||
recordField("conversation", state.conversationId),
|
||||
recordField("trace", message.traceId),
|
||||
recordField("message", message.messageId),
|
||||
message.error?.message ? `失败原因=${message.error.message}` : null
|
||||
message.error?.message ? `失败原因=${safeFailureReason(message.error.message)}` : null
|
||||
].filter(Boolean).join(" / "),
|
||||
tone: message.status === "failed" ? "blocked" : "source"
|
||||
})
|
||||
@@ -1572,6 +1572,15 @@ function recordField(label, value) {
|
||||
return `${label}=${value}`;
|
||||
}
|
||||
|
||||
function safeFailureReason(value) {
|
||||
const text = String(value ?? "").trim();
|
||||
if (!text) return "未知错误";
|
||||
if (/OPENAI_API_KEY|hwlab-code-agent-provider|Secret|secretRef/iu.test(text)) {
|
||||
return "服务暂不可用";
|
||||
}
|
||||
return text.length > 120 ? `${text.slice(0, 117)}...` : text;
|
||||
}
|
||||
|
||||
function sourceKindLabel(tone) {
|
||||
return statusLabel(tone);
|
||||
}
|
||||
@@ -1703,7 +1712,7 @@ function renderAgentChatStatus(status, result = null) {
|
||||
completed: "DEV-LIVE 回复",
|
||||
source: "SOURCE 回复",
|
||||
failed: "发送失败",
|
||||
blocked: "BLOCKED 凭证缺口"
|
||||
blocked: "服务受阻"
|
||||
};
|
||||
el.agentChatStatus.textContent = labels[status] ?? statusLabel(status);
|
||||
el.agentChatStatus.className = `state-tag tone-${toneClass(status === "completed" ? "dev-live" : status === "failed" || status === "blocked" ? "blocked" : "source")}`;
|
||||
@@ -1755,10 +1764,7 @@ function failureMessage(result) {
|
||||
const availability = result.error?.providerStatus || result.availability?.status !== "blocked"
|
||||
? codeAgentAvailabilityFromResult(result)
|
||||
: result.availability ?? codeAgentAvailabilityFromResult(result);
|
||||
const missing = Array.isArray(result.error?.missingEnv) && result.error.missingEnv.length > 0
|
||||
? ` 当前缺口:${result.error.missingEnv.join("、")}。`
|
||||
: "";
|
||||
return `${availability.summary}${missing}`;
|
||||
return codeAgentBlockedSummary(availability);
|
||||
}
|
||||
const missing = [
|
||||
...(result.error?.missingCommands ?? []),
|
||||
@@ -1947,7 +1953,8 @@ function isHttpNon2xxStatus(value) {
|
||||
}
|
||||
|
||||
function codeAgentAvailabilityFrom(live) {
|
||||
return live?.restIndex?.data?.codeAgent ?? live?.healthLive?.data?.codeAgent ?? null;
|
||||
const availability = live?.restIndex?.data?.codeAgent ?? live?.healthLive?.data?.codeAgent ?? null;
|
||||
return sanitizeCodeAgentAvailability(availability);
|
||||
}
|
||||
|
||||
function codeAgentAvailabilityFromResult(result) {
|
||||
@@ -1973,11 +1980,21 @@ function codeAgentAvailabilityFromResult(result) {
|
||||
};
|
||||
}
|
||||
|
||||
function sanitizeCodeAgentAvailability(availability) {
|
||||
if (!availability || typeof availability !== "object") return availability;
|
||||
if (availability.status !== "blocked") return availability;
|
||||
return {
|
||||
...availability,
|
||||
blocker: "服务受阻",
|
||||
summary: codeAgentBlockedSummary(availability)
|
||||
};
|
||||
}
|
||||
|
||||
function codeAgentStatusMessage(availability) {
|
||||
if (availability?.status === "blocked") {
|
||||
return {
|
||||
role: "system",
|
||||
title: "Code Agent 状态:BLOCKED 凭证缺口",
|
||||
title: "Code Agent 状态:服务受阻",
|
||||
text: codeAgentBlockedSummary(availability),
|
||||
status: "blocked"
|
||||
};
|
||||
@@ -2008,7 +2025,7 @@ function codeAgentStatusMessage(availability) {
|
||||
|
||||
function codeAgentPromptText(availability) {
|
||||
if (availability?.status === "blocked") {
|
||||
return "可以继续输入并保留草稿;发送会走真实 /v1/agent/chat,但当前 DEV provider 凭证缺口会返回结构化失败,不会冒充真实 Codex 回复。";
|
||||
return "可以继续输入并保留草稿;发送会走真实 /v1/agent/chat。服务恢复前会显示结构化失败,不会冒充真实 Codex 回复。";
|
||||
}
|
||||
return "请在底部输入中文消息并点击发送;完成态只来自真实 /v1/agent/chat completed 回复。";
|
||||
}
|
||||
@@ -2029,7 +2046,11 @@ function codeAgentControlSummary(availability) {
|
||||
}
|
||||
|
||||
function codeAgentBlockedSummary(availability) {
|
||||
return availability?.summary ?? "真实后端已接入,但当前 DEV provider Secret hwlab-code-agent-provider/openai-api-key 未注入,因此不能返回真实回复。";
|
||||
const providerStatus = availability?.error?.providerStatus ?? availability?.providerStatus;
|
||||
if (providerStatus) {
|
||||
return `真实后端已接入,但当前上游响应 HTTP ${providerStatus};工作台保持只读和可重试,不会冒充真实 Code Agent 回复。`;
|
||||
}
|
||||
return "真实后端已接入,但当前 Code Agent 服务暂不可用;工作台保持只读和可重试,不会冒充真实回复。";
|
||||
}
|
||||
|
||||
function untrustedCompletionMessage(result) {
|
||||
@@ -2039,7 +2060,7 @@ function untrustedCompletionMessage(result) {
|
||||
|
||||
function codeAgentAvailabilitySummary() {
|
||||
if (state.codeAgentAvailability?.status === "blocked") {
|
||||
return "同源 API 可响应;Code Agent 为 BLOCKED/凭证缺口,真实后端已接入但 DEV provider Secret hwlab-code-agent-provider/openai-api-key 未注入。";
|
||||
return "同源 API 可响应;Code Agent 服务暂不可用,工作台保持只读和可重试。";
|
||||
}
|
||||
if (String(state.codeAgentAvailability?.sourceKind ?? state.codeAgentAvailability?.evidenceLevel ?? "").toUpperCase() === "SOURCE") {
|
||||
return "同源 API 可响应;当前 Code Agent 回复来源是 SOURCE fixture,仅用于本地浏览器 smoke,不是 DEV-LIVE。";
|
||||
|
||||
@@ -230,7 +230,7 @@
|
||||
<span class="hardware-row-label">hwlab-patch-panel</span>
|
||||
<span class="state-tag tone-source">SOURCE</span>
|
||||
</div>
|
||||
<span class="hardware-row-value">SOURCE route</span>
|
||||
<span class="hardware-row-value">来源拓扑</span>
|
||||
<span class="hardware-row-detail">res_boxsimu_1:DO1 -> hwlab-patch-panel -> res_boxsimu_2:DI1 仅为源码兜底显示。</span>
|
||||
</div>
|
||||
<div class="hardware-row tone-border-blocked" data-source-kind="BLOCKED">
|
||||
@@ -238,7 +238,7 @@
|
||||
<span class="hardware-row-label">DO1 -> patch-panel -> DI1</span>
|
||||
<span class="state-tag tone-blocked">BLOCKED</span>
|
||||
</div>
|
||||
<span class="hardware-row-value">waiting-for-dev-live</span>
|
||||
<span class="hardware-row-value">等待可信记录</span>
|
||||
<span class="hardware-row-detail">缺少 patch-panel live report 与 operation/trace/audit/evidence IDs,不能标为 DEV-LIVE。</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -321,8 +321,8 @@
|
||||
<td class="mono wrap">res_boxsimu_2</td>
|
||||
<td class="mono">DI1</td>
|
||||
<td><span class="state-tag tone-blocked">阻塞 BLOCKED</span></td>
|
||||
<td class="wrap">SOURCE / required M3 route</td>
|
||||
<td class="mono wrap">m3-route-required / waiting-for-dev-live</td>
|
||||
<td class="wrap">来源拓扑 / required M3 route</td>
|
||||
<td class="mono wrap">等待可信记录(m3-route-required / waiting-for-dev-live)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -169,6 +169,7 @@ assert.match(app, /auditCard\(event, liveRecordTone\(event, live\), liveRecordDu
|
||||
assert.match(app, /evidenceCard\(record, liveRecordTone\(record, live\), liveRecordDurabilityBlocker\(live\)\)/);
|
||||
assert.match(app, /function recordGroup/);
|
||||
assert.match(app, /function recordField/);
|
||||
assert.match(app, /function safeFailureReason/);
|
||||
assert.match(app, /function sourceKindLabel/);
|
||||
assert.match(app, /function liveFailureCard/);
|
||||
assert.match(app, /state\.liveSurface/);
|
||||
@@ -274,7 +275,7 @@ for (const helpTerm of [
|
||||
}
|
||||
const workspaceHtml = sectionSource(html, "workspace");
|
||||
const visibleShellHtml = `${beforeSection(html, "help")}\n${workspaceHtml}`;
|
||||
for (const backendTerm of [/Gate/u, /诊断/u, /验收/u, /BLOCKED/u, /M0-M5/u, /执行轨迹/u]) {
|
||||
for (const backendTerm of [/Gate/u, /诊断/u, /验收/u, /BLOCKED/u, /M0-M5/u, /执行轨迹/u, /OPENAI_API_KEY/u, /Secret/u, /secretRef/u, /hwlab-code-agent-provider/u, /m3-route-required/u, /waiting-for-dev-live/u]) {
|
||||
assert.doesNotMatch(visibleShellHtml, backendTerm, `default workbench must not expose backend term ${backendTerm}`);
|
||||
}
|
||||
for (const fullNavLabel of ["工作台", "内部复核", "使用说明", "资源树"]) {
|
||||
@@ -355,11 +356,11 @@ assert.match(app, /isHttpNon2xxStatus/);
|
||||
assert.match(app, /providerStatus/);
|
||||
assert.match(app, /codeAgentAvailability/);
|
||||
assert.match(app, /codeAgentAvailabilityFrom/);
|
||||
assert.match(app, /sanitizeCodeAgentAvailability/);
|
||||
assert.match(app, /latestCompletedAgentMessage/);
|
||||
assert.match(app, /BLOCKED 凭证缺口/);
|
||||
assert.match(app, /服务受阻/);
|
||||
assert.match(app, /provider_unavailable/);
|
||||
assert.match(app, /OPENAI_API_KEY/);
|
||||
assert.match(app, /hwlab-code-agent-provider\/openai-api-key/);
|
||||
assert.match(app, /只有真实 completed 回复才标 DEV-LIVE/);
|
||||
assert.match(app, /不能因为只有 conversationId 标为开发实况/);
|
||||
assert.match(app, /TRUSTED_CODE_AGENT_PROVIDERS/);
|
||||
@@ -400,6 +401,23 @@ assert.match(styles, /\.message-user\s*{/);
|
||||
assert.match(styles, /\.message-agent,\s*\n\.message-system\s*{/);
|
||||
assert.match(styles, /\.message-evidence\s*{/);
|
||||
assert.match(styles, /\.message-evidence-chip\s*{/);
|
||||
assert.match(styles, /\.rail-button\s*{[^}]*min-width:\s*0;[^}]*min-height:\s*36px;[^}]*text-align:\s*center;[^}]*word-break:\s*keep-all;/s);
|
||||
assert.match(styles, /\.side-tab\s*{[^}]*min-width:\s*0;[^}]*min-height:\s*34px;[^}]*overflow-wrap:\s*anywhere;[^}]*word-break:\s*keep-all;/s);
|
||||
assert.match(styles, /\.(?:status-dot|state-tag|badge)[^{]*{[^}]*max-width:\s*100%;[^}]*line-height:\s*1\.25;[^}]*white-space:\s*normal;[^}]*overflow-wrap:\s*anywhere;/s);
|
||||
assert.match(styles, /\.probe-card\s*{[^}]*min-width:\s*0;/s);
|
||||
assert.match(styles, /\.probe-card strong\s*{[^}]*line-height:\s*1\.2;[^}]*overflow-wrap:\s*anywhere;/s);
|
||||
assert.match(styles, /@media \(max-width: 860px\)[\s\S]*?\.message-evidence\s*{[\s\S]*?grid-column:\s*1;/);
|
||||
for (const userFacingFunctionName of [
|
||||
"codeAgentStatusMessage",
|
||||
"codeAgentPromptText",
|
||||
"codeAgentControlSummary",
|
||||
"codeAgentBlockedSummary",
|
||||
"codeAgentAvailabilitySummary",
|
||||
"failureMessage",
|
||||
"renderWiringList"
|
||||
]) {
|
||||
assert.doesNotMatch(functionBody(app, userFacingFunctionName), /OPENAI_API_KEY|hwlab-code-agent-provider|Secret|secretRef|m3-route-required|waiting-for-dev-live|BLOCKED 凭证缺口/u, `${userFacingFunctionName} must keep default copy sanitized`);
|
||||
}
|
||||
assert.match(app, /state\.conversationId/);
|
||||
assert.match(app, /conversationId/);
|
||||
assert.match(app, /messageId/);
|
||||
|
||||
@@ -103,6 +103,7 @@ ul {
|
||||
|
||||
.rail-button {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
min-height: 36px;
|
||||
padding: 6px 5px;
|
||||
border: 1px solid transparent;
|
||||
@@ -112,7 +113,9 @@ ul {
|
||||
font-weight: 760;
|
||||
line-height: 1.2;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
overflow-wrap: anywhere;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
.rail-button:hover,
|
||||
@@ -202,6 +205,8 @@ h3 {
|
||||
.badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 0 1 auto;
|
||||
width: fit-content;
|
||||
max-width: 100%;
|
||||
min-height: 22px;
|
||||
@@ -212,6 +217,9 @@ h3 {
|
||||
font-size: 10px;
|
||||
font-weight: 760;
|
||||
text-transform: uppercase;
|
||||
line-height: 1.25;
|
||||
white-space: normal;
|
||||
text-align: center;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
@@ -383,6 +391,7 @@ h3 {
|
||||
}
|
||||
|
||||
.probe-card {
|
||||
min-width: 0;
|
||||
display: grid;
|
||||
align-content: center;
|
||||
gap: 4px;
|
||||
@@ -393,8 +402,9 @@ h3 {
|
||||
|
||||
.probe-card strong {
|
||||
font-size: 17px;
|
||||
line-height: 1;
|
||||
line-height: 1.2;
|
||||
text-transform: uppercase;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.probe-card small {
|
||||
@@ -875,6 +885,7 @@ h3 {
|
||||
}
|
||||
|
||||
.side-tab {
|
||||
min-width: 0;
|
||||
min-height: 34px;
|
||||
padding: 6px 4px;
|
||||
border: 0;
|
||||
@@ -884,6 +895,8 @@ h3 {
|
||||
font-size: 11px;
|
||||
font-weight: 760;
|
||||
cursor: pointer;
|
||||
overflow-wrap: anywhere;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
.side-tab:last-child {
|
||||
@@ -1254,6 +1267,7 @@ tbody tr:last-child td {
|
||||
|
||||
.rail-button {
|
||||
min-height: 42px;
|
||||
line-height: 1.15;
|
||||
}
|
||||
|
||||
.explorer {
|
||||
@@ -1296,6 +1310,10 @@ tbody tr:last-child td {
|
||||
padding: 8px 10px;
|
||||
}
|
||||
|
||||
.probe-card strong {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.workbench-view,
|
||||
.gate-view,
|
||||
.help-view,
|
||||
@@ -1341,6 +1359,10 @@ tbody tr:last-child td {
|
||||
.trace-item {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.message-evidence {
|
||||
grid-column: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 520px) {
|
||||
|
||||
Reference in New Issue
Block a user