@getcodesentinel/codesentinel 1.9.5 → 1.10.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
@@ -178,6 +178,9 @@ codesentinel analyze . --author-identity likely_merge
178
178
  # Deterministic: strict email identity, no heuristic merging
179
179
  codesentinel analyze . --author-identity strict_email
180
180
 
181
+ # Tune recency window (days) used for evolution volatility
182
+ codesentinel analyze . --recent-window-days 60
183
+
181
184
  # Quiet mode (only JSON output)
182
185
  codesentinel analyze . --log-level silent
183
186
 
@@ -203,6 +206,7 @@ codesentinel explain . --module src/components
203
206
  # Explain in markdown or json
204
207
  codesentinel explain . --format md
205
208
  codesentinel explain . --format json
209
+ codesentinel explain . --recent-window-days 60
206
210
 
207
211
  # Report generation (human + machine readable)
208
212
  codesentinel report .
@@ -223,6 +227,7 @@ Notes:
223
227
  - At `info`/`debug`, structural, evolution, and dependency stages report progress so long analyses are observable.
224
228
  - `--output summary` (default) prints a compact result for terminal use.
225
229
  - `--output json` (or `--json`) prints the full analysis object.
230
+ - `--recent-window-days <days>` customizes the git recency window used to compute `recentVolatility` (default: `30`).
226
231
 
227
232
  When running through pnpm, pass CLI arguments after `--`:
228
233
 
@@ -318,7 +323,7 @@ Exit codes:
318
323
 
319
324
  Text/markdown output includes:
320
325
 
321
- - repository score and risk band (`low|moderate|high|very_high`)
326
+ - repository score and risk band (`low|moderate|elevated|high|very_high`)
322
327
  - plain-language primary drivers
323
328
  - concrete evidence values behind those drivers
324
329
  - intersected signals (composite interaction terms)
package/dist/index.js CHANGED
@@ -4992,7 +4992,7 @@ var createEvolutionProgressReporter = (logger) => {
4992
4992
  }
4993
4993
  };
4994
4994
  };
