codesift-mcp 0.9.10 → 0.10.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 (65) hide show
  1. package/README.md +23 -0
  2. package/dist/cli/commands.d.ts.map +1 -1
  3. package/dist/cli/commands.js +4 -0
  4. package/dist/cli/commands.js.map +1 -1
  5. package/dist/cli/telemetry-commands.d.ts +2 -0
  6. package/dist/cli/telemetry-commands.d.ts.map +1 -0
  7. package/dist/cli/telemetry-commands.js +50 -0
  8. package/dist/cli/telemetry-commands.js.map +1 -0
  9. package/dist/register-tool-groups/meta.js +1 -1
  10. package/dist/register-tool-groups/meta.js.map +1 -1
  11. package/dist/server-helpers.d.ts.map +1 -1
  12. package/dist/server-helpers.js +9 -2
  13. package/dist/server-helpers.js.map +1 -1
  14. package/dist/server.d.ts.map +1 -1
  15. package/dist/server.js +6 -0
  16. package/dist/server.js.map +1 -1
  17. package/dist/storage/_shared.d.ts +9 -0
  18. package/dist/storage/_shared.d.ts.map +1 -1
  19. package/dist/storage/_shared.js +24 -0
  20. package/dist/storage/_shared.js.map +1 -1
  21. package/dist/storage/telemetry/aggregator.d.ts +52 -0
  22. package/dist/storage/telemetry/aggregator.d.ts.map +1 -0
  23. package/dist/storage/telemetry/aggregator.js +188 -0
  24. package/dist/storage/telemetry/aggregator.js.map +1 -0
  25. package/dist/storage/telemetry/anon-id.d.ts +11 -0
  26. package/dist/storage/telemetry/anon-id.d.ts.map +1 -0
  27. package/dist/storage/telemetry/anon-id.js +62 -0
  28. package/dist/storage/telemetry/anon-id.js.map +1 -0
  29. package/dist/storage/telemetry/config.d.ts +37 -0
  30. package/dist/storage/telemetry/config.d.ts.map +1 -0
  31. package/dist/storage/telemetry/config.js +130 -0
  32. package/dist/storage/telemetry/config.js.map +1 -0
  33. package/dist/storage/telemetry/env-profile.d.ts +19 -0
  34. package/dist/storage/telemetry/env-profile.d.ts.map +1 -0
  35. package/dist/storage/telemetry/env-profile.js +67 -0
  36. package/dist/storage/telemetry/env-profile.js.map +1 -0
  37. package/dist/storage/telemetry/payload.d.ts +8 -0
  38. package/dist/storage/telemetry/payload.d.ts.map +1 -0
  39. package/dist/storage/telemetry/payload.js +22 -0
  40. package/dist/storage/telemetry/payload.js.map +1 -0
  41. package/dist/storage/telemetry/sanitizer.d.ts +48 -0
  42. package/dist/storage/telemetry/sanitizer.d.ts.map +1 -0
  43. package/dist/storage/telemetry/sanitizer.js +82 -0
  44. package/dist/storage/telemetry/sanitizer.js.map +1 -0
  45. package/dist/storage/telemetry/uploader.d.ts +11 -0
  46. package/dist/storage/telemetry/uploader.d.ts.map +1 -0
  47. package/dist/storage/telemetry/uploader.js +140 -0
  48. package/dist/storage/telemetry/uploader.js.map +1 -0
  49. package/dist/storage/usage-tracker.d.ts +13 -0
  50. package/dist/storage/usage-tracker.d.ts.map +1 -1
  51. package/dist/storage/usage-tracker.js +21 -0
  52. package/dist/storage/usage-tracker.js.map +1 -1
  53. package/dist/tools/project-tools.d.ts +3 -0
  54. package/dist/tools/project-tools.d.ts.map +1 -1
  55. package/dist/tools/project-tools.js +2 -0
  56. package/dist/tools/project-tools.js.map +1 -1
  57. package/dist/utils/edge-provenance.d.ts +55 -0
  58. package/dist/utils/edge-provenance.d.ts.map +1 -0
  59. package/dist/utils/edge-provenance.js +53 -0
  60. package/dist/utils/edge-provenance.js.map +1 -0
  61. package/dist/utils/overlay-cache.d.ts +38 -0
  62. package/dist/utils/overlay-cache.d.ts.map +1 -0
  63. package/dist/utils/overlay-cache.js +73 -0
  64. package/dist/utils/overlay-cache.js.map +1 -0
  65. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"_shared.js","sourceRoot":"","sources":["../../src/storage/_shared.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,UAAkB,EAClB,OAAe;IAEf,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAChC,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEtC,0EAA0E;IAC1E,4EAA4E;IAC5E,2DAA2D;IAC3D,MAAM,OAAO,GAAG,GAAG,UAAU,QAAQ,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IAE3G,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QAC3C,MAAM,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC;YAAC,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,yBAAyB,CAAC,CAAC;QAClE,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"_shared.js","sourceRoot":"","sources":["../../src/storage/_shared.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,UAAkB,EAClB,OAAe;IAEf,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAChC,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEtC,0EAA0E;IAC1E,4EAA4E;IAC5E,2DAA2D;IAC3D,MAAM,OAAO,GAAG,GAAG,UAAU,QAAQ,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IAE3G,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QAC3C,MAAM,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC;YAAC,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,yBAAyB,CAAC,CAAC;QAClE,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,UAAkB,EAClB,GAAW;IAEX,MAAM,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAChC,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEtC,MAAM,OAAO,GAAG,GAAG,UAAU,QAAQ,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IAE3G,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QAC9B,MAAM,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC;YAAC,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC,CAAC,yBAAyB,CAAC,CAAC;QAClE,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}
