@rkarim08/sia 1.0.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/.claude-plugin/marketplace.json +35 -0
- package/.claude-plugin/plugin.json +27 -0
- package/.mcp.json +13 -0
- package/CLAUDE.md +226 -0
- package/LICENSE +202 -0
- package/PLUGIN_README.md +253 -0
- package/README.md +1013 -0
- package/agents/sia-changelog-writer.md +89 -0
- package/agents/sia-code-reviewer.md +86 -0
- package/agents/sia-conflict-resolver.md +100 -0
- package/agents/sia-convention-enforcer.md +69 -0
- package/agents/sia-debug.md +106 -0
- package/agents/sia-decision-reviewer.md +101 -0
- package/agents/sia-dependency-tracker.md +80 -0
- package/agents/sia-explain.md +126 -0
- package/agents/sia-feature.md +116 -0
- package/agents/sia-knowledge-capture.md +117 -0
- package/agents/sia-lead-architecture-advisor.md +93 -0
- package/agents/sia-lead-team-health.md +107 -0
- package/agents/sia-migration.md +100 -0
- package/agents/sia-onboarding.md +115 -0
- package/agents/sia-orientation.md +99 -0
- package/agents/sia-pm-briefing.md +106 -0
- package/agents/sia-pm-risk-advisor.md +82 -0
- package/agents/sia-qa-analyst.md +116 -0
- package/agents/sia-qa-regression-map.md +94 -0
- package/agents/sia-refactor.md +115 -0
- package/agents/sia-regression.md +112 -0
- package/agents/sia-security-audit.md +125 -0
- package/agents/sia-test-advisor.md +91 -0
- package/hooks/hooks.json +98 -0
- package/migrations/bridge/001_initial.sql +34 -0
- package/migrations/episodic/001_initial.sql +35 -0
- package/migrations/meta/001_initial.sql +68 -0
- package/migrations/semantic/001_initial.sql +292 -0
- package/migrations/semantic/002_ontology.sql +89 -0
- package/migrations/semantic/003_freshness.sql +63 -0
- package/migrations/semantic/004_v5_unified_schema.sql +194 -0
- package/migrations/semantic/005_backfill_event_kinds.sql +8 -0
- package/migrations/semantic/006_tree_sitter.sql +6 -0
- package/migrations/semantic/007_branch_snapshots.sql +22 -0
- package/package.json +110 -0
- package/scripts/branch-switch.sh +13 -0
- package/scripts/build-wasm-grammars.sh +81 -0
- package/scripts/post-compact.sh +8 -0
- package/scripts/post-tool-use.sh +10 -0
- package/scripts/pre-compact.sh +8 -0
- package/scripts/session-end.sh +8 -0
- package/scripts/session-start.sh +8 -0
- package/scripts/start-mcp.ts +45 -0
- package/scripts/stop-hook.sh +8 -0
- package/scripts/user-prompt-submit.sh +8 -0
- package/scripts/viz-server.ts +152 -0
- package/skills/sia-brainstorm/SKILL.md +156 -0
- package/skills/sia-brainstorm/scripts/frame-template.html +214 -0
- package/skills/sia-brainstorm/scripts/helper.js +95 -0
- package/skills/sia-brainstorm/scripts/server.cjs +338 -0
- package/skills/sia-brainstorm/scripts/start-server.sh +153 -0
- package/skills/sia-brainstorm/scripts/stop-server.sh +55 -0
- package/skills/sia-brainstorm/spec-document-reviewer-prompt.md +49 -0
- package/skills/sia-brainstorm/visual-companion.md +286 -0
- package/skills/sia-capture/SKILL.md +64 -0
- package/skills/sia-compare/SKILL.md +33 -0
- package/skills/sia-conflicts/SKILL.md +38 -0
- package/skills/sia-debug-workflow/SKILL.md +120 -0
- package/skills/sia-debug-workflow/root-cause-tracing.md +70 -0
- package/skills/sia-debug-workflow/scripts/find-polluter.sh +64 -0
- package/skills/sia-debug-workflow/temporal-investigation.md +72 -0
- package/skills/sia-digest/SKILL.md +23 -0
- package/skills/sia-dispatch/SKILL.md +69 -0
- package/skills/sia-dispatch/agent-task-template.md +99 -0
- package/skills/sia-doctor/SKILL.md +39 -0
- package/skills/sia-execute/SKILL.md +70 -0
- package/skills/sia-execute-plan/SKILL.md +85 -0
- package/skills/sia-export-import/SKILL.md +49 -0
- package/skills/sia-export-knowledge/SKILL.md +46 -0
- package/skills/sia-finish/SKILL.md +100 -0
- package/skills/sia-finish/pr-summary-template.md +54 -0
- package/skills/sia-freshness/SKILL.md +38 -0
- package/skills/sia-history/SKILL.md +42 -0
- package/skills/sia-impact/SKILL.md +70 -0
- package/skills/sia-index/SKILL.md +54 -0
- package/skills/sia-install/SKILL.md +39 -0
- package/skills/sia-lead-compliance/SKILL.md +16 -0
- package/skills/sia-lead-drift-report/SKILL.md +16 -0
- package/skills/sia-lead-knowledge-map/SKILL.md +16 -0
- package/skills/sia-learn/SKILL.md +58 -0
- package/skills/sia-plan/SKILL.md +68 -0
- package/skills/sia-plan/plan-reviewer-prompt.md +63 -0
- package/skills/sia-playbooks/SKILL.md +29 -0
- package/skills/sia-playbooks/reference-feature.md +100 -0
- package/skills/sia-playbooks/reference-flagging.md +50 -0
- package/skills/sia-playbooks/reference-orientation.md +92 -0
- package/skills/sia-playbooks/reference-regression.md +115 -0
- package/skills/sia-playbooks/reference-review.md +64 -0
- package/skills/sia-playbooks/reference-tools.md +239 -0
- package/skills/sia-pm-decision-log/SKILL.md +28 -0
- package/skills/sia-pm-risk-dashboard/SKILL.md +24 -0
- package/skills/sia-pm-sprint-summary/SKILL.md +27 -0
- package/skills/sia-prune/SKILL.md +45 -0
- package/skills/sia-qa-coverage/SKILL.md +28 -0
- package/skills/sia-qa-flaky/SKILL.md +20 -0
- package/skills/sia-qa-report/SKILL.md +26 -0
- package/skills/sia-reindex/SKILL.md +30 -0
- package/skills/sia-review-respond/SKILL.md +88 -0
- package/skills/sia-review-respond/pushback-patterns.md +90 -0
- package/skills/sia-search/SKILL.md +47 -0
- package/skills/sia-setup/SKILL.md +82 -0
- package/skills/sia-setup/setup-checklist.md +97 -0
- package/skills/sia-stats/SKILL.md +36 -0
- package/skills/sia-status/SKILL.md +44 -0
- package/skills/sia-sync/SKILL.md +46 -0
- package/skills/sia-team/SKILL.md +64 -0
- package/skills/sia-test/SKILL.md +92 -0
- package/skills/sia-test/testing-anti-patterns.md +104 -0
- package/skills/sia-tour/SKILL.md +29 -0
- package/skills/sia-upgrade/SKILL.md +43 -0
- package/skills/sia-verify/SKILL.md +81 -0
- package/skills/sia-visualize/SKILL.md +28 -0
- package/skills/sia-visualize-live/SKILL.md +55 -0
- package/skills/sia-visualize-live/scripts/graph-template.html +389 -0
- package/skills/sia-visualize-live/scripts/start-visualizer.sh +161 -0
- package/skills/sia-visualize-live/scripts/stop-visualizer.sh +55 -0
- package/skills/sia-visualize-live/scripts/visualizer-server.cjs +264 -0
- package/skills/sia-workspace/SKILL.md +57 -0
- package/src/agent/claude-md-template-flagging.md +219 -0
- package/src/agent/claude-md-template.md +213 -0
- package/src/agent/modules/sia-feature.md +100 -0
- package/src/agent/modules/sia-flagging.md +50 -0
- package/src/agent/modules/sia-orientation.md +92 -0
- package/src/agent/modules/sia-regression.md +115 -0
- package/src/agent/modules/sia-review.md +64 -0
- package/src/agent/modules/sia-tools.md +239 -0
- package/src/ast/extractors/c-include.ts +189 -0
- package/src/ast/extractors/csharp-project.ts +260 -0
- package/src/ast/extractors/prisma-schema.ts +44 -0
- package/src/ast/extractors/project-manifest.ts +111 -0
- package/src/ast/extractors/sql-schema.ts +67 -0
- package/src/ast/extractors/tier-a.ts +423 -0
- package/src/ast/extractors/tier-b.ts +289 -0
- package/src/ast/extractors/tier-dispatch.ts +247 -0
- package/src/ast/index-worker.ts +108 -0
- package/src/ast/indexer.ts +484 -0
- package/src/ast/languages.ts +408 -0
- package/src/ast/pagerank-builder.ts +125 -0
- package/src/ast/path-utils.ts +137 -0
- package/src/ast/tree-sitter/backends/native.ts +57 -0
- package/src/ast/tree-sitter/backends/wasm.ts +39 -0
- package/src/ast/tree-sitter/call-walker.ts +44 -0
- package/src/ast/tree-sitter/edit-computer.ts +55 -0
- package/src/ast/tree-sitter/query-runner.ts +46 -0
- package/src/ast/tree-sitter/service.ts +174 -0
- package/src/ast/tree-sitter/tree-cache.ts +39 -0
- package/src/ast/tree-sitter/types.ts +79 -0
- package/src/ast/watcher.ts +322 -0
- package/src/capture/chunker.ts +169 -0
- package/src/capture/consolidate.ts +127 -0
- package/src/capture/edge-inferrer.ts +161 -0
- package/src/capture/embedder.ts +166 -0
- package/src/capture/embedding-cache.ts +73 -0
- package/src/capture/flag-processor.ts +64 -0
- package/src/capture/hook.ts +67 -0
- package/src/capture/pipeline.ts +450 -0
- package/src/capture/prompts/consolidate.ts +25 -0
- package/src/capture/prompts/edge-infer.ts +29 -0
- package/src/capture/prompts/extract-flagged.ts +36 -0
- package/src/capture/prompts/extract.ts +42 -0
- package/src/capture/tokenizer.ts +147 -0
- package/src/capture/track-a-ast.ts +93 -0
- package/src/capture/track-b-llm.ts +149 -0
- package/src/capture/types.ts +64 -0
- package/src/cli/commands/community.ts +137 -0
- package/src/cli/commands/compare.ts +123 -0
- package/src/cli/commands/conflicts.ts +41 -0
- package/src/cli/commands/digest.ts +197 -0
- package/src/cli/commands/disable-flagging.ts +34 -0
- package/src/cli/commands/doctor.ts +240 -0
- package/src/cli/commands/download-model.ts +161 -0
- package/src/cli/commands/enable-flagging.ts +34 -0
- package/src/cli/commands/export-knowledge.ts +208 -0
- package/src/cli/commands/export.ts +85 -0
- package/src/cli/commands/freshness.ts +164 -0
- package/src/cli/commands/graph.ts +51 -0
- package/src/cli/commands/history.ts +139 -0
- package/src/cli/commands/import.ts +335 -0
- package/src/cli/commands/install.ts +156 -0
- package/src/cli/commands/lead-report.ts +241 -0
- package/src/cli/commands/learn.ts +321 -0
- package/src/cli/commands/pm-report.ts +413 -0
- package/src/cli/commands/prune.ts +75 -0
- package/src/cli/commands/qa-report.ts +278 -0
- package/src/cli/commands/reindex.ts +104 -0
- package/src/cli/commands/rollback.ts +70 -0
- package/src/cli/commands/search.ts +103 -0
- package/src/cli/commands/server.ts +91 -0
- package/src/cli/commands/share.ts +33 -0
- package/src/cli/commands/stats.ts +79 -0
- package/src/cli/commands/status.ts +176 -0
- package/src/cli/commands/sync.ts +96 -0
- package/src/cli/commands/team.ts +118 -0
- package/src/cli/commands/tour.ts +157 -0
- package/src/cli/commands/visualize-live.ts +162 -0
- package/src/cli/commands/workspace.ts +117 -0
- package/src/cli/index.ts +424 -0
- package/src/cli/learn-progress.ts +87 -0
- package/src/community/detection-bridge.ts +344 -0
- package/src/community/leiden.ts +462 -0
- package/src/community/raptor.ts +210 -0
- package/src/community/scheduler.ts +74 -0
- package/src/community/summarize.ts +115 -0
- package/src/decay/archiver.ts +73 -0
- package/src/decay/bridge-orphan-cleanup.ts +212 -0
- package/src/decay/consolidation-sweep.ts +112 -0
- package/src/decay/decay.ts +116 -0
- package/src/decay/deep-validator.ts +62 -0
- package/src/decay/episodic-promoter.ts +132 -0
- package/src/decay/maintenance-scheduler.ts +326 -0
- package/src/decay/scheduler.ts +6 -0
- package/src/decay/session-sweeper.ts +79 -0
- package/src/decay/types.ts +17 -0
- package/src/freshness/confidence-decay.ts +122 -0
- package/src/freshness/cuckoo-filter.ts +176 -0
- package/src/freshness/deep-validation.ts +345 -0
- package/src/freshness/dirty-tracker.ts +237 -0
- package/src/freshness/file-watcher-layer.ts +119 -0
- package/src/freshness/firewall.ts +64 -0
- package/src/freshness/git-reconcile-layer.ts +161 -0
- package/src/freshness/inverted-index.ts +158 -0
- package/src/freshness/stale-read-layer.ts +222 -0
- package/src/graph/audit.ts +69 -0
- package/src/graph/bridge-db.ts +141 -0
- package/src/graph/communities.ts +195 -0
- package/src/graph/db-interface.ts +259 -0
- package/src/graph/edges.ts +163 -0
- package/src/graph/entities.ts +327 -0
- package/src/graph/episodic-db.ts +113 -0
- package/src/graph/flags.ts +31 -0
- package/src/graph/meta-db.ts +200 -0
- package/src/graph/semantic-db.ts +101 -0
- package/src/graph/session-resume.ts +56 -0
- package/src/graph/snapshots.ts +342 -0
- package/src/graph/staging.ts +151 -0
- package/src/graph/types.ts +128 -0
- package/src/hooks/adapters/claude-code.ts +21 -0
- package/src/hooks/adapters/cline.ts +43 -0
- package/src/hooks/adapters/cursor.ts +65 -0
- package/src/hooks/adapters/generic.ts +12 -0
- package/src/hooks/agent-detect.ts +34 -0
- package/src/hooks/claude-md-directives.ts +32 -0
- package/src/hooks/event-router.ts +182 -0
- package/src/hooks/extractors/pattern-detector.ts +111 -0
- package/src/hooks/handlers/post-compact.ts +30 -0
- package/src/hooks/handlers/post-tool-use.ts +403 -0
- package/src/hooks/handlers/pre-compact.ts +100 -0
- package/src/hooks/handlers/session-end.ts +47 -0
- package/src/hooks/handlers/session-start.ts +154 -0
- package/src/hooks/handlers/stop.ts +128 -0
- package/src/hooks/handlers/user-prompt-submit.ts +68 -0
- package/src/hooks/plugin-branch-switch.ts +68 -0
- package/src/hooks/plugin-common.ts +47 -0
- package/src/hooks/plugin-post-compact.ts +28 -0
- package/src/hooks/plugin-post-tool-use.ts +38 -0
- package/src/hooks/plugin-pre-compact.ts +37 -0
- package/src/hooks/plugin-session-end.ts +37 -0
- package/src/hooks/plugin-session-start.ts +75 -0
- package/src/hooks/plugin-stop.ts +61 -0
- package/src/hooks/plugin-user-prompt-submit.ts +47 -0
- package/src/hooks/types.ts +43 -0
- package/src/knowledge/discovery.ts +238 -0
- package/src/knowledge/external-refs.ts +98 -0
- package/src/knowledge/freshness.ts +221 -0
- package/src/knowledge/ingest.ts +330 -0
- package/src/knowledge/markdown-export.ts +229 -0
- package/src/knowledge/markdown-import.ts +359 -0
- package/src/knowledge/patterns.ts +74 -0
- package/src/knowledge/templates.ts +307 -0
- package/src/llm/ai-sdk-adapter.ts +46 -0
- package/src/llm/config.ts +88 -0
- package/src/llm/cost-tracker.ts +110 -0
- package/src/llm/prompts/extraction.ts +55 -0
- package/src/llm/prompts/summarization.ts +36 -0
- package/src/llm/prompts/validation.ts +37 -0
- package/src/llm/provider-registry.ts +68 -0
- package/src/llm/reliability.ts +179 -0
- package/src/llm/schemas.ts +52 -0
- package/src/mcp/freshness-annotator.ts +69 -0
- package/src/mcp/server.ts +949 -0
- package/src/mcp/tools/sia-ast-query.ts +225 -0
- package/src/mcp/tools/sia-at-time.ts +151 -0
- package/src/mcp/tools/sia-backlinks.ts +87 -0
- package/src/mcp/tools/sia-batch-execute.ts +169 -0
- package/src/mcp/tools/sia-by-file.ts +89 -0
- package/src/mcp/tools/sia-community.ts +113 -0
- package/src/mcp/tools/sia-doctor.ts +73 -0
- package/src/mcp/tools/sia-execute-file.ts +122 -0
- package/src/mcp/tools/sia-execute.ts +104 -0
- package/src/mcp/tools/sia-expand.ts +158 -0
- package/src/mcp/tools/sia-fetch-and-index.ts +241 -0
- package/src/mcp/tools/sia-flag.ts +65 -0
- package/src/mcp/tools/sia-index.ts +111 -0
- package/src/mcp/tools/sia-note.ts +134 -0
- package/src/mcp/tools/sia-search.ts +105 -0
- package/src/mcp/tools/sia-stats.ts +63 -0
- package/src/mcp/tools/sia-sync-status.ts +44 -0
- package/src/mcp/tools/sia-upgrade.ts +247 -0
- package/src/mcp/truncate.ts +231 -0
- package/src/native/bridge.ts +167 -0
- package/src/native/fallback-ast-diff.ts +144 -0
- package/src/native/fallback-graph.ts +325 -0
- package/src/ontology/constraints.ts +56 -0
- package/src/ontology/errors.ts +8 -0
- package/src/ontology/middleware.ts +266 -0
- package/src/retrieval/bm25-search.ts +151 -0
- package/src/retrieval/context-assembly.ts +76 -0
- package/src/retrieval/graph-traversal.ts +168 -0
- package/src/retrieval/pagerank.ts +40 -0
- package/src/retrieval/query-classifier.ts +106 -0
- package/src/retrieval/reranker.ts +156 -0
- package/src/retrieval/search.ts +236 -0
- package/src/retrieval/throttle.ts +102 -0
- package/src/retrieval/vector-search.ts +203 -0
- package/src/retrieval/workspace-search.ts +130 -0
- package/src/sandbox/context-mode.ts +285 -0
- package/src/sandbox/credential-pass.ts +55 -0
- package/src/sandbox/executor.ts +235 -0
- package/src/security/pattern-detector.ts +127 -0
- package/src/security/rule-of-two.ts +50 -0
- package/src/security/sanitize.ts +46 -0
- package/src/security/semantic-consistency.ts +93 -0
- package/src/security/staging-promoter.ts +154 -0
- package/src/shared/config.ts +302 -0
- package/src/shared/diagnostics.ts +210 -0
- package/src/shared/errors.ts +48 -0
- package/src/shared/git-utils.ts +143 -0
- package/src/shared/llm-client.ts +120 -0
- package/src/shared/logger.ts +99 -0
- package/src/shared/types.ts +79 -0
- package/src/sync/client.ts +43 -0
- package/src/sync/conflict.ts +106 -0
- package/src/sync/dedup.ts +183 -0
- package/src/sync/hlc.ts +117 -0
- package/src/sync/keychain.ts +144 -0
- package/src/sync/pull.ts +232 -0
- package/src/sync/push.ts +131 -0
- package/src/types/chokidar.d.ts +23 -0
- package/src/visualization/graph-renderer.ts +312 -0
- package/src/visualization/subgraph-extract.ts +208 -0
- package/src/visualization/views/community-clusters.ts +246 -0
- package/src/visualization/views/dependency-map.ts +189 -0
- package/src/visualization/views/graph-explorer.ts +364 -0
- package/src/visualization/views/timeline.ts +247 -0
- package/src/workspace/api-contracts.ts +226 -0
- package/src/workspace/cross-repo.ts +61 -0
- package/src/workspace/detector.ts +190 -0
- package/src/workspace/manifest.ts +141 -0
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
// Module: markdown-import — Import markdown vault into knowledge graph
|
|
2
|
+
|
|
3
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
4
|
+
import { basename, join } from "node:path";
|
|
5
|
+
import type { SiaDb } from "@/graph/db-interface";
|
|
6
|
+
import { insertEdge } from "@/graph/edges";
|
|
7
|
+
import { insertEntity } from "@/graph/entities";
|
|
8
|
+
|
|
9
|
+
export interface MarkdownImportResult {
|
|
10
|
+
entitiesImported: number;
|
|
11
|
+
edgesCreated: number;
|
|
12
|
+
errors: string[];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Parsed markdown file with metadata and content. */
|
|
16
|
+
interface ParsedMarkdownFile {
|
|
17
|
+
filePath: string;
|
|
18
|
+
slug: string;
|
|
19
|
+
frontmatter: Record<string, unknown>;
|
|
20
|
+
body: string;
|
|
21
|
+
heading: string | null;
|
|
22
|
+
wikilinks: string[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Parse YAML frontmatter from a markdown string.
|
|
27
|
+
* Expects content to start with `---` delimiter followed by YAML key-value
|
|
28
|
+
* pairs and closed with another `---`.
|
|
29
|
+
*
|
|
30
|
+
* Returns the parsed frontmatter object and the remaining body.
|
|
31
|
+
* If no frontmatter is found, returns an empty object and the full content as body.
|
|
32
|
+
*/
|
|
33
|
+
function parseFrontmatter(content: string): { frontmatter: Record<string, unknown>; body: string } {
|
|
34
|
+
const trimmed = content.trimStart();
|
|
35
|
+
if (!trimmed.startsWith("---")) {
|
|
36
|
+
return { frontmatter: {}, body: content };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Find the closing `---` (must be on its own line after the opening)
|
|
40
|
+
const afterOpening = trimmed.slice(3);
|
|
41
|
+
const closingIdx = afterOpening.indexOf("\n---");
|
|
42
|
+
if (closingIdx === -1) {
|
|
43
|
+
return { frontmatter: {}, body: content };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const yamlBlock = afterOpening.slice(0, closingIdx).trim();
|
|
47
|
+
const body = afterOpening.slice(closingIdx + 4).trim();
|
|
48
|
+
|
|
49
|
+
const frontmatter: Record<string, unknown> = {};
|
|
50
|
+
|
|
51
|
+
for (const line of yamlBlock.split("\n")) {
|
|
52
|
+
const colonIdx = line.indexOf(":");
|
|
53
|
+
if (colonIdx === -1) continue;
|
|
54
|
+
|
|
55
|
+
const key = line.slice(0, colonIdx).trim();
|
|
56
|
+
let value: unknown = line.slice(colonIdx + 1).trim();
|
|
57
|
+
|
|
58
|
+
if (key === "" || value === "") continue;
|
|
59
|
+
|
|
60
|
+
const strValue = value as string;
|
|
61
|
+
|
|
62
|
+
// Parse YAML arrays: [a, b, c]
|
|
63
|
+
if (strValue.startsWith("[") && strValue.endsWith("]")) {
|
|
64
|
+
const inner = strValue.slice(1, -1);
|
|
65
|
+
if (inner.trim() === "") {
|
|
66
|
+
value = [];
|
|
67
|
+
} else {
|
|
68
|
+
value = inner.split(",").map((item) => parseYamlScalar(item.trim()));
|
|
69
|
+
}
|
|
70
|
+
} else {
|
|
71
|
+
value = parseYamlScalar(strValue);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
frontmatter[key] = value;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return { frontmatter, body };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Parse a YAML scalar value into a JS primitive.
|
|
82
|
+
* Handles numbers, booleans, null, and quoted strings.
|
|
83
|
+
*/
|
|
84
|
+
function parseYamlScalar(raw: string): string | number | boolean | null {
|
|
85
|
+
// Unquote double-quoted strings
|
|
86
|
+
if (raw.startsWith('"') && raw.endsWith('"')) {
|
|
87
|
+
return raw.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, "\\");
|
|
88
|
+
}
|
|
89
|
+
// Unquote single-quoted strings
|
|
90
|
+
if (raw.startsWith("'") && raw.endsWith("'")) {
|
|
91
|
+
return raw.slice(1, -1);
|
|
92
|
+
}
|
|
93
|
+
// null / ~
|
|
94
|
+
if (raw === "null" || raw === "~") return null;
|
|
95
|
+
// booleans
|
|
96
|
+
if (raw === "true") return true;
|
|
97
|
+
if (raw === "false") return false;
|
|
98
|
+
// numbers
|
|
99
|
+
const num = Number(raw);
|
|
100
|
+
if (!Number.isNaN(num) && raw !== "") return num;
|
|
101
|
+
// fallback to string
|
|
102
|
+
return raw;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Extract wikilinks from markdown content.
|
|
107
|
+
* Matches `[[path/slug]]` patterns and returns the link targets.
|
|
108
|
+
*/
|
|
109
|
+
function extractWikilinks(content: string): string[] {
|
|
110
|
+
const regex = /\[\[([^\]]+)\]\]/g;
|
|
111
|
+
const links: string[] = [];
|
|
112
|
+
let match: RegExpExecArray | null;
|
|
113
|
+
match = regex.exec(content);
|
|
114
|
+
while (match !== null) {
|
|
115
|
+
if (match[1] !== undefined) {
|
|
116
|
+
links.push(match[1]);
|
|
117
|
+
}
|
|
118
|
+
match = regex.exec(content);
|
|
119
|
+
}
|
|
120
|
+
return links;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Extract the first H1 heading from a markdown body.
|
|
125
|
+
* Returns null if no heading is found.
|
|
126
|
+
*/
|
|
127
|
+
function extractHeading(body: string): string | null {
|
|
128
|
+
const match = /^#\s+(.+)$/m.exec(body);
|
|
129
|
+
return match ? (match[1]?.trim() ?? null) : null;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Strip the "## Related" section from the body content so it doesn't
|
|
134
|
+
* pollute the entity content.
|
|
135
|
+
*/
|
|
136
|
+
function stripRelatedSection(body: string): string {
|
|
137
|
+
const relatedIdx = body.indexOf("\n## Related");
|
|
138
|
+
if (relatedIdx === -1) return body;
|
|
139
|
+
return body.slice(0, relatedIdx).trimEnd();
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Derive the entity type from the directory name of the file.
|
|
144
|
+
* "decisions" -> "Decision", "bugs" -> "Bug", etc.
|
|
145
|
+
* Falls back to "Concept" if the directory doesn't map to a known type.
|
|
146
|
+
*/
|
|
147
|
+
function dirToType(dirName: string): string {
|
|
148
|
+
const mapping: Record<string, string> = {
|
|
149
|
+
decisions: "Decision",
|
|
150
|
+
conventions: "Convention",
|
|
151
|
+
bugs: "Bug",
|
|
152
|
+
solutions: "Solution",
|
|
153
|
+
concepts: "Concept",
|
|
154
|
+
code: "CodeEntity",
|
|
155
|
+
files: "FileNode",
|
|
156
|
+
};
|
|
157
|
+
return mapping[dirName] ?? "Concept";
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Extract the slug portion from a wikilink target.
|
|
162
|
+
* "decisions/use-jwt-rs256" -> "use-jwt-rs256"
|
|
163
|
+
* "use-jwt-rs256" -> "use-jwt-rs256"
|
|
164
|
+
*/
|
|
165
|
+
function slugFromLink(link: string): string {
|
|
166
|
+
const parts = link.split("/");
|
|
167
|
+
return parts[parts.length - 1] ?? link;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Walk a directory recursively, collecting all .md file paths.
|
|
172
|
+
* Skips index.md at any level.
|
|
173
|
+
*/
|
|
174
|
+
function walkMarkdownFiles(dir: string): string[] {
|
|
175
|
+
const results: string[] = [];
|
|
176
|
+
|
|
177
|
+
if (!existsSync(dir)) return results;
|
|
178
|
+
|
|
179
|
+
let names: string[];
|
|
180
|
+
try {
|
|
181
|
+
names = readdirSync(dir);
|
|
182
|
+
} catch {
|
|
183
|
+
return results;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
for (const name of names) {
|
|
187
|
+
const fullPath = join(dir, name);
|
|
188
|
+
let stat: ReturnType<typeof statSync>;
|
|
189
|
+
try {
|
|
190
|
+
stat = statSync(fullPath);
|
|
191
|
+
} catch {
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
if (stat.isDirectory()) {
|
|
195
|
+
results.push(...walkMarkdownFiles(fullPath));
|
|
196
|
+
} else if (stat.isFile() && name.endsWith(".md") && name !== "index.md") {
|
|
197
|
+
results.push(fullPath);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return results;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Import markdown files from a vault directory into the knowledge graph.
|
|
206
|
+
* Parses YAML frontmatter for metadata, markdown body for content.
|
|
207
|
+
* Resolves [[wikilinks]] to graph edges.
|
|
208
|
+
*/
|
|
209
|
+
export async function importFromMarkdown(
|
|
210
|
+
db: SiaDb,
|
|
211
|
+
inputDir: string,
|
|
212
|
+
): Promise<MarkdownImportResult> {
|
|
213
|
+
const errors: string[] = [];
|
|
214
|
+
let entitiesImported = 0;
|
|
215
|
+
let edgesCreated = 0;
|
|
216
|
+
|
|
217
|
+
// Phase 1: Discover and parse all markdown files
|
|
218
|
+
const filePaths = walkMarkdownFiles(inputDir);
|
|
219
|
+
const parsed: ParsedMarkdownFile[] = [];
|
|
220
|
+
|
|
221
|
+
for (const filePath of filePaths) {
|
|
222
|
+
try {
|
|
223
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
224
|
+
const { frontmatter, body } = parseFrontmatter(raw);
|
|
225
|
+
|
|
226
|
+
// Determine heading: prefer extracted H1, then fall back to filename
|
|
227
|
+
const heading = extractHeading(body);
|
|
228
|
+
const fallbackName = basename(filePath, ".md")
|
|
229
|
+
.replace(/-/g, " ")
|
|
230
|
+
.replace(/\b\w/g, (c) => c.toUpperCase());
|
|
231
|
+
|
|
232
|
+
// Determine slug from filename (without extension)
|
|
233
|
+
const slug = basename(filePath, ".md");
|
|
234
|
+
|
|
235
|
+
// Extract wikilinks from the body
|
|
236
|
+
const wikilinks = extractWikilinks(body);
|
|
237
|
+
|
|
238
|
+
parsed.push({
|
|
239
|
+
filePath,
|
|
240
|
+
slug,
|
|
241
|
+
frontmatter,
|
|
242
|
+
body,
|
|
243
|
+
heading: heading ?? fallbackName,
|
|
244
|
+
wikilinks,
|
|
245
|
+
});
|
|
246
|
+
} catch (err) {
|
|
247
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
248
|
+
errors.push(`Failed to parse ${filePath}: ${msg}`);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Phase 2: Insert entities
|
|
253
|
+
// Map slug -> entity ID for edge resolution
|
|
254
|
+
const slugToId = new Map<string, string>();
|
|
255
|
+
|
|
256
|
+
for (const file of parsed) {
|
|
257
|
+
try {
|
|
258
|
+
const fm = file.frontmatter;
|
|
259
|
+
|
|
260
|
+
// Determine type from frontmatter.kind or from the parent directory name
|
|
261
|
+
let type = "Concept";
|
|
262
|
+
if (typeof fm.kind === "string" && fm.kind !== "") {
|
|
263
|
+
type = fm.kind;
|
|
264
|
+
} else {
|
|
265
|
+
// Infer from parent directory
|
|
266
|
+
const parentDir = basename(join(file.filePath, ".."));
|
|
267
|
+
type = dirToType(parentDir);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Clean body: strip the heading line and the related section
|
|
271
|
+
let content = stripRelatedSection(file.body);
|
|
272
|
+
// Remove the leading H1 heading from content since we store name separately
|
|
273
|
+
content = content.replace(/^#\s+.+\n*/, "").trim();
|
|
274
|
+
|
|
275
|
+
// Build tags
|
|
276
|
+
let tags = "[]";
|
|
277
|
+
if (Array.isArray(fm.tags)) {
|
|
278
|
+
tags = JSON.stringify(fm.tags.map(String));
|
|
279
|
+
} else if (typeof fm.tags === "string") {
|
|
280
|
+
tags = fm.tags;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Resolve trust_tier
|
|
284
|
+
const trustTier = typeof fm.trust_tier === "number" ? fm.trust_tier : 1;
|
|
285
|
+
|
|
286
|
+
// Resolve importance
|
|
287
|
+
const importance = typeof fm.importance === "number" ? fm.importance : 0.5;
|
|
288
|
+
|
|
289
|
+
// Build summary: first 150 characters of content
|
|
290
|
+
const summary = content.length > 150 ? `${content.slice(0, 147)}...` : content;
|
|
291
|
+
|
|
292
|
+
const entity = await insertEntity(db, {
|
|
293
|
+
type,
|
|
294
|
+
name: file.heading ?? file.slug,
|
|
295
|
+
content,
|
|
296
|
+
summary,
|
|
297
|
+
tags,
|
|
298
|
+
trust_tier: trustTier,
|
|
299
|
+
importance,
|
|
300
|
+
extraction_method: "markdown-import",
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
slugToId.set(file.slug, entity.id);
|
|
304
|
+
entitiesImported++;
|
|
305
|
+
} catch (err) {
|
|
306
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
307
|
+
errors.push(`Failed to import ${file.filePath}: ${msg}`);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Phase 3: Resolve wikilinks to edges
|
|
312
|
+
for (const file of parsed) {
|
|
313
|
+
const sourceId = slugToId.get(file.slug);
|
|
314
|
+
if (!sourceId) continue;
|
|
315
|
+
|
|
316
|
+
for (const link of file.wikilinks) {
|
|
317
|
+
try {
|
|
318
|
+
const targetSlug = slugFromLink(link);
|
|
319
|
+
const targetId = slugToId.get(targetSlug);
|
|
320
|
+
if (!targetId) continue;
|
|
321
|
+
if (targetId === sourceId) continue;
|
|
322
|
+
|
|
323
|
+
// Determine edge type from the wikilink context:
|
|
324
|
+
// Look for "- {edge_type}: [[link]]" pattern
|
|
325
|
+
const edgeType = resolveEdgeType(file.body, link);
|
|
326
|
+
|
|
327
|
+
await insertEdge(db, {
|
|
328
|
+
from_id: sourceId,
|
|
329
|
+
to_id: targetId,
|
|
330
|
+
type: edgeType,
|
|
331
|
+
extraction_method: "markdown-import",
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
edgesCreated++;
|
|
335
|
+
} catch (err) {
|
|
336
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
337
|
+
errors.push(`Failed to create edge from ${file.slug} -> ${link}: ${msg}`);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
return { entitiesImported, edgesCreated, errors };
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Attempt to resolve the edge type from the surrounding markdown context.
|
|
347
|
+
* Looks for the pattern `- {edge_type}: [[link]]` near the wikilink.
|
|
348
|
+
* Falls back to "relates_to" if no pattern is found.
|
|
349
|
+
*/
|
|
350
|
+
function resolveEdgeType(body: string, link: string): string {
|
|
351
|
+
// Match "- some_edge_type: [[link]]"
|
|
352
|
+
const escapedLink = link.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
353
|
+
const pattern = new RegExp(`-\\s+([\\w_]+):\\s*\\[\\[${escapedLink}\\]\\]`);
|
|
354
|
+
const match = pattern.exec(body);
|
|
355
|
+
if (match && match[1] !== undefined) {
|
|
356
|
+
return match[1];
|
|
357
|
+
}
|
|
358
|
+
return "relates_to";
|
|
359
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// Module: patterns — File patterns for documentation auto-discovery
|
|
2
|
+
|
|
3
|
+
export interface DiscoveryPattern {
|
|
4
|
+
glob: string;
|
|
5
|
+
priority: 1 | 2 | 3 | 4 | 5;
|
|
6
|
+
tag: string;
|
|
7
|
+
trustTier: 1 | 2;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Priority 1 — AI context files (highest signal density)
|
|
11
|
+
// Priority 2 — Architecture documentation
|
|
12
|
+
// Priority 3 — Project documentation
|
|
13
|
+
// Priority 4 — API documentation
|
|
14
|
+
// Priority 5 — Change history
|
|
15
|
+
|
|
16
|
+
export const DISCOVERY_PATTERNS: DiscoveryPattern[] = [
|
|
17
|
+
// Priority 1 — AI context files
|
|
18
|
+
{ glob: "AGENTS.md", priority: 1, tag: "ai-context", trustTier: 1 },
|
|
19
|
+
{ glob: "CLAUDE.md", priority: 1, tag: "ai-context", trustTier: 1 },
|
|
20
|
+
{ glob: ".claude/CLAUDE.md", priority: 1, tag: "ai-context", trustTier: 1 },
|
|
21
|
+
{ glob: "GEMINI.md", priority: 1, tag: "ai-context", trustTier: 1 },
|
|
22
|
+
{ glob: ".cursor/rules/*.mdc", priority: 1, tag: "ai-context", trustTier: 1 },
|
|
23
|
+
{ glob: ".windsurf/rules/*.md", priority: 1, tag: "ai-context", trustTier: 1 },
|
|
24
|
+
{ glob: ".clinerules/*.md", priority: 1, tag: "ai-context", trustTier: 1 },
|
|
25
|
+
{ glob: ".github/copilot-instructions.md", priority: 1, tag: "ai-context", trustTier: 1 },
|
|
26
|
+
{ glob: ".github/instructions/*.instructions.md", priority: 1, tag: "ai-context", trustTier: 1 },
|
|
27
|
+
{ glob: ".amazonq/rules/*.md", priority: 1, tag: "ai-context", trustTier: 1 },
|
|
28
|
+
{ glob: ".continue/rules/*.md", priority: 1, tag: "ai-context", trustTier: 1 },
|
|
29
|
+
|
|
30
|
+
// Priority 2 — Architecture documentation
|
|
31
|
+
{ glob: "ARCHITECTURE.md", priority: 2, tag: "architecture", trustTier: 1 },
|
|
32
|
+
{ glob: "DESIGN.md", priority: 2, tag: "architecture", trustTier: 1 },
|
|
33
|
+
{ glob: "docs/adr/*.md", priority: 2, tag: "architecture", trustTier: 1 },
|
|
34
|
+
{ glob: "docs/decisions/*.md", priority: 2, tag: "architecture", trustTier: 1 },
|
|
35
|
+
{ glob: "docs/architecture/*.md", priority: 2, tag: "architecture", trustTier: 1 },
|
|
36
|
+
|
|
37
|
+
// Priority 3 — Project documentation
|
|
38
|
+
{ glob: "README.md", priority: 3, tag: "project-docs", trustTier: 1 },
|
|
39
|
+
{ glob: "CONTRIBUTING.md", priority: 3, tag: "project-docs", trustTier: 1 },
|
|
40
|
+
{ glob: "CONVENTIONS.md", priority: 3, tag: "project-docs", trustTier: 1 },
|
|
41
|
+
{ glob: "STANDARDS.md", priority: 3, tag: "project-docs", trustTier: 1 },
|
|
42
|
+
{ glob: "CONTEXT.md", priority: 3, tag: "project-docs", trustTier: 1 },
|
|
43
|
+
{ glob: "docs/*.md", priority: 3, tag: "project-docs", trustTier: 1 },
|
|
44
|
+
|
|
45
|
+
// Priority 4 — API documentation
|
|
46
|
+
{ glob: "openapi.yaml", priority: 4, tag: "api-docs", trustTier: 2 },
|
|
47
|
+
{ glob: "openapi.json", priority: 4, tag: "api-docs", trustTier: 2 },
|
|
48
|
+
{ glob: "swagger.yaml", priority: 4, tag: "api-docs", trustTier: 2 },
|
|
49
|
+
{ glob: "swagger.json", priority: 4, tag: "api-docs", trustTier: 2 },
|
|
50
|
+
{ glob: "schema.graphql", priority: 4, tag: "api-docs", trustTier: 2 },
|
|
51
|
+
{ glob: "API.md", priority: 4, tag: "api-docs", trustTier: 2 },
|
|
52
|
+
{ glob: "docs/api/*.md", priority: 4, tag: "api-docs", trustTier: 2 },
|
|
53
|
+
|
|
54
|
+
// Priority 5 — Change history
|
|
55
|
+
{ glob: "CHANGELOG.md", priority: 5, tag: "changelog", trustTier: 2 },
|
|
56
|
+
{ glob: "HISTORY.md", priority: 5, tag: "changelog", trustTier: 2 },
|
|
57
|
+
{ glob: "MIGRATION.md", priority: 5, tag: "changelog", trustTier: 2 },
|
|
58
|
+
{ glob: "UPGRADING.md", priority: 5, tag: "changelog", trustTier: 2 },
|
|
59
|
+
];
|
|
60
|
+
|
|
61
|
+
export const EXCLUDED_DIRS = new Set([
|
|
62
|
+
"node_modules",
|
|
63
|
+
"vendor",
|
|
64
|
+
".git",
|
|
65
|
+
"dist",
|
|
66
|
+
"build",
|
|
67
|
+
".next",
|
|
68
|
+
".nuxt",
|
|
69
|
+
"__pycache__",
|
|
70
|
+
".venv",
|
|
71
|
+
"target",
|
|
72
|
+
"coverage",
|
|
73
|
+
".cache",
|
|
74
|
+
]);
|