nolo-cli 0.210.0-alpha.2 → 0.212.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{_executeModel-VVQEOY3D.js → _executeModel-KE6MBNUJ.js} +51 -48
- package/{action-U235TV4P.js → action-DF5UYSJF.js} +4 -4
- package/{addContentAction-7C76J7ST.js → addContentAction-N2YC5IL3.js} +8 -8
- package/{addDialogAgentAction-KTYANUEC.js → addDialogAgentAction-3NKVQCEC.js} +15 -12
- package/{agentDeleteCommand-WHRU6VDJ.js → agentDeleteCommand-NWK7VU4N.js} +71 -67
- package/{agentEmailCommands-ALLHXPW3.js → agentEmailCommands-UZ4DHEX2.js} +77 -72
- package/{agentListCommands-POKMEKMS.js → agentListCommands-HE7L2A6L.js} +190 -77
- package/{agentMachineCommands-WJLZLBPI.js → agentMachineCommands-6TE4MBMP.js} +30 -29
- package/{agentProviderCommands-MN3ABDME.js → agentProviderCommands-Q5O33MED.js} +33 -4
- package/{agentRecordCommands-OULZW3KM.js → agentRecordCommands-L3QQ7HZ4.js} +66 -61
- package/{agentRunCommand-ZNG4LGNQ.js → agentRunCommand-2IFGQHCO.js} +68 -64
- package/{agentRunControl-AF7BMR22.js → agentRunControl-OI3LOENH.js} +7 -6
- package/{agentRuntimeLocal-YMUHFV5M.js → agentRuntimeLocal-HL526DNQ.js} +28 -25
- package/{agentSlice-WNGUIMQZ.js → agentSlice-TMYP2UEA.js} +12 -12
- package/{appDeleteCommands-6MXPLAVF.js → appDeleteCommands-ZERW4AXY.js} +30 -29
- package/{appDeployCommands-ERRSVASW.js → appDeployCommands-DUWSMYHL.js} +30 -29
- package/{appDeployStatusCommands-ULICISLI.js → appDeployStatusCommands-N2KIE4BF.js} +30 -29
- package/{appGetCommands-WYYYWROF.js → appGetCommands-YVR4NPVY.js} +30 -29
- package/{appListCommands-DFCUCRCV.js → appListCommands-JS6HOHZS.js} +30 -29
- package/{authCommand-ZJMWXFMA.js → authCommand-FE2C3ZUM.js} +14 -14
- package/{authCommands-WK6E42L2.js → authCommands-HV3EAU3V.js} +2 -2
- package/{builtinSkillRegistry-HH75G5J3.js → builtinSkillRegistry-3YOIGEF6.js} +5 -4
- package/{chunk-JKW6LERJ.js → chunk-22CIEBYO.js} +14 -14
- package/{chunk-6HVBI6TI.js → chunk-25JZEIXN.js} +1 -218
- package/{chunk-TRZP7JZ7.js → chunk-2QHFH3DR.js} +1 -0
- package/{chunk-4LEGTOSR.js → chunk-3AKFVZ2I.js} +1 -1
- package/{chunk-XE4Q46FF.js → chunk-3CGG2PAL.js} +1 -1
- package/{chunk-25M2K6OA.js → chunk-3FOQHGHN.js} +3 -3
- package/{chunk-BSISWVB4.js → chunk-4I7ERB7F.js} +1 -1
- package/{chunk-TCTSYFDM.js → chunk-4KH4J3G5.js} +19 -6
- package/{chunk-NEZGPBL7.js → chunk-5AQR3DGV.js} +2 -2
- package/{chunk-YLTLB5A7.js → chunk-5RYBGBQH.js} +7 -6
- package/{chunk-RIALQUSF.js → chunk-6NSSLV67.js} +5 -5
- package/{chunk-RXCCWVA2.js → chunk-6OQUPIQF.js} +3 -3
- package/chunk-6VLJ6YA7.js +11751 -0
- package/{chunk-27E2CBBY.js → chunk-7OCO4TDT.js} +1 -1
- package/chunk-7RFNTILS.js +2213 -0
- package/{chunk-4WCEC56C.js → chunk-AVTVGMDY.js} +1 -1
- package/{chunk-3J3U3KXB.js → chunk-B7NJ3T4A.js} +4 -4
- package/{chunk-UMEGDH6A.js → chunk-BFM34N54.js} +7 -7
- package/chunk-CJEIOP3E.js +0 -0
- package/{chunk-YXOBCDNW.js → chunk-CJRONOYL.js} +5 -5
- package/{chunk-LT3EAHJY.js → chunk-CQ46IRNN.js} +38 -36
- package/{chunk-NTSRCTUX.js → chunk-CTPXME7U.js} +2 -2
- package/{chunk-M4NTDZG3.js → chunk-D5RCRX4A.js} +134 -141
- package/{chunk-25OB36GU.js → chunk-DM6UMOEL.js} +4 -4
- package/{chunk-TPCDYNJK.js → chunk-EYUBHHFB.js} +1 -1
- package/{chunk-Y6M7KJOA.js → chunk-EZFQ6XRV.js} +2 -2
- package/{chunk-ZOO3WJIE.js → chunk-FHU44LN3.js} +711 -40
- package/chunk-FY7F4Q6X.js +127 -0
- package/chunk-G7MLNNEX.js +84 -0
- package/{chunk-RYWO5AKN.js → chunk-GNDJKC4B.js} +10 -10
- package/{chunk-V3M6IXQI.js → chunk-GPO7FCEZ.js} +187 -36
- package/{chunk-RQ22OZD7.js → chunk-H2TJUNCH.js} +1 -1
- package/{chunk-C2XZM3K4.js → chunk-HIRC32DV.js} +5 -24
- package/{chunk-QQM464AL.js → chunk-HPFCI4SK.js} +3 -3
- package/chunk-HRMJUN5J.js +26 -0
- package/{chunk-HD3WR3TD.js → chunk-IAPCBNEE.js} +1 -1
- package/{chunk-XDMGY5IU.js → chunk-IF45XG7K.js} +220 -9
- package/{chunk-NLT32XBZ.js → chunk-IIQ6JGRI.js} +2 -2
- package/{chunk-OP7PTBAJ.js → chunk-IJXYFTV7.js} +8 -8
- package/{chunk-IIHY4ZAI.js → chunk-INSBKSBB.js} +8 -4
- package/{chunk-PAFTGNWA.js → chunk-JIT6FSXJ.js} +1 -1
- package/{chunk-WTKYP6QO.js → chunk-JTDORD5P.js} +5 -5
- package/{chunk-ECX3NKRD.js → chunk-JY5NGFFH.js} +11 -0
- package/chunk-KC4XDTT3.js +227 -0
- package/{chunk-PLYWH7XM.js → chunk-KIM6CLW5.js} +7 -7
- package/{chunk-SCYQJPGA.js → chunk-M6RL5JCD.js} +147 -20
- package/chunk-MMA3LZ3W.js +105 -0
- package/{chunk-I5PBXF7O.js → chunk-MMNYUVLW.js} +1 -1
- package/{chunk-NHQKWPLP.js → chunk-NJR3WKVP.js} +24 -22
- package/{chunk-W5VC7F7V.js → chunk-NOMIGOST.js} +59 -60
- package/{chunk-WI6OGHXJ.js → chunk-NRFKLKRU.js} +5 -5
- package/{chunk-NXCGNS4N.js → chunk-OHNELDTO.js} +1 -1
- package/{chunk-7IYBN7IA.js → chunk-OOF4UPC5.js} +22 -13
- package/{chunk-UIOEHFF6.js → chunk-OQHIVPG4.js} +1 -0
- package/{chunk-X4F26D5K.js → chunk-P5L7CXOC.js} +58 -33
- package/{chunk-5ORJGHTL.js → chunk-PDGKOTO7.js} +5 -5
- package/{chunk-UCPAVEQB.js → chunk-PYRUW7XN.js} +1 -1
- package/{chunk-SU3QL7YG.js → chunk-QT6PKHYJ.js} +1 -1
- package/{chunk-SN5XE6GQ.js → chunk-RPQXPZZF.js} +4 -4
- package/{chunk-ZN5AH4BY.js → chunk-RU4SD66C.js} +6 -6
- package/{chunk-YKFP6UGT.js → chunk-SOHTHFV2.js} +14 -14
- package/{chunk-CKOO42G5.js → chunk-UHJGXRJ4.js} +4 -4
- package/{chunk-CVCRAO6Q.js → chunk-UTV2AYEG.js} +9 -7
- package/{chunk-DQLB4NQ3.js → chunk-VPAZOH2D.js} +2 -2
- package/{chunk-MBS6CTZB.js → chunk-VZKUKCA6.js} +236 -1993
- package/{chunk-LNYHAKBP.js → chunk-W4S457LU.js} +1 -1
- package/chunk-WPORQFYN.js +74 -0
- package/{chunk-ET2CWLIJ.js → chunk-WXYLV624.js} +3 -3
- package/chunk-XFYFMTOM.js +92 -0
- package/{chunk-NV572QM3.js → chunk-YJMRHHGY.js} +15 -15
- package/{chunk-JBOUVTZX.js → chunk-YOIW77S2.js} +13 -2
- package/{chunk-ADBWFYJD.js → chunk-YPD3VJZW.js} +9 -9
- package/{chunk-DA7CTWT4.js → chunk-YWSEPJ7C.js} +5 -5
- package/{chunk-3V2QMRNN.js → chunk-ZL5RAEEB.js} +3 -3
- package/cliAgentConfigHelpers-WJBZQTLW.js +41 -0
- package/{commandRegistry-FI2IOQ3U.js → commandRegistry-VVMTPFAX.js} +85 -81
- package/{contentThunks-5LKNNDGY.js → contentThunks-N52O67MI.js} +25 -24
- package/{createAgentAutomationAction-TI4QG4CY.js → createAgentAutomationAction-ZC57YRSV.js} +25 -24
- package/{createDialogAction-TJ3JKLO4.js → createDialogAction-VQW5WDYX.js} +27 -26
- package/{createPageAction-GKXT6WEH.js → createPageAction-M5VDA7SC.js} +26 -25
- package/{dbSlice-LPMZ2DGJ.js → dbSlice-HP7G4LX3.js} +7 -7
- package/{deleteFile-EPUQHKPA.js → deleteFile-7VQGLK2V.js} +3 -3
- package/{dialogCommands-IWPXIZ5P.js → dialogCommands-JHMR2N2Y.js} +32 -30
- package/{dialogSlice-ZWNNS7GZ.js → dialogSlice-GRSVGDTF.js} +23 -22
- package/{dialogUsageCommand-ZCPPHPJ5.js → dialogUsageCommand-7KCPYGHG.js} +1 -1
- package/{docCreateCommands-HFSPKJSI.js → docCreateCommands-F2K3UPSQ.js} +28 -27
- package/{docDeleteCommands-CRL62POH.js → docDeleteCommands-XGXB5RFT.js} +29 -28
- package/{docReadCommands-QOTOX3XW.js → docReadCommands-7HWZZV6J.js} +28 -27
- package/{docStore-WYLRB7ED.js → docStore-KNZK6Y2G.js} +10 -10
- package/{docUpdateCommands-7BMH4MCA.js → docUpdateCommands-OZZ7NQII.js} +28 -27
- package/{fetchMessages-YY4SATNR.js → fetchMessages-M3QU7ZCQ.js} +1 -1
- package/{getPricing-OQXBJ6VZ.js → getPricing-2MNMXEVG.js} +3 -3
- package/{handleSendMessageAction-P27YP2DQ.js → handleSendMessageAction-SHIH74GJ.js} +46 -44
- package/hostCredentialCreate-X64WK4JD.js +357 -0
- package/index.js +5 -5
- package/{keys-P4ZDOVJW.js → keys-BEGDOTRL.js} +3 -1
- package/{localDialogRead-5VCMQQZF.js → localDialogRead-XRLAH4CZ.js} +1 -1
- package/{localRuntimeAdapter-GP6ZSSO3.js → localRuntimeAdapter-A7K3ABA6.js} +73 -66
- package/{machineCommands-6Z6H4BFX.js → machineCommands-DE3MR7CJ.js} +65 -60
- package/{machineWsRunDispatch-F2ZIXMYM.js → machineWsRunDispatch-R26P5V36.js} +65 -60
- package/{memberThunks-YSEFJF47.js → memberThunks-7WJAY5V6.js} +8 -8
- package/package.json +1 -1
- package/{projectArchive-PIGEOX3D.js → projectArchive-GGL5HLMD.js} +26 -25
- package/{providerPresetApply-ZYMLQA46.js → providerPresetApply-YXGV6NXB.js} +4 -4
- package/{providerRegistry-E34XWDLJ.js → providerRegistry-S6UL6UNA.js} +4 -4
- package/{read-DIIQBOOO.js → read-4VZQODSN.js} +3 -3
- package/{readDocTool-HXYGOEA7.js → readDocTool-AVD32RUJ.js} +1 -1
- package/{readlineWorkspace-UG25G7KC.js → readlineWorkspace-XKYKNL2I.js} +157 -100
- package/{removeDialogAgentAction-ALJDUJ2E.js → removeDialogAgentAction-FKL4BYMR.js} +17 -14
- package/{runAgentClientLoop-IO5F7TCZ.js → runAgentClientLoop-V7E2WBVM.js} +49 -46
- package/{runtimeDoctorCommands-PGAA47G5.js → runtimeDoctorCommands-QAI3MBKQ.js} +6 -6
- package/{secretCommands-ZCZ4KVET.js → secretCommands-4QS3HCA2.js} +3 -3
- package/{setDialogExtraReferencesAction-O3SVMD5A.js → setDialogExtraReferencesAction-TLIOLWWI.js} +10 -10
- package/{setPrimaryDialogAgentAction-HE7RVFFF.js → setPrimaryDialogAgentAction-2OLWRFYR.js} +18 -15
- package/{settingThunks-BWWJQG4L.js → settingThunks-UGBPCNYF.js} +12 -11
- package/{spaceCommands-UAELIFEI.js → spaceCommands-4KSLKVNF.js} +28 -27
- package/{streamAgentChatTurn-VUKZQYJR.js → streamAgentChatTurn-7FR7X2NU.js} +57 -54
- package/{switchDialogAgentAction-3VZS7SOS.js → switchDialogAgentAction-UZSAG2N5.js} +15 -12
- package/{tools-VRXJAVYI.js → tools-ZLKCC25W.js} +43 -40
- package/{tuiSummaryLlmCaller-TGCHZLSW.js → tuiSummaryLlmCaller-WC54MVGP.js} +10 -10
- package/{updateCommands-Q6CYAEYJ.js → updateCommands-4744PL3P.js} +3 -1
- package/{updateDialogTitleAction-MULWCJCW.js → updateDialogTitleAction-U53ZT7PJ.js} +38 -70
- package/usageCommand-F4IPVMIZ.js +32 -0
- package/usageRebuildCommand-HAW2AD5N.js +626 -0
- package/chunk-4LCOCOR5.js +0 -50
- package/chunk-7AUQ3WCW.js +0 -51
- package/chunk-ZRAU6T47.js +0 -56
- package/{agentFavoriteCommands-GAFEXKKP.js → agentFavoriteCommands-EDK743YA.js} +1 -1
- package/{agentGrantCommands-V5FOQKFD.js → agentGrantCommands-RQWK2TEV.js} +1 -1
- package/{agentPullCommand-2JMJP5BS.js → agentPullCommand-6EM3URVK.js} +1 -1
- package/{chunk-BTYQAODF.js → chunk-CZM5YTZ7.js} +3 -3
- package/{chunk-A2ZMIRLN.js → chunk-INN4LTAJ.js} +5 -5
- package/{chunk-XPHZK3PJ.js → chunk-JNKSDZFS.js} +3 -3
- package/{chunk-PV6JJAUB.js → chunk-TCZHTTUU.js} +8 -8
- package/{chunk-AKE53VMW.js → chunk-ZCWRMUWT.js} +0 -0
- package/{tableCommands-D7WR4QSM.js → tableCommands-MP6VFSVT.js} +3 -3
|
@@ -0,0 +1,626 @@
|
|
|
1
|
+
import {
|
|
2
|
+
parseUsageArgs,
|
|
3
|
+
require_date_fns,
|
|
4
|
+
resolveDateWindow
|
|
5
|
+
} from "./chunk-6VLJ6YA7.js";
|
|
6
|
+
import "./chunk-FY7F4Q6X.js";
|
|
7
|
+
import {
|
|
8
|
+
applyTokenUsageToDayStats,
|
|
9
|
+
normalizeStats
|
|
10
|
+
} from "./chunk-7RFNTILS.js";
|
|
11
|
+
import "./chunk-WPORQFYN.js";
|
|
12
|
+
import "./chunk-MMA3LZ3W.js";
|
|
13
|
+
import {
|
|
14
|
+
getDefaultCliLocalRuntimeDb
|
|
15
|
+
} from "./chunk-AZMYUSVF.js";
|
|
16
|
+
import "./chunk-GLKOYSRU.js";
|
|
17
|
+
import {
|
|
18
|
+
isLevelNotFoundError
|
|
19
|
+
} from "./chunk-OW765XBU.js";
|
|
20
|
+
import {
|
|
21
|
+
createTokenKey,
|
|
22
|
+
createTokenStatsKey,
|
|
23
|
+
createUsageBackupKey
|
|
24
|
+
} from "./chunk-JY5NGFFH.js";
|
|
25
|
+
import "./chunk-XJWWBO34.js";
|
|
26
|
+
import "./chunk-I42VC5KR.js";
|
|
27
|
+
import "./chunk-U6VC4MU4.js";
|
|
28
|
+
import "./chunk-WWC7I6TA.js";
|
|
29
|
+
import "./chunk-3EUW3WEO.js";
|
|
30
|
+
import "./chunk-G3SUCT4W.js";
|
|
31
|
+
import {
|
|
32
|
+
__toESM
|
|
33
|
+
} from "./chunk-4VNS5WPM.js";
|
|
34
|
+
|
|
35
|
+
// packages/cli/usageRebuildCommand.ts
|
|
36
|
+
var import_date_fns = __toESM(require_date_fns(), 1);
|
|
37
|
+
async function writeRebuildOps(db, ops) {
|
|
38
|
+
if (typeof db.batchWrite === "function") return db.batchWrite(ops);
|
|
39
|
+
if (typeof db.batch === "function") return db.batch(ops);
|
|
40
|
+
throw new Error("rebuild db \u7F3A\u5C11\u6279\u91CF\u5199\u80FD\u529B\uFF1A\u65E2\u6CA1\u6709 batchWrite() \u4E5F\u6CA1\u6709 batch()");
|
|
41
|
+
}
|
|
42
|
+
var TOKEN_PREFIX = "token-";
|
|
43
|
+
function classifyDetailKey(key) {
|
|
44
|
+
if (!key.startsWith(TOKEN_PREFIX)) return { kind: "skip", reason: "not-token-prefix" };
|
|
45
|
+
if (key.startsWith("token-stats-")) return { kind: "skip", reason: "stats-namespace" };
|
|
46
|
+
if (key.startsWith("token-charge-stats-")) return { kind: "skip", reason: "stats-namespace" };
|
|
47
|
+
if (key.startsWith("idx-")) return { kind: "skip", reason: "foreign-namespace" };
|
|
48
|
+
return { kind: "candidate" };
|
|
49
|
+
}
|
|
50
|
+
var asNumber = (value, fallback = 0) => typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
51
|
+
var asNonEmptyString = (value) => {
|
|
52
|
+
if (typeof value !== "string") return void 0;
|
|
53
|
+
const trimmed = value.trim();
|
|
54
|
+
return trimmed ? trimmed : void 0;
|
|
55
|
+
};
|
|
56
|
+
function userIdFromDetailKey(key) {
|
|
57
|
+
if (!key.startsWith(TOKEN_PREFIX)) return void 0;
|
|
58
|
+
const rest = key.slice(TOKEN_PREFIX.length);
|
|
59
|
+
const match = /^(.*)-(\d{10,13})(?:-.*)?$/.exec(rest);
|
|
60
|
+
return match ? match[1] : void 0;
|
|
61
|
+
}
|
|
62
|
+
function timestampFromDetailKey(key) {
|
|
63
|
+
const match = /-(\d{10,13})(?:-|$)/.exec(key);
|
|
64
|
+
if (!match) return void 0;
|
|
65
|
+
const parsed = Number.parseInt(match[1], 10);
|
|
66
|
+
return Number.isFinite(parsed) ? parsed : void 0;
|
|
67
|
+
}
|
|
68
|
+
function normalizeDetailRecord(key, value) {
|
|
69
|
+
if (!value || typeof value !== "object") return null;
|
|
70
|
+
const v = value;
|
|
71
|
+
const isTokenRecord = v.type === "token" || typeof v.input_tokens === "number";
|
|
72
|
+
if (!isTokenRecord) return null;
|
|
73
|
+
const userId = asNonEmptyString(v.userId) ?? userIdFromDetailKey(key);
|
|
74
|
+
if (!userId) return null;
|
|
75
|
+
const timestamp = asNumber(v.timestamp, asNumber(v.createdAt, Number.NaN)) || asNumber(timestampFromDetailKey(key), Number.NaN);
|
|
76
|
+
const dateKey = Number.isFinite(timestamp) && timestamp > 0 ? (0, import_date_fns.format)(new Date(timestamp), "yyyy-MM-dd") : asNonEmptyString(v.dateKey);
|
|
77
|
+
if (!dateKey || !/^\d{4}-\d{2}-\d{2}$/.test(dateKey)) return null;
|
|
78
|
+
const failed = v.status === "failed";
|
|
79
|
+
const agentRaw = asNonEmptyString(v.agentId) ?? asNonEmptyString(v.cybotId);
|
|
80
|
+
return {
|
|
81
|
+
userId,
|
|
82
|
+
dateKey,
|
|
83
|
+
input: asNumber(v.input_tokens),
|
|
84
|
+
output: asNumber(v.output_tokens),
|
|
85
|
+
cacheRead: asNumber(v.cache_read_input_tokens),
|
|
86
|
+
cacheCreation: asNumber(v.cache_creation_input_tokens),
|
|
87
|
+
cost: asNumber(v.cost),
|
|
88
|
+
model: asNonEmptyString(v.model),
|
|
89
|
+
provider: asNonEmptyString(v.provider),
|
|
90
|
+
agentId: agentRaw,
|
|
91
|
+
entryPath: asNonEmptyString(v.entry_path),
|
|
92
|
+
billable: v.billable === true,
|
|
93
|
+
// 只有明确的 true/false 才算已知;缺失、null、字符串 "true"、1 一律按未知处理。
|
|
94
|
+
billableUnknown: typeof v.billable !== "boolean",
|
|
95
|
+
failed
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
var detailGroupKey = (userId, dateKey) => `${userId}\0${dateKey}`;
|
|
99
|
+
function aggregateDetailsByDay(records) {
|
|
100
|
+
const byDay = /* @__PURE__ */ new Map();
|
|
101
|
+
let accepted = 0;
|
|
102
|
+
let missingAgent = 0;
|
|
103
|
+
let unknownBillable = 0;
|
|
104
|
+
const unknownBillableByDay = /* @__PURE__ */ new Map();
|
|
105
|
+
for (const record of records) {
|
|
106
|
+
const key = detailGroupKey(record.userId, record.dateKey);
|
|
107
|
+
const prev = byDay.get(key) ?? null;
|
|
108
|
+
if (!record.agentId) missingAgent++;
|
|
109
|
+
if (record.billableUnknown && !record.failed) {
|
|
110
|
+
unknownBillable++;
|
|
111
|
+
unknownBillableByDay.set(key, (unknownBillableByDay.get(key) ?? 0) + 1);
|
|
112
|
+
}
|
|
113
|
+
byDay.set(
|
|
114
|
+
key,
|
|
115
|
+
applyTokenUsageToDayStats(prev, {
|
|
116
|
+
userId: record.userId,
|
|
117
|
+
timeKey: record.dateKey,
|
|
118
|
+
model: record.model,
|
|
119
|
+
provider: record.provider,
|
|
120
|
+
input_tokens: record.input,
|
|
121
|
+
output_tokens: record.output,
|
|
122
|
+
cost: record.cost,
|
|
123
|
+
cache_read_input_tokens: record.cacheRead,
|
|
124
|
+
cache_creation_input_tokens: record.cacheCreation,
|
|
125
|
+
// 明细里没有 agentId 时**不传**:传了会让 applyTokenUsageToDayStats 建一个
|
|
126
|
+
// "unknown" 桶,把「这一维没记录」伪装成「确实有这么多未知 agent 用量」。
|
|
127
|
+
...record.agentId ? { agentId: record.agentId } : {},
|
|
128
|
+
...record.entryPath ? { entry_path: record.entryPath } : {},
|
|
129
|
+
...record.failed ? { status: "failed" } : {},
|
|
130
|
+
// 与 client/localRuntimeDialog.ts 同一口径:(billable ?? false) ? platform : subscription
|
|
131
|
+
billingCategory: record.billable ? "platform" : "subscription"
|
|
132
|
+
})
|
|
133
|
+
);
|
|
134
|
+
accepted++;
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
byDay,
|
|
138
|
+
accepted,
|
|
139
|
+
rejectedNonUsage: 0,
|
|
140
|
+
rejectedUnkeyed: 0,
|
|
141
|
+
missingAgent,
|
|
142
|
+
unknownBillable,
|
|
143
|
+
unknownBillableByDay
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
var TOKEN_METRICS = ["input", "output", "cacheRead", "cacheCreation"];
|
|
147
|
+
var DIMENSION_BUCKETS = [
|
|
148
|
+
"models",
|
|
149
|
+
"providers",
|
|
150
|
+
"agents",
|
|
151
|
+
"entryPaths",
|
|
152
|
+
"categories",
|
|
153
|
+
"modelCategories"
|
|
154
|
+
];
|
|
155
|
+
var describeLoss = (before, after) => {
|
|
156
|
+
const diffs = [];
|
|
157
|
+
if (after.count < before.count) diffs.push(`count ${before.count}\u2192${after.count}`);
|
|
158
|
+
if (after.cost < before.cost) diffs.push(`cost ${before.cost}\u2192${after.cost}`);
|
|
159
|
+
for (const metric of TOKEN_METRICS) {
|
|
160
|
+
if (after.tokens[metric] < before.tokens[metric]) {
|
|
161
|
+
diffs.push(`${metric} ${before.tokens[metric]}\u2192${after.tokens[metric]}`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return diffs;
|
|
165
|
+
};
|
|
166
|
+
function detectOverwriteRisks(existing, rebuilt) {
|
|
167
|
+
if (existing === null) return [];
|
|
168
|
+
const risks = [];
|
|
169
|
+
const before = normalizeStats(existing.total);
|
|
170
|
+
const after = normalizeStats(rebuilt.total);
|
|
171
|
+
const totalLosses = describeLoss(before, after);
|
|
172
|
+
if (totalLosses.length > 0) risks.push(`total \u51CF\u5C11: ${totalLosses.join(", ")}`);
|
|
173
|
+
for (const bucket of DIMENSION_BUCKETS) {
|
|
174
|
+
const beforeBucket = existing[bucket] ?? {};
|
|
175
|
+
const afterBucket = rebuilt[bucket] ?? {};
|
|
176
|
+
for (const [name, rawBefore] of Object.entries(beforeBucket)) {
|
|
177
|
+
const losses = describeLoss(normalizeStats(rawBefore), normalizeStats(afterBucket[name]));
|
|
178
|
+
if (losses.length === 0) continue;
|
|
179
|
+
const label = `${bucket}/${name}`;
|
|
180
|
+
risks.push(
|
|
181
|
+
afterBucket[name] === void 0 ? `${label} \u6876\u4F1A\u6574\u4F53\u6D88\u5931\uFF08${losses.join(", ")}\uFF09` : `${label} \u51CF\u5C11: ${losses.join(", ")}`
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return risks;
|
|
186
|
+
}
|
|
187
|
+
function planRebuild(args) {
|
|
188
|
+
const plans = [];
|
|
189
|
+
for (const rebuilt of args.rebuiltByDay) {
|
|
190
|
+
const { userId, timeKey } = rebuilt;
|
|
191
|
+
const statsKey = createTokenStatsKey(userId, timeKey);
|
|
192
|
+
const groupKey = detailGroupKey(userId, timeKey);
|
|
193
|
+
const existing = args.existingByKey.get(groupKey) ?? null;
|
|
194
|
+
const existingTotal = normalizeStats(existing?.total);
|
|
195
|
+
const rebuiltTotal = normalizeStats(rebuilt.total);
|
|
196
|
+
const preservedFailed = Math.max(0, existingTotal.failedCount - rebuiltTotal.failedCount);
|
|
197
|
+
const merged = preservedFailed > 0 ? {
|
|
198
|
+
...rebuilt,
|
|
199
|
+
total: { ...rebuilt.total, failedCount: rebuiltTotal.failedCount + preservedFailed }
|
|
200
|
+
} : rebuilt;
|
|
201
|
+
const unknownBillable = args.unknownBillableByDay?.get(groupKey) ?? 0;
|
|
202
|
+
const blocked = unknownBillable > 0;
|
|
203
|
+
const regressions = detectOverwriteRisks(existing, merged);
|
|
204
|
+
const skip = blocked || regressions.length > 0 && !args.force;
|
|
205
|
+
plans.push({
|
|
206
|
+
userId,
|
|
207
|
+
dateKey: timeKey,
|
|
208
|
+
statsKey,
|
|
209
|
+
rebuilt: merged,
|
|
210
|
+
existing,
|
|
211
|
+
existingCalls: existingTotal.count,
|
|
212
|
+
rebuiltCalls: rebuiltTotal.count,
|
|
213
|
+
existingFailed: existingTotal.failedCount,
|
|
214
|
+
rebuiltFailed: rebuiltTotal.failedCount,
|
|
215
|
+
preservedFailed,
|
|
216
|
+
unknownBillable,
|
|
217
|
+
blocked,
|
|
218
|
+
action: skip ? "skip" : existing === null ? "create" : "overwrite",
|
|
219
|
+
regressions,
|
|
220
|
+
...skip ? {
|
|
221
|
+
skipReason: blocked ? `\u6709 ${unknownBillable} \u6761\u6210\u529F\u660E\u7EC6\u7684 billable \u7F3A\u5931\u6216\u975E\u5E03\u5C14\uFF0C\u6536\u8D39\u7C7B\u522B\u4E0E\u91D1\u989D\u65E0\u6CD5\u786E\u5B9A\uFF0C\u4E0D\u53EF\u91CD\u5EFA\uFF08--force \u4E5F\u4E0D\u89E3\u9664\uFF1B\u5148\u8865\u9F50\u660E\u7EC6\u518D\u91CD\u5EFA\uFF09` + (regressions.length > 0 ? `\u3002\u6B64\u5916\u8986\u76D6\u8FD8\u4F1A\u51CF\u5C11\u73B0\u6709\u6570\u636E\uFF1A${regressions.join("\uFF1B")}` : "") : `\u8986\u76D6\u4F1A\u51CF\u5C11\u73B0\u6709\u6570\u636E\uFF08\u73B0\u6709 ${existingTotal.count} \u6B21 / \u91CD\u5EFA ${rebuiltTotal.count} \u6B21\uFF09\uFF1A${regressions.join("\uFF1B")}\u3002\u5DF2\u8DF3\u8FC7\uFF1B\u786E\u8BA4\u8981\u8986\u76D6\u8BF7\u52A0 --force`
|
|
222
|
+
} : {}
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
return plans.sort((a, b) => a.dateKey.localeCompare(b.dateKey) || a.userId.localeCompare(b.userId));
|
|
226
|
+
}
|
|
227
|
+
function backupStatsKey(userId, dateKey, nowMs) {
|
|
228
|
+
return createUsageBackupKey(userId, dateKey, nowMs);
|
|
229
|
+
}
|
|
230
|
+
async function scanDetails(args) {
|
|
231
|
+
const range = args.userId ? createTokenKey.rangeOfUser(args.userId) : { start: TOKEN_PREFIX, end: `${TOKEN_PREFIX}\uFFFF` };
|
|
232
|
+
const byDay = /* @__PURE__ */ new Map();
|
|
233
|
+
let totalScanned = 0;
|
|
234
|
+
let skippedKeys = 0;
|
|
235
|
+
let accepted = 0;
|
|
236
|
+
let rejectedNonUsage = 0;
|
|
237
|
+
let rejectedUnkeyed = 0;
|
|
238
|
+
let missingAgent = 0;
|
|
239
|
+
let unknownBillable = 0;
|
|
240
|
+
const unknownBillableByDay = /* @__PURE__ */ new Map();
|
|
241
|
+
for await (const [rawKey, value] of args.db.iterator({ gte: range.start, lte: range.end })) {
|
|
242
|
+
const key = String(rawKey);
|
|
243
|
+
const verdict = classifyDetailKey(key);
|
|
244
|
+
if (verdict.kind === "skip") {
|
|
245
|
+
skippedKeys++;
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
totalScanned++;
|
|
249
|
+
const record = normalizeDetailRecord(key, value);
|
|
250
|
+
if (!record) {
|
|
251
|
+
if (value && typeof value === "object" && value.type === "token") rejectedUnkeyed++;
|
|
252
|
+
else rejectedNonUsage++;
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
if (args.userId && record.userId !== args.userId) {
|
|
256
|
+
rejectedUnkeyed++;
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
259
|
+
if (args.from && record.dateKey < args.from) continue;
|
|
260
|
+
if (args.to && record.dateKey > args.to) continue;
|
|
261
|
+
if (!record.agentId) missingAgent++;
|
|
262
|
+
const groupKey = detailGroupKey(record.userId, record.dateKey);
|
|
263
|
+
if (record.billableUnknown && !record.failed) {
|
|
264
|
+
unknownBillable++;
|
|
265
|
+
unknownBillableByDay.set(groupKey, (unknownBillableByDay.get(groupKey) ?? 0) + 1);
|
|
266
|
+
}
|
|
267
|
+
byDay.set(
|
|
268
|
+
groupKey,
|
|
269
|
+
applyTokenUsageToDayStats(byDay.get(groupKey) ?? null, {
|
|
270
|
+
userId: record.userId,
|
|
271
|
+
timeKey: record.dateKey,
|
|
272
|
+
model: record.model,
|
|
273
|
+
provider: record.provider,
|
|
274
|
+
input_tokens: record.input,
|
|
275
|
+
output_tokens: record.output,
|
|
276
|
+
cost: record.cost,
|
|
277
|
+
cache_read_input_tokens: record.cacheRead,
|
|
278
|
+
cache_creation_input_tokens: record.cacheCreation,
|
|
279
|
+
...record.agentId ? { agentId: record.agentId } : {},
|
|
280
|
+
...record.entryPath ? { entry_path: record.entryPath } : {},
|
|
281
|
+
...record.failed ? { status: "failed" } : {},
|
|
282
|
+
billingCategory: record.billable ? "platform" : "subscription"
|
|
283
|
+
})
|
|
284
|
+
);
|
|
285
|
+
accepted++;
|
|
286
|
+
}
|
|
287
|
+
return {
|
|
288
|
+
byDay,
|
|
289
|
+
accepted,
|
|
290
|
+
rejectedNonUsage,
|
|
291
|
+
rejectedUnkeyed,
|
|
292
|
+
missingAgent,
|
|
293
|
+
unknownBillable,
|
|
294
|
+
unknownBillableByDay,
|
|
295
|
+
totalScanned,
|
|
296
|
+
skippedKeys
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
var hasFlag = (args, flag) => args.includes(flag);
|
|
300
|
+
function parseRebuildArgs(args) {
|
|
301
|
+
const base = parseUsageArgs(args);
|
|
302
|
+
if (base.days !== void 0) {
|
|
303
|
+
throw new Error("usage rebuild \u4E0D\u652F\u6301 --days\uFF1A\u91CD\u5EFA\u7A97\u53E3\u8981\u663E\u5F0F\u7ED9 --from/--to\uFF08\u6216\u7701\u7565\u8868\u793A\u5168\u90E8\u5386\u53F2\uFF09");
|
|
304
|
+
}
|
|
305
|
+
if (base.groupBy !== void 0 || base.agent || base.provider || base.model) {
|
|
306
|
+
throw new Error("usage rebuild \u4E0D\u63A5\u53D7 --by / --agent / --provider / --model\uFF1A\u5B83\u53EA\u91CD\u5EFA\u805A\u5408");
|
|
307
|
+
}
|
|
308
|
+
return { ...base, apply: hasFlag(args, "--apply"), force: hasFlag(args, "--force") };
|
|
309
|
+
}
|
|
310
|
+
var formatInt = (value) => value.toLocaleString("en-US");
|
|
311
|
+
var summarizeBuckets = (map) => {
|
|
312
|
+
const entries = Object.entries(map ?? {});
|
|
313
|
+
if (entries.length === 0) return "{}";
|
|
314
|
+
const shown = entries.slice(0, 4).map(([k, v]) => `${k}:${formatInt(normalizeStats(v).count)}`);
|
|
315
|
+
return `{${shown.join(", ")}${entries.length > 4 ? `, \u2026+${entries.length - 4}` : ""}}`;
|
|
316
|
+
};
|
|
317
|
+
var REBUILD_TEXT = [
|
|
318
|
+
"\u7528\u6CD5: nolo usage rebuild [\u9009\u9879]",
|
|
319
|
+
"",
|
|
320
|
+
" \u4ECE\u660E\u7EC6\u8BA1\u8D39\u8BB0\u5F55\uFF08token-<userId>-<timestamp>\u2026\uFF09\u91CD\u5EFA\u672C\u5730\u65E5\u805A\u5408 DayStats\uFF0C",
|
|
321
|
+
" \u8865\u56DE\u5386\u53F2\u4E0A\u7F3A\u5931\u7684 cacheRead / cacheCreation / agents / entryPaths \u7EF4\u5EA6\u3002",
|
|
322
|
+
"",
|
|
323
|
+
" \u9ED8\u8BA4 dry-run\uFF1A\u53EA\u6253\u5370\u5C06\u53D1\u751F\u7684\u53D8\u66F4\uFF0C\u4E0D\u5199\u5E93\u3002",
|
|
324
|
+
"",
|
|
325
|
+
"\u9009\u9879:",
|
|
326
|
+
" --from <date> \u53EA\u91CD\u5EFA\u8BE5\u65E5\u671F\u8D77\uFF08YYYY-MM-DD\uFF0C\u672C\u5730\u65E5\u671F\uFF09",
|
|
327
|
+
" --to <date> \u53EA\u91CD\u5EFA\u5230\u8BE5\u65E5\u671F\uFF08\u542B\uFF09",
|
|
328
|
+
" --all-users \u5904\u7406\u672C\u673A\u6240\u6709\u8D26\u53F7\uFF08\u9ED8\u8BA4\u53EA\u5904\u7406\u5F53\u524D\u767B\u5F55\u8D26\u53F7\uFF09",
|
|
329
|
+
" --apply \u771F\u6B63\u5199\u5E93\uFF08\u5148\u5907\u4EFD\u539F\u503C\uFF09",
|
|
330
|
+
" --force \u5141\u8BB8\u8986\u76D6\u300C\u73B0\u6709\u8C03\u7528\u6570 > \u91CD\u5EFA\u503C\u300D\u7684\u65E5\u671F",
|
|
331
|
+
" --json \u8F93\u51FA JSON",
|
|
332
|
+
" -h, --help \u663E\u793A\u672C\u5E2E\u52A9",
|
|
333
|
+
"",
|
|
334
|
+
"\u8BF4\u660E:",
|
|
335
|
+
" \xB7 \u91CD\u5EFA\u53EA\u4F9D\u8D56\u660E\u7EC6\u3002\u67D0\u5929\u73B0\u6709 total.calls \u5927\u4E8E\u91CD\u5EFA\u503C\u65F6\uFF0C\u8BF4\u660E\u8BE5\u5929\u6709\u660E\u7EC6\u4E4B\u5916\u7684\u6765\u6E90\uFF0C",
|
|
336
|
+
" \u9ED8\u8BA4\u8DF3\u8FC7\u5E76\u5728\u62A5\u544A\u91CC\u9010\u6761\u5217\u51FA\u300C\u73B0\u6709 N / \u91CD\u5EFA M\u300D\u3002",
|
|
337
|
+
" \xB7 \u73B0\u6709 failedCount \u9AD8\u4E8E\u91CD\u5EFA\u503C\u65F6\u4F1A\u4FDD\u7559\u73B0\u6709\u503C\uFF08\u5931\u8D25\u8BB0\u5F55\u662F\u540E\u52A0\u7EF4\u5EA6\uFF0C\u65E7\u6570\u636E\u65E0\u660E\u7EC6\u53EF\u4F9D\uFF09\u3002"
|
|
338
|
+
].join("\n");
|
|
339
|
+
function buildReport(args) {
|
|
340
|
+
const days = args.plans.map((plan) => {
|
|
341
|
+
const existingTotal = normalizeStats(plan.existing?.total);
|
|
342
|
+
const rebuiltTotal = normalizeStats(plan.rebuilt.total);
|
|
343
|
+
return {
|
|
344
|
+
userId: plan.userId,
|
|
345
|
+
dateKey: plan.dateKey,
|
|
346
|
+
action: plan.action,
|
|
347
|
+
existingCalls: plan.existingCalls,
|
|
348
|
+
rebuiltCalls: plan.rebuiltCalls,
|
|
349
|
+
existingFailed: plan.existingFailed,
|
|
350
|
+
rebuiltFailed: plan.rebuiltFailed,
|
|
351
|
+
preservedFailed: plan.preservedFailed,
|
|
352
|
+
existingCacheRead: existingTotal.tokens.cacheRead,
|
|
353
|
+
rebuiltCacheRead: rebuiltTotal.tokens.cacheRead,
|
|
354
|
+
existingCacheCreation: existingTotal.tokens.cacheCreation,
|
|
355
|
+
rebuiltCacheCreation: rebuiltTotal.tokens.cacheCreation,
|
|
356
|
+
existingAgents: Object.keys(plan.existing?.agents ?? {}),
|
|
357
|
+
rebuiltAgents: Object.keys(plan.rebuilt.agents ?? {}),
|
|
358
|
+
unknownBillable: plan.unknownBillable,
|
|
359
|
+
blocked: plan.blocked,
|
|
360
|
+
...plan.regressions.length > 0 ? { regressions: plan.regressions } : {},
|
|
361
|
+
...plan.skipReason ? { skipReason: plan.skipReason } : {}
|
|
362
|
+
};
|
|
363
|
+
});
|
|
364
|
+
return {
|
|
365
|
+
scope: args.allUsers ? "all" : "user",
|
|
366
|
+
userId: args.userId,
|
|
367
|
+
applied: args.applied,
|
|
368
|
+
force: args.options.force === true,
|
|
369
|
+
window: args.window,
|
|
370
|
+
scanned: {
|
|
371
|
+
detailCandidates: args.scan.totalScanned,
|
|
372
|
+
skippedNonUserKeys: args.scan.skippedKeys,
|
|
373
|
+
accepted: args.scan.accepted,
|
|
374
|
+
rejectedNonUsage: args.scan.rejectedNonUsage,
|
|
375
|
+
rejectedUnkeyed: args.scan.rejectedUnkeyed,
|
|
376
|
+
missingAgent: args.scan.missingAgent,
|
|
377
|
+
unknownBillable: args.scan.unknownBillable
|
|
378
|
+
},
|
|
379
|
+
days,
|
|
380
|
+
written: args.plans.filter((p) => p.action !== "skip").length,
|
|
381
|
+
skipped: args.plans.filter((p) => p.action === "skip").length,
|
|
382
|
+
backups: args.backups
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
function formatRebuildReport(report) {
|
|
386
|
+
const lines = [];
|
|
387
|
+
const scopeLabel = report.scope === "all" ? "\u672C\u673A\u6240\u6709\u8D26\u53F7" : report.userId;
|
|
388
|
+
lines.push(
|
|
389
|
+
`\u8303\u56F4: ${scopeLabel} \u7A97\u53E3: ${report.window.from ?? "\u6700\u65E9"} \u2192 ${report.window.to ?? "\u4ECA\u5929"}`
|
|
390
|
+
);
|
|
391
|
+
lines.push(
|
|
392
|
+
`\u660E\u7EC6: \u5019\u9009 ${formatInt(report.scanned.detailCandidates)} \u6761\uFF08\u6536\u4E0B ${formatInt(report.scanned.accepted)}\uFF0C\u975E\u7528\u91CF ${formatInt(report.scanned.rejectedNonUsage)}\uFF0C\u53D6\u4E0D\u5230 userId/\u65E5\u671F ${formatInt(report.scanned.rejectedUnkeyed)}\uFF09`
|
|
393
|
+
);
|
|
394
|
+
if (report.scanned.missingAgent > 0) {
|
|
395
|
+
lines.push(
|
|
396
|
+
`\u6CE8\u610F: \u6709 ${formatInt(report.scanned.missingAgent)} \u6761\u660E\u7EC6\u6CA1\u6709 agentId/cybotId\uFF0C\u8FD9\u4E9B\u7528\u91CF\u4E0D\u4F1A\u8FDB agents \u7EF4\u5EA6\u3002`
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
if (report.scanned.unknownBillable > 0) {
|
|
400
|
+
lines.push(
|
|
401
|
+
`\u6CE8\u610F: \u6709 ${formatInt(report.scanned.unknownBillable)} \u6761\u6210\u529F\u660E\u7EC6\u7684 billable \u7F3A\u5931\u6216\u4E0D\u662F\u5E03\u5C14\u503C\uFF0C\u6536\u8D39\u7C7B\u522B\u4E0E\u91D1\u989D\u65E0\u6CD5\u786E\u5B9A \u2014\u2014 \u8FD9\u4E9B\u65E5\u671F\u4E0D\u53EF\u91CD\u5EFA\uFF08--force \u4E5F\u4E0D\u89E3\u9664\uFF1B\u8865\u9F50\u660E\u7EC6\u540E\u518D\u91CD\u5EFA\uFF09\u3002`
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
if (report.days.length === 0) {
|
|
405
|
+
lines.push("");
|
|
406
|
+
lines.push("\u6240\u9009\u7A97\u53E3\u5185\u6CA1\u6709\u53EF\u91CD\u5EFA\u7684\u660E\u7EC6\u3002");
|
|
407
|
+
return lines.join("\n");
|
|
408
|
+
}
|
|
409
|
+
lines.push("");
|
|
410
|
+
lines.push(report.applied ? "\u53D8\u66F4\uFF08\u5DF2\u5199\u5165\uFF09:" : "\u53D8\u66F4\uFF08dry-run\uFF0C\u672A\u5199\u5E93\uFF1B\u52A0 --apply \u624D\u4F1A\u5199\uFF09:");
|
|
411
|
+
for (const day of report.days) {
|
|
412
|
+
const head = ` ${day.dateKey} ${day.userId}`;
|
|
413
|
+
if (day.blocked) {
|
|
414
|
+
lines.push(
|
|
415
|
+
`${head} \u4E0D\u53EF\u91CD\u5EFA \u2014\u2014 ${formatInt(day.unknownBillable)} \u6761\u6210\u529F\u660E\u7EC6\u7684 billable \u672A\u77E5\uFF1B\u6536\u8D39\u7C7B\u522B/\u91D1\u989D\u65E0\u6CD5\u786E\u5B9A\uFF0C\u91CD\u5EFA\u503C\u4E0D\u7B97\u51C6\u786E\u7ED3\u679C\uFF0C\u6545\u4E0D\u5199\u5E93\uFF08--force \u4E5F\u4E0D\u8986\u76D6\uFF09`
|
|
416
|
+
);
|
|
417
|
+
if (day.skipReason) lines.push(` ${day.skipReason}`);
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
if (day.action === "skip") {
|
|
421
|
+
lines.push(`${head} \u8DF3\u8FC7 \u2014\u2014 \u73B0\u6709 ${formatInt(day.existingCalls)} / \u91CD\u5EFA ${formatInt(day.rebuiltCalls)} \u6B21\u8C03\u7528`);
|
|
422
|
+
if (day.skipReason) lines.push(` ${day.skipReason}`);
|
|
423
|
+
continue;
|
|
424
|
+
}
|
|
425
|
+
lines.push(
|
|
426
|
+
`${head} ${day.action === "create" ? "\u65B0\u5EFA" : "\u8986\u76D6"} \u8C03\u7528 ${formatInt(day.existingCalls)} \u2192 ${formatInt(day.rebuiltCalls)} \u7F13\u5B58\u8BFB ${formatInt(day.existingCacheRead)} \u2192 ${formatInt(day.rebuiltCacheRead)} \u7F13\u5B58\u5199 ${formatInt(day.existingCacheCreation)} \u2192 ${formatInt(day.rebuiltCacheCreation)}`
|
|
427
|
+
);
|
|
428
|
+
lines.push(
|
|
429
|
+
` agent \u6876 ${day.existingAgents.length} \u2192 ${day.rebuiltAgents.length}` + (day.rebuiltAgents.length > 0 ? `\uFF08${day.rebuiltAgents.slice(0, 4).join(", ")}${day.rebuiltAgents.length > 4 ? ", \u2026" : ""}\uFF09` : "")
|
|
430
|
+
);
|
|
431
|
+
if (day.preservedFailed > 0) {
|
|
432
|
+
lines.push(
|
|
433
|
+
` \u4FDD\u7559\u73B0\u6709 failedCount: \u73B0\u6709 ${formatInt(day.existingFailed)} / \u91CD\u5EFA ${formatInt(day.rebuiltFailed)}\uFF08\u4FDD\u7559 ${formatInt(day.preservedFailed)}\uFF09`
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
if (day.regressions && day.regressions.length > 0) {
|
|
437
|
+
lines.push(` \u26A0 \u5F3A\u5236\u8986\u76D6\u4F1A\u8BA9\u73B0\u6709\u6570\u636E\u53D8\u5C11: ${day.regressions.join("\uFF1B")}`);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
lines.push("");
|
|
441
|
+
lines.push(`\u5408\u8BA1: \u5F85\u5199 ${formatInt(report.written)} \u5929\uFF0C\u8DF3\u8FC7 ${formatInt(report.skipped)} \u5929`);
|
|
442
|
+
const blockedDays = report.days.filter((day) => day.blocked).length;
|
|
443
|
+
if (blockedDays > 0) {
|
|
444
|
+
lines.push(`\u5176\u4E2D billable \u672A\u77E5\u4E0D\u53EF\u91CD\u5EFA ${formatInt(blockedDays)} \u5929\uFF08\u4E34\u65F6 0 \u4E0D\u4F5C\u4E3A\u51C6\u786E\u91CD\u5EFA\u7ED3\u679C\uFF0C\u672A\u5199\u5E93\uFF09`);
|
|
445
|
+
}
|
|
446
|
+
if (report.applied) {
|
|
447
|
+
const withOriginal = report.backups.filter((b) => b.hadOriginal).length;
|
|
448
|
+
lines.push(`\u5DF2\u5199\u5165 ${formatInt(report.written)} \u4E2A\u65E5\u805A\u5408\u952E\uFF1B\u5907\u4EFD ${formatInt(withOriginal)} \u4E2A\u539F\u503C\u952E`);
|
|
449
|
+
if (withOriginal > 0) {
|
|
450
|
+
lines.push("\u56DE\u6EDA\uFF1A\u628A backup-* \u952E\u7684\u503C\u5199\u56DE\u5BF9\u5E94\u65E5\u805A\u5408\u952E\u5373\u53EF\u3002");
|
|
451
|
+
}
|
|
452
|
+
} else if (report.skipped > 0) {
|
|
453
|
+
lines.push("\u88AB\u8DF3\u8FC7\u7684\u65E5\u671F\u8BF4\u660E\u8BE5\u5929\u5B58\u5728\u660E\u7EC6\u4E4B\u5916\u7684\u6765\u6E90\uFF1B\u786E\u8BA4\u540E\u53EF\u7528 --force \u8986\u76D6\u3002");
|
|
454
|
+
}
|
|
455
|
+
return lines.join("\n");
|
|
456
|
+
}
|
|
457
|
+
async function resolveRebuildUserId(env) {
|
|
458
|
+
const { resolveLocalUserId } = await import("./cliAgentConfigHelpers-WJBZQTLW.js");
|
|
459
|
+
return resolveLocalUserId(env);
|
|
460
|
+
}
|
|
461
|
+
async function runUsageRebuildCommand(args, deps) {
|
|
462
|
+
const output = deps.output ?? process.stdout;
|
|
463
|
+
const errorOutput = deps.errorOutput ?? process.stderr;
|
|
464
|
+
if (hasFlag(args, "-h") || hasFlag(args, "--help")) {
|
|
465
|
+
output.write(`${REBUILD_TEXT}
|
|
466
|
+
`);
|
|
467
|
+
return 0;
|
|
468
|
+
}
|
|
469
|
+
let options;
|
|
470
|
+
const window = {};
|
|
471
|
+
try {
|
|
472
|
+
options = parseRebuildArgs(args);
|
|
473
|
+
if (options.from !== void 0 || options.to !== void 0) {
|
|
474
|
+
const resolved = resolveDateWindow(options);
|
|
475
|
+
window.from = resolved.from;
|
|
476
|
+
window.to = resolved.to;
|
|
477
|
+
}
|
|
478
|
+
} catch (error) {
|
|
479
|
+
errorOutput.write(`[nolo] ${error instanceof Error ? error.message : String(error)}
|
|
480
|
+
`);
|
|
481
|
+
errorOutput.write(`${REBUILD_TEXT}
|
|
482
|
+
`);
|
|
483
|
+
return 1;
|
|
484
|
+
}
|
|
485
|
+
const userId = deps.userId?.trim() || await resolveRebuildUserId(deps.env);
|
|
486
|
+
const allUsers = options.allUsers === true;
|
|
487
|
+
const nowMs = deps.nowMs ?? (() => Date.now());
|
|
488
|
+
let db;
|
|
489
|
+
try {
|
|
490
|
+
db = deps.db ?? await getDefaultCliLocalRuntimeDb();
|
|
491
|
+
} catch (error) {
|
|
492
|
+
errorOutput.write(
|
|
493
|
+
`[nolo] \u6253\u5F00\u672C\u5730\u5E93\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}
|
|
494
|
+
`
|
|
495
|
+
);
|
|
496
|
+
return 1;
|
|
497
|
+
}
|
|
498
|
+
let scan;
|
|
499
|
+
try {
|
|
500
|
+
scan = await scanDetails({
|
|
501
|
+
db,
|
|
502
|
+
userId: allUsers ? void 0 : userId,
|
|
503
|
+
from: window.from,
|
|
504
|
+
to: window.to
|
|
505
|
+
});
|
|
506
|
+
} catch (error) {
|
|
507
|
+
errorOutput.write(
|
|
508
|
+
`[nolo] \u626B\u63CF\u660E\u7EC6\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}
|
|
509
|
+
`
|
|
510
|
+
);
|
|
511
|
+
return 1;
|
|
512
|
+
}
|
|
513
|
+
const existingByKey = /* @__PURE__ */ new Map();
|
|
514
|
+
for (const rebuilt of scan.byDay.values()) {
|
|
515
|
+
const statsKey = createTokenStatsKey(rebuilt.userId, rebuilt.timeKey);
|
|
516
|
+
let existing = null;
|
|
517
|
+
try {
|
|
518
|
+
const raw = await db.get(statsKey);
|
|
519
|
+
existing = raw && typeof raw === "object" ? raw : null;
|
|
520
|
+
} catch (error) {
|
|
521
|
+
if (!isLevelNotFoundError(error)) {
|
|
522
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
523
|
+
errorOutput.write(`[nolo] \u8BFB\u53D6\u73B0\u6709\u65E5\u805A\u5408\u5931\u8D25\uFF08${statsKey}\uFF09: ${reason}
|
|
524
|
+
`);
|
|
525
|
+
errorOutput.write(`[nolo] \u65E0\u6CD5\u786E\u8BA4\u8BE5\u952E\u662F\u5426\u771F\u7684\u4E0D\u5B58\u5728\uFF0C\u5DF2\u4E2D\u6B62\uFF1B\u672C\u6B21\u672A\u5199\u5165\u4EFB\u4F55\u65E5\u805A\u5408\u3002
|
|
526
|
+
`);
|
|
527
|
+
return 1;
|
|
528
|
+
}
|
|
529
|
+
existing = null;
|
|
530
|
+
}
|
|
531
|
+
existingByKey.set(detailGroupKey(rebuilt.userId, rebuilt.timeKey), existing);
|
|
532
|
+
}
|
|
533
|
+
const plans = planRebuild({
|
|
534
|
+
rebuiltByDay: scan.byDay.values(),
|
|
535
|
+
existingByKey,
|
|
536
|
+
unknownBillableByDay: scan.unknownBillableByDay,
|
|
537
|
+
force: options.force === true
|
|
538
|
+
});
|
|
539
|
+
const writable = plans.filter((plan) => plan.action !== "skip");
|
|
540
|
+
const backups = [];
|
|
541
|
+
let writeError = 0;
|
|
542
|
+
if (options.apply) {
|
|
543
|
+
const stamp = nowMs();
|
|
544
|
+
const backupOps = [];
|
|
545
|
+
for (const plan of writable) {
|
|
546
|
+
const backupKey = backupStatsKey(plan.userId, plan.dateKey, stamp);
|
|
547
|
+
backups.push({
|
|
548
|
+
userId: plan.userId,
|
|
549
|
+
dateKey: plan.dateKey,
|
|
550
|
+
backupKey,
|
|
551
|
+
hadOriginal: plan.existing !== null
|
|
552
|
+
});
|
|
553
|
+
if (plan.existing !== null) {
|
|
554
|
+
backupOps.push({ type: "put", key: backupKey, value: plan.existing });
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
if (backupOps.length > 0) {
|
|
558
|
+
try {
|
|
559
|
+
await writeRebuildOps(db, backupOps);
|
|
560
|
+
} catch (error) {
|
|
561
|
+
errorOutput.write(
|
|
562
|
+
`[nolo] \u5907\u4EFD\u539F\u503C\u5931\u8D25\uFF0C\u5DF2\u6574\u4F53\u4E2D\u6B62\u3001\u672A\u5199\u5165\u4EFB\u4F55\u65E5\u805A\u5408: ${error instanceof Error ? error.message : String(error)}
|
|
563
|
+
`
|
|
564
|
+
);
|
|
565
|
+
return 2;
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
const statsOps = writable.map((plan) => ({
|
|
569
|
+
type: "put",
|
|
570
|
+
key: plan.statsKey,
|
|
571
|
+
value: plan.rebuilt
|
|
572
|
+
}));
|
|
573
|
+
if (statsOps.length > 0) {
|
|
574
|
+
try {
|
|
575
|
+
await writeRebuildOps(db, statsOps);
|
|
576
|
+
} catch (error) {
|
|
577
|
+
errorOutput.write(
|
|
578
|
+
`[nolo] \u5199\u5165\u65E5\u805A\u5408\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}
|
|
579
|
+
`
|
|
580
|
+
);
|
|
581
|
+
errorOutput.write(`[nolo] \u539F\u503C\u5DF2\u5907\u4EFD\u5230 usage-backup-* \u952E\uFF0C\u53EF\u56DE\u6EDA\u3002
|
|
582
|
+
`);
|
|
583
|
+
writeError = 1;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
const report = buildReport({
|
|
588
|
+
plans,
|
|
589
|
+
scan,
|
|
590
|
+
userId,
|
|
591
|
+
allUsers,
|
|
592
|
+
options,
|
|
593
|
+
window,
|
|
594
|
+
backups,
|
|
595
|
+
applied: options.apply === true && writeError === 0
|
|
596
|
+
});
|
|
597
|
+
if (options.json) {
|
|
598
|
+
output.write(`${JSON.stringify(report, null, 2)}
|
|
599
|
+
`);
|
|
600
|
+
return writeError;
|
|
601
|
+
}
|
|
602
|
+
if (allUsers) output.write("\u8303\u56F4: \u672C\u673A\u6240\u6709\u8D26\u53F7\n");
|
|
603
|
+
output.write(`${formatRebuildReport(report)}
|
|
604
|
+
`);
|
|
605
|
+
return writeError;
|
|
606
|
+
}
|
|
607
|
+
function describeDayStats(stats) {
|
|
608
|
+
const total = normalizeStats(stats.total);
|
|
609
|
+
return `calls=${total.count} failed=${total.failedCount} cacheRead=${total.tokens.cacheRead} cacheCreation=${total.tokens.cacheCreation} models=${summarizeBuckets(stats.models)} agents=${summarizeBuckets(stats.agents)}`;
|
|
610
|
+
}
|
|
611
|
+
export {
|
|
612
|
+
aggregateDetailsByDay,
|
|
613
|
+
backupStatsKey,
|
|
614
|
+
classifyDetailKey,
|
|
615
|
+
describeDayStats,
|
|
616
|
+
detailGroupKey,
|
|
617
|
+
detectOverwriteRisks,
|
|
618
|
+
normalizeDetailRecord,
|
|
619
|
+
parseRebuildArgs,
|
|
620
|
+
planRebuild,
|
|
621
|
+
runUsageRebuildCommand,
|
|
622
|
+
scanDetails,
|
|
623
|
+
timestampFromDetailKey,
|
|
624
|
+
userIdFromDetailKey,
|
|
625
|
+
writeRebuildOps
|
|
626
|
+
};
|
package/chunk-4LCOCOR5.js
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
// node_modules/date-fns/esm/_lib/requiredArgs/index.js
|
|
2
|
-
function requiredArgs(required, args) {
|
|
3
|
-
if (args.length < required) {
|
|
4
|
-
throw new TypeError(required + " argument" + (required > 1 ? "s" : "") + " required, but only " + args.length + " present");
|
|
5
|
-
}
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
// node_modules/@babel/runtime/helpers/esm/typeof.js
|
|
9
|
-
function _typeof(o) {
|
|
10
|
-
"@babel/helpers - typeof";
|
|
11
|
-
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o2) {
|
|
12
|
-
return typeof o2;
|
|
13
|
-
} : function(o2) {
|
|
14
|
-
return o2 && "function" == typeof Symbol && o2.constructor === Symbol && o2 !== Symbol.prototype ? "symbol" : typeof o2;
|
|
15
|
-
}, _typeof(o);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// node_modules/date-fns/esm/toDate/index.js
|
|
19
|
-
function toDate(argument) {
|
|
20
|
-
requiredArgs(1, arguments);
|
|
21
|
-
var argStr = Object.prototype.toString.call(argument);
|
|
22
|
-
if (argument instanceof Date || _typeof(argument) === "object" && argStr === "[object Date]") {
|
|
23
|
-
return new Date(argument.getTime());
|
|
24
|
-
} else if (typeof argument === "number" || argStr === "[object Number]") {
|
|
25
|
-
return new Date(argument);
|
|
26
|
-
} else {
|
|
27
|
-
if ((typeof argument === "string" || argStr === "[object String]") && typeof console !== "undefined") {
|
|
28
|
-
console.warn("Starting with v2.0.0-beta.1 date-fns doesn't accept strings as date arguments. Please use `parseISO` to parse strings. See: https://github.com/date-fns/date-fns/blob/master/docs/upgradeGuide.md#string-arguments");
|
|
29
|
-
console.warn(new Error().stack);
|
|
30
|
-
}
|
|
31
|
-
return /* @__PURE__ */ new Date(NaN);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// node_modules/date-fns/esm/_lib/addLeadingZeros/index.js
|
|
36
|
-
function addLeadingZeros(number, targetLength) {
|
|
37
|
-
var sign = number < 0 ? "-" : "";
|
|
38
|
-
var output = Math.abs(number).toString();
|
|
39
|
-
while (output.length < targetLength) {
|
|
40
|
-
output = "0" + output;
|
|
41
|
-
}
|
|
42
|
-
return sign + output;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export {
|
|
46
|
-
_typeof,
|
|
47
|
-
requiredArgs,
|
|
48
|
-
toDate,
|
|
49
|
-
addLeadingZeros
|
|
50
|
-
};
|