ccc-notifier 0.4.0 → 0.6.0
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/README.md +129 -122
- package/dist/{budget-EHWPEYXY.js → budget-V7CCMJHF.js} +1 -1
- package/dist/{chunk-J6Y3RMMC.js → chunk-27SJELD2.js} +107 -22
- package/dist/{chunk-2VPBBIDW.js → chunk-4JSRGJCZ.js} +61 -22
- package/dist/chunk-6HTETN26.js +226 -0
- package/dist/{chunk-5LHZOZZO.js → chunk-CH34OJ7Q.js} +241 -110
- package/dist/chunk-D4D76RGQ.js +547 -0
- package/dist/chunk-HLJAJS2W.js +55 -0
- package/dist/chunk-OOAC5ULQ.js +1101 -0
- package/dist/chunk-OYD6H3ZZ.js +124 -0
- package/dist/{chunk-TUZVISLD.js → chunk-T6Z2ZAN4.js} +1 -1
- package/dist/cli.js +388 -77
- package/dist/{dashboard-GYKABTTN.js → dashboard-NORNHUPT.js} +3 -4
- package/dist/{history-6OUJLXJT.js → history-DL4SG3PG.js} +3 -5
- package/dist/{mute-GBDNN5PB.js → mute-UIR5P5N5.js} +2 -2
- package/dist/{setup-W3CSTHJC.js → setup-3SRNQ5PG.js} +4 -3
- package/dist/subagent-store-US4TJJQR.js +31 -0
- package/dist/sweep-RUPPGAWJ.js +795 -0
- package/dist/{track-QT2U3E2R.js → track-H4AIT575.js} +53 -31
- package/package.json +1 -1
- package/dist/chunk-26CISNOE.js +0 -324
- package/dist/chunk-CKVK3UCA.js +0 -357
- package/dist/chunk-LHKBGA5K.js +0 -462
- package/dist/chunk-ZHIZZ6V5.js +0 -92
- package/dist/sweep-IBSV4LRD.js +0 -604
|
@@ -0,0 +1,795 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
listCodexRollouts
|
|
4
|
+
} from "./chunk-HLJAJS2W.js";
|
|
5
|
+
import {
|
|
6
|
+
codexHome
|
|
7
|
+
} from "./chunk-HTYUYKFW.js";
|
|
8
|
+
import {
|
|
9
|
+
collectSubagentUsage
|
|
10
|
+
} from "./chunk-OYD6H3ZZ.js";
|
|
11
|
+
import {
|
|
12
|
+
extractBucket,
|
|
13
|
+
getUsdJpy,
|
|
14
|
+
promptCandidate,
|
|
15
|
+
splitIntoCodexTurnDrafts
|
|
16
|
+
} from "./chunk-D4D76RGQ.js";
|
|
17
|
+
import {
|
|
18
|
+
computeCost,
|
|
19
|
+
loadPriceTable
|
|
20
|
+
} from "./chunk-6HTETN26.js";
|
|
21
|
+
import {
|
|
22
|
+
writeDashboardHtml
|
|
23
|
+
} from "./chunk-4JSRGJCZ.js";
|
|
24
|
+
import "./chunk-DGXUSPS4.js";
|
|
25
|
+
import {
|
|
26
|
+
formatJPY,
|
|
27
|
+
formatUSD,
|
|
28
|
+
modelDisplayName
|
|
29
|
+
} from "./chunk-J5QAYTFE.js";
|
|
30
|
+
import {
|
|
31
|
+
invalidateCanonicalDashboards,
|
|
32
|
+
makeFullDashboardState,
|
|
33
|
+
waitForDataLock,
|
|
34
|
+
writeFullDashboardStateAtomic
|
|
35
|
+
} from "./chunk-27SJELD2.js";
|
|
36
|
+
import {
|
|
37
|
+
appendTurn,
|
|
38
|
+
loadCursor,
|
|
39
|
+
logError,
|
|
40
|
+
paths,
|
|
41
|
+
readConfig,
|
|
42
|
+
readConfigReadOnly,
|
|
43
|
+
readTurns,
|
|
44
|
+
resetHistoryAndCursors,
|
|
45
|
+
sanitizeCursor,
|
|
46
|
+
saveCursor
|
|
47
|
+
} from "./chunk-OOAC5ULQ.js";
|
|
48
|
+
|
|
49
|
+
// src/sweep.ts
|
|
50
|
+
import { readFile } from "fs/promises";
|
|
51
|
+
import { promises as fsp } from "fs";
|
|
52
|
+
import { join } from "path";
|
|
53
|
+
import { homedir } from "os";
|
|
54
|
+
var NEWLINE = 10;
|
|
55
|
+
var MAX_SEEN_KEYS = 500;
|
|
56
|
+
var SYNTHETIC_MODEL = "<synthetic>";
|
|
57
|
+
var DAY_MS = 864e5;
|
|
58
|
+
var SWEEP_PROGRESS_INTERVAL = 25;
|
|
59
|
+
function createSweepProgressReporter() {
|
|
60
|
+
const lastSourceCount = {};
|
|
61
|
+
return (event) => {
|
|
62
|
+
if (event.type === "preparing") {
|
|
63
|
+
console.log(`\u6E96\u5099: \u5358\u4FA1\u8868\u30FB\u70BA\u66FF\u3092\u8AAD\u307F\u8FBC\u307F\u307E\u3059${event.dryRun ? " (dry-run)" : ""}`);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (event.type === "lock") {
|
|
67
|
+
console.log("lock: \u53D6\u5F97\u3092\u5F85\u3063\u3066\u3044\u307E\u3059");
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (event.type === "scan-start") {
|
|
71
|
+
console.log(
|
|
72
|
+
`\u8D70\u67FB\u958B\u59CB: Claude project ${event.claudeProjects} / Codex rollout ${event.codexRollouts}`
|
|
73
|
+
);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (event.type === "source-progress") {
|
|
77
|
+
if (event.completed <= 0 || event.total <= 0) return;
|
|
78
|
+
if (event.completed % SWEEP_PROGRESS_INTERVAL !== 0) return;
|
|
79
|
+
if (lastSourceCount[event.source] === event.completed) return;
|
|
80
|
+
lastSourceCount[event.source] = event.completed;
|
|
81
|
+
const label = event.source === "claude" ? "Claude transcript" : "Codex rollout";
|
|
82
|
+
console.log(`\u8D70\u67FB\u9032\u6357: ${label} ${event.completed}/${event.total}`);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (event.type === "scan-complete") {
|
|
86
|
+
console.log(
|
|
87
|
+
`\u8D70\u67FB\u5B8C\u4E86: Claude transcript ${event.claudeTranscripts} / Codex rollout ${event.codexRollouts} / \u5BFE\u8C61 ${event.records} \u30BF\u30FC\u30F3 / \u5931\u6557 ${event.failures}`
|
|
88
|
+
);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
console.log("dashboard: \u751F\u6210\u958B\u59CB");
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
function isRecord(v) {
|
|
95
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
96
|
+
}
|
|
97
|
+
function strOrNull(v) {
|
|
98
|
+
return typeof v === "string" ? v : null;
|
|
99
|
+
}
|
|
100
|
+
function emptyBuckets() {
|
|
101
|
+
return { input: 0, output: 0, cacheWrite5m: 0, cacheWrite1h: 0, cacheRead: 0 };
|
|
102
|
+
}
|
|
103
|
+
function addToModel(target, model, b) {
|
|
104
|
+
const cur = target[model] ?? emptyBuckets();
|
|
105
|
+
cur.input += b.input;
|
|
106
|
+
cur.output += b.output;
|
|
107
|
+
cur.cacheWrite5m += b.cacheWrite5m;
|
|
108
|
+
cur.cacheWrite1h += b.cacheWrite1h;
|
|
109
|
+
cur.cacheRead += b.cacheRead;
|
|
110
|
+
target[model] = cur;
|
|
111
|
+
}
|
|
112
|
+
function sumBuckets(usage) {
|
|
113
|
+
const total = emptyBuckets();
|
|
114
|
+
for (const b of Object.values(usage)) {
|
|
115
|
+
total.input += b.input;
|
|
116
|
+
total.output += b.output;
|
|
117
|
+
total.cacheWrite5m += b.cacheWrite5m;
|
|
118
|
+
total.cacheWrite1h += b.cacheWrite1h;
|
|
119
|
+
total.cacheRead += b.cacheRead;
|
|
120
|
+
}
|
|
121
|
+
return total;
|
|
122
|
+
}
|
|
123
|
+
function addToBuckets(target, src) {
|
|
124
|
+
target.input += src.input;
|
|
125
|
+
target.output += src.output;
|
|
126
|
+
target.cacheWrite5m += src.cacheWrite5m;
|
|
127
|
+
target.cacheWrite1h += src.cacheWrite1h;
|
|
128
|
+
target.cacheRead += src.cacheRead;
|
|
129
|
+
}
|
|
130
|
+
function collectModels(main, sidechain) {
|
|
131
|
+
const models = [];
|
|
132
|
+
for (const m of Object.keys(main)) if (!models.includes(m)) models.push(m);
|
|
133
|
+
for (const m of Object.keys(sidechain)) if (!models.includes(m)) models.push(m);
|
|
134
|
+
return models;
|
|
135
|
+
}
|
|
136
|
+
function newBuffer() {
|
|
137
|
+
return {
|
|
138
|
+
prompt: null,
|
|
139
|
+
pending: /* @__PURE__ */ new Map(),
|
|
140
|
+
sessionId: "",
|
|
141
|
+
cwd: null,
|
|
142
|
+
gitBranch: null,
|
|
143
|
+
firstTs: null,
|
|
144
|
+
lastTs: null
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
async function readAll(path) {
|
|
148
|
+
try {
|
|
149
|
+
return await readFile(path);
|
|
150
|
+
} catch {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
async function splitIntoTurnDrafts(transcriptPath, cursor) {
|
|
155
|
+
const buffer = await readAll(transcriptPath);
|
|
156
|
+
if (buffer === null) {
|
|
157
|
+
const nc = cursor ?? { offset: 0, lastUuid: null, lastTs: null, seenMessageKeys: [] };
|
|
158
|
+
return { drafts: [], newCursor: nc, messageKeys: [] };
|
|
159
|
+
}
|
|
160
|
+
const fileSize = buffer.length;
|
|
161
|
+
let startOffset;
|
|
162
|
+
let rescan;
|
|
163
|
+
if (cursor !== null && cursor.offset > 0 && cursor.offset <= fileSize && buffer[cursor.offset - 1] === NEWLINE) {
|
|
164
|
+
startOffset = cursor.offset;
|
|
165
|
+
rescan = false;
|
|
166
|
+
} else {
|
|
167
|
+
startOffset = 0;
|
|
168
|
+
rescan = cursor !== null;
|
|
169
|
+
}
|
|
170
|
+
const priorSeen = new Set(cursor?.seenMessageKeys ?? []);
|
|
171
|
+
const tsFloor = cursor?.lastTs ?? null;
|
|
172
|
+
const drafts = [];
|
|
173
|
+
const runSeen = /* @__PURE__ */ new Set();
|
|
174
|
+
const newKeys = [];
|
|
175
|
+
let winLastUuid = null;
|
|
176
|
+
let winLastTs = null;
|
|
177
|
+
let cur = newBuffer();
|
|
178
|
+
const flush = () => {
|
|
179
|
+
if (cur.pending.size === 0) return;
|
|
180
|
+
const mainPerModel = {};
|
|
181
|
+
const sidechainPerModel = {};
|
|
182
|
+
for (const [key, pm] of cur.pending) {
|
|
183
|
+
runSeen.add(key);
|
|
184
|
+
newKeys.push(key);
|
|
185
|
+
if (pm.isSidechain) addToModel(sidechainPerModel, pm.model, pm.bucket);
|
|
186
|
+
else addToModel(mainPerModel, pm.model, pm.bucket);
|
|
187
|
+
}
|
|
188
|
+
drafts.push({
|
|
189
|
+
prompt: cur.prompt ?? "",
|
|
190
|
+
mainPerModel,
|
|
191
|
+
sidechainPerModel,
|
|
192
|
+
apiCalls: cur.pending.size,
|
|
193
|
+
firstTs: cur.firstTs,
|
|
194
|
+
lastTs: cur.lastTs,
|
|
195
|
+
cwd: cur.cwd,
|
|
196
|
+
gitBranch: cur.gitBranch,
|
|
197
|
+
sessionId: cur.sessionId
|
|
198
|
+
});
|
|
199
|
+
};
|
|
200
|
+
const handleLine = (raw) => {
|
|
201
|
+
if (raw.trim().length === 0) return;
|
|
202
|
+
let obj;
|
|
203
|
+
try {
|
|
204
|
+
obj = JSON.parse(raw);
|
|
205
|
+
} catch {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
if (!isRecord(obj)) return;
|
|
209
|
+
const ts = strOrNull(obj.timestamp);
|
|
210
|
+
if (rescan && tsFloor !== null && ts !== null && ts <= tsFloor) return;
|
|
211
|
+
const isSide = obj.isSidechain === true;
|
|
212
|
+
const type = obj.type;
|
|
213
|
+
const message = isRecord(obj.message) ? obj.message : null;
|
|
214
|
+
let isBoundary = false;
|
|
215
|
+
let boundaryPrompt = "";
|
|
216
|
+
if (type === "user" && !isSide && message !== null) {
|
|
217
|
+
const cand = promptCandidate(message.content);
|
|
218
|
+
if (cand !== null) {
|
|
219
|
+
const t = cand.trim();
|
|
220
|
+
if (t.length > 0 && !t.startsWith("<")) {
|
|
221
|
+
isBoundary = true;
|
|
222
|
+
boundaryPrompt = t;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (isBoundary) {
|
|
227
|
+
flush();
|
|
228
|
+
cur = newBuffer();
|
|
229
|
+
cur.prompt = boundaryPrompt;
|
|
230
|
+
}
|
|
231
|
+
const sid = strOrNull(obj.sessionId);
|
|
232
|
+
if (sid !== null) cur.sessionId = sid;
|
|
233
|
+
if (!isSide) {
|
|
234
|
+
const c = strOrNull(obj.cwd);
|
|
235
|
+
if (c !== null) cur.cwd = c;
|
|
236
|
+
const gb = strOrNull(obj.gitBranch);
|
|
237
|
+
if (gb !== null) cur.gitBranch = gb;
|
|
238
|
+
}
|
|
239
|
+
if (ts !== null) {
|
|
240
|
+
if (cur.firstTs === null || ts < cur.firstTs) cur.firstTs = ts;
|
|
241
|
+
if (cur.lastTs === null || ts > cur.lastTs) cur.lastTs = ts;
|
|
242
|
+
if (winLastTs === null || ts > winLastTs) winLastTs = ts;
|
|
243
|
+
}
|
|
244
|
+
const uuid = strOrNull(obj.uuid);
|
|
245
|
+
if (uuid !== null) winLastUuid = uuid;
|
|
246
|
+
if (type === "assistant" && message !== null) {
|
|
247
|
+
const usage = message.usage;
|
|
248
|
+
if (isRecord(usage)) {
|
|
249
|
+
const rawModel = message.model;
|
|
250
|
+
if (rawModel !== SYNTHETIC_MODEL) {
|
|
251
|
+
const id = strOrNull(message.id) ?? "";
|
|
252
|
+
const reqId = strOrNull(obj.requestId) ?? "";
|
|
253
|
+
const key = `${id}:${reqId}`;
|
|
254
|
+
if (!priorSeen.has(key) && !runSeen.has(key)) {
|
|
255
|
+
const model = strOrNull(rawModel) ?? "unknown";
|
|
256
|
+
cur.pending.set(key, { model, isSidechain: isSide, bucket: extractBucket(usage) });
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
let lineStart = startOffset;
|
|
263
|
+
for (let pos = startOffset; pos < fileSize; pos++) {
|
|
264
|
+
if (buffer[pos] !== NEWLINE) continue;
|
|
265
|
+
handleLine(buffer.toString("utf8", lineStart, pos));
|
|
266
|
+
lineStart = pos + 1;
|
|
267
|
+
}
|
|
268
|
+
const newOffset = lineStart;
|
|
269
|
+
flush();
|
|
270
|
+
const combined = [...cursor?.seenMessageKeys ?? [], ...newKeys];
|
|
271
|
+
const seenMessageKeys = combined.length > MAX_SEEN_KEYS ? combined.slice(combined.length - MAX_SEEN_KEYS) : combined;
|
|
272
|
+
const newCursor = {
|
|
273
|
+
offset: newOffset,
|
|
274
|
+
lastUuid: winLastUuid,
|
|
275
|
+
lastTs: winLastTs,
|
|
276
|
+
seenMessageKeys
|
|
277
|
+
};
|
|
278
|
+
return { drafts, newCursor, messageKeys: newKeys };
|
|
279
|
+
}
|
|
280
|
+
function draftToRecord(draft, ts, table, fx) {
|
|
281
|
+
const breakdown = computeCost(draft.mainPerModel, draft.sidechainPerModel, table);
|
|
282
|
+
const sidechainHasModels = Object.keys(draft.sidechainPerModel).length > 0;
|
|
283
|
+
const rec = {
|
|
284
|
+
schemaVersion: 1,
|
|
285
|
+
ts,
|
|
286
|
+
sessionId: draft.sessionId,
|
|
287
|
+
project: draft.cwd ?? "",
|
|
288
|
+
gitBranch: draft.gitBranch,
|
|
289
|
+
models: collectModels(draft.mainPerModel, draft.sidechainPerModel),
|
|
290
|
+
tokens: sumBuckets(draft.mainPerModel),
|
|
291
|
+
sidechainTokens: sidechainHasModels ? sumBuckets(draft.sidechainPerModel) : null,
|
|
292
|
+
apiCalls: draft.apiCalls,
|
|
293
|
+
costUSD: breakdown.usd,
|
|
294
|
+
costByModel: breakdown.byModel,
|
|
295
|
+
costJPY: breakdown.usd * fx.rate,
|
|
296
|
+
// 円換算は sweep 実行時レート
|
|
297
|
+
fxRate: fx.rate,
|
|
298
|
+
fxSource: fx.source,
|
|
299
|
+
prompt: draft.prompt,
|
|
300
|
+
ingest: "sweep"
|
|
301
|
+
};
|
|
302
|
+
if (breakdown.unknownModels.length > 0) rec.unknownModels = breakdown.unknownModels;
|
|
303
|
+
return rec;
|
|
304
|
+
}
|
|
305
|
+
function mergeUnknownModels(rec, extra) {
|
|
306
|
+
if (extra.length === 0) return;
|
|
307
|
+
const merged = rec.unknownModels ? [...rec.unknownModels] : [];
|
|
308
|
+
for (const m of extra) if (!merged.includes(m)) merged.push(m);
|
|
309
|
+
rec.unknownModels = merged;
|
|
310
|
+
}
|
|
311
|
+
async function processTranscriptLocked(mainPath, table, fx, daysCutoff, dryRun, summary, opts = {}) {
|
|
312
|
+
if (opts.strictRead) {
|
|
313
|
+
const file = await fsp.open(mainPath, "r");
|
|
314
|
+
await file.close();
|
|
315
|
+
}
|
|
316
|
+
const cursor = opts.ignoreCursors ? null : sanitizeCursor(loadCursor(mainPath));
|
|
317
|
+
const { drafts, newCursor, messageKeys } = await splitIntoTurnDrafts(mainPath, cursor);
|
|
318
|
+
const records = [];
|
|
319
|
+
for (const draft of drafts) {
|
|
320
|
+
const ts = draft.lastTs ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
321
|
+
if (daysCutoff !== null) {
|
|
322
|
+
const tsMs = Date.parse(ts);
|
|
323
|
+
if (!Number.isFinite(tsMs) || tsMs < daysCutoff) continue;
|
|
324
|
+
}
|
|
325
|
+
records.push(draftToRecord(draft, ts, table, fx));
|
|
326
|
+
}
|
|
327
|
+
let sa = null;
|
|
328
|
+
try {
|
|
329
|
+
sa = await collectSubagentUsage(mainPath, {
|
|
330
|
+
ignoreCursors: opts.ignoreCursors,
|
|
331
|
+
strictRead: opts.strictRead,
|
|
332
|
+
includeAllFiles: opts.ignoreCursors,
|
|
333
|
+
excludeMessageKeys: new Set(messageKeys),
|
|
334
|
+
minTimestampMs: daysCutoff
|
|
335
|
+
});
|
|
336
|
+
} catch (err) {
|
|
337
|
+
if (opts.strictRead) throw err;
|
|
338
|
+
logError("sweep:subagents", err);
|
|
339
|
+
sa = null;
|
|
340
|
+
}
|
|
341
|
+
const saHasUsage = sa !== null && sa.apiCalls > 0;
|
|
342
|
+
if (saHasUsage) {
|
|
343
|
+
const parentRecords = [...records];
|
|
344
|
+
for (const group of sa.groups) {
|
|
345
|
+
const saBreakdown = computeCost(group.perModel, {}, table);
|
|
346
|
+
summary.subagentsUSD += saBreakdown.usd;
|
|
347
|
+
const saBlock = {
|
|
348
|
+
costUSD: saBreakdown.usd,
|
|
349
|
+
costByModel: { ...saBreakdown.byModel },
|
|
350
|
+
tokens: sumBuckets(group.perModel),
|
|
351
|
+
apiCalls: group.apiCalls,
|
|
352
|
+
agentFiles: 1
|
|
353
|
+
};
|
|
354
|
+
const groupMs = group.lastTs === null ? NaN : Date.parse(group.lastTs);
|
|
355
|
+
let target;
|
|
356
|
+
if (Number.isFinite(groupMs)) {
|
|
357
|
+
target = parentRecords.find((rec) => {
|
|
358
|
+
const recMs = Date.parse(rec.ts);
|
|
359
|
+
return Number.isFinite(recMs) && recMs >= groupMs;
|
|
360
|
+
});
|
|
361
|
+
} else {
|
|
362
|
+
target = parentRecords[parentRecords.length - 1];
|
|
363
|
+
}
|
|
364
|
+
if (target === void 0) {
|
|
365
|
+
target = {
|
|
366
|
+
schemaVersion: 1,
|
|
367
|
+
ts: group.lastTs ?? sa.lastTs ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
368
|
+
sessionId: sa.sessionId,
|
|
369
|
+
project: sa.cwd ?? "",
|
|
370
|
+
gitBranch: sa.gitBranch,
|
|
371
|
+
models: collectModels(group.perModel, {}),
|
|
372
|
+
tokens: emptyBuckets(),
|
|
373
|
+
sidechainTokens: null,
|
|
374
|
+
apiCalls: 0,
|
|
375
|
+
costUSD: 0,
|
|
376
|
+
costByModel: {},
|
|
377
|
+
costJPY: 0,
|
|
378
|
+
fxRate: fx.rate,
|
|
379
|
+
fxSource: fx.source,
|
|
380
|
+
prompt: "",
|
|
381
|
+
ingest: "sweep"
|
|
382
|
+
};
|
|
383
|
+
records.push(target);
|
|
384
|
+
}
|
|
385
|
+
if (target.subagents === void 0) {
|
|
386
|
+
target.subagents = saBlock;
|
|
387
|
+
} else {
|
|
388
|
+
target.subagents.costUSD += saBlock.costUSD;
|
|
389
|
+
target.subagents.apiCalls += saBlock.apiCalls;
|
|
390
|
+
target.subagents.agentFiles += 1;
|
|
391
|
+
addToBuckets(target.subagents.tokens, saBlock.tokens);
|
|
392
|
+
for (const [model, usd] of Object.entries(saBlock.costByModel)) {
|
|
393
|
+
target.subagents.costByModel[model] = (target.subagents.costByModel[model] ?? 0) + usd;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
mergeUnknownModels(target, saBreakdown.unknownModels);
|
|
397
|
+
}
|
|
398
|
+
summary.agentFiles += sa.agentFiles;
|
|
399
|
+
}
|
|
400
|
+
for (const rec of records) {
|
|
401
|
+
summary.newRecords += 1;
|
|
402
|
+
summary.totalUSD += rec.costUSD;
|
|
403
|
+
if (rec.costByModel) {
|
|
404
|
+
for (const [m, c] of Object.entries(rec.costByModel)) {
|
|
405
|
+
summary.byModel[m] = (summary.byModel[m] ?? 0) + c;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
if (!dryRun) {
|
|
410
|
+
for (const rec of records) appendTurn(rec);
|
|
411
|
+
if (drafts.length > 0) saveCursor(mainPath, newCursor);
|
|
412
|
+
if (sa !== null) {
|
|
413
|
+
for (const nc of sa.newCursors) saveCursor(nc.path, nc.cursor);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
function codexDraftToRecord(draft, ts, table, fx) {
|
|
418
|
+
const main = draft.agg.main;
|
|
419
|
+
const breakdown = computeCost(main, {}, table);
|
|
420
|
+
const rec = {
|
|
421
|
+
schemaVersion: 1,
|
|
422
|
+
ts,
|
|
423
|
+
sessionId: draft.agg.sessionId,
|
|
424
|
+
project: draft.agg.cwd ?? "",
|
|
425
|
+
gitBranch: null,
|
|
426
|
+
// rollout に git 情報は無い
|
|
427
|
+
models: collectModels(main, {}),
|
|
428
|
+
tokens: sumBuckets(main),
|
|
429
|
+
sidechainTokens: null,
|
|
430
|
+
apiCalls: draft.agg.apiCalls,
|
|
431
|
+
costUSD: breakdown.usd,
|
|
432
|
+
costByModel: breakdown.byModel,
|
|
433
|
+
costJPY: breakdown.usd * fx.rate,
|
|
434
|
+
// 円換算は sweep 実行時レート(Claude 側と同じ)
|
|
435
|
+
fxRate: fx.rate,
|
|
436
|
+
fxSource: fx.source,
|
|
437
|
+
prompt: draft.agg.prompt ?? "",
|
|
438
|
+
ingest: "sweep",
|
|
439
|
+
source: "codex"
|
|
440
|
+
};
|
|
441
|
+
if (breakdown.unknownModels.length > 0) rec.unknownModels = breakdown.unknownModels;
|
|
442
|
+
return rec;
|
|
443
|
+
}
|
|
444
|
+
async function processCodexRolloutLocked(rolloutPath, table, fx, daysCutoff, dryRun, summary, opts = {}) {
|
|
445
|
+
if (opts.strictRead) {
|
|
446
|
+
const file = await fsp.open(rolloutPath, "r");
|
|
447
|
+
await file.close();
|
|
448
|
+
}
|
|
449
|
+
const cursor = opts.ignoreCursors ? null : sanitizeCursor(loadCursor(rolloutPath));
|
|
450
|
+
const drafts = await splitIntoCodexTurnDrafts(rolloutPath, cursor);
|
|
451
|
+
if (drafts === null || drafts.length === 0) return;
|
|
452
|
+
if (drafts[0].isSubagentRollout) return;
|
|
453
|
+
const records = [];
|
|
454
|
+
for (const draft of drafts) {
|
|
455
|
+
const ts = draft.endTs ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
456
|
+
if (daysCutoff !== null) {
|
|
457
|
+
const tsMs = Date.parse(ts);
|
|
458
|
+
if (!Number.isFinite(tsMs) || tsMs < daysCutoff) continue;
|
|
459
|
+
}
|
|
460
|
+
records.push(codexDraftToRecord(draft, ts, table, fx));
|
|
461
|
+
}
|
|
462
|
+
for (const rec of records) {
|
|
463
|
+
summary.newRecords += 1;
|
|
464
|
+
summary.totalUSD += rec.costUSD;
|
|
465
|
+
summary.codexRecords += 1;
|
|
466
|
+
summary.codexUSD += rec.costUSD;
|
|
467
|
+
if (rec.costByModel) {
|
|
468
|
+
for (const [m, c] of Object.entries(rec.costByModel)) {
|
|
469
|
+
summary.byModel[m] = (summary.byModel[m] ?? 0) + c;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
if (!dryRun) {
|
|
474
|
+
for (const rec of records) appendTurn(rec);
|
|
475
|
+
saveCursor(rolloutPath, drafts[drafts.length - 1].agg.newCursor);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
function isMissingPathError(err) {
|
|
479
|
+
return err?.code === "ENOENT";
|
|
480
|
+
}
|
|
481
|
+
async function discoverCodexSweepSource() {
|
|
482
|
+
const home = codexHome();
|
|
483
|
+
let homeStat;
|
|
484
|
+
try {
|
|
485
|
+
homeStat = await fsp.lstat(home);
|
|
486
|
+
} catch (err) {
|
|
487
|
+
if (isMissingPathError(err)) return null;
|
|
488
|
+
return { discovery: { rollouts: [], unreadableDirs: 1 } };
|
|
489
|
+
}
|
|
490
|
+
if (!homeStat.isDirectory()) {
|
|
491
|
+
return { discovery: { rollouts: [], unreadableDirs: 1 } };
|
|
492
|
+
}
|
|
493
|
+
const sessionsRoot = join(home, "sessions");
|
|
494
|
+
try {
|
|
495
|
+
await fsp.lstat(sessionsRoot);
|
|
496
|
+
} catch (err) {
|
|
497
|
+
if (isMissingPathError(err)) return null;
|
|
498
|
+
return { discovery: { rollouts: [], unreadableDirs: 1 } };
|
|
499
|
+
}
|
|
500
|
+
return { discovery: await listCodexRollouts(sessionsRoot) };
|
|
501
|
+
}
|
|
502
|
+
function projectsRoot(override) {
|
|
503
|
+
if (override) return override;
|
|
504
|
+
return process.env.CCCN_CLAUDE_PROJECTS || join(homedir(), ".claude", "projects");
|
|
505
|
+
}
|
|
506
|
+
function parseSweepFlags(argv) {
|
|
507
|
+
const flags = {
|
|
508
|
+
dryRun: false,
|
|
509
|
+
days: null,
|
|
510
|
+
projects: null
|
|
511
|
+
};
|
|
512
|
+
for (let i = 0; i < argv.length; i++) {
|
|
513
|
+
const a = argv[i];
|
|
514
|
+
if (a === "--dry-run") {
|
|
515
|
+
flags.dryRun = true;
|
|
516
|
+
} else if (a === "--days" || a.startsWith("--days=")) {
|
|
517
|
+
const v = a.includes("=") ? a.slice("--days=".length) : argv[++i];
|
|
518
|
+
if (v === void 0 || v.length === 0) return { error: "--days \u306B\u306F\u5024\u304C\u5FC5\u8981\u3067\u3059" };
|
|
519
|
+
const n = Number(v);
|
|
520
|
+
if (!Number.isFinite(n) || n < 0) return { error: "--days \u306F0\u4EE5\u4E0A\u306E\u6570\u3067\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044" };
|
|
521
|
+
flags.days = n;
|
|
522
|
+
} else if (a === "--projects" || a.startsWith("--projects=")) {
|
|
523
|
+
const v = a.includes("=") ? a.slice("--projects=".length) : argv[++i];
|
|
524
|
+
if (!v) return { error: "--projects \u306B\u306F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u304C\u5FC5\u8981\u3067\u3059" };
|
|
525
|
+
flags.projects = v;
|
|
526
|
+
} else {
|
|
527
|
+
return { error: `\u4E0D\u660E\u306Aoption\u307E\u305F\u306F\u4F59\u5206\u306A\u5F15\u6570\u3067\u3059: ${a}` };
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
return { flags };
|
|
531
|
+
}
|
|
532
|
+
async function listProjectDirs(root) {
|
|
533
|
+
try {
|
|
534
|
+
const entries = await fsp.readdir(root, { withFileTypes: true });
|
|
535
|
+
return entries.filter((e) => e.isDirectory()).map((e) => join(root, e.name));
|
|
536
|
+
} catch {
|
|
537
|
+
return null;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
async function listTranscriptsStrict(projectDir) {
|
|
541
|
+
try {
|
|
542
|
+
const entries = await fsp.readdir(projectDir, { withFileTypes: true });
|
|
543
|
+
return entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => join(projectDir, e.name));
|
|
544
|
+
} catch {
|
|
545
|
+
return null;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
function printSweepSummary(summary, fx) {
|
|
549
|
+
if (summary.dryRun) {
|
|
550
|
+
console.log("(dry-run: \u66F8\u304D\u8FBC\u307F\u306F\u884C\u3063\u3066\u3044\u307E\u305B\u3093)");
|
|
551
|
+
}
|
|
552
|
+
console.log(
|
|
553
|
+
`\u8D70\u67FB: \u30D7\u30ED\u30B8\u30A7\u30AF\u30C8 ${summary.projects} / transcript ${summary.transcripts} / \u30B5\u30D6\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8\u30D5\u30A1\u30A4\u30EB ${summary.agentFiles}`
|
|
554
|
+
);
|
|
555
|
+
if (summary.newRecords === 0) {
|
|
556
|
+
console.log("\u518D\u751F\u6210\u5BFE\u8C61\u306F\u3042\u308A\u307E\u305B\u3093\u3067\u3057\u305F");
|
|
557
|
+
} else {
|
|
558
|
+
console.log(
|
|
559
|
+
`\u518D\u751F\u6210: ${summary.newRecords} \u30BF\u30FC\u30F3\u3001\u5408\u8A08 ${formatUSD(summary.totalUSD)}(${formatJPY(summary.totalJPY)})`
|
|
560
|
+
);
|
|
561
|
+
if (summary.subagentsUSD > 0) {
|
|
562
|
+
console.log(
|
|
563
|
+
` \u3046\u3061\u30B5\u30D6\u30A8\u30FC\u30B8\u30A7\u30F3\u30C8: ${formatUSD(summary.subagentsUSD)}(${formatJPY(summary.subagentsUSD * fx.rate)})`
|
|
564
|
+
);
|
|
565
|
+
}
|
|
566
|
+
if (summary.codexRecords > 0) {
|
|
567
|
+
console.log(
|
|
568
|
+
` Codex: ${summary.codexRecords} \u30BF\u30FC\u30F3 ${formatUSD(summary.codexUSD)}(${formatJPY(summary.codexUSD * fx.rate)})`
|
|
569
|
+
);
|
|
570
|
+
}
|
|
571
|
+
const top = Object.entries(summary.byModel).filter(([, c]) => c > 0).sort((a, b) => b[1] - a[1]).slice(0, 5);
|
|
572
|
+
if (top.length > 0) {
|
|
573
|
+
console.log(" \u30E2\u30C7\u30EB\u5225(\u4E0A\u4F4D):");
|
|
574
|
+
for (const [m, c] of top) {
|
|
575
|
+
console.log(` ${modelDisplayName(m)}: ${formatUSD(c)}`);
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
console.log(`\u5186\u63DB\u7B97\u30EC\u30FC\u30C8: 1USD = ${fx.rate}JPY(source=${fx.source})`);
|
|
580
|
+
}
|
|
581
|
+
function reportSourceFailure(summary, dryRun, scope, err, count = 1) {
|
|
582
|
+
summary.sourceFailures += count;
|
|
583
|
+
if (dryRun) {
|
|
584
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
585
|
+
console.error(`${scope}: ${message}`);
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
logError(scope, err);
|
|
589
|
+
}
|
|
590
|
+
async function scanAllSources(projectDirs, codexSource, table, fx, daysCutoff, dryRun, summary, progress) {
|
|
591
|
+
const codexRollouts = codexSource?.discovery.rollouts.length ?? 0;
|
|
592
|
+
progress({
|
|
593
|
+
type: "scan-start",
|
|
594
|
+
claudeProjects: projectDirs?.length ?? 0,
|
|
595
|
+
codexRollouts
|
|
596
|
+
});
|
|
597
|
+
const transcriptPaths = [];
|
|
598
|
+
for (const projectDir of projectDirs ?? []) {
|
|
599
|
+
const transcripts = await listTranscriptsStrict(projectDir);
|
|
600
|
+
if (transcripts === null) {
|
|
601
|
+
reportSourceFailure(
|
|
602
|
+
summary,
|
|
603
|
+
dryRun,
|
|
604
|
+
"sweep:discovery",
|
|
605
|
+
new Error(`cannot read project: ${projectDir}`)
|
|
606
|
+
);
|
|
607
|
+
continue;
|
|
608
|
+
}
|
|
609
|
+
transcriptPaths.push(...transcripts);
|
|
610
|
+
}
|
|
611
|
+
for (const mainPath of transcriptPaths) {
|
|
612
|
+
summary.transcripts += 1;
|
|
613
|
+
try {
|
|
614
|
+
await processTranscriptLocked(mainPath, table, fx, daysCutoff, dryRun, summary, {
|
|
615
|
+
ignoreCursors: true,
|
|
616
|
+
strictRead: true
|
|
617
|
+
});
|
|
618
|
+
} catch (err) {
|
|
619
|
+
reportSourceFailure(summary, dryRun, "sweep:transcript", err);
|
|
620
|
+
}
|
|
621
|
+
progress({
|
|
622
|
+
type: "source-progress",
|
|
623
|
+
source: "claude",
|
|
624
|
+
completed: summary.transcripts,
|
|
625
|
+
total: transcriptPaths.length
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
let completedCodexRollouts = 0;
|
|
629
|
+
if (codexSource !== null) {
|
|
630
|
+
const { discovery } = codexSource;
|
|
631
|
+
if (discovery.unreadableDirs > 0) {
|
|
632
|
+
reportSourceFailure(
|
|
633
|
+
summary,
|
|
634
|
+
dryRun,
|
|
635
|
+
"sweep:codex-discovery",
|
|
636
|
+
new Error(`${discovery.unreadableDirs} directories could not be read`),
|
|
637
|
+
discovery.unreadableDirs
|
|
638
|
+
);
|
|
639
|
+
}
|
|
640
|
+
for (const rolloutPath of discovery.rollouts) {
|
|
641
|
+
try {
|
|
642
|
+
await processCodexRolloutLocked(rolloutPath, table, fx, daysCutoff, dryRun, summary, {
|
|
643
|
+
ignoreCursors: true,
|
|
644
|
+
strictRead: true
|
|
645
|
+
});
|
|
646
|
+
} catch (err) {
|
|
647
|
+
reportSourceFailure(summary, dryRun, "sweep:codex", err);
|
|
648
|
+
}
|
|
649
|
+
completedCodexRollouts += 1;
|
|
650
|
+
progress({
|
|
651
|
+
type: "source-progress",
|
|
652
|
+
source: "codex",
|
|
653
|
+
completed: completedCodexRollouts,
|
|
654
|
+
total: codexRollouts
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
progress({
|
|
659
|
+
type: "scan-complete",
|
|
660
|
+
claudeTranscripts: summary.transcripts,
|
|
661
|
+
codexRollouts: completedCodexRollouts,
|
|
662
|
+
records: summary.newRecords,
|
|
663
|
+
failures: summary.sourceFailures
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
async function runSweep(argv, deps = {}) {
|
|
667
|
+
const parsed = parseSweepFlags(argv);
|
|
668
|
+
if ("error" in parsed) {
|
|
669
|
+
console.error(`${parsed.error}
|
|
670
|
+
\u4F7F\u3044\u65B9 / Usage: ccc-notifier sweep [--dry-run] [--days N] [--projects DIR]`);
|
|
671
|
+
return 1;
|
|
672
|
+
}
|
|
673
|
+
const flags = parsed.flags;
|
|
674
|
+
const progress = createSweepProgressReporter();
|
|
675
|
+
const root = projectsRoot(flags.projects);
|
|
676
|
+
const projectDirs = await listProjectDirs(root);
|
|
677
|
+
const codexSource = await discoverCodexSweepSource();
|
|
678
|
+
if (projectDirs === null) {
|
|
679
|
+
if (codexSource === null || codexSource.discovery.unreadableDirs > 0) {
|
|
680
|
+
console.log(`\u8D70\u67FB\u30EB\u30FC\u30C8\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093: ${root}`);
|
|
681
|
+
return 1;
|
|
682
|
+
}
|
|
683
|
+
console.log(`Claude \u306E\u8D70\u67FB\u30EB\u30FC\u30C8\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093: ${root}(Codex \u306E\u307F\u8D70\u67FB\u3057\u307E\u3059)`);
|
|
684
|
+
}
|
|
685
|
+
progress({ type: "preparing", dryRun: flags.dryRun });
|
|
686
|
+
const cfg = flags.dryRun ? readConfigReadOnly((err) => {
|
|
687
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
688
|
+
console.error(`sweep:config: ${message}(\u65E2\u5B9A\u5024\u3067\u7D9A\u884C\u3057\u307E\u3059)`);
|
|
689
|
+
}) : readConfig();
|
|
690
|
+
const cacheDir = paths().cacheDir;
|
|
691
|
+
const table = await loadPriceTable(cacheDir, { offline: false });
|
|
692
|
+
const fx = await getUsdJpy(cfg, cacheDir);
|
|
693
|
+
const summary = {
|
|
694
|
+
projects: projectDirs === null ? 0 : projectDirs.length,
|
|
695
|
+
transcripts: 0,
|
|
696
|
+
agentFiles: 0,
|
|
697
|
+
newRecords: 0,
|
|
698
|
+
totalUSD: 0,
|
|
699
|
+
totalJPY: 0,
|
|
700
|
+
subagentsUSD: 0,
|
|
701
|
+
byModel: {},
|
|
702
|
+
codexRecords: 0,
|
|
703
|
+
codexUSD: 0,
|
|
704
|
+
dryRun: flags.dryRun,
|
|
705
|
+
sourceFailures: 0
|
|
706
|
+
};
|
|
707
|
+
const daysCutoff = flags.days !== null ? Date.now() - flags.days * DAY_MS : null;
|
|
708
|
+
const lockProvider = deps.lockProvider ?? (() => waitForDataLock());
|
|
709
|
+
if (flags.dryRun) {
|
|
710
|
+
try {
|
|
711
|
+
await scanAllSources(projectDirs, codexSource, table, fx, daysCutoff, true, summary, progress);
|
|
712
|
+
} catch (err) {
|
|
713
|
+
reportSourceFailure(summary, true, "sweep:dry-run", err);
|
|
714
|
+
}
|
|
715
|
+
summary.totalJPY = summary.totalUSD * fx.rate;
|
|
716
|
+
printSweepSummary(summary, fx);
|
|
717
|
+
if (summary.sourceFailures > 0) {
|
|
718
|
+
console.error(
|
|
719
|
+
`\u4E00\u90E8\u3092\u8D70\u67FB\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F(${summary.sourceFailures}\u4EF6\u5931\u6557)\u3002source\u3092\u78BA\u8A8D\u3057\u3066\u540C\u3058 ccc-notifier sweep --dry-run \u3092\u518D\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044`
|
|
720
|
+
);
|
|
721
|
+
return 1;
|
|
722
|
+
}
|
|
723
|
+
return 0;
|
|
724
|
+
}
|
|
725
|
+
progress({ type: "lock" });
|
|
726
|
+
const lock = await lockProvider();
|
|
727
|
+
if (lock === null) {
|
|
728
|
+
console.error("\u5168\u518D\u751F\u6210\u306Edata lock\u3092\u53D6\u5F97\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u5F8C\u3067\u3082\u3046\u4E00\u5EA6\u304A\u8A66\u3057\u304F\u3060\u3055\u3044");
|
|
729
|
+
return 1;
|
|
730
|
+
}
|
|
731
|
+
let dashboardFailure = false;
|
|
732
|
+
try {
|
|
733
|
+
invalidateCanonicalDashboards();
|
|
734
|
+
resetHistoryAndCursors();
|
|
735
|
+
await scanAllSources(projectDirs, codexSource, table, fx, daysCutoff, false, summary, progress);
|
|
736
|
+
try {
|
|
737
|
+
invalidateCanonicalDashboards();
|
|
738
|
+
if (summary.sourceFailures === 0 && cfg.dashboard.autoRegenerate) {
|
|
739
|
+
progress({ type: "dashboard-start" });
|
|
740
|
+
const generatedAt = /* @__PURE__ */ new Date();
|
|
741
|
+
const generatedAtIso = generatedAt.toISOString();
|
|
742
|
+
const allTurns = readTurns();
|
|
743
|
+
writeDashboardHtml({
|
|
744
|
+
days: cfg.dashboard.days,
|
|
745
|
+
outPath: paths().recentDashboardFile,
|
|
746
|
+
autoReloadSec: cfg.dashboard.autoReloadSec,
|
|
747
|
+
allTurns,
|
|
748
|
+
variant: "recent",
|
|
749
|
+
generatedAt: generatedAtIso
|
|
750
|
+
});
|
|
751
|
+
writeDashboardHtml({
|
|
752
|
+
days: null,
|
|
753
|
+
outPath: paths().fullDashboardFile,
|
|
754
|
+
autoReloadSec: cfg.dashboard.autoReloadSec,
|
|
755
|
+
allTurns,
|
|
756
|
+
variant: "full",
|
|
757
|
+
generatedAt: generatedAtIso
|
|
758
|
+
});
|
|
759
|
+
writeFullDashboardStateAtomic(makeFullDashboardState(generatedAt));
|
|
760
|
+
}
|
|
761
|
+
} catch (err) {
|
|
762
|
+
dashboardFailure = true;
|
|
763
|
+
logError("sweep:dashboard", err);
|
|
764
|
+
try {
|
|
765
|
+
invalidateCanonicalDashboards();
|
|
766
|
+
} catch (invalidateErr) {
|
|
767
|
+
logError("sweep:dashboard-invalidate", invalidateErr);
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
} catch (err) {
|
|
771
|
+
reportSourceFailure(summary, false, "sweep", err);
|
|
772
|
+
} finally {
|
|
773
|
+
lock.release();
|
|
774
|
+
}
|
|
775
|
+
summary.totalJPY = summary.totalUSD * fx.rate;
|
|
776
|
+
printSweepSummary(summary, fx);
|
|
777
|
+
if (summary.sourceFailures > 0) {
|
|
778
|
+
console.error(
|
|
779
|
+
`\u4E00\u90E8\u518D\u751F\u6210\u3067\u3059(${summary.sourceFailures}\u4EF6\u5931\u6557)\u3002\u540C\u3058 ccc-notifier sweep \u3092\u518D\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044 / partial regeneration; retry`
|
|
780
|
+
);
|
|
781
|
+
return 1;
|
|
782
|
+
}
|
|
783
|
+
if (dashboardFailure) {
|
|
784
|
+
console.error(
|
|
785
|
+
"\u5C65\u6B74\u306F\u518D\u751F\u6210\u6E08\u307F\u3067\u3059\u304C\u3001\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9\u3092\u751F\u6210\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002ccc-notifier dashboard \u3068 ccc-notifier dashboard --all \u3092\u624B\u52D5\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044"
|
|
786
|
+
);
|
|
787
|
+
return 1;
|
|
788
|
+
}
|
|
789
|
+
console.log("\u5C65\u6B74\u3068\u53D6\u308A\u8FBC\u307F\u4F4D\u7F6E\u3092\u5143JSONL\u304B\u3089\u5168\u518D\u751F\u6210\u3057\u307E\u3057\u305F");
|
|
790
|
+
return 0;
|
|
791
|
+
}
|
|
792
|
+
export {
|
|
793
|
+
runSweep,
|
|
794
|
+
splitIntoTurnDrafts
|
|
795
|
+
};
|