flaglint 0.7.0 → 0.8.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/CHANGELOG.md CHANGED
@@ -5,15 +5,41 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.8.0] - 2026-06-13
9
+
10
+ ### Changed
11
+
12
+ - **`--cost-estimate` renamed to `--effort-estimate`** (breaking) — the flag outputs
13
+ hours, not dollars; "effort" is more accurate. Update any scripts or CI pipelines
14
+ that use `--cost-estimate`.
15
+
16
+ ### Fixed
17
+
18
+ - Homepage email-capture / Loops signup section removed.
19
+ - Version displayed on homepage now read from `package.json` at build time — can no
20
+ longer drift from the published npm version.
21
+ - `robots.txt` sitemap URL updated to `/sitemap-index.xml` (was `/sitemap.xml`, which 404'd).
22
+ - Audit sample numbers corrected to real fixture output: 13 unique flags across 19 call
23
+ sites, readiness 53/100, estimate 20.8h–40h.
24
+
25
+ ### Infrastructure
26
+
27
+ - Vitest `testTimeout`/`hookTimeout` raised to 30 s to fix flaky Windows/Node 22 CI timeouts.
28
+ - `npm publish --provenance` re-enabled in release workflow.
29
+ - `scripts/metrics/collect.mjs` added: fetches npm downloads + GitHub stars/forks/issues
30
+ and appends a JSON line to `.agent-output/metrics/history.jsonl`.
31
+
32
+ ---
33
+
8
34
  ## [0.7.0] - 2026-06-07
9
35
 
10
36
  ### Added
11
37
 
12
- - `flaglint audit --cost-estimate` — adds a directional migration-effort estimate to
38
+ - `flaglint audit --effort-estimate` — adds a directional migration-effort estimate to
13
39
  audit output. Computes low/high hour ranges from automatable and manual-review call
14
40
  counts using configurable planning heuristics.
15
41
  - `flaglint audit --hourly-rate <rate>` — adds engineering cost projection
16
- (`costLow`/`costHigh`) to the estimate. Requires `--cost-estimate`.
42
+ (`costLow`/`costHigh`) to the estimate. Requires `--effort-estimate`.
17
43
  - Migration readiness score displayed in `flaglint audit` terminal output: 0–100 ratio
18
44
  of safely automatable calls to total detected LaunchDarkly calls, with grade
19
45
  (`ready` | `moderate` | `complex` | `not-applicable`) and progress bar.
package/README.md CHANGED
@@ -30,27 +30,27 @@ npx flaglint audit ./src
30
30
  ```
31
31
 
32
32
  ```
33
- ✓ Audit complete: 13 flags — 3 high risk, 10 medium risk
33
+ ✓ Audit complete: 13 unique flags across 19 call sites — 3 high risk, 10 medium risk
34
34
 
35
- Migration readiness: 50/100 · moderate
36
- [█████████████░░░░░░░░░░░░] 50%
37
- 10 safely automatable · 10 require manual review
35
+ Migration readiness: 53/100 · moderate
36
+ [█████████████░░░░░░░░░░░░] 53%
37
+ 10 of 19 call sites safely automatable · 9 require manual review
38
38
  ```
39
39
 
40
- Add `--cost-estimate` to include a directional planning estimate:
40
+ Add `--effort-estimate` to include a directional planning estimate:
41
41
 
42
42
  ```bash
43
- npx flaglint audit ./src --cost-estimate
43
+ npx flaglint audit ./src --effort-estimate
44
44
  ```
45
45
 
46
46
  ```
47
- ✓ Audit complete: 13 flags — 3 high risk, 10 medium risk
47
+ ✓ Audit complete: 13 unique flags across 19 call sites — 3 high risk, 10 medium risk
48
48
 
49
- Migration readiness: 50/100 · moderate
50
- [█████████████░░░░░░░░░░░░] 50%
51
- 10 safely automatable · 10 require manual review
49
+ Migration readiness: 53/100 · moderate
50
+ [█████████████░░░░░░░░░░░░] 53%
51
+ 10 of 19 call sites safely automatable · 9 require manual review
52
52
 
53
- Estimated migration effort: 22.8h – 43.9h
53
+ Estimated migration effort: 20.8h – 40h
54
54
  Estimates are directional. See the report for assumptions.
55
55
  ```
56
56
 
@@ -58,6 +58,8 @@ For the full report see `--format html`. [Documentation](https://flaglint.dev/do
58
58
 
59
59
  No API key. No source upload. LaunchDarkly stays your provider — OpenFeature becomes the evaluation API your application calls.
60
60
 
61
+ Migrating an existing Node.js service? Read the [complete LaunchDarkly-to-OpenFeature migration guide](https://flaglint.dev/guides/launchdarkly-to-openfeature-nodejs/).
62
+
61
63
  ---
62
64
 
63
65
  ## The problem FlagLint solves
@@ -789,7 +789,7 @@ function formatHTML(result, options) {
789
789
  <div class="card"><div class="card-num orange">${manualCount}</div><div class="card-label">Manual Review (${manualPct}%)</div></div>
790
790
  <div class="card"><div class="card-num blue">${detailBulkCount}</div><div class="card-label">Detail/Bulk Calls</div></div>` : "";
791
791
  const title = options.title ? esc(options.title) : "FlagLint Scan Report";
792
- const version = true ? "0.7.0" : "0.1.0";
792
+ const version = true ? "0.8.0" : "0.1.0";
793
793
  return `<!DOCTYPE html>
794
794
  <html lang="en">
795
795
  <head>
@@ -1322,7 +1322,7 @@ function formatMigrationReport(analysis) {
1322
1322
  unsupportedUnknownCount
1323
1323
  } = analysis;
1324
1324
  const date = (/* @__PURE__ */ new Date()).toLocaleDateString();
1325
- const version = true ? "0.7.0" : "0.1.0";
1325
+ const version = true ? "0.8.0" : "0.1.0";
1326
1326
  const lines = [];
1327
1327
  lines.push("# OpenFeature Migration Inventory");
1328
1328
  lines.push(`Generated by FlagLint v${version} on ${date}`);
@@ -2329,7 +2329,7 @@ function formatAuditMarkdown(report, options) {
2329
2329
  }
2330
2330
  function formatAuditHtml(report, options) {
2331
2331
  const { summary, flags, readiness } = report;
2332
- const version = true ? "0.7.0" : "0.1.0";
2332
+ const version = true ? "0.8.0" : "0.1.0";
2333
2333
  const date = new Date(summary.scannedAt).toLocaleString();
2334
2334
  const riskBadge = (level) => {
2335
2335
  if (level === "high")
@@ -2593,15 +2593,15 @@ function computeEstimate(readiness, overrides, hourlyRate) {
2593
2593
  // src/commands/audit.ts
2594
2594
  var VALID_AUDIT_FORMATS = ["json", "markdown", "html"];
2595
2595
  function registerAuditCommand(program2) {
2596
- program2.command("audit").description("Generate a flag debt audit report").argument("[dir]", "directory to audit", process.cwd()).option("-f, --format <format>", "output format: json | markdown | html", "markdown").option("-o, --output <file>", "write report to file").option("-c, --config <path>", "path to .flaglintrc config file").option("--exclude-tests", "exclude test files (*.test.*, *.spec.*, __tests__/, tests/)").option("--cost-estimate", "include a migration effort estimate in the report. The default assumptions are configurable planning heuristics, not observed industry benchmarks.").option("--hourly-rate <rate>", "hourly rate for cost projection (requires --cost-estimate)").addHelpText(
2596
+ program2.command("audit").description("Generate a flag debt audit report").argument("[dir]", "directory to audit", process.cwd()).option("-f, --format <format>", "output format: json | markdown | html", "markdown").option("-o, --output <file>", "write report to file").option("-c, --config <path>", "path to .flaglintrc config file").option("--exclude-tests", "exclude test files (*.test.*, *.spec.*, __tests__/, tests/)").option("--effort-estimate", "include a migration effort estimate in the report. The default assumptions are configurable planning heuristics, not observed industry benchmarks.").option("--hourly-rate <rate>", "hourly rate for cost projection (requires --effort-estimate)").addHelpText(
2597
2597
  "after",
2598
2598
  `
2599
2599
  Examples:
2600
2600
  $ flaglint audit generate flag debt audit report
2601
2601
  $ flaglint audit --format html shareable HTML report
2602
2602
  $ flaglint audit --output audit.md save to file
2603
- $ flaglint audit --cost-estimate include migration effort estimate
2604
- $ flaglint audit --cost-estimate --hourly-rate 125 include cost projection`
2603
+ $ flaglint audit --effort-estimate include migration effort estimate
2604
+ $ flaglint audit --effort-estimate --hourly-rate 125 include cost projection`
2605
2605
  ).action(
2606
2606
  async (dir, options) => {
2607
2607
  if (!VALID_AUDIT_FORMATS.includes(options.format)) {
@@ -2615,9 +2615,9 @@ Examples:
2615
2615
  }
2616
2616
  let hourlyRate;
2617
2617
  if (options.hourlyRate !== void 0) {
2618
- if (!options.costEstimate) {
2618
+ if (!options.effortEstimate) {
2619
2619
  process.stderr.write(
2620
- chalk4.yellow("warn: --hourly-rate has no effect without --cost-estimate\n")
2620
+ chalk4.yellow("warn: --hourly-rate has no effect without --effort-estimate\n")
2621
2621
  );
2622
2622
  } else {
2623
2623
  const parsed = Number(options.hourlyRate);
@@ -2710,11 +2710,11 @@ Examples:
2710
2710
  `
2711
2711
  )
2712
2712
  );
2713
- if (format === "json" && options.costEstimate) {
2713
+ if (format === "json" && options.effortEstimate) {
2714
2714
  const emptyReport = buildAuditReport(scanResult, []);
2715
2715
  process.stdout.write(formatAuditJson(emptyReport, { estimate: null }) + "\n");
2716
2716
  process.stderr.write(chalk4.dim("Migration estimate: N/A\n"));
2717
- } else if (options.costEstimate) {
2717
+ } else if (options.effortEstimate) {
2718
2718
  process.stderr.write(chalk4.dim("Migration estimate: N/A\n"));
2719
2719
  }
2720
2720
  process.exit(0);
@@ -2723,7 +2723,7 @@ Examples:
2723
2723
  scanResult,
2724
2724
  scanResult.migrationInventory ?? []
2725
2725
  );
2726
- const renderOptions = options.costEstimate ? { estimate: computeEstimate(auditReport.readiness, void 0, hourlyRate) } : void 0;
2726
+ const renderOptions = options.effortEstimate ? { estimate: computeEstimate(auditReport.readiness, void 0, hourlyRate) } : void 0;
2727
2727
  let output;
2728
2728
  if (format === "json") {
2729
2729
  output = formatAuditJson(auditReport, renderOptions);
@@ -2762,7 +2762,7 @@ Examples:
2762
2762
  process.stderr.write("\n");
2763
2763
  if (readiness.grade === "not-applicable") {
2764
2764
  process.stderr.write(chalk4.dim("Migration readiness: N/A \u2014 no direct LaunchDarkly calls detected.\n"));
2765
- if (options.costEstimate) {
2765
+ if (options.effortEstimate) {
2766
2766
  process.stderr.write(chalk4.dim("Migration estimate: N/A\n"));
2767
2767
  }
2768
2768
  } else {
@@ -2777,7 +2777,7 @@ Examples:
2777
2777
  `
2778
2778
  )
2779
2779
  );
2780
- if (options.costEstimate && renderOptions?.estimate) {
2780
+ if (options.effortEstimate && renderOptions?.estimate) {
2781
2781
  const est = renderOptions.estimate;
2782
2782
  process.stderr.write("\n");
2783
2783
  process.stderr.write(
@@ -2800,7 +2800,7 @@ Examples:
2800
2800
  // src/cli.ts
2801
2801
  function createCLI() {
2802
2802
  const program2 = new Command();
2803
- program2.name("flaglint").description("Scan LaunchDarkly Node.js SDK usage, generate safe OpenFeature migration diffs, and enforce the vendor boundary in CI.").version("0.7.0", "-v, --version", "output the current version").addHelpText(
2803
+ program2.name("flaglint").description("Scan LaunchDarkly Node.js SDK usage, generate safe OpenFeature migration diffs, and enforce the vendor boundary in CI.").version("0.8.0", "-v, --version", "output the current version").addHelpText(
2804
2804
  "after",
2805
2805
  `
2806
2806
  Examples:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flaglint",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "Scan LaunchDarkly Node.js SDK usage, generate safe OpenFeature migration diffs, and enforce the vendor boundary in CI.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -51,6 +51,7 @@
51
51
  "preview:docs": "ASTRO_TELEMETRY_DISABLED=1 astro preview --port 4321",
52
52
  "test:package": "tsx scripts/test-package.ts",
53
53
  "test:smoke": "playwright test",
54
+ "metrics": "node scripts/metrics/collect.mjs",
54
55
  "new-branch": "tsx scripts/new-branch.ts",
55
56
  "release:patch": "tsx scripts/release.ts patch",
56
57
  "release:minor": "tsx scripts/release.ts minor",