clud-bug 0.6.33 → 0.7.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/bin/clud-bug.js +10 -1353
  2. package/dist/cli/agents-md.d.ts +16 -0
  3. package/dist/cli/agents-md.d.ts.map +1 -0
  4. package/dist/cli/agents-md.js +226 -0
  5. package/dist/cli/agents-md.js.map +1 -0
  6. package/dist/cli/audit.d.ts +13 -0
  7. package/dist/cli/audit.d.ts.map +1 -0
  8. package/dist/cli/audit.js +90 -0
  9. package/dist/cli/audit.js.map +1 -0
  10. package/dist/cli/branch-protection.d.ts +57 -0
  11. package/dist/cli/branch-protection.d.ts.map +1 -0
  12. package/dist/cli/branch-protection.js +118 -0
  13. package/dist/cli/branch-protection.js.map +1 -0
  14. package/dist/cli/edit-workflow.d.ts +18 -0
  15. package/dist/cli/edit-workflow.d.ts.map +1 -0
  16. package/dist/cli/edit-workflow.js +43 -0
  17. package/dist/cli/edit-workflow.js.map +1 -0
  18. package/dist/cli/index.d.ts +8 -0
  19. package/dist/cli/index.d.ts.map +1 -0
  20. package/dist/cli/index.js +18 -0
  21. package/dist/cli/index.js.map +1 -0
  22. package/dist/cli/main.d.ts +3 -0
  23. package/dist/cli/main.d.ts.map +1 -0
  24. package/dist/cli/main.js +1336 -0
  25. package/dist/cli/main.js.map +1 -0
  26. package/dist/cli/skill-usage.d.ts +109 -0
  27. package/dist/cli/skill-usage.d.ts.map +1 -0
  28. package/dist/cli/skill-usage.js +380 -0
  29. package/dist/cli/skill-usage.js.map +1 -0
  30. package/dist/cli/skills.d.ts +56 -0
  31. package/dist/cli/skills.d.ts.map +1 -0
  32. package/dist/cli/skills.js +292 -0
  33. package/dist/cli/skills.js.map +1 -0
  34. package/dist/cli/update.d.ts +29 -0
  35. package/dist/cli/update.d.ts.map +1 -0
  36. package/dist/cli/update.js +186 -0
  37. package/dist/cli/update.js.map +1 -0
  38. package/dist/cli/usage.d.ts +142 -0
  39. package/dist/cli/usage.d.ts.map +1 -0
  40. package/dist/cli/usage.js +348 -0
  41. package/dist/cli/usage.js.map +1 -0
  42. package/dist/core/audit.d.ts +8 -0
  43. package/dist/core/audit.d.ts.map +1 -0
  44. package/dist/core/audit.js +47 -0
  45. package/dist/core/audit.js.map +1 -0
  46. package/dist/core/detect.d.ts +77 -0
  47. package/dist/core/detect.d.ts.map +1 -0
  48. package/dist/core/detect.js +262 -0
  49. package/dist/core/detect.js.map +1 -0
  50. package/dist/core/index.d.ts +8 -0
  51. package/dist/core/index.d.ts.map +1 -0
  52. package/dist/core/index.js +14 -0
  53. package/dist/core/index.js.map +1 -0
  54. package/dist/core/prompts.d.ts +9 -0
  55. package/dist/core/prompts.d.ts.map +1 -0
  56. package/dist/core/prompts.js +401 -0
  57. package/dist/core/prompts.js.map +1 -0
  58. package/dist/core/render-review.d.ts +6 -0
  59. package/dist/core/render-review.d.ts.map +1 -0
  60. package/dist/core/render-review.js +219 -0
  61. package/dist/core/render-review.js.map +1 -0
  62. package/dist/core/render.d.ts +13 -0
  63. package/dist/core/render.d.ts.map +1 -0
  64. package/dist/core/render.js +80 -0
  65. package/dist/core/render.js.map +1 -0
  66. package/dist/core/review-schema.d.ts +42 -0
  67. package/dist/core/review-schema.d.ts.map +1 -0
  68. package/dist/core/review-schema.js +156 -0
  69. package/dist/core/review-schema.js.map +1 -0
  70. package/dist/core/skills.d.ts +80 -0
  71. package/dist/core/skills.d.ts.map +1 -0
  72. package/dist/core/skills.js +510 -0
  73. package/dist/core/skills.js.map +1 -0
  74. package/package.json +27 -4
  75. package/{lib/agents-md.js → src/cli/agents-md.ts} +25 -14
  76. package/{lib/audit.js → src/cli/audit.ts} +37 -44
  77. package/{lib/branch-protection.js → src/cli/branch-protection.ts} +75 -11
  78. package/{lib/edit-workflow.js → src/cli/edit-workflow.ts} +32 -11
  79. package/src/cli/index.ts +101 -0
  80. package/src/cli/main.ts +1376 -0
  81. package/{lib/skill-usage.js → src/cli/skill-usage.ts} +168 -94
  82. package/src/cli/skills.ts +386 -0
  83. package/{lib/update.js → src/cli/update.ts} +68 -27
  84. package/{lib/usage.js → src/cli/usage.ts} +167 -76
  85. package/src/core/audit.ts +53 -0
  86. package/{lib/detect.js → src/core/detect.ts} +100 -47
  87. package/src/core/index.ts +70 -0
  88. package/{lib/prompts.js → src/core/prompts.ts} +16 -2
  89. package/{lib/render-review.js → src/core/render-review.ts} +57 -25
  90. package/{lib/render.js → src/core/render.ts} +36 -10
  91. package/{lib/review-schema.js → src/core/review-schema.ts} +68 -5
  92. package/{lib/skills.js → src/core/skills.ts} +172 -343
  93. package/templates/workflow-py.yml.tmpl +2 -2
  94. package/templates/workflow-ts.yml.tmpl +2 -2
  95. package/templates/workflow.yml.tmpl +17 -8
