@rasensio/aidlc 1.26.1 → 1.27.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 (73) hide show
  1. package/dist/commands/cost.d.ts +7 -0
  2. package/dist/commands/cost.d.ts.map +1 -1
  3. package/dist/commands/cost.js +137 -0
  4. package/dist/commands/cost.js.map +1 -1
  5. package/dist/commands/discover.d.ts.map +1 -1
  6. package/dist/commands/discover.js +11 -3
  7. package/dist/commands/discover.js.map +1 -1
  8. package/dist/commands/review.d.ts +15 -2
  9. package/dist/commands/review.d.ts.map +1 -1
  10. package/dist/commands/review.js +163 -9
  11. package/dist/commands/review.js.map +1 -1
  12. package/dist/commands/start.d.ts.map +1 -1
  13. package/dist/commands/start.js +27 -66
  14. package/dist/commands/start.js.map +1 -1
  15. package/dist/commands/transition.d.ts.map +1 -1
  16. package/dist/commands/transition.js +45 -8
  17. package/dist/commands/transition.js.map +1 -1
  18. package/dist/commands/update.d.ts.map +1 -1
  19. package/dist/commands/update.js +8 -2
  20. package/dist/commands/update.js.map +1 -1
  21. package/dist/core/lifecycle.d.ts.map +1 -1
  22. package/dist/core/lifecycle.js +30 -1
  23. package/dist/core/lifecycle.js.map +1 -1
  24. package/dist/cost/context.d.ts +72 -0
  25. package/dist/cost/context.d.ts.map +1 -0
  26. package/dist/cost/context.js +155 -0
  27. package/dist/cost/context.js.map +1 -0
  28. package/dist/cost/dedupe-history.d.ts +98 -0
  29. package/dist/cost/dedupe-history.d.ts.map +1 -0
  30. package/dist/cost/dedupe-history.js +275 -0
  31. package/dist/cost/dedupe-history.js.map +1 -0
  32. package/dist/cost/ledger.d.ts.map +1 -1
  33. package/dist/cost/ledger.js +11 -5
  34. package/dist/cost/ledger.js.map +1 -1
  35. package/dist/cost/providers/claude-code.d.ts +13 -1
  36. package/dist/cost/providers/claude-code.d.ts.map +1 -1
  37. package/dist/cost/providers/claude-code.js +112 -10
  38. package/dist/cost/providers/claude-code.js.map +1 -1
  39. package/dist/cost/rates.d.ts +16 -1
  40. package/dist/cost/rates.d.ts.map +1 -1
  41. package/dist/cost/rates.js +21 -0
  42. package/dist/cost/rates.js.map +1 -1
  43. package/dist/cost/recorder.d.ts.map +1 -1
  44. package/dist/cost/recorder.js +3 -0
  45. package/dist/cost/recorder.js.map +1 -1
  46. package/dist/cost/report.d.ts +30 -0
  47. package/dist/cost/report.d.ts.map +1 -1
  48. package/dist/cost/report.js +96 -5
  49. package/dist/cost/report.js.map +1 -1
  50. package/dist/cost/sync.d.ts +18 -0
  51. package/dist/cost/sync.d.ts.map +1 -1
  52. package/dist/cost/sync.js +1 -1
  53. package/dist/cost/sync.js.map +1 -1
  54. package/dist/cost/types.d.ts +40 -0
  55. package/dist/cost/types.d.ts.map +1 -1
  56. package/dist/cost/types.js +15 -0
  57. package/dist/cost/types.js.map +1 -1
  58. package/dist/discover/scanner.d.ts +20 -2
  59. package/dist/discover/scanner.d.ts.map +1 -1
  60. package/dist/discover/scanner.js +80 -14
  61. package/dist/discover/scanner.js.map +1 -1
  62. package/dist/doctor/migrations/findings-filename.d.ts +77 -0
  63. package/dist/doctor/migrations/findings-filename.d.ts.map +1 -0
  64. package/dist/doctor/migrations/findings-filename.js +189 -0
  65. package/dist/doctor/migrations/findings-filename.js.map +1 -0
  66. package/dist/doctor/migrations/index.d.ts.map +1 -1
  67. package/dist/doctor/migrations/index.js +8 -0
  68. package/dist/doctor/migrations/index.js.map +1 -1
  69. package/dist/review/findings-naming.d.ts +112 -0
  70. package/dist/review/findings-naming.d.ts.map +1 -0
  71. package/dist/review/findings-naming.js +132 -0
  72. package/dist/review/findings-naming.js.map +1 -0
  73. package/package.json +2 -2
