hacklab 0.18.0 → 0.20.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 (56) hide show
  1. package/README.md +43 -34
  2. package/dist/cli.js +2 -2
  3. package/dist/cli.js.map +1 -1
  4. package/dist/commands/config.d.ts.map +1 -1
  5. package/dist/commands/config.js +18 -19
  6. package/dist/commands/config.js.map +1 -1
  7. package/dist/commands/login.d.ts +4 -2
  8. package/dist/commands/login.d.ts.map +1 -1
  9. package/dist/commands/login.js +6 -11
  10. package/dist/commands/login.js.map +1 -1
  11. package/dist/commands/scan.d.ts.map +1 -1
  12. package/dist/commands/scan.js +5 -2
  13. package/dist/commands/scan.js.map +1 -1
  14. package/dist/commands/setup-rail.d.ts +4 -3
  15. package/dist/commands/setup-rail.d.ts.map +1 -1
  16. package/dist/commands/setup-rail.js +5 -4
  17. package/dist/commands/setup-rail.js.map +1 -1
  18. package/dist/commands/setup.d.ts +2 -2
  19. package/dist/commands/setup.d.ts.map +1 -1
  20. package/dist/commands/setup.js +39 -33
  21. package/dist/commands/setup.js.map +1 -1
  22. package/dist/commands/sync.d.ts.map +1 -1
  23. package/dist/commands/sync.js +32 -17
  24. package/dist/commands/sync.js.map +1 -1
  25. package/dist/config.d.ts +8 -2
  26. package/dist/config.d.ts.map +1 -1
  27. package/dist/config.js +1 -1
  28. package/dist/config.js.map +1 -1
  29. package/dist/prompt-consent.d.ts +37 -23
  30. package/dist/prompt-consent.d.ts.map +1 -1
  31. package/dist/prompt-consent.js +75 -58
  32. package/dist/prompt-consent.js.map +1 -1
  33. package/dist/prompt-stats.d.ts +116 -7
  34. package/dist/prompt-stats.d.ts.map +1 -1
  35. package/dist/prompt-stats.js +205 -25
  36. package/dist/prompt-stats.js.map +1 -1
  37. package/dist/registry.js +1 -1
  38. package/dist/registry.js.map +1 -1
  39. package/dist/scanners/incremental.d.ts +114 -17
  40. package/dist/scanners/incremental.d.ts.map +1 -1
  41. package/dist/scanners/incremental.js +235 -74
  42. package/dist/scanners/incremental.js.map +1 -1
  43. package/dist/scanners/index.d.ts +7 -3
  44. package/dist/scanners/index.d.ts.map +1 -1
  45. package/dist/scanners/index.js +8 -40
  46. package/dist/scanners/index.js.map +1 -1
  47. package/dist/scanners/util.d.ts +32 -15
  48. package/dist/scanners/util.d.ts.map +1 -1
  49. package/dist/scanners/util.js +10 -34
  50. package/dist/scanners/util.js.map +1 -1
  51. package/dist/session.d.ts +4 -4
  52. package/dist/sync.d.ts +3 -3
  53. package/dist/sync.d.ts.map +1 -1
  54. package/dist/sync.js +27 -14
  55. package/dist/sync.js.map +1 -1
  56. package/package.json +1 -1
@@ -1,67 +1,81 @@
1
1
  import { createInterface } from 'node:readline';
2
- import { loadConfig, saveConfig } from './config.js';
2
+ import { loadConfig, updateConfig } from './config.js';
3
3
  import { bold, dim, info } from './ui.js';
