pi-lens 3.6.2 → 3.6.4
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.
- package/CHANGELOG.md +10 -2
- package/package.json +4 -4
- package/tsconfig.json +1 -1
- package/clients/__tests__/file-time.test.js +0 -216
- package/clients/__tests__/file-time.test.ts +0 -276
- package/clients/__tests__/format-service.test.js +0 -245
- package/clients/__tests__/format-service.test.ts +0 -339
- package/clients/__tests__/formatters.test.js +0 -271
- package/clients/__tests__/formatters.test.ts +0 -401
- package/clients/agent-behavior-client.js +0 -110
- package/clients/agent-behavior-client.test.js +0 -94
- package/clients/agent-behavior-client.test.ts +0 -116
- package/clients/amain-types.js +0 -164
- package/clients/architect-client.js +0 -291
- package/clients/ast-grep-client.js +0 -253
- package/clients/ast-grep-parser.js +0 -84
- package/clients/ast-grep-rule-manager.js +0 -89
- package/clients/ast-grep-types.js +0 -9
- package/clients/auto-loop.js +0 -131
- package/clients/biome-client.js +0 -420
- package/clients/biome-client.test.js +0 -144
- package/clients/biome-client.test.ts +0 -163
- package/clients/cache/rule-cache.js +0 -72
- package/clients/cache-manager.js +0 -245
- package/clients/cache-manager.test.js +0 -197
- package/clients/cache-manager.test.ts +0 -299
- package/clients/complexity-client.js +0 -675
- package/clients/complexity-client.test.js +0 -234
- package/clients/complexity-client.test.ts +0 -255
- package/clients/config-validator.js +0 -465
- package/clients/dependency-checker.js +0 -325
- package/clients/dependency-checker.test.js +0 -60
- package/clients/dependency-checker.test.ts +0 -71
- package/clients/dispatch/__tests__/autofix-integration.test.js +0 -245
- package/clients/dispatch/__tests__/autofix-integration.test.ts +0 -300
- package/clients/dispatch/__tests__/runner-registration.test.js +0 -234
- package/clients/dispatch/__tests__/runner-registration.test.ts +0 -286
- package/clients/dispatch/debug.log +0 -1
- package/clients/dispatch/dispatcher.edge.test.js +0 -82
- package/clients/dispatch/dispatcher.edge.test.ts +0 -100
- package/clients/dispatch/dispatcher.format.test.js +0 -46
- package/clients/dispatch/dispatcher.format.test.ts +0 -58
- package/clients/dispatch/dispatcher.inline.test.js +0 -74
- package/clients/dispatch/dispatcher.inline.test.ts +0 -93
- package/clients/dispatch/dispatcher.js +0 -381
- package/clients/dispatch/dispatcher.test.js +0 -116
- package/clients/dispatch/dispatcher.test.ts +0 -149
- package/clients/dispatch/integration.js +0 -108
- package/clients/dispatch/plan.js +0 -183
- package/clients/dispatch/runners/architect.js +0 -83
- package/clients/dispatch/runners/architect.test.js +0 -138
- package/clients/dispatch/runners/architect.test.ts +0 -162
- package/clients/dispatch/runners/ast-grep-napi.js +0 -405
- package/clients/dispatch/runners/ast-grep-napi.test.js +0 -107
- package/clients/dispatch/runners/ast-grep-napi.test.ts +0 -129
- package/clients/dispatch/runners/ast-grep.js +0 -157
- package/clients/dispatch/runners/biome.js +0 -55
- package/clients/dispatch/runners/config-validation.js +0 -67
- package/clients/dispatch/runners/go-vet.js +0 -48
- package/clients/dispatch/runners/index.js +0 -47
- package/clients/dispatch/runners/lsp.js +0 -102
- package/clients/dispatch/runners/oxlint.js +0 -67
- package/clients/dispatch/runners/oxlint.test.js +0 -230
- package/clients/dispatch/runners/oxlint.test.ts +0 -303
- package/clients/dispatch/runners/pyright.js +0 -100
- package/clients/dispatch/runners/pyright.test.js +0 -98
- package/clients/dispatch/runners/pyright.test.ts +0 -121
- package/clients/dispatch/runners/python-slop.js +0 -97
- package/clients/dispatch/runners/python-slop.test.js +0 -203
- package/clients/dispatch/runners/python-slop.test.ts +0 -298
- package/clients/dispatch/runners/ruff.js +0 -48
- package/clients/dispatch/runners/rust-clippy.js +0 -102
- package/clients/dispatch/runners/scan_codebase.test.js +0 -89
- package/clients/dispatch/runners/scan_codebase.test.ts +0 -105
- package/clients/dispatch/runners/shellcheck.js +0 -147
- package/clients/dispatch/runners/shellcheck.test.js +0 -98
- package/clients/dispatch/runners/shellcheck.test.ts +0 -129
- package/clients/dispatch/runners/similarity.js +0 -230
- package/clients/dispatch/runners/spellcheck.js +0 -106
- package/clients/dispatch/runners/spellcheck.test.js +0 -158
- package/clients/dispatch/runners/spellcheck.test.ts +0 -214
- package/clients/dispatch/runners/tree-sitter.js +0 -246
- package/clients/dispatch/runners/ts-lsp.js +0 -125
- package/clients/dispatch/runners/ts-slop.js +0 -113
- package/clients/dispatch/runners/type-safety.js +0 -142
- package/clients/dispatch/runners/utils/diagnostic-parsers.js +0 -134
- package/clients/dispatch/runners/utils/runner-helpers.js +0 -115
- package/clients/dispatch/runners/utils.js +0 -51
- package/clients/dispatch/runners/yaml-rule-parser.js +0 -360
- package/clients/dispatch/types.js +0 -16
- package/clients/dispatch/utils/format-utils.js +0 -44
- package/clients/dogfood.test.js +0 -201
- package/clients/dogfood.test.ts +0 -269
- package/clients/file-kinds.js +0 -177
- package/clients/file-kinds.test.js +0 -169
- package/clients/file-kinds.test.ts +0 -210
- package/clients/file-time.js +0 -152
- package/clients/file-utils.js +0 -40
- package/clients/fix-scanners.js +0 -204
- package/clients/format-service.js +0 -184
- package/clients/formatters.js +0 -488
- package/clients/go-client.js +0 -203
- package/clients/go-client.test.js +0 -127
- package/clients/go-client.test.ts +0 -143
- package/clients/installer/index.js +0 -403
- package/clients/interviewer-templates.js +0 -75
- package/clients/interviewer.js +0 -173
- package/clients/jscpd-client.js +0 -196
- package/clients/jscpd-client.test.js +0 -127
- package/clients/jscpd-client.test.ts +0 -145
- package/clients/knip-client.js +0 -239
- package/clients/knip-client.test.js +0 -112
- package/clients/knip-client.test.ts +0 -128
- package/clients/latency-logger.js +0 -40
- package/clients/lsp/__tests__/client.test.js +0 -310
- package/clients/lsp/__tests__/client.test.ts +0 -412
- package/clients/lsp/__tests__/config.test.js +0 -167
- package/clients/lsp/__tests__/config.test.ts +0 -217
- package/clients/lsp/__tests__/error-recovery.test.js +0 -213
- package/clients/lsp/__tests__/error-recovery.test.ts +0 -279
- package/clients/lsp/__tests__/integration.test.js +0 -127
- package/clients/lsp/__tests__/integration.test.ts +0 -160
- package/clients/lsp/__tests__/launch.test.js +0 -313
- package/clients/lsp/__tests__/launch.test.ts +0 -394
- package/clients/lsp/__tests__/server.test.js +0 -259
- package/clients/lsp/__tests__/server.test.ts +0 -332
- package/clients/lsp/__tests__/service.test.js +0 -438
- package/clients/lsp/__tests__/service.test.ts +0 -530
- package/clients/lsp/client.js +0 -350
- package/clients/lsp/config.js +0 -112
- package/clients/lsp/index.js +0 -318
- package/clients/lsp/installer/index.js +0 -391
- package/clients/lsp/interactive-install.js +0 -221
- package/clients/lsp/language.js +0 -170
- package/clients/lsp/launch.js +0 -329
- package/clients/lsp/lsp/launch.js +0 -116
- package/clients/lsp/lsp/server.js +0 -532
- package/clients/lsp/lsp-index.js +0 -10
- package/clients/lsp/path-utils.js +0 -5
- package/clients/lsp/server.js +0 -725
- package/clients/lsp/test-py-spawn/requirements.txt +0 -1
- package/clients/lsp/test-py-spawn/test.py +0 -3
- package/clients/lsp/test-py-svc/requirements.txt +0 -1
- package/clients/lsp/test-py-svc/test.py +0 -3
- package/clients/lsp/test-python-project/requirements.txt +0 -1
- package/clients/lsp/test-python-project/test.py +0 -5
- package/clients/metrics-client.js +0 -107
- package/clients/metrics-client.test.js +0 -128
- package/clients/metrics-client.test.ts +0 -163
- package/clients/metrics-history.js +0 -367
- package/clients/path-utils.js +0 -142
- package/clients/pipeline.js +0 -272
- package/clients/production-readiness.js +0 -522
- package/clients/project-index.js +0 -255
- package/clients/project-metadata.js +0 -531
- package/clients/ruff-client.js +0 -325
- package/clients/ruff-client.test.js +0 -132
- package/clients/ruff-client.test.ts +0 -153
- package/clients/rules-scanner.js +0 -97
- package/clients/runner-tracker.js +0 -152
- package/clients/rust-client.js +0 -205
- package/clients/rust-client.test.js +0 -108
- package/clients/rust-client.test.ts +0 -130
- package/clients/safe-spawn-async.js +0 -163
- package/clients/safe-spawn.js +0 -241
- package/clients/sanitize.js +0 -291
- package/clients/sanitize.test.js +0 -177
- package/clients/sanitize.test.ts +0 -223
- package/clients/scan-architectural-debt.js +0 -167
- package/clients/scan-utils.js +0 -83
- package/clients/secrets-scanner.js +0 -119
- package/clients/secrets-scanner.test.js +0 -100
- package/clients/secrets-scanner.test.ts +0 -113
- package/clients/sg-runner.js +0 -292
- package/clients/state-matrix.js +0 -160
- package/clients/subprocess-client.js +0 -65
- package/clients/symbol-types.js +0 -5
- package/clients/test-runner-client.js +0 -523
- package/clients/test-runner-client.test.js +0 -192
- package/clients/test-runner-client.test.ts +0 -253
- package/clients/test-utils.js +0 -27
- package/clients/test-utils.ts +0 -36
- package/clients/todo-scanner.js +0 -200
- package/clients/todo-scanner.test.js +0 -301
- package/clients/todo-scanner.test.ts +0 -352
- package/clients/tool-availability.js +0 -207
- package/clients/tree-sitter-client.js +0 -601
- package/clients/tree-sitter-query-loader.js +0 -355
- package/clients/tree-sitter-symbol-extractor.js +0 -289
- package/clients/ts-service.js +0 -129
- package/clients/type-coverage-client.js +0 -127
- package/clients/type-coverage-client.test.js +0 -105
- package/clients/type-coverage-client.test.ts +0 -125
- package/clients/type-safety-client.js +0 -138
- package/clients/types.js +0 -11
- package/clients/typescript-client.codefix.test.js +0 -157
- package/clients/typescript-client.codefix.test.ts +0 -186
- package/clients/typescript-client.js +0 -509
- package/clients/typescript-client.test.js +0 -105
- package/clients/typescript-client.test.ts +0 -126
- package/commands/booboo.js +0 -1007
- package/commands/fix-from-booboo.js +0 -398
- package/commands/fix-simplified.js +0 -618
- package/commands/rate.js +0 -281
- package/commands/rate.test.js +0 -119
- package/commands/rate.test.ts +0 -131
- package/commands/refactor.js +0 -130
|
@@ -1 +0,0 @@
|
|
|
1
|
-
# test
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
# test
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
# test
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Silent Metrics Client for pi-lens
|
|
3
|
-
*
|
|
4
|
-
* Tracks code quality metrics silently during the session.
|
|
5
|
-
* Metrics are aggregated and shown in session summary only.
|
|
6
|
-
*
|
|
7
|
-
* Tracks:
|
|
8
|
-
* - Code Entropy: Shannon entropy delta per file
|
|
9
|
-
*
|
|
10
|
-
* These are observational metrics — they inform the human in session summary,
|
|
11
|
-
* they don't gate or interrupt the agent mid-task.
|
|
12
|
-
*/
|
|
13
|
-
import * as fs from "node:fs";
|
|
14
|
-
import * as path from "node:path";
|
|
15
|
-
// --- Client ---
|
|
16
|
-
export class MetricsClient {
|
|
17
|
-
constructor(verbose = false) {
|
|
18
|
-
this.fileBaselines = new Map();
|
|
19
|
-
this.log = verbose
|
|
20
|
-
? (msg) => console.error(`[metrics] ${msg}`)
|
|
21
|
-
: () => { };
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Record initial state of a file when first touched this session
|
|
25
|
-
*/
|
|
26
|
-
recordBaseline(filePath) {
|
|
27
|
-
const absolutePath = path.resolve(filePath);
|
|
28
|
-
if (!fs.existsSync(absolutePath))
|
|
29
|
-
return;
|
|
30
|
-
if (this.fileBaselines.has(absolutePath))
|
|
31
|
-
return; // Already recorded
|
|
32
|
-
const content = fs.readFileSync(absolutePath, "utf-8");
|
|
33
|
-
const entropy = this.calculateEntropy(content);
|
|
34
|
-
this.fileBaselines.set(absolutePath, { content, entropy });
|
|
35
|
-
this.log(`Baseline recorded: ${path.basename(filePath)} (entropy: ${entropy.toFixed(2)})`);
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Get metrics for a specific file
|
|
39
|
-
*/
|
|
40
|
-
getFileMetrics(filePath) {
|
|
41
|
-
const absolutePath = path.resolve(filePath);
|
|
42
|
-
const baseline = this.fileBaselines.get(absolutePath);
|
|
43
|
-
if (!baseline)
|
|
44
|
-
return null;
|
|
45
|
-
if (!fs.existsSync(absolutePath))
|
|
46
|
-
return null;
|
|
47
|
-
const currentContent = fs.readFileSync(absolutePath, "utf-8");
|
|
48
|
-
const totalLines = currentContent.split("\n").length;
|
|
49
|
-
const entropyCurrent = this.calculateEntropy(currentContent);
|
|
50
|
-
const entropyDelta = entropyCurrent - baseline.entropy;
|
|
51
|
-
return {
|
|
52
|
-
filePath: path.relative(process.cwd(), absolutePath),
|
|
53
|
-
totalLines,
|
|
54
|
-
entropyStart: baseline.entropy,
|
|
55
|
-
entropyCurrent,
|
|
56
|
-
entropyDelta,
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Get entropy delta for all touched files
|
|
61
|
-
*/
|
|
62
|
-
getEntropyDeltas() {
|
|
63
|
-
const results = [];
|
|
64
|
-
for (const [filePath, baseline] of this.fileBaselines) {
|
|
65
|
-
if (!fs.existsSync(filePath))
|
|
66
|
-
continue;
|
|
67
|
-
const content = fs.readFileSync(filePath, "utf-8");
|
|
68
|
-
const current = this.calculateEntropy(content);
|
|
69
|
-
const delta = current - baseline.entropy;
|
|
70
|
-
results.push({
|
|
71
|
-
file: path.relative(process.cwd(), filePath),
|
|
72
|
-
start: baseline.entropy,
|
|
73
|
-
current,
|
|
74
|
-
delta,
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
return results.sort((a, b) => Math.abs(b.delta) - Math.abs(a.delta));
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Calculate Shannon entropy of a string
|
|
81
|
-
* Returns bits per character
|
|
82
|
-
*/
|
|
83
|
-
calculateEntropy(text) {
|
|
84
|
-
if (text.length === 0)
|
|
85
|
-
return 0;
|
|
86
|
-
const freq = new Map();
|
|
87
|
-
for (const char of text) {
|
|
88
|
-
freq.set(char, (freq.get(char) || 0) + 1);
|
|
89
|
-
}
|
|
90
|
-
let entropy = 0;
|
|
91
|
-
const len = text.length;
|
|
92
|
-
for (const count of freq.values()) {
|
|
93
|
-
const p = count / len;
|
|
94
|
-
if (p > 0) {
|
|
95
|
-
entropy -= p * Math.log2(p);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
return entropy;
|
|
99
|
-
}
|
|
100
|
-
/**
|
|
101
|
-
* Reset session state (for new session)
|
|
102
|
-
*/
|
|
103
|
-
reset() {
|
|
104
|
-
this.fileBaselines.clear();
|
|
105
|
-
this.log("Session metrics reset");
|
|
106
|
-
}
|
|
107
|
-
}
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import * as fs from "node:fs";
|
|
2
|
-
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
3
|
-
import { MetricsClient } from "./metrics-client.js";
|
|
4
|
-
import { createTempFile, setupTestEnvironment } from "./test-utils.js";
|
|
5
|
-
describe("MetricsClient", () => {
|
|
6
|
-
let client;
|
|
7
|
-
let tmpDir;
|
|
8
|
-
let cleanup;
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
client = new MetricsClient();
|
|
11
|
-
({ tmpDir, cleanup } = setupTestEnvironment("pi-lens-metrics-test-"));
|
|
12
|
-
});
|
|
13
|
-
afterEach(() => {
|
|
14
|
-
cleanup();
|
|
15
|
-
});
|
|
16
|
-
afterEach(() => {
|
|
17
|
-
cleanup();
|
|
18
|
-
});
|
|
19
|
-
describe("calculateEntropy", () => {
|
|
20
|
-
it("should return 0 for empty string", () => {
|
|
21
|
-
expect(client.calculateEntropy("")).toBe(0);
|
|
22
|
-
});
|
|
23
|
-
it("should return 0 for single repeated character", () => {
|
|
24
|
-
expect(client.calculateEntropy("aaaaaa")).toBe(0);
|
|
25
|
-
});
|
|
26
|
-
it("should return 1 for two equally likely characters", () => {
|
|
27
|
-
expect(client.calculateEntropy("ababab")).toBe(1);
|
|
28
|
-
});
|
|
29
|
-
it("should return higher entropy for more diverse content", () => {
|
|
30
|
-
const lowEntropy = "aaaaaaaaaaaaaaaaaaaaaaaaaa";
|
|
31
|
-
const highEntropy = "abcdefghijklmnopqrstuvwxyz";
|
|
32
|
-
expect(client.calculateEntropy(highEntropy)).toBeGreaterThan(client.calculateEntropy(lowEntropy));
|
|
33
|
-
});
|
|
34
|
-
it("should match expected Shannon entropy for known input", () => {
|
|
35
|
-
// "aabb" has p(a)=0.5, p(b)=0.5, entropy = -2*(0.5*log2(0.5)) = 1
|
|
36
|
-
expect(client.calculateEntropy("aabb")).toBeCloseTo(1, 5);
|
|
37
|
-
});
|
|
38
|
-
});
|
|
39
|
-
describe("recordBaseline", () => {
|
|
40
|
-
it("should record baseline for existing file", () => {
|
|
41
|
-
const content = "const x = 1;\nconst y = 2;";
|
|
42
|
-
const filePath = createTempFile(tmpDir, "test.ts", content);
|
|
43
|
-
client.recordBaseline(filePath);
|
|
44
|
-
const metrics = client.getFileMetrics(filePath);
|
|
45
|
-
expect(metrics).not.toBeNull();
|
|
46
|
-
expect(metrics?.totalLines).toBeGreaterThanOrEqual(2);
|
|
47
|
-
});
|
|
48
|
-
it("should not record baseline for non-existent file", () => {
|
|
49
|
-
client.recordBaseline("/nonexistent/file.ts");
|
|
50
|
-
// Should not throw, just silently skip
|
|
51
|
-
});
|
|
52
|
-
it("should not overwrite existing baseline", () => {
|
|
53
|
-
const content1 = "const x = 1;\n";
|
|
54
|
-
const content2 = "const x = 1;\nconst y = 2;\nconst z = 3;\n";
|
|
55
|
-
const filePath = createTempFile(tmpDir, "test.ts", content1);
|
|
56
|
-
client.recordBaseline(filePath);
|
|
57
|
-
// Modify file
|
|
58
|
-
fs.writeFileSync(filePath, content2);
|
|
59
|
-
// Record again - should not update baseline
|
|
60
|
-
client.recordBaseline(filePath);
|
|
61
|
-
const metrics = client.getFileMetrics(filePath);
|
|
62
|
-
expect(metrics?.entropyStart).toBe(client.calculateEntropy(content1));
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
describe("getFileMetrics", () => {
|
|
66
|
-
it("should return null for file without baseline", () => {
|
|
67
|
-
const filePath = createTempFile(tmpDir, "test.ts", "content");
|
|
68
|
-
// Don't record baseline
|
|
69
|
-
const metrics = client.getFileMetrics(filePath);
|
|
70
|
-
expect(metrics).toBeNull();
|
|
71
|
-
});
|
|
72
|
-
it("should track entropy changes", () => {
|
|
73
|
-
const simple = "const x = 1;\n";
|
|
74
|
-
const filePath = createTempFile(tmpDir, "test.ts", simple);
|
|
75
|
-
client.recordBaseline(filePath);
|
|
76
|
-
// Make file more complex
|
|
77
|
-
const complex = `
|
|
78
|
-
function complex(a: number, b: number, c: number): number {
|
|
79
|
-
if (a > 0) {
|
|
80
|
-
if (b > 0) {
|
|
81
|
-
if (c > 0) {
|
|
82
|
-
return a + b + c;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
return 0;
|
|
87
|
-
}
|
|
88
|
-
`;
|
|
89
|
-
fs.writeFileSync(filePath, complex);
|
|
90
|
-
const metrics = client.getFileMetrics(filePath);
|
|
91
|
-
expect(metrics?.entropyDelta).not.toBe(0);
|
|
92
|
-
});
|
|
93
|
-
});
|
|
94
|
-
describe("getEntropyDeltas", () => {
|
|
95
|
-
it("should track entropy changes for baselined files", () => {
|
|
96
|
-
const simple = "const x = 1;\n";
|
|
97
|
-
const filePath = createTempFile(tmpDir, "test.ts", simple);
|
|
98
|
-
client.recordBaseline(filePath);
|
|
99
|
-
// Make file more complex
|
|
100
|
-
const complex = `
|
|
101
|
-
function complex(a: number, b: number, c: number): number {
|
|
102
|
-
if (a > 0) {
|
|
103
|
-
if (b > 0) {
|
|
104
|
-
if (c > 0) {
|
|
105
|
-
return a + b + c;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
return 0;
|
|
110
|
-
}
|
|
111
|
-
`;
|
|
112
|
-
fs.writeFileSync(filePath, complex);
|
|
113
|
-
const deltas = client.getEntropyDeltas();
|
|
114
|
-
expect(deltas.length).toBe(1);
|
|
115
|
-
expect(deltas[0].delta).not.toBe(0);
|
|
116
|
-
});
|
|
117
|
-
});
|
|
118
|
-
describe("reset", () => {
|
|
119
|
-
it("should clear all tracked data", () => {
|
|
120
|
-
const filePath = createTempFile(tmpDir, "test.ts", "content\n");
|
|
121
|
-
client.recordBaseline(filePath);
|
|
122
|
-
client.reset();
|
|
123
|
-
// After reset, metrics should be null (baseline cleared)
|
|
124
|
-
const metrics = client.getFileMetrics(filePath);
|
|
125
|
-
expect(metrics).toBeNull();
|
|
126
|
-
});
|
|
127
|
-
});
|
|
128
|
-
});
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
import * as fs from "node:fs";
|
|
2
|
-
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
3
|
-
import { MetricsClient } from "./metrics-client.js";
|
|
4
|
-
import { createTempFile, setupTestEnvironment } from "./test-utils.js";
|
|
5
|
-
|
|
6
|
-
describe("MetricsClient", () => {
|
|
7
|
-
let client: MetricsClient;
|
|
8
|
-
let tmpDir: string;
|
|
9
|
-
let cleanup: () => void;
|
|
10
|
-
|
|
11
|
-
beforeEach(() => {
|
|
12
|
-
client = new MetricsClient();
|
|
13
|
-
({ tmpDir, cleanup } = setupTestEnvironment("pi-lens-metrics-test-"));
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
afterEach(() => {
|
|
17
|
-
cleanup();
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
afterEach(() => {
|
|
21
|
-
cleanup();
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
describe("calculateEntropy", () => {
|
|
25
|
-
it("should return 0 for empty string", () => {
|
|
26
|
-
expect(client.calculateEntropy("")).toBe(0);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it("should return 0 for single repeated character", () => {
|
|
30
|
-
expect(client.calculateEntropy("aaaaaa")).toBe(0);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it("should return 1 for two equally likely characters", () => {
|
|
34
|
-
expect(client.calculateEntropy("ababab")).toBe(1);
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it("should return higher entropy for more diverse content", () => {
|
|
38
|
-
const lowEntropy = "aaaaaaaaaaaaaaaaaaaaaaaaaa";
|
|
39
|
-
const highEntropy = "abcdefghijklmnopqrstuvwxyz";
|
|
40
|
-
|
|
41
|
-
expect(client.calculateEntropy(highEntropy)).toBeGreaterThan(
|
|
42
|
-
client.calculateEntropy(lowEntropy),
|
|
43
|
-
);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it("should match expected Shannon entropy for known input", () => {
|
|
47
|
-
// "aabb" has p(a)=0.5, p(b)=0.5, entropy = -2*(0.5*log2(0.5)) = 1
|
|
48
|
-
expect(client.calculateEntropy("aabb")).toBeCloseTo(1, 5);
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
describe("recordBaseline", () => {
|
|
53
|
-
it("should record baseline for existing file", () => {
|
|
54
|
-
const content = "const x = 1;\nconst y = 2;";
|
|
55
|
-
const filePath = createTempFile(tmpDir, "test.ts", content);
|
|
56
|
-
|
|
57
|
-
client.recordBaseline(filePath);
|
|
58
|
-
|
|
59
|
-
const metrics = client.getFileMetrics(filePath);
|
|
60
|
-
expect(metrics).not.toBeNull();
|
|
61
|
-
expect(metrics?.totalLines).toBeGreaterThanOrEqual(2);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
it("should not record baseline for non-existent file", () => {
|
|
65
|
-
client.recordBaseline("/nonexistent/file.ts");
|
|
66
|
-
|
|
67
|
-
// Should not throw, just silently skip
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it("should not overwrite existing baseline", () => {
|
|
71
|
-
const content1 = "const x = 1;\n";
|
|
72
|
-
const content2 = "const x = 1;\nconst y = 2;\nconst z = 3;\n";
|
|
73
|
-
const filePath = createTempFile(tmpDir, "test.ts", content1);
|
|
74
|
-
|
|
75
|
-
client.recordBaseline(filePath);
|
|
76
|
-
|
|
77
|
-
// Modify file
|
|
78
|
-
fs.writeFileSync(filePath, content2);
|
|
79
|
-
|
|
80
|
-
// Record again - should not update baseline
|
|
81
|
-
client.recordBaseline(filePath);
|
|
82
|
-
|
|
83
|
-
const metrics = client.getFileMetrics(filePath);
|
|
84
|
-
expect(metrics?.entropyStart).toBe(client.calculateEntropy(content1));
|
|
85
|
-
});
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
describe("getFileMetrics", () => {
|
|
89
|
-
it("should return null for file without baseline", () => {
|
|
90
|
-
const filePath = createTempFile(tmpDir, "test.ts", "content");
|
|
91
|
-
|
|
92
|
-
// Don't record baseline
|
|
93
|
-
const metrics = client.getFileMetrics(filePath);
|
|
94
|
-
expect(metrics).toBeNull();
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
it("should track entropy changes", () => {
|
|
98
|
-
const simple = "const x = 1;\n";
|
|
99
|
-
const filePath = createTempFile(tmpDir, "test.ts", simple);
|
|
100
|
-
|
|
101
|
-
client.recordBaseline(filePath);
|
|
102
|
-
|
|
103
|
-
// Make file more complex
|
|
104
|
-
const complex = `
|
|
105
|
-
function complex(a: number, b: number, c: number): number {
|
|
106
|
-
if (a > 0) {
|
|
107
|
-
if (b > 0) {
|
|
108
|
-
if (c > 0) {
|
|
109
|
-
return a + b + c;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
return 0;
|
|
114
|
-
}
|
|
115
|
-
`;
|
|
116
|
-
fs.writeFileSync(filePath, complex);
|
|
117
|
-
|
|
118
|
-
const metrics = client.getFileMetrics(filePath);
|
|
119
|
-
expect(metrics?.entropyDelta).not.toBe(0);
|
|
120
|
-
});
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
describe("getEntropyDeltas", () => {
|
|
124
|
-
it("should track entropy changes for baselined files", () => {
|
|
125
|
-
const simple = "const x = 1;\n";
|
|
126
|
-
const filePath = createTempFile(tmpDir, "test.ts", simple);
|
|
127
|
-
|
|
128
|
-
client.recordBaseline(filePath);
|
|
129
|
-
|
|
130
|
-
// Make file more complex
|
|
131
|
-
const complex = `
|
|
132
|
-
function complex(a: number, b: number, c: number): number {
|
|
133
|
-
if (a > 0) {
|
|
134
|
-
if (b > 0) {
|
|
135
|
-
if (c > 0) {
|
|
136
|
-
return a + b + c;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
return 0;
|
|
141
|
-
}
|
|
142
|
-
`;
|
|
143
|
-
fs.writeFileSync(filePath, complex);
|
|
144
|
-
|
|
145
|
-
const deltas = client.getEntropyDeltas();
|
|
146
|
-
expect(deltas.length).toBe(1);
|
|
147
|
-
expect(deltas[0].delta).not.toBe(0);
|
|
148
|
-
});
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
describe("reset", () => {
|
|
152
|
-
it("should clear all tracked data", () => {
|
|
153
|
-
const filePath = createTempFile(tmpDir, "test.ts", "content\n");
|
|
154
|
-
client.recordBaseline(filePath);
|
|
155
|
-
|
|
156
|
-
client.reset();
|
|
157
|
-
|
|
158
|
-
// After reset, metrics should be null (baseline cleared)
|
|
159
|
-
const metrics = client.getFileMetrics(filePath);
|
|
160
|
-
expect(metrics).toBeNull();
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
|
-
});
|