@contextos/core 0.4.2 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +887 -92
  2. package/package.json +4 -2
package/dist/index.js CHANGED
@@ -29,10 +29,27 @@ var ConstraintSchema = z.object({
29
29
  suggestion: z.string().optional(),
30
30
  related: z.array(z.string()).optional()
31
31
  });
32
+ var isValidGlobPattern = (pattern) => {
33
+ const dangerousPatterns = [
34
+ /\.\./,
35
+ // Directory traversal
36
+ /^~/,
37
+ // Home directory access
38
+ /^\//
39
+ // Absolute path (may be too restrictive)
40
+ ];
41
+ return !dangerousPatterns.some((p) => p.test(pattern));
42
+ };
32
43
  var BoundarySchema = z.object({
33
44
  name: z.string().min(1),
34
- allow: z.array(z.string()),
35
- deny: z.array(z.string())
45
+ allow: z.array(z.string()).refine(
46
+ (patterns) => patterns.every(isValidGlobPattern),
47
+ { message: "Boundary patterns must not contain directory traversal (..) or absolute paths" }
48
+ ),
49
+ deny: z.array(z.string()).refine(
50
+ (patterns) => patterns.every(isValidGlobPattern),
51
+ { message: "Boundary patterns must not contain directory traversal (..) or absolute paths" }
52
+ )
36
53
  });
