import type { UniDeskConfig } from "../config"; import type { RenderedCliResult } from "../output"; import { readCodexPoolConfig } from "./config"; import { boolField, compactCapture, parseJsonOutput, runRemoteCodexPoolScript } from "./remote"; import { profitScript } from "./remote-scripts"; import { codexPoolRuntimeTarget, defaultCodexPoolRuntimeTargetId } from "./runtime-target"; interface ProfitOptions { since: string; targetId: string; json: boolean; accounts: boolean; missingCosts: boolean; pageToken: string | null; } const PROFIT_ACCOUNT_PAGE_SIZE = 8; export async function codexPoolProfit(config: UniDeskConfig, args: string[]): Promise | RenderedCliResult> { const pool = readCodexPoolConfig(); if (args.includes("--help")) return renderProfitHelp(pool.profit.defaultWindow); const options = parseProfitOptions(args, pool.profit.defaultWindow); const target = codexPoolRuntimeTarget(options.targetId); const payload = { since: options.since, config: pool.profit }; const remote = await runRemoteCodexPoolScript(config, "profit", profitScript(payload, pool, target), target); const report = parseJsonOutput(remote.stdout); const ok = remote.exitCode === 0 && boolField(report, "ok", false); const projectedReport = projectProfitReport(report, options); const baseCommand = `bun scripts/cli.ts platform-infra sub2api codex-pool profit --target ${target.id} --since ${options.since}`; const accountPage = record(record(projectedReport).accountPage); const response = { ok, action: "platform-infra-sub2api-codex-pool-profit", target: { id: target.id, route: target.route, runtimeMode: target.runtimeMode, endpoint: target.serviceDns }, source: { kind: "sub2api-native-admin-usage", mutation: false, configPath: "config/platform-infra/sub2api-codex-pool.yaml#profit", }, report: projectedReport, disclosure: { accountsIncluded: options.accounts, missingCostsIncluded: options.missingCosts, accountCount: arrayOfRecords(record(report).accounts).length, accounts: `${baseCommand} --accounts`, accountsNext: accountPage.nextPageToken ? `${baseCommand} --accounts --page-token ${text(accountPage.nextPageToken)}` : null, missingCosts: `${baseCommand} --missing-costs`, json: `${baseCommand} --json`, }, remote: compactCapture(remote, { full: !ok || report === null }), valuesPrinted: false, }; return options.json ? renderProfitJson(response) : renderProfit(response); } function parseProfitOptions(args: string[], defaultWindow: string): ProfitOptions { let since = defaultWindow; let targetId = defaultCodexPoolRuntimeTargetId(); let json = false; let accounts = false; let missingCosts = false; let pageToken: string | null = null; const readValue = (index: number, option: string): [string, number] => { const value = args[index + 1]; if (value === undefined || value.startsWith("--")) throw new Error(`${option} requires a value`); return [value.trim(), index + 1]; }; for (let index = 0; index < args.length; index += 1) { const arg = args[index]!; if (arg === "--json") json = true; else if (arg === "--accounts") accounts = true; else if (arg === "--missing-costs") missingCosts = true; else if (arg === "--page-token") { [pageToken, index] = readValue(index, "--page-token"); } else if (arg.startsWith("--page-token=")) pageToken = arg.slice("--page-token=".length).trim(); else if (arg === "--since") { [since, index] = readValue(index, "--since"); } else if (arg.startsWith("--since=")) since = arg.slice("--since=".length).trim(); else if (arg === "--target") { [targetId, index] = readValue(index, "--target"); } else if (arg.startsWith("--target=")) targetId = arg.slice("--target=".length).trim(); else throw new Error(`unsupported profit option: ${arg}`); } if (!/^[1-9][0-9]*(?:s|m|h|d)$/u.test(since)) throw new Error("--since must be a duration such as 24h, 90m, or 7d"); if (!targetId || /[\r\n\0]/u.test(targetId)) throw new Error("--target has an unsupported format"); if (accounts && missingCosts) throw new Error("--accounts and --missing-costs are separate semantic disclosures"); if (pageToken !== null && !accounts) throw new Error("--page-token requires --accounts"); if (pageToken !== null && (!pageToken || /[\r\n\0\s]/u.test(pageToken))) throw new Error("--page-token has an unsupported format"); return { since, targetId, json, accounts, missingCosts, pageToken }; } function renderProfitHelp(defaultWindow: string): RenderedCliResult { return { ok: true, command: "platform-infra sub2api codex-pool profit --help", renderedText: [ "SUB2API CODEX-POOL PROFIT", "Usage:", " bun scripts/cli.ts platform-infra sub2api codex-pool profit [--since 24h] [--target PK01] [--accounts [--page-token ]|--missing-costs] [--json]", "Options:", ` --since Native usage window; YAML default is ${defaultWindow}.`, " --target ", " --accounts Include one fixed-size account page with complete names and IDs.", " --page-token Continue after the account ID returned by the previous page.", " --missing-costs Include the missing-cost account list and API USD bases.", " --json Emit exact structured values.", "Notes:", " Default output is a compact summary; use --accounts or --missing-costs for semantic disclosure.", " This command is read-only and does not change Sub2API runtime state.", ].join("\n"), contentType: "text/plain", }; } function renderProfit(response: Record): RenderedCliResult { const report = record(response.report); const window = record(report.window); const policy = record(report.policy); const summary = record(report.summary); const completeness = record(report.completeness); const confirmedCosts = record(summary.confirmedCostsCny); const confirmedProfit = record(summary.confirmedProfitCny); const unknownBasis = record(summary.unknownCostBasisApiUsd); const formulas = record(summary.profitFormula); const disclosure = record(response.disclosure); const lines = [ `SUB2API PROFIT status=${text(report.status)} target=${text(record(response.target).id)} window=${text(window.since)}`, `WINDOW ${text(window.startAt)} -> ${text(window.endAt)} SOURCE native-admin-usage/${text(record(report.source).usageCostField)}`, `POLICY sale-rate=${text(policy.saleRateCnyPerApiUsd)}CNY/API_USD account-cost=${text(policy.accountCostSource)}`, "", "SUMMARY", ]; lines.push(table( ["SCOPE", "STATUS", "REVENUE_CNY", "PROFIT_POOL_COST_CNY", "SELF_USE_COST_CNY", "CONFIRMED_PROFIT_CNY", "UNKNOWN_API_USD"], [ ["不扣自用", text(record(summary.withoutSelfUse).status), cny(summary.revenueCny), cny(confirmedCosts.profitPool), "-", cny(confirmedProfit.withoutSelfUse), apiUsd(unknownBasis.profitPool)], ["扣除自用", text(record(summary.withSelfUse).status), cny(summary.revenueCny), cny(confirmedCosts.profitPool), cny(confirmedCosts.selfUse), cny(confirmedProfit.withSelfUse), apiUsd(unknownBasis.total)], ], )); lines.push("", "FORMULA"); lines.push(`- 不扣自用: ${text(formulas.withoutSelfUse)}`); lines.push(`- 扣除自用: ${text(formulas.withSelfUse)}`); lines.push("", `COMPLETENESS status=${text(report.status)} missing-cost=${text(completeness.missingCostAccountCount)} unclassified=${text(completeness.unclassifiedTrafficCount)} missing-groups=${text(completeness.configuredGroupMissingCount)}`); lines.push(`NEXT accounts: ${text(disclosure.accounts)}`); lines.push(`NEXT missing-costs: ${text(disclosure.missingCosts)}`); const accounts = arrayOfRecords(report.accounts); if (accounts.length > 0) { lines.push("", "ACCOUNTS"); lines.push(table( ["GROUP", "CLASS", "ACCOUNT", "ID", "REQ", "TOKENS", "API_USD", "COST_CNY/USD", "REVENUE_CNY", "UPSTREAM_CNY", "PROFIT_CNY", "STATUS"], accounts.map((row) => [ text(row.groupName), text(row.class), text(row.accountName), text(row.accountId), text(row.requestCount), compactTokens(row.tokenCount), apiUsd(row.apiAmountUsd), text(row.costRateCnyPerApiUsd), cny(row.revenueCny), cny(row.upstreamCostCny), cny(row.profitContributionCny), text(row.completeness), ]), )); const accountPage = record(report.accountPage); if (accountPage.nextPageToken) lines.push(`NEXT account-page: ${text(disclosure.accountsNext)}`); } const missingCosts = arrayOfRecords(completeness.missingCostAccounts); if (missingCosts.length > 0) { lines.push("", "MISSING COST ACCOUNTS"); for (const row of missingCosts) lines.push(`- class=${text(row.class)} group=${text(row.groupName)} account=${text(row.accountName)} id=${text(row.accountId)} api-usd=${text(row.apiAmountUsd)}`); } if (accounts.length > 0 || missingCosts.length > 0) { const unclassified = arrayOfRecords(completeness.unclassifiedTraffic); const missingGroups = Array.isArray(completeness.configuredGroupsMissingAtRuntime) ? completeness.configuredGroupsMissingAtRuntime : []; if (unclassified.length || missingGroups.length) { lines.push("", "COMPLETENESS DETAILS"); for (const row of unclassified) lines.push(`- unclassified-traffic group=${text(row.groupName)} account=${text(row.accountName)} requests=${text(row.requestCount)}`); for (const group of missingGroups) lines.push(`- configured-group-missing ${text(group)}`); } } return { ok: response.ok === true, command: "platform-infra sub2api codex-pool profit", renderedText: lines.join("\n"), contentType: "text/plain", projection: response, }; } function projectProfitReport(report: Record | null, options: ProfitOptions): Record | null { if (report === null) return null; const { accounts: rawAccounts, completeness: rawCompleteness, ...summaryReport } = report; const accounts = arrayOfRecords(rawAccounts); const completeness = record(rawCompleteness); const compactCompleteness = { missingCostAccountCount: arrayOfRecords(completeness.missingCostAccounts).length, unclassifiedTrafficCount: arrayOfRecords(completeness.unclassifiedTraffic).length, configuredGroupMissingCount: Array.isArray(completeness.configuredGroupsMissingAtRuntime) ? completeness.configuredGroupsMissingAtRuntime.length : 0, }; const compactReport = { ...summaryReport, accountCount: accounts.length, completeness: compactCompleteness, }; if (options.missingCosts) { return { ...compactReport, completeness: { ...compactCompleteness, missingCostAccounts: arrayOfRecords(completeness.missingCostAccounts), }, }; } if (!options.accounts) return compactReport; let startIndex = 0; if (options.pageToken !== null) { const tokenIndex = accounts.findIndex((row) => text(row.accountId) === options.pageToken); if (tokenIndex < 0) throw new Error(`profit account page token not found: ${options.pageToken}`); startIndex = tokenIndex + 1; } const pageAccounts = accounts.slice(startIndex, startIndex + PROFIT_ACCOUNT_PAGE_SIZE); const hasNext = startIndex + pageAccounts.length < accounts.length; const nextPageToken = hasNext ? text(pageAccounts.at(-1)?.accountId) : null; return { ...compactReport, accounts: pageAccounts, accountPage: { pageSize: PROFIT_ACCOUNT_PAGE_SIZE, returned: pageAccounts.length, nextPageToken, }, }; } function renderProfitJson(response: Record): RenderedCliResult { return { ok: response.ok === true, command: "platform-infra sub2api codex-pool profit --json", renderedText: JSON.stringify(response), contentType: "application/json", projection: response, }; } function record(value: unknown): Record { return typeof value === "object" && value !== null && !Array.isArray(value) ? value as Record : {}; } function arrayOfRecords(value: unknown): Record[] { return Array.isArray(value) ? value.filter((item): item is Record => typeof item === "object" && item !== null && !Array.isArray(item)) : []; } function text(value: unknown): string { if (value === null || value === undefined || value === "") return "-"; return String(value).replace(/[\r\n\t]+/gu, " "); } function compactTokens(value: unknown): string { const numeric = Number(value); if (!Number.isFinite(numeric)) return text(value); if (Math.abs(numeric) >= 1_000_000_000) return `${(numeric / 1_000_000_000).toFixed(3)}B`; if (Math.abs(numeric) >= 1_000_000) return `${(numeric / 1_000_000).toFixed(3)}M`; if (Math.abs(numeric) >= 1_000) return `${(numeric / 1_000).toFixed(3)}K`; return String(numeric); } function apiUsd(value: unknown): string { if (value === null || value === undefined || value === "") return "-"; const numeric = Number(value); return Number.isFinite(numeric) ? `$${numeric.toFixed(6)}` : text(value); } function cny(value: unknown): string { if (value === null || value === undefined || value === "") return "-"; const numeric = Number(value); return Number.isFinite(numeric) ? `¥${numeric.toFixed(6)}` : text(value); } function table(headers: string[], rows: string[][]): string { if (rows.length === 0) return `${headers.join(" ")}\n-`; const widths = headers.map((header, index) => Math.max(header.length, ...rows.map((row) => (row[index] ?? "").length))); return [headers, ...rows].map((row) => row.map((cell, index) => cell.padEnd(widths[index]!)).join(" ").trimEnd()).join("\n"); }