Code reference detail
workspace-index.ts
packages/analytical/src/index-store/workspace-index.ts
| Idea | Status | Tags | Summary | Katz |
|---|---|---|---|---|
| active_base_switch | done | Changing the active base is a **pointer swap** onto a per-base `WorkspaceIndex` / store. - Do **not** await soft-sync, hard-rebuild, or a full `.rq` walk on the switch call itself. - Host surfaces rebind views to the newly active store ( status snapshot, tables, context panes ) immediately. - If the selected base is not yet ready, show its readiness / progress and **schedule** the normal activate catch-up ( open if needed, then one soft sync ) fire-and-forget — same path as ["../indexer/indexer.rq".triggers] / ["../extension/index-host/graph-analysers.rq".indexing_trigger_open], not a special switcher rebuild. - Idle staleness checks only touch bases that are already open; they must not reopen every discovered base ( ["../extension/index-host/sqlite-artifact-lifecycle.rq".release_when_idle] ). - Open failures stay isolated per base so one bad base cannot leave siblings stranded in `uninitialized`. - Editor-follow must not overwrite a user pin on the same refresh that applies the selection. - Inactive bases release SQLite artifacts when the active pointer moves away ( ["../extension/index-host/sqlite-artifact-lifecycle.rq".sqlite_artifact_lifecycle] ). Surfaces: activity bar ["../extension/local-context/activitybar-panels/workspace.rq".workspace_base_picker], Ideas Summary ["../extension/workspace-summary/ideas_summary/base-scope.rq".ideas_summary_base_scope]. Implemented by [editor_index_adapter] ( `setActiveBaseId` / `scheduleBaseCatchUp` ); engine: [base_registry] `ensureBaseReady` / `releaseArtifacts`, [workspace_index] `ensureReady` / `deactivate`. | 0.093 | |
| base_ownership | Each base holds its own [ideas_index] store under `<base>/.reqlan/ideas-index.sqlite`. Path keys inside the index are relative to that base root, not the VS Code workspace root. Store path: [application_memory_impl]; per-base engine: [workspace_index] via [base_registry]. | 0.112 | ||
| analytical_package | in-progress | `packages/analytical` ( `@reqlan/analytical` ) is the shared requirement graph index and analysis layer. It owns the [indexer]: extracts ideas and edges into a rusqlite store via the core native engine ( [workspace_index] ), holds Zustand analytical state, and exposes analysers and an analysis API. Headless CLI / MCP entry is `@reqlan/analytical/core` via `openAnalysisApi` ( native required; no Langium ). Consumers: [extension_package] ( thin editor adapter ), [mcp_package], [cli_package]. Depends on [language_package] for the editor LSP only. Published to npm alongside [cli_package]; version graph role: [package_versioning]. Rust engine port ( lexer / parser-for-index, indexer, search, export ): [rust_port.analytical_rust_port], shipped per [distribution.rust_binary_distribution]. | 0.167 | |
| ideas_index | The ideas index is built and maintained by the [indexer] in [analytical_package]. Path: Rust parse / extract → SQLite via [workspace_index] ( [rust_port.analytical_rust_port] ). Application memory: each [bases.base] holds SQLite under `<base>/.reqlan/` ( shared by extension, [cli_package], and [mcp_package] ) — see ["./extension/index-host/index.rq".application_memory]. Multi-base: a BaseRegistry owns one [workspace_index] per discovered base; the extension adapter routes file events to the owning base. In the editor, [editor_index_adapter] watches `**\*.rq` and forwards changes to the owning base's [workspace_index]; it serves UIs, commands, chat, and analysers. The Rust language server reads the same store for catalogs, rename, and find-references ( [lsp_rust.language_server_rust] ). Headless ( MCP / CLI ) uses [analysis_runtime] ( nearest base containing cwd when several exist ). Capability requirements: [indexer.index_ideas], [indexer.index_technology], and sibling analysers in that file. Triggers: [indexer.triggers] and ["./extension/index-host/index.rq".idea_index_triggers]. | 0.100 | ||
| runtime_topology | The editor and the index do not share one process. - LSP process: `reqlan-lsp` for live `.rq` editing ( [lsp_rust.language_server_rust] ). - Analytical [workspace_index] ( extension host via [editor_index_adapter], MCP / CLI via [analysis_runtime] ): full-workspace graph for tables, local graph, chat, MCP. Editor ↔ extension host: VS Code APIs and webview postMessage. Editor ↔ LSP: vscode-languageclient over stdio. The language server reads the ideas index directly. Host catalog notifications are optional. Stack sketch: [development_core.stack]. | 0.040 | ||
| configuration_location | An optional `.reqlan/config.json` may appear under a base's `.reqlan` directory. For a given `.rq` file, the applying base is the nearest ancestor directory that owns a `.reqlan` folder. The applying config is that base's `.reqlan/config.json` when present. If the owning base has no `config.json`, or no owning base is found, defaults from [configuration_import_roots] apply. A child base does not inherit a parent base's config. | 0.190 | ||
| configuration_rqignore | done | Each base may define path ignore rules in `.reqlan/.rqignore` using **gitignore syntax**. Patterns are relative to the base root ( parent of `.reqlan` ), not the `.reqlan` directory. Owned by `@reqlan/analytical` so the CLI, MCP, and extension share one filter for discovery and indexing walks. Built-in defaults always apply ( dependencies, venvs, build output, VCS / editor stores, `*.db3` / sqlite DBs and SQLite sidecars, binary globs per ["../index-host/index.rq".binary_ignore], files that have no comments per ["../index-host/index.rq".commentless_file_ignore], `*.secret.rq`, hidden entries, and `.reqlan/` itself ); the on-disk file adds or overrides via the same syntax, including `!` negation. New bases seed `.reqlan/.rqignore` with those defaults ( ["../index-host/index.rq".rqignore] ). Missing or unreadable `.rqignore` still uses built-in defaults. Location convention: [configuration_location]. Application memory: ["../index-host/index.rq".application_memory]. | 0.223 | |
| extension_startup_reliability | done | Reqlan startup must make the activity-bar shell and contributed commands available before optional indexing, parser construction, database initialization, or language-client startup can monopolize the extension host. The implementation contract is [first_paint_contract], [webview_claim_race], [deferred_startup_sequence], [lazy_runtime_dependencies], and [development_bundle_freshness]. Operational diagnosis follows [startup_diagnostics]. [activation.activation_sequence] [activitybar.loading_state] [indexer.nonblocking_index] [build.extension_bundle] | 0.046 | |
| lazy_runtime_dependencies | done | Base discovery must be cheap: - Constructing `WorkspaceIndex` does not construct Langium / Chevrotain services; index sync uses the core native engine ( rusqlite ). - The host-matching `reqlan_napi` `.node` is required at activate; there is no sql. js vendor bundle in the extension host. - Export / physics source is generated at build time rather than read via extension-runtime URLs. ["../../../packages/analytical/src/index-store/workspace-index.ts"] ["../../../packages/analytical/src/index-store/sqlite-store.ts"] ["../../../packages/analytical/src/index-store/index-diagnostics-store.ts"] ["../../../packages/extension/esbuild.mjs"] | 0.046 | |
| index_diagnostics_metrics | done | For each sync / index run on a base, record: - wall-clock **sum / total duration** of the pass - **file count** ( visited ), skipped-by-mtime count, indexed ( parse / persist attempted ) count, error count - **average path depth** of visited files ( segments under the base root ) - per-file **duration** and outcome ( `mtime_skip` | `mtime_refresh` | `hash_skip` | `persisted` | `error` ) Runs are attributable to a trigger ( `soft_sync` | `rebuild` | `enqueue` | `stale` ). Instrumentation wraps [workspace_index] soft sync and [indexer.nonblocking_index] single-file paths via [diagnostics_store]. | 0.120 | |
| application_memory | done | Base-local application memory for reqlan tools lives under `<base>/.reqlan/`. The presence of `.reqlan` **marks** a directory as a ["../../bases/base.rq".base]; each base owns its own store. Shared by the VS Code extension, ["../../cli/cli_package.rq".cli_package], and MCP ( [mcp_server] ) — not VS Code `globalStorageUri` / extension-private storage. The ideas graph index ( [indexer.index_ideas] and [indexer.index_technology] ) persists as `ideas-index.sqlite` inside that directory. Schema: ["../../indexer/sqlite-schema.rq".ideas_index_sqlite]. Index timing diagnostics persist separately as `index-diagnostics.sqlite` ( [index_diagnostics_store] / ["./index-diagnostics.rq".index_diagnostics] ) so rebuilds of the ideas index do not wipe history. Click session state persists as `click-sessions.sqlite` ( ["../../cli/click.rq".click_session] ) so agent / CLI click cursors survive ideas-index rebuilds. Diagnostics schema: ["../../indexer/diagnostics-schema.rq".diagnostics_sqlite]. WAL sidecars and JSON siblings: ["../../indexer/sidecars.rq".reqlan_directory_layout]. Export form defaults ( all formats via ["../export/export.rq".export_webview], including HTML options in ["../export/html-export.rq".html_export_form] ) persist as `export_settings.json` in the same directory ( active base ). Path ignore rules live as `.rqignore` in the same directory ( [rqignore] / [configuration.configuration_rqignore] ). Git ignore for SQLite stores lives as `.gitignore` in the same directory ( ["../../bases/base.rq".base_initialisation_ignore] ). Path resolution is owned by [application_memory_impl] ( `resolveApplicationMemoryPath` ); consumers must use it ( or `REQLAN_INDEX_PATH` override for a single store ) so tools read and write the same store for a given base. Multi-base discovery / registry: ["../../bases/base.rq".multi_base_environment]. Index engine ownership: ["../../indexer/indexer.rq".ownership]. Extension wiring: [analytical_submodule]. Aligns with ["../../cli/cli_package.rq".function_parity]: shared analytical memory, not host-only state. | 0.494 | |
| rqignore | done | `.reqlan/.rqignore` filters which paths discovery and indexing crawl, using gitignore syntax relative to the base root. Owned by [rqignore_impl] in `@reqlan/analytical` so CLI and editor share behaviour. Defaults cover `node_modules/`, virtualenvs, build dirs ( `bin/`, `generated/`, `out/` ), VCS / editor stores, database files ( `*.db3`, sqlite ) and SQLite sidecars, binary globs ( [binary_ignore] ), `*.html`, secrets, and hidden entries. Walks also skip common files that have no comments ( [commentless_file_ignore] ). New bases seed the file via [rqignore_initialisation]. Product configuration statement: [configuration.configuration_rqignore]. | 0.296 | |
| release_when_idle | done | After an index or analysis pass finishes, and after the idle quiet period ( [idle_stale_check] / indexing_trigger_auto ), [editor_index_adapter] must release every open base SQLite handle via [base_registry] `releaseArtifacts` → [workspace_index] `deactivate`. Descriptors stay registered so the next event can reopen the same base. Idle must not leave connections open after a heal / sync, and must not schedule another open unless a real host event arrives ( file change, pin / switch, focus reopen, command, UI query ). | 0.077 | |
| sqlite_artifact_lifecycle | done | Base SQLite artifacts under `<base>/.reqlan/` ( [base_ownership] ) must not stay locked for the whole extension session. The host opens them only while work runs, then releases file handles so users can delete or replace the files. Aligns with [event_driven]: open and close are reactions to index or analysis events, not a permanent connection or a reconnect loop. Mediation: only [workspace_index] / [analysis_runtime] own SQLite connections. The extension adapter ( [editor_index_adapter] ) must not keep a second long-lived analysis runtime beside the index, and must not call native open without a matching dispose / release. Related: [index_sequencing], [idle_stale_check], [headless_consumers], [multi_base_environment]. | 0.052 | |
| file_crawl_sequence | done | Workspace crawl is the indexer ( [index], [index_sequencing] ). It is not the open-file path. Native sync walks `.rq` files, then allowlisted code files, and writes SQLite. Open-file links must not wait for that walk ( [open_file_algorithm] ). The language server watches `.rq` files only ( ["./initialisation-and-sequencing.rq".lsp_file_watch] ). Related: [extension_startup_sequence], [background_startup]. | 0.040 | |
| open_file_algorithm | done | When the editor opens or changes a `.rq` buffer, `reqlan-lsp` runs this sequence. Do not wait for the ideas index. Do not wait for a workspace crawl. Detail: [open_file_sequence_diagram]. Related: [open_file_reference_sequencing], [language_server_rust], [ast_lifecycle], [outbound_one_hop], [open_file_hot_path], [token_colour_sequence], [missing_reference_colour_sequence], [lazy_features_after_outbound]. The hot path finishes before the first diagnostics publish. 1. Parse this buffer once ( [ast_lifecycle] ). 2. Colour tokens from that parse ( [token_colour_sequence] ). 3. Emit same-file links and same-file missing-idea errors from that parse. 4. Parse each imported file once, at depth 1, for idea names and lines ( [outbound_one_hop] ). Link an imported name that exists. Underline an imported name that does not ( [missing_reference_colour_sequence] ). 5. Return. A qualified reference may link to its file from the path token. Do not read that file on this path. After that publish, a background pass fills the rest ( [lazy_features_after_outbound] ). That pass must not delay steps 1 – 5. The server sends the hot publish before it starts that pass. It runs that pass only while no client message waits. A hover or a definition request goes first. A change reuses the import roots loaded at open. It does not read the config again. The node engine keeps [node_engine_open_path]. | 0.330 | |
| local_graph_view | The activity bar provides a local graph view scoped to the current file or selected idea. The local graph should show direct and optionally indirect references with a configurable depth. | 0.055 | ||
| performance | done | Sidebar webviews share the same constraints as [graph_lib.webview_threading]. - The HTML / Svelte shell paints before index discovery begins; the post-paint `ready` handshake starts indexing. - Require the host-matching core engine at activate; do not embed a sql. js vendor in the activation-critical host bundle. - Default neighbourhood slices; never load the full workspace graph into a pane. - Debounce editor selection and cursor events before rebuilding slices. - Lazy-mount cytoscape only for visible sub-panes; destroy when collapsed or hidden. - Reuse [indexer.local_graph_analysis] and graph query builders rather than ad-hoc index walks in the webview. - Interactive actions ( `openIdea`, insert ref, add to chat, phonebook / Ideas Summary links ) are handled on a priority path: they cancel in-flight search / refresh work and briefly quiet editor-driven rebuilds so subsequent clicks stay snappy. - Idea search scoring runs in a worker thread with a preloaded catalog; catalog load yields so it cannot monopolize the host. - Link navigation must stay snappy once a target is already resolved: [link_open_decoupled_from_git], [link_open_interactive_quiet], [lean_resolved_open], [git_focus_cache_by_head]. | 0.040 | |
| refactor_changes | On rename, move, or delete of files or symbols, the extension should update the idea index, import statements, embedded file references, comment references, and other idea references that are affected. The index should be resilient to duplication, particularly when ideas move between files: the old hosting file URI must be cleared before or when the destination is reindexed. [refactor_file_moves] [refactor_symbol_rename] [refactor_symbol_move] [refactor_symbol_delete] [comment_reference_refactor_support] Implemented by ["../../../packages/analytical/src/index-store/workspace-index.ts"], ["../../../packages/extension/src/analytical_submodule/index-store/index-service.ts"], ["../../../packages/language/src/reqlan-idea-refactor.ts"], and ["../../../packages/extension/src/mutation_module/register-file-mutation-hooks.ts"]. | 0.114 | ||
| inbound_snapshot_events | done | Host → LSP inbound snapshots are event-driven and incremental. Push only when the ideas index is ready ( catalog update, ready-edge, visible-editor change, or window focus ). While Syncing or not ready, do not push an empty batch that clears the language-server last-good map; set a deferred flag and flush on the next ready event. The language client often starts before the index — registration must ensure-open / defer, not skip forever. Each notification is a per-document merge for visible editors; URIs not in the batch stay as last-good until replaced or the document closes. After a single-file enqueue reaches ready, notify catalog so consumers get a ready-state event ( mid-sync catalog notifies alone are not enough ). Coalesce concurrent push work so catalog spam drains to one ready pass. Related: [unify_inbound_indexes], ["../extension/language/support/open-file-sequencing.rq".lazy_features_after_outbound], ["../extension/language/syntax/features-syntax-highlighting.rq".inbound_inlay_index_performance]. | 0.133 | |
| index_cache_reuse | draft | Identify where the ideas index, diagnostics store, or in-process caches already hold data that other modules recompute. Goal: one walk, one sync, one open store where possible; reuse SQLite edges and mtime maps instead of rebuilding graphs from scratch. Related: [nonblocking_index], [indexing_incrementality], [consumers.index_consumers], [sequencing.index_sequencing]. | 0.164 | |
| single_open_store | draft | The extension adapter owns a live [workspace_index] / SQLite connection per base. `getAnalysisApi()` / [analysis_runtime] must not open a second runtime that re-runs `ensure_ready` → `sync_workspace` when the adapter already synced. Reuse the open store for file-context, deprecation, and semantic commands. [index_cache_reuse] [consumers.extension_ui_consumers] | 0.040 | |
| single_sync_walk | done | One native directory walk records base roots, `.rq` paths, and allowlisted code paths. The walk does not read file bodies. Startup, Refresh, and create-base each run that walk once. They do not call `findFiles` and they do not run a second native `syncWorkspace` walk. Soft sync indexes the path list and skips unchanged mtimes. Idle stale check stats paths already stored in SQLite. New files arrive from the file watcher. The language server does not walk. The extension sends the base roots after the scan. Overlapping callers share one in-flight scan. CLI and MCP `sync_workspace` uses the same walk ( one pass, stop at nested bases ). [index_cache_reuse] [sequencing.soft_sync] [sequencing.scan_limits] | 0.080 | |
| index_consumers | done | Modules that read or write [ideas_schema.ideas_index_sqlite] / [index]: - Engine write / read: [workspace_index], Rust sync / store under [ownership] - Extension adapter: [editor_index_adapter] ( watchers, Uri conversion, multi-base ) - Headless: [analysis_runtime] for [cli_package] and [mcp_server] - Activity bar: [activity_bar_host] ( ideas-in-file, hop refs, search via fuzzy ) - Ideas Summary: [ideas_summary_panel] ( table SQL, graph slices, overview ) - Search: [fuzzy_search], [file_search] - Check / analyse / export: [check], analytical export APIs - Local graph: [local_graph_analysis] Product aliases: [index_ideas], [index_technology], [consumption]. Related: [cache_reuse.index_cache_reuse], ["./sequencing.rq".index_sequencing]. | 0.169 | |
| definition | The indexer should live in the [core_analysis] module. On-disk schema: [sqlite_schema.ideas_index_sqlite] and [diagnostics_schema.diagnostics_sqlite]. Layout and WAL sidecars: [sidecars.reqlan_directory_layout]. Consumers: [consumers.index_consumers] ( extends [consumption] ). Sequencing and triggers: [sequencing.index_sequencing] ( extends [triggers] ). Cache reuse opportunities: [cache_reuse.index_cache_reuse]. | 0.040 | ||
| index_ideas | Each ["../bases/base.rq".base] maintains an index of its ideas for fast lookup and navigation ( [index] ). The index should update incrementally as. rq files change within that base ( nested child bases excluded ). Persistence lives in [app_memory_doc.application_memory] per base, shared with CLI and MCP — not VS Code extension storage. Engine ownership: [workspace_index] in `@reqlan/analytical`; multi-base via BaseRegistry; editor watches via [editor_index_adapter]. | 0.173 | ||
| index_technology | The [index_ideas] graph database is rusqlite via the core native engine. On-disk location is [app_memory_doc.application_memory] ( `<base>/.reqlan/ideas-index.sqlite` ), not `context.globalStorageUri`. Implementation: [application_memory_impl], [workspace_index], headless [analysis_runtime] for CLI / MCP, and [editor_index_adapter] for the VS Code host. | 0.152 | ||
| nonblocking_index | done | Index sync must stay non-blocking for the host UI ( notably [activity_bar_doc.activity_bar] and [workspace_pane_doc.workspace_loading] ). Editor startup is gated by ["../extension/host/activation.rq".first_paint_startup]; discovering a base must not construct Langium services, which are initialized lazily on the first parse. While syncing, surface progress — state, processed / total, and the current file — in [workspace_pane_doc.workspace_pane] and [ideas_summary_doc.index_panel]. In-flight sync must be cancellable from those surfaces; cancel keeps already-indexed rows and returns the index to ready. Incremental behaviour ( see also [indexing_incrementality] ): - Single-file create / change / delete via watchers indexes only that file — never a full base walk. - Soft full sync ( `syncWorkspace` / Refresh ) skips parse + persist when the file's mtime matches the value stored on the documents row. - Hard refresh ( `clearAndRebuildIndex` / Clear & rebuild ) wipes the store and reindexes every file. - Every sync and stale check applies `.rqignore` to the paths it receives, the same as the base walk; the native single-file index also drops an ignored path. Thus base discovery cannot make the first sync index ignored files. Implemented by [workspace_index]; editor adapter [editor_index_adapter]. | 0.372 | |
| ownership | The [index] / indexer lives in `packages/analytical` ( `@reqlan/analytical` ). Canonical single-base engine: [workspace_index] ( `WorkspaceIndex` facade ). Sync / idle impl: [workspace_index_sync]; one-file parse + persist: [workspace_index_file]; mtime stale diff: [workspace_mtime]. Multi-base registry: one `WorkspaceIndex` per discovered ["../bases/base.rq".base] under [app_memory_doc.application_memory] ( `<base>/.reqlan/` ). Headless entry: [analysis_runtime] via native-only `openAnalysisApi` ( CLI / MCP ). On-disk store path: [application_memory_impl] under `<base>/.reqlan/` — see [app_memory_doc.application_memory]. | 0.237 | ||
| index_sequencing | done | Describe when the ideas index starts, updates, and idles, and which trigger owns each pass. Capability aliases live in [triggers] and [idea_index_triggers]. Detail ideas below; keep [nonblocking_index] and [indexing_incrementality] as the UX rules. Related: [consumers.index_consumers], [cache_reuse.index_cache_reuse], [ideas_schema.documents_table], [diagnostics_schema.sync_runs_table]. | 0.179 |
Reference labels
"../../../../packages/analytical/src/index-store/workspace-index.ts", "../../../packages/analytical/src/index-store/workspace-index.ts", "../../packages/analytical/src/index-store/workspace-index.ts", ../../../../packages/analytical/src/index-store/workspace-index.ts, ../../../packages/analytical/src/index-store/workspace-index.ts, ../../packages/analytical/src/index-store/workspace-index.ts, ../packages/analytical/src/index-store/workspace-index.ts