Problem: a TU skipped because a prior run quarantined it was not analysed, but coverage did not say so. The serial path dropped it from the attempted set, so a scan whose only TU was quarantined was complete and exited 0; the fan-out path saw no file_finished record and called it frontend-failed. Fix: the shard runner counts every requested TU and records skipped ones with gap reason `quarantined`; a worker emits a file_finished record with that reason so the parent classifies it the same way. USAGE lists the reason. Test: test_subprocess_fanout "[quarantine]" covers serial (was 2 attempted, no gap) and fan-out (was frontend-failed). CLI probe: serial and fan-out both exit 2 with a `quarantined` gap.
463 lines
21 KiB
Markdown
463 lines
21 KiB
Markdown
# Usage
|
|
|
|
## CLI
|
|
|
|
```
|
|
fold scan [options] [--compile-db <path> | <files...>]
|
|
fold scan --mode hybrid --compile-db <path> --binary <path> [options]
|
|
fold scan --input-type binary --binary <path> [options]
|
|
fold confirm [options] <compile_commands.json>
|
|
fold quality [--compile-db <path>] [--manifest <project.json>] [options]
|
|
```
|
|
|
|
`--compile-db` is optional. If omitted, pass source files as positional
|
|
arguments and fold infers compile flags:
|
|
|
|
```sh
|
|
fold scan src/*.cpp --detectors null-deref
|
|
|
|
# Or with explicit C++ standard:
|
|
fold scan --std c++20 file.cpp --detectors dead
|
|
```
|
|
|
|
If a `compile_flags.txt` exists in the source tree, fold reads it
|
|
automatically (clang-tidy convention).
|
|
|
|
### quality command
|
|
|
|
`fold quality` is the local quality gate. It checks formatting and diff hygiene,
|
|
runs the focused evaluator/source-structure tests, evaluates a manifest policy,
|
|
and, when `--compile-db` is supplied, scans changed C/C++ files. It writes an
|
|
aggregated `summary.json` under `build/quality` by default.
|
|
|
|
```sh
|
|
fold quality --compile-db build/release/compile_commands.json
|
|
fold quality --skip-policy --allow-findings
|
|
```
|
|
|
|
Use `--out-dir`, `--manifest`, and the individual `--skip-*` switches to adapt
|
|
the gate for a focused local iteration. Exit status `1` means a completed
|
|
quality gate failed; `2` means setup or execution failed.
|
|
|
|
### scan options
|
|
|
|
| Flag | Description |
|
|
|------|-------------|
|
|
| `--detectors NAME ...` | Which detectors to run (default: all) |
|
|
| `--format sarif\|findings-json\|markdown\|json` | Output format (default: SARIF). `findings-json` emits the versioned native envelope; `json` is a deprecated SARIF alias. |
|
|
| `--output PATH` | Write output to file |
|
|
| `--processes N` | Worker processes (default: auto). Ordinary source scans use an isolated worker even at `1`; profile/incremental scans currently use the in-process serial path. |
|
|
| `--budget-seconds N` | Per-TU time budget |
|
|
| `--per-query-ms N` | Per-Z3-query timeout |
|
|
| `--loop-unroll N` | Loop unrolling depth (default: 3) |
|
|
| `--exclude-glob PATTERN` | Skip files matching glob. Relative patterns also match absolute compile-database paths at component boundaries. |
|
|
| `--trace` | Log Z3 query traces |
|
|
| `--scope security\|quality\|redundancy\|binary\|all` | High-level scan scope; expands to the matching detector category. Composes with `--detectors` |
|
|
| `--profile` | JSON performance profile (metrics). A value is a deprecated alias for `--preset` |
|
|
| `--profile-output PATH` | Atomically write profile JSON and imply `--profile`; must differ from `--output`. |
|
|
| `--preset NAME` | Apply a modeling preset (currently `freestanding`, the [embedded-firmware bundle](#freestanding-preset)) |
|
|
| `--complexity-threshold N` | Cyclomatic-complexity threshold for the `complexity` detector (default 15) |
|
|
| `--profile-solver` | Per-detector Z3 statistics |
|
|
| `--profile-reach` | Encoder coverage report |
|
|
| `--incremental` | Skip functions unchanged since last scan |
|
|
| `--build-summaries` | Build leaf-function symbolic summaries |
|
|
| `--config-profile PATH` | Load a strict versioned runtime-configuration profile and persist privacy-safe guarded callsites (source/hybrid only) |
|
|
| `--portfolio` | Use parallel Z3 tactic portfolio |
|
|
| `--nullable-allocations` | Opt in to heuristic null-deref findings for unchecked `malloc`/`calloc`/`new` results |
|
|
| `--suppressions PATH` | Suppress findings by detector, `file:line`, or finding-id prefix |
|
|
| `--baseline PATH` | Apply previous-scan baseline JSON (`accepted`/`dismissed` findings) |
|
|
| `--mode auto\|source\|binary\|hybrid\|rust\|swift` | Select scan router mode (default: `auto`) |
|
|
| `--input-type source\|binary` | *(hidden)* Deprecated compatibility alias for source/binary mode |
|
|
| `--binary PATH` | Binary, object file, or firmware image for binary mode |
|
|
| `--binary-max-functions N` | Limit binary function extraction (`0` = all) |
|
|
| `--hybrid-strategy merge-only` | Hybrid routing strategy. Unimplemented hint-exchange strategies are rejected rather than silently falling back. |
|
|
| `--source-detectors NAME ...` | Source-side detector override for hybrid scans |
|
|
| `--binary-detectors NAME ...` | Binary-side detector override for hybrid scans |
|
|
| `--havoc-external-symbols` | Model external/linker symbols (`_edata`, weak, `[[gnu::section]]`) as opaque addresses instead of concrete constants |
|
|
| `--havoc-statics-at-entry` | Havoc mutable static/global state to an unknown value at function entry unless provably single-assignment |
|
|
| `--volatile-read-havoc` | Treat each volatile/MMIO read as a fresh unknown (reserved; volatile derefs already return fresh unknowns) |
|
|
| `--suppress-loop-bound-always-conditions` | Don't report a loop's own controlling predicate as always-true when the proof leans on the bounded-unroll loop bound |
|
|
|
|
Use `fold scan --advanced-help` for the generated detector-tuning, profiling,
|
|
cache, and quarantine option table. These flags remain callable but are omitted
|
|
from normal help to keep the common scan workflow concise.
|
|
|
|
Native finding JSON uses the stable envelope
|
|
`{"output_version":1,"tool":{"name":"fold","version":"..."},"findings":[...]}`.
|
|
SARIF remains the interoperability format; Markdown remains the human-readable
|
|
report. Requested report/profile paths are written atomically; failures return
|
|
exit `2`. Console counts and both machine formats use the same filtered and
|
|
deduplicated finding set.
|
|
|
|
Both machine formats record which C/C++ translation units were analyzed: the
|
|
native JSON gains a `coverage` object (`tus_attempted`, `tus_analyzed`, and one
|
|
`gaps` entry per unanalyzed TU with a reason: `compile-errors`,
|
|
`frontend-failed`, `analysis-failed`, `timeout`, `crash`, `worker-exit`, or
|
|
`quarantined` for a TU a prior run's quarantine skipped),
|
|
and SARIF carries the same data as an `invocations` entry with
|
|
`executionSuccessful` and one `toolExecutionNotifications` entry per gap. A
|
|
scan with any gap, or one that analyzed no TU, exits `2` after writing its
|
|
report: no findings from an incomplete scan is not evidence of no bugs.
|
|
Diagnostics go to stderr, so a report written to stdout stays parseable.
|
|
|
|
`fold --version` reports the Meson semantic version plus Git revision and a
|
|
`.dirty` suffix for builds configured from modified trees. SARIF, native JSON,
|
|
profiles, and benchmark run artifacts retain the same provenance.
|
|
|
|
### Query existing finding reports
|
|
|
|
`fold grep` searches Fold SARIF and native findings-json reports, not arbitrary
|
|
source text. Matching is bounded fixed-string matching; regex input is not
|
|
accepted.
|
|
|
|
```sh
|
|
fold grep "null pointer" findings.sarif --field message --ignore-case
|
|
fold grep "fold.null-deref" findings.sarif --field rule \
|
|
--backend source --path-glob 'src/*.cpp' --actionable-only
|
|
fold grep "token" source.sarif binary.json --format json --output matches.json
|
|
```
|
|
|
|
Searchable fields are `message`, `id`, `rule`, `path`, `function`, and
|
|
`evidence`; omitting `--field` searches all of them. Typed filters cover rule,
|
|
confidence, backend provenance, path glob, baseline status, and suppression.
|
|
`--offset` and `--limit` provide deterministic ID/location-ordered pagination.
|
|
JSON output includes totals, actionable totals, next-offset, has-more, and
|
|
truncation metadata while retaining complete finding records on the selected
|
|
page. Exit status is `1` when the query matches an unsuppressed finding, `0`
|
|
when it does not, and `2` for malformed reports or other input/output failures.
|
|
|
|
### Configuration profiles
|
|
|
|
`--config-profile` accepts a strict version-1 JSON artifact for source and hybrid
|
|
scans. It records normalized guards on callsites without pruning graph edges;
|
|
whole-program reachability classifications are a separate analysis phase.
|
|
Profiles support typed Boolean or signed-integer globals, entry arguments,
|
|
zero-argument accessors, and `getenv` set/unset state:
|
|
|
|
```json
|
|
{
|
|
"version": 1,
|
|
"entrypoints": ["main"],
|
|
"assumptions": [
|
|
{"kind": "global", "selector": "feature_enabled", "value": false},
|
|
{"kind": "entry_arg", "entrypoint": "main", "index": 1, "value": 4},
|
|
{"kind": "getenv", "selector": "FEATURE_X", "state": "unset"},
|
|
{"kind": "accessor", "selector": "Config::enabled", "value": true}
|
|
]
|
|
}
|
|
```
|
|
|
|
Unknown fields, duplicate selectors, type mismatches, unsupported versions, and
|
|
invalid entrypoint references fail with exit `2`. Persisted guards contain only
|
|
opaque SHA-256 symbol IDs; performance telemetry exposes the profile hash,
|
|
version, and aggregate projected/unconditional/unknown counts, never selectors
|
|
or source expressions.
|
|
|
|
### freestanding preset
|
|
|
|
`fold scan --preset freestanding ...` bundles the four embedded-firmware
|
|
modeling toggles plus secondary-section rendering. On freestanding/bare-metal
|
|
code fold's bounded symbolic engine otherwise over-reports: it concretizes
|
|
values it cannot soundly know (linker symbols, volatile/MMIO reads, mutable
|
|
statics) and reports the bounded-unroll in-bound loop guard as a universal
|
|
truth. Each shortcut produces a false `Proved` finding, which is why fold is
|
|
advisory rather than gating on firmware.
|
|
|
|
The preset is equivalent to:
|
|
|
|
```
|
|
--havoc-external-symbols --havoc-statics-at-entry --volatile-read-havoc \
|
|
--suppress-loop-bound-always-conditions # + redundancy-lane-secondary
|
|
```
|
|
|
|
| Gap | Symptom | Fix |
|
|
|-----|---------|-----|
|
|
| A — bounded unroll | `i < 6` / `i >= 0` loop guard reported always-true | The loop induction variable is pinned with a `LoopBoundUnroll` tracked assumption; when a proof's Z3 UNSAT core leans on it the finding is downgraded `Proved → Heuristic` or suppressed |
|
|
| B — linker symbols | `dst < &_edata` always-true | External/linker symbol addresses become opaque unknowns (soundness fix — the real bug also becomes findable) |
|
|
| C — volatile reads | busy-wait exit edge pruned | Volatile/MMIO loads return a fresh unknown per read |
|
|
| D — mutable statics | `heap + n > limit` always-false (`_sbrk`) | Mutable static locals are havoc'd at entry instead of re-applying the initializer each call |
|
|
|
|
The four modeling toggles are gated and default off, so a normal
|
|
`fold scan` (no preset) behaves exactly as before. Under the preset the
|
|
syntactic redundancy lane (clone/equiv/dead/always-condition) renders as a
|
|
clearly-secondary report section (markdown) or carries a
|
|
`properties.category: "redundancy"` tag (SARIF/JSON) so it doesn't bury the
|
|
security findings.
|
|
|
|
### binary backend
|
|
|
|
The binary backend is a prototype that uses radare2 to recover functions,
|
|
sections, calls, strings, and pseudocode-like text. It reuses fold's `Finding`
|
|
and reporting pipeline, but it does not yet run the Clang/Z3 source detectors on
|
|
a lifted IR. Current binary findings are heuristic and focus on:
|
|
|
|
* hardcoded secrets, API keys, URLs, and private-key markers in binary strings
|
|
* calls to known unsafe C routines such as `strcpy`, `sprintf`, and `gets`
|
|
* simple null-deref patterns in radare2 pseudocode
|
|
|
|
Example:
|
|
|
|
```sh
|
|
fold scan --input-type binary --binary /usr/bin/curl \
|
|
--binary-max-functions 64 --detectors security --format sarif
|
|
```
|
|
|
|
`--binary-max-functions` is useful for smoke tests and large system binaries.
|
|
Use `0` (the default) for a full binary scan.
|
|
|
|
Rust programs can use the same binary path after compilation:
|
|
|
|
```sh
|
|
rustc -C opt-level=0 src/main.rs -o target/fold-rust-smoke
|
|
fold scan --mode binary --binary target/fold-rust-smoke --detectors security
|
|
```
|
|
|
|
### rust frontend
|
|
|
|
Rust source inputs route through `fold-rust` when `--mode rust` is selected or
|
|
when auto mode sees `.rs` files / Cargo crate directories. Use binary mode for
|
|
compiled Rust artifacts; source and binary provenance stay separate.
|
|
|
|
```sh
|
|
fold scan --mode rust path/to/crate --detectors rust-security --format sarif
|
|
```
|
|
|
|
`fold-rust` itself requires a nightly `rustc_private` analyzer at Rust 1.98 or
|
|
newer with `rustc-dev`, `rustfmt`, and `llvm-tools-preview`. The authoritative
|
|
analyzer pin is `tools/fold-rust/rust-toolchain.toml`; Meson does not duplicate
|
|
it. A crate may select a different Cargo target nightly: the workspace wrapper
|
|
keeps using the analyzer binary's linked compiler while preserving Cargo's
|
|
crate graph and arguments. Inspect the compiled analyzer with:
|
|
|
|
```sh
|
|
fold-rust toolchain-info
|
|
python3 scripts/check_rust_toolchain_skew.py \
|
|
--output build/release/meson-logs/rust-toolchain-skew.json
|
|
```
|
|
|
|
The check dynamically uses installed toolchains, exercises same-version and
|
|
newer-target scans, records exact releases/components, and emits an explicit
|
|
skip when no newer nightly is installed. Stable toolchains are listed with the
|
|
actionable reason they cannot be used to build the `rustc_private` analyzer.
|
|
The check never downloads or silently substitutes a toolchain.
|
|
|
|
Cargo workspace scans refuse to execute `build.rs` scripts or proc macros by
|
|
default. Scan only trusted workspaces with the explicit opt-in:
|
|
|
|
```sh
|
|
fold scan --mode rust path/to/trusted-crate --rust-allow-build-code
|
|
```
|
|
|
|
`fold fuzz prep` also accepts Rust scans and writes the normal
|
|
`findings.predicted.json` file plus the shared confirmation sidecar
|
|
`confirmation.tasks.json`. Current Rust detectors are HIR heuristics and do not
|
|
yet emit Z3 path witnesses, so Rust fuzz-prep runs may produce an empty
|
|
prediction set until Rust-specific witness extraction / cargo-fuzz harness
|
|
emission lands.
|
|
|
|
### swift frontend
|
|
|
|
Swift source inputs route through `fold-swift` when `--mode swift` is selected or
|
|
when auto mode sees `.swift` files. `fold-swift` invokes `swiftc -emit-sil` on
|
|
each input and emits NDJSON with function metadata, findings (heuristic), and
|
|
interface records. Use binary mode for compiled Swift artifacts; source and
|
|
binary provenance stay separate.
|
|
|
|
```sh
|
|
fold scan --mode swift path/to/file.swift --detectors rust-unsafe-api,null-deref --format sarif
|
|
```
|
|
|
|
Current Swift detectors are SIL heuristics:
|
|
|
|
| Detector | Hazard |
|
|
|----------|--------|
|
|
| `rust-unsafe-api` | `unchecked_ref_cast`, `unchecked_addr_cast`, `unchecked_trivial_bit_cast` bypass Swift type safety |
|
|
| `null-deref` | `load` through raw `UnsafePointer` without provenance check |
|
|
|
|
Swift findings are heuristic today; they preserve backend provenance and
|
|
stable rule IDs, but do not yet perform interprocedural taint proof or
|
|
SIL-level path feasibility.
|
|
|
|
### hybrid router
|
|
|
|
Hybrid mode runs the source and binary backends in one in-memory router pass and
|
|
emits a single report. The initial implementation is merge-only: source findings
|
|
and binary findings are produced independently, tagged with backend provenance,
|
|
and merged without writing intermediate SARIF files.
|
|
|
|
```sh
|
|
fold scan --mode hybrid \
|
|
--compile-db build/compile_commands.json \
|
|
--binary build/app \
|
|
--detectors security \
|
|
--format sarif \
|
|
--output fold-hybrid.sarif
|
|
```
|
|
|
|
`--mode auto` selects hybrid when both source inputs and `--binary` are present.
|
|
`--input-type binary --binary <path>` remains supported for existing scripts.
|
|
|
|
### suppressions and baselines
|
|
|
|
Suppression files are plain text, one pattern per line. Blank lines and `#`
|
|
comments are ignored. Patterns match either detector name, exact `file:line`, or
|
|
finding-id prefix:
|
|
|
|
```text
|
|
# suppress all integer-overflow findings
|
|
int-overflow
|
|
|
|
# suppress one location
|
|
src/foo.cpp:42
|
|
|
|
# suppress an ID family
|
|
dead:
|
|
```
|
|
|
|
Baselines are JSON files with current finding decisions:
|
|
|
|
```json
|
|
{
|
|
"version": 1,
|
|
"tool": "fold",
|
|
"findings": [
|
|
{"id": "null-deref:src/foo.cpp:42:10", "status": "accepted"},
|
|
{"id": "int-overflow:src/bar.cpp:12:7", "status": "dismissed"}
|
|
]
|
|
}
|
|
```
|
|
|
|
Current scans mark unmatched findings as `new`; `dismissed` baseline entries are
|
|
reported as suppressed. SARIF encodes suppressed findings with `level: "none"`
|
|
and an external suppression justification.
|
|
|
|
### confirmation and fuzz witness output
|
|
|
|
Fold has two confirmation surfaces:
|
|
|
|
* `fold confirm`: deeper bounded symbolic rerun for selected source findings.
|
|
* `fold fuzz prep` / `fold fuzz run`: libFuzzer + ASan confirmation that promotes
|
|
matched crashes to `confidence: "concrete-witness"`.
|
|
|
|
`fold fuzz prep` preserves legacy `findings.predicted.json` and also emits
|
|
`confirmation.tasks.json`. `fold fuzz run` preserves the augmented findings JSON
|
|
and also writes `confirmation.results.json` in the prep directory.
|
|
|
|
An optional KLEE smoke adapter exists for development validation:
|
|
|
|
```sh
|
|
tests/confirmation/klee/run_klee_smoke.sh
|
|
```
|
|
|
|
It skips cleanly when KLEE is not installed.
|
|
|
|
### confirm options
|
|
|
|
| Flag | Description |
|
|
|------|-------------|
|
|
| `--finding ID` | Confirm a specific finding |
|
|
| `--rule DETECTOR` | Confirm all findings of a detector |
|
|
| `--at FILE:LINE` | Confirm findings at a location |
|
|
| `--unwind N` | Loop unrolling depth (default: 10) |
|
|
| `--budget N` | Per-function solver budget (ms) |
|
|
| `--witness DIR` | Write SV-COMP GraphML witnesses |
|
|
| `--output PATH` | Write confirmation report |
|
|
|
|
## Detectors
|
|
|
|
| Detector | CWE | Method |
|
|
|----------|-----|--------|
|
|
| `clone` | — | Structural hash + Levenshtein (Type 2/3) |
|
|
| `equiv` | — | Z3-proved semantic equivalence (Type 4) |
|
|
| `class-dup` | — | Cross-class member equivalence |
|
|
| `complexity` | — | McCabe-style complexity; available for C++ and Rust HIR functions |
|
|
| `dead` | 561 | Path predicate UNSAT for branch |
|
|
| `null-deref` | 476 | SAT-check pointer==0 under path |
|
|
| `div-by-zero` | 369 | SAT-check divisor==0 under path |
|
|
| `int-overflow` | 190 | BV overflow predicates at source width |
|
|
| `oob` | 121 | Array subscript bounds + stdlib buffer size |
|
|
| `int-truncation` | 197 | Implicit integer truncation |
|
|
| `sign-conversion` | 195 | Value-changing signed/unsigned casts |
|
|
| `taint-track` | — | Untrusted-input-to-sink flow |
|
|
| `rust-unsafe-api` | — | HIR scan for unsafe Rust APIs such as `transmute`, `from_raw_parts`, and `set_len` |
|
|
| `rust-unchecked-index` | — | HIR scan for `get_unchecked` / `get_unchecked_mut` bounds bypasses |
|
|
| `rust-path-traversal` | 22 | Heuristic Rust filesystem path sink scan |
|
|
| `rust-command-injection` | 78 | Heuristic Rust `std::process::Command` argument sink scan |
|
|
| `rust-crypto-misuse` | 327 | Heuristic weak-hash / crypto misuse scan |
|
|
|
|
Rust detector findings are heuristic today: they preserve backend provenance and
|
|
stable rule IDs, but they do not yet perform interprocedural taint proof or
|
|
MIR-level path feasibility.
|
|
|
|
## Project Evaluation
|
|
|
|
Use the manifest-driven runner to profile Fold and evaluate finding drift on a
|
|
real C++ source tree, Rust workspace, or compiled binary. It writes SARIF,
|
|
profile JSON, immutable run artifacts, and a `summary.json`/`summary.md` with
|
|
stability, resource, disposition, gold, and baseline-comparison results.
|
|
|
|
```sh
|
|
python3 scripts/benchmarks/run_project_eval.py \
|
|
--manifest tests/benchmarks/projects/yams_source.json \
|
|
--out-dir /tmp/fold-yams-eval
|
|
|
|
python3 scripts/benchmarks/run_project_eval.py \
|
|
--manifest tests/benchmarks/projects/sage_rust.json \
|
|
--out-dir /tmp/fold-sage-eval
|
|
```
|
|
|
|
Manifest schema version 1 is validated by `fold_eval.project`. A manifest pins
|
|
the lane, corpus/build input, detector scope, budgets, repetitions, and
|
|
optional gold/disposition/performance-baseline inputs. Relative paths resolve
|
|
from the manifest directory. Rust manifests automatically use the frontend's
|
|
pinned toolchain unless `analysis.rust_toolchain` overrides it.
|
|
Set `evaluation.min_functions` for a production Rust or binary target to fail
|
|
closed when frontend/toolchain failure produces an empty scan.
|
|
|
|
For binary projects, set `lane` to `binary` and provide one or more
|
|
`corpus.binaries` paths. Binary observations remain heuristic, but retain
|
|
artifact/function identity for review even when no source line is available.
|
|
|
|
`fold scan --profile --profile-output profile.json` emits comparable top-level
|
|
timings across lanes. C++ source profiles provide source-phase and detector/Z3
|
|
metrics; Rust/Swift profiles add `frontend_extraction_ms`; binary profiles add
|
|
`binary-heuristic`, `binary-ir`, and `binary-pcode` rows, including P-Code Z3
|
|
query results.
|
|
|
|
## Output
|
|
|
|
SARIF 2.1.0 with `properties.confidence`: `concrete-witness` (runtime
|
|
ASan/libFuzzer confirmation), `proved` (Z3 proof under Fold's bounded model),
|
|
`heuristic` (over-approx in path), `syntactic` (structural only).
|
|
|
|
## MCP
|
|
|
|
```
|
|
fold mcp
|
|
```
|
|
|
|
JSON-RPC 2.0 over stdio. Protocol version `2024-11-05`.
|
|
Advertised tools: `fold.scan` (router-backed source/binary/hybrid/rust scan),
|
|
`fold.scan_start` / `fold.scan_status` / `fold.scan_jobs` for queued scans,
|
|
`fold.scan_job_findings` / `fold.scan_activate` for completed jobs,
|
|
`fold.get_scan_context`, `fold.get_findings`, `fold.query_findings`,
|
|
`fold.suggest_merge`, and `fold.explain`.
|
|
`fold.query_findings` applies the same fixed-string fields, typed filters, and
|
|
pagination engine as `fold grep` to either the current context or a completed
|
|
`job_id`. Session-scoped finding/context cache. Use `fold.scan` with
|
|
`background: true`, or `fold.scan_start`, for long-running scans. Deprecated
|
|
scan and detector wrapper names remain callable but are hidden from
|
|
`tools/list`.
|
|
|
|
Rust inputs are passed as `paths` and route to the Rust frontend when `mode` is
|
|
`rust` or when `mode` is omitted and the paths are `.rs` files or Cargo crate
|
|
directories.
|
|
|
|
## LSP
|
|
|
|
```
|
|
fold lsp
|
|
```
|
|
|
|
Content-Length-framed JSON-RPC. Diagnostics through `textDocument/didOpen`
|
|
and `textDocument/didChange`. Code actions for fold findings.
|