4
4
  /**
5
- * Consent for uploading anything derived from the user's Claude Code
5
+ * Consent for syncing anything derived from the user's Claude Code
6
6
  * conversations.
7
7
  *
8
8
  * Nothing conversation-derived leaves the machine until someone has answered
9
9
  * this explicitly. The tiers are additive:
10
10
  *
11
- * none token counts only — exactly what the CLI did before this existed
12
- * stats + prompt-length histogram and per-project prompt counts (numbers
13
- * only; no prompt text ever leaves the machine)
14
- * full + a sample of the raw prompt text, so the backend can score how
15
- * technical the prompting is. It scores the sample and discards it.
11
+ * none token counts only — nothing prompt-related leaves the machine
12
+ * stats + continuous prompt metadata: counts, word counts, timestamps and
13
+ * session ids, synced every minute alongside tokens, so the profile
14
+ * can show sessions, concurrent sessions and prompt counts. Prompt
15
+ * text never leaves the machine.
16
+ * full + a rolling sample of the most recent prompts (up to 20,000
17
+ * characters) sent with the daily sync, used only to estimate a
18
+ * technical-level score and then discarded. Never stored.
16
19
  *
17
- * The answer is remembered in ~/.hacklab/config.json so the question is asked
18
- * once, and can be changed or revoked at any time with
19
- * `hacklab config prompt-stats <tier>`.
20
+ * The answer is remembered in ~/.hacklab/config.json under `promptSync` so the
21
+ * question is asked once, and can be changed or revoked at any time with
22
+ * `hacklab config prompt-sync <tier>`.
20
23
  */
21
- export const PROMPT_CONSENT_TIERS = ['none', 'stats', 'full'];
22
- export function isPromptConsentTier(value) {
24
+ export const PROMPT_SYNC_TIERS = ['none', 'stats', 'full'];
25
+ export function isPromptSyncTier(value) {
23
26
  return (typeof value === 'string' &&
24
- PROMPT_CONSENT_TIERS.includes(value));
27
+ PROMPT_SYNC_TIERS.includes(value));
25
28
  }