@@ -0,0 +1,52 @@
1
+ import type { UsageEntry } from "../usage-tracker.js";
2
+ export interface ToolAggregate {
3
+ tool: string;
4
+ day: string;
5
+ count: number;
6
+ p50_ms: number;
7
+ p95_ms: number;
8
+ max_ms: number;
9
+ error_rate: number;
10
+ empty_result_rate: number;
11
+ cache_hit_rate: number;
12
+ }
13
+ export interface HintEmission {
14
+ day: string;
15
+ hint_code: string;
16
+ emitted: number;
17
+ applied: number;
18
+ }
19
+ export interface PlanTurnFunnel {
20
+ day: string;
21
+ recommended: number;
22
+ used: number;
23
+ }
24
+ /**
25
+ * Pure aggregation over a set of usage entries. Groups by (tool, day) and
26
+ * derives count, latency p50/p95/max, error_rate, empty_result_rate and
27
+ * cache_hit_rate. Cache-served calls (`cache_hit === true`) are counted only
28
+ * toward cache_hit_rate — never latency/error/empty (they didn't execute).
29
+ * `empty_result_rate` uses result_chunks===0 — a query/path-free "did this
30
+ * call find anything" signal already on the entry.
31
+ */
32
+ export declare function aggregateToolMetrics(entries: UsageEntry[]): ToolAggregate[];
33
+ /**
34
+ * Hint efficacy funnel (spec §1): per (day, code), how often a hint was emitted
35
+ * on a call that had a follow-up, and how often that follow-up actually acted on
36
+ * it. Correlation is per session, in ts order, and reads only args_summary keys
37
+ * locally — the wire payload carries just the counts.
38
+ */
39
+ export declare function aggregateHintFunnel(entries: UsageEntry[]): HintEmission[];
40
+ /**
41
+ * Discovery funnel (spec §1): per day, how often plan_turn recommended >=1 tool
42
+ * (on a call with a follow-up) and how often the next call used one of them —
43
+ * i.e. is the router's advice actually taken?
44
+ */
45
+ export declare function aggregatePlanTurnFunnel(entries: UsageEntry[]): PlanTurnFunnel[];
46
+ /**
47
+ * Read + parse the local usage.jsonl (best-effort — skips malformed lines).
48
+ * `afterTs` is EXCLUSIVE (strictly greater) so it composes with an upload
49
+ * watermark (the max ts already sent) without re-sending the boundary entry.
50
+ */
51
+ export declare function readLocalUsageEntries(afterTs?: number): Promise<UsageEntry[]>;
52
+ //# sourceMappingURL=aggregator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aggregator.d.ts","sourceRoot":"","sources":["../../../src/storage/telemetry/aggregator.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGtD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAyBD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,aAAa,EAAE,CA2C3E;AAiCD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,YAAY,EAAE,CAyBzE;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,cAAc,EAAE,CAiB/E;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CAAC,OAAO,SAAI,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAkB9E"}
@@ -0,0 +1,188 @@
1
+ // Client-side aggregation: raw local usage entries → per-tool-per-day metrics.
2
+ // We send aggregates, never raw events (spec §3) — smaller payload, less leak
3
+ // surface. Only reads fields that already exist on UsageEntry.
4
+ import { readFile } from "node:fs/promises";
5
+ import { getUsagePath } from "../usage-tracker.js";
6
+ function dayOf(ts) {
7
+ return new Date(ts).toISOString().slice(0, 10);
8
+ }
9
+ /** Nearest-rank percentile over an already-sorted-ascending array. */
10
+ function percentile(sortedAsc, p) {
11
+ if (sortedAsc.length === 0)
12
+ return 0;
13
+ const idx = Math.min(sortedAsc.length - 1, Math.max(0, Math.ceil(p * sortedAsc.length) - 1));
14
+ return sortedAsc[idx];
15
+ }
16
+ const round3 = (n) => Math.round(n * 1000) / 1000;
17
+ /**
18
+ * Pure aggregation over a set of usage entries. Groups by (tool, day) and
19
+ * derives count, latency p50/p95/max, error_rate, empty_result_rate and
20
+ * cache_hit_rate. Cache-served calls (`cache_hit === true`) are counted only
21
+ * toward cache_hit_rate — never latency/error/empty (they didn't execute).
22
+ * `empty_result_rate` uses result_chunks===0 — a query/path-free "did this
23
+ * call find anything" signal already on the entry.
24
+ */
25
+ export function aggregateToolMetrics(entries) {
26
+ const buckets = new Map();
27
+ for (const e of entries) {
28
+ if (!e || typeof e.tool !== "string" || typeof e.ts !== "number")
29
+ continue;
30
+ const day = dayOf(e.ts);
31
+ const key = `${e.tool}\0${day}`;
32
+ let b = buckets.get(key);
33
+ if (!b) {
34
+ b = { tool: e.tool, day, latencies: [], errors: 0, empties: 0, executed: 0, cacheHits: 0 };
35
+ buckets.set(key, b);
36
+ }
37
+ if (e.cache_hit === true) {
38
+ b.cacheHits++;
39
+ continue;
40
+ }
41
+ b.executed++;
42
+ if (typeof e.elapsed_ms === "number" && Number.isFinite(e.elapsed_ms)) {
43
+ b.latencies.push(e.elapsed_ms);
44
+ }
45
+ if (e.error === true)
46
+ b.errors++;
47
+ if (e.result_chunks === 0)
48
+ b.empties++;
49
+ }
50
+ const out = [];
51
+ for (const b of buckets.values()) {
52
+ const sorted = b.latencies.slice().sort((a, c) => a - c);
53
+ const total = b.executed + b.cacheHits;
54
+ out.push({
55
+ tool: b.tool,
56
+ day: b.day,
57
+ count: total,
58
+ p50_ms: percentile(sorted, 0.5),
59
+ p95_ms: percentile(sorted, 0.95),
60
+ max_ms: sorted.length ? sorted[sorted.length - 1] : 0,
61
+ error_rate: b.executed ? round3(b.errors / b.executed) : 0,
62
+ empty_result_rate: b.executed ? round3(b.empties / b.executed) : 0,
63
+ cache_hit_rate: total ? round3(b.cacheHits / total) : 0,
64
+ });
65
+ }
66
+ // Deterministic order (day desc, then tool) — stable payloads, easier diffing.
67
+ out.sort((a, c) => (a.day === c.day ? a.tool.localeCompare(c.tool) : c.day.localeCompare(a.day)));
68
+ return out;
69
+ }
70
+ /** Group entries into per-session chains sorted by ts, for next-call correlation. */
71
+ function sessionChains(entries) {
72
+ const bySession = new Map();
73
+ for (const e of entries) {
74
+ if (!e || typeof e.ts !== "number")
75
+ continue;
76
+ const s = typeof e.session_id === "string" ? e.session_id : "?";
77
+ (bySession.get(s) ?? bySession.set(s, []).get(s)).push(e);
78
+ }
79
+ for (const chain of bySession.values())
80
+ chain.sort((a, b) => a.ts - b.ts);
81
+ return [...bySession.values()];
82
+ }
83
+ const has = (e, k) => e.args_summary != null && typeof e.args_summary === "object" && k in e.args_summary;
84
+ /** Did the follow-up call `n` act on hint `code`? Codes without a rule are
85
+ * counted as emitted but never applied (honest under-report). */
86
+ const HINT_APPLIED = {
87
+ H1: (n) => has(n, "group_by_file") && n.args_summary["group_by_file"] === true,
88
+ H2: (n) => n.tool === "get_symbols" || n.tool === "codebase_retrieval",
89
+ H3: (n) => n.tool !== "list_repos",
90
+ H4: (n) => has(n, "file_pattern"),
91
+ H5: (n) => n.tool !== "get_file_tree",
92
+ H6: (n) => has(n, "detail_level"),
93
+ H7: (n) => n.tool === "get_context_bundle",
94
+ H8: (n) => n.tool === "assemble_context",
95
+ H9: (n) => n.tool === "semantic_search" || n.tool === "codebase_retrieval",
96
+ H10: (n) => n.tool === "get_session_snapshot",
97
+ H12: (n) => n.tool === "codebase_retrieval",
98
+ };
99
+ /**
100
+ * Hint efficacy funnel (spec §1): per (day, code), how often a hint was emitted
101
+ * on a call that had a follow-up, and how often that follow-up actually acted on
102
+ * it. Correlation is per session, in ts order, and reads only args_summary keys
103
+ * locally — the wire payload carries just the counts.
104
+ */
105
+ export function aggregateHintFunnel(entries) {
106
+ const acc = new Map();
107
+ for (const chain of sessionChains(entries)) {
108
+ for (let i = 0; i < chain.length - 1; i++) {
109
+ const e = chain[i];
110
+ const next = chain[i + 1];
111
+ if (!Array.isArray(e.hints_emitted))
112
+ continue;
113
+ const day = dayOf(e.ts);
114
+ for (const code of e.hints_emitted) {
115
+ if (typeof code !== "string")
116
+ continue;
117
+ const key = `${day}\0${code}`;
118
+ const a = acc.get(key) ?? { emitted: 0, applied: 0 };
119
+ a.emitted++;
120
+ if (HINT_APPLIED[code]?.(next))
121
+ a.applied++;
122
+ acc.set(key, a);
123
+ }
124
+ }
125
+ }
126
+ const out = [];
127
+ for (const [key, v] of acc) {
128
+ const [day, code] = key.split("\0");
129
+ out.push({ day: day, hint_code: code, emitted: v.emitted, applied: v.applied });
130
+ }
131
+ out.sort((a, c) => (a.day === c.day ? a.hint_code.localeCompare(c.hint_code) : c.day.localeCompare(a.day)));
132
+ return out;
133
+ }
134
+ /**
135
+ * Discovery funnel (spec §1): per day, how often plan_turn recommended >=1 tool
136
+ * (on a call with a follow-up) and how often the next call used one of them —
137
+ * i.e. is the router's advice actually taken?
138
+ */
139
+ export function aggregatePlanTurnFunnel(entries) {
140
+ const acc = new Map();
141
+ for (const chain of sessionChains(entries)) {
142
+ for (let i = 0; i < chain.length - 1; i++) {
143
+ const e = chain[i];
144
+ if (e.tool !== "plan_turn" || !Array.isArray(e.recommended_tools) || e.recommended_tools.length === 0)
145
+ continue;
146
+ const day = dayOf(e.ts);
147
+ const a = acc.get(day) ?? { recommended: 0, used: 0 };
148
+ a.recommended++;
149
+ if (e.recommended_tools.includes(chain[i + 1].tool))
150
+ a.used++;
151
+ acc.set(day, a);
152
+ }
153
+ }
154
+ const out = [];
155
+ for (const [day, v] of acc)
156
+ out.push({ day, recommended: v.recommended, used: v.used });
157
+ out.sort((a, c) => c.day.localeCompare(a.day));
158
+ return out;
159
+ }
160
+ /**
161
+ * Read + parse the local usage.jsonl (best-effort — skips malformed lines).
162
+ * `afterTs` is EXCLUSIVE (strictly greater) so it composes with an upload
163
+ * watermark (the max ts already sent) without re-sending the boundary entry.
164
+ */
165
+ export async function readLocalUsageEntries(afterTs = 0) {
166
+ let raw;
167
+ try {
168
+ raw = await readFile(getUsagePath(), "utf-8");
169
+ }
170
+ catch {
171
+ return [];
172
+ }
173
+ const entries = [];
174
+ for (const line of raw.split("\n")) {
175
+ if (!line)
176
+ continue;
177
+ try {
178
+ const e = JSON.parse(line);
179
+ if (typeof e.ts === "number" && e.ts > afterTs)
180
+ entries.push(e);
181
+ }
182
+ catch {
183
+ /* skip torn/partial line */
184
+ }
185
+ }
186
+ return entries;
187
+ }
188
+ //# sourceMappingURL=aggregator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aggregator.js","sourceRoot":"","sources":["../../../src/storage/telemetry/aggregator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ export declare function getAnonIdPath(): string;
2
+ /**
3
+ * Return the persistent anon id, creating it on first call. Purely random
4
+ * (UUID v4). Best-effort: if the file can't be written (read-only FS), a
5
+ * fresh random id is returned for this process so telemetry still works —
6
+ * it just won't be stable across restarts on that box.
7
+ */
8
+ export declare function getAnonId(): string;
9
+ /** Test-only: drop the in-process cache. */
10
+ export declare function _resetAnonIdCacheForTests(): void;
11
+ //# sourceMappingURL=anon-id.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anon-id.d.ts","sourceRoot":"","sources":["../../../src/storage/telemetry/anon-id.ts"],"names":[],"mappings":"AAYA,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAID;;;;;GAKG;AACH,wBAAgB,SAAS,IAAI,MAAM,CAkClC;AAED,4CAA4C;AAC5C,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD"}
@@ -0,0 +1,62 @@
1
+ // Stable random anonymous ID — generated once on first use, persisted, and
2
+ // NEVER derived from hardware / hostname / username (spec §1). Lets the
3
+ // collector count unique installs without identifying anyone.
4
+ import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
5
+ import { randomUUID } from "node:crypto";
6
+ import { join } from "node:path";
7
+ import { homedir } from "node:os";
8
+ function dataDir() {
9
+ return process.env["CODESIFT_DATA_DIR"] ?? join(homedir(), ".codesift");
10
+ }
11
+ export function getAnonIdPath() {
12
+ return join(dataDir(), "telemetry-id");
13
+ }
14
+ let cached = null;
15
+ /**
16
+ * Return the persistent anon id, creating it on first call. Purely random
17
+ * (UUID v4). Best-effort: if the file can't be written (read-only FS), a
18
+ * fresh random id is returned for this process so telemetry still works —
19
+ * it just won't be stable across restarts on that box.
20
+ */
21
+ export function getAnonId() {
22
+ if (cached)
23
+ return cached;
24
+ const path = getAnonIdPath();
25
+ try {
26
+ const existing = readFileSync(path, "utf-8").trim();
27
+ if (existing) {
28
+ cached = existing;
29
+ return existing;
30
+ }
31
+ }
32
+ catch {
33
+ /* not created yet */
34
+ }
35
+ const id = randomUUID();
36
+ try {
37
+ mkdirSync(dataDir(), { recursive: true });
38
+ writeFileSync(path, id + "\n", { encoding: "utf-8", flag: "wx" });
39
+ cached = id;
40
+ return id;
41
+ }
42
+ catch {
43
+ // Lost a race (another process created it) or FS is read-only.
44
+ try {
45
+ const raced = readFileSync(path, "utf-8").trim();
46
+ if (raced) {
47
+ cached = raced;
48
+ return raced;
49
+ }
50
+ }
51
+ catch {
52
+ /* still unwritable — fall through to ephemeral */
53
+ }
54
+ cached = id;
55
+ return id;
56
+ }
57
+ }
58
+ /** Test-only: drop the in-process cache. */
59
+ export function _resetAnonIdCacheForTests() {
60
+ cached = null;
61
+ }
62
+ //# sourceMappingURL=anon-id.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anon-id.js","sourceRoot":"","sources":["../../../src/storage/telemetry/anon-id.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,wEAAwE;AACxE,8DAA8D;AAC9D,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,SAAS,OAAO;IACd,OAAO,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,WAAW,CAAC,CAAC;AAC1E,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,cAAc,CAAC,CAAC;AACzC,CAAC;AAED,IAAI,MAAM,GAAkB,IAAI,CAAC;AAEjC;;;;;GAKG;AACH,MAAM,UAAU,SAAS;IACvB,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAE1B,MAAM,IAAI,GAAG,aAAa,EAAE,CAAC;IAC7B,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;QACpD,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,GAAG,QAAQ,CAAC;YAClB,OAAO,QAAQ,CAAC;QAClB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,qBAAqB;IACvB,CAAC;IAED,MAAM,EAAE,GAAG,UAAU,EAAE,CAAC;IACxB,IAAI,CAAC;QACH,SAAS,CAAC,OAAO,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1C,aAAa,CAAC,IAAI,EAAE,EAAE,GAAG,IAAI,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAClE,MAAM,GAAG,EAAE,CAAC;QACZ,OAAO,EAAE,CAAC;IACZ,CAAC;IAAC,MAAM,CAAC;QACP,+DAA+D;QAC/D,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;YACjD,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,GAAG,KAAK,CAAC;gBACf,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,kDAAkD;QACpD,CAAC;QACD,MAAM,GAAG,EAAE,CAAC;QACZ,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,4CAA4C;AAC5C,MAAM,UAAU,yBAAyB;IACvC,MAAM,GAAG,IAAI,CAAC;AAChB,CAAC"}
@@ -0,0 +1,37 @@
1
+ export type TelemetryLevel = "off" | "anon" | "full";
2
+ /** Bump when the L1 payload shape changes. Collector tolerates unknown versions. */
3
+ export declare const TELEMETRY_SCHEMA_VERSION = 1;
4
+ export declare function getConfigPath(): string;
5
+ interface StoredConfig {
6
+ telemetry?: string | {
7
+ level?: string;
8
+ };
9
+ }
10
+ /** Best-effort read of ~/.codesift/config.json — never throws. */
11
+ export declare function readStoredConfig(): StoredConfig;
12
+ /**
13
+ * Resolve the effective telemetry level. Precedence (first match wins):
14
+ * 1. DO_NOT_TRACK truthy → off (respect the cross-tool standard)
15
+ * 2. CODESIFT_TELEMETRY env → off | anon | full
16
+ * 3. config.json `telemetry` → off | anon | full (level string or {level})
17
+ * 4. default → anon (opt-out model — spec decision)
18
+ */
19
+ export declare function resolveTelemetryLevel(): TelemetryLevel;
20
+ /**
21
+ * Persist the telemetry level into ~/.codesift/config.json (merging with any
22
+ * existing config). Atomic tmp+rename. Used by `codesift telemetry on|off|full`.
23
+ */
24
+ export declare function writeStoredTelemetryLevel(level: TelemetryLevel): void;
25
+ /**
26
+ * Print the one-time consent notice to STDERR (spec §4). Shown once per machine
27
+ * when telemetry is anon, then a marker file suppresses it. STDERR so it never
28
+ * corrupts the MCP stdio protocol. Best-effort — never throws.
29
+ */
30
+ export declare function maybePrintFirstRunNotice(): void;
31
+ /** Human-readable reason for the current level — powers `codesift telemetry show`. */
32
+ export declare function telemetrySource(): {
33
+ level: TelemetryLevel;
34
+ reason: string;
35
+ };
36
+ export {};
37
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/storage/telemetry/config.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;AAErD,oFAAoF;AACpF,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAM1C,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,UAAU,YAAY;IACpB,SAAS,CAAC,EAAE,MAAM,GAAG;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACzC;AAED,kEAAkE;AAClE,wBAAgB,gBAAgB,IAAI,YAAY,CAS/C;AAiBD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,IAAI,cAAc,CAatD;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAcrE;AAMD;;;;GAIG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAoB/C;AAED,sFAAsF;AACtF,wBAAgB,eAAe,IAAI;IAAE,KAAK,EAAE,cAAc,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAc3E"}
@@ -0,0 +1,130 @@
1
+ // Telemetry level resolution + opt-out. No network here — this module only
2
+ // decides WHETHER and at what level telemetry runs. See spec
3
+ // docs/specs/2026-07-19-telemetry-spec.md §4.
4
+ import { readFileSync, writeFileSync, mkdirSync, renameSync } from "node:fs";
5
+ import { join } from "node:path";
6
+ import { homedir } from "node:os";
7
+ /** Bump when the L1 payload shape changes. Collector tolerates unknown versions. */
8
+ export const TELEMETRY_SCHEMA_VERSION = 1;
9
+ function dataDir() {
10
+ return process.env["CODESIFT_DATA_DIR"] ?? join(homedir(), ".codesift");
11
+ }
12
+ export function getConfigPath() {
13
+ return join(dataDir(), "config.json");
14
+ }
15
+ /** Best-effort read of ~/.codesift/config.json — never throws. */
16
+ export function readStoredConfig() {
17
+ try {
18
+ const raw = readFileSync(getConfigPath(), "utf-8");
19
+ const parsed = JSON.parse(raw);
20
+ if (parsed && typeof parsed === "object")
21
+ return parsed;
22
+ }
23
+ catch {
24
+ /* absent or malformed → defaults */
25
+ }
26
+ return {};
27
+ }
28
+ function normalizeLevel(v) {
29
+ if (typeof v !== "string")
30
+ return null;
31
+ const s = v.trim().toLowerCase();
32
+ if (s === "off" || s === "0" || s === "false" || s === "no")
33
+ return "off";
34
+ if (s === "full")
35
+ return "full";
36
+ if (s === "anon" || s === "on" || s === "1" || s === "true" || s === "anonymous")
37
+ return "anon";
38
+ return null;
39
+ }
40
+ function isTruthyEnv(v) {
41
+ if (!v)
42
+ return false;
43
+ const s = v.trim().toLowerCase();
44
+ return s !== "" && s !== "0" && s !== "false" && s !== "no";
45
+ }
46
+ /**
47
+ * Resolve the effective telemetry level. Precedence (first match wins):
48
+ * 1. DO_NOT_TRACK truthy → off (respect the cross-tool standard)
49
+ * 2. CODESIFT_TELEMETRY env → off | anon | full
50
+ * 3. config.json `telemetry` → off | anon | full (level string or {level})
51
+ * 4. default → anon (opt-out model — spec decision)
52
+ */
53
+ export function resolveTelemetryLevel() {
54
+ if (isTruthyEnv(process.env["DO_NOT_TRACK"]))
55
+ return "off";
56
+ const fromEnv = normalizeLevel(process.env["CODESIFT_TELEMETRY"]);
57
+ if (fromEnv)
58
+ return fromEnv;
59
+ const stored = readStoredConfig().telemetry;
60
+ const fromStore = normalizeLevel(typeof stored === "object" && stored !== null ? stored.level : stored);
61
+ if (fromStore)
62
+ return fromStore;
63
+ return "anon";
64
+ }
65
+ /**
66
+ * Persist the telemetry level into ~/.codesift/config.json (merging with any
67
+ * existing config). Atomic tmp+rename. Used by `codesift telemetry on|off|full`.
68
+ */
69
+ export function writeStoredTelemetryLevel(level) {
70
+ const path = getConfigPath();
71
+ let cfg = {};
72
+ try {
73
+ const parsed = JSON.parse(readFileSync(path, "utf-8"));
74
+ if (parsed && typeof parsed === "object")
75
+ cfg = parsed;
76
+ }
77
+ catch {
78
+ /* absent/malformed → start fresh */
79
+ }
80
+ cfg["telemetry"] = { level };
81
+ mkdirSync(dataDir(), { recursive: true });
82
+ const tmp = path + ".tmp";
83
+ writeFileSync(tmp, JSON.stringify(cfg, null, 2) + "\n", "utf-8");
84
+ renameSync(tmp, path);
85
+ }
86
+ function noticePath() {
87
+ return join(dataDir(), "telemetry-notice-shown");
88
+ }
89
+ /**
90
+ * Print the one-time consent notice to STDERR (spec §4). Shown once per machine
91
+ * when telemetry is anon, then a marker file suppresses it. STDERR so it never
92
+ * corrupts the MCP stdio protocol. Best-effort — never throws.
93
+ */
94
+ export function maybePrintFirstRunNotice() {
95
+ try {
96
+ if (resolveTelemetryLevel() !== "anon")
97
+ return;
98
+ const marker = noticePath();
99
+ try {
100
+ readFileSync(marker, "utf-8");
101
+ return; // already shown
102
+ }
103
+ catch {
104
+ /* not shown yet */
105
+ }
106
+ process.stderr.write("[codesift] Anonymous usage stats are ON (tool names, latencies, error/empty rates,\n" +
107
+ " bucketed env — NO queries, paths, repo names or code). See exactly what is sent:\n" +
108
+ " `codesift telemetry show`. Opt out: CODESIFT_TELEMETRY=off (or DO_NOT_TRACK=1).\n");
109
+ mkdirSync(dataDir(), { recursive: true });
110
+ writeFileSync(marker, String(Date.now()) + "\n", "utf-8");
111
+ }
112
+ catch {
113
+ /* ignore */
114
+ }
115
+ }
116
+ /** Human-readable reason for the current level — powers `codesift telemetry show`. */
117
+ export function telemetrySource() {
118
+ if (isTruthyEnv(process.env["DO_NOT_TRACK"])) {
119
+ return { level: "off", reason: "DO_NOT_TRACK env is set" };
120
+ }
121
+ const fromEnv = normalizeLevel(process.env["CODESIFT_TELEMETRY"]);
122
+ if (fromEnv)
123
+ return { level: fromEnv, reason: `CODESIFT_TELEMETRY=${process.env["CODESIFT_TELEMETRY"]}` };
124
+ const stored = readStoredConfig().telemetry;
125
+ const fromStore = normalizeLevel(typeof stored === "object" && stored !== null ? stored.level : stored);
126
+ if (fromStore)
127
+ return { level: fromStore, reason: `config.json telemetry=${fromStore}` };
128
+ return { level: "anon", reason: "default (anonymous, opt-out)" };
129
+ }
130
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/storage/telemetry/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ export interface EnvProfile {
2
+ platform: string;
3
+ arch: string;
4
+ ram_bucket: string;
5
+ cores: number;
6
+ node_ver: string;
7
+ codesift_ver: string;
8
+ repo_size_bucket?: string;
9
+ top3_ext?: string[];
10
+ }
11
+ export declare function repoSizeBucket(fileCount: number): string;
12
+ export declare function getCodesiftVersion(): string;
13
+ /** Build the environment profile. Repo dimensions are optional — omitted when
14
+ * no repo is in scope (e.g. `telemetry show` outside a project). */
15
+ export declare function buildEnvProfile(repo?: {
16
+ fileCount: number;
17
+ topExts: string[];
18
+ }): EnvProfile;
19
+ //# sourceMappingURL=env-profile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-profile.d.ts","sourceRoot":"","sources":["../../../src/storage/telemetry/env-profile.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAWD,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAKxD;AAID,wBAAgB,kBAAkB,IAAI,MAAM,CAiB3C;AAED;qEACqE;AACrE,wBAAgB,eAAe,CAAC,IAAI,CAAC,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,UAAU,CAe3F"}
@@ -0,0 +1,67 @@
1
+ // Bucketed environment profile — coarse enough that it can never identify a
2
+ // machine, precise enough to slice behaviour by config (spec §1). No hostnames,
3
+ // no paths, no exact counts that could fingerprint.
4
+ import { readFileSync } from "node:fs";
5
+ import { fileURLToPath } from "node:url";
6
+ import * as os from "node:os";
7
+ function ramBucket(bytes) {
8
+ const gb = bytes / 1024 ** 3;
9
+ if (gb < 8)
10
+ return "<8gb";
11
+ if (gb < 16)
12
+ return "8-16gb";
13
+ if (gb < 32)
14
+ return "16-32gb";
15
+ if (gb < 64)
16
+ return "32-64gb";
17
+ return ">=64gb";
18
+ }
19
+ export function repoSizeBucket(fileCount) {
20
+ if (fileCount < 1000)
21
+ return "<1k";
22
+ if (fileCount < 10_000)
23
+ return "1-10k";
24
+ if (fileCount < 50_000)
25
+ return "10-50k";
26
+ return ">50k";
27
+ }
28
+ let versionCache = null;
29
+ export function getCodesiftVersion() {
30
+ if (versionCache)
31
+ return versionCache;
32
+ // package.json sits at the repo root; this module is src|dist/storage/telemetry/.
33
+ for (const rel of ["../../../package.json", "../../../../package.json"]) {
34
+ try {
35
+ const p = fileURLToPath(new URL(rel, import.meta.url));
36
+ const pkg = JSON.parse(readFileSync(p, "utf-8"));
37
+ if (pkg.name === "codesift-mcp" && typeof pkg.version === "string") {
38
+ versionCache = pkg.version;
39
+ return versionCache;
40
+ }
41
+ }
42
+ catch {
43
+ /* try next */
44
+ }
45
+ }
46
+ versionCache = "unknown";
47
+ return versionCache;
48
+ }
49
+ /** Build the environment profile. Repo dimensions are optional — omitted when
50
+ * no repo is in scope (e.g. `telemetry show` outside a project). */
51
+ export function buildEnvProfile(repo) {
52
+ const nodeMajor = process.versions.node.split(".")[0] ?? process.versions.node;
53
+ const profile = {
54
+ platform: os.platform(),
55
+ arch: os.arch(),
56
+ ram_bucket: ramBucket(os.totalmem()),
57
+ cores: os.cpus().length,
58
+ node_ver: nodeMajor,
59
+ codesift_ver: getCodesiftVersion(),
60
+ };
61
+ if (repo) {
62
+ profile.repo_size_bucket = repoSizeBucket(repo.fileCount);
63
+ profile.top3_ext = repo.topExts.slice(0, 3);
64
+ }
65
+ return profile;
66
+ }
67
+ //# sourceMappingURL=env-profile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-profile.js","sourceRoot":"","sources":["../../../src/storage/telemetry/env-profile.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,gFAAgF;AAChF,oDAAoD;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAa9B,SAAS,SAAS,CAAC,KAAa;IAC9B,MAAM,EAAE,GAAG,KAAK,GAAG,IAAI,IAAI,CAAC,CAAC;IAC7B,IAAI,EAAE,GAAG,CAAC;QAAE,OAAO,MAAM,CAAC;IAC1B,IAAI,EAAE,GAAG,EAAE;QAAE,OAAO,QAAQ,CAAC;IAC7B,IAAI,EAAE,GAAG,EAAE;QAAE,OAAO,SAAS,CAAC;IAC9B,IAAI,EAAE,GAAG,EAAE;QAAE,OAAO,SAAS,CAAC;IAC9B,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,SAAiB;IAC9C,IAAI,SAAS,GAAG,IAAI;QAAE,OAAO,KAAK,CAAC;IACnC,IAAI,SAAS,GAAG,MAAM;QAAE,OAAO,OAAO,CAAC;IACvC,IAAI,SAAS,GAAG,MAAM;QAAE,OAAO,QAAQ,CAAC;IACxC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,IAAI,YAAY,GAAkB,IAAI,CAAC;AAEvC,MAAM,UAAU,kBAAkB;IAChC,IAAI,YAAY;QAAE,OAAO,YAAY,CAAC;IACtC,kFAAkF;IAClF,KAAK,MAAM,GAAG,IAAI,CAAC,uBAAuB,EAAE,0BAA0B,CAAC,EAAE,CAAC;QACxE,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YACvD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,CAAwC,CAAC;YACxF,IAAI,GAAG,CAAC,IAAI,KAAK,cAAc,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;gBACnE,YAAY,GAAG,GAAG,CAAC,OAAO,CAAC;gBAC3B,OAAO,YAAY,CAAC;YACtB,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,cAAc;QAChB,CAAC;IACH,CAAC;IACD,YAAY,GAAG,SAAS,CAAC;IACzB,OAAO,YAAY,CAAC;AACtB,CAAC;AAED;qEACqE;AACrE,MAAM,UAAU,eAAe,CAAC,IAA+C;IAC7E,MAAM,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC;IAC/E,MAAM,OAAO,GAAe;QAC1B,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE;QACvB,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE;QACf,UAAU,EAAE,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC;QACpC,KAAK,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,MAAM;QACvB,QAAQ,EAAE,SAAS;QACnB,YAAY,EAAE,kBAAkB,EAAE;KACnC,CAAC;IACF,IAAI,IAAI,EAAE,CAAC;QACT,OAAO,CAAC,gBAAgB,GAAG,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC1D,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC9C,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { type Level1Payload } from "./sanitizer.js";
2
+ /**
3
+ * Build the exact Level-1 payload that would be sent right now, from the local
4
+ * usage.jsonl. Repo dimensions are omitted here (added per-context at push
5
+ * time). Runs the sanitizer guard so `telemetry show` proves the allowlist.
6
+ */
7
+ export declare function buildCurrentLevel1Payload(now: number, sinceTs?: number): Promise<Level1Payload>;
8
+ //# sourceMappingURL=payload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payload.d.ts","sourceRoot":"","sources":["../../../src/storage/telemetry/payload.ts"],"names":[],"mappings":"AAKA,OAAO,EAAuC,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEzF;;;;GAIG;AACH,wBAAsB,yBAAyB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,SAAI,GAAG,OAAO,CAAC,aAAa,CAAC,CAShG"}