@aiready/cli 0.14.26 → 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.
package/dist/cli.js CHANGED
@@ -25,8 +25,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
25
25
 
26
26
  // src/cli.ts
27
27
  var import_commander = require("commander");
28
- var import_fs8 = require("fs");
29
- var import_path7 = require("path");
28
+ var import_fs9 = require("fs");
29
+ var import_path8 = require("path");
30
30
  var import_url = require("url");
31
31
 
32
32
  // src/commands/scan.ts
@@ -544,7 +544,8 @@ var SCAN_DEFAULTS = {
544
544
  "testability-index",
545
545
  "doc-drift",
546
546
  "dependency-health",
547
- "change-amplification"
547
+ "change-amplification",
548
+ "contract-enforcement"
548
549
  ],
549
550
  include: void 0,
550
551
  exclude: void 0,
@@ -602,6 +603,7 @@ var TOOL_PACKAGE_MAP = {
602
603
  [import_core7.ToolName.DocDrift]: "@aiready/doc-drift",
603
604
  [import_core7.ToolName.DependencyHealth]: "@aiready/deps",
604
605
  [import_core7.ToolName.ChangeAmplification]: "@aiready/change-amplification",
606
+ [import_core7.ToolName.ContractEnforcement]: "@aiready/contract-enforcement",
605
607
  // Aliases handled by registry
606
608
  patterns: "@aiready/pattern-detect",
607
609
  duplicates: "@aiready/pattern-detect",
@@ -612,7 +614,8 @@ var TOOL_PACKAGE_MAP = {
612
614
  grounding: "@aiready/agent-grounding",
613
615
  testability: "@aiready/testability",
614
616
  "deps-health": "@aiready/deps",
615
- "change-amp": "@aiready/change-amplification"
617
+ "change-amp": "@aiready/change-amplification",
618
+ contract: "@aiready/contract-enforcement"
616
619
  };
617
620
  var UnifiedOrchestrator = class {
618
621
  /**
@@ -761,7 +764,8 @@ var UnifiedOrchestrator = class {
761
764
  "testability-index": ["testabilityIndex", "testability"],
762
765
  "doc-drift": ["docDrift"],
763
766
  "dependency-health": ["dependencyHealth", "deps"],
764
- "change-amplification": ["changeAmplification"]
767
+ "change-amplification": ["changeAmplification"],
768
+ "contract-enforcement": ["contractEnforcement", "contract"]
765
769
  };
766
770
  for (const [kebabKey, aliases] of Object.entries(keyMappings)) {
767
771
  if (result[kebabKey]) {
@@ -1075,6 +1079,28 @@ async function scanAction(directory, options) {
1075
1079
  finalOptions,
1076
1080
  results
1077
1081
  );
1082
+ const isCI = options.ci ?? process.env.CI === "true";
1083
+ if (!isCI) {
1084
+ console.log(
1085
+ import_chalk6.default.dim(
1086
+ "\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
1087
+ )
1088
+ );
1089
+ console.log(import_chalk6.default.bold("\u{1F4C8} Want to see the full interactive report?"));
1090
+ console.log(
1091
+ import_chalk6.default.cyan(
1092
+ ` Upload this report to: ${import_chalk6.default.bold("https://platform.getaiready.dev")}`
1093
+ )
1094
+ );
1095
+ console.log(
1096
+ import_chalk6.default.dim(" Or run: ") + import_chalk6.default.white(`aiready upload ${outputPath}`)
1097
+ );
1098
+ console.log(
1099
+ import_chalk6.default.dim(
1100
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
1101
+ )
1102
+ );
1103
+ }
1078
1104
  } catch (error) {
1079
1105
  (0, import_core10.handleCLIError)(error, "Analysis");
1080
1106
  }
@@ -2063,8 +2089,79 @@ async function testabilityAction(directory, options) {
2063
2089
  // src/commands/change-amplification.ts
2064
2090
  var import_cli = require("@aiready/change-amplification/dist/cli.js");
2065
2091
 
2066
- // src/commands/bug.ts
2092
+ // src/commands/contract-enforcement.ts
2067
2093
  var import_chalk16 = __toESM(require("chalk"));
2094
+ async function contractEnforcementAction(directory, options) {
2095
+ return await executeToolAction(directory, options, {
2096
+ toolName: "contract-enforcement",
2097
+ label: "Contract enforcement analysis",
2098
+ emoji: "\u{1F6E1}\uFE0F",
2099
+ defaults: {
2100
+ minChainDepth: 3,
2101
+ include: void 0,
2102
+ exclude: void 0,
2103
+ output: { format: "console", file: void 0 }
2104
+ },
2105
+ getCliOptions: (opts) => ({
2106
+ minChainDepth: opts.minChainDepth ? parseInt(opts.minChainDepth, 10) : void 0
2107
+ }),
2108
+ importTool: async () => {
2109
+ const tool = await import("@aiready/contract-enforcement");
2110
+ return {
2111
+ analyze: tool.analyzeContractEnforcement,
2112
+ generateSummary: (report) => report.summary,
2113
+ calculateScore: tool.calculateContractEnforcementScore
2114
+ };
2115
+ },
2116
+ renderConsole: ({ results, summary, score }) => {
2117
+ renderToolHeader(
2118
+ "Contract Enforcement",
2119
+ "\u{1F6E1}\uFE0F",
2120
+ score?.score || 0,
2121
+ summary.rating
2122
+ );
2123
+ const rawData = results.rawData || results;
2124
+ console.log(
2125
+ import_chalk16.default.dim(
2126
+ ` Patterns: ${summary.totalDefensivePatterns} (${summary.defensiveDensity}/kLOC) | ${summary.sourceFiles} files scanned`
2127
+ )
2128
+ );
2129
+ const dims = summary.dimensions;
2130
+ if (dims) {
2131
+ const entries = [
2132
+ ["Type Escape Hatches", dims.typeEscapeHatchScore],
2133
+ ["Fallback Cascades", dims.fallbackCascadeScore],
2134
+ ["Error Transparency", dims.errorTransparencyScore],
2135
+ ["Boundary Validation", dims.boundaryValidationScore]
2136
+ ];
2137
+ for (const [name, val] of entries) {
2138
+ const color = val >= 80 ? import_chalk16.default.green : val >= 60 ? import_chalk16.default.yellow : import_chalk16.default.red;
2139
+ console.log(import_chalk16.default.dim(` ${name}: ${color(val + "/100")}`));
2140
+ }
2141
+ }
2142
+ if (summary.totalDefensivePatterns > 0 && rawData["as-any"] !== void 0) {
2143
+ const breakdown = [
2144
+ rawData["as-any"] && `as-any: ${rawData["as-any"]}`,
2145
+ rawData["as-unknown"] && `as-unknown: ${rawData["as-unknown"]}`,
2146
+ rawData["deep-optional-chain"] && `deep-?.: ${rawData["deep-optional-chain"]}`,
2147
+ rawData["nullish-literal-default"] && `?? literal: ${rawData["nullish-literal-default"]}`,
2148
+ rawData["swallowed-error"] && `swallowed-error: ${rawData["swallowed-error"]}`,
2149
+ rawData["env-fallback"] && `env-fallback: ${rawData["env-fallback"]}`,
2150
+ rawData["unnecessary-guard"] && `guard-clause: ${rawData["unnecessary-guard"]}`,
2151
+ rawData["any-parameter"] && `any-param: ${rawData["any-parameter"]}`,
2152
+ rawData["any-return"] && `any-return: ${rawData["any-return"]}`
2153
+ ].filter(Boolean).join(" | ");
2154
+ console.log(import_chalk16.default.dim(` ${breakdown}`));
2155
+ }
2156
+ if (score) {
2157
+ renderToolScoreFooter(score);
2158
+ }
2159
+ }
2160
+ });
2161
+ }
2162
+
2163
+ // src/commands/bug.ts
2164
+ var import_chalk17 = __toESM(require("chalk"));
2068
2165
  var import_child_process2 = require("child_process");
2069
2166
  async function bugAction(message, options) {
2070
2167
  const repoUrl = "https://github.com/caopengau/aiready-cli";
@@ -2082,35 +2179,35 @@ Generated via AIReady CLI 'bug' command.
2082
2179
  Type: ${type}
2083
2180
  `.trim();
2084
2181
  if (options.submit) {
2085
- console.log(import_chalk16.default.blue("\u{1F680} Submitting issue via GitHub CLI...\n"));
2182
+ console.log(import_chalk17.default.blue("\u{1F680} Submitting issue via GitHub CLI...\n"));
2086
2183
  try {
2087
2184
  (0, import_child_process2.execSync)("gh auth status", { stdio: "ignore" });
2088
2185
  const command = `gh issue create --repo ${repoSlug} --title ${JSON.stringify(title)} --body ${JSON.stringify(body)} --label ${label}`;
2089
2186
  const output = (0, import_child_process2.execSync)(command, { encoding: "utf8" }).trim();
2090
- console.log(import_chalk16.default.green("\u2705 Issue Created Successfully!"));
2091
- console.log(import_chalk16.default.cyan(output));
2187
+ console.log(import_chalk17.default.green("\u2705 Issue Created Successfully!"));
2188
+ console.log(import_chalk17.default.cyan(output));
2092
2189
  return;
2093
2190
  } catch {
2094
- console.error(import_chalk16.default.red("\n\u274C Failed to submit via gh CLI."));
2191
+ console.error(import_chalk17.default.red("\n\u274C Failed to submit via gh CLI."));
2095
2192
  console.log(
2096
- import_chalk16.default.yellow(
2193
+ import_chalk17.default.yellow(
2097
2194
  ' Make sure gh is installed and run "gh auth login".\n'
2098
2195
  )
2099
2196
  );
2100
- console.log(import_chalk16.default.dim(" Falling back to URL generation..."));
2197
+ console.log(import_chalk17.default.dim(" Falling back to URL generation..."));
2101
2198
  }
2102
2199
  }
2103
2200
  const template = type === "bug" ? "bug_report.md" : type === "feature" ? "feature_request.md" : "new_metric_idea.md";
2104
2201
  const fullUrl = `${repoUrl}/issues/new?title=${encodeURIComponent(title)}&body=${encodeURIComponent(body)}&labels=${label}&template=${template}`;
2105
- console.log(import_chalk16.default.green("\u{1F680} Issue Draft Prepared!\n"));
2106
- console.log(import_chalk16.default.bold("Title: ") + title);
2107
- console.log(import_chalk16.default.bold("Type: ") + type);
2108
- console.log(import_chalk16.default.bold("\nClick the link below to submit this issue:"));
2109
- console.log(import_chalk16.default.cyan(fullUrl));
2110
- console.log(import_chalk16.default.bold("\n\u{1F916} [FOR AI AGENTS]:"));
2111
- console.log(import_chalk16.default.dim(" You have successfully prepared a report."));
2202
+ console.log(import_chalk17.default.green("\u{1F680} Issue Draft Prepared!\n"));
2203
+ console.log(import_chalk17.default.bold("Title: ") + title);
2204
+ console.log(import_chalk17.default.bold("Type: ") + type);
2205
+ console.log(import_chalk17.default.bold("\nClick the link below to submit this issue:"));
2206
+ console.log(import_chalk17.default.cyan(fullUrl));
2207
+ console.log(import_chalk17.default.bold("\n\u{1F916} [FOR AI AGENTS]:"));
2208
+ console.log(import_chalk17.default.dim(" You have successfully prepared a report."));
2112
2209
  console.log(
2113
- import_chalk16.default.dim(
2210
+ import_chalk17.default.dim(
2114
2211
  " Please present the URL above to the user so they can finalize the submission."
2115
2212
  )
2116
2213
  );
@@ -2119,14 +2216,14 @@ Type: ${type}
2119
2216
  const bugUrl = `${repoUrl}/issues/new?template=bug_report.md`;
2120
2217
  const featureUrl = `${repoUrl}/issues/new?template=feature_request.md`;
2121
2218
  const metricUrl = `${repoUrl}/issues/new?template=new_metric_idea.md`;
2122
- console.log(import_chalk16.default.blue("\u{1F4AC} Feedback & Bug Reports\n"));
2123
- console.log(` Report a Bug: ${import_chalk16.default.cyan(bugUrl)}`);
2124
- console.log(` Request a Feature: ${import_chalk16.default.cyan(featureUrl)}`);
2125
- console.log(` Suggest a Metric: ${import_chalk16.default.cyan(metricUrl)}`);
2126
- console.log(import_chalk16.default.bold("\n\u{1F916} [FOR AI AGENTS]:"));
2127
- console.log(import_chalk16.default.dim(" To prepare a specific report, run:"));
2219
+ console.log(import_chalk17.default.blue("\u{1F4AC} Feedback & Bug Reports\n"));
2220
+ console.log(` Report a Bug: ${import_chalk17.default.cyan(bugUrl)}`);
2221
+ console.log(` Request a Feature: ${import_chalk17.default.cyan(featureUrl)}`);
2222
+ console.log(` Suggest a Metric: ${import_chalk17.default.cyan(metricUrl)}`);
2223
+ console.log(import_chalk17.default.bold("\n\u{1F916} [FOR AI AGENTS]:"));
2224
+ console.log(import_chalk17.default.dim(" To prepare a specific report, run:"));
2128
2225
  console.log(
2129
- import_chalk16.default.cyan(
2226
+ import_chalk17.default.cyan(
2130
2227
  ' aiready bug "your description here" --type bug|feature|metric'
2131
2228
  )
2132
2229
  );
@@ -2139,14 +2236,105 @@ EXAMPLES:
2139
2236
  $ aiready bug "Fix typo in scan output" --submit # Submit directly via gh CLI
2140
2237
  `;
2141
2238
 
2239
+ // src/commands/remediate.ts
2240
+ var import_chalk18 = __toESM(require("chalk"));
2241
+ var import_path7 = require("path");
2242
+ var import_fs8 = require("fs");
2243
+ var import_core18 = require("@aiready/core");
2244
+ async function remediateAction(directory, options) {
2245
+ const resolvedDir = (0, import_path7.resolve)(process.cwd(), directory || ".");
2246
+ const serverUrl = options.server || "https://platform.getaiready.dev";
2247
+ (0, import_core18.printTerminalHeader)("AIREADY REMEDIATION SWARM");
2248
+ console.log(import_chalk18.default.cyan("\u{1F916} Initializing local remediation agent..."));
2249
+ let reportPath = options.report;
2250
+ if (!reportPath) {
2251
+ const aireadyDir = (0, import_path7.resolve)(resolvedDir, ".aiready");
2252
+ if ((0, import_fs8.existsSync)(aireadyDir)) {
2253
+ const files = (0, import_fs8.readdirSync)(aireadyDir).filter((f) => f.startsWith("aiready-report-") && f.endsWith(".json")).sort().reverse();
2254
+ if (files.length > 0) {
2255
+ reportPath = (0, import_path7.resolve)(aireadyDir, files[0]);
2256
+ console.log(import_chalk18.default.dim(`\u{1F4C2} Using latest report: ${files[0]}`));
2257
+ }
2258
+ }
2259
+ }
2260
+ if (!reportPath || !(0, import_fs8.existsSync)(reportPath)) {
2261
+ console.log(import_chalk18.default.yellow("\n\u26A0\uFE0F No AIReady report found."));
2262
+ console.log(
2263
+ import_chalk18.default.dim(
2264
+ " Remediation requires a recent scan report to identify issues."
2265
+ )
2266
+ );
2267
+ console.log(import_chalk18.default.white(` Run ${import_chalk18.default.bold("aiready scan")} first.
2268
+ `));
2269
+ return;
2270
+ }
2271
+ console.log(import_chalk18.default.green("\n\u2705 Analysis data loaded."));
2272
+ console.log(import_chalk18.default.bold("\n\u{1F680} Remediation Strategy:"));
2273
+ if (options.tool === "patterns" || !options.tool) {
2274
+ console.log(
2275
+ import_chalk18.default.white(
2276
+ ` \u2022 ${import_chalk18.default.bold("Pattern Consolidation")}: Suggested refactors for 95%+ similar code blocks.`
2277
+ )
2278
+ );
2279
+ }
2280
+ if (options.tool === "consistency" || !options.tool) {
2281
+ console.log(
2282
+ import_chalk18.default.white(
2283
+ ` \u2022 ${import_chalk18.default.bold("Naming Alignment")}: Automated TSDoc generation and constant extraction.`
2284
+ )
2285
+ );
2286
+ }
2287
+ if (options.tool === "context" || !options.tool) {
2288
+ console.log(
2289
+ import_chalk18.default.white(
2290
+ ` \u2022 ${import_chalk18.default.bold("Context Optimization")}: Barrel file cleanup and import flattening.`
2291
+ )
2292
+ );
2293
+ }
2294
+ console.log(
2295
+ import_chalk18.default.dim(
2296
+ "\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
2297
+ )
2298
+ );
2299
+ console.log(import_chalk18.default.bold("\u2728 Use the Platform Swarm for Automated Fixes"));
2300
+ console.log(
2301
+ import_chalk18.default.cyan(` The high-performance Remediation Swarm is available at:`)
2302
+ );
2303
+ console.log(import_chalk18.default.white(` ${import_chalk18.default.bold(`${serverUrl}/remediate`)}`));
2304
+ console.log(
2305
+ import_chalk18.default.dim(
2306
+ "\n The swarm uses specialized agents to safely refactor your code,"
2307
+ )
2308
+ );
2309
+ console.log(
2310
+ import_chalk18.default.dim(" ensuring every change improves your AI-readiness score.")
2311
+ );
2312
+ console.log(
2313
+ import_chalk18.default.dim(
2314
+ "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"
2315
+ )
2316
+ );
2317
+ console.log(
2318
+ import_chalk18.default.dim(
2319
+ '\n\u{1F4A1} Next Version: Local "aiready fix" command for minor documentation issues.'
2320
+ )
2321
+ );
2322
+ }
2323
+ var REMEDIATE_HELP_TEXT = `
2324
+ EXAMPLES:
2325
+ $ aiready remediate # See remediation options for latest report
2326
+ $ aiready remediate --tool patterns # Focus on pattern consolidation
2327
+ $ aiready remediate --report ./custom-report.json
2328
+ `;
2329
+
2142
2330
  // src/cli.ts
2143
2331
  var import_meta = {};
2144
2332
  var getDirname = () => {
2145
2333
  if (typeof __dirname !== "undefined") return __dirname;
2146
- return (0, import_path7.dirname)((0, import_url.fileURLToPath)(import_meta.url));
2334
+ return (0, import_path8.dirname)((0, import_url.fileURLToPath)(import_meta.url));
2147
2335
  };
2148
2336
  var packageJson = JSON.parse(
2149
- (0, import_fs8.readFileSync)((0, import_path7.join)(getDirname(), "../package.json"), "utf8")
2337
+ (0, import_fs9.readFileSync)((0, import_path8.join)(getDirname(), "../package.json"), "utf8")
2150
2338
  );
2151
2339
  var program = new import_commander.Command();
2152
2340
  program.name("aiready").description("AIReady - Assess and improve AI-readiness of codebases").version(packageJson.version).addHelpText(
@@ -2290,9 +2478,19 @@ program.command("change-amplification").description("Analyze graph metrics for c
2290
2478
  program.command("testability").description("Analyze test coverage and AI readiness").argument("[directory]", "Directory to analyze", ".").option("--min-coverage <ratio>", "Minimum acceptable coverage ratio", "0.3").option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").action(async (directory, options) => {
2291
2479
  await testabilityAction(directory, options);
2292
2480
  });
2481
+ program.command("contract").description("Analyze structural contract enforcement and defensive coding").argument("[directory]", "Directory to analyze", ".").option(
2482
+ "--min-chain-depth <depth>",
2483
+ "Minimum optional chain depth to flag",
2484
+ "3"
2485
+ ).option("--include <patterns>", "File patterns to include (comma-separated)").option("--exclude <patterns>", "File patterns to exclude (comma-separated)").option("-o, --output <format>", "Output format: console, json", "console").option("--output-file <path>", "Output file path (for json)").action(async (directory, options) => {
2486
+ await contractEnforcementAction(directory, options);
2487
+ });
2293
2488
  program.command("upload").description("Upload an AIReady report JSON to the platform").argument("<file>", "Report JSON file to upload").option("--api-key <key>", "Platform API key").option("--repo-id <id>", "Platform repository ID (optional)").option("--server <url>", "Custom platform URL").addHelpText("after", UPLOAD_HELP_TEXT).action(async (file, options) => {
2294
2489
  await uploadAction(file, options);
2295
2490
  });
2491
+ program.command("remediate").description("Suggest AI-ready refactors based on a scan report").argument("[directory]", "Directory to remediate", ".").option("-r, --report <path>", "AIReady report JSON file").option("-t, --tool <name>", "Filter by tool: patterns, context, consistency").option("--server <url>", "Custom platform URL").addHelpText("after", REMEDIATE_HELP_TEXT).action(async (directory, options) => {
2492
+ await remediateAction(directory, options);
2493
+ });
2296
2494
  program.command("bug").description("Report a bug or provide feedback (Agent-friendly)").argument("[message]", "Short description of the issue").option("-t, --type <type>", "Issue type: bug, feature, metric", "bug").option("--submit", "Submit the issue directly using the GitHub CLI (gh)").addHelpText("after", BUG_HELP_TEXT).action(async (message, options) => {
2297
2495
  await bugAction(message, options);
2298
2496
  });