@ctxo/cli 0.13.0 → 0.13.1

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
@@ -145,11 +145,11 @@ Agents get the same view from `get_architectural_overlay(mode: "contexts")`, and
145
145
 
146
146
  | Language | Plugin | Tier | Notes |
147
147
  |---|---|---|---|
148
- | TypeScript / JavaScript | `@ctxo/lang-typescript` | full | ts-morph; type-aware cross-file resolution |
149
- | Go | `@ctxo/lang-go` | syntax | tree-sitter; exported-symbol analysis |
148
+ | TypeScript / JavaScript | `@ctxo/lang-typescript` | full | ts-morph; type-aware cross-file resolution; decorators as annotations; test blocks as symbols; SQL at known call sites (pg, mysql2, mssql, knex, Prisma, TypeORM, Sequelize, better-sqlite3 raw SQL) |
149
+ | Go | `@ctxo/lang-go` | syntax / full | `ctxo-go-analyzer` full tier (Go 1.22+), tree-sitter fallback; struct tags as annotations; `_test.go` functions as symbols (full tier); SQL at known call sites (`database/sql`, sqlx, pgx, gorm raw; full tier) |
150
150
  | C# | `@ctxo/lang-csharp` | full | Roslyn; .NET SDK 8+ for full tier, tree-sitter fallback |
151
- | Java | `@ctxo/lang-java` | syntax / full | tree-sitter syntax tier built-in; full tier via `@ctxo/lang-java-analyzer` companion (JRE 11+ required, covers Java 8-21); detected by `pom.xml` / `build.gradle` |
152
- | SQL (T-SQL) | `@ctxo/lang-sql` | syntax | `.sql` tables, views, procedures and functions with `reads` / `writes` / `executes` edges; no database or .NET needed. With it installed, the C# plugin's Roslyn tier also links constant SQL at ADO.NET, Dapper, `SqlBulkCopy` and EF Core call sites to the same tables |
151
+ | Java | `@ctxo/lang-java` | syntax / full | tree-sitter syntax tier built-in; full tier via `@ctxo/lang-java-analyzer` companion (JRE 11+ required, covers Java 8-21); detected by `pom.xml` / `build.gradle`; annotations in both tiers; test methods with their annotations; SQL at known call sites (JDBC, Spring `JdbcTemplate`, JPA native queries, MyBatis; full tier) |
152
+ | SQL (T-SQL) | `@ctxo/lang-sql` | syntax | `.sql` tables, views, procedures and functions with `reads` / `writes` / `executes` edges; no database or .NET needed. With it installed, the C# plugin's Roslyn tier also links constant SQL at ADO.NET, Dapper, `SqlBulkCopy` and EF Core call sites to the same tables, and so do the TypeScript, Java and Go plugins at their known call sites |
153
153
 
154
154
  Install via the CLI shortcut:
155
155
 
@@ -2247,7 +2247,7 @@ var ArchitecturalOverlay = class {
2247
2247
  };
2248
2248
 
2249
2249
  // src/core/dead-code/dead-code-detector.ts
