flamerjs 0.1.6 → 1.0.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 (3) hide show
  1. package/README.md +43 -18
  2. package/dist/cli.js +80 -2
  3. package/package.json +3 -1
package/README.md CHANGED
@@ -52,12 +52,18 @@ can be used locally, in pull requests, or in CI.
52
52
  C#, Zig, SQL, notebooks, and additional language profiles.
53
53
  - **Stable JSON output:** suitable for CI annotations and other automation.
54
54
  - **Single-pass scanning:** files are walked once and content is read once.
55
+ - **Optional native workers:** Rust and C++ workers for isolated file metrics,
56
+ with TypeScript remaining the default engine.
55
57
 
56
58
  ## Requirements
57
59
 
58
60
  - Node.js 18 or newer
59
61
  - npm
60
62
 
63
+ The default TypeScript engine needs only Node.js and npm. Native mode additionally
64
+ requires Rust/Cargo for the Rust worker or a C++17 compiler and CMake for the
65
+ C++ worker.
66
+
61
67
  ## Quick start
62
68
 
63
69
  Run the published CLI without installing it permanently:
@@ -101,23 +107,24 @@ flamerjs /path/to/repository --format summary
101
107
  flamerjs [path] [options]
102
108
  ```
103
109
 
104
- | Option | Description |
105
- | --------------------------- | ----------------------------------------------------------------------------- |
106
- | `--package, --scope <name>` | Analyze only a named sub-project |
107
- | `--path <dir>` | Set the repository root; defaults to the current directory |
108
- | `--format <json\|summary>` | Select JSON or human-readable output; summary is the default |
109
- | `--out <file>` | Also write the JSON report to a file |
110
- | `--fail-on <SEVERITY>` | Exit with status 1 at or above `CRITICAL`, `HIGH`, `MEDIUM`, `LOW`, or `INFO` |
111
- | `--max-files <n>` | Limit the number of files scanned |
112
- | `--commit-limit <n>` | Limit commits inspected by Git checks |
113
- | `--no-git` | Skip Git analysis |
114
- | `--no-lockfile-warning` | Suppress the missing-lockfile suggestion |
115
- | `--ignore-dir <name>` | Ignore an additional directory name; repeatable |
116
- | `--quiet` | Suppress the human summary |
117
- | `--color` | Force ANSI colors |
118
- | `--no-color` | Disable ANSI colors |
119
- | `--list-languages` | List recognized language profiles |
120
- | `--help` | Show command help |
110
+ | Option | Description |
111
+ | ------------------------------------- | ----------------------------------------------------------------------------- |
112
+ | `--package, --scope <name>` | Analyze only a named sub-project |
113
+ | `--path <dir>` | Set the repository root; defaults to the current directory |
114
+ | `--format <json\|summary>` | Select JSON or human-readable output; summary is the default |
115
+ | `--out <file>` | Also write the JSON report to a file |
116
+ | `--fail-on <SEVERITY>` | Exit with status 1 at or above `CRITICAL`, `HIGH`, `MEDIUM`, `LOW`, or `INFO` |
117
+ | `--max-files <n>` | Limit the number of files scanned |
118
+ | `--commit-limit <n>` | Limit commits inspected by Git checks |
119
+ | `--no-git` | Skip Git analysis |
120
+ | `--no-lockfile-warning` | Suppress the missing-lockfile suggestion |
121
+ | `--ignore-dir <name>` | Ignore an additional directory name; repeatable |
122
+ | `--quiet` | Suppress the human summary |
123
+ | `--color` | Force ANSI colors |
124
+ | `--no-color` | Disable ANSI colors |
125
+ | `--engine <typescript\|native\|auto>` | Select the scan engine; TypeScript is the default |
126
+ | `--list-languages` | List recognized language profiles |
127
+ | `--help` | Show command help |
121
128
 
122
129
  Exit status `0` means the scan completed; findings may still exist. Status `1`
123
130
  means `--fail-on` was reached, and status `2` indicates invalid usage or a
@@ -170,12 +177,30 @@ The project uses Node.js and npm as its supported development toolchain.
170
177
  `package-lock.json` is the canonical dependency lockfile.
171
178
  The current test suite contains **175 tests**.
172
179
 
180
+ ### Optional native engine
181
+
182
+ Flamer includes an experimental Rust worker for native file metrics. It is
183
+ disabled by default and does not change findings:
184
+
185
+ ```bash
186
+ npm run native:build
187
+ node dist/cli.js . --engine native
188
+ ```
189
+
190
+ Use `--engine auto` to fall back to TypeScript when the worker is unavailable.
191
+ The native protocol and worker details are documented in
192
+ [`native/core/README.md`](native/core/README.md).
193
+
194
+ See [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) for the runtime layers,
195
+ worker protocol, engine selection, and native development workflow.
196
+
173
197
  ## How it works
174
198
 
175
199
  1. Detect the repository layout, languages, and ecosystems.
176
200
  2. Walk the tree once and collect file metadata and content-derived signals.
177
201
  3. Run isolated analyzers against the collected records.
178
- 4. Sort findings and emit JSON or a concise summary.
202
+ 4. Optionally collect native file metrics through the versioned worker protocol.
203
+ 5. Sort findings and emit JSON or a concise summary.
179
204
 
180
205
  Analyzers are intentionally factual and conservative. A finding should identify
181
206
  something actionable rather than merely express a preference.
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli.ts
4
- import { writeFileSync, existsSync as existsSync3 } from "fs";
4
+ import { writeFileSync, existsSync as existsSync4 } from "fs";
5
5
  import { resolve, basename } from "path";
6
6
 
7
7
  // src/util/fs.ts
@@ -2901,6 +2901,42 @@ var ANALYZERS = [
2901
2901
  { id: "systems", label: "Rust / Go / C / C++ / C# / Zig", fn: analyze6 }
2902
2902
  ];
2903
2903
 
2904
+ // src/native.ts
2905
+ import { spawnSync } from "child_process";
2906
+ import { existsSync as existsSync3 } from "fs";
2907
+ import { join as join6 } from "path";
2908
+ function nativeWorkerPath(root) {
2909
+ const configured = process.env.FLAMER_CORE;
2910
+ if (configured) return configured;
2911
+ return join6(root, "native", "core", "rust", "target", "release", "flamer-core");
2912
+ }
2913
+ function runNativeMetrics(root, files) {
2914
+ const worker = nativeWorkerPath(root);
2915
+ if (!existsSync3(worker)) {
2916
+ throw new Error(`native worker not found at ${worker}; run npm run native:build`);
2917
+ }
2918
+ const request = JSON.stringify({ protocol: 1, operation: "file_metrics", root, files });
2919
+ const result = spawnSync(worker, { input: `${request}
2920
+ `, encoding: "utf8", timeout: 3e4 });
2921
+ if (result.error) throw new Error(`native worker failed: ${result.error.message}`);
2922
+ if (result.status !== 0) {
2923
+ throw new Error(`native worker exited with status ${result.status}: ${result.stderr.trim()}`);
2924
+ }
2925
+ let response;
2926
+ try {
2927
+ response = JSON.parse(result.stdout);
2928
+ } catch {
2929
+ throw new Error("native worker returned invalid JSON");
2930
+ }
2931
+ if (response.protocol !== 1 || response.operation !== "file_metrics") {
2932
+ throw new Error("native worker returned an incompatible response");
2933
+ }
2934
+ if (!response.ok) {
2935
+ throw new Error(response.errors.map((error) => `${error.path}: ${error.message}`).join("; "));
2936
+ }
2937
+ return response;
2938
+ }
2939
+
2904
2940
  // src/cli.ts
2905
2941
  var SPEC_VERSION = 1;
2906
2942
  function parseArgs(argv) {
@@ -2918,6 +2954,7 @@ function parseArgs(argv) {
2918
2954
  listLanguages: false,
2919
2955
  help: false,
2920
2956
  color: null,
2957
+ engine: "typescript",
2921
2958
  ignoreDirs: []
2922
2959
  };
2923
2960
  for (let i = 0; i < argv.length; i++) {
@@ -2963,6 +3000,14 @@ function parseArgs(argv) {
2963
3000
  case "--no-color":
2964
3001
  opts.color = false;
2965
3002
  break;
3003
+ case "--engine":
3004
+ opts.engine = argv[++i] || "typescript";
3005
+ if (!["typescript", "native", "auto"].includes(opts.engine)) {
3006
+ process.stderr.write(`invalid engine: ${opts.engine}
3007
+ `);
3008
+ process.exit(2);
3009
+ }
3010
+ break;
2966
3011
  case "--list-languages":
2967
3012
  opts.listLanguages = true;
2968
3013
  break;
@@ -3004,6 +3049,8 @@ Options:
3004
3049
  --quiet suppress the human summary
3005
3050
  --color force ANSI colors
3006
3051
  --no-color disable ANSI colors
3052
+ --engine <typescript|native|auto>
3053
+ choose the scan engine (default: typescript)
3007
3054
  --list-languages print the supported language table
3008
3055
  -h, --help show this help
3009
3056
  `);
