kirograph 0.17.0 → 0.19.0
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/LICENSE +1 -1
- package/README.md +103 -1822
- package/dist/architecture/layers/dart.js +112 -0
- package/dist/architecture/layers/dart.js.map +7 -0
- package/dist/architecture/layers/index.js +3 -1
- package/dist/architecture/layers/index.js.map +2 -2
- package/dist/bin/banner.js +74 -6
- package/dist/bin/banner.js.map +2 -2
- package/dist/bin/commands/attack-surface.js +157 -0
- package/dist/bin/commands/attack-surface.js.map +7 -0
- package/dist/bin/commands/benchmark.js +206 -0
- package/dist/bin/commands/benchmark.js.map +7 -0
- package/dist/bin/commands/budget.js +70 -0
- package/dist/bin/commands/budget.js.map +7 -0
- package/dist/bin/commands/communities.js +77 -0
- package/dist/bin/commands/communities.js.map +7 -0
- package/dist/bin/commands/dep-confusion.js +119 -0
- package/dist/bin/commands/dep-confusion.js.map +7 -0
- package/dist/bin/commands/export.js +304 -10
- package/dist/bin/commands/export.js.map +2 -2
- package/dist/bin/commands/flows.js +97 -0
- package/dist/bin/commands/flows.js.map +7 -0
- package/dist/bin/commands/help.js +382 -101
- package/dist/bin/commands/help.js.map +2 -2
- package/dist/bin/commands/install.js +90 -8
- package/dist/bin/commands/install.js.map +2 -2
- package/dist/bin/commands/licenses.js +201 -0
- package/dist/bin/commands/licenses.js.map +7 -0
- package/dist/bin/commands/reachability.js +160 -0
- package/dist/bin/commands/reachability.js.map +7 -0
- package/dist/bin/commands/read.js +100 -0
- package/dist/bin/commands/read.js.map +7 -0
- package/dist/bin/commands/refactor.js +116 -0
- package/dist/bin/commands/refactor.js.map +7 -0
- package/dist/bin/commands/remediation.js +133 -0
- package/dist/bin/commands/remediation.js.map +7 -0
- package/dist/bin/commands/sbom.js +76 -0
- package/dist/bin/commands/sbom.js.map +7 -0
- package/dist/bin/commands/security-ci-report.js +267 -0
- package/dist/bin/commands/security-ci-report.js.map +7 -0
- package/dist/bin/commands/security-export.js +1349 -0
- package/dist/bin/commands/security-export.js.map +7 -0
- package/dist/bin/commands/security-flows.js +126 -0
- package/dist/bin/commands/security-flows.js.map +7 -0
- package/dist/bin/commands/security-secrets.js +170 -0
- package/dist/bin/commands/security-secrets.js.map +7 -0
- package/dist/bin/commands/security.js +193 -0
- package/dist/bin/commands/security.js.map +7 -0
- package/dist/bin/commands/staleness.js +144 -0
- package/dist/bin/commands/staleness.js.map +7 -0
- package/dist/bin/commands/status.js +102 -2
- package/dist/bin/commands/status.js.map +2 -2
- package/dist/bin/commands/supply-chain.js +138 -0
- package/dist/bin/commands/supply-chain.js.map +7 -0
- package/dist/bin/commands/uninit.js +109 -60
- package/dist/bin/commands/uninit.js.map +2 -2
- package/dist/bin/commands/vex.js +76 -0
- package/dist/bin/commands/vex.js.map +7 -0
- package/dist/bin/commands/vuln-suppress.js +95 -0
- package/dist/bin/commands/vuln-suppress.js.map +7 -0
- package/dist/bin/commands/vulns.js +382 -0
- package/dist/bin/commands/vulns.js.map +7 -0
- package/dist/bin/installer/auto-detect.js +125 -0
- package/dist/bin/installer/auto-detect.js.map +7 -0
- package/dist/bin/installer/cli-agent.js +28 -5
- package/dist/bin/installer/cli-agent.js.map +2 -2
- package/dist/bin/installer/common.js +47 -0
- package/dist/bin/installer/common.js.map +2 -2
- package/dist/bin/installer/config-prompt.js +12 -1
- package/dist/bin/installer/config-prompt.js.map +2 -2
- package/dist/bin/installer/detect.js +309 -0
- package/dist/bin/installer/detect.js.map +7 -0
- package/dist/bin/installer/index.js +9 -1
- package/dist/bin/installer/index.js.map +2 -2
- package/dist/bin/installer/instructions.js +195 -3
- package/dist/bin/installer/instructions.js.map +2 -2
- package/dist/bin/installer/steering.js +407 -0
- package/dist/bin/installer/steering.js.map +2 -2
- package/dist/bin/installer/targets/aider.js +3 -3
- package/dist/bin/installer/targets/aider.js.map +2 -2
- package/dist/bin/installer/targets/amp.js +3 -3
- package/dist/bin/installer/targets/amp.js.map +2 -2
- package/dist/bin/installer/targets/antigravity.js +35 -6
- package/dist/bin/installer/targets/antigravity.js.map +2 -2
- package/dist/bin/installer/targets/augment.js +3 -3
- package/dist/bin/installer/targets/augment.js.map +2 -2
- package/dist/bin/installer/targets/claude.js +49 -5
- package/dist/bin/installer/targets/claude.js.map +2 -2
- package/dist/bin/installer/targets/cline.js +32 -6
- package/dist/bin/installer/targets/cline.js.map +2 -2
- package/dist/bin/installer/targets/codex.js +64 -12
- package/dist/bin/installer/targets/codex.js.map +2 -2
- package/dist/bin/installer/targets/continue.js +2 -2
- package/dist/bin/installer/targets/continue.js.map +2 -2
- package/dist/bin/installer/targets/copilot-cli.js +101 -0
- package/dist/bin/installer/targets/copilot-cli.js.map +7 -0
- package/dist/bin/installer/targets/copilot.js +31 -5
- package/dist/bin/installer/targets/copilot.js.map +2 -2
- package/dist/bin/installer/targets/cursor.js +4 -4
- package/dist/bin/installer/targets/cursor.js.map +2 -2
- package/dist/bin/installer/targets/devin.js +2 -2
- package/dist/bin/installer/targets/devin.js.map +2 -2
- package/dist/bin/installer/targets/gemini-cli.js +2 -2
- package/dist/bin/installer/targets/gemini-cli.js.map +2 -2
- package/dist/bin/installer/targets/generic.js +2 -14
- package/dist/bin/installer/targets/generic.js.map +2 -2
- package/dist/bin/installer/targets/goose.js +3 -3
- package/dist/bin/installer/targets/goose.js.map +2 -2
- package/dist/bin/installer/targets/index.js +250 -0
- package/dist/bin/installer/targets/index.js.map +2 -2
- package/dist/bin/installer/targets/junie.js +2 -2
- package/dist/bin/installer/targets/junie.js.map +2 -2
- package/dist/bin/installer/targets/kilo.js +2 -2
- package/dist/bin/installer/targets/kilo.js.map +2 -2
- package/dist/bin/installer/targets/kiro.js +3 -3
- package/dist/bin/installer/targets/kiro.js.map +2 -2
- package/dist/bin/installer/targets/opencode.js +2 -2
- package/dist/bin/installer/targets/opencode.js.map +2 -2
- package/dist/bin/installer/targets/openhands.js +3 -3
- package/dist/bin/installer/targets/openhands.js.map +2 -2
- package/dist/bin/installer/targets/qoder.js +91 -0
- package/dist/bin/installer/targets/qoder.js.map +7 -0
- package/dist/bin/installer/targets/qwen.js +96 -0
- package/dist/bin/installer/targets/qwen.js.map +7 -0
- package/dist/bin/installer/targets/replit.js +3 -3
- package/dist/bin/installer/targets/replit.js.map +2 -2
- package/dist/bin/installer/targets/roo.js +2 -2
- package/dist/bin/installer/targets/roo.js.map +2 -2
- package/dist/bin/installer/targets/tabnine.js +3 -3
- package/dist/bin/installer/targets/tabnine.js.map +2 -2
- package/dist/bin/installer/targets/trae.js +5 -5
- package/dist/bin/installer/targets/trae.js.map +2 -2
- package/dist/bin/installer/targets/warp.js +2 -2
- package/dist/bin/installer/targets/warp.js.map +2 -2
- package/dist/bin/installer/targets/windsurf.js +35 -6
- package/dist/bin/installer/targets/windsurf.js.map +2 -2
- package/dist/bin/kirograph.js +72 -6
- package/dist/bin/kirograph.js.map +3 -3
- package/dist/compression/tracker.js +80 -0
- package/dist/compression/tracker.js.map +2 -2
- package/dist/config.js +90 -3
- package/dist/config.js.map +2 -2
- package/dist/core/pipeline.js +36 -2
- package/dist/core/pipeline.js.map +2 -2
- package/dist/db/database.js +56 -5
- package/dist/db/database.js.map +2 -2
- package/dist/db/memory-schema.sql +5 -1
- package/dist/db/schema.sql +3 -1
- package/dist/db/security-schema.sql +72 -0
- package/dist/extraction/extractor.js +81 -0
- package/dist/extraction/extractor.js.map +2 -2
- package/dist/extraction/grammars.js +32 -8
- package/dist/extraction/grammars.js.map +2 -2
- package/dist/extraction/languages.js +43 -1
- package/dist/extraction/languages.js.map +2 -2
- package/dist/extraction/notebook.js +300 -0
- package/dist/extraction/notebook.js.map +7 -0
- package/dist/extraction/wasm/tree-sitter-astro.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-gdscript.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-julia.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-nix.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-perl.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-powershell.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-r.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-sql.wasm +0 -0
- package/dist/extraction/wasm/tree-sitter-verilog.wasm +0 -0
- package/dist/frameworks/flutter.js +130 -0
- package/dist/frameworks/flutter.js.map +7 -0
- package/dist/frameworks/index.js +7 -1
- package/dist/frameworks/index.js.map +3 -3
- package/dist/graph/communities.js +317 -0
- package/dist/graph/communities.js.map +7 -0
- package/dist/graph/flows.js +138 -0
- package/dist/graph/flows.js.map +7 -0
- package/dist/graph/refactor.js +155 -0
- package/dist/graph/refactor.js.map +7 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +2 -2
- package/dist/mcp/cache.js +172 -0
- package/dist/mcp/cache.js.map +7 -0
- package/dist/mcp/read-modes.js +295 -0
- package/dist/mcp/read-modes.js.map +7 -0
- package/dist/mcp/server.js +2 -1
- package/dist/mcp/server.js.map +2 -2
- package/dist/mcp/tool-names.js +21 -1
- package/dist/mcp/tool-names.js.map +2 -2
- package/dist/mcp/tools.js +1160 -1
- package/dist/mcp/tools.js.map +3 -3
- package/dist/memory/database.js +32 -2
- package/dist/memory/database.js.map +2 -2
- package/dist/memory/types.js.map +1 -1
- package/dist/resolution/bridges/android-rn.js +298 -0
- package/dist/resolution/bridges/android-rn.js.map +7 -0
- package/dist/resolution/bridges/expo-modules.js +155 -0
- package/dist/resolution/bridges/expo-modules.js.map +7 -0
- package/dist/resolution/bridges/flutter-channel.js +385 -0
- package/dist/resolution/bridges/flutter-channel.js.map +7 -0
- package/dist/resolution/bridges/index.js +80 -0
- package/dist/resolution/bridges/index.js.map +7 -0
- package/dist/resolution/bridges/native-events.js +188 -0
- package/dist/resolution/bridges/native-events.js.map +7 -0
- package/dist/resolution/bridges/native-views.js +244 -0
- package/dist/resolution/bridges/native-views.js.map +7 -0
- package/dist/resolution/bridges/react-native.js +161 -0
- package/dist/resolution/bridges/react-native.js.map +7 -0
- package/dist/resolution/bridges/swift-objc.js +227 -0
- package/dist/resolution/bridges/swift-objc.js.map +7 -0
- package/dist/resolution/bridges/turbomodules.js +216 -0
- package/dist/resolution/bridges/turbomodules.js.map +7 -0
- package/dist/resolution/index.js +61 -2
- package/dist/resolution/index.js.map +2 -2
- package/dist/security/attack-surface.js +164 -0
- package/dist/security/attack-surface.js.map +7 -0
- package/dist/security/context-warnings.js +123 -0
- package/dist/security/context-warnings.js.map +7 -0
- package/dist/security/context-warnings.test.js +300 -0
- package/dist/security/context-warnings.test.js.map +7 -0
- package/dist/security/data-flows.js +228 -0
- package/dist/security/data-flows.js.map +7 -0
- package/dist/security/dep-confusion.js +255 -0
- package/dist/security/dep-confusion.js.map +7 -0
- package/dist/security/errors.js +51 -0
- package/dist/security/errors.js.map +7 -0
- package/dist/security/export/fix-suggestions.js +58 -0
- package/dist/security/export/fix-suggestions.js.map +7 -0
- package/dist/security/export/fix-suggestions.test.js +74 -0
- package/dist/security/export/fix-suggestions.test.js.map +7 -0
- package/dist/security/export/sbom.js +230 -0
- package/dist/security/export/sbom.js.map +7 -0
- package/dist/security/export/sbom.test.js +288 -0
- package/dist/security/export/sbom.test.js.map +7 -0
- package/dist/security/export/serialization.js +142 -0
- package/dist/security/export/serialization.js.map +7 -0
- package/dist/security/export/serialization.test.js +310 -0
- package/dist/security/export/serialization.test.js.map +7 -0
- package/dist/security/export/vex.js +220 -0
- package/dist/security/export/vex.js.map +7 -0
- package/dist/security/export/vex.test.js +278 -0
- package/dist/security/export/vex.test.js.map +7 -0
- package/dist/security/index.js +67 -0
- package/dist/security/index.js.map +7 -0
- package/dist/security/integrator-transitives.test.js +359 -0
- package/dist/security/integrator-transitives.test.js.map +7 -0
- package/dist/security/integrator.js +491 -0
- package/dist/security/integrator.js.map +7 -0
- package/dist/security/integrator.test.js +237 -0
- package/dist/security/integrator.test.js.map +7 -0
- package/dist/security/license.js +70 -0
- package/dist/security/license.js.map +7 -0
- package/dist/security/manifest/adapter.js +243 -0
- package/dist/security/manifest/adapter.js.map +7 -0
- package/dist/security/manifest/adapter.test.js +272 -0
- package/dist/security/manifest/adapter.test.js.map +7 -0
- package/dist/security/manifest/parser.js +376 -0
- package/dist/security/manifest/parser.js.map +7 -0
- package/dist/security/manifest/parser.test.js +110 -0
- package/dist/security/manifest/parser.test.js.map +7 -0
- package/dist/security/manifest/plugins/cargo.js +233 -0
- package/dist/security/manifest/plugins/cargo.js.map +7 -0
- package/dist/security/manifest/plugins/cargo.test.js +304 -0
- package/dist/security/manifest/plugins/cargo.test.js.map +7 -0
- package/dist/security/manifest/plugins/composer.js +152 -0
- package/dist/security/manifest/plugins/composer.js.map +7 -0
- package/dist/security/manifest/plugins/go.js +146 -0
- package/dist/security/manifest/plugins/go.js.map +7 -0
- package/dist/security/manifest/plugins/go.test.js +341 -0
- package/dist/security/manifest/plugins/go.test.js.map +7 -0
- package/dist/security/manifest/plugins/gradle.js +159 -0
- package/dist/security/manifest/plugins/gradle.js.map +7 -0
- package/dist/security/manifest/plugins/hex.js +159 -0
- package/dist/security/manifest/plugins/hex.js.map +7 -0
- package/dist/security/manifest/plugins/maven.js +128 -0
- package/dist/security/manifest/plugins/maven.js.map +7 -0
- package/dist/security/manifest/plugins/maven.test.js +389 -0
- package/dist/security/manifest/plugins/maven.test.js.map +7 -0
- package/dist/security/manifest/plugins/npm.js +284 -0
- package/dist/security/manifest/plugins/npm.js.map +7 -0
- package/dist/security/manifest/plugins/npm.test.js +298 -0
- package/dist/security/manifest/plugins/npm.test.js.map +7 -0
- package/dist/security/manifest/plugins/nuget.js +186 -0
- package/dist/security/manifest/plugins/nuget.js.map +7 -0
- package/dist/security/manifest/plugins/pip.js +123 -0
- package/dist/security/manifest/plugins/pip.js.map +7 -0
- package/dist/security/manifest/plugins/pip.test.js +208 -0
- package/dist/security/manifest/plugins/pip.test.js.map +7 -0
- package/dist/security/manifest/plugins/pubspec.js +212 -0
- package/dist/security/manifest/plugins/pubspec.js.map +7 -0
- package/dist/security/manifest/plugins/pyproject.js +261 -0
- package/dist/security/manifest/plugins/pyproject.js.map +7 -0
- package/dist/security/manifest/plugins/rubygems.js +185 -0
- package/dist/security/manifest/plugins/rubygems.js.map +7 -0
- package/dist/security/manifest/plugins/swift.js +200 -0
- package/dist/security/manifest/plugins/swift.js.map +7 -0
- package/dist/security/owasp.js +104 -0
- package/dist/security/owasp.js.map +7 -0
- package/dist/security/pipeline.js +125 -0
- package/dist/security/pipeline.js.map +7 -0
- package/dist/security/reachability.js +276 -0
- package/dist/security/reachability.js.map +7 -0
- package/dist/security/reachability.test.js +394 -0
- package/dist/security/reachability.test.js.map +7 -0
- package/dist/security/remediation.js +126 -0
- package/dist/security/remediation.js.map +7 -0
- package/dist/security/secrets.js +176 -0
- package/dist/security/secrets.js.map +7 -0
- package/dist/security/staleness.js +231 -0
- package/dist/security/staleness.js.map +7 -0
- package/dist/security/supply-chain.js +301 -0
- package/dist/security/supply-chain.js.map +7 -0
- package/dist/security/suppressions.js +106 -0
- package/dist/security/suppressions.js.map +7 -0
- package/dist/security/types.js +17 -0
- package/dist/security/types.js.map +7 -0
- package/dist/security/vuln/client.js +355 -0
- package/dist/security/vuln/client.js.map +7 -0
- package/dist/security/vuln/client.test.js +288 -0
- package/dist/security/vuln/client.test.js.map +7 -0
- package/dist/security/vuln/epss-client.js +95 -0
- package/dist/security/vuln/epss-client.js.map +7 -0
- package/dist/security/vuln/index.js +29 -0
- package/dist/security/vuln/index.js.map +7 -0
- package/dist/security/vuln/osv-adapter.js +321 -0
- package/dist/security/vuln/osv-adapter.js.map +7 -0
- package/dist/security/vuln/osv-adapter.test.js +391 -0
- package/dist/security/vuln/osv-adapter.test.js.map +7 -0
- package/dist/security/vuln/types.js +17 -0
- package/dist/security/vuln/types.js.map +7 -0
- package/dist/types.js.map +2 -2
- package/package.json +2 -1
|
@@ -45,6 +45,43 @@ async function generateExport(projectPath, opts) {
|
|
|
45
45
|
const cg = await KiroGraph.open(target);
|
|
46
46
|
const nodes = cg.getAllNodes();
|
|
47
47
|
const edges = cg.getAllEdges();
|
|
48
|
+
let securityOverlay;
|
|
49
|
+
try {
|
|
50
|
+
const db = cg.getDatabase();
|
|
51
|
+
db.applySecuritySchema();
|
|
52
|
+
const depRows = db.getRawDb().all(
|
|
53
|
+
`SELECT d.node_id, r.verdict
|
|
54
|
+
FROM sec_dependencies d
|
|
55
|
+
LEFT JOIN edges e ON e.source = d.node_id AND e.kind = 'has_vulnerability'
|
|
56
|
+
LEFT JOIN sec_reachability r ON r.vulnerability_node_id = e.target
|
|
57
|
+
ORDER BY
|
|
58
|
+
CASE r.verdict
|
|
59
|
+
WHEN 'affected' THEN 0
|
|
60
|
+
WHEN 'under_investigation' THEN 1
|
|
61
|
+
WHEN 'not_affected' THEN 2
|
|
62
|
+
ELSE 3
|
|
63
|
+
END`
|
|
64
|
+
);
|
|
65
|
+
const depVerdicts = /* @__PURE__ */ new Map();
|
|
66
|
+
for (const row of depRows) {
|
|
67
|
+
if (!depVerdicts.has(row.node_id)) {
|
|
68
|
+
const status = row.verdict === "affected" ? "affected" : row.verdict === "under_investigation" ? "under_investigation" : row.verdict === "not_affected" ? "not_affected" : "none";
|
|
69
|
+
depVerdicts.set(row.node_id, status);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const vulnRows = db.getRawDb().all(
|
|
73
|
+
`SELECT node_id, verdict FROM sec_reachability`
|
|
74
|
+
);
|
|
75
|
+
const vulnVerdicts = /* @__PURE__ */ new Map();
|
|
76
|
+
for (const row of vulnRows) {
|
|
77
|
+
const status = row.verdict === "affected" ? "affected" : row.verdict === "under_investigation" ? "under_investigation" : row.verdict === "not_affected" ? "not_affected" : "none";
|
|
78
|
+
vulnVerdicts.set(row.node_id, status);
|
|
79
|
+
}
|
|
80
|
+
if (depVerdicts.size > 0 || vulnVerdicts.size > 0) {
|
|
81
|
+
securityOverlay = { depVerdicts, vulnVerdicts };
|
|
82
|
+
}
|
|
83
|
+
} catch {
|
|
84
|
+
}
|
|
48
85
|
cg.close();
|
|
49
86
|
const projectName = path.basename(target);
|
|
50
87
|
let logoBase64;
|
|
@@ -69,7 +106,7 @@ async function generateExport(projectPath, opts) {
|
|
|
69
106
|
}
|
|
70
107
|
const outDir = opts.output ? path.resolve(opts.output) : path.join(target, ".kirograph", "export");
|
|
71
108
|
fs.mkdirSync(outDir, { recursive: true });
|
|
72
|
-
const { html, css, js } = buildFiles(nodes, edges, projectName, opts.includeContains, logoBase64, fileModified);
|
|
109
|
+
const { html, css, js } = buildFiles(nodes, edges, projectName, opts.includeContains, logoBase64, fileModified, securityOverlay);
|
|
73
110
|
fs.writeFileSync(path.join(outDir, "index.html"), html, "utf8");
|
|
74
111
|
fs.writeFileSync(path.join(outDir, "app.css"), css, "utf8");
|
|
75
112
|
fs.writeFileSync(path.join(outDir, "app.js"), js, "utf8");
|
|
@@ -137,7 +174,18 @@ function lighten(hex) {
|
|
|
137
174
|
function escHtml(s) {
|
|
138
175
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
139
176
|
}
|
|
140
|
-
|
|
177
|
+
const SEC_DEP_COLOR = {
|
|
178
|
+
affected: "#ef4444",
|
|
179
|
+
under_investigation: "#f59e0b",
|
|
180
|
+
not_affected: "#22c55e",
|
|
181
|
+
none: "#64748b"
|
|
182
|
+
};
|
|
183
|
+
const SEC_VULN_COLOR = {
|
|
184
|
+
affected: "#dc2626",
|
|
185
|
+
under_investigation: "#d97706",
|
|
186
|
+
not_affected: "#16a34a"
|
|
187
|
+
};
|
|
188
|
+
function buildFiles(nodes, edges, projectName, includeContains, logoBase64, fileModified, securityOverlay) {
|
|
141
189
|
const filteredEdges = includeContains ? edges : edges.filter((e) => e.kind !== "contains");
|
|
142
190
|
const degree = /* @__PURE__ */ new Map();
|
|
143
191
|
for (const e of filteredEdges) {
|
|
@@ -149,14 +197,28 @@ function buildFiles(nodes, edges, projectName, includeContains, logoBase64, file
|
|
|
149
197
|
const fp = n.filePath ?? "";
|
|
150
198
|
const parts = fp.split("/").filter(Boolean);
|
|
151
199
|
const dir = parts.length >= 2 ? parts.slice(0, 2).join("/") : parts[0] ?? "";
|
|
200
|
+
let securityStatus = "none";
|
|
201
|
+
let baseColor = KIND_COLOR[n.kind] ?? "#424242";
|
|
202
|
+
if (securityOverlay) {
|
|
203
|
+
if (n.kind === "dependency") {
|
|
204
|
+
securityStatus = securityOverlay.depVerdicts.get(n.id) ?? "none";
|
|
205
|
+
baseColor = SEC_DEP_COLOR[securityStatus];
|
|
206
|
+
} else if (n.kind === "vulnerability") {
|
|
207
|
+
const verdict = securityOverlay.vulnVerdicts.get(n.id);
|
|
208
|
+
if (verdict) {
|
|
209
|
+
securityStatus = verdict;
|
|
210
|
+
baseColor = SEC_VULN_COLOR[verdict] ?? baseColor;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
152
214
|
return {
|
|
153
215
|
id: n.id,
|
|
154
216
|
label: n.name,
|
|
155
217
|
color: {
|
|
156
|
-
background:
|
|
157
|
-
border: lighten(
|
|
218
|
+
background: baseColor,
|
|
219
|
+
border: lighten(baseColor),
|
|
158
220
|
highlight: { background: "#e040fb", border: "#ea80fc" },
|
|
159
|
-
hover: { background: lighten(
|
|
221
|
+
hover: { background: lighten(baseColor), border: "#ea80fc" }
|
|
160
222
|
},
|
|
161
223
|
size: Math.max(8, Math.min(40, 8 + (degree.get(n.id) ?? 0) * 1.5)),
|
|
162
224
|
font: { size: 11, color: "#e0e0e0", face: "monospace" },
|
|
@@ -170,7 +232,8 @@ function buildFiles(nodes, edges, projectName, includeContains, logoBase64, file
|
|
|
170
232
|
degree: degree.get(n.id) ?? 0,
|
|
171
233
|
borderWidth: n.isExported ? 2 : 1,
|
|
172
234
|
borderWidthSelected: 3,
|
|
173
|
-
lastModified: fileModified ? fileModified[fp] ?? 0 : 0
|
|
235
|
+
lastModified: fileModified ? fileModified[fp] ?? 0 : 0,
|
|
236
|
+
securityStatus
|
|
174
237
|
};
|
|
175
238
|
});
|
|
176
239
|
const visEdges = filteredEdges.map((e, i) => ({
|
|
@@ -188,6 +251,7 @@ function buildFiles(nodes, edges, projectName, includeContains, logoBase64, file
|
|
|
188
251
|
}));
|
|
189
252
|
const allNodeKinds = [...new Set(nodes.map((n) => n.kind))].sort();
|
|
190
253
|
const allEdgeKinds = [...new Set(filteredEdges.map((e) => e.kind))].sort();
|
|
254
|
+
const hasSecurityNodes = visNodes.some((n) => n.kind === "dependency" || n.kind === "vulnerability");
|
|
191
255
|
const logoTag = logoBase64 ? `<img src="data:image/png;base64,${logoBase64}" alt="KiroGraph">` : `<h1>\u2B21 KiroGraph</h1>`;
|
|
192
256
|
const loaderLogoTag = logoBase64 ? `<img src="data:image/png;base64,${logoBase64}" alt="KiroGraph">` : `<div style="color:#c792ea;font-size:18px;font-weight:600;letter-spacing:.05em">\u2B21 KiroGraph</div>`;
|
|
193
257
|
const nodeLegend = allNodeKinds.map((k) => `<div class="legend-item" data-nkind="${k}">
|
|
@@ -254,7 +318,8 @@ function buildFiles(nodes, edges, projectName, includeContains, logoBase64, file
|
|
|
254
318
|
<button class="fbtn" id="btn-focus" title="Focus on node and neighbors">\u25CE <span class="fbtn-label">Focus</span></button>
|
|
255
319
|
<button class="fbtn" id="btn-path" title="Find path between two nodes">\u27F6 <span class="fbtn-label">Path</span></button>
|
|
256
320
|
<button class="fbtn" id="btn-cluster" title="Cluster by directory">\u2B21 <span class="fbtn-label">Cluster</span></button>
|
|
257
|
-
<button class="fbtn" id="btn-heat" title="Heat map by file recency">\u{1F321} <span class="fbtn-label">Heat</span></button
|
|
321
|
+
<button class="fbtn" id="btn-heat" title="Heat map by file recency">\u{1F321} <span class="fbtn-label">Heat</span></button>${hasSecurityNodes ? `
|
|
322
|
+
<button class="fbtn" id="btn-security" title="Security overlay \u2014 highlight dependency/vulnerability nodes">\u{1F512} <span class="fbtn-label">Security</span></button>` : ""}
|
|
258
323
|
<button class="fbtn" id="btn-charts" title="Analytics charts">\u{1F4CA} <span class="fbtn-label">Charts</span></button>
|
|
259
324
|
</div>
|
|
260
325
|
|
|
@@ -269,7 +334,20 @@ function buildFiles(nodes, edges, projectName, includeContains, logoBase64, file
|
|
|
269
334
|
<div class="heat-stop" data-tip="Modified more than 6 months ago"><span class="heat-stop-dot" style="background:#2980b9"></span>Older</div>
|
|
270
335
|
</div>
|
|
271
336
|
<div id="heat-tip"></div>
|
|
272
|
-
</div
|
|
337
|
+
</div>${hasSecurityNodes ? `
|
|
338
|
+
|
|
339
|
+
<div id="security-legend">
|
|
340
|
+
<div class="security-legend-title">\u{1F512} Security status</div>
|
|
341
|
+
<div class="security-stops">
|
|
342
|
+
<div class="security-stop"><span class="security-stop-dot" style="background:#ef4444"></span>Affected</div>
|
|
343
|
+
<div class="security-stop"><span class="security-stop-dot" style="background:#f59e0b"></span>Under investigation</div>
|
|
344
|
+
<div class="security-stop"><span class="security-stop-dot" style="background:#22c55e"></span>Not affected</div>
|
|
345
|
+
<div class="security-stop"><span class="security-stop-dot" style="background:#64748b"></span>No vuln data</div>
|
|
346
|
+
<div class="security-stop"><span class="security-stop-dot" style="background:#dc2626;border:2px solid #fff"></span>Vuln: affected</div>
|
|
347
|
+
<div class="security-stop"><span class="security-stop-dot" style="background:#d97706;border:2px solid #fff"></span>Vuln: investigating</div>
|
|
348
|
+
<div class="security-stop"><span class="security-stop-dot" style="background:#16a34a;border:2px solid #fff"></span>Vuln: not affected</div>
|
|
349
|
+
</div>
|
|
350
|
+
</div>` : ""}
|
|
273
351
|
</div>
|
|
274
352
|
</div><!-- /float-sidebar -->
|
|
275
353
|
|
|
@@ -415,7 +493,7 @@ function buildFiles(nodes, edges, projectName, includeContains, logoBase64, file
|
|
|
415
493
|
</body>
|
|
416
494
|
</html>`;
|
|
417
495
|
const css = buildCss();
|
|
418
|
-
const js = buildJs(visNodes, visEdges, KIND_COLOR, EDGE_COLOR);
|
|
496
|
+
const js = buildJs(visNodes, visEdges, KIND_COLOR, EDGE_COLOR, hasSecurityNodes);
|
|
419
497
|
return { html, css, js };
|
|
420
498
|
}
|
|
421
499
|
function buildCss() {
|
|
@@ -941,9 +1019,47 @@ input[type=range] {
|
|
|
941
1019
|
min-height: 14px;
|
|
942
1020
|
font-style: italic;
|
|
943
1021
|
}
|
|
1022
|
+
|
|
1023
|
+
/* \u2500\u2500 Security legend (inside sidebar) \u2500\u2500 */
|
|
1024
|
+
#security-legend {
|
|
1025
|
+
display: none;
|
|
1026
|
+
background: rgba(8, 8, 18, 0.97);
|
|
1027
|
+
border: 1px solid #3a3a5e;
|
|
1028
|
+
border-radius: 12px;
|
|
1029
|
+
padding: 12px 14px;
|
|
1030
|
+
box-shadow: 0 4px 24px rgba(0,0,0,.75);
|
|
1031
|
+
width: 200px;
|
|
1032
|
+
}
|
|
1033
|
+
.security-legend-title {
|
|
1034
|
+
font-size: 11px;
|
|
1035
|
+
font-weight: 600;
|
|
1036
|
+
color: #9da8cc;
|
|
1037
|
+
margin-bottom: 10px;
|
|
1038
|
+
}
|
|
1039
|
+
.security-stops {
|
|
1040
|
+
display: flex;
|
|
1041
|
+
flex-direction: column;
|
|
1042
|
+
gap: 5px;
|
|
1043
|
+
}
|
|
1044
|
+
.security-stop {
|
|
1045
|
+
display: flex;
|
|
1046
|
+
align-items: center;
|
|
1047
|
+
gap: 8px;
|
|
1048
|
+
font-size: 11px;
|
|
1049
|
+
color: #7a86aa;
|
|
1050
|
+
cursor: default;
|
|
1051
|
+
padding: 2px 4px;
|
|
1052
|
+
border-radius: 4px;
|
|
1053
|
+
}
|
|
1054
|
+
.security-stop-dot {
|
|
1055
|
+
width: 9px; height: 9px;
|
|
1056
|
+
border-radius: 50%;
|
|
1057
|
+
flex-shrink: 0;
|
|
1058
|
+
box-sizing: border-box;
|
|
1059
|
+
}
|
|
944
1060
|
`;
|
|
945
1061
|
}
|
|
946
|
-
function buildJs(visNodes, visEdges, kindColors, edgeColors) {
|
|
1062
|
+
function buildJs(visNodes, visEdges, kindColors, edgeColors, hasSecurityNodes) {
|
|
947
1063
|
return `// \u2500\u2500 Data \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
948
1064
|
const NODES_DATA = ${JSON.stringify(visNodes)};
|
|
949
1065
|
const EDGES_DATA = ${JSON.stringify(visEdges)};
|
|
@@ -1551,6 +1667,7 @@ document.getElementById('btn-cluster').addEventListener('click', () => {
|
|
|
1551
1667
|
document.getElementById('heat-legend').style.display = 'none';
|
|
1552
1668
|
nodesDS.update(NODES_DATA.map(n => ({ id: n.id, color: originalColors[n.id] })));
|
|
1553
1669
|
}
|
|
1670
|
+
${hasSecurityNodes ? `if (securityActive) { exitSecurityOverlay(); }` : ""}
|
|
1554
1671
|
if (focusActive) exitFocus();
|
|
1555
1672
|
if (pathMode) exitPath(true);
|
|
1556
1673
|
network.unselectAll();
|
|
@@ -1769,6 +1886,55 @@ document.querySelectorAll('.heat-stop').forEach(function(el) {
|
|
|
1769
1886
|
el.addEventListener('mouseleave', function() { if (tip) tip.textContent = ''; });
|
|
1770
1887
|
});
|
|
1771
1888
|
|
|
1889
|
+
${hasSecurityNodes ? `// \u2500\u2500 Security overlay \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
1890
|
+
let securityActive = false;
|
|
1891
|
+
|
|
1892
|
+
// Colours embedded from build-time palette
|
|
1893
|
+
const SEC_DEP_COLORS = { affected: '#ef4444', under_investigation: '#f59e0b', not_affected: '#22c55e', none: '#64748b' };
|
|
1894
|
+
const SEC_VULN_COLORS = { affected: '#dc2626', under_investigation: '#d97706', not_affected: '#16a34a' };
|
|
1895
|
+
|
|
1896
|
+
function enterSecurityOverlay() {
|
|
1897
|
+
securityActive = true;
|
|
1898
|
+
document.getElementById('btn-security').classList.add('active');
|
|
1899
|
+
document.getElementById('security-legend').style.display = 'block';
|
|
1900
|
+
|
|
1901
|
+
const DIM = { background: '#111118', border: '#1a1a2a', highlight: { background: '#111118', border: '#1a1a2a' }, hover: { background: '#111118', border: '#1a1a2a' } };
|
|
1902
|
+
const secNodeIds = new Set(
|
|
1903
|
+
NODES_DATA
|
|
1904
|
+
.filter(n => n.kind === 'dependency' || n.kind === 'vulnerability')
|
|
1905
|
+
.map(n => n.id)
|
|
1906
|
+
);
|
|
1907
|
+
|
|
1908
|
+
// Dim edges that don't connect to any security node
|
|
1909
|
+
const secEdgeIds = new Set(
|
|
1910
|
+
EDGES_DATA
|
|
1911
|
+
.filter(e => secNodeIds.has(e.from) || secNodeIds.has(e.to))
|
|
1912
|
+
.map(e => e.id)
|
|
1913
|
+
);
|
|
1914
|
+
|
|
1915
|
+
nodesDS.update(NODES_DATA.map(n => ({
|
|
1916
|
+
id: n.id,
|
|
1917
|
+
color: secNodeIds.has(n.id) ? originalColors[n.id] : DIM,
|
|
1918
|
+
})));
|
|
1919
|
+
edgesDS.update(EDGES_DATA.map(e => ({
|
|
1920
|
+
id: e.id,
|
|
1921
|
+
color: secEdgeIds.has(e.id) ? originalEdgeColors[e.id] : { color: '#111118', opacity: 0.08 },
|
|
1922
|
+
})));
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1925
|
+
function exitSecurityOverlay() {
|
|
1926
|
+
securityActive = false;
|
|
1927
|
+
document.getElementById('btn-security').classList.remove('active');
|
|
1928
|
+
document.getElementById('security-legend').style.display = 'none';
|
|
1929
|
+
nodesDS.update(NODES_DATA.map(n => ({ id: n.id, color: originalColors[n.id] })));
|
|
1930
|
+
edgesDS.update(EDGES_DATA.map(e => ({ id: e.id, color: originalEdgeColors[e.id] })));
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1933
|
+
document.getElementById('btn-security').addEventListener('click', () => {
|
|
1934
|
+
if (securityActive) { exitSecurityOverlay(); } else { enterSecurityOverlay(); }
|
|
1935
|
+
});
|
|
1936
|
+
` : "// Security overlay: no security nodes in this graph"}
|
|
1937
|
+
|
|
1772
1938
|
// \u2500\u2500 Keyboard shortcuts \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
1773
1939
|
document.addEventListener('keydown', e => {
|
|
1774
1940
|
if (e.key === 'Escape') {
|
|
@@ -1821,6 +1987,9 @@ function resetToEmpty() {
|
|
|
1821
1987
|
document.getElementById('heat-legend').style.display = 'none';
|
|
1822
1988
|
}
|
|
1823
1989
|
|
|
1990
|
+
// Reset security overlay
|
|
1991
|
+
${hasSecurityNodes ? `if (securityActive) { exitSecurityOverlay(); }` : ""}
|
|
1992
|
+
|
|
1824
1993
|
// Reset context menu
|
|
1825
1994
|
document.getElementById('ctx-menu').style.display = 'none';
|
|
1826
1995
|
ctxNodeId = null;
|
|
@@ -2612,6 +2781,131 @@ function register(program) {
|
|
|
2612
2781
|
`);
|
|
2613
2782
|
openBrowser(indexPath);
|
|
2614
2783
|
});
|
|
2784
|
+
exportCmd.command("graphml [projectPath]").description("Export graph as GraphML (for Gephi, yEd)").option("-o, --output <file>", "Output file path").action(async (projectPath, opts) => {
|
|
2785
|
+
const KiroGraph = (await Promise.resolve().then(() => require("../../index.js"))).default;
|
|
2786
|
+
const target = path.resolve(projectPath ?? process.cwd());
|
|
2787
|
+
const cg = await KiroGraph.open(target);
|
|
2788
|
+
const nodes = cg.getAllNodes();
|
|
2789
|
+
const edges = cg.getAllEdges();
|
|
2790
|
+
cg.close();
|
|
2791
|
+
const outPath = opts.output ?? path.join(target, ".kirograph", "export", "graph.graphml");
|
|
2792
|
+
fs.mkdirSync(path.dirname(outPath), { recursive: true });
|
|
2793
|
+
const lines = [
|
|
2794
|
+
'<?xml version="1.0" encoding="UTF-8"?>',
|
|
2795
|
+
'<graphml xmlns="http://graphml.graphstruct.org/graphml">',
|
|
2796
|
+
' <key id="kind" for="node" attr.name="kind" attr.type="string"/>',
|
|
2797
|
+
' <key id="name" for="node" attr.name="name" attr.type="string"/>',
|
|
2798
|
+
' <key id="file" for="node" attr.name="file" attr.type="string"/>',
|
|
2799
|
+
' <key id="line" for="node" attr.name="line" attr.type="int"/>',
|
|
2800
|
+
' <key id="edgeKind" for="edge" attr.name="kind" attr.type="string"/>',
|
|
2801
|
+
' <graph id="G" edgedefault="directed">'
|
|
2802
|
+
];
|
|
2803
|
+
for (const n of nodes) {
|
|
2804
|
+
lines.push(` <node id="${escHtml(n.id)}">`);
|
|
2805
|
+
lines.push(` <data key="kind">${escHtml(n.kind)}</data>`);
|
|
2806
|
+
lines.push(` <data key="name">${escHtml(n.name)}</data>`);
|
|
2807
|
+
lines.push(` <data key="file">${escHtml(n.filePath)}</data>`);
|
|
2808
|
+
lines.push(` <data key="line">${n.startLine}</data>`);
|
|
2809
|
+
lines.push(` </node>`);
|
|
2810
|
+
}
|
|
2811
|
+
for (const e of edges) {
|
|
2812
|
+
lines.push(` <edge source="${escHtml(e.source)}" target="${escHtml(e.target)}">`);
|
|
2813
|
+
lines.push(` <data key="edgeKind">${escHtml(e.kind)}</data>`);
|
|
2814
|
+
lines.push(` </edge>`);
|
|
2815
|
+
}
|
|
2816
|
+
lines.push(" </graph>", "</graphml>");
|
|
2817
|
+
fs.writeFileSync(outPath, lines.join("\n"), "utf8");
|
|
2818
|
+
console.log(`
|
|
2819
|
+
${import_ui.green}GraphML exported${import_ui.reset}: ${outPath}`);
|
|
2820
|
+
console.log(` ${import_ui.dim}${nodes.length} nodes, ${edges.length} edges${import_ui.reset}
|
|
2821
|
+
`);
|
|
2822
|
+
});
|
|
2823
|
+
exportCmd.command("cypher [projectPath]").description("Export graph as Neo4j Cypher statements").option("-o, --output <file>", "Output file path").action(async (projectPath, opts) => {
|
|
2824
|
+
const KiroGraph = (await Promise.resolve().then(() => require("../../index.js"))).default;
|
|
2825
|
+
const target = path.resolve(projectPath ?? process.cwd());
|
|
2826
|
+
const cg = await KiroGraph.open(target);
|
|
2827
|
+
const nodes = cg.getAllNodes();
|
|
2828
|
+
const edges = cg.getAllEdges();
|
|
2829
|
+
cg.close();
|
|
2830
|
+
const outPath = opts.output ?? path.join(target, ".kirograph", "export", "graph.cypher");
|
|
2831
|
+
fs.mkdirSync(path.dirname(outPath), { recursive: true });
|
|
2832
|
+
const lines = ["// Generated by KiroGraph", "// Import with: cat graph.cypher | cypher-shell", ""];
|
|
2833
|
+
for (const n of nodes) {
|
|
2834
|
+
const label = n.kind.charAt(0).toUpperCase() + n.kind.slice(1);
|
|
2835
|
+
const props = `{id: "${n.id.replace(/"/g, '\\"')}", name: "${n.name.replace(/"/g, '\\"')}", file: "${n.filePath.replace(/"/g, '\\"')}", line: ${n.startLine}}`;
|
|
2836
|
+
lines.push(`CREATE (:${label} ${props});`);
|
|
2837
|
+
}
|
|
2838
|
+
lines.push("");
|
|
2839
|
+
for (const e of edges) {
|
|
2840
|
+
const relType = e.kind.toUpperCase();
|
|
2841
|
+
lines.push(`MATCH (a {id: "${e.source.replace(/"/g, '\\"')}"}), (b {id: "${e.target.replace(/"/g, '\\"')}"}) CREATE (a)-[:${relType}]->(b);`);
|
|
2842
|
+
}
|
|
2843
|
+
fs.writeFileSync(outPath, lines.join("\n"), "utf8");
|
|
2844
|
+
console.log(`
|
|
2845
|
+
${import_ui.green}Neo4j Cypher exported${import_ui.reset}: ${outPath}`);
|
|
2846
|
+
console.log(` ${import_ui.dim}${nodes.length} nodes, ${edges.length} edges${import_ui.reset}
|
|
2847
|
+
`);
|
|
2848
|
+
});
|
|
2849
|
+
exportCmd.command("obsidian [projectPath]").description("Export graph as an Obsidian vault with wikilinks").option("-o, --output <dir>", "Output directory path").action(async (projectPath, opts) => {
|
|
2850
|
+
const KiroGraph = (await Promise.resolve().then(() => require("../../index.js"))).default;
|
|
2851
|
+
const target = path.resolve(projectPath ?? process.cwd());
|
|
2852
|
+
const cg = await KiroGraph.open(target);
|
|
2853
|
+
const nodes = cg.getAllNodes();
|
|
2854
|
+
const edges = cg.getAllEdges();
|
|
2855
|
+
cg.close();
|
|
2856
|
+
const outDir = opts.output ?? path.join(target, ".kirograph", "export", "obsidian");
|
|
2857
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
2858
|
+
const callersMap = /* @__PURE__ */ new Map();
|
|
2859
|
+
const calleesMap = /* @__PURE__ */ new Map();
|
|
2860
|
+
const nodeById = new Map(nodes.map((n) => [n.id, n]));
|
|
2861
|
+
for (const e of edges) {
|
|
2862
|
+
if (e.kind === "calls") {
|
|
2863
|
+
const targetNode = nodeById.get(e.target);
|
|
2864
|
+
const sourceNode = nodeById.get(e.source);
|
|
2865
|
+
if (targetNode) {
|
|
2866
|
+
if (!calleesMap.has(e.source)) calleesMap.set(e.source, []);
|
|
2867
|
+
calleesMap.get(e.source).push(targetNode.name);
|
|
2868
|
+
}
|
|
2869
|
+
if (sourceNode) {
|
|
2870
|
+
if (!callersMap.has(e.target)) callersMap.set(e.target, []);
|
|
2871
|
+
callersMap.get(e.target).push(sourceNode.name);
|
|
2872
|
+
}
|
|
2873
|
+
}
|
|
2874
|
+
}
|
|
2875
|
+
let fileCount = 0;
|
|
2876
|
+
for (const n of nodes) {
|
|
2877
|
+
if (n.kind === "variable" || n.kind === "parameter") continue;
|
|
2878
|
+
const callers = callersMap.get(n.id) ?? [];
|
|
2879
|
+
const callees = calleesMap.get(n.id) ?? [];
|
|
2880
|
+
const lines = [
|
|
2881
|
+
`# ${n.name}`,
|
|
2882
|
+
"",
|
|
2883
|
+
`- **Kind**: ${n.kind}`,
|
|
2884
|
+
`- **File**: \`${n.filePath}:${n.startLine}\``
|
|
2885
|
+
];
|
|
2886
|
+
if (n.signature) lines.push(`- **Signature**: \`${n.signature}\``);
|
|
2887
|
+
if (n.isExported) lines.push(`- **Exported**: yes`);
|
|
2888
|
+
if (callees.length > 0) {
|
|
2889
|
+
lines.push("", "## Calls", "");
|
|
2890
|
+
for (const c of [...new Set(callees)].slice(0, 20)) {
|
|
2891
|
+
lines.push(`- [[${c}]]`);
|
|
2892
|
+
}
|
|
2893
|
+
}
|
|
2894
|
+
if (callers.length > 0) {
|
|
2895
|
+
lines.push("", "## Called by", "");
|
|
2896
|
+
for (const c of [...new Set(callers)].slice(0, 20)) {
|
|
2897
|
+
lines.push(`- [[${c}]]`);
|
|
2898
|
+
}
|
|
2899
|
+
}
|
|
2900
|
+
const safeName = n.name.replace(/[<>:"/\\|?*]/g, "_");
|
|
2901
|
+
fs.writeFileSync(path.join(outDir, `${safeName}.md`), lines.join("\n"), "utf8");
|
|
2902
|
+
fileCount++;
|
|
2903
|
+
}
|
|
2904
|
+
console.log(`
|
|
2905
|
+
${import_ui.green}Obsidian vault exported${import_ui.reset}: ${outDir}`);
|
|
2906
|
+
console.log(` ${import_ui.dim}${fileCount} markdown files with wikilinks${import_ui.reset}
|
|
2907
|
+
`);
|
|
2908
|
+
});
|
|
2615
2909
|
}
|
|
2616
2910
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2617
2911
|
0 && (module.exports = {
|