Skip to content

Commit 8d980be

Browse files
committed
v0.4.2: Modelbase alignment, IndexPipelineStates, alignment workflow
- Align indexer to behaviour IndexPipelineStates (pipeline-phases.ts, phase comments) - Add IMPLEMENTATION_PLAN.md, MODELBASE_ALIGNMENT.md; README links - Model-codebase alignment: check, alignment_status, sysmledgraph://alignment, registry indexedAt - README: re-index behaviour, future work, docs list Made-with: Cursor
1 parent 59f2671 commit 8d980be

17 files changed

Lines changed: 497 additions & 27 deletions

README.md

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,10 @@ Run from the project root (after `npm run build`) or via `npx sysmledgraph` if l
4343

4444
| Command | Description |
4545
|--------|-------------|
46-
| **analyze** `<paths...>` | Index one or more directory trees: discover `.sysml` and `.kerml`, parse via LSP, build the graph. Paths are resolved to absolute and stored in the registry. |
46+
| **analyze** `<paths...>` | Index one or more directory trees: discover `.sysml` and `.kerml`, parse via LSP, build the graph. Paths are resolved to absolute and stored in the registry (with last-indexed time for alignment). |
4747
| **list** | Print all indexed root paths (from the registry). |
4848
| **clean** `[path]` | Remove the index for a given path, or for **all** indexed paths if `path` is omitted. Deletes the DB file and registry entry. |
49+
| **check** | Check model–codebase alignment. Exits 0 if no `.sysml`/`.kerml` changes since last index; exits 1 and prints stale path(s) if the codebase no longer aligns with the index. Re-run **analyze** to refresh. |
4950

5051
**Examples:**
5152

@@ -64,14 +65,23 @@ npx sysmledgraph clean ./path/to/sysml-models
6465