@@ -0,0 +1,142 @@
1
+ export interface ModelPricing {
2
+ input: number;
3
+ output: number;
4
+ cacheRead: number;
5
+ cacheWrite: number;
6
+ }
7
+ export declare const PRICING: Record<string, ModelPricing>;
8
+ export interface TokenCounts {
9
+ input_tokens?: number | undefined;
10
+ output_tokens?: number | undefined;
11
+ cache_read_input_tokens?: number | undefined;
12
+ cache_creation_input_tokens?: number | undefined;
13
+ }
14
+ export interface CostParts {
15
+ input: number;
16
+ output: number;
17
+ cacheRead: number;
18
+ cacheWrite: number;
19
+ }
20
+ export interface ReviewCost {
21
+ total: number;
22
+ parts: CostParts;
23
+ model: string;
24
+ unknownModel: boolean;
25
+ }
26
+ /**
27
+ * Compute the USD cost of a single clud-bug review from token counts +
28
+ * model. All four token classes are billed independently.
29
+ */
30
+ export declare function computeReviewCost(tokens: TokenCounts, model: string | null | undefined): ReviewCost;
31
+ /**
32
+ * $/LOC for a single review. PR size denominator is additions + deletions
33
+ * — the same metric `gh pr view --json additions,deletions` returns.
34
+ *
35
+ * Returns 0 if additions + deletions === 0 (avoid div-by-zero on
36
+ * docs-only / empty PRs); callers can filter zero-LOC reviews out of
37
+ * trend lines as outliers.
38
+ */
39
+ export declare function costPerLOC(cost: number, additions: number | null | undefined, deletions: number | null | undefined): number;
40
+ /**
41
+ * Cache hit rate: cached_read / (cached_read + creation + input).
42
+ * Cached creation is the cost of WRITING new entries (paid 1.25× per
43
+ * Anthropic); cached read is what we get back at 10% of input price.
44
+ * High hit rate proves the v0.6.3 caching layer is firing on
45
+ * re-reviews and fix-pushes.
46
+ */
47
+ export declare function cacheHitRate(tokens: TokenCounts): number;
48
+ export interface ExtractedTokens {
49
+ model: string | null;
50
+ tokens: Required<TokenCounts> | null;
51
+ ok: boolean;
52
+ }
53
+ /**
54
+ * Parse the model + token counts from a clud-bug-review job log dump.
55
+ *
56
+ * PR #104 fix (token double-count): the SDK's stream-output emits a
57
+ * `"type": "result"` event at the end of a review with a CUMULATIVE
58
+ * `usage` block. It ALSO emits per-turn `"type": "assistant"` events
59
+ * (each with its own usage), AND the result event's usage contains an
60
+ * `iterations` array of per-message breakdowns. Naively summing every
61
+ * `"input_tokens"` occurrence in the log would triple-or-more count
62
+ * the same tokens.
63
+ *
64
+ * Right approach: locate the FINAL `"type": "result"` event and extract
65
+ * the FIRST `"usage": {`-block within it. That's the cumulative bill,
66
+ * the same number Anthropic charges. If no result event exists, the
67
+ * review didn't complete successfully — return ok:false so the caller
68
+ * skips this run rather than trusting partial token data.
69
+ */
70
+ export declare function extractTokensFromLog(logText: unknown): ExtractedTokens;
71
+ export interface ReviewRecord {
72
+ repo: string;
73
+ pr: number;
74
+ createdAt: string;
75
+ model: string;
76
+ tokens: TokenCounts;
77
+ additions: number;
78
+ deletions: number;
79
+ cost: number;
80
+ costPerLOC: number;
81
+ cacheRate: number;
82
+ unknownModel?: boolean | undefined;
83
+ modelObserved?: string | undefined;
84
+ }
85
+ export interface RollupGroupStats {
86
+ reviews: number;
87
+ cost: number;
88
+ loc: number;
89
+ costPerLOC: number;
90
+ cacheRate: number;
91
+ }
92
+ export interface RollupTotal {
93
+ reviews: number;
94
+ cost: number;
95
+ loc: number;
96
+ costPerLOC: number;
97
+ cacheRate: number;
98
+ }
99
+ export interface RollupTrend {
100
+ current: number;
101
+ previous: number | null;
102
+ slopePct: number | null;
103
+ }
104
+ export interface RollupOutlier {
105
+ repo: string;
106
+ pr: number;
107
+ costPerLOC: number;
108
+ multiple: number;
109
+ cost: number;
110
+ reason: string;
111
+ }
112
+ export interface UnknownModelReview {
113
+ repo: string;
114
+ pr: number;
115
+ modelObserved: string | undefined;
116
+ }
117
+ export interface Rollup {
118
+ total: RollupTotal;
119
+ perRepo: Record<string, RollupGroupStats>;
120
+ perModel: Record<string, RollupGroupStats>;
121
+ trend30d: RollupTrend;
122
+ outliers: RollupOutlier[];
123
+ unknownModelReviews: UnknownModelReview[];
124
+ }
125
+ /**
126
+ * Roll up an array of per-review records into a structured summary.
127
+ *
128
+ * Pre-conditions: callers should drop zero-LOC reviews before passing in.
129
+ */
130
+ export declare function rollup(reviews: ReviewRecord[]): Rollup;
131
+ export interface FormatRollupOptions {
132
+ json?: boolean | undefined;
133
+ }
134
+ /**
135
+ * Render the rollup as a human-readable table. Mirrors the sample output
136
+ * from the Phase 0.5 plan.
137
+ *
138
+ * Pass `{ json: true }` for the machine-readable form (the same data
139
+ * the rollup() function returns).
140
+ */
141
+ export declare function formatRollup(rollup: Rollup, opts?: FormatRollupOptions): string;
142
+ //# sourceMappingURL=usage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../../src/cli/usage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,348 @@
1
+ // src/cli/usage.ts — Q7-clud-bug $/LOC compute.
2
+ //
3
+ // Pure functions, no I/O. Driven from bin/clud-bug.js which fetches workflow
4
+ // run JSON + PR metadata via gh CLI. Implementation of the 0.0.M.1 dashboard
5
+ // per the Phase 0.5 plan.
6
+ //
7
+ // Reads:
8
+ // - clud-bug-review job logs (via `gh api .../jobs/<id>/logs`), which
9
+ // contain the SDK's `result` messages including:
10
+ // "model": "claude-sonnet-4-6"
11
+ // "input_tokens": N
12
+ // "output_tokens": N
13
+ // "cache_read_input_tokens": N
14
+ // "cache_creation_input_tokens": N
15
+ // - `gh pr view --json additions,deletions` for the LOC denominator.
16
+ //
17
+ // Computes:
18
+ // $/LOC = total_cost(tokens, model) / (additions + deletions)
19
+ //
20
+ // Q7-clud-bug enforcement: dashboard reports the 30-day rolling trend; the
21
+ // next Phase 0.5 PR ships when the trend stops declining.
22
+ // Anthropic pricing as of 2026-05 (per MTok). Cache write is 1.25× input
23
+ // per Anthropic's published 5-min-TTL ephemeral cache rate.
24
+ export const PRICING = {
25
+ 'claude-sonnet-4-6': {
26
+ input: 3.0, output: 15.0, cacheRead: 0.30, cacheWrite: 3.75,
27
+ },
28
+ 'claude-haiku-4-5-20251001': {
29
+ input: 0.80, output: 4.0, cacheRead: 0.08, cacheWrite: 1.0,
30
+ },
31
+ 'claude-opus-4-7': {
32
+ input: 15.0, output: 75.0, cacheRead: 1.50, cacheWrite: 18.75,
33
+ },
34
+ };
35
+ // Fallback when the model field is missing or new. Use Sonnet pricing —
36
+ // conservative for unknown-but-likely-Sonnet, undercounts Opus until we
37
+ // update the table. The `unknown` flag in the result lets callers warn.
38
+ const DEFAULT_MODEL = 'claude-sonnet-4-6';
39
+ /**
40
+ * Compute the USD cost of a single clud-bug review from token counts +
41
+ * model. All four token classes are billed independently.
42
+ */
43
+ export function computeReviewCost(tokens, model) {
44
+ const t = {
45
+ input: tokens.input_tokens || 0,
46
+ output: tokens.output_tokens || 0,
47
+ cacheRead: tokens.cache_read_input_tokens || 0,
48
+ cacheWrite: tokens.cache_creation_input_tokens || 0,
49
+ };
50
+ const normalized = model && PRICING[model] ? model : DEFAULT_MODEL;
51
+ // PRICING[normalized] is guaranteed to exist (normalized is either a
52
+ // known key or DEFAULT_MODEL which is defined above). Non-null assert
53
+ // to satisfy noUncheckedIndexedAccess.
54
+ const p = PRICING[normalized];
55
+ const parts = {
56
+ input: (t.input / 1e6) * p.input,
57
+ output: (t.output / 1e6) * p.output,
58
+ cacheRead: (t.cacheRead / 1e6) * p.cacheRead,
59
+ cacheWrite: (t.cacheWrite / 1e6) * p.cacheWrite,
60
+ };
61
+ const total = parts.input + parts.output + parts.cacheRead + parts.cacheWrite;
62
+ return {
63
+ total,
64
+ parts,
65
+ model: normalized,
66
+ unknownModel: !(model && PRICING[model]),
67
+ };
68
+ }
69
+ /**
70
+ * $/LOC for a single review. PR size denominator is additions + deletions
71
+ * — the same metric `gh pr view --json additions,deletions` returns.
72
+ *
73
+ * Returns 0 if additions + deletions === 0 (avoid div-by-zero on
74
+ * docs-only / empty PRs); callers can filter zero-LOC reviews out of
75
+ * trend lines as outliers.
76
+ */
77
+ export function costPerLOC(cost, additions, deletions) {
78
+ const loc = (additions || 0) + (deletions || 0);
79
+ if (loc === 0)
80
+ return 0;
81
+ return cost / loc;
82
+ }
83
+ /**
84
+ * Cache hit rate: cached_read / (cached_read + creation + input).
85
+ * Cached creation is the cost of WRITING new entries (paid 1.25× per
86
+ * Anthropic); cached read is what we get back at 10% of input price.
87
+ * High hit rate proves the v0.6.3 caching layer is firing on
88
+ * re-reviews and fix-pushes.
89
+ */
90
+ export function cacheHitRate(tokens) {
91
+ const read = tokens.cache_read_input_tokens || 0;
92
+ const write = tokens.cache_creation_input_tokens || 0;
93
+ const input = tokens.input_tokens || 0;
94
+ const denom = read + write + input;
95
+ if (denom === 0)
96
+ return 0;
97
+ return read / denom;
98
+ }
99
+ /**
100
+ * Parse the model + token counts from a clud-bug-review job log dump.
101
+ *
102
+ * PR #104 fix (token double-count): the SDK's stream-output emits a
103
+ * `"type": "result"` event at the end of a review with a CUMULATIVE
104
+ * `usage` block. It ALSO emits per-turn `"type": "assistant"` events
105
+ * (each with its own usage), AND the result event's usage contains an
106
+ * `iterations` array of per-message breakdowns. Naively summing every
107
+ * `"input_tokens"` occurrence in the log would triple-or-more count
108
+ * the same tokens.
109
+ *
110
+ * Right approach: locate the FINAL `"type": "result"` event and extract
111
+ * the FIRST `"usage": {`-block within it. That's the cumulative bill,
112
+ * the same number Anthropic charges. If no result event exists, the
113
+ * review didn't complete successfully — return ok:false so the caller
114
+ * skips this run rather than trusting partial token data.
115
+ */
116
+ export function extractTokensFromLog(logText) {
117
+ if (typeof logText !== 'string' || logText.length === 0) {
118
+ return { model: null, tokens: null, ok: false };
119
+ }
120
+ // The LAST model field — final message wins (a multi-turn review
121
+ // uses the same model throughout). Captured before the usage parse
122
+ // so model is reported even when we can't find a result event.
123
+ const modelMatches = [...logText.matchAll(/"model"\s*:\s*"([^"]+)"/g)];
124
+ // matchAll yields RegExpMatchArray entries; capture group 1 is the
125
+ // model string. Under noUncheckedIndexedAccess every index is typed
126
+ // possibly-undefined — coalesce so the return type stays string|null.
127
+ const model = modelMatches.length > 0
128
+ ? (modelMatches[modelMatches.length - 1]?.[1] ?? null)
129
+ : null;
130
+ // Locate the final result event. There may be multiple over the
131
+ // life of a long-running session — take the LAST one.
132
+ const resultMarkerRe = /"type"\s*:\s*"result"/g;
133
+ let lastResultIdx = -1;
134
+ let m;
135
+ while ((m = resultMarkerRe.exec(logText)) !== null) {
136
+ lastResultIdx = m.index;
137
+ }
138
+ if (lastResultIdx < 0) {
139
+ // No result event — partial log or job that errored before
140
+ // emitting one. Don't sum the per-turn fields; the data isn't
141
+ // billable-equivalent.
142
+ return { model, tokens: null, ok: false };
143
+ }
144
+ // Within the result event, find the first `"usage": {` and extract
145
+ // its top-level token fields. We scope each field's regex to a window
146
+ // starting at the usage block so we don't pick up the `iterations`
147
+ // array's per-message fields (which are nested deeper but still
148
+ // appear within the same overall result block).
149
+ const fromResult = logText.slice(lastResultIdx);
150
+ const usageIdx = fromResult.search(/"usage"\s*:\s*\{/);
151
+ if (usageIdx < 0) {
152
+ return { model, tokens: null, ok: false };
153
+ }
154
+ // Slice up to the start of `"iterations"` (if present) so we don't
155
+ // double-count per-iteration breakdowns nested inside usage.
156
+ const fromUsage = fromResult.slice(usageIdx);
157
+ const iterationsIdx = fromUsage.search(/"iterations"\s*:/);
158
+ const usageOnly = iterationsIdx >= 0
159
+ ? fromUsage.slice(0, iterationsIdx)
160
+ : fromUsage;
161
+ const pluck = (re) => {
162
+ const match = usageOnly.match(re);
163
+ return match && match[1] !== undefined ? Number(match[1]) : 0;
164
+ };
165
+ const input = pluck(/"input_tokens"\s*:\s*(\d+)/);
166
+ const output = pluck(/"output_tokens"\s*:\s*(\d+)/);
167
+ const cacheRead = pluck(/"cache_read_input_tokens"\s*:\s*(\d+)/);
168
+ const cacheWrite = pluck(/"cache_creation_input_tokens"\s*:\s*(\d+)/);
169
+ const anyTokens = input + output + cacheRead + cacheWrite;
170
+ if (anyTokens === 0) {
171
+ return { model, tokens: null, ok: false };
172
+ }
173
+ return {
174
+ model,
175
+ tokens: {
176
+ input_tokens: input,
177
+ output_tokens: output,
178
+ cache_read_input_tokens: cacheRead,
179
+ cache_creation_input_tokens: cacheWrite,
180
+ },
181
+ ok: true,
182
+ };
183
+ }
184
+ /**
185
+ * Roll up an array of per-review records into a structured summary.
186
+ *
187
+ * Pre-conditions: callers should drop zero-LOC reviews before passing in.
188
+ */
189
+ export function rollup(reviews) {
190
+ const valid = reviews.filter((r) => r.costPerLOC > 0);
191
+ const total = {
192
+ reviews: valid.length,
193
+ cost: valid.reduce((a, r) => a + r.cost, 0),
194
+ loc: valid.reduce((a, r) => a + (r.additions + r.deletions), 0),
195
+ costPerLOC: median(valid.map((r) => r.costPerLOC)),
196
+ cacheRate: median(valid.map((r) => r.cacheRate)),
197
+ };
198
+ const groupBy = (key) => {
199
+ const out = {};
200
+ for (const r of valid) {
201
+ const k = String(r[key]);
202
+ let bucket = out[k];
203
+ if (!bucket) {
204
+ bucket = { reviews: 0, cost: 0, loc: 0, costPerLOCs: [], cacheRates: [] };
205
+ out[k] = bucket;
206
+ }
207
+ bucket.reviews += 1;
208
+ bucket.cost += r.cost;
209
+ bucket.loc += r.additions + r.deletions;
210
+ bucket.costPerLOCs.push(r.costPerLOC);
211
+ bucket.cacheRates.push(r.cacheRate);
212
+ }
213
+ const finalized = {};
214
+ for (const k of Object.keys(out)) {
215
+ const bucket = out[k];
216
+ finalized[k] = {
217
+ reviews: bucket.reviews,
218
+ cost: bucket.cost,
219
+ loc: bucket.loc,
220
+ costPerLOC: median(bucket.costPerLOCs),
221
+ cacheRate: median(bucket.cacheRates),
222
+ };
223
+ }
224
+ return finalized;
225
+ };
226
+ const perRepo = groupBy('repo');
227
+ const perModel = groupBy('model');
228
+ // Outliers: > 2× total.costPerLOC.
229
+ const outliers = valid
230
+ .filter((r) => r.costPerLOC > total.costPerLOC * 2)
231
+ .map((r) => ({
232
+ repo: r.repo,
233
+ pr: r.pr,
234
+ costPerLOC: r.costPerLOC,
235
+ multiple: r.costPerLOC / total.costPerLOC,
236
+ cost: r.cost,
237
+ reason: r.cacheRate < 0.3 ? 'low cache hit' : 'unknown',
238
+ }));
239
+ // 30-day trend: median $/LOC per calendar day. Bucket by createdAt date.
240
+ // Slope reported as MoM % change between the most recent 30-day window's
241
+ // median and the previous 30-day window's median.
242
+ const trend30d = computeTrend(valid);
243
+ // PR #104 fix: surface reviews whose model wasn't in PRICING. The
244
+ // computeReviewCost fallback applied Sonnet rates to unknown models
245
+ // (~5× undercount of Opus), AND bucketed them under Sonnet in the
246
+ // per-model table — exactly the false-good signal Q7 must NOT produce.
247
+ // Caller renders this as a loud warning so the dashboard reader knows
248
+ // to update the PRICING table.
249
+ const unknownModelReviews = valid
250
+ .filter((r) => r.unknownModel === true)
251
+ .map((r) => ({ repo: r.repo, pr: r.pr, modelObserved: r.modelObserved }));
252
+ return { total, perRepo, perModel, trend30d, outliers, unknownModelReviews };
253
+ }
254
+ function median(nums) {
255
+ if (nums.length === 0)
256
+ return 0;
257
+ const sorted = [...nums].sort((a, b) => a - b);
258
+ const mid = Math.floor(sorted.length / 2);
259
+ // sorted is non-empty here so sorted[mid] is defined; the `!`
260
+ // satisfies noUncheckedIndexedAccess and matches JS semantics.
261
+ return sorted.length % 2 === 0
262
+ ? (sorted[mid - 1] + sorted[mid]) / 2
263
+ : sorted[mid];
264
+ }
265
+ function computeTrend(reviews) {
266
+ // PR #104 fix: distinguish "no prior window" (previous bucket empty)
267
+ // from "exactly flat trend" (current === previous > 0). The original
268
+ // code returned slopePct=0 for both, which masked the dangerous case
269
+ // — a stable expensive month-over-month trend rendered as if there
270
+ // were no comparison data, hiding the very signal Q7 enforces.
271
+ // `previous: null` now means "no prior window"; renderer keys on this.
272
+ if (reviews.length === 0) {
273
+ return { current: 0, previous: null, slopePct: null };
274
+ }
275
+ const now = Date.now();
276
+ const day = 24 * 60 * 60 * 1000;
277
+ const currentWindow = reviews.filter((r) => now - new Date(r.createdAt).getTime() <= 30 * day);
278
+ const previousWindow = reviews.filter((r) => {
279
+ const age = now - new Date(r.createdAt).getTime();
280
+ return age > 30 * day && age <= 60 * day;
281
+ });
282
+ const current = median(currentWindow.map((r) => r.costPerLOC));
283
+ if (previousWindow.length === 0) {
284
+ return { current, previous: null, slopePct: null };
285
+ }
286
+ const previous = median(previousWindow.map((r) => r.costPerLOC));
287
+ // previous > 0 because every review in valid[] has costPerLOC > 0
288
+ // (zero-LOC reviews dropped upstream).
289
+ const slopePct = previous > 0 ? ((current - previous) / previous) * 100 : null;
290
+ return { current, previous, slopePct };
291
+ }
292
+ /**
293
+ * Render the rollup as a human-readable table. Mirrors the sample output
294
+ * from the Phase 0.5 plan.
295
+ *
296
+ * Pass `{ json: true }` for the machine-readable form (the same data
297
+ * the rollup() function returns).
298
+ */
299
+ export function formatRollup(rollup, opts = {}) {
300
+ if (opts.json) {
301
+ return JSON.stringify(rollup, null, 2);
302
+ }
303
+ const lines = [];
304
+ const t = rollup.total;
305
+ const trend = rollup.trend30d;
306
+ // PR #104 fix: null slopePct = "no prior window" (prior 30d bucket
307
+ // was empty). A REAL 0% slope (flat trend) renders as "→ 0% MoM",
308
+ // not as "(no prior window)" — masking the latter was the bug.
309
+ let trendStr;
310
+ if (trend.slopePct === null) {
311
+ trendStr = '(no prior window)';
312
+ }
313
+ else {
314
+ const trendArrow = trend.slopePct < 0 ? '↓' : trend.slopePct > 0 ? '↑' : '→';
315
+ trendStr = `${trendArrow} ${trend.slopePct.toFixed(0)}% MoM`;
316
+ }
317
+ lines.push(`ok: ${t.reviews} reviews, 30-day $/LOC trend: ${trendStr}`);
318
+ const perRepoEntries = Object.entries(rollup.perRepo)
319
+ .sort((a, b) => b[1].costPerLOC - a[1].costPerLOC);
320
+ if (perRepoEntries.length > 0) {
321
+ lines.push(' per-repo $/LOC (most → least expensive):');
322
+ for (const [repo, stats] of perRepoEntries) {
323
+ const cache = `${(stats.cacheRate * 100).toFixed(0)}% cached`;
324
+ lines.push(` ${repo.padEnd(28)} ${`$${stats.costPerLOC.toFixed(4)}/LOC`.padEnd(16)} · ${String(stats.reviews).padStart(2)} reviews · ${cache}`);
325
+ }
326
+ }
327
+ lines.push(` org median $/LOC: $${t.costPerLOC.toFixed(4)} · org cache hit: ${(t.cacheRate * 100).toFixed(0)}%`);
328
+ lines.push(` total spend: $${t.cost.toFixed(2)} across ${(t.loc).toLocaleString()} LOC`);
329
+ if (rollup.outliers.length > 0) {
330
+ lines.push(` outliers (>2× median):`);
331
+ for (const o of rollup.outliers) {
332
+ lines.push(` ${o.repo}#${o.pr} ($${o.costPerLOC.toFixed(4)}/LOC, ${o.multiple.toFixed(1)}× median — ${o.reason})`);
333
+ }
334
+ }
335
+ // PR #104 fix: loud warning when one or more reviews used a model
336
+ // not in PRICING (we fell back to Sonnet rates — that can undercount
337
+ // by ~5× if the real model was an Opus variant). Update PRICING and
338
+ // re-run.
339
+ if (rollup.unknownModelReviews && rollup.unknownModelReviews.length > 0) {
340
+ lines.push(` ⚠️ ${rollup.unknownModelReviews.length} review${rollup.unknownModelReviews.length === 1 ? '' : 's'} used model${rollup.unknownModelReviews.length === 1 ? '' : 's'} not in PRICING; cost may be undercounted:`);
341
+ const observed = new Set(rollup.unknownModelReviews.map((u) => u.modelObserved));
342
+ for (const m of observed) {
343
+ lines.push(` seen: "${m}" — add to lib/usage.js PRICING table`);
344
+ }
345
+ }
346
+ return lines.join('\n') + '\n';
347
+ }
348
+ //# sourceMappingURL=usage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.js","sourceRoot":"","sources":["../../src/cli/usage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export declare function durationToGitSince(input: string | null | undefined): string | null;
2
+ export interface AuditHeaderInput {
3
+ date: string;
4
+ scopeLabel: string;
5
+ files: string[];
6
+ }
7
+ export declare function renderAuditHeader({ date, scopeLabel, files }: AuditHeaderInput): string;
8
+ //# sourceMappingURL=audit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/core/audit.ts"],"names":[],"mappings":"AAUA,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAWlF;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAID,wBAAgB,iBAAiB,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,gBAAgB,GAAG,MAAM,CAqBvF"}
@@ -0,0 +1,47 @@
1
+ // Pure audit helpers — no FS, no git, no child_process.
2
+ //
3
+ // Split from lib/audit.js during the v0.7.0 TS migration: durationToGitSince
4
+ // and renderAuditHeader are pure functions safe to consume from any runtime
5
+ // (e.g. clud-bug-app's serverless review path), so they live in src/core/.
6
+ // The git-spawning siblings (gitLines, computeAuditFileSet) live in
7
+ // src/cli/audit.ts.
8
+ // Convert a duration like "7d", "2w", "1mo", "3mo", "1y" to a git --since arg.
9
+ // Returns null if the input is empty/undefined; throws on malformed input.
10
+ export function durationToGitSince(input) {
11
+ if (!input)
12
+ return null;
13
+ const m = String(input).trim().match(/^(\d+)\s*(d|w|mo|m|y)$/i);
14
+ if (!m) {
15
+ throw new Error(`Unrecognized duration "${input}". Examples: 7d, 2w, 1mo, 1y.`);
16
+ }
17
+ // Capture group 1 (\d+) is always present when m is truthy; same for group 2.
18
+ const n = Number(m[1]);
19
+ const unit = m[2].toLowerCase();
20
+ const map = { d: 'day', w: 'week', mo: 'month', m: 'month', y: 'year' };
21
+ return `${n} ${map[unit]}${n === 1 ? '' : 's'} ago`;
22
+ }
23
+ // Render the audit report's initial markdown body. The Action's Claude run
24
+ // will append findings under a "## Findings" section after this header.
25
+ export function renderAuditHeader({ date, scopeLabel, files }) {
26
+ const head = `# 🐛 Clud Bug audit — ${date}
27
+
28
+ A scheduled walk through the habitat. Scope: ${scopeLabel}.
29
+ Files surveyed: **${files.length}**.
30
+
31
+ <details>
32
+ <summary>File manifest (${files.length})</summary>
33
+
34
+ \`\`\`
35
+ ${files.join('\n')}
36
+ \`\`\`
37
+
38
+ </details>
39
+
40
+ ---
41
+
42
+ ## Findings
43
+
44
+ `;
45
+ return head;
46
+ }
47
+ //# sourceMappingURL=audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../src/core/audit.ts"],"names":[],"mappings":"AAAA,wDAAwD;AACxD,EAAE;AACF,6EAA6E;AAC7E,4EAA4E;AAC5E,2EAA2E;AAC3E,oEAAoE;AACpE,oBAAoB;AAEpB,+EAA+E;AAC/E,2EAA2E;AAC3E,MAAM,UAAU,kBAAkB,CAAC,KAAgC;IACjE,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAChE,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,0BAA0B,KAAK,+BAA+B,CAAC,CAAC;IAClF,CAAC;IACD,8EAA8E;IAC9E,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACvB,MAAM,IAAI,GAAI,CAAC,CAAC,CAAC,CAAY,CAAC,WAAW,EAAE,CAAC;IAC5C,MAAM,GAAG,GAA2B,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;IAChG,OAAO,GAAG,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC;AACtD,CAAC;AAQD,2EAA2E;AAC3E,wEAAwE;AACxE,MAAM,UAAU,iBAAiB,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAoB;IAC7E,MAAM,IAAI,GAAG,yBAAyB,IAAI;;+CAEG,UAAU;oBACrC,KAAK,CAAC,MAAM;;;0BAGN,KAAK,CAAC,MAAM;;;EAGpC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;;;;;;;;;CASjB,CAAC;IACA,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,77 @@
1
+ export declare const EXT_TO_LANG: {
2
+ readonly '.ts': "typescript";
3
+ readonly '.tsx': "typescript";
4
+ readonly '.js': "javascript";
5
+ readonly '.jsx': "javascript";
6
+ readonly '.mjs': "javascript";
7
+ readonly '.cjs': "javascript";
8
+ readonly '.py': "python";
9
+ readonly '.go': "go";
10
+ readonly '.rs': "rust";
11
+ readonly '.rb': "ruby";
12
+ readonly '.java': "java";
13
+ readonly '.kt': "kotlin";
14
+ readonly '.swift': "swift";
15
+ readonly '.php': "php";
16
+ readonly '.cs': "csharp";
17
+ readonly '.c': "c";
18
+ readonly '.h': "c";
19
+ readonly '.cpp': "cpp";
20
+ readonly '.cc': "cpp";
21
+ readonly '.hpp': "cpp";
22
+ };
23
+ export declare const DEP_TO_TERM: {
24
+ readonly next: "nextjs";
25
+ readonly react: "react";
26
+ readonly vue: "vue";
27
+ readonly svelte: "svelte";
28
+ readonly '@angular/core': "angular";
29
+ readonly 'solid-js': "solid";
30
+ readonly express: "express";
31
+ readonly fastify: "fastify";
32
+ readonly koa: "koa";
33
+ readonly hono: "hono";
34
+ readonly prisma: "prisma";
35
+ readonly '@prisma/client': "prisma";
36
+ readonly 'drizzle-orm': "drizzle";
37
+ readonly mongoose: "mongodb";
38
+ readonly mongodb: "mongodb";
39
+ readonly tailwindcss: "tailwind";
40
+ readonly vitest: "vitest";
41
+ readonly jest: "jest";
42
+ readonly playwright: "playwright";
43
+ readonly '@playwright/test': "playwright";
44
+ readonly typescript: "typescript";
45
+ };
46
+ export declare const PY_DEP_TO_TERM: {
47
+ readonly django: "django";
48
+ readonly flask: "flask";
49
+ readonly fastapi: "fastapi";
50
+ readonly click: "click";
51
+ readonly typer: "typer";
52
+ readonly pytest: "pytest";
53
+ readonly sqlalchemy: "sqlalchemy";
54
+ readonly pydantic: "pydantic";
55
+ readonly numpy: "numpy";
56
+ readonly pandas: "pandas";
57
+ };
58
+ export interface DetectedSignals {
59
+ name: string | null;
60
+ description: string | null;
61
+ languages: string[];
62
+ histogram: Record<string, number>;
63
+ searchTerms: string[];
64
+ primaryLanguage: string | null;
65
+ }
66
+ declare function fileHistogram(root: string): Promise<Record<string, number>>;
67
+ declare function firstParagraph(readme: string | null): string | null;
68
+ export declare function detect(root: string): Promise<DetectedSignals>;
69
+ export interface DescriptionLineSignals {
70
+ name?: string | null;
71
+ description?: string | null;
72
+ primaryLanguage?: string | null;
73
+ searchTerms?: string[];
74
+ }
75
+ export declare function buildDescriptionLine(signals: DescriptionLineSignals): string;
76
+ export { fileHistogram, firstParagraph };
77
+ //# sourceMappingURL=detect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../../src/core/detect.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;CAamB,CAAC;AAK5C,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;CAUmB,CAAC;AAE5C,eAAO,MAAM,cAAc;;;;;;;;;;;CAKgB,CAAC;AAK5C,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AA2HD,iBAAe,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAqB1E;AAED,iBAAS,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAS5D;AAED,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAoCnE;AAKD,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,sBAAsB,GAAG,MAAM,CAuB5E;AASD,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,CAAC"}