fix(code-queue): add workdirs contract checks
This commit is contained in:
+1
-1
@@ -110,7 +110,7 @@ function numberOption(args: string[], name: string, fallback: number): number {
|
||||
|
||||
function requireRevision(value: string | null): string {
|
||||
if (value === null || value.length === 0) throw new Error("ci run requires --revision <commit-or-ref>");
|
||||
if (!/^[A-Za-z0-9._/@:-]{1,160}$/u.test(value)) throw new Error("ci --revision contains unsupported characters");
|
||||
if (!/^[A-Za-z0-9._/@:-]{1,160}$/u.test(value) || value.startsWith("-") || value.includes("..")) throw new Error("ci --revision contains unsupported characters");
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
+30
-1
@@ -93,6 +93,7 @@ const SERVICE_CHECK_NAMES = [
|
||||
"microservice:todo-note-write-path",
|
||||
"microservice:code-queue-status",
|
||||
"microservice:code-queue-health",
|
||||
"microservice:code-queue-workdirs",
|
||||
"microservice:code-queue-tasks",
|
||||
"microservice:decision-center-status",
|
||||
"microservice:decision-center-health",
|
||||
@@ -137,6 +138,7 @@ const FRONTEND_CHECK_NAMES = [
|
||||
"frontend:oa-event-flow-visible",
|
||||
"frontend:decision-center-visible",
|
||||
"frontend:code-queue-integrated-visible",
|
||||
"frontend:code-queue-workdirs-loaded",
|
||||
"frontend:code-queue-enqueue-await-smoke",
|
||||
"frontend:code-queue-summary-mobile-wrap",
|
||||
"frontend:code-queue-long-prompt-observation",
|
||||
@@ -1235,6 +1237,9 @@ async function serviceChecks(config: UniDeskConfig, urls: PublicUrls, checks: E2
|
||||
const k3sctlControlPlane = dockerCoreJson("/api/microservices/k3sctl-adapter/proxy/api/control-plane");
|
||||
const codeQueueStatus = dockerCoreJson("/api/microservices/code-queue/status");
|
||||
const codeQueueHealth = dockerCoreJson("/api/microservices/code-queue/health");
|
||||
const codeQueueWorkdirs = wantsCheck(options, "microservice:code-queue-workdirs")
|
||||
? dockerCoreJson("/api/microservices/code-queue/proxy/api/workdirs")
|
||||
: null;
|
||||
const codeQueueTasks = dockerCoreJson("/api/microservices/code-queue/proxy/api/tasks/overview?limit=5&transcriptLimit=1&compact=1&afterSeq=0&preferId=");
|
||||
const decisionCenterStatus = dockerCoreJson("/api/microservices/decision-center/status");
|
||||
const decisionCenterHealth = dockerCoreJson("/api/microservices/decision-center/health");
|
||||
@@ -1313,6 +1318,7 @@ async function serviceChecks(config: UniDeskConfig, urls: PublicUrls, checks: E2
|
||||
const oaEventFlowPipelineEventsBody = (oaEventFlowPipelineEvents as { body?: { ok?: boolean; events?: Array<{ tags?: unknown[]; sourceId?: string; type?: string; payload?: { runId?: string; pipelineId?: string } }>; returned?: number } }).body;
|
||||
const oaEventFlowStatsBody = (oaEventFlowStats as { body?: { ok?: boolean; stats?: unknown[]; returned?: number } }).body;
|
||||
const codeQueueHealthBody = (codeQueueHealth as { body?: { ok?: boolean; egressProxy?: { connected?: boolean }; queue?: { defaultModel?: string; judgeConfigured?: boolean; modelReasoningEfforts?: Record<string, string> } } }).body;
|
||||
const codeQueueWorkdirsBody = (codeQueueWorkdirs as { body?: { ok?: boolean; workdirs?: Array<{ path?: string; providerId?: string; executionMode?: string }>; defaultProviderId?: string; defaultWorkdir?: string } } | null)?.body;
|
||||
const codeQueueTasksBody = (codeQueueTasks as { body?: { ok?: boolean; queue?: { defaultModel?: string; modelReasoningEfforts?: Record<string, string> }; tasks?: unknown[] } }).body;
|
||||
const decisionCenterHealthBody = (decisionCenterHealth as { body?: { ok?: boolean; service?: string; storage?: string; schemaReady?: boolean; recordCount?: number; deploy?: { commit?: string } } }).body;
|
||||
const decisionCenterRecordsBody = (decisionCenterRecords as { body?: { ok?: boolean; records?: unknown[]; returned?: number } }).body;
|
||||
@@ -1500,6 +1506,14 @@ async function serviceChecks(config: UniDeskConfig, urls: PublicUrls, checks: E2
|
||||
addSelectedCheck(checks, options, "microservice:oa-event-flow-stats", (oaEventFlowStats as { ok?: boolean }).ok === true && oaEventFlowStatsBody?.ok === true && Array.isArray(oaEventFlowStatsBody.stats), oaEventFlowStats);
|
||||
addSelectedCheck(checks, options, "microservice:code-queue-status", (codeQueueStatus as { ok?: boolean }).ok === true && (codeQueueStatus as { body?: { microservice?: { id?: string; providerId?: string } } }).body?.microservice?.providerId === "D601", codeQueueStatus);
|
||||
addSelectedCheck(checks, options, "microservice:code-queue-health", (codeQueueHealth as { ok?: boolean }).ok === true && codeQueueHealthBody?.ok === true && codeQueueHealthBody.egressProxy?.connected === true && codeQueueHealthBody.queue?.defaultModel === "gpt-5.5" && codeQueueHealthBody.queue?.modelReasoningEfforts?.["gpt-5.5"] === "xhigh", codeQueueHealth);
|
||||
addSelectedCheck(checks, options, "microservice:code-queue-workdirs",
|
||||
(codeQueueWorkdirs as { ok?: boolean; status?: number } | null)?.ok === true
|
||||
&& (codeQueueWorkdirs as { status?: number } | null)?.status === 200
|
||||
&& codeQueueWorkdirsBody?.ok === true
|
||||
&& Array.isArray(codeQueueWorkdirsBody.workdirs)
|
||||
&& codeQueueWorkdirsBody.workdirs.some((workdir) => workdir?.path === "/workspace")
|
||||
&& codeQueueWorkdirsBody.workdirs.every((workdir) => typeof workdir?.path === "string" && typeof workdir?.providerId === "string" && typeof workdir?.executionMode === "string"),
|
||||
codeQueueWorkdirs);
|
||||
addSelectedCheck(checks, options, "microservice:code-queue-tasks", (codeQueueTasks as { ok?: boolean }).ok === true && codeQueueTasksBody?.ok === true && Array.isArray(codeQueueTasksBody.tasks) && codeQueueTasksBody.queue?.defaultModel === "gpt-5.5" && codeQueueTasksBody.queue?.modelReasoningEfforts?.["gpt-5.5"] === "xhigh", codeQueueTasks);
|
||||
addSelectedCheck(checks, options, "microservice:decision-center-status", (decisionCenterStatus as { ok?: boolean }).ok === true && (decisionCenterStatus as { body?: { microservice?: { id?: string; providerId?: string } } }).body?.microservice?.providerId === "D601", decisionCenterStatus);
|
||||
addSelectedCheck(checks, options, "microservice:decision-center-health", (decisionCenterHealth as { ok?: boolean }).ok === true && decisionCenterHealthBody?.ok === true && decisionCenterHealthBody.service === "decision-center" && decisionCenterHealthBody.storage === "postgres" && decisionCenterHealthBody.schemaReady === true, decisionCenterHealth);
|
||||
@@ -1606,6 +1620,7 @@ async function frontendCheck(config: UniDeskConfig, urls: PublicUrls, checks: E2
|
||||
const needDecisionCenter = wants("frontend:decision-center-visible");
|
||||
const needCodeQueue = wantsAny([
|
||||
"frontend:code-queue-integrated-visible",
|
||||
"frontend:code-queue-workdirs-loaded",
|
||||
"frontend:code-queue-enqueue-await-smoke",
|
||||
"frontend:code-queue-summary-mobile-wrap",
|
||||
"frontend:code-queue-initial-prompt-full-expand",
|
||||
@@ -1701,7 +1716,7 @@ async function frontendCheck(config: UniDeskConfig, urls: PublicUrls, checks: E2
|
||||
let codeQueueTaskCount = 0;
|
||||
let codeQueueOptions: string[] = [];
|
||||
let codeQueueSwitchMetrics: any = { optionCount: 0, switched: false };
|
||||
let codeQueueSubmitQueueControl: any = { tagName: "", createButtonVisible: false, oldInputMissing: false };
|
||||
let codeQueueSubmitQueueControl: any = { tagName: "", createButtonVisible: false, oldInputMissing: false, workdirSelectOptionTexts: [] };
|
||||
let codeQueueTracePlacement: any = { firstChildIsTrace: false, noPageTopStatus: false, filterInsideTracePanel: false, traceStatusVisible: false, markAllReadVisible: false };
|
||||
let codeQueueGlobalStatus: any = { activeMicroserviceVisible: false };
|
||||
let codeQueueSidebarUpdateMetrics: any = { cardCount: 0, labels: [], hasRecentUpdateLabel: false };
|
||||
@@ -2100,6 +2115,7 @@ async function frontendCheck(config: UniDeskConfig, urls: PublicUrls, checks: E2
|
||||
const prompt = document.querySelector('[data-testid="code-queue-task-form"] textarea') as HTMLTextAreaElement | null;
|
||||
const provider = document.querySelector('[data-testid="codex-provider-select"]') as HTMLSelectElement | null;
|
||||
const cwd = document.querySelector('[data-testid="codex-cwd-input"]') as HTMLInputElement | null;
|
||||
const cwdSelect = document.querySelector('[data-testid="codex-cwd-select"]') as HTMLSelectElement | null;
|
||||
const maxAttempts = document.querySelector('[data-testid="codex-max-attempts-input"]') as HTMLInputElement | null;
|
||||
const moveSelect = document.querySelector('[data-testid="codex-task-queue-move-select"]') as HTMLSelectElement | null;
|
||||
const moveButton = document.querySelector('[data-testid="codex-task-queue-move-button"]') as HTMLButtonElement | null;
|
||||
@@ -2116,6 +2132,8 @@ async function frontendCheck(config: UniDeskConfig, urls: PublicUrls, checks: E2
|
||||
providerValue: provider?.value || "",
|
||||
providerOptions: Array.from(provider?.options || []).map((option) => ({ value: option.value, text: option.textContent || "" })),
|
||||
cwdValue: cwd?.value || "",
|
||||
workdirSelectValue: cwdSelect?.value || "",
|
||||
workdirSelectOptionTexts: Array.from(cwdSelect?.options || []).map((option) => option.textContent || ""),
|
||||
maxAttemptsMax: maxAttempts?.max || "",
|
||||
maxAttemptsValue: maxAttempts?.value || "",
|
||||
moveQueueVisible: Boolean(moveSelect && moveSelect.offsetParent !== null && moveButton && moveButton.offsetParent !== null),
|
||||
@@ -2569,6 +2587,7 @@ async function frontendCheck(config: UniDeskConfig, urls: PublicUrls, checks: E2
|
||||
const prompt = document.querySelector('[data-testid="code-queue-task-form"] textarea') as HTMLTextAreaElement | null;
|
||||
const provider = document.querySelector('[data-testid="codex-provider-select"]') as HTMLSelectElement | null;
|
||||
const cwd = document.querySelector('[data-testid="codex-cwd-input"]') as HTMLInputElement | null;
|
||||
const cwdSelect = document.querySelector('[data-testid="codex-cwd-select"]') as HTMLSelectElement | null;
|
||||
const maxAttempts = document.querySelector('[data-testid="codex-max-attempts-input"]') as HTMLInputElement | null;
|
||||
const moveSelect = document.querySelector('[data-testid="codex-task-queue-move-select"]') as HTMLSelectElement | null;
|
||||
const moveButton = document.querySelector('[data-testid="codex-task-queue-move-button"]') as HTMLButtonElement | null;
|
||||
@@ -2585,6 +2604,8 @@ async function frontendCheck(config: UniDeskConfig, urls: PublicUrls, checks: E2
|
||||
providerValue: provider?.value || "",
|
||||
providerOptions: Array.from(provider?.options || []).map((option) => ({ value: option.value, text: option.textContent || "" })),
|
||||
cwdValue: cwd?.value || "",
|
||||
workdirSelectValue: cwdSelect?.value || "",
|
||||
workdirSelectOptionTexts: Array.from(cwdSelect?.options || []).map((option) => option.textContent || ""),
|
||||
maxAttemptsMax: maxAttempts?.max || "",
|
||||
maxAttemptsValue: maxAttempts?.value || "",
|
||||
moveQueueVisible: Boolean(moveSelect && moveSelect.offsetParent !== null && moveButton && moveButton.offsetParent !== null),
|
||||
@@ -3184,6 +3205,14 @@ async function frontendCheck(config: UniDeskConfig, urls: PublicUrls, checks: E2
|
||||
&& !decisionCenterText.includes("{\n"),
|
||||
{ decisionCenterMetrics, decisionCenterE2eRecord, decisionCenterDeleteResult, decisionCenterTextPreview: decisionCenterText.slice(0, 1400) });
|
||||
addSelectedCheck(checks, options, "frontend:code-queue-integrated-visible", codeQueueTextLower.includes("code queue") && codeQueueText.includes("gpt-5.4-mini") && codeQueueText.includes("gpt-5.4") && codeQueueText.includes("gpt-5.5") && codeQueueText.includes("提交任务") && codeQueueText.includes("执行 Provider") && codeQueueText.includes("入队份数") && codeQueueText.includes("追加 prompt") && codeQueueText.includes("打断") && codeQueueTextLower.includes("查看 queue") && codeQueueText.includes("创建 queue") && codeQueueText.includes("合并 queue") && codeQueueOptions.some((text) => text.includes("All queues")) && codeQueueTracePlacement.firstChildIsTrace === true && codeQueueTracePlacement.noPageTopStatus === true && codeQueueTracePlacement.filterInsideTracePanel === true && codeQueueTracePlacement.taskSearchVisible === true && codeQueueTracePlacement.traceStatusVisible === true && codeQueueTracePlacement.markAllReadVisible === true && codeQueueGlobalStatus.activeMicroserviceVisible === true && codeQueueSidebarUpdateMetrics.hasRecentUpdateLabel === true && codeQueueHtmlGuard.rootAttrMissing === true && codeQueueHtmlGuard.sourceAttrMissing === true && codeQueueHtmlGuard.sourceNoBasePrompt === true && codeQueueSubmitQueueControl.tagName === "select" && codeQueueSubmitQueueControl.createButtonVisible === true && codeQueueSubmitQueueControl.mergeButtonVisible === true && codeQueueSubmitQueueControl.mergeSourceInlineMissing === true && codeQueueSubmitQueueControl.mergeDialogMissingBeforeClick === true && (codeQueueSubmitQueueControl.mergeButtonDisabled === true || (codeQueueSubmitQueueControl.mergeDialogVisible === true && codeQueueSubmitQueueControl.mergeDialogSelectVisible === true && Number(codeQueueSubmitQueueControl.mergeDialogSourceOptionCount || 0) > 1 && codeQueueSubmitQueueControl.mergeDialogSelectInsideSubmitForm !== true && codeQueueSubmitQueueControl.mergeDialogUsesCommonComponent === true && codeQueueSubmitQueueControl.mergeDialogDeleteNoteVisible === true)) && codeQueueSubmitQueueControl.oldInputMissing === true && codeQueueSubmitQueueControl.providerValue === "D601" && codeQueueSubmitQueueControl.cwdValue === "/workspace" && Array.isArray(codeQueueSubmitQueueControl.providerOptions) && codeQueueSubmitQueueControl.providerOptions.some((item: any) => item.value === "D601" && String(item.text || "").includes("/workspace")) && codeQueueSubmitQueueControl.maxAttemptsMax === "99" && codeQueueSubmitQueueControl.maxAttemptsValue === "99" && codeQueueSubmitQueueControl.moveQueueVisible === true && codeQueuePromptDefaultEmpty === true && codeQueueSubmitGuard.batchRowVisible === true && codeQueueSubmitGuard.checkboxVisible === true && codeQueueSubmitGuard.disabledBeforeConfirm === true && codeQueueSubmitGuard.enabledAfterConfirm === true && codeQueueSubmitGuard.waitElementMissingBeforeSubmit === true && codeQueueScrollbarMetrics.transcriptThin === true && codeQueueScrollbarMetrics.toolHorizontalHidden === true && (codeQueueSwitchMetrics.optionCount <= 1 || codeQueueSwitchMetrics.switched === true) && codeQueueTextLower.includes("attempts") && codeQueueText.includes("仅 UniDesk frontend 代理访问") && (codeQueueTaskCount === 0 || codeQueueOutputText.includes("Submitted prompt")), { codeQueueTaskCount, codeQueueOptions, codeQueueSwitchMetrics, codeQueueSubmitQueueControl, codeQueueSubmitGuard, codeQueueScrollbarMetrics, codeQueuePromptDefaultEmpty, codeQueueTracePlacement, codeQueueGlobalStatus, codeQueueSidebarUpdateMetrics, codeQueueHtmlGuard, codeQueueOutputPreview: codeQueueOutputText.slice(0, 900), codeQueueTextPreview: codeQueueText.slice(0, 1400) });
|
||||
addSelectedCheck(checks, options, "frontend:code-queue-workdirs-loaded",
|
||||
codeQueueSubmitQueueControl.cwdValue === "/workspace"
|
||||
&& codeQueueSubmitQueueControl.workdirSelectValue === "/workspace"
|
||||
&& Array.isArray(codeQueueSubmitQueueControl.workdirSelectOptionTexts)
|
||||
&& codeQueueSubmitQueueControl.workdirSelectOptionTexts.some((text: string) => text.includes("/workspace"))
|
||||
&& !codeQueueText.includes("加载工作目录失败")
|
||||
&& !codeQueueText.includes("HTTP 404"),
|
||||
{ codeQueueSubmitQueueControl, codeQueueTextPreview: codeQueueText.slice(0, 1200) });
|
||||
addSelectedCheck(checks, options, "frontend:code-queue-enqueue-await-smoke",
|
||||
codeQueueEnqueueAwaitSmoke.checked === true
|
||||
&& codeQueueEnqueueAwaitSmoke.delayedPostCount === 1
|
||||
|
||||
Reference in New Issue
Block a user