chore: remove prompt lint and contract tests

This commit is contained in:
Codex
2026-06-11 11:54:35 +00:00
parent 4d68ad6ae3
commit 5e44545f07
98 changed files with 58 additions and 20917 deletions
+2 -175
View File
@@ -14,13 +14,6 @@ interface CheckItem {
const syntaxFiles = [
"scripts/cli.ts",
"scripts/playwright-cli.ts",
"scripts/playwright-cli-contract-test.ts",
"scripts/platform-infra-sub2api-codex-local-config-contract-test.ts",
"scripts/platform-infra-sub2api-codex-routing-contract-test.ts",
"scripts/platform-infra-sub2api-codex-temp-unsched-contract-test.ts",
"scripts/platform-infra-sub2api-http-upstream-contract-test.ts",
"scripts/check-command-progress-contract-test.ts",
"scripts/check-gh-contract-scope-contract-test.ts",
"scripts/src/playwright-cli.ts",
"scripts/src/check.ts",
"scripts/src/artifact-registry.ts",
@@ -37,32 +30,10 @@ const syntaxFiles = [
"scripts/src/e2e.ts",
"scripts/src/help.ts",
"scripts/src/commander.ts",
"scripts/src/commander-prompt-lint.ts",
"scripts/src/recovery-guardrails.ts",
"scripts/src/server-cleanup.ts",
"scripts/src/remote.ts",
"scripts/host-codex-commander-contract-test.ts",
"scripts/host-codex-commander-no-daemon-smoke-contract-test.ts",
"scripts/host-codex-commander-prompt-lint-contract-test.ts",
"scripts/host-codex-commander-skeleton-contract-test.ts",
"scripts/auth-broker-contract-test.ts",
"scripts/code-queue-cli-disclosure-contract-test.ts",
"scripts/code-queue-prompt-lint-contract-test.ts",
"scripts/code-queue-cli-steer-test.ts",
"scripts/code-queue-steer-confirmation-contract-test.ts",
"scripts/code-queue-cli-submit-prompt-contract-test.ts",
"scripts/code-queue-submit-execution-mode-contract-test.ts",
"scripts/code-queue-submit-summary-contract-test.ts",
"scripts/code-queue-cli-read-terminal-contract-test.ts",
"scripts/code-queue-gh-auth-redaction-contract-test.ts",
"scripts/d601-recovery-guardrails-contract-test.ts",
"scripts/hwlab-cd-wrapper-contract-test.ts",
"scripts/code-queue-queues-shape-contract-test.ts",
"scripts/microservice-health-output-contract-test.ts",
"scripts/code-queue-supervisor-disclosure-contract-test.ts",
"scripts/code-queue-commander-view-contract-test.ts",
"scripts/code-queue-postgres-rotation-contract-test.ts",
"scripts/ssh-argv-guidance-contract-test.ts",
"src/components/frontend/src/index.ts",
"src/components/frontend/src/app.tsx",
"src/components/frontend/src/decision-center.tsx",
@@ -88,7 +59,6 @@ export interface CheckOptions {
compose: boolean;
logs: boolean;
recoveryGuardrails: boolean;
ghContracts: boolean;
rust: boolean;
scriptsTypecheckTimeoutMs: number;
checkHeartbeatMs: number;
@@ -105,7 +75,6 @@ const defaultCheckOptions: CheckOptions = {
compose: false,
logs: false,
recoveryGuardrails: false,
ghContracts: false,
rust: false,
scriptsTypecheckTimeoutMs: defaultScriptsTypecheckTimeoutMs,
checkHeartbeatMs: defaultCheckHeartbeatMs,
@@ -124,18 +93,17 @@ export function checkHelp(): Record<string, unknown> {
ok: true,
command: "check",
usage: [
"bun scripts/cli.ts check [--syntax-only|--full|--files|--scripts-typecheck|--scripts-typecheck-timeout-ms N|--check-heartbeat-ms N|--gh-contracts|--components|--compose|--logs|--recovery-guardrails|--rust]",
"bun scripts/cli.ts check [--syntax-only|--full|--files|--scripts-typecheck|--scripts-typecheck-timeout-ms N|--check-heartbeat-ms N|--components|--compose|--logs|--recovery-guardrails|--rust]",
"bun scripts/cli.ts check recovery-guardrails",
],
defaultMode: "syntax/config only; Rust is never compiled on the master server by default",
options: [
{ name: "--syntax-only|--basic", description: "Run only config validation, Bun version and TypeScript syntax transpile." },
{ name: "--full", description: "Enable all non-Rust checks, including explicit GitHub CLI contracts." },
{ name: "--full", description: "Enable all non-Rust checks." },
{ name: "--files", description: "Verify required entrypoint files, including backend-core Cargo files." },
{ name: "--scripts-typecheck", description: "Run scripts TypeScript typecheck through the observed checker." },
{ name: "--scripts-typecheck-timeout-ms N", description: `Bound scripts TypeScript typecheck duration; default ${defaultScriptsTypecheckTimeoutMs}.` },
{ name: "--check-heartbeat-ms N", description: `Emit unidesk.check.progress JSON lines for running command checks; default ${defaultCheckHeartbeatMs}.` },
{ name: "--gh-contracts", description: "Run slower GitHub CLI contract tests; intentionally separate from generic scripts typecheck." },
{ name: "--components", description: "Run component TypeScript typecheck." },
{ name: "--compose", description: "Render Docker Compose config." },
{ name: "--logs", description: "Check unified log rotation policy." },
@@ -166,7 +134,6 @@ export function parseCheckOptions(args: string[]): CheckOptions {
options.compose = true;
options.logs = true;
options.recoveryGuardrails = true;
options.ghContracts = true;
} else if (arg === "--scripts-typecheck-timeout-ms") {
options.scriptsTypecheckTimeoutMs = positiveIntegerOption(arg, args[index + 1], 600_000);
index += 1;
@@ -177,8 +144,6 @@ export function parseCheckOptions(args: string[]): CheckOptions {
options.files = true;
} else if (arg === "--scripts-typecheck") {
options.scriptsTypecheck = true;
} else if (arg === "--gh-contracts") {
options.ghContracts = true;
} else if (arg === "--components") {
options.components = true;
} else if (arg === "--compose") {
@@ -430,60 +395,21 @@ export async function runChecks(config: UniDeskConfig, options: CheckOptions = d
fileItem("src/components/microservices/host-codex-commander/src/redaction.ts"),
fileItem("src/components/microservices/host-codex-commander/src/state.ts"),
fileItem("src/components/microservices/code-queue-mgr/src/prompt-observation.ts"),
fileItem("scripts/src/commander-prompt-lint.ts"),
fileItem("scripts/src/deploy.ts"),
fileItem("scripts/code-queue-issue3-regression-test.ts"),
fileItem("scripts/code-queue-liveness-diagnostics-test.ts"),
fileItem("scripts/src/code-queue-liveness-fixtures.ts"),
fileItem("scripts/code-queue-trace-summary-contract-test.ts"),
fileItem("scripts/code-queue-pr-preflight-contract-test.ts"),
fileItem("scripts/code-queue-runner-skills-contract-test.ts"),
fileItem("scripts/code-queue-cli-disclosure-contract-test.ts"),
fileItem("scripts/code-queue-prompt-lint-contract-test.ts"),
fileItem("scripts/code-queue-cli-steer-test.ts"),
fileItem("scripts/code-queue-steer-confirmation-contract-test.ts"),
fileItem("scripts/code-queue-cli-read-terminal-contract-test.ts"),
fileItem("scripts/code-queue-cli-submit-prompt-contract-test.ts"),
fileItem("scripts/code-queue-submit-summary-contract-test.ts"),
fileItem("scripts/code-queue-submit-routing-contract-test.ts"),
fileItem("scripts/code-queue-gh-auth-redaction-contract-test.ts"),
fileItem("scripts/code-queue-queues-shape-contract-test.ts"),
fileItem("scripts/code-queue-supervisor-disclosure-contract-test.ts"),
fileItem("scripts/code-queue-commander-view-contract-test.ts"),
fileItem("scripts/code-queue-postgres-rotation-contract-test.ts"),
fileItem("scripts/host-codex-commander-skeleton-contract-test.ts"),
fileItem("scripts/host-codex-commander-no-daemon-smoke-contract-test.ts"),
fileItem("scripts/host-codex-commander-prompt-lint-contract-test.ts"),
fileItem("scripts/provider-runner-triage-contract-test.ts"),
fileItem("scripts/ssh-argv-guidance-contract-test.ts"),
fileItem("scripts/src/provider-triage.ts"),
fileItem("src/components/microservices/code-queue/src/runner-error-classifier.ts"),
fileItem("scripts/src/ci.ts"),
fileItem("scripts/src/e2e.ts"),
fileItem("scripts/deploy-artifact-matrix-contract-test.ts"),
fileItem("scripts/artifact-registry-local-provider-contract-test.ts"),
fileItem("scripts/decision-center-diary-summary-contract-test.ts"),
fileItem("scripts/decision-center-desired-state-contract-test.ts"),
fileItem("scripts/code-queue-prompt-observation-test.ts"),
fileItem("scripts/check-command-progress-contract-test.ts"),
fileItem("scripts/check-gh-contract-scope-contract-test.ts"),
fileItem("scripts/gh-cli-issue-guard-contract-test.ts"),
fileItem("scripts/gh-cli-pr-files-contract-test.ts"),
fileItem("scripts/gh-cli-pr-contract-test.ts"),
fileItem("scripts/playwright-cli-contract-test.ts"),
fileItem("scripts/platform-infra-sub2api-codex-local-config-contract-test.ts"),
fileItem("scripts/platform-infra-sub2api-codex-routing-contract-test.ts"),
fileItem("scripts/platform-infra-sub2api-codex-temp-unsched-contract-test.ts"),
fileItem("scripts/code-queue-pr-preflight-example.ts"),
fileItem("scripts/schedule-cli-contract-test.ts"),
fileItem("scripts/server-cleanup-plan-contract-test.ts"),
fileItem("scripts/src/artifact-registry.ts"),
fileItem("scripts/src/server-cleanup.ts"),
fileItem("scripts/src/recovery-guardrails.ts"),
fileItem("scripts/src/auth-broker.ts"),
fileItem("scripts/auth-broker-contract-test.ts"),
fileItem("scripts/d601-recovery-guardrails-contract-test.ts"),
fileItem("scripts/hwlab-cd-wrapper-contract-test.ts"),
fileItem("src/components/microservices/auth-broker/Cargo.toml"),
fileItem("src/components/microservices/auth-broker/Dockerfile"),
fileItem("src/components/microservices/auth-broker/src/main.rs"),
@@ -498,113 +424,14 @@ export async function runChecks(config: UniDeskConfig, options: CheckOptions = d
}
if (options.scriptsTypecheck) {
items.push(await commandItem("typescript:scripts", ["bun", "--bun", "tsc", "-p", "scripts/tsconfig.json", "--noEmit", "--pretty", "false"], options.scriptsTypecheckTimeoutMs, process.env, options.checkHeartbeatMs));
items.push(await commandItem("check:command-progress-contract", ["bun", "scripts/check-command-progress-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("code-queue:prompt-observation-contract", ["bun", "scripts/code-queue-prompt-observation-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("code-queue:issue3-diagnostics-and-image-preflight", ["bun", "scripts/code-queue-issue3-regression-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("code-queue:trace-summary-contract", ["bun", "scripts/code-queue-trace-summary-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("code-queue:pr-preflight-contract", ["bun", "scripts/code-queue-pr-preflight-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("code-queue:runner-skills-contract", ["bun", "scripts/code-queue-runner-skills-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("code-queue:cli-disclosure-contract", ["bun", "scripts/code-queue-cli-disclosure-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("code-queue:prompt-lint-contract", ["bun", "scripts/code-queue-prompt-lint-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("code-queue:cli-steer-contract", ["bun", "scripts/code-queue-cli-steer-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("code-queue:steer-confirmation-contract", ["bun", "scripts/code-queue-steer-confirmation-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("code-queue:resume-contract", ["bun", "scripts/code-queue-resume-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("code-queue:read-terminal-contract", ["bun", "scripts/code-queue-cli-read-terminal-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("code-queue:submit-prompt-contract", ["bun", "scripts/code-queue-cli-submit-prompt-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("code-queue:submit-execution-mode-contract", ["bun", "scripts/code-queue-submit-execution-mode-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("code-queue:submit-summary-contract", ["bun", "scripts/code-queue-submit-summary-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("code-queue:submit-routing-contract", ["bun", "scripts/code-queue-submit-routing-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("code-queue:gh-auth-redaction-contract", ["bun", "scripts/code-queue-gh-auth-redaction-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("code-queue:queues-shape-contract", ["bun", "scripts/code-queue-queues-shape-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("code-queue:supervisor-disclosure-contract", ["bun", "scripts/code-queue-supervisor-disclosure-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("code-queue:commander-view-contract", ["bun", "scripts/code-queue-commander-view-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("code-queue:postgres-rotation-contract", ["bun", "scripts/code-queue-postgres-rotation-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("host-codex-commander:skeleton-contract", ["bun", "scripts/host-codex-commander-skeleton-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("host-codex-commander:no-daemon-smoke-contract", ["bun", "scripts/host-codex-commander-no-daemon-smoke-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("host-codex-commander:prompt-lint-contract", ["bun", "scripts/host-codex-commander-prompt-lint-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("provider:runner-triage-contract", ["bun", "scripts/provider-runner-triage-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("ssh:argv-guidance-contract", ["bun", "scripts/ssh-argv-guidance-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("deploy:artifact-matrix-contract", ["bun", "scripts/deploy-artifact-matrix-contract-test.ts"], 90_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("artifact-registry:local-provider-contract", ["bun", "scripts/artifact-registry-local-provider-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("decision-center:diary-summary-contract", ["bun", "scripts/decision-center-diary-summary-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("decision-center:desired-state-contract", ["bun", "scripts/decision-center-desired-state-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("code-queue:active-run-heartbeat-visible", ["bun", "scripts/code-queue-liveness-diagnostics-test.ts", "--only", "code-queue:active-run-heartbeat-visible"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("code-queue:trace-gap-not-stale", ["bun", "scripts/code-queue-liveness-diagnostics-test.ts", "--only", "code-queue:trace-gap-not-stale"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("code-queue:stale-active-owner-expired", ["bun", "scripts/code-queue-liveness-diagnostics-test.ts", "--only", "code-queue:stale-active-owner-expired"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("code-queue:control-plane-split-brain-diagnostics", ["bun", "scripts/code-queue-liveness-diagnostics-test.ts", "--only", "code-queue:control-plane-split-brain-diagnostics"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("code-queue:oa-publisher-degraded-visible", ["bun", "scripts/code-queue-liveness-diagnostics-test.ts", "--only", "code-queue:oa-publisher-degraded-visible"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("baidu-netdisk:artifact-guard-contract", ["bun", "scripts/baidu-netdisk-artifact-guard-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("artifact-registry:direct-compose-dry-run-matrix", ["bun", "scripts/artifact-consumer-dry-run-matrix-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("schedule:cli-contract", ["bun", "scripts/schedule-cli-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("server:cleanup-plan-contract", ["bun", "scripts/server-cleanup-plan-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("check:gh-contract-scope-contract", ["bun", "scripts/check-gh-contract-scope-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("playwright:cli-wrapper-contract", ["bun", "scripts/playwright-cli-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("platform-infra:sub2api-codex-local-config-contract", ["bun", "scripts/platform-infra-sub2api-codex-local-config-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("platform-infra:sub2api-codex-routing-contract", ["bun", "scripts/platform-infra-sub2api-codex-routing-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("platform-infra:sub2api-codex-sentinel-contract", ["bun", "scripts/platform-infra-sub2api-codex-sentinel-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("platform-infra:sub2api-codex-temp-unsched-contract", ["bun", "scripts/platform-infra-sub2api-codex-temp-unsched-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("platform-infra:sub2api-http-upstream-contract", ["bun", "scripts/platform-infra-sub2api-http-upstream-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("auth-broker:p0-contract", ["bun", "scripts/auth-broker-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("d601:recovery-guardrails-contract", ["bun", "scripts/d601-recovery-guardrails-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("hwlab:cd-wrapper-contract", ["bun", "scripts/hwlab-cd-wrapper-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
} else {
items.push(skippedItem("typescript:scripts", "scripts TypeScript typecheck is opt-in", "--scripts-typecheck or --full"));
items.push(skippedItem("check:command-progress-contract", "observed command progress contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("code-queue:prompt-observation-contract", "prompt observation contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("code-queue:issue3-diagnostics-and-image-preflight", "Code Queue issue #3 regression fixtures are opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("code-queue:trace-summary-contract", "Code Queue trace summary contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("code-queue:pr-preflight-contract", "Code Queue PR preflight contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("code-queue:runner-skills-contract", "Code Queue runner skill availability contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("code-queue:cli-disclosure-contract", "Code Queue CLI disclosure/noise contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("code-queue:prompt-lint-contract", "Code Queue prompt live-authorization lint contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("code-queue:cli-steer-contract", "Code Queue steer CLI contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("code-queue:steer-confirmation-contract", "Code Queue steer delivery confirmation contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("code-queue:resume-contract", "Code Queue resume CLI and delivery contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("code-queue:read-terminal-contract", "Code Queue terminal read contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("code-queue:submit-prompt-contract", "Code Queue submit prompt contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("code-queue:submit-execution-mode-contract", "Code Queue submit execution-mode contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("code-queue:submit-summary-contract", "Code Queue submit summary contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("code-queue:submit-routing-contract", "Code Queue submit routing contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("code-queue:gh-auth-redaction-contract", "Code Queue GitHub auth output redaction contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("code-queue:queues-shape-contract", "Code Queue queues shape contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("code-queue:supervisor-disclosure-contract", "Code Queue supervisor disclosure contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("code-queue:commander-view-contract", "Code Queue commander view contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("code-queue:postgres-rotation-contract", "Code Queue postgres rotation crash contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("host-codex-commander:skeleton-contract", "host Codex commander skeleton contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("host-codex-commander:no-daemon-smoke-contract", "host Codex commander no-daemon smoke contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("host-codex-commander:prompt-lint-contract", "host Codex commander prompt boundary lint contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("provider:runner-triage-contract", "Provider runner triage contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("ssh:argv-guidance-contract", "SSH argv guidance and failure hint contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("deploy:artifact-matrix-contract", "deploy artifact matrix contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("artifact-registry:local-provider-contract", "artifact registry local provider contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("decision-center:diary-summary-contract", "Decision Center diary summary contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("decision-center:desired-state-contract", "Decision Center desired-state drift contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("code-queue:liveness-diagnostics-fixtures", "Code Queue liveness diagnostics fixtures are opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("baidu-netdisk:artifact-guard-contract", "Baidu Netdisk artifact guard contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("artifact-registry:direct-compose-dry-run-matrix", "main-server direct artifact consumer dry-run matrix is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("schedule:cli-contract", "Schedule CLI contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("server:cleanup-plan-contract", "Server cleanup dry-run contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("check:gh-contract-scope-contract", "Check option scope contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("playwright:cli-wrapper-contract", "Playwright wrapper/headless/session contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("platform-infra:sub2api-codex-sentinel-contract", "Sub2API Codex account sentinel contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("auth-broker:p0-contract", "Auth Broker P0 skeleton and CLI adapter contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("d601:recovery-guardrails-contract", "D601 recovery guardrails fixture contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("hwlab:cd-wrapper-contract", "HWLAB DEV CD wrapper contract is opt-in with script checks", "--scripts-typecheck or --full"));
}
if (options.logs) {
items.push(unifiedLogRotationItem());
} else {
items.push(skippedItem("logs:unified-hourly-rotation", "policy scan is opt-in", "--logs or --full"));
}
if (options.ghContracts) {
items.push(await commandItem("gh:issue-guard-contract", ["bun", "scripts/gh-cli-issue-guard-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("gh:pr-files-contract", ["bun", "scripts/gh-cli-pr-files-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
items.push(await commandItem("gh:pr-contract", ["bun", "scripts/gh-cli-pr-contract-test.ts"], 30_000, process.env, options.checkHeartbeatMs));
} else {
items.push(skippedItem("gh:issue-guard-contract", "GitHub issue CLI contract is opt-in because it can be slower than generic scripts typecheck", "--gh-contracts or --full"));
items.push(skippedItem("gh:pr-files-contract", "GitHub PR files/stat contract is opt-in because it can be slower than generic scripts typecheck", "--gh-contracts or --full"));
items.push(skippedItem("gh:pr-contract", "GitHub PR CLI contract is opt-in because it can be slower than generic scripts typecheck", "--gh-contracts or --full"));
}
if (options.recoveryGuardrails) {
const recovery = runRecoveryGuardrailsCheck(config);
items.push({
+2 -283
View File
@@ -154,71 +154,6 @@ interface CodexJudgeOptions {
includePrompt: boolean;
}
type LiveTestAuthorizationClass = "read-only" | "live-read" | "live-mutating";
type PromptLintSeverity = "info" | "warning" | "block";
type PromptLintDisposition = "ready" | "review" | "needs-authorization";
interface CodexPromptLintOptions {
prompt: string;
}
interface PromptLintSignal {
id: string;
severity: PromptLintSeverity;
matched: boolean;
evidence: string[];
message: string;
}
interface PromptLiveAuthorizationLint {
ok: boolean;
dryRun: true;
mutation: false;
dispatchDisposition: PromptLintDisposition;
declaredClass: LiveTestAuthorizationClass | null;
effectiveClass: LiveTestAuthorizationClass;
requiredClass: LiveTestAuthorizationClass;
defaultedReadOnly: boolean;
liveMutationAuthorized: boolean;
promptShape: {
chars: number;
lines: number;
textEchoed: false;
};
requiredPromptFields: {
devTestClass: {
present: boolean;
value: LiveTestAuthorizationClass | null;
allowedValues: LiveTestAuthorizationClass[];
};
allowedLiveMutation: {
present: boolean;
nonNone: boolean;
requiredWhen: "live-mutating";
};
forbiddenActions: {
present: boolean;
};
closeoutFields: {
present: boolean;
};
};
signals: PromptLintSignal[];
missingOrContradictory: string[];
policy: {
defaultWhenUnclassified: "read-only";
promptLintOnly: true;
accessesLiveService: false;
printsPromptText: false;
reference: string;
};
commands: {
lintFile: string;
submitDryRun: string;
steerDryRun: string;
};
}
interface CodexSubmitOptions {
prompt: string;
queueId: string | undefined;
@@ -1397,196 +1332,6 @@ function routeSignal(id: string, severity: SubmitRouteSignalSeverity, evidence:
return { id, severity, matched: evidence.length > 0, evidence, message };
}
function promptLintSignal(id: string, severity: PromptLintSeverity, evidence: string[], message: string): PromptLintSignal {
return { id, severity, matched: evidence.length > 0, evidence, message };
}
function declaredLiveTestClass(prompt: string): LiveTestAuthorizationClass | null {
const patterns: Array<[LiveTestAuthorizationClass, RegExp[]]> = [
["live-mutating", [
/\bDEV\s+test\s+class\s*[:]\s*`?live-mutating`?/iu,
/\blive\s+test\s+class\s*[:]\s*`?live-mutating`?/iu,
/\btest\s+class\s*[:]\s*`?live-mutating`?/iu,
/\bDEV\s+(?:)?\s*[:]\s*`?live-mutating`?/iu,
]],
["live-read", [
/\bDEV\s+test\s+class\s*[:]\s*`?live-read`?/iu,
/\blive\s+test\s+class\s*[:]\s*`?live-read`?/iu,
/\btest\s+class\s*[:]\s*`?live-read`?/iu,
/\bDEV\s+(?:)?\s*[:]\s*`?live-read`?/iu,
]],
["read-only", [
/\bDEV\s+test\s+class\s*[:]\s*`?read-only`?/iu,
/\blive\s+test\s+class\s*[:]\s*`?read-only`?/iu,
/\btest\s+class\s*[:]\s*`?read-only`?/iu,
/\bDEV\s+(?:)?\s*[:]\s*`?read-only`?/iu,
]],
];
for (const [value, valuePatterns] of patterns) {
if (valuePatterns.some((pattern) => pattern.test(prompt))) return value;
}
return null;
}
function liveClassRank(value: LiveTestAuthorizationClass): number {
if (value === "read-only") return 0;
if (value === "live-read") return 1;
return 2;
}
function hasPromptField(prompt: string, patterns: RegExp[]): boolean {
return patterns.some((pattern) => pattern.test(prompt));
}
function sanitizePromptLintEvidence(evidence: string[]): string[] {
return evidence.map((item) => item
.replace(/([?&](?:token|api[_-]?key|secret|password|credential)=)[^&\s]+/giu, "$1<redacted>")
.replace(/((?:token|api[_-]?key|secret|password|credential)\s*[:=]\s*)[^\s,;]+/giu, "$1<redacted>")
.replace(/(Bearer\s+)[A-Za-z0-9._~+/-]+=*/giu, "$1<redacted>")
.slice(0, 160));
}
function buildPromptLiveAuthorizationLint(prompt: string): PromptLiveAuthorizationLint {
const declaredClass = declaredLiveTestClass(prompt);
const effectiveClass = declaredClass ?? "read-only";
const allowedClasses: LiveTestAuthorizationClass[] = ["read-only", "live-read", "live-mutating"];
const liveReadEvidence = sanitizePromptLintEvidence(regexEvidenceWithoutNegatedContext(prompt, [
/\blive[- ]read\b/giu,
/\blive\s+(?:dev\s+)?(?:service|runtime|endpoint|health|status|logs?|metrics?)\b/giu,
/\bGET\s+\/(?:health|status|live|metrics|api\/diagnostics)\b/gu,
/\bkubectl\s+(?:get|describe|logs)\b/giu,
/\bmicroservice\s+(?:health|status|diagnostics)\b/giu,
/\bdiagnostics\b|\bstatus\b|\bmetrics\b|\blogs?\b/giu,
/(?:||||)/gu,
/\s*(?:DEV|live||||)/giu,
]));
const liveMutationEvidence = sanitizePromptLintEvidence(regexEvidenceWithoutNegatedContext(prompt, [
/\blive-mutating\b/giu,
/\bDEV\s+smoke\b|\blive\s+smoke\b|\bM3\s+smoke\b/giu,
/\bdeploy\s+apply\b|\brollout\s+restart\b|\bkubectl\s+(?:apply|delete|patch|rollout)\b/giu,
/\b(?:POST|PUT|PATCH|DELETE)\s+\/[A-Za-z0-9_./:-]*/gu,
/\bcodex\s+(?:submit|steer|interrupt|cancel)\b/giu,
/\btask\s+(?:submit|steer|retry|trigger)\b/giu,
/\btrigger\s+(?:schedule|job|task|operation|audit|evidence)\b/giu,
/\bschedule\s+(?:run|retry-run|delete)\b/giu,
/\b(?:create|write|post|put|patch)\b[^\n]{0,40}\b(?:operation|audit|evidence)\b/giu,
/\b(?:operation|audit|evidence)\s+(?:id|record|write|create)\b/giu,
/\bDO\d+\b|\bDI\d+\b|\bres_boxsimu_\d+\b|\bhwlab-patch-panel\b/giu,
/||||||(?:|operation|audit|evidence)||/gu,
]));
const prodMutationEvidence = sanitizePromptLintEvidence(regexEvidenceWithoutNegatedContext(prompt, [
/\bprod(?:uction)?\b[^\n]*(?:deploy|restart|write|mutation|mutating|apply|rollout|delete|patch)\b/giu,
/\b(?:deploy|restart|write|mutation|mutating|apply|rollout|delete|patch)\b[^\n]*\bprod(?:uction)?\b/giu,
/[^\n]*(?:|||||)/gu,
]));
const requiredClass = liveMutationEvidence.length > 0 || prodMutationEvidence.length > 0
? "live-mutating"
: liveReadEvidence.length > 0
? "live-read"
: "read-only";
const allowedLiveMutationPresent = hasPromptField(prompt, [
/\ballowed\s+live\s+mutation\s*[:]/iu,
/\s*live\s*mutation\s*[:]/iu,
/(?:||)?(?:||mutation)\s*[:]/iu,
]);
const allowedLiveMutationNone = hasPromptField(prompt, [
/\ballowed\s+live\s+mutation\s*[:]\s*(?:`?none`?||)(?:\s|$|[.;,])/iu,
/\s*live\s*mutation\s*[:]\s*(?:`?none`?||)(?:\s|$|[.;,])/iu,
/(?:||)?(?:||mutation)\s*[:]\s*(?:`?none`?||)(?:\s|$|[.;,])/iu,
]);
const forbiddenActionsPresent = hasPromptField(prompt, [
/\bforbidden\s+actions?\s*[:]/iu,
/\s*[:]/u,
/\s*[:]/u,
]);
const closeoutFieldsPresent = hasPromptField(prompt, [
/\bcloseout\s+fields?\s*[:]/iu,
/\bfinal\s+response\b[^\n]*(?:must|include|report)/iu,
/\b\s*[:]/u,
/\bfinal\s+response\b[^\n]*/iu,
]);
const effectiveInsufficient = liveClassRank(effectiveClass) < liveClassRank(requiredClass);
const liveMutationAuthorized = effectiveClass === "live-mutating" && allowedLiveMutationPresent && !allowedLiveMutationNone;
const contradictionEvidence = [
...(effectiveClass === "read-only" && liveMutationEvidence.length > 0 ? ["declares/read-only but prompt contains live mutation signals"] : []),
...(effectiveClass === "live-read" && liveMutationEvidence.length > 0 ? ["declares/live-read but prompt contains live mutation signals"] : []),
...(effectiveClass === "live-mutating" && allowedLiveMutationNone ? ["declares/live-mutating but allowed live mutation is none"] : []),
...(prodMutationEvidence.length > 0 ? prodMutationEvidence.map((item) => `prod mutation signal: ${item}`) : []),
];
const missingOrContradictory = [
...(declaredClass === null ? ["missing DEV test class; defaulting to read-only"] : []),
...(effectiveInsufficient ? [`effective class ${effectiveClass} is below required ${requiredClass}`] : []),
...(requiredClass === "live-mutating" && !allowedLiveMutationPresent ? ["live-mutating prompt must include allowed live mutation"] : []),
...(requiredClass === "live-mutating" && allowedLiveMutationNone ? ["live-mutating prompt cannot set allowed live mutation to none"] : []),
...(!forbiddenActionsPresent ? ["missing forbidden actions"] : []),
...(!closeoutFieldsPresent ? ["missing closeout fields"] : []),
...contradictionEvidence,
];
const signals = [
promptLintSignal("declared-dev-test-class", "info", declaredClass === null ? [] : [declaredClass], "Prompt explicitly declares DEV test class."),
promptLintSignal("live-read-signal", "warning", liveReadEvidence, "Prompt appears to read live DEV service state, logs, health, status, metrics, or Kubernetes objects."),
promptLintSignal("live-mutation-signal", "block", liveMutationEvidence, "Prompt appears to trigger runtime writes, deployment, task control, operation/audit/evidence creation, or HWLAB DO/DI activity."),
promptLintSignal("prod-mutation-signal", "block", prodMutationEvidence, "Prompt appears to mention production mutation; Code Queue runner prompts must not implicitly authorize this."),
promptLintSignal("allowed-live-mutation-field", requiredClass === "live-mutating" ? "block" : "info", allowedLiveMutationPresent && !allowedLiveMutationNone ? ["present"] : [], "live-mutating prompts must enumerate allowed live mutation commands and target state changes."),
promptLintSignal("forbidden-actions-field", "warning", forbiddenActionsPresent ? ["present"] : [], "Prompt should list forbidden high-risk actions."),
promptLintSignal("closeout-fields-field", "warning", closeoutFieldsPresent ? ["present"] : [], "Prompt should require final closeout fields for class, mutation, commands, targets, evidence, and residual risk."),
];
const ok = missingOrContradictory.length === 0;
const dispatchDisposition: PromptLintDisposition = ok
? "ready"
: requiredClass === "live-mutating" || effectiveInsufficient || contradictionEvidence.length > 0
? "needs-authorization"
: "review";
return {
ok,
dryRun: true,
mutation: false,
dispatchDisposition,
declaredClass,
effectiveClass,
requiredClass,
defaultedReadOnly: declaredClass === null,
liveMutationAuthorized,
promptShape: {
chars: prompt.length,
lines: prompt.split(/\r\n|\r|\n/u).length,
textEchoed: false,
},
requiredPromptFields: {
devTestClass: {
present: declaredClass !== null,
value: declaredClass,
allowedValues: allowedClasses,
},
allowedLiveMutation: {
present: allowedLiveMutationPresent,
nonNone: allowedLiveMutationPresent && !allowedLiveMutationNone,
requiredWhen: "live-mutating",
},
forbiddenActions: {
present: forbiddenActionsPresent,
},
closeoutFields: {
present: closeoutFieldsPresent,
},
},
signals,
missingOrContradictory,
policy: {
defaultWhenUnclassified: "read-only",
promptLintOnly: true,
accessesLiveService: false,
printsPromptText: false,
reference: "docs/reference/code-queue-supervision.md#dev-测试授权分级",
},
commands: {
lintFile: "bun scripts/cli.ts codex prompt-lint --prompt-file <path>",
submitDryRun: "bun scripts/cli.ts codex submit --prompt-file <path> --dry-run",
steerDryRun: "bun scripts/cli.ts codex steer <taskId> --prompt-file <path> --dry-run",
},
};
}
function submitPolicyContract(): SubmitRoutingRecommendation["policyContract"] {
return {
selectionPrinciples: [
@@ -1752,7 +1497,7 @@ function submitRoutingRecommendation(options: CodexSubmitOptions): SubmitRouting
routeSignal("issue-auxiliary-source-guard", "info", issueAuxiliaryGuard, "Prompt explicitly says GitHub issue is auxiliary and not the only source."),
routeSignal("cross-module-release", "warning", crossModule, "Mentions cross-module architecture, CI/CD rollout, release line, or rollback work."),
routeSignal("medium-complexity-verifiable", "info", mediumComplexityEvidence, "Mentions bounded medium-complexity work such as frontend, local CLI/helper, user-service module, or contract guard changes."),
routeSignal("low-risk-verifiable", "info", lowRiskEvidence, "Mentions low-risk or verifiable work such as docs, read-only checks, dry-run, preflight, or contract tests."),
routeSignal("low-risk-verifiable", "info", lowRiskEvidence, "Mentions low-risk or verifiable work such as docs, read-only checks, dry-run, preflight, or syntax checks."),
routeSignal("evidence-requested", "info", evidenceRequest, "Prompt asks for tests, validation, commit, or evidence."),
routeSignal("self-contained-hints", "info", selfContainedHints, "Prompt includes explicit task sections that make it easier to verify without reading an issue."),
];
@@ -5611,16 +5356,6 @@ function parseResumeOptions(args: string[]): CodexResumeOptions {
};
}
function parsePromptLintOptions(args: string[]): CodexPromptLintOptions {
assertKnownOptions(args, {
flags: ["--prompt-stdin", "--stdin"],
valueOptions: ["--prompt-file", "--file"],
}, "codex prompt-lint");
return {
prompt: promptFromArgs(args, "codex prompt-lint", steerPromptValueOptions),
};
}
function submitPayload(options: CodexSubmitOptions): Record<string, unknown> {
return {
prompt: options.prompt,
@@ -7978,28 +7713,17 @@ export function codexSubmitRoutingRecommendationForTest(prompt: string, model?:
});
}
export function codexPromptLiveAuthorizationLintForTest(prompt: string): PromptLiveAuthorizationLint {
return buildPromptLiveAuthorizationLint(prompt);
}
export function codexSubmitModelRegistryForTest(models: string[] = sharedDefaultCodeModels): ReturnType<typeof submitModelRegistry> {
return submitModelRegistry(models);
}
function codexPromptLintTask(args: string[]): unknown {
const options = parsePromptLintOptions(args);
return buildPromptLiveAuthorizationLint(options.prompt);
}
function codexSubmitTask(args: string[]): unknown {
const options = parseSubmitOptions(args);
const payload = submitPayload(options);
const promptLint = buildPromptLiveAuthorizationLint(options.prompt);
if (options.dryRun) {
return {
ok: true,
dryRun: true,
promptLint,
executionMode: executionModeSummary(options.executionMode),
runnerPermissions: dryRunRunnerPermissionsSummary(),
routingRecommendation: submitRoutingRecommendation(options),
@@ -8033,7 +7757,6 @@ function codexInterruptTask(taskId: string): unknown {
function codexSteerTask(taskId: string, args: string[], fetcher: CodexResponseFetcher = coreInternalFetch): unknown {
const options = parseSteerOptions(args);
const promptLint = buildPromptLiveAuthorizationLint(options.prompt);
const steerId = options.steerId ?? createSteerId(taskId, options.prompt);
const targetPath = `/api/tasks/${encodeURIComponent(taskId)}/steer`;
const stableProxyPath = codeQueueProxyPath(targetPath);
@@ -8064,7 +7787,6 @@ function codexSteerTask(taskId: string, args: string[], fetcher: CodexResponseFe
return {
ok: true,
dryRun: true,
promptLint,
request,
commands: {
run: `bun scripts/cli.ts codex steer ${taskId} --prompt-file <path> --steer-id ${steerId}`,
@@ -8401,9 +8123,6 @@ function codexResumeTask(taskId: string, args: string[], fetcher: CodexResponseF
export async function runCodeQueueCommand(config: UniDeskConfig, args: string[]): Promise<unknown> {
const [action = "task", taskIdArg] = args;
if (action === "prompt-lint" || action === "lint-prompt") {
return codexPromptLintTask(args.slice(1));
}
if (action === "submit" || action === "enqueue") {
return legacyCodeQueueFrozenMutation(`codex ${action}`);
}
@@ -8462,5 +8181,5 @@ export async function runCodeQueueCommand(config: UniDeskConfig, args: string[])
const taskId = requireTaskId(taskIdArg, `codex ${action}`);
return codexSteerTraceConfirm(taskId, args.slice(2));
}
throw new Error("codex command must be one of: prompt-lint, submit, enqueue, task, summary, show, tasks, overview, unread, terminal-unread, output, judge, read, mark-read, dev-ready, health, skills-sync, execution-plane, exec-plane, runtime-plane, pr-preflight, runtime-preflight, queues, queue list, queue create, queue merge, move, steer, resume, steer-confirm, interrupt, cancel");
throw new Error("codex command must be one of: submit, enqueue, task, summary, show, tasks, overview, unread, terminal-unread, output, judge, read, mark-read, dev-ready, health, skills-sync, execution-plane, exec-plane, runtime-plane, pr-preflight, runtime-preflight, queues, queue list, queue create, queue merge, move, steer, resume, steer-confirm, interrupt, cancel");
}
-245
View File
@@ -1,245 +0,0 @@
import { readFileSync } from "node:fs";
export type CommanderPromptLintKind = "gpt55-pr";
export type CommanderPromptLintRiskLevel = "low" | "medium" | "high";
interface ClauseCheck {
id: string;
label: string;
required: boolean;
matched: boolean;
severity: "medium" | "high";
suggestion: string;
}
export interface CommanderPromptLintResult {
ok: boolean;
kind: CommanderPromptLintKind;
missingClauses: string[];
riskLevel: CommanderPromptLintRiskLevel;
suggestedPatchSnippet: string;
promptShape: {
chars: number;
lines: number;
textEchoed: false;
};
policy: {
advisoryOnly: true;
mutatesScheduler: false;
changesCodexSubmitDefault: false;
printsPromptText: false;
supportedInputs: Array<"--stdin" | "--prompt-file">;
reference: string;
};
}
interface ParsedPromptLintArgs {
kind: CommanderPromptLintKind;
prompt: string;
}
const gpt55PrSnippet = [
"GPT-5.5 runner boundary:",
"- You may create/update the branch and PR, resolve conflicts, rebase/update from the target branch, and self-merge/close an ordinary PR when checks pass and the task boundary is satisfied.",
"- You may use repo-owned CI/CD, publish, or equivalent controlled build paths to build/publish DEV images or artifacts, and must report commit, image tag, digest, artifact report, and validation evidence.",
"- DEV deploy apply, rollout, and live health verification are owned by the host commander unless this prompt explicitly contains ROLLOUT_OK.",
"- Without explicit ROLLOUT_OK, do not acquire the DEV CD lock, run deploy apply, perform rollout/restart, or compete with host commander live verification.",
"- Forbidden: PROD mutation, reading or printing secrets, manual database writes, destructive rollback, Code Queue backend/scheduler restart, or interrupt/cancel running tasks unless explicitly authorized.",
].join("\n");
function hasFlag(args: string[], flag: string): boolean {
return args.includes(flag);
}
function optionValue(args: string[], names: string[]): string | undefined {
for (const name of names) {
const index = args.indexOf(name);
if (index === -1) continue;
const value = args[index + 1];
if (value === undefined || value.startsWith("--")) throw new Error(`${name} requires a value`);
return value;
}
return undefined;
}
function assertKnownOptions(args: string[]): void {
const flags = new Set(["--stdin"]);
const valueOptions = new Set(["--kind", "--prompt-file", "--file"]);
for (let index = 0; index < args.length; index += 1) {
const arg = args[index] ?? "";
if (!arg.startsWith("--")) throw new Error(`commander prompt-lint does not accept positional prompt text; use --stdin or --prompt-file`);
if (flags.has(arg)) continue;
if (valueOptions.has(arg)) {
index += 1;
if (index >= args.length) throw new Error(`${arg} requires a value`);
continue;
}
throw new Error(`unknown commander prompt-lint option: ${arg}`);
}
}
function parseKind(raw: string | undefined): CommanderPromptLintKind {
const kind = raw ?? "gpt55-pr";
if (kind !== "gpt55-pr") throw new Error(`unsupported commander prompt-lint kind: ${kind}`);
return kind;
}
function readPromptFromArgs(args: string[]): string {
const promptFile = optionValue(args, ["--prompt-file", "--file"]);
const promptStdin = hasFlag(args, "--stdin");
const sources = [promptFile !== undefined, promptStdin].filter(Boolean).length;
if (sources !== 1) throw new Error("commander prompt-lint requires exactly one prompt source: --prompt-file or --stdin");
const prompt = promptFile !== undefined
? (promptFile === "-" ? readFileSync(0, "utf8") : readFileSync(promptFile, "utf8"))
: readFileSync(0, "utf8");
if (prompt.trim().length === 0) throw new Error("commander prompt-lint prompt must not be empty");
return prompt;
}
export function parseCommanderPromptLintArgs(args: string[]): ParsedPromptLintArgs {
assertKnownOptions(args);
return {
kind: parseKind(optionValue(args, ["--kind"])),
prompt: readPromptFromArgs(args),
};
}
function any(patterns: RegExp[], prompt: string): boolean {
return patterns.some((pattern) => pattern.test(prompt));
}
function rolloutOkPresent(prompt: string): boolean {
return /\bROLLOUT_OK\b/u.test(prompt);
}
function gpt55PrClauseChecks(prompt: string): ClauseCheck[] {
const prAuthorization = any([
/\bPR\b[^\n]{0,120}(?:create|update|push|branch|merge|close|rebase|conflict)/iu,
/(?:||push||||rebase|)[^\n]{0,80}\bPR\b/iu,
], prompt) && any([
/self[- ]?(?:merge|close)|(?:||)||/iu,
/merge\/close|\//iu,
], prompt) && any([
/\brebase\b|\bupdate\b||(?:|base|master|)/iu,
], prompt);
const artifactAuthorization = any([
/\b(?:build|publish)\b[^\n]{0,80}\b(?:artifact|image|DEV image||)\b/iu,
/\b(?:artifact|image||)\b[^\n]{0,80}\b(?:build|publish|tag|digest||)\b/iu,
/(?:|)[^\n]{0,80}(?:||artifact|image)/iu,
], prompt) && any([
/\b(?:tag|digest|artifact report|image tag)\b/iu,
/(?:\s*tag|digest||artifact report)/iu,
], prompt);
const hostOwnsDevRollout = any([
/DEV[^\n]{0,120}(?:deploy apply|rollout|live health|live verification)[^\n]{0,120}(?:host commander|commander|host|||)/iu,
/(?:host commander|commander|host|)[^\n]{0,120}DEV[^\n]{0,120}(?:deploy apply|rollout|live health|live verification||线|)/iu,
/DEV[^\n]{0,80}(?:|线|rollout|)[^\n]{0,80}(?:host|commander||)/iu,
], prompt);
const forbidsRunnerRolloutUnlessOk = any([
/unless[^\n]{0,80}\bROLLOUT_OK\b/iu,
/[^\n]{0,60}\bROLLOUT_OK\b[^\n]{0,80}(?:|||do not|don't|must not)/iu,
/\bROLLOUT_OK\b[^\n]{0,80}(?:|unless|only if|explicit)/iu,
], prompt) && any([
/(?:do not|don't|must not|||)[^\n]{0,100}(?:DEV CD lock|deploy apply|rollout|live health|rollout restart||)/iu,
/(?:DEV CD lock|deploy apply|rollout|live health|rollout restart||)[^\n]{0,100}(?:do not|don't|must not|||)/iu,
], prompt);
const prodForbidden = any([
/(?:|||must not|do not|don't|\bno\b|forbid|forbidden)[^\n]{0,80}(?:PROD|prod|production|)/iu,
/(?:PROD|prod|production|)[^\n]{0,80}(?:|||must not|do not|don't|\bno\b|forbid|forbidden|not allowed)/iu,
], prompt);
const secretForbidden = any([
/(?:|||must not|do not|don't|\bno\b|forbid|forbidden)[^\n]{0,80}(?:secret|token|credential||)/iu,
/(?:secret|token|credential||)[^\n]{0,80}(?:|||must not|do not|don't|\bno\b|forbid|forbidden|not allowed||)/iu,
], prompt);
const dbForbidden = any([
/(?:|||must not|do not|don't|\bno\b|forbid|forbidden)[^\n]{0,80}(?:database|DB|)/iu,
/(?:database|DB|)[^\n]{0,80}(?:manual||patch|write|||||must not|do not|don't|\bno\b)/iu,
], prompt);
const rollbackForbidden = any([
/(?:|||must not|do not|don't|\bno\b|forbid|forbidden)[^\n]{0,80}(?:destructive rollback||)/iu,
/(?:destructive rollback|)[^\n]{0,80}(?:|||must not|do not|don't|\bno\b|forbid|forbidden|not allowed)/iu,
], prompt);
return [
{
id: "pr-self-merge-rebase-authorization",
label: "PR/自合并/rebase/update 授权文本",
required: true,
matched: prAuthorization,
severity: "high",
suggestion: "明确授权 runner 创建/更新 PR、rebase/update/解决冲突,并在普通 PR 满足任务边界和检查通过时自合并/关闭。",
},
{
id: "artifact-build-publish-authorization",
label: "build/publish artifact 授权文本",
required: true,
matched: artifactAuthorization,
severity: "high",
suggestion: "明确授权使用 repo-owned CI/CD 或受控构建路径发布 DEV image/artifact,并要求回报 tag、digest 和 artifact report。",
},
{
id: "host-owned-dev-rollout",
label: "DEV deploy apply/rollout/live verification 由 host 统一执行文本",
required: true,
matched: hostOwnsDevRollout,
severity: "high",
suggestion: "写明 DEV deploy apply、rollout 和 live health verification 默认由 host commander 统一执行。",
},
{
id: "runner-rollout-forbidden-without-rollout-ok",
label: "未显式 ROLLOUT_OK 时禁止 runner rollout",
required: true,
matched: forbidsRunnerRolloutUnlessOk,
severity: "high",
suggestion: "写明未显式包含 ROLLOUT_OK 时,runner 不得抢 DEV CD lock、deploy apply、rollout 或 live verification。",
},
{
id: "prod-secret-db-rollback-boundary",
label: "PROD/secret/DB/破坏性回滚边界",
required: true,
matched: prodForbidden && secretForbidden && dbForbidden && rollbackForbidden,
severity: "high",
suggestion: "同时禁止 PROD mutation、密钥读取/打印、数据库手工写入和破坏性回滚。",
},
];
}
export function lintCommanderPrompt(prompt: string, kind: CommanderPromptLintKind = "gpt55-pr"): CommanderPromptLintResult {
const clauses = gpt55PrClauseChecks(prompt);
const missingClauses = clauses.filter((clause) => clause.required && !clause.matched).map((clause) => clause.id);
const highMissing = clauses.some((clause) => clause.severity === "high" && !clause.matched);
const rolloutOk = rolloutOkPresent(prompt);
const riskLevel: CommanderPromptLintRiskLevel = missingClauses.length === 0
? rolloutOk ? "medium" : "low"
: highMissing ? "high" : "medium";
return {
ok: missingClauses.length === 0,
kind,
missingClauses,
riskLevel,
suggestedPatchSnippet: missingClauses.length === 0 ? "" : gpt55PrSnippet,
promptShape: {
chars: prompt.length,
lines: prompt.split(/\r\n|\r|\n/u).length,
textEchoed: false,
},
policy: {
advisoryOnly: true,
mutatesScheduler: false,
changesCodexSubmitDefault: false,
printsPromptText: false,
supportedInputs: ["--stdin", "--prompt-file"],
reference: "docs/reference/host-codex-commander.md",
},
};
}
export function runCommanderPromptLintCommand(args: string[]): CommanderPromptLintResult {
const options = parseCommanderPromptLintArgs(args);
return lintCommanderPrompt(options.prompt, options.kind);
}
+3 -7
View File
@@ -1,7 +1,6 @@
import { buildCommanderApprovalNotificationDraft, commanderApprovalNotificationPathUnavailable } from "../../src/components/microservices/host-codex-commander/src/approval-notification";
import { commanderContract as hostCommanderContract, commanderHighRiskActions as highRiskActions } from "../../src/components/microservices/host-codex-commander/src/contract";
import { redactText } from "../../src/components/microservices/host-codex-commander/src/redaction";
import { runCommanderPromptLintCommand } from "./commander-prompt-lint";
const requiredDryRunMessage = "This host Codex commander skeleton only supports dry-run planning; live daemon/control operations are not implemented.";
@@ -37,7 +36,6 @@ function commanderHelp(): Record<string, unknown> {
"bun scripts/cli.ts commander plan --dry-run [--session-id id]",
"bun scripts/cli.ts commander smoke --dry-run [--session-id id]",
"bun scripts/cli.ts commander approval request --action <action> --dry-run [--reason text] [--task-id id]",
"bun scripts/cli.ts commander prompt-lint --kind gpt55-pr (--prompt-file <file>|--stdin)",
],
highRiskActions,
reference: "docs/reference/host-codex-commander.md",
@@ -264,7 +262,7 @@ function healthEndpointValidation(): Record<string, unknown> {
return {
surface: "health endpoint",
endpoint: "GET /health",
validationMethod: "invoke createCommanderRequestHandler with a temporary RuntimeConfig inside a short-lived contract test",
validationMethod: "invoke createCommanderRequestHandler with a temporary RuntimeConfig during dry-run/manual inspection",
expectedEvidence: [
"body.ok=true",
"body.service=host-codex-commander",
@@ -283,7 +281,7 @@ function stateFileValidation(sessionId: string): Record<string, unknown> {
return {
surface: "state file",
storageRoot: ".state/commander/",
validationMethod: "write and read a session record only under a temporary directory owned by the contract test",
validationMethod: "write and read a session record only under a temporary directory during dry-run/manual inspection",
files: [
`sessions/${sessionId}.json`,
`events/${sessionId}.jsonl`,
@@ -402,7 +400,6 @@ function commanderSmoke(args: string[]): Record<string, unknown> {
"bun scripts/cli.ts commander plan --dry-run",
"bun scripts/cli.ts commander smoke --dry-run",
"bun scripts/cli.ts commander approval request --action <action> --dry-run",
"bun scripts/host-codex-commander-no-daemon-smoke-contract-test.ts",
],
},
validationPlan: [
@@ -414,7 +411,7 @@ function commanderSmoke(args: string[]): Record<string, unknown> {
],
manualAuthorizationBeforeLiveRuntime: [
"operator explicitly names the exact live action and target session/task/service",
"current source-contract smoke and skeleton contract tests are green",
"current dry-run smoke plan and source inspection are acceptable",
"risk review confirms no token output, no direct database patch, and no backend restart bypass",
"ClaudeQQ approval draft is reviewed, any authorized send uses backend-core /api/microservices/claudeqq/proxy, and the reply is matched to an explicit approval id",
"rollback and observation steps are written before enabling any daemon or bridge",
@@ -497,7 +494,6 @@ export function runCommanderCommand(args: string[]): Record<string, unknown> {
if (sub === "plan") return commanderPlan(args.slice(1));
if (sub === "smoke") return commanderSmoke(args.slice(1));
if (sub === "approval" && second === "request") return commanderApprovalRequest(args.slice(2));
if (sub === "prompt-lint") return runCommanderPromptLintCommand(args.slice(1)) as unknown as Record<string, unknown>;
return {
ok: false,
error: "unsupported-command",
+4 -23
View File
@@ -54,7 +54,7 @@ export function rootHelp(): unknown {
{ command: "artifact-registry plan|render|status|health|install|deploy-backend-core|deploy-service", description: "Manage the D601 host-managed CNCF Distribution registry and run pull-only artifact CD for supported services, including D601 direct, k3s-managed, and code-queue dev-only consumers." },
{ command: "auth-broker contract|health --dry-run|credential-request --dry-run|pr-preflight --dry-run", description: "Inspect the P0 Rust auth broker and CLI adapter contract without reading token values, writing GitHub, or starting services." },
{ command: "gh preflight|auth|issue|pr", description: "Run safe GitHub issue and PR CRUD/lifecycle operations through REST with body-file update replace/append, comment delete, token diagnostics, PR closeout preflight, hard delete unsupported, and guarded PR merge." },
{ command: "commander contract|plan --dry-run|smoke --dry-run|approval request --dry-run|prompt-lint --kind gpt55-pr", description: "Host Codex commander skeleton contract, no-daemon smoke plan, dry-run approval preview, and advisory GPT-5.5 PR prompt boundary lint without live bridges, message sends, or submit gating." },
{ command: "commander contract|plan --dry-run|smoke --dry-run|approval request --dry-run", description: "Host Codex commander skeleton contract, no-daemon smoke plan, and dry-run approval preview without live bridges or message sends." },
{ command: "hwlab nodes control-plane|git-mirror|secret --node G14 --lane v03", description: "Manage HWLAB node/lane runtime prerequisites for v0.3+ with the node identity passed as data instead of a command family." },
{ command: "hwlab g14 monitor-prs | hwlab g14 control-plane status|apply|trigger-current|runtime-migration|cleanup-runs|cleanup-released-pvs | hwlab g14 git-mirror status|apply|sync|flush | hwlab g14 tools-image status|build", description: "Start the legacy G14 PR monitor, run bounded v0.2 Tekton/Argo control-plane, manual PipelineRun trigger, runtime migration, CI workspace retention, manual devops-infra git mirror/relay maintenance, or fixed HWLAB CI tools image actions; long confirmed trigger/sync/flush actions return async jobs by default." },
{ command: "agentrun get|describe|events|logs|result|ack|cancel|dispatch|create|apply|steer|send|control-plane|git-mirror", description: "Use AgentRun v0.1 resource primitives with low-noise human output by default; legacy bridge groups remain available for raw compatibility." },
@@ -64,7 +64,6 @@ export function rootHelp(): unknown {
{ command: "schedule list|get|runs|run|retry-run|delete", description: "Manage backend-core scheduled tasks and run history; schedule run <id> supports --wait-ms N and retry-run reuses the failed run's schedule." },
{ command: "schedule upsert-pgdata-backup [--time HH:MM] [--remote-base /SERVER_DATA/UNIDESK_PG_DATA]", description: "Create or update the daily PGDATA physical backup task that uploads monthly rotated archives to Baidu Netdisk." },
{ command: "codex deploy <commitId> [--provider-id D601] [--timeout-ms N]", description: "Disabled legacy Code Queue deploy path; use the dev-only artifact consumer instead." },
{ command: "codex prompt-lint [prompt|--prompt-file path|--prompt-stdin]", description: "Dry-run lint a runner prompt for DEV test class read-only/live-read/live-mutating authorization without echoing prompt text or touching live services." },
{ command: "codex submit|steer|resume|queue create|queue merge|move", description: "Frozen legacy Code Queue write commands; use agentrun create/apply/steer/send for new commander work. Historical codex task/tasks/output/read/unread/queues remain available for archive troubleshooting." },
{ command: "codex skills-sync --dry-run [--full]", description: "Inspect the controlled runner skills hostPath lifecycle contract without copying files, restarting services, reading secrets, or mutating live runner paths." },
{ command: "codex execution-plane [--full|--raw]", description: "Read-only D601 native k3s Code Queue execution-plane inspection; compares formal deployments, deprecated Compose residuals, commit markers, pod digest, and mounted worktree HEAD." },
@@ -331,31 +330,22 @@ function gcHelp(): unknown {
function commanderHelp(): unknown {
return {
command: "commander contract|plan|smoke|approval|prompt-lint",
command: "commander contract|plan|smoke|approval",
output: "json",
usage: [
"bun scripts/cli.ts commander contract",
"bun scripts/cli.ts commander plan --dry-run [--session-id id]",
"bun scripts/cli.ts commander smoke --dry-run [--session-id id]",
"bun scripts/cli.ts commander approval request --action <action> --dry-run [--reason text] [--task-id id]",
"bun scripts/cli.ts commander prompt-lint --kind gpt55-pr (--prompt-file <file>|--stdin)",
],
description: "Inspect the local host Codex commander skeleton contract, dry-run planner, no-daemon smoke validation plan, state helpers, trace summary aggregator, approval draft preview, and advisory GPT-5.5 PR prompt boundary lint.",
description: "Inspect the local host Codex commander skeleton contract, dry-run planner, no-daemon smoke validation plan, state helpers, trace summary aggregator, and approval draft preview.",
boundary: [
"the current skeleton is local-only and never attaches to live bridges",
"dry-run commands never open SSH, PTY, or stdio bridges",
"high-risk actions only produce a <=200 char Chinese ClaudeQQ approval draft and notification-path-unavailable blocker",
"authorized future sends must use backend-core /api/microservices/claudeqq/proxy, not local skill or powershell paths",
"prompt-lint is commander advisory output for AgentRun payload review; legacy codex submit is frozen",
"token and secret values must never be printed",
],
promptLint: {
command: "bun scripts/cli.ts commander prompt-lint --kind gpt55-pr --prompt-file <path>",
stdin: "cat prompt.md | bun scripts/cli.ts commander prompt-lint --kind gpt55-pr --stdin",
outputFields: ["ok", "missingClauses", "riskLevel", "suggestedPatchSnippet"],
fullPromptEchoed: false,
gate: "advisory-only; not a business PR gate and not a Code Queue submit admission change",
},
reference: "docs/reference/host-codex-commander.md",
};
}
@@ -380,11 +370,10 @@ function scheduleHelp(): unknown {
function codexHelp(): unknown {
return {
command: "codex deploy|prompt-lint|submit|task|tasks|unread|output|read|dev-ready|skills-sync|execution-plane|pr-preflight|judge|steer|resume|interrupt|cancel|queues|queue|move",
command: "codex deploy|submit|task|tasks|unread|output|read|dev-ready|skills-sync|execution-plane|pr-preflight|judge|steer|resume|interrupt|cancel|queues|queue|move",
output: "json",
usage: [
"bun scripts/cli.ts codex deploy <commitId> # disabled legacy deployment entry",
"bun scripts/cli.ts codex prompt-lint [prompt|--prompt-file path|--prompt-stdin]",
"bun scripts/cli.ts agentrun get tasks --queue commander --limit 20",
"bun scripts/cli.ts agentrun describe aipodspec/Artificer",
"bun scripts/cli.ts agentrun create task --aipod Artificer --prompt-stdin",
@@ -452,7 +441,6 @@ function codexHelp(): unknown {
blockers: ["deployment-drift", "deprecated-compose-residual", "d601-k3s-guard-blocked"],
},
examples: {
promptLint: "bun scripts/cli.ts codex prompt-lint --prompt-file /tmp/code-queue-prompt.md",
agentRunCommander: "bun scripts/cli.ts agentrun get tasks --queue commander --limit 20",
agentRunAipod: "bun scripts/cli.ts agentrun create task --aipod Artificer --prompt-stdin",
agentRunSubmit: "bun scripts/cli.ts agentrun apply -f - --dry-run",
@@ -475,13 +463,6 @@ function codexHelp(): unknown {
redline: "data.supervisor.activeRunning.redline names the count field, routine target, burst redline, hard redline, and decisionReady flag.",
limitSemantics: "filters.requestedLimit preserves the user input; filters.limit/effectiveLimit shows the capped query budget; section outputBudget/rowPage show returned-row caps.",
},
promptLiveAuthorization: {
classes: ["read-only", "live-read", "live-mutating"],
defaultWhenMissing: "read-only",
command: "bun scripts/cli.ts codex prompt-lint --prompt-file <path>",
embeddedIn: [],
reference: "docs/reference/code-queue-supervision.md#dev-测试授权分级",
},
description: "Operate legacy Code Queue as a read-only archive through bounded task/output/read/unread/queues views. New task dispatch, retry/resume, steer, queue mutation, move, and workdir mutation are frozen and replaced by AgentRun resource primitives via bun scripts/cli.ts agentrun get|describe|events|logs|result|ack|cancel|dispatch|create|apply|steer|send.",
};
}