infiniloom-node 0.6.2 → 0.6.3

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.
Binary file
Binary file
Binary file
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "infiniloom-node",
3
- "version": "0.6.2",
3
+ "version": "0.6.3",
4
4
  "description": "Node.js bindings for Infiniloom - AST-aware code context engine for RAG and vector databases. Tree-sitter parsing, PageRank ranking, BLAKE3 content-addressable chunks, 27+ tokenizers.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -64,18 +64,53 @@
64
64
  "artifacts": "napi artifacts",
65
65
  "build": "napi build --platform --release",
66
66
  "build:debug": "napi build --platform",
67
- "prepublishOnly": "napi prepublish -t npm",
67
+ "build:types": "tsc -p tsconfig.json --declaration --emitDeclarationOnly --outDir .",
68
+ "prepublishOnly": "napi prepublish -t npm && npm run build:types",
68
69
  "test": "node --test",
70
+ "typecheck": "tsc --noEmit",
69
71
  "version": "napi version"
70
72
  },
73
+ "dependencies": {
74
+ "zod": "^3.23.0"
75
+ },
71
76
  "devDependencies": {
72
- "@napi-rs/cli": "^2.18.0"
77
+ "@napi-rs/cli": "^2.18.0",
78
+ "typescript": "^5.3.0"
73
79
  },
74
80
  "files": [
75
81
  "index.js",
76
82
  "index.d.ts",
83
+ "types.ts",
84
+ "types.d.ts",
85
+ "schemas.ts",
86
+ "schemas.d.ts",
87
+ "schemas.js",
88
+ "tsconfig.json",
77
89
  "*.node"
78
90
  ],
91
+ "exports": {
92
+ ".": {
93
+ "types": "./index.d.ts",
94
+ "require": "./index.js",
95
+ "import": "./index.js"
96
+ },
97
+ "./types": {
98
+ "types": "./types.d.ts",
99
+ "require": "./types.js",
100
+ "import": "./types.js"
101
+ },
102
+ "./schemas": {
103
+ "types": "./schemas.d.ts",
104
+ "require": "./schemas.js",
105
+ "import": "./schemas.js"
106
+ }
107
+ },
108
+ "typesVersions": {
109
+ "*": {
110
+ "types": ["./types.d.ts"],
111
+ "schemas": ["./schemas.d.ts"]
112
+ }
113
+ },
79
114
  "bugs": {
80
115
  "url": "https://github.com/Topos-Labs/infiniloom/issues"
81
116
  },
