ctxloom-pro 1.2.7 → 1.3.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 CHANGED
@@ -502,6 +502,83 @@ Pass `--no-git` to disable the overlay entirely. Tools degrade gracefully — th
502
502
 
503
503
  ---
504
504
 
505
+ ## Response Budgets (v1.2.7+)
506
+
507
+ Twelve source-returning tools accept a server-enforced **token budget**. When a response would exceed the budget, the server auto-substitutes a lighter form (Skeletonizer signature view, summary-only XML, or paths-without-snippets) instead of dumping 50KB of source into your context window.
508
+
509
+ ### Opting in
510
+
511
+ Pass any of these three optional fields to any of the 12 supported tools:
512
+
513
+ ```json
514
+ {
515
+ "max_response_tokens": 4000,
516
+ "on_budget_exceeded": "skeleton",
517
+ "response_format": "auto"
518
+ }
519
+ ```
520
+
521
+ | Field | Values | Default |
522
+ |---|---|---|
523
+ | `max_response_tokens` | positive integer | per-tool (see below) |
524
+ | `on_budget_exceeded` | `"skeleton"` \| `"truncate"` \| `"error"` | `"skeleton"` |
525
+ | `response_format` | `"full"` \| `"skeleton"` \| `"auto"` | `"auto"` |
526
+
527
+ **Back-compat:** when none of these fields are passed, the tool returns its raw response unchanged. Existing callers see zero behavior change.
528
+
529
+ ### Response envelope
530
+
531
+ When you opt in, the response is wrapped in a JSON envelope:
532
+
533
+ ```json
534
+ {
535
+ "data": "<the actual tool output — XML, text, or whatever the tool returns>",
536
+ "meta": {
537
+ "format": "full" | "skeleton" | "truncated",
538
+ "original_tokens_est": 8400,
539
+ "returned_tokens_est": 1600,
540
+ "fallback_reason": null | "budget_exceeded" | "minified_input" | "size_cap" | "skeleton_failed"
541
+ }
542
+ }
543
+ ```
544
+
545
+ ### Supported tools + default budgets
546
+
547
+ Defaults activate only when you opt in (any of the 3 fields above) without specifying `max_response_tokens` explicitly.
548
+
549
+ | Tool | Default | Skeleton fallback |
550
+ |---|---:|---|
551
+ | `ctx_get_file` | 8000 | Skeletonizer view of the file (~90% reduction on TS) |
552
+ | `ctx_get_context_packet` | 6000 | Re-render with the primary file skeletonized |
553
+ | `ctx_get_definition` | 2000 | none — truncate-only (already structural) |
554
+ | `ctx_git_diff_review` | 8000 | Drop `<skeleton>` blocks + omit transitive importers |
555
+ | `ctx_search` | 4000 | Drop content snippets (paths + scores only) |
556
+ | `ctx_full_text_search` | 4000 | Drop match snippets (paths + match counts only) |
557
+ | `ctx_wiki_generate` | 12000 | Downgrade to `detail_level=minimal` |
558
+ | `ctx_find_large_functions` | 2000 | none — truncate-only |
559
+ | `ctx_apply_refactor` | 2000 | none — truncate-only |
560
+ | `ctx_refactor_preview` | 4000 | Drop per-change before/after, keep file summary |
561
+ | `ctx_cross_repo_search` | 4000 | Drop content snippets |
562
+ | `ctx_execution_flow` | 4000 | none — truncate-only |
563
+
564
+ Defaults are **provisional** (derived from the issue's initial table); a future release will re-derive them from real per-tool p75 telemetry once enough usage data accumulates.
565
+
566
+ ### Token estimator
567
+
568
+ Default = `chars / 4` — within ±10% of GPT/Claude tokenizers on code with zero tokenization cost. Pluggable per-tool via the `estimator` option on `BudgetOptions` for callers that need accuracy-critical estimation (e.g. tiktoken).
569
+
570
+ ### Kill switch
571
+
572
+ Set `CTXLOOM_DISABLE_BUDGET=1` in the environment to silently ignore every `max_response_tokens` arg server-wide. Tools behave exactly as in pre-v1.2.7. Documented escape hatch for the soak period.
573
+
574
+ ### Telemetry
575
+
576
+ Set `CTXLOOM_TELEMETRY_LEVEL=full` to emit structured `mcp.budget.exceeded` and `mcp.fallback.used` events to stderr. Useful for tuning defaults against your own usage patterns.
577
+
578
+ > **Note:** `CTXLOOM_TELEMETRY_LEVEL` is also consumed by the license / PostHog telemetry layer (see [Telemetry](#telemetry) below) which only recognizes `all` / `error` / `off`. `full` is a separate, **additive** level — it enables budget-event emission *without narrowing* PostHog scope. To narrow PostHog telemetry, set the variable to `error` or `off`; those values disable budget events as a side effect.
579
+
580
+ ---
581
+
505
582
  ## CLI Commands
506
583
 
507
584
  ```
@@ -11422,7 +11422,7 @@ function resolveTelemetryLevel() {
11422
11422
  }
11423
11423
  var TELEMETRY_LEVEL = resolveTelemetryLevel();
11424
11424
  var TELEMETRY_DISABLED = TELEMETRY_LEVEL === "off";
11425
- var CTXLOOM_VERSION = "1.2.7".length > 0 ? "1.2.7" : "dev";
11425
+ var CTXLOOM_VERSION = "1.3.0".length > 0 ? "1.3.0" : "dev";
11426
11426
  var POSTHOG_HOST = "https://eu.i.posthog.com";
11427
11427
  var POSTHOG_KEY = process.env["POSTHOG_API_KEY"] ?? (true ? "phc_CiDkmFLcZ2K6uCpcoSUQLmFrnnUvsyXGhSxopX5TVKE6" : "");
11428
11428
  var SENTRY_DSN = process.env["SENTRY_DSN"] ?? (true ? "https://81c94a0f04a8e242dee493ac1e17f733@o4508531702497280.ingest.de.sentry.io/4511256875368528" : "");
@@ -9342,7 +9342,7 @@ var TELEMETRY_DISABLED = TELEMETRY_LEVEL === "off";
9342
9342
  function getTelemetryLevel() {
9343
9343
  return TELEMETRY_LEVEL;
9344
9344
  }
9345
- var CTXLOOM_VERSION = "1.2.7".length > 0 ? "1.2.7" : "dev";
9345
+ var CTXLOOM_VERSION = "1.3.0".length > 0 ? "1.3.0" : "dev";
9346
9346
  var POSTHOG_HOST = "https://eu.i.posthog.com";
9347
9347
  var POSTHOG_KEY = process.env["POSTHOG_API_KEY"] ?? (true ? "phc_CiDkmFLcZ2K6uCpcoSUQLmFrnnUvsyXGhSxopX5TVKE6" : "");
9348
9348
  var SENTRY_DSN = process.env["SENTRY_DSN"] ?? (true ? "https://81c94a0f04a8e242dee493ac1e17f733@o4508531702497280.ingest.de.sentry.io/4511256875368528" : "");
@@ -10072,4 +10072,4 @@ export {
10072
10072
  FirstTouchTracker,
10073
10073
  EmittedOnceTracker
10074
10074
  };
10075
- //# sourceMappingURL=chunk-RY3JAC2Q.js.map
10075
+ //# sourceMappingURL=chunk-Q2KTZNNU.js.map
package/dist/index.js CHANGED
@@ -49,7 +49,7 @@ import {
49
49
  validateDefaultRoot,
50
50
  wrapWithIndexingEnvelope,
51
51
  writeCODEOWNERS
52
- } from "./chunk-RY3JAC2Q.js";
52
+ } from "./chunk-Q2KTZNNU.js";
53
53
  import {
54
54
  VectorStore
55
55
  } from "./chunk-DVI2RWJR.js";
@@ -1018,7 +1018,7 @@ try {
1018
1018
  } catch {
1019
1019
  }
1020
1020
  var args = process.argv.slice(2);
1021
- var ctxloomVersion = "1.2.7".length > 0 ? "1.2.7" : "dev";
1021
+ var ctxloomVersion = "1.3.0".length > 0 ? "1.3.0" : "dev";
1022
1022
  if (args.includes("--version") || args.includes("-v")) {
1023
1023
  process.stdout.write(`ctxloom ${ctxloomVersion}
1024
1024
  `);
@@ -1091,7 +1091,7 @@ async function checkLicense() {
1091
1091
  if (command !== void 0 && LICENSE_GATE_BYPASS_COMMANDS.has(command)) return;
1092
1092
  const ciKey = process.env["CTXLOOM_LICENSE_KEY"];
1093
1093
  if (ciKey) {
1094
- const { ApiClient } = await import("./src-3ZB6BHFW.js");
1094
+ const { ApiClient } = await import("./src-HNXOOOWF.js");
1095
1095
  const client = new ApiClient(process.env["CTXLOOM_API_BASE"]);
1096
1096
  try {
1097
1097
  const result = await client.validate(ciKey, "ci-ephemeral");
@@ -1496,7 +1496,7 @@ async function main() {
1496
1496
  process.exit(1);
1497
1497
  }
1498
1498
  if (alias !== void 0) {
1499
- const { validateAlias } = await import("./src-3ZB6BHFW.js");
1499
+ const { validateAlias } = await import("./src-HNXOOOWF.js");
1500
1500
  const v = validateAlias(alias);
1501
1501
  if (!v.ok) {
1502
1502
  console.error(`[ctxloom] Invalid alias: ${v.reason}`);
@@ -1743,7 +1743,7 @@ Suggested reviewers for ${files.length} file(s):`);
1743
1743
  process.stderr.write("[ctxloom] --limit must be a non-negative integer (0 for unlimited)\n");
1744
1744
  process.exit(2);
1745
1745
  }
1746
- const { loadRulesConfig, RulesChecker, formatText, formatJson, RulesConfigError } = await import("./src-3ZB6BHFW.js");
1746
+ const { loadRulesConfig, RulesChecker, formatText, formatJson, RulesConfigError } = await import("./src-HNXOOOWF.js");
1747
1747
  let config;
1748
1748
  try {
1749
1749
  config = await loadRulesConfig(root);
@@ -1767,7 +1767,7 @@ Suggested reviewers for ${files.length} file(s):`);
1767
1767
  }
1768
1768
  let graph;
1769
1769
  if (useSnapshot) {
1770
- const { DependencyGraph: DG } = await import("./src-3ZB6BHFW.js");
1770
+ const { DependencyGraph: DG } = await import("./src-HNXOOOWF.js");
1771
1771
  graph = new DG();
1772
1772
  const loaded = await graph.loadSnapshotOnly(root);
1773
1773
  if (!loaded) {
@@ -1776,7 +1776,7 @@ Suggested reviewers for ${files.length} file(s):`);
1776
1776
  }