@@ -3023,7 +3070,7 @@ ${allExtensions().length} file extensions recognized.
3023
3070
  function run2(opts) {
3024
3071
  const started = Date.now();
3025
3072
  const root = opts.root;
3026
- if (!existsSync3(root) || !isDir(root)) {
3073
+ if (!existsSync4(root) || !isDir(root)) {
3027
3074
  const err = {
3028
3075
  specVersion: SPEC_VERSION,
3029
3076
  tool: "flamer",
@@ -3161,6 +3208,37 @@ function run2(opts) {
3161
3208
  analyzers: analyzerResults
3162
3209
  }
3163
3210
  };
3211
+ if (opts.engine !== "typescript") {
3212
+ try {
3213
+ const native = runNativeMetrics(
3214
+ root,
3215
+ scopedFiles.map((file) => file.rel)
3216
+ );
3217
+ report.metadata.native = {
3218
+ engine: "rust",
3219
+ files: native.metrics.files,
3220
+ bytes: native.metrics.bytes,
3221
+ lines: native.metrics.lines,
3222
+ durationMs: native.duration_ms
3223
+ };
3224
+ } catch (error) {
3225
+ const message = error?.message || String(error);
3226
+ if (opts.engine === "native") {
3227
+ findings.push(
3228
+ finding({
3229
+ category: "error",
3230
+ severity: "CRITICAL",
3231
+ title: "Native engine failed",
3232
+ detail: message
3233
+ })
3234
+ );
3235
+ report.findings = sortFindings(findings);
3236
+ report.metadata.native = { engine: "rust", error: message };
3237
+ return { report, exitCode: 2 };
3238
+ }
3239
+ report.metadata.native = { engine: "typescript", fallback: message };
3240
+ }
3241
+ }
3164
3242
  let exitCode = 0;
3165
3243
  if (opts.failOn && report.metadata.worst && rank(report.metadata.worst) <= rank(opts.failOn)) {
3166
3244
  exitCode = 1;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flamerjs",
3
- "version": "0.1.6",
3
+ "version": "1.0.0",
4
4
  "description": "Language-agnostic code health auditor that walks a repository once and reports what is wrong with it",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -25,6 +25,8 @@
25
25
  "scripts": {
26
26
  "build": "tsup",
27
27
  "dev": "tsup --watch",
28
+ "native:build": "cargo build --release --manifest-path native/core/rust/Cargo.toml",
29
+ "native:test": "cargo test --manifest-path native/core/rust/Cargo.toml",
28
30
  "prepublishOnly": "npm run lint && npm run build && npm test",
29
31
  "lint": "eslint .",
30
32
  "lint:fix": "eslint . --fix",