ts-knowledge-graph 0.1.2 → 0.1.6
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.
- package/README.md +99 -41
- package/contribs/webview/README.md +83 -0
- package/contribs/webview/web/css/style.css +310 -0
- package/contribs/webview/web/index.html +109 -0
- package/contribs/webview/web/js/app.js +1249 -0
- package/contribs/webview/web/js_autogenerated/.gitignore +3 -0
- package/contribs/webview/web/js_autogenerated/kind_descriptions.js +39 -0
- package/contribs/webview/web/types/app_globals.d.ts +154 -0
- package/dist/benchmark/benchmark_stats.d.ts +41 -0
- package/dist/benchmark/benchmark_stats.d.ts.map +1 -0
- package/dist/benchmark/benchmark_stats.js +61 -0
- package/dist/benchmark/benchmark_stats.js.map +1 -0
- package/dist/benchmark/node_benchmark.d.ts +78 -0
- package/dist/benchmark/node_benchmark.d.ts.map +1 -0
- package/dist/benchmark/node_benchmark.js +112 -0
- package/dist/benchmark/node_benchmark.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +16 -4
- package/dist/cli.js.map +1 -1
- package/dist/cluster/cluster_weights.d.ts +20 -0
- package/dist/cluster/cluster_weights.d.ts.map +1 -0
- package/dist/cluster/cluster_weights.js +32 -0
- package/dist/cluster/cluster_weights.js.map +1 -0
- package/dist/cluster/community_detector.d.ts +61 -0
- package/dist/cluster/community_detector.d.ts.map +1 -0
- package/dist/cluster/community_detector.js +120 -0
- package/dist/cluster/community_detector.js.map +1 -0
- package/dist/cluster/community_labeler.d.ts +84 -0
- package/dist/cluster/community_labeler.d.ts.map +1 -0
- package/dist/cluster/community_labeler.js +194 -0
- package/dist/cluster/community_labeler.js.map +1 -0
- package/dist/cluster/graph_clusterer.d.ts +47 -0
- package/dist/cluster/graph_clusterer.d.ts.map +1 -0
- package/dist/cluster/graph_clusterer.js +126 -0
- package/dist/cluster/graph_clusterer.js.map +1 -0
- package/dist/commands/benchmark_command.d.ts +11 -0
- package/dist/commands/benchmark_command.d.ts.map +1 -0
- package/dist/commands/benchmark_command.js +94 -0
- package/dist/commands/benchmark_command.js.map +1 -0
- package/dist/commands/blast_radius_command.d.ts.map +1 -1
- package/dist/commands/blast_radius_command.js +7 -6
- package/dist/commands/blast_radius_command.js.map +1 -1
- package/dist/commands/cluster_command.d.ts +7 -0
- package/dist/commands/cluster_command.d.ts.map +1 -0
- package/dist/commands/cluster_command.js +55 -0
- package/dist/commands/cluster_command.js.map +1 -0
- package/dist/commands/command_helpers.d.ts +9 -4
- package/dist/commands/command_helpers.d.ts.map +1 -1
- package/dist/commands/command_helpers.js +13 -8
- package/dist/commands/command_helpers.js.map +1 -1
- package/dist/commands/cost_command.d.ts +13 -0
- package/dist/commands/cost_command.d.ts.map +1 -0
- package/dist/commands/cost_command.js +139 -0
- package/dist/commands/cost_command.js.map +1 -0
- package/dist/commands/{load.d.ts → enrich_command.d.ts} +3 -2
- package/dist/commands/enrich_command.d.ts.map +1 -0
- package/dist/commands/enrich_command.js +64 -0
- package/dist/commands/enrich_command.js.map +1 -0
- package/dist/commands/extract_command.d.ts.map +1 -1
- package/dist/commands/extract_command.js +12 -6
- package/dist/commands/extract_command.js.map +1 -1
- package/dist/commands/hotspots_command.d.ts +7 -0
- package/dist/commands/hotspots_command.d.ts.map +1 -0
- package/dist/commands/hotspots_command.js +68 -0
- package/dist/commands/hotspots_command.js.map +1 -0
- package/dist/commands/install_command.d.ts +15 -6
- package/dist/commands/install_command.d.ts.map +1 -1
- package/dist/commands/install_command.js +62 -25
- package/dist/commands/install_command.js.map +1 -1
- package/dist/commands/load_command.d.ts.map +1 -1
- package/dist/commands/load_command.js +20 -13
- package/dist/commands/load_command.js.map +1 -1
- package/dist/commands/neighbors_command.d.ts.map +1 -1
- package/dist/commands/neighbors_command.js +6 -5
- package/dist/commands/neighbors_command.js.map +1 -1
- package/dist/commands/references_command.d.ts.map +1 -1
- package/dist/commands/references_command.js +6 -5
- package/dist/commands/references_command.js.map +1 -1
- package/dist/commands/report_command.d.ts +16 -0
- package/dist/commands/report_command.d.ts.map +1 -0
- package/dist/commands/report_command.js +115 -0
- package/dist/commands/report_command.js.map +1 -0
- package/dist/commands/verify_command.d.ts +8 -0
- package/dist/commands/verify_command.d.ts.map +1 -0
- package/dist/commands/verify_command.js +57 -0
- package/dist/commands/verify_command.js.map +1 -0
- package/dist/commands/web_command.d.ts +27 -0
- package/dist/commands/web_command.d.ts.map +1 -1
- package/dist/commands/web_command.js +109 -3
- package/dist/commands/web_command.js.map +1 -1
- package/dist/commands/webview_command.d.ts +36 -0
- package/dist/commands/webview_command.d.ts.map +1 -0
- package/dist/commands/webview_command.js +186 -0
- package/dist/commands/webview_command.js.map +1 -0
- package/dist/enrich/cpu_profile.d.ts +160 -0
- package/dist/enrich/cpu_profile.d.ts.map +1 -0
- package/dist/enrich/cpu_profile.js +185 -0
- package/dist/enrich/cpu_profile.js.map +1 -0
- package/dist/enrich/runtime_enricher.d.ts +64 -0
- package/dist/enrich/runtime_enricher.d.ts.map +1 -0
- package/dist/enrich/runtime_enricher.js +98 -0
- package/dist/enrich/runtime_enricher.js.map +1 -0
- package/dist/enrich/runtime_join.d.ts +124 -0
- package/dist/enrich/runtime_join.d.ts.map +1 -0
- package/dist/enrich/runtime_join.js +270 -0
- package/dist/enrich/runtime_join.js.map +1 -0
- package/dist/extract/api_extractor.d.ts +24 -0
- package/dist/extract/api_extractor.d.ts.map +1 -0
- package/dist/extract/api_extractor.js +71 -0
- package/dist/extract/api_extractor.js.map +1 -0
- package/dist/extract/config_extractor.d.ts +22 -0
- package/dist/extract/config_extractor.d.ts.map +1 -0
- package/dist/extract/config_extractor.js +61 -0
- package/dist/extract/config_extractor.js.map +1 -0
- package/dist/extract/endpoint_extractor.d.ts +36 -0
- package/dist/extract/endpoint_extractor.d.ts.map +1 -0
- package/dist/extract/endpoint_extractor.js +117 -0
- package/dist/extract/endpoint_extractor.js.map +1 -0
- package/dist/extract/git_source.d.ts +23 -0
- package/dist/extract/git_source.d.ts.map +1 -0
- package/dist/extract/git_source.js +75 -0
- package/dist/extract/git_source.js.map +1 -0
- package/dist/extract/graph_builder.d.ts +8 -0
- package/dist/extract/graph_builder.d.ts.map +1 -1
- package/dist/extract/graph_builder.js +23 -1
- package/dist/extract/graph_builder.js.map +1 -1
- package/dist/extract/node_id.d.ts +16 -0
- package/dist/extract/node_id.d.ts.map +1 -1
- package/dist/extract/node_id.js +22 -0
- package/dist/extract/node_id.js.map +1 -1
- package/dist/extract/scope_resolver.d.ts +22 -0
- package/dist/extract/scope_resolver.d.ts.map +1 -0
- package/dist/extract/scope_resolver.js +53 -0
- package/dist/extract/scope_resolver.js.map +1 -0
- package/dist/extract/semantic_extractor.d.ts +25 -0
- package/dist/extract/semantic_extractor.d.ts.map +1 -1
- package/dist/extract/semantic_extractor.js +96 -2
- package/dist/extract/semantic_extractor.js.map +1 -1
- package/dist/extract/structural_extractor.d.ts +6 -0
- package/dist/extract/structural_extractor.d.ts.map +1 -1
- package/dist/extract/structural_extractor.js +22 -12
- package/dist/extract/structural_extractor.js.map +1 -1
- package/dist/project_root.d.ts +7 -0
- package/dist/project_root.d.ts.map +1 -0
- package/dist/project_root.js +9 -0
- package/dist/project_root.js.map +1 -0
- package/dist/query/graph_query.d.ts +269 -0
- package/dist/query/graph_query.d.ts.map +1 -1
- package/dist/query/graph_query.js +585 -11
- package/dist/query/graph_query.js.map +1 -1
- package/dist/report/graph_report.d.ts +51 -0
- package/dist/report/graph_report.d.ts.map +1 -0
- package/dist/report/graph_report.js +312 -0
- package/dist/report/graph_report.js.map +1 -0
- package/dist/report/pdf_renderer.d.ts +22 -0
- package/dist/report/pdf_renderer.d.ts.map +1 -0
- package/dist/report/pdf_renderer.js +54 -0
- package/dist/report/pdf_renderer.js.map +1 -0
- package/dist/report/report_data.d.ts +128 -0
- package/dist/report/report_data.d.ts.map +1 -0
- package/dist/report/report_data.js +191 -0
- package/dist/report/report_data.js.map +1 -0
- package/dist/schema/edge.d.ts +40 -5
- package/dist/schema/edge.d.ts.map +1 -1
- package/dist/schema/edge.js +73 -0
- package/dist/schema/edge.js.map +1 -1
- package/dist/schema/node.d.ts +20 -5
- package/dist/schema/node.d.ts.map +1 -1
- package/dist/schema/node.js +36 -0
- package/dist/schema/node.js.map +1 -1
- package/dist/schema/runtime_manifest.d.ts +36 -0
- package/dist/schema/runtime_manifest.d.ts.map +1 -0
- package/dist/schema/runtime_manifest.js +23 -0
- package/dist/schema/runtime_manifest.js.map +1 -0
- package/dist/schema/source_manifest.d.ts +30 -0
- package/dist/schema/source_manifest.d.ts.map +1 -0
- package/dist/schema/source_manifest.js +21 -0
- package/dist/schema/source_manifest.js.map +1 -0
- package/dist/store/jsonl_reader.d.ts +4 -0
- package/dist/store/jsonl_reader.d.ts.map +1 -1
- package/dist/store/jsonl_reader.js +13 -1
- package/dist/store/jsonl_reader.js.map +1 -1
- package/dist/store/jsonl_store.d.ts +2 -1
- package/dist/store/jsonl_store.d.ts.map +1 -1
- package/dist/store/jsonl_store.js +4 -1
- package/dist/store/jsonl_store.js.map +1 -1
- package/dist/store/kuzu_store.d.ts +59 -0
- package/dist/store/kuzu_store.d.ts.map +1 -1
- package/dist/store/kuzu_store.js +124 -5
- package/dist/store/kuzu_store.js.map +1 -1
- package/dist/store/output_folder.d.ts +43 -0
- package/dist/store/output_folder.d.ts.map +1 -0
- package/dist/store/output_folder.js +61 -0
- package/dist/store/output_folder.js.map +1 -0
- package/dist/verify/project_verifier.d.ts +85 -0
- package/dist/verify/project_verifier.d.ts.map +1 -0
- package/dist/verify/project_verifier.js +138 -0
- package/dist/verify/project_verifier.js.map +1 -0
- package/dotclaude_folder/commands/code-graph-interview.md +123 -0
- package/dotclaude_folder/commands/code-graph-optimize.md +65 -0
- package/{skills/ts-knowledge-graph → dotclaude_folder/skills/code-graph-query}/SKILL.md +6 -6
- package/package.json +99 -10
- package/.env-sample +0 -34
- package/contribs/web_visualisation/README.md +0 -55
- package/contribs/web_visualisation/web/css/style.css +0 -115
- package/contribs/web_visualisation/web/data/.gitignore +0 -2
- package/contribs/web_visualisation/web/index.html +0 -58
- package/contribs/web_visualisation/web/js/app.js +0 -364
- package/dist/agent/agent-tools.d.ts +0 -13
- package/dist/agent/agent-tools.d.ts.map +0 -1
- package/dist/agent/agent-tools.js +0 -153
- package/dist/agent/agent-tools.js.map +0 -1
- package/dist/agent/agent_tools.d.ts +0 -13
- package/dist/agent/agent_tools.d.ts.map +0 -1
- package/dist/agent/agent_tools.js +0 -153
- package/dist/agent/agent_tools.js.map +0 -1
- package/dist/agent/code-editor.d.ts +0 -18
- package/dist/agent/code-editor.d.ts.map +0 -1
- package/dist/agent/code-editor.js +0 -43
- package/dist/agent/code-editor.js.map +0 -1
- package/dist/agent/code_editor.d.ts +0 -18
- package/dist/agent/code_editor.d.ts.map +0 -1
- package/dist/agent/code_editor.js +0 -43
- package/dist/agent/code_editor.js.map +0 -1
- package/dist/agent/optimizer-agent.d.ts +0 -30
- package/dist/agent/optimizer-agent.d.ts.map +0 -1
- package/dist/agent/optimizer-agent.js +0 -97
- package/dist/agent/optimizer-agent.js.map +0 -1
- package/dist/agent/optimizer_agent.d.ts +0 -30
- package/dist/agent/optimizer_agent.d.ts.map +0 -1
- package/dist/agent/optimizer_agent.js +0 -97
- package/dist/agent/optimizer_agent.js.map +0 -1
- package/dist/agent/verifier.d.ts +0 -9
- package/dist/agent/verifier.d.ts.map +0 -1
- package/dist/agent/verifier.js +0 -19
- package/dist/agent/verifier.js.map +0 -1
- package/dist/commands/blast-radius.d.ts +0 -5
- package/dist/commands/blast-radius.d.ts.map +0 -1
- package/dist/commands/blast-radius.js +0 -18
- package/dist/commands/blast-radius.js.map +0 -1
- package/dist/commands/blast_radius.d.ts +0 -5
- package/dist/commands/blast_radius.d.ts.map +0 -1
- package/dist/commands/blast_radius.js +0 -18
- package/dist/commands/blast_radius.js.map +0 -1
- package/dist/commands/calls.d.ts +0 -5
- package/dist/commands/calls.d.ts.map +0 -1
- package/dist/commands/calls.js +0 -7
- package/dist/commands/calls.js.map +0 -1
- package/dist/commands/command-helpers.d.ts +0 -15
- package/dist/commands/command-helpers.d.ts.map +0 -1
- package/dist/commands/command-helpers.js +0 -61
- package/dist/commands/command-helpers.js.map +0 -1
- package/dist/commands/dead-exports.d.ts +0 -5
- package/dist/commands/dead-exports.d.ts.map +0 -1
- package/dist/commands/dead-exports.js +0 -7
- package/dist/commands/dead-exports.js.map +0 -1
- package/dist/commands/dead_exports.d.ts +0 -5
- package/dist/commands/dead_exports.d.ts.map +0 -1
- package/dist/commands/dead_exports.js +0 -7
- package/dist/commands/dead_exports.js.map +0 -1
- package/dist/commands/extract.d.ts +0 -8
- package/dist/commands/extract.d.ts.map +0 -1
- package/dist/commands/extract.js +0 -49
- package/dist/commands/extract.js.map +0 -1
- package/dist/commands/find.d.ts +0 -5
- package/dist/commands/find.d.ts.map +0 -1
- package/dist/commands/find.js +0 -7
- package/dist/commands/find.js.map +0 -1
- package/dist/commands/load.d.ts.map +0 -1
- package/dist/commands/load.js +0 -28
- package/dist/commands/load.js.map +0 -1
- package/dist/commands/neighbors.d.ts +0 -5
- package/dist/commands/neighbors.d.ts.map +0 -1
- package/dist/commands/neighbors.js +0 -17
- package/dist/commands/neighbors.js.map +0 -1
- package/dist/commands/optimize.d.ts +0 -6
- package/dist/commands/optimize.d.ts.map +0 -1
- package/dist/commands/optimize.js +0 -59
- package/dist/commands/optimize.js.map +0 -1
- package/dist/commands/optimize_command.d.ts +0 -6
- package/dist/commands/optimize_command.d.ts.map +0 -1
- package/dist/commands/optimize_command.js +0 -59
- package/dist/commands/optimize_command.js.map +0 -1
- package/dist/commands/references.d.ts +0 -5
- package/dist/commands/references.d.ts.map +0 -1
- package/dist/commands/references.js +0 -17
- package/dist/commands/references.js.map +0 -1
- package/dist/commands/web.d.ts +0 -19
- package/dist/commands/web.d.ts.map +0 -1
- package/dist/commands/web.js +0 -120
- package/dist/commands/web.js.map +0 -1
- package/dist/commands/who-calls.d.ts +0 -5
- package/dist/commands/who-calls.d.ts.map +0 -1
- package/dist/commands/who-calls.js +0 -7
- package/dist/commands/who-calls.js.map +0 -1
- package/dist/commands/who_calls.d.ts +0 -5
- package/dist/commands/who_calls.d.ts.map +0 -1
- package/dist/commands/who_calls.js +0 -7
- package/dist/commands/who_calls.js.map +0 -1
- package/dist/extract/graph-builder.d.ts +0 -16
- package/dist/extract/graph-builder.d.ts.map +0 -1
- package/dist/extract/graph-builder.js +0 -39
- package/dist/extract/graph-builder.js.map +0 -1
- package/dist/extract/node-id.d.ts +0 -8
- package/dist/extract/node-id.d.ts.map +0 -1
- package/dist/extract/node-id.js +0 -22
- package/dist/extract/node-id.js.map +0 -1
- package/dist/extract/project-loader.d.ts +0 -5
- package/dist/extract/project-loader.d.ts.map +0 -1
- package/dist/extract/project-loader.js +0 -19
- package/dist/extract/project-loader.js.map +0 -1
- package/dist/extract/semantic-extractor.d.ts +0 -22
- package/dist/extract/semantic-extractor.d.ts.map +0 -1
- package/dist/extract/semantic-extractor.js +0 -254
- package/dist/extract/semantic-extractor.js.map +0 -1
- package/dist/extract/structural-extractor.d.ts +0 -18
- package/dist/extract/structural-extractor.d.ts.map +0 -1
- package/dist/extract/structural-extractor.js +0 -97
- package/dist/extract/structural-extractor.js.map +0 -1
- package/dist/query/graph-query.d.ts +0 -28
- package/dist/query/graph-query.d.ts.map +0 -1
- package/dist/query/graph-query.js +0 -93
- package/dist/query/graph-query.js.map +0 -1
- package/dist/store/jsonl-reader.d.ts +0 -11
- package/dist/store/jsonl-reader.d.ts.map +0 -1
- package/dist/store/jsonl-reader.js +0 -19
- package/dist/store/jsonl-reader.js.map +0 -1
- package/dist/store/jsonl-store.d.ts +0 -7
- package/dist/store/jsonl-store.d.ts.map +0 -1
- package/dist/store/jsonl-store.js +0 -13
- package/dist/store/jsonl-store.js.map +0 -1
- package/dist/store/kuzu-store.d.ts +0 -14
- package/dist/store/kuzu-store.d.ts.map +0 -1
- package/dist/store/kuzu-store.js +0 -52
- package/dist/store/kuzu-store.js.map +0 -1
package/README.md
CHANGED
|
@@ -25,7 +25,9 @@ Compiler API) rather than a syntax-only parser.
|
|
|
25
25
|
## Graph model
|
|
26
26
|
|
|
27
27
|
**Nodes** — `Module`, `Class`, `Interface`, `TypeAlias`, `Enum`, `Function`,
|
|
28
|
-
`Method`, `Property`, `Parameter`, `Variable`, `ExternalModule
|
|
28
|
+
`Method`, `Property`, `Parameter`, `Variable`, `ExternalModule`, and the
|
|
29
|
+
system-level `ConfigFlag` (environment variables), `ExternalAPI` (outbound HTTP
|
|
30
|
+
hosts), and `Endpoint` (HTTP routes).
|
|
29
31
|
|
|
30
32
|
**Edges**
|
|
31
33
|
|
|
@@ -34,9 +36,22 @@ Compiler API) rather than a syntax-only parser.
|
|
|
34
36
|
| Structural | `CONTAINS`, `IMPORTS`, `EXPORTS` |
|
|
35
37
|
| Type | `EXTENDS`, `IMPLEMENTS`, `USES_TYPE`, `RETURNS`, `PARAM_TYPE` |
|
|
36
38
|
| Behavioral | `CALLS`, `INSTANTIATES`, `OVERRIDES`, `READS`, `WRITES` |
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
| System-level | `READS_CONFIG`, `CALLS_EXTERNAL`, `HANDLES` |
|
|
40
|
+
| Runtime | `CALLS_RUNTIME` |
|
|
41
|
+
|
|
42
|
+
The structural layer — plus the always-on config and outbound-HTTP surfaces
|
|
43
|
+
(`ConfigFlag` / `READS_CONFIG`, `ExternalAPI` / `CALLS_EXTERNAL`) — is cheap and
|
|
44
|
+
needs no symbol resolution. The type, behavioral, and endpoint (`Endpoint` /
|
|
45
|
+
`HANDLES`) layers require symbol resolution and are emitted with `--semantic`. The
|
|
46
|
+
runtime layer (`CALLS_RUNTIME`) is reconstructed from a CPU profile's call tree by
|
|
47
|
+
[`enrich`](docs/commands/enrich.md), not parsed from source — the calls that
|
|
48
|
+
actually fired, dynamic dispatch included.
|
|
49
|
+
|
|
50
|
+
`ConfigFlag` nodes come from `process.env.X` reads; `ExternalAPI` nodes from
|
|
51
|
+
`fetch(...)` call sites (one per host); `Endpoint` nodes from route registrations
|
|
52
|
+
like `app.get('/users', handler)`, each with a `HANDLES` edge to the handler
|
|
53
|
+
function. These are the system-level kinds tracked in
|
|
54
|
+
[#31](https://github.com/jeromeetienne/ts_knowledge_graph/issues/31).
|
|
40
55
|
|
|
41
56
|
## Usage
|
|
42
57
|
|
|
@@ -50,9 +65,9 @@ npm run extract -- <path-to-project>
|
|
|
50
65
|
npm run extract -- <path-to-project> --semantic
|
|
51
66
|
```
|
|
52
67
|
|
|
53
|
-
Output is two JSONL files —
|
|
54
|
-
|
|
55
|
-
to inspect, diff, and load into any store.
|
|
68
|
+
Output is two JSONL files — `.ts_knowledge_graph/graph/nodes.jsonl` and
|
|
69
|
+
`.ts_knowledge_graph/graph/edges.jsonl` (override the base folder with `-o, --output-folder`)
|
|
70
|
+
— one record per line, easy to inspect, diff, and load into any store.
|
|
56
71
|
|
|
57
72
|
### Querying the graph
|
|
58
73
|
|
|
@@ -60,7 +75,7 @@ Load the JSONL into an embedded [Kùzu](https://kuzudb.com) database, then run t
|
|
|
60
75
|
query tools:
|
|
61
76
|
|
|
62
77
|
```bash
|
|
63
|
-
npm run dev -- load # reads
|
|
78
|
+
npm run dev -- load # reads ./.ts_knowledge_graph/graph, writes ./.ts_knowledge_graph/graph.kuzu
|
|
64
79
|
|
|
65
80
|
npm run dev -- find <name> # resolve a name to node ids
|
|
66
81
|
npm run dev -- who-calls <id> # direct callers of a symbol
|
|
@@ -69,6 +84,10 @@ npm run dev -- blast-radius <id> --depth 10 # transitive callers (impact set)
|
|
|
69
84
|
npm run dev -- references <id> # everything that references a symbol/type
|
|
70
85
|
npm run dev -- dead-exports # exported symbols with no inbound refs
|
|
71
86
|
npm run dev -- neighbors <id> # one-hop neighbourhood (in + out)
|
|
87
|
+
npm run dev -- hotspots --by self-time # rank nodes by optimization leverage
|
|
88
|
+
npm run dev -- cost # inclusive cost + share-of-total (causal)
|
|
89
|
+
npm run dev -- cost <id> # where one node's cost goes / who causes it
|
|
90
|
+
npm run dev -- cluster # detect code communities (Leiden) -> metadata.community
|
|
72
91
|
```
|
|
73
92
|
|
|
74
93
|
Every query command accepts `--json` to emit machine-readable output — this is
|
|
@@ -76,8 +95,8 @@ the shape the optimization agent consumes. Node ids come from `find` or another
|
|
|
76
95
|
query's results; do not hand-write them.
|
|
77
96
|
|
|
78
97
|
The query methods on `GraphQuery` (`whoCalls`, `blastRadius`, `deadExports`,
|
|
79
|
-
`neighborhood`, …) are designed to
|
|
80
|
-
JSON out.
|
|
98
|
+
`hotspots`, `costRanking`, `costAttribution`, `neighborhood`, …) are designed to
|
|
99
|
+
map one-to-one onto agent tools: JSON in, JSON out.
|
|
81
100
|
|
|
82
101
|
For a task-oriented walk-through of these commands — using them by hand to
|
|
83
102
|
answer impact, dead-code, and dependency questions — see the
|
|
@@ -93,36 +112,55 @@ answer impact, dead-code, and dependency questions — see the
|
|
|
93
112
|
|
|
94
113
|
Serve the database as an interactive graph — pan/zoom, kind filters, symbol
|
|
95
114
|
search, per-node edge listing (see
|
|
96
|
-
[contribs/
|
|
115
|
+
[contribs/webview](contribs/webview)):
|
|
97
116
|
|
|
98
117
|
```bash
|
|
99
|
-
npm run
|
|
100
|
-
npm run
|
|
118
|
+
npm run webview # reads ./.ts_knowledge_graph/graph.kuzu, serves http://localhost:4173
|
|
119
|
+
npm run webview -- -o ./.ts_knowledge_graph --port 8080
|
|
101
120
|
```
|
|
102
121
|
|
|
103
122
|
### The optimization agent
|
|
104
123
|
|
|
105
124
|
The end goal: an agent that uses the graph to find and apply optimizations,
|
|
106
|
-
verifying each one before keeping it.
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
125
|
+
verifying each one before keeping it. It ships as a [Claude Code](https://claude.com/claude-code)
|
|
126
|
+
slash command, `/code-graph-optimize`, defined in
|
|
127
|
+
[`dotclaude_folder/commands/code-graph-optimize.md`](dotclaude_folder/commands/code-graph-optimize.md)
|
|
128
|
+
— so the agent runtime is your Claude Code subscription, with no API key or
|
|
129
|
+
provider configuration to set up.
|
|
130
|
+
|
|
131
|
+
```text
|
|
132
|
+
/code-graph-optimize
|
|
133
|
+
/code-graph-optimize Inline the single-use helper X
|
|
112
134
|
```
|
|
113
135
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
136
|
+
With no argument the command runs its default mission: find one genuinely dead
|
|
137
|
+
exported symbol, confirm it has zero inbound references, and remove it safely.
|
|
138
|
+
|
|
139
|
+
The command drives a find → confirm → edit → verify loop. It queries the graph
|
|
140
|
+
through this CLI (`dead-exports`, `references`, `who-calls`, `blast-radius`) to
|
|
141
|
+
gather context and confirm blast radius, makes exactly one edit, then runs
|
|
142
|
+
[`ts-knowledge-graph verify`](docs/commands/verify.md) — the type-check **and**
|
|
143
|
+
the test suite as a single gate. **If verify passes the edit stands; if it fails
|
|
144
|
+
the edit is reverted with `git restore`** and the change is abandoned or retried.
|
|
145
|
+
On a project with no test script verify degrades to type-check-only and the agent
|
|
146
|
+
says so, rather than implying the change was behaviourally verified. Run it on a
|
|
147
|
+
clean git tree so you can review (and `git checkout`) what it kept.
|
|
148
|
+
|
|
149
|
+
A companion command, `/code-graph-interview`
|
|
150
|
+
([`code-graph-interview.md`](dotclaude_folder/commands/code-graph-interview.md)),
|
|
151
|
+
is read-only: it interviews you to scope a measurable optimization target and
|
|
152
|
+
grounds each candidate in the graph, producing tasks you can then hand to
|
|
153
|
+
`/code-graph-optimize`. Both commands, plus the `code-graph-query` skill, live
|
|
154
|
+
under [`dotclaude_folder/`](dotclaude_folder) and are mirrored into `.claude/`.
|
|
155
|
+
|
|
156
|
+
To install all of them into another project, run
|
|
157
|
+
[`install`](docs/commands/install.md) from that project — it copies every
|
|
158
|
+
bundled command and skill into the project's `.claude/` directory:
|
|
118
159
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
the compiler errors back for another attempt. Edits are unique-match
|
|
124
|
-
find/replace with in-memory backups; run on a clean git tree so you can review
|
|
125
|
-
(and `git checkout`) what it kept.
|
|
160
|
+
```bash
|
|
161
|
+
npx ts-knowledge-graph install # into ./.claude
|
|
162
|
+
npx ts-knowledge-graph install --force # overwrite previously installed copies
|
|
163
|
+
```
|
|
126
164
|
|
|
127
165
|
## Architecture
|
|
128
166
|
|
|
@@ -141,14 +179,15 @@ src/
|
|
|
141
179
|
kuzu_store.ts load the graph into embedded Kùzu, run Cypher
|
|
142
180
|
query/
|
|
143
181
|
graph_query.ts the agent's query tools (who-calls, blast-radius…)
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
code_editor.ts unique-match find/replace with in-memory backup + revert
|
|
147
|
-
verifier.ts runs `tsc --noEmit`, returns pass/fail + output
|
|
148
|
-
optimizer_agent.ts the LLM tool-calling loop (propose → verify → keep/revert)
|
|
149
|
-
cli.ts extract / load / query / optimize commands
|
|
182
|
+
commands/ one file per CLI command (extract, load, query, web, install)
|
|
183
|
+
cli.ts wires the commands into the ts-knowledge-graph CLI
|
|
150
184
|
```
|
|
151
185
|
|
|
186
|
+
The optimization agent is not part of this `src/` tree — it is the
|
|
187
|
+
`/code-graph-optimize` Claude Code command under
|
|
188
|
+
[`dotclaude_folder/commands/`](dotclaude_folder/commands), which drives the same
|
|
189
|
+
queries through the CLI.
|
|
190
|
+
|
|
152
191
|
Node ids are derived purely from the declaration (`kind:relPath#name@line`), so
|
|
153
192
|
any extractor computes the same id for the same symbol without a shared
|
|
154
193
|
registry — that is what lets the semantic layer link a call site to the exact
|
|
@@ -165,10 +204,29 @@ declaration node the structural layer emitted.
|
|
|
165
204
|
contained member is referenced.
|
|
166
205
|
- [x] **Value-reference (`READS`) edges** — value-identifier usage, so exported
|
|
167
206
|
`const`s (e.g. schemas) are no longer false-positive dead exports.
|
|
168
|
-
- [x] **
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
- [
|
|
172
|
-
|
|
207
|
+
- [x] **Runtime enrichment** — the [`enrich`](docs/commands/enrich.md) command
|
|
208
|
+
ingests a V8 CPU profile and attaches measured self time / sample count onto
|
|
209
|
+
nodes as `metadata.runtime`, joining frames to nodes by enclosing range.
|
|
210
|
+
- [x] **Hotspot / leverage ranking** — the [`hotspots`](docs/commands/hotspots.md)
|
|
211
|
+
command ranks nodes by optimization value (runtime self-time, fan-in,
|
|
212
|
+
call-count, or transitive blast radius), defaulting to measured self time when
|
|
213
|
+
enriched and degrading gracefully to static fan-in when not.
|
|
214
|
+
- [x] **Optimization agent** — the `/code-graph-optimize` Claude Code command,
|
|
215
|
+
which proposes one edit and keeps it only if [`verify`](docs/commands/verify.md)
|
|
216
|
+
(type-check **and** tests) passes (otherwise reverts with `git restore`).
|
|
217
|
+
- [x] **Test verification** — the [`verify`](docs/commands/verify.md) command runs
|
|
218
|
+
the project's `typecheck` and `test` scripts as one keep/revert gate, so
|
|
219
|
+
behavior-changing edits are caught, not just type errors. A project with no test
|
|
220
|
+
script degrades to type-check-only, reported honestly (`behaviorVerified: false`).
|
|
221
|
+
- [x] **Benchmark verification** — the [`benchmark`](docs/commands/benchmark.md)
|
|
222
|
+
command measures a target node's runtime metric (profile → enrich → cost) over
|
|
223
|
+
N runs and reports the median + spread, with an advisory baseline→after delta —
|
|
224
|
+
so an optimization is reported by its *measured* impact (e.g. −57% self-time on
|
|
225
|
+
`titleCase`) rather than a guess. Advisory by design, distinct from the hard
|
|
226
|
+
`verify` gate.
|
|
227
|
+
- [x] **Community detection** — the [`cluster`](docs/commands/cluster.md) command
|
|
228
|
+
runs the Leiden algorithm (CPM) over the weighted coupling graph and attaches a
|
|
229
|
+
module index onto nodes as `metadata.community`, with the internal-connectedness
|
|
230
|
+
guarantee Louvain lacks.
|
|
173
231
|
- [ ] **Vector index** — embed per-node summaries for hybrid graph + semantic
|
|
174
232
|
retrieval, so the agent can find candidates by meaning, not just by name.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# WebView
|
|
2
|
+
|
|
3
|
+
Interactive viewer for the knowledge graph — pan/zoom, color-coded node and
|
|
4
|
+
edge kinds with toggleable filters, symbol search, and a per-node detail panel
|
|
5
|
+
showing every incoming/outgoing edge.
|
|
6
|
+
|
|
7
|
+
**No server required.** The page (in [web/](web)) is fully static; only the
|
|
8
|
+
Cytoscape.js library comes from a CDN (so you need internet, or vendor the
|
|
9
|
+
file).
|
|
10
|
+
|
|
11
|
+
## Commands
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm run build # embed ../../.ts_knowledge_graph/graph/*.jsonl into web/js_autogenerated/graph_data.js
|
|
15
|
+
npm start # serve web/ on http://localhost:4173 (optional)
|
|
16
|
+
npm run open # open web/index.html directly (file://, macOS)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Loading data — pick one
|
|
20
|
+
|
|
21
|
+
**A. Embed the data, then open the page** (works from `file://`, no server):
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# from the repo root, after `npm run extract -- . --semantic`
|
|
25
|
+
cd contribs/webview
|
|
26
|
+
npm run build
|
|
27
|
+
npm run open
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`scripts/build-data.ts` reads `../../.ts_knowledge_graph/graph/{nodes,edges}.jsonl` by
|
|
31
|
+
default; pass a different graph directory as the first argument
|
|
32
|
+
(`npx tsx scripts/build-data.ts /path/to/graph`).
|
|
33
|
+
|
|
34
|
+
**B. Drag & drop** — open `web/index.html` any way at all and drop
|
|
35
|
+
`.ts_knowledge_graph/graph/nodes.jsonl` + `.ts_knowledge_graph/graph/edges.jsonl` onto the page.
|
|
36
|
+
|
|
37
|
+
**C. Serve the repo root** — the page then auto-fetches
|
|
38
|
+
`../../../.ts_knowledge_graph/graph/*.jsonl`:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# from the repo root
|
|
42
|
+
npx serve # or: python3 -m http.server
|
|
43
|
+
# open http://localhost:3000/contribs/webview/web/
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Reading the graph
|
|
47
|
+
|
|
48
|
+
- **Node size** scales with degree (how connected a symbol is).
|
|
49
|
+
- **Edge colors**: red `CALLS`, green/teal type edges (`USES_TYPE`, `RETURNS`,
|
|
50
|
+
`PARAM_TYPE`), yellow `READS`, violet heritage, gray structure
|
|
51
|
+
(`CONTAINS`, `IMPORTS`).
|
|
52
|
+
- **Edge width** scales with call-site count — how many times the call / import /
|
|
53
|
+
read occurs between the two symbols (shown as `×N` in the detail panel). Thick
|
|
54
|
+
edges are the hot connections.
|
|
55
|
+
- Uncheck noisy kinds (`CONTAINS`, `IMPORTS`) to see the behavioral core;
|
|
56
|
+
enable **hide isolated nodes** to drop whatever the filter disconnected.
|
|
57
|
+
- The **all** checkbox atop Node kinds / Edge kinds toggles every kind at once —
|
|
58
|
+
hide all, then re-check just the few you want to isolate (it shows a dash when
|
|
59
|
+
only some kinds are visible).
|
|
60
|
+
- Click a node to fade everything outside its neighborhood and list its edges
|
|
61
|
+
in the sidebar — the links navigate the graph.
|
|
62
|
+
- **Fold any sidebar section** by clicking its header (Runtime, Hotspots, Node
|
|
63
|
+
kinds, Edge kinds, …); the collapsed state is remembered across reloads.
|
|
64
|
+
|
|
65
|
+
## Runtime hotspots
|
|
66
|
+
|
|
67
|
+
When the graph has been enriched (`ts-knowledge-graph enrich <profile.cpuprofile>`),
|
|
68
|
+
each measured symbol carries `metadata.runtime` (self-time + sample count). The
|
|
69
|
+
sidebar's **Runtime** panel surfaces it:
|
|
70
|
+
|
|
71
|
+
- **Coverage line** — how many nodes were measured and the total self-time, so a
|
|
72
|
+
partial profile reads as partial.
|
|
73
|
+
- **Heat map toggle** — re-encodes the graph by measured self-time: nodes are
|
|
74
|
+
**sized and heat-coloured** (cool → yellow → red) by how hot they are, instead
|
|
75
|
+
of by kind/degree. Toggle off to return to the structural view.
|
|
76
|
+
- **Hotspots list** — the top symbols ranked by self-time; click one to focus it.
|
|
77
|
+
- **Only measured nodes** — hides the un-enriched nodes so only the measured
|
|
78
|
+
subgraph remains, to focus on where the cost actually is.
|
|
79
|
+
- Selecting any node adds a **runtime** block (self-time, samples, source) to the
|
|
80
|
+
detail panel.
|
|
81
|
+
|
|
82
|
+
Un-measured nodes render at a neutral, dashed baseline — "no metric" means
|
|
83
|
+
*inlined or not sampled*, not "free".
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
/* Dark theme (default). Every colour is a variable so a single `data-theme`
|
|
2
|
+
attribute on <html> repaints the whole viewer; see [data-theme="light"] below
|
|
3
|
+
and the matching graph-canvas variables read by js/app.js (cyStyle). */
|
|
4
|
+
:root {
|
|
5
|
+
color-scheme: dark;
|
|
6
|
+
--bg: #0f172a;
|
|
7
|
+
--surface: #111c33;
|
|
8
|
+
--surface-raised: #1e293b;
|
|
9
|
+
--surface-hover: #334155;
|
|
10
|
+
--border: #1e293b;
|
|
11
|
+
--border-control: #334155;
|
|
12
|
+
--border-subtle: #475569;
|
|
13
|
+
--input-bg: #0f172a;
|
|
14
|
+
--text: #cbd5e1;
|
|
15
|
+
--heading: #f1f5f9;
|
|
16
|
+
--muted: #64748b;
|
|
17
|
+
--muted-strong: #94a3b8;
|
|
18
|
+
--text-on-control: #e2e8f0;
|
|
19
|
+
--accent: #4f8cff;
|
|
20
|
+
--link: #7db2ff;
|
|
21
|
+
--tooltip-bg: #0b1424;
|
|
22
|
+
--tooltip-text: #e2e8f0;
|
|
23
|
+
--overlay-bg: rgba(15, 23, 42, .85);
|
|
24
|
+
--shadow: 0 4px 14px rgba(0, 0, 0, .45);
|
|
25
|
+
--on-swatch: #0f172a;
|
|
26
|
+
--num: #f59e0b;
|
|
27
|
+
--unmeasured-fill: #243044;
|
|
28
|
+
--unmeasured-border: #475569;
|
|
29
|
+
/* Graph canvas colours, read from JS so the graph tracks the theme. */
|
|
30
|
+
--graph-label: #cbd5e1;
|
|
31
|
+
--graph-label-bg: #0f172a;
|
|
32
|
+
--graph-sel-border: #ffffff;
|
|
33
|
+
--graph-node-border: #334155;
|
|
34
|
+
--graph-node-border-width: 0;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
[data-theme="light"] {
|
|
38
|
+
color-scheme: light;
|
|
39
|
+
--bg: #f8fafc;
|
|
40
|
+
--surface: #f1f5f9;
|
|
41
|
+
--surface-raised: #e2e8f0;
|
|
42
|
+
--surface-hover: #cbd5e1;
|
|
43
|
+
--border: #e2e8f0;
|
|
44
|
+
--border-control: #cbd5e1;
|
|
45
|
+
--border-subtle: #94a3b8;
|
|
46
|
+
--input-bg: #ffffff;
|
|
47
|
+
--text: #334155;
|
|
48
|
+
--heading: #0f172a;
|
|
49
|
+
--muted: #64748b;
|
|
50
|
+
--muted-strong: #475569;
|
|
51
|
+
--text-on-control: #1e293b;
|
|
52
|
+
--accent: #2563eb;
|
|
53
|
+
--link: #2563eb;
|
|
54
|
+
--tooltip-bg: #ffffff;
|
|
55
|
+
--tooltip-text: #1e293b;
|
|
56
|
+
--overlay-bg: rgba(226, 232, 240, .85);
|
|
57
|
+
--shadow: 0 4px 14px rgba(15, 23, 42, .18);
|
|
58
|
+
--on-swatch: #0f172a;
|
|
59
|
+
--num: #b45309;
|
|
60
|
+
--unmeasured-fill: #e2e8f0;
|
|
61
|
+
--unmeasured-border: #94a3b8;
|
|
62
|
+
--graph-label: #334155;
|
|
63
|
+
--graph-label-bg: #f8fafc;
|
|
64
|
+
--graph-sel-border: #0f172a;
|
|
65
|
+
--graph-node-border: #cbd5e1;
|
|
66
|
+
--graph-node-border-width: 1;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
* { box-sizing: border-box; }
|
|
70
|
+
|
|
71
|
+
html, body {
|
|
72
|
+
margin: 0;
|
|
73
|
+
height: 100%;
|
|
74
|
+
font: 13px/1.45 -apple-system, 'Segoe UI', Roboto, sans-serif;
|
|
75
|
+
background: var(--bg);
|
|
76
|
+
color: var(--text);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
body { display: flex; }
|
|
80
|
+
|
|
81
|
+
#sidebar {
|
|
82
|
+
width: 300px;
|
|
83
|
+
flex: none;
|
|
84
|
+
height: 100%;
|
|
85
|
+
overflow-y: auto;
|
|
86
|
+
padding: 14px;
|
|
87
|
+
background: var(--surface);
|
|
88
|
+
border-right: 1px solid var(--border);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.sidebar-head { display: flex; align-items: center; gap: 8px; margin: 0 0 4px; }
|
|
92
|
+
#sidebar h1 { font-size: 15px; margin: 0; flex: 1; color: var(--heading); }
|
|
93
|
+
#sidebar h2 { font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); margin: 16px 0 6px; }
|
|
94
|
+
#sidebar section { margin-top: 8px; }
|
|
95
|
+
|
|
96
|
+
.theme-toggle {
|
|
97
|
+
flex: none;
|
|
98
|
+
width: 26px;
|
|
99
|
+
height: 26px;
|
|
100
|
+
padding: 0;
|
|
101
|
+
display: inline-flex;
|
|
102
|
+
align-items: center;
|
|
103
|
+
justify-content: center;
|
|
104
|
+
font-size: 14px;
|
|
105
|
+
line-height: 1;
|
|
106
|
+
border-radius: 6px;
|
|
107
|
+
background: var(--surface-raised);
|
|
108
|
+
color: var(--text-on-control);
|
|
109
|
+
border: 1px solid var(--border-control);
|
|
110
|
+
cursor: pointer;
|
|
111
|
+
}
|
|
112
|
+
.theme-toggle:hover { background: var(--surface-hover); }
|
|
113
|
+
|
|
114
|
+
#sidebar .foldable {
|
|
115
|
+
display: flex;
|
|
116
|
+
align-items: center;
|
|
117
|
+
gap: 7px;
|
|
118
|
+
line-height: 1;
|
|
119
|
+
cursor: pointer;
|
|
120
|
+
user-select: none;
|
|
121
|
+
}
|
|
122
|
+
#sidebar .foldable:hover { color: var(--muted-strong); }
|
|
123
|
+
#sidebar .foldable::before {
|
|
124
|
+
content: '';
|
|
125
|
+
flex: none;
|
|
126
|
+
width: 0;
|
|
127
|
+
height: 0;
|
|
128
|
+
border-left: 5px solid currentColor;
|
|
129
|
+
border-top: 4px solid transparent;
|
|
130
|
+
border-bottom: 4px solid transparent;
|
|
131
|
+
transition: transform .12s ease;
|
|
132
|
+
}
|
|
133
|
+
#sidebar .foldable:not(.collapsed)::before { transform: rotate(90deg); }
|
|
134
|
+
#sidebar .foldable.collapsed ~ * { display: none; }
|
|
135
|
+
|
|
136
|
+
#status { font-size: 11px; color: var(--muted); margin-bottom: 10px; }
|
|
137
|
+
|
|
138
|
+
#search {
|
|
139
|
+
width: 100%;
|
|
140
|
+
padding: 6px 8px;
|
|
141
|
+
border: 1px solid var(--border-control);
|
|
142
|
+
border-radius: 6px;
|
|
143
|
+
background: var(--input-bg);
|
|
144
|
+
color: var(--text-on-control);
|
|
145
|
+
}
|
|
146
|
+
#search:focus { outline: none; border-color: var(--accent); }
|
|
147
|
+
|
|
148
|
+
#search-results { margin-top: 4px; }
|
|
149
|
+
#search-results .hit {
|
|
150
|
+
padding: 3px 6px;
|
|
151
|
+
border-radius: 4px;
|
|
152
|
+
cursor: pointer;
|
|
153
|
+
font-size: 12px;
|
|
154
|
+
white-space: nowrap;
|
|
155
|
+
overflow: hidden;
|
|
156
|
+
text-overflow: ellipsis;
|
|
157
|
+
}
|
|
158
|
+
#search-results .hit:hover { background: var(--surface-raised); }
|
|
159
|
+
#search-results .hit .loc { color: var(--muted); font-size: 10px; }
|
|
160
|
+
|
|
161
|
+
.legend label {
|
|
162
|
+
display: flex;
|
|
163
|
+
align-items: center;
|
|
164
|
+
gap: 6px;
|
|
165
|
+
padding: 1px 0;
|
|
166
|
+
cursor: pointer;
|
|
167
|
+
user-select: none;
|
|
168
|
+
}
|
|
169
|
+
.legend .swatch {
|
|
170
|
+
width: 10px;
|
|
171
|
+
height: 10px;
|
|
172
|
+
border-radius: 3px;
|
|
173
|
+
flex: none;
|
|
174
|
+
}
|
|
175
|
+
.legend .count { margin-left: auto; color: var(--muted); font-size: 11px; }
|
|
176
|
+
.legend .help-badge {
|
|
177
|
+
flex: none;
|
|
178
|
+
width: 13px;
|
|
179
|
+
height: 13px;
|
|
180
|
+
border-radius: 50%;
|
|
181
|
+
border: 1px solid var(--border-subtle);
|
|
182
|
+
color: var(--muted-strong);
|
|
183
|
+
font-size: 9px;
|
|
184
|
+
font-weight: 600;
|
|
185
|
+
line-height: 11px;
|
|
186
|
+
text-align: center;
|
|
187
|
+
user-select: none;
|
|
188
|
+
opacity: 0.5;
|
|
189
|
+
}
|
|
190
|
+
.legend .help-badge:hover,
|
|
191
|
+
.legend .help-badge:focus {
|
|
192
|
+
background: var(--surface-hover);
|
|
193
|
+
color: var(--text-on-control);
|
|
194
|
+
border-color: var(--muted);
|
|
195
|
+
outline: none;
|
|
196
|
+
}
|
|
197
|
+
.legend label.master {
|
|
198
|
+
margin-bottom: 4px;
|
|
199
|
+
padding-bottom: 4px;
|
|
200
|
+
border-bottom: 1px solid var(--border);
|
|
201
|
+
color: var(--muted-strong);
|
|
202
|
+
}
|
|
203
|
+
.legend .swatch.spacer { background: transparent; }
|
|
204
|
+
|
|
205
|
+
.kind-tooltip {
|
|
206
|
+
position: fixed;
|
|
207
|
+
z-index: 1000;
|
|
208
|
+
max-width: 260px;
|
|
209
|
+
padding: 6px 9px;
|
|
210
|
+
border-radius: 6px;
|
|
211
|
+
background: var(--tooltip-bg);
|
|
212
|
+
border: 1px solid var(--border-control);
|
|
213
|
+
color: var(--tooltip-text);
|
|
214
|
+
font-size: 11px;
|
|
215
|
+
line-height: 1.4;
|
|
216
|
+
box-shadow: var(--shadow);
|
|
217
|
+
pointer-events: none;
|
|
218
|
+
}
|
|
219
|
+
.kind-tooltip[hidden] { display: none; }
|
|
220
|
+
|
|
221
|
+
.row { display: flex; align-items: center; gap: 6px; margin: 4px 0; }
|
|
222
|
+
|
|
223
|
+
select, button {
|
|
224
|
+
background: var(--surface-raised);
|
|
225
|
+
color: var(--text-on-control);
|
|
226
|
+
border: 1px solid var(--border-control);
|
|
227
|
+
border-radius: 6px;
|
|
228
|
+
padding: 4px 8px;
|
|
229
|
+
font: inherit;
|
|
230
|
+
cursor: pointer;
|
|
231
|
+
}
|
|
232
|
+
button:hover { background: var(--surface-hover); }
|
|
233
|
+
select { flex: 1; }
|
|
234
|
+
.colour-by label { font-size: 12px; color: var(--muted-strong); white-space: nowrap; }
|
|
235
|
+
|
|
236
|
+
#details-body { font-size: 12px; }
|
|
237
|
+
#details-body .id { color: var(--muted); font-size: 10px; word-break: break-all; }
|
|
238
|
+
#details-body .kind-tag {
|
|
239
|
+
display: inline-block;
|
|
240
|
+
padding: 1px 6px;
|
|
241
|
+
border-radius: 4px;
|
|
242
|
+
font-size: 10px;
|
|
243
|
+
color: var(--on-swatch);
|
|
244
|
+
font-weight: 600;
|
|
245
|
+
}
|
|
246
|
+
#details-body h3 { font-size: 11px; color: var(--muted); margin: 10px 0 3px; }
|
|
247
|
+
#details-body .edge-row { padding: 1px 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
248
|
+
#details-body .edge-kind { color: var(--muted); font-size: 10px; }
|
|
249
|
+
#details-body .edge-count { color: var(--num); font-size: 10px; font-variant-numeric: tabular-nums; }
|
|
250
|
+
#details-body a { color: var(--link); cursor: pointer; text-decoration: none; }
|
|
251
|
+
#details-body a:hover { text-decoration: underline; }
|
|
252
|
+
#details-body a.file-link { text-decoration: underline; word-break: break-all; }
|
|
253
|
+
#details-body a.file-link::after { content: '↗'; margin-left: 3px; font-size: 9px; opacity: 0.7; }
|
|
254
|
+
|
|
255
|
+
#runtime.empty .heat-legend,
|
|
256
|
+
#runtime.empty .heat-note,
|
|
257
|
+
#runtime.empty .hotspots-title,
|
|
258
|
+
#runtime.empty #hotspots,
|
|
259
|
+
#runtime.empty label.row { display: none; }
|
|
260
|
+
|
|
261
|
+
#communities.empty { display: none; }
|
|
262
|
+
|
|
263
|
+
#coverage { font-size: 11px; color: var(--muted-strong); margin: 2px 0 6px; }
|
|
264
|
+
|
|
265
|
+
#runtime label.row { font-size: 12px; }
|
|
266
|
+
|
|
267
|
+
.heat-legend { display: flex; align-items: center; gap: 6px; margin: 8px 0 4px; }
|
|
268
|
+
.heat-bar { flex: 1; height: 10px; border-radius: 3px; background: linear-gradient(90deg, #64748b, #fde047, #dc2626); }
|
|
269
|
+
.heat-legend .heat-min, .heat-legend .heat-max { font-size: 10px; color: var(--muted); }
|
|
270
|
+
|
|
271
|
+
.heat-note { display: flex; align-items: center; gap: 6px; font-size: 10px; color: var(--muted); }
|
|
272
|
+
.heat-swatch { width: 10px; height: 10px; border-radius: 3px; flex: none; display: inline-block; }
|
|
273
|
+
.heat-swatch.unmeasured { background: var(--unmeasured-fill); border: 1px dashed var(--unmeasured-border); }
|
|
274
|
+
|
|
275
|
+
.hotspots-title { font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); margin: 12px 0 4px; }
|
|
276
|
+
#hotspots .hotspot {
|
|
277
|
+
display: flex;
|
|
278
|
+
align-items: center;
|
|
279
|
+
gap: 6px;
|
|
280
|
+
padding: 2px 4px;
|
|
281
|
+
border-radius: 4px;
|
|
282
|
+
cursor: pointer;
|
|
283
|
+
font-size: 12px;
|
|
284
|
+
}
|
|
285
|
+
#hotspots .hotspot:hover { background: var(--surface-raised); }
|
|
286
|
+
.hotspot-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
287
|
+
.hotspot-ms { margin-left: auto; flex: none; color: var(--num); font-size: 11px; font-variant-numeric: tabular-nums; }
|
|
288
|
+
|
|
289
|
+
#details-body .runtime-block { margin-top: 8px; }
|
|
290
|
+
#details-body .runtime-block .metric { display: flex; justify-content: space-between; gap: 8px; padding: 1px 0; }
|
|
291
|
+
#details-body .runtime-block .metric span { color: var(--muted); }
|
|
292
|
+
|
|
293
|
+
#cy { flex: 1; height: 100%; }
|
|
294
|
+
|
|
295
|
+
#dropzone {
|
|
296
|
+
position: fixed;
|
|
297
|
+
inset: 0;
|
|
298
|
+
display: flex;
|
|
299
|
+
align-items: center;
|
|
300
|
+
justify-content: center;
|
|
301
|
+
font-size: 18px;
|
|
302
|
+
color: var(--text-on-control);
|
|
303
|
+
background: var(--overlay-bg);
|
|
304
|
+
border: 3px dashed var(--accent);
|
|
305
|
+
pointer-events: none;
|
|
306
|
+
opacity: 0;
|
|
307
|
+
transition: opacity .15s;
|
|
308
|
+
}
|
|
309
|
+
#dropzone.active { opacity: 1; }
|
|
310
|
+
#dropzone code { color: var(--link); }
|