@carboncode/cli 0.1.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.
Files changed (159) hide show
  1. package/LICENSE +21 -0
  2. package/LICENSES/DeepSeek-Reasonix-MIT.txt +21 -0
  3. package/README.md +109 -0
  4. package/README.zh-CN.md +91 -0
  5. package/THIRD_PARTY_NOTICES.md +14 -0
  6. package/dashboard/app.css +3233 -0
  7. package/dashboard/dist/app.js +30444 -0
  8. package/dashboard/dist/app.js.map +1 -0
  9. package/dashboard/dist/vendor-hljs.css +10 -0
  10. package/dashboard/dist/vendor-uplot.css +1 -0
  11. package/dashboard/index.html +19 -0
  12. package/data/deepseek-tokenizer.json.gz +0 -0
  13. package/dist/cli/acp-35C4ME6Y.js +711 -0
  14. package/dist/cli/acp-35C4ME6Y.js.map +1 -0
  15. package/dist/cli/chat-A6UJDPGV.js +51 -0
  16. package/dist/cli/chat-A6UJDPGV.js.map +1 -0
  17. package/dist/cli/chunk-2425HK6U.js +54 -0
  18. package/dist/cli/chunk-2425HK6U.js.map +1 -0
  19. package/dist/cli/chunk-25T6CVUP.js +172 -0
  20. package/dist/cli/chunk-25T6CVUP.js.map +1 -0
  21. package/dist/cli/chunk-2UQP6H6T.js +31 -0
  22. package/dist/cli/chunk-2UQP6H6T.js.map +1 -0
  23. package/dist/cli/chunk-3OAR6NVL.js +96 -0
  24. package/dist/cli/chunk-3OAR6NVL.js.map +1 -0
  25. package/dist/cli/chunk-3T6VBZCL.js +54 -0
  26. package/dist/cli/chunk-3T6VBZCL.js.map +1 -0
  27. package/dist/cli/chunk-4IBIPQVB.js +153 -0
  28. package/dist/cli/chunk-4IBIPQVB.js.map +1 -0
  29. package/dist/cli/chunk-4MQ3VURH.js +3106 -0
  30. package/dist/cli/chunk-4MQ3VURH.js.map +1 -0
  31. package/dist/cli/chunk-4TVNJWMA.js +11619 -0
  32. package/dist/cli/chunk-4TVNJWMA.js.map +1 -0
  33. package/dist/cli/chunk-4VR6XF4P.js +341 -0
  34. package/dist/cli/chunk-4VR6XF4P.js.map +1 -0
  35. package/dist/cli/chunk-5QCB62C4.js +25319 -0
  36. package/dist/cli/chunk-5QCB62C4.js.map +1 -0
  37. package/dist/cli/chunk-6OWJV3YW.js +390 -0
  38. package/dist/cli/chunk-6OWJV3YW.js.map +1 -0
  39. package/dist/cli/chunk-7EO27TB3.js +130 -0
  40. package/dist/cli/chunk-7EO27TB3.js.map +1 -0
  41. package/dist/cli/chunk-7L2WTRNU.js +308 -0
  42. package/dist/cli/chunk-7L2WTRNU.js.map +1 -0
  43. package/dist/cli/chunk-BHTZFEYE.js +47 -0
  44. package/dist/cli/chunk-BHTZFEYE.js.map +1 -0
  45. package/dist/cli/chunk-BSGCXZQN.js +343 -0
  46. package/dist/cli/chunk-BSGCXZQN.js.map +1 -0
  47. package/dist/cli/chunk-BSINVTTL.js +464 -0
  48. package/dist/cli/chunk-BSINVTTL.js.map +1 -0
  49. package/dist/cli/chunk-CPKCNHRR.js +323 -0
  50. package/dist/cli/chunk-CPKCNHRR.js.map +1 -0
  51. package/dist/cli/chunk-CXVWUPA3.js +96 -0
  52. package/dist/cli/chunk-CXVWUPA3.js.map +1 -0
  53. package/dist/cli/chunk-D5NFKRGO.js +160 -0
  54. package/dist/cli/chunk-D5NFKRGO.js.map +1 -0
  55. package/dist/cli/chunk-ECHSFYOY.js +109 -0
  56. package/dist/cli/chunk-ECHSFYOY.js.map +1 -0
  57. package/dist/cli/chunk-FEZK652I.js +3644 -0
  58. package/dist/cli/chunk-FEZK652I.js.map +1 -0
  59. package/dist/cli/chunk-GALC45Q2.js +696 -0
  60. package/dist/cli/chunk-GALC45Q2.js.map +1 -0
  61. package/dist/cli/chunk-IAUOP25G.js +2984 -0
  62. package/dist/cli/chunk-IAUOP25G.js.map +1 -0
  63. package/dist/cli/chunk-ILJOIQ5W.js +163 -0
  64. package/dist/cli/chunk-ILJOIQ5W.js.map +1 -0
  65. package/dist/cli/chunk-IX6XI2RG.js +225 -0
  66. package/dist/cli/chunk-IX6XI2RG.js.map +1 -0
  67. package/dist/cli/chunk-J5BYPUB5.js +62795 -0
  68. package/dist/cli/chunk-J5BYPUB5.js.map +1 -0
  69. package/dist/cli/chunk-J5XJHLWM.js +55 -0
  70. package/dist/cli/chunk-J5XJHLWM.js.map +1 -0
  71. package/dist/cli/chunk-JKGYMRX5.js +101 -0
  72. package/dist/cli/chunk-JKGYMRX5.js.map +1 -0
  73. package/dist/cli/chunk-JMBMLOBP.js +26 -0
  74. package/dist/cli/chunk-JMBMLOBP.js.map +1 -0
  75. package/dist/cli/chunk-LN3B5PMX.js +128 -0
  76. package/dist/cli/chunk-LN3B5PMX.js.map +1 -0
  77. package/dist/cli/chunk-M2UFZUX3.js +635 -0
  78. package/dist/cli/chunk-M2UFZUX3.js.map +1 -0
  79. package/dist/cli/chunk-PJS34556.js +809 -0
  80. package/dist/cli/chunk-PJS34556.js.map +1 -0
  81. package/dist/cli/chunk-QJG7OF27.js +655 -0
  82. package/dist/cli/chunk-QJG7OF27.js.map +1 -0
  83. package/dist/cli/chunk-QVC75MR3.js +232 -0
  84. package/dist/cli/chunk-QVC75MR3.js.map +1 -0
  85. package/dist/cli/chunk-S2KIUQKQ.js +378 -0
  86. package/dist/cli/chunk-S2KIUQKQ.js.map +1 -0
  87. package/dist/cli/chunk-S4XVGLRW.js +499 -0
  88. package/dist/cli/chunk-S4XVGLRW.js.map +1 -0
  89. package/dist/cli/chunk-T5TQ4NDT.js +190 -0
  90. package/dist/cli/chunk-T5TQ4NDT.js.map +1 -0
  91. package/dist/cli/chunk-TH756VLN.js +1924 -0
  92. package/dist/cli/chunk-TH756VLN.js.map +1 -0
  93. package/dist/cli/chunk-TUK7OWJA.js +51 -0
  94. package/dist/cli/chunk-TUK7OWJA.js.map +1 -0
  95. package/dist/cli/chunk-U4IJVG32.js +363 -0
  96. package/dist/cli/chunk-U4IJVG32.js.map +1 -0
  97. package/dist/cli/chunk-UI66BH6D.js +624 -0
  98. package/dist/cli/chunk-UI66BH6D.js.map +1 -0
  99. package/dist/cli/chunk-VPMBGAND.js +53 -0
  100. package/dist/cli/chunk-VPMBGAND.js.map +1 -0
  101. package/dist/cli/chunk-WLHH3OSR.js +522 -0
  102. package/dist/cli/chunk-WLHH3OSR.js.map +1 -0
  103. package/dist/cli/chunk-WRN65TRD.js +908 -0
  104. package/dist/cli/chunk-WRN65TRD.js.map +1 -0
  105. package/dist/cli/chunk-X53B3JIX.js +34320 -0
  106. package/dist/cli/chunk-X53B3JIX.js.map +1 -0
  107. package/dist/cli/chunk-XJ5SRLKK.js +50 -0
  108. package/dist/cli/chunk-XJ5SRLKK.js.map +1 -0
  109. package/dist/cli/chunk-YZSXRGFH.js +54 -0
  110. package/dist/cli/chunk-YZSXRGFH.js.map +1 -0
  111. package/dist/cli/code-4TUTAGO5.js +163 -0
  112. package/dist/cli/code-4TUTAGO5.js.map +1 -0
  113. package/dist/cli/commands-KMOZEYCF.js +356 -0
  114. package/dist/cli/commands-KMOZEYCF.js.map +1 -0
  115. package/dist/cli/commit-DTFA56VQ.js +292 -0
  116. package/dist/cli/commit-DTFA56VQ.js.map +1 -0
  117. package/dist/cli/desktop-7N3MHNBD.js +1274 -0
  118. package/dist/cli/desktop-7N3MHNBD.js.map +1 -0
  119. package/dist/cli/devtools-HW3WDT3Q.js +91 -0
  120. package/dist/cli/devtools-HW3WDT3Q.js.map +1 -0
  121. package/dist/cli/diff-E5OWTF4C.js +165 -0
  122. package/dist/cli/diff-E5OWTF4C.js.map +1 -0
  123. package/dist/cli/doctor-IEJQRJMN.js +27 -0
  124. package/dist/cli/doctor-IEJQRJMN.js.map +1 -0
  125. package/dist/cli/events-4625EGXI.js +340 -0
  126. package/dist/cli/events-4625EGXI.js.map +1 -0
  127. package/dist/cli/index.js +3536 -0
  128. package/dist/cli/index.js.map +1 -0
  129. package/dist/cli/mcp-PDI2PDLG.js +277 -0
  130. package/dist/cli/mcp-PDI2PDLG.js.map +1 -0
  131. package/dist/cli/mcp-browse-OSPXOFPZ.js +178 -0
  132. package/dist/cli/mcp-browse-OSPXOFPZ.js.map +1 -0
  133. package/dist/cli/mcp-inspect-QRFVTHMF.js +148 -0
  134. package/dist/cli/mcp-inspect-QRFVTHMF.js.map +1 -0
  135. package/dist/cli/package.json +3 -0
  136. package/dist/cli/prompt-3CDII3UO.js +16 -0
  137. package/dist/cli/prompt-3CDII3UO.js.map +1 -0
  138. package/dist/cli/prune-sessions-KZX4SXKW.js +44 -0
  139. package/dist/cli/prune-sessions-KZX4SXKW.js.map +1 -0
  140. package/dist/cli/replay-HYOSRQIV.js +291 -0
  141. package/dist/cli/replay-HYOSRQIV.js.map +1 -0
  142. package/dist/cli/run-2ZHADOUP.js +220 -0
  143. package/dist/cli/run-2ZHADOUP.js.map +1 -0
  144. package/dist/cli/server-X75PAZG5.js +3572 -0
  145. package/dist/cli/server-X75PAZG5.js.map +1 -0
  146. package/dist/cli/sessions-POOZA5CQ.js +120 -0
  147. package/dist/cli/sessions-POOZA5CQ.js.map +1 -0
  148. package/dist/cli/setup-YLPFI3OH.js +618 -0
  149. package/dist/cli/setup-YLPFI3OH.js.map +1 -0
  150. package/dist/cli/stats-NXJ3TO2D.js +16 -0
  151. package/dist/cli/stats-NXJ3TO2D.js.map +1 -0
  152. package/dist/cli/update-ZUO5MKQ6.js +15 -0
  153. package/dist/cli/update-ZUO5MKQ6.js.map +1 -0
  154. package/dist/cli/version-NXXWE3WN.js +33 -0
  155. package/dist/cli/version-NXXWE3WN.js.map +1 -0
  156. package/dist/index.d.ts +2523 -0
  157. package/dist/index.js +15408 -0
  158. package/dist/index.js.map +1 -0
  159. package/package.json +112 -0
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire as __cr } from 'node:module'; if (typeof globalThis.require === 'undefined') { globalThis.require = __cr(import.meta.url); }
3
+ import {
4
+ Box_default,
5
+ Text,
6
+ require_react
7
+ } from "./chunk-X53B3JIX.js";
8
+ import {
9
+ t
10
+ } from "./chunk-IAUOP25G.js";
11
+ import {
12
+ __toESM
13
+ } from "./chunk-TUK7OWJA.js";
14
+
15
+ // src/cli/ui/RecordView.tsx
16
+ var import_react = __toESM(require_react(), 1);
17
+ function RecordView({ rec, compact = false }) {
18
+ const toolArgsMax = compact ? 120 : 200;
19
+ const toolContentMax = compact ? 200 : 400;
20
+ if (rec.role === "user") {
21
+ const content = rec.content.includes("\n") ? rec.content.split("\n").join("\n ") : rec.content;
22
+ return /* @__PURE__ */ import_react.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react.default.createElement(Text, { bold: true, color: "cyan" }, t("recordView.userPrefix")), /* @__PURE__ */ import_react.default.createElement(Text, null, content));
23
+ }
24
+ if (rec.role === "assistant_final") {
25
+ return /* @__PURE__ */ import_react.default.createElement(Box_default, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ import_react.default.createElement(Box_default, null, /* @__PURE__ */ import_react.default.createElement(Text, { bold: true, color: "green" }, t("recordView.assistant")), rec.cost !== void 0 ? /* @__PURE__ */ import_react.default.createElement(Text, { dimColor: true }, " $", rec.cost.toFixed(6)) : null, rec.usage ? /* @__PURE__ */ import_react.default.createElement(CacheBadge, { usage: rec.usage }) : null), rec.content ? /* @__PURE__ */ import_react.default.createElement(Text, null, rec.content) : /* @__PURE__ */ import_react.default.createElement(Text, { dimColor: true, italic: true }, t("recordView.toolCallOnly")));
26
+ }
27
+ if (rec.role === "tool") {
28
+ return /* @__PURE__ */ import_react.default.createElement(Box_default, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ import_react.default.createElement(Text, { color: "yellow" }, t("recordView.toolPrefix"), rec.tool ?? "?", ">"), rec.args ? /* @__PURE__ */ import_react.default.createElement(Text, { dimColor: true }, t("recordView.argsLabel"), truncate(rec.args, toolArgsMax)) : null, /* @__PURE__ */ import_react.default.createElement(Text, { dimColor: true }, t("recordView.resultArrow"), truncate(rec.content, toolContentMax)));
29
+ }
30
+ if (rec.role === "error") {
31
+ return /* @__PURE__ */ import_react.default.createElement(Box_default, { marginTop: 1 }, /* @__PURE__ */ import_react.default.createElement(Text, { color: "red", bold: true }, t("recordView.error")), /* @__PURE__ */ import_react.default.createElement(Text, { color: "red" }, rec.error ?? rec.content));
32
+ }
33
+ if (rec.role === "done" || rec.role === "assistant_delta") {
34
+ return null;
35
+ }
36
+ return /* @__PURE__ */ import_react.default.createElement(Box_default, null, /* @__PURE__ */ import_react.default.createElement(Text, { dimColor: true }, "[", rec.role, "] ", rec.content));
37
+ }
38
+ function CacheBadge({ usage }) {
39
+ const hit = usage.prompt_cache_hit_tokens ?? 0;
40
+ const miss = usage.prompt_cache_miss_tokens ?? 0;
41
+ const total = hit + miss;
42
+ if (total === 0) return null;
43
+ const pct = hit / total * 100;
44
+ const color = pct >= 70 ? "green" : pct >= 40 ? "yellow" : "red";
45
+ return /* @__PURE__ */ import_react.default.createElement(Text, null, /* @__PURE__ */ import_react.default.createElement(Text, { dimColor: true }, t("recordView.cache")), /* @__PURE__ */ import_react.default.createElement(Text, { color }, pct.toFixed(1), "%"));
46
+ }
47
+ function truncate(s, max) {
48
+ return s.length <= max ? s : `${s.slice(0, max)}${t("recordView.truncateExtra", { extra: s.length - max })}`;
49
+ }
50
+
51
+ export {
52
+ RecordView
53
+ };
54
+ //# sourceMappingURL=chunk-3T6VBZCL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/cli/ui/RecordView.tsx"],"sourcesContent":["/** Shared renderer for a single TranscriptRecord — used by ReplayApp and DiffApp. */\n\nimport { Box, Text } from \"ink\";\nimport React from \"react\";\nimport { t } from \"../../i18n/index.js\";\nimport type { TranscriptRecord } from \"../../transcript/log.js\";\n\nexport interface RecordViewProps {\n rec: TranscriptRecord;\n /**\n * When rendering side-by-side in diff mode, shorter truncation limits\n * keep long tool results from dominating the pane. Passes through\n * untouched when undefined.\n */\n compact?: boolean;\n}\n\nexport function RecordView({ rec, compact = false }: RecordViewProps) {\n const toolArgsMax = compact ? 120 : 200;\n const toolContentMax = compact ? 200 : 400;\n\n if (rec.role === \"user\") {\n // Continuation indent of 6 spaces matches the `you › ` prefix width\n // so wrapped multi-line user messages align under the body text\n // instead of jumping to column 0.\n const content = rec.content.includes(\"\\n\")\n ? rec.content.split(\"\\n\").join(\"\\n \")\n : rec.content;\n return (\n <Box marginTop={1}>\n <Text bold color=\"cyan\">\n {t(\"recordView.userPrefix\")}\n </Text>\n <Text>{content}</Text>\n </Box>\n );\n }\n if (rec.role === \"assistant_final\") {\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n <Box>\n <Text bold color=\"green\">\n {t(\"recordView.assistant\")}\n </Text>\n {rec.cost !== undefined ? (\n <Text dimColor>\n {\" $\"}\n {rec.cost.toFixed(6)}\n </Text>\n ) : null}\n {rec.usage ? <CacheBadge usage={rec.usage} /> : null}\n </Box>\n {rec.content ? (\n <Text>{rec.content}</Text>\n ) : (\n <Text dimColor italic>\n {t(\"recordView.toolCallOnly\")}\n </Text>\n )}\n </Box>\n );\n }\n if (rec.role === \"tool\") {\n return (\n <Box flexDirection=\"column\" marginTop={1}>\n <Text color=\"yellow\">\n {t(\"recordView.toolPrefix\")}\n {rec.tool ?? \"?\"}\n {\">\"}\n </Text>\n {rec.args ? (\n <Text dimColor>\n {t(\"recordView.argsLabel\")}\n {truncate(rec.args, toolArgsMax)}\n </Text>\n ) : null}\n <Text dimColor>\n {t(\"recordView.resultArrow\")}\n {truncate(rec.content, toolContentMax)}\n </Text>\n </Box>\n );\n }\n if (rec.role === \"error\") {\n return (\n <Box marginTop={1}>\n <Text color=\"red\" bold>\n {t(\"recordView.error\")}\n </Text>\n <Text color=\"red\">{rec.error ?? rec.content}</Text>\n </Box>\n );\n }\n if (rec.role === \"done\" || rec.role === \"assistant_delta\") {\n // Noise in replay; skip.\n return null;\n }\n return (\n <Box>\n <Text dimColor>\n [{rec.role}] {rec.content}\n </Text>\n </Box>\n );\n}\n\nfunction CacheBadge({ usage }: { usage: NonNullable<TranscriptRecord[\"usage\"]> }) {\n const hit = usage.prompt_cache_hit_tokens ?? 0;\n const miss = usage.prompt_cache_miss_tokens ?? 0;\n const total = hit + miss;\n if (total === 0) return null;\n const pct = (hit / total) * 100;\n const color = pct >= 70 ? \"green\" : pct >= 40 ? \"yellow\" : \"red\";\n return (\n <Text>\n <Text dimColor>{t(\"recordView.cache\")}</Text>\n <Text color={color}>{pct.toFixed(1)}%</Text>\n </Text>\n );\n}\n\nfunction truncate(s: string, max: number): string {\n return s.length <= max\n ? s\n : `${s.slice(0, max)}${t(\"recordView.truncateExtra\", { extra: s.length - max })}`;\n}\n"],"mappings":"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","names":["React"]}
@@ -0,0 +1,153 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire as __cr } from 'node:module'; if (typeof globalThis.require === 'undefined') { globalThis.require = __cr(import.meta.url); }
3
+ import {
4
+ aggregateUsage,
5
+ bucketCacheHitRatio,
6
+ bucketSavingsFraction,
7
+ defaultUsageLogPath,
8
+ formatLogSize,
9
+ readUsageLog
10
+ } from "./chunk-QVC75MR3.js";
11
+ import {
12
+ t
13
+ } from "./chunk-IAUOP25G.js";
14
+
15
+ // src/cli/commands/stats.ts
16
+ import { existsSync, readFileSync } from "fs";
17
+ function statsCommand(opts) {
18
+ if (opts.transcript) {
19
+ transcriptSummary(opts.transcript);
20
+ return;
21
+ }
22
+ dashboard(opts);
23
+ }
24
+ function transcriptSummary(path) {
25
+ if (!existsSync(path)) {
26
+ console.error(`no such transcript: ${path}`);
27
+ process.exit(1);
28
+ }
29
+ const lines = readFileSync(path, "utf8").split(/\r?\n/).filter(Boolean);
30
+ let assistantTurns = 0;
31
+ let toolCalls = 0;
32
+ let lastTurn = 0;
33
+ for (const line of lines) {
34
+ try {
35
+ const rec = JSON.parse(line);
36
+ if (rec.role === "assistant_final") assistantTurns++;
37
+ if (rec.role === "tool") toolCalls++;
38
+ if (typeof rec.turn === "number") lastTurn = Math.max(lastTurn, rec.turn);
39
+ } catch {
40
+ }
41
+ }
42
+ console.log(`transcript: ${path}`);
43
+ console.log(`assistant turns: ${assistantTurns}`);
44
+ console.log(`tool invocations: ${toolCalls}`);
45
+ console.log(`last turn index: ${lastTurn}`);
46
+ }
47
+ function dashboard(opts) {
48
+ const path = opts.logPath ?? defaultUsageLogPath();
49
+ const records = readUsageLog(path);
50
+ if (records.length === 0) {
51
+ console.log("no usage data yet.");
52
+ console.log("");
53
+ console.log(` ${path}`);
54
+ console.log("");
55
+ console.log(t("stats.usageHint"));
56
+ console.log(t("stats.usageDetail"));
57
+ return;
58
+ }
59
+ const agg = aggregateUsage(records, { now: opts.now });
60
+ console.log(renderDashboard(agg, path));
61
+ }
62
+ function renderDashboard(agg, logPath) {
63
+ const lines = [];
64
+ const size = formatLogSize(logPath);
65
+ lines.push(`Carbon Code usage \u2014 ${logPath}${size ? ` (${size})` : ""}`);
66
+ lines.push("");
67
+ lines.push(header());
68
+ lines.push(divider());
69
+ for (const b of agg.buckets) {
70
+ lines.push(bucketRow(b));
71
+ }
72
+ lines.push("");
73
+ if (agg.byModel.length > 0) {
74
+ const totalTurns = agg.buckets[agg.buckets.length - 1]?.turns ?? 0;
75
+ const top = agg.byModel[0];
76
+ if (top && totalTurns > 0) {
77
+ const pct = (top.turns / totalTurns * 100).toFixed(0);
78
+ lines.push(`most used model: ${top.model} (${pct}% of turns)`);
79
+ }
80
+ }
81
+ if (agg.bySession.length > 0) {
82
+ const top = agg.bySession[0];
83
+ if (top) lines.push(`top session: ${top.session} (${top.turns} turns)`);
84
+ }
85
+ if (agg.firstSeen) {
86
+ lines.push(`tracked since: ${new Date(agg.firstSeen).toISOString().slice(0, 10)}`);
87
+ }
88
+ if (agg.subagents) {
89
+ lines.push("");
90
+ lines.push(renderSubagentSection(agg.subagents));
91
+ }
92
+ return lines.join("\n");
93
+ }
94
+ function renderSubagentSection(sub) {
95
+ const lines = [];
96
+ const seconds = (sub.totalDurationMs / 1e3).toFixed(1);
97
+ lines.push(
98
+ `subagent activity: ${sub.total} run(s) \xB7 $${sub.costUsd.toFixed(6)} \xB7 ${seconds}s total`
99
+ );
100
+ const top = sub.bySkill.slice(0, 5);
101
+ for (const s of top) {
102
+ const sec = (s.durationMs / 1e3).toFixed(1);
103
+ lines.push(
104
+ ` ${pad(s.skillName, 18)} ${pad(`${s.count}`, 4, "right")} $${s.costUsd.toFixed(6)} ${sec}s`
105
+ );
106
+ }
107
+ if (sub.bySkill.length > top.length) {
108
+ lines.push(` (+${sub.bySkill.length - top.length} more)`);
109
+ }
110
+ return lines.join("\n");
111
+ }
112
+ function header() {
113
+ return [
114
+ pad("", 10),
115
+ pad("turns", 8, "right"),
116
+ pad("cache hit", 10, "right"),
117
+ pad("cost (USD)", 14, "right"),
118
+ pad("cache saved", 14, "right"),
119
+ pad("vs Claude", 14, "right"),
120
+ pad("saved", 10, "right")
121
+ ].join(" ");
122
+ }
123
+ function divider() {
124
+ return "-".repeat(86);
125
+ }
126
+ function bucketRow(b) {
127
+ const hit = bucketCacheHitRatio(b);
128
+ const savings = bucketSavingsFraction(b);
129
+ return [
130
+ pad(b.label, 10),
131
+ pad(b.turns.toString(), 8, "right"),
132
+ pad(b.turns > 0 ? `${(hit * 100).toFixed(1)}%` : "\u2014", 10, "right"),
133
+ pad(b.turns > 0 ? `$${b.costUsd.toFixed(6)}` : "\u2014", 14, "right"),
134
+ pad(
135
+ b.turns > 0 && b.cacheSavingsUsd > 0 ? `$${b.cacheSavingsUsd.toFixed(4)}` : "\u2014",
136
+ 14,
137
+ "right"
138
+ ),
139
+ pad(b.turns > 0 ? `$${b.claudeEquivUsd.toFixed(4)}` : "\u2014", 14, "right"),
140
+ pad(b.turns > 0 && savings > 0 ? `${(savings * 100).toFixed(1)}%` : "\u2014", 10, "right")
141
+ ].join(" ");
142
+ }
143
+ function pad(s, width, align = "left") {
144
+ if (s.length >= width) return s;
145
+ const fill = " ".repeat(width - s.length);
146
+ return align === "right" ? `${fill}${s}` : `${s}${fill}`;
147
+ }
148
+
149
+ export {
150
+ statsCommand,
151
+ renderDashboard
152
+ };
153
+ //# sourceMappingURL=chunk-4IBIPQVB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/cli/commands/stats.ts"],"sourcesContent":["/** `carboncode stats [path]` — path arg switches to per-transcript mode; default is the cross-session dashboard. */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { t } from \"../../i18n/index.js\";\nimport {\n type UsageAggregate,\n type UsageBucket,\n aggregateUsage,\n bucketCacheHitRatio,\n bucketSavingsFraction,\n defaultUsageLogPath,\n formatLogSize,\n readUsageLog,\n} from \"../../telemetry/usage.js\";\n\nexport interface StatsOptions {\n /** Optional transcript path. Absent → dashboard mode. */\n transcript?: string;\n /** Override usage log location (tests). */\n logPath?: string;\n /** Inject a fixed timestamp (tests) so rolling windows are deterministic. */\n now?: number;\n}\n\nexport function statsCommand(opts: StatsOptions): void {\n if (opts.transcript) {\n transcriptSummary(opts.transcript);\n return;\n }\n dashboard(opts);\n}\n\nfunction transcriptSummary(path: string): void {\n if (!existsSync(path)) {\n console.error(`no such transcript: ${path}`);\n process.exit(1);\n }\n const lines = readFileSync(path, \"utf8\").split(/\\r?\\n/).filter(Boolean);\n let assistantTurns = 0;\n let toolCalls = 0;\n let lastTurn = 0;\n for (const line of lines) {\n try {\n const rec = JSON.parse(line);\n if (rec.role === \"assistant_final\") assistantTurns++;\n if (rec.role === \"tool\") toolCalls++;\n if (typeof rec.turn === \"number\") lastTurn = Math.max(lastTurn, rec.turn);\n } catch {\n /* skip */\n }\n }\n console.log(`transcript: ${path}`);\n console.log(`assistant turns: ${assistantTurns}`);\n console.log(`tool invocations: ${toolCalls}`);\n console.log(`last turn index: ${lastTurn}`);\n}\n\nfunction dashboard(opts: StatsOptions): void {\n const path = opts.logPath ?? defaultUsageLogPath();\n const records = readUsageLog(path);\n if (records.length === 0) {\n console.log(\"no usage data yet.\");\n console.log(\"\");\n console.log(` ${path}`);\n console.log(\"\");\n console.log(t(\"stats.usageHint\"));\n console.log(t(\"stats.usageDetail\"));\n return;\n }\n\n const agg = aggregateUsage(records, { now: opts.now });\n console.log(renderDashboard(agg, path));\n}\n\n/** Pure renderer — pulled out so tests can assert on the string directly. */\nexport function renderDashboard(agg: UsageAggregate, logPath: string): string {\n const lines: string[] = [];\n const size = formatLogSize(logPath);\n lines.push(`Carbon Code usage — ${logPath}${size ? ` (${size})` : \"\"}`);\n lines.push(\"\");\n lines.push(header());\n lines.push(divider());\n for (const b of agg.buckets) {\n lines.push(bucketRow(b));\n }\n lines.push(\"\");\n\n // Model + session breakdown — both trim to top 3 so a user with 20\n // sessions doesn't drown the table.\n if (agg.byModel.length > 0) {\n const totalTurns = agg.buckets[agg.buckets.length - 1]?.turns ?? 0;\n const top = agg.byModel[0];\n if (top && totalTurns > 0) {\n const pct = ((top.turns / totalTurns) * 100).toFixed(0);\n lines.push(`most used model: ${top.model} (${pct}% of turns)`);\n }\n }\n if (agg.bySession.length > 0) {\n const top = agg.bySession[0];\n if (top) lines.push(`top session: ${top.session} (${top.turns} turns)`);\n }\n if (agg.firstSeen) {\n lines.push(`tracked since: ${new Date(agg.firstSeen).toISOString().slice(0, 10)}`);\n }\n if (agg.subagents) {\n lines.push(\"\");\n lines.push(renderSubagentSection(agg.subagents));\n }\n return lines.join(\"\\n\");\n}\n\nfunction renderSubagentSection(sub: NonNullable<UsageAggregate[\"subagents\"]>): string {\n const lines: string[] = [];\n const seconds = (sub.totalDurationMs / 1000).toFixed(1);\n lines.push(\n `subagent activity: ${sub.total} run(s) · $${sub.costUsd.toFixed(6)} · ${seconds}s total`,\n );\n // Show at most 5 skills so the section never dwarfs the main table.\n const top = sub.bySkill.slice(0, 5);\n for (const s of top) {\n const sec = (s.durationMs / 1000).toFixed(1);\n lines.push(\n ` ${pad(s.skillName, 18)} ${pad(`${s.count}`, 4, \"right\")} $${s.costUsd.toFixed(6)} ${sec}s`,\n );\n }\n if (sub.bySkill.length > top.length) {\n lines.push(` (+${sub.bySkill.length - top.length} more)`);\n }\n return lines.join(\"\\n\");\n}\n\nfunction header(): string {\n // Fixed column widths so alignment works in any TTY.\n // `cache saved` reports DeepSeek's hit-vs-miss USD diff; the existing\n // `saved` column is the % saved vs Claude-Sonnet equivalent.\n return [\n pad(\"\", 10),\n pad(\"turns\", 8, \"right\"),\n pad(\"cache hit\", 10, \"right\"),\n pad(\"cost (USD)\", 14, \"right\"),\n pad(\"cache saved\", 14, \"right\"),\n pad(\"vs Claude\", 14, \"right\"),\n pad(\"saved\", 10, \"right\"),\n ].join(\" \");\n}\n\nfunction divider(): string {\n return \"-\".repeat(86);\n}\n\nfunction bucketRow(b: UsageBucket): string {\n const hit = bucketCacheHitRatio(b);\n const savings = bucketSavingsFraction(b);\n return [\n pad(b.label, 10),\n pad(b.turns.toString(), 8, \"right\"),\n pad(b.turns > 0 ? `${(hit * 100).toFixed(1)}%` : \"—\", 10, \"right\"),\n pad(b.turns > 0 ? `$${b.costUsd.toFixed(6)}` : \"—\", 14, \"right\"),\n pad(\n b.turns > 0 && b.cacheSavingsUsd > 0 ? `$${b.cacheSavingsUsd.toFixed(4)}` : \"—\",\n 14,\n \"right\",\n ),\n pad(b.turns > 0 ? `$${b.claudeEquivUsd.toFixed(4)}` : \"—\", 14, \"right\"),\n pad(b.turns > 0 && savings > 0 ? `${(savings * 100).toFixed(1)}%` : \"—\", 10, \"right\"),\n ].join(\" \");\n}\n\nfunction pad(s: string, width: number, align: \"left\" | \"right\" = \"left\"): string {\n if (s.length >= width) return s;\n const fill = \" \".repeat(width - s.length);\n return align === \"right\" ? `${fill}${s}` : `${s}${fill}`;\n}\n"],"mappings":"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","names":[]}