@@ -0,0 +1,72 @@
1
+ /**
2
+ * How large is the context this session is carrying, and is it over budget?
3
+ *
4
+ * 91% of what an AIDLC project spends on inference is cache traffic — re-reading
5
+ * the same conversation prefix, turn after turn. Measured over 20,920 attributed
6
+ * ledger records, the average carried prefix grows monotonically through the
7
+ * lifecycle: 80k tokens in ideation, 164k in requirements, 259k in implementation,
8
+ * 395k in deployment, 791k in maintenance. The `complete` phase does comparable
9
+ * work at 76k for one reason — it runs in its own session.
10
+ *
11
+ * So a phase boundary is a free context reset, and this is how a phase skill checks
12
+ * whether it should have taken one.
13
+ *
14
+ * **Reads the transcript, not the ledger.** The question is asked at a phase
15
+ * boundary, which is exactly when no capture has run recently and the ledger is
16
+ * stale or empty — and it must answer on a machine where no cost hook was ever
17
+ * installed, because this project already has a lesson about a capability whose
18
+ * arming was manual and was therefore inert on arrival.
19
+ *
20
+ * Only token counts are read. No transcript content — no prompt text, no file
21
+ * body, no tool output — is copied anywhere, so nothing here can leak a secret into
22
+ * a report (NFR-4).
23
+ *
24
+ * Requirements: context-budget/AC-16, AC-17, AC-18, AC-19; NFR-4
25
+ * Design: design.md Part 4 (D4.3, D4.4)
26
+ *
27
+ * @module
28
+ */
29
+ import type { CostConfig } from './types.js';
30
+ import type { ProviderEnv } from './providers/provider.js';
31
+ export interface ContextReading {
32
+ /**
33
+ * Resident prefix at the most recent API call, in tokens — everything the model
34
+ * had to be *given*. Null when no usage-bearing transcript line was found for
35
+ * this project, which is an ordinary state (a fresh session that has not yet made
36
+ * a call), not a failure.
37
+ */
38
+ residentTokens: number | null;
39
+ /** Model of that call, for context. Null when unknown. */
40
+ model: string | null;
41
+ /** ISO timestamp of that call. Null when unknown. */
42
+ at: string | null;
43
+ /** The budget in force, from config or the measured default. */
44
+ budgetTokens: number;
45
+ /** True when `residentTokens` exceeds the budget. Always false when unmeasured. */
46
+ overBudget: boolean;
47
+ /** Transcripts belonging to this project that were considered. */
48
+ transcriptsScanned: number;
49
+ /**
50
+ * Transcripts that could not be read through to the end.
51
+ *
52
+ * Counted rather than swallowed. A silent fail-soft here would report `unmeasured`
53
+ * with no reason on a machine where every transcript is unreadable, which looks
54
+ * identical to a fresh session — and "an unmeasured reading with no explanation" is
55
+ * the shape of failure this project has already paid for once. SOC 2 CC7.2 asks the
56
+ * same thing of any failure path: record it with enough context to notice.
57
+ */
58
+ transcriptsUnreadable: number;
59
+ }
60
+ /** The budget in force: config when set to a positive number, else the measured default. */
61
+ export declare function contextBudget(config: CostConfig | null): number;
62
+ /**
63
+ * Read resident context for this project's most recent API call.
64
+ *
65
+ * Scopes to this repository via `projectClaudeCodeRecords`, which resolves each
66
+ * transcript's `cwd` to a git common dir rather than comparing path prefixes — the
67
+ * transcript root holds every project this machine has ever worked on, and a
68
+ * prefix match once put 711 entries of another repository's work into this one's
69
+ * ledgers.
70
+ */
71
+ export declare function readContext(projectRoot: string, config: CostConfig | null, env?: ProviderEnv): Promise<ContextReading>;
72
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/cost/context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAG7C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;IACH,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,0DAA0D;IAC1D,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,qDAAqD;IACrD,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;IAClB,gEAAgE;IAChE,YAAY,EAAE,MAAM,CAAC;IACrB,mFAAmF;IACnF,UAAU,EAAE,OAAO,CAAC;IACpB,kEAAkE;IAClE,kBAAkB,EAAE,MAAM,CAAC;IAC3B;;;;;;;;OAQG;IACH,qBAAqB,EAAE,MAAM,CAAC;CAC/B;AAED,4FAA4F;AAC5F,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,GAAG,MAAM,CAG/D;AAyFD;;;;;;;;GAQG;AACH,wBAAsB,WAAW,CAC/B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,UAAU,GAAG,IAAI,EACzB,GAAG,GAAE,WAA6B,GACjC,OAAO,CAAC,cAAc,CAAC,CAwBzB"}
@@ -0,0 +1,155 @@
1
+ /**
2
+ * How large is the context this session is carrying, and is it over budget?
3
+ *
4
+ * 91% of what an AIDLC project spends on inference is cache traffic — re-reading
5
+ * the same conversation prefix, turn after turn. Measured over 20,920 attributed
6
+ * ledger records, the average carried prefix grows monotonically through the
7
+ * lifecycle: 80k tokens in ideation, 164k in requirements, 259k in implementation,
8
+ * 395k in deployment, 791k in maintenance. The `complete` phase does comparable
9
+ * work at 76k for one reason — it runs in its own session.
10
+ *
11
+ * So a phase boundary is a free context reset, and this is how a phase skill checks
12
+ * whether it should have taken one.
13
+ *
14
+ * **Reads the transcript, not the ledger.** The question is asked at a phase
15
+ * boundary, which is exactly when no capture has run recently and the ledger is
16
+ * stale or empty — and it must answer on a machine where no cost hook was ever
17
+ * installed, because this project already has a lesson about a capability whose
18
+ * arming was manual and was therefore inert on arrival.
19
+ *
20
+ * Only token counts are read. No transcript content — no prompt text, no file
21
+ * body, no tool output — is copied anywhere, so nothing here can leak a secret into
22
+ * a report (NFR-4).
23
+ *
24
+ * Requirements: context-budget/AC-16, AC-17, AC-18, AC-19; NFR-4
25
+ * Design: design.md Part 4 (D4.3, D4.4)
26
+ *
27
+ * @module
28
+ */
29
+ import { createReadStream } from 'node:fs';
30
+ import { createInterface } from 'node:readline';
31
+ import { DEFAULT_CONTEXT_BUDGET_TOKENS, MODEL_ID_RE } from './types.js';
32
+ import { projectClaudeCodeRecords } from './sync.js';
33
+ /** The budget in force: config when set to a positive number, else the measured default. */
34
+ export function contextBudget(config) {
35
+ const v = config?.context_budget_tokens;
36
+ return typeof v === 'number' && Number.isFinite(v) && v > 0 ? v : DEFAULT_CONTEXT_BUDGET_TOKENS;
37
+ }
38
+ function isCount(v) {
39
+ return typeof v === 'number' && Number.isFinite(v) && v >= 0;
40
+ }
41
+ /**
42
+ * The newest usage-bearing line in one transcript.
43
+ *
44
+ * Streams rather than reading the file: transcripts here run to megabytes, and this
45
+ * is called at a phase boundary where the answer must be cheap enough that nobody
46
+ * skips asking for it.
47
+ */
48
+ async function latestOf(path) {
49
+ let best = null;
50
+ let rl;
51
+ try {
52
+ rl = createInterface({
53
+ input: createReadStream(path, { encoding: 'utf8' }),
54
+ crlfDelay: Infinity,
55
+ });
56
+ }
57
+ catch {
58
+ return { latest: null, readable: false };
59
+ }
60
+ let readable = true;
61
+ /*
62
+ * Fail-soft on the *stream*, not just on each line.
63
+ *
64
+ * `createInterface` does not throw for a path that is gone — the error surfaces
65
+ * when the stream is iterated, so a transcript deleted or rotated between the
66
+ * directory walk and this read would otherwise reject out of here and take
67
+ * `aidlc cost context` down with it. Transcripts are churning files owned by
68
+ * another process; a read that loses one must report what it has, exactly as the
69
+ * provider skips a malformed line.
70
+ */
71
+ try {
72
+ for await (const line of rl) {
73
+ const t = line.trim();
74
+ if (t === '')
75
+ continue;
76
+ let entry;
77
+ try {
78
+ entry = JSON.parse(t);
79
+ }
80
+ catch {
81
+ // Fail-soft, exactly as the provider is: a malformed line is skipped, never
82
+ // fatal. A truncated last line is normal in a file being appended to.
83
+ continue;
84
+ }
85
+ const message = entry.message;
86
+ const usage = message?.usage;
87
+ const model = typeof message?.model === 'string' ? message.model : null;
88
+ const at = typeof entry.timestamp === 'string' && !Number.isNaN(Date.parse(entry.timestamp))
89
+ ? entry.timestamp
90
+ : null;
91
+ if (!usage || model === null || !MODEL_ID_RE.test(model) || at === null)
92
+ continue;
93
+ /*
94
+ * Resident context = everything given to the model, output excluded.
95
+ *
96
+ * The three input-side counters are disjoint in Anthropic's shape — fresh
97
+ * input, cache reads, cache writes — so adding them is a sum, not a double
98
+ * count. Output is excluded because it is what the turn produced, not what it
99
+ * had to carry.
100
+ */
101
+ const tokens = (isCount(usage.input_tokens) ? usage.input_tokens : 0) +
102
+ (isCount(usage.cache_read_input_tokens) ? usage.cache_read_input_tokens : 0) +
103
+ (isCount(usage.cache_creation_input_tokens) ? usage.cache_creation_input_tokens : 0);
104
+ if (best === null || Date.parse(at) >= Date.parse(best.at)) {
105
+ best = { at, tokens, model };
106
+ }
107
+ }
108
+ }
109
+ catch {
110
+ // Stream died mid-read. Return what was seen rather than nothing — a partial
111
+ // reading is still a reading — but say that it happened, so an unmeasured result
112
+ // is never indistinguishable from a quiet failure.
113
+ readable = false;
114
+ }
115
+ finally {
116
+ rl.close();
117
+ }
118
+ return { latest: best, readable };
119
+ }
120
+ /**
121
+ * Read resident context for this project's most recent API call.
122
+ *
123
+ * Scopes to this repository via `projectClaudeCodeRecords`, which resolves each
124
+ * transcript's `cwd` to a git common dir rather than comparing path prefixes — the
125
+ * transcript root holds every project this machine has ever worked on, and a
126
+ * prefix match once put 711 entries of another repository's work into this one's
127
+ * ledgers.
128
+ */
129
+ export async function readContext(projectRoot, config, env = { projectRoot }) {
130
+ const budgetTokens = contextBudget(config);
131
+ const records = projectClaudeCodeRecords(projectRoot, env);
132
+ let best = null;
133
+ let unreadable = 0;
134
+ for (const { path } of records) {
135
+ const { latest, readable } = await latestOf(path);
136
+ if (!readable)
137
+ unreadable++;
138
+ if (latest === null)
139
+ continue;
140
+ if (best === null || Date.parse(latest.at) >= Date.parse(best.at))
141
+ best = latest;
142
+ }
143
+ return {
144
+ residentTokens: best?.tokens ?? null,
145
+ model: best?.model ?? null,
146
+ at: best?.at ?? null,
147
+ budgetTokens,
148
+ // Unmeasured is never "over": an absent reading must not raise an alarm it has
149
+ // no evidence for.
150
+ overBudget: best !== null && best.tokens > budgetTokens,
151
+ transcriptsScanned: records.length,
152
+ transcriptsUnreadable: unreadable,
153
+ };
154
+ }
155
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/cost/context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Correct ledger entries written while one API response was counted many times.
3
+ *
4
+ * The claude-code provider used to emit one usage record per transcript *line*.
5
+ * Claude Code writes one line per content block and repeats the response's `usage`
6
+ * object on every one, so a response spanning three blocks was charged three times.
7
+ * Measured on this repo's 53 transcripts: 17,292 usage-bearing lines against 9,357
8
+ * unique `message.id` values — an over-count factor of **1.848**, with 7,935 repeat
9
+ * lines and zero whose usage object differed.
10
+ *
11
+ * `providers/claude-code.ts` now groups by `message.id`, which fixes capture going
12
+ * forward. This corrects what is already on disk, by re-reading each entry's source
13
+ * transcript through the fixed provider.
14
+ *
15
+ * Three properties are deliberate, and each is the same choice `rederive.ts` made
16
+ * for the same reason:
17
+ *
18
+ * 1. **Bounded by the entry's own coverage window.** One entry's cursor sits in a
19
+ * 633-record transcript while the entry covers only 80 of them, so re-deriving
20
+ * over the whole file inflated it 23x there. The bound is what makes this
21
+ * arithmetic rather than estimation.
22
+ * 2. **A missing transcript is reported, never estimated.** An entry that cannot be
23
+ * re-read is left byte-identical and counted. Scaling it by the measured 1.848x
24
+ * is explicitly rejected: an estimate that looks like a measurement is the
25
+ * defect this whole change exists to remove. `provenance.ts` keeps `unknown`
26
+ * distinct from `foreign` for the same reason — under-recovering is the safe
27
+ * direction.
28
+ * 3. **Verification is on precedence-weighted dollars, not raw token sums.** Raw
29
+ * sums can balance while weighted totals move, which is the exact shape of a
30
+ * defect that once reported a plausible total while double-counting 950 entries.
31
+ *
32
+ * Read-only unless `apply` is set. The plan names the dollar delta before anything
33
+ * is written, because applying it moves every cost figure this project has already
34
+ * published in a retrospective or a blog post.
35
+ *
36
+ * Requirements: context-budget/AC-11, AC-12, AC-13; NFR-5
37
+ * Design: design.md Part 3
38
+ *
39
+ * @module
40
+ */
41
+ import type { CostConfig } from './types.js';
42
+ import type { ProviderEnv } from './providers/provider.js';
43
+ import type { ProvenanceIndex } from './provenance.js';
44
+ export interface DedupeReport {
45
+ /** Priced entries examined. */
46
+ scanned: number;
47
+ /** Entries whose units were re-derived to a smaller figure. */
48
+ rederived: number;
49
+ /** Entries re-read and found already correct. */
50
+ unchanged: number;
51
+ /**
52
+ * Entries that are provably a second charge for a response already counted.
53
+ *
54
+ * These are the bulk of the historical defect, and they are *extra entries*
55
+ * rather than inflated ones: `rederive.ts` split most buckets into one zero-width
56
+ * entry per transcript line, so each duplicate line became its own ledger entry.
57
+ * Re-deriving such an entry is meaningless — the correct figure for it is that it
58
+ * should not exist.
59
+ *
60
+ * The proof is what separates this from `transcriptGone`: the entry's transcript
61
+ * **resolved**, and the deduped read of it emits no record at this entry's own
62
+ * instant. A timestamp disappears from the deduped output for exactly one reason —
63
+ * its line was a non-leading content block of a response whose usage is now
64
+ * carried by the group's first line. So the charge exists elsewhere.
65
+ *
66
+ * Dropped under `--apply`; counted and left alone in a plan.
67
+ */
68
+ duplicates: number;
69
+ /** Micro-USD carried by those duplicate entries, unweighted. */
70
+ duplicateMicroUsd: number;
71
+ /**
72
+ * Entries whose transcript could not be found, with the reason, left byte-identical.
73
+ *
74
+ * Kept strictly separate from `duplicates` because the two justify opposite
75
+ * actions and only one of them is proven. A cursor that resolves nowhere is an
76
+ * honest unknown — the transcript rotated or was deleted — and an unknown is never
77
+ * resolved by deleting data or by scaling it to a plausible figure.
78
+ */
79
+ transcriptGone: string[];
80
+ /** Entries a human placed with `cost record --manual`; never overruled. */
81
+ manualSkipped: number;
82
+ /** Precedence-weighted dollars before, in micro-USD. */
83
+ microUsdBefore: number;
84
+ /** Precedence-weighted dollars after, in micro-USD. */
85
+ microUsdAfter: number;
86
+ /** False for a plan; true when ledgers were rewritten. */
87
+ applied: boolean;
88
+ /** Ledger files that would change (or did). */
89
+ files: string[];
90
+ }
91
+ /**
92
+ * Plan (or apply) the dedupe correction across every ledger.
93
+ *
94
+ * @param apply - false plans and writes nothing; true rewrites each changed ledger
95
+ * atomically via `rewriteLedger`, all-or-nothing per file (NFR-5).
96
+ */
97
+ export declare function dedupeHistory(projectRoot: string, config: CostConfig | null, apply: boolean, env?: ProviderEnv, provenanceFiles?: ProvenanceIndex): Promise<DedupeReport>;
98
+ //# sourceMappingURL=dedupe-history.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dedupe-history.d.ts","sourceRoot":"","sources":["../../src/cost/dedupe-history.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAIH,OAAO,KAAK,EAAa,UAAU,EAA4B,MAAM,YAAY,CAAC;AAUlF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEvD,MAAM,WAAW,YAAY;IAC3B,+BAA+B;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,+DAA+D;IAC/D,SAAS,EAAE,MAAM,CAAC;IAClB,iDAAiD;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;;;;;;;;;;;;OAgBG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB,gEAAgE;IAChE,iBAAiB,EAAE,MAAM,CAAC;IAC1B;;;;;;;OAOG;IACH,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,2EAA2E;IAC3E,aAAa,EAAE,MAAM,CAAC;IACtB,wDAAwD;IACxD,cAAc,EAAE,MAAM,CAAC;IACvB,uDAAuD;IACvD,aAAa,EAAE,MAAM,CAAC;IACtB,0DAA0D;IAC1D,OAAO,EAAE,OAAO,CAAC;IACjB,+CAA+C;IAC/C,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AA6HD;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,UAAU,GAAG,IAAI,EACzB,KAAK,EAAE,OAAO,EACd,GAAG,GAAE,WAA6B,EAClC,eAAe,CAAC,EAAE,eAAe,GAChC,OAAO,CAAC,YAAY,CAAC,CA0GvB"}
@@ -0,0 +1,275 @@
1
+ /**
2
+ * Correct ledger entries written while one API response was counted many times.
3
+ *
4
+ * The claude-code provider used to emit one usage record per transcript *line*.
5
+ * Claude Code writes one line per content block and repeats the response's `usage`
6
+ * object on every one, so a response spanning three blocks was charged three times.
7
+ * Measured on this repo's 53 transcripts: 17,292 usage-bearing lines against 9,357
8
+ * unique `message.id` values — an over-count factor of **1.848**, with 7,935 repeat
9
+ * lines and zero whose usage object differed.
10
+ *
11
+ * `providers/claude-code.ts` now groups by `message.id`, which fixes capture going
12
+ * forward. This corrects what is already on disk, by re-reading each entry's source
13
+ * transcript through the fixed provider.
14
+ *
15
+ * Three properties are deliberate, and each is the same choice `rederive.ts` made
16
+ * for the same reason:
17
+ *
18
+ * 1. **Bounded by the entry's own coverage window.** One entry's cursor sits in a
19
+ * 633-record transcript while the entry covers only 80 of them, so re-deriving
20
+ * over the whole file inflated it 23x there. The bound is what makes this
21
+ * arithmetic rather than estimation.
22
+ * 2. **A missing transcript is reported, never estimated.** An entry that cannot be
23
+ * re-read is left byte-identical and counted. Scaling it by the measured 1.848x
24
+ * is explicitly rejected: an estimate that looks like a measurement is the
25
+ * defect this whole change exists to remove. `provenance.ts` keeps `unknown`
26
+ * distinct from `foreign` for the same reason — under-recovering is the safe
27
+ * direction.
28
+ * 3. **Verification is on precedence-weighted dollars, not raw token sums.** Raw
29
+ * sums can balance while weighted totals move, which is the exact shape of a
30
+ * defect that once reported a plausible total while double-counting 950 entries.
31
+ *
32
+ * Read-only unless `apply` is set. The plan names the dollar delta before anything
33
+ * is written, because applying it moves every cost figure this project has already
34
+ * published in a retrospective or a blog post.
35
+ *
36
+ * Requirements: context-budget/AC-11, AC-12, AC-13; NFR-5
37
+ * Design: design.md Part 3
38
+ *
39
+ * @module
40
+ */
41
+ import { existsSync, readdirSync } from 'node:fs';
42
+ import { join } from 'node:path';
43
+ import { readEntries, rewriteLedger, applyPrecedence, ledgerPath, unattributedPath, } from './ledger.js';
44
+ import { effectiveRates, priceUnits } from './rates.js';
45
+ import { claudeCodeProvider } from './providers/claude-code.js';
46
+ import { buildCursorFileIndex } from './rederive.js';
47
+ function emptyReport(applied) {
48
+ return {
49
+ scanned: 0,
50
+ rederived: 0,
51
+ unchanged: 0,
52
+ duplicates: 0,
53
+ duplicateMicroUsd: 0,
54
+ transcriptGone: [],
55
+ manualSkipped: 0,
56
+ microUsdBefore: 0,
57
+ microUsdAfter: 0,
58
+ applied,
59
+ files: [],
60
+ };
61
+ }
62
+ /** Locate the single transcript holding `cursor`, or null when it is gone or ambiguous. */
63
+ function fileForCursor(cursor, index) {
64
+ if (cursor === null)
65
+ return null;
66
+ const files = index.get(cursor);
67
+ // A uuid in two files is ambiguous, never resolved by picking one: `/branch`
68
+ // copies transcripts, so the same uuid legitimately appears twice.
69
+ if (files === undefined || files.size !== 1)
70
+ return null;
71
+ return [...files][0];
72
+ }
73
+ /**
74
+ * Precedence-weighted micro-USD over a set of entries.
75
+ *
76
+ * Weighted, not raw, because `applyPrecedence` reduces overlap across fidelity
77
+ * ranks — a total that ignores it can balance while the real figure moves.
78
+ */
79
+ function weightedMicroUsd(entries, rates) {
80
+ let micro = 0;
81
+ for (const { entry, weight } of applyPrecedence(entries)) {
82
+ if (weight === 0 || entry.units === null)
83
+ continue;
84
+ const price = priceUnits(entry.units, rates);
85
+ if (price !== null)
86
+ micro += price * weight;
87
+ }
88
+ return Math.round(micro);
89
+ }
90
+ function sameTokens(a, b) {
91
+ return (a.model === b.model &&
92
+ a.input_tokens === b.input_tokens &&
93
+ a.output_tokens === b.output_tokens &&
94
+ a.cache_read_tokens === b.cache_read_tokens &&
95
+ a.cache_write_tokens === b.cache_write_tokens);
96
+ }
97
+ /**
98
+ * Re-derive one entry's units from its transcript.
99
+ *
100
+ * Three outcomes, deliberately distinct because they justify three different
101
+ * actions: corrected units (rewrite), `'duplicate'` (drop — the charge is already
102
+ * counted elsewhere, provably), or `'unreadable'` (leave alone — an honest unknown).
103
+ *
104
+ * Returns the number of unique responses behind the corrected units, so the entry
105
+ * can carry a response count that pre-fix entries lack.
106
+ */
107
+ async function rederiveUnits(entry, source, env, cache) {
108
+ /*
109
+ * One parse per transcript, not one per entry.
110
+ *
111
+ * Many entries share a source — this repo has 30,824 candidate entries across 53
112
+ * transcripts — so re-extracting per entry re-reads each megabyte file hundreds of
113
+ * times. Cached by path, which is safe because a single pass is a point-in-time
114
+ * correction: re-reading the same file twice mid-run and getting different answers
115
+ * would make the plan disagree with the apply.
116
+ *
117
+ * `null` caches a *failure* too, so an unreadable file is attempted once rather
118
+ * than once per entry that points at it.
119
+ */
120
+ let segments = cache.get(source);
121
+ if (segments === undefined) {
122
+ try {
123
+ segments = await claudeCodeProvider.extract({ provider: 'claude-code', path: source }, null, env);
124
+ }
125
+ catch {
126
+ segments = null;
127
+ }
128
+ cache.set(source, segments);
129
+ }
130
+ if (segments === null)
131
+ return 'unreadable';
132
+ if (entry.units === null || entry.units.kind !== 'tokens')
133
+ return 'unreadable';
134
+ const model = entry.units.model;
135
+ const lo = Date.parse(entry.coverage.from);
136
+ const hi = Date.parse(entry.coverage.to);
137
+ const sum = {
138
+ kind: 'tokens',
139
+ model,
140
+ input_tokens: 0,
141
+ output_tokens: 0,
142
+ cache_read_tokens: 0,
143
+ cache_write_tokens: 0,
144
+ };
145
+ let responses = 0;
146
+ for (const s of segments) {
147
+ if (s.units.kind !== 'tokens' || s.units.model !== model)
148
+ continue;
149
+ const at = Date.parse(s.at);
150
+ if (at < lo || at > hi)
151
+ continue;
152
+ sum.input_tokens += s.units.input_tokens;
153
+ sum.output_tokens += s.units.output_tokens;
154
+ sum.cache_read_tokens += s.units.cache_read_tokens;
155
+ sum.cache_write_tokens += s.units.cache_write_tokens;
156
+ responses += 1;
157
+ }
158
+ // No deduped record inside the window, in a transcript that *was* found. The
159
+ // entry's line was a non-leading content block of a response now carried by its
160
+ // group's first line, so this entry is a second charge for something already
161
+ // counted. Signalled distinctly from a read failure, because it justifies dropping
162
+ // the entry while a read failure justifies leaving it alone.
163
+ if (responses === 0)
164
+ return 'duplicate';
165
+ return { units: sum, responses };
166
+ }
167
+ /**
168
+ * Plan (or apply) the dedupe correction across every ledger.
169
+ *
170
+ * @param apply - false plans and writes nothing; true rewrites each changed ledger
171
+ * atomically via `rewriteLedger`, all-or-nothing per file (NFR-5).
172
+ */
173
+ export async function dedupeHistory(projectRoot, config, apply, env = { projectRoot }, provenanceFiles) {
174
+ const report = emptyReport(apply);
175
+ const rates = effectiveRates(projectRoot, config);
176
+ const targets = [];
177
+ const stateDir = join(projectRoot, '.aidlc', 'state');
178
+ if (existsSync(stateDir)) {
179
+ for (const d of readdirSync(stateDir, { withFileTypes: true })) {
180
+ if (!d.isDirectory())
181
+ continue;
182
+ const p = ledgerPath(projectRoot, d.name);
183
+ if (existsSync(p))
184
+ targets.push(p);
185
+ }
186
+ }
187
+ const un = unattributedPath(projectRoot);
188
+ if (existsSync(un))
189
+ targets.push(un);
190
+ if (targets.length === 0)
191
+ return report;
192
+ const cursorFiles = provenanceFiles ?? buildCursorFileIndex(env);
193
+ /** Parsed segments per transcript path, shared across every entry in this run. */
194
+ const segmentCache = new Map();
195
+ for (const file of targets) {
196
+ const entries = readEntries(file);
197
+ report.microUsdBefore += weightedMicroUsd(entries, rates);
198
+ const kept = [];
199
+ let changed = false;
200
+ for (const e of entries) {
201
+ // A human placed these deliberately; a re-read must not overrule them.
202
+ if (e.provider === 'manual') {
203
+ report.manualSkipped++;
204
+ kept.push(e);
205
+ continue;
206
+ }
207
+ // `unknown`-fidelity interval markers carry no units and no money.
208
+ if (e.units === null || e.units.kind !== 'tokens') {
209
+ kept.push(e);
210
+ continue;
211
+ }
212
+ // Already counted per response — nothing to correct.
213
+ if (typeof e.responses === 'number') {
214
+ kept.push(e);
215
+ continue;
216
+ }
217
+ report.scanned++;
218
+ const source = fileForCursor(e.cursor, cursorFiles);
219
+ if (source === null) {
220
+ report.transcriptGone.push(`${file}: cursor ${e.cursor ?? 'null'} has no unique transcript`);
221
+ kept.push(e);
222
+ continue;
223
+ }
224
+ const fixed = await rederiveUnits(e, source, env, segmentCache);
225
+ if (fixed === 'unreadable') {
226
+ report.transcriptGone.push(`${file}: could not read ${source} for ${e.cursor ?? 'null'}`);
227
+ kept.push(e);
228
+ continue;
229
+ }
230
+ if (fixed === 'duplicate') {
231
+ /*
232
+ * A second charge for a response counted elsewhere — see
233
+ * DedupeReport.duplicates for why this is proven rather than inferred.
234
+ *
235
+ * Dropped from `kept` in **both** modes, because `kept` is what
236
+ * `microUsdAfter` is measured from and a plan whose projected total ignores
237
+ * its own largest correction is not a plan. Only `rewriteLedger` is gated on
238
+ * `apply`.
239
+ */
240
+ report.duplicates++;
241
+ const price = priceUnits(e.units, rates);
242
+ if (price !== null)
243
+ report.duplicateMicroUsd += price;
244
+ changed = true;
245
+ continue;
246
+ }
247
+ if (sameTokens(e.units, fixed.units)) {
248
+ // Re-read and identical: the entry was never a duplicate. It still gains a
249
+ // response count, which is new information and costs nothing.
250
+ report.unchanged++;
251
+ kept.push({ ...e, responses: fixed.responses });
252
+ changed = true;
253
+ continue;
254
+ }
255
+ /*
256
+ * `reconciled` is how this schema already says "corrected after the fact",
257
+ * and `applyPrecedence` already ranks it above `metered`. So a reader of an
258
+ * older retrospective can tell a moved figure from a historical one without a
259
+ * new field, and no new fidelity value is minted (AC-11).
260
+ */
261
+ kept.push({ ...e, units: fixed.units, responses: fixed.responses, fidelity: 'reconciled' });
262
+ report.rederived++;
263
+ changed = true;
264
+ }
265
+ report.microUsdAfter += weightedMicroUsd(kept, rates);
266
+ if (changed) {
267
+ report.files.push(file);
268
+ // Atomic per file: an interrupted run leaves the original intact (NFR-5).
269
+ if (apply)
270
+ rewriteLedger(file, kept);
271
+ }
272
+ }
273
+ return report;
274
+ }
275
+ //# sourceMappingURL=dedupe-history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dedupe-history.js","sourceRoot":"","sources":["../../src/cost/dedupe-history.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EACL,WAAW,EACX,aAAa,EACb,eAAe,EACf,UAAU,EACV,gBAAgB,GACjB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAEhE,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAmDrD,SAAS,WAAW,CAAC,OAAgB;IACnC,OAAO;QACL,OAAO,EAAE,CAAC;QACV,SAAS,EAAE,CAAC;QACZ,SAAS,EAAE,CAAC;QACZ,UAAU,EAAE,CAAC;QACb,iBAAiB,EAAE,CAAC;QACpB,cAAc,EAAE,EAAE;QAClB,aAAa,EAAE,CAAC;QAChB,cAAc,EAAE,CAAC;QACjB,aAAa,EAAE,CAAC;QAChB,OAAO;QACP,KAAK,EAAE,EAAE;KACV,CAAC;AACJ,CAAC;AAED,2FAA2F;AAC3F,SAAS,aAAa,CAAC,MAAqB,EAAE,KAAsB;IAClE,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACjC,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAChC,6EAA6E;IAC7E,mEAAmE;IACnE,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACzD,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACvB,CAAC;AAED;;;;;GAKG;AACH,SAAS,gBAAgB,CAAC,OAAoB,EAAE,KAAwC;IACtF,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC;QACzD,IAAI,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,KAAK,IAAI;YAAE,SAAS;QACnD,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAC7C,IAAI,KAAK,KAAK,IAAI;YAAE,KAAK,IAAI,KAAK,GAAG,MAAM,CAAC;IAC9C,CAAC;IACD,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AAC3B,CAAC;AAED,SAAS,UAAU,CAAC,CAAa,EAAE,CAAa;IAC9C,OAAO,CACL,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK;QACnB,CAAC,CAAC,YAAY,KAAK,CAAC,CAAC,YAAY;QACjC,CAAC,CAAC,aAAa,KAAK,CAAC,CAAC,aAAa;QACnC,CAAC,CAAC,iBAAiB,KAAK,CAAC,CAAC,iBAAiB;QAC3C,CAAC,CAAC,kBAAkB,KAAK,CAAC,CAAC,kBAAkB,CAC9C,CAAC;AACJ,CAAC;AAED;;;;;;;;;GASG;AACH,KAAK,UAAU,aAAa,CAC1B,KAAgB,EAChB,MAAc,EACd,GAAgB,EAChB,KAAyC;IAEzC;;;;;;;;;;;OAWG;IACH,IAAI,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACjC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,kBAAkB,CAAC,OAAO,CAAC,EAAE,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;QACpG,CAAC;QAAC,MAAM,CAAC;YACP,QAAQ,GAAG,IAAI,CAAC;QAClB,CAAC;QACD,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC9B,CAAC;IACD,IAAI,QAAQ,KAAK,IAAI;QAAE,OAAO,YAAY,CAAC;IAC3C,IAAI,KAAK,CAAC,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,QAAQ;QAAE,OAAO,YAAY,CAAC;IAC/E,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC;IAChC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC3C,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAEzC,MAAM,GAAG,GAAe;QACtB,IAAI,EAAE,QAAQ;QACd,KAAK;QACL,YAAY,EAAE,CAAC;QACf,aAAa,EAAE,CAAC;QAChB,iBAAiB,EAAE,CAAC;QACpB,kBAAkB,EAAE,CAAC;KACtB,CAAC;IACF,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,KAAK,CAAC,KAAK,KAAK,KAAK;YAAE,SAAS;QACnE,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC5B,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE;YAAE,SAAS;QACjC,GAAG,CAAC,YAAY,IAAI,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC;QACzC,GAAG,CAAC,aAAa,IAAI,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC;QAC3C,GAAG,CAAC,iBAAiB,IAAI,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC;QACnD,GAAG,CAAC,kBAAkB,IAAI,CAAC,CAAC,KAAK,CAAC,kBAAkB,CAAC;QACrD,SAAS,IAAI,CAAC,CAAC;IACjB,CAAC;IACD,6EAA6E;IAC7E,gFAAgF;IAChF,6EAA6E;IAC7E,mFAAmF;IACnF,6DAA6D;IAC7D,IAAI,SAAS,KAAK,CAAC;QAAE,OAAO,WAAW,CAAC;IACxC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC;AACnC,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,WAAmB,EACnB,MAAyB,EACzB,KAAc,EACd,MAAmB,EAAE,WAAW,EAAE,EAClC,eAAiC;IAEjC,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IAClC,MAAM,KAAK,GAAG,cAAc,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IAElD,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IACtD,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACzB,KAAK,MAAM,CAAC,IAAI,WAAW,CAAC,QAAQ,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;YAC/D,IAAI,CAAC,CAAC,CAAC,WAAW,EAAE;gBAAE,SAAS;YAC/B,MAAM,CAAC,GAAG,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;YAC1C,IAAI,UAAU,CAAC,CAAC,CAAC;gBAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IACD,MAAM,EAAE,GAAG,gBAAgB,CAAC,WAAW,CAAC,CAAC;IACzC,IAAI,UAAU,CAAC,EAAE,CAAC;QAAE,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACrC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC;IAExC,MAAM,WAAW,GAAG,eAAe,IAAI,oBAAoB,CAAC,GAAG,CAAC,CAAC;IACjE,kFAAkF;IAClF,MAAM,YAAY,GAAG,IAAI,GAAG,EAAiC,CAAC;IAE9D,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,cAAc,IAAI,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAE1D,MAAM,IAAI,GAAgB,EAAE,CAAC;QAC7B,IAAI,OAAO,GAAG,KAAK,CAAC;QAEpB,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,uEAAuE;YACvE,IAAI,CAAC,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;gBAC5B,MAAM,CAAC,aAAa,EAAE,CAAC;gBACvB,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBACb,SAAS;YACX,CAAC;YACD,mEAAmE;YACnE,IAAI,CAAC,CAAC,KAAK,KAAK,IAAI,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAClD,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBACb,SAAS;YACX,CAAC;YACD,qDAAqD;YACrD,IAAI,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;gBACpC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBACb,SAAS;YACX,CAAC;YACD,MAAM,CAAC,OAAO,EAAE,CAAC;YAEjB,MAAM,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;YACpD,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;gBACpB,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,IAAI,YAAY,CAAC,CAAC,MAAM,IAAI,MAAM,2BAA2B,CAAC,CAAC;gBAC7F,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBACb,SAAS;YACX,CAAC;YAED,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC;YAChE,IAAI,KAAK,KAAK,YAAY,EAAE,CAAC;gBAC3B,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,IAAI,oBAAoB,MAAM,QAAQ,CAAC,CAAC,MAAM,IAAI,MAAM,EAAE,CAAC,CAAC;gBAC1F,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBACb,SAAS;YACX,CAAC;YACD,IAAI,KAAK,KAAK,WAAW,EAAE,CAAC;gBAC1B;;;;;;;;mBAQG;gBACH,MAAM,CAAC,UAAU,EAAE,CAAC;gBACpB,MAAM,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;gBACzC,IAAI,KAAK,KAAK,IAAI;oBAAE,MAAM,CAAC,iBAAiB,IAAI,KAAK,CAAC;gBACtD,OAAO,GAAG,IAAI,CAAC;gBACf,SAAS;YACX,CAAC;YAED,IAAI,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;gBACrC,2EAA2E;gBAC3E,8DAA8D;gBAC9D,MAAM,CAAC,SAAS,EAAE,CAAC;gBACnB,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;gBAChD,OAAO,GAAG,IAAI,CAAC;gBACf,SAAS;YACX,CAAC;YAED;;;;;eAKG;YACH,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC,CAAC;YAC5F,MAAM,CAAC,SAAS,EAAE,CAAC;YACnB,OAAO,GAAG,IAAI,CAAC;QACjB,CAAC;QAED,MAAM,CAAC,aAAa,IAAI,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QACtD,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACxB,0EAA0E;YAC1E,IAAI,KAAK;gBAAE,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACvC,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ledger.d.ts","sourceRoot":"","sources":["../../src/cost/ledger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAaH,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAa,MAAM,YAAY,CAAC;AAoDrE;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CA0C3D;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,IAAI,CAUtE;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,EAAE,CAkC3D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,IAAI,CAU5E;AAED,mCAAmC;AACnC,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAExE;AAED,uCAAuC;AACvC,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAerF;AAiDD,uEAAuE;AACvE,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,SAAS,CAAC;IACjB,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,aAAa,EAAE,CA8CrE;AAED,+DAA+D;AAC/D,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC9F,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;CAC/C;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,WAAW,CAsBjE"}
1
+ {"version":3,"file":"ledger.d.ts","sourceRoot":"","sources":["../../src/cost/ledger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAaH,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAa,MAAM,YAAY,CAAC;AAuDrE;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CA8C3D;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,IAAI,CAUtE;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,EAAE,CAkC3D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,IAAI,CAU5E;AAED,mCAAmC;AACnC,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAExE;AAED,uCAAuC;AACvC,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAerF;AAiDD,uEAAuE;AACvE,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,SAAS,CAAC;IACjB,sEAAsE;IACtE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,aAAa,EAAE,CA8CrE;AAED,+DAA+D;AAC/D,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC9F,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;CAC/C;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,WAAW,CAsBjE"}