@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,308 @@
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
+ computeReplayStats
5
+ } from "./chunk-T5TQ4NDT.js";
6
+
7
+ // src/transcript/diff.ts
8
+ function findNextDivergence(pairs, fromIdx) {
9
+ for (let i = fromIdx + 1; i < pairs.length; i++) {
10
+ if (pairs[i].kind !== "match") return i;
11
+ }
12
+ return -1;
13
+ }
14
+ function findPrevDivergence(pairs, fromIdx) {
15
+ const start = Math.min(fromIdx - 1, pairs.length - 1);
16
+ for (let i = start; i >= 0; i--) {
17
+ if (pairs[i].kind !== "match") return i;
18
+ }
19
+ return -1;
20
+ }
21
+ function diffTranscripts(a, b) {
22
+ const aSide = {
23
+ label: a.label,
24
+ meta: a.parsed.meta,
25
+ records: a.parsed.records,
26
+ stats: computeReplayStats(a.parsed.records)
27
+ };
28
+ const bSide = {
29
+ label: b.label,
30
+ meta: b.parsed.meta,
31
+ records: b.parsed.records,
32
+ stats: computeReplayStats(b.parsed.records)
33
+ };
34
+ const aByTurn = groupByTurn(a.parsed.records);
35
+ const bByTurn = groupByTurn(b.parsed.records);
36
+ const turns = [.../* @__PURE__ */ new Set([...aByTurn.keys(), ...bByTurn.keys()])].sort((x, y) => x - y);
37
+ const pairs = [];
38
+ let firstDivergenceTurn = null;
39
+ for (const turn of turns) {
40
+ const aGroup = aByTurn.get(turn) ?? { assistant: void 0, tools: [] };
41
+ const bGroup = bByTurn.get(turn) ?? { assistant: void 0, tools: [] };
42
+ const aAssistant = aGroup.assistant;
43
+ const bAssistant = bGroup.assistant;
44
+ const aTools = aGroup.tools;
45
+ const bTools = bGroup.tools;
46
+ let kind;
47
+ let divergenceNote;
48
+ if (!aAssistant && bAssistant) kind = "only_in_b";
49
+ else if (aAssistant && !bAssistant) kind = "only_in_a";
50
+ else if (!aAssistant && !bAssistant)
51
+ kind = "diverge";
52
+ else {
53
+ divergenceNote = classifyDivergence(aAssistant, bAssistant, aTools, bTools);
54
+ kind = divergenceNote ? "diverge" : "match";
55
+ }
56
+ if (kind !== "match" && firstDivergenceTurn === null) firstDivergenceTurn = turn;
57
+ pairs.push({ turn, aAssistant, bAssistant, aTools, bTools, kind, divergenceNote });
58
+ }
59
+ return { a: aSide, b: bSide, pairs, firstDivergenceTurn };
60
+ }
61
+ function classifyDivergence(a, b, aTools, bTools) {
62
+ const aNames = aTools.map((t) => t.tool ?? "").sort();
63
+ const bNames = bTools.map((t) => t.tool ?? "").sort();
64
+ if (aNames.join(",") !== bNames.join(",")) {
65
+ return `tool calls differ: A=[${aNames.join(",") || "\u2014"}] B=[${bNames.join(",") || "\u2014"}]`;
66
+ }
67
+ for (let i = 0; i < aTools.length; i++) {
68
+ const at = aTools[i];
69
+ const bt = bTools[i];
70
+ if (at.tool !== bt.tool) continue;
71
+ if ((at.args ?? "") !== (bt.args ?? "")) {
72
+ return `"${at.tool}" args differ`;
73
+ }
74
+ }
75
+ const simRatio = similarity(a.content, b.content);
76
+ if (simRatio < 0.75) return `text similarity ${(simRatio * 100).toFixed(0)}%`;
77
+ return void 0;
78
+ }
79
+ function similarity(a, b) {
80
+ if (a === b) return 1;
81
+ if (!a && !b) return 1;
82
+ if (!a || !b) return 0;
83
+ const maxLen = Math.max(a.length, b.length);
84
+ if (maxLen > 2e3) return tokenOverlap(a, b);
85
+ const dist = levenshtein(a, b);
86
+ return 1 - dist / maxLen;
87
+ }
88
+ function tokenOverlap(a, b) {
89
+ const ta = new Set(a.toLowerCase().split(/\s+/).filter(Boolean));
90
+ const tb = new Set(b.toLowerCase().split(/\s+/).filter(Boolean));
91
+ if (ta.size === 0 && tb.size === 0) return 1;
92
+ let shared = 0;
93
+ for (const t of ta) if (tb.has(t)) shared++;
94
+ return 2 * shared / (ta.size + tb.size);
95
+ }
96
+ function levenshtein(a, b) {
97
+ const m = a.length;
98
+ const n = b.length;
99
+ if (m === 0) return n;
100
+ if (n === 0) return m;
101
+ let prev = new Array(n + 1);
102
+ let curr = new Array(n + 1);
103
+ for (let j = 0; j <= n; j++) prev[j] = j;
104
+ for (let i = 1; i <= m; i++) {
105
+ curr[0] = i;
106
+ for (let j = 1; j <= n; j++) {
107
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
108
+ curr[j] = Math.min(curr[j - 1] + 1, prev[j] + 1, prev[j - 1] + cost);
109
+ }
110
+ [prev, curr] = [curr, prev];
111
+ }
112
+ return prev[n];
113
+ }
114
+ function groupByTurn(records) {
115
+ const out = /* @__PURE__ */ new Map();
116
+ for (const rec of records) {
117
+ if (rec.role === "user") continue;
118
+ const g = out.get(rec.turn) ?? { tools: [] };
119
+ if (rec.role === "assistant_final") g.assistant = rec;
120
+ else if (rec.role === "tool") g.tools.push(rec);
121
+ out.set(rec.turn, g);
122
+ }
123
+ return out;
124
+ }
125
+ function renderSummaryTable(report, _opts = {}) {
126
+ const a = report.a;
127
+ const b = report.b;
128
+ const lines = [];
129
+ lines.push("Comparing:");
130
+ lines.push(` A ${a.label}`);
131
+ lines.push(` B ${b.label}`);
132
+ lines.push("");
133
+ lines.push(row(["", "A", "B", "\u0394"], [20, 14, 14, 14]));
134
+ lines.push(
135
+ row(["\u2500".repeat(20), "\u2500".repeat(14), "\u2500".repeat(14), "\u2500".repeat(14)], [20, 14, 14, 14])
136
+ );
137
+ lines.push(statRow("model calls", a.stats.turns, b.stats.turns));
138
+ lines.push(statRow("user turns", a.stats.userTurns, b.stats.userTurns));
139
+ lines.push(statRow("tool calls", a.stats.toolCalls, b.stats.toolCalls));
140
+ lines.push(
141
+ row(
142
+ [
143
+ "cache hit",
144
+ `${pct(a.stats.cacheHitRatio)}`,
145
+ `${pct(b.stats.cacheHitRatio)}`,
146
+ signPct(b.stats.cacheHitRatio - a.stats.cacheHitRatio)
147
+ ],
148
+ [20, 14, 14, 14]
149
+ )
150
+ );
151
+ lines.push(
152
+ row(
153
+ [
154
+ "cost (USD)",
155
+ `$${a.stats.totalCostUsd.toFixed(6)}`,
156
+ `$${b.stats.totalCostUsd.toFixed(6)}`,
157
+ costDelta(a.stats.totalCostUsd, b.stats.totalCostUsd)
158
+ ],
159
+ [20, 14, 14, 14]
160
+ )
161
+ );
162
+ lines.push(statRow("prefix hashes", a.stats.prefixHashes.length, b.stats.prefixHashes.length));
163
+ lines.push("");
164
+ const aPrefixStable = a.stats.prefixHashes.length <= 1;
165
+ const bPrefixStable = b.stats.prefixHashes.length <= 1;
166
+ if (aPrefixStable !== bPrefixStable) {
167
+ const stable = aPrefixStable ? "A" : "B";
168
+ const churn = aPrefixStable ? "B" : "A";
169
+ const churnCount = aPrefixStable ? b.stats.prefixHashes.length : a.stats.prefixHashes.length;
170
+ lines.push(
171
+ `prefix stability: ${stable} stayed byte-stable across ${Math.max(
172
+ a.stats.turns,
173
+ b.stats.turns
174
+ )} turns; ${churn} churned ${churnCount} distinct prefixes.`
175
+ );
176
+ lines.push("");
177
+ } else if (a.stats.prefixHashes[0] && a.stats.prefixHashes[0] === b.stats.prefixHashes[0]) {
178
+ lines.push(
179
+ `prefix: A and B share the same prefix hash (${a.stats.prefixHashes[0].slice(0, 12)}\u2026) \u2014 cache delta is attributable to log stability, not prompt change.`
180
+ );
181
+ lines.push("");
182
+ }
183
+ if (report.firstDivergenceTurn !== null) {
184
+ const p = report.pairs.find((p2) => p2.turn === report.firstDivergenceTurn);
185
+ lines.push(
186
+ `first divergence: turn ${report.firstDivergenceTurn} \u2014 ${p?.divergenceNote ?? "?"}`
187
+ );
188
+ if (p?.aAssistant) lines.push(` A \u2192 ${truncate(p.aAssistant.content, 100)}`);
189
+ if (p?.bAssistant) lines.push(` B \u2192 ${truncate(p.bAssistant.content, 100)}`);
190
+ } else {
191
+ lines.push("no material divergence detected (texts within similarity threshold).");
192
+ }
193
+ return lines.join("\n");
194
+ }
195
+ function renderMarkdown(report) {
196
+ const a = report.a;
197
+ const b = report.b;
198
+ const out = [];
199
+ out.push(`# Transcript diff: ${a.label} vs ${b.label}`);
200
+ out.push("");
201
+ if (a.meta || b.meta) {
202
+ out.push("## Meta");
203
+ out.push("");
204
+ out.push(`| | ${a.label} | ${b.label} |`);
205
+ out.push("|---|---|---|");
206
+ out.push(`| source | ${a.meta?.source ?? "\u2014"} | ${b.meta?.source ?? "\u2014"} |`);
207
+ out.push(`| model | ${a.meta?.model ?? "\u2014"} | ${b.meta?.model ?? "\u2014"} |`);
208
+ out.push(`| task | ${a.meta?.task ?? "\u2014"} | ${b.meta?.task ?? "\u2014"} |`);
209
+ out.push(`| startedAt | ${a.meta?.startedAt ?? "\u2014"} | ${b.meta?.startedAt ?? "\u2014"} |`);
210
+ out.push("");
211
+ }
212
+ out.push("## Summary");
213
+ out.push("");
214
+ out.push(`| metric | ${a.label} | ${b.label} | delta |`);
215
+ out.push("|---|---:|---:|---:|");
216
+ out.push(
217
+ `| model calls | ${a.stats.turns} | ${b.stats.turns} | ${signed(b.stats.turns - a.stats.turns)} |`
218
+ );
219
+ out.push(
220
+ `| user turns | ${a.stats.userTurns} | ${b.stats.userTurns} | ${signed(b.stats.userTurns - a.stats.userTurns)} |`
221
+ );
222
+ out.push(
223
+ `| tool calls | ${a.stats.toolCalls} | ${b.stats.toolCalls} | ${signed(b.stats.toolCalls - a.stats.toolCalls)} |`
224
+ );
225
+ out.push(
226
+ `| cache hit | ${pct(a.stats.cacheHitRatio)} | ${pct(b.stats.cacheHitRatio)} | **${signPct(b.stats.cacheHitRatio - a.stats.cacheHitRatio)}** |`
227
+ );
228
+ out.push(
229
+ `| cost (USD) | $${a.stats.totalCostUsd.toFixed(6)} | $${b.stats.totalCostUsd.toFixed(6)} | ${costDelta(a.stats.totalCostUsd, b.stats.totalCostUsd)} |`
230
+ );
231
+ out.push(
232
+ `| prefix hashes | ${a.stats.prefixHashes.length} | ${b.stats.prefixHashes.length} | \u2014 |`
233
+ );
234
+ out.push("");
235
+ out.push("## Turn-by-turn");
236
+ out.push("");
237
+ out.push(`| turn | kind | ${a.label} tool calls | ${b.label} tool calls | note |`);
238
+ out.push("|---:|:---:|---|---|---|");
239
+ for (const p of report.pairs) {
240
+ const aTools = p.aTools.map((t) => t.tool).filter(Boolean).join(", ") || "\u2014";
241
+ const bTools = p.bTools.map((t) => t.tool).filter(Boolean).join(", ") || "\u2014";
242
+ out.push(`| ${p.turn} | ${p.kind} | ${aTools} | ${bTools} | ${p.divergenceNote ?? ""} |`);
243
+ }
244
+ out.push("");
245
+ if (report.firstDivergenceTurn !== null) {
246
+ const p = report.pairs.find((x) => x.turn === report.firstDivergenceTurn);
247
+ out.push(`## First divergence (turn ${report.firstDivergenceTurn})`);
248
+ out.push("");
249
+ out.push(p?.divergenceNote ?? "");
250
+ out.push("");
251
+ if (p?.aAssistant) {
252
+ out.push(`**${a.label}:**`);
253
+ out.push("");
254
+ out.push("```");
255
+ out.push(p.aAssistant.content);
256
+ out.push("```");
257
+ out.push("");
258
+ }
259
+ if (p?.bAssistant) {
260
+ out.push(`**${b.label}:**`);
261
+ out.push("");
262
+ out.push("```");
263
+ out.push(p.bAssistant.content);
264
+ out.push("```");
265
+ out.push("");
266
+ }
267
+ }
268
+ return out.join("\n");
269
+ }
270
+ function row(cols, widths) {
271
+ return cols.map((c, i) => padRight(c, widths[i] ?? c.length)).join(" ");
272
+ }
273
+ function statRow(label, av, bv) {
274
+ return row([label, `${av}`, `${bv}`, signed(bv - av)], [20, 14, 14, 14]);
275
+ }
276
+ function padRight(s, w) {
277
+ return s.length >= w ? s : s + " ".repeat(w - s.length);
278
+ }
279
+ function signed(n) {
280
+ if (n === 0) return "0";
281
+ return `${n > 0 ? "+" : ""}${n}`;
282
+ }
283
+ function signPct(diff) {
284
+ if (diff === 0) return "0pp";
285
+ const s = (diff * 100).toFixed(1);
286
+ return `${diff > 0 ? "+" : ""}${s}pp`;
287
+ }
288
+ function pct(x) {
289
+ return `${(x * 100).toFixed(1)}%`;
290
+ }
291
+ function costDelta(a, b) {
292
+ if (a === 0 && b === 0) return "\u2014";
293
+ if (a === 0) return "new";
294
+ const pctChange = (b - a) / a * 100;
295
+ return `${pctChange > 0 ? "+" : ""}${pctChange.toFixed(1)}%`;
296
+ }
297
+ function truncate(s, n) {
298
+ return s.length > n ? `${s.slice(0, n)}\u2026` : s;
299
+ }
300
+
301
+ export {
302
+ findNextDivergence,
303
+ findPrevDivergence,
304
+ diffTranscripts,
305
+ renderSummaryTable,
306
+ renderMarkdown
307
+ };
308
+ //# sourceMappingURL=chunk-7L2WTRNU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/transcript/diff.ts"],"sourcesContent":["/** Transcript diff — pairs assistant_final by turn number; unmatched extras become only_in_a / only_in_b. */\n\nimport type { ReadTranscriptResult, TranscriptRecord } from \"./log.js\";\nimport { type ReplayStats, computeReplayStats } from \"./replay.js\";\n\nexport interface DiffSide {\n label: string;\n meta: ReadTranscriptResult[\"meta\"];\n records: TranscriptRecord[];\n stats: ReplayStats;\n}\n\nexport interface TurnPair {\n turn: number;\n aAssistant?: TranscriptRecord;\n bAssistant?: TranscriptRecord;\n aTools: TranscriptRecord[];\n bTools: TranscriptRecord[];\n kind: \"match\" | \"diverge\" | \"only_in_a\" | \"only_in_b\";\n /** When kind === \"diverge\", a short one-liner pointing at what differs. */\n divergenceNote?: string;\n}\n\nexport interface DiffReport {\n a: DiffSide;\n b: DiffSide;\n pairs: TurnPair[];\n firstDivergenceTurn: number | null;\n}\n\nexport function findNextDivergence(pairs: TurnPair[], fromIdx: number): number {\n for (let i = fromIdx + 1; i < pairs.length; i++) {\n if (pairs[i]!.kind !== \"match\") return i;\n }\n return -1;\n}\n\nexport function findPrevDivergence(pairs: TurnPair[], fromIdx: number): number {\n const start = Math.min(fromIdx - 1, pairs.length - 1);\n for (let i = start; i >= 0; i--) {\n if (pairs[i]!.kind !== \"match\") return i;\n }\n return -1;\n}\n\nexport function diffTranscripts(\n a: { label: string; parsed: ReadTranscriptResult },\n b: { label: string; parsed: ReadTranscriptResult },\n): DiffReport {\n const aSide: DiffSide = {\n label: a.label,\n meta: a.parsed.meta,\n records: a.parsed.records,\n stats: computeReplayStats(a.parsed.records),\n };\n const bSide: DiffSide = {\n label: b.label,\n meta: b.parsed.meta,\n records: b.parsed.records,\n stats: computeReplayStats(b.parsed.records),\n };\n\n const aByTurn = groupByTurn(a.parsed.records);\n const bByTurn = groupByTurn(b.parsed.records);\n const turns = [...new Set([...aByTurn.keys(), ...bByTurn.keys()])].sort((x, y) => x - y);\n\n const pairs: TurnPair[] = [];\n let firstDivergenceTurn: number | null = null;\n for (const turn of turns) {\n const aGroup = aByTurn.get(turn) ?? { assistant: undefined, tools: [] };\n const bGroup = bByTurn.get(turn) ?? { assistant: undefined, tools: [] };\n const aAssistant = aGroup.assistant;\n const bAssistant = bGroup.assistant;\n const aTools = aGroup.tools;\n const bTools = bGroup.tools;\n\n let kind: TurnPair[\"kind\"];\n let divergenceNote: string | undefined;\n if (!aAssistant && bAssistant) kind = \"only_in_b\";\n else if (aAssistant && !bAssistant) kind = \"only_in_a\";\n else if (!aAssistant && !bAssistant)\n kind = \"diverge\"; // tool-only turn (rare)\n else {\n divergenceNote = classifyDivergence(aAssistant!, bAssistant!, aTools, bTools);\n kind = divergenceNote ? \"diverge\" : \"match\";\n }\n\n if (kind !== \"match\" && firstDivergenceTurn === null) firstDivergenceTurn = turn;\n pairs.push({ turn, aAssistant, bAssistant, aTools, bTools, kind, divergenceNote });\n }\n\n return { a: aSide, b: bSide, pairs, firstDivergenceTurn };\n}\n\nfunction classifyDivergence(\n a: TranscriptRecord,\n b: TranscriptRecord,\n aTools: TranscriptRecord[],\n bTools: TranscriptRecord[],\n): string | undefined {\n const aNames = aTools.map((t) => t.tool ?? \"\").sort();\n const bNames = bTools.map((t) => t.tool ?? \"\").sort();\n if (aNames.join(\",\") !== bNames.join(\",\")) {\n return `tool calls differ: A=[${aNames.join(\",\") || \"—\"}] B=[${bNames.join(\",\") || \"—\"}]`;\n }\n // Same tool names — did they pass different args?\n for (let i = 0; i < aTools.length; i++) {\n const at = aTools[i]!;\n const bt = bTools[i]!;\n if (at.tool !== bt.tool) continue;\n if ((at.args ?? \"\") !== (bt.args ?? \"\")) {\n return `\"${at.tool}\" args differ`;\n }\n }\n const simRatio = similarity(a.content, b.content);\n if (simRatio < 0.75) return `text similarity ${(simRatio * 100).toFixed(0)}%`;\n return undefined;\n}\n\n/** Falls back to token-overlap above 2000 chars to keep diff fast on chatty transcripts. */\nexport function similarity(a: string, b: string): number {\n if (a === b) return 1;\n if (!a && !b) return 1;\n if (!a || !b) return 0;\n const maxLen = Math.max(a.length, b.length);\n if (maxLen > 2000) return tokenOverlap(a, b);\n const dist = levenshtein(a, b);\n return 1 - dist / maxLen;\n}\n\nfunction tokenOverlap(a: string, b: string): number {\n const ta = new Set(a.toLowerCase().split(/\\s+/).filter(Boolean));\n const tb = new Set(b.toLowerCase().split(/\\s+/).filter(Boolean));\n if (ta.size === 0 && tb.size === 0) return 1;\n let shared = 0;\n for (const t of ta) if (tb.has(t)) shared++;\n return (2 * shared) / (ta.size + tb.size);\n}\n\nfunction levenshtein(a: string, b: string): number {\n const m = a.length;\n const n = b.length;\n if (m === 0) return n;\n if (n === 0) return m;\n let prev = new Array(n + 1);\n let curr = new Array(n + 1);\n for (let j = 0; j <= n; j++) prev[j] = j;\n for (let i = 1; i <= m; i++) {\n curr[0] = i;\n for (let j = 1; j <= n; j++) {\n const cost = a[i - 1] === b[j - 1] ? 0 : 1;\n curr[j] = Math.min(curr[j - 1] + 1, prev[j] + 1, prev[j - 1] + cost);\n }\n [prev, curr] = [curr, prev];\n }\n return prev[n];\n}\n\ninterface TurnGroup {\n assistant?: TranscriptRecord;\n tools: TranscriptRecord[];\n}\n\nfunction groupByTurn(records: TranscriptRecord[]): Map<number, TurnGroup> {\n const out = new Map<number, TurnGroup>();\n for (const rec of records) {\n if (rec.role === \"user\") continue; // user msg is input to the turn, not its output\n const g = out.get(rec.turn) ?? { tools: [] };\n if (rec.role === \"assistant_final\") g.assistant = rec;\n else if (rec.role === \"tool\") g.tools.push(rec);\n out.set(rec.turn, g);\n }\n return out;\n}\n\nexport interface RenderOptions {\n /** Monochrome output (for file redirection or piping). Defaults to true. */\n monochrome?: boolean;\n}\n\nexport function renderSummaryTable(report: DiffReport, _opts: RenderOptions = {}): string {\n const a = report.a;\n const b = report.b;\n const lines: string[] = [];\n lines.push(\"Comparing:\");\n lines.push(` A ${a.label}`);\n lines.push(` B ${b.label}`);\n lines.push(\"\");\n lines.push(row([\"\", \"A\", \"B\", \"Δ\"], [20, 14, 14, 14]));\n lines.push(\n row([\"─\".repeat(20), \"─\".repeat(14), \"─\".repeat(14), \"─\".repeat(14)], [20, 14, 14, 14]),\n );\n lines.push(statRow(\"model calls\", a.stats.turns, b.stats.turns));\n lines.push(statRow(\"user turns\", a.stats.userTurns, b.stats.userTurns));\n lines.push(statRow(\"tool calls\", a.stats.toolCalls, b.stats.toolCalls));\n lines.push(\n row(\n [\n \"cache hit\",\n `${pct(a.stats.cacheHitRatio)}`,\n `${pct(b.stats.cacheHitRatio)}`,\n signPct(b.stats.cacheHitRatio - a.stats.cacheHitRatio),\n ],\n [20, 14, 14, 14],\n ),\n );\n lines.push(\n row(\n [\n \"cost (USD)\",\n `$${a.stats.totalCostUsd.toFixed(6)}`,\n `$${b.stats.totalCostUsd.toFixed(6)}`,\n costDelta(a.stats.totalCostUsd, b.stats.totalCostUsd),\n ],\n [20, 14, 14, 14],\n ),\n );\n lines.push(statRow(\"prefix hashes\", a.stats.prefixHashes.length, b.stats.prefixHashes.length));\n lines.push(\"\");\n\n // Prefix stability story — the headline finding when comparing bench modes.\n const aPrefixStable = a.stats.prefixHashes.length <= 1;\n const bPrefixStable = b.stats.prefixHashes.length <= 1;\n if (aPrefixStable !== bPrefixStable) {\n const stable = aPrefixStable ? \"A\" : \"B\";\n const churn = aPrefixStable ? \"B\" : \"A\";\n const churnCount = aPrefixStable ? b.stats.prefixHashes.length : a.stats.prefixHashes.length;\n lines.push(\n `prefix stability: ${stable} stayed byte-stable across ${Math.max(\n a.stats.turns,\n b.stats.turns,\n )} turns; ${churn} churned ${churnCount} distinct prefixes.`,\n );\n lines.push(\"\");\n } else if (a.stats.prefixHashes[0] && a.stats.prefixHashes[0] === b.stats.prefixHashes[0]) {\n lines.push(\n `prefix: A and B share the same prefix hash (${a.stats.prefixHashes[0].slice(0, 12)}…) — cache delta is attributable to log stability, not prompt change.`,\n );\n lines.push(\"\");\n }\n\n if (report.firstDivergenceTurn !== null) {\n const p = report.pairs.find((p) => p.turn === report.firstDivergenceTurn);\n lines.push(\n `first divergence: turn ${report.firstDivergenceTurn} — ${p?.divergenceNote ?? \"?\"}`,\n );\n if (p?.aAssistant) lines.push(` A → ${truncate(p.aAssistant.content, 100)}`);\n if (p?.bAssistant) lines.push(` B → ${truncate(p.bAssistant.content, 100)}`);\n } else {\n lines.push(\"no material divergence detected (texts within similarity threshold).\");\n }\n\n return lines.join(\"\\n\");\n}\n\nexport function renderMarkdown(report: DiffReport): string {\n const a = report.a;\n const b = report.b;\n const out: string[] = [];\n out.push(`# Transcript diff: ${a.label} vs ${b.label}`);\n out.push(\"\");\n if (a.meta || b.meta) {\n out.push(\"## Meta\");\n out.push(\"\");\n out.push(`| | ${a.label} | ${b.label} |`);\n out.push(\"|---|---|---|\");\n out.push(`| source | ${a.meta?.source ?? \"—\"} | ${b.meta?.source ?? \"—\"} |`);\n out.push(`| model | ${a.meta?.model ?? \"—\"} | ${b.meta?.model ?? \"—\"} |`);\n out.push(`| task | ${a.meta?.task ?? \"—\"} | ${b.meta?.task ?? \"—\"} |`);\n out.push(`| startedAt | ${a.meta?.startedAt ?? \"—\"} | ${b.meta?.startedAt ?? \"—\"} |`);\n out.push(\"\");\n }\n\n out.push(\"## Summary\");\n out.push(\"\");\n out.push(`| metric | ${a.label} | ${b.label} | delta |`);\n out.push(\"|---|---:|---:|---:|\");\n out.push(\n `| model calls | ${a.stats.turns} | ${b.stats.turns} | ${signed(b.stats.turns - a.stats.turns)} |`,\n );\n out.push(\n `| user turns | ${a.stats.userTurns} | ${b.stats.userTurns} | ${signed(b.stats.userTurns - a.stats.userTurns)} |`,\n );\n out.push(\n `| tool calls | ${a.stats.toolCalls} | ${b.stats.toolCalls} | ${signed(b.stats.toolCalls - a.stats.toolCalls)} |`,\n );\n out.push(\n `| cache hit | ${pct(a.stats.cacheHitRatio)} | ${pct(b.stats.cacheHitRatio)} | **${signPct(b.stats.cacheHitRatio - a.stats.cacheHitRatio)}** |`,\n );\n out.push(\n `| cost (USD) | $${a.stats.totalCostUsd.toFixed(6)} | $${b.stats.totalCostUsd.toFixed(6)} | ${costDelta(a.stats.totalCostUsd, b.stats.totalCostUsd)} |`,\n );\n out.push(\n `| prefix hashes | ${a.stats.prefixHashes.length} | ${b.stats.prefixHashes.length} | — |`,\n );\n out.push(\"\");\n\n out.push(\"## Turn-by-turn\");\n out.push(\"\");\n out.push(`| turn | kind | ${a.label} tool calls | ${b.label} tool calls | note |`);\n out.push(\"|---:|:---:|---|---|---|\");\n for (const p of report.pairs) {\n const aTools =\n p.aTools\n .map((t) => t.tool)\n .filter(Boolean)\n .join(\", \") || \"—\";\n const bTools =\n p.bTools\n .map((t) => t.tool)\n .filter(Boolean)\n .join(\", \") || \"—\";\n out.push(`| ${p.turn} | ${p.kind} | ${aTools} | ${bTools} | ${p.divergenceNote ?? \"\"} |`);\n }\n out.push(\"\");\n\n if (report.firstDivergenceTurn !== null) {\n const p = report.pairs.find((x) => x.turn === report.firstDivergenceTurn);\n out.push(`## First divergence (turn ${report.firstDivergenceTurn})`);\n out.push(\"\");\n out.push(p?.divergenceNote ?? \"\");\n out.push(\"\");\n if (p?.aAssistant) {\n out.push(`**${a.label}:**`);\n out.push(\"\");\n out.push(\"```\");\n out.push(p.aAssistant.content);\n out.push(\"```\");\n out.push(\"\");\n }\n if (p?.bAssistant) {\n out.push(`**${b.label}:**`);\n out.push(\"\");\n out.push(\"```\");\n out.push(p.bAssistant.content);\n out.push(\"```\");\n out.push(\"\");\n }\n }\n return out.join(\"\\n\");\n}\n\nfunction row(cols: string[], widths: number[]): string {\n return cols.map((c, i) => padRight(c, widths[i] ?? c.length)).join(\" \");\n}\n\nfunction statRow(label: string, av: number, bv: number): string {\n return row([label, `${av}`, `${bv}`, signed(bv - av)], [20, 14, 14, 14]);\n}\n\nfunction padRight(s: string, w: number): string {\n return s.length >= w ? s : s + \" \".repeat(w - s.length);\n}\n\nfunction signed(n: number): string {\n if (n === 0) return \"0\";\n return `${n > 0 ? \"+\" : \"\"}${n}`;\n}\n\nfunction signPct(diff: number): string {\n if (diff === 0) return \"0pp\";\n const s = (diff * 100).toFixed(1);\n return `${diff > 0 ? \"+\" : \"\"}${s}pp`;\n}\n\nfunction pct(x: number): string {\n return `${(x * 100).toFixed(1)}%`;\n}\n\nfunction costDelta(a: number, b: number): string {\n if (a === 0 && b === 0) return \"—\";\n if (a === 0) return \"new\";\n const pctChange = ((b - a) / a) * 100;\n return `${pctChange > 0 ? \"+\" : \"\"}${pctChange.toFixed(1)}%`;\n}\n\nfunction truncate(s: string, n: number): string {\n return s.length > n ? `${s.slice(0, n)}…` : s;\n}\n"],"mappings":"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","names":["p"]}
@@ -0,0 +1,47 @@
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
+
4
+ // src/mcp/catalog.ts
5
+ var MCP_CATALOG = [
6
+ {
7
+ name: "filesystem",
8
+ summary: "read/write/search files inside a sandboxed directory",
9
+ package: "@modelcontextprotocol/server-filesystem",
10
+ userArgs: "<dir>",
11
+ note: "the directory is a hard sandbox \u2014 the server refuses access outside it"
12
+ },
13
+ {
14
+ name: "memory",
15
+ summary: "persistent key-value memory across sessions",
16
+ package: "@modelcontextprotocol/server-memory"
17
+ },
18
+ {
19
+ name: "github",
20
+ summary: "read issues, PRs, code search (needs GITHUB_PERSONAL_ACCESS_TOKEN)",
21
+ package: "@modelcontextprotocol/server-github",
22
+ note: "set GITHUB_PERSONAL_ACCESS_TOKEN in your env before spawning"
23
+ },
24
+ {
25
+ name: "puppeteer",
26
+ summary: "browser automation \u2014 take screenshots, click, type",
27
+ package: "@modelcontextprotocol/server-puppeteer",
28
+ note: "downloads Chromium on first run (~200 MB)"
29
+ },
30
+ {
31
+ name: "everything",
32
+ summary: "official test server \u2014 exercises every MCP feature",
33
+ package: "@modelcontextprotocol/server-everything",
34
+ note: "useful for debugging your Carbon Code setup"
35
+ }
36
+ ];
37
+ function mcpCommandFor(entry) {
38
+ const pkg = entry.package;
39
+ const tail = entry.userArgs ? ` ${entry.userArgs}` : "";
40
+ return `--mcp "${entry.name}=npx -y ${pkg}${tail}"`;
41
+ }
42
+
43
+ export {
44
+ MCP_CATALOG,
45
+ mcpCommandFor
46
+ };
47
+ //# sourceMappingURL=chunk-BHTZFEYE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/mcp/catalog.ts"],"sourcesContent":["/** Hardcoded — fetching this list at runtime would make `mcp list` flaky offline / behind proxies. */\n\nexport interface CatalogEntry {\n /** Short name, used as the namespace prefix when suggested. */\n name: string;\n /** One-line description shown in `carboncode mcp list`. */\n summary: string;\n /** npm package id (for `npx -y <pkg>`). */\n package: string;\n /** Extra args the user must supply (e.g. a directory path). */\n userArgs?: string;\n /** Notes the user needs to know — shown dimmed. */\n note?: string;\n}\n\n// Every entry below is verified to exist on npm as of this release.\n// `fetch` and `sqlite` are deliberately *absent* — their reference\n// servers are Python-only (`pip install mcp-server-fetch`), so a Node\n// user running `npx -y @modelcontextprotocol/server-fetch` hits a 404\n// from the npm registry. We'd rather ship a smaller list that always\n// works than a longer list where two options silently 404 on the user.\nexport const MCP_CATALOG: CatalogEntry[] = [\n {\n name: \"filesystem\",\n summary: \"read/write/search files inside a sandboxed directory\",\n package: \"@modelcontextprotocol/server-filesystem\",\n userArgs: \"<dir>\",\n note: \"the directory is a hard sandbox — the server refuses access outside it\",\n },\n {\n name: \"memory\",\n summary: \"persistent key-value memory across sessions\",\n package: \"@modelcontextprotocol/server-memory\",\n },\n {\n name: \"github\",\n summary: \"read issues, PRs, code search (needs GITHUB_PERSONAL_ACCESS_TOKEN)\",\n package: \"@modelcontextprotocol/server-github\",\n note: \"set GITHUB_PERSONAL_ACCESS_TOKEN in your env before spawning\",\n },\n {\n name: \"puppeteer\",\n summary: \"browser automation — take screenshots, click, type\",\n package: \"@modelcontextprotocol/server-puppeteer\",\n note: \"downloads Chromium on first run (~200 MB)\",\n },\n {\n name: \"everything\",\n summary: \"official test server — exercises every MCP feature\",\n package: \"@modelcontextprotocol/server-everything\",\n note: \"useful for debugging your Carbon Code setup\",\n },\n];\n\nexport function mcpCommandFor(entry: CatalogEntry): string {\n const pkg = entry.package;\n const tail = entry.userArgs ? ` ${entry.userArgs}` : \"\";\n return `--mcp \"${entry.name}=npx -y ${pkg}${tail}\"`;\n}\n"],"mappings":";;;;AAqBO,IAAM,cAA8B;AAAA,EACzC;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,IACT,SAAS;AAAA,IACT,UAAU;AAAA,IACV,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,IACT,SAAS;AAAA,IACT,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,IACT,SAAS;AAAA,IACT,MAAM;AAAA,EACR;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,IACT,SAAS;AAAA,IACT,MAAM;AAAA,EACR;AACF;AAEO,SAAS,cAAc,OAA6B;AACzD,QAAM,MAAM,MAAM;AAClB,QAAM,OAAO,MAAM,WAAW,IAAI,MAAM,QAAQ,KAAK;AACrD,SAAO,UAAU,MAAM,IAAI,WAAW,GAAG,GAAG,IAAI;AAClD;","names":[]}