package/schemas.ts ADDED
@@ -0,0 +1,691 @@
1
+ /**
2
+ * Zod schemas for runtime validation of infiniloom-node options
3
+ *
4
+ * These schemas provide runtime validation with helpful error messages.
5
+ * Use them when accepting options from external sources (API calls, config files, etc.)
6
+ *
7
+ * Usage:
8
+ * ```typescript
9
+ * import { PackOptionsSchema, validatePackOptions } from 'infiniloom-node/schemas';
10
+ * import { pack } from 'infiniloom-node';
11
+ *
12
+ * // Validate options from external source
13
+ * const result = PackOptionsSchema.safeParse(userInput);
14
+ * if (!result.success) {
15
+ * console.error('Invalid options:', result.error.format());
16
+ * return;
17
+ * }
18
+ *
19
+ * // Or use the helper function
20
+ * const options = validatePackOptions(userInput);
21
+ * const output = pack('./repo', options);
22
+ * ```
23
+ */
24
+
25
+ import { z } from 'zod';
26
+
27
+ // ============================================================================
28
+ // Enum Schemas
29
+ // ============================================================================
30
+
31
+ /**
32
+ * Output format enum schema
33
+ */
34
+ export const OutputFormatSchema = z.enum([
35
+ 'xml',
36
+ 'markdown',
37
+ 'json',
38
+ 'yaml',
39
+ 'toon',
40
+ 'plain',
41
+ ]);
42
+ export type OutputFormat = z.infer<typeof OutputFormatSchema>;
43
+
44
+ /**
45
+ * Tokenizer model enum schema
46
+ */
47
+ export const TokenizerModelSchema = z.enum([
48
+ // OpenAI models (exact tokenization via tiktoken)
49
+ 'gpt-5.2',
50
+ 'gpt-5.2-pro',
51
+ 'gpt-5.1',
52
+ 'gpt-5.1-mini',
53
+ 'gpt-5.1-codex',
54
+ 'gpt-5',
55
+ 'gpt-5-mini',
56
+ 'gpt-5-nano',
57
+ 'o4-mini',
58
+ 'o3',
59
+ 'o3-mini',
60
+ 'o1',
61
+ 'o1-mini',
62
+ 'o1-preview',
63
+ 'gpt-4o',
64
+ 'gpt-4o-mini',
65
+ 'gpt-4',
66
+ 'gpt-4-turbo',
67
+ 'gpt-3.5-turbo',
68
+ // Anthropic
69
+ 'claude',
70
+ // Google
71
+ 'gemini',
72
+ 'gemini-1.5',
73
+ 'gemini-2.0',
74
+ // Meta
75
+ 'llama',
76
+ 'llama-3',
77
+ 'llama-3.1',
78
+ 'llama-3.2',
79
+ 'codellama',
80
+ // Mistral
81
+ 'mistral',
82
+ 'mixtral',
83
+ // DeepSeek
84
+ 'deepseek',
85
+ 'deepseek-v3',
86
+ // Alibaba
87
+ 'qwen',
88
+ 'qwen-2.5',
89
+ // Cohere
90
+ 'cohere',
91
+ 'command-r',
92
+ // xAI
93
+ 'grok',
94
+ ]);
95
+ export type TokenizerModel = z.infer<typeof TokenizerModelSchema>;
96
+
97
+ /**
98
+ * Compression level enum schema
99
+ */
100
+ export const CompressionLevelSchema = z.enum([
101
+ 'none',
102
+ 'minimal',
103
+ 'balanced',
104
+ 'aggressive',
105
+ 'extreme',
106
+ 'focused',
107
+ 'semantic',
108
+ ]);
109
+ export type CompressionLevel = z.infer<typeof CompressionLevelSchema>;
110
+
111
+ /**
112
+ * Security severity enum schema
113
+ */
114
+ export const SecuritySeveritySchema = z.enum([
115
+ 'critical',
116
+ 'high',
117
+ 'medium',
118
+ 'low',
119
+ 'info',
120
+ ]);
121
+ export type SecuritySeverity = z.infer<typeof SecuritySeveritySchema>;
122
+
123
+ /**
124
+ * Symbol kind enum schema
125
+ */
126
+ export const SymbolKindSchema = z.enum([
127
+ 'function',
128
+ 'method',
129
+ 'class',
130
+ 'struct',
131
+ 'interface',
132
+ 'trait',
133
+ 'enum',
134
+ 'constant',
135
+ 'variable',
136
+ 'import',
137
+ 'export',
138
+ 'type',
139
+ 'module',
140
+ 'macro',
141
+ ]);
142
+ export type SymbolKind = z.infer<typeof SymbolKindSchema>;
143
+
144
+ /**
145
+ * Visibility enum schema
146
+ */
147
+ export const VisibilitySchema = z.enum([
148
+ 'public',
149
+ 'private',
150
+ 'protected',
151
+ 'internal',
152
+ ]);
153
+ export type Visibility = z.infer<typeof VisibilitySchema>;
154
+
155
+ /**
156
+ * Chunk strategy enum schema
157
+ */
158
+ export const ChunkStrategySchema = z.enum([
159
+ 'fixed',
160
+ 'file',
161
+ 'module',
162
+ 'symbol',
163
+ 'semantic',
164
+ 'dependency',
165
+ ]);
166
+ export type ChunkStrategy = z.infer<typeof ChunkStrategySchema>;
167
+
168
+ /**
169
+ * Impact level enum schema
170
+ */
171
+ export const ImpactLevelSchema = z.enum([
172
+ 'low',
173
+ 'medium',
174
+ 'high',
175
+ 'critical',
176
+ ]);
177
+ export type ImpactLevel = z.infer<typeof ImpactLevelSchema>;
178
+
179
+ /**
180
+ * Git status enum schema
181
+ */
182
+ export const GitStatusSchema = z.enum([
183
+ 'Added',
184
+ 'Modified',
185
+ 'Deleted',
186
+ 'Renamed',
187
+ 'Copied',
188
+ 'Unknown',
189
+ ]);
190
+ export type GitStatus = z.infer<typeof GitStatusSchema>;
191
+
192
+ /**
193
+ * Change type enum schema
194
+ */
195
+ export const ChangeTypeSchema = z.enum([
196
+ 'added',
197
+ 'modified',
198
+ 'deleted',
199
+ ]);
200
+ export type ChangeType = z.infer<typeof ChangeTypeSchema>;
201
+
202
+ /**
203
+ * Breaking change severity enum schema
204
+ */
205
+ export const ChangeSeveritySchema = z.enum([
206
+ 'critical',
207
+ 'high',
208
+ 'medium',
209
+ 'low',
210
+ ]);
211
+ export type ChangeSeverity = z.infer<typeof ChangeSeveritySchema>;
212
+
213
+ // ============================================================================
214
+ // Option Schemas
215
+ // ============================================================================
216
+
217
+ /**
218
+ * Pack options schema with full validation
219
+ */
220
+ export const PackOptionsSchema = z.object({
221
+ format: OutputFormatSchema.optional(),
222
+ model: TokenizerModelSchema.optional(),
223
+ compression: CompressionLevelSchema.optional(),
224
+ mapBudget: z.number().int().nonnegative().max(10_000_000).optional(),
225
+ maxSymbols: z.number().int().positive().max(10_000).optional(),
226
+ skipSecurity: z.boolean().optional(),
227
+ redactSecrets: z.boolean().optional(),
228
+ skipSymbols: z.boolean().optional(),
229
+ include: z.array(z.string().max(256)).max(100).optional(),
230
+ exclude: z.array(z.string().max(256)).max(100).optional(),
231
+ includeTests: z.boolean().optional(),
232
+ securityThreshold: SecuritySeveritySchema.optional(),
233
+ tokenBudget: z.number().int().nonnegative().max(10_000_000).optional(),
234
+ changedOnly: z.boolean().optional(),
235
+ baseSha: z.string().regex(/^[a-f0-9]{7,40}$/i).optional(),
236
+ headSha: z.string().regex(/^[a-f0-9]{7,40}$/i).optional(),
237
+ stagedOnly: z.boolean().optional(),
238
+ includeRelated: z.boolean().optional(),
239
+ relatedDepth: z.union([z.literal(1), z.literal(2), z.literal(3)]).optional(),
240
+ }).strict();
241
+ export type PackOptions = z.infer<typeof PackOptionsSchema>;
242
+
243
+ /**
244
+ * Scan options schema
245
+ */
246
+ export const ScanOptionsSchema = z.object({
247
+ model: TokenizerModelSchema.optional(),
248
+ include: z.array(z.string()).optional(),
249
+ exclude: z.array(z.string()).optional(),
250
+ includeTests: z.boolean().optional(),
251
+ applyDefaultIgnores: z.boolean().optional(),
252
+ }).strict();
253
+ export type ScanOptions = z.infer<typeof ScanOptionsSchema>;
254
+
255
+ /**
256
+ * Chunk options schema
257
+ */
258
+ export const ChunkOptionsSchema = z.object({
259
+ strategy: ChunkStrategySchema.optional(),
260
+ maxTokens: z.number().int().positive().max(100_000).optional(),
261
+ overlap: z.number().int().nonnegative().max(10_000).optional(),
262
+ model: TokenizerModelSchema.optional(),
263
+ format: OutputFormatSchema.optional(),
264
+ priorityFirst: z.boolean().optional(),
265
+ exclude: z.array(z.string().max(256)).max(100).optional(),
266
+ }).strict();
267
+ export type ChunkOptions = z.infer<typeof ChunkOptionsSchema>;
268
+
269
+ /**
270
+ * Index options schema
271
+ */
272
+ export const IndexOptionsSchema = z.object({
273
+ force: z.boolean().optional(),
274
+ includeTests: z.boolean().optional(),
275
+ maxFileSize: z.number().int().positive().max(100 * 1024 * 1024).optional(), // 100MB max
276
+ exclude: z.array(z.string().max(256)).max(100).optional(),
277
+ incremental: z.boolean().optional(),
278
+ }).strict();
279
+ export type IndexOptions = z.infer<typeof IndexOptionsSchema>;
280
+
281
+ /**
282
+ * Diff context options schema
283
+ */
284
+ export const DiffContextOptionsSchema = z.object({
285
+ depth: z.union([z.literal(1), z.literal(2), z.literal(3)]).optional(),
286
+ budget: z.number().int().positive().max(10_000_000).optional(),
287
+ includeDiff: z.boolean().optional(),
288
+ format: OutputFormatSchema.optional(),
289
+ model: TokenizerModelSchema.optional(),
290
+ exclude: z.array(z.string().max(256)).max(100).optional(),
291
+ include: z.array(z.string().max(256)).max(100).optional(),
292
+ }).strict();
293
+ export type DiffContextOptions = z.infer<typeof DiffContextOptionsSchema>;
294
+
295
+ /**
296
+ * Impact options schema
297
+ */
298
+ export const ImpactOptionsSchema = z.object({
299
+ depth: z.union([z.literal(1), z.literal(2), z.literal(3)]).optional(),
300
+ includeTests: z.boolean().optional(),
301
+ model: TokenizerModelSchema.optional(),
302
+ exclude: z.array(z.string().max(256)).max(100).optional(),
303
+ include: z.array(z.string().max(256)).max(100).optional(),
304
+ }).strict();
305
+ export type ImpactOptions = z.infer<typeof ImpactOptionsSchema>;
306
+
307
+ /**
308
+ * Embed options schema
309
+ */
310
+ export const EmbedOptionsSchema = z.object({
311
+ maxTokens: z.number().int().positive().max(100_000).optional(),
312
+ minTokens: z.number().int().nonnegative().max(10_000).optional(),
313
+ contextLines: z.number().int().nonnegative().max(1_000).optional(),
314
+ includeImports: z.boolean().optional(),
315
+ includeTopLevel: z.boolean().optional(),
316
+ includeTests: z.boolean().optional(),
317
+ securityScan: z.boolean().optional(),
318
+ includePatterns: z.array(z.string().max(256)).max(100).optional(),
319
+ excludePatterns: z.array(z.string().max(256)).max(100).optional(),
320
+ manifestPath: z.string().max(4096).refine(p => !p.includes('..'), { message: 'Path traversal not allowed' }).optional(),
321
+ diffOnly: z.boolean().optional(),
322
+ }).strict();
323
+ export type EmbedOptions = z.infer<typeof EmbedOptionsSchema>;
324
+
325
+ /**
326
+ * Query filter schema
327
+ */
328
+ export const QueryFilterSchema = z.object({
329
+ kinds: z.array(SymbolKindSchema).optional(),
330
+ excludeKinds: z.array(SymbolKindSchema).optional(),
331
+ }).strict();
332
+ export type QueryFilter = z.infer<typeof QueryFilterSchema>;
333
+
334
+ /**
335
+ * Symbol filter schema
336
+ */
337
+ export const SymbolFilterSchema = z.object({
338
+ kind: SymbolKindSchema.optional(),
339
+ visibility: VisibilitySchema.optional(),
340
+ }).strict();
341
+ export type SymbolFilter = z.infer<typeof SymbolFilterSchema>;
342
+
343
+ /**
344
+ * Call graph options schema
345
+ */
346
+ export const CallGraphOptionsSchema = z.object({
347
+ maxNodes: z.number().int().positive().max(100_000).optional(),
348
+ maxEdges: z.number().int().positive().max(100_000).optional(),
349
+ }).strict();
350
+ export type CallGraphOptions = z.infer<typeof CallGraphOptionsSchema>;
351
+
352
+ /**
353
+ * Semantic compress options schema
354
+ */
355
+ export const SemanticCompressOptionsSchema = z.object({
356
+ similarityThreshold: z.number().min(0).max(1).optional(),
357
+ budgetRatio: z.number().min(0).max(1).optional(),
358
+ minChunkSize: z.number().int().positive().max(100_000).optional(),
359
+ maxChunkSize: z.number().int().positive().max(100_000).optional(),
360
+ }).strict();
361
+ export type SemanticCompressOptions = z.infer<typeof SemanticCompressOptionsSchema>;
362
+
363
+ /**
364
+ * Generate map options schema
365
+ */
366
+ export const GenerateMapOptionsSchema = z.object({
367
+ budget: z.number().int().positive().max(10_000_000).optional(),
368
+ maxSymbols: z.number().int().positive().max(10_000).optional(),
369
+ }).strict();
370
+ export type GenerateMapOptions = z.infer<typeof GenerateMapOptionsSchema>;
371
+
372
+ /**
373
+ * Transitive callers options schema
374
+ */
375
+ export const TransitiveCallersOptionsSchema = z.object({
376
+ maxDepth: z.number().int().positive().max(100).optional(),
377
+ maxResults: z.number().int().positive().max(10_000).optional(),
378
+ }).strict();
379
+ export type TransitiveCallersOptions = z.infer<typeof TransitiveCallersOptionsSchema>;
380
+
381
+ /**
382
+ * Call sites context options schema
383
+ */
384
+ export const CallSitesContextOptionsSchema = z.object({
385
+ linesBefore: z.number().int().nonnegative().max(1_000).optional(),
386
+ linesAfter: z.number().int().nonnegative().max(1_000).optional(),
387
+ }).strict();
388
+ export type CallSitesContextOptions = z.infer<typeof CallSitesContextOptionsSchema>;
389
+
390
+ /**
391
+ * Changed symbols filter schema
392
+ */
393
+ export const ChangedSymbolsFilterSchema = z.object({
394
+ kinds: z.array(SymbolKindSchema).optional(),
395
+ excludeKinds: z.array(SymbolKindSchema).optional(),
396
+ }).strict();
397
+ export type ChangedSymbolsFilter = z.infer<typeof ChangedSymbolsFilterSchema>;
398
+
399
+ /**
400
+ * Breaking change options schema
401
+ */
402
+ export const BreakingChangeOptionsSchema = z.object({
403
+ oldRef: z.string().min(1),
404
+ newRef: z.string().min(1),
405
+ }).strict();
406
+ export type BreakingChangeOptions = z.infer<typeof BreakingChangeOptionsSchema>;
407
+
408
+ /**
409
+ * Dead code options schema
410
+ */
411
+ export const DeadCodeOptionsSchema = z.object({
412
+ paths: z.array(z.string()).optional(),
413
+ languages: z.array(z.string()).optional(),
414
+ }).strict();
415
+ export type DeadCodeOptions = z.infer<typeof DeadCodeOptionsSchema>;
416
+
417
+ /**
418
+ * Multi-repo entry schema
419
+ */
420
+ export const MultiRepoEntrySchema = z.object({
421
+ id: z.string().min(1),
422
+ name: z.string().min(1),
423
+ path: z.string().min(1),
424
+ }).strict();
425
+ export type MultiRepoEntry = z.infer<typeof MultiRepoEntrySchema>;
426
+
427
+ /**
428
+ * Multi-repo options schema
429
+ */
430
+ export const MultiRepoOptionsSchema = z.object({
431
+ repositories: z.array(MultiRepoEntrySchema),
432
+ }).strict();
433
+ export type MultiRepoOptions = z.infer<typeof MultiRepoOptionsSchema>;
434
+
435
+ /**
436
+ * Extract documentation options schema
437
+ */
438
+ export const ExtractDocOptionsSchema = z.object({
439
+ language: z.string().min(1),
440
+ }).strict();
441
+ export type ExtractDocOptions = z.infer<typeof ExtractDocOptionsSchema>;
442
+
443
+ /**
444
+ * Complexity options schema
445
+ */
446
+ export const ComplexityOptionsSchema = z.object({
447
+ language: z.string().min(1),
448
+ }).strict();
449
+ export type ComplexityOptions = z.infer<typeof ComplexityOptionsSchema>;
450
+
451
+ // ============================================================================
452
+ // Validation Helper Functions
453
+ // ============================================================================
454
+
455
+ /**
456
+ * Validate pack options with detailed error messages
457
+ * @throws {z.ZodError} if validation fails
458
+ */
459
+ export function validatePackOptions(input: unknown): PackOptions {
460
+ return PackOptionsSchema.parse(input);
461
+ }
462
+
463
+ /**
464
+ * Safely validate pack options, returns result object
465
+ */
466
+ export function safeValidatePackOptions(input: unknown): z.SafeParseReturnType<unknown, PackOptions> {
467
+ return PackOptionsSchema.safeParse(input);
468
+ }
469
+
470
+ /**
471
+ * Validate scan options
472
+ * @throws {z.ZodError} if validation fails
473
+ */
474
+ export function validateScanOptions(input: unknown): ScanOptions {
475
+ return ScanOptionsSchema.parse(input);
476
+ }
477
+
478
+ /**
479
+ * Safely validate scan options
480
+ */
481
+ export function safeValidateScanOptions(input: unknown): z.SafeParseReturnType<unknown, ScanOptions> {
482
+ return ScanOptionsSchema.safeParse(input);
483
+ }
484
+
485
+ /**
486
+ * Validate chunk options
487
+ * @throws {z.ZodError} if validation fails
488
+ */
489
+ export function validateChunkOptions(input: unknown): ChunkOptions {
490
+ return ChunkOptionsSchema.parse(input);
491
+ }
492
+
493
+ /**
494
+ * Safely validate chunk options
495
+ */
496
+ export function safeValidateChunkOptions(input: unknown): z.SafeParseReturnType<unknown, ChunkOptions> {
497
+ return ChunkOptionsSchema.safeParse(input);
498
+ }
499
+
500
+ /**
501
+ * Validate embed options
502
+ * @throws {z.ZodError} if validation fails
503
+ */
504
+ export function validateEmbedOptions(input: unknown): EmbedOptions {
505
+ return EmbedOptionsSchema.parse(input);
506
+ }
507
+
508
+ /**
509
+ * Safely validate embed options
510
+ */
511
+ export function safeValidateEmbedOptions(input: unknown): z.SafeParseReturnType<unknown, EmbedOptions> {
512
+ return EmbedOptionsSchema.safeParse(input);
513
+ }
514
+
515
+ /**
516
+ * Validate index options
517
+ * @throws {z.ZodError} if validation fails
518
+ */
519
+ export function validateIndexOptions(input: unknown): IndexOptions {
520
+ return IndexOptionsSchema.parse(input);
521
+ }
522
+
523
+ /**
524
+ * Safely validate index options
525
+ */
526
+ export function safeValidateIndexOptions(input: unknown): z.SafeParseReturnType<unknown, IndexOptions> {
527
+ return IndexOptionsSchema.safeParse(input);
528
+ }
529
+
530
+ /**
531
+ * Validate diff context options
532
+ * @throws {z.ZodError} if validation fails
533
+ */
534
+ export function validateDiffContextOptions(input: unknown): DiffContextOptions {
535
+ return DiffContextOptionsSchema.parse(input);
536
+ }
537
+
538
+ /**
539
+ * Safely validate diff context options
540
+ */
541
+ export function safeValidateDiffContextOptions(input: unknown): z.SafeParseReturnType<unknown, DiffContextOptions> {
542
+ return DiffContextOptionsSchema.safeParse(input);
543
+ }
544
+
545
+ /**
546
+ * Validate impact options
547
+ * @throws {z.ZodError} if validation fails
548
+ */
549
+ export function validateImpactOptions(input: unknown): ImpactOptions {
550
+ return ImpactOptionsSchema.parse(input);
551
+ }
552
+
553
+ /**
554
+ * Safely validate impact options
555
+ */
556
+ export function safeValidateImpactOptions(input: unknown): z.SafeParseReturnType<unknown, ImpactOptions> {
557
+ return ImpactOptionsSchema.safeParse(input);
558
+ }
559
+
560
+ // ============================================================================
561
+ // Output Schemas (for validating return values)
562
+ // ============================================================================
563
+
564
+ /**
565
+ * Language stat schema
566
+ */
567
+ export const LanguageStatSchema = z.object({
568
+ language: z.string(),
569
+ files: z.number().int().nonnegative(),
570
+ lines: z.number().int().nonnegative(),
571
+ percentage: z.number().min(0).max(100),
572
+ });
573
+ export type LanguageStat = z.infer<typeof LanguageStatSchema>;
574
+
575
+ /**
576
+ * Scan stats schema
577
+ */
578
+ export const ScanStatsSchema = z.object({
579
+ name: z.string(),
580
+ totalFiles: z.number().int().nonnegative(),
581
+ totalLines: z.number().int().nonnegative(),
582
+ totalTokens: z.number().int().nonnegative(),
583
+ primaryLanguage: z.string().optional(),
584
+ languages: z.array(LanguageStatSchema),
585
+ securityFindings: z.number().int().nonnegative(),
586
+ });
587
+ export type ScanStats = z.infer<typeof ScanStatsSchema>;
588
+
589
+ /**
590
+ * Security finding schema
591
+ */
592
+ export const SecurityFindingSchema = z.object({
593
+ file: z.string(),
594
+ line: z.number().int().positive(),
595
+ severity: z.string(),
596
+ kind: z.string(),
597
+ pattern: z.string(),
598
+ });
599
+ export type SecurityFinding = z.infer<typeof SecurityFindingSchema>;
600
+
601
+ /**
602
+ * Index status schema
603
+ */
604
+ export const IndexStatusSchema = z.object({
605
+ exists: z.boolean(),
606
+ fileCount: z.number().int().nonnegative(),
607
+ symbolCount: z.number().int().nonnegative(),
608
+ lastBuilt: z.string().optional(),
609
+ version: z.string().optional(),
610
+ filesUpdated: z.number().int().nonnegative().optional(),
611
+ incremental: z.boolean().optional(),
612
+ });
613
+ export type IndexStatus = z.infer<typeof IndexStatusSchema>;
614
+
615
+ /**
616
+ * Symbol info schema
617
+ */
618
+ export const SymbolInfoSchema = z.object({
619
+ id: z.number().int().nonnegative(),
620
+ name: z.string(),
621
+ kind: z.string(),
622
+ file: z.string(),
623
+ line: z.number().int().positive(),
624
+ endLine: z.number().int().positive(),
625
+ signature: z.string().optional(),
626
+ visibility: z.string(),
627
+ });
628
+ export type SymbolInfo = z.infer<typeof SymbolInfoSchema>;
629
+
630
+ /**
631
+ * Embed chunk schema
632
+ */
633
+ export const EmbedChunkSchema = z.object({
634
+ id: z.string().regex(/^ec_[a-f0-9]{32}$/),
635
+ fullHash: z.string(),
636
+ content: z.string(),
637
+ tokens: z.number().int().nonnegative(),
638
+ kind: z.string(),
639
+ source: z.object({
640
+ file: z.string(),
641
+ linesStart: z.number().int().positive(),
642
+ linesEnd: z.number().int().positive(),
643
+ symbol: z.string(),
644
+ fqn: z.string().optional(),
645
+ language: z.string(),
646
+ parent: z.string().optional(),
647
+ visibility: z.string(),
648
+ isTest: z.boolean(),
649
+ }),
650
+ context: z.object({
651
+ docstring: z.string().optional(),
652
+ comments: z.array(z.string()),
653
+ signature: z.string().optional(),
654
+ calls: z.array(z.string()),
655
+ calledBy: z.array(z.string()),
656
+ imports: z.array(z.string()),
657
+ tags: z.array(z.string()),
658
+ linesOfCode: z.number().int().nonnegative(),
659
+ maxNestingDepth: z.number().int().nonnegative(),
660
+ }),
661
+ part: z.object({
662
+ part: z.number().int().positive(),
663
+ of: z.number().int().positive(),
664
+ parentId: z.string(),
665
+ parentSignature: z.string().optional(),
666
+ }).optional(),
667
+ });
668
+ export type EmbedChunk = z.infer<typeof EmbedChunkSchema>;
669
+
670
+ /**
671
+ * Embed diff summary schema
672
+ */
673
+ export const EmbedDiffSummarySchema = z.object({
674
+ added: z.number().int().nonnegative(),
675
+ modified: z.number().int().nonnegative(),
676
+ removed: z.number().int().nonnegative(),
677
+ unchanged: z.number().int().nonnegative(),
678
+ totalChunks: z.number().int().nonnegative(),
679
+ });
680
+ export type EmbedDiffSummary = z.infer<typeof EmbedDiffSummarySchema>;
681
+
682
+ /**
683
+ * Embed result schema
684
+ */
685
+ export const EmbedResultSchema = z.object({
686
+ chunks: z.array(EmbedChunkSchema),
687
+ diff: EmbedDiffSummarySchema.optional(),
688
+ manifestVersion: z.number().int().nonnegative(),
689
+ elapsedMs: z.number().int().nonnegative(),
690
+ });
691
+ export type EmbedResult = z.infer<typeof EmbedResultSchema>;
package/tsconfig.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "compilerOptions": {
4
+ "target": "ES2020",
5
+ "module": "commonjs",
6
+ "moduleResolution": "node",
7
+ "lib": ["ES2020"],
8
+ "declaration": true,
9
+ "declarationMap": true,
10
+ "outDir": ".",
11
+ "strict": true,
12
+ "strictNullChecks": true,
13
+ "strictFunctionTypes": true,
14
+ "strictBindCallApply": true,
15
+ "strictPropertyInitialization": true,
16
+ "noImplicitAny": true,
17
+ "noImplicitThis": true,
18
+ "noImplicitReturns": true,
19
+ "noUnusedLocals": true,
20
+ "noUnusedParameters": true,
21
+ "noFallthroughCasesInSwitch": true,
22
+ "noUncheckedIndexedAccess": true,
23
+ "exactOptionalPropertyTypes": true,
24
+ "esModuleInterop": true,
25
+ "allowSyntheticDefaultImports": true,
26
+ "skipLibCheck": true,
27
+ "forceConsistentCasingInFileNames": true,
28
+ "resolveJsonModule": true,
29
+ "isolatedModules": true
30
+ },
31
+ "include": [
32
+ "types.ts",
33
+ "schemas.ts"
34
+ ],
35
+ "exclude": [
36
+ "node_modules",
37
+ "*.node",
38
+ "*.js"
39
+ ]
40
+ }
package/types.ts ADDED
@@ -0,0 +1,588 @@
1
+ /**
2
+ * Strict TypeScript types for infiniloom-node
3
+ *
4
+ * These types provide string literal unions for better type safety
5
+ * compared to the auto-generated index.d.ts which uses generic strings.
6
+ *
7
+ * Usage:
8
+ * ```typescript
9
+ * import type { StrictPackOptions, OutputFormat, TokenizerModel } from 'infiniloom-node/types';
10
+ * import { pack } from 'infiniloom-node';
11
+ *
12
+ * const options: StrictPackOptions = {
13
+ * format: 'xml', // Type-checked!
14
+ * model: 'claude',
15
+ * compression: 'balanced'
16
+ * };
17
+ *
18
+ * const output = pack('./repo', options);
19
+ * ```
20
+ */
21
+
22
+ // Re-export base types from auto-generated index
23
+ export type {
24
+ ScanStats,
25
+ LanguageStat,
26
+ GitFileStatus,
27
+ GitChangedFile,
28
+ GitCommit,
29
+ GitBlameLine,
30
+ GitDiffLine,
31
+ GitDiffHunk,
32
+ SecurityFinding,
33
+ IndexStatus,
34
+ SymbolInfo,
35
+ ReferenceInfo,
36
+ CallGraphEdge,
37
+ CallGraphStats,
38
+ CallGraph,
39
+ DependencyCycle,
40
+ SymbolSourceResult,
41
+ RepoChunk,
42
+ AffectedSymbol,
43
+ DiffFileContext,
44
+ ContextSymbolInfo,
45
+ CallSite,
46
+ CallSiteWithContext,
47
+ ChangedSymbolInfo,
48
+ TransitiveCallerInfo,
49
+ EmbedChunkSource,
50
+ EmbedChunkContext,
51
+ EmbedChunkPart,
52
+ EmbedChunk,
53
+ EmbedDiffSummary,
54
+ EmbedResult,
55
+ EmbedManifestStatus,
56
+ JsTypeInfo,
57
+ JsParameterInfo,
58
+ JsGenericParam,
59
+ JsTypeSignature,
60
+ JsParamDoc,
61
+ JsReturnDoc,
62
+ JsThrowsDoc,
63
+ JsExample,
64
+ JsDocumentation,
65
+ JsAncestorInfo,
66
+ JsTypeHierarchy,
67
+ JsHalsteadMetrics,
68
+ JsLocMetrics,
69
+ JsComplexityMetrics,
70
+ JsUnusedExport,
71
+ JsUnreachableCode,
72
+ JsUnusedSymbol,
73
+ JsUnusedImport,
74
+ JsUnusedVariable,
75
+ JsDeadCodeInfo,
76
+ JsBreakingChange,
77
+ JsBreakingChangeSummary,
78
+ JsBreakingChangeReport,
79
+ JsRepoEntry,
80
+ JsCrossRepoLink,
81
+ JsUnifiedSymbolRef,
82
+ JsMultiRepoStats,
83
+ } from './index';
84
+
85
+ // ============================================================================
86
+ // String Literal Union Types
87
+ // ============================================================================
88
+
89
+ /**
90
+ * Output format for pack/chunk operations
91
+ * - xml: Optimized for Claude (CDATA sections, structured XML)
92
+ * - markdown: Optimized for GPT models (fenced code blocks)
93
+ * - json: Machine-readable JSON format
94
+ * - yaml: Optimized for Gemini (query at end)
95
+ * - toon: Token-efficient format (30-40% fewer tokens)
96
+ * - plain: Plain text format
97
+ */
98
+ export type OutputFormat = 'xml' | 'markdown' | 'json' | 'yaml' | 'toon' | 'plain';
99
+
100
+ /**
101
+ * Supported LLM tokenizer models
102
+ *
103
+ * OpenAI models (exact via tiktoken):
104
+ * - gpt-5.2, gpt-5.1, gpt-5, o4-mini, o3, o1, gpt-4o, gpt-4o-mini: o200k_base encoding
105
+ * - gpt-4, gpt-4-turbo, gpt-3.5-turbo: cl100k_base encoding
106
+ *
107
+ * Other models (calibrated estimation):
108
+ * - claude: Anthropic Claude models
109
+ * - gemini, gemini-1.5, gemini-2.0: Google Gemini models
110
+ * - llama, llama-3, llama-3.1, llama-3.2, codellama: Meta Llama models
111
+ * - mistral, mixtral: Mistral AI models
112
+ * - deepseek, deepseek-v3: DeepSeek models
113
+ * - qwen, qwen-2.5: Alibaba Qwen models
114
+ * - cohere, command-r: Cohere models
115
+ * - grok: xAI Grok models
116
+ */
117
+ export type TokenizerModel =
118
+ // OpenAI models (exact tokenization via tiktoken)
119
+ | 'gpt-5.2'
120
+ | 'gpt-5.2-pro'
121
+ | 'gpt-5.1'
122
+ | 'gpt-5.1-mini'
123
+ | 'gpt-5.1-codex'
124
+ | 'gpt-5'
125
+ | 'gpt-5-mini'
126
+ | 'gpt-5-nano'
127
+ | 'o4-mini'
128
+ | 'o3'
129
+ | 'o3-mini'
130
+ | 'o1'
131
+ | 'o1-mini'
132
+ | 'o1-preview'
133
+ | 'gpt-4o'
134
+ | 'gpt-4o-mini'
135
+ | 'gpt-4'
136
+ | 'gpt-4-turbo'
137
+ | 'gpt-3.5-turbo'
138
+ // Anthropic
139
+ | 'claude'
140
+ // Google
141
+ | 'gemini'
142
+ | 'gemini-1.5'
143
+ | 'gemini-2.0'
144
+ // Meta
145
+ | 'llama'
146
+ | 'llama-3'
147
+ | 'llama-3.1'
148
+ | 'llama-3.2'
149
+ | 'codellama'
150
+ // Mistral
151
+ | 'mistral'
152
+ | 'mixtral'
153
+ // DeepSeek
154
+ | 'deepseek'
155
+ | 'deepseek-v3'
156
+ // Alibaba
157
+ | 'qwen'
158
+ | 'qwen-2.5'
159
+ // Cohere
160
+ | 'cohere'
161
+ | 'command-r'
162
+ // xAI
163
+ | 'grok';
164
+
165
+ /**
166
+ * Compression level for output
167
+ * - none: No compression, full output
168
+ * - minimal: Light compression (remove blank lines)
169
+ * - balanced: Moderate compression (recommended)
170
+ * - aggressive: Heavy compression (remove comments, simplify)
171
+ * - extreme: Maximum compression (signatures only)
172
+ * - focused: Focus on key symbols
173
+ * - semantic: AI-aware semantic compression
174
+ */
175
+ export type CompressionLevel =
176
+ | 'none'
177
+ | 'minimal'
178
+ | 'balanced'
179
+ | 'aggressive'
180
+ | 'extreme'
181
+ | 'focused'
182
+ | 'semantic';
183
+
184
+ /**
185
+ * Security severity levels
186
+ */
187
+ export type SecuritySeverity = 'critical' | 'high' | 'medium' | 'low' | 'info';
188
+
189
+ /**
190
+ * Git file status
191
+ */
192
+ export type GitStatus = 'Added' | 'Modified' | 'Deleted' | 'Renamed' | 'Copied' | 'Unknown';
193
+
194
+ /**
195
+ * Diff line change type
196
+ */
197
+ export type DiffChangeType = 'add' | 'remove' | 'context';
198
+
199
+ /**
200
+ * Symbol kinds (matches Rust SymbolKind enum)
201
+ */
202
+ export type SymbolKind =
203
+ | 'function'
204
+ | 'method'
205
+ | 'class'
206
+ | 'struct'
207
+ | 'interface'
208
+ | 'trait'
209
+ | 'enum'
210
+ | 'constant'
211
+ | 'variable'
212
+ | 'import'
213
+ | 'export'
214
+ | 'type'
215
+ | 'module'
216
+ | 'macro';
217
+
218
+ /**
219
+ * Symbol visibility
220
+ */
221
+ export type Visibility = 'public' | 'private' | 'protected' | 'internal';
222
+
223
+ /**
224
+ * Impact type for affected symbols
225
+ */
226
+ export type ImpactType = 'direct' | 'caller' | 'callee' | 'dependent';
227
+
228
+ /**
229
+ * Impact level for analysis results
230
+ */
231
+ export type ImpactLevel = 'low' | 'medium' | 'high' | 'critical';
232
+
233
+ /**
234
+ * Reference kind
235
+ */
236
+ export type ReferenceKind = 'call' | 'import' | 'inherit' | 'implement';
237
+
238
+ /**
239
+ * Context symbol reason
240
+ */
241
+ export type ContextReason = 'changed' | 'caller' | 'callee' | 'dependent';
242
+
243
+ /**
244
+ * Change type for symbols
245
+ */
246
+ export type ChangeType = 'added' | 'modified' | 'deleted';
247
+
248
+ /**
249
+ * Chunking strategy
250
+ */
251
+ export type ChunkStrategy =
252
+ | 'fixed'
253
+ | 'file'
254
+ | 'module'
255
+ | 'symbol'
256
+ | 'semantic'
257
+ | 'dependency';
258
+
259
+ /**
260
+ * Embed chunk kind (matches Rust ChunkKind enum)
261
+ */
262
+ export type EmbedChunkKind =
263
+ | 'function'
264
+ | 'method'
265
+ | 'class'
266
+ | 'struct'
267
+ | 'enum'
268
+ | 'interface'
269
+ | 'trait'
270
+ | 'module'
271
+ | 'constant'
272
+ | 'variable'
273
+ | 'imports'
274
+ | 'top_level'
275
+ | 'function_part'
276
+ | 'class_part';
277
+
278
+ /**
279
+ * Breaking change type
280
+ */
281
+ export type BreakingChangeType =
282
+ | 'removed'
283
+ | 'signature_changed'
284
+ | 'type_changed'
285
+ | 'visibility_reduced'
286
+ | 'parameter_added'
287
+ | 'parameter_removed'
288
+ | 'return_type_changed';
289
+
290
+ /**
291
+ * Breaking change severity
292
+ */
293
+ export type ChangeSeverity = 'critical' | 'high' | 'medium' | 'low';
294
+
295
+ /**
296
+ * Cross-repo link type
297
+ */
298
+ export type CrossRepoLinkType = 'import' | 'call' | 'inherit' | 'implement';
299
+
300
+ /**
301
+ * Variance for generic parameters
302
+ */
303
+ export type GenericVariance = 'invariant' | 'covariant' | 'contravariant' | 'bivariant';
304
+
305
+ /**
306
+ * Parameter kind
307
+ */
308
+ export type ParameterKind = 'positional' | 'named' | 'rest' | 'keyword_only' | 'positional_only';
309
+
310
+ // ============================================================================
311
+ // Strict Option Interfaces
312
+ // ============================================================================
313
+
314
+ /**
315
+ * Strict pack options with literal union types
316
+ */
317
+ export interface StrictPackOptions {
318
+ /** Output format with strict typing */
319
+ format?: OutputFormat;
320
+ /** Target model with strict typing */
321
+ model?: TokenizerModel;
322
+ /** Compression level with strict typing */
323
+ compression?: CompressionLevel;
324
+ /** Token budget for repository map */
325
+ mapBudget?: number;
326
+ /** Maximum number of symbols in map */
327
+ maxSymbols?: number;
328
+ /** Skip security scanning */
329
+ skipSecurity?: boolean;
330
+ /** Redact detected secrets in output */
331
+ redactSecrets?: boolean;
332
+ /** Skip symbol extraction */
333
+ skipSymbols?: boolean;
334
+ /** Glob patterns to include */
335
+ include?: readonly string[];
336
+ /** Glob patterns to exclude */
337
+ exclude?: readonly string[];
338
+ /** Include test files */
339
+ includeTests?: boolean;
340
+ /** Minimum security severity to block on */
341
+ securityThreshold?: SecuritySeverity;
342
+ /** Token budget for total output (0 = no limit) */
343
+ tokenBudget?: number;
344
+ /** Only include files changed in git */
345
+ changedOnly?: boolean;
346
+ /** Base SHA/ref for diff comparison */
347
+ baseSha?: string;
348
+ /** Head SHA/ref for diff comparison */
349
+ headSha?: string;
350
+ /** Include staged changes only */
351
+ stagedOnly?: boolean;
352
+ /** Include related files */
353
+ includeRelated?: boolean;
354
+ /** Depth for related file traversal (1-3) */
355
+ relatedDepth?: 1 | 2 | 3;
356
+ }
357
+
358
+ /**
359
+ * Strict scan options with literal union types
360
+ */
361
+ export interface StrictScanOptions {
362
+ /** Target model for token counting */
363
+ model?: TokenizerModel;
364
+ /** Glob patterns to include */
365
+ include?: readonly string[];
366
+ /** Glob patterns to exclude */
367
+ exclude?: readonly string[];
368
+ /** Include test files */
369
+ includeTests?: boolean;
370
+ /** Apply default ignores */
371
+ applyDefaultIgnores?: boolean;
372
+ }
373
+
374
+ /**
375
+ * Strict chunk options with literal union types
376
+ */
377
+ export interface StrictChunkOptions {
378
+ /** Chunking strategy */
379
+ strategy?: ChunkStrategy;
380
+ /** Maximum tokens per chunk */
381
+ maxTokens?: number;
382
+ /** Token overlap between chunks */
383
+ overlap?: number;
384
+ /** Target model for token counting */
385
+ model?: TokenizerModel;
386
+ /** Output format */
387
+ format?: OutputFormat;
388
+ /** Sort chunks by priority */
389
+ priorityFirst?: boolean;
390
+ /** Directories/patterns to exclude */
391
+ exclude?: readonly string[];
392
+ }
393
+
394
+ /**
395
+ * Strict diff context options
396
+ */
397
+ export interface StrictDiffContextOptions {
398
+ /** Depth of context expansion (1-3) */
399
+ depth?: 1 | 2 | 3;
400
+ /** Token budget for context */
401
+ budget?: number;
402
+ /** Include the actual diff content */
403
+ includeDiff?: boolean;
404
+ /** Output format */
405
+ format?: OutputFormat;
406
+ /** Target model for token counting */
407
+ model?: TokenizerModel;
408
+ /** Glob patterns to exclude */
409
+ exclude?: readonly string[];
410
+ /** Glob patterns to include */
411
+ include?: readonly string[];
412
+ }
413
+
414
+ /**
415
+ * Strict impact options
416
+ */
417
+ export interface StrictImpactOptions {
418
+ /** Depth of dependency traversal (1-3) */
419
+ depth?: 1 | 2 | 3;
420
+ /** Include test files in analysis */
421
+ includeTests?: boolean;
422
+ /** Target model for token counting */
423
+ model?: TokenizerModel;
424
+ /** Glob patterns to exclude */
425
+ exclude?: readonly string[];
426
+ /** Glob patterns to include */
427
+ include?: readonly string[];
428
+ }
429
+
430
+ /**
431
+ * Strict embed options
432
+ */
433
+ export interface StrictEmbedOptions {
434
+ /** Maximum tokens per chunk */
435
+ maxTokens?: number;
436
+ /** Minimum tokens for a chunk */
437
+ minTokens?: number;
438
+ /** Lines of context around symbols */
439
+ contextLines?: number;
440
+ /** Include imports in chunks */
441
+ includeImports?: boolean;
442
+ /** Include top-level code */
443
+ includeTopLevel?: boolean;
444
+ /** Include test files */
445
+ includeTests?: boolean;
446
+ /** Enable secret scanning */
447
+ securityScan?: boolean;
448
+ /** Include patterns (glob) */
449
+ includePatterns?: readonly string[];
450
+ /** Exclude patterns (glob) */
451
+ excludePatterns?: readonly string[];
452
+ /** Path to manifest file */
453
+ manifestPath?: string;
454
+ /** Only return changed chunks (diff mode) */
455
+ diffOnly?: boolean;
456
+ }
457
+
458
+ /**
459
+ * Strict query filter
460
+ */
461
+ export interface StrictQueryFilter {
462
+ /** Filter by symbol kinds */
463
+ kinds?: readonly SymbolKind[];
464
+ /** Exclude specific kinds */
465
+ excludeKinds?: readonly SymbolKind[];
466
+ }
467
+
468
+ /**
469
+ * Strict symbol filter
470
+ */
471
+ export interface StrictSymbolFilter {
472
+ /** Filter by symbol kind */
473
+ kind?: SymbolKind;
474
+ /** Filter by visibility */
475
+ visibility?: Visibility;
476
+ }
477
+
478
+ /**
479
+ * Strict index options
480
+ */
481
+ export interface StrictIndexOptions {
482
+ /** Force full rebuild */
483
+ force?: boolean;
484
+ /** Include test files */
485
+ includeTests?: boolean;
486
+ /** Maximum file size to index (bytes) */
487
+ maxFileSize?: number;
488
+ /** Directories/patterns to exclude */
489
+ exclude?: readonly string[];
490
+ /** Incremental update */
491
+ incremental?: boolean;
492
+ }
493
+
494
+ // ============================================================================
495
+ // Type Guards
496
+ // ============================================================================
497
+
498
+ /**
499
+ * Type guard for OutputFormat
500
+ */
501
+ export function isOutputFormat(value: unknown): value is OutputFormat {
502
+ return (
503
+ typeof value === 'string' &&
504
+ ['xml', 'markdown', 'json', 'yaml', 'toon', 'plain'].includes(value)
505
+ );
506
+ }
507
+
508
+ /**
509
+ * Type guard for TokenizerModel
510
+ */
511
+ export function isTokenizerModel(value: unknown): value is TokenizerModel {
512
+ const models: TokenizerModel[] = [
513
+ // OpenAI models (exact tokenization via tiktoken)
514
+ 'gpt-5.2', 'gpt-5.2-pro', 'gpt-5.1', 'gpt-5.1-mini', 'gpt-5.1-codex',
515
+ 'gpt-5', 'gpt-5-mini', 'gpt-5-nano',
516
+ 'o4-mini', 'o3', 'o3-mini', 'o1', 'o1-mini', 'o1-preview',
517
+ 'gpt-4o', 'gpt-4o-mini', 'gpt-4', 'gpt-4-turbo', 'gpt-3.5-turbo',
518
+ // Anthropic
519
+ 'claude',
520
+ // Google
521
+ 'gemini', 'gemini-1.5', 'gemini-2.0',
522
+ // Meta
523
+ 'llama', 'llama-3', 'llama-3.1', 'llama-3.2', 'codellama',
524
+ // Mistral
525
+ 'mistral', 'mixtral',
526
+ // DeepSeek
527
+ 'deepseek', 'deepseek-v3',
528
+ // Alibaba
529
+ 'qwen', 'qwen-2.5',
530
+ // Cohere
531
+ 'cohere', 'command-r',
532
+ // xAI
533
+ 'grok',
534
+ ];
535
+ return typeof value === 'string' && models.includes(value as TokenizerModel);
536
+ }
537
+
538
+ /**
539
+ * Type guard for CompressionLevel
540
+ */
541
+ export function isCompressionLevel(value: unknown): value is CompressionLevel {
542
+ return (
543
+ typeof value === 'string' &&
544
+ ['none', 'minimal', 'balanced', 'aggressive', 'extreme', 'focused', 'semantic'].includes(value)
545
+ );
546
+ }
547
+
548
+ /**
549
+ * Type guard for SymbolKind
550
+ */
551
+ export function isSymbolKind(value: unknown): value is SymbolKind {
552
+ const kinds: SymbolKind[] = [
553
+ 'function', 'method', 'class', 'struct', 'interface', 'trait',
554
+ 'enum', 'constant', 'variable', 'import', 'export', 'type', 'module', 'macro',
555
+ ];
556
+ return typeof value === 'string' && kinds.includes(value as SymbolKind);
557
+ }
558
+
559
+ /**
560
+ * Type guard for SecuritySeverity
561
+ */
562
+ export function isSecuritySeverity(value: unknown): value is SecuritySeverity {
563
+ return (
564
+ typeof value === 'string' &&
565
+ ['critical', 'high', 'medium', 'low', 'info'].includes(value)
566
+ );
567
+ }
568
+
569
+ // ============================================================================
570
+ // Utility Types
571
+ // ============================================================================
572
+
573
+ /**
574
+ * Make specific properties required
575
+ */
576
+ export type WithRequired<T, K extends keyof T> = T & { [P in K]-?: T[P] };
577
+
578
+ /**
579
+ * Make all properties readonly and non-nullable
580
+ */
581
+ export type Strict<T> = {
582
+ readonly [P in keyof T]-?: NonNullable<T[P]>;
583
+ };
584
+
585
+ /**
586
+ * Extract the element type from an array type
587
+ */
588
+ export type ElementOf<T> = T extends readonly (infer E)[] ? E : never;