6566
# Remove all indexed paths
6667
npx sysmledgraph clean
68+
69+
# Check if models align with index (prompts when files changed after last index)
70+
npx sysmledgraph check
6771
```
6872

73+
**Model–codebase alignment (model-based development):** When you change `.sysml` or `.kerml` files, the index can become out of date. Use **`check`** to see if any indexed path has file changes since last index; if so, the tool prompts you to re-run **analyze** so the graph stays aligned with the models. The MCP resource **sysmledgraph://context** and tool **alignment_status** report the same; the resource **sysmledgraph://alignment** gives a detailed alignment report.
74+
6975
**Options and environment:**
7076

7177
- **`--storage <path>`** — Override the storage root (default: `~/.sysmledgraph`). Same as env **`SYSMEDGRAPH_STORAGE_ROOT`**.
7278
- **`SYSMLLSP_SERVER_PATH`** — Optional. Path to the sysml-v2-lsp server JS (e.g. `dist/server/server.js`). If unset, the CLI looks in the current workspace/repo first (walk up from cwd), then in sysmledgraph’s `node_modules`.
7379

74-
**Storage layout:** Under the storage root: `registry.json` (list of indexed paths), and `db/<sanitized-path>.kuzu` (one Kuzu database per indexed path). On failure, the CLI writes errors to stderr and exits non-zero.
80+
**Storage layout:** Under the storage root: `registry.json` (list of indexed paths and last-indexed time per path), and `db/<sanitized-path>.kuzu` (one Kuzu database per indexed path). On failure, the CLI writes errors to stderr and exits non-zero.
81+
82+
**Re-index behaviour:** Running **analyze** (or **indexDbGraph**) again on an already-indexed path **merges** into the existing graph: nodes and edges are upserted by id (MERGE in Cypher). The graph is not cleared first. To start fresh for a path, run **clean** for that path, then **analyze** again.
83+
84+
**Future work (after v1):** detect_changes (Git diff → affected symbols) is not implemented. Multi-path: one DB per path; MCP tools currently use the first indexed path for read operations. See [docs/IMPLEMENTATION_PLAN.md](docs/IMPLEMENTATION_PLAN.md) for full plan traceability.
7585

7686
**Kuzu lock:** Only one process should open the same DB at a time. For a full CLI reindex, close Cursor (or disable the sysmledgraph MCP) first to avoid “Could not set lock on file”. See [docs/MCP-AND-KUZU.md](docs/MCP-AND-KUZU.md).
7787

@@ -125,11 +135,13 @@ Server name: **sysmledgraph**. The MCP server uses the same storage root as the
125135
| **context** | `name` (string) | Get one node by id or name and its adjacent edges (types and targets). |
126136
| **impact** | `target` (string), `direction` (`"upstream"` \| `"downstream"`, optional) | List nodes that depend on `target` (upstream) or that `target` depends on (downstream). |
127137
| **rename** | `symbol` (string), `newName` (string), `dry_run` (boolean, optional) | Preview or perform a rename of a symbol across the graph. |
138+
| **alignment_status** || Check model–codebase alignment. Returns whether the index is stale (files changed after last index) and prompts to re-run indexDbGraph or analyze. |
128139

129140
**Resources:**
130141

131-
- **sysmledgraph://context** — Index stats and list of indexed paths (Markdown).
142+
- **sysmledgraph://context** — Index stats, indexed paths, and alignment hint (Markdown).
132143
- **sysmledgraph://schema** — Graph node and edge schema (Markdown).
144+
- **sysmledgraph://alignment** — Model–codebase alignment report; prompts when index is stale (Markdown).
133145

134146
Tools that need a graph (cypher, query, context, impact) use the **first** entry in the registry as the target DB. Ensure at least one path is indexed (CLI or indexDbGraph) before calling them.
135147

@@ -148,15 +160,15 @@ For ad-hoc Cypher or exporting the graph without MCP:
148160

149161
The graph uses a single node table **Node**; always use the label in Cypher: `MATCH (n:Node) ...`.
150162

151-
- **Export graph for viewing:** Run `npm run export-graph` (writes `graph-export.json` in the current directory). Open `viewer/view.html` in a browser, click “Load graph.json”, and select that file for a force-directed view; click a node for details. Custom output path: `node scripts/export-graph.mjs path/to/out.json`.
163+
- **Export graph for viewing:** See **View the graph** below (Option A/B).
152164

153165
## Project layout
154166

155167
- `src/` — Core: indexer, graph, mcp, cli, discovery, parser, symbol-to-graph, storage.
156168
- `bin/cli.ts` — CLI entrypoint.
157169
- `mcp/index.ts` — MCP server entrypoint (stdio).
158170
- `test/` — Unit and integration tests.
159-
- `docs/`[INSTALL_NOTES.md](docs/INSTALL_NOTES.md) (slow install, Windows), [MCP-AND-KUZU.md](docs/MCP-AND-KUZU.md) (two MCPs, Kuzu lock, LSP path), [grammar-and-mapping.md](docs/grammar-and-mapping.md).
171+
- `docs/`[INSTALL_NOTES.md](docs/INSTALL_NOTES.md) (slow install, Windows), [MCP-AND-KUZU.md](docs/MCP-AND-KUZU.md) (two MCPs, Kuzu lock, LSP path), [grammar-and-mapping.md](docs/grammar-and-mapping.md), [IMPLEMENTATION_PLAN.md](docs/IMPLEMENTATION_PLAN.md) (plan step → implementation traceability), [MODELBASE_ALIGNMENT.md](docs/MODELBASE_ALIGNMENT.md) (codebase vs modelbase alignment).
160172

161173
## Development
162174

@@ -166,7 +178,26 @@ For ad-hoc Cypher or exporting the graph without MCP:
166178

167179
## View the graph
168180

169-
See **Usage → Querying the graph (scripts)** for the full flow. Short version: `npm run export-graph` writes `graph-export.json`; open `viewer/view.html` in a browser and load that file for a force-directed graph (click nodes for id/label/path).
181+
Open **`viewer/view.html`** in a browser, then load a `graph-export.json` file. The viewer shows a force-directed graph; click a node to see id, label, and path in the right panel.
182+
183+
### Option A: Minimal export (works with Cursor open)
184+
185+
If you already have a small `graph-export.json` (e.g. from a previous export), open `viewer/view.html`, click **"Load graph.json"**, and choose that file. The graph may be tiny (e.g. one indexed path with little content). To get the full graph, use Option B.
186+
187+
### Option B: Full export (DB must be free)
188+
189+
The export script opens the Kuzu DB, so it conflicts with the MCP. To avoid the lock:
190+
191+
1. **Close Cursor** (so the sysmledgraph MCP stops and releases the DB).
192+
2. In a terminal:
193+
```bash
194+
cd /path/to/sysmledgraph
195+
node scripts/export-graph.mjs graph-export.json
196+
```
197+
Or: `npm run export-graph` (writes `graph-export.json` in the current directory). Custom path: `node scripts/export-graph.mjs path/to/out.json`.
198+
3. Reopen Cursor, then open `viewer/view.html` in a browser and load the new `graph-export.json`.
199+
200+
The export includes all nodes and edges (up to the script’s limits) for the first indexed path. After indexing more projects, run the export again to refresh the graph.
170201

171202
## Schema (graph)
172203

bin/cli.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
cmdAnalyze,
1010
cmdList,
1111
cmdClean,
12+
cmdCheck,
1213
} from '../src/cli/commands.js';
1314

1415
program
@@ -56,4 +57,18 @@ program
5657
}
5758
});
5859

60+
program
61+
.command('check')
62+
.description('Check model–codebase alignment; exit non-zero if index is stale')
63+
.action(async () => {
64+
configureStorageRoot(program.opts().storage);
65+
const result = await cmdCheck();
66+
console.log(result.message);
67+
if (result.stalePaths.length > 0) {
68+
process.stderr.write('Stale path(s): ' + result.stalePaths.join(', ') + '\n');
69+
process.stderr.write('Re-run: sysmledgraph analyze <path> to refresh.\n');
70+
process.exit(1);
71+
}
72+
});
73+
5974
program.parse();

docs/IMPLEMENTATION_PLAN.md

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Implementation plan traceability
2+
3+
This document maps the **development plan** (source: `sysml-v2-models/projects/sysmledgraph/outputs/sysmledgraph-DEVELOPMENT_PLAN.md`) to the implementation in this repo. Requirements R1–R8 and the deploy/behaviour models are the source of truth.
4+
5+
**Behaviour model (index pipeline):** The modelbase defines **IndexPipelineStates** in `behaviour-sysmledgraph.sysml`: states *discovering**loadOrdering**parsing**mapping**writing**complete*, with events DiscoveryComplete, LoadOrderComplete, ParseComplete, MapComplete, WriteComplete. The indexer in `src/indexer/indexer.ts` is structured in the same order; `src/indexer/pipeline-phases.ts` exports the phase names for traceability.
6+
7+
---
8+
9+
## Phase 1 – Repo and pipeline
10+
11+
| Step | Plan | Implementation |
12+
|------|------|-----------------|
13+
| 1 | Create implementation location; layout per CODEBASE_STRUCTURE; Node/TS, dependencies (Kuzu, MCP SDK, commander, fast-glob); Node 20+; sysml-v2-lsp. | `package.json`, `tsconfig.json`, `.nvmrc`, `src/`, `bin/`, `mcp/`, `test/`, `schema/`, `docs/`. Dependencies: kuzu, @modelcontextprotocol/sdk, commander, fast-glob, sysml-v2-lsp (GitHub). |
14+
| 2 | Build and test (tsc + vitest); scripts build, test, optional analyze. | `npm run build` (tsc), `npm test` (vitest), `npm run analyze` (dist CLI). |
15+
| 3 | SysML parsing: sysml-v2-lsp as library or stdio client; documentSymbol/definition/references. | **stdio client**: `src/parser/lsp-client.ts` (spawn LSP, Content-Length framing, documentSymbol). `src/parser/symbols.ts`: getSymbolsForFile, flatten tree, IN_DOCUMENT/IN_PACKAGE. |
16+
| 4 | File discovery: .sysml (and .kerml); config.yaml model_files, model_dir. | `src/discovery/find-sysml.ts` (fast-glob). `src/discovery/load-order.ts`: config.yaml, model_files, model_dir. |
17+
| 5 | Verify parse; document symbol→graph mapping. | `src/symbol-to-graph/mapping.ts` (symbolKindToNodeLabel, relationToEdgeType). `docs/grammar-and-mapping.md`. |
18+
19+
---
20+
21+
## Phase 2 – Graph and index
22+
23+
| Step | Plan | Implementation |
24+
|------|------|-----------------|
25+
| 6 | Graph schema: node labels (Document, Package, PartDef, …), edge types (IN_DOCUMENT, IN_PACKAGE, …). | `src/graph/schema.ts`: NODE_TABLE, getSchemaDdl(), NODE_LABELS, EDGE_TYPES. Single Node table + one rel table per edge type. |
26+
| 7 | GraphStore: open/create Kuzu DB; addDocument(path, indexedAt?), addSymbol, addEdge, getConnection(); storage root + registry + DB per path. | `src/graph/graph-store.ts`: openGraphStore, getCachedOrOpenGraphStore, invalidateGraphStoreCache. `src/storage/location.ts`: getDbPathForIndexedPath (.kuzu). |
27+
| 8 | Indexer: discovery → load order → parse → map → write. Multiple roots; re-index behaviour documented. **R8:** on failure report, graph unchanged. | `src/indexer/indexer.ts`: pipeline phases (discovering → loadOrdering → parsing → mapping → writing) align with **SysmledgraphBehaviour::IndexPipelineStates** (modelbase `models/behaviour-sysmledgraph.sysml`). `src/indexer/pipeline-phases.ts`: phase names for traceability. findSysmlFiles, applyLoadOrder, getSymbolsForFile, addDocument/addSymbol/addEdge. Registry indexedAt. Re-index: merge (README). |
28+
| 9 | list (registry); clean (delete DB, update registry). **R8:** on failure report, graph unchanged. | `src/storage/list.ts`, `src/storage/clean.ts`, `src/storage/registry.ts`. clean_index invalidates cache before clean. |
29+
| 10 | Verify: index path, list, Cypher. | Integration test `test/integration/cli-and-graph.test.ts`; unit tests discovery, graph-store, load-order. |
30+
31+
---
32+
33+
## Phase 3 – MCP server
34+
35+
| Step | Plan | Implementation |
36+
|------|------|-----------------|
37+
| 11 | MCP server stdio; server name **sysmledgraph**. | `mcp/index.ts`, `src/mcp/server.ts`: McpServer, StdioServerTransport. |
38+
| 12 | Tools: indexDbGraph (path/paths), query (query, kind?), context (name), impact (target, direction?), rename (symbol, newName, dry_run?), cypher (query), list_indexed, clean_index (path?). **R8:** structured error in tool result. | `src/mcp/tools/*.ts`. All tools return ok/error; server sets isError on result. Plus **alignment_status** (model–codebase alignment). |
39+
| 13 | Resources: sysmledgraph://context (index stats, staleness), sysmledgraph://schema. Optional per-path. | `src/mcp/resources/context.ts`, `schema.ts`, **alignment.ts**. Resources: context, schema, alignment. (Per-path resource not implemented.) |
40+
| 14 | Verify: index from Cursor, query, context, impact, rename dry_run, schema resource. | Manual / smoke. |
41+
42+
---
43+
44+
## Phase 4 – CLI and docs
45+
46+
| Step | Plan | Implementation |
47+
|------|------|-----------------|
48+
| 15 | CLI: analyze (index path(s)), list, clean (path optional). **R8:** non-zero exit, stderr. | `bin/cli.ts`, `src/cli/commands.ts`: analyze, list, clean, **check** (alignment). |
49+
| 16 | README: install, usage, env/config, storage, schema summary, MCP setup. | README: Install, Usage (CLI, MCP, Querying, View the graph), alignment, Schema, docs links. |
50+
| 17 | Verify: CLI analyze/list/clean; docs match. | Tests; README and INSTALL_NOTES, MCP-AND-KUZU, grammar-and-mapping. |
51+
52+
---
53+
54+
## R8 (error reporting)
55+
56+
- **MCP:** Tool results include `ok: false` and `error`; server returns `isError: true` for failures.
57+
- **CLI:** On failure, stderr message and `process.exit(1)`.
58+
- **Index/Clean:** On failure, no partial commit; graph/registry unchanged. Indexer returns ok/error; addToRegistry only after success.
59+
60+
---
61+
62+
## Risks (plan) → mitigations (implementation)
63+
64+
- **Kuzu DB lock:** Per-process connection cache (getCachedOrOpenGraphStore); invalidate on index/clean. Document: close Cursor before full CLI re-index (MCP-AND-KUZU.md, README).
65+
- **LSP path:** Resolve LSP from SYSMLLSP_SERVER_PATH, then workspace/repo (walk up from cwd), then package node_modules.
66+
- **Load order:** config.yaml model_files, model_dir; else deterministic sort.
67+
68+
---
69+
70+
## After v1 (plan, optional)
71+
72+
- **detect_changes:** Not implemented (Git diff → affected symbols).
73+
- **Export:** Implemented: `scripts/export-graph.mjs`, `viewer/view.html`.
74+
- **Multi-path:** One DB per indexed path (not one merged graph); tools use first indexed path for cypher/query/context/impact.

0 commit comments

Comments
 (0)