@ctxo/cli 0.14.0 → 0.15.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.
Files changed (41) hide show
  1. package/README.md +10 -1
  2. package/dist/{chunk-ZL36YS2V.js → chunk-A4URKKPP.js} +3 -177
  3. package/dist/{chunk-SRQZDGFZ.js → chunk-BBSJB4CG.js} +2 -2
  4. package/dist/{chunk-X4TVFJ4C.js → chunk-EC6INGPV.js} +1 -1
  5. package/dist/{chunk-7HSA5JVP.js → chunk-I7RPXT6L.js} +193 -1
  6. package/dist/chunk-IT426P3F.js +1036 -0
  7. package/dist/{chunk-G4BMKCKG.js → chunk-JDL6GGTO.js} +16 -5
  8. package/dist/{cli-router-AZCDNX5R.js → cli-router-W56INOQ3.js} +10 -10
  9. package/dist/index.js +3 -3
  10. package/dist/internal.d.ts +90 -3
  11. package/dist/internal.js +4 -4
  12. package/dist/{json-index-reader-DBW32TCN.js → json-index-reader-DKEIP2QR.js} +2 -2
  13. package/dist/{mcp-server-6YG2QE6E.js → mcp-server-IYCCE74E.js} +178 -446
  14. package/dist/module-host-KTGDODES.js +13 -0
  15. package/llms-full.txt +68 -3
  16. package/llms.txt +14 -2
  17. package/package.json +4 -3
  18. package/dist/atomic-write-BAFH464Q.js.map +0 -1
  19. package/dist/chunk-2Q76LH2H.js.map +0 -1
  20. package/dist/chunk-5DSKZJNN.js.map +0 -1
  21. package/dist/chunk-72CEQEQD.js.map +0 -1
  22. package/dist/chunk-7HSA5JVP.js.map +0 -1
  23. package/dist/chunk-G4BMKCKG.js.map +0 -1
  24. package/dist/chunk-L2CAUER6.js +0 -508
  25. package/dist/chunk-L2CAUER6.js.map +0 -1
  26. package/dist/chunk-LAX6VVBU.js.map +0 -1
  27. package/dist/chunk-PSKDDLSF.js.map +0 -1
  28. package/dist/chunk-RFEXMBTG.js.map +0 -1
  29. package/dist/chunk-SRQZDGFZ.js.map +0 -1
  30. package/dist/chunk-X4TVFJ4C.js.map +0 -1
  31. package/dist/chunk-ZL36YS2V.js.map +0 -1
  32. package/dist/cli-router-AZCDNX5R.js.map +0 -1
  33. package/dist/index.js.map +0 -1
  34. package/dist/internal.js.map +0 -1
  35. package/dist/json-index-reader-DBW32TCN.js.map +0 -1
  36. package/dist/mcp-server-6YG2QE6E.js.map +0 -1
  37. package/dist/module-host-KNMKS62R.js +0 -13
  38. package/dist/module-host-KNMKS62R.js.map +0 -1
  39. package/dist/module-loader-B3LYF3W7.js.map +0 -1
  40. package/dist/plugin-discovery-XRXI3IJF.js.map +0 -1
  41. package/dist/staleness-detector-4HJYBQ7Z.js.map +0 -1
@@ -1,9 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ DOCUMENT_SEARCH_CONFIG,
4
+ SearchEngine,
3
5
  buildGraphFromIndices
4
- } from "./chunk-L2CAUER6.js";
6
+ } from "./chunk-IT426P3F.js";
5
7
  import {
6
8
  SimpleGitAdapter,
9
+ SymbolTokenizer,
7
10
  TEST_FRAMEWORK_ANNOTATIONS,
8
11
  createTestFileClassifier,
9
12
  filesWithTestAnnotations,
@@ -14,20 +17,21 @@ import {
14
17
  resolveCoChangeConfig,
15
18
  selectWindow,
16
19
  windowCutoff
17
- } from "./chunk-7HSA5JVP.js";
20
+ } from "./chunk-I7RPXT6L.js";
18
21
  import {
19
22
  getVersion,
20
23
  locateGitRoot
21
24
  } from "./chunk-72CEQEQD.js";
