@kevinbermudezc/context-guard 1.0.1 → 1.1.1
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/README.md +70 -32
- package/dist/bin/claude-hook.js +27 -3
- package/dist/bin/claude-hook.js.map +1 -1
- package/dist/src/file-classifier.d.ts +15 -0
- package/dist/src/file-classifier.d.ts.map +1 -0
- package/dist/src/file-classifier.js +101 -0
- package/dist/src/file-classifier.js.map +1 -0
- package/dist/src/import-collapser.d.ts +13 -0
- package/dist/src/import-collapser.d.ts.map +1 -0
- package/dist/src/import-collapser.js +112 -0
- package/dist/src/import-collapser.js.map +1 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +26 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/skeletonizer.d.ts +2 -0
- package/dist/src/skeletonizer.d.ts.map +1 -1
- package/dist/src/skeletonizer.js +86 -7
- package/dist/src/skeletonizer.js.map +1 -1
- package/dist/src/types.d.ts +1 -1
- package/dist/src/types.d.ts.map +1 -1
- package/dist/tests/claude-hook.test.js +39 -9
- package/dist/tests/claude-hook.test.js.map +1 -1
- package/dist/tests/file-classifier.test.d.ts +2 -0
- package/dist/tests/file-classifier.test.d.ts.map +1 -0
- package/dist/tests/file-classifier.test.js +46 -0
- package/dist/tests/file-classifier.test.js.map +1 -0
- package/dist/tests/framework-sfc.test.d.ts +2 -0
- package/dist/tests/framework-sfc.test.d.ts.map +1 -0
- package/dist/tests/framework-sfc.test.js +151 -0
- package/dist/tests/framework-sfc.test.js.map +1 -0
- package/dist/tests/import-collapser.test.d.ts +2 -0
- package/dist/tests/import-collapser.test.d.ts.map +1 -0
- package/dist/tests/import-collapser.test.js +35 -0
- package/dist/tests/import-collapser.test.js.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -31,40 +31,78 @@ Frontier models are incredible at reasoning, but reading massive files (1,000+ l
|
|
|
31
31
|
|
|
32
32
|
## 🏗️ How ContextGuard Works
|
|
33
33
|
|
|
34
|
-
ContextGuard acts as an **admission turnstile** using Claude Code's native `PreToolUse` hook lifecycle:
|
|
34
|
+
ContextGuard acts as an **intelligent admission turnstile** using Claude Code's native `PreToolUse` hook lifecycle:
|
|
35
|
+
|
|
36
|
+
```mermaid
|
|
37
|
+
flowchart TD
|
|
38
|
+
A["🤖 <b>Claude Code / Agent Invocation</b><br><code>Read</code> or <code>cat file</code>"] --> B{"Is it an Image, PDF,<br>or Notebook (.ipynb)?"}
|
|
39
|
+
|
|
40
|
+
B -- "YES" --> E["✅ <b>ALLOW (Exit 0)</b><br>Claude Code native multimodal vision & viewer"]
|
|
41
|
+
|
|
42
|
+
B -- "NO" --> C{"Is it a Binary (wasm/zip/so),<br>Lockfile or Minified file?"}
|
|
43
|
+
|
|
44
|
+
C -- "YES" --> D["🛑 <b>TURNSTILE HARD BLOCK (Exit 2)</b><br>• Binary: Blocks wasm, zip, sqlite, binaries<br>• Lockfile: Suggests <code>pnpm why</code> / CLI<br>• Minified: Recommends <code>src/</code> source"]
|
|
45
|
+
|
|
46
|
+
C -- "NO" --> F{"File > 300 lines &<br>Un-scoped full read?"}
|
|
47
|
+
|
|
48
|
+
F -- "NO (Small or scoped range)" --> E
|
|
49
|
+
|
|
50
|
+
F -- "YES (Large un-scoped read)" --> G["🛡️ <b>CONTEXTGUARD SHUNT TRIGGER</b>"]
|
|
51
|
+
|
|
52
|
+
G --> H["<b>Tier 0: Local AST Skeletonizer</b><br>TS, JS, Python, Go, Rust, Java, C#<br>+ Svelte 5, Vue 3, Angular, Astro SFCs<br>• Collapses import walls (>5 imports)<br>• Cost: <b>$0.00</b> | Latency: <b>< 5ms</b>"]
|
|
53
|
+
G --> I["<b>Tier 1: Worker Model</b><br>Logs, JSON, Markdown, Docs<br>• Gemini 2.5 Flash / Local Ollama<br>• Cost: <b>~95% cheaper</b> than Frontier"]
|
|
54
|
+
|
|
55
|
+
H --> J["🛑 <b>HARD BLOCK (Exit Code 2)</b><br>Emits line-tagged skeleton <code>[L89]</code> to stderr"]
|
|
56
|
+
I --> J
|
|
57
|
+
|
|
58
|
+
J --> K["🎯 <b>Targeted Second Read</b><br>Claude reads feedback & fetches exact slice:<br><code>Read(file, offset=89, limit=35)</code><br><b>Tokens saved: 95% - 99%</b>"]
|
|
59
|
+
|
|
60
|
+
classDef block fill:#ef4444,stroke:#991b1b,stroke-width:2px,color:#fff;
|
|
61
|
+
classDef allow fill:#22c55e,stroke:#15803d,stroke-width:2px,color:#fff;
|
|
62
|
+
classDef trigger fill:#3b82f6,stroke:#1d4ed8,stroke-width:2px,color:#fff;
|
|
63
|
+
classDef tier fill:#6366f1,stroke:#4338ca,stroke-width:2px,color:#fff;
|
|
64
|
+
classDef action fill:#10b981,stroke:#047857,stroke-width:2px,color:#fff;
|
|
65
|
+
|
|
66
|
+
class D,J block;
|
|
67
|
+
class E allow;
|
|
68
|
+
class G trigger;
|
|
69
|
+
class H,I tier;
|
|
70
|
+
class K action;
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
35
74
|
|
|
75
|
+
## 💡 Real-World Use Case: Before vs. After
|
|
76
|
+
|
|
77
|
+
Imagine Claude Code needs to inspect how refund errors are handled in `src/payment-gateway.ts`, a 1,500-line service file with 28 imports and several auxiliary database queries.
|
|
78
|
+
|
|
79
|
+
### ❌ Without ContextGuard (Standard Behavior)
|
|
80
|
+
```text
|
|
81
|
+
1. Claude Code executes: Read("src/payment-gateway.ts")
|
|
82
|
+
└── ❌ Dumps all 1,500 lines into the frontier reasoning context
|
|
83
|
+
├── Tokens burned: ~8,500 tokens (~$0.13 in Claude Opus for a single read)
|
|
84
|
+
├── Context window saturated with 28 repetitive imports & unrelated schema logic
|
|
85
|
+
└── High risk of "Lost in the Middle" attention degradation and hallucinations
|
|
36
86
|
```
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
• Cost: $0.00 • Gemini Flash / Ollama
|
|
57
|
-
• Latency: < 5ms • Cost: ~95% cheaper
|
|
58
|
-
│ │
|
|
59
|
-
└────────────┬────────────┘
|
|
60
|
-
│
|
|
61
|
-
▼
|
|
62
|
-
[HARD BLOCK: Exit 2]
|
|
63
|
-
Emits signature skeleton with [L120] line tags to stderr
|
|
64
|
-
│
|
|
65
|
-
▼
|
|
66
|
-
Claude receives system feedback & requests
|
|
67
|
-
the exact slice needed (e.g. offset=130, limit=40)
|
|
87
|
+
|
|
88
|
+
### ✅ With ContextGuard (Context Shield Active)
|
|
89
|
+
```text
|
|
90
|
+
1. Claude Code executes: Read("src/payment-gateway.ts")
|
|
91
|
+
└── 🛡️ ContextGuard intercepts in <15ms and aborts with Exit Code 2:
|
|
92
|
+
🛑 [CONTEXTGUARD: READ BLOCKED (1,500 LINES)]
|
|
93
|
+
[L1-L32] 📦 28 imports collapsed (12 packages: @stripe/stripe-node, express...; 16 local).
|
|
94
|
+
[L45] export class PaymentGatewayService
|
|
95
|
+
[L52] constructor(private stripe: Stripe, private db: Database)
|
|
96
|
+
[L89] async processRefund(chargeId: string, amount: number): Promise<RefundResult>
|
|
97
|
+
[L145] async verifyWebhookSignature(payload: Buffer, sig: string): boolean
|
|
98
|
+
👉 Please request a targeted range using offset and limit.
|
|
99
|
+
|
|
100
|
+
2. Claude Code parses the structural skeleton and executes:
|
|
101
|
+
Read("src/payment-gateway.ts", offset=89, limit=35)
|
|
102
|
+
└── ✅ Allowed immediately!
|
|
103
|
+
├── Tokens consumed: ~160 tokens (instead of 8,500)
|
|
104
|
+
├── Savings: 98% token reduction and cost down to < $0.002
|
|
105
|
+
└── Razor-sharp attention, pinpoint accuracy, and zero hallucinations
|
|
68
106
|
```
|
|
69
107
|
|
|
70
108
|
---
|
package/dist/bin/claude-hook.js
CHANGED
|
@@ -10,6 +10,7 @@ import fs from 'node:fs';
|
|
|
10
10
|
import path from 'node:path';
|
|
11
11
|
import { CONFIG } from '../src/config.js';
|
|
12
12
|
import { extractCodeSkeleton } from '../src/skeletonizer.js';
|
|
13
|
+
import { classifyFile } from '../src/file-classifier.js';
|
|
13
14
|
async function runHook() {
|
|
14
15
|
const inputChunks = [];
|
|
15
16
|
for await (const chunk of process.stdin) {
|
|
@@ -34,11 +35,12 @@ async function runHook() {
|
|
|
34
35
|
if (isReadTool) {
|
|
35
36
|
const rawPath = toolInput.file_path || toolInput.path || toolInput.filePath || toolInput.AbsolutePath;
|
|
36
37
|
targetFilePath = typeof rawPath === 'string' ? rawPath : null;
|
|
37
|
-
// Check if Claude specified line bounds
|
|
38
|
+
// Check if Claude specified line bounds or page ranges (e.g. for PDFs)
|
|
38
39
|
if (toolInput.offset !== undefined ||
|
|
39
40
|
toolInput.limit !== undefined ||
|
|
40
41
|
toolInput.StartLine !== undefined ||
|
|
41
|
-
toolInput.EndLine !== undefined
|
|
42
|
+
toolInput.EndLine !== undefined ||
|
|
43
|
+
toolInput.pages !== undefined) {
|
|
42
44
|
isScoped = true;
|
|
43
45
|
}
|
|
44
46
|
}
|
|
@@ -62,11 +64,33 @@ async function runHook() {
|
|
|
62
64
|
if (!fs.existsSync(resolvedPath) || fs.statSync(resolvedPath).isDirectory()) {
|
|
63
65
|
process.exit(0);
|
|
64
66
|
}
|
|
67
|
+
const ext = path.extname(resolvedPath).toLowerCase();
|
|
68
|
+
// 3. Allow Claude Code native multimodal formats & notebooks (.png, .jpg, .pdf, .ipynb)
|
|
69
|
+
// Claude Code's Read tool natively renders images for multimodal vision, parses PDFs, and formats notebooks.
|
|
70
|
+
const CLAUDE_NATIVE_MEDIA_EXTENSIONS = new Set([
|
|
71
|
+
'.png', '.jpg', '.jpeg', '.gif', '.webp', '.svg', '.ico', '.bmp', '.avif',
|
|
72
|
+
'.pdf',
|
|
73
|
+
'.ipynb'
|
|
74
|
+
]);
|
|
75
|
+
if (CLAUDE_NATIVE_MEDIA_EXTENSIONS.has(ext)) {
|
|
76
|
+
process.exit(0); // Exit 0 = ALLOW Claude native vision & viewer
|
|
77
|
+
}
|
|
78
|
+
// 4. Check for Non-Multimodal Binaries, Lockfiles, and Minified files
|
|
79
|
+
const classification = classifyFile(resolvedPath);
|
|
80
|
+
if (classification.category !== 'source_code') {
|
|
81
|
+
const feedback = [
|
|
82
|
+
`🛑 [CONTEXTGUARD: ACCESO DENEGADO - ${classification.category.toUpperCase()}]`,
|
|
83
|
+
classification.reason,
|
|
84
|
+
``,
|
|
85
|
+
`👉 ${classification.recommendedAction}`
|
|
86
|
+
].join('\n');
|
|
87
|
+
process.stderr.write(feedback + '\n');
|
|
88
|
+
process.exit(2);
|
|
89
|
+
}
|
|
65
90
|
const stat = fs.statSync(resolvedPath);
|
|
66
91
|
const rawContent = fs.readFileSync(resolvedPath, 'utf-8');
|
|
67
92
|
const lines = rawContent.split('\n');
|
|
68
93
|
const totalLines = lines.length;
|
|
69
|
-
const ext = path.extname(resolvedPath);
|
|
70
94
|
// If within safety thresholds, allow direct read
|
|
71
95
|
if (totalLines <= CONFIG.maxLines && stat.size <= CONFIG.maxBytes) {
|
|
72
96
|
process.exit(0); // Exit 0 = ALLOW
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-hook.js","sourceRoot":"","sources":["../../bin/claude-hook.ts"],"names":[],"mappings":";AAEA;;;;;;GAMG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"claude-hook.js","sourceRoot":"","sources":["../../bin/claude-hook.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type FileCategory = 'binary' | 'lockfile' | 'minified' | 'source_code';
|
|
2
|
+
export interface FileClassification {
|
|
3
|
+
category: FileCategory;
|
|
4
|
+
reason?: string;
|
|
5
|
+
recommendedAction?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Inspects magic bytes (first 512 bytes) to detect binary contents
|
|
9
|
+
*/
|
|
10
|
+
export declare function isBinaryBuffer(buffer: Buffer): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Classifies a file to determine if it should be shunted, blocked, or parsed
|
|
13
|
+
*/
|
|
14
|
+
export declare function classifyFile(filePath: string): FileClassification;
|
|
15
|
+
//# sourceMappingURL=file-classifier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-classifier.d.ts","sourceRoot":"","sources":["../../src/file-classifier.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,UAAU,GAAG,UAAU,GAAG,aAAa,CAAC;AAE9E,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,YAAY,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AA0BD;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAmBtD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,CAuDjE"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
const BINARY_EXTENSIONS = new Set([
|
|
4
|
+
// Images
|
|
5
|
+
'.png', '.jpg', '.jpeg', '.gif', '.webp', '.ico', '.bmp', '.tiff', '.avif',
|
|
6
|
+
// Documents & Media
|
|
7
|
+
'.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx', '.mp3', '.mp4', '.mov', '.avi',
|
|
8
|
+
// Fonts & Binaries
|
|
9
|
+
'.woff', '.woff2', '.ttf', '.otf', '.eot',
|
|
10
|
+
'.wasm', '.dylib', '.so', '.dll', '.exe', '.bin', '.obj', '.o',
|
|
11
|
+
// Archives & Databases
|
|
12
|
+
'.zip', '.tar', '.gz', '.7z', '.rar', '.bz2', '.sqlite', '.sqlite3', '.db'
|
|
13
|
+
]);
|
|
14
|
+
const LOCKFILES = new Set([
|
|
15
|
+
'pnpm-lock.yaml',
|
|
16
|
+
'package-lock.json',
|
|
17
|
+
'yarn.lock',
|
|
18
|
+
'cargo.lock',
|
|
19
|
+
'composer.lock',
|
|
20
|
+
'gemfile.lock',
|
|
21
|
+
'poetry.lock',
|
|
22
|
+
'bun.lockb',
|
|
23
|
+
'bun.lock'
|
|
24
|
+
]);
|
|
25
|
+
/**
|
|
26
|
+
* Inspects magic bytes (first 512 bytes) to detect binary contents
|
|
27
|
+
*/
|
|
28
|
+
export function isBinaryBuffer(buffer) {
|
|
29
|
+
const checkLen = Math.min(buffer.length, 512);
|
|
30
|
+
if (checkLen === 0)
|
|
31
|
+
return false;
|
|
32
|
+
let nonPrintableCount = 0;
|
|
33
|
+
for (let i = 0; i < checkLen; i++) {
|
|
34
|
+
const byte = buffer[i];
|
|
35
|
+
// Check for null bytes (typical of binary data)
|
|
36
|
+
if (byte === 0) {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
// Byte values below 32 (except common whitespace: \t, \n, \r) or above 126
|
|
40
|
+
if ((byte < 7 || (byte > 13 && byte < 32)) && byte !== 27) {
|
|
41
|
+
nonPrintableCount++;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// If > 25% of bytes are non-printable control characters, consider it binary
|
|
45
|
+
return nonPrintableCount / checkLen > 0.25;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Classifies a file to determine if it should be shunted, blocked, or parsed
|
|
49
|
+
*/
|
|
50
|
+
export function classifyFile(filePath) {
|
|
51
|
+
const fileName = path.basename(filePath).toLowerCase();
|
|
52
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
53
|
+
// 1. Check for Lockfiles
|
|
54
|
+
if (LOCKFILES.has(fileName)) {
|
|
55
|
+
return {
|
|
56
|
+
category: 'lockfile',
|
|
57
|
+
reason: `El archivo "${path.basename(filePath)}" es un lockfile de dependencias.`,
|
|
58
|
+
recommendedAction: `No leas el lockfile crudo. Usa comandos de introspección como "pnpm why <paquete>" o "npm ls <paquete>".`
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
// 2. Check for Minified / Sourcemaps
|
|
62
|
+
if (fileName.endsWith('.min.js') || fileName.endsWith('.min.css') || fileName.endsWith('.bundle.js') || fileName.endsWith('.map')) {
|
|
63
|
+
return {
|
|
64
|
+
category: 'minified',
|
|
65
|
+
reason: `El archivo "${path.basename(filePath)}" está minificado o es un sourcemap.`,
|
|
66
|
+
recommendedAction: `Inspecciona los archivos originales de código fuente en "src/" en lugar del bundle empaquetado.`
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
// 3. Check for Binary Extensions
|
|
70
|
+
if (BINARY_EXTENSIONS.has(ext)) {
|
|
71
|
+
const isDoc = ext === '.pdf' || ext.startsWith('.doc') || ext.startsWith('.xls');
|
|
72
|
+
return {
|
|
73
|
+
category: 'binary',
|
|
74
|
+
reason: `El archivo "${path.basename(filePath)}" es un recurso binario (${ext}).`,
|
|
75
|
+
recommendedAction: isDoc
|
|
76
|
+
? `Usa herramientas como "pdftotext" o lectores de documentos para extraer texto plano.`
|
|
77
|
+
: `Los archivos multimedia y binarios no deben volcarse como texto. Usa herramientas de visión multimodal o comandos de sistema.`
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
// 4. Inspect buffer if file exists
|
|
81
|
+
try {
|
|
82
|
+
const fd = fs.openSync(filePath, 'r');
|
|
83
|
+
const buffer = Buffer.alloc(512);
|
|
84
|
+
const bytesRead = fs.readSync(fd, buffer, 0, 512, 0);
|
|
85
|
+
fs.closeSync(fd);
|
|
86
|
+
if (isBinaryBuffer(buffer.subarray(0, bytesRead))) {
|
|
87
|
+
return {
|
|
88
|
+
category: 'binary',
|
|
89
|
+
reason: `El archivo "${path.basename(filePath)}" contiene bytes binarios o caracteres nulos.`,
|
|
90
|
+
recommendedAction: `No intentes leer archivos binarios como texto plano.`
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
// If unable to open or read header, proceed with fallback
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
category: 'source_code'
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=file-classifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-classifier.js","sourceRoot":"","sources":["../../src/file-classifier.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface CollapsedImportResult {
|
|
2
|
+
hasCollapsed: boolean;
|
|
3
|
+
lines: string[];
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Checks if a line is an import statement
|
|
7
|
+
*/
|
|
8
|
+
export declare function isImportLine(line: string, ext: string): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Processes a collection of lines, collapsing import walls exceeding threshold
|
|
11
|
+
*/
|
|
12
|
+
export declare function collapseImportWall(rawLines: string[], ext: string, maxThreshold?: number): CollapsedImportResult;
|
|
13
|
+
//# sourceMappingURL=import-collapser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-collapser.d.ts","sourceRoot":"","sources":["../../src/import-collapser.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,qBAAqB;IACpC,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AA0CD;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAiB/D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,GAAE,MAAU,GAAG,qBAAqB,CAkEnH"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses import source from JS/TS and Python statements
|
|
3
|
+
*/
|
|
4
|
+
function extractImportSource(line) {
|
|
5
|
+
const trimmed = line.trim();
|
|
6
|
+
// TypeScript / JavaScript: import ... from 'source' or import 'source'
|
|
7
|
+
const tsMatch = trimmed.match(/from\s+['"]([^'"]+)['"]/);
|
|
8
|
+
if (tsMatch) {
|
|
9
|
+
const src = tsMatch[1];
|
|
10
|
+
return { source: src, isExternal: !src.startsWith('.') };
|
|
11
|
+
}
|
|
12
|
+
const tsBareMatch = trimmed.match(/^import\s+['"]([^'"]+)['"]/);
|
|
13
|
+
if (tsBareMatch) {
|
|
14
|
+
const src = tsBareMatch[1];
|
|
15
|
+
return { source: src, isExternal: !src.startsWith('.') };
|
|
16
|
+
}
|
|
17
|
+
// Python: from module import ... or import module
|
|
18
|
+
const pyFromMatch = trimmed.match(/^from\s+([A-Za-z0-9_.]+)\s+import/);
|
|
19
|
+
if (pyFromMatch) {
|
|
20
|
+
const src = pyFromMatch[1];
|
|
21
|
+
return { source: src, isExternal: !src.startsWith('.') };
|
|
22
|
+
}
|
|
23
|
+
const pyImportMatch = trimmed.match(/^import\s+([A-Za-z0-9_.]+)/);
|
|
24
|
+
if (pyImportMatch) {
|
|
25
|
+
const src = pyImportMatch[1];
|
|
26
|
+
return { source: src, isExternal: !src.startsWith('.') };
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Checks if a line is an import statement
|
|
32
|
+
*/
|
|
33
|
+
export function isImportLine(line, ext) {
|
|
34
|
+
const trimmed = line.trim();
|
|
35
|
+
const normalized = ext.toLowerCase().replace(/^\./, '');
|
|
36
|
+
if (['ts', 'tsx', 'js', 'jsx', 'mjs', 'cjs', 'svelte', 'vue', 'astro'].includes(normalized)) {
|
|
37
|
+
return trimmed.startsWith('import ') || trimmed.startsWith('import{') || /^const\s+.*\s*=\s*require\(/.test(trimmed);
|
|
38
|
+
}
|
|
39
|
+
if (normalized === 'py') {
|
|
40
|
+
return trimmed.startsWith('import ') || trimmed.startsWith('from ');
|
|
41
|
+
}
|
|
42
|
+
if (normalized === 'go') {
|
|
43
|
+
return trimmed.startsWith('import ') || trimmed.startsWith('import (');
|
|
44
|
+
}
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Processes a collection of lines, collapsing import walls exceeding threshold
|
|
49
|
+
*/
|
|
50
|
+
export function collapseImportWall(rawLines, ext, maxThreshold = 5) {
|
|
51
|
+
const imports = [];
|
|
52
|
+
const otherLines = [];
|
|
53
|
+
rawLines.forEach((line, index) => {
|
|
54
|
+
const lineNum = index + 1;
|
|
55
|
+
if (isImportLine(line, ext)) {
|
|
56
|
+
const parsed = extractImportSource(line) || { source: '', isExternal: true };
|
|
57
|
+
imports.push({
|
|
58
|
+
lineNum,
|
|
59
|
+
rawText: line.trim(),
|
|
60
|
+
source: parsed.source,
|
|
61
|
+
isExternal: parsed.isExternal
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
otherLines.push({ lineNum, text: line });
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
// If imports are below or equal to threshold, keep them intact
|
|
69
|
+
if (imports.length <= maxThreshold) {
|
|
70
|
+
return {
|
|
71
|
+
hasCollapsed: false,
|
|
72
|
+
lines: rawLines
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
// Extract unique external and local package names
|
|
76
|
+
const externalPkgs = new Set();
|
|
77
|
+
const localModules = new Set();
|
|
78
|
+
imports.forEach((imp) => {
|
|
79
|
+
if (!imp.source)
|
|
80
|
+
return;
|
|
81
|
+
if (imp.isExternal) {
|
|
82
|
+
// For scoped packages like @angular/core, grab full package name
|
|
83
|
+
const parts = imp.source.split('/');
|
|
84
|
+
const pkg = imp.source.startsWith('@') ? `${parts[0]}/${parts[1] || ''}` : parts[0];
|
|
85
|
+
externalPkgs.add(pkg);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
const parts = imp.source.split('/');
|
|
89
|
+
const mod = parts.slice(0, 2).join('/');
|
|
90
|
+
localModules.add(mod);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
const startLine = imports[0].lineNum;
|
|
94
|
+
const endLine = imports[imports.length - 1].lineNum;
|
|
95
|
+
const extList = Array.from(externalPkgs).slice(0, 4).join(', ');
|
|
96
|
+
const locList = Array.from(localModules).slice(0, 3).join(', ');
|
|
97
|
+
const summaryParts = [];
|
|
98
|
+
if (extList)
|
|
99
|
+
summaryParts.push(`Dependencias: ${extList}${externalPkgs.size > 4 ? '...' : ''}`);
|
|
100
|
+
if (locList)
|
|
101
|
+
summaryParts.push(`Locales: ${locList}${localModules.size > 3 ? '...' : ''}`);
|
|
102
|
+
const details = summaryParts.length > 0 ? ` (${summaryParts.join(' | ')})` : '';
|
|
103
|
+
const collapsedBanner = [
|
|
104
|
+
`[L${startLine}-L${endLine}] 📦 ${imports.length} imports colapsados${details}`,
|
|
105
|
+
`👉 Tip: Si necesitas ver todas las dependencias, corre Read(offset=${startLine}, limit=${endLine - startLine + 1})`
|
|
106
|
+
].join('\n');
|
|
107
|
+
return {
|
|
108
|
+
hasCollapsed: true,
|
|
109
|
+
lines: [collapsedBanner]
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=import-collapser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-collapser.js","sourceRoot":"","sources":["../../src/import-collapser.ts"],"names":[],"mappings":"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"}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ export * from './types.js';
|
|
|
3
3
|
export * from './config.js';
|
|
4
4
|
export * from './skeletonizer.js';
|
|
5
5
|
export * from './worker-model.js';
|
|
6
|
+
export * from './file-classifier.js';
|
|
7
|
+
export * from './import-collapser.js';
|
|
6
8
|
/**
|
|
7
9
|
* Main engine of ContextGuard
|
|
8
10
|
* Evaluates file size and either passes it through or shunts it to an AST/Worker summary.
|
package/dist/src/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAExE,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AAEtC;;;GAGG;AACH,wBAAsB,uBAAuB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA4HrG"}
|
package/dist/src/index.js
CHANGED
|
@@ -3,10 +3,13 @@ import path from 'node:path';
|
|
|
3
3
|
import { CONFIG } from './config.js';
|
|
4
4
|
import { extractCodeSkeleton } from './skeletonizer.js';
|
|
5
5
|
import { callWorkerModel } from './worker-model.js';
|
|
6
|
+
import { classifyFile } from './file-classifier.js';
|
|
6
7
|
export * from './types.js';
|
|
7
8
|
export * from './config.js';
|
|
8
9
|
export * from './skeletonizer.js';
|
|
9
10
|
export * from './worker-model.js';
|
|
11
|
+
export * from './file-classifier.js';
|
|
12
|
+
export * from './import-collapser.js';
|
|
10
13
|
/**
|
|
11
14
|
* Main engine of ContextGuard
|
|
12
15
|
* Evaluates file size and either passes it through or shunts it to an AST/Worker summary.
|
|
@@ -21,6 +24,29 @@ export async function processWithContextGuard(options) {
|
|
|
21
24
|
content: ''
|
|
22
25
|
};
|
|
23
26
|
}
|
|
27
|
+
// 1. Check for Binaries, Lockfiles, and Minified files
|
|
28
|
+
const classification = classifyFile(resolved);
|
|
29
|
+
if (classification.category === 'binary') {
|
|
30
|
+
return {
|
|
31
|
+
status: 'BLOCKED_BINARY',
|
|
32
|
+
reason: classification.reason,
|
|
33
|
+
content: `<!-- CONTEXTGUARD: ${classification.reason} -->\n<!-- ${classification.recommendedAction} -->`
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
if (classification.category === 'lockfile') {
|
|
37
|
+
return {
|
|
38
|
+
status: 'BLOCKED_LOCKFILE',
|
|
39
|
+
reason: classification.reason,
|
|
40
|
+
content: `<!-- CONTEXTGUARD: ${classification.reason} -->\n<!-- ${classification.recommendedAction} -->`
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
if (classification.category === 'minified') {
|
|
44
|
+
return {
|
|
45
|
+
status: 'BLOCKED_MINIFIED',
|
|
46
|
+
reason: classification.reason,
|
|
47
|
+
content: `<!-- CONTEXTGUARD: ${classification.reason} -->\n<!-- ${classification.recommendedAction} -->`
|
|
48
|
+
};
|
|
49
|
+
}
|
|
24
50
|
const stat = fs.statSync(resolved);
|
|
25
51
|
const rawContent = fs.readFileSync(resolved, 'utf-8');
|
|
26
52
|
const lines = rawContent.split('\n');
|
package/dist/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGpD,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tier 0 Structural Skeletonizer
|
|
3
3
|
* Extracts structural declarations, signatures, imports, and types with line numbers.
|
|
4
|
+
* Supports TypeScript, JavaScript, Python, Go, Rust, Java, C#, and
|
|
5
|
+
* Frontend Single File Components (Svelte, Vue, Angular, Astro).
|
|
4
6
|
* Cost: $0.00 | Execution: < 5ms
|
|
5
7
|
*/
|
|
6
8
|
export declare function isSupportedExtension(ext: string): string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skeletonizer.d.ts","sourceRoot":"","sources":["../../src/skeletonizer.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"skeletonizer.d.ts","sourceRoot":"","sources":["../../src/skeletonizer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA8DH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAa/D;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAoF/E"}
|
package/dist/src/skeletonizer.js
CHANGED
|
@@ -1,15 +1,45 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tier 0 Structural Skeletonizer
|
|
3
3
|
* Extracts structural declarations, signatures, imports, and types with line numbers.
|
|
4
|
+
* Supports TypeScript, JavaScript, Python, Go, Rust, Java, C#, and
|
|
5
|
+
* Frontend Single File Components (Svelte, Vue, Angular, Astro).
|
|
4
6
|
* Cost: $0.00 | Execution: < 5ms
|
|
5
7
|
*/
|
|
8
|
+
import { isImportLine, collapseImportWall } from './import-collapser.js';
|
|
6
9
|
const LANGUAGE_PATTERNS = {
|
|
7
|
-
// TypeScript &
|
|
10
|
+
// TypeScript, JavaScript & Angular
|
|
8
11
|
ts: [
|
|
9
12
|
/^(export\s+)?(default\s+)?(class|interface|type|enum)\s+([A-Za-z0-9_]+)/,
|
|
10
13
|
/^(export\s+)?(async\s+)?function\s+([A-Za-z0-9_]+)\s*\(/,
|
|
11
14
|
/^(export\s+)?const\s+([A-Za-z0-9_]+)\s*=\s*(async\s*)?\(/,
|
|
12
|
-
/^(export\s+)?((public|private|protected|static|async|\*)\s+)*([A-Za-z0-9_]+)\s*\([^)]*\)\s*[:{]
|
|
15
|
+
/^(export\s+)?((public|private|protected|static|async|readonly|\*)\s+)*([A-Za-z0-9_]+)\s*\([^)]*\)\s*[:{]/,
|
|
16
|
+
// Angular Decorators & Signals
|
|
17
|
+
/^@(Component|Injectable|Directive|Pipe|NgModule)\s*\(/,
|
|
18
|
+
/^@(Input|Output)\s*\(\s*\)\s+([A-Za-z0-9_]+)/,
|
|
19
|
+
/^(public|private|protected|readonly|\s+)*(readonly\s+)?([A-Za-z0-9_]+)\s*=\s*(input|output|model|computed|signal)(\.[A-Za-z0-9_]+)?\s*[\(<]/,
|
|
20
|
+
/^(ngOnInit|ngOnChanges|ngOnDestroy|ngAfterViewInit)\s*\(/
|
|
21
|
+
],
|
|
22
|
+
// Svelte Component Logic
|
|
23
|
+
svelte: [
|
|
24
|
+
/^(export\s+)?let\s+([A-Za-z0-9_]+)/,
|
|
25
|
+
/^(let|const)\s+([A-Za-z0-9_{}\s,]+)\s*=\s*\$(props|state|derived|effect)\s*\(/,
|
|
26
|
+
/^\$:\s+/,
|
|
27
|
+
/^(export\s+)?(async\s+)?function\s+([A-Za-z0-9_]+)\s*\(/,
|
|
28
|
+
/^(export\s+)?const\s+([A-Za-z0-9_]+)\s*=\s*(async\s*)?\(/
|
|
29
|
+
],
|
|
30
|
+
// Vue Component Logic
|
|
31
|
+
vue: [
|
|
32
|
+
/^(const|let)\s+([A-Za-z0-9_{}\s,]+)\s*=\s*(defineProps|defineEmits|defineModel)\s*[\(<]/,
|
|
33
|
+
/^(const|let)\s+([A-Za-z0-9_]+)\s*=\s*(ref|computed|reactive)\s*[\(<]/,
|
|
34
|
+
/^(export\s+)?(async\s+)?function\s+([A-Za-z0-9_]+)\s*\(/,
|
|
35
|
+
/^(export\s+)?const\s+([A-Za-z0-9_]+)\s*=\s*(async\s*)?\(/
|
|
36
|
+
],
|
|
37
|
+
// Astro Component Frontmatter
|
|
38
|
+
astro: [
|
|
39
|
+
/^(export\s+)?interface\s+Props/,
|
|
40
|
+
/^(const|let)\s+([A-Za-z0-9_{}\s,]+)\s*=\s*Astro\.props/,
|
|
41
|
+
/^(export\s+)?(async\s+)?function\s+([A-Za-z0-9_]+)\s*\(/,
|
|
42
|
+
/^(export\s+)?const\s+([A-Za-z0-9_]+)\s*=\s*(async\s*)?\(/
|
|
13
43
|
],
|
|
14
44
|
// Python
|
|
15
45
|
py: [
|
|
@@ -37,6 +67,9 @@ export function isSupportedExtension(ext) {
|
|
|
37
67
|
const normalized = ext.toLowerCase().replace(/^\./, '');
|
|
38
68
|
const mapping = {
|
|
39
69
|
ts: 'ts', tsx: 'ts', js: 'ts', jsx: 'ts', mjs: 'ts', cjs: 'ts',
|
|
70
|
+
svelte: 'svelte',
|
|
71
|
+
vue: 'vue',
|
|
72
|
+
astro: 'astro',
|
|
40
73
|
py: 'py',
|
|
41
74
|
go: 'go',
|
|
42
75
|
rs: 'rs',
|
|
@@ -51,26 +84,72 @@ export function extractCodeSkeleton(content, ext) {
|
|
|
51
84
|
const patterns = LANGUAGE_PATTERNS[langKey] || [];
|
|
52
85
|
const lines = content.split('\n');
|
|
53
86
|
const skeleton = [];
|
|
87
|
+
// Separate import lines and scan for style blocks
|
|
88
|
+
const importLines = [];
|
|
89
|
+
const bodyItems = [];
|
|
90
|
+
let insideStyleBlock = false;
|
|
91
|
+
let styleStartLine = 0;
|
|
92
|
+
let styleLineCount = 0;
|
|
54
93
|
lines.forEach((line, index) => {
|
|
55
94
|
const lineNum = index + 1;
|
|
56
95
|
const trimmed = line.trim();
|
|
96
|
+
// 1. Detect and collapse <style> blocks (Svelte / Vue)
|
|
97
|
+
if (trimmed.startsWith('<style') && !insideStyleBlock) {
|
|
98
|
+
insideStyleBlock = true;
|
|
99
|
+
styleStartLine = lineNum;
|
|
100
|
+
styleLineCount = 1;
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (insideStyleBlock) {
|
|
104
|
+
styleLineCount++;
|
|
105
|
+
if (trimmed.includes('</style>')) {
|
|
106
|
+
insideStyleBlock = false;
|
|
107
|
+
const styleEndLine = lineNum;
|
|
108
|
+
if (styleLineCount > 5) {
|
|
109
|
+
bodyItems.push({
|
|
110
|
+
lineNum: styleStartLine,
|
|
111
|
+
text: `[L${styleStartLine}-L${styleEndLine}] 🎨 ${styleLineCount} líneas de CSS colapsadas. Corre Read(offset=${styleStartLine}, limit=${styleLineCount}) si necesitas estilos.`
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
57
117
|
if (!trimmed || trimmed.startsWith('//') || trimmed.startsWith('#') || trimmed.startsWith('/*')) {
|
|
58
118
|
return;
|
|
59
119
|
}
|
|
60
|
-
//
|
|
61
|
-
if (
|
|
62
|
-
|
|
120
|
+
// 2. Check for imports
|
|
121
|
+
if (isImportLine(line, ext)) {
|
|
122
|
+
importLines.push(line);
|
|
63
123
|
return;
|
|
64
124
|
}
|
|
125
|
+
// 3. Match Structural Patterns
|
|
65
126
|
for (const pattern of patterns) {
|
|
66
127
|
if (pattern.test(trimmed)) {
|
|
67
|
-
// Strip trailing curly braces or semicolons for brevity
|
|
68
128
|
const clean = trimmed.replace(/\{\s*$/, '').trim();
|
|
69
|
-
|
|
129
|
+
bodyItems.push({ lineNum, text: `[L${lineNum}] ${clean}` });
|
|
70
130
|
break;
|
|
71
131
|
}
|
|
72
132
|
}
|
|
73
133
|
});
|
|
134
|
+
// 4. Process and collapse import statements
|
|
135
|
+
if (importLines.length > 0) {
|
|
136
|
+
const collapsed = collapseImportWall(importLines, ext, 5);
|
|
137
|
+
if (collapsed.hasCollapsed) {
|
|
138
|
+
skeleton.push(collapsed.lines[0]);
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
// If <= 5 imports, keep them as individual lines
|
|
142
|
+
importLines.forEach((impLine) => {
|
|
143
|
+
const originalIndex = lines.findIndex((l) => l.trim() === impLine.trim());
|
|
144
|
+
const lNum = originalIndex !== -1 ? originalIndex + 1 : 1;
|
|
145
|
+
skeleton.push(`[L${lNum}] ${impLine.trim()}`);
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// 5. Append body structural declarations
|
|
150
|
+
bodyItems.forEach((item) => {
|
|
151
|
+
skeleton.push(item.text);
|
|
152
|
+
});
|
|
74
153
|
return skeleton.length > 0 ? skeleton.join('\n') : null;
|
|
75
154
|
}
|
|
76
155
|
//# sourceMappingURL=skeletonizer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skeletonizer.js","sourceRoot":"","sources":["../../src/skeletonizer.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"skeletonizer.js","sourceRoot":"","sources":["../../src/skeletonizer.ts"],"names":[],"mappings":"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"}
|
package/dist/src/types.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ export interface ProcessFileOptions {
|
|
|
18
18
|
endLine?: number;
|
|
19
19
|
forceWorker?: boolean;
|
|
20
20
|
}
|
|
21
|
-
export type ProcessFileStatus = 'PASSTHROUGH_FULL' | 'PASSTHROUGH_SLICE' | 'SHUNTED_LOCAL_AST' | 'SHUNTED_WORKER_MODEL' | 'SHUNT_FALLBACK' | 'ERROR';
|
|
21
|
+
export type ProcessFileStatus = 'PASSTHROUGH_FULL' | 'PASSTHROUGH_SLICE' | 'SHUNTED_LOCAL_AST' | 'SHUNTED_WORKER_MODEL' | 'SHUNT_FALLBACK' | 'BLOCKED_BINARY' | 'BLOCKED_LOCKFILE' | 'BLOCKED_MINIFIED' | 'ERROR';
|
|
22
22
|
export interface ProcessFileResult {
|
|
23
23
|
status: ProcessFileStatus;
|
|
24
24
|
content: string;
|
package/dist/src/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,CAAC;AAEzE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,cAAc,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,MAAM,iBAAiB,GACzB,kBAAkB,GAClB,mBAAmB,GACnB,mBAAmB,GACnB,sBAAsB,GACtB,gBAAgB,GAChB,OAAO,CAAC;AAEZ,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,iBAAiB,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,KAAK,CAAC,EAAE,eAAe,CAAC;CACzB"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,CAAC;AAEzE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,cAAc,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,MAAM,iBAAiB,GACzB,kBAAkB,GAClB,mBAAmB,GACnB,mBAAmB,GACnB,sBAAsB,GACtB,gBAAgB,GAChB,gBAAgB,GAChB,kBAAkB,GAClB,kBAAkB,GAClB,OAAO,CAAC;AAEZ,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,iBAAiB,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,KAAK,CAAC,EAAE,eAAe,CAAC;CACzB"}
|
|
@@ -94,18 +94,48 @@ describe('Claude Code Hook PreToolUse End-to-End', () => {
|
|
|
94
94
|
assert.strictEqual(res.stderr, '');
|
|
95
95
|
fs.rmSync(tempDir, { recursive: true });
|
|
96
96
|
});
|
|
97
|
-
it('should
|
|
97
|
+
it('should allow reading native multimodal and notebook files (images, PDFs, ipynb) with Exit Code 0', async () => {
|
|
98
98
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'cg-hook-'));
|
|
99
|
-
const
|
|
100
|
-
fs.writeFileSync(
|
|
99
|
+
const imgFile = path.join(tempDir, 'screenshot.png');
|
|
100
|
+
fs.writeFileSync(imgFile, Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x00]));
|
|
101
|
+
const resImg = await runHookWithStdin({
|
|
102
|
+
tool_name: 'Read',
|
|
103
|
+
tool_input: { file_path: imgFile }
|
|
104
|
+
});
|
|
105
|
+
assert.strictEqual(resImg.exitCode, 0, 'Must allow image file for multimodal vision');
|
|
106
|
+
assert.strictEqual(resImg.stderr, '');
|
|
107
|
+
const pdfFile = path.join(tempDir, 'document.pdf');
|
|
108
|
+
fs.writeFileSync(pdfFile, '%PDF-1.4 ...');
|
|
109
|
+
const resPdf = await runHookWithStdin({
|
|
110
|
+
tool_name: 'Read',
|
|
111
|
+
tool_input: { file_path: pdfFile, pages: '1-3' }
|
|
112
|
+
});
|
|
113
|
+
assert.strictEqual(resPdf.exitCode, 0, 'Must allow scoped PDF read');
|
|
114
|
+
assert.strictEqual(resPdf.stderr, '');
|
|
115
|
+
fs.rmSync(tempDir, { recursive: true });
|
|
116
|
+
});
|
|
117
|
+
it('should block non-multimodal binary files like wasm, archives, or compiled binaries with Exit Code 2', async () => {
|
|
118
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'cg-hook-'));
|
|
119
|
+
const wasmFile = path.join(tempDir, 'module.wasm');
|
|
120
|
+
fs.writeFileSync(wasmFile, Buffer.from([0x00, 0x61, 0x73, 0x6d, 0x01]));
|
|
101
121
|
const res = await runHookWithStdin({
|
|
102
|
-
tool_name: '
|
|
103
|
-
tool_input: {
|
|
104
|
-
|
|
105
|
-
|
|
122
|
+
tool_name: 'Read',
|
|
123
|
+
tool_input: { file_path: wasmFile }
|
|
124
|
+
});
|
|
125
|
+
assert.strictEqual(res.exitCode, 2, 'Must block non-multimodal binary file with exit code 2');
|
|
126
|
+
assert.ok(res.stderr.includes('ACCESO DENEGADO - BINARY'), 'Must emit binary warning');
|
|
127
|
+
fs.rmSync(tempDir, { recursive: true });
|
|
128
|
+
});
|
|
129
|
+
it('should block reading lockfiles with Exit Code 2 and suggest CLI introspection', async () => {
|
|
130
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'cg-hook-'));
|
|
131
|
+
const lockFile = path.join(tempDir, 'pnpm-lock.yaml');
|
|
132
|
+
fs.writeFileSync(lockFile, 'lockfileVersion: 5.4\npackages:\n foo: 1.0.0');
|
|
133
|
+
const res = await runHookWithStdin({
|
|
134
|
+
tool_name: 'Read',
|
|
135
|
+
tool_input: { file_path: lockFile }
|
|
106
136
|
});
|
|
107
|
-
assert.strictEqual(res.exitCode, 2, 'Must block
|
|
108
|
-
assert.ok(res.stderr.includes('
|
|
137
|
+
assert.strictEqual(res.exitCode, 2, 'Must block lockfile with exit code 2');
|
|
138
|
+
assert.ok(res.stderr.includes('lockfile de dependencias'), 'Must advise using pnpm why');
|
|
109
139
|
fs.rmSync(tempDir, { recursive: true });
|
|
110
140
|
});
|
|
111
141
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-hook.test.js","sourceRoot":"","sources":["../../tests/claude-hook.test.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"claude-hook.test.js","sourceRoot":"","sources":["../../tests/claude-hook.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-classifier.test.d.ts","sourceRoot":"","sources":["../../tests/file-classifier.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { describe, it } from 'node:test';
|
|
2
|
+
import assert from 'node:assert';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import os from 'node:os';
|
|
6
|
+
import { classifyFile } from '../src/file-classifier.js';
|
|
7
|
+
describe('File Classifier (SPEC-002)', () => {
|
|
8
|
+
it('should detect binary image files by extension', () => {
|
|
9
|
+
const res = classifyFile('assets/logo.png');
|
|
10
|
+
assert.strictEqual(res.category, 'binary');
|
|
11
|
+
assert.ok(res.reason?.includes('.png'));
|
|
12
|
+
});
|
|
13
|
+
it('should detect PDF documents by extension and advise pdftotext', () => {
|
|
14
|
+
const res = classifyFile('docs/manual.pdf');
|
|
15
|
+
assert.strictEqual(res.category, 'binary');
|
|
16
|
+
assert.ok(res.recommendedAction?.includes('pdftotext'));
|
|
17
|
+
});
|
|
18
|
+
it('should detect lockfiles and suggest CLI commands', () => {
|
|
19
|
+
const pnpmRes = classifyFile('pnpm-lock.yaml');
|
|
20
|
+
assert.strictEqual(pnpmRes.category, 'lockfile');
|
|
21
|
+
assert.ok(pnpmRes.recommendedAction?.includes('pnpm why'));
|
|
22
|
+
const npmRes = classifyFile('package-lock.json');
|
|
23
|
+
assert.strictEqual(npmRes.category, 'lockfile');
|
|
24
|
+
assert.ok(npmRes.recommendedAction?.includes('npm ls'));
|
|
25
|
+
});
|
|
26
|
+
it('should detect minified files and recommend source inspection', () => {
|
|
27
|
+
const res = classifyFile('dist/bundle.min.js');
|
|
28
|
+
assert.strictEqual(res.category, 'minified');
|
|
29
|
+
assert.ok(res.recommendedAction?.includes('src/'));
|
|
30
|
+
});
|
|
31
|
+
it('should detect binary contents with null bytes via buffer scanner', () => {
|
|
32
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'cg-bin-'));
|
|
33
|
+
const tempFile = path.join(tempDir, 'unknown_data');
|
|
34
|
+
// Write buffer with null bytes
|
|
35
|
+
const buf = Buffer.from([0x00, 0x01, 0x02, 0x00, 0x7f, 0x80]);
|
|
36
|
+
fs.writeFileSync(tempFile, buf);
|
|
37
|
+
const res = classifyFile(tempFile);
|
|
38
|
+
assert.strictEqual(res.category, 'binary');
|
|
39
|
+
fs.rmSync(tempDir, { recursive: true });
|
|
40
|
+
});
|
|
41
|
+
it('should classify normal code files as source_code', () => {
|
|
42
|
+
const res = classifyFile('src/index.ts');
|
|
43
|
+
assert.strictEqual(res.category, 'source_code');
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
//# sourceMappingURL=file-classifier.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-classifier.test.js","sourceRoot":"","sources":["../../tests/file-classifier.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"framework-sfc.test.d.ts","sourceRoot":"","sources":["../../tests/framework-sfc.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { describe, it } from 'node:test';
|
|
2
|
+
import assert from 'node:assert';
|
|
3
|
+
import { extractCodeSkeleton } from '../src/skeletonizer.js';
|
|
4
|
+
describe('Frontend Frameworks & SFC Distillation (SPEC-002)', () => {
|
|
5
|
+
it('should distill Svelte components, extracting runes and collapsing styles', () => {
|
|
6
|
+
const svelteCode = `
|
|
7
|
+
<script lang="ts">
|
|
8
|
+
import { onMount } from 'svelte';
|
|
9
|
+
|
|
10
|
+
let { name, age } = $props();
|
|
11
|
+
let count = $state(0);
|
|
12
|
+
let double = $derived(count * 2);
|
|
13
|
+
|
|
14
|
+
function increment() {
|
|
15
|
+
count += 1;
|
|
16
|
+
}
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<main>
|
|
20
|
+
<h1>Hello {name}!</h1>
|
|
21
|
+
<button on:click={increment}>Count: {count}</button>
|
|
22
|
+
</main>
|
|
23
|
+
|
|
24
|
+
<style>
|
|
25
|
+
main {
|
|
26
|
+
text-align: center;
|
|
27
|
+
padding: 1em;
|
|
28
|
+
max-width: 240px;
|
|
29
|
+
margin: 0 auto;
|
|
30
|
+
color: red;
|
|
31
|
+
}
|
|
32
|
+
h1 {
|
|
33
|
+
color: #ff3e00;
|
|
34
|
+
text-transform: uppercase;
|
|
35
|
+
font-size: 4em;
|
|
36
|
+
font-weight: 100;
|
|
37
|
+
}
|
|
38
|
+
</style>
|
|
39
|
+
`.trim();
|
|
40
|
+
const skeleton = extractCodeSkeleton(svelteCode, '.svelte');
|
|
41
|
+
assert.ok(skeleton !== null);
|
|
42
|
+
if (!skeleton)
|
|
43
|
+
throw new Error('Skeleton is null');
|
|
44
|
+
assert.ok(skeleton.includes('$props()'));
|
|
45
|
+
assert.ok(skeleton.includes('$state(0)'));
|
|
46
|
+
assert.ok(skeleton.includes('$derived(count * 2)'));
|
|
47
|
+
assert.ok(skeleton.includes('function increment()'));
|
|
48
|
+
// Style block should be collapsed
|
|
49
|
+
assert.ok(skeleton.includes('🎨') && skeleton.includes('líneas de CSS colapsadas'));
|
|
50
|
+
});
|
|
51
|
+
it('should distill Vue components with script setup macros and collapse scoped styles', () => {
|
|
52
|
+
const vueCode = `
|
|
53
|
+
<script setup lang="ts">
|
|
54
|
+
import { ref, computed } from 'vue';
|
|
55
|
+
|
|
56
|
+
const props = defineProps<{ title: string }>();
|
|
57
|
+
const emit = defineEmits<['submit']>();
|
|
58
|
+
const active = ref(false);
|
|
59
|
+
const formattedTitle = computed(() => props.title.toUpperCase());
|
|
60
|
+
</script>
|
|
61
|
+
|
|
62
|
+
<template>
|
|
63
|
+
<div class="card">
|
|
64
|
+
<h2>{{ formattedTitle }}</h2>
|
|
65
|
+
</div>
|
|
66
|
+
</template>
|
|
67
|
+
|
|
68
|
+
<style scoped>
|
|
69
|
+
.card {
|
|
70
|
+
background: #fff;
|
|
71
|
+
border-radius: 8px;
|
|
72
|
+
padding: 16px;
|
|
73
|
+
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
74
|
+
}
|
|
75
|
+
h2 {
|
|
76
|
+
margin: 0;
|
|
77
|
+
font-size: 18px;
|
|
78
|
+
}
|
|
79
|
+
</style>
|
|
80
|
+
`.trim();
|
|
81
|
+
const skeleton = extractCodeSkeleton(vueCode, '.vue');
|
|
82
|
+
assert.ok(skeleton !== null);
|
|
83
|
+
if (!skeleton)
|
|
84
|
+
throw new Error('Skeleton is null');
|
|
85
|
+
assert.ok(skeleton.includes('defineProps'));
|
|
86
|
+
assert.ok(skeleton.includes('defineEmits'));
|
|
87
|
+
assert.ok(skeleton.includes('ref'));
|
|
88
|
+
assert.ok(skeleton.includes('computed'));
|
|
89
|
+
assert.ok(skeleton.includes('🎨') && skeleton.includes('CSS colapsadas'));
|
|
90
|
+
});
|
|
91
|
+
it('should distill Angular components with decorators and modern Signals', () => {
|
|
92
|
+
const angularCode = `
|
|
93
|
+
import { Component, input, output, signal } from '@angular/core';
|
|
94
|
+
|
|
95
|
+
@Component({
|
|
96
|
+
selector: 'app-user-badge',
|
|
97
|
+
templateUrl: './user-badge.component.html'
|
|
98
|
+
})
|
|
99
|
+
export class UserBadgeComponent {
|
|
100
|
+
readonly userId = input.required<string>();
|
|
101
|
+
readonly statusChanged = output<boolean>();
|
|
102
|
+
readonly isOnline = signal(false);
|
|
103
|
+
|
|
104
|
+
ngOnInit() {
|
|
105
|
+
console.log('init');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
public toggleStatus() {
|
|
109
|
+
this.isOnline.set(!this.isOnline());
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
`.trim();
|
|
113
|
+
const skeleton = extractCodeSkeleton(angularCode, '.ts');
|
|
114
|
+
assert.ok(skeleton !== null);
|
|
115
|
+
if (!skeleton)
|
|
116
|
+
throw new Error('Skeleton is null');
|
|
117
|
+
assert.ok(skeleton.includes('@Component'));
|
|
118
|
+
assert.ok(skeleton.includes('export class UserBadgeComponent'));
|
|
119
|
+
assert.ok(skeleton.includes('userId = input.required<string>()'));
|
|
120
|
+
assert.ok(skeleton.includes('statusChanged = output<boolean>()'));
|
|
121
|
+
assert.ok(skeleton.includes('isOnline = signal(false)'));
|
|
122
|
+
assert.ok(skeleton.includes('ngOnInit()'));
|
|
123
|
+
assert.ok(skeleton.includes('public toggleStatus()'));
|
|
124
|
+
});
|
|
125
|
+
it('should distill Astro components extracting frontmatter and props', () => {
|
|
126
|
+
const astroCode = `
|
|
127
|
+
---
|
|
128
|
+
import Header from '../components/Header.astro';
|
|
129
|
+
|
|
130
|
+
interface Props {
|
|
131
|
+
title: string;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const { title } = Astro.props;
|
|
135
|
+
---
|
|
136
|
+
<html lang="en">
|
|
137
|
+
<body>
|
|
138
|
+
<Header />
|
|
139
|
+
<h1>{title}</h1>
|
|
140
|
+
</body>
|
|
141
|
+
</html>
|
|
142
|
+
`.trim();
|
|
143
|
+
const skeleton = extractCodeSkeleton(astroCode, '.astro');
|
|
144
|
+
assert.ok(skeleton !== null);
|
|
145
|
+
if (!skeleton)
|
|
146
|
+
throw new Error('Skeleton is null');
|
|
147
|
+
assert.ok(skeleton.includes('interface Props'));
|
|
148
|
+
assert.ok(skeleton.includes('const { title } = Astro.props'));
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
//# sourceMappingURL=framework-sfc.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"framework-sfc.test.js","sourceRoot":"","sources":["../../tests/framework-sfc.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-collapser.test.d.ts","sourceRoot":"","sources":["../../tests/import-collapser.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { describe, it } from 'node:test';
|
|
2
|
+
import assert from 'node:assert';
|
|
3
|
+
import { collapseImportWall } from '../src/import-collapser.js';
|
|
4
|
+
describe('Import Collapser (SPEC-002)', () => {
|
|
5
|
+
it('should keep imports intact when total imports <= 5', () => {
|
|
6
|
+
const lines = [
|
|
7
|
+
"import { useState } from 'react';",
|
|
8
|
+
"import { useEffect } from 'react';",
|
|
9
|
+
"import { Button } from './Button.js';"
|
|
10
|
+
];
|
|
11
|
+
const result = collapseImportWall(lines, '.tsx', 5);
|
|
12
|
+
assert.strictEqual(result.hasCollapsed, false);
|
|
13
|
+
assert.strictEqual(result.lines.length, 3);
|
|
14
|
+
});
|
|
15
|
+
it('should collapse import wall when total imports > 5', () => {
|
|
16
|
+
const lines = [
|
|
17
|
+
"import { Component } from '@angular/core';",
|
|
18
|
+
"import { CommonModule } from '@angular/common';",
|
|
19
|
+
"import { Observable } from 'rxjs';",
|
|
20
|
+
"import { map, filter } from 'rxjs/operators';",
|
|
21
|
+
"import { UserService } from './user.service.js';",
|
|
22
|
+
"import { UserDto } from './user.dto.js';",
|
|
23
|
+
"import { Config } from '../config.js';"
|
|
24
|
+
];
|
|
25
|
+
const result = collapseImportWall(lines, '.ts', 5);
|
|
26
|
+
assert.strictEqual(result.hasCollapsed, true);
|
|
27
|
+
assert.strictEqual(result.lines.length, 1);
|
|
28
|
+
const banner = result.lines[0];
|
|
29
|
+
assert.ok(banner.includes('[L1-L7] 📦 7 imports colapsados'));
|
|
30
|
+
assert.ok(banner.includes('@angular/core') || banner.includes('rxjs'));
|
|
31
|
+
assert.ok(banner.includes('./user.service.js') || banner.includes('./user.dto.js'));
|
|
32
|
+
assert.ok(banner.includes('Read(offset=1, limit=7)'));
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
//# sourceMappingURL=import-collapser.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import-collapser.test.js","sourceRoot":"","sources":["../../tests/import-collapser.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAEhE,QAAQ,CAAC,6BAA6B,EAAE,GAAG,EAAE;IAC3C,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,KAAK,GAAG;YACZ,mCAAmC;YACnC,oCAAoC;YACpC,uCAAuC;SACxC,CAAC;QAEF,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;QACpD,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;QAC/C,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,KAAK,GAAG;YACZ,4CAA4C;YAC5C,iDAAiD;YACjD,oCAAoC;YACpC,+CAA+C;YAC/C,kDAAkD;YAClD,0CAA0C;YAC1C,wCAAwC;SACzC,CAAC;QAEF,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QACnD,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;QAC9C,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAE3C,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,iCAAiC,CAAC,CAAC,CAAC;QAC9D,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;QACvE,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC;QACpF,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,yBAAyB,CAAC,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/package.json
CHANGED