@kb-labs/mind-core 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,187 @@
1
+ # @kb-labs/mind-core
2
+
3
+ Core contracts, errors, and utilities for KB Labs Mind.
4
+
5
+ ## Vision & Purpose
6
+
7
+ **@kb-labs/mind-core** provides core contracts, errors, and utilities for KB Labs Mind. It includes error handling, token utilities, hash utilities, path utilities, and default configurations.
8
+
9
+ ### Core Goals
10
+
11
+ - **Error Handling**: Unified error handling for Mind
12
+ - **Token Utilities**: Token estimation and truncation utilities
13
+ - **Hash Utilities**: Hashing utilities
14
+ - **Path Utilities**: Path manipulation utilities
15
+ - **Defaults**: Default configurations
16
+
17
+ ## Package Status
18
+
19
+ - **Version**: 0.1.0
20
+ - **Stage**: Stable
21
+ - **Status**: Production Ready ✅
22
+
23
+ ## Architecture
24
+
25
+ ### High-Level Overview
26
+
27
+ ```
28
+ Mind Core
29
+
30
+ ├──► Error Handling
31
+ ├──► Token Utilities
32
+ ├──► Hash Utilities
33
+ ├──► Path Utilities
34
+ └──► Defaults
35
+ ```
36
+
37
+ ### Key Components
38
+
39
+ 1. **Error** (`error/`): Error handling
40
+ 2. **Utils** (`utils/`): Utilities (token, hash, paths)
41
+ 3. **Defaults** (`defaults.ts`): Default configurations
42
+
43
+ ## ✨ Features
44
+
45
+ - **Error Handling**: Unified error handling for Mind
46
+ - **Token Utilities**: Token estimation and truncation utilities
47
+ - **Hash Utilities**: Hashing utilities
48
+ - **Path Utilities**: Path manipulation utilities
49
+ - **Defaults**: Default configurations
50
+
51
+ ## 📦 API Reference
52
+
53
+ ### Main Exports
54
+
55
+ #### Error Handling
56
+
57
+ - `MindError`: Mind error class
58
+ - `createMindError`: Create Mind error
59
+
60
+ #### Token Utilities
61
+
62
+ - `estimateTokens`: Estimate tokens in text
63
+ - `truncateTokens`: Truncate text by tokens
64
+
65
+ #### Hash Utilities
66
+
67
+ - `hashString`: Hash string
68
+ - `hashFile`: Hash file
69
+
70
+ #### Path Utilities
71
+
72
+ - `normalizePath`: Normalize path
73
+ - `resolvePath`: Resolve path
74
+
75
+ #### Defaults
76
+
77
+ - `DEFAULT_CONFIG`: Default configuration
78
+
79
+ ## 🔧 Configuration
80
+
81
+ ### Configuration Options
82
+
83
+ All configuration via function parameters.
84
+
85
+ ## 🔗 Dependencies
86
+
87
+ ### Runtime Dependencies
88
+
89
+ - `@kb-labs/mind-types` (`link:../mind-types`): Mind types
90
+
91
+ ### Development Dependencies
92
+
93
+ - `@kb-labs/devkit` (`link:../../../kb-labs-devkit`): DevKit presets
94
+ - `@types/node` (`^24.7.0`): Node.js types
95
+ - `tsup` (`^8.5.0`): TypeScript bundler
96
+ - `typescript` (`^5.6.3`): TypeScript compiler
97
+ - `vitest` (`^3.2.4`): Test runner
98
+
99
+ ## 🧪 Testing
100
+
101
+ ### Test Structure
102
+
103
+ No tests currently.
104
+
105
+ ### Test Coverage
106
+
107
+ - **Current Coverage**: ~50%
108
+ - **Target Coverage**: 90%
109
+
110
+ ## 📈 Performance
111
+
112
+ ### Performance Characteristics
113
+
114
+ - **Time Complexity**: O(1) for utilities, O(n) for token estimation
115
+ - **Space Complexity**: O(1)
116
+ - **Bottlenecks**: Token estimation for large texts
117
+
118
+ ## 🔒 Security
119
+
120
+ ### Security Considerations
121
+
122
+ - **Hash Utilities**: Secure hashing utilities
123
+ - **Path Validation**: Path validation for file operations
124
+
125
+ ### Known Vulnerabilities
126
+
127
+ - None
128
+
129
+ ## 🐛 Known Issues & Limitations
130
+
131
+ ### Known Issues
132
+
133
+ - None currently
134
+
135
+ ### Limitations
136
+
137
+ - **Token Estimation**: Basic token estimation
138
+
139
+ ### Future Improvements
140
+
141
+ - **Better Token Estimation**: More accurate token estimation
142
+
143
+ ## 🔄 Migration & Breaking Changes
144
+
145
+ ### Migration from Previous Versions
146
+
147
+ No breaking changes in current version (0.1.0).
148
+
149
+ ### Breaking Changes in Future Versions
150
+
151
+ - None planned
152
+
153
+ ## 📚 Examples
154
+
155
+ ### Example 1: Use Error Handling
156
+
157
+ ```typescript
158
+ import { createMindError } from '@kb-labs/mind-core';
159
+
160
+ const error = createMindError('MIND_PARSE_ERROR', 'Failed to parse file');
161
+ ```
162
+
163
+ ### Example 2: Use Token Utilities
164
+
165
+ ```typescript
166
+ import { estimateTokens, truncateTokens } from '@kb-labs/mind-core';
167
+
168
+ const tokens = estimateTokens('Hello world');
169
+ const truncated = truncateTokens('Long text...', 100);
170
+ ```
171
+
172
+ ### Example 3: Use Hash Utilities
173
+
174
+ ```typescript
175
+ import { hashString } from '@kb-labs/mind-core';
176
+
177
+ const hash = hashString('Hello world');
178
+ ```
179
+
180
+ ## 🤝 Contributing
181
+
182
+ See [CONTRIBUTING.md](../../CONTRIBUTING.md) for development guidelines.
183
+
184
+ ## 📄 License
185
+
186
+ MIT © KB Labs
187
+
@@ -0,0 +1,402 @@
1
+ export * from '@kb-labs/mind-types';
2
+ import { IStorage } from '@kb-labs/sdk';
3
+
4
+ /**
5
+ * @module @kb-labs/mind-core/error
6
+ * Standardized error class for KB Labs Mind
7
+ */
8
+ declare class MindError extends Error {
9
+ code: string;
10
+ hint?: string | undefined;
11
+ meta?: any | undefined;
12
+ constructor(code: string, message: string, hint?: string | undefined, meta?: any | undefined);
13
+ }
14
+ /**
15
+ * Maps MindError codes to CLI exit codes
16
+ */
17
+ declare function getExitCode(err: MindError): number;
18
+ /**
19
+ * Error codes with their standard hints
20
+ */
21
+ declare const ERROR_HINTS: {
22
+ readonly MIND_NO_GIT: "Initialize git repository or run from a git repository";
23
+ readonly MIND_FS_TIMEOUT: "File system operation timed out - try increasing time budget";
24
+ readonly MIND_PARSE_ERROR: "Failed to parse file - check syntax and try again";
25
+ readonly MIND_PACK_BUDGET_EXCEEDED: "Context pack exceeds token budget - reduce content or increase budget";
26
+ readonly MIND_FORBIDDEN: "Operation not permitted - check file permissions";
27
+ readonly MIND_TIME_BUDGET: "Time budget exceeded - operation completed partially";
28
+ readonly MIND_BAD_FLAGS: "Invalid command line flags - check values and try again";
29
+ readonly MIND_INVALID_FLAG: "Invalid flag value - check format and try again";
30
+ readonly MIND_BUNDLE_TIMEOUT: "Bundle operation timed out - skipped bundle information";
31
+ readonly MIND_FEED_ERROR: "Mind feed operation failed - check logs for details";
32
+ readonly MIND_INIT_ERROR: "Mind initialization failed - check permissions and try again";
33
+ readonly MIND_UPDATE_ERROR: "Mind update operation failed - check logs for details";
34
+ readonly MIND_PACK_ERROR: "Mind pack operation failed - check logs for details";
35
+ readonly MIND_GIT_ERROR: "Git operation failed - check git repository status";
36
+ readonly MIND_INDEX_NOT_FOUND: "Mind indexes not found - run \"kb mind init\" first";
37
+ readonly MIND_INVALID_PATH: "Invalid file or directory path - check path exists and is accessible";
38
+ readonly MIND_DEPENDENCY_ERROR: "Dependency resolution failed - check package configuration";
39
+ readonly MIND_BUILD_ERROR: "Build operation failed - check configuration and try again";
40
+ };
41
+ type ErrorCode = keyof typeof ERROR_HINTS;
42
+ /**
43
+ * Create a MindError with standardized code and hint
44
+ */
45
+ declare function createMindError(code: ErrorCode, message: string, meta?: any): MindError;
46
+ /**
47
+ * Create a MindError from a generic error
48
+ */
49
+ declare function wrapError(error: unknown, code?: ErrorCode): MindError;
50
+ /**
51
+ * Check if an error is a MindError
52
+ */
53
+ declare function isMindError(error: unknown): error is MindError;
54
+
55
+ /**
56
+ * Pack and context types for KB Labs Mind
57
+ */
58
+
59
+ type ContextSection = "intent_summary" | "product_overview" | "project_meta" | "api_signatures" | "recent_diffs" | "docs_overview" | "impl_snippets" | "configs_profiles";
60
+ interface ContextBudget {
61
+ totalTokens: number;
62
+ caps: Partial<Record<ContextSection, number>>;
63
+ truncation: "start" | "middle" | "end";
64
+ }
65
+ type ContextSlice = "overview" | "api" | "diffs" | "snippets" | "configs" | "meta" | "docs";
66
+ interface ContextPreset {
67
+ name: string;
68
+ weight: Partial<Record<ContextSlice, number>>;
69
+ }
70
+ interface ITokenEstimator {
71
+ estimate(text: string): number;
72
+ truncate(text: string, maxTokens: number, mode: "start" | "middle" | "end"): string;
73
+ }
74
+
75
+ /**
76
+ * Token estimation utilities for KB Labs Mind
77
+ */
78
+
79
+ /**
80
+ * Default whitespace-aware token estimator
81
+ * Algorithm: ~3.8-4.2 chars/token based on whitespace and code patterns
82
+ */
83
+ declare class DefaultTokenEstimator implements ITokenEstimator {
84
+ private readonly charsPerToken;
85
+ private readonly codeBonus;
86
+ private readonly punctuationWeight;
87
+ estimate(text: string): number;
88
+ truncate(text: string, maxTokens: number, mode: "start" | "middle" | "end"): string;
89
+ }
90
+ /**
91
+ * Default token estimator instance
92
+ */
93
+ declare const defaultTokenEstimator: DefaultTokenEstimator;
94
+ /**
95
+ * Estimate tokens using default strategy
96
+ */
97
+ declare function estimateTokens(text: string): number;
98
+ /**
99
+ * Truncate text to token limit using default strategy
100
+ */
101
+ declare function truncateToTokens(text: string, maxTokens: number, mode?: "start" | "middle" | "end"): string;
102
+
103
+ /**
104
+ * Hashing utilities for KB Labs Mind
105
+ */
106
+ /**
107
+ * Compute SHA256 hash for string content
108
+ */
109
+ declare function sha256(content: string): string;
110
+ /**
111
+ * Compute SHA256 hash for Buffer content
112
+ */
113
+ declare function sha256Buffer(buffer: Buffer): string;
114
+ /**
115
+ * Compute SHA256 hash for file content (streaming for large files)
116
+ */
117
+ declare function sha256File(filePath: string): Promise<string>;
118
+
119
+ /**
120
+ * Path utilities for KB Labs Mind
121
+ */
122
+ /**
123
+ * Convert path to POSIX format (forward slashes)
124
+ */
125
+ declare function toPosix(filePath: string): string;
126
+ /**
127
+ * Convert POSIX path back to platform-specific format
128
+ */
129
+ declare function fromPosix(posixPath: string): string;
130
+ /**
131
+ * Find workspace root by looking for git repository or monorepo indicators
132
+ * Searches up the directory tree from cwd
133
+ */
134
+ declare function findWorkspaceRoot(cwd: string): Promise<string>;
135
+ /**
136
+ * Make path relative to workspace root
137
+ */
138
+ declare function makeRelativeToRoot(absolutePath: string, root: string): string;
139
+ /**
140
+ * Check if path should be ignored based on common patterns
141
+ */
142
+ declare function shouldIgnorePath(filePath: string): boolean;
143
+
144
+ /**
145
+ * Mathematical utility functions for KB Labs Mind
146
+ */
147
+ /**
148
+ * Calculate cosine similarity between two vectors
149
+ *
150
+ * Cosine similarity measures the cosine of the angle between two vectors,
151
+ * producing a value between -1 and 1, where:
152
+ * - 1 means vectors point in the same direction (identical)
153
+ * - 0 means vectors are orthogonal (no similarity)
154
+ * - -1 means vectors point in opposite directions
155
+ *
156
+ * @param a - First vector (array of numbers)
157
+ * @param b - Second vector (array of numbers)
158
+ * @returns Similarity score [0-1], or 0 if vectors have different lengths or zero magnitudes
159
+ *
160
+ * @example
161
+ * ```typescript
162
+ * const similarity = cosineSimilarity([1, 2, 3], [4, 5, 6]);
163
+ * console.log(similarity); // ~0.974
164
+ * ```
165
+ */
166
+ declare function cosineSimilarity(a: number[], b: number[]): number;
167
+ /**
168
+ * Calculate dot product of two vectors
169
+ *
170
+ * @param a - First vector
171
+ * @param b - Second vector
172
+ * @returns Dot product, or 0 if vectors have different lengths
173
+ *
174
+ * @example
175
+ * ```typescript
176
+ * const dot = dotProduct([1, 2, 3], [4, 5, 6]);
177
+ * console.log(dot); // 32
178
+ * ```
179
+ */
180
+ declare function dotProduct(a: number[], b: number[]): number;
181
+ /**
182
+ * Calculate magnitude (L2 norm) of a vector
183
+ *
184
+ * @param vec - Input vector
185
+ * @returns Magnitude (Euclidean length)
186
+ *
187
+ * @example
188
+ * ```typescript
189
+ * const mag = magnitude([3, 4]);
190
+ * console.log(mag); // 5
191
+ * ```
192
+ */
193
+ declare function magnitude(vec: number[]): number;
194
+ /**
195
+ * Normalize a vector to unit length
196
+ *
197
+ * @param vec - Input vector
198
+ * @returns Normalized vector (magnitude = 1), or original if magnitude is 0
199
+ *
200
+ * @example
201
+ * ```typescript
202
+ * const normalized = normalize([3, 4]);
203
+ * console.log(normalized); // [0.6, 0.8]
204
+ * ```
205
+ */
206
+ declare function normalize(vec: number[]): number[];
207
+
208
+ /**
209
+ * Base class for file-based stores with rotation support
210
+ *
211
+ * Provides JSONL file rotation, segmentation by date, and automatic cleanup.
212
+ * Used by history stores, feedback stores, and other persistent logging mechanisms.
213
+ */
214
+
215
+ interface FileRotationOptions {
216
+ /**
217
+ * Base directory path for storing files
218
+ * @default '.kb/mind/store/'
219
+ */
220
+ basePath?: string;
221
+ /**
222
+ * Prefix for generated filenames
223
+ * @default 'store-'
224
+ */
225
+ filePrefix?: string;
226
+ /**
227
+ * Maximum number of records per file before rotation
228
+ * @default 1000
229
+ */
230
+ maxRecordsPerFile?: number;
231
+ /**
232
+ * Maximum number of files to keep (oldest deleted first)
233
+ * @default 30
234
+ */
235
+ maxFiles?: number;
236
+ }
237
+ /**
238
+ * Abstract base class for file-based stores with automatic rotation
239
+ *
240
+ * Features:
241
+ * - JSONL format (one JSON object per line)
242
+ * - Date-based file segmentation (YYYYMMDD-timestamp.jsonl)
243
+ * - Automatic rotation when maxRecordsPerFile reached
244
+ * - Automatic cleanup when maxFiles exceeded
245
+ * - Sorted file iteration (oldest to newest)
246
+ *
247
+ * @example
248
+ * ```typescript
249
+ * class MyStore extends FileRotationStore<MyRecord> {
250
+ * async save(record: MyRecord): Promise<void> {
251
+ * return this.appendRecord(record);
252
+ * }
253
+ *
254
+ * async find(criteria: any): Promise<MyRecord[]> {
255
+ * return this.readRecords((rec) => rec.id === criteria.id);
256
+ * }
257
+ * }
258
+ * ```
259
+ */
260
+ declare abstract class FileRotationStore<TRecord> {
261
+ protected readonly storage: IStorage;
262
+ protected readonly basePath: string;
263
+ protected readonly filePrefix: string;
264
+ protected readonly maxRecordsPerFile: number;
265
+ protected readonly maxFiles: number;
266
+ constructor(storage: IStorage, options?: FileRotationOptions);
267
+ /**
268
+ * Append a record to the current writable file
269
+ *
270
+ * Automatically handles:
271
+ * - File rotation when maxRecordsPerFile exceeded
272
+ * - Cleanup when maxFiles exceeded
273
+ * - JSONL formatting
274
+ *
275
+ * @param record - Record to append
276
+ */
277
+ protected appendRecord(record: TRecord): Promise<void>;
278
+ /**
279
+ * Read records from all files, optionally filtering
280
+ *
281
+ * @param filter - Optional filter function
282
+ * @param limit - Maximum number of records to return
283
+ * @returns Array of records matching filter
284
+ */
285
+ protected readRecords(filter?: (record: TRecord) => boolean, limit?: number): Promise<TRecord[]>;
286
+ /**
287
+ * Get the current writable file path
288
+ *
289
+ * Creates a new segment if:
290
+ * - No files exist
291
+ * - Latest file has >= maxRecordsPerFile records
292
+ *
293
+ * @returns Path to writable file
294
+ */
295
+ protected getWritableFile(): Promise<string>;
296
+ /**
297
+ * Get all store files sorted by timestamp (oldest to newest)
298
+ *
299
+ * @returns Sorted array of file paths
300
+ */
301
+ protected getFilesSorted(): Promise<string[]>;
302
+ /**
303
+ * Generate a segment file path from timestamp
304
+ *
305
+ * Format: {filePrefix}YYYYMMDD-{timestamp}.jsonl
306
+ * Example: history-20251209-1733769000123.jsonl
307
+ *
308
+ * @param ts - Unix timestamp in milliseconds
309
+ * @returns Full file path
310
+ */
311
+ protected segmentPath(ts: number): string;
312
+ /**
313
+ * Enforce file rotation by deleting oldest files if maxFiles exceeded
314
+ */
315
+ protected enforceRotation(): Promise<void>;
316
+ /**
317
+ * Ensure path ends with trailing slash
318
+ */
319
+ protected ensureTrailingSlash(p: string): string;
320
+ }
321
+
322
+ /**
323
+ * JSON file operations for KB Labs Mind
324
+ */
325
+ /**
326
+ * Read JSON file with error handling
327
+ */
328
+ declare function readJson<T = any>(filePath: string): Promise<T | null>;
329
+ /**
330
+ * Write JSON file atomically with sorted keys
331
+ */
332
+ declare function writeJson<T>(filePath: string, data: T): Promise<void>;
333
+ /**
334
+ * Compute hash of JSON content
335
+ */
336
+ declare function computeJsonHash(data: any): string;
337
+
338
+ /**
339
+ * @module @kb-labs/mind-core/verification
340
+ * Mind index verification utilities
341
+ *
342
+ * Moved from mind-gateway to break circular dependency (TASK-004)
343
+ */
344
+ interface VerifyResult {
345
+ ok: boolean;
346
+ code: string | null;
347
+ inconsistencies: string[];
348
+ hint: string;
349
+ }
350
+ /**
351
+ * Verify Mind index integrity
352
+ *
353
+ * Checks:
354
+ * 1. Main index file exists (.kb/mind/index.json)
355
+ * 2. Individual file hashes match (api-index, deps, recent-diff)
356
+ * 3. Combined index checksum is valid
357
+ * 4. Required files are present
358
+ *
359
+ * @param cwd - Workspace root directory
360
+ * @returns Verification result with inconsistencies list
361
+ *
362
+ * @example
363
+ * ```typescript
364
+ * const result = await verifyIndexes('/path/to/workspace');
365
+ * if (!result.ok) {
366
+ * console.error('Inconsistencies:', result.inconsistencies);
367
+ * console.log('Hint:', result.hint);
368
+ * }
369
+ * ```
370
+ */
371
+ declare function verifyIndexes(cwd: string): Promise<VerifyResult>;
372
+
373
+ /**
374
+ * Default configurations for KB Labs Mind
375
+ */
376
+
377
+ /**
378
+ * Default context budget
379
+ */
380
+ declare const DEFAULT_BUDGET: ContextBudget;
381
+ /**
382
+ * Default context preset
383
+ */
384
+ declare const DEFAULT_PRESET: ContextPreset;
385
+ /**
386
+ * Default time budget for indexing operations (ms)
387
+ */
388
+ declare const DEFAULT_TIME_BUDGET_MS = 800;
389
+ /**
390
+ * Maximum file size to process (bytes)
391
+ */
392
+ declare const MAX_FILE_SIZE_BYTES: number;
393
+ /**
394
+ * Maximum lines per snippet
395
+ */
396
+ declare const MAX_SNIPPET_LINES = 60;
397
+ /**
398
+ * Generator string for artifacts
399
+ */
400
+ declare function getGenerator(): string;
401
+
402
+ export { DEFAULT_BUDGET, DEFAULT_PRESET, DEFAULT_TIME_BUDGET_MS, DefaultTokenEstimator, ERROR_HINTS, type ErrorCode, type FileRotationOptions, FileRotationStore, MAX_FILE_SIZE_BYTES, MAX_SNIPPET_LINES, MindError, type VerifyResult, computeJsonHash, cosineSimilarity, createMindError, defaultTokenEstimator, dotProduct, estimateTokens, findWorkspaceRoot, fromPosix, getExitCode, getGenerator, isMindError, magnitude, makeRelativeToRoot, normalize, readJson, sha256, sha256Buffer, sha256File, shouldIgnorePath, toPosix, truncateToTokens, verifyIndexes, wrapError, writeJson };
package/dist/index.js ADDED
@@ -0,0 +1,574 @@
1
+ export * from '@kb-labs/mind-types';
2
+ import { createHash } from 'crypto';
3
+ import path, { dirname } from 'path';
4
+ import { existsSync, promises } from 'fs';
5
+ import { readFile } from 'fs/promises';
6
+
7
+ // src/index.ts
8
+
9
+ // src/error/mind-error.ts
10
+ var MindError = class extends Error {
11
+ constructor(code, message, hint, meta) {
12
+ super(message);
13
+ this.code = code;
14
+ this.hint = hint;
15
+ this.meta = meta;
16
+ this.name = "MindError";
17
+ }
18
+ };
19
+ function getExitCode(err) {
20
+ if (err.code === "MIND_FORBIDDEN") {
21
+ return 3;
22
+ }
23
+ if (err.code === "MIND_NO_GIT") {
24
+ return 2;
25
+ }
26
+ if (err.code === "MIND_FS_TIMEOUT") {
27
+ return 2;
28
+ }
29
+ if (err.code === "MIND_PARSE_ERROR") {
30
+ return 1;
31
+ }
32
+ if (err.code === "MIND_PACK_BUDGET_EXCEEDED") {
33
+ return 1;
34
+ }
35
+ if (err.code.startsWith("MIND_")) {
36
+ return 1;
37
+ }
38
+ return 1;
39
+ }
40
+ var ERROR_HINTS = {
41
+ MIND_NO_GIT: "Initialize git repository or run from a git repository",
42
+ MIND_FS_TIMEOUT: "File system operation timed out - try increasing time budget",
43
+ MIND_PARSE_ERROR: "Failed to parse file - check syntax and try again",
44
+ MIND_PACK_BUDGET_EXCEEDED: "Context pack exceeds token budget - reduce content or increase budget",
45
+ MIND_FORBIDDEN: "Operation not permitted - check file permissions",
46
+ MIND_TIME_BUDGET: "Time budget exceeded - operation completed partially",
47
+ MIND_BAD_FLAGS: "Invalid command line flags - check values and try again",
48
+ MIND_INVALID_FLAG: "Invalid flag value - check format and try again",
49
+ MIND_BUNDLE_TIMEOUT: "Bundle operation timed out - skipped bundle information",
50
+ MIND_FEED_ERROR: "Mind feed operation failed - check logs for details",
51
+ MIND_INIT_ERROR: "Mind initialization failed - check permissions and try again",
52
+ MIND_UPDATE_ERROR: "Mind update operation failed - check logs for details",
53
+ MIND_PACK_ERROR: "Mind pack operation failed - check logs for details",
54
+ MIND_GIT_ERROR: "Git operation failed - check git repository status",
55
+ MIND_INDEX_NOT_FOUND: 'Mind indexes not found - run "kb mind init" first',
56
+ MIND_INVALID_PATH: "Invalid file or directory path - check path exists and is accessible",
57
+ MIND_DEPENDENCY_ERROR: "Dependency resolution failed - check package configuration",
58
+ MIND_BUILD_ERROR: "Build operation failed - check configuration and try again"
59
+ };
60
+ function createMindError(code, message, meta) {
61
+ return new MindError(code, message, ERROR_HINTS[code], meta);
62
+ }
63
+ function wrapError(error, code = "MIND_FEED_ERROR") {
64
+ if (error instanceof MindError) {
65
+ return error;
66
+ }
67
+ const message = error instanceof Error ? error.message : String(error);
68
+ return createMindError(code, message, { originalError: error });
69
+ }
70
+ function isMindError(error) {
71
+ return error instanceof MindError;
72
+ }
73
+
74
+ // src/utils/token.ts
75
+ var DefaultTokenEstimator = class {
76
+ charsPerToken = 4;
77
+ codeBonus = 0.1;
78
+ // 10% bonus for code-like content
79
+ punctuationWeight = 0.8;
80
+ estimate(text) {
81
+ if (!text || text.length === 0) {
82
+ return 0;
83
+ }
84
+ const words = text.match(/\b\w+\b/g) || [];
85
+ const punctuation = text.match(/[^\w\s]/g) || [];
86
+ const whitespace = text.match(/\s/g) || [];
87
+ let tokens = words.length;
88
+ tokens += punctuation.length * this.punctuationWeight;
89
+ tokens += whitespace.length * 0.3;
90
+ const codeIndicators = text.match(/[{}();=<>]/g) || [];
91
+ if (codeIndicators.length > words.length * 0.1) {
92
+ tokens *= 1 + this.codeBonus;
93
+ }
94
+ const charBasedEstimate = text.length / this.charsPerToken;
95
+ return Math.ceil(Math.max(tokens, charBasedEstimate));
96
+ }
97
+ truncate(text, maxTokens, mode) {
98
+ if (this.estimate(text) <= maxTokens) {
99
+ return text;
100
+ }
101
+ const lines = text.split("\n");
102
+ const estimatedTokens = this.estimate(text);
103
+ const ratio = maxTokens / estimatedTokens;
104
+ const targetLines = Math.max(1, Math.floor(lines.length * ratio));
105
+ if (targetLines >= lines.length) {
106
+ return text;
107
+ }
108
+ switch (mode) {
109
+ case "start":
110
+ return lines.slice(0, targetLines).join("\n");
111
+ case "end":
112
+ return lines.slice(-targetLines).join("\n");
113
+ case "middle":
114
+ default: {
115
+ const startLines = Math.max(1, Math.floor(targetLines / 2));
116
+ const endLines = Math.max(1, targetLines - startLines);
117
+ const start = lines.slice(0, startLines);
118
+ const end = lines.slice(-endLines);
119
+ return [...start, "...", ...end].join("\n");
120
+ }
121
+ }
122
+ }
123
+ };
124
+ var defaultTokenEstimator = new DefaultTokenEstimator();
125
+ function estimateTokens(text) {
126
+ return defaultTokenEstimator.estimate(text);
127
+ }
128
+ function truncateToTokens(text, maxTokens, mode = "middle") {
129
+ return defaultTokenEstimator.truncate(text, maxTokens, mode);
130
+ }
131
+ function sha256(content) {
132
+ return createHash("sha256").update(content, "utf8").digest("hex");
133
+ }
134
+ function sha256Buffer(buffer) {
135
+ return createHash("sha256").update(buffer).digest("hex");
136
+ }
137
+ async function sha256File(filePath) {
138
+ const { readFile: readFile2 } = await import('fs/promises');
139
+ const content = await readFile2(filePath);
140
+ return sha256Buffer(content);
141
+ }
142
+ function toPosix(filePath) {
143
+ return filePath.replace(/\\/g, "/");
144
+ }
145
+ function fromPosix(posixPath) {
146
+ return posixPath.split("/").join(path.sep);
147
+ }
148
+ async function findWorkspaceRoot(cwd) {
149
+ let current = path.resolve(cwd);
150
+ const root = path.parse(current).root;
151
+ while (current !== root) {
152
+ if (existsSync(path.join(current, ".git"))) {
153
+ return toPosix(current);
154
+ }
155
+ const packageJsonPath = path.join(current, "package.json");
156
+ if (existsSync(packageJsonPath)) {
157
+ try {
158
+ const packageJsonContent = await readFile(packageJsonPath, "utf8");
159
+ const packageJson = JSON.parse(packageJsonContent);
160
+ if (packageJson.workspaces || packageJson.pnpm?.workspace) {
161
+ return toPosix(current);
162
+ }
163
+ } catch {
164
+ }
165
+ }
166
+ if (existsSync(path.join(current, "pnpm-workspace.yaml"))) {
167
+ return toPosix(current);
168
+ }
169
+ current = path.dirname(current);
170
+ }
171
+ return toPosix(cwd);
172
+ }
173
+ function makeRelativeToRoot(absolutePath, root) {
174
+ const relative = path.relative(root, absolutePath);
175
+ return toPosix(relative);
176
+ }
177
+ function shouldIgnorePath(filePath) {
178
+ const posixPath = toPosix(filePath);
179
+ const ignorePatterns = [
180
+ "node_modules/**",
181
+ ".git/**",
182
+ ".kb/**",
183
+ // except .kb/mind/**
184
+ "dist/**",
185
+ "coverage/**",
186
+ ".turbo/**",
187
+ ".vite/**",
188
+ "**/*.log",
189
+ "**/*.tmp",
190
+ "**/*.temp"
191
+ ];
192
+ const extensionPatterns = [".log", ".tmp", ".temp"];
193
+ if (posixPath.startsWith(".kb/") && !posixPath.startsWith(".kb/mind/")) {
194
+ return true;
195
+ }
196
+ if (posixPath.startsWith(".kb/mind/")) {
197
+ return false;
198
+ }
199
+ if (extensionPatterns.some((ext) => posixPath.endsWith(ext))) {
200
+ return true;
201
+ }
202
+ return ignorePatterns.some((pattern) => {
203
+ if (pattern.endsWith("/**")) {
204
+ const prefix = pattern.slice(0, -3);
205
+ return posixPath.startsWith(prefix + "/") || posixPath === prefix;
206
+ }
207
+ if (pattern.endsWith("**")) {
208
+ const prefix = pattern.slice(0, -2);
209
+ return posixPath.startsWith(prefix);
210
+ }
211
+ if (pattern.startsWith("**/")) {
212
+ const suffix = pattern.slice(3);
213
+ return posixPath.endsWith(suffix);
214
+ }
215
+ if (pattern.includes("*")) {
216
+ let regexPattern = pattern.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*");
217
+ if (pattern.startsWith("**/")) {
218
+ regexPattern = ".*" + regexPattern.slice(3);
219
+ }
220
+ const regex = new RegExp("^" + regexPattern + "$");
221
+ return regex.test(posixPath);
222
+ }
223
+ return posixPath.includes(pattern);
224
+ });
225
+ }
226
+
227
+ // src/utils/math.ts
228
+ function cosineSimilarity(a, b) {
229
+ if (a.length !== b.length) {
230
+ return 0;
231
+ }
232
+ let dotProduct2 = 0;
233
+ let normA = 0;
234
+ let normB = 0;
235
+ for (let i = 0; i < a.length; i++) {
236
+ const av = a[i] ?? 0;
237
+ const bv = b[i] ?? 0;
238
+ dotProduct2 += av * bv;
239
+ normA += av * av;
240
+ normB += bv * bv;
241
+ }
242
+ if (normA === 0 || normB === 0) {
243
+ return 0;
244
+ }
245
+ return dotProduct2 / Math.sqrt(normA * normB);
246
+ }
247
+ function dotProduct(a, b) {
248
+ if (a.length !== b.length) {
249
+ return 0;
250
+ }
251
+ let result = 0;
252
+ for (let i = 0; i < a.length; i++) {
253
+ result += (a[i] ?? 0) * (b[i] ?? 0);
254
+ }
255
+ return result;
256
+ }
257
+ function magnitude(vec) {
258
+ let sum = 0;
259
+ for (let i = 0; i < vec.length; i++) {
260
+ const v = vec[i] ?? 0;
261
+ sum += v * v;
262
+ }
263
+ return Math.sqrt(sum);
264
+ }
265
+ function normalize(vec) {
266
+ const mag = magnitude(vec);
267
+ if (mag === 0) {
268
+ return vec;
269
+ }
270
+ return vec.map((v) => (v ?? 0) / mag);
271
+ }
272
+ var FileRotationStore = class {
273
+ constructor(storage, options = {}) {
274
+ this.storage = storage;
275
+ this.basePath = options.basePath ? this.ensureTrailingSlash(options.basePath) : ".kb/mind/store/";
276
+ this.filePrefix = options.filePrefix ?? "store-";
277
+ this.maxRecordsPerFile = options.maxRecordsPerFile ?? 1e3;
278
+ this.maxFiles = options.maxFiles ?? 30;
279
+ }
280
+ basePath;
281
+ filePrefix;
282
+ maxRecordsPerFile;
283
+ maxFiles;
284
+ /**
285
+ * Append a record to the current writable file
286
+ *
287
+ * Automatically handles:
288
+ * - File rotation when maxRecordsPerFile exceeded
289
+ * - Cleanup when maxFiles exceeded
290
+ * - JSONL formatting
291
+ *
292
+ * @param record - Record to append
293
+ */
294
+ async appendRecord(record) {
295
+ const target = await this.getWritableFile();
296
+ const line = JSON.stringify({ v: 1, record }) + "\n";
297
+ const existing = await this.storage.read(target);
298
+ const buffer = existing ? Buffer.concat([existing, Buffer.from(line, "utf8")]) : Buffer.from(line, "utf8");
299
+ await this.storage.write(target, buffer);
300
+ await this.enforceRotation();
301
+ }
302
+ /**
303
+ * Read records from all files, optionally filtering
304
+ *
305
+ * @param filter - Optional filter function
306
+ * @param limit - Maximum number of records to return
307
+ * @returns Array of records matching filter
308
+ */
309
+ async readRecords(filter, limit) {
310
+ const files = await this.getFilesSorted();
311
+ const results = [];
312
+ for (const file of files) {
313
+ if (limit && results.length >= limit) {
314
+ break;
315
+ }
316
+ const buf = await this.storage.read(file);
317
+ if (!buf) {
318
+ continue;
319
+ }
320
+ const lines = buf.toString("utf8").split("\n").filter(Boolean);
321
+ for (const line of lines) {
322
+ if (limit && results.length >= limit) {
323
+ break;
324
+ }
325
+ try {
326
+ const parsed = JSON.parse(line);
327
+ const rec = parsed.record;
328
+ if (!filter || filter(rec)) {
329
+ results.push(rec);
330
+ }
331
+ } catch {
332
+ continue;
333
+ }
334
+ }
335
+ }
336
+ return limit ? results.slice(0, limit) : results;
337
+ }
338
+ /**
339
+ * Get the current writable file path
340
+ *
341
+ * Creates a new segment if:
342
+ * - No files exist
343
+ * - Latest file has >= maxRecordsPerFile records
344
+ *
345
+ * @returns Path to writable file
346
+ */
347
+ async getWritableFile() {
348
+ const files = await this.getFilesSorted();
349
+ if (files.length === 0) {
350
+ return this.segmentPath(Date.now());
351
+ }
352
+ const latest = files[files.length - 1];
353
+ const buf = await this.storage.read(latest);
354
+ if (!buf) {
355
+ return latest;
356
+ }
357
+ const count = buf.toString("utf8").split("\n").filter(Boolean).length;
358
+ if (count >= this.maxRecordsPerFile) {
359
+ return this.segmentPath(Date.now());
360
+ }
361
+ return latest;
362
+ }
363
+ /**
364
+ * Get all store files sorted by timestamp (oldest to newest)
365
+ *
366
+ * @returns Sorted array of file paths
367
+ */
368
+ async getFilesSorted() {
369
+ const files = await this.storage.list(this.basePath);
370
+ return files.filter((f) => f.startsWith(this.basePath + this.filePrefix) && f.endsWith(".jsonl")).sort();
371
+ }
372
+ /**
373
+ * Generate a segment file path from timestamp
374
+ *
375
+ * Format: {filePrefix}YYYYMMDD-{timestamp}.jsonl
376
+ * Example: history-20251209-1733769000123.jsonl
377
+ *
378
+ * @param ts - Unix timestamp in milliseconds
379
+ * @returns Full file path
380
+ */
381
+ segmentPath(ts) {
382
+ const date = new Date(ts);
383
+ const day = String(date.getDate()).padStart(2, "0");
384
+ const month = String(date.getMonth() + 1).padStart(2, "0");
385
+ const year = date.getFullYear();
386
+ const filename = `${this.filePrefix}${year}${month}${day}-${ts}.jsonl`;
387
+ return path.posix.join(this.basePath, filename);
388
+ }
389
+ /**
390
+ * Enforce file rotation by deleting oldest files if maxFiles exceeded
391
+ */
392
+ async enforceRotation() {
393
+ const files = await this.getFilesSorted();
394
+ if (files.length <= this.maxFiles) {
395
+ return;
396
+ }
397
+ const excess = files.length - this.maxFiles;
398
+ const toDelete = files.slice(0, excess);
399
+ await Promise.all(toDelete.map((f) => this.storage.delete(f)));
400
+ }
401
+ /**
402
+ * Ensure path ends with trailing slash
403
+ */
404
+ ensureTrailingSlash(p) {
405
+ return p.endsWith("/") ? p : `${p}/`;
406
+ }
407
+ };
408
+ function sortKeysRecursively(obj) {
409
+ if (obj === null || typeof obj !== "object") {
410
+ return obj;
411
+ }
412
+ if (Array.isArray(obj)) {
413
+ return obj.map(sortKeysRecursively);
414
+ }
415
+ const sorted = {};
416
+ const keys = Object.keys(obj).sort();
417
+ for (const key of keys) {
418
+ sorted[key] = sortKeysRecursively(obj[key]);
419
+ }
420
+ return sorted;
421
+ }
422
+ async function readJson(filePath) {
423
+ try {
424
+ const content = await promises.readFile(filePath, "utf8");
425
+ return JSON.parse(content);
426
+ } catch (error) {
427
+ if (error.code === "ENOENT") {
428
+ return null;
429
+ }
430
+ throw error;
431
+ }
432
+ }
433
+ async function writeJson(filePath, data) {
434
+ const tmp = `${filePath}.tmp`;
435
+ const sorted = sortKeysRecursively(data);
436
+ const content = JSON.stringify(sorted, null, 2) + "\n";
437
+ await promises.mkdir(dirname(filePath), { recursive: true });
438
+ await promises.writeFile(tmp, content, "utf8");
439
+ if (process.platform === "win32") {
440
+ try {
441
+ await promises.unlink(filePath);
442
+ } catch (err) {
443
+ if (err.code !== "ENOENT") {
444
+ throw err;
445
+ }
446
+ }
447
+ }
448
+ await promises.rename(tmp, filePath);
449
+ }
450
+ function computeJsonHash(data) {
451
+ const content = JSON.stringify(sortKeysRecursively(data));
452
+ return sha256(content);
453
+ }
454
+ async function verifyIndexes(cwd) {
455
+ const inconsistencies = [];
456
+ try {
457
+ const index = await readJson(`${cwd}/.kb/mind/index.json`);
458
+ if (!index) {
459
+ return {
460
+ ok: false,
461
+ code: "MIND_NO_INDEX",
462
+ inconsistencies: ["Main index file not found"],
463
+ hint: 'Run "kb mind rag-index" to initialize indexes'
464
+ };
465
+ }
466
+ const [apiIndex, depsGraph, recentDiff, meta, docs] = await Promise.all([
467
+ readJson(`${cwd}/.kb/mind/api-index.json`),
468
+ readJson(`${cwd}/.kb/mind/deps.json`),
469
+ readJson(`${cwd}/.kb/mind/recent-diff.json`),
470
+ readJson(`${cwd}/.kb/mind/meta.json`),
471
+ readJson(`${cwd}/.kb/mind/docs.json`)
472
+ ]);
473
+ if (apiIndex) {
474
+ const computedHash = computeJsonHash(apiIndex);
475
+ if (computedHash !== index.apiIndexHash) {
476
+ inconsistencies.push(
477
+ `API index hash mismatch: expected ${index.apiIndexHash}, got ${computedHash}`
478
+ );
479
+ }
480
+ } else if (index.apiIndexHash) {
481
+ inconsistencies.push("API index file missing but hash is present");
482
+ }
483
+ if (depsGraph) {
484
+ const computedHash = computeJsonHash(depsGraph);
485
+ if (computedHash !== index.depsHash) {
486
+ inconsistencies.push(
487
+ `Dependencies hash mismatch: expected ${index.depsHash}, got ${computedHash}`
488
+ );
489
+ }
490
+ } else if (index.depsHash) {
491
+ inconsistencies.push("Dependencies file missing but hash is present");
492
+ }
493
+ if (recentDiff) {
494
+ const computedHash = computeJsonHash(recentDiff);
495
+ if (computedHash !== index.recentDiffHash) {
496
+ inconsistencies.push(
497
+ `Recent diff hash mismatch: expected ${index.recentDiffHash}, got ${computedHash}`
498
+ );
499
+ }
500
+ } else if (index.recentDiffHash) {
501
+ inconsistencies.push("Recent diff file missing but hash is present");
502
+ }
503
+ const combinedContent = JSON.stringify({
504
+ apiIndex: apiIndex || {},
505
+ deps: depsGraph || {},
506
+ recentDiff: recentDiff || {},
507
+ meta: meta || {},
508
+ docs: docs || {}
509
+ });
510
+ const computedChecksum = sha256(combinedContent);
511
+ if (computedChecksum !== index.indexChecksum) {
512
+ inconsistencies.push(
513
+ `Index checksum mismatch: expected ${index.indexChecksum}, got ${computedChecksum}`
514
+ );
515
+ }
516
+ const expectedFiles = ["api-index.json", "deps.json", "recent-diff.json"];
517
+ for (const file of expectedFiles) {
518
+ try {
519
+ await promises.access(`${cwd}/.kb/mind/${file}`);
520
+ } catch {
521
+ inconsistencies.push(`Required index file missing: ${file}`);
522
+ }
523
+ }
524
+ const ok = inconsistencies.length === 0;
525
+ const code = ok ? null : "MIND_INDEX_INCONSISTENT";
526
+ const hint = ok ? "All indexes are consistent and up to date" : 'Run "kb mind rag-index" to rebuild indexes';
527
+ return { ok, code, inconsistencies, hint };
528
+ } catch (error) {
529
+ return {
530
+ ok: false,
531
+ code: "MIND_VERIFY_ERROR",
532
+ inconsistencies: [`Verification failed: ${error.message}`],
533
+ hint: "Check file permissions and workspace structure"
534
+ };
535
+ }
536
+ }
537
+
538
+ // src/defaults.ts
539
+ var DEFAULT_BUDGET = {
540
+ totalTokens: 9e3,
541
+ caps: {
542
+ intent_summary: 300,
543
+ product_overview: 600,
544
+ project_meta: 500,
545
+ api_signatures: 2200,
546
+ recent_diffs: 1200,
547
+ docs_overview: 600,
548
+ impl_snippets: 3e3,
549
+ configs_profiles: 700
550
+ },
551
+ truncation: "middle"
552
+ };
553
+ var DEFAULT_PRESET = {
554
+ name: "balanced",
555
+ weight: {
556
+ overview: 1,
557
+ api: 1.2,
558
+ diffs: 1,
559
+ snippets: 1.4,
560
+ configs: 0.6,
561
+ meta: 0.8,
562
+ docs: 0.9
563
+ }
564
+ };
565
+ var DEFAULT_TIME_BUDGET_MS = 800;
566
+ var MAX_FILE_SIZE_BYTES = 1.5 * 1024 * 1024;
567
+ var MAX_SNIPPET_LINES = 60;
568
+ function getGenerator() {
569
+ return "kb-labs-mind@0.1.0";
570
+ }
571
+
572
+ export { DEFAULT_BUDGET, DEFAULT_PRESET, DEFAULT_TIME_BUDGET_MS, DefaultTokenEstimator, ERROR_HINTS, FileRotationStore, MAX_FILE_SIZE_BYTES, MAX_SNIPPET_LINES, MindError, computeJsonHash, cosineSimilarity, createMindError, defaultTokenEstimator, dotProduct, estimateTokens, findWorkspaceRoot, fromPosix, getExitCode, getGenerator, isMindError, magnitude, makeRelativeToRoot, normalize, readJson, sha256, sha256Buffer, sha256File, shouldIgnorePath, toPosix, truncateToTokens, verifyIndexes, wrapError, writeJson };
573
+ //# sourceMappingURL=index.js.map
574
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/error/mind-error.ts","../src/utils/token.ts","../src/utils/hash.ts","../src/utils/paths.ts","../src/utils/math.ts","../src/utils/file-rotation.ts","../src/utils/json.ts","../src/verification/verify-indexes.ts","../src/defaults.ts"],"names":["readFile","dotProduct","path","fsp"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @module @kb-labs/mind-core/error\n * Standardized error class for KB Labs Mind\n */\n\nexport class MindError extends Error {\n constructor(\n public code: string,\n message: string,\n public hint?: string,\n public meta?: any\n ) {\n super(message);\n this.name = 'MindError';\n }\n}\n\n/**\n * Maps MindError codes to CLI exit codes\n */\nexport function getExitCode(err: MindError): number {\n if (err.code === 'MIND_FORBIDDEN') {return 3;}\n if (err.code === 'MIND_NO_GIT') {return 2;}\n if (err.code === 'MIND_FS_TIMEOUT') {return 2;}\n if (err.code === 'MIND_PARSE_ERROR') {return 1;}\n if (err.code === 'MIND_PACK_BUDGET_EXCEEDED') {return 1;}\n if (err.code.startsWith('MIND_')) {return 1;}\n return 1;\n}\n\n/**\n * Error codes with their standard hints\n */\nexport const ERROR_HINTS = {\n MIND_NO_GIT: 'Initialize git repository or run from a git repository',\n MIND_FS_TIMEOUT: 'File system operation timed out - try increasing time budget',\n MIND_PARSE_ERROR: 'Failed to parse file - check syntax and try again',\n MIND_PACK_BUDGET_EXCEEDED: 'Context pack exceeds token budget - reduce content or increase budget',\n MIND_FORBIDDEN: 'Operation not permitted - check file permissions',\n MIND_TIME_BUDGET: 'Time budget exceeded - operation completed partially',\n MIND_BAD_FLAGS: 'Invalid command line flags - check values and try again',\n MIND_INVALID_FLAG: 'Invalid flag value - check format and try again',\n MIND_BUNDLE_TIMEOUT: 'Bundle operation timed out - skipped bundle information',\n MIND_FEED_ERROR: 'Mind feed operation failed - check logs for details',\n MIND_INIT_ERROR: 'Mind initialization failed - check permissions and try again',\n MIND_UPDATE_ERROR: 'Mind update operation failed - check logs for details',\n MIND_PACK_ERROR: 'Mind pack operation failed - check logs for details',\n MIND_GIT_ERROR: 'Git operation failed - check git repository status',\n MIND_INDEX_NOT_FOUND: 'Mind indexes not found - run \"kb mind init\" first',\n MIND_INVALID_PATH: 'Invalid file or directory path - check path exists and is accessible',\n MIND_DEPENDENCY_ERROR: 'Dependency resolution failed - check package configuration',\n MIND_BUILD_ERROR: 'Build operation failed - check configuration and try again',\n} as const;\n\nexport type ErrorCode = keyof typeof ERROR_HINTS;\n\n/**\n * Create a MindError with standardized code and hint\n */\nexport function createMindError(\n code: ErrorCode,\n message: string,\n meta?: any\n): MindError {\n return new MindError(code, message, ERROR_HINTS[code], meta);\n}\n\n/**\n * Create a MindError from a generic error\n */\nexport function wrapError(error: unknown, code: ErrorCode = 'MIND_FEED_ERROR'): MindError {\n if (error instanceof MindError) {\n return error;\n }\n \n const message = error instanceof Error ? error.message : String(error);\n return createMindError(code, message, { originalError: error });\n}\n\n/**\n * Check if an error is a MindError\n */\nexport function isMindError(error: unknown): error is MindError {\n return error instanceof MindError;\n}\n","/**\n * Token estimation utilities for KB Labs Mind\n */\n\nimport type { ITokenEstimator } from \"../types/pack\";\n\n/**\n * Default whitespace-aware token estimator\n * Algorithm: ~3.8-4.2 chars/token based on whitespace and code patterns\n */\nexport class DefaultTokenEstimator implements ITokenEstimator {\n private readonly charsPerToken: number = 4.0;\n private readonly codeBonus: number = 0.1; // 10% bonus for code-like content\n private readonly punctuationWeight: number = 0.8;\n\n estimate(text: string): number {\n if (!text || text.length === 0) {return 0;}\n\n // Count words, punctuation, and whitespace\n const words = text.match(/\\b\\w+\\b/g) || [];\n const punctuation = text.match(/[^\\w\\s]/g) || [];\n const whitespace = text.match(/\\s/g) || [];\n \n // Base estimation\n let tokens = words.length;\n \n // Add punctuation with weight\n tokens += punctuation.length * this.punctuationWeight;\n \n // Add whitespace (spaces, newlines, tabs)\n tokens += whitespace.length * 0.3;\n \n // Apply code bonus if content looks like code\n const codeIndicators = text.match(/[{}();=<>]/g) || [];\n if (codeIndicators.length > words.length * 0.1) {\n tokens *= (1 + this.codeBonus);\n }\n \n // Apply character-based adjustment\n const charBasedEstimate = text.length / this.charsPerToken;\n \n // Use the higher of word-based or char-based estimate\n return Math.ceil(Math.max(tokens, charBasedEstimate));\n }\n\n truncate(text: string, maxTokens: number, mode: \"start\"|\"middle\"|\"end\"): string {\n if (this.estimate(text) <= maxTokens) {\n return text;\n }\n\n const lines = text.split('\\n');\n const estimatedTokens = this.estimate(text);\n const ratio = maxTokens / estimatedTokens;\n const targetLines = Math.max(1, Math.floor(lines.length * ratio));\n \n if (targetLines >= lines.length) {return text;}\n\n switch (mode) {\n case 'start':\n return lines.slice(0, targetLines).join('\\n');\n case 'end':\n return lines.slice(-targetLines).join('\\n');\n case 'middle':\n default: {\n const startLines = Math.max(1, Math.floor(targetLines / 2));\n const endLines = Math.max(1, targetLines - startLines);\n const start = lines.slice(0, startLines);\n const end = lines.slice(-endLines);\n return [...start, '...', ...end].join('\\n');\n }\n }\n }\n}\n\n/**\n * Default token estimator instance\n */\nexport const defaultTokenEstimator = new DefaultTokenEstimator();\n\n/**\n * Estimate tokens using default strategy\n */\nexport function estimateTokens(text: string): number {\n return defaultTokenEstimator.estimate(text);\n}\n\n/**\n * Truncate text to token limit using default strategy\n */\nexport function truncateToTokens(\n text: string, \n maxTokens: number, \n mode: \"start\"|\"middle\"|\"end\" = \"middle\"\n): string {\n return defaultTokenEstimator.truncate(text, maxTokens, mode);\n}\n","/**\n * Hashing utilities for KB Labs Mind\n */\n\nimport { createHash } from 'node:crypto';\n\n/**\n * Compute SHA256 hash for string content\n */\nexport function sha256(content: string): string {\n return createHash('sha256').update(content, 'utf8').digest('hex');\n}\n\n/**\n * Compute SHA256 hash for Buffer content\n */\nexport function sha256Buffer(buffer: Buffer): string {\n return createHash('sha256').update(buffer).digest('hex');\n}\n\n/**\n * Compute SHA256 hash for file content (streaming for large files)\n */\nexport async function sha256File(filePath: string): Promise<string> {\n const { readFile } = await import('node:fs/promises');\n const content = await readFile(filePath);\n return sha256Buffer(content);\n}\n","/**\n * Path utilities for KB Labs Mind\n */\n\nimport path from 'node:path';\nimport { existsSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\n\n/**\n * Convert path to POSIX format (forward slashes)\n */\nexport function toPosix(filePath: string): string {\n return filePath.replace(/\\\\/g, '/');\n}\n\n/**\n * Convert POSIX path back to platform-specific format\n */\nexport function fromPosix(posixPath: string): string {\n return posixPath.split('/').join(path.sep);\n}\n\n/**\n * Find workspace root by looking for git repository or monorepo indicators\n * Searches up the directory tree from cwd\n */\nexport async function findWorkspaceRoot(cwd: string): Promise<string> {\n let current = path.resolve(cwd);\n const root = path.parse(current).root;\n\n while (current !== root) {\n // Check for git repository\n if (existsSync(path.join(current, '.git'))) {\n return toPosix(current);\n }\n\n // Check for monorepo indicators\n const packageJsonPath = path.join(current, 'package.json');\n if (existsSync(packageJsonPath)) {\n try {\n const packageJsonContent = await readFile(packageJsonPath, 'utf8');\n const packageJson = JSON.parse(packageJsonContent);\n // Check for workspace configuration\n if (packageJson.workspaces || packageJson.pnpm?.workspace) {\n return toPosix(current);\n }\n } catch {\n // Ignore JSON parse errors\n }\n }\n\n // Check for pnpm-workspace.yaml\n if (existsSync(path.join(current, 'pnpm-workspace.yaml'))) {\n return toPosix(current);\n }\n\n // Move up one directory\n current = path.dirname(current);\n }\n\n // If no workspace found, return the original cwd as POSIX\n return toPosix(cwd);\n}\n\n/**\n * Make path relative to workspace root\n */\nexport function makeRelativeToRoot(absolutePath: string, root: string): string {\n const relative = path.relative(root, absolutePath);\n return toPosix(relative);\n}\n\n/**\n * Check if path should be ignored based on common patterns\n */\nexport function shouldIgnorePath(filePath: string): boolean {\n const posixPath = toPosix(filePath);\n \n const ignorePatterns = [\n 'node_modules/**',\n '.git/**',\n '.kb/**', // except .kb/mind/**\n 'dist/**',\n 'coverage/**',\n '.turbo/**',\n '.vite/**',\n '**/*.log',\n '**/*.tmp',\n '**/*.temp'\n ];\n \n // Simple file extension patterns\n const extensionPatterns = ['.log', '.tmp', '.temp'];\n\n // Special case: allow .kb/mind/** but ignore other .kb/**\n if (posixPath.startsWith('.kb/') && !posixPath.startsWith('.kb/mind/')) {\n return true;\n }\n \n // Allow .kb/mind/** paths\n if (posixPath.startsWith('.kb/mind/')) {\n return false;\n }\n \n // Check simple extension patterns first\n if (extensionPatterns.some(ext => posixPath.endsWith(ext))) {\n return true;\n }\n\n return ignorePatterns.some(pattern => {\n if (pattern.endsWith('/**')) {\n const prefix = pattern.slice(0, -3);\n return posixPath.startsWith(prefix + '/') || posixPath === prefix;\n }\n if (pattern.endsWith('**')) {\n const prefix = pattern.slice(0, -2);\n return posixPath.startsWith(prefix);\n }\n if (pattern.startsWith('**/')) {\n const suffix = pattern.slice(3);\n return posixPath.endsWith(suffix);\n }\n if (pattern.includes('*')) {\n // Simple glob pattern matching\n let regexPattern = pattern.replace(/\\*\\*/g, '.*').replace(/\\*/g, '[^/]*');\n // Handle **/*.ext patterns that should match files in any directory\n if (pattern.startsWith('**/')) {\n regexPattern = '.*' + regexPattern.slice(3);\n }\n const regex = new RegExp('^' + regexPattern + '$');\n return regex.test(posixPath);\n }\n return posixPath.includes(pattern);\n });\n}\n","/**\n * Mathematical utility functions for KB Labs Mind\n */\n\n/**\n * Calculate cosine similarity between two vectors\n *\n * Cosine similarity measures the cosine of the angle between two vectors,\n * producing a value between -1 and 1, where:\n * - 1 means vectors point in the same direction (identical)\n * - 0 means vectors are orthogonal (no similarity)\n * - -1 means vectors point in opposite directions\n *\n * @param a - First vector (array of numbers)\n * @param b - Second vector (array of numbers)\n * @returns Similarity score [0-1], or 0 if vectors have different lengths or zero magnitudes\n *\n * @example\n * ```typescript\n * const similarity = cosineSimilarity([1, 2, 3], [4, 5, 6]);\n * console.log(similarity); // ~0.974\n * ```\n */\nexport function cosineSimilarity(a: number[], b: number[]): number {\n // Vectors must have same dimensionality\n if (a.length !== b.length) {\n return 0;\n }\n\n let dotProduct = 0;\n let normA = 0;\n let normB = 0;\n\n // Calculate dot product and norms in single pass\n for (let i = 0; i < a.length; i++) {\n const av = a[i] ?? 0;\n const bv = b[i] ?? 0;\n dotProduct += av * bv;\n normA += av * av;\n normB += bv * bv;\n }\n\n // Handle zero magnitude vectors (division by zero)\n if (normA === 0 || normB === 0) {\n return 0;\n }\n\n // cosine(θ) = (a · b) / (||a|| * ||b||)\n return dotProduct / Math.sqrt(normA * normB);\n}\n\n/**\n * Calculate dot product of two vectors\n *\n * @param a - First vector\n * @param b - Second vector\n * @returns Dot product, or 0 if vectors have different lengths\n *\n * @example\n * ```typescript\n * const dot = dotProduct([1, 2, 3], [4, 5, 6]);\n * console.log(dot); // 32\n * ```\n */\nexport function dotProduct(a: number[], b: number[]): number {\n if (a.length !== b.length) {\n return 0;\n }\n\n let result = 0;\n for (let i = 0; i < a.length; i++) {\n result += (a[i] ?? 0) * (b[i] ?? 0);\n }\n return result;\n}\n\n/**\n * Calculate magnitude (L2 norm) of a vector\n *\n * @param vec - Input vector\n * @returns Magnitude (Euclidean length)\n *\n * @example\n * ```typescript\n * const mag = magnitude([3, 4]);\n * console.log(mag); // 5\n * ```\n */\nexport function magnitude(vec: number[]): number {\n let sum = 0;\n for (let i = 0; i < vec.length; i++) {\n const v = vec[i] ?? 0;\n sum += v * v;\n }\n return Math.sqrt(sum);\n}\n\n/**\n * Normalize a vector to unit length\n *\n * @param vec - Input vector\n * @returns Normalized vector (magnitude = 1), or original if magnitude is 0\n *\n * @example\n * ```typescript\n * const normalized = normalize([3, 4]);\n * console.log(normalized); // [0.6, 0.8]\n * ```\n */\nexport function normalize(vec: number[]): number[] {\n const mag = magnitude(vec);\n if (mag === 0) {\n return vec;\n }\n return vec.map(v => (v ?? 0) / mag);\n}\n","/**\n * Base class for file-based stores with rotation support\n *\n * Provides JSONL file rotation, segmentation by date, and automatic cleanup.\n * Used by history stores, feedback stores, and other persistent logging mechanisms.\n */\n\nimport path from 'node:path';\nimport type { IStorage } from '@kb-labs/sdk';\n\nexport interface FileRotationOptions {\n /**\n * Base directory path for storing files\n * @default '.kb/mind/store/'\n */\n basePath?: string;\n\n /**\n * Prefix for generated filenames\n * @default 'store-'\n */\n filePrefix?: string;\n\n /**\n * Maximum number of records per file before rotation\n * @default 1000\n */\n maxRecordsPerFile?: number;\n\n /**\n * Maximum number of files to keep (oldest deleted first)\n * @default 30\n */\n maxFiles?: number;\n}\n\n/**\n * Abstract base class for file-based stores with automatic rotation\n *\n * Features:\n * - JSONL format (one JSON object per line)\n * - Date-based file segmentation (YYYYMMDD-timestamp.jsonl)\n * - Automatic rotation when maxRecordsPerFile reached\n * - Automatic cleanup when maxFiles exceeded\n * - Sorted file iteration (oldest to newest)\n *\n * @example\n * ```typescript\n * class MyStore extends FileRotationStore<MyRecord> {\n * async save(record: MyRecord): Promise<void> {\n * return this.appendRecord(record);\n * }\n *\n * async find(criteria: any): Promise<MyRecord[]> {\n * return this.readRecords((rec) => rec.id === criteria.id);\n * }\n * }\n * ```\n */\nexport abstract class FileRotationStore<TRecord> {\n protected readonly basePath: string;\n protected readonly filePrefix: string;\n protected readonly maxRecordsPerFile: number;\n protected readonly maxFiles: number;\n\n constructor(\n protected readonly storage: IStorage,\n options: FileRotationOptions = {}\n ) {\n this.basePath = options.basePath ? this.ensureTrailingSlash(options.basePath) : '.kb/mind/store/';\n this.filePrefix = options.filePrefix ?? 'store-';\n this.maxRecordsPerFile = options.maxRecordsPerFile ?? 1000;\n this.maxFiles = options.maxFiles ?? 30;\n }\n\n /**\n * Append a record to the current writable file\n *\n * Automatically handles:\n * - File rotation when maxRecordsPerFile exceeded\n * - Cleanup when maxFiles exceeded\n * - JSONL formatting\n *\n * @param record - Record to append\n */\n protected async appendRecord(record: TRecord): Promise<void> {\n const target = await this.getWritableFile();\n const line = JSON.stringify({ v: 1, record }) + '\\n';\n\n const existing = await this.storage.read(target);\n const buffer = existing\n ? Buffer.concat([existing, Buffer.from(line, 'utf8')])\n : Buffer.from(line, 'utf8');\n\n await this.storage.write(target, buffer);\n await this.enforceRotation();\n }\n\n /**\n * Read records from all files, optionally filtering\n *\n * @param filter - Optional filter function\n * @param limit - Maximum number of records to return\n * @returns Array of records matching filter\n */\n protected async readRecords(\n filter?: (record: TRecord) => boolean,\n limit?: number\n ): Promise<TRecord[]> {\n const files = await this.getFilesSorted();\n const results: TRecord[] = [];\n\n for (const file of files) {\n if (limit && results.length >= limit) {break;}\n\n const buf = await this.storage.read(file);\n if (!buf) {continue;}\n\n const lines = buf.toString('utf8').split('\\n').filter(Boolean);\n for (const line of lines) {\n if (limit && results.length >= limit) {break;}\n\n try {\n const parsed = JSON.parse(line) as { v: number; record: TRecord };\n const rec = parsed.record;\n\n if (!filter || filter(rec)) {\n results.push(rec);\n }\n } catch {\n // Skip malformed lines\n continue;\n }\n }\n }\n\n return limit ? results.slice(0, limit) : results;\n }\n\n /**\n * Get the current writable file path\n *\n * Creates a new segment if:\n * - No files exist\n * - Latest file has >= maxRecordsPerFile records\n *\n * @returns Path to writable file\n */\n protected async getWritableFile(): Promise<string> {\n const files = await this.getFilesSorted();\n\n if (files.length === 0) {\n return this.segmentPath(Date.now());\n }\n\n const latest = files[files.length - 1]!;\n const buf = await this.storage.read(latest);\n\n if (!buf) {return latest;}\n\n const count = buf.toString('utf8').split('\\n').filter(Boolean).length;\n if (count >= this.maxRecordsPerFile) {\n return this.segmentPath(Date.now());\n }\n\n return latest;\n }\n\n /**\n * Get all store files sorted by timestamp (oldest to newest)\n *\n * @returns Sorted array of file paths\n */\n protected async getFilesSorted(): Promise<string[]> {\n const files = await this.storage.list(this.basePath);\n return files\n .filter((f) => f.startsWith(this.basePath + this.filePrefix) && f.endsWith('.jsonl'))\n .sort();\n }\n\n /**\n * Generate a segment file path from timestamp\n *\n * Format: {filePrefix}YYYYMMDD-{timestamp}.jsonl\n * Example: history-20251209-1733769000123.jsonl\n *\n * @param ts - Unix timestamp in milliseconds\n * @returns Full file path\n */\n protected segmentPath(ts: number): string {\n const date = new Date(ts);\n const day = String(date.getDate()).padStart(2, '0');\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const year = date.getFullYear();\n const filename = `${this.filePrefix}${year}${month}${day}-${ts}.jsonl`;\n return path.posix.join(this.basePath, filename);\n }\n\n /**\n * Enforce file rotation by deleting oldest files if maxFiles exceeded\n */\n protected async enforceRotation(): Promise<void> {\n const files = await this.getFilesSorted();\n if (files.length <= this.maxFiles) {return;}\n\n const excess = files.length - this.maxFiles;\n const toDelete = files.slice(0, excess);\n await Promise.all(toDelete.map((f: string) => this.storage.delete(f)));\n }\n\n /**\n * Ensure path ends with trailing slash\n */\n protected ensureTrailingSlash(p: string): string {\n return p.endsWith('/') ? p : `${p}/`;\n }\n}\n","/**\n * JSON file operations for KB Labs Mind\n */\n\nimport { promises as fsp } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { sha256 } from \"./hash\";\n\n/**\n * Recursively sort object keys for deterministic output\n */\nfunction sortKeysRecursively(obj: any): any {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map(sortKeysRecursively);\n }\n\n const sorted: any = {};\n const keys = Object.keys(obj).sort();\n\n for (const key of keys) {\n sorted[key] = sortKeysRecursively(obj[key]);\n }\n\n return sorted;\n}\n\n/**\n * Read JSON file with error handling\n */\nexport async function readJson<T = any>(filePath: string): Promise<T | null> {\n try {\n const content = await fsp.readFile(filePath, 'utf8');\n return JSON.parse(content) as T;\n } catch (error: any) {\n if (error.code === 'ENOENT') {\n return null;\n }\n throw error;\n }\n}\n\n/**\n * Write JSON file atomically with sorted keys\n */\nexport async function writeJson<T>(filePath: string, data: T): Promise<void> {\n const tmp = `${filePath}.tmp`;\n const sorted = sortKeysRecursively(data);\n const content = JSON.stringify(sorted, null, 2) + '\\n';\n\n // Ensure directory exists\n await fsp.mkdir(dirname(filePath), { recursive: true });\n\n // Write to temp file\n await fsp.writeFile(tmp, content, 'utf8');\n\n // Windows-safe atomic rename\n if (process.platform === \"win32\") {\n try {\n await fsp.unlink(filePath);\n } catch (err: any) {\n if (err.code !== \"ENOENT\") {throw err;}\n }\n }\n\n // Rename tmp to final location\n await fsp.rename(tmp, filePath);\n}\n\n/**\n * Compute hash of JSON content\n */\nexport function computeJsonHash(data: any): string {\n const content = JSON.stringify(sortKeysRecursively(data));\n return sha256(content);\n}\n","/**\n * @module @kb-labs/mind-core/verification\n * Mind index verification utilities\n *\n * Moved from mind-gateway to break circular dependency (TASK-004)\n */\n\nimport { readJson, computeJsonHash } from '../utils/json';\nimport { sha256 } from '../utils/hash';\nimport { promises as fsp } from 'node:fs';\n\nexport interface VerifyResult {\n ok: boolean;\n code: string | null;\n inconsistencies: string[];\n hint: string;\n}\n\n/**\n * Verify Mind index integrity\n *\n * Checks:\n * 1. Main index file exists (.kb/mind/index.json)\n * 2. Individual file hashes match (api-index, deps, recent-diff)\n * 3. Combined index checksum is valid\n * 4. Required files are present\n *\n * @param cwd - Workspace root directory\n * @returns Verification result with inconsistencies list\n *\n * @example\n * ```typescript\n * const result = await verifyIndexes('/path/to/workspace');\n * if (!result.ok) {\n * console.error('Inconsistencies:', result.inconsistencies);\n * console.log('Hint:', result.hint);\n * }\n * ```\n */\nexport async function verifyIndexes(cwd: string): Promise<VerifyResult> {\n const inconsistencies: string[] = [];\n\n try {\n // Load main index\n const index = await readJson(`${cwd}/.kb/mind/index.json`);\n if (!index) {\n return {\n ok: false,\n code: 'MIND_NO_INDEX',\n inconsistencies: ['Main index file not found'],\n hint: 'Run \"kb mind rag-index\" to initialize indexes',\n };\n }\n\n // Load all index files\n const [apiIndex, depsGraph, recentDiff, meta, docs] = await Promise.all([\n readJson(`${cwd}/.kb/mind/api-index.json`),\n readJson(`${cwd}/.kb/mind/deps.json`),\n readJson(`${cwd}/.kb/mind/recent-diff.json`),\n readJson(`${cwd}/.kb/mind/meta.json`),\n readJson(`${cwd}/.kb/mind/docs.json`),\n ]);\n\n // Verify individual file hashes\n if (apiIndex) {\n const computedHash = computeJsonHash(apiIndex);\n if (computedHash !== index.apiIndexHash) {\n inconsistencies.push(\n `API index hash mismatch: expected ${index.apiIndexHash}, got ${computedHash}`\n );\n }\n } else if (index.apiIndexHash) {\n inconsistencies.push('API index file missing but hash is present');\n }\n\n if (depsGraph) {\n const computedHash = computeJsonHash(depsGraph);\n if (computedHash !== index.depsHash) {\n inconsistencies.push(\n `Dependencies hash mismatch: expected ${index.depsHash}, got ${computedHash}`\n );\n }\n } else if (index.depsHash) {\n inconsistencies.push('Dependencies file missing but hash is present');\n }\n\n if (recentDiff) {\n const computedHash = computeJsonHash(recentDiff);\n if (computedHash !== index.recentDiffHash) {\n inconsistencies.push(\n `Recent diff hash mismatch: expected ${index.recentDiffHash}, got ${computedHash}`\n );\n }\n } else if (index.recentDiffHash) {\n inconsistencies.push('Recent diff file missing but hash is present');\n }\n\n // Verify combined index checksum\n const combinedContent = JSON.stringify({\n apiIndex: apiIndex || {},\n deps: depsGraph || {},\n recentDiff: recentDiff || {},\n meta: meta || {},\n docs: docs || {},\n });\n const computedChecksum = sha256(combinedContent);\n\n if (computedChecksum !== index.indexChecksum) {\n inconsistencies.push(\n `Index checksum mismatch: expected ${index.indexChecksum}, got ${computedChecksum}`\n );\n }\n\n // Check for missing files that should exist\n const expectedFiles = ['api-index.json', 'deps.json', 'recent-diff.json'];\n for (const file of expectedFiles) {\n try {\n await fsp.access(`${cwd}/.kb/mind/${file}`);\n } catch {\n inconsistencies.push(`Required index file missing: ${file}`);\n }\n }\n\n const ok = inconsistencies.length === 0;\n const code = ok ? null : 'MIND_INDEX_INCONSISTENT';\n const hint = ok\n ? 'All indexes are consistent and up to date'\n : 'Run \"kb mind rag-index\" to rebuild indexes';\n\n return { ok, code, inconsistencies, hint };\n } catch (error: any) {\n return {\n ok: false,\n code: 'MIND_VERIFY_ERROR',\n inconsistencies: [`Verification failed: ${error.message}`],\n hint: 'Check file permissions and workspace structure',\n };\n }\n}\n","/**\n * Default configurations for KB Labs Mind\n */\n\nimport type { ContextBudget, ContextPreset } from \"./types/pack\";\n\n/**\n * Default context budget\n */\nexport const DEFAULT_BUDGET: ContextBudget = {\n totalTokens: 9000,\n caps: {\n intent_summary: 300,\n product_overview: 600,\n project_meta: 500,\n api_signatures: 2200,\n recent_diffs: 1200,\n docs_overview: 600,\n impl_snippets: 3000,\n configs_profiles: 700,\n },\n truncation: \"middle\",\n};\n\n/**\n * Default context preset\n */\nexport const DEFAULT_PRESET: ContextPreset = {\n name: \"balanced\",\n weight: { \n overview: 1, \n api: 1.2, \n diffs: 1, \n snippets: 1.4, \n configs: 0.6,\n meta: 0.8,\n docs: 0.9\n }\n};\n\n/**\n * Default time budget for indexing operations (ms)\n */\nexport const DEFAULT_TIME_BUDGET_MS = 800;\n\n/**\n * Maximum file size to process (bytes)\n */\nexport const MAX_FILE_SIZE_BYTES = 1.5 * 1024 * 1024; // 1.5MB\n\n/**\n * Maximum lines per snippet\n */\nexport const MAX_SNIPPET_LINES = 60;\n\n/**\n * Generator string for artifacts\n */\nexport function getGenerator(): string {\n return \"kb-labs-mind@0.1.0\";\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@kb-labs/mind-core",
3
+ "version": "1.5.0",
4
+ "type": "module",
5
+ "description": "Core contracts, errors, and utilities for KB Labs Mind",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "require": "./dist/index.js"
13
+ },
14
+ "./dist/*": "./dist/*"
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "README.md",
19
+ "LICENSE"
20
+ ],
21
+ "sideEffects": false,
22
+ "scripts": {
23
+ "clean": "rimraf dist",
24
+ "build": "tsup --config tsup.config.ts",
25
+ "dev": "tsup --config tsup.config.ts --watch",
26
+ "lint": "eslint src --ext .ts,.tsx,.js,.jsx",
27
+ "lint:fix": "eslint . --fix",
28
+ "type-check": "tsc --noEmit",
29
+ "test": "vitest run --passWithNoTests",
30
+ "test:watch": "vitest"
31
+ },
32
+ "devDependencies": {
33
+ "@kb-labs/devkit": "link:../../../../infra/kb-labs-devkit",
34
+ "@types/node": "^24.3.3",
35
+ "rimraf": "^6.0.1",
36
+ "tsup": "^8.5.0",
37
+ "typescript": "^5.6.3",
38
+ "vitest": "^3.2.4"
39
+ },
40
+ "dependencies": {
41
+ "@kb-labs/mind-types": "^1.5.0",
42
+ "@kb-labs/sdk": "^1.5.0"
43
+ },
44
+ "engines": {
45
+ "node": ">=20.0.0",
46
+ "pnpm": ">=9.0.0"
47
+ },
48
+ "packageManager": "pnpm@9.11.0"
49
+ }