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
+22 -31
View File
@@ -1314,41 +1314,23 @@ async function sendClaudeQqEndpoint(config: ClaudeQqConfig, endpoint: string, pa
method: "POST",
body: payload,
maxResponseBytes: 240_000,
timeoutMs: config.timeoutMs,
});
if (claudeQqResponseOk(response)) return { ok: true, endpoint, status: isRecord(response) && typeof response.status === "number" ? response.status : 200, response };
return summarizeClaudeQqProxyFailure(response, endpoint);
}
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), config.timeoutMs);
try {
const response = await fetch(normalizeClaudeQqEndpoint(config.baseUrl, endpoint), {
method: "POST",
signal: controller.signal,
headers: { "Content-Type": "application/json", Accept: "application/json" },
body: JSON.stringify(payload),
});
const parsed = await parseGitHubResponse(response);
const bodyFailed = isRecord(parsed) && (parsed.ok === false || parsed.success === false);
if (response.ok && !bodyFailed) return { ok: true, endpoint, status: response.status, response: parsed };
return {
ok: false,
endpoint,
status: response.status,
degradedReason: bodyFailed ? "upstream-rejected" : "http-failed",
message: isRecord(parsed) && typeof parsed.error === "string" ? parsed.error : response.statusText,
response: sanitizedErrorDetails(parsed),
};
} catch (error) {
return {
ok: false,
endpoint,
degradedReason: "network-proxy-failed",
message: error instanceof Error ? error.message : String(error),
};
} finally {
clearTimeout(timeout);
}
return {
ok: false,
endpoint,
degradedReason: "notification-path-unavailable",
message: "ClaudeQQ notifications must use backend-core /api/microservices/claudeqq/proxy; local skill, powershell, direct host, and ad-hoc ClaudeQQ URLs are not supported.",
response: {
baseUrl: sanitizeUrlForOutput(config.baseUrl),
requiredBaseUrl: DEFAULT_COMMANDER_BRIEF_CLAUDEQQ_BASE_URL,
recommendedCommand: "bun scripts/cli.ts microservice proxy claudeqq /api/push/text --method POST --body-json '<payload>' --raw",
},
};
}
async function sendCommanderBriefClaudeQq(config: ClaudeQqConfig, message: string): Promise<ClaudeQqSendResult> {
@@ -1377,6 +1359,7 @@ async function sendCommanderBriefClaudeQq(config: ClaudeQqConfig, message: strin
}
function commanderBriefNotificationPlan(issueNumber: number, body: string, diff: CommanderBriefDiff, config: ClaudeQqConfig): Record<string, unknown> {
const proxyBasePath = proxiedClaudeQqBasePath(config.baseUrl);
return {
enabled: config.enabled,
issueNumber,
@@ -1395,10 +1378,18 @@ function commanderBriefNotificationPlan(issueNumber: number, body: string, diff:
},
claudeqq: {
dryRun: true,
wouldSend: config.enabled && diff.ok,
wouldSend: config.enabled && diff.ok && proxyBasePath !== null,
baseUrl: sanitizeUrlForOutput(config.baseUrl),
proxyBasePath,
servicePath: proxyBasePath === null ? null : normalizeClaudeQqEndpoint(proxyBasePath, "/api/push/text"),
target: maskedTarget(config),
timeoutMs: config.timeoutMs,
...(proxyBasePath === null
? {
blockedReason: "notification-path-unavailable",
recommendedCommand: "bun scripts/cli.ts microservice proxy claudeqq /api/push/text --method POST --body-json '<payload>' --raw",
}
: {}),
},
};
}