@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,241 @@
|
|
|
1
|
+
// Module: lead-report — tech lead intelligence reports
|
|
2
|
+
//
|
|
3
|
+
// Usage:
|
|
4
|
+
// sia lead-report --type drift|knowledge-map|compliance
|
|
5
|
+
|
|
6
|
+
import type { SiaDb } from "@/graph/db-interface";
|
|
7
|
+
|
|
8
|
+
const ACTIVE_FILTER = "t_valid_until IS NULL AND archived_at IS NULL";
|
|
9
|
+
|
|
10
|
+
// --- Drift Report ---
|
|
11
|
+
|
|
12
|
+
export interface DriftEntity {
|
|
13
|
+
id: string;
|
|
14
|
+
name: string;
|
|
15
|
+
content: string;
|
|
16
|
+
filePaths: string[];
|
|
17
|
+
createdAt: string;
|
|
18
|
+
trustTier: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface DriftReport {
|
|
22
|
+
type: "drift";
|
|
23
|
+
decisions: DriftEntity[];
|
|
24
|
+
conventions: DriftEntity[];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function generateDriftReport(db: SiaDb): Promise<DriftReport> {
|
|
28
|
+
const decisions = await queryEntitiesByType(db, "Decision");
|
|
29
|
+
const conventions = await queryEntitiesByType(db, "Convention");
|
|
30
|
+
return { type: "drift", decisions, conventions };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// --- Knowledge Map Report ---
|
|
34
|
+
|
|
35
|
+
export interface KnowledgeMapReport {
|
|
36
|
+
type: "knowledge-map";
|
|
37
|
+
totalEntities: number;
|
|
38
|
+
byType: Record<string, number>;
|
|
39
|
+
byContributor: Record<string, number>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function generateKnowledgeMapReport(db: SiaDb): Promise<KnowledgeMapReport> {
|
|
43
|
+
const { rows: totalRows } = await db.execute(
|
|
44
|
+
`SELECT COUNT(*) AS cnt FROM graph_nodes WHERE ${ACTIVE_FILTER}`,
|
|
45
|
+
);
|
|
46
|
+
const totalEntities = (totalRows[0]?.cnt as number) ?? 0;
|
|
47
|
+
|
|
48
|
+
const byType: Record<string, number> = {};
|
|
49
|
+
const { rows: typeRows } = await db.execute(
|
|
50
|
+
`SELECT type, COUNT(*) AS cnt FROM graph_nodes WHERE ${ACTIVE_FILTER} GROUP BY type`,
|
|
51
|
+
);
|
|
52
|
+
for (const row of typeRows) {
|
|
53
|
+
byType[row.type as string] = row.cnt as number;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const byContributor: Record<string, number> = {};
|
|
57
|
+
const { rows: contribRows } = await db.execute(
|
|
58
|
+
`SELECT created_by, COUNT(*) AS cnt FROM graph_nodes WHERE ${ACTIVE_FILTER} GROUP BY created_by`,
|
|
59
|
+
);
|
|
60
|
+
for (const row of contribRows) {
|
|
61
|
+
byContributor[row.created_by as string] = row.cnt as number;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return { type: "knowledge-map", totalEntities, byType, byContributor };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// --- Compliance Report ---
|
|
68
|
+
|
|
69
|
+
export interface ComplianceConvention {
|
|
70
|
+
id: string;
|
|
71
|
+
name: string;
|
|
72
|
+
content: string;
|
|
73
|
+
filePaths: string[];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface ComplianceReport {
|
|
77
|
+
type: "compliance";
|
|
78
|
+
conventions: ComplianceConvention[];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function generateComplianceReport(db: SiaDb): Promise<ComplianceReport> {
|
|
82
|
+
const entities = await queryEntitiesByType(db, "Convention");
|
|
83
|
+
const conventions: ComplianceConvention[] = entities.map(({ id, name, content, filePaths }) => ({
|
|
84
|
+
id,
|
|
85
|
+
name,
|
|
86
|
+
content,
|
|
87
|
+
filePaths,
|
|
88
|
+
}));
|
|
89
|
+
return { type: "compliance", conventions };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// --- Shared ---
|
|
93
|
+
|
|
94
|
+
async function queryEntitiesByType(db: SiaDb, entityType: string): Promise<DriftEntity[]> {
|
|
95
|
+
const { rows } = await db.execute(
|
|
96
|
+
`SELECT id, name, content, file_paths, created_at, trust_tier
|
|
97
|
+
FROM graph_nodes
|
|
98
|
+
WHERE type = ? AND ${ACTIVE_FILTER}
|
|
99
|
+
ORDER BY created_at DESC`,
|
|
100
|
+
[entityType],
|
|
101
|
+
);
|
|
102
|
+
return rows.map((row) => ({
|
|
103
|
+
id: row.id as string,
|
|
104
|
+
name: row.name as string,
|
|
105
|
+
content: row.content as string,
|
|
106
|
+
filePaths: parseJsonArray(row.file_paths as string),
|
|
107
|
+
createdAt: new Date(row.created_at as number).toISOString(),
|
|
108
|
+
trustTier: row.trust_tier as number,
|
|
109
|
+
}));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function parseJsonArray(raw: string): string[] {
|
|
113
|
+
try {
|
|
114
|
+
const parsed = JSON.parse(raw);
|
|
115
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
116
|
+
} catch {
|
|
117
|
+
return [];
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// --- Public API ---
|
|
122
|
+
|
|
123
|
+
export type LeadReport = DriftReport | KnowledgeMapReport | ComplianceReport;
|
|
124
|
+
|
|
125
|
+
export interface LeadReportOptions {
|
|
126
|
+
type: "drift" | "knowledge-map" | "compliance";
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export async function generateLeadReport(db: SiaDb, opts: LeadReportOptions): Promise<LeadReport> {
|
|
130
|
+
switch (opts.type) {
|
|
131
|
+
case "drift":
|
|
132
|
+
return generateDriftReport(db);
|
|
133
|
+
case "knowledge-map":
|
|
134
|
+
return generateKnowledgeMapReport(db);
|
|
135
|
+
case "compliance":
|
|
136
|
+
return generateComplianceReport(db);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function formatLeadReport(report: LeadReport): string {
|
|
141
|
+
switch (report.type) {
|
|
142
|
+
case "drift":
|
|
143
|
+
return formatDriftReport(report);
|
|
144
|
+
case "knowledge-map":
|
|
145
|
+
return formatKnowledgeMapReport(report);
|
|
146
|
+
case "compliance":
|
|
147
|
+
return formatComplianceReport(report);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function formatDriftReport(report: DriftReport): string {
|
|
152
|
+
const lines: string[] = [];
|
|
153
|
+
lines.push("=== Architecture Drift Report ===");
|
|
154
|
+
lines.push("");
|
|
155
|
+
|
|
156
|
+
lines.push(`Decisions: ${report.decisions.length}`);
|
|
157
|
+
for (const d of report.decisions) {
|
|
158
|
+
lines.push(` - ${d.name}`);
|
|
159
|
+
if (d.filePaths.length > 0) {
|
|
160
|
+
lines.push(` Files: ${d.filePaths.join(", ")}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
lines.push("");
|
|
165
|
+
lines.push(`Conventions: ${report.conventions.length}`);
|
|
166
|
+
for (const c of report.conventions) {
|
|
167
|
+
lines.push(` - ${c.name}`);
|
|
168
|
+
if (c.filePaths.length > 0) {
|
|
169
|
+
lines.push(` Files: ${c.filePaths.join(", ")}`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return lines.join("\n");
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function formatKnowledgeMapReport(report: KnowledgeMapReport): string {
|
|
177
|
+
const lines: string[] = [];
|
|
178
|
+
lines.push("=== Knowledge Distribution Map ===");
|
|
179
|
+
lines.push("");
|
|
180
|
+
lines.push(`Total entities: ${report.totalEntities}`);
|
|
181
|
+
|
|
182
|
+
lines.push("");
|
|
183
|
+
lines.push("--- By Type ---");
|
|
184
|
+
for (const [type, count] of Object.entries(report.byType).sort((a, b) => b[1] - a[1])) {
|
|
185
|
+
lines.push(` ${type.padEnd(20)} ${count}`);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
lines.push("");
|
|
189
|
+
lines.push("--- By Contributor ---");
|
|
190
|
+
for (const [contrib, count] of Object.entries(report.byContributor).sort((a, b) => b[1] - a[1])) {
|
|
191
|
+
lines.push(` ${contrib.padEnd(20)} ${count}`);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return lines.join("\n");
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function formatComplianceReport(report: ComplianceReport): string {
|
|
198
|
+
const lines: string[] = [];
|
|
199
|
+
lines.push("=== Convention Compliance ===");
|
|
200
|
+
lines.push("");
|
|
201
|
+
lines.push(`Conventions tracked: ${report.conventions.length}`);
|
|
202
|
+
|
|
203
|
+
for (const c of report.conventions) {
|
|
204
|
+
lines.push("");
|
|
205
|
+
lines.push(` ${c.name}`);
|
|
206
|
+
if (c.filePaths.length > 0) {
|
|
207
|
+
lines.push(` Referenced files: ${c.filePaths.join(", ")}`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return lines.join("\n");
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// --- CLI Entry Point ---
|
|
215
|
+
|
|
216
|
+
export async function runLeadReport(args: string[]): Promise<void> {
|
|
217
|
+
const { resolveRepoHash } = await import("@/capture/hook");
|
|
218
|
+
const { openGraphDb } = await import("@/graph/semantic-db");
|
|
219
|
+
|
|
220
|
+
let type: LeadReportOptions["type"] = "drift";
|
|
221
|
+
for (let i = 0; i < args.length; i++) {
|
|
222
|
+
if (args[i] === "--type" && args[i + 1]) {
|
|
223
|
+
const val = args[i + 1];
|
|
224
|
+
if (val === "drift" || val === "knowledge-map" || val === "compliance") {
|
|
225
|
+
type = val;
|
|
226
|
+
} else {
|
|
227
|
+
console.error(`Unknown report type: ${val}. Use: drift, knowledge-map, compliance`);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const repoHash = resolveRepoHash(process.cwd());
|
|
234
|
+
const db = openGraphDb(repoHash);
|
|
235
|
+
try {
|
|
236
|
+
const report = await generateLeadReport(db, { type });
|
|
237
|
+
console.log(formatLeadReport(report));
|
|
238
|
+
} finally {
|
|
239
|
+
await db.close();
|
|
240
|
+
}
|
|
241
|
+
}
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
// Module: learn — Full knowledge graph builder orchestrator.
|
|
2
|
+
//
|
|
3
|
+
// Usage:
|
|
4
|
+
// sia learn Full rebuild (default)
|
|
5
|
+
// sia learn --incremental Only process changed files
|
|
6
|
+
// sia learn --force Skip snapshot restore, rebuild everything
|
|
7
|
+
// sia learn --verbose Phase-by-phase progress (default)
|
|
8
|
+
// sia learn --quiet Summary only
|
|
9
|
+
// sia learn --interactive Confirm after each phase
|
|
10
|
+
|
|
11
|
+
import { readFileSync } from "node:fs";
|
|
12
|
+
import { resolve } from "node:path";
|
|
13
|
+
import { resolveRepoHash } from "@/capture/hook";
|
|
14
|
+
import {
|
|
15
|
+
deleteProgress,
|
|
16
|
+
type LearnProgress,
|
|
17
|
+
readProgress,
|
|
18
|
+
runWithRetry,
|
|
19
|
+
writeProgress,
|
|
20
|
+
} from "@/cli/learn-progress";
|
|
21
|
+
import { getConfig, resolveSiaHome } from "@/shared/config";
|
|
22
|
+
|
|
23
|
+
export type Verbosity = "verbose" | "quiet" | "interactive";
|
|
24
|
+
|
|
25
|
+
export interface LearnOptions {
|
|
26
|
+
cwd?: string;
|
|
27
|
+
siaHome?: string;
|
|
28
|
+
incremental?: boolean;
|
|
29
|
+
force?: boolean;
|
|
30
|
+
verbosity?: Verbosity;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface LearnResult {
|
|
34
|
+
phasesCompleted: number[];
|
|
35
|
+
phasesFailed: number[];
|
|
36
|
+
codeEntities: number;
|
|
37
|
+
codeFiles: number;
|
|
38
|
+
codeCacheHits: number;
|
|
39
|
+
docsIngested: number;
|
|
40
|
+
docChunks: number;
|
|
41
|
+
externalRefs: number;
|
|
42
|
+
communities: number;
|
|
43
|
+
skippedFiles: Array<{ path: string; error: string }>;
|
|
44
|
+
durationMs: number;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function log(verbosity: Verbosity, msg: string): void {
|
|
48
|
+
if (verbosity !== "quiet") {
|
|
49
|
+
process.stderr.write(`${msg}\n`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export async function siaLearn(opts: LearnOptions = {}): Promise<LearnResult | null> {
|
|
54
|
+
const start = Date.now();
|
|
55
|
+
const cwd = resolve(opts.cwd ?? process.cwd());
|
|
56
|
+
const siaHome = opts.siaHome ?? resolveSiaHome();
|
|
57
|
+
const verbosity = opts.verbosity ?? "verbose";
|
|
58
|
+
const config = getConfig(siaHome);
|
|
59
|
+
|
|
60
|
+
const result: LearnResult = {
|
|
61
|
+
phasesCompleted: [],
|
|
62
|
+
phasesFailed: [],
|
|
63
|
+
codeEntities: 0,
|
|
64
|
+
codeFiles: 0,
|
|
65
|
+
codeCacheHits: 0,
|
|
66
|
+
docsIngested: 0,
|
|
67
|
+
docChunks: 0,
|
|
68
|
+
externalRefs: 0,
|
|
69
|
+
communities: 0,
|
|
70
|
+
skippedFiles: [],
|
|
71
|
+
durationMs: 0,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// Check for resumable progress
|
|
75
|
+
const existingProgress = readProgress(cwd);
|
|
76
|
+
let phasesToSkip: Set<number> = new Set();
|
|
77
|
+
if (existingProgress && !opts.force) {
|
|
78
|
+
const repoHash = resolveRepoHash(cwd);
|
|
79
|
+
if (existingProgress.repo_hash === repoHash) {
|
|
80
|
+
phasesToSkip = new Set(existingProgress.phases_completed);
|
|
81
|
+
log(
|
|
82
|
+
verbosity,
|
|
83
|
+
`[sia-learn] Resuming — phases ${[...phasesToSkip].join(", ")} already complete`,
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Initialize progress file
|
|
89
|
+
const progress: LearnProgress = {
|
|
90
|
+
started_at: existingProgress?.started_at ?? Date.now(),
|
|
91
|
+
repo_hash: resolveRepoHash(cwd),
|
|
92
|
+
branch: "",
|
|
93
|
+
phases_completed: [...phasesToSkip],
|
|
94
|
+
files_indexed: existingProgress?.files_indexed ?? 0,
|
|
95
|
+
total_files: 0,
|
|
96
|
+
last_checkpoint_at: Date.now(),
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
// Try to get current branch
|
|
100
|
+
try {
|
|
101
|
+
const { execFileSync } = await import("node:child_process");
|
|
102
|
+
progress.branch = execFileSync("git", ["branch", "--show-current"], {
|
|
103
|
+
cwd,
|
|
104
|
+
encoding: "utf-8",
|
|
105
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
106
|
+
}).trim();
|
|
107
|
+
} catch {
|
|
108
|
+
progress.branch = "unknown";
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// --- Phase 0: Install (idempotent) ---
|
|
112
|
+
if (!phasesToSkip.has(0)) {
|
|
113
|
+
log(verbosity, "[sia-learn] Phase 0: Installing SIA...");
|
|
114
|
+
const installResult = await runWithRetry("Phase 0: Install", async () => {
|
|
115
|
+
const { siaInstall } = await import("@/cli/commands/install");
|
|
116
|
+
await siaInstall({ cwd, siaHome });
|
|
117
|
+
});
|
|
118
|
+
if (installResult !== null) {
|
|
119
|
+
result.phasesCompleted.push(0);
|
|
120
|
+
progress.phases_completed.push(0);
|
|
121
|
+
writeProgress(cwd, progress);
|
|
122
|
+
log(verbosity, "[sia-learn] Phase 0: Done");
|
|
123
|
+
} else {
|
|
124
|
+
result.phasesFailed.push(0);
|
|
125
|
+
// Install failure is fatal — can't continue without databases
|
|
126
|
+
log(verbosity, "[sia-learn] Phase 0: FAILED — cannot continue without databases");
|
|
127
|
+
result.durationMs = Date.now() - start;
|
|
128
|
+
return result;
|
|
129
|
+
}
|
|
130
|
+
} else {
|
|
131
|
+
result.phasesCompleted.push(0);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Open graph DB for remaining phases
|
|
135
|
+
const { openGraphDb } = await import("@/graph/semantic-db");
|
|
136
|
+
const repoHash = resolveRepoHash(cwd);
|
|
137
|
+
const db = openGraphDb(repoHash, siaHome);
|
|
138
|
+
|
|
139
|
+
try {
|
|
140
|
+
// --- Phase 1: AST code indexing (delegates to siaReindex) ---
|
|
141
|
+
if (!phasesToSkip.has(1)) {
|
|
142
|
+
log(verbosity, "[sia-learn] Phase 1: Indexing code...");
|
|
143
|
+
const indexResult = await runWithRetry("Phase 1: Code indexing", async () => {
|
|
144
|
+
const { siaReindex } = await import("@/cli/commands/reindex");
|
|
145
|
+
return siaReindex({ cwd, siaHome });
|
|
146
|
+
});
|
|
147
|
+
if (indexResult) {
|
|
148
|
+
result.codeEntities = indexResult.entitiesCreated;
|
|
149
|
+
result.codeFiles = indexResult.filesProcessed;
|
|
150
|
+
result.codeCacheHits = indexResult.cacheHits;
|
|
151
|
+
result.phasesCompleted.push(1);
|
|
152
|
+
progress.phases_completed.push(1);
|
|
153
|
+
progress.files_indexed = indexResult.filesProcessed;
|
|
154
|
+
writeProgress(cwd, progress);
|
|
155
|
+
log(
|
|
156
|
+
verbosity,
|
|
157
|
+
`[sia-learn] Phase 1: Done — ${indexResult.entitiesCreated} entities from ${indexResult.filesProcessed} files (${indexResult.cacheHits} cached)`,
|
|
158
|
+
);
|
|
159
|
+
} else {
|
|
160
|
+
result.phasesFailed.push(1);
|
|
161
|
+
}
|
|
162
|
+
} else {
|
|
163
|
+
result.phasesCompleted.push(1);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// --- Phase 2: Markdown doc ingestion ---
|
|
167
|
+
if (!phasesToSkip.has(2)) {
|
|
168
|
+
log(verbosity, "[sia-learn] Phase 2: Ingesting docs...");
|
|
169
|
+
const docResult = await runWithRetry("Phase 2: Doc ingestion", async () => {
|
|
170
|
+
const { discoverDocFiles } = await import("@/knowledge/discovery");
|
|
171
|
+
const { ingestDocument } = await import("@/knowledge/ingest");
|
|
172
|
+
const { detectExternalRefs } = await import("@/knowledge/external-refs");
|
|
173
|
+
|
|
174
|
+
const docFiles = discoverDocFiles(cwd);
|
|
175
|
+
let docsIngested = 0;
|
|
176
|
+
let chunksCreated = 0;
|
|
177
|
+
let refsFound = 0;
|
|
178
|
+
|
|
179
|
+
for (const doc of docFiles) {
|
|
180
|
+
try {
|
|
181
|
+
// Incremental: skip if file hasn't changed
|
|
182
|
+
if (opts.incremental && !opts.force) {
|
|
183
|
+
const { statSync } = await import("node:fs");
|
|
184
|
+
const fileMtime = statSync(doc.absolutePath).mtimeMs;
|
|
185
|
+
const existing = await db.execute(
|
|
186
|
+
`SELECT updated_at FROM graph_nodes
|
|
187
|
+
WHERE file_paths LIKE ? AND type = 'FileNode'
|
|
188
|
+
AND t_valid_until IS NULL AND archived_at IS NULL
|
|
189
|
+
LIMIT 1`,
|
|
190
|
+
[`%${doc.relativePath}%`],
|
|
191
|
+
);
|
|
192
|
+
if (existing.rows.length > 0 && (existing.rows[0] as any).updated_at >= fileMtime) {
|
|
193
|
+
continue; // Skip unchanged file
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const ingestResult = await ingestDocument(db, doc.absolutePath, doc.relativePath, {
|
|
198
|
+
tag: doc.pattern.tag,
|
|
199
|
+
trustTier: doc.pattern.trustTier as 1 | 2,
|
|
200
|
+
packagePath: doc.packagePath,
|
|
201
|
+
});
|
|
202
|
+
docsIngested++;
|
|
203
|
+
chunksCreated += ingestResult.chunksCreated;
|
|
204
|
+
|
|
205
|
+
// Detect external refs in doc content
|
|
206
|
+
try {
|
|
207
|
+
const content = readFileSync(doc.absolutePath, "utf-8");
|
|
208
|
+
const refs = detectExternalRefs(content);
|
|
209
|
+
refsFound += refs.length;
|
|
210
|
+
} catch {
|
|
211
|
+
// Non-fatal — skip external ref detection for this file
|
|
212
|
+
}
|
|
213
|
+
} catch (err) {
|
|
214
|
+
// Per-file error — log and continue
|
|
215
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
216
|
+
process.stderr.write(
|
|
217
|
+
`[sia-learn] Warning: Failed to ingest ${doc.relativePath}: ${msg}\n`,
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return { docsIngested, chunksCreated, refsFound };
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
if (docResult) {
|
|
226
|
+
result.docsIngested = docResult.docsIngested;
|
|
227
|
+
result.docChunks = docResult.chunksCreated;
|
|
228
|
+
result.externalRefs = docResult.refsFound;
|
|
229
|
+
result.phasesCompleted.push(2);
|
|
230
|
+
progress.phases_completed.push(2);
|
|
231
|
+
writeProgress(cwd, progress);
|
|
232
|
+
log(
|
|
233
|
+
verbosity,
|
|
234
|
+
`[sia-learn] Phase 2: Done — ${docResult.chunksCreated} chunks from ${docResult.docsIngested} documents, ${docResult.refsFound} external refs`,
|
|
235
|
+
);
|
|
236
|
+
} else {
|
|
237
|
+
result.phasesFailed.push(2);
|
|
238
|
+
}
|
|
239
|
+
} else {
|
|
240
|
+
result.phasesCompleted.push(2);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// --- Phase 3: Community detection + summarization ---
|
|
244
|
+
if (!phasesToSkip.has(3)) {
|
|
245
|
+
log(verbosity, "[sia-learn] Phase 3: Detecting communities...");
|
|
246
|
+
const communityResult = await runWithRetry("Phase 3: Community detection", async () => {
|
|
247
|
+
const { detectCommunities } = await import("@/community/leiden");
|
|
248
|
+
const { summarizeCommunities } = await import("@/community/summarize");
|
|
249
|
+
|
|
250
|
+
const detectionResult = await detectCommunities(db);
|
|
251
|
+
|
|
252
|
+
// Summarize if we have communities
|
|
253
|
+
if (detectionResult.totalCommunities > 0) {
|
|
254
|
+
await summarizeCommunities(db, { airGapped: config.airGapped ?? false });
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return detectionResult;
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
if (communityResult) {
|
|
261
|
+
result.communities = communityResult.totalCommunities;
|
|
262
|
+
result.phasesCompleted.push(3);
|
|
263
|
+
progress.phases_completed.push(3);
|
|
264
|
+
writeProgress(cwd, progress);
|
|
265
|
+
log(
|
|
266
|
+
verbosity,
|
|
267
|
+
`[sia-learn] Phase 3: Done — ${communityResult.totalCommunities} communities formed`,
|
|
268
|
+
);
|
|
269
|
+
} else {
|
|
270
|
+
result.phasesFailed.push(3);
|
|
271
|
+
}
|
|
272
|
+
} else {
|
|
273
|
+
result.phasesCompleted.push(3);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// --- Branch snapshot save (if Phase D.5 is available) ---
|
|
277
|
+
try {
|
|
278
|
+
// Check if branch_snapshots table exists
|
|
279
|
+
await db.execute("SELECT 1 FROM branch_snapshots LIMIT 0");
|
|
280
|
+
// Table exists — save snapshot for current branch
|
|
281
|
+
const { createBranchSnapshot } = await import("@/graph/snapshots");
|
|
282
|
+
const { execFileSync } = await import("node:child_process");
|
|
283
|
+
const branch = execFileSync("git", ["branch", "--show-current"], {
|
|
284
|
+
cwd,
|
|
285
|
+
encoding: "utf-8",
|
|
286
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
287
|
+
}).trim();
|
|
288
|
+
const commit = execFileSync("git", ["rev-parse", "--short", "HEAD"], {
|
|
289
|
+
cwd,
|
|
290
|
+
encoding: "utf-8",
|
|
291
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
292
|
+
}).trim();
|
|
293
|
+
if (branch) {
|
|
294
|
+
await createBranchSnapshot(db, branch, commit);
|
|
295
|
+
log(verbosity, `[sia-learn] Saved snapshot for branch '${branch}' at ${commit}`);
|
|
296
|
+
}
|
|
297
|
+
} catch {
|
|
298
|
+
// branch_snapshots table doesn't exist — Phase D.5 not implemented yet, skip silently
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// --- Summary ---
|
|
302
|
+
result.durationMs = Date.now() - start;
|
|
303
|
+
deleteProgress(cwd); // Clean finish
|
|
304
|
+
|
|
305
|
+
const summary = `
|
|
306
|
+
=== SIA Learn Complete ===
|
|
307
|
+
Code entities: ${result.codeEntities} (${result.codeFiles} files, ${result.codeCacheHits} cached)
|
|
308
|
+
Doc chunks: ${result.docChunks} (${result.docsIngested} documents)
|
|
309
|
+
External refs: ${result.externalRefs}
|
|
310
|
+
Communities: ${result.communities}
|
|
311
|
+
Duration: ${(result.durationMs / 1000).toFixed(1)}s
|
|
312
|
+
${result.phasesFailed.length > 0 ? `Failed phases: ${result.phasesFailed.join(", ")}` : ""}
|
|
313
|
+
${result.skippedFiles.length > 0 ? `Skipped files: ${result.skippedFiles.length}` : ""}`;
|
|
314
|
+
|
|
315
|
+
process.stderr.write(`${summary.trim()}\n`);
|
|
316
|
+
|
|
317
|
+
return result;
|
|
318
|
+
} finally {
|
|
319
|
+
await db.close();
|
|
320
|
+
}
|
|
321
|
+
}
|