22
25
  import {
23
26
  JsonIndexReader
24
- } from "./chunk-X4TVFJ4C.js";
27
+ } from "./chunk-EC6INGPV.js";
25
28
  import {
26
29
  createLogger
27
30
  } from "./chunk-5DSKZJNN.js";
28
31
 
29
32
  // src/cli/module-host.ts
30
33
  import { join } from "path";
34
+ import { DATA_RESOURCE_KINDS } from "@ctxo/plugin-api";
31
35
  var log = createLogger("ctxo:module-host");
32
36
  async function readCoChangeWindow(projectRoot, config) {
33
37
  try {
@@ -58,7 +62,14 @@ var HOST_SERVICES = Object.freeze({
58
62
  buildGraph: buildGraphFromIndices,
59
63
  readCoChangeWindow,
60
64
  findGitRoot: (dir) => locateGitRoot(dir) ?? void 0,
61
- testFrameworkAnnotations: TEST_FRAMEWORK_ANNOTATIONS
65
+ testFrameworkAnnotations: TEST_FRAMEWORK_ANNOTATIONS,
66
+ dataResourceKinds: DATA_RESOURCE_KINDS,
67
+ createDocumentSearch: (documents) => {
68
+ const engine = new SearchEngine(DOCUMENT_SEARCH_CONFIG);
69
+ engine.buildDocumentIndex(documents);
70
+ return { search: (query, limit) => engine.search(query, limit) };
71
+ },
72
+ splitIdentifier: (name) => SymbolTokenizer.splitName(name)
62
73
  });
63
74
  function createModuleHost(options) {
64
75
  return {
@@ -73,4 +84,4 @@ function createModuleHost(options) {
73
84
  export {
74
85
  createModuleHost
75
86
  };
76
- //# sourceMappingURL=chunk-G4BMKCKG.js.map
87
+ //# sourceMappingURL=chunk-JDL6GGTO.js.map
@@ -12,11 +12,10 @@ import {
12
12
  RevertDetector,
13
13
  SessionRecorderAdapter,
14
14
  SqliteStorageAdapter,
15
- SymbolTokenizer,
16
15
  buildCoChangeMatrix,
17
16
  detectWorkspace,
18
17
  findCoChangedFilesForBlastRadius
19
- } from "./chunk-ZL36YS2V.js";
18
+ } from "./chunk-A4URKKPP.js";
20
19
  import {
21
20
  FAST_ROUTE_COMMANDS,
22
21
  isKnownModuleCommand,
@@ -24,7 +23,7 @@ import {
24
23
  moduleHelpLines,
25
24
  runFastRoute,
26
25
  runModuleCommand
27
- } from "./chunk-SRQZDGFZ.js";
26
+ } from "./chunk-BBSJB4CG.js";
28
27
  import {
29
28
  DOMAIN_MODULE_PACKAGE,
30
29
  loadCtxoModules
@@ -38,6 +37,7 @@ import {
38
37
  DATA_EDGE_KINDS,
39
38
  SimpleGitAdapter,
40
39
  SymbolGraph,
40
+ SymbolTokenizer,
41
41
  communityDetectorOptions,
42
42
  createTestFileClassifier,
43
43
  factsRequested,
@@ -55,7 +55,7 @@ import {
55
55
  selectWindow,
56
56
  watchSnapshotMinFileChanges,
57
57
  windowCutoff
58
- } from "./chunk-7HSA5JVP.js";
58
+ } from "./chunk-I7RPXT6L.js";
59
59
  import {
60
60
  compareCodepoint,
61
61
  getCliPackageRoot,
@@ -67,7 +67,7 @@ import {
67
67
  INDEX_ARTIFACT_FILES,
68
68
  JsonIndexReader,
69
69
  isMarkedArtifact
70
- } from "./chunk-X4TVFJ4C.js";
70
+ } from "./chunk-EC6INGPV.js";
71
71
  import {
72
72
  atomicWrite
73
73
  } from "./chunk-RFEXMBTG.js";
@@ -2607,7 +2607,7 @@ var IndexCommand = class {
2607
2607
  if (passes.length === 0) return;
2608
2608
  let ctx;
2609
2609
  try {
2610
- const { createModuleHost } = await import("./module-host-KNMKS62R.js");
2610
+ const { createModuleHost } = await import("./module-host-KTGDODES.js");
2611
2611
  const { services } = createModuleHost({ projectRoot: this.projectRoot, mode: "cli" });
2612
2612
  let graph;
2613
2613
  ctx = {
@@ -2783,7 +2783,7 @@ var IndexCommand = class {
2783
2783
  if (_roslyn) await _roslyn.dispose();
2784
2784
  const hasher = new ContentHasher();
2785
2785
  const files = this.discoverFilesIn(this.projectRoot);
2786
- const reader = new (await import("./json-index-reader-DBW32TCN.js")).JsonIndexReader(this.ctxoRoot);
2786
+ const reader = new (await import("./json-index-reader-DKEIP2QR.js")).JsonIndexReader(this.ctxoRoot);
2787
2787
  const indices = reader.readAll();
2788
2788
  const indexedMap = new Map(indices.map((i) => [i.file, i]));
2789
2789
  let staleCount = 0;
@@ -4656,7 +4656,7 @@ var InitCommand = class {
4656
4656
  const [{ DOMAIN_MODULE_PACKAGE: DOMAIN_MODULE_PACKAGE2, loadCtxoModules: loadCtxoModules2 }, { resolvePackageCandidates: resolvePackageCandidates2 }, { createModuleHost }] = await Promise.all([
4657
4657
  import("./module-loader-B3LYF3W7.js"),
4658
4658
  import("./plugin-discovery-XRXI3IJF.js"),
4659
- import("./module-host-KNMKS62R.js")
4659
+ import("./module-host-KTGDODES.js")
4660
4660
  ]);
4661
4661
  if (resolvePackageCandidates2(DOMAIN_MODULE_PACKAGE2, this.projectRoot, this.cliAnchor).length === 0) return void 0;
4662
4662
  const host = createModuleHost({ projectRoot: this.projectRoot, mode: "cli" });
@@ -5619,7 +5619,7 @@ async function collectModuleReports(projectRoot, options = {}) {
5619
5619
  if (resolvePackageCandidates(DOMAIN_MODULE_PACKAGE, projectRoot, options.cliAnchor).length === 0) {
5620
5620
  return [{ name: DOMAIN_MODULE_PACKAGE, status: "not-installed" }];
5621
5621
  }
5622
- const { createModuleHost } = await import("./module-host-KNMKS62R.js");
5622
+ const { createModuleHost } = await import("./module-host-KTGDODES.js");
5623
5623
  const { reports } = await loadCtxoModules(createModuleHost({ projectRoot, mode: "cli" }), { cliAnchor: options.cliAnchor });
5624
5624
  return reports;
5625
5625
  } catch (err) {
@@ -8409,4 +8409,4 @@ Usage:
8409
8409
  export {
8410
8410
  CliRouter
8411
8411
  };
8412
- //# sourceMappingURL=cli-router-AZCDNX5R.js.map
8412
+ //# sourceMappingURL=cli-router-W56INOQ3.js.map
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  FAST_ROUTE_COMMANDS,
4
4
  runFastRoute
5
- } from "./chunk-SRQZDGFZ.js";
5
+ } from "./chunk-BBSJB4CG.js";
6
6
  import "./chunk-72CEQEQD.js";
7
7
  import {
8
8
  createLogger
@@ -28,12 +28,12 @@ async function main() {
28
28
  process.exitCode = await runFastRoute(args, process.cwd());
29
29
  return;
30
30
  }
31
- const { CliRouter } = await import("./cli-router-AZCDNX5R.js");
31
+ const { CliRouter } = await import("./cli-router-W56INOQ3.js");
32
32
  const router = new CliRouter(process.cwd());
33
33
  await router.route(args);
34
34
  return;
35
35
  }
36
- const { startMcpServer } = await import("./mcp-server-6YG2QE6E.js");
36
+ const { startMcpServer } = await import("./mcp-server-IYCCE74E.js");
37
37
  await startMcpServer(httpPortStr ? { httpPort: parseInt(httpPortStr, 10) } : {});
38
38
  }
39
39
  main().catch((err) => {
@@ -216,6 +216,51 @@ interface GitRefs {
216
216
  /** Remote-tracking branches as `<remote>/<name>` (refs/remotes, no HEAD aliases), in codepoint order. */
217
217
  readonly remoteBranches?: readonly string[];
218
218
  }
219
+ interface SearchResult {
220
+ symbolId: string;
221
+ name: string;
222
+ kind: string;
223
+ filePath: string;
224
+ /** BM25 relevance score (higher = more relevant) */
225
+ relevanceScore: number;
226
+ /** PageRank importance score (0-1) */
227
+ importanceScore: number;
228
+ /** Final combined score after all boosts */
229
+ combinedScore: number;
230
+ }
231
+ /**
232
+ * A document for the BM25 engine's document index (`SearchEngine.buildDocumentIndex`). A hit carries `id` in
233
+ * `symbolId`, `title` in `name`, `kind` and `path` in `filePath`.
234
+ */
235
+ interface SearchDocument {
236
+ readonly id: string;
237
+ readonly title: string;
238
+ readonly kind: string;
239
+ readonly path: string;
240
+ readonly text: string;
241
+ }
242
+ interface SearchMetrics {
243
+ porterHits: number;
244
+ trigramHits: number;
245
+ phase2Activated: boolean;
246
+ fuzzyApplied: boolean;
247
+ latencyMs: number;
248
+ }
249
+ interface FuzzyCorrection {
250
+ originalQuery: string;
251
+ correctedQuery: string;
252
+ corrections: Array<{
253
+ original: string;
254
+ corrected: string;
255
+ distance: number;
256
+ }>;
257
+ }
258
+ interface SearchResponse {
259
+ query: string;
260
+ results: SearchResult[];
261
+ metrics: SearchMetrics;
262
+ fuzzyCorrection?: FuzzyCorrection;
263
+ }
219
264
  interface CommunityEntry {
220
265
  readonly symbolId: string;
221
266
  readonly communityId: number;
@@ -533,9 +578,34 @@ interface IGitPort {
533
578
  type CoreToolName = 'get_logic_slice' | 'get_why_context' | 'get_change_intelligence' | 'get_blast_radius' | 'get_architectural_overlay' | 'find_dead_code' | 'get_context_for_task' | 'get_ranked_context' | 'search_symbols' | 'get_changed_symbols' | 'find_importers' | 'get_class_hierarchy' | 'get_symbol_importance' | 'get_pr_impact';
534
579
  /**
535
580
  * Adds fields to a core tool's payload before the envelope, truncation and masking see it. Additive only:
536
- * it returns the payload with its fields added and never removes or rewrites the core's fields.
581
+ * it returns the payload with its fields added and never removes or rewrites the core's fields. Seven core
582
+ * tools have the seam: `get_blast_radius`, `get_pr_impact` and `get_why_context` await a Promise result;
583
+ * the synchronous `search_symbols`, `find_importers`, `get_logic_slice` and `get_context_for_task` cannot,
584
+ * so for them a Promise result is dropped with a warning.
537
585
  */
538
- type ResponseEnricher = (payload: Record<string, unknown>, args: Readonly<Record<string, unknown>>) => Record<string, unknown>;
586
+ type ResponseEnricher = (payload: Record<string, unknown>, args: Readonly<Record<string, unknown>>) => Record<string, unknown> | Promise<Record<string, unknown>>;
587
+ /**
588
+ * The tokens a module keeps back from `get_context_for_task`'s budget for the fields its enricher adds,
589
+ * given the tool's validated arguments. The core packs the code context into what is left; it rounds the
590
+ * value and caps it at a quarter of the budget, and reserves nothing when it throws or is not finite.
591
+ */
592
+ type TokenReservation = (args: Readonly<Record<string, unknown>>) => number;
593
+ /**
594
+ * A scope of `get_ranked_context` a module contributes (`scope: "<name>"`). The tool gains its `scope`
595
+ * parameter only when a module provides one; `"code"`, the symbol ranking, stays the default. The CLI
596
+ * validates `query` and `tokenBudget` (at least 100, default 4000), then wraps the result in the `_meta`
597
+ * envelope and masks it. `strategy` and `searchMode` do not reach a module scope.
598
+ */
599
+ interface RankedContextScope {
600
+ /** The scope name, never `code`. */
601
+ readonly scope: string;
602
+ /** One sentence appended to the `scope` parameter description, such as `"domain": card sections.` */
603
+ readonly description: string;
604
+ search(args: {
605
+ readonly query: string;
606
+ readonly tokenBudget: number;
607
+ }): Promise<Record<string, unknown>> | Record<string, unknown>;
608
+ }
539
609
  /** An MCP tool a module contributes. The CLI wraps the handler with the envelope, masking and recording. */
540
610
  interface ModuleToolDefinition {
541
611
  readonly name: string;
@@ -634,10 +704,18 @@ interface CtxoModuleRegistration {
634
704
  indexPass?(ctx: IndexPassContext): Promise<void>;
635
705
  registerTools?(registrar: ToolRegistrar): void;
636
706
  readonly enrich?: Partial<Record<CoreToolName, ResponseEnricher>>;
707
+ /** Tokens kept back from `get_context_for_task`'s budget for this module's enriched fields. */
708
+ readonly reserveTaskContextTokens?: TokenReservation;
709
+ /** Extra `get_ranked_context` scopes; a name already taken, or `code`, is skipped with a warning. */
710
+ readonly rankedContextScopes?: readonly RankedContextScope[];
637
711
  registerCommands?(registrar: CommandRegistrar): void;
638
712
  readonly init?: InitContribution;
639
713
  readonly doctorChecks?: readonly IHealthCheck[];
640
714
  }
715
+ /** A built document index. Hits carry the document `id` in `symbolId`, its `title` in `name`, its `kind` and `path`. */
716
+ interface DocumentSearch {
717
+ search(query: string, limit?: number): SearchResponse;
718
+ }
641
719
  /** The runtime services a module gets from the CLI instead of importing them. */
642
720
  interface CtxoHostServices {
643
721
  createLogger(namespace: string): Logger;
@@ -655,6 +733,15 @@ interface CtxoHostServices {
655
733
  findGitRoot(dir: string): string | undefined;
656
734
  /** Short names of the attributes that mark a test (`Fact`, `Test`, `TestMethod`, ...): the classifier's own list. */
657
735
  readonly testFrameworkAnnotations: readonly string[];
736
+ /** Symbol kinds that are data resources (`table`, `view`): plugin-api's own `DATA_RESOURCE_KINDS`, one source. */
737
+ readonly dataResourceKinds: readonly string[];
738
+ /**
739
+ * A BM25 search over documents (the core engine: camelCase-aware, trigram and fuzzy fallback), built once.
740
+ * Pass the documents in codepoint order (of `id`, say): equal scores keep the input order.
741
+ */
742
+ createDocumentSearch(documents: readonly SearchDocument[]): DocumentSearch;
743
+ /** Splits an identifier into its words: `ILoanRepository` gives `I`, `Loan`, `Repository`; `member_account_id` gives `member`, `account`, `id`. */
744
+ splitIdentifier(name: string): string[];
658
745
  }
659
746
  interface CtxoHost {
660
747
  readonly cliVersion: string;
@@ -744,4 +831,4 @@ declare function createModuleHost(options: CreateModuleHostOptions): CtxoHost;
744
831
  type SymbolGraph = SymbolGraph$1;
745
832
  type BlastRadiusCalculator = BlastRadiusCalculator$1;
746
833
 
747
- export { type BlastRadiusCalculator, type ChangeLog, type CheckContext, type CheckResult, type CheckStatus, type ClaudeHookEntry, type CoChangeEntry, type CoChangeWindowCommits, type CommandRegistrar, type CommitChangeSet, type CoreToolName, type CtxoConfig, type CtxoHost, type CtxoHostServices, type CtxoModuleRegister, type CtxoModuleRegistration, type EdgeKind, type FileChange, type FileChangeStatus, type FileIndex, type GitRange, type GitRefs, type GraphEdge, type IGitPort, type IHealthCheck, type IMaskingPort, type IStoragePort, type IndexPassContext, type InitContribution, type InitFileResult, type InitPartContext, type InitPrompter, type LoadedConfig, type Logger, type ModuleCommand, type ModuleCommandContext, type ModuleToolDefinition, type RangeCommit, type ResponseEnricher, type ResponseMeta, type SymbolGraph, type SymbolKind, type SymbolNode, type TestFileCheck, type ToolRegistrar, createModuleHost };
834
+ export { type BlastRadiusCalculator, type ChangeLog, type CheckContext, type CheckResult, type CheckStatus, type ClaudeHookEntry, type CoChangeEntry, type CoChangeWindowCommits, type CommandRegistrar, type CommitChangeSet, type CoreToolName, type CtxoConfig, type CtxoHost, type CtxoHostServices, type CtxoModuleRegister, type CtxoModuleRegistration, type DocumentSearch, type EdgeKind, type FileChange, type FileChangeStatus, type FileIndex, type GitRange, type GitRefs, type GraphEdge, type IGitPort, type IHealthCheck, type IMaskingPort, type IStoragePort, type IndexPassContext, type InitContribution, type InitFileResult, type InitPartContext, type InitPrompter, type LoadedConfig, type Logger, type ModuleCommand, type ModuleCommandContext, type ModuleToolDefinition, type RangeCommit, type RankedContextScope, type ResponseEnricher, type ResponseMeta, type SearchDocument, type SearchMetrics, type SearchResponse, type SearchResult, type SymbolGraph, type SymbolKind, type SymbolNode, type TestFileCheck, type TokenReservation, type ToolRegistrar, createModuleHost };
package/dist/internal.js CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  createModuleHost
4
- } from "./chunk-G4BMKCKG.js";
5
- import "./chunk-L2CAUER6.js";
6
- import "./chunk-7HSA5JVP.js";
4
+ } from "./chunk-JDL6GGTO.js";
5
+ import "./chunk-IT426P3F.js";
6
+ import "./chunk-I7RPXT6L.js";
7
7
  import "./chunk-72CEQEQD.js";
8
- import "./chunk-X4TVFJ4C.js";
8
+ import "./chunk-EC6INGPV.js";
9
9
  import "./chunk-5DSKZJNN.js";
10
10
  export {
11
11
  createModuleHost
@@ -4,7 +4,7 @@ import {
4
4
  INDEX_ARTIFACT_FILES,
5
5
  JsonIndexReader,
6
6
  isMarkedArtifact
7
- } from "./chunk-X4TVFJ4C.js";
7
+ } from "./chunk-EC6INGPV.js";
8
8
  import "./chunk-5DSKZJNN.js";
9
9
  export {
10
10
  COMMUNITY_HISTORY_DIR,
@@ -12,4 +12,4 @@ export {
12
12
  JsonIndexReader,
13
13
  isMarkedArtifact
14
14
  };
15
- //# sourceMappingURL=json-index-reader-DBW32TCN.js.map
15
+ //# sourceMappingURL=json-index-reader-DKEIP2QR.js.map