ts-knowledge-graph 0.1.2 → 0.1.4
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 +74 -34
- package/contribs/web_visualisation/README.md +28 -0
- package/contribs/web_visualisation/web/css/style.css +104 -0
- package/contribs/web_visualisation/web/data/.gitignore +1 -0
- package/contribs/web_visualisation/web/data/kind_descriptions.js +38 -0
- package/contribs/web_visualisation/web/index.html +20 -4
- package/contribs/web_visualisation/web/js/app.js +581 -35
- package/contribs/web_visualisation/web/tsconfig.json +18 -0
- package/contribs/web_visualisation/web/types/app_globals.d.ts +146 -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 +10 -2
- package/dist/cli.js.map +1 -1
- 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 +91 -0
- package/dist/commands/benchmark_command.js.map +1 -0
- package/dist/commands/blast_radius_command.js +1 -1
- package/dist/commands/blast_radius_command.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 +122 -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 +62 -0
- package/dist/commands/enrich_command.js.map +1 -0
- 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 +67 -0
- package/dist/commands/hotspots_command.js.map +1 -0
- package/dist/commands/install_command.d.ts +2 -3
- package/dist/commands/install_command.d.ts.map +1 -1
- package/dist/commands/install_command.js +7 -8
- 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 +2 -0
- package/dist/commands/load_command.js.map +1 -1
- 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/enrich/cpu_profile.d.ts +127 -0
- package/dist/enrich/cpu_profile.d.ts.map +1 -0
- package/dist/enrich/cpu_profile.js +97 -0
- package/dist/enrich/cpu_profile.js.map +1 -0
- package/dist/enrich/runtime_enricher.d.ts +56 -0
- package/dist/enrich/runtime_enricher.d.ts.map +1 -0
- package/dist/enrich/runtime_enricher.js +80 -0
- package/dist/enrich/runtime_enricher.js.map +1 -0
- package/dist/enrich/runtime_join.d.ts +100 -0
- package/dist/enrich/runtime_join.d.ts.map +1 -0
- package/dist/enrich/runtime_join.js +227 -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/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 +234 -0
- package/dist/query/graph_query.d.ts.map +1 -1
- package/dist/query/graph_query.js +522 -11
- package/dist/query/graph_query.js.map +1 -1
- package/dist/schema/edge.d.ts +40 -5
- package/dist/schema/edge.d.ts.map +1 -1
- package/dist/schema/edge.js +70 -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/store/kuzu_store.d.ts +46 -0
- package/dist/store/kuzu_store.d.ts.map +1 -1
- package/dist/store/kuzu_store.js +95 -5
- package/dist/store/kuzu_store.js.map +1 -1
- 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/{skills/ts-knowledge-graph → dotclaude_folder/skills/code-graph-query}/SKILL.md +2 -2
- package/package.json +86 -7
- package/.env-sample +0 -34
- 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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify_command.js","sourceRoot":"","sources":["../../src/commands/verify_command.ts"],"names":[],"mappings":"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"}
|
|
@@ -13,6 +13,33 @@ export declare class WebCommand {
|
|
|
13
13
|
* `window.GRAPH_DATA` script the visualisation page loads on boot.
|
|
14
14
|
*/
|
|
15
15
|
private static buildDataScript;
|
|
16
|
+
/**
|
|
17
|
+
* Decodes the JSON `metadata` column into a record so the visualisation can
|
|
18
|
+
* read `metadata.runtime`. A missing, empty (`{}`), or malformed value yields
|
|
19
|
+
* `undefined`, which `JSON.stringify` omits — keeping the payload small and
|
|
20
|
+
* letting un-enriched nodes simply carry no metadata.
|
|
21
|
+
*/
|
|
22
|
+
private static decodeMetadata;
|
|
23
|
+
/**
|
|
24
|
+
* Renders the `window.GRAPH_SOURCE` script that lets the visualisation link
|
|
25
|
+
* file paths to GitHub. Returns an empty string when `sourceDir` is not a
|
|
26
|
+
* GitHub work tree, so the page falls back to plain-text file paths.
|
|
27
|
+
*/
|
|
28
|
+
private static buildSourceScript;
|
|
29
|
+
/**
|
|
30
|
+
* Detects the GitHub repository, HEAD commit, and in-repo path prefix for the
|
|
31
|
+
* directory the graph was extracted from. Returns `undefined` when `sourceDir`
|
|
32
|
+
* is not a Git work tree, has no GitHub `origin` remote, or Git is unavailable.
|
|
33
|
+
*/
|
|
34
|
+
private static detectGitHubSource;
|
|
35
|
+
/**
|
|
36
|
+
* Normalises a Git `origin` URL to its GitHub web base
|
|
37
|
+
* (`https://<host>/<owner>/<repo>`), or `undefined` for non-GitHub remotes.
|
|
38
|
+
* Handles the SCP-like (`git@host:owner/repo.git`), `https://`, `git://`, and
|
|
39
|
+
* `ssh://` forms, with or without a trailing `.git`. The host is kept as-is so
|
|
40
|
+
* GitHub Enterprise remotes resolve to their own domain.
|
|
41
|
+
*/
|
|
42
|
+
static githubBaseUrl(remoteUrl: string): string | undefined;
|
|
16
43
|
private static handle;
|
|
17
44
|
private static notFound;
|
|
18
45
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web_command.d.ts","sourceRoot":"","sources":["../../src/commands/web_command.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"web_command.d.ts","sourceRoot":"","sources":["../../src/commands/web_command.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA4CpC;;;;;GAKG;AACH,qBAAa,UAAU;IACtB,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;mBAYlB,GAAG;IAoBxB;;;OAGG;mBACkB,eAAe;IAsCpC;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,cAAc;IAe7B;;;;OAIG;mBACkB,iBAAiB;IAUtC;;;;OAIG;mBACkB,kBAAkB;IAsBvC;;;;;;OAMG;IACH,MAAM,CAAC,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;mBA8BtC,MAAM;IAwB3B,OAAO,CAAC,MAAM,CAAC,QAAQ;CAIvB"}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
1
2
|
import { existsSync } from 'node:fs';
|
|
2
3
|
import { readFile } from 'node:fs/promises';
|
|
3
4
|
import { createServer } from 'node:http';
|
|
4
5
|
import { extname, join, normalize, resolve, sep } from 'node:path';
|
|
5
6
|
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { promisify } from 'node:util';
|
|
6
8
|
import chalk from 'chalk';
|
|
7
9
|
import { KuzuStore } from '../store/kuzu_store.js';
|
|
8
10
|
import { DEFAULT_DB_PATH } from './command_helpers.js';
|
|
11
|
+
const execFileAsync = promisify(execFile);
|
|
9
12
|
/**
|
|
10
13
|
* Static assets of the web visualisation, resolved relative to this module so
|
|
11
14
|
* the same path works from `src/` (tsx) and from `dist/` (published package).
|
|
@@ -34,6 +37,7 @@ export class WebCommand {
|
|
|
34
37
|
.description('serve the knowledge graph database in a web visualisation')
|
|
35
38
|
.option('-d, --db <path>', 'Kùzu database path', DEFAULT_DB_PATH)
|
|
36
39
|
.option('-p, --port <port>', 'HTTP port to listen on', DEFAULT_PORT)
|
|
40
|
+
.option('-s, --source <dir>', 'project root the graph was extracted from, used to link files to GitHub', '.')
|
|
37
41
|
.action(async (options) => {
|
|
38
42
|
await WebCommand.run(options);
|
|
39
43
|
});
|
|
@@ -45,7 +49,8 @@ export class WebCommand {
|
|
|
45
49
|
process.exitCode = 1;
|
|
46
50
|
return;
|
|
47
51
|
}
|
|
48
|
-
const
|
|
52
|
+
const sourceScript = await WebCommand.buildSourceScript(resolve(options.source));
|
|
53
|
+
const dataScript = sourceScript + await WebCommand.buildDataScript(dbPath);
|
|
49
54
|
const server = createServer((request, response) => {
|
|
50
55
|
void WebCommand.handle(request, response, dataScript);
|
|
51
56
|
});
|
|
@@ -62,8 +67,8 @@ export class WebCommand {
|
|
|
62
67
|
const store = new KuzuStore(dbPath);
|
|
63
68
|
await store.initSchema();
|
|
64
69
|
try {
|
|
65
|
-
const nodeRows = await store.run('MATCH (n:GraphNode) RETURN n.id AS id, n.kind AS kind, n.name AS name, n.filePath AS filePath, n.exported AS exported, n.startLine AS startLine, n.endLine AS endLine');
|
|
66
|
-
const edgeRows = await store.run('MATCH (f:GraphNode)-[e:Edge]->(t:GraphNode) RETURN f.id AS from, e.kind AS kind, t.id AS to');
|
|
70
|
+
const nodeRows = await store.run('MATCH (n:GraphNode) RETURN n.id AS id, n.kind AS kind, n.name AS name, n.filePath AS filePath, n.exported AS exported, n.startLine AS startLine, n.endLine AS endLine, n.metadata AS metadata');
|
|
71
|
+
const edgeRows = await store.run('MATCH (f:GraphNode)-[e:Edge]->(t:GraphNode) RETURN f.id AS from, e.kind AS kind, t.id AS to, e.metadata AS metadata');
|
|
67
72
|
const nodes = nodeRows.map((row) => ({
|
|
68
73
|
id: String(row.id),
|
|
69
74
|
kind: String(row.kind),
|
|
@@ -76,12 +81,14 @@ export class WebCommand {
|
|
|
76
81
|
endLine: Number(row.endLine),
|
|
77
82
|
endColumn: 0,
|
|
78
83
|
},
|
|
84
|
+
metadata: WebCommand.decodeMetadata(row.metadata),
|
|
79
85
|
}));
|
|
80
86
|
const edges = edgeRows.map((row, index) => ({
|
|
81
87
|
id: `e${index}`,
|
|
82
88
|
kind: String(row.kind),
|
|
83
89
|
from: String(row.from),
|
|
84
90
|
to: String(row.to),
|
|
91
|
+
metadata: WebCommand.decodeMetadata(row.metadata),
|
|
85
92
|
}));
|
|
86
93
|
console.log(chalk.cyan(`loaded ${nodes.length} nodes, ${edges.length} edges from ${dbPath}`));
|
|
87
94
|
return `window.GRAPH_DATA = ${JSON.stringify({ nodes, edges })};\n`;
|
|
@@ -90,6 +97,105 @@ export class WebCommand {
|
|
|
90
97
|
await store.close();
|
|
91
98
|
}
|
|
92
99
|
}
|
|
100
|
+
/**
|
|
101
|
+
* Decodes the JSON `metadata` column into a record so the visualisation can
|
|
102
|
+
* read `metadata.runtime`. A missing, empty (`{}`), or malformed value yields
|
|
103
|
+
* `undefined`, which `JSON.stringify` omits — keeping the payload small and
|
|
104
|
+
* letting un-enriched nodes simply carry no metadata.
|
|
105
|
+
*/
|
|
106
|
+
static decodeMetadata(value) {
|
|
107
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
const parsed = JSON.parse(value);
|
|
112
|
+
if (typeof parsed === 'object' && parsed !== null && Object.keys(parsed).length > 0) {
|
|
113
|
+
return parsed;
|
|
114
|
+
}
|
|
115
|
+
return undefined;
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Renders the `window.GRAPH_SOURCE` script that lets the visualisation link
|
|
123
|
+
* file paths to GitHub. Returns an empty string when `sourceDir` is not a
|
|
124
|
+
* GitHub work tree, so the page falls back to plain-text file paths.
|
|
125
|
+
*/
|
|
126
|
+
static async buildSourceScript(sourceDir) {
|
|
127
|
+
const github = await WebCommand.detectGitHubSource(sourceDir);
|
|
128
|
+
if (github === undefined) {
|
|
129
|
+
console.log(chalk.gray('no GitHub remote detected — file paths will not link to source'));
|
|
130
|
+
return '';
|
|
131
|
+
}
|
|
132
|
+
console.log(chalk.cyan(`linking files to ${github.baseUrl} @ ${github.commit.slice(0, 7)}`));
|
|
133
|
+
return `window.GRAPH_SOURCE = ${JSON.stringify({ github })};\n`;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Detects the GitHub repository, HEAD commit, and in-repo path prefix for the
|
|
137
|
+
* directory the graph was extracted from. Returns `undefined` when `sourceDir`
|
|
138
|
+
* is not a Git work tree, has no GitHub `origin` remote, or Git is unavailable.
|
|
139
|
+
*/
|
|
140
|
+
static async detectGitHubSource(sourceDir) {
|
|
141
|
+
const git = async (...args) => {
|
|
142
|
+
try {
|
|
143
|
+
const { stdout } = await execFileAsync('git', ['-C', sourceDir, ...args]);
|
|
144
|
+
return stdout.trim();
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
if (await git('rev-parse', '--is-inside-work-tree') !== 'true') {
|
|
151
|
+
return undefined;
|
|
152
|
+
}
|
|
153
|
+
const remoteUrl = await git('remote', 'get-url', 'origin');
|
|
154
|
+
const commit = await git('rev-parse', 'HEAD');
|
|
155
|
+
const baseUrl = remoteUrl === undefined ? undefined : WebCommand.githubBaseUrl(remoteUrl);
|
|
156
|
+
if (baseUrl === undefined || commit === undefined) {
|
|
157
|
+
return undefined;
|
|
158
|
+
}
|
|
159
|
+
return { baseUrl, commit, prefix: await git('rev-parse', '--show-prefix') ?? '' };
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Normalises a Git `origin` URL to its GitHub web base
|
|
163
|
+
* (`https://<host>/<owner>/<repo>`), or `undefined` for non-GitHub remotes.
|
|
164
|
+
* Handles the SCP-like (`git@host:owner/repo.git`), `https://`, `git://`, and
|
|
165
|
+
* `ssh://` forms, with or without a trailing `.git`. The host is kept as-is so
|
|
166
|
+
* GitHub Enterprise remotes resolve to their own domain.
|
|
167
|
+
*/
|
|
168
|
+
static githubBaseUrl(remoteUrl) {
|
|
169
|
+
const trimmed = remoteUrl.trim();
|
|
170
|
+
let host;
|
|
171
|
+
let path;
|
|
172
|
+
if (trimmed.includes('://') === true) {
|
|
173
|
+
try {
|
|
174
|
+
const parsed = new URL(trimmed);
|
|
175
|
+
host = parsed.host;
|
|
176
|
+
path = parsed.pathname;
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
return undefined;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
const scpMatch = trimmed.match(/^[^@]+@([^:]+):(.+)$/);
|
|
184
|
+
if (scpMatch === null) {
|
|
185
|
+
return undefined;
|
|
186
|
+
}
|
|
187
|
+
host = scpMatch[1];
|
|
188
|
+
path = scpMatch[2];
|
|
189
|
+
}
|
|
190
|
+
if (host.toLowerCase().includes('github') === false) {
|
|
191
|
+
return undefined;
|
|
192
|
+
}
|
|
193
|
+
const segments = path.replace(/\.git$/, '').split('/').filter((segment) => segment.length > 0);
|
|
194
|
+
if (segments.length < 2) {
|
|
195
|
+
return undefined;
|
|
196
|
+
}
|
|
197
|
+
return `https://${host}/${segments[0]}/${segments[1]}`;
|
|
198
|
+
}
|
|
93
199
|
static async handle(request, response, dataScript) {
|
|
94
200
|
const url = new URL(request.url ?? '/', 'http://localhost');
|
|
95
201
|
const pathname = url.pathname === '/' ? '/index.html' : url.pathname;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web_command.js","sourceRoot":"","sources":["../../src/commands/web_command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD;;;GAGG;AACH,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,sCAAsC,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAEjG,MAAM,gBAAgB,GAAG,qBAAqB,CAAC;AAC/C,MAAM,YAAY,GAAG,MAAM,CAAC;AAE5B,MAAM,UAAU,GAA2B;IAC1C,MAAM,EAAE,yBAAyB;IACjC,OAAO,EAAE,0BAA0B;IACnC,KAAK,EAAE,gCAAgC;IACvC,OAAO,EAAE,iCAAiC;IAC1C,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,eAAe;CACvB,CAAC;
|
|
1
|
+
{"version":3,"file":"web_command.js","sourceRoot":"","sources":["../../src/commands/web_command.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* The on-disk shape of a `node --cpu-prof` output (`.cpuprofile`). `samples`
|
|
4
|
+
* holds one profile-node id per sampling tick; `timeDeltas` holds the elapsed
|
|
5
|
+
* microseconds preceding each tick. Both are optional because some producers
|
|
6
|
+
* emit only per-node `hitCount`.
|
|
7
|
+
*/
|
|
8
|
+
export declare const CpuProfileSchema: z.ZodObject<{
|
|
9
|
+
nodes: z.ZodArray<z.ZodObject<{
|
|
10
|
+
id: z.ZodNumber;
|
|
11
|
+
callFrame: z.ZodObject<{
|
|
12
|
+
functionName: z.ZodString;
|
|
13
|
+
scriptId: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
|
|
14
|
+
url: z.ZodString;
|
|
15
|
+
lineNumber: z.ZodNumber;
|
|
16
|
+
columnNumber: z.ZodNumber;
|
|
17
|
+
}, "strip", z.ZodTypeAny, {
|
|
18
|
+
functionName: string;
|
|
19
|
+
url: string;
|
|
20
|
+
lineNumber: number;
|
|
21
|
+
columnNumber: number;
|
|
22
|
+
scriptId?: string | number | undefined;
|
|
23
|
+
}, {
|
|
24
|
+
functionName: string;
|
|
25
|
+
url: string;
|
|
26
|
+
lineNumber: number;
|
|
27
|
+
columnNumber: number;
|
|
28
|
+
scriptId?: string | number | undefined;
|
|
29
|
+
}>;
|
|
30
|
+
hitCount: z.ZodOptional<z.ZodNumber>;
|
|
31
|
+
children: z.ZodOptional<z.ZodArray<z.ZodNumber, "many">>;
|
|
32
|
+
}, "strip", z.ZodTypeAny, {
|
|
33
|
+
id: number;
|
|
34
|
+
callFrame: {
|
|
35
|
+
functionName: string;
|
|
36
|
+
url: string;
|
|
37
|
+
lineNumber: number;
|
|
38
|
+
columnNumber: number;
|
|
39
|
+
scriptId?: string | number | undefined;
|
|
40
|
+
};
|
|
41
|
+
hitCount?: number | undefined;
|
|
42
|
+
children?: number[] | undefined;
|
|
43
|
+
}, {
|
|
44
|
+
id: number;
|
|
45
|
+
callFrame: {
|
|
46
|
+
functionName: string;
|
|
47
|
+
url: string;
|
|
48
|
+
lineNumber: number;
|
|
49
|
+
columnNumber: number;
|
|
50
|
+
scriptId?: string | number | undefined;
|
|
51
|
+
};
|
|
52
|
+
hitCount?: number | undefined;
|
|
53
|
+
children?: number[] | undefined;
|
|
54
|
+
}>, "many">;
|
|
55
|
+
startTime: z.ZodOptional<z.ZodNumber>;
|
|
56
|
+
endTime: z.ZodOptional<z.ZodNumber>;
|
|
57
|
+
samples: z.ZodOptional<z.ZodArray<z.ZodNumber, "many">>;
|
|
58
|
+
timeDeltas: z.ZodOptional<z.ZodArray<z.ZodNumber, "many">>;
|
|
59
|
+
}, "strip", z.ZodTypeAny, {
|
|
60
|
+
nodes: {
|
|
61
|
+
id: number;
|
|
62
|
+
callFrame: {
|
|
63
|
+
functionName: string;
|
|
64
|
+
url: string;
|
|
65
|
+
lineNumber: number;
|
|
66
|
+
columnNumber: number;
|
|
67
|
+
scriptId?: string | number | undefined;
|
|
68
|
+
};
|
|
69
|
+
hitCount?: number | undefined;
|
|
70
|
+
children?: number[] | undefined;
|
|
71
|
+
}[];
|
|
72
|
+
startTime?: number | undefined;
|
|
73
|
+
endTime?: number | undefined;
|
|
74
|
+
samples?: number[] | undefined;
|
|
75
|
+
timeDeltas?: number[] | undefined;
|
|
76
|
+
}, {
|
|
77
|
+
nodes: {
|
|
78
|
+
id: number;
|
|
79
|
+
callFrame: {
|
|
80
|
+
functionName: string;
|
|
81
|
+
url: string;
|
|
82
|
+
lineNumber: number;
|
|
83
|
+
columnNumber: number;
|
|
84
|
+
scriptId?: string | number | undefined;
|
|
85
|
+
};
|
|
86
|
+
hitCount?: number | undefined;
|
|
87
|
+
children?: number[] | undefined;
|
|
88
|
+
}[];
|
|
89
|
+
startTime?: number | undefined;
|
|
90
|
+
endTime?: number | undefined;
|
|
91
|
+
samples?: number[] | undefined;
|
|
92
|
+
timeDeltas?: number[] | undefined;
|
|
93
|
+
}>;
|
|
94
|
+
export type CpuProfileData = z.infer<typeof CpuProfileSchema>;
|
|
95
|
+
/**
|
|
96
|
+
* One executing location distilled from the profile: its call frame plus the
|
|
97
|
+
* self time and sample count attributed to it. `line` is converted to the
|
|
98
|
+
* one-based convention so it can be compared against graph node ranges.
|
|
99
|
+
*/
|
|
100
|
+
export type FrameSample = {
|
|
101
|
+
functionName: string;
|
|
102
|
+
url: string;
|
|
103
|
+
line: number;
|
|
104
|
+
column: number;
|
|
105
|
+
samples: number;
|
|
106
|
+
selfMicros: number;
|
|
107
|
+
};
|
|
108
|
+
export declare class CpuProfile {
|
|
109
|
+
/**
|
|
110
|
+
* Parses and validates raw `.cpuprofile` JSON text. Throws a `ZodError` if
|
|
111
|
+
* the document does not match the V8 profile shape.
|
|
112
|
+
*/
|
|
113
|
+
static parse(jsonText: string): CpuProfileData;
|
|
114
|
+
/**
|
|
115
|
+
* Collapses the profile into one {@link FrameSample} per profile node that
|
|
116
|
+
* received at least one sample.
|
|
117
|
+
*
|
|
118
|
+
* Self time is summed from `timeDeltas`, attributing `timeDeltas[i]` to
|
|
119
|
+
* `samples[i]` — the standard self-time approximation where total attributed
|
|
120
|
+
* time equals the sum of all deltas. When `samples`/`timeDeltas` are absent,
|
|
121
|
+
* it falls back to each node's `hitCount` with zero self time.
|
|
122
|
+
*/
|
|
123
|
+
static aggregate(profile: CpuProfileData): FrameSample[];
|
|
124
|
+
/** Total number of sampling ticks in the profile, for coverage reporting. */
|
|
125
|
+
static totalSamples(profile: CpuProfileData): number;
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=cpu_profile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cpu_profile.d.ts","sourceRoot":"","sources":["../../src/enrich/cpu_profile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAsBxB;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAM3B,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE9D;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,qBAAa,UAAU;IACtB;;;OAGG;IACH,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc;IAI9C;;;;;;;;OAQG;IACH,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE,cAAc,GAAG,WAAW,EAAE;IAyCxD,6EAA6E;IAC7E,MAAM,CAAC,YAAY,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM;CAMpD"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* A single call frame as it appears in a V8 CPU profile node. Line and column
|
|
4
|
+
* numbers are **zero-based** in the V8 inspector protocol, unlike the one-based
|
|
5
|
+
* lines ts-morph (and therefore the graph's `range`) uses.
|
|
6
|
+
*/
|
|
7
|
+
const CallFrameSchema = z.object({
|
|
8
|
+
functionName: z.string(),
|
|
9
|
+
scriptId: z.union([z.string(), z.number()]).optional(),
|
|
10
|
+
url: z.string(),
|
|
11
|
+
lineNumber: z.number(),
|
|
12
|
+
columnNumber: z.number(),
|
|
13
|
+
});
|
|
14
|
+
const ProfileNodeSchema = z.object({
|
|
15
|
+
id: z.number(),
|
|
16
|
+
callFrame: CallFrameSchema,
|
|
17
|
+
hitCount: z.number().optional(),
|
|
18
|
+
children: z.array(z.number()).optional(),
|
|
19
|
+
});
|
|
20
|
+
/**
|
|
21
|
+
* The on-disk shape of a `node --cpu-prof` output (`.cpuprofile`). `samples`
|
|
22
|
+
* holds one profile-node id per sampling tick; `timeDeltas` holds the elapsed
|
|
23
|
+
* microseconds preceding each tick. Both are optional because some producers
|
|
24
|
+
* emit only per-node `hitCount`.
|
|
25
|
+
*/
|
|
26
|
+
export const CpuProfileSchema = z.object({
|
|
27
|
+
nodes: z.array(ProfileNodeSchema),
|
|
28
|
+
startTime: z.number().optional(),
|
|
29
|
+
endTime: z.number().optional(),
|
|
30
|
+
samples: z.array(z.number()).optional(),
|
|
31
|
+
timeDeltas: z.array(z.number()).optional(),
|
|
32
|
+
});
|
|
33
|
+
export class CpuProfile {
|
|
34
|
+
/**
|
|
35
|
+
* Parses and validates raw `.cpuprofile` JSON text. Throws a `ZodError` if
|
|
36
|
+
* the document does not match the V8 profile shape.
|
|
37
|
+
*/
|
|
38
|
+
static parse(jsonText) {
|
|
39
|
+
return CpuProfileSchema.parse(JSON.parse(jsonText));
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Collapses the profile into one {@link FrameSample} per profile node that
|
|
43
|
+
* received at least one sample.
|
|
44
|
+
*
|
|
45
|
+
* Self time is summed from `timeDeltas`, attributing `timeDeltas[i]` to
|
|
46
|
+
* `samples[i]` — the standard self-time approximation where total attributed
|
|
47
|
+
* time equals the sum of all deltas. When `samples`/`timeDeltas` are absent,
|
|
48
|
+
* it falls back to each node's `hitCount` with zero self time.
|
|
49
|
+
*/
|
|
50
|
+
static aggregate(profile) {
|
|
51
|
+
const samplesByNode = new Map();
|
|
52
|
+
const microsByNode = new Map();
|
|
53
|
+
const samples = profile.samples;
|
|
54
|
+
if (samples !== undefined && samples.length > 0) {
|
|
55
|
+
const deltas = profile.timeDeltas ?? [];
|
|
56
|
+
for (let index = 0; index < samples.length; index += 1) {
|
|
57
|
+
const nodeId = samples[index];
|
|
58
|
+
samplesByNode.set(nodeId, (samplesByNode.get(nodeId) ?? 0) + 1);
|
|
59
|
+
const delta = deltas[index] ?? 0;
|
|
60
|
+
const safeDelta = delta > 0 ? delta : 0;
|
|
61
|
+
microsByNode.set(nodeId, (microsByNode.get(nodeId) ?? 0) + safeDelta);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
for (const node of profile.nodes) {
|
|
66
|
+
const hits = node.hitCount ?? 0;
|
|
67
|
+
if (hits > 0) {
|
|
68
|
+
samplesByNode.set(node.id, hits);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const frames = [];
|
|
73
|
+
for (const node of profile.nodes) {
|
|
74
|
+
const sampleCount = samplesByNode.get(node.id) ?? 0;
|
|
75
|
+
if (sampleCount === 0) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
frames.push({
|
|
79
|
+
functionName: node.callFrame.functionName,
|
|
80
|
+
url: node.callFrame.url,
|
|
81
|
+
line: node.callFrame.lineNumber + 1,
|
|
82
|
+
column: node.callFrame.columnNumber,
|
|
83
|
+
samples: sampleCount,
|
|
84
|
+
selfMicros: microsByNode.get(node.id) ?? 0,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
return frames;
|
|
88
|
+
}
|
|
89
|
+
/** Total number of sampling ticks in the profile, for coverage reporting. */
|
|
90
|
+
static totalSamples(profile) {
|
|
91
|
+
if (profile.samples !== undefined && profile.samples.length > 0) {
|
|
92
|
+
return profile.samples.length;
|
|
93
|
+
}
|
|
94
|
+
return profile.nodes.reduce((sum, node) => sum + (node.hitCount ?? 0), 0);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=cpu_profile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cpu_profile.js","sourceRoot":"","sources":["../../src/enrich/cpu_profile.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { KuzuStore } from '../store/kuzu_store.js';
|
|
2
|
+
import { DroppedFrameGroup } from './runtime_join.js';
|
|
3
|
+
/** The telemetry source tag written into `metadata.runtime.source`. */
|
|
4
|
+
export declare const RUNTIME_SOURCE_CPU_PROFILE = "v8-cpuprofile";
|
|
5
|
+
/** Namespaced key under which runtime metrics are stored on a node's metadata. */
|
|
6
|
+
export declare const RUNTIME_METADATA_KEY = "runtime";
|
|
7
|
+
/**
|
|
8
|
+
* The measured-weight metrics attached to a node under `metadata.runtime`. The
|
|
9
|
+
* shape is intentionally open-ended (latency, call frequency, cost, … may join
|
|
10
|
+
* later); a CPU profile populates self time and sample count.
|
|
11
|
+
*/
|
|
12
|
+
export type RuntimeMetrics = {
|
|
13
|
+
source: string;
|
|
14
|
+
samples: number;
|
|
15
|
+
selfMicros: number;
|
|
16
|
+
selfMs: number;
|
|
17
|
+
};
|
|
18
|
+
export type Hotspot = {
|
|
19
|
+
id: string;
|
|
20
|
+
name: string;
|
|
21
|
+
kind: string;
|
|
22
|
+
filePath: string;
|
|
23
|
+
selfMs: number;
|
|
24
|
+
samples: number;
|
|
25
|
+
};
|
|
26
|
+
export type EnrichReport = {
|
|
27
|
+
totalSamples: number;
|
|
28
|
+
matchedNodes: number;
|
|
29
|
+
matchedFrames: number;
|
|
30
|
+
matchedSamples: number;
|
|
31
|
+
matchedSelfMs: number;
|
|
32
|
+
matchedByName: number;
|
|
33
|
+
matchedByRange: number;
|
|
34
|
+
droppedFrames: number;
|
|
35
|
+
droppedSamples: number;
|
|
36
|
+
dropped: DroppedFrameGroup[];
|
|
37
|
+
hotspots: Hotspot[];
|
|
38
|
+
};
|
|
39
|
+
export type EnrichOptions = {
|
|
40
|
+
/** Project root the profile's absolute frame urls resolve against. */
|
|
41
|
+
root: string;
|
|
42
|
+
};
|
|
43
|
+
export declare class RuntimeEnricher {
|
|
44
|
+
/**
|
|
45
|
+
* Ingests a V8 CPU profile and attaches `metadata.runtime` (self time and
|
|
46
|
+
* sample count) onto the graph nodes whose ranges enclose the profiled
|
|
47
|
+
* frames. Existing metadata is preserved; only the `runtime` key is written,
|
|
48
|
+
* so re-running with the same profile is idempotent. Unmatched frames are
|
|
49
|
+
* counted and returned in the report rather than dropped silently.
|
|
50
|
+
*/
|
|
51
|
+
static enrich(store: KuzuStore, profileText: string, options: EnrichOptions): Promise<EnrichReport>;
|
|
52
|
+
private static toMetrics;
|
|
53
|
+
/** Converts microseconds to milliseconds, rounded to microsecond precision. */
|
|
54
|
+
private static microsToMs;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=runtime_enricher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime_enricher.d.ts","sourceRoot":"","sources":["../../src/enrich/runtime_enricher.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAEnD,OAAO,EAAE,iBAAiB,EAAmC,MAAM,mBAAmB,CAAC;AAEvF,uEAAuE;AACvE,eAAO,MAAM,0BAA0B,kBAAkB,CAAC;AAE1D,kFAAkF;AAClF,eAAO,MAAM,oBAAoB,YAAY,CAAC;AAE9C;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAC7B,QAAQ,EAAE,OAAO,EAAE,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC3B,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,qBAAa,eAAe;IAC3B;;;;;;OAMG;WACU,MAAM,CAAC,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IA0DzG,OAAO,CAAC,MAAM,CAAC,SAAS;IASxB,+EAA+E;IAC/E,OAAO,CAAC,MAAM,CAAC,UAAU;CAGzB"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { RUNTIME_MANIFEST_KEY } from '../schema/runtime_manifest.js';
|
|
2
|
+
import { CpuProfile } from './cpu_profile.js';
|
|
3
|
+
import { RuntimeJoin } from './runtime_join.js';
|
|
4
|
+
/** The telemetry source tag written into `metadata.runtime.source`. */
|
|
5
|
+
export const RUNTIME_SOURCE_CPU_PROFILE = 'v8-cpuprofile';
|
|
6
|
+
/** Namespaced key under which runtime metrics are stored on a node's metadata. */
|
|
7
|
+
export const RUNTIME_METADATA_KEY = 'runtime';
|
|
8
|
+
export class RuntimeEnricher {
|
|
9
|
+
/**
|
|
10
|
+
* Ingests a V8 CPU profile and attaches `metadata.runtime` (self time and
|
|
11
|
+
* sample count) onto the graph nodes whose ranges enclose the profiled
|
|
12
|
+
* frames. Existing metadata is preserved; only the `runtime` key is written,
|
|
13
|
+
* so re-running with the same profile is idempotent. Unmatched frames are
|
|
14
|
+
* counted and returned in the report rather than dropped silently.
|
|
15
|
+
*/
|
|
16
|
+
static async enrich(store, profileText, options) {
|
|
17
|
+
const profile = CpuProfile.parse(profileText);
|
|
18
|
+
const frames = CpuProfile.aggregate(profile);
|
|
19
|
+
const nodes = await store.readNodes();
|
|
20
|
+
const result = RuntimeJoin.join(nodes, frames, { root: options.root });
|
|
21
|
+
const nodeById = new Map(nodes.map((node) => [node.id, node]));
|
|
22
|
+
const updates = [];
|
|
23
|
+
const hotspots = [];
|
|
24
|
+
for (const [id, attribution] of result.attributions) {
|
|
25
|
+
const node = nodeById.get(id);
|
|
26
|
+
if (node === undefined) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
const metrics = RuntimeEnricher.toMetrics(attribution);
|
|
30
|
+
updates.push({
|
|
31
|
+
id,
|
|
32
|
+
metadata: { ...node.metadata, [RUNTIME_METADATA_KEY]: metrics },
|
|
33
|
+
});
|
|
34
|
+
hotspots.push({
|
|
35
|
+
id,
|
|
36
|
+
name: node.name,
|
|
37
|
+
kind: node.kind,
|
|
38
|
+
filePath: node.filePath,
|
|
39
|
+
selfMs: metrics.selfMs,
|
|
40
|
+
samples: metrics.samples,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
await store.writeNodeMetadata(updates);
|
|
44
|
+
const manifest = {
|
|
45
|
+
source: RUNTIME_SOURCE_CPU_PROFILE,
|
|
46
|
+
totalSamples: CpuProfile.totalSamples(profile),
|
|
47
|
+
matchedSamples: result.matchedSamples,
|
|
48
|
+
totalSelfMicros: result.matchedSelfMicros + result.droppedSelfMicros,
|
|
49
|
+
matchedSelfMicros: result.matchedSelfMicros,
|
|
50
|
+
};
|
|
51
|
+
await store.writeGraphMeta(RUNTIME_MANIFEST_KEY, manifest);
|
|
52
|
+
hotspots.sort((a, b) => b.selfMs - a.selfMs || b.samples - a.samples);
|
|
53
|
+
return {
|
|
54
|
+
totalSamples: CpuProfile.totalSamples(profile),
|
|
55
|
+
matchedNodes: updates.length,
|
|
56
|
+
matchedFrames: result.matchedFrames,
|
|
57
|
+
matchedSamples: result.matchedSamples,
|
|
58
|
+
matchedSelfMs: RuntimeEnricher.microsToMs(result.matchedSelfMicros),
|
|
59
|
+
matchedByName: result.matchedByName,
|
|
60
|
+
matchedByRange: result.matchedByRange,
|
|
61
|
+
droppedFrames: result.droppedFrames,
|
|
62
|
+
droppedSamples: result.droppedSamples,
|
|
63
|
+
dropped: result.dropped,
|
|
64
|
+
hotspots,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
static toMetrics(attribution) {
|
|
68
|
+
return {
|
|
69
|
+
source: RUNTIME_SOURCE_CPU_PROFILE,
|
|
70
|
+
samples: attribution.samples,
|
|
71
|
+
selfMicros: attribution.selfMicros,
|
|
72
|
+
selfMs: RuntimeEnricher.microsToMs(attribution.selfMicros),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/** Converts microseconds to milliseconds, rounded to microsecond precision. */
|
|
76
|
+
static microsToMs(micros) {
|
|
77
|
+
return Math.round(micros) / 1000;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=runtime_enricher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime_enricher.js","sourceRoot":"","sources":["../../src/enrich/runtime_enricher.ts"],"names":[],"mappings":"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"}
|