@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,450 @@
1
+ // Module: pipeline — End-to-end capture pipeline orchestration
2
+ //
3
+ // Wires together: chunker -> Track A + Track B -> consolidation -> edge inference -> flag processing.
4
+ // Includes circuit breaker for consolidation failures and global timeout.
5
+
6
+ import { randomUUID } from "node:crypto";
7
+ import { chunkPayload } from "@/capture/chunker";
8
+ import { consolidate } from "@/capture/consolidate";
9
+ import { inferEdges } from "@/capture/edge-inferrer";
10
+ import { processFlags } from "@/capture/flag-processor";
11
+ import { resolveRepoHash } from "@/capture/hook";
12
+ import { extractTrackA } from "@/capture/track-a-ast";
13
+ import { extractTrackB } from "@/capture/track-b-llm";
14
+ import type {
15
+ CandidateFact,
16
+ ConsolidationResult,
17
+ HookPayload,
18
+ PipelineResult,
19
+ } from "@/capture/types";
20
+ import { writeAuditEntry } from "@/graph/audit";
21
+ import { insertCrossRepoEdge, openBridgeDb } from "@/graph/bridge-db";
22
+ import type { SiaDb } from "@/graph/db-interface";
23
+ import { insertEntity, updateEntity } from "@/graph/entities";
24
+ import { openEpisodicDb, openGraphDb } from "@/graph/semantic-db";
25
+ import { insertStagedFact } from "@/graph/staging";
26
+ import { getConfig, type SiaConfig } from "@/shared/config";
27
+
28
+ // ---------------------------------------------------------------------------
29
+ // Types
30
+ // ---------------------------------------------------------------------------
31
+
32
+ export interface PipelineOpts {
33
+ siaHome?: string;
34
+ config?: SiaConfig;
35
+ /** Optional meta.db handle for sharing rules enforcement. */
36
+ metaDb?: SiaDb;
37
+ }
38
+
39
+ // ---------------------------------------------------------------------------
40
+ // Circuit breaker — module-level state
41
+ // ---------------------------------------------------------------------------
42
+
43
+ let failureCount = 0;
44
+ let breakerActiveUntil = 0;
45
+
46
+ /** Reset the circuit breaker (for testing). */
47
+ export function resetCircuitBreaker(): void {
48
+ failureCount = 0;
49
+ breakerActiveUntil = 0;
50
+ }
51
+
52
+ function isCircuitBreakerActive(): boolean {
53
+ if (Date.now() > breakerActiveUntil && breakerActiveUntil > 0) {
54
+ // Breaker expired — reset
55
+ failureCount = 0;
56
+ breakerActiveUntil = 0;
57
+ }
58
+ return Date.now() < breakerActiveUntil;
59
+ }
60
+
61
+ // ---------------------------------------------------------------------------
62
+ // Cross-repo detection
63
+ // ---------------------------------------------------------------------------
64
+
65
+ /**
66
+ * Scan candidates for workspace:* npm imports or TypeScript project references.
67
+ * When metaDb is provided, looks up api_contracts where the current repo is the consumer
68
+ * and writes depends_on edges to bridge.db for matching patterns.
69
+ * Returns the number of cross-repo edges written (0 if no metaDb provided).
70
+ */
71
+ export async function detectCrossRepoEdges(
72
+ _graphDb: SiaDb,
73
+ bridgeDb: SiaDb,
74
+ candidates: CandidateFact[],
75
+ repoHash: string,
76
+ metaDb?: SiaDb,
77
+ ): Promise<number> {
78
+ if (!metaDb) {
79
+ return 0;
80
+ }
81
+
82
+ // Find candidates that match cross-repo patterns
83
+ const matchingCandidates: CandidateFact[] = [];
84
+ for (const candidate of candidates) {
85
+ if (/"workspace:\*"/.test(candidate.content) || /"references":/.test(candidate.content)) {
86
+ matchingCandidates.push(candidate);
87
+ }
88
+ }
89
+
90
+ if (matchingCandidates.length === 0) {
91
+ return 0;
92
+ }
93
+
94
+ // Look up api_contracts where this repo is the consumer
95
+ const { rows: contracts } = await metaDb.execute(
96
+ "SELECT id, provider_repo_id, consumer_repo_id, contract_type FROM api_contracts WHERE consumer_repo_id = ?",
97
+ [repoHash],
98
+ );
99
+
100
+ if (contracts.length === 0) {
101
+ return 0;
102
+ }
103
+
104
+ // Write a depends_on edge for each (matching candidate, contract) pair
105
+ let edgesWritten = 0;
106
+ for (const candidate of matchingCandidates) {
107
+ for (const contract of contracts) {
108
+ const providerRepoId = contract.provider_repo_id as string;
109
+ await insertCrossRepoEdge(bridgeDb, {
110
+ source_repo_id: repoHash,
111
+ source_entity_id: candidate.name,
112
+ target_repo_id: providerRepoId,
113
+ target_entity_id: providerRepoId,
114
+ type: "depends_on",
115
+ trust_tier: 2,
116
+ created_by: "auto-detect",
117
+ });
118
+ edgesWritten++;
119
+ }
120
+ }
121
+
122
+ return edgesWritten;
123
+ }
124
+
125
+ // ---------------------------------------------------------------------------
126
+ // Session compaction
127
+ // ---------------------------------------------------------------------------
128
+
129
+ /**
130
+ * Compact session content when it exceeds the working memory token budget.
131
+ * Creates a summary entity tagged with 'session-compaction'.
132
+ */
133
+ export async function compactSession(
134
+ db: SiaDb,
135
+ sessionContent: string,
136
+ config: SiaConfig,
137
+ ): Promise<void> {
138
+ // Rough token estimate: 1 token ~ 4 chars
139
+ const estimatedTokens = Math.ceil(sessionContent.length / 4);
140
+ if (estimatedTokens <= config.workingMemoryTokenBudget) {
141
+ return;
142
+ }
143
+
144
+ const summary = sessionContent.slice(0, 200);
145
+ await insertEntity(db, {
146
+ type: "Concept",
147
+ name: summary.slice(0, 50),
148
+ content: summary,
149
+ summary: summary.slice(0, 80),
150
+ tags: JSON.stringify(["session-compaction"]),
151
+ });
152
+ }
153
+
154
+ // ---------------------------------------------------------------------------
155
+ // Pipeline timeout helper
156
+ // ---------------------------------------------------------------------------
157
+
158
+ const PIPELINE_TIMEOUT_MS = 8_000;
159
+
160
+ function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {
161
+ return Promise.race([
162
+ promise,
163
+ new Promise<never>((_resolve, reject) => {
164
+ setTimeout(() => reject(new Error("Pipeline timeout")), ms);
165
+ }),
166
+ ]);
167
+ }
168
+
169
+ // ---------------------------------------------------------------------------
170
+ // Sharing rules enforcement (Task 11.6)
171
+ // ---------------------------------------------------------------------------
172
+
173
+ /**
174
+ * After consolidation, check sharing_rules in meta.db and override entity
175
+ * visibility for entities matching a rule's workspace + type criteria.
176
+ * Logs auto-promotion to audit_log.
177
+ */
178
+ async function applySharingRules(
179
+ graphDb: SiaDb,
180
+ metaDb: SiaDb,
181
+ repoHash: string,
182
+ entityIds: string[],
183
+ ): Promise<void> {
184
+ if (entityIds.length === 0) return;
185
+
186
+ // Find which workspace this repo belongs to
187
+ const { rows: wsRows } = await metaDb.execute(
188
+ "SELECT workspace_id FROM workspace_repos WHERE repo_id = ?",
189
+ [repoHash],
190
+ );
191
+ if (wsRows.length === 0) return;
192
+
193
+ const workspaceId = wsRows[0].workspace_id as string;
194
+
195
+ // Query sharing rules for this workspace (or global rules where workspace_id IS NULL)
196
+ const { rows: rules } = await metaDb.execute(
197
+ `SELECT entity_type, default_visibility FROM sharing_rules
198
+ WHERE (workspace_id = ? OR workspace_id IS NULL)
199
+ ORDER BY workspace_id DESC`,
200
+ [workspaceId],
201
+ );
202
+ if (rules.length === 0) return;
203
+
204
+ // Build a type→visibility lookup (workspace-specific rules take precedence)
205
+ const ruleMap = new Map<string | null, string>();
206
+ for (const rule of rules) {
207
+ const type = (rule.entity_type as string | null) ?? null;
208
+ if (!ruleMap.has(type)) {
209
+ ruleMap.set(type, rule.default_visibility as string);
210
+ }
211
+ }
212
+
213
+ // Apply rules to newly created entities
214
+ for (const entityId of entityIds) {
215
+ const { rows } = await graphDb.execute(
216
+ "SELECT type, visibility FROM graph_nodes WHERE id = ?",
217
+ [entityId],
218
+ );
219
+ if (rows.length === 0) continue;
220
+
221
+ const entityType = rows[0].type as string;
222
+ const currentVisibility = rows[0].visibility as string;
223
+
224
+ // Check type-specific rule first, then wildcard (null type)
225
+ const newVisibility = ruleMap.get(entityType) ?? ruleMap.get(null);
226
+ if (newVisibility && newVisibility !== currentVisibility) {
227
+ await updateEntity(graphDb, entityId, { visibility: newVisibility });
228
+ await writeAuditEntry(graphDb, "UPDATE", { entity_id: entityId });
229
+ }
230
+ }
231
+ }
232
+
233
+ // ---------------------------------------------------------------------------
234
+ // Main pipeline
235
+ // ---------------------------------------------------------------------------
236
+
237
+ export async function runPipeline(
238
+ payload: HookPayload,
239
+ opts?: PipelineOpts,
240
+ ): Promise<PipelineResult> {
241
+ const start = Date.now();
242
+ const siaHome = opts?.siaHome;
243
+ const config = opts?.config ?? getConfig(siaHome);
244
+ const repoHash = resolveRepoHash(payload.cwd);
245
+
246
+ const graphDb = openGraphDb(repoHash, siaHome);
247
+ const episodicDb = openEpisodicDb(repoHash, siaHome);
248
+
249
+ // Partial result used on timeout or failure
250
+ const partialResult = (): PipelineResult => ({
251
+ candidates: 0,
252
+ consolidation: { added: 0, updated: 0, invalidated: 0, noops: 0 },
253
+ edgesCreated: 0,
254
+ flagsProcessed: 0,
255
+ durationMs: Date.now() - start,
256
+ circuitBreakerActive: isCircuitBreakerActive(),
257
+ });
258
+
259
+ async function run(): Promise<PipelineResult> {
260
+ try {
261
+ // Step 4-5: Write episode to episodic.db FIRST
262
+ const episodeId = randomUUID();
263
+ const episodeType = payload.toolName ? "tool_use" : "conversation";
264
+ const role = payload.type === "Stop" ? "assistant" : "tool";
265
+
266
+ await episodicDb.execute(
267
+ `INSERT INTO episodes (id, session_id, ts, type, role, content, tool_name, file_path, trust_tier)
268
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
269
+ [
270
+ episodeId,
271
+ payload.sessionId,
272
+ Date.now(),
273
+ episodeType,
274
+ role,
275
+ payload.content,
276
+ payload.toolName ?? null,
277
+ payload.filePath ?? null,
278
+ payload.type === "Stop" ? 1 : 3,
279
+ ],
280
+ );
281
+
282
+ // Step 6: Run chunker
283
+ const chunkerCandidates = await chunkPayload(payload, config, graphDb);
284
+
285
+ // Step 7: Run Track A + Track B in parallel
286
+ const [trackAResult, trackBResult] = await Promise.allSettled([
287
+ Promise.resolve(extractTrackA(payload.content, payload.filePath)),
288
+ extractTrackB(payload.content, {
289
+ captureModel: config.captureModel,
290
+ minExtractConfidence: config.minExtractConfidence,
291
+ airGapped: config.airGapped,
292
+ }),
293
+ ]);
294
+
295
+ // Step 8: Merge all candidates
296
+ const allCandidates: CandidateFact[] = [...chunkerCandidates];
297
+ if (trackAResult.status === "fulfilled") {
298
+ allCandidates.push(...trackAResult.value);
299
+ }
300
+ if (trackBResult.status === "fulfilled") {
301
+ allCandidates.push(...trackBResult.value);
302
+ }
303
+
304
+ // Step 9: Consolidation (or direct-write if circuit breaker active)
305
+ let consolidation: ConsolidationResult = { added: 0, updated: 0, invalidated: 0, noops: 0 };
306
+ const newEntityIds: string[] = [];
307
+
308
+ if (isCircuitBreakerActive()) {
309
+ // Direct-write: insert all as ADD
310
+ for (const candidate of allCandidates) {
311
+ const entity = await insertEntity(graphDb, {
312
+ type: candidate.type,
313
+ name: candidate.name,
314
+ content: candidate.content,
315
+ summary: candidate.summary,
316
+ tags: JSON.stringify(candidate.tags),
317
+ file_paths: JSON.stringify(candidate.file_paths),
318
+ trust_tier: candidate.trust_tier,
319
+ confidence: candidate.confidence,
320
+ extraction_method: candidate.extraction_method ?? null,
321
+ t_valid_from: candidate.t_valid_from ?? null,
322
+ });
323
+ newEntityIds.push(entity.id);
324
+ consolidation.added++;
325
+ }
326
+ } else {
327
+ try {
328
+ // Route Tier 4 candidates to staging instead of consolidation
329
+ const tier4Candidates = allCandidates.filter((c) => c.trust_tier === 4);
330
+ const nonTier4Candidates = allCandidates.filter((c) => c.trust_tier !== 4);
331
+
332
+ for (const candidate of tier4Candidates) {
333
+ await insertStagedFact(graphDb, {
334
+ source_episode: payload.sessionId,
335
+ proposed_type: candidate.type,
336
+ proposed_name: candidate.name,
337
+ proposed_content: candidate.content,
338
+ proposed_tags: JSON.stringify(candidate.tags ?? []),
339
+ proposed_file_paths: JSON.stringify(candidate.file_paths ?? []),
340
+ trust_tier: candidate.trust_tier,
341
+ raw_confidence: candidate.confidence,
342
+ });
343
+ }
344
+
345
+ // Only consolidate non-Tier-4 candidates
346
+ consolidation = await consolidate(graphDb, nonTier4Candidates);
347
+
348
+ // Gather IDs of newly added entities for edge inference
349
+ for (const candidate of nonTier4Candidates) {
350
+ const result = await graphDb.execute(
351
+ "SELECT id FROM graph_nodes WHERE name = ? AND type = ? AND t_valid_until IS NULL AND archived_at IS NULL ORDER BY t_created DESC LIMIT 1",
352
+ [candidate.name, candidate.type],
353
+ );
354
+ const row = result.rows[0] as { id: string } | undefined;
355
+ if (row) {
356
+ newEntityIds.push(row.id);
357
+ }
358
+ }
359
+
360
+ // Reset failure count on success
361
+ failureCount = 0;
362
+ } catch {
363
+ failureCount++;
364
+ if (failureCount >= 3) {
365
+ breakerActiveUntil = Date.now() + 5 * 60 * 1000;
366
+ }
367
+ // Fall through — consolidation failed but pipeline continues
368
+ }
369
+ }
370
+
371
+ // Step 10: Edge inference
372
+ const edgesCreated = newEntityIds.length > 0 ? await inferEdges(graphDb, newEntityIds) : 0;
373
+
374
+ // Step 10.6: Cross-repo edge detection — writes depends_on edges to bridge.db
375
+ if (opts?.metaDb && allCandidates.length > 0) {
376
+ try {
377
+ const bridgeDb = openBridgeDb(siaHome);
378
+ try {
379
+ await detectCrossRepoEdges(graphDb, bridgeDb, allCandidates, repoHash, opts.metaDb);
380
+ } finally {
381
+ await bridgeDb.close();
382
+ }
383
+ } catch {
384
+ // Best effort — bridge edge detection failure should not break pipeline
385
+ }
386
+ }
387
+
388
+ // Step 10.5: Sharing rules enforcement (Task 11.6)
389
+ if (opts?.metaDb && newEntityIds.length > 0) {
390
+ try {
391
+ await applySharingRules(graphDb, opts.metaDb, repoHash, newEntityIds);
392
+ } catch {
393
+ // Best effort — sharing rules failure should not break pipeline
394
+ }
395
+ }
396
+
397
+ // Step 11: Flag processor
398
+ const flagsProcessed = await processFlags(graphDb, payload.sessionId, config);
399
+
400
+ // Step 12: Write sessions_processed entry
401
+ await episodicDb.execute(
402
+ `INSERT OR REPLACE INTO sessions_processed (session_id, processing_status, processed_at, entity_count, pipeline_version)
403
+ VALUES (?, ?, ?, ?, ?)`,
404
+ [payload.sessionId, "complete", Date.now(), consolidation.added, config.captureModel],
405
+ );
406
+
407
+ return {
408
+ candidates: allCandidates.length,
409
+ consolidation,
410
+ edgesCreated,
411
+ flagsProcessed,
412
+ durationMs: Date.now() - start,
413
+ circuitBreakerActive: isCircuitBreakerActive(),
414
+ };
415
+ } catch (err) {
416
+ // Write failed status
417
+ try {
418
+ await episodicDb.execute(
419
+ `INSERT OR REPLACE INTO sessions_processed (session_id, processing_status, processed_at, entity_count, pipeline_version)
420
+ VALUES (?, ?, ?, ?, ?)`,
421
+ [payload.sessionId, "failed", Date.now(), 0, config.captureModel],
422
+ );
423
+ } catch {
424
+ // Best effort
425
+ }
426
+ throw err;
427
+ }
428
+ }
429
+
430
+ try {
431
+ const result = await withTimeout(run(), PIPELINE_TIMEOUT_MS);
432
+ return result;
433
+ } catch (_err) {
434
+ // On timeout or unhandled error: write failed status, return partial
435
+ try {
436
+ await episodicDb.execute(
437
+ `INSERT OR REPLACE INTO sessions_processed (session_id, processing_status, processed_at, entity_count, pipeline_version)
438
+ VALUES (?, ?, ?, ?, ?)`,
439
+ [payload.sessionId, "failed", Date.now(), 0, config.captureModel],
440
+ );
441
+ } catch {
442
+ // Best effort
443
+ }
444
+ return partialResult();
445
+ } finally {
446
+ // Step 13: Close databases
447
+ await graphDb.close();
448
+ await episodicDb.close();
449
+ }
450
+ }
@@ -0,0 +1,25 @@
1
+ // src/capture/prompts/consolidate.ts — Two-phase consolidation prompt template
2
+
3
+ export function consolidatePrompt(
4
+ candidate: { kind: string; name: string; content: string; summary: string },
5
+ existingEntities: Array<{
6
+ id: string;
7
+ name: string;
8
+ content: string;
9
+ summary: string;
10
+ type: string;
11
+ }>,
12
+ ): { system: string; user: string } {
13
+ const system = `You are a knowledge graph consolidation engine. A new candidate fact has been extracted. Compare it against the existing entities and choose exactly one operation:
14
+
15
+ - NOOP: candidate duplicates an existing entity (>80% content overlap)
16
+ - UPDATE: candidate adds new information to an existing entity (20–80% overlap). Specify which entity ID.
17
+ - INVALIDATE: candidate supersedes or contradicts an existing entity. Specify which entity ID.
18
+ - ADD: candidate is genuinely new knowledge (no significant overlap with any existing entity)
19
+
20
+ Return JSON: { "decision": "ADD"|"UPDATE"|"INVALIDATE"|"NOOP", "target_id": "<entity_id or null>", "reasoning": "<brief explanation>" }
21
+ target_id is required for UPDATE and INVALIDATE, null for ADD and NOOP.`;
22
+
23
+ const user = `Candidate:\n${JSON.stringify(candidate, null, 2)}\n\nExisting entities:\n${JSON.stringify(existingEntities, null, 2)}`;
24
+ return { system, user };
25
+ }
@@ -0,0 +1,29 @@
1
+ // src/capture/prompts/edge-infer.ts — Edge inference prompt template
2
+
3
+ export function edgeInferPrompt(
4
+ source: { id: string; kind: string; name: string; content: string },
5
+ candidates: Array<{ id: string; kind: string; name: string; summary: string }>,
6
+ ): { system: string; user: string } {
7
+ const system = `You are a relationship inference engine for a code knowledge graph. Given a newly created entity and candidate related entities, propose edges (relationships) between them.
8
+
9
+ Valid edge types by source→target kind:
10
+ - Decision/Convention/Concept → CodeEntity/FileNode: pertains_to
11
+ - Bug → CodeEntity/FileNode: caused_by
12
+ - Solution → Bug: solves
13
+ - Solution → CodeEntity/FileNode: pertains_to
14
+ - Concept → Decision: elaborates
15
+ - Same kind → same kind: supersedes (if new replaces old)
16
+ - Same kind → same kind: contradicts (if they conflict)
17
+ - Any → Any: relates_to (general relationship)
18
+
19
+ Return JSON: { "edges": [{ "target_id": "<id>", "type": "<edge_type>", "weight": 0.0-1.0, "confidence": 0.0-1.0 }] }
20
+
21
+ Rules:
22
+ - Max 5 edges per entity
23
+ - Discard edges with weight < 0.3
24
+ - Only propose edges with valid source→target kind combinations
25
+ - Return { "edges": [] } if no meaningful relationships found`;
26
+
27
+ const user = `New entity:\n${JSON.stringify(source, null, 2)}\n\nCandidate targets:\n${JSON.stringify(candidates, null, 2)}`;
28
+ return { system, user };
29
+ }
@@ -0,0 +1,36 @@
1
+ // src/capture/prompts/extract-flagged.ts — Augmented extraction for developer-flagged content
2
+ import { sanitizeFlagReason, sanitizePromptInput } from "@/security/sanitize";
3
+
4
+ export function extractFlaggedPrompt(
5
+ flag: { reason: string; session_id: string },
6
+ transcriptChunk: string,
7
+ ): { system: string; user: string } {
8
+ const system = `You are a knowledge extraction engine for a code knowledge graph.
9
+ The developer has explicitly flagged the following content as significant.
10
+ Apply a lower confidence threshold (0.4) and pay special attention to the flagged reason.
11
+
12
+ Extract structured facts with confidence >= 0.4 (lower than the normal 0.6 threshold).
13
+ Return a JSON object with a "facts" array. Each fact must have:
14
+ - type: one of "Decision", "Convention", "Bug", "Solution", "Concept"
15
+ - name: concise name (3–200 characters)
16
+ - content: full description (10–2000 characters)
17
+ - summary: one sentence (max 20 words)
18
+ - tags: up to 5 relevant string tags
19
+ - file_paths: related file paths mentioned in context
20
+ - confidence: number 0.0–1.0
21
+ - proposed_relationships: optional array of { target_name, type, weight }
22
+
23
+ Return { "facts": [] } if nothing worth extracting.`;
24
+
25
+ const sanitizedReason = sanitizeFlagReason(flag.reason);
26
+ const sanitizedContent = sanitizePromptInput(transcriptChunk);
27
+
28
+ const user = `*** DEVELOPER FLAG ***
29
+ Reason: ${sanitizedReason}
30
+ *** END FLAG ***
31
+
32
+ Content to analyze:
33
+ ${sanitizedContent}`;
34
+
35
+ return { system, user };
36
+ }
@@ -0,0 +1,42 @@
1
+ // src/capture/prompts/extract.ts — Track B LLM extraction prompt template
2
+ import { sanitizePromptInput } from "@/security/sanitize";
3
+
4
+ export interface EntityContext {
5
+ name: string;
6
+ type: string;
7
+ summary: string;
8
+ }
9
+
10
+ export function extractPrompt(
11
+ content: string,
12
+ context?: EntityContext[],
13
+ ): { system: string; user: string } {
14
+ let contextBlock = "";
15
+ if (context && context.length > 0) {
16
+ const entries = context.map((e) => `- ${e.name} (${e.type}): ${e.summary}`).join("\n");
17
+ contextBlock = `\nThe graph already contains these entities — avoid duplicates:\n${entries}\n`;
18
+ }
19
+
20
+ const system = `You are a knowledge extraction engine for a code knowledge graph.
21
+ Extract structured facts from the content provided by the user.
22
+ ${contextBlock}
23
+ Return a JSON object with a "facts" array. Each fact must have:
24
+ - type: one of "Decision", "Convention", "Bug", "Solution", "Concept"
25
+ - name: concise name (3–200 characters)
26
+ - content: full description (10–2000 characters)
27
+ - summary: one sentence (max 20 words)
28
+ - tags: up to 5 relevant string tags
29
+ - file_paths: related file paths mentioned in context
30
+ - confidence: number 0.0–1.0 (how certain this fact is)
31
+ - proposed_relationships: optional array of { target_name: string, type: string, weight: number }
32
+
33
+ Rules:
34
+ - Only extract facts with confidence >= 0.6
35
+ - Do not extract raw code snippets as facts
36
+ - Decisions must include rationale
37
+ - Bugs must include symptoms or root cause
38
+ - Return { "facts": [] } if nothing worth extracting`;
39
+
40
+ const user = `Content to analyze:\n\n${sanitizePromptInput(content)}`;
41
+ return { system, user };
42
+ }