2250
- var TEST_PATTERNS = [/__tests__/, /\.test\.ts$/, /\.spec\.ts$/, /\btests\//, /\bfixtures?\//];
2250
+ var FIXTURE_PATTERN = /\bfixtures?\//;
2251
2251
  var CONFIG_PATTERNS = [/\.(config|rc)\.(ts|js|json)$/, /tsconfig/, /eslint/, /\.d\.ts$/];
2252
2252
  var SQL_PATTERN = /\.sql$/i;
2253
2253
  var FRAMEWORK_PATTERNS = [
@@ -2273,14 +2273,23 @@ var SCAFFOLDING_PATTERNS = [
2273
2273
  var DeadCodeDetector = class {
2274
2274
  detect(graph, options = {}) {
2275
2275
  const allNodes = graph.allNodes();
2276
+ const annotationAware = allNodes.some(
2277
+ (n) => (n.symbolId.split("::")[0] ?? "").endsWith(".cs") && (n.annotations?.length ?? 0) > 0
2278
+ );
2279
+ const isTestFile = createTestFileClassifier(
2280
+ [],
2281
+ filesWithTestAnnotations(allNodes.map((n) => ({ file: n.symbolId.split("::")[0] ?? "", symbols: [n] }))),
2282
+ { annotationAware }
2283
+ );
2284
+ const isExcluded = (file) => isTestFile(file) || FIXTURE_PATTERN.test(file) || this.matchesAny(file, CONFIG_PATTERNS);
2276
2285
  const candidates = allNodes.filter((n) => {
2277
2286
  const file = n.symbolId.split("::")[0] ?? "";
2278
2287
  if (SQL_PATTERN.test(file)) return false;
2279
2288
  if (options.includeTests) return true;
2280
- return !this.matchesAny(file, TEST_PATTERNS) && !this.matchesAny(file, CONFIG_PATTERNS);
2289
+ return !isExcluded(file);
2281
2290
  });
2282
2291
  if (candidates.length === 0) {
2283
- return { totalSymbols: 0, reachableSymbols: 0, deadSymbols: [], unusedExports: [], deadFiles: [], scaffolding: this.detectScaffolding(options.sourceContents), deadCodePercentage: 0 };
2292
+ return { totalSymbols: 0, reachableSymbols: 0, deadSymbols: [], unusedExports: [], deadFiles: [], scaffolding: this.detectScaffolding(isExcluded, options.sourceContents), deadCodePercentage: 0 };
2284
2293
  }
2285
2294
  const candidateIds = new Set(candidates.map((n) => n.symbolId));
2286
2295
  const entryPoints = /* @__PURE__ */ new Set();
@@ -2322,7 +2331,7 @@ var DeadCodeDetector = class {
2322
2331
  for (const node of candidates) {
2323
2332
  if (!deadIds.has(node.symbolId)) continue;
2324
2333
  const file = node.symbolId.split("::")[0] ?? "";
2325
- const confidence = this.computeConfidence(graph, node.symbolId, deadIds);
2334
+ const confidence = this.computeConfidence(graph, node.symbolId, deadIds, isExcluded);
2326
2335
  const cascadeDepth = cascadeDepthMap.get(node.symbolId);
2327
2336
  deadSymbols.push({
2328
2337
  symbolId: node.symbolId,
@@ -2358,7 +2367,7 @@ var DeadCodeDetector = class {
2358
2367
  });
2359
2368
  }
2360
2369
  }
2361
- const scaffolding = this.detectScaffolding(options.sourceContents);
2370
+ const scaffolding = this.detectScaffolding(isExcluded, options.sourceContents);
2362
2371
  const deadCodePercentage = Math.round(deadSymbols.length / candidates.length * 100 * 10) / 10;
2363
2372
  return {
2364
2373
  totalSymbols: candidates.length,
@@ -2370,14 +2379,14 @@ var DeadCodeDetector = class {
2370
2379
  deadCodePercentage
2371
2380
  };
2372
2381
  }
2373
- computeConfidence(graph, symbolId, deadIds) {
2382
+ computeConfidence(graph, symbolId, deadIds, isExcluded) {
2374
2383
  const reverseEdges = graph.getReverseEdges(symbolId);
2375
2384
  if (reverseEdges.length === 0) {
2376
2385
  return 1;
2377
2386
  }
2378
2387
  const allImportersExcluded = reverseEdges.every((e) => {
2379
2388
  const importerFile = e.from.split("::")[0] ?? "";
2380
- return this.matchesAny(importerFile, TEST_PATTERNS) || this.matchesAny(importerFile, CONFIG_PATTERNS);
2389
+ return isExcluded(importerFile);
2381
2390
  });
2382
2391
  if (allImportersExcluded) {
2383
2392
  return 0.9;
@@ -2427,11 +2436,11 @@ var DeadCodeDetector = class {
2427
2436
  }
2428
2437
  return depths;
2429
2438
  }
2430
- detectScaffolding(sourceContents) {
2439
+ detectScaffolding(isExcluded, sourceContents) {
2431
2440
  if (!sourceContents || sourceContents.size === 0) return [];
2432
2441
  const results = [];
2433
2442
  for (const [file, content] of sourceContents) {
2434
- if (this.matchesAny(file, TEST_PATTERNS) || this.matchesAny(file, CONFIG_PATTERNS)) continue;
2443
+ if (isExcluded(file)) continue;
2435
2444
  const lines = content.split("\n");
2436
2445
  for (let i = 0; i < lines.length; i++) {
2437
2446
  const line = lines[i];
@@ -2846,4 +2855,4 @@ export {
2846
2855
  SessionRecorderAdapter,
2847
2856
  detectWorkspace
2848
2857
  };
2849
- //# sourceMappingURL=chunk-BYX3UFBJ.js.map
2858
+ //# sourceMappingURL=chunk-WB7WZKX4.js.map