37
54
  var MetaSchema = z.object({
38
55
  last_indexed: z.string().datetime().optional(),
@@ -48,6 +65,7 @@ var ContextYamlSchema = z.object({
48
65
  boundaries: z.array(BoundarySchema).optional().default([]),
49
66
  meta: MetaSchema.optional()
50
67
  });
68
+ var fileSizePattern = /^\d+(\.\d+)?\s*(B|KB|MB|GB|TB)$/i;
51
69
  var IndexingConfigSchema = z.object({
52
70
  watch_mode: z.boolean().default(true),
53
71
  ignore_patterns: z.array(z.string()).default([
@@ -57,7 +75,9 @@ var IndexingConfigSchema = z.object({
57
75
  "dist/**",
58
76
  ".git/**"
59
77
  ]),
60
- file_size_limit: z.string().default("1MB")
78
+ file_size_limit: z.string().default("1MB").refine((val) => fileSizePattern.test(val), {
79
+ message: 'File size limit must be in format like "1MB", "500KB", "2GB", etc.'
80
+ })
61
81
  });
62
82
  var GraphConfigSchema = z.object({
63
83
  max_depth: z.number().int().min(1).max(10).default(2),
@@ -167,7 +187,7 @@ function findContextosRoot(startDir = process.cwd()) {
167
187
  function loadContextYaml(rootDir) {
168
188
  const contextPath = join(rootDir, CONTEXTOS_DIR, CONTEXT_FILE);
169
189
  if (!existsSync(contextPath)) {
170
- throw new Error(`context.yaml not found at ${contextPath}. Run 'ctx init' first.`);
190
+ throw new Error(`ContextOS not initialized: context.yaml not found at ${contextPath}. Run 'ctx init' first.`);
171
191
  }
172
192
  const rawContent = readFileSync(contextPath, "utf-8");
173
193
  const parsed = parseYaml(rawContent);
@@ -1183,6 +1203,17 @@ var DependencyGraph = class {
1183
1203
  import Database from "better-sqlite3";
1184
1204
  import { existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
1185
1205
  import { dirname as dirname3 } from "path";
1206
+
1207
+ // src/constants.ts
1208
+ var DEFAULT_TIMEOUT = 1e4;
1209
+ var SANDBOX_TIMEOUT_RATIO = 10;
1210
+ var MAX_VISITED_PATHS = 50;
1211
+ var PATH_CLEANUP_BATCH_SIZE = 10;
1212
+ var VECTOR_PAGE_SIZE = 1e3;
1213
+ var CHARS_PER_TOKEN_CODE = 4;
1214
+ var GIT_MAX_BUFFER = 1024 * 1024;
1215
+
1216
+ // src/embedding/vector-store.ts
1186
1217
  var VectorStore = class {
1187
1218
  db = null;
1188
1219
  embedder = null;
@@ -1306,7 +1337,7 @@ var VectorStore = class {
1306
1337
  */
1307
1338
  vectorSearch(queryEmbedding, limit) {
1308
1339
  if (!this.db) throw new Error("VectorStore not initialized");
1309
- const pageSize = 1e3;
1340
+ const pageSize = VECTOR_PAGE_SIZE;
1310
1341
  let offset = 0;
1311
1342
  const allResults = [];
1312
1343
  while (allResults.length < limit * 2) {
@@ -1341,7 +1372,7 @@ var VectorStore = class {
1341
1372
  textSearch(query, limit) {
1342
1373
  if (!this.db) throw new Error("VectorStore not initialized");
1343
1374
  const terms = query.toLowerCase().split(/\s+/);
1344
- const pageSize = 1e3;
1375
+ const pageSize = VECTOR_PAGE_SIZE;
1345
1376
  let offset = 0;
1346
1377
  const allResults = [];
1347
1378
  while (allResults.length < limit * 2) {
@@ -1739,11 +1770,15 @@ var TokenBudget = class {
1739
1770
  this.maxTokens = maxTokens || MODEL_LIMITS[modelName] || 32e3;
1740
1771
  }
1741
1772
  /**
1742
- * Count tokens in text (approximate)
1743
- * In production, use tiktoken for accurate counts
1773
+ * Count tokens in text (improved approximation)
1774
+ * Uses CHARS_PER_TOKEN_CODE constant for code-dense content
1775
+ *
1776
+ * Note: For production use, consider integrating tiktoken for accurate counts.
1777
+ * This approximation works well for most code scenarios.
1744
1778
  */
1745
1779
  count(text) {
1746
- return Math.ceil(text.length / 4);
1780
+ if (!text) return 0;
1781
+ return Math.ceil(text.length / CHARS_PER_TOKEN_CODE);
1747
1782
  }
1748
1783
  /**
1749
1784
  * Get allocation percentages based on budget size
@@ -1865,7 +1900,7 @@ var TokenBudget = class {
1865
1900
  * Truncate text to fit within token limit
1866
1901
  */
1867
1902
  truncateToTokens(text, maxTokens) {
1868
- const estimatedChars = maxTokens * 4;
1903
+ const estimatedChars = maxTokens * CHARS_PER_TOKEN_CODE;
1869
1904
  if (text.length <= estimatedChars) return text;
1870
1905
  const truncated = text.slice(0, estimatedChars);
1871
1906
  const lastNewline = truncated.lastIndexOf("\n");
@@ -2331,24 +2366,24 @@ var ContextBuilder = class {
2331
2366
  }
2332
2367
  /**
2333
2368
  * Execute git diff with proper sanitization and error handling
2369
+ * SECURITY: Uses safe command strings with shell:false to prevent injection
2334
2370
  */
2335
2371
  async getGitDiff(type) {
2336
2372
  try {
2337
2373
  const { execSync: execSync2 } = await import("child_process");
2338
2374
  const cwd = this.sanitizeGitPath(this.config?.rootDir);
2339
- const flag = type === "cached" ? "--cached" : "";
2340
- return execSync2(
2341
- `git diff ${flag} --name-only`,
2342
- {
2343
- cwd,
2344
- encoding: "utf-8",
2345
- maxBuffer: 1024 * 1024,
2346
- // 1MB
2347
- stdio: ["ignore", "pipe", "pipe"],
2348
- timeout: 5e3
2349
- // 5 second timeout
2350
- }
2351
- ).trim();
2375
+ const command = type === "cached" ? "git diff --cached --name-only" : "git diff --name-only";
2376
+ return execSync2(command, {
2377
+ cwd,
2378
+ encoding: "utf-8",
2379
+ maxBuffer: 1024 * 1024,
2380
+ // 1MB
2381
+ stdio: ["ignore", "pipe", "pipe"],
2382
+ timeout: 5e3,
2383
+ // 5 second timeout
2384
+ shell: false
2385
+ // Explicitly disable shell to prevent injection
2386
+ }).trim();
2352
2387
  } catch (error) {
2353
2388
  const errorMessage = error instanceof Error ? error.message : String(error);
2354
2389
  console.warn(`Git command failed: ${errorMessage}`);
@@ -2491,14 +2526,18 @@ var ContextBuilder = class {
2491
2526
  encoding: "utf-8",
2492
2527
  maxBuffer: 1024 * 1024,
2493
2528
  // 1MB max
2494
- timeout: 5e3
2529
+ timeout: 5e3,
2530
+ shell: false
2531
+ // Prevent command injection
2495
2532
  });
2496
2533
  if (!gitDiff) {
2497
2534
  gitDiff = execSync2("git diff", {
2498
2535
  cwd,
2499
2536
  encoding: "utf-8",
2500
2537
  maxBuffer: 1024 * 1024,
2501
- timeout: 5e3
2538
+ timeout: 5e3,
2539
+ shell: false
2540
+ // Prevent command injection
2502
2541
  });
2503
2542
  }
2504
2543
  } catch {
@@ -3241,6 +3280,25 @@ var DEFAULT_RLM_CONFIG = {
3241
3280
  };
3242
3281
 
3243
3282
  // src/rlm/context-api.ts
3283
+ var patternCache = /* @__PURE__ */ new Map();
3284
+ function getCachedPattern(key, pattern, flags = "") {
3285
+ const cacheKey = `${key}:${flags}`;
3286
+ if (!patternCache.has(cacheKey)) {
3287
+ patternCache.set(cacheKey, new RegExp(pattern, flags));
3288
+ }
3289
+ return patternCache.get(cacheKey);
3290
+ }
3291
+ var CACHED_IMPORT_PATTERNS = [
3292
+ getCachedPattern("import-es6", "^import\\s+.+", ""),
3293
+ getCachedPattern("import-python", "^from\\s+.+\\s+import\\s+.+", ""),
3294
+ getCachedPattern("import-commonjs1", "^const\\s+.+=\\s*require\\(", ""),
3295
+ getCachedPattern("import-commonjs2", "^require\\s*\\(", "")
3296
+ ];
3297
+ var CACHED_EXPORT_PATTERNS = [
3298
+ getCachedPattern("export-default", "^export\\s+(default\\s+)?(class|function|const|let|interface|type|enum)", ""),
3299
+ getCachedPattern("export-named", "^export\\s*\\{", ""),
3300
+ getCachedPattern("export-commonjs", "^module\\.exports\\s*=", "")
3301
+ ];
3244
3302
  function createContextAPI(rawContext) {
3245
3303
  const lines = rawContext.split("\n");
3246
3304
  return {
@@ -3354,19 +3412,9 @@ function createContextAPI(rawContext) {
3354
3412
  },
3355
3413
  getImports: () => {
3356
3414
  const imports = [];
3357
- const importPatterns = [
3358
- /^import\s+.+/,
3359
- // ES6 import
3360
- /^from\s+.+\s+import\s+.+/,
3361
- // Python from import
3362
- /^const\s+.+=\s*require\(/,
3363
- // CommonJS require
3364
- /^require\s*\(/
3365
- // require()
3366
- ];
3367
3415
  for (const line of lines) {
3368
3416
  const trimmed = line.trim();
3369
- for (const pattern of importPatterns) {
3417
+ for (const pattern of CACHED_IMPORT_PATTERNS) {
3370
3418
  if (pattern.test(trimmed)) {
3371
3419
  imports.push(trimmed);
3372
3420
  break;
@@ -3377,14 +3425,9 @@ function createContextAPI(rawContext) {
3377
3425
  },
3378
3426
  getExports: () => {
3379
3427
  const exports = [];
3380
- const exportPatterns = [
3381
- /^export\s+(default\s+)?(class|function|const|let|interface|type|enum)/,
3382
- /^export\s*\{/,
3383
- /^module\.exports\s*=/
3384
- ];
3385
3428
  for (const line of lines) {
3386
3429
  const trimmed = line.trim();
3387
- for (const pattern of exportPatterns) {
3430
+ for (const pattern of CACHED_EXPORT_PATTERNS) {
3388
3431
  if (pattern.test(trimmed)) {
3389
3432
  exports.push(trimmed);
3390
3433
  break;
@@ -3397,17 +3440,17 @@ function createContextAPI(rawContext) {
3397
3440
  const outline = [];
3398
3441
  const patterns = {
3399
3442
  function: [
3400
- /^(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*\(([^)]*)\)/,
3401
- /^(?:export\s+)?(?:const|let)\s+(\w+)\s*=\s*(?:async\s+)?\([^)]*\)\s*=>/
3443
+ getCachedPattern("outline-fn1", "^(?:export\\s+)?(?:async\\s+)?function\\s+(\\w+)\\s*\\(([^)]*)\\)"),
3444
+ getCachedPattern("outline-fn2", "^(?:export\\s+)?(?:const|let)\\s+(\\w+)\\s*=\\s*(?:async\\s+)?\\([^)]*\\)\\s*=>")
3402
3445
  ],
3403
3446
  class: [
3404
- /^(?:export\s+)?(?:abstract\s+)?class\s+(\w+)/
3447
+ getCachedPattern("outline-class", "^(?:export\\s+)?(?:abstract\\s+)?class\\s+(\\w+)")
3405
3448
  ],
3406
3449
  interface: [
3407
- /^(?:export\s+)?interface\s+(\w+)/
3450
+ getCachedPattern("outline-interface", "^(?:export\\s+)?interface\\s+(\\w+)")
3408
3451
  ],
3409
3452
  type: [
3410
- /^(?:export\s+)?type\s+(\w+)/
3453
+ getCachedPattern("outline-type", "^(?:export\\s+)?type\\s+(\\w+)")
3411
3454
  ]
3412
3455
  };
3413
3456
  for (let i = 0; i < lines.length; i++) {
@@ -3665,19 +3708,57 @@ function prepareSandboxVariables(rawContext, additionalVariables = {}) {
3665
3708
  function validateCode(code) {
3666
3709
  const issues = [];
3667
3710
  const dangerousPatterns = [
3711
+ // Module system bypasses
3668
3712
  { pattern: /\brequire\s*\(/, message: "require() is not allowed" },
3669
3713
  { pattern: /\bimport\s*\(/, message: "Dynamic import() is not allowed" },
3670
- { pattern: /\bprocess\./, message: "process access is not allowed" },
3671
- { pattern: /\bglobal\./, message: "global access is not allowed" },
3672
- { pattern: /\bglobalThis\./, message: "globalThis access is not allowed" },
3714
+ { pattern: /\bimport\s+\.+/, message: "Relative import is not allowed" },
3715
+ // Global object access
3716
+ { pattern: /\bprocess\s*\./, message: "process property access is not allowed" },
3717
+ { pattern: /\bprocess\s*$/, message: "process variable access is not allowed" },
3718
+ { pattern: /\bglobal\s*\./, message: "global access is not allowed" },
3719
+ { pattern: /\bglobal\s*$/, message: "global variable access is not allowed" },
3720
+ { pattern: /\bglobalThis\s*\./, message: "globalThis access is not allowed" },
3721
+ { pattern: /\bglobalThis\s*$/, message: "globalThis variable access is not allowed" },
3722
+ // Code execution
3673
3723
  { pattern: /\beval\s*\(/, message: "eval() is not allowed" },
3674
3724
  { pattern: /\bFunction\s*\(/, message: "Function constructor is not allowed" },
3675
- { pattern: /\bchild_process/, message: "child_process is not allowed" },
3676
- { pattern: /\bfs\./, message: "fs module is not allowed" },
3725
+ { pattern: /\bnew\s+Function\s*\(/, message: "new Function() is not allowed" },
3726
+ { pattern: /\bsetTimeout\s*\(/, message: "setTimeout() is not allowed" },
3727
+ { pattern: /\bsetInterval\s*\(/, message: "setInterval() is not allowed" },
3728
+ { pattern: /\bsetImmediate\s*\(/, message: "setImmediate() is not allowed" },
3729
+ // Child process and system access
3730
+ { pattern: /\bchild_process/, message: "child_process module is not allowed" },
3677
3731
  { pattern: /\bexec\s*\(/, message: "exec() is not allowed" },
3678
3732
  { pattern: /\bspawn\s*\(/, message: "spawn() is not allowed" },
3733
+ { pattern: /\bfork\s*\(/, message: "fork() is not allowed" },
3734
+ { pattern: /\bexecSync\s*\(/, message: "execSync() is not allowed" },
3735
+ // File system access
3736
+ { pattern: /\bfs\s*\./, message: "fs module access is not allowed" },
3737
+ { pattern: /\bfs\s*$/, message: "fs module variable is not allowed" },
3738
+ { pattern: /\brequire\s*\(\s*['"]fs['"]/, message: "fs module require is not allowed" },
3739
+ // Directory traversal
3740
+ { pattern: /\bprocess\s*\.\s*chdir\s*\(/, message: "process.chdir() is not allowed" },
3741
+ { pattern: /\bprocess\s*\.\s*cwd\s*\(/, message: "process.cwd() is not allowed" },
3742
+ // Buffer exploits
3743
+ { pattern: /\bBuffer\s*\./, message: "Buffer static methods are not allowed" },
3744
+ { pattern: /\bnew\s+Buffer\s*\(/, message: "new Buffer() is not allowed" },
3745
+ // Prototype pollution
3679
3746
  { pattern: /\b__proto__/, message: "__proto__ access is not allowed" },
3680
- { pattern: /\bconstructor\s*\[/, message: "constructor access is not allowed" }
3747
+ { pattern: /\bconstructor\s*\[/, message: "constructor array access is not allowed" },
3748
+ { pattern: /\bprototype\s*\./, message: "prototype modification is not allowed" },
3749
+ { pattern: /\bObject\s*\.\s*prototype/, message: "Object.prototype modification is not allowed" },
3750
+ // Reflect and Proxy exploits
3751
+ { pattern: /\bReflect\s*\.\s*set\s*\(/, message: "Reflect.set() is not allowed" },
3752
+ { pattern: /\bnew\s+Proxy\s*\(/, message: "Proxy constructor is not allowed" },
3753
+ // Async function exploits
3754
+ { pattern: /\basync\s+Function\s*\(/, message: "async Function constructor is not allowed" },
3755
+ // Module and namespace access
3756
+ { pattern: /\bmodule\s*\./, message: "module access is not allowed" },
3757
+ { pattern: /\bmodule\s*$/, message: "module variable access is not allowed" },
3758
+ { pattern: /\bexports\s*\./, message: "exports access is not allowed" },
3759
+ { pattern: /\bexports\s*$/, message: "exports variable access is not allowed" },
3760
+ { pattern: /\b__dirname/, message: "__dirname access is not allowed" },
3761
+ { pattern: /\b__filename/, message: "__filename access is not allowed" }
3681
3762
  ];
3682
3763
  for (const { pattern, message } of dangerousPatterns) {
3683
3764
  if (pattern.test(code)) {
@@ -3902,7 +3983,7 @@ var RLMEngine = class {
3902
3983
  constructor(options = {}) {
3903
3984
  this.config = { ...DEFAULT_RLM_CONFIG, ...options };
3904
3985
  this.sandbox = createSandbox(this.config.environment, {
3905
- timeout: Math.min(1e4, this.config.timeoutMs / 10)
3986
+ timeout: Math.min(DEFAULT_TIMEOUT, this.config.timeoutMs / SANDBOX_TIMEOUT_RATIO)
3906
3987
  });
3907
3988
  this.executionId = this.generateExecutionId();
3908
3989
  }
@@ -4045,10 +4126,10 @@ Depth: ${depth}/${this.config.maxDepth}`
4045
4126
  continue;
4046
4127
  }
4047
4128
  state.visitedPaths.set(pathKey, now);
4048
- if (state.visitedPaths.size > 50) {
4129
+ if (state.visitedPaths.size > MAX_VISITED_PATHS) {
4049
4130
  const entries = Array.from(state.visitedPaths.entries());
4050
4131
  entries.sort((a, b) => a[1] - b[1]);
4051
- for (let i = 0; i < 10; i++) {
4132
+ for (let i = 0; i < PATH_CLEANUP_BATCH_SIZE; i++) {
4052
4133
  state.visitedPaths.delete(entries[i][0]);
4053
4134
  }
4054
4135
  }
@@ -4872,15 +4953,17 @@ var ScopeManager = class {
4872
4953
  switch (condition.type) {
4873
4954
  case "always":
4874
4955
  return true;
4875
- case "goal_contains":
4956
+ case "goal_contains": {
4876
4957
  const values = Array.isArray(condition.value) ? condition.value : [condition.value || ""];
4877
4958
  return values.some((v) => goalLower.includes(v.toLowerCase()));
4878
- case "file_in":
4959
+ }
4960
+ case "file_in": {
4879
4961
  if (!targetFiles) return false;
4880
4962
  const patterns = Array.isArray(condition.value) ? condition.value : [condition.value || ""];
4881
4963
  return targetFiles.some(
4882
4964
  (file) => patterns.some((pattern) => this.matchGlob(file, pattern))
4883
4965
  );
4966
+ }
4884
4967
  case "tag_is":
4885
4968
  return false;
4886
4969
  default:
@@ -5056,7 +5139,7 @@ function createWatchdog(config) {
5056
5139
 
5057
5140
  // src/sync/team-sync.ts
5058
5141
  import { execSync } from "child_process";
5059
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
5142
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
5060
5143
  import { join as join5 } from "path";
5061
5144
  import { parse, stringify as stringify2 } from "yaml";
5062
5145
  function validateGitBranchName(branch) {
@@ -5096,7 +5179,7 @@ var TeamSync = class {
5096
5179
  loadSyncConfig() {
5097
5180
  const configPath = join5(this.contextosDir, "sync.yaml");
5098
5181
  if (existsSync5(configPath)) {
5099
- const content = readFileSync5(configPath, "utf-8");
5182
+ const content = readFileSync4(configPath, "utf-8");
5100
5183
  return { ...DEFAULT_SYNC_CONFIG, ...parse(content) };
5101
5184
  }
5102
5185
  return DEFAULT_SYNC_CONFIG;
@@ -5230,7 +5313,7 @@ var TemplateManager = class {
5230
5313
  const files = __require("fs").readdirSync(this.templatesDir);
5231
5314
  for (const file of files) {
5232
5315
  if (file.endsWith(".yaml")) {
5233
- const content = readFileSync5(join5(this.templatesDir, file), "utf-8");
5316
+ const content = readFileSync4(join5(this.templatesDir, file), "utf-8");
5234
5317
  templates.push(parse(content));
5235
5318
  }
5236
5319
  }
@@ -5249,8 +5332,8 @@ var TemplateManager = class {
5249
5332
  description,
5250
5333
  author,
5251
5334
  version: "1.0.0",
5252
- context: existsSync5(contextPath) ? parse(readFileSync5(contextPath, "utf-8")) : {},
5253
- config: existsSync5(configPath) ? parse(readFileSync5(configPath, "utf-8")) : {}
5335
+ context: existsSync5(contextPath) ? parse(readFileSync4(contextPath, "utf-8")) : {},
5336
+ config: existsSync5(configPath) ? parse(readFileSync4(configPath, "utf-8")) : {}
5254
5337
  };
5255
5338
  const templatePath = join5(this.templatesDir, `${name}.yaml`);
5256
5339
  writeFileSync2(templatePath, stringify2(template, { indent: 2 }), "utf-8");
@@ -5263,7 +5346,7 @@ var TemplateManager = class {
5263
5346
  if (!existsSync5(templatePath)) {
5264
5347
  throw new Error(`Template '${name}' not found`);
5265
5348
  }
5266
- const template = parse(readFileSync5(templatePath, "utf-8"));
5349
+ const template = parse(readFileSync4(templatePath, "utf-8"));
5267
5350
  const contextPath = join5(this.templatesDir, "..", "context.yaml");
5268
5351
  const configPath = join5(this.templatesDir, "..", "config.yaml");
5269
5352
  if (template.context && Object.keys(template.context).length > 0) {
@@ -5483,7 +5566,7 @@ var CloudSync = class {
5483
5566
  };
5484
5567
 
5485
5568
  // src/analytics/analytics.ts
5486
- import { existsSync as existsSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4 } from "fs";
5569
+ import { existsSync as existsSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4 } from "fs";
5487
5570
  import { join as join7 } from "path";
5488
5571
  var AnalyticsCollector = class {
5489
5572
  analyticsDir;
@@ -5534,7 +5617,7 @@ var AnalyticsCollector = class {
5534
5617
  loadEvents() {
5535
5618
  if (existsSync7(this.eventsFile)) {
5536
5619
  try {
5537
- return JSON.parse(readFileSync7(this.eventsFile, "utf-8"));
5620
+ return JSON.parse(readFileSync6(this.eventsFile, "utf-8"));
5538
5621
  } catch {
5539
5622
  return [];
5540
5623
  }
@@ -5562,7 +5645,7 @@ var AnalyticsCollector = class {
5562
5645
  loadDailyStats() {
5563
5646
  if (existsSync7(this.statsFile)) {
5564
5647
  try {
5565
- return JSON.parse(readFileSync7(this.statsFile, "utf-8"));
5648
+ return JSON.parse(readFileSync6(this.statsFile, "utf-8"));
5566
5649
  } catch {
5567
5650
  return [];
5568
5651
  }
@@ -5628,7 +5711,7 @@ var AnalyticsCollector = class {
5628
5711
  };
5629
5712
 
5630
5713
  // src/compliance/rbac.ts
5631
- import { readFileSync as readFileSync8, writeFileSync as writeFileSync5, existsSync as existsSync8, mkdirSync as mkdirSync5 } from "fs";
5714
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync8, mkdirSync as mkdirSync5 } from "fs";
5632
5715
  import { join as join8 } from "path";
5633
5716
  import crypto2 from "crypto";
5634
5717
  var BUILT_IN_ROLES = [
@@ -5704,7 +5787,7 @@ var RBACManager = class {
5704
5787
  }
5705
5788
  if (existsSync8(this.rolesFile)) {
5706
5789
  try {
5707
- const customRoles = JSON.parse(readFileSync8(this.rolesFile, "utf-8"));
5790
+ const customRoles = JSON.parse(readFileSync7(this.rolesFile, "utf-8"));
5708
5791
  for (const role of customRoles) {
5709
5792
  this.roles.set(role.id, role);
5710
5793
  }
@@ -5713,7 +5796,7 @@ var RBACManager = class {
5713
5796
  }
5714
5797
  if (existsSync8(this.usersFile)) {
5715
5798
  try {
5716
- const users = JSON.parse(readFileSync8(this.usersFile, "utf-8"));
5799
+ const users = JSON.parse(readFileSync7(this.usersFile, "utf-8"));
5717
5800
  for (const user of users) {
5718
5801
  this.users.set(user.id, user);
5719
5802
  }
@@ -5722,7 +5805,7 @@ var RBACManager = class {
5722
5805
  }
5723
5806
  if (existsSync8(this.policiesFile)) {
5724
5807
  try {
5725
- this.policies = JSON.parse(readFileSync8(this.policiesFile, "utf-8"));
5808
+ this.policies = JSON.parse(readFileSync7(this.policiesFile, "utf-8"));
5726
5809
  } catch {
5727
5810
  }
5728
5811
  }
@@ -5883,7 +5966,7 @@ var RBACManager = class {
5883
5966
  };
5884
5967
 
5885
5968
  // src/compliance/audit.ts
5886
- import { existsSync as existsSync9, readFileSync as readFileSync9, writeFileSync as writeFileSync6, appendFileSync, mkdirSync as mkdirSync6 } from "fs";
5969
+ import { existsSync as existsSync9, readFileSync as readFileSync8, writeFileSync as writeFileSync6, appendFileSync, mkdirSync as mkdirSync6 } from "fs";
5887
5970
  import { join as join9 } from "path";
5888
5971
  import crypto3 from "crypto";
5889
5972
  var AuditLogger = class {
@@ -5945,7 +6028,7 @@ var AuditLogger = class {
5945
6028
  loadIndex() {
5946
6029
  if (existsSync9(this.indexFile)) {
5947
6030
  try {
5948
- return JSON.parse(readFileSync9(this.indexFile, "utf-8"));
6031
+ return JSON.parse(readFileSync8(this.indexFile, "utf-8"));
5949
6032
  } catch {
5950
6033
  return {};
5951
6034
  }
@@ -5962,7 +6045,7 @@ var AuditLogger = class {
5962
6045
  for (const logFile of logFiles) {
5963
6046
  if (entries.length >= limit) break;
5964
6047
  const filePath = join9(this.auditDir, logFile);
5965
- const content = readFileSync9(filePath, "utf-8");
6048
+ const content = readFileSync8(filePath, "utf-8");
5966
6049
  const lines = content.trim().split("\n").filter(Boolean);
5967
6050
  for (const line of lines.reverse()) {
5968
6051
  if (entries.length >= limit) break;
@@ -5999,7 +6082,7 @@ var AuditLogger = class {
5999
6082
  */
6000
6083
  verifyLogFile(filename) {
6001
6084
  const filePath = join9(this.auditDir, filename);
6002
- const content = readFileSync9(filePath, "utf-8");
6085
+ const content = readFileSync8(filePath, "utf-8");
6003
6086
  const lines = content.trim().split("\n").filter(Boolean);
6004
6087
  const result = { valid: 0, invalid: 0, entries: [] };
6005
6088
  for (const line of lines) {
@@ -6053,7 +6136,7 @@ var AuditLogger = class {
6053
6136
  };
6054
6137
 
6055
6138
  // src/plugins/manager.ts
6056
- import { existsSync as existsSync10, readdirSync, readFileSync as readFileSync10, mkdirSync as mkdirSync7, rmSync, writeFileSync as writeFileSync7 } from "fs";
6139
+ import { existsSync as existsSync10, readdirSync, readFileSync as readFileSync9, mkdirSync as mkdirSync7, rmSync, writeFileSync as writeFileSync7 } from "fs";
6057
6140
  import { join as join10, resolve, normalize as normalize2 } from "path";
6058
6141
  var PluginManager = class {
6059
6142
  plugins = /* @__PURE__ */ new Map();
@@ -6107,7 +6190,7 @@ var PluginManager = class {
6107
6190
  if (!existsSync10(manifestPath)) {
6108
6191
  throw new Error(`Plugin manifest not found: ${manifestPath}`);
6109
6192
  }
6110
- const manifestContent = readFileSync10(manifestPath, "utf-8");
6193
+ const manifestContent = readFileSync9(manifestPath, "utf-8");
6111
6194
  let manifest;
6112
6195
  try {
6113
6196
  manifest = JSON.parse(manifestContent);
@@ -6202,7 +6285,7 @@ The file may contain invalid JSON.`
6202
6285
  mkdirSync7(targetDir, { recursive: true });
6203
6286
  let manifest;
6204
6287
  try {
6205
- const manifestContent = readFileSync10(join10(sourcePath, "package.json"), "utf-8");
6288
+ const manifestContent = readFileSync9(join10(sourcePath, "package.json"), "utf-8");
6206
6289
  manifest = JSON.parse(manifestContent);
6207
6290
  } catch (error) {
6208
6291
  throw new Error(
@@ -6210,7 +6293,7 @@ The file may contain invalid JSON.`
6210
6293
  );
6211
6294
  }
6212
6295
  writeFileSync7(join10(targetDir, "package.json"), JSON.stringify(manifest, null, 2));
6213
- const mainContent = readFileSync10(join10(sourcePath, manifest.main), "utf-8");
6296
+ const mainContent = readFileSync9(join10(sourcePath, manifest.main), "utf-8");
6214
6297
  writeFileSync7(join10(targetDir, manifest.main), mainContent);
6215
6298
  } else {
6216
6299
  throw new Error("Remote plugin installation not yet implemented");
@@ -6370,7 +6453,7 @@ ${commandsCode}
6370
6453
  if (!normalized.startsWith(rootNormalized)) {
6371
6454
  throw new Error(`Path traversal detected: "${path}" escapes project boundaries`);
6372
6455
  }
6373
- return readFileSync10(normalized, "utf-8");
6456
+ return readFileSync9(normalized, "utf-8");
6374
6457
  },
6375
6458
  getDependencies: async (_path, _depth = 2) => {
6376
6459
  return [];
@@ -6390,7 +6473,7 @@ function createPluginManager(projectRoot) {
6390
6473
  }
6391
6474
 
6392
6475
  // src/plugins/registry.ts
6393
- import { existsSync as existsSync11, readdirSync as readdirSync2, readFileSync as readFileSync11 } from "fs";
6476
+ import { existsSync as existsSync11, readdirSync as readdirSync2, readFileSync as readFileSync10 } from "fs";
6394
6477
  import { join as join11 } from "path";
6395
6478
  var PluginRegistry = class {
6396
6479
  config;
@@ -6414,7 +6497,7 @@ var PluginRegistry = class {
6414
6497
  if (!existsSync11(manifestPath)) continue;
6415
6498
  try {
6416
6499
  const manifest = JSON.parse(
6417
- readFileSync11(manifestPath, "utf-8")
6500
+ readFileSync10(manifestPath, "utf-8")
6418
6501
  );
6419
6502
  const disabledPath = join11(pluginPath, ".disabled");
6420
6503
  const enabled = !existsSync11(disabledPath);
@@ -6555,7 +6638,7 @@ function createPluginRegistry(projectRoot) {
6555
6638
  }
6556
6639
 
6557
6640
  // src/finetuning/collector.ts
6558
- import { existsSync as existsSync12, readFileSync as readFileSync12, writeFileSync as writeFileSync8, mkdirSync as mkdirSync8 } from "fs";
6641
+ import { existsSync as existsSync12, readFileSync as readFileSync11, writeFileSync as writeFileSync8, mkdirSync as mkdirSync8 } from "fs";
6559
6642
  import { join as join12 } from "path";
6560
6643
  import { createHash as createHash4 } from "crypto";
6561
6644
  var TrainingDataCollector = class {
@@ -6576,7 +6659,7 @@ var TrainingDataCollector = class {
6576
6659
  const dataFile = join12(this.dataDir, "examples.json");
6577
6660
  if (existsSync12(dataFile)) {
6578
6661
  try {
6579
- const data = JSON.parse(readFileSync12(dataFile, "utf-8"));
6662
+ const data = JSON.parse(readFileSync11(dataFile, "utf-8"));
6580
6663
  this.examples = data.examples || [];
6581
6664
  } catch {
6582
6665
  this.examples = [];
@@ -7591,12 +7674,711 @@ function setGlobalLogger(logger) {
7591
7674
  globalLogger = logger;
7592
7675
  }
7593
7676
 
7677
+ // src/telemetry/metrics.ts
7678
+ var MetricsCollector = class {
7679
+ counters = /* @__PURE__ */ new Map();
7680
+ gauges = /* @__PURE__ */ new Map();
7681
+ histograms = /* @__PURE__ */ new Map();
7682
+ enabled;
7683
+ flushInterval = null;
7684
+ onFlush;
7685
+ constructor(options = {}) {
7686
+ this.enabled = options.enabled ?? process.env.CONTEXTOS_TELEMETRY !== "false";
7687
+ this.onFlush = options.onFlush;
7688
+ if (options.flushIntervalMs && options.flushIntervalMs > 0) {
7689
+ this.flushInterval = setInterval(() => {
7690
+ this.flush();
7691
+ }, options.flushIntervalMs);
7692
+ }
7693
+ }
7694
+ /**
7695
+ * Increment a counter
7696
+ */
7697
+ increment(name, value = 1, labels) {
7698
+ if (!this.enabled) return;
7699
+ const key = this.makeKey(name, labels);
7700
+ const current = this.counters.get(key) || 0;
7701
+ this.counters.set(key, current + value);
7702
+ }
7703
+ /**
7704
+ * Set a gauge value
7705
+ */
7706
+ gauge(name, value, labels) {
7707
+ if (!this.enabled) return;
7708
+ const key = this.makeKey(name, labels);
7709
+ this.gauges.set(key, value);
7710
+ }
7711
+ /**
7712
+ * Record a histogram value (typically timing)
7713
+ */
7714
+ histogram(name, value, labels) {
7715
+ if (!this.enabled) return;
7716
+ const key = this.makeKey(name, labels);
7717
+ const values = this.histograms.get(key) || [];
7718
+ values.push(value);
7719
+ this.histograms.set(key, values);
7720
+ }
7721
+ /**
7722
+ * Time a function execution
7723
+ */
7724
+ async time(name, fn, labels) {
7725
+ const start = performance.now();
7726
+ try {
7727
+ return await fn();
7728
+ } finally {
7729
+ const duration = performance.now() - start;
7730
+ this.histogram(name, duration, labels);
7731
+ }
7732
+ }
7733
+ /**
7734
+ * Time a synchronous function execution
7735
+ */
7736
+ timeSync(name, fn, labels) {
7737
+ const start = performance.now();
7738
+ try {
7739
+ return fn();
7740
+ } finally {
7741
+ const duration = performance.now() - start;
7742
+ this.histogram(name, duration, labels);
7743
+ }
7744
+ }
7745
+ /**
7746
+ * Get current snapshot of all metrics
7747
+ */
7748
+ getSnapshot() {
7749
+ const snapshot = {
7750
+ timestamp: /* @__PURE__ */ new Date(),
7751
+ counters: Object.fromEntries(this.counters),
7752
+ gauges: Object.fromEntries(this.gauges),
7753
+ histograms: {}
7754
+ };
7755
+ for (const [key, values] of this.histograms) {
7756
+ if (values.length === 0) continue;
7757
+ const sorted = [...values].sort((a, b) => a - b);
7758
+ snapshot.histograms[key] = {
7759
+ count: values.length,
7760
+ sum: values.reduce((a, b) => a + b, 0),
7761
+ min: sorted[0],
7762
+ max: sorted[sorted.length - 1],
7763
+ avg: values.reduce((a, b) => a + b, 0) / values.length,
7764
+ p50: this.percentile(sorted, 50),
7765
+ p90: this.percentile(sorted, 90),
7766
+ p99: this.percentile(sorted, 99)
7767
+ };
7768
+ }
7769
+ return snapshot;
7770
+ }
7771
+ /**
7772
+ * Flush metrics and reset
7773
+ */
7774
+ flush() {
7775
+ const snapshot = this.getSnapshot();
7776
+ if (this.onFlush) {
7777
+ this.onFlush(snapshot);
7778
+ }
7779
+ this.counters.clear();
7780
+ this.histograms.clear();
7781
+ return snapshot;
7782
+ }
7783
+ /**
7784
+ * Stop the flush interval
7785
+ */
7786
+ stop() {
7787
+ if (this.flushInterval) {
7788
+ clearInterval(this.flushInterval);
7789
+ this.flushInterval = null;
7790
+ }
7791
+ }
7792
+ makeKey(name, labels) {
7793
+ if (!labels || Object.keys(labels).length === 0) {
7794
+ return name;
7795
+ }
7796
+ const labelStr = Object.entries(labels).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => `${k}=${v}`).join(",");
7797
+ return `${name}{${labelStr}}`;
7798
+ }
7799
+ percentile(sorted, p) {
7800
+ const index = Math.ceil(p / 100 * sorted.length) - 1;
7801
+ return sorted[Math.max(0, index)];
7802
+ }
7803
+ };
7804
+ var METRICS = {
7805
+ // Indexing
7806
+ INDEX_FILES_TOTAL: "contextos_index_files_total",
7807
+ INDEX_DURATION_MS: "contextos_index_duration_ms",
7808
+ INDEX_ERRORS: "contextos_index_errors_total",
7809
+ // Context building
7810
+ CONTEXT_BUILD_DURATION_MS: "contextos_context_build_duration_ms",
7811
+ CONTEXT_FILES_INCLUDED: "contextos_context_files_included",
7812
+ CONTEXT_TOKENS: "contextos_context_tokens",
7813
+ // API calls
7814
+ API_CALLS_TOTAL: "contextos_api_calls_total",
7815
+ API_DURATION_MS: "contextos_api_duration_ms",
7816
+ API_ERRORS: "contextos_api_errors_total",
7817
+ API_TOKENS_USED: "contextos_api_tokens_used",
7818
+ // RLM
7819
+ RLM_EXECUTIONS: "contextos_rlm_executions_total",
7820
+ RLM_DURATION_MS: "contextos_rlm_duration_ms",
7821
+ RLM_DEPTH: "contextos_rlm_depth",
7822
+ RLM_WATCHDOG_TERMINATIONS: "contextos_rlm_watchdog_terminations",
7823
+ // Cache
7824
+ CACHE_HITS: "contextos_cache_hits_total",
7825
+ CACHE_MISSES: "contextos_cache_misses_total",
7826
+ CACHE_SIZE_BYTES: "contextos_cache_size_bytes",
7827
+ // Memory
7828
+ MEMORY_HEAP_USED: "contextos_memory_heap_used_bytes",
7829
+ MEMORY_HEAP_TOTAL: "contextos_memory_heap_total_bytes"
7830
+ };
7831
+
7832
+ // src/telemetry/tracer.ts
7833
+ var Span = class _Span {
7834
+ context;
7835
+ name;
7836
+ startTime;
7837
+ endTime;
7838
+ status = "unset";
7839
+ statusMessage;
7840
+ attributes = {};
7841
+ events = [];
7842
+ children = [];
7843
+ constructor(name, parentContext, attributes) {
7844
+ this.name = name;
7845
+ this.startTime = /* @__PURE__ */ new Date();
7846
+ this.context = {
7847
+ traceId: parentContext?.traceId || this.generateId(32),
7848
+ spanId: this.generateId(16),
7849
+ parentSpanId: parentContext?.spanId
7850
+ };
7851
+ if (attributes) {
7852
+ this.attributes = { ...attributes };
7853
+ }
7854
+ }
7855
+ /**
7856
+ * Set an attribute on the span
7857
+ */
7858
+ setAttribute(key, value) {
7859
+ this.attributes[key] = value;
7860
+ return this;
7861
+ }
7862
+ /**
7863
+ * Set multiple attributes
7864
+ */
7865
+ setAttributes(attributes) {
7866
+ Object.assign(this.attributes, attributes);
7867
+ return this;
7868
+ }
7869
+ /**
7870
+ * Add an event to the span
7871
+ */
7872
+ addEvent(name, attributes) {
7873
+ this.events.push({
7874
+ name,
7875
+ timestamp: /* @__PURE__ */ new Date(),
7876
+ attributes
7877
+ });
7878
+ return this;
7879
+ }
7880
+ /**
7881
+ * Set the span status
7882
+ */
7883
+ setStatus(status, message) {
7884
+ this.status = status;
7885
+ this.statusMessage = message;
7886
+ return this;
7887
+ }
7888
+ /**
7889
+ * Record an exception
7890
+ */
7891
+ recordException(error) {
7892
+ this.addEvent("exception", {
7893
+ "exception.type": error.name,
7894
+ "exception.message": error.message,
7895
+ "exception.stacktrace": error.stack
7896
+ });
7897
+ this.setStatus("error", error.message);
7898
+ return this;
7899
+ }
7900
+ /**
7901
+ * End the span
7902
+ */
7903
+ end() {
7904
+ if (!this.endTime) {
7905
+ this.endTime = /* @__PURE__ */ new Date();
7906
+ if (this.status === "unset") {
7907
+ this.status = "ok";
7908
+ }
7909
+ }
7910
+ return this;
7911
+ }
7912
+ /**
7913
+ * Get span duration in milliseconds
7914
+ */
7915
+ getDuration() {
7916
+ const end = this.endTime || /* @__PURE__ */ new Date();
7917
+ return end.getTime() - this.startTime.getTime();
7918
+ }
7919
+ /**
7920
+ * Check if span has ended
7921
+ */
7922
+ isEnded() {
7923
+ return !!this.endTime;
7924
+ }
7925
+ /**
7926
+ * Create a child span
7927
+ */
7928
+ startChild(name, attributes) {
7929
+ const child = new _Span(name, this.context, attributes);
7930
+ this.children.push(child);
7931
+ return child;
7932
+ }
7933
+ /**
7934
+ * Convert to JSON for logging/export
7935
+ */
7936
+ toJSON() {
7937
+ return {
7938
+ traceId: this.context.traceId,
7939
+ spanId: this.context.spanId,
7940
+ parentSpanId: this.context.parentSpanId,
7941
+ name: this.name,
7942
+ startTime: this.startTime.toISOString(),
7943
+ endTime: this.endTime?.toISOString(),
7944
+ duration: this.getDuration(),
7945
+ status: this.status,
7946
+ statusMessage: this.statusMessage,
7947
+ attributes: this.attributes,
7948
+ events: this.events.map((e) => ({
7949
+ name: e.name,
7950
+ timestamp: e.timestamp.toISOString(),
7951
+ attributes: e.attributes
7952
+ })),
7953
+ children: this.children.map((c) => c.toJSON())
7954
+ };
7955
+ }
7956
+ generateId(length) {
7957
+ const chars = "0123456789abcdef";
7958
+ let result = "";
7959
+ for (let i = 0; i < length; i++) {
7960
+ result += chars[Math.floor(Math.random() * chars.length)];
7961
+ }
7962
+ return result;
7963
+ }
7964
+ };
7965
+ var Tracer = class {
7966
+ name;
7967
+ version;
7968
+ activeSpan = null;
7969
+ spans = [];
7970
+ enabled;
7971
+ onSpanEnd;
7972
+ constructor(options) {
7973
+ this.name = options.name;
7974
+ this.version = options.version || "1.0.0";
7975
+ this.enabled = options.enabled ?? process.env.CONTEXTOS_TRACING !== "false";
7976
+ this.onSpanEnd = options.onSpanEnd;
7977
+ }
7978
+ /**
7979
+ * Start a new span
7980
+ */
7981
+ startSpan(name, attributes) {
7982
+ const parentContext = this.activeSpan?.context;
7983
+ const span = new Span(name, parentContext, {
7984
+ "service.name": this.name,
7985
+ "service.version": this.version,
7986
+ ...attributes
7987
+ });
7988
+ if (this.enabled) {
7989
+ this.spans.push(span);
7990
+ this.activeSpan = span;
7991
+ }
7992
+ return span;
7993
+ }
7994
+ /**
7995
+ * End a span and optionally export it
7996
+ */
7997
+ endSpan(span) {
7998
+ span.end();
7999
+ if (this.enabled && this.onSpanEnd) {
8000
+ this.onSpanEnd(span);
8001
+ }
8002
+ if (this.activeSpan === span && span.context.parentSpanId) {
8003
+ this.activeSpan = this.spans.find(
8004
+ (s) => s.context.spanId === span.context.parentSpanId
8005
+ ) || null;
8006
+ }
8007
+ }
8008
+ /**
8009
+ * Execute a function within a span
8010
+ */
8011
+ async withSpan(name, fn, attributes) {
8012
+ const span = this.startSpan(name, attributes);
8013
+ try {
8014
+ const result = await fn(span);
8015
+ span.setStatus("ok");
8016
+ return result;
8017
+ } catch (error) {
8018
+ if (error instanceof Error) {
8019
+ span.recordException(error);
8020
+ }
8021
+ throw error;
8022
+ } finally {
8023
+ this.endSpan(span);
8024
+ }
8025
+ }
8026
+ /**
8027
+ * Execute a sync function within a span
8028
+ */
8029
+ withSpanSync(name, fn, attributes) {
8030
+ const span = this.startSpan(name, attributes);
8031
+ try {
8032
+ const result = fn(span);
8033
+ span.setStatus("ok");
8034
+ return result;
8035
+ } catch (error) {
8036
+ if (error instanceof Error) {
8037
+ span.recordException(error);
8038
+ }
8039
+ throw error;
8040
+ } finally {
8041
+ this.endSpan(span);
8042
+ }
8043
+ }
8044
+ /**
8045
+ * Get all recorded spans
8046
+ */
8047
+ getSpans() {
8048
+ return [...this.spans];
8049
+ }
8050
+ /**
8051
+ * Clear recorded spans
8052
+ */
8053
+ clear() {
8054
+ this.spans = [];
8055
+ this.activeSpan = null;
8056
+ }
8057
+ /**
8058
+ * Get active span
8059
+ */
8060
+ getActiveSpan() {
8061
+ return this.activeSpan;
8062
+ }
8063
+ };
8064
+ var SPAN_NAMES = {
8065
+ // CLI operations
8066
+ CLI_INIT: "cli.init",
8067
+ CLI_INDEX: "cli.index",
8068
+ CLI_BUILD: "cli.build",
8069
+ CLI_ANALYZE: "cli.analyze",
8070
+ // Core operations
8071
+ PARSE_FILE: "core.parse_file",
8072
+ BUILD_GRAPH: "core.build_graph",
8073
+ COMPUTE_EMBEDDINGS: "core.compute_embeddings",
8074
+ RANK_FILES: "core.rank_files",
8075
+ BUILD_CONTEXT: "core.build_context",
8076
+ // RLM operations
8077
+ RLM_EXECUTE: "rlm.execute",
8078
+ RLM_SPAWN_AGENT: "rlm.spawn_agent",
8079
+ RLM_SANDBOX_RUN: "rlm.sandbox_run",
8080
+ // API operations
8081
+ API_COMPLETION: "api.completion",
8082
+ API_EMBEDDING: "api.embedding",
8083
+ // MCP operations
8084
+ MCP_TOOL_CALL: "mcp.tool_call",
8085
+ MCP_RESOURCE_READ: "mcp.resource_read"
8086
+ };
8087
+
8088
+ // src/telemetry/error-reporter.ts
8089
+ var ErrorReporter = class {
8090
+ enabled;
8091
+ handlers = [];
8092
+ breadcrumbs = [];
8093
+ maxBreadcrumbs = 50;
8094
+ globalTags = {};
8095
+ globalExtra = {};
8096
+ version;
8097
+ constructor(options = {}) {
8098
+ this.enabled = options.enabled ?? process.env.CONTEXTOS_ERROR_REPORTING !== "false";
8099
+ this.version = options.version || "2.0.0";
8100
+ this.maxBreadcrumbs = options.maxBreadcrumbs || 50;
8101
+ if (options.handlers) {
8102
+ this.handlers = options.handlers;
8103
+ }
8104
+ if (process.env.NODE_ENV === "development") {
8105
+ this.addHandler((report) => {
8106
+ console.error("[ErrorReporter]", report.error.name, report.error.message);
8107
+ });
8108
+ }
8109
+ }
8110
+ /**
8111
+ * Add an error report handler
8112
+ */
8113
+ addHandler(handler) {
8114
+ this.handlers.push(handler);
8115
+ }
8116
+ /**
8117
+ * Set global tags for all reports
8118
+ */
8119
+ setTags(tags) {
8120
+ Object.assign(this.globalTags, tags);
8121
+ }
8122
+ /**
8123
+ * Set global extra data for all reports
8124
+ */
8125
+ setExtra(extra) {
8126
+ Object.assign(this.globalExtra, extra);
8127
+ }
8128
+ /**
8129
+ * Add a breadcrumb
8130
+ */
8131
+ addBreadcrumb(breadcrumb) {
8132
+ this.breadcrumbs.push({
8133
+ ...breadcrumb,
8134
+ timestamp: /* @__PURE__ */ new Date()
8135
+ });
8136
+ if (this.breadcrumbs.length > this.maxBreadcrumbs) {
8137
+ this.breadcrumbs = this.breadcrumbs.slice(-this.maxBreadcrumbs);
8138
+ }
8139
+ }
8140
+ /**
8141
+ * Capture and report an error
8142
+ */
8143
+ async captureException(error, context) {
8144
+ if (!this.enabled) return null;
8145
+ const report = this.createReport(error, context);
8146
+ for (const handler of this.handlers) {
8147
+ try {
8148
+ await handler(report);
8149
+ } catch (handlerError) {
8150
+ console.error("[ErrorReporter] Handler failed:", handlerError);
8151
+ }
8152
+ }
8153
+ return report.id;
8154
+ }
8155
+ /**
8156
+ * Capture a message as an error
8157
+ */
8158
+ async captureMessage(message, level = "error", context) {
8159
+ const error = new Error(message);
8160
+ error.name = `Message.${level}`;
8161
+ return this.captureException(error, context);
8162
+ }
8163
+ /**
8164
+ * Wrap a function to auto-capture errors
8165
+ */
8166
+ wrap(fn, context) {
8167
+ const reporter = this;
8168
+ return ((...args) => {
8169
+ try {
8170
+ const result = fn(...args);
8171
+ if (result instanceof Promise) {
8172
+ return result.catch((error) => {
8173
+ reporter.captureException(error, context);
8174
+ throw error;
8175
+ });
8176
+ }
8177
+ return result;
8178
+ } catch (error) {
8179
+ if (error instanceof Error) {
8180
+ reporter.captureException(error, context);
8181
+ }
8182
+ throw error;
8183
+ }
8184
+ });
8185
+ }
8186
+ /**
8187
+ * Clear breadcrumbs
8188
+ */
8189
+ clearBreadcrumbs() {
8190
+ this.breadcrumbs = [];
8191
+ }
8192
+ /**
8193
+ * Get recent reports (for debugging)
8194
+ */
8195
+ getRecentBreadcrumbs() {
8196
+ return [...this.breadcrumbs];
8197
+ }
8198
+ createReport(error, context) {
8199
+ const isContextOSError = error instanceof ContextOSError;
8200
+ return {
8201
+ id: this.generateId(),
8202
+ timestamp: /* @__PURE__ */ new Date(),
8203
+ error: {
8204
+ name: error.name,
8205
+ message: error.message,
8206
+ stack: error.stack,
8207
+ code: isContextOSError ? error.code : void 0
8208
+ },
8209
+ context: {
8210
+ tags: { ...this.globalTags, ...context?.tags },
8211
+ extra: {
8212
+ ...this.globalExtra,
8213
+ ...context?.extra,
8214
+ ...isContextOSError ? error.context : {}
8215
+ },
8216
+ user: context?.user,
8217
+ operation: context?.operation,
8218
+ breadcrumbs: [...this.breadcrumbs, ...context?.breadcrumbs || []]
8219
+ },
8220
+ environment: {
8221
+ nodeVersion: process.version,
8222
+ platform: process.platform,
8223
+ arch: process.arch,
8224
+ contextosVersion: this.version
8225
+ }
8226
+ };
8227
+ }
8228
+ generateId() {
8229
+ return `err_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
8230
+ }
8231
+ };
8232
+ function createSentryHandler(dsn) {
8233
+ return async (report) => {
8234
+ if (process.env.NODE_ENV === "development") {
8235
+ console.log("[Sentry Mock] Would send to:", dsn);
8236
+ console.log("[Sentry Mock] Report:", JSON.stringify(report, null, 2));
8237
+ }
8238
+ };
8239
+ }
8240
+ function createConsoleHandler() {
8241
+ return (report) => {
8242
+ console.error(`
8243
+ \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
8244
+ \u2551 ERROR REPORT: ${report.id.padEnd(43)}\u2551
8245
+ \u2560\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2563
8246
+ \u2551 ${report.error.name}: ${report.error.message.substring(0, 50).padEnd(50)}\u2551
8247
+ \u2551 Code: ${(report.error.code || "N/A").padEnd(53)}\u2551
8248
+ \u2551 Time: ${report.timestamp.toISOString().padEnd(53)}\u2551
8249
+ \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
8250
+ `);
8251
+ };
8252
+ }
8253
+ function createFileHandler(logPath) {
8254
+ return async (report) => {
8255
+ const fs = await import("fs/promises");
8256
+ const line = JSON.stringify(report) + "\n";
8257
+ await fs.appendFile(logPath, line);
8258
+ };
8259
+ }
8260
+
8261
+ // src/telemetry/index.ts
8262
+ var Telemetry = class {
8263
+ metrics;
8264
+ tracer;
8265
+ errors;
8266
+ config;
8267
+ constructor(config = {}) {
8268
+ this.config = {
8269
+ enabled: true,
8270
+ serviceName: "contextos",
8271
+ serviceVersion: "2.0.0",
8272
+ metricsFlushIntervalMs: 6e4,
8273
+ // 1 minute
8274
+ ...config
8275
+ };
8276
+ this.metrics = new MetricsCollector({
8277
+ enabled: this.config.enabled,
8278
+ flushIntervalMs: this.config.metricsFlushIntervalMs,
8279
+ onFlush: this.config.onMetricsFlush
8280
+ });
8281
+ this.tracer = new Tracer({
8282
+ name: this.config.serviceName,
8283
+ version: this.config.serviceVersion,
8284
+ enabled: this.config.enabled,
8285
+ onSpanEnd: this.config.onSpanEnd
8286
+ });
8287
+ this.errors = new ErrorReporter({
8288
+ enabled: this.config.enabled,
8289
+ version: this.config.serviceVersion,
8290
+ handlers: this.config.errorHandlers || [createConsoleHandler()]
8291
+ });
8292
+ if (this.config.enabled) {
8293
+ this.setupGlobalHandlers();
8294
+ }
8295
+ }
8296
+ /**
8297
+ * Execute an operation with full telemetry
8298
+ */
8299
+ async traced(name, operation, options) {
8300
+ const span = this.tracer.startSpan(name, options?.attributes);
8301
+ const startTime = performance.now();
8302
+ try {
8303
+ const result = await operation(span);
8304
+ span.setStatus("ok");
8305
+ this.metrics.histogram(`${name}_duration_ms`, performance.now() - startTime);
8306
+ this.metrics.increment(`${name}_success`);
8307
+ return result;
8308
+ } catch (error) {
8309
+ if (error instanceof Error) {
8310
+ span.recordException(error);
8311
+ await this.errors.captureException(error, options?.errorContext);
8312
+ }
8313
+ this.metrics.increment(`${name}_error`);
8314
+ throw error;
8315
+ } finally {
8316
+ this.tracer.endSpan(span);
8317
+ }
8318
+ }
8319
+ /**
8320
+ * Record memory usage
8321
+ */
8322
+ recordMemoryUsage() {
8323
+ const usage = process.memoryUsage();
8324
+ this.metrics.gauge(METRICS.MEMORY_HEAP_USED, usage.heapUsed);
8325
+ this.metrics.gauge(METRICS.MEMORY_HEAP_TOTAL, usage.heapTotal);
8326
+ }
8327
+ /**
8328
+ * Flush all metrics
8329
+ */
8330
+ flush() {
8331
+ return this.metrics.flush();
8332
+ }
8333
+ /**
8334
+ * Shutdown telemetry
8335
+ */
8336
+ shutdown() {
8337
+ this.metrics.stop();
8338
+ this.tracer.clear();
8339
+ }
8340
+ setupGlobalHandlers() {
8341
+ process.on("unhandledRejection", (reason) => {
8342
+ if (reason instanceof Error) {
8343
+ this.errors.captureException(reason, {
8344
+ tags: { type: "unhandledRejection" }
8345
+ });
8346
+ }
8347
+ });
8348
+ process.on("uncaughtException", (error) => {
8349
+ this.errors.captureException(error, {
8350
+ tags: { type: "uncaughtException" }
8351
+ });
8352
+ });
8353
+ }
8354
+ };
8355
+ var globalTelemetry = null;
8356
+ function getTelemetry(config) {
8357
+ if (!globalTelemetry) {
8358
+ globalTelemetry = new Telemetry(config);
8359
+ }
8360
+ return globalTelemetry;
8361
+ }
8362
+ function initTelemetry(config) {
8363
+ if (globalTelemetry) {
8364
+ globalTelemetry.shutdown();
8365
+ }
8366
+ globalTelemetry = new Telemetry(config);
8367
+ return globalTelemetry;
8368
+ }
8369
+ function shutdownTelemetry() {
8370
+ if (globalTelemetry) {
8371
+ globalTelemetry.shutdown();
8372
+ globalTelemetry = null;
8373
+ }
8374
+ }
8375
+
7594
8376
  // src/generator/index.ts
7595
- import { existsSync as existsSync16, mkdirSync as mkdirSync10, writeFileSync as writeFileSync11, readFileSync as readFileSync15 } from "fs";
8377
+ import { existsSync as existsSync16, mkdirSync as mkdirSync10, writeFileSync as writeFileSync11, readFileSync as readFileSync14 } from "fs";
7596
8378
  import { dirname as dirname5, join as join15, resolve as resolve2, normalize as normalize3 } from "path";
7597
8379
 
7598
8380
  // src/generator/shadow-fs.ts
7599
- import { existsSync as existsSync14, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9, readFileSync as readFileSync13, rmSync as rmSync2, renameSync, copyFileSync } from "fs";
8381
+ import { existsSync as existsSync14, mkdirSync as mkdirSync9, writeFileSync as writeFileSync9, readFileSync as readFileSync12, rmSync as rmSync2, renameSync, copyFileSync } from "fs";
7600
8382
  import { join as join13, dirname as dirname4 } from "path";
7601
8383
  import { randomUUID } from "crypto";
7602
8384
  var ShadowFileSystem = class {
@@ -7661,11 +8443,11 @@ var ShadowFileSystem = class {
7661
8443
  if (tx && tx.files.has(realPath)) {
7662
8444
  const shadowPath = tx.files.get(realPath);
7663
8445
  if (existsSync14(shadowPath)) {
7664
- return readFileSync13(shadowPath, "utf-8");
8446
+ return readFileSync12(shadowPath, "utf-8");
7665
8447
  }
7666
8448
  }
7667
8449
  if (existsSync14(realPath)) {
7668
- return readFileSync13(realPath, "utf-8");
8450
+ return readFileSync12(realPath, "utf-8");
7669
8451
  }
7670
8452
  return null;
7671
8453
  }
@@ -7765,7 +8547,7 @@ function createShadowFS(rootDir) {
7765
8547
  }
7766
8548
 
7767
8549
  // src/context/negative-context.ts
7768
- import { existsSync as existsSync15, readFileSync as readFileSync14, writeFileSync as writeFileSync10 } from "fs";
8550
+ import { existsSync as existsSync15, readFileSync as readFileSync13, writeFileSync as writeFileSync10 } from "fs";
7769
8551
  import { join as join14 } from "path";
7770
8552
  var NegativeContextManager = class {
7771
8553
  contextIgnorePath;
@@ -7783,7 +8565,7 @@ var NegativeContextManager = class {
7783
8565
  return;
7784
8566
  }
7785
8567
  try {
7786
- const content = readFileSync14(this.contextIgnorePath, "utf-8");
8568
+ const content = readFileSync13(this.contextIgnorePath, "utf-8");
7787
8569
  const lines = content.split("\n").filter((line) => line.trim() && !line.startsWith("#"));
7788
8570
  this.rules = lines.map((line) => {
7789
8571
  const match = line.match(/^(\w+):(.+?)\|(.+)$/);
@@ -8073,7 +8855,7 @@ var AIGenerator = class {
8073
8855
  for (const prdPath of prdPaths) {
8074
8856
  const fullPath = join15(this.rootDir, prdPath);
8075
8857
  if (existsSync16(fullPath)) {
8076
- const content = readFileSync15(fullPath, "utf-8");
8858
+ const content = readFileSync14(fullPath, "utf-8");
8077
8859
  parts.push(`## ${prdPath}
8078
8860
 
8079
8861
  ${content}`);
@@ -8188,7 +8970,7 @@ Generate the files now:`;
8188
8970
  }
8189
8971
  if (!file.isNew && options.backupBeforeOverwrite) {
8190
8972
  const backupPath = `${fullPath}.bak`;
8191
- const existingContent = readFileSync15(fullPath, "utf-8");
8973
+ const existingContent = readFileSync14(fullPath, "utf-8");
8192
8974
  writeFileSync11(backupPath, existingContent);
8193
8975
  }
8194
8976
  writeFileSync11(fullPath, file.content, "utf-8");
@@ -8225,6 +9007,7 @@ export {
8225
9007
  E2EEncryption,
8226
9008
  EmbeddingConfigSchema,
8227
9009
  ErrorCode,
9010
+ ErrorReporter,
8228
9011
  Errors,
8229
9012
  GeminiClient,
8230
9013
  GraphConfigSchema,
@@ -8233,8 +9016,10 @@ export {
8233
9016
  LocalSandbox,
8234
9017
  LogLevel,
8235
9018
  Logger,
9019
+ METRICS,
8236
9020
  MODEL_SPECIFIC_ADDENDUM,
8237
9021
  MetaSchema,
9022
+ MetricsCollector,
8238
9023
  NegativeContextManager,
8239
9024
  OpenAIAdapter,
8240
9025
  PluginManager,
@@ -8244,13 +9029,17 @@ export {
8244
9029
  RBACManager,
8245
9030
  RLMEngine,
8246
9031
  RLM_BASE_SYSTEM_PROMPT,
9032
+ SPAN_NAMES,
8247
9033
  ScopeManager,
8248
9034
  ShadowFileSystem,
9035
+ Span,
8249
9036
  StackConfigSchema,
8250
9037
  SupportedLanguageSchema,
8251
9038
  TeamSync,
9039
+ Telemetry,
8252
9040
  TemplateManager,
8253
9041
  TokenBudget,
9042
+ Tracer,
8254
9043
  TrainingDataCollector,
8255
9044
  VectorStore,
8256
9045
  Watchdog,
@@ -8260,8 +9049,10 @@ export {
8260
9049
  createAIGenerator,
8261
9050
  createAnthropicAdapter,
8262
9051
  createBlackboard,
9052
+ createConsoleHandler,
8263
9053
  createContextAPI,
8264
9054
  createDatasetFormatter,
9055
+ createFileHandler,
8265
9056
  createGeminiClient,
8266
9057
  createInitialUserMessage,
8267
9058
  createLogger,
@@ -8275,6 +9066,7 @@ export {
8275
9066
  createSandbox,
8276
9067
  createSandboxContext,
8277
9068
  createScopeManager,
9069
+ createSentryHandler,
8278
9070
  createShadowFS,
8279
9071
  createSubAgentResultMessage,
8280
9072
  createTrainingDataCollector,
@@ -8300,7 +9092,9 @@ export {
8300
9092
  getModelPricing,
8301
9093
  getParser,
8302
9094
  getSupportedLanguages,
9095
+ getTelemetry,
8303
9096
  getTreeSitterLanguage,
9097
+ initTelemetry,
8304
9098
  isAnthropicAvailable,
8305
9099
  isGeminiAvailable,
8306
9100
  isInitialized,
@@ -8319,6 +9113,7 @@ export {
8319
9113
  saveConfigYaml,
8320
9114
  saveContextYaml,
8321
9115
  setGlobalLogger,
9116
+ shutdownTelemetry,
8322
9117
  splitContextToFiles,
8323
9118
  validateCode,
8324
9119
  validateLicense