1777
1777
  } else {
1778
1778
  process.stderr.write("[ctxloom] Building dependency graph...\n");
1779
- const { ASTParser: ASTParser2, DependencyGraph: DependencyGraph2 } = await import("./src-3ZB6BHFW.js");
1779
+ const { ASTParser: ASTParser2, DependencyGraph: DependencyGraph2 } = await import("./src-HNXOOOWF.js");
1780
1780
  let parser;
1781
1781
  try {
1782
1782
  parser = new ASTParser2();
@@ -103,7 +103,7 @@ import {
103
103
  validateDefaultRoot,
104
104
  wrapWithIndexingEnvelope,
105
105
  writeCODEOWNERS
106
- } from "./chunk-RY3JAC2Q.js";
106
+ } from "./chunk-Q2KTZNNU.js";
107
107
  import {
108
108
  VectorStore
109
109
  } from "./chunk-DVI2RWJR.js";
@@ -228,4 +228,4 @@ export {
228
228
  wrapWithIndexingEnvelope,
229
229
  writeCODEOWNERS
230
230
  };
231
- //# sourceMappingURL=src-3ZB6BHFW.js.map
231
+ //# sourceMappingURL=src-HNXOOOWF.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ctxloom-pro",
3
- "version": "1.2.7",
3
+ "version": "1.3.0",
4
4
  "description": "ctxloom — The Universal Code Context Engine. A local-first MCP server providing intelligent code context via hybrid Vector + AST + Graph search with Skeletonization (92% token reduction).",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",