projscan 1.6.0 → 1.6.2

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.
@@ -1,90 +0,0 @@
1
- /**
2
- * Opt-in, privacy-preserving telemetry (0.14).
3
- *
4
- * What it records: tool name, duration, success/failure, projscan version,
5
- * iso timestamp. That's it. NO source content, NO file paths, NO arguments,
6
- * NO repository identifiers, NO machine identifiers.
7
- *
8
- * What it does NOT do: send anything off the machine. The MVP sink is a
9
- * local JSONL file the user controls. A remote sink may follow in a later
10
- * release once we have a server worth pointing at.
11
- *
12
- * Discoverability: off by default. Enable via .projscanrc telemetry block,
13
- * or PROJSCAN_TELEMETRY=1 env var (env wins). PROJSCAN_TELEMETRY=0 disables
14
- * even when the config opts in (per-machine kill switch).
15
- */
16
- export interface TelemetryConfig {
17
- enabled: boolean;
18
- /**
19
- * Where to write events. Default: `~/.projscan/telemetry.jsonl`.
20
- * Either a path or the literal string "stderr" (test/diagnostic use).
21
- */
22
- sink: string;
23
- }
24
- export interface TelemetryEvent {
25
- ts: string;
26
- version: string;
27
- tool: string;
28
- durationMs: number;
29
- ok: boolean;
30
- errorCode?: string;
31
- }
32
- /**
33
- * Resolve effective config. Env var takes precedence; .projscanrc supplies
34
- * the sink and acts as the default. Non-throwing — bad config silently
35
- * disables.
36
- */
37
- export declare function resolveTelemetryConfig(rcConfig?: {
38
- enabled?: boolean;
39
- sink?: string;
40
- }): TelemetryConfig;
41
- /** Test-only: drop the cached config so tests can mutate env between cases. */
42
- export declare function _resetTelemetryConfigForTests(): void;
43
- /**
44
- * Fire-and-forget event recorder. Catches every error path so an unwritable
45
- * sink can never affect the calling tool. Does nothing when disabled.
46
- */
47
- export declare function recordToolCall(tool: string, durationMs: number, ok: boolean, errorCode?: string, rcConfig?: {
48
- enabled?: boolean;
49
- sink?: string;
50
- }): Promise<void>;
51
- /** Returns the JSON used by `projscan_telemetry` to surface state to the user. */
52
- export declare function describeTelemetryConfig(rcConfig?: {
53
- enabled?: boolean;
54
- sink?: string;
55
- }): TelemetryConfig & {
56
- defaultSink: string;
57
- envOverride: string | null;
58
- };
59
- export interface ToolHistogram {
60
- tool: string;
61
- count: number;
62
- errorCount: number;
63
- errorRate: number;
64
- /** Latency percentiles (ms). null when count is 0 (shouldn't happen post-filter). */
65
- p50Ms: number | null;
66
- p95Ms: number | null;
67
- p99Ms: number | null;
68
- meanMs: number;
69
- minMs: number;
70
- maxMs: number;
71
- }
72
- export interface TelemetryAggregate {
73
- available: boolean;
74
- reason?: string;
75
- sink: string;
76
- totalEvents: number;
77
- windowFrom: string | null;
78
- windowTo: string | null;
79
- byTool: ToolHistogram[];
80
- }
81
- /**
82
- * Read the JSONL sink and bucket events by tool, returning latency
83
- * percentiles per tool. Returns available:false (with a reason) when the
84
- * sink doesn't exist yet — typical case for users who haven't enabled
85
- * telemetry or haven't run anything yet.
86
- */
87
- export declare function aggregateTelemetry(rcConfig?: {
88
- enabled?: boolean;
89
- sink?: string;
90
- }): Promise<TelemetryAggregate>;
@@ -1,199 +0,0 @@
1
- import fs from 'node:fs/promises';
2
- import os from 'node:os';
3
- import path from 'node:path';
4
- import { readFileSync } from 'node:fs';
5
- import { fileURLToPath } from 'node:url';
6
- const DEFAULT_SINK_DIR = path.join(os.homedir(), '.projscan');
7
- const DEFAULT_SINK_FILE = path.join(DEFAULT_SINK_DIR, 'telemetry.jsonl');
8
- let cachedConfig;
9
- let cachedVersion;
10
- /**
11
- * Resolve effective config. Env var takes precedence; .projscanrc supplies
12
- * the sink and acts as the default. Non-throwing — bad config silently
13
- * disables.
14
- */
15
- export function resolveTelemetryConfig(rcConfig) {
16
- if (cachedConfig)
17
- return cachedConfig;
18
- const envFlag = process.env.PROJSCAN_TELEMETRY;
19
- let enabled = !!rcConfig?.enabled;
20
- if (envFlag === '1' || envFlag?.toLowerCase() === 'true')
21
- enabled = true;
22
- if (envFlag === '0' || envFlag?.toLowerCase() === 'false')
23
- enabled = false;
24
- const sink = rcConfig?.sink || DEFAULT_SINK_FILE;
25
- cachedConfig = { enabled, sink };
26
- return cachedConfig;
27
- }
28
- /** Test-only: drop the cached config so tests can mutate env between cases. */
29
- export function _resetTelemetryConfigForTests() {
30
- cachedConfig = undefined;
31
- cachedVersion = undefined;
32
- }
33
- function readVersion() {
34
- if (cachedVersion)
35
- return cachedVersion;
36
- try {
37
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
38
- const pkg = JSON.parse(readFileSync(path.resolve(__dirname, '../../package.json'), 'utf-8'));
39
- cachedVersion = String(pkg.version ?? '0.0.0');
40
- }
41
- catch {
42
- cachedVersion = '0.0.0';
43
- }
44
- return cachedVersion;
45
- }
46
- /**
47
- * Fire-and-forget event recorder. Catches every error path so an unwritable
48
- * sink can never affect the calling tool. Does nothing when disabled.
49
- */
50
- export async function recordToolCall(tool, durationMs, ok, errorCode, rcConfig) {
51
- const config = resolveTelemetryConfig(rcConfig);
52
- if (!config.enabled)
53
- return;
54
- const event = {
55
- ts: new Date().toISOString(),
56
- version: readVersion(),
57
- tool,
58
- durationMs: Math.round(durationMs),
59
- ok,
60
- };
61
- if (errorCode)
62
- event.errorCode = errorCode;
63
- try {
64
- if (config.sink === 'stderr') {
65
- process.stderr.write(`[telemetry] ${JSON.stringify(event)}\n`);
66
- return;
67
- }
68
- await fs.mkdir(path.dirname(config.sink), { recursive: true });
69
- await fs.appendFile(config.sink, JSON.stringify(event) + '\n', 'utf-8');
70
- }
71
- catch {
72
- // Sink failures are silent by design. Telemetry must never break a tool.
73
- }
74
- }
75
- /** Returns the JSON used by `projscan_telemetry` to surface state to the user. */
76
- export function describeTelemetryConfig(rcConfig) {
77
- const config = resolveTelemetryConfig(rcConfig);
78
- const env = process.env.PROJSCAN_TELEMETRY ?? null;
79
- return {
80
- ...config,
81
- defaultSink: DEFAULT_SINK_FILE,
82
- envOverride: env,
83
- };
84
- }
85
- /**
86
- * Read the JSONL sink and bucket events by tool, returning latency
87
- * percentiles per tool. Returns available:false (with a reason) when the
88
- * sink doesn't exist yet — typical case for users who haven't enabled
89
- * telemetry or haven't run anything yet.
90
- */
91
- export async function aggregateTelemetry(rcConfig) {
92
- const config = resolveTelemetryConfig(rcConfig);
93
- const sinkPath = config.sink === 'stderr' ? '' : config.sink;
94
- if (!sinkPath) {
95
- return {
96
- available: false,
97
- reason: 'Sink is "stderr"; nothing to aggregate from disk.',
98
- sink: config.sink,
99
- totalEvents: 0,
100
- windowFrom: null,
101
- windowTo: null,
102
- byTool: [],
103
- };
104
- }
105
- let raw;
106
- try {
107
- raw = await fs.readFile(sinkPath, 'utf-8');
108
- }
109
- catch {
110
- return {
111
- available: false,
112
- reason: `No telemetry sink found at ${sinkPath}. Enable telemetry and run a few tools first.`,
113
- sink: sinkPath,
114
- totalEvents: 0,
115
- windowFrom: null,
116
- windowTo: null,
117
- byTool: [],
118
- };
119
- }
120
- const events = [];
121
- for (const line of raw.split('\n')) {
122
- const trimmed = line.trim();
123
- if (!trimmed)
124
- continue;
125
- try {
126
- const obj = JSON.parse(trimmed);
127
- if (typeof obj?.tool === 'string' && typeof obj?.durationMs === 'number') {
128
- events.push(obj);
129
- }
130
- }
131
- catch {
132
- // Skip malformed lines silently — JSONL files can be partially written
133
- // when a process is killed mid-append.
134
- }
135
- }
136
- if (events.length === 0) {
137
- return {
138
- available: true,
139
- sink: sinkPath,
140
- totalEvents: 0,
141
- windowFrom: null,
142
- windowTo: null,
143
- byTool: [],
144
- };
145
- }
146
- const byToolMap = new Map();
147
- let windowFrom = events[0].ts;
148
- let windowTo = events[0].ts;
149
- for (const e of events) {
150
- if (e.ts < windowFrom)
151
- windowFrom = e.ts;
152
- if (e.ts > windowTo)
153
- windowTo = e.ts;
154
- if (!byToolMap.has(e.tool))
155
- byToolMap.set(e.tool, []);
156
- byToolMap.get(e.tool).push(e);
157
- }
158
- const byTool = [];
159
- for (const [tool, toolEvents] of byToolMap) {
160
- const durations = toolEvents.map((e) => e.durationMs).sort((a, b) => a - b);
161
- const errorCount = toolEvents.filter((e) => e.ok === false).length;
162
- byTool.push({
163
- tool,
164
- count: toolEvents.length,
165
- errorCount,
166
- errorRate: Math.round((errorCount / toolEvents.length) * 1000) / 1000,
167
- p50Ms: percentile(durations, 50),
168
- p95Ms: percentile(durations, 95),
169
- p99Ms: percentile(durations, 99),
170
- meanMs: Math.round(durations.reduce((s, n) => s + n, 0) / durations.length),
171
- minMs: durations[0],
172
- maxMs: durations[durations.length - 1],
173
- });
174
- }
175
- byTool.sort((a, b) => b.count - a.count);
176
- return {
177
- available: true,
178
- sink: sinkPath,
179
- totalEvents: events.length,
180
- windowFrom,
181
- windowTo,
182
- byTool,
183
- };
184
- }
185
- /** Linear-interpolation percentile over a pre-sorted ascending array. */
186
- function percentile(sorted, p) {
187
- if (sorted.length === 0)
188
- return null;
189
- if (sorted.length === 1)
190
- return sorted[0];
191
- const rank = (p / 100) * (sorted.length - 1);
192
- const lo = Math.floor(rank);
193
- const hi = Math.ceil(rank);
194
- if (lo === hi)
195
- return sorted[lo];
196
- const frac = rank - lo;
197
- return Math.round(sorted[lo] * (1 - frac) + sorted[hi] * frac);
198
- }
199
- //# sourceMappingURL=telemetry.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"telemetry.js","sourceRoot":"","sources":["../../src/core/telemetry.ts"],"names":[],"mappings":"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"}
@@ -1,3 +0,0 @@
1
- export declare function cacheGet<T>(key: string): Promise<T | null>;
2
- export declare function cacheSet<T>(key: string, data: T, ttlMs?: number): Promise<void>;
3
- export declare function cacheInvalidate(key: string): Promise<void>;
@@ -1,51 +0,0 @@
1
- import fs from 'node:fs/promises';
2
- import path from 'node:path';
3
- import os from 'node:os';
4
- import crypto from 'node:crypto';
5
- const CACHE_DIR = path.join(os.tmpdir(), 'projscan-cache');
6
- const DEFAULT_TTL_MS = 60_000; // 1 minute
7
- async function ensureCacheDir() {
8
- await fs.mkdir(CACHE_DIR, { recursive: true });
9
- }
10
- function getCacheFilePath(key) {
11
- const hash = crypto.createHash('sha256').update(key).digest('hex').slice(0, 16);
12
- return path.join(CACHE_DIR, `${hash}.json`);
13
- }
14
- export async function cacheGet(key) {
15
- try {
16
- const filePath = getCacheFilePath(key);
17
- const raw = await fs.readFile(filePath, 'utf-8');
18
- const entry = JSON.parse(raw);
19
- if (Date.now() > entry.expiresAt) {
20
- await fs.unlink(filePath).catch(() => { });
21
- return null;
22
- }
23
- return entry.data;
24
- }
25
- catch {
26
- return null;
27
- }
28
- }
29
- export async function cacheSet(key, data, ttlMs = DEFAULT_TTL_MS) {
30
- try {
31
- await ensureCacheDir();
32
- const filePath = getCacheFilePath(key);
33
- const entry = {
34
- data,
35
- expiresAt: Date.now() + ttlMs,
36
- };
37
- await fs.writeFile(filePath, JSON.stringify(entry), 'utf-8');
38
- }
39
- catch {
40
- // Cache write failure is non-critical
41
- }
42
- }
43
- export async function cacheInvalidate(key) {
44
- try {
45
- await fs.unlink(getCacheFilePath(key));
46
- }
47
- catch {
48
- // Ignore
49
- }
50
- }
51
- //# sourceMappingURL=cache.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/utils/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,MAAM,MAAM,aAAa,CAAC;AAEjC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,gBAAgB,CAAC,CAAC;AAC3D,MAAM,cAAc,GAAG,MAAM,CAAC,CAAC,WAAW;AAE1C,KAAK,UAAU,cAAc;IAC3B,MAAM,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AACjD,CAAC;AAED,SAAS,gBAAgB,CAAC,GAAW;IACnC,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAChF,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,IAAI,OAAO,CAAC,CAAC;AAC9C,CAAC;AAOD,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAI,GAAW;IAC3C,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;QACvC,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACjD,MAAM,KAAK,GAAkB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAE7C,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;YACjC,MAAM,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YAC1C,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,CAAC;IACpB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAI,GAAW,EAAE,IAAO,EAAE,KAAK,GAAG,cAAc;IAC5E,IAAI,CAAC;QACH,MAAM,cAAc,EAAE,CAAC;QACvB,MAAM,QAAQ,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;QACvC,MAAM,KAAK,GAAkB;YAC3B,IAAI;YACJ,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;SAC9B,CAAC;QACF,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC;IAC/D,CAAC;IAAC,MAAM,CAAC;QACP,sCAAsC;IACxC,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,GAAW;IAC/C,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,SAAS;IACX,CAAC;AACH,CAAC"}