26
- /** The stored answer, or null when the user has never been asked. */
27
- export async function loadPromptConsent() {
29
+ /**
30
+ * The stored answer, or null when the user has never been asked *this*
31
+ * question. The pre-continuous-sync key (`promptStatsConsent`) is deliberately
32
+ * not read: it answered a different question — a one-off scan, not a minutely
33
+ * sync of session metadata — so it can't stand in for this one.
34
+ */
35
+ export async function loadPromptSync() {
28
36
  const config = await loadConfig();
29
- return isPromptConsentTier(config.promptStatsConsent)
30
- ? config.promptStatsConsent
31
- : null;
37
+ return isPromptSyncTier(config.promptSync) ? config.promptSync : null;
32
38
  }
33
- export async function savePromptConsent(tier) {
34
- const config = await loadConfig();
35
- config.promptStatsConsent = tier;
36
- await saveConfig(config);
39
+ /**
40
+ * Remember the answer. Read-modify-write via `updateConfig` rather than a bare
41
+ * `saveConfig`, because the background jobs call this too and must never
42
+ * flatten a config file they couldn't read. The obsolete key goes with it, so
43
+ * a machine is never carrying two answers to two different questions.
44
+ */
45
+ export async function savePromptSync(tier) {
46
+ await updateConfig((config) => {
47
+ config.promptSync = tier;
48
+ delete config.promptStatsConsent;
49
+ return config;
50
+ });
37
51
  }
38
52
  /**
39
- * Read `--share-prompt-stats[=<tier>]` out of a command's args.
53
+ * Read `--share-prompt-sync[=<tier>]` out of a command's args.
40
54
  *
41
55
  * This is the agent-friendly path: it answers the question up front so an
42
56
  * unattended run never blocks on a prompt it can't see. Bare
43
- * `--share-prompt-stats` means the numbers-only tier — the safe reading of an
57
+ * `--share-prompt-sync` means the metadata-only tier — the safe reading of an
44
58
  * unqualified yes, since sending prompt *text* should always be deliberate.
45
- * `--no-share-prompt-stats` is an explicit refusal.
59
+ * `--no-share-prompt-sync` is an explicit refusal.
46
60
  *
47
61
  * Returns the chosen tier, or null when the flag is absent. `rest` is the args
48
62
  * with the flag removed so per-command parsing never sees it.
49
63
  */
50
- export function parsePromptStatsFlag(args) {
64
+ export function parsePromptSyncFlag(args) {
51
65
  const rest = [];
52
66
  let tier = null;
53
67
  for (const arg of args) {
54
- if (arg === '--no-share-prompt-stats') {
68
+ if (arg === '--no-share-prompt-sync') {
55
69
  tier = 'none';
56
70
  continue;
57
71
  }
58
- if (arg === '--share-prompt-stats') {
72
+ if (arg === '--share-prompt-sync') {
59
73
  tier = 'stats';
60
74
  continue;
61
75
  }
62
- if (arg.startsWith('--share-prompt-stats=')) {
63
- const value = arg.slice('--share-prompt-stats='.length);
64
- tier = isPromptConsentTier(value) ? value : 'stats';
76
+ if (arg.startsWith('--share-prompt-sync=')) {
77
+ const value = arg.slice('--share-prompt-sync='.length);
78
+ tier = isPromptSyncTier(value) ? value : 'stats';
65
79
  continue;
66
80
  }
67
81
  rest.push(arg);
@@ -106,62 +120,65 @@ export async function askYesNo(question) {
106
120
  /** The disclosure. Printed verbatim before the first question. */
107
121
  function printDisclosure() {
108
122
  console.log('');
109
- console.log(bold(' share prompt stats?'));
123
+ console.log(bold(' sync your prompt activity?'));
110
124
  console.log('');
111
- info(' hacklab can read your local Claude Code history to chart how you prompt.');
112
- info(` it is read on this machine, from ${dim('~/.claude/projects')}.`);
125
+ info(' hacklab can keep your profile up to date with how you work with AI,');
126
+ info(` reading your Claude Code history from ${dim('~/.claude/projects')}.`);
113
127
  console.log('');
114
- info(` ${bold('what would be uploaded')}`);
115
- info(' how many prompts you have sent, and how long they are in words');
116
- info(' a prompt count per project, matched by its git remote');
128
+ info(` ${bold('what would be synced, every minute:')}`);
129
+ info(` ${dim('-')} how many prompts you send, and how long they are in words`);
130
+ info(` ${dim('-')} when each session started and last ran, and its session id`);
131
+ info(` ${dim('-')} a prompt count per project, matched by its git remote`);
117
132
  console.log('');
118
- info(` ${bold('what would not')}`);
119
- info(' the text of your prompts, unless you separately say yes below');
120
- info(' anything from a project without a git remote');
133
+ info(` ${bold('what stays on this machine:')}`);
134
+ info(` ${dim('-')} the text of your prompts, unless you separately say yes below`);
135
+ info(` ${dim('-')} anything from a project without a git remote`);
121
136
  console.log('');
122
- info(dim(' hacklab stores the numbers on your profile. you can change or revoke'));
123
- info(dim(' this later with `hacklab config prompt-stats <none|stats|full>`.'));
137
+ info(dim(' your profile shows your sessions, how many you run at once, and'));
138
+ info(dim(' your prompt counts. change or revoke this any time with'));
139
+ info(dim(' `hacklab config prompt-sync <none|stats|full>`.'));
124
140
  console.log('');
125
141
  }
126
142
  /**
127
- * Resolve the consent tier for this run.
143
+ * Resolve the prompt-sync tier for this run.
128
144
  *
129
145
  * Precedence: an explicit flag wins (and is remembered), then the stored
130
146
  * answer, then the interactive questions. An unattended run that has never
131
147
  * answered gets `none` — silence is never consent.
132
148
  */
133
- export async function resolvePromptConsent(flagTier, opts = {}) {
149
+ export async function resolvePromptSync(flagTier, opts = {}) {
134
150
  if (flagTier) {
135
- await savePromptConsent(flagTier);
151
+ await savePromptSync(flagTier);
136
152
  return flagTier;
137
153
  }
138
- const stored = await loadPromptConsent();
154
+ const stored = await loadPromptSync();
139
155
  if (stored)
140
156
  return stored;
141
157
  if (!opts.interactive || !process.stdin.isTTY)
142
158
  return 'none';
143
159
  printDisclosure();
144
- const shareNumbers = await askYesNo(' share these numbers with hacklab?');
145
- if (shareNumbers === null)
160
+ const shareActivity = await askYesNo(' sync this to hacklab?');
161
+ if (shareActivity === null)
146
162
  return 'none';
147
- if (!shareNumbers) {
148
- await savePromptConsent('none');
163
+ if (!shareActivity) {
164
+ await savePromptSync('none');
149
165
  console.log('');
150
- info(dim(' no problem — syncing token counts only, as before.'));
166
+ info(dim(' no problem — syncing token counts only.'));
151
167
  return 'none';
152
168
  }
153
169
  console.log('');
154
- info(' optional: a sample of your prompt text (up to 20k characters) can be');
155
- info(' sent so an LLM can score how technical your prompting is. hacklab');
156
- info(` scores it and ${bold('discards it')} — the text is never stored.`);
170
+ info(' optional: a rolling sample of your most recent prompts (up to 20,000');
171
+ info(' characters) can go out with the daily sync, so a model can estimate');
172
+ info(` how technical your prompting is. hacklab scores it and ${bold('discards it')} —`);
173
+ info(' the text is never stored.');
157
174
  console.log('');
158
- const shareText = await askYesNo(' also send a sample of your prompt text?');
175
+ const shareText = await askYesNo(' also send a sample of your most recent prompts?');
159
176
  const tier = shareText === true ? 'full' : 'stats';
160
- await savePromptConsent(tier);
177
+ await savePromptSync(tier);
161
178
  console.log('');
162
179
  info(dim(tier === 'full'
163
- ? ' sharing prompt stats and a text sample.'
164
- : ' sharing prompt stats. numbers only, no text.'));
180
+ ? ' syncing prompt activity and a text sample.'
181
+ : ' syncing prompt activity. numbers only, no text.'));
165
182
  return tier;
166
183
  }
167
184
  //# sourceMappingURL=prompt-consent.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"prompt-consent.js","sourceRoot":"","sources":["../src/prompt-consent.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"prompt-consent.js","sourceRoot":"","sources":["../src/prompt-consent.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,10 @@
1
1
  /** Buckets are `1..bucketMax`, so the axis stays readable at any prompt length. */
2
2
  export declare const PROMPT_LENGTH_BUCKET_MIN = 10;
3
3
  export declare const PROMPT_LENGTH_BUCKET_MAX = 100;
4
- /** The percentile that sets `bucketMax`; everything above lands in the overflow. */
5
- export declare const PROMPT_LENGTH_OVERFLOW_PERCENTILE = 0.9;
4
+ /** The percentile that sets `bucketMax`; everything above it lands in `tail`. */
5
+ export declare const PROMPT_LENGTH_AXIS_PERCENTILE = 0.9;
6
+ /** The server's cap on `tail` entries; longer distributions are coarsened. */
7
+ export declare const PROMPT_TAIL_MAX_ENTRIES = 400;
6
8
  /** Matches the backend's cap — anything longer is truncated before upload. */
7
9
  export declare const CONVERSATION_SAMPLE_MAX_CHARS = 20000;
8
10
  export type PromptStatsProject = {
@@ -10,6 +12,27 @@ export type PromptStatsProject = {
10
12
  promptCount: number;
11
13
  lastActiveAt: string;
12
14
  };
15
+ /** One session's running aggregate, as both the tick and a full scan build it. */
16
+ export type PromptSessionAggregate = {
17
+ /** ISO timestamp of the first prompt seen in this session. */
18
+ startedAt: string;
19
+ /** ISO timestamp of the most recent one. */
20
+ lastActiveAt: string;
21
+ promptCount: number;
22
+ };
23
+ /** One day's running tally. Cumulative for this machine, never a delta. */
24
+ export type PromptDayAggregate = {
25
+ prompts: number;
26
+ words: number;
27
+ };
28
+ /**
29
+ * The whole prompt-activity aggregate, keyed for cheap merging: sessions by
30
+ * session id, days by YYYY-MM-DD.
31
+ */
32
+ export type PromptActivityAggregate = {
33
+ sessions: Record<string, PromptSessionAggregate>;
34
+ daily: Record<string, PromptDayAggregate>;
35
+ };
13
36
  export type PromptStats = {
14
37
  totalPrompts: number;
15
38
  bucketMax: number;
@@ -17,7 +40,27 @@ export type PromptStats = {
17
40
  length: number;
18
41
  count: number;
19
42
  }[];
43
+ /**
44
+ * The exact distribution above `bucketMax`, and the only place those prompts
45
+ * are reported — the histogram stops at `bucketMax`. One entry per distinct
46
+ * word count, ascending, coarsened if there are more than
47
+ * `PROMPT_TAIL_MAX_ENTRIES` of them. Always present, empty when nothing
48
+ * exceeds `bucketMax`: the field's presence is what tells the server this
49
+ * histogram is exact, as opposed to a legacy snapshot whose last bar lumped
50
+ * everything at or above `bucketMax`.
51
+ */
52
+ tail: {
53
+ length: number;
54
+ count: number;
55
+ }[];
20
56
  projects: PromptStatsProject[];
57
+ /**
58
+ * Sessions and per-day counts for the whole local history. Not part of the
59
+ * `promptStats` block on the wire — the caller hands it to `stageFullScan`,
60
+ * which re-bases the tick's incremental state on it and works out which rows
61
+ * this upload still has to carry.
62
+ */
63
+ activity: PromptActivityAggregate;
21
64
  /** Only ever set under the `full` consent tier. */
22
65
  conversationSample?: string;
23
66
  };
@@ -34,9 +77,43 @@ export type PromptStats = {
34
77
  export declare function promptTextFrom(entry: unknown): string | null;
35
78
  /** Whitespace-separated word count. Zero-word prompts are dropped by callers. */
36
79
  export declare function countWords(text: string): number;
80
+ /** The server's cap on a session id. Longer than this and the row is rejected. */
81
+ export declare const PROMPT_SESSION_ID_MAX_CHARS = 128;
82
+ /** One prompt, reduced to the three facts the activity aggregate needs. */
83
+ export type PromptLine = {
84
+ sessionId: string;
85
+ /** Canonical ISO-8601 UTC, so string order is time order. */
86
+ timestamp: string;
87
+ words: number;
88
+ };
37
89
  /**
38
- * The overflow threshold for this user's own distribution: their p90 prompt
39
- * length rounded up to a multiple of 10, clamped to [10, 100].
90
+ * A transcript line as prompt activity, or null when it isn't one.
91
+ *
92
+ * Stricter than `promptTextFrom` on purpose: a prompt with no session id or no
93
+ * usable timestamp can't be placed on a session or a day, and the server's
94
+ * schema would reject it, so it counts towards the histogram (which needs
95
+ * neither) and nothing else.
96
+ */
97
+ export declare function parsePromptLine(line: string): PromptLine | null;
98
+ /** An ISO-8601 UTC string, or null when the value isn't a usable instant. */
99
+ export declare function normalizeTimestamp(value: unknown): string | null;
100
+ export declare function emptyPromptActivity(): PromptActivityAggregate;
101
+ /**
102
+ * Fold one prompt into an activity aggregate, returning the session and date it
103
+ * landed on so an incremental caller can mark exactly those dirty.
104
+ *
105
+ * The date is the UTC day of the timestamp — the same attribution
106
+ * `toDateStr` gives every token daily row, so the two halves of a sync agree
107
+ * about which day a piece of work belongs to.
108
+ */
109
+ export declare function addPromptToActivity(activity: PromptActivityAggregate, line: PromptLine): {
110
+ sessionId: string;
111
+ date: string;
112
+ };
113
+ /**
114
+ * Where the histogram's axis ends for this user's own distribution: their p90
115
+ * prompt length rounded up to a multiple of 10, clamped to [10, 100]. Anything
116
+ * longer is reported by `buildTail` instead.
40
117
  *
41
118
  * Per-user rather than fixed because prompt length varies enormously between
42
119
  * people — a fixed axis would either crush a terse user's histogram into the
@@ -44,14 +121,40 @@ export declare function countWords(text: string): number;
44
121
  */
45
122
  export declare function bucketMaxFor(wordCounts: number[]): number;
46
123
  /**
47
- * Bucket the word counts. Buckets `1..bucketMax-1` are exact word counts; the
48
- * bucket at `bucketMax` is the overflow, holding every prompt that long or
49
- * longer. Empty buckets are omitted — the chart fills the gaps.
124
+ * Bucket the word counts. Every bucket `1..bucketMax` is an exact word count —
125
+ * there is no overflow bar. Empty buckets are omitted; the chart fills the gaps.
126
+ *
127
+ * Prompts longer than `bucketMax` are not in here at all: they are reported by
128
+ * `buildTail`, and only there. So the histogram and the tail partition the
129
+ * scan — sum(histogram counts) + sum(tail counts) === totalPrompts, always.
50
130
  */
51
131
  export declare function buildHistogram(wordCounts: number[], bucketMax: number): {
52
132
  length: number;
53
133
  count: number;
54
134
  }[];
135
+ /**
136
+ * The exact distribution of everything *longer* than `bucketMax`, which the
137
+ * histogram does not cover at all. One entry per distinct word count,
138
+ * ascending; empty (never absent) when nothing exceeds `bucketMax` — the
139
+ * field's presence on the wire is the marker that the histogram's bars are
140
+ * exact.
141
+ *
142
+ * Lengths only — no prompt text is involved here, or anywhere near it.
143
+ *
144
+ * A machine with a long history can have thousands of distinct long lengths,
145
+ * far past what the server accepts, so an over-cap tail is coarsened: lengths
146
+ * are rounded to multiples of 2, then 4, 8, … until at most
147
+ * `PROMPT_TAIL_MAX_ENTRIES` entries remain, summing the counts that collapse
148
+ * together. Rounding is *up* so that a coarsened entry still sits above
149
+ * `bucketMax` — rounding down could claim a length inside the histogram's own
150
+ * exact range for a prompt the histogram never counted.
151
+ *
152
+ * Deterministic: the result depends only on the multiset of word counts.
153
+ */
154
+ export declare function buildTail(wordCounts: number[], bucketMax: number): {
155
+ length: number;
156
+ count: number;
157
+ }[];
55
158
  /**
56
159
  * The `origin` remote of the repo at `cwd`, or null when there isn't one (not
57
160
  * a repo, no origin, no git binary, or the directory is gone). The URL is sent
@@ -69,4 +172,10 @@ export declare function gitOriginUrl(cwd: string): Promise<string | null>;
69
172
  export declare function scanPromptStats(options?: {
70
173
  includeSample?: boolean;
71
174
  }): Promise<PromptStats | null>;
175
+ /**
176
+ * The `promptStats` block as the server takes it. `activity` is deliberately
177
+ * dropped: it is local bookkeeping for the tick's incremental state, and it
178
+ * travels under its own top-level `promptActivity` field instead.
179
+ */
180
+ export declare function promptStatsPayload(stats: PromptStats): Omit<PromptStats, 'activity'>;
72
181
  //# sourceMappingURL=prompt-stats.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"prompt-stats.d.ts","sourceRoot":"","sources":["../src/prompt-stats.ts"],"names":[],"mappings":"AA6BA,mFAAmF;AACnF,eAAO,MAAM,wBAAwB,KAAK,CAAA;AAC1C,eAAO,MAAM,wBAAwB,MAAM,CAAA;AAC3C,oFAAoF;AACpF,eAAO,MAAM,iCAAiC,MAAM,CAAA;AACpD,8EAA8E;AAC9E,eAAO,MAAM,6BAA6B,QAAS,CAAA;AAEnD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IAC9C,QAAQ,EAAE,kBAAkB,EAAE,CAAA;IAC9B,mDAAmD;IACnD,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC5B,CAAA;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAwB5D;AAED,iFAAiF;AACjF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG/C;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,CAazD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,UAAU,EAAE,MAAM,EAAE,EACpB,SAAS,EAAE,MAAM,GAChB;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,CAUrC;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAYtE;AAQD;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,OAAO,GAAE;IAAE,aAAa,CAAC,EAAE,OAAO,CAAA;CAAO,GACxC,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAoF7B"}
1
+ {"version":3,"file":"prompt-stats.d.ts","sourceRoot":"","sources":["../src/prompt-stats.ts"],"names":[],"mappings":"AAmCA,mFAAmF;AACnF,eAAO,MAAM,wBAAwB,KAAK,CAAA;AAC1C,eAAO,MAAM,wBAAwB,MAAM,CAAA;AAC3C,iFAAiF;AACjF,eAAO,MAAM,6BAA6B,MAAM,CAAA;AAChD,8EAA8E;AAC9E,eAAO,MAAM,uBAAuB,MAAM,CAAA;AAC1C,8EAA8E;AAC9E,eAAO,MAAM,6BAA6B,QAAS,CAAA;AAEnD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,kFAAkF;AAClF,MAAM,MAAM,sBAAsB,GAAG;IACnC,8DAA8D;IAC9D,SAAS,EAAE,MAAM,CAAA;IACjB,4CAA4C;IAC5C,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,2EAA2E;AAC3E,MAAM,MAAM,kBAAkB,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAA;AAEnE;;;GAGG;AACH,MAAM,MAAM,uBAAuB,GAAG;IACpC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAA;IAChD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAA;CAC1C,CAAA;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IAC9C;;;;;;;;OAQG;IACH,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;IACzC,QAAQ,EAAE,kBAAkB,EAAE,CAAA;IAC9B;;;;;OAKG;IACH,QAAQ,EAAE,uBAAuB,CAAA;IACjC,mDAAmD;IACnD,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC5B,CAAA;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAwB5D;AAED,iFAAiF;AACjF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG/C;AAED,kFAAkF;AAClF,eAAO,MAAM,2BAA2B,MAAM,CAAA;AAE9C,2EAA2E;AAC3E,MAAM,MAAM,UAAU,GAAG;IACvB,SAAS,EAAE,MAAM,CAAA;IACjB,6DAA6D;IAC7D,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAsB/D;AAED,6EAA6E;AAC7E,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAKhE;AAED,wBAAgB,mBAAmB,IAAI,uBAAuB,CAE7D;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,uBAAuB,EACjC,IAAI,EAAE,UAAU,GACf;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CA0BrC;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,CAazD;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,UAAU,EAAE,MAAM,EAAE,EACpB,SAAS,EAAE,MAAM,GAChB;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,CAUrC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,SAAS,CACvB,UAAU,EAAE,MAAM,EAAE,EACpB,SAAS,EAAE,MAAM,GAChB;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAAE,CAyBrC;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAYtE;AA2BD;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,OAAO,GAAE;IAAE,aAAa,CAAC,EAAE,OAAO,CAAA;CAAO,GACxC,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAiG7B;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,WAAW,GACjB,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,CAG/B"}