MANDATORY FIRST CALL for C/C++ projects. Return metadata about the
most recently indexed build configuration — check index health before
using any other fw-context tools.
Read-only, and it spawns no subprocess — the startup daemon thread and
the file watcher own the background reindex.
Act on ``status``:
* ``"ready"`` — up to date. Continue.
* ``"reindexing"`` — background reindex running; queries stay accurate.
Continue. ``reindex_progress`` holds its last log line.
* ``"reindex_needed"`` — schema mismatch, changed compile_commands.json,
or a source file that compile_commands.json does not cover. Queries
still work on existing data. Read ``reindex_reasons``: a missing
source file needs ``fw-context index --build``, the other two need
only ``fw-context index``.
* ``"no_index"`` — initialized, never indexed. Run ``fw-context index``.
* ``"not_initialized"`` — run ``fw-context init``.
* ``"error"`` — DB corruption or access error. Use other tools.
Three conditions set ``reindex_needed``: an outdated schema, a changed
compile_commands.json, and a source file that is on disk but absent from
compile_commands.json. The third one needs a build, because only the
build system writes that file — a plain reindex has no translation unit
for the file and skips it without a word. Modified source files are
something else: they are handled per-query, and never set it.
``indexed_at`` and ``first_indexed_at`` are UTC; file mtimes are local
time. Never compare the two directly — in UTC+2 a correctly indexed
file looks 2 hours newer than ``indexed_at``. Call with ``fast=False``
to find modified files.
``analysis`` splits the LLM-analysis coverage into project and vendor
symbols:
* ``model`` — the model of the analysis, or None. One model only, even
when several were used.
* ``analyze_vendor`` — the value at index time, not the current config.
* ``project`` / ``vendor`` — ``{analyzed, skipped, total}``.
``skipped`` = tried, but not analyzable (body larger than the model
context, an unparseable answer, or a body that was not readable).
* ``complete`` — no work left: every project symbol is analyzed or
skipped. True exactly when ``reindex_reasons`` holds no "unanalyzed
symbols" entry. Vendor symbols excluded by ``analyze_vendor=False``
never block it, thus ``vendor.total`` large with ``vendor.analyzed=0``
is expected, not a defect.
Args:
project_root: Project root directory. Auto-detected from CWD if
omitted.
project: Project name or project_id — call list_projects to get them.
Use it to ask about a project that is not the project of the
current directory. It is an alternative to project_root, which
takes a root path. Give one of the two, not both.
fast: When True (default), the header check reuses the cached
manifest hashes. Both modes run the per-file scan, thus
``modified_files_count`` is accurate either way — a tool that
reported "ready" while the search tools warned about the same
file gave the caller two readings and no way to choose.
False recomputes the header hashes and costs several times more.
Returns:
dict: {config_hash, project_id, project_root, build_system,
compile_commands, indexed_at (str — "YYYY-MM-DD HH:MM:SS" in UTC,
the completion time of the last full index), symbol_count, file_count,
reference_count, modified_files_count (int — files whose content no
longer matches the index; counted in both modes),
header_affected_tus (int — number of TUs with stale header
dependencies), manifest_verification (str —
"full" when manifest.json exists, "none" otherwise),
analysis (dict — LLM-analysis coverage split by project/vendor:
{model, analyze_vendor, project: {analyzed, skipped, total},
vendor: {analyzed, skipped, total}, complete}),
description (str), first_indexed_at (str — UTC, same format as
indexed_at),
vendor_paths (list[str] — config index.vendor_paths),
project_paths (list[str] — config index.project_paths),
bg_reindex_running (bool),
reindex_progress (str or None — last log line when reindex is running),
schema_version (int — DB schema version),
current_schema (int — code expects), status (str — "ready"|"reindexing"|
"reindex_needed"|"no_index"|"not_initialized"|"error"), reindex_needed (bool —
structural mismatch requiring a full reindex),
reindex_reasons (list[str] — why reindex is needed, empty when False.
One of them asks for `fw-context index --build` rather than a plain
reindex: when the tree is on a different branch than the index,
compile_commands.json belongs to the OLD branch and carries its file
list and its compiler flags, so only a build regenerates it. Read
the reason text — it names the command it needs),
stale (bool — True when reindex_needed or header_affected_tus > 0),
_warning (str, optional — when manifest verification is not "full"),
vec_available (bool), vec_error (str, optional),
index_message (str — human-readable summary of index state),
multi (bool — True for a multi-variant project),
variants (list[dict] — {name, description, board}),
images (list[dict] — {name, description, dir, type}),
variant_images (dict — variant name to its image names),
active_variant (str or None — [build] default_variant),
active_image (str or None — [build] default_image),
entry_point (str — the `ENTRY()` of the linker script of the build
that the other fields describe, empty when no script names one),
memory (list[dict] — the `MEMORY` regions of that build:
{name, attributes, origin, length, origin_value, length_value,
file_path, line})}
About ``memory``: ``origin`` and ``length`` hold the expression the
script writes, thus they differ by platform — an mbed script writes
`0xefe00` and a Zephyr script writes `((673792) - 0xe6)`.
``origin_value`` and ``length_value`` hold the number, and both are
None for an expression that names a symbol, such as
`ORIGIN(RAM) + LENGTH(RAM)`. The end of a region is
``origin_value + length_value``.
``memory`` and ``entry_point`` describe ONE build. For a
multi-variant project they follow ``config_hash``, which is the
build named by ``[build] default_variant``, and both are empty when
the config names no default. Use ``list_variants`` for the map of
every build.
``memory`` is empty for a build system that records no linker
script. A PlatformIO project is the measured case: SCons writes no
ninja file and no link command the index can read, and the map file
never names the script. An empty list means "not recorded", never
"no memory".
``defines`` (dict — the `-D` flags of that build) and
``defines_varying`` (int). ``defines`` holds only the names that
EVERY translation unit of the build carries with the same value, so
the tool never shows the defines of one file as the defines of the
build. ``defines_varying`` counts the names left out, thus a name
absent from ``defines`` is either not defined at all or not defined
everywhere — measured on the Mbed project: 27 names in all 881 units, 59
in only some, where the three assembly files get a shorter set.
This is the configuration the BUILD states, not every macro the
preprocessor saw. The second is three orders of magnitude larger —
27800 distinct names on the STM32 project — and almost all of it comes from the
headers and the compiler. A Zephyr build keeps its real
configuration in ``autoconf.h`` (740 `CONFIG_*` names) and passes
few `-D` flags, so ``defines`` says little there and a great deal on
an mbed build, where it holds `APPLICATION_ADDR`,
`APPLICATION_SIZE`, and `CMSIS_VECTAB_VIRTUAL`.
For a project that is not initialized, the result holds only
``status``, ``project_root``, and ``index_message``. When no index
exists, the result adds ``project_id``.