fix(commander): add ClaudeQQ approval proxy draft path (#134)

Co-authored-by: Codex <codex@noreply.local>
This commit is contained in:
Lyon
2026-05-23 19:22:07 +08:00
committed by GitHub
parent 431d6bd25b
commit 86f388722f
17 changed files with 424 additions and 80 deletions
+20 -22
View File
@@ -1,4 +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";
const requiredDryRunMessage = "This host Codex commander skeleton only supports dry-run planning; live daemon/control operations are not implemented.";
@@ -24,24 +26,6 @@ function isHighRiskAction(value: string): value is HighRiskAction {
return highRiskActions.some((action) => action === value);
}
function redactText(value: string): { text: string; redactionsApplied: number } {
let redactionsApplied = 0;
const patterns = [
/\b(?:sk|ghp|github_pat|xoxb|xoxp|AKIA)[A-Za-z0-9_=-]{8,}\b/g,
/\b(?:token|secret|password|passwd|authorization|cookie|api[_-]?key)\s*[:=]\s*[^,\s]+/gi,
/\bBearer\s+[A-Za-z0-9._~+/-]+=*\b/gi,
/https?:\/\/[^/\s]+:[^@\s]+@[^/\s]+/gi,
];
let text = value;
for (const pattern of patterns) {
text = text.replace(pattern, () => {
redactionsApplied += 1;
return "<redacted>";
});
}
return { text, redactionsApplied };
}
function commanderHelp(): Record<string, unknown> {
return {
command: "commander",
@@ -59,7 +43,7 @@ function commanderHelp(): Record<string, unknown> {
}
export function commanderContract(): Record<string, unknown> {
return hostCommanderContract();
return hostCommanderContract() as unknown as Record<string, unknown>;
}
function safetyBoundary(): Record<string, unknown> {
@@ -264,6 +248,9 @@ function commanderPlan(args: string[]): Record<string, unknown> {
claudeqqApproval: {
mutation: false,
commandShape: "bun scripts/cli.ts commander approval request --action <action> --dry-run",
dryRunDraft: "Chinese plain-text ClaudeQQ approval draft, <=200 chars, no Markdown",
liveSendBlockedBy: "notification-path-unavailable",
backendCoreProxyOnly: "bun scripts/cli.ts microservice proxy claudeqq /api/push/text --method POST --body-json '<payload>' --raw",
highRiskActions,
},
safetyBoundary: safetyBoundary(),
@@ -342,6 +329,9 @@ function approvalDraftValidation(): Record<string, unknown> {
"requiresExplicitUserApproval=true",
"claudeqq.mutation=false",
"claudeqq.sendImplemented=false",
"claudeqq.notificationDraft.message is <=200 Chinese chars and plain text",
"claudeqq.notificationPath.error=notification-path-unavailable",
"backend-core microservice proxy command is returned instead of a local skill/powershell command",
"reason and messageTemplate are redacted",
],
noRuntimeSideEffects: [
@@ -423,7 +413,7 @@ function commanderSmoke(args: string[]): Record<string, unknown> {
"operator explicitly names the exact live action and target session/task/service",
"current source-contract smoke and skeleton contract tests are green",
"risk review confirms no token output, no direct database patch, and no backend restart bypass",
"ClaudeQQ approval draft is reviewed, sent by an authorized future path, and matched to an explicit approval id",
"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",
],
};
@@ -458,6 +448,8 @@ function commanderApprovalRequest(args: string[]): Record<string, unknown> {
const rawReason = optionValue(args, "--reason") ?? "operator-supplied reason required before live execution";
const reason = redactText(rawReason);
const taskId = optionValue(args, "--task-id") ?? null;
const notificationDraft = buildCommanderApprovalNotificationDraft({ action, taskId, reason: rawReason });
const notificationPath = commanderApprovalNotificationPathUnavailable(notificationDraft.message);
return {
ok: true,
phase: "source-contract",
@@ -468,12 +460,18 @@ function commanderApprovalRequest(args: string[]): Record<string, unknown> {
reason: reason.text,
redactionsApplied: reason.redactionsApplied,
requiresExplicitUserApproval: true,
notificationDraft,
claudeqq: {
mutation: false,
endpointShape: "POST /api/microservices/claudeqq/proxy/api/push/text",
endpointShape: `POST ${notificationPath.servicePath}`,
fallbackEndpointShape: `POST ${notificationPath.fallbackServicePath}`,
target: "configured primary user private chat",
messageTemplate: `Approval required for ${action}. Reason: ${reason.text}. Reply with explicit approval id before execution.`,
messageTemplate: notificationDraft.message,
sendImplemented: false,
dryRunNoClaudeQqSend: true,
notificationDraft,
notificationPath,
noLocalSkillFallback: true,
},
approvalRecordShape: {
id: "commander-approval-<stable-id>",