@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,208 @@
|
|
|
1
|
+
// Module: export-knowledge — Generate human-readable knowledge document
|
|
2
|
+
//
|
|
3
|
+
// Queries the graph and produces a structured markdown document organized
|
|
4
|
+
// by knowledge category: decisions, conventions, bugs, solutions, concepts,
|
|
5
|
+
// community structure, and documentation.
|
|
6
|
+
|
|
7
|
+
import { writeFileSync } from "node:fs";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import type { SiaDb } from "@/graph/db-interface";
|
|
10
|
+
|
|
11
|
+
export interface ExportOptions {
|
|
12
|
+
projectName?: string;
|
|
13
|
+
outputPath?: string;
|
|
14
|
+
includeCommunities?: boolean;
|
|
15
|
+
includeCodeEntities?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface EntityRow {
|
|
19
|
+
id: string;
|
|
20
|
+
type: string;
|
|
21
|
+
name: string;
|
|
22
|
+
content: string;
|
|
23
|
+
summary: string | null;
|
|
24
|
+
trust_tier: number;
|
|
25
|
+
importance: number;
|
|
26
|
+
created_at: number;
|
|
27
|
+
file_paths: string | null;
|
|
28
|
+
kind: string | null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function queryByType(db: SiaDb, type: string, limit: number = 50): Promise<EntityRow[]> {
|
|
32
|
+
const result = await db.execute(
|
|
33
|
+
`SELECT id, type, name, content, summary, trust_tier, importance, created_at, file_paths, kind
|
|
34
|
+
FROM graph_nodes
|
|
35
|
+
WHERE type = ? AND t_valid_until IS NULL AND archived_at IS NULL
|
|
36
|
+
ORDER BY importance DESC, created_at DESC
|
|
37
|
+
LIMIT ?`,
|
|
38
|
+
[type, limit],
|
|
39
|
+
);
|
|
40
|
+
return result.rows as unknown as EntityRow[];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function formatDate(ms: number): string {
|
|
44
|
+
return new Date(ms).toISOString().split("T")[0];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function tierLabel(tier: number): string {
|
|
48
|
+
return tier === 1
|
|
49
|
+
? "verified"
|
|
50
|
+
: tier === 2
|
|
51
|
+
? "code-derived"
|
|
52
|
+
: tier === 3
|
|
53
|
+
? "inferred"
|
|
54
|
+
: "external";
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function formatEntities(entities: EntityRow[], showContent: boolean = true): string {
|
|
58
|
+
if (entities.length === 0) return "*None captured yet.*\n";
|
|
59
|
+
|
|
60
|
+
return entities
|
|
61
|
+
.map((e) => {
|
|
62
|
+
const date = formatDate(e.created_at);
|
|
63
|
+
const tier = tierLabel(e.trust_tier);
|
|
64
|
+
const files = e.file_paths ? ` | Files: ${e.file_paths}` : "";
|
|
65
|
+
let text = `### ${e.name}\n`;
|
|
66
|
+
text += `*${date} | ${tier}${files}*\n\n`;
|
|
67
|
+
if (showContent && e.content) {
|
|
68
|
+
text += `${e.content.slice(0, 500)}\n`;
|
|
69
|
+
} else if (e.summary) {
|
|
70
|
+
text += `${e.summary}\n`;
|
|
71
|
+
}
|
|
72
|
+
return text;
|
|
73
|
+
})
|
|
74
|
+
.join("\n---\n\n");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export async function generateKnowledgeDocument(
|
|
78
|
+
db: SiaDb,
|
|
79
|
+
opts: ExportOptions = {},
|
|
80
|
+
): Promise<string> {
|
|
81
|
+
const projectName = opts.projectName ?? "Project";
|
|
82
|
+
|
|
83
|
+
const decisions = await queryByType(db, "Decision");
|
|
84
|
+
const conventions = await queryByType(db, "Convention");
|
|
85
|
+
const bugs = await queryByType(db, "Bug");
|
|
86
|
+
const solutions = await queryByType(db, "Solution");
|
|
87
|
+
const concepts = await queryByType(db, "Concept");
|
|
88
|
+
|
|
89
|
+
// Count totals
|
|
90
|
+
const totalResult = await db.execute(
|
|
91
|
+
"SELECT COUNT(*) as cnt FROM graph_nodes WHERE t_valid_until IS NULL AND archived_at IS NULL",
|
|
92
|
+
);
|
|
93
|
+
const totalEntities = (totalResult.rows[0] as any).cnt;
|
|
94
|
+
|
|
95
|
+
if (totalEntities === 0) {
|
|
96
|
+
return `# ${projectName} — Knowledge Base\n\n*No knowledge captured yet. Run \`/sia-learn\` to build the knowledge graph.*\n`;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const sections: string[] = [];
|
|
100
|
+
|
|
101
|
+
// Header
|
|
102
|
+
sections.push(`# ${projectName} — Knowledge Base`);
|
|
103
|
+
sections.push(
|
|
104
|
+
`\n*Generated by SIA on ${formatDate(Date.now())} | ${totalEntities} total entities*\n`,
|
|
105
|
+
);
|
|
106
|
+
sections.push("---\n");
|
|
107
|
+
|
|
108
|
+
// Table of Contents
|
|
109
|
+
sections.push("## Table of Contents\n");
|
|
110
|
+
if (decisions.length > 0)
|
|
111
|
+
sections.push(`- [Architectural Decisions](#architectural-decisions) (${decisions.length})`);
|
|
112
|
+
if (conventions.length > 0)
|
|
113
|
+
sections.push(`- [Coding Conventions](#coding-conventions) (${conventions.length})`);
|
|
114
|
+
if (bugs.length > 0) sections.push(`- [Known Issues](#known-issues) (${bugs.length})`);
|
|
115
|
+
if (solutions.length > 0) sections.push(`- [Solutions](#solutions) (${solutions.length})`);
|
|
116
|
+
if (concepts.length > 0) sections.push(`- [Key Concepts](#key-concepts) (${concepts.length})`);
|
|
117
|
+
sections.push("");
|
|
118
|
+
|
|
119
|
+
// Decisions
|
|
120
|
+
if (decisions.length > 0) {
|
|
121
|
+
sections.push("## Architectural Decisions\n");
|
|
122
|
+
sections.push(formatEntities(decisions));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Conventions
|
|
126
|
+
if (conventions.length > 0) {
|
|
127
|
+
sections.push("## Coding Conventions\n");
|
|
128
|
+
sections.push(formatEntities(conventions));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Bugs
|
|
132
|
+
if (bugs.length > 0) {
|
|
133
|
+
sections.push("## Known Issues\n");
|
|
134
|
+
sections.push(formatEntities(bugs));
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Solutions
|
|
138
|
+
if (solutions.length > 0) {
|
|
139
|
+
sections.push("## Solutions\n");
|
|
140
|
+
sections.push(formatEntities(solutions));
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Concepts
|
|
144
|
+
if (concepts.length > 0) {
|
|
145
|
+
sections.push("## Key Concepts\n");
|
|
146
|
+
sections.push(formatEntities(concepts));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Community structure
|
|
150
|
+
if (opts.includeCommunities !== false) {
|
|
151
|
+
const communities = await db.execute(
|
|
152
|
+
"SELECT id, summary, member_count FROM communities WHERE level = 2 ORDER BY member_count DESC LIMIT 10",
|
|
153
|
+
);
|
|
154
|
+
if ((communities.rows as any[]).length > 0) {
|
|
155
|
+
sections.push("## Architecture (Community Structure)\n");
|
|
156
|
+
for (const c of communities.rows as any[]) {
|
|
157
|
+
sections.push(`### Community (${c.member_count} members)`);
|
|
158
|
+
sections.push(`${c.summary ?? "No summary available"}\n`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Footer
|
|
164
|
+
sections.push("---\n");
|
|
165
|
+
sections.push("*This document was auto-generated by SIA's knowledge graph export.*");
|
|
166
|
+
sections.push("*Run `/sia-export-knowledge` to regenerate with the latest knowledge.*");
|
|
167
|
+
|
|
168
|
+
return sections.join("\n");
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export async function runExportKnowledge(args: string[]): Promise<void> {
|
|
172
|
+
const { resolveRepoHash } = await import("@/capture/hook");
|
|
173
|
+
const { openGraphDb } = await import("@/graph/semantic-db");
|
|
174
|
+
const { resolveSiaHome } = await import("@/shared/config");
|
|
175
|
+
|
|
176
|
+
let outputPath = "KNOWLEDGE.md";
|
|
177
|
+
let projectName: string | undefined;
|
|
178
|
+
|
|
179
|
+
for (let i = 0; i < args.length; i++) {
|
|
180
|
+
if (args[i] === "--output" && args[i + 1]) outputPath = args[++i];
|
|
181
|
+
if (args[i] === "--name" && args[i + 1]) projectName = args[++i];
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const cwd = process.cwd();
|
|
185
|
+
const repoHash = resolveRepoHash(cwd);
|
|
186
|
+
const siaHome = resolveSiaHome();
|
|
187
|
+
const db = openGraphDb(repoHash, siaHome);
|
|
188
|
+
|
|
189
|
+
try {
|
|
190
|
+
// Auto-detect project name from package.json if not provided
|
|
191
|
+
if (!projectName) {
|
|
192
|
+
try {
|
|
193
|
+
const { readFileSync } = await import("node:fs");
|
|
194
|
+
const pkg = JSON.parse(readFileSync(join(cwd, "package.json"), "utf-8"));
|
|
195
|
+
projectName = pkg.name;
|
|
196
|
+
} catch {
|
|
197
|
+
projectName = cwd.split("/").pop() ?? "Project";
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const markdown = await generateKnowledgeDocument(db, { projectName });
|
|
202
|
+
const fullPath = join(cwd, outputPath);
|
|
203
|
+
writeFileSync(fullPath, markdown, "utf-8");
|
|
204
|
+
console.log(`Knowledge document written to ${outputPath} (${markdown.length} chars)`);
|
|
205
|
+
} finally {
|
|
206
|
+
await db.close();
|
|
207
|
+
}
|
|
208
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// Module: export — serialize active graph to portable JSON
|
|
2
|
+
|
|
3
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { dirname } from "node:path";
|
|
5
|
+
import type { SiaDb } from "@/graph/db-interface";
|
|
6
|
+
|
|
7
|
+
/** Options for graph export. */
|
|
8
|
+
export interface ExportOpts {
|
|
9
|
+
/** Optional bridge.db handle for cross-repo edges */
|
|
10
|
+
bridgeDb?: SiaDb;
|
|
11
|
+
/** Repo hash for filtering bridge edges */
|
|
12
|
+
repoHash?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Portable snapshot of the active graph. */
|
|
16
|
+
export interface ExportData {
|
|
17
|
+
version: 1;
|
|
18
|
+
exportedAt: number;
|
|
19
|
+
entities: Record<string, unknown>[];
|
|
20
|
+
edges: Record<string, unknown>[];
|
|
21
|
+
communities: Record<string, unknown>[];
|
|
22
|
+
crossRepoEdges: Record<string, unknown>[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Export the active graph to a portable JSON structure.
|
|
27
|
+
*
|
|
28
|
+
* 1. Active entities (not invalidated, not archived)
|
|
29
|
+
* 2. Active edges (not invalidated)
|
|
30
|
+
* 3. All communities
|
|
31
|
+
* 4. Optionally, active cross-repo edges from bridge.db
|
|
32
|
+
*/
|
|
33
|
+
export async function exportGraph(db: SiaDb, opts?: ExportOpts): Promise<ExportData> {
|
|
34
|
+
// 1. Active entities
|
|
35
|
+
const entitiesResult = await db.execute(
|
|
36
|
+
"SELECT * FROM graph_nodes WHERE t_valid_until IS NULL AND archived_at IS NULL",
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
// 2. Active edges
|
|
40
|
+
const edgesResult = await db.execute("SELECT * FROM graph_edges WHERE t_valid_until IS NULL");
|
|
41
|
+
|
|
42
|
+
// 3. All communities
|
|
43
|
+
const communitiesResult = await db.execute("SELECT * FROM communities");
|
|
44
|
+
|
|
45
|
+
// 4. Cross-repo edges (only if bridgeDb + repoHash provided)
|
|
46
|
+
let crossRepoEdges: Record<string, unknown>[] = [];
|
|
47
|
+
if (opts?.bridgeDb && opts?.repoHash) {
|
|
48
|
+
const crossResult = await opts.bridgeDb.execute(
|
|
49
|
+
"SELECT * FROM cross_repo_edges WHERE (source_repo_id = ? OR target_repo_id = ?) AND t_valid_until IS NULL",
|
|
50
|
+
[opts.repoHash, opts.repoHash],
|
|
51
|
+
);
|
|
52
|
+
crossRepoEdges = crossResult.rows;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return {
|
|
56
|
+
version: 1,
|
|
57
|
+
exportedAt: Date.now(),
|
|
58
|
+
entities: entitiesResult.rows,
|
|
59
|
+
edges: edgesResult.rows,
|
|
60
|
+
communities: communitiesResult.rows,
|
|
61
|
+
crossRepoEdges,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Export the active graph to a JSON file on disk.
|
|
67
|
+
*
|
|
68
|
+
* Creates parent directories if they don't exist.
|
|
69
|
+
* Returns the output path.
|
|
70
|
+
*/
|
|
71
|
+
export async function exportToFile(
|
|
72
|
+
db: SiaDb,
|
|
73
|
+
outputPath: string,
|
|
74
|
+
opts?: ExportOpts,
|
|
75
|
+
): Promise<string> {
|
|
76
|
+
const data = await exportGraph(db, opts);
|
|
77
|
+
|
|
78
|
+
const dir = dirname(outputPath);
|
|
79
|
+
if (!existsSync(dir)) {
|
|
80
|
+
mkdirSync(dir, { recursive: true });
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
writeFileSync(outputPath, JSON.stringify(data, null, 2), "utf-8");
|
|
84
|
+
return outputPath;
|
|
85
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
// Module: freshness — CLI freshness report command
|
|
2
|
+
|
|
3
|
+
import type { SiaDb } from "@/graph/db-interface";
|
|
4
|
+
import { getNativeModuleStatus } from "@/native/bridge";
|
|
5
|
+
|
|
6
|
+
export interface FreshnessReport {
|
|
7
|
+
totalNodes: number;
|
|
8
|
+
freshNodes: number;
|
|
9
|
+
staleNodes: number;
|
|
10
|
+
rottenNodes: number;
|
|
11
|
+
pendingRevalidation: number;
|
|
12
|
+
avgConfidenceByTier: Record<string, number>;
|
|
13
|
+
lastDeepValidation: number | null;
|
|
14
|
+
indexCoverage: number; // percentage of nodes with source mappings
|
|
15
|
+
nativeModuleStatus: string; // "native" | "wasm" | "typescript"
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Confidence thresholds for freshness classification
|
|
19
|
+
const FRESH_THRESHOLD = 0.7;
|
|
20
|
+
const ROTTEN_THRESHOLD = 0.3;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Generate a freshness report for the graph.
|
|
24
|
+
*/
|
|
25
|
+
export async function generateFreshnessReport(db: SiaDb): Promise<FreshnessReport> {
|
|
26
|
+
// 1. Total node count
|
|
27
|
+
const { rows: totalRows } = await db.execute("SELECT COUNT(*) AS cnt FROM graph_nodes");
|
|
28
|
+
const totalNodes = (totalRows[0]?.cnt as number) ?? 0;
|
|
29
|
+
|
|
30
|
+
// 2. Active node count (not archived, not invalidated)
|
|
31
|
+
const { rows: activeRows } = await db.execute(
|
|
32
|
+
"SELECT COUNT(*) AS cnt FROM graph_nodes WHERE archived_at IS NULL AND t_valid_until IS NULL",
|
|
33
|
+
);
|
|
34
|
+
const activeNodes = (activeRows[0]?.cnt as number) ?? 0;
|
|
35
|
+
|
|
36
|
+
// 3. Fresh nodes: confidence > FRESH_THRESHOLD (active only)
|
|
37
|
+
const { rows: freshRows } = await db.execute(
|
|
38
|
+
"SELECT COUNT(*) AS cnt FROM graph_nodes WHERE archived_at IS NULL AND t_valid_until IS NULL AND confidence > ?",
|
|
39
|
+
[FRESH_THRESHOLD],
|
|
40
|
+
);
|
|
41
|
+
const freshNodes = (freshRows[0]?.cnt as number) ?? 0;
|
|
42
|
+
|
|
43
|
+
// 4. Rotten nodes: confidence < ROTTEN_THRESHOLD (active only)
|
|
44
|
+
const { rows: rottenRows } = await db.execute(
|
|
45
|
+
"SELECT COUNT(*) AS cnt FROM graph_nodes WHERE archived_at IS NULL AND t_valid_until IS NULL AND confidence < ?",
|
|
46
|
+
[ROTTEN_THRESHOLD],
|
|
47
|
+
);
|
|
48
|
+
const rottenNodes = (rottenRows[0]?.cnt as number) ?? 0;
|
|
49
|
+
|
|
50
|
+
// 5. Stale nodes: between thresholds
|
|
51
|
+
const staleNodes = activeNodes - freshNodes - rottenNodes;
|
|
52
|
+
|
|
53
|
+
// 6. Pending revalidation: invalidated but not yet replaced
|
|
54
|
+
const { rows: pendingRows } = await db.execute(
|
|
55
|
+
"SELECT COUNT(*) AS cnt FROM graph_nodes WHERE t_valid_until IS NOT NULL AND archived_at IS NULL",
|
|
56
|
+
);
|
|
57
|
+
const pendingRevalidation = (pendingRows[0]?.cnt as number) ?? 0;
|
|
58
|
+
|
|
59
|
+
// 7. Average confidence by trust tier
|
|
60
|
+
const { rows: tierRows } = await db.execute(
|
|
61
|
+
"SELECT trust_tier, AVG(confidence) AS avg_conf FROM graph_nodes WHERE archived_at IS NULL AND t_valid_until IS NULL GROUP BY trust_tier",
|
|
62
|
+
);
|
|
63
|
+
const avgConfidenceByTier: Record<string, number> = {};
|
|
64
|
+
for (const row of tierRows) {
|
|
65
|
+
const tier = String(row.trust_tier as number);
|
|
66
|
+
avgConfidenceByTier[tier] = Math.round((row.avg_conf as number) * 100) / 100;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// 8. Index coverage: percentage of active nodes with at least one source mapping
|
|
70
|
+
let indexCoverage = 0;
|
|
71
|
+
if (totalNodes > 0) {
|
|
72
|
+
const { rows: mappedRows } = await db.execute(
|
|
73
|
+
"SELECT COUNT(DISTINCT node_id) AS cnt FROM source_deps",
|
|
74
|
+
);
|
|
75
|
+
const mappedNodes = (mappedRows[0]?.cnt as number) ?? 0;
|
|
76
|
+
indexCoverage = Math.round((mappedNodes / totalNodes) * 100 * 10) / 10;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// 9. Last deep validation: not persisted in DB yet — return null
|
|
80
|
+
const lastDeepValidation: number | null = null;
|
|
81
|
+
|
|
82
|
+
// 10. Native module status
|
|
83
|
+
const nativeModuleStatus = getNativeModuleStatus();
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
totalNodes,
|
|
87
|
+
freshNodes,
|
|
88
|
+
staleNodes,
|
|
89
|
+
rottenNodes,
|
|
90
|
+
pendingRevalidation,
|
|
91
|
+
avgConfidenceByTier,
|
|
92
|
+
lastDeepValidation,
|
|
93
|
+
indexCoverage,
|
|
94
|
+
nativeModuleStatus,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Format the report as human-readable output for CLI.
|
|
100
|
+
*/
|
|
101
|
+
export function formatFreshnessReport(report: FreshnessReport): string {
|
|
102
|
+
const lines: string[] = [];
|
|
103
|
+
|
|
104
|
+
const sep = "──────────────────────────────";
|
|
105
|
+
|
|
106
|
+
lines.push("Sia Graph Freshness Report");
|
|
107
|
+
lines.push(sep);
|
|
108
|
+
|
|
109
|
+
// Node counts
|
|
110
|
+
const total = report.totalNodes;
|
|
111
|
+
const freshPct = total > 0 ? ((report.freshNodes / total) * 100).toFixed(1) : "0.0";
|
|
112
|
+
const stalePct = total > 0 ? ((report.staleNodes / total) * 100).toFixed(1) : "0.0";
|
|
113
|
+
const rottenPct = total > 0 ? ((report.rottenNodes / total) * 100).toFixed(1) : "0.0";
|
|
114
|
+
|
|
115
|
+
lines.push(`Total nodes: ${formatNumber(total)}`);
|
|
116
|
+
lines.push(` Fresh: ${formatNumber(report.freshNodes)} (${freshPct}%)`);
|
|
117
|
+
lines.push(` Stale: ${formatNumber(report.staleNodes)} (${stalePct}%)`);
|
|
118
|
+
lines.push(` Rotten: ${formatNumber(report.rottenNodes)} (${rottenPct}%)`);
|
|
119
|
+
lines.push("");
|
|
120
|
+
|
|
121
|
+
// Confidence by trust tier
|
|
122
|
+
const tierNames: Record<string, string> = {
|
|
123
|
+
"1": "Tier 1 (User)",
|
|
124
|
+
"2": "Tier 2 (AST)",
|
|
125
|
+
"3": "Tier 3 (LLM)",
|
|
126
|
+
"4": "Tier 4 (External)",
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const tierKeys = Object.keys(report.avgConfidenceByTier).sort();
|
|
130
|
+
if (tierKeys.length > 0) {
|
|
131
|
+
lines.push("Confidence by Trust Tier:");
|
|
132
|
+
for (const tier of tierKeys) {
|
|
133
|
+
const name = tierNames[tier] ?? `Tier ${tier}`;
|
|
134
|
+
const conf = report.avgConfidenceByTier[tier]?.toFixed(2) ?? "N/A";
|
|
135
|
+
lines.push(` ${name.padEnd(22)} ${conf}`);
|
|
136
|
+
}
|
|
137
|
+
lines.push("");
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Index coverage
|
|
141
|
+
lines.push(
|
|
142
|
+
`Index Coverage: ${report.indexCoverage.toFixed(1)}% (nodes with source mappings)`,
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
// Native module
|
|
146
|
+
lines.push(`Native Module: ${report.nativeModuleStatus}`);
|
|
147
|
+
|
|
148
|
+
// Last deep validation
|
|
149
|
+
const lastVal =
|
|
150
|
+
report.lastDeepValidation !== null
|
|
151
|
+
? new Date(report.lastDeepValidation).toISOString().replace("T", " ").slice(0, 19)
|
|
152
|
+
: "never";
|
|
153
|
+
lines.push(`Last Deep Validation: ${lastVal}`);
|
|
154
|
+
|
|
155
|
+
return lines.join("\n");
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// ---------------------------------------------------------------------------
|
|
159
|
+
// Internal helpers
|
|
160
|
+
// ---------------------------------------------------------------------------
|
|
161
|
+
|
|
162
|
+
function formatNumber(n: number): string {
|
|
163
|
+
return n.toLocaleString("en-US");
|
|
164
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// Module: graph — CLI command to generate knowledge graph visualization
|
|
2
|
+
|
|
3
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { dirname, resolve } from "node:path";
|
|
5
|
+
import type { SiaDb } from "@/graph/db-interface";
|
|
6
|
+
import { renderGraphHtml } from "@/visualization/graph-renderer";
|
|
7
|
+
import { type ExtractOpts, extractSubgraph } from "@/visualization/subgraph-extract";
|
|
8
|
+
|
|
9
|
+
export interface GraphCommandOpts {
|
|
10
|
+
output?: string;
|
|
11
|
+
scope?: string;
|
|
12
|
+
nodeType?: string;
|
|
13
|
+
maxNodes?: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Generate a knowledge graph visualization as a self-contained HTML file.
|
|
18
|
+
*
|
|
19
|
+
* 1. Extracts a subgraph according to the provided options.
|
|
20
|
+
* 2. Renders the subgraph as a self-contained HTML document with D3.js.
|
|
21
|
+
* 3. Writes the HTML to the output path.
|
|
22
|
+
* 4. Returns the absolute path of the written file.
|
|
23
|
+
*/
|
|
24
|
+
export async function generateGraphVisualization(
|
|
25
|
+
db: SiaDb,
|
|
26
|
+
opts?: GraphCommandOpts,
|
|
27
|
+
): Promise<string> {
|
|
28
|
+
const extractOpts: ExtractOpts = {
|
|
29
|
+
scope: opts?.scope,
|
|
30
|
+
nodeType: opts?.nodeType,
|
|
31
|
+
maxNodes: opts?.maxNodes,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const data = await extractSubgraph(db, extractOpts);
|
|
35
|
+
|
|
36
|
+
// Build a descriptive title from the options
|
|
37
|
+
let title = "Sia Knowledge Graph";
|
|
38
|
+
if (opts?.scope) {
|
|
39
|
+
title = `Sia Graph — ${opts.scope}`;
|
|
40
|
+
} else if (opts?.nodeType) {
|
|
41
|
+
title = `Sia Graph — ${opts.nodeType} entities`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const html = renderGraphHtml(data, title);
|
|
45
|
+
|
|
46
|
+
const outputPath = resolve(opts?.output ?? "./sia-graph.html");
|
|
47
|
+
mkdirSync(dirname(outputPath), { recursive: true });
|
|
48
|
+
writeFileSync(outputPath, html, "utf-8");
|
|
49
|
+
|
|
50
|
+
return outputPath;
|
|
51
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// Module: history — Temporal exploration of the knowledge graph
|
|
2
|
+
//
|
|
3
|
+
// Usage:
|
|
4
|
+
// sia history Show last 7 days of knowledge
|
|
5
|
+
// sia history --since 2026-03-01 Since a specific date
|
|
6
|
+
// sia history --types Decision,Bug Filter by entity type
|
|
7
|
+
// sia history --file src/auth/login.ts Filter by file
|
|
8
|
+
|
|
9
|
+
import type { SiaDb } from "@/graph/db-interface";
|
|
10
|
+
|
|
11
|
+
export interface HistoryOptions {
|
|
12
|
+
since?: number;
|
|
13
|
+
until?: number;
|
|
14
|
+
types?: string[];
|
|
15
|
+
file?: string;
|
|
16
|
+
limit?: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface HistoryResult {
|
|
20
|
+
entities: Array<{
|
|
21
|
+
id: string;
|
|
22
|
+
type: string;
|
|
23
|
+
name: string;
|
|
24
|
+
summary: string | null;
|
|
25
|
+
kind: string | null;
|
|
26
|
+
created_at: number;
|
|
27
|
+
trust_tier: number;
|
|
28
|
+
}>;
|
|
29
|
+
timeRange: { since: number; until: number };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function getHistory(db: SiaDb, opts: HistoryOptions = {}): Promise<HistoryResult> {
|
|
33
|
+
const since = opts.since ?? Date.now() - 7 * 86400000; // default 7 days
|
|
34
|
+
const until = opts.until ?? Date.now();
|
|
35
|
+
const limit = opts.limit ?? 50;
|
|
36
|
+
|
|
37
|
+
let query = `SELECT id, type, name, summary, kind, created_at, trust_tier, file_paths
|
|
38
|
+
FROM graph_nodes
|
|
39
|
+
WHERE created_at >= ? AND created_at <= ?
|
|
40
|
+
AND t_valid_until IS NULL AND archived_at IS NULL`;
|
|
41
|
+
const params: unknown[] = [since, until];
|
|
42
|
+
|
|
43
|
+
if (opts.types && opts.types.length > 0) {
|
|
44
|
+
const placeholders = opts.types.map(() => "?").join(", ");
|
|
45
|
+
query += ` AND type IN (${placeholders})`;
|
|
46
|
+
params.push(...opts.types);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (opts.file) {
|
|
50
|
+
query += " AND file_paths LIKE ?";
|
|
51
|
+
params.push(`%${opts.file}%`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
query += " ORDER BY created_at DESC LIMIT ?";
|
|
55
|
+
params.push(limit);
|
|
56
|
+
|
|
57
|
+
const result = await db.execute(query, params);
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
entities: result.rows as HistoryResult["entities"],
|
|
61
|
+
timeRange: { since, until },
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function formatHistory(history: HistoryResult): string {
|
|
66
|
+
const lines: string[] = [];
|
|
67
|
+
const sinceDate = new Date(history.timeRange.since).toISOString().split("T")[0];
|
|
68
|
+
const untilDate = new Date(history.timeRange.until).toISOString().split("T")[0];
|
|
69
|
+
|
|
70
|
+
lines.push(`=== SIA Knowledge History (${sinceDate} to ${untilDate}) ===\n`);
|
|
71
|
+
|
|
72
|
+
if (history.entities.length === 0) {
|
|
73
|
+
lines.push("No knowledge captured in this time range.");
|
|
74
|
+
return lines.join("\n");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Group by date
|
|
78
|
+
const byDate = new Map<string, typeof history.entities>();
|
|
79
|
+
for (const entity of history.entities) {
|
|
80
|
+
const date = new Date(entity.created_at).toISOString().split("T")[0];
|
|
81
|
+
if (!byDate.has(date)) byDate.set(date, []);
|
|
82
|
+
byDate.get(date)?.push(entity);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
for (const [date, entities] of byDate) {
|
|
86
|
+
lines.push(`--- ${date} (${entities.length} entities) ---`);
|
|
87
|
+
for (const e of entities) {
|
|
88
|
+
const tierLabel =
|
|
89
|
+
e.trust_tier === 1
|
|
90
|
+
? "user"
|
|
91
|
+
: e.trust_tier === 2
|
|
92
|
+
? "code"
|
|
93
|
+
: e.trust_tier === 3
|
|
94
|
+
? "llm"
|
|
95
|
+
: "ext";
|
|
96
|
+
lines.push(` [${e.type}] ${e.name} (tier:${tierLabel})`);
|
|
97
|
+
if (e.summary) lines.push(` ${e.summary.slice(0, 100)}`);
|
|
98
|
+
}
|
|
99
|
+
lines.push("");
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
lines.push(`Total: ${history.entities.length} entities`);
|
|
103
|
+
return lines.join("\n");
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export async function runHistory(args: string[]): Promise<void> {
|
|
107
|
+
const { resolveRepoHash } = await import("@/capture/hook");
|
|
108
|
+
const { openGraphDb } = await import("@/graph/semantic-db");
|
|
109
|
+
const { resolveSiaHome } = await import("@/shared/config");
|
|
110
|
+
|
|
111
|
+
const opts: HistoryOptions = {};
|
|
112
|
+
|
|
113
|
+
// Parse args
|
|
114
|
+
for (let i = 0; i < args.length; i++) {
|
|
115
|
+
if (args[i] === "--since" && args[i + 1]) {
|
|
116
|
+
opts.since = new Date(args[++i]).getTime();
|
|
117
|
+
} else if (args[i] === "--until" && args[i + 1]) {
|
|
118
|
+
opts.until = new Date(args[++i]).getTime();
|
|
119
|
+
} else if (args[i] === "--types" && args[i + 1]) {
|
|
120
|
+
opts.types = args[++i].split(",");
|
|
121
|
+
} else if (args[i] === "--file" && args[i + 1]) {
|
|
122
|
+
opts.file = args[++i];
|
|
123
|
+
} else if (args[i] === "--limit" && args[i + 1]) {
|
|
124
|
+
opts.limit = parseInt(args[++i], 10);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const cwd = process.cwd();
|
|
129
|
+
const repoHash = resolveRepoHash(cwd);
|
|
130
|
+
const siaHome = resolveSiaHome();
|
|
131
|
+
const db = openGraphDb(repoHash, siaHome);
|
|
132
|
+
|
|
133
|
+
try {
|
|
134
|
+
const history = await getHistory(db, opts);
|
|
135
|
+
console.log(formatHistory(history));
|
|
136
|
+
} finally {
|
|
137
|
+
await db.close();
|
|
138
|
+
}
|
|
139
|
+
}
|