ccc-notifier 0.6.2 → 0.7.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 +5 -0
- package/dist/{budget-V7CCMJHF.js → budget-O4VAP6RB.js} +2 -2
- package/dist/chunk-3M5UQK76.js +92 -0
- package/dist/{sweep-65D57PXU.js → chunk-6BXD6HU5.js} +275 -113
- package/dist/chunk-6IVSZ3S4.js +22 -0
- package/dist/{chunk-NV5UOHJA.js → chunk-JLDI4D5E.js} +5 -5
- package/dist/{chunk-T6Z2ZAN4.js → chunk-ML5H43NH.js} +1 -1
- package/dist/{chunk-6UZXXO5J.js → chunk-O2E4VTDR.js} +36 -9
- package/dist/{chunk-D4D76RGQ.js → chunk-OCKZZVOG.js} +353 -20
- package/dist/{chunk-27SJELD2.js → chunk-PXMXEFM7.js} +22 -107
- package/dist/{chunk-6HTETN26.js → chunk-Q45AAPJY.js} +18 -1
- package/dist/chunk-V4IS4FXH.js +454 -0
- package/dist/{chunk-OOAC5ULQ.js → chunk-WONMZ466.js} +184 -4
- package/dist/{chunk-OXXDZZPJ.js → chunk-X7U63BZG.js} +4 -6
- package/dist/{chunk-J5QAYTFE.js → chunk-XG73C6CC.js} +10 -1
- package/dist/cli.js +286 -29
- package/dist/{dashboard-VEKQ4TI3.js → dashboard-64XHDUVT.js} +6 -4
- package/dist/{history-DL4SG3PG.js → history-W34EJOVV.js} +5 -3
- package/dist/{mute-UIR5P5N5.js → mute-23BWQXS3.js} +2 -2
- package/dist/reset-cursors-5CCM6MQL.js +41 -0
- package/dist/scan-UB6ORRZK.js +87 -0
- package/dist/{setup-I3JNGWZG.js → setup-VLMW433R.js} +5 -6
- package/dist/{subagent-store-US4TJJQR.js → subagent-store-USG3WJEB.js} +1 -1
- package/dist/sweep-DVOV4XIZ.js +20 -0
- package/dist/track-P6A5WDJZ.js +368 -0
- package/package.json +1 -1
- package/dist/chunk-HLJAJS2W.js +0 -55
- package/dist/chunk-HTYUYKFW.js +0 -21
- package/dist/chunk-OYD6H3ZZ.js +0 -124
- package/dist/track-WCP7446C.js +0 -257
package/dist/cli.js
CHANGED
|
@@ -1,34 +1,37 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
fmtMuteUntil
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-ML5H43NH.js";
|
|
5
5
|
import {
|
|
6
6
|
CODEX_HOOK_EVENTS,
|
|
7
7
|
CODEX_HOOK_TIMEOUT_SECONDS,
|
|
8
8
|
matchesMarker,
|
|
9
9
|
parseConfiguredOwnedCodexHookCommand
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-X7U63BZG.js";
|
|
11
11
|
import {
|
|
12
12
|
notifyOS,
|
|
13
13
|
notifySlack,
|
|
14
14
|
selectNotifyBackend
|
|
15
|
-
} from "./chunk-
|
|
16
|
-
import {
|
|
17
|
-
findLatestCodexRollout
|
|
18
|
-
} from "./chunk-HLJAJS2W.js";
|
|
19
|
-
import {
|
|
20
|
-
codexHome,
|
|
21
|
-
detectCodex
|
|
22
|
-
} from "./chunk-HTYUYKFW.js";
|
|
15
|
+
} from "./chunk-JLDI4D5E.js";
|
|
23
16
|
import {
|
|
24
17
|
aggregateNewTurn,
|
|
18
|
+
claudeTranscriptRoots,
|
|
19
|
+
findLatestCodexRollout,
|
|
25
20
|
getUsdJpy,
|
|
21
|
+
listCodexRollouts,
|
|
22
|
+
rootForClaudePath,
|
|
26
23
|
splitIntoCodexTurnDrafts
|
|
27
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-OCKZZVOG.js";
|
|
28
25
|
import {
|
|
26
|
+
codexHome,
|
|
29
27
|
computeCost,
|
|
28
|
+
detectCodex,
|
|
30
29
|
loadPriceTable
|
|
31
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-Q45AAPJY.js";
|
|
31
|
+
import {
|
|
32
|
+
effectiveSurface,
|
|
33
|
+
surfaceLabel
|
|
34
|
+
} from "./chunk-6IVSZ3S4.js";
|
|
32
35
|
import {
|
|
33
36
|
isWSL
|
|
34
37
|
} from "./chunk-DGXUSPS4.js";
|
|
@@ -36,14 +39,16 @@ import {
|
|
|
36
39
|
formatJPY,
|
|
37
40
|
formatTokens,
|
|
38
41
|
formatUSD
|
|
39
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-XG73C6CC.js";
|
|
40
43
|
import {
|
|
44
|
+
cursorPaths,
|
|
45
|
+
hasUnresolvedPendingMarker,
|
|
41
46
|
isMuted,
|
|
42
47
|
paths,
|
|
43
48
|
readConfig,
|
|
44
49
|
readMuteState,
|
|
45
50
|
readTurns
|
|
46
|
-
} from "./chunk-
|
|
51
|
+
} from "./chunk-WONMZ466.js";
|
|
47
52
|
|
|
48
53
|
// src/cli.ts
|
|
49
54
|
import { realpathSync as realpathSync2 } from "fs";
|
|
@@ -52,7 +57,7 @@ import { fileURLToPath, pathToFileURL } from "url";
|
|
|
52
57
|
|
|
53
58
|
// src/doctor.ts
|
|
54
59
|
import { existsSync as existsSync2, readdirSync, statSync as statSync2 } from "fs";
|
|
55
|
-
import { readFile } from "fs/promises";
|
|
60
|
+
import { open, readFile } from "fs/promises";
|
|
56
61
|
import { homedir } from "os";
|
|
57
62
|
import { join as join2 } from "path";
|
|
58
63
|
|
|
@@ -643,6 +648,211 @@ async function checkCodexRecentSessionTotal(configured) {
|
|
|
643
648
|
return true;
|
|
644
649
|
}
|
|
645
650
|
}
|
|
651
|
+
var PEEK_CHUNK_BYTES = 64 * 1024;
|
|
652
|
+
var PEEK_MAX_BYTES = 4 * 1024 * 1024;
|
|
653
|
+
async function peekFirstJsonLine(path, maxBytes = PEEK_MAX_BYTES) {
|
|
654
|
+
try {
|
|
655
|
+
const fh = await open(path, "r");
|
|
656
|
+
try {
|
|
657
|
+
const chunk = Buffer.alloc(Math.min(PEEK_CHUNK_BYTES, maxBytes));
|
|
658
|
+
const parts = [];
|
|
659
|
+
let read = 0;
|
|
660
|
+
let line = null;
|
|
661
|
+
while (read < maxBytes) {
|
|
662
|
+
const { bytesRead } = await fh.read(chunk, 0, Math.min(chunk.length, maxBytes - read), read);
|
|
663
|
+
if (bytesRead === 0) {
|
|
664
|
+
line = Buffer.concat(parts).toString("utf8");
|
|
665
|
+
break;
|
|
666
|
+
}
|
|
667
|
+
const slice = chunk.subarray(0, bytesRead);
|
|
668
|
+
const nl = slice.indexOf(10);
|
|
669
|
+
if (nl !== -1) {
|
|
670
|
+
parts.push(Buffer.from(slice.subarray(0, nl)));
|
|
671
|
+
line = Buffer.concat(parts).toString("utf8");
|
|
672
|
+
break;
|
|
673
|
+
}
|
|
674
|
+
parts.push(Buffer.from(slice));
|
|
675
|
+
read += bytesRead;
|
|
676
|
+
}
|
|
677
|
+
if (line === null) return null;
|
|
678
|
+
const trimmed = line.trim();
|
|
679
|
+
if (trimmed.length === 0) return null;
|
|
680
|
+
const obj = JSON.parse(trimmed);
|
|
681
|
+
return isRecord(obj) ? obj : null;
|
|
682
|
+
} finally {
|
|
683
|
+
await fh.close();
|
|
684
|
+
}
|
|
685
|
+
} catch {
|
|
686
|
+
return null;
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
async function listProjectDirsSafe(root) {
|
|
690
|
+
try {
|
|
691
|
+
const entries = readdirSync(root, { withFileTypes: true });
|
|
692
|
+
return entries.filter((e) => e.isDirectory()).map((e) => join2(root, e.name));
|
|
693
|
+
} catch {
|
|
694
|
+
return [];
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
async function listTranscriptsSafe(projectDir) {
|
|
698
|
+
try {
|
|
699
|
+
const entries = readdirSync(projectDir, { withFileTypes: true });
|
|
700
|
+
return entries.filter((e) => e.isFile() && e.name.endsWith(".jsonl")).map((e) => join2(projectDir, e.name));
|
|
701
|
+
} catch {
|
|
702
|
+
return [];
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
async function discoverClaudeFilesForDoctor(roots) {
|
|
706
|
+
const files = [];
|
|
707
|
+
for (const root of roots) {
|
|
708
|
+
for (const dir of await listProjectDirsSafe(root.path)) {
|
|
709
|
+
files.push(...await listTranscriptsSafe(dir));
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
return files;
|
|
713
|
+
}
|
|
714
|
+
async function checkDesktopScan() {
|
|
715
|
+
const roots = await claudeTranscriptRoots();
|
|
716
|
+
const desktopRoots = roots.filter((r) => r.surface === "desktop");
|
|
717
|
+
if (desktopRoots.length === 0) {
|
|
718
|
+
log("ok", "Claude \u30C7\u30B9\u30AF\u30C8\u30C3\u30D7\u306E\u30B9\u30AD\u30E3\u30F3\u30EB\u30FC\u30C8\u306F\u691C\u51FA\u3055\u308C\u307E\u305B\u3093\u3067\u3057\u305F(\u672A\u4F7F\u7528\u3001\u307E\u305F\u306F macOS \u4EE5\u5916\u30FBCCCN_CLAUDE_DESKTOP_ROOTS \u672A\u8A2D\u5B9A)");
|
|
719
|
+
} else {
|
|
720
|
+
for (const root of desktopRoots) {
|
|
721
|
+
const exists = existsSync2(root.path);
|
|
722
|
+
log(
|
|
723
|
+
exists ? "ok" : "warn",
|
|
724
|
+
`Claude \u30C7\u30B9\u30AF\u30C8\u30C3\u30D7\u306E\u30B9\u30AD\u30E3\u30F3\u30EB\u30FC\u30C8: ${root.path}${exists ? "" : "(\u73FE\u5728\u306F\u4E0D\u5728\u3002\u30A2\u30D7\u30EA\u66F4\u65B0\u3067\u30EC\u30A4\u30A2\u30A6\u30C8\u304C\u5909\u308F\u3063\u305F\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059)"}`
|
|
725
|
+
);
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
const tracked = cursorPaths();
|
|
729
|
+
const claudeFiles = await discoverClaudeFilesForDoctor(roots);
|
|
730
|
+
const claudeUntracked = claudeFiles.filter((f) => !tracked.has(f)).length;
|
|
731
|
+
log(
|
|
732
|
+
"ok",
|
|
733
|
+
`Claude transcript \u8FFD\u8DE1\u6F0F\u308C: ${claudeUntracked}\u4EF6(\u5168 ${claudeFiles.length}\u4EF6\u4E2D\u3002\u672A\u8FFD\u8DE1\u5206\u306F ccc-notifier scan \u3067\u56DE\u53CE\u3067\u304D\u307E\u3059)`
|
|
734
|
+
);
|
|
735
|
+
const sessionToFiles = /* @__PURE__ */ new Map();
|
|
736
|
+
for (const f of claudeFiles) {
|
|
737
|
+
const line = await peekFirstJsonLine(f);
|
|
738
|
+
const sid = typeof line?.sessionId === "string" ? line.sessionId : null;
|
|
739
|
+
if (sid === null || sid.length === 0) continue;
|
|
740
|
+
const files = sessionToFiles.get(sid) ?? [];
|
|
741
|
+
files.push(f);
|
|
742
|
+
sessionToFiles.set(sid, files);
|
|
743
|
+
}
|
|
744
|
+
const dupEntries = [...sessionToFiles.entries()].filter(([, files]) => files.length > 1);
|
|
745
|
+
if (dupEntries.length > 0) {
|
|
746
|
+
const multiRoot = dupEntries.filter(
|
|
747
|
+
([, files]) => new Set(files.map((f) => rootForClaudePath(f, roots)?.path ?? "")).size > 1
|
|
748
|
+
).length;
|
|
749
|
+
const sample = dupEntries.slice(0, 3).map(([sid, files]) => `${sid.slice(0, 8)}\u2026(${files.length}\u30D5\u30A1\u30A4\u30EB)`).join(" / ");
|
|
750
|
+
log(
|
|
751
|
+
"warn",
|
|
752
|
+
`\u540C\u4E00 sessionId \u304C\u8907\u6570\u306E transcript \u30D5\u30A1\u30A4\u30EB\u306B\u73FE\u308C\u3066\u3044\u307E\u3059(${dupEntries.length}\u4EF6\u30FB\u3046\u3061\u8907\u6570\u30EB\u30FC\u30C8\u306B\u307E\u305F\u304C\u308B\u3082\u306E ${multiRoot}\u4EF6): ${sample}\u3002\u4E8C\u91CD\u8A08\u4E0A\u306E\u53EF\u80FD\u6027\u304C\u3042\u308B\u305F\u3081 history \u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044`
|
|
753
|
+
);
|
|
754
|
+
} else {
|
|
755
|
+
log("ok", "\u540C\u4E00 sessionId \u304C\u8907\u6570\u306E Claude transcript \u30D5\u30A1\u30A4\u30EB\u306B\u91CD\u8907\u3059\u308B\u30B1\u30FC\u30B9\u306F\u691C\u51FA\u3055\u308C\u307E\u305B\u3093\u3067\u3057\u305F");
|
|
756
|
+
}
|
|
757
|
+
const sessionsRoot = join2(codexHome(), "sessions");
|
|
758
|
+
if (!existsSync2(sessionsRoot)) {
|
|
759
|
+
log("ok", "Codex \u30BB\u30C3\u30B7\u30E7\u30F3\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u304C\u7121\u3044\u305F\u3081 originator \u5185\u8A33\u30FB\u8FFD\u8DE1\u6F0F\u308C\u306F\u30B9\u30AD\u30C3\u30D7\u3057\u307E\u3057\u305F");
|
|
760
|
+
return true;
|
|
761
|
+
}
|
|
762
|
+
let codexFiles = [];
|
|
763
|
+
try {
|
|
764
|
+
codexFiles = (await listCodexRollouts(sessionsRoot)).rollouts;
|
|
765
|
+
} catch (err) {
|
|
766
|
+
log("warn", `Codex rollout \u306E\u5217\u6319\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u307E\u3057\u305F: ${errMessage(err)}`);
|
|
767
|
+
return true;
|
|
768
|
+
}
|
|
769
|
+
const codexUntracked = codexFiles.filter((f) => !tracked.has(f)).length;
|
|
770
|
+
log(
|
|
771
|
+
"ok",
|
|
772
|
+
`Codex rollout \u8FFD\u8DE1\u6F0F\u308C: ${codexUntracked}\u4EF6(\u5168 ${codexFiles.length}\u4EF6\u4E2D\u3002\u672A\u8FFD\u8DE1\u5206\u306F ccc-notifier scan \u3067\u56DE\u53CE\u3067\u304D\u307E\u3059)`
|
|
773
|
+
);
|
|
774
|
+
const originatorCounts = /* @__PURE__ */ new Map();
|
|
775
|
+
const sessionIdToFiles = /* @__PURE__ */ new Map();
|
|
776
|
+
for (const f of codexFiles) {
|
|
777
|
+
const line = await peekFirstJsonLine(f);
|
|
778
|
+
const payload = isRecord(line?.payload) ? line.payload : null;
|
|
779
|
+
const originator = typeof payload?.originator === "string" ? payload.originator : "(unknown)";
|
|
780
|
+
originatorCounts.set(originator, (originatorCounts.get(originator) ?? 0) + 1);
|
|
781
|
+
const sid = typeof payload?.id === "string" ? payload.id : typeof payload?.session_id === "string" ? payload.session_id : null;
|
|
782
|
+
if (sid !== null && sid.length > 0) {
|
|
783
|
+
const set = sessionIdToFiles.get(sid) ?? /* @__PURE__ */ new Set();
|
|
784
|
+
set.add(f);
|
|
785
|
+
sessionIdToFiles.set(sid, set);
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
const originatorSummary = [...originatorCounts.entries()].sort((a, b) => b[1] - a[1]).map(([k, v]) => `${k}:${v}`).join(" / ");
|
|
789
|
+
log("ok", `Codex originator \u5185\u8A33: ${originatorSummary.length > 0 ? originatorSummary : "(rollout \u306A\u3057)"}`);
|
|
790
|
+
const dupCodex = [...sessionIdToFiles.values()].filter((files) => files.size > 1).length;
|
|
791
|
+
if (dupCodex > 0) {
|
|
792
|
+
log(
|
|
793
|
+
"warn",
|
|
794
|
+
`\u540C\u4E00 session_id \u3092\u6301\u3064 Codex rollout \u304C\u8907\u6570\u30D5\u30A1\u30A4\u30EB\u306B\u307E\u305F\u304C\u3063\u3066\u3044\u307E\u3059(${dupCodex}\u4EF6)\u3002\u4E8C\u91CD\u8A08\u4E0A\u306E\u53EF\u80FD\u6027\u304C\u3042\u308B\u305F\u3081 history \u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044`
|
|
795
|
+
);
|
|
796
|
+
} else {
|
|
797
|
+
log("ok", "\u540C\u4E00 session_id \u304C\u8907\u6570\u306E Codex rollout \u30D5\u30A1\u30A4\u30EB\u306B\u91CD\u8907\u3059\u308B\u30B1\u30FC\u30B9\u306F\u691C\u51FA\u3055\u308C\u307E\u305B\u3093\u3067\u3057\u305F");
|
|
798
|
+
}
|
|
799
|
+
return true;
|
|
800
|
+
}
|
|
801
|
+
function checkPendingAppendMarker() {
|
|
802
|
+
if (!hasUnresolvedPendingMarker()) {
|
|
803
|
+
log("ok", "\u53D6\u308A\u8FBC\u307F\u4FDD\u7559\u30DE\u30FC\u30AB\u30FC\u306F\u6B63\u5E38\u3067\u3059");
|
|
804
|
+
return true;
|
|
805
|
+
}
|
|
806
|
+
log(
|
|
807
|
+
"warn",
|
|
808
|
+
"\u53D6\u308A\u8FBC\u307F\u4FDD\u7559\u30DE\u30FC\u30AB\u30FC(cache/pending-append.json)\u304C\u58CA\u308C\u305F\u5F62\u8DE1\u304C\u3042\u308A\u307E\u3059\u3002\u5B89\u5168\u5074\u3067\u5168\u30BB\u30C3\u30B7\u30E7\u30F3\u3092\u4FDD\u7559\u6271\u3044\u306B\u3057\u3066\u3044\u308B\u305F\u3081\u3001Stop hook \u306E\u305F\u3073\u306B history \u3092\u8AAD\u307F\u76F4\u3057\u307E\u3059(\u4E8C\u91CD\u8A08\u4E0A\u306F\u8D77\u304D\u307E\u305B\u3093)\u3002\u89E3\u6D88\u3059\u308B\u306B\u306F ccc-notifier reset-cursors \u3092\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044(\u53D6\u308A\u8FBC\u307F\u4F4D\u7F6E\u3092\u6368\u3066\u3066\u304B\u3089\u89E3\u9664\u3057\u307E\u3059\u3002\u5C65\u6B74\u306F\u4FDD\u6301\u3055\u308C\u3001\u6B21\u56DE\u306E\u53D6\u308A\u8FBC\u307F\u3060\u3051\u5168\u518D\u8D70\u67FB\u3067\u6642\u9593\u304C\u304B\u304B\u308A\u307E\u3059)\u3002\u30DE\u30FC\u30AB\u30FC\u30D5\u30A1\u30A4\u30EB\u5358\u72EC\u306E\u524A\u9664\u3067\u306F\u3001\u307E\u3060\u56DE\u5FA9\u3057\u3066\u3044\u306A\u3044\u30BB\u30C3\u30B7\u30E7\u30F3\u304C\u518D\u8A08\u4E0A\u3055\u308C\u5F97\u307E\u3059"
|
|
809
|
+
);
|
|
810
|
+
return true;
|
|
811
|
+
}
|
|
812
|
+
function checkDuplicateHistoryTurns() {
|
|
813
|
+
const turns = readTurns();
|
|
814
|
+
const groups = /* @__PURE__ */ new Map();
|
|
815
|
+
const byIngestKey = /* @__PURE__ */ new Map();
|
|
816
|
+
for (const rec of turns) {
|
|
817
|
+
if (typeof rec.ingestKey === "string" && rec.ingestKey.length > 0) {
|
|
818
|
+
const keyed = byIngestKey.get(rec.ingestKey) ?? [];
|
|
819
|
+
keyed.push(rec);
|
|
820
|
+
byIngestKey.set(rec.ingestKey, keyed);
|
|
821
|
+
}
|
|
822
|
+
if (!rec.sessionId || !rec.ts) continue;
|
|
823
|
+
const key = `${rec.sessionId} ${rec.ts} ${rec.source ?? "claude"}`;
|
|
824
|
+
const list = groups.get(key) ?? [];
|
|
825
|
+
list.push(rec);
|
|
826
|
+
groups.set(key, list);
|
|
827
|
+
}
|
|
828
|
+
const dupKeys = [...byIngestKey.entries()].filter(([, list]) => list.length > 1);
|
|
829
|
+
if (dupKeys.length > 0) {
|
|
830
|
+
const rows = dupKeys.reduce((sum, [, list]) => sum + list.length, 0);
|
|
831
|
+
const sample2 = dupKeys.slice(0, 3).map(([key, list]) => `${key.slice(0, 8)}\u2026(${list[0].sessionId.slice(0, 8)}\u2026 apiCalls ${list.map((r) => r.apiCalls).join("/")})`);
|
|
832
|
+
log(
|
|
833
|
+
"warn",
|
|
834
|
+
`history.jsonl \u306B\u540C\u4E00\u306E\u53D6\u308A\u8FBC\u307F\u30AD\u30FC\u3092\u6301\u3064\u30EC\u30B3\u30FC\u30C9\u304C\u8907\u6570\u3042\u308A\u307E\u3059(${dupKeys.length}\u7D44\u30FB${rows}\u884C)\u3002\u540C\u3058 API \u547C\u3073\u51FA\u3057\u3092\u4E8C\u5EA6\u8A08\u4E0A\u3057\u3066\u3044\u307E\u3059\u3002\u4F8B: ${sample2.join(", ")}`
|
|
835
|
+
);
|
|
836
|
+
} else {
|
|
837
|
+
log("ok", "history.jsonl \u306B\u540C\u4E00\u306E\u53D6\u308A\u8FBC\u307F\u30AD\u30FC\u3092\u6301\u3064\u91CD\u8907\u30EC\u30B3\u30FC\u30C9\u306F\u691C\u51FA\u3055\u308C\u307E\u305B\u3093\u3067\u3057\u305F");
|
|
838
|
+
}
|
|
839
|
+
const dupGroups = [...groups.entries()].filter(([, list]) => list.length > 1);
|
|
840
|
+
if (dupGroups.length === 0) {
|
|
841
|
+
log("ok", "history.jsonl \u306B\u540C\u4E00 sessionId+ts \u306E\u91CD\u8907\u30BF\u30FC\u30F3\u306F\u691C\u51FA\u3055\u308C\u307E\u305B\u3093\u3067\u3057\u305F");
|
|
842
|
+
return true;
|
|
843
|
+
}
|
|
844
|
+
const totalDupRows = dupGroups.reduce((sum, [, list]) => sum + list.length, 0);
|
|
845
|
+
const sample = dupGroups.slice(0, 3).map(([key, list]) => {
|
|
846
|
+
const [sessionId] = key.split(" ");
|
|
847
|
+
const apiCallsList = list.map((r) => r.apiCalls).join("/");
|
|
848
|
+
return `${sessionId.slice(0, 8)}\u2026(apiCalls ${apiCallsList})`;
|
|
849
|
+
});
|
|
850
|
+
log(
|
|
851
|
+
"warn",
|
|
852
|
+
`history.jsonl \u306B\u540C\u4E00 sessionId+ts \u306E\u91CD\u8907\u30BF\u30FC\u30F3\u3092\u691C\u51FA\u3057\u307E\u3057\u305F(${dupGroups.length}\u7D44\u30FB${totalDupRows}\u884C)\u3002\u4E8C\u91CD\u8A08\u4E0A\u306E\u53EF\u80FD\u6027\u304C\u3042\u308A\u307E\u3059\u3002\u4F8B: ${sample.join(", ")}\u3002\u5143 JSONL \u304B\u3089\u4F5C\u308A\u76F4\u3059\u306A\u3089 ccc-notifier sweep\u3001\u500B\u5225\u306B\u6D88\u3059\u306A\u3089 history clear \u3092\u691C\u8A0E\u3057\u3066\u304F\u3060\u3055\u3044`
|
|
853
|
+
);
|
|
854
|
+
return true;
|
|
855
|
+
}
|
|
646
856
|
async function runDoctor() {
|
|
647
857
|
const results = [];
|
|
648
858
|
results.push(await safeRun("settings.json", () => checkHookRegistration()));
|
|
@@ -667,6 +877,9 @@ async function runDoctor() {
|
|
|
667
877
|
results.push(await safeRun("notify", () => checkNotification(cfg)));
|
|
668
878
|
results.push(await safeRun("claude-recent-session", () => checkClaudeRecentSessionTotal(latestTranscript)));
|
|
669
879
|
results.push(await safeRun("codex-recent-session", () => checkCodexRecentSessionTotal(codexStopConfigured)));
|
|
880
|
+
results.push(await safeRun("desktop-scan", () => checkDesktopScan()));
|
|
881
|
+
results.push(await safeRun("pending-append", () => Promise.resolve(checkPendingAppendMarker())));
|
|
882
|
+
results.push(await safeRun("duplicate-history", () => Promise.resolve(checkDuplicateHistoryTurns())));
|
|
670
883
|
const hasFailure = results.some((ok) => ok === false);
|
|
671
884
|
return hasFailure ? 1 : 0;
|
|
672
885
|
}
|
|
@@ -741,6 +954,7 @@ function turnCostByModelWithSA(rec) {
|
|
|
741
954
|
function aggregate(turns) {
|
|
742
955
|
const dailyMap = /* @__PURE__ */ new Map();
|
|
743
956
|
const modelMap = /* @__PURE__ */ new Map();
|
|
957
|
+
const surfaceMap = /* @__PURE__ */ new Map();
|
|
744
958
|
const total = {
|
|
745
959
|
turns: 0,
|
|
746
960
|
inputTokens: 0,
|
|
@@ -777,6 +991,12 @@ function aggregate(turns) {
|
|
|
777
991
|
m.costJPY += modelUsd * rec.fxRate;
|
|
778
992
|
modelMap.set(model, m);
|
|
779
993
|
}
|
|
994
|
+
const surface = effectiveSurface(rec);
|
|
995
|
+
const s = surfaceMap.get(surface) ?? { turns: 0, costUSD: 0, costJPY: 0 };
|
|
996
|
+
s.turns += 1;
|
|
997
|
+
s.costUSD += totalUsd;
|
|
998
|
+
s.costJPY += totalJpy;
|
|
999
|
+
surfaceMap.set(surface, s);
|
|
780
1000
|
total.turns += 1;
|
|
781
1001
|
total.inputTokens += inTok;
|
|
782
1002
|
total.outputTokens += outTok;
|
|
@@ -799,7 +1019,9 @@ function aggregate(turns) {
|
|
|
799
1019
|
const daily = [...dailyMap.values()].sort((a, b) => a.date.localeCompare(b.date));
|
|
800
1020
|
const byModel = {};
|
|
801
1021
|
for (const [model, agg] of modelMap) byModel[model] = agg;
|
|
802
|
-
|
|
1022
|
+
const bySurface = {};
|
|
1023
|
+
for (const [surface, agg] of surfaceMap) bySurface[surface] = agg;
|
|
1024
|
+
return { daily, byModel, bySurface, total };
|
|
803
1025
|
}
|
|
804
1026
|
function printTable(result, days) {
|
|
805
1027
|
console.log(`\u76F4\u8FD1 ${days} \u65E5\u9593\u306E\u96C6\u8A08 (last ${days} days):`);
|
|
@@ -834,6 +1056,17 @@ function printTable(result, days) {
|
|
|
834
1056
|
);
|
|
835
1057
|
}
|
|
836
1058
|
console.log("\u203B \u8907\u6570\u30E2\u30C7\u30EB\u3092\u4F7F\u3063\u305F\u30BF\u30FC\u30F3\u306F\u5404\u30E2\u30C7\u30EB\u306E\u884C\u306B1\u305A\u3064\u8A08\u4E0A\u3057\u307E\u3059(\u30BF\u30FC\u30F3\u6570\u306E\u5408\u8A08\u306F\u7DCF\u30BF\u30FC\u30F3\u6570\u3092\u8D85\u3048\u308B\u3053\u3068\u304C\u3042\u308A\u307E\u3059)\u3002");
|
|
1059
|
+
const surfaceEntries = Object.entries(result.bySurface);
|
|
1060
|
+
if (surfaceEntries.length > 1 || surfaceEntries.length === 1 && surfaceEntries[0][0] !== "cli") {
|
|
1061
|
+
console.log("");
|
|
1062
|
+
console.log("\u30B5\u30FC\u30D5\u30A7\u30B9\u5225 (By surface):");
|
|
1063
|
+
console.log("\u30B5\u30FC\u30D5\u30A7\u30B9".padEnd(20) + "\u30BF\u30FC\u30F3".padStart(8) + "USD".padStart(10) + "JPY".padStart(12));
|
|
1064
|
+
for (const [surface, s] of surfaceEntries.sort((a, b) => b[1].costUSD - a[1].costUSD)) {
|
|
1065
|
+
console.log(
|
|
1066
|
+
surfaceLabel(surface).padEnd(20) + String(s.turns).padStart(8) + formatUSD(s.costUSD).padStart(10) + formatJPY(s.costJPY).padStart(12)
|
|
1067
|
+
);
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
837
1070
|
console.log("");
|
|
838
1071
|
console.log(`\u5408\u8A08 (Total): ${formatUSD(result.total.costUSD)} (${formatJPY(result.total.costJPY)}) / ${result.total.turns} turns`);
|
|
839
1072
|
}
|
|
@@ -846,7 +1079,13 @@ async function runReport(argv) {
|
|
|
846
1079
|
}
|
|
847
1080
|
const result = aggregate(turns);
|
|
848
1081
|
if (json) {
|
|
849
|
-
console.log(
|
|
1082
|
+
console.log(
|
|
1083
|
+
JSON.stringify(
|
|
1084
|
+
{ days, daily: result.daily, byModel: result.byModel, bySurface: result.bySurface, total: result.total },
|
|
1085
|
+
null,
|
|
1086
|
+
2
|
|
1087
|
+
)
|
|
1088
|
+
);
|
|
850
1089
|
return 0;
|
|
851
1090
|
}
|
|
852
1091
|
printTable(result, days);
|
|
@@ -872,11 +1111,21 @@ var COMMANDS = [
|
|
|
872
1111
|
ja: "HTML\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9\u3092\u751F\u6210\u3057\u3066\u30D6\u30E9\u30A6\u30B6\u3067\u958B\u304F",
|
|
873
1112
|
en: "Generate and open the HTML dashboard"
|
|
874
1113
|
},
|
|
1114
|
+
{
|
|
1115
|
+
cmd: "reset-cursors",
|
|
1116
|
+
ja: "\u53D6\u308A\u8FBC\u307F\u4F4D\u7F6E\u3092\u6368\u3066\u3066\u6B21\u56DE\u306B\u5168\u518D\u8D70\u67FB\u3055\u305B\u308B(\u5C65\u6B74\u306F\u4FDD\u6301\u3002\u4FDD\u7559\u30DE\u30FC\u30AB\u30FC\u306E\u89E3\u9664\u306B\u3082\u4F7F\u3046)",
|
|
1117
|
+
en: "Discard ingest cursors so the next run rescans everything (history is kept)"
|
|
1118
|
+
},
|
|
875
1119
|
{
|
|
876
1120
|
cmd: "sweep [--dry-run] [--days N]",
|
|
877
1121
|
ja: "\u5C65\u6B74\u3068\u53D6\u308A\u8FBC\u307F\u4F4D\u7F6E\u3092\u6368\u3066\u3001\u5143JSONL\u304B\u3089\u6982\u7B97\u3092\u518D\u751F\u6210(--dry-run\u306Fpreview)",
|
|
878
1122
|
en: "Reset and rebuild estimates from source JSONL (--dry-run previews)"
|
|
879
1123
|
},
|
|
1124
|
+
{
|
|
1125
|
+
cmd: "scan [--dry-run] [--json]",
|
|
1126
|
+
ja: "hook\u975E\u4F9D\u5B58\u306E\u5897\u5206\u53D6\u308A\u8FBC\u307F(\u30C7\u30B9\u30AF\u30C8\u30C3\u30D7\u30A2\u30D7\u30EA\u7B49\u306E\u53D6\u308A\u3053\u307C\u3057\u3092\u56DE\u53CE\u3002--dry-run\u306Fpreview)",
|
|
1127
|
+
en: "Hook-independent incremental ingest (catches desktop app etc.; --dry-run previews)"
|
|
1128
|
+
},
|
|
880
1129
|
{
|
|
881
1130
|
cmd: "history <clear|redact> [--days N] [--yes]",
|
|
882
1131
|
ja: "\u5C65\u6B74\u3092\u524A\u9664(clear=\u30EC\u30B3\u30FC\u30C9\u3054\u3068 / redact=\u30D7\u30ED\u30F3\u30D7\u30C8\u306E\u307F\u3002--days \u3067\u53E4\u3044\u5206\u3060\u3051)",
|
|
@@ -908,13 +1157,13 @@ function isCodexPassiveEvent(value) {
|
|
|
908
1157
|
async function runCodexPassiveHook(event, text) {
|
|
909
1158
|
try {
|
|
910
1159
|
if (event === "Stop") {
|
|
911
|
-
const trackMod = await import("./track-
|
|
1160
|
+
const trackMod = await import("./track-P6A5WDJZ.js");
|
|
912
1161
|
await trackMod.runTrack(text, { codex: true });
|
|
913
1162
|
} else if (event === "UserPromptSubmit") {
|
|
914
|
-
const activity = await import("./subagent-store-
|
|
1163
|
+
const activity = await import("./subagent-store-USG3WJEB.js");
|
|
915
1164
|
activity.handleCodexUserPromptSubmitHook(text);
|
|
916
1165
|
} else {
|
|
917
|
-
const activity = await import("./subagent-store-
|
|
1166
|
+
const activity = await import("./subagent-store-USG3WJEB.js");
|
|
918
1167
|
activity.handleCodexSubagentHook(text, event === "SubagentStart" ? "start" : "stop");
|
|
919
1168
|
}
|
|
920
1169
|
} catch {
|
|
@@ -993,18 +1242,18 @@ async function main(argv) {
|
|
|
993
1242
|
const text = await readStdin();
|
|
994
1243
|
const codex = rest.includes("--codex");
|
|
995
1244
|
try {
|
|
996
|
-
const trackMod = await import("./track-
|
|
1245
|
+
const trackMod = await import("./track-P6A5WDJZ.js");
|
|
997
1246
|
await trackMod.runTrack(text, { codex });
|
|
998
1247
|
} catch {
|
|
999
1248
|
}
|
|
1000
1249
|
return 0;
|
|
1001
1250
|
}
|
|
1002
1251
|
case "init": {
|
|
1003
|
-
const { runInit } = await import("./setup-
|
|
1252
|
+
const { runInit } = await import("./setup-VLMW433R.js");
|
|
1004
1253
|
return await runInit(rest);
|
|
1005
1254
|
}
|
|
1006
1255
|
case "uninstall": {
|
|
1007
|
-
const { runUninstall } = await import("./setup-
|
|
1256
|
+
const { runUninstall } = await import("./setup-VLMW433R.js");
|
|
1008
1257
|
return await runUninstall(rest);
|
|
1009
1258
|
}
|
|
1010
1259
|
case "doctor":
|
|
@@ -1012,27 +1261,35 @@ async function main(argv) {
|
|
|
1012
1261
|
case "report":
|
|
1013
1262
|
return await runReport(rest);
|
|
1014
1263
|
case "dashboard": {
|
|
1015
|
-
const { runDashboard } = await import("./dashboard-
|
|
1264
|
+
const { runDashboard } = await import("./dashboard-64XHDUVT.js");
|
|
1016
1265
|
return await runDashboard(rest);
|
|
1017
1266
|
}
|
|
1018
1267
|
case "sweep": {
|
|
1019
|
-
const { runSweep } = await import("./sweep-
|
|
1268
|
+
const { runSweep } = await import("./sweep-DVOV4XIZ.js");
|
|
1020
1269
|
return await runSweep(rest);
|
|
1021
1270
|
}
|
|
1271
|
+
case "scan": {
|
|
1272
|
+
const { runScan } = await import("./scan-UB6ORRZK.js");
|
|
1273
|
+
return await runScan(rest);
|
|
1274
|
+
}
|
|
1275
|
+
case "reset-cursors": {
|
|
1276
|
+
const { runResetCursors } = await import("./reset-cursors-5CCM6MQL.js");
|
|
1277
|
+
return await runResetCursors(rest);
|
|
1278
|
+
}
|
|
1022
1279
|
case "history": {
|
|
1023
|
-
const { runHistory } = await import("./history-
|
|
1280
|
+
const { runHistory } = await import("./history-W34EJOVV.js");
|
|
1024
1281
|
return await runHistory(rest);
|
|
1025
1282
|
}
|
|
1026
1283
|
case "budget": {
|
|
1027
|
-
const { runBudget } = await import("./budget-
|
|
1284
|
+
const { runBudget } = await import("./budget-O4VAP6RB.js");
|
|
1028
1285
|
return runBudget(rest);
|
|
1029
1286
|
}
|
|
1030
1287
|
case "mute": {
|
|
1031
|
-
const { runMute } = await import("./mute-
|
|
1288
|
+
const { runMute } = await import("./mute-23BWQXS3.js");
|
|
1032
1289
|
return runMute(rest);
|
|
1033
1290
|
}
|
|
1034
1291
|
case "unmute": {
|
|
1035
|
-
const { runUnmute } = await import("./mute-
|
|
1292
|
+
const { runUnmute } = await import("./mute-23BWQXS3.js");
|
|
1036
1293
|
return runUnmute();
|
|
1037
1294
|
}
|
|
1038
1295
|
case "--version":
|
|
@@ -3,11 +3,13 @@ import {
|
|
|
3
3
|
browserOpenPlan,
|
|
4
4
|
runDashboard,
|
|
5
5
|
writeDashboardHtml
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-O2E4VTDR.js";
|
|
7
|
+
import "./chunk-3M5UQK76.js";
|
|
8
|
+
import "./chunk-PXMXEFM7.js";
|
|
9
|
+
import "./chunk-6IVSZ3S4.js";
|
|
7
10
|
import "./chunk-DGXUSPS4.js";
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-OOAC5ULQ.js";
|
|
11
|
+
import "./chunk-XG73C6CC.js";
|
|
12
|
+
import "./chunk-WONMZ466.js";
|
|
11
13
|
export {
|
|
12
14
|
browserOpenPlan,
|
|
13
15
|
runDashboard,
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
invalidateCanonicalDashboards
|
|
3
|
+
invalidateCanonicalDashboards
|
|
4
|
+
} from "./chunk-3M5UQK76.js";
|
|
5
|
+
import {
|
|
4
6
|
waitForDataLock
|
|
5
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-PXMXEFM7.js";
|
|
6
8
|
import {
|
|
7
9
|
paths
|
|
8
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-WONMZ466.js";
|
|
9
11
|
|
|
10
12
|
// src/history.ts
|
|
11
13
|
import { existsSync, readFileSync, writeFileSync, renameSync, rmSync } from "fs";
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
waitForDataLock
|
|
4
|
+
} from "./chunk-PXMXEFM7.js";
|
|
5
|
+
import {
|
|
6
|
+
paths,
|
|
7
|
+
pendingAppendPath
|
|
8
|
+
} from "./chunk-WONMZ466.js";
|
|
9
|
+
|
|
10
|
+
// src/reset-cursors.ts
|
|
11
|
+
import { rmSync } from "fs";
|
|
12
|
+
async function runResetCursors(argv) {
|
|
13
|
+
if (argv.length > 0) {
|
|
14
|
+
console.error(`\u4E0D\u660E\u306Aoption\u307E\u305F\u306F\u4F59\u5206\u306A\u5F15\u6570\u3067\u3059: ${argv[0]}
|
|
15
|
+
\u4F7F\u3044\u65B9 / Usage: ccc-notifier reset-cursors`);
|
|
16
|
+
return 1;
|
|
17
|
+
}
|
|
18
|
+
const lock = await waitForDataLock();
|
|
19
|
+
if (lock === null) {
|
|
20
|
+
console.error("reset-cursors \u306E data 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");
|
|
21
|
+
return 1;
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
rmSync(paths().cursorsFile, { force: true });
|
|
25
|
+
rmSync(pendingAppendPath(), { force: true });
|
|
26
|
+
} catch (err) {
|
|
27
|
+
console.error(
|
|
28
|
+
`\u53D6\u308A\u8FBC\u307F\u4F4D\u7F6E\u306E\u7834\u68C4\u306B\u5931\u6557\u3057\u307E\u3057\u305F / failed to reset cursors: ${err instanceof Error ? err.message : String(err)}`
|
|
29
|
+
);
|
|
30
|
+
return 1;
|
|
31
|
+
} finally {
|
|
32
|
+
lock.release();
|
|
33
|
+
}
|
|
34
|
+
console.log("\u53D6\u308A\u8FBC\u307F\u4F4D\u7F6E(cursors.json)\u3068\u4FDD\u7559\u30DE\u30FC\u30AB\u30FC\u3092\u7834\u68C4\u3057\u307E\u3057\u305F\u3002");
|
|
35
|
+
console.log("\u5C65\u6B74(history.jsonl)\u30FB\u8A2D\u5B9A\u30FB\u901A\u77E5\u5148\u306F\u305D\u306E\u307E\u307E\u3067\u3059\u3002\u4E8C\u91CD\u8A08\u4E0A\u306F\u5C65\u6B74\u5074\u306E\u6307\u7D0B\u3067\u9632\u304E\u307E\u3059\u3002");
|
|
36
|
+
console.log("\u6B21\u56DE\u306E\u53D6\u308A\u8FBC\u307F\u306F\u5168 transcript / rollout \u3092\u8AAD\u307F\u76F4\u3059\u305F\u3081\u3001\u4E00\u5EA6\u3060\u3051\u6642\u9593\u304C\u304B\u304B\u308A\u307E\u3059\u3002");
|
|
37
|
+
return 0;
|
|
38
|
+
}
|
|
39
|
+
export {
|
|
40
|
+
runResetCursors
|
|
41
|
+
};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
notifyIngestSummary,
|
|
4
|
+
runIngest
|
|
5
|
+
} from "./chunk-V4IS4FXH.js";
|
|
6
|
+
import "./chunk-JLDI4D5E.js";
|
|
7
|
+
import "./chunk-6BXD6HU5.js";
|
|
8
|
+
import "./chunk-OCKZZVOG.js";
|
|
9
|
+
import "./chunk-Q45AAPJY.js";
|
|
10
|
+
import "./chunk-O2E4VTDR.js";
|
|
11
|
+
import "./chunk-3M5UQK76.js";
|
|
12
|
+
import "./chunk-PXMXEFM7.js";
|
|
13
|
+
import "./chunk-6IVSZ3S4.js";
|
|
14
|
+
import "./chunk-DGXUSPS4.js";
|
|
15
|
+
import {
|
|
16
|
+
formatJPY,
|
|
17
|
+
formatUSD
|
|
18
|
+
} from "./chunk-XG73C6CC.js";
|
|
19
|
+
import {
|
|
20
|
+
readConfig
|
|
21
|
+
} from "./chunk-WONMZ466.js";
|
|
22
|
+
|
|
23
|
+
// src/scan.ts
|
|
24
|
+
function parseScanFlags(argv) {
|
|
25
|
+
const flags = { dryRun: false, json: false };
|
|
26
|
+
for (const a of argv) {
|
|
27
|
+
if (a === "--dry-run") flags.dryRun = true;
|
|
28
|
+
else if (a === "--json") flags.json = true;
|
|
29
|
+
else return { error: `\u4E0D\u660E\u306Aoption\u307E\u305F\u306F\u4F59\u5206\u306A\u5F15\u6570\u3067\u3059: ${a}` };
|
|
30
|
+
}
|
|
31
|
+
return { flags };
|
|
32
|
+
}
|
|
33
|
+
async function runScan(argv) {
|
|
34
|
+
const parsed = parseScanFlags(argv);
|
|
35
|
+
if ("error" in parsed) {
|
|
36
|
+
console.error(`${parsed.error}
|
|
37
|
+
\u4F7F\u3044\u65B9 / Usage: ccc-notifier scan [--dry-run] [--json]`);
|
|
38
|
+
return 1;
|
|
39
|
+
}
|
|
40
|
+
const { dryRun, json } = parsed.flags;
|
|
41
|
+
const result = await runIngest({ dryRun, offlinePricing: false });
|
|
42
|
+
if (!dryRun && !result.lockAcquired) {
|
|
43
|
+
console.error("scan \u306E data 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");
|
|
44
|
+
return 1;
|
|
45
|
+
}
|
|
46
|
+
if (!dryRun && result.records.length > 0) {
|
|
47
|
+
const cfg = readConfig();
|
|
48
|
+
await notifyIngestSummary(result, cfg);
|
|
49
|
+
}
|
|
50
|
+
if (json) {
|
|
51
|
+
console.log(
|
|
52
|
+
JSON.stringify(
|
|
53
|
+
{
|
|
54
|
+
dryRun: result.dryRun,
|
|
55
|
+
records: result.records.length,
|
|
56
|
+
scannedFiles: result.scannedFiles,
|
|
57
|
+
skippedByMtime: result.skippedByMtime,
|
|
58
|
+
failures: result.failures,
|
|
59
|
+
totalUSD: result.totalUSD,
|
|
60
|
+
totalJPY: result.totalJPY,
|
|
61
|
+
bySurface: result.bySurface
|
|
62
|
+
},
|
|
63
|
+
null,
|
|
64
|
+
2
|
|
65
|
+
)
|
|
66
|
+
);
|
|
67
|
+
return result.failures > 0 ? 1 : 0;
|
|
68
|
+
}
|
|
69
|
+
if (dryRun) console.log("(dry-run: \u66F8\u304D\u8FBC\u307F\u306F\u884C\u3063\u3066\u3044\u307E\u305B\u3093)");
|
|
70
|
+
console.log(
|
|
71
|
+
`\u8D70\u67FB: \u5BFE\u8C61 ${result.scannedFiles}\u30D5\u30A1\u30A4\u30EB(mtime\u5909\u5316\u306A\u3057\u3067\u30B9\u30AD\u30C3\u30D7 ${result.skippedByMtime}\u4EF6) / \u5931\u6557 ${result.failures}\u4EF6`
|
|
72
|
+
);
|
|
73
|
+
if (result.records.length === 0) {
|
|
74
|
+
console.log("\u65B0\u898F\u53D6\u308A\u8FBC\u307F\u306F\u3042\u308A\u307E\u305B\u3093\u3067\u3057\u305F");
|
|
75
|
+
} else {
|
|
76
|
+
console.log(`\u53D6\u308A\u8FBC\u307F: ${result.records.length} \u30BF\u30FC\u30F3\u3001\u5408\u8A08 ${formatUSD(result.totalUSD)}(${formatJPY(result.totalJPY)})`);
|
|
77
|
+
const bySurface = Object.entries(result.bySurface).sort((a, b) => (b[1]?.usd ?? 0) - (a[1]?.usd ?? 0));
|
|
78
|
+
for (const [surface, v] of bySurface) {
|
|
79
|
+
if (!v) continue;
|
|
80
|
+
console.log(` ${surface}: ${v.turns}\u30BF\u30FC\u30F3 ${formatUSD(v.usd)}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return result.failures > 0 ? 1 : 0;
|
|
84
|
+
}
|
|
85
|
+
export {
|
|
86
|
+
runScan
|
|
87
|
+
};
|
|
@@ -4,13 +4,12 @@ import {
|
|
|
4
4
|
matchesMarker,
|
|
5
5
|
runInit,
|
|
6
6
|
runUninstall
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-6HTETN26.js";
|
|
7
|
+
} from "./chunk-X7U63BZG.js";
|
|
8
|
+
import "./chunk-JLDI4D5E.js";
|
|
9
|
+
import "./chunk-Q45AAPJY.js";
|
|
11
10
|
import "./chunk-DGXUSPS4.js";
|
|
12
|
-
import "./chunk-
|
|
13
|
-
import "./chunk-
|
|
11
|
+
import "./chunk-XG73C6CC.js";
|
|
12
|
+
import "./chunk-WONMZ466.js";
|
|
14
13
|
export {
|
|
15
14
|
maskWebhookUrl,
|
|
16
15
|
matchesMarker,
|