@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.
Files changed (355) hide show
  1. package/.claude-plugin/marketplace.json +35 -0
  2. package/.claude-plugin/plugin.json +27 -0
  3. package/.mcp.json +13 -0
  4. package/CLAUDE.md +226 -0
  5. package/LICENSE +202 -0
  6. package/PLUGIN_README.md +253 -0
  7. package/README.md +1013 -0
  8. package/agents/sia-changelog-writer.md +89 -0
  9. package/agents/sia-code-reviewer.md +86 -0
  10. package/agents/sia-conflict-resolver.md +100 -0
  11. package/agents/sia-convention-enforcer.md +69 -0
  12. package/agents/sia-debug.md +106 -0
  13. package/agents/sia-decision-reviewer.md +101 -0
  14. package/agents/sia-dependency-tracker.md +80 -0
  15. package/agents/sia-explain.md +126 -0
  16. package/agents/sia-feature.md +116 -0
  17. package/agents/sia-knowledge-capture.md +117 -0
  18. package/agents/sia-lead-architecture-advisor.md +93 -0
  19. package/agents/sia-lead-team-health.md +107 -0
  20. package/agents/sia-migration.md +100 -0
  21. package/agents/sia-onboarding.md +115 -0
  22. package/agents/sia-orientation.md +99 -0
  23. package/agents/sia-pm-briefing.md +106 -0
  24. package/agents/sia-pm-risk-advisor.md +82 -0
  25. package/agents/sia-qa-analyst.md +116 -0
  26. package/agents/sia-qa-regression-map.md +94 -0
  27. package/agents/sia-refactor.md +115 -0
  28. package/agents/sia-regression.md +112 -0
  29. package/agents/sia-security-audit.md +125 -0
  30. package/agents/sia-test-advisor.md +91 -0
  31. package/hooks/hooks.json +98 -0
  32. package/migrations/bridge/001_initial.sql +34 -0
  33. package/migrations/episodic/001_initial.sql +35 -0
  34. package/migrations/meta/001_initial.sql +68 -0
  35. package/migrations/semantic/001_initial.sql +292 -0
  36. package/migrations/semantic/002_ontology.sql +89 -0
  37. package/migrations/semantic/003_freshness.sql +63 -0
  38. package/migrations/semantic/004_v5_unified_schema.sql +194 -0
  39. package/migrations/semantic/005_backfill_event_kinds.sql +8 -0
  40. package/migrations/semantic/006_tree_sitter.sql +6 -0
  41. package/migrations/semantic/007_branch_snapshots.sql +22 -0
  42. package/package.json +110 -0
  43. package/scripts/branch-switch.sh +13 -0
  44. package/scripts/build-wasm-grammars.sh +81 -0
  45. package/scripts/post-compact.sh +8 -0
  46. package/scripts/post-tool-use.sh +10 -0
  47. package/scripts/pre-compact.sh +8 -0
  48. package/scripts/session-end.sh +8 -0
  49. package/scripts/session-start.sh +8 -0
  50. package/scripts/start-mcp.ts +45 -0
  51. package/scripts/stop-hook.sh +8 -0
  52. package/scripts/user-prompt-submit.sh +8 -0
  53. package/scripts/viz-server.ts +152 -0
  54. package/skills/sia-brainstorm/SKILL.md +156 -0
  55. package/skills/sia-brainstorm/scripts/frame-template.html +214 -0
  56. package/skills/sia-brainstorm/scripts/helper.js +95 -0
  57. package/skills/sia-brainstorm/scripts/server.cjs +338 -0
  58. package/skills/sia-brainstorm/scripts/start-server.sh +153 -0
  59. package/skills/sia-brainstorm/scripts/stop-server.sh +55 -0
  60. package/skills/sia-brainstorm/spec-document-reviewer-prompt.md +49 -0
  61. package/skills/sia-brainstorm/visual-companion.md +286 -0
  62. package/skills/sia-capture/SKILL.md +64 -0
  63. package/skills/sia-compare/SKILL.md +33 -0
  64. package/skills/sia-conflicts/SKILL.md +38 -0
  65. package/skills/sia-debug-workflow/SKILL.md +120 -0
  66. package/skills/sia-debug-workflow/root-cause-tracing.md +70 -0
  67. package/skills/sia-debug-workflow/scripts/find-polluter.sh +64 -0
  68. package/skills/sia-debug-workflow/temporal-investigation.md +72 -0
  69. package/skills/sia-digest/SKILL.md +23 -0
  70. package/skills/sia-dispatch/SKILL.md +69 -0
  71. package/skills/sia-dispatch/agent-task-template.md +99 -0
  72. package/skills/sia-doctor/SKILL.md +39 -0
  73. package/skills/sia-execute/SKILL.md +70 -0
  74. package/skills/sia-execute-plan/SKILL.md +85 -0
  75. package/skills/sia-export-import/SKILL.md +49 -0
  76. package/skills/sia-export-knowledge/SKILL.md +46 -0
  77. package/skills/sia-finish/SKILL.md +100 -0
  78. package/skills/sia-finish/pr-summary-template.md +54 -0
  79. package/skills/sia-freshness/SKILL.md +38 -0
  80. package/skills/sia-history/SKILL.md +42 -0
  81. package/skills/sia-impact/SKILL.md +70 -0
  82. package/skills/sia-index/SKILL.md +54 -0
  83. package/skills/sia-install/SKILL.md +39 -0
  84. package/skills/sia-lead-compliance/SKILL.md +16 -0
  85. package/skills/sia-lead-drift-report/SKILL.md +16 -0
  86. package/skills/sia-lead-knowledge-map/SKILL.md +16 -0
  87. package/skills/sia-learn/SKILL.md +58 -0
  88. package/skills/sia-plan/SKILL.md +68 -0
  89. package/skills/sia-plan/plan-reviewer-prompt.md +63 -0
  90. package/skills/sia-playbooks/SKILL.md +29 -0
  91. package/skills/sia-playbooks/reference-feature.md +100 -0
  92. package/skills/sia-playbooks/reference-flagging.md +50 -0
  93. package/skills/sia-playbooks/reference-orientation.md +92 -0
  94. package/skills/sia-playbooks/reference-regression.md +115 -0
  95. package/skills/sia-playbooks/reference-review.md +64 -0
  96. package/skills/sia-playbooks/reference-tools.md +239 -0
  97. package/skills/sia-pm-decision-log/SKILL.md +28 -0
  98. package/skills/sia-pm-risk-dashboard/SKILL.md +24 -0
  99. package/skills/sia-pm-sprint-summary/SKILL.md +27 -0
  100. package/skills/sia-prune/SKILL.md +45 -0
  101. package/skills/sia-qa-coverage/SKILL.md +28 -0
  102. package/skills/sia-qa-flaky/SKILL.md +20 -0
  103. package/skills/sia-qa-report/SKILL.md +26 -0
  104. package/skills/sia-reindex/SKILL.md +30 -0
  105. package/skills/sia-review-respond/SKILL.md +88 -0
  106. package/skills/sia-review-respond/pushback-patterns.md +90 -0
  107. package/skills/sia-search/SKILL.md +47 -0
  108. package/skills/sia-setup/SKILL.md +82 -0
  109. package/skills/sia-setup/setup-checklist.md +97 -0
  110. package/skills/sia-stats/SKILL.md +36 -0
  111. package/skills/sia-status/SKILL.md +44 -0
  112. package/skills/sia-sync/SKILL.md +46 -0
  113. package/skills/sia-team/SKILL.md +64 -0
  114. package/skills/sia-test/SKILL.md +92 -0
  115. package/skills/sia-test/testing-anti-patterns.md +104 -0
  116. package/skills/sia-tour/SKILL.md +29 -0
  117. package/skills/sia-upgrade/SKILL.md +43 -0
  118. package/skills/sia-verify/SKILL.md +81 -0
  119. package/skills/sia-visualize/SKILL.md +28 -0
  120. package/skills/sia-visualize-live/SKILL.md +55 -0
  121. package/skills/sia-visualize-live/scripts/graph-template.html +389 -0
  122. package/skills/sia-visualize-live/scripts/start-visualizer.sh +161 -0
  123. package/skills/sia-visualize-live/scripts/stop-visualizer.sh +55 -0
  124. package/skills/sia-visualize-live/scripts/visualizer-server.cjs +264 -0
  125. package/skills/sia-workspace/SKILL.md +57 -0
  126. package/src/agent/claude-md-template-flagging.md +219 -0
  127. package/src/agent/claude-md-template.md +213 -0
  128. package/src/agent/modules/sia-feature.md +100 -0
  129. package/src/agent/modules/sia-flagging.md +50 -0
  130. package/src/agent/modules/sia-orientation.md +92 -0
  131. package/src/agent/modules/sia-regression.md +115 -0
  132. package/src/agent/modules/sia-review.md +64 -0
  133. package/src/agent/modules/sia-tools.md +239 -0
  134. package/src/ast/extractors/c-include.ts +189 -0
  135. package/src/ast/extractors/csharp-project.ts +260 -0
  136. package/src/ast/extractors/prisma-schema.ts +44 -0
  137. package/src/ast/extractors/project-manifest.ts +111 -0
  138. package/src/ast/extractors/sql-schema.ts +67 -0
  139. package/src/ast/extractors/tier-a.ts +423 -0
  140. package/src/ast/extractors/tier-b.ts +289 -0
  141. package/src/ast/extractors/tier-dispatch.ts +247 -0
  142. package/src/ast/index-worker.ts +108 -0
  143. package/src/ast/indexer.ts +484 -0
  144. package/src/ast/languages.ts +408 -0
  145. package/src/ast/pagerank-builder.ts +125 -0
  146. package/src/ast/path-utils.ts +137 -0
  147. package/src/ast/tree-sitter/backends/native.ts +57 -0
  148. package/src/ast/tree-sitter/backends/wasm.ts +39 -0
  149. package/src/ast/tree-sitter/call-walker.ts +44 -0
  150. package/src/ast/tree-sitter/edit-computer.ts +55 -0
  151. package/src/ast/tree-sitter/query-runner.ts +46 -0
  152. package/src/ast/tree-sitter/service.ts +174 -0
  153. package/src/ast/tree-sitter/tree-cache.ts +39 -0
  154. package/src/ast/tree-sitter/types.ts +79 -0
  155. package/src/ast/watcher.ts +322 -0
  156. package/src/capture/chunker.ts +169 -0
  157. package/src/capture/consolidate.ts +127 -0
  158. package/src/capture/edge-inferrer.ts +161 -0
  159. package/src/capture/embedder.ts +166 -0
  160. package/src/capture/embedding-cache.ts +73 -0
  161. package/src/capture/flag-processor.ts +64 -0
  162. package/src/capture/hook.ts +67 -0
  163. package/src/capture/pipeline.ts +450 -0
  164. package/src/capture/prompts/consolidate.ts +25 -0
  165. package/src/capture/prompts/edge-infer.ts +29 -0
  166. package/src/capture/prompts/extract-flagged.ts +36 -0
  167. package/src/capture/prompts/extract.ts +42 -0
  168. package/src/capture/tokenizer.ts +147 -0
  169. package/src/capture/track-a-ast.ts +93 -0
  170. package/src/capture/track-b-llm.ts +149 -0
  171. package/src/capture/types.ts +64 -0
  172. package/src/cli/commands/community.ts +137 -0
  173. package/src/cli/commands/compare.ts +123 -0
  174. package/src/cli/commands/conflicts.ts +41 -0
  175. package/src/cli/commands/digest.ts +197 -0
  176. package/src/cli/commands/disable-flagging.ts +34 -0
  177. package/src/cli/commands/doctor.ts +240 -0
  178. package/src/cli/commands/download-model.ts +161 -0
  179. package/src/cli/commands/enable-flagging.ts +34 -0
  180. package/src/cli/commands/export-knowledge.ts +208 -0
  181. package/src/cli/commands/export.ts +85 -0
  182. package/src/cli/commands/freshness.ts +164 -0
  183. package/src/cli/commands/graph.ts +51 -0
  184. package/src/cli/commands/history.ts +139 -0
  185. package/src/cli/commands/import.ts +335 -0
  186. package/src/cli/commands/install.ts +156 -0
  187. package/src/cli/commands/lead-report.ts +241 -0
  188. package/src/cli/commands/learn.ts +321 -0
  189. package/src/cli/commands/pm-report.ts +413 -0
  190. package/src/cli/commands/prune.ts +75 -0
  191. package/src/cli/commands/qa-report.ts +278 -0
  192. package/src/cli/commands/reindex.ts +104 -0
  193. package/src/cli/commands/rollback.ts +70 -0
  194. package/src/cli/commands/search.ts +103 -0
  195. package/src/cli/commands/server.ts +91 -0
  196. package/src/cli/commands/share.ts +33 -0
  197. package/src/cli/commands/stats.ts +79 -0
  198. package/src/cli/commands/status.ts +176 -0
  199. package/src/cli/commands/sync.ts +96 -0
  200. package/src/cli/commands/team.ts +118 -0
  201. package/src/cli/commands/tour.ts +157 -0
  202. package/src/cli/commands/visualize-live.ts +162 -0
  203. package/src/cli/commands/workspace.ts +117 -0
  204. package/src/cli/index.ts +424 -0
  205. package/src/cli/learn-progress.ts +87 -0
  206. package/src/community/detection-bridge.ts +344 -0
  207. package/src/community/leiden.ts +462 -0
  208. package/src/community/raptor.ts +210 -0
  209. package/src/community/scheduler.ts +74 -0
  210. package/src/community/summarize.ts +115 -0
  211. package/src/decay/archiver.ts +73 -0
  212. package/src/decay/bridge-orphan-cleanup.ts +212 -0
  213. package/src/decay/consolidation-sweep.ts +112 -0
  214. package/src/decay/decay.ts +116 -0
  215. package/src/decay/deep-validator.ts +62 -0
  216. package/src/decay/episodic-promoter.ts +132 -0
  217. package/src/decay/maintenance-scheduler.ts +326 -0
  218. package/src/decay/scheduler.ts +6 -0
  219. package/src/decay/session-sweeper.ts +79 -0
  220. package/src/decay/types.ts +17 -0
  221. package/src/freshness/confidence-decay.ts +122 -0
  222. package/src/freshness/cuckoo-filter.ts +176 -0
  223. package/src/freshness/deep-validation.ts +345 -0
  224. package/src/freshness/dirty-tracker.ts +237 -0
  225. package/src/freshness/file-watcher-layer.ts +119 -0
  226. package/src/freshness/firewall.ts +64 -0
  227. package/src/freshness/git-reconcile-layer.ts +161 -0
  228. package/src/freshness/inverted-index.ts +158 -0
  229. package/src/freshness/stale-read-layer.ts +222 -0
  230. package/src/graph/audit.ts +69 -0
  231. package/src/graph/bridge-db.ts +141 -0
  232. package/src/graph/communities.ts +195 -0
  233. package/src/graph/db-interface.ts +259 -0
  234. package/src/graph/edges.ts +163 -0
  235. package/src/graph/entities.ts +327 -0
  236. package/src/graph/episodic-db.ts +113 -0
  237. package/src/graph/flags.ts +31 -0
  238. package/src/graph/meta-db.ts +200 -0
  239. package/src/graph/semantic-db.ts +101 -0
  240. package/src/graph/session-resume.ts +56 -0
  241. package/src/graph/snapshots.ts +342 -0
  242. package/src/graph/staging.ts +151 -0
  243. package/src/graph/types.ts +128 -0
  244. package/src/hooks/adapters/claude-code.ts +21 -0
  245. package/src/hooks/adapters/cline.ts +43 -0
  246. package/src/hooks/adapters/cursor.ts +65 -0
  247. package/src/hooks/adapters/generic.ts +12 -0
  248. package/src/hooks/agent-detect.ts +34 -0
  249. package/src/hooks/claude-md-directives.ts +32 -0
  250. package/src/hooks/event-router.ts +182 -0
  251. package/src/hooks/extractors/pattern-detector.ts +111 -0
  252. package/src/hooks/handlers/post-compact.ts +30 -0
  253. package/src/hooks/handlers/post-tool-use.ts +403 -0
  254. package/src/hooks/handlers/pre-compact.ts +100 -0
  255. package/src/hooks/handlers/session-end.ts +47 -0
  256. package/src/hooks/handlers/session-start.ts +154 -0
  257. package/src/hooks/handlers/stop.ts +128 -0
  258. package/src/hooks/handlers/user-prompt-submit.ts +68 -0
  259. package/src/hooks/plugin-branch-switch.ts +68 -0
  260. package/src/hooks/plugin-common.ts +47 -0
  261. package/src/hooks/plugin-post-compact.ts +28 -0
  262. package/src/hooks/plugin-post-tool-use.ts +38 -0
  263. package/src/hooks/plugin-pre-compact.ts +37 -0
  264. package/src/hooks/plugin-session-end.ts +37 -0
  265. package/src/hooks/plugin-session-start.ts +75 -0
  266. package/src/hooks/plugin-stop.ts +61 -0
  267. package/src/hooks/plugin-user-prompt-submit.ts +47 -0
  268. package/src/hooks/types.ts +43 -0
  269. package/src/knowledge/discovery.ts +238 -0
  270. package/src/knowledge/external-refs.ts +98 -0
  271. package/src/knowledge/freshness.ts +221 -0
  272. package/src/knowledge/ingest.ts +330 -0
  273. package/src/knowledge/markdown-export.ts +229 -0
  274. package/src/knowledge/markdown-import.ts +359 -0
  275. package/src/knowledge/patterns.ts +74 -0
  276. package/src/knowledge/templates.ts +307 -0
  277. package/src/llm/ai-sdk-adapter.ts +46 -0
  278. package/src/llm/config.ts +88 -0
  279. package/src/llm/cost-tracker.ts +110 -0
  280. package/src/llm/prompts/extraction.ts +55 -0
  281. package/src/llm/prompts/summarization.ts +36 -0
  282. package/src/llm/prompts/validation.ts +37 -0
  283. package/src/llm/provider-registry.ts +68 -0
  284. package/src/llm/reliability.ts +179 -0
  285. package/src/llm/schemas.ts +52 -0
  286. package/src/mcp/freshness-annotator.ts +69 -0
  287. package/src/mcp/server.ts +949 -0
  288. package/src/mcp/tools/sia-ast-query.ts +225 -0
  289. package/src/mcp/tools/sia-at-time.ts +151 -0
  290. package/src/mcp/tools/sia-backlinks.ts +87 -0
  291. package/src/mcp/tools/sia-batch-execute.ts +169 -0
  292. package/src/mcp/tools/sia-by-file.ts +89 -0
  293. package/src/mcp/tools/sia-community.ts +113 -0
  294. package/src/mcp/tools/sia-doctor.ts +73 -0
  295. package/src/mcp/tools/sia-execute-file.ts +122 -0
  296. package/src/mcp/tools/sia-execute.ts +104 -0
  297. package/src/mcp/tools/sia-expand.ts +158 -0
  298. package/src/mcp/tools/sia-fetch-and-index.ts +241 -0
  299. package/src/mcp/tools/sia-flag.ts +65 -0
  300. package/src/mcp/tools/sia-index.ts +111 -0
  301. package/src/mcp/tools/sia-note.ts +134 -0
  302. package/src/mcp/tools/sia-search.ts +105 -0
  303. package/src/mcp/tools/sia-stats.ts +63 -0
  304. package/src/mcp/tools/sia-sync-status.ts +44 -0
  305. package/src/mcp/tools/sia-upgrade.ts +247 -0
  306. package/src/mcp/truncate.ts +231 -0
  307. package/src/native/bridge.ts +167 -0
  308. package/src/native/fallback-ast-diff.ts +144 -0
  309. package/src/native/fallback-graph.ts +325 -0
  310. package/src/ontology/constraints.ts +56 -0
  311. package/src/ontology/errors.ts +8 -0
  312. package/src/ontology/middleware.ts +266 -0
  313. package/src/retrieval/bm25-search.ts +151 -0
  314. package/src/retrieval/context-assembly.ts +76 -0
  315. package/src/retrieval/graph-traversal.ts +168 -0
  316. package/src/retrieval/pagerank.ts +40 -0
  317. package/src/retrieval/query-classifier.ts +106 -0
  318. package/src/retrieval/reranker.ts +156 -0
  319. package/src/retrieval/search.ts +236 -0
  320. package/src/retrieval/throttle.ts +102 -0
  321. package/src/retrieval/vector-search.ts +203 -0
  322. package/src/retrieval/workspace-search.ts +130 -0
  323. package/src/sandbox/context-mode.ts +285 -0
  324. package/src/sandbox/credential-pass.ts +55 -0
  325. package/src/sandbox/executor.ts +235 -0
  326. package/src/security/pattern-detector.ts +127 -0
  327. package/src/security/rule-of-two.ts +50 -0
  328. package/src/security/sanitize.ts +46 -0
  329. package/src/security/semantic-consistency.ts +93 -0
  330. package/src/security/staging-promoter.ts +154 -0
  331. package/src/shared/config.ts +302 -0
  332. package/src/shared/diagnostics.ts +210 -0
  333. package/src/shared/errors.ts +48 -0
  334. package/src/shared/git-utils.ts +143 -0
  335. package/src/shared/llm-client.ts +120 -0
  336. package/src/shared/logger.ts +99 -0
  337. package/src/shared/types.ts +79 -0
  338. package/src/sync/client.ts +43 -0
  339. package/src/sync/conflict.ts +106 -0
  340. package/src/sync/dedup.ts +183 -0
  341. package/src/sync/hlc.ts +117 -0
  342. package/src/sync/keychain.ts +144 -0
  343. package/src/sync/pull.ts +232 -0
  344. package/src/sync/push.ts +131 -0
  345. package/src/types/chokidar.d.ts +23 -0
  346. package/src/visualization/graph-renderer.ts +312 -0
  347. package/src/visualization/subgraph-extract.ts +208 -0
  348. package/src/visualization/views/community-clusters.ts +246 -0
  349. package/src/visualization/views/dependency-map.ts +189 -0
  350. package/src/visualization/views/graph-explorer.ts +364 -0
  351. package/src/visualization/views/timeline.ts +247 -0
  352. package/src/workspace/api-contracts.ts +226 -0
  353. package/src/workspace/cross-repo.ts +61 -0
  354. package/src/workspace/detector.ts +190 -0
  355. 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
+ }