4995
- var collectAnalysisInputs = async (inputPath, authorIdentityMode, logger = createSilentLogger()) => {
4995
+ var collectAnalysisInputs = async (inputPath, authorIdentityMode, options = {}, logger = createSilentLogger()) => {
4996
4996
  const invocationCwd = process.env["INIT_CWD"] ?? process.cwd();
4997
4997
  const targetPath = resolveTargetPath(inputPath, invocationCwd);
4998
4998
  logger.info(`analyzing repository: ${targetPath}`);
@@ -5008,7 +5008,10 @@ var collectAnalysisInputs = async (inputPath, authorIdentityMode, logger = creat
5008
5008
  const evolution = analyzeRepositoryEvolutionFromGit(
5009
5009
  {
5010
5010
  repositoryPath: targetPath,
5011
- config: { authorIdentityMode }
5011
+ config: {
5012
+ authorIdentityMode,
5013
+ ...options.recentWindowDays === void 0 ? {} : { recentWindowDays: options.recentWindowDays }
5014
+ }
5012
5015
  },
5013
5016
  createEvolutionProgressReporter(logger)
5014
5017
  );
@@ -5037,8 +5040,8 @@ var collectAnalysisInputs = async (inputPath, authorIdentityMode, logger = creat
5037
5040
  external
5038
5041
  };
5039
5042
  };
5040
- var runAnalyzeCommand = async (inputPath, authorIdentityMode, logger = createSilentLogger()) => {
5041
- const analysisInputs = await collectAnalysisInputs(inputPath, authorIdentityMode, logger);
5043
+ var runAnalyzeCommand = async (inputPath, authorIdentityMode, options = {}, logger = createSilentLogger()) => {
5044
+ const analysisInputs = await collectAnalysisInputs(inputPath, authorIdentityMode, options, logger);
5042
5045
  logger.info("computing risk summary");
5043
5046
  const risk = computeRepositoryRiskSummary(analysisInputs);
5044
5047
  logger.info(`analysis completed (repositoryScore=${risk.repositoryScore})`);
@@ -5053,7 +5056,14 @@ import { readFile, writeFile } from "fs/promises";
5053
5056
 
5054
5057
  // src/application/build-analysis-snapshot.ts
5055
5058
  var buildAnalysisSnapshot = async (inputPath, authorIdentityMode, options, logger) => {
5056
- const analysisInputs = await collectAnalysisInputs(inputPath, authorIdentityMode, logger);
5059
+ const analysisInputs = await collectAnalysisInputs(
5060
+ inputPath,
5061
+ authorIdentityMode,
5062
+ {
5063
+ ...options.recentWindowDays === void 0 ? {} : { recentWindowDays: options.recentWindowDays }
5064
+ },
5065
+ logger
5066
+ );
5057
5067
  const evaluation = evaluateRepositoryRisk(analysisInputs, { explain: options.includeTrace });
5058
5068
  const summary = {
5059
5069
  ...analysisInputs,
@@ -5064,7 +5074,8 @@ var buildAnalysisSnapshot = async (inputPath, authorIdentityMode, options, logge
5064
5074
  ...evaluation.trace === void 0 ? {} : { trace: evaluation.trace },
5065
5075
  analysisConfig: {
5066
5076
  authorIdentityMode,
5067
- includeTrace: options.includeTrace
5077
+ includeTrace: options.includeTrace,
5078
+ recentWindowDays: analysisInputs.evolution.available ? analysisInputs.evolution.metrics.recentWindowDays : options.recentWindowDays ?? null
5068
5079
  }
5069
5080
  });
5070
5081
  };
@@ -5096,7 +5107,10 @@ var runCheckCommand = async (inputPath, authorIdentityMode, options, logger = cr
5096
5107
  const current = await buildAnalysisSnapshot(
5097
5108
  inputPath,
5098
5109
  authorIdentityMode,
5099
- { includeTrace: options.includeTrace },
5110
+ {
5111
+ includeTrace: options.includeTrace,
5112
+ ...options.recentWindowDays === void 0 ? {} : { recentWindowDays: options.recentWindowDays }
5113
+ },
5100
5114
  logger
5101
5115
  );
5102
5116
  let baseline;
@@ -5163,7 +5177,10 @@ var runCiCommand = async (inputPath, authorIdentityMode, options, logger = creat
5163
5177
  const current = await buildAnalysisSnapshot(
5164
5178
  inputPath,
5165
5179
  authorIdentityMode,
5166
- { includeTrace: options.includeTrace },
5180
+ {
5181
+ includeTrace: options.includeTrace,
5182
+ ...options.recentWindowDays === void 0 ? {} : { recentWindowDays: options.recentWindowDays }
5183
+ },
5167
5184
  logger
5168
5185
  );
5169
5186
  if (options.snapshotPath !== void 0) {
@@ -5218,7 +5235,10 @@ var runCiCommand = async (inputPath, authorIdentityMode, options, logger = creat
5218
5235
  return buildAnalysisSnapshot(
5219
5236
  baselineTargetPath,
5220
5237
  authorIdentityMode,
5221
- { includeTrace: options.includeTrace },
5238
+ {
5239
+ includeTrace: options.includeTrace,
5240
+ ...options.recentWindowDays === void 0 ? {} : { recentWindowDays: options.recentWindowDays }
5241
+ },
5222
5242
  logger
5223
5243
  );
5224
5244
  }
@@ -5290,7 +5310,10 @@ var runReportCommand = async (inputPath, authorIdentityMode, options, logger = c
5290
5310
  const current = await buildAnalysisSnapshot(
5291
5311
  inputPath,
5292
5312
  authorIdentityMode,
5293
- { includeTrace: options.includeTrace },
5313
+ {
5314
+ includeTrace: options.includeTrace,
5315
+ ...options.recentWindowDays === void 0 ? {} : { recentWindowDays: options.recentWindowDays }
5316
+ },
5294
5317
  logger
5295
5318
  );
5296
5319
  if (options.snapshotPath !== void 0) {
@@ -5336,7 +5359,14 @@ var selectTargets = (trace, summary, options) => {
5336
5359
  );
5337
5360
  };
5338
5361
  var runExplainCommand = async (inputPath, authorIdentityMode, options, logger = createSilentLogger()) => {
5339
- const analysisInputs = await collectAnalysisInputs(inputPath, authorIdentityMode, logger);
5362
+ const analysisInputs = await collectAnalysisInputs(
5363
+ inputPath,
5364
+ authorIdentityMode,
5365
+ {
5366
+ ...options.recentWindowDays === void 0 ? {} : { recentWindowDays: options.recentWindowDays }
5367
+ },
5368
+ logger
5369
+ );
5340
5370
  logger.info("computing explainable risk summary");
5341
5371
  const evaluation = evaluateRepositoryRisk(analysisInputs, { explain: true });
5342
5372
  if (evaluation.trace === void 0) {
@@ -5358,6 +5388,13 @@ var runExplainCommand = async (inputPath, authorIdentityMode, options, logger =
5358
5388
  var program = new Command();
5359
5389
  var packageJsonPath = resolve5(dirname(fileURLToPath(import.meta.url)), "../package.json");
5360
5390
  var { version } = JSON.parse(readFileSync2(packageJsonPath, "utf8"));
5391
+ var parseRecentWindowDays = (value) => {
5392
+ const parsed = Number.parseInt(value, 10);
5393
+ if (!Number.isInteger(parsed) || parsed <= 0) {
5394
+ throw new Error("--recent-window-days must be a positive integer");
5395
+ }
5396
+ return parsed;
5397
+ };
5361
5398
  program.name("codesentinel").description("Structural and evolutionary risk analysis for TypeScript/JavaScript codebases").version(version);
5362
5399
  program.command("analyze").argument("[path]", "path to the project to analyze").addOption(
5363
5400
  new Option(
@@ -5371,10 +5408,20 @@ program.command("analyze").argument("[path]", "path to the project to analyze").
5371
5408
  ).choices(["silent", "error", "warn", "info", "debug"]).default(parseLogLevel(process.env["CODESENTINEL_LOG_LEVEL"]))
5372
5409
  ).addOption(
5373
5410
  new Option("--output <mode>", "output mode: summary (default) or json (full analysis object)").choices(["summary", "json"]).default("summary")
5374
- ).option("--json", "shortcut for --output json").action(
5411
+ ).option("--json", "shortcut for --output json").addOption(
5412
+ new Option(
5413
+ "--recent-window-days <days>",
5414
+ "git recency window in days used for evolution volatility metrics"
5415
+ ).argParser(parseRecentWindowDays).default(30)
5416
+ ).action(
5375
5417
  async (path, options) => {
5376
5418
  const logger = createStderrLogger(options.logLevel);
5377
- const summary = await runAnalyzeCommand(path, options.authorIdentity, logger);
5419
+ const summary = await runAnalyzeCommand(
5420
+ path,
5421
+ options.authorIdentity,
5422
+ { recentWindowDays: options.recentWindowDays },
5423
+ logger
5424
+ );
5378
5425
  const outputMode = options.json === true ? "json" : options.output;
5379
5426
  process.stdout.write(`${formatAnalyzeOutput(summary, outputMode)}
5380
5427
  `);
@@ -5391,6 +5438,11 @@ program.command("explain").argument("[path]", "path to the project to analyze").
5391
5438
  "log verbosity: silent, error, warn, info, debug (logs are written to stderr)"
5392
5439
  ).choices(["silent", "error", "warn", "info", "debug"]).default(parseLogLevel(process.env["CODESENTINEL_LOG_LEVEL"]))
5393
5440
  ).option("--file <path>", "explain a specific file target").option("--module <name>", "explain a specific module target").option("--top <count>", "number of top hotspots to explain when no target is selected", "5").addOption(
5441
+ new Option(
5442
+ "--recent-window-days <days>",
5443
+ "git recency window in days used for evolution volatility metrics"
5444
+ ).argParser(parseRecentWindowDays).default(30)
5445
+ ).addOption(
5394
5446
  new Option("--format <mode>", "output format: text, json, md").choices(["text", "json", "md"]).default("md")
5395
5447
  ).action(
5396
5448
  async (path, options) => {
@@ -5400,6 +5452,7 @@ program.command("explain").argument("[path]", "path to the project to analyze").
5400
5452
  ...options.file === void 0 ? {} : { file: options.file },
5401
5453
  ...options.module === void 0 ? {} : { module: options.module },
5402
5454
  top: Number.isFinite(top) ? top : 5,
5455
+ recentWindowDays: options.recentWindowDays,
5403
5456
  format: options.format
5404
5457
  };
5405
5458
  const result = await runExplainCommand(path, options.authorIdentity, explainOptions, logger);
@@ -5449,7 +5502,12 @@ program.command("report").argument("[path]", "path to the project to analyze").a
5449
5502
  ).choices(["silent", "error", "warn", "info", "debug"]).default(parseLogLevel(process.env["CODESENTINEL_LOG_LEVEL"]))
5450
5503
  ).addOption(
5451
5504
  new Option("--format <mode>", "output format: text, json, md").choices(["text", "json", "md"]).default("md")
5452
- ).option("--output <path>", "write rendered report to a file path").option("--compare <baseline>", "compare against a baseline snapshot JSON file").option("--snapshot <path>", "write current snapshot JSON artifact").option("--no-trace", "disable trace embedding in generated snapshot").action(
5505
+ ).option("--output <path>", "write rendered report to a file path").option("--compare <baseline>", "compare against a baseline snapshot JSON file").option("--snapshot <path>", "write current snapshot JSON artifact").option("--no-trace", "disable trace embedding in generated snapshot").addOption(
5506
+ new Option(
5507
+ "--recent-window-days <days>",
5508
+ "git recency window in days used for evolution volatility metrics"
5509
+ ).argParser(parseRecentWindowDays).default(30)
5510
+ ).action(
5453
5511
  async (path, options) => {
5454
5512
  const logger = createStderrLogger(options.logLevel);
5455
5513
  const result = await runReportCommand(
@@ -5460,7 +5518,8 @@ program.command("report").argument("[path]", "path to the project to analyze").a
5460
5518
  ...options.output === void 0 ? {} : { outputPath: options.output },
5461
5519
  ...options.compare === void 0 ? {} : { comparePath: options.compare },
5462
5520
  ...options.snapshot === void 0 ? {} : { snapshotPath: options.snapshot },
5463
- includeTrace: options.trace
5521
+ includeTrace: options.trace,
5522
+ recentWindowDays: options.recentWindowDays
5464
5523
  },
5465
5524
  logger
5466
5525
  );
@@ -5525,7 +5584,12 @@ program.command("check").argument("[path]", "path to the project to analyze").ad
5525
5584
  new Option("--fail-on <level>", "failing severity threshold").choices(["error", "warn"]).default("error")
5526
5585
  ).addOption(
5527
5586
  new Option("--format <mode>", "output format: text, json, md").choices(["text", "json", "md"]).default("text")
5528
- ).option("--output <path>", "write check output to a file path").option("--no-trace", "disable trace embedding in generated snapshot").action(
5587
+ ).option("--output <path>", "write check output to a file path").option("--no-trace", "disable trace embedding in generated snapshot").addOption(
5588
+ new Option(
5589
+ "--recent-window-days <days>",
5590
+ "git recency window in days used for evolution volatility metrics"
5591
+ ).argParser(parseRecentWindowDays).default(30)
5592
+ ).action(
5529
5593
  async (path, options) => {
5530
5594
  const logger = createStderrLogger(options.logLevel);
5531
5595
  try {
@@ -5536,6 +5600,7 @@ program.command("check").argument("[path]", "path to the project to analyze").ad
5536
5600
  {
5537
5601
  ...options.compare === void 0 ? {} : { baselinePath: options.compare },
5538
5602
  includeTrace: options.trace,
5603
+ recentWindowDays: options.recentWindowDays,
5539
5604
  gateConfig,
5540
5605
  outputFormat: options.format,
5541
5606
  ...options.output === void 0 ? {} : { outputPath: options.output }
@@ -5584,7 +5649,12 @@ program.command("ci").argument("[path]", "path to the project to analyze").addOp
5584
5649
  "comma-separated default branch candidates for auto baseline resolution (for example: main,master)"
5585
5650
  ).option("--snapshot <path>", "write current snapshot JSON to path").option("--report <path>", "write markdown CI summary report").option("--json-output <path>", "write machine-readable CI JSON output").option("--max-repo-delta <value>", "maximum allowed normalized repository score increase").option("--no-new-cycles", "fail if new structural cycles are introduced").option("--no-new-high-risk-deps", "fail if new high-risk direct dependencies are introduced").option("--max-new-hotspots <count>", "maximum allowed number of new hotspots").option("--new-hotspot-score-threshold <score>", "minimum hotspot score to count as new hotspot").option("--max-repo-score <score>", "absolute repository score limit (0..100)").addOption(
5586
5651
  new Option("--fail-on <level>", "failing severity threshold").choices(["error", "warn"]).default("error")
5587
- ).option("--no-trace", "disable trace embedding in generated snapshot").action(
5652
+ ).option("--no-trace", "disable trace embedding in generated snapshot").addOption(
5653
+ new Option(
5654
+ "--recent-window-days <days>",
5655
+ "git recency window in days used for evolution volatility metrics"
5656
+ ).argParser(parseRecentWindowDays).default(30)
5657
+ ).action(
5588
5658
  async (path, options) => {
5589
5659
  const logger = createStderrLogger(options.logLevel);
5590
5660
  try {
@@ -5602,6 +5672,7 @@ program.command("ci").argument("[path]", "path to the project to analyze").addOp
5602
5672
  ...options.report === void 0 ? {} : { reportPath: options.report },
5603
5673
  ...options.jsonOutput === void 0 ? {} : { jsonOutputPath: options.jsonOutput },
5604
5674
  includeTrace: options.trace,
5675
+ recentWindowDays: options.recentWindowDays,
5605
5676
  gateConfig
5606
5677
  },